From bd1a458ad10d22271ef2ef220a25b6dcf2e433b9 Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Sat, 14 Sep 2024 15:34:25 +0800 Subject: [PATCH 01/23] Move add --- content/en/overview/_index.md | 33 +- content/en/overview/core-features/_index.md | 8 - .../en/overview/core-features/ecosystem.md | 43 - .../overview/core-features/extensibility.md | 102 -- .../en/overview/core-features/load-balance.md | 66 -- content/en/overview/core-features/more.md | 70 -- .../overview/core-features/observability.md | 54 - .../en/overview/core-features/protocols.md | 97 -- content/en/overview/core-features/security.md | 98 -- .../core-features/service-definition.md | 151 --- .../core-features/service-discovery.md | 68 -- .../en/overview/core-features/service-mesh.md | 76 -- .../overview/core-features/traffic/_index.md | 12 - .../core-features/traffic/condition-rule.md | 72 -- .../traffic/configuration-rule.md | 7 - .../core-features/traffic/mesh-rule.md | 8 - .../core-features/traffic/script-rule.md | 8 - .../core-features/traffic/tag-rule.md | 8 - content/en/overview/demo/_index.md | 4 +- content/en/overview/home/_index.md | 72 ++ content/en/overview/mannual/Golang.md | 14 - content/en/overview/mannual/Java.md | 13 - content/en/overview/mannual/Rust.md | 13 - content/en/overview/mannual/_index.md | 99 +- .../overview/mannual/control-plane/_index.md | 10 + .../mannual/control-plane/architecture.md | 296 ++++++ .../mannual/control-plane/documentation.md | 17 + .../en/overview/mannual/control-plane/mock.md | 176 ++++ .../overview/mannual/control-plane/search.md | 55 + .../en/overview/mannual/control-plane/test.md | 193 ++++ .../en/overview/mannual/golang-sdk/_index.md | 10 + .../mannual/golang-sdk/introduction.md | 124 +++ .../mannual/golang-sdk/quickstart/_index.md | 12 + .../golang-sdk/quickstart/microservices.md | 195 ++++ .../mannual/golang-sdk/quickstart/rpc.md | 248 +++++ .../mannual/golang-sdk/refer/_index.md | 11 + .../mannual/golang-sdk/refer/ecology.md | 64 ++ .../mannual/golang-sdk/refer/generic.md | 162 +++ .../mannual/golang-sdk/refer/nacos.md | 147 +++ .../refer/sourcecode/3.0_feature.md | 80 ++ .../golang-sdk/refer/sourcecode/_index.md | 10 + .../refer/sourcecode/aop_and_extension.md | 111 ++ .../refer/sourcecode/app_and_interface.md | 74 ++ .../refer/sourcecode/architecture.md | 31 + .../golang-sdk/refer/sourcecode/generic-2.md | 112 ++ .../golang-sdk/refer/sourcecode/generic.md | 107 ++ .../golang-sdk/refer/sourcecode/protocol.md | 33 + .../golang-sdk/refer/sourcecode/registry.md | 61 ++ .../golang-sdk/refer/use_dubbogo_cli.md | 436 ++++++++ .../mannual/golang-sdk/tutorial/_index.md | 11 + .../tutorial/configuration/_index.md | 161 +++ .../golang-sdk/tutorial/configuration/file.md | 280 +++++ .../tutorial/configuration/remote.md | 80 ++ .../golang-sdk/tutorial/deploy2/_index.md | 10 + .../golang-sdk/tutorial/deploy2/deploy.md | 430 ++++++++ .../tutorial/deploy2/graceful_shutdown.md | 66 ++ .../golang-sdk/tutorial/deploy2/istio.md | 40 + .../deploy2/proxyless_service_mesh.md | 116 +++ .../tutorial/deploy2/traffic_management.md | 425 ++++++++ .../golang-sdk/tutorial/gateway/_index.md | 7 + .../tutorial/gateway/http_triple.md | 88 ++ .../tutorial/gateway/pixiu-nacos-triple.md | 79 ++ .../tutorial/interop-dubbo/_index.md | 10 + .../call_java_protocol_dubbo_non_protobuf.md | 77 ++ .../call_java_protocol_triple_protobuf.md | 106 ++ .../interop-dubbo/service-discovery.md | 80 ++ .../tutorial/interop-grpc/_index.md | 10 + .../tutorial/interop-grpc/call_grpc.md | 244 +++++ .../tutorial/load-balance/_index.md | 6 + .../tutorial/load-balance/loadbalance.md | 61 ++ .../tutorial/observability/_index.md | 10 + .../tutorial/observability/logger.md | 77 ++ .../tutorial/observability/rpc_metrics.md | 147 +++ .../tutorial/observability/tracing.md | 85 ++ .../mannual/golang-sdk/tutorial/rpc/_index.md | 9 + .../golang-sdk/tutorial/rpc/attachments.md | 181 ++++ .../mannual/golang-sdk/tutorial/rpc/error.md | 156 +++ .../mannual/golang-sdk/tutorial/rpc/filter.md | 97 ++ .../golang-sdk/tutorial/rpc/healthcheck.md | 95 ++ .../golang-sdk/tutorial/rpc/protocol.md | 143 +++ .../mannual/golang-sdk/tutorial/rpc/retry.md | 185 ++++ .../golang-sdk/tutorial/rpc/start-check.md | 43 + .../golang-sdk/tutorial/rpc/streaming.md | 216 ++++ .../golang-sdk/tutorial/rpc/timeout.md | 155 +++ .../tutorial/service-discovery/_index.md | 11 + .../service-discovery/multi_registry.md | 86 ++ .../tutorial/service-discovery/nacos.md | 58 ++ .../tutorial/service-discovery/zookeeper.md | 68 ++ .../golang-sdk/tutorial/traffic/_index.md | 9 + .../golang-sdk/tutorial/traffic/router.md | 11 + .../golang-sdk/tutorial/traffic/sentinel.md | 35 + .../golang-sdk/tutorial/transaction/_index.md | 7 + .../golang-sdk/tutorial/transaction/seata.md | 18 + .../overview/mannual/golang-sdk/versions.md | 41 + .../en/overview/mannual/java-sdk/_index.md | 34 + .../mannual/java-sdk/quick-start/_index.md | 14 + .../mannual/java-sdk/quick-start/deploy.md | 139 +++ .../mannual/java-sdk/quick-start/starter.md | 178 ++++ .../java-sdk/reference-manual/_index.md | 11 + .../reference-manual/architecture/_index.md | 11 + .../architecture/code-architecture.md | 113 ++ .../architecture/dubbo-spi.md | 913 +++++++++++++++++ .../reference-manual/architecture/mesh.md.bak | 80 ++ .../architecture/multi-instance/_index.md | 7 + .../architecture/multi-instance/develop.md | Bin 0 -> 7392 bytes .../architecture/multi-instance/model.md | 178 ++++ .../multi-instance/multi-instance.md | 113 ++ .../architecture/multi-instance/workflow.md | 25 + .../architecture/multi-protocol.md | 132 +++ .../architecture/overall-architecture.md.bak | 75 ++ .../architecture/service-discovery.md.bak | 68 ++ .../architecture/service-invocation.md | 159 +++ .../reference-manual/config-center/_index.md | 31 + .../reference-manual/config-center/apollo.md | 119 +++ .../config-center/introduction.md | 29 + .../reference-manual/config-center/nacos.md | 116 +++ .../reference-manual/config-center/others.md | 54 + .../config-center/zookeeper.md | 99 ++ .../reference-manual/config/_index.md | 11 + .../reference-manual/config/api/_index.md | 10 + .../reference-manual/config/api/api.md | 389 +++++++ .../reference-manual/config/maven-plugin.md | 179 ++++ .../reference-manual/config/principle.md | 578 +++++++++++ .../reference-manual/config/properties.md | 804 +++++++++++++++ .../config/properties3.md.bak | 578 +++++++++++ .../reference-manual/config/spring/_index.md | 10 + .../config/spring/spring-boot.md | 93 ++ .../reference-manual/config/spring/xml.md | 199 ++++ .../java-sdk/reference-manual/faq/0/1.md | 29 + .../java-sdk/reference-manual/faq/0/10.md | 25 + .../java-sdk/reference-manual/faq/0/11.md | 25 + .../java-sdk/reference-manual/faq/0/12.md | 25 + .../java-sdk/reference-manual/faq/0/13.md | 25 + .../java-sdk/reference-manual/faq/0/14.md | 27 + .../java-sdk/reference-manual/faq/0/15.md | 29 + .../java-sdk/reference-manual/faq/0/16.md | 27 + .../java-sdk/reference-manual/faq/0/17.md | 25 + .../java-sdk/reference-manual/faq/0/18.md | 25 + .../java-sdk/reference-manual/faq/0/19.md | 25 + .../java-sdk/reference-manual/faq/0/2.md | 18 + .../java-sdk/reference-manual/faq/0/20.md | 27 + .../java-sdk/reference-manual/faq/0/21.md | 24 + .../java-sdk/reference-manual/faq/0/22.md | 31 + .../java-sdk/reference-manual/faq/0/23.md | 29 + .../java-sdk/reference-manual/faq/0/24.md | 27 + .../java-sdk/reference-manual/faq/0/25.md | 26 + .../java-sdk/reference-manual/faq/0/26.md | 24 + .../java-sdk/reference-manual/faq/0/27.md | 24 + .../java-sdk/reference-manual/faq/0/28.md | 25 + .../java-sdk/reference-manual/faq/0/29.md | 39 + .../java-sdk/reference-manual/faq/0/3.md | 41 + .../java-sdk/reference-manual/faq/0/4.md | 58 ++ .../java-sdk/reference-manual/faq/0/5.md | 33 + .../java-sdk/reference-manual/faq/0/6.md | 26 + .../java-sdk/reference-manual/faq/0/7.md | 27 + .../java-sdk/reference-manual/faq/0/8.md | 25 + .../java-sdk/reference-manual/faq/0/9.md | 25 + .../java-sdk/reference-manual/faq/0/99.md | 24 + .../java-sdk/reference-manual/faq/0/_index.md | 18 + .../java-sdk/reference-manual/faq/1/1.md | 25 + .../java-sdk/reference-manual/faq/1/10.md | 26 + .../java-sdk/reference-manual/faq/1/11.md | 24 + .../java-sdk/reference-manual/faq/1/12.md | 25 + .../java-sdk/reference-manual/faq/1/13.md | 24 + .../java-sdk/reference-manual/faq/1/14.md | 25 + .../java-sdk/reference-manual/faq/1/15.md | 25 + .../java-sdk/reference-manual/faq/1/16.md | 27 + .../java-sdk/reference-manual/faq/1/17.md | 26 + .../java-sdk/reference-manual/faq/1/18.md | 26 + .../java-sdk/reference-manual/faq/1/19.md | 26 + .../java-sdk/reference-manual/faq/1/20.md | 24 + .../java-sdk/reference-manual/faq/1/21.md | 25 + .../java-sdk/reference-manual/faq/1/22.md | 24 + .../java-sdk/reference-manual/faq/1/26.md | 24 + .../java-sdk/reference-manual/faq/1/27.md | 24 + .../java-sdk/reference-manual/faq/1/28.md | 24 + .../java-sdk/reference-manual/faq/1/29.md | 25 + .../java-sdk/reference-manual/faq/1/3.md | 23 + .../java-sdk/reference-manual/faq/1/30.md | 28 + .../java-sdk/reference-manual/faq/1/31.md | 26 + .../java-sdk/reference-manual/faq/1/32.md | 28 + .../java-sdk/reference-manual/faq/1/33.md | 26 + .../java-sdk/reference-manual/faq/1/34.md | 24 + .../java-sdk/reference-manual/faq/1/35.md | 26 + .../java-sdk/reference-manual/faq/1/36.md | 22 + .../java-sdk/reference-manual/faq/1/37.md | 24 + .../java-sdk/reference-manual/faq/1/38.md | 25 + .../java-sdk/reference-manual/faq/1/39.md | 26 + .../java-sdk/reference-manual/faq/1/4.md | 28 + .../java-sdk/reference-manual/faq/1/40.md | 26 + .../java-sdk/reference-manual/faq/1/41.md | 24 + .../java-sdk/reference-manual/faq/1/42.md | 19 + .../java-sdk/reference-manual/faq/1/5.md | 24 + .../java-sdk/reference-manual/faq/1/6.md | 25 + .../java-sdk/reference-manual/faq/1/7.md | 25 + .../java-sdk/reference-manual/faq/1/8.md | 28 + .../java-sdk/reference-manual/faq/1/9.md | 35 + .../java-sdk/reference-manual/faq/1/_index.md | 18 + .../java-sdk/reference-manual/faq/2/1.md | 18 + .../java-sdk/reference-manual/faq/2/10.md | 27 + .../java-sdk/reference-manual/faq/2/11.md | 24 + .../java-sdk/reference-manual/faq/2/12.md | 23 + .../java-sdk/reference-manual/faq/2/13.md | 23 + .../java-sdk/reference-manual/faq/2/14.md | 24 + .../java-sdk/reference-manual/faq/2/15.md | 23 + .../java-sdk/reference-manual/faq/2/16.md | 22 + .../java-sdk/reference-manual/faq/2/17.md | 24 + .../java-sdk/reference-manual/faq/2/18.md | 23 + .../java-sdk/reference-manual/faq/2/19.md | 25 + .../java-sdk/reference-manual/faq/2/2.md | 32 + .../java-sdk/reference-manual/faq/2/20.md | 24 + .../java-sdk/reference-manual/faq/2/3.md | 23 + .../java-sdk/reference-manual/faq/2/4.md | 23 + .../java-sdk/reference-manual/faq/2/5.md | 25 + .../java-sdk/reference-manual/faq/2/6.md | 24 + .../java-sdk/reference-manual/faq/2/7.md | 23 + .../java-sdk/reference-manual/faq/2/8.md | 24 + .../java-sdk/reference-manual/faq/2/9.md | 23 + .../java-sdk/reference-manual/faq/2/_index.md | 11 + .../java-sdk/reference-manual/faq/3/1.md | 28 + .../java-sdk/reference-manual/faq/3/2.md | 27 + .../java-sdk/reference-manual/faq/3/3.md | 22 + .../java-sdk/reference-manual/faq/3/4.md | 26 + .../java-sdk/reference-manual/faq/3/5.md | 26 + .../java-sdk/reference-manual/faq/3/6.md | 26 + .../java-sdk/reference-manual/faq/3/7.md | 29 + .../java-sdk/reference-manual/faq/3/8.md | 30 + .../java-sdk/reference-manual/faq/3/_index.md | 11 + .../java-sdk/reference-manual/faq/4/1.md | 28 + .../java-sdk/reference-manual/faq/4/10.md | 37 + .../java-sdk/reference-manual/faq/4/11.md | 28 + .../java-sdk/reference-manual/faq/4/12.md | 26 + .../java-sdk/reference-manual/faq/4/13.md | 28 + .../java-sdk/reference-manual/faq/4/14.md | 26 + .../java-sdk/reference-manual/faq/4/15.md | 22 + .../java-sdk/reference-manual/faq/4/16.md | 24 + .../java-sdk/reference-manual/faq/4/17.md | 26 + .../java-sdk/reference-manual/faq/4/18.md | 22 + .../java-sdk/reference-manual/faq/4/19.md | 26 + .../java-sdk/reference-manual/faq/4/2.md | 24 + .../java-sdk/reference-manual/faq/4/20.md | 24 + .../java-sdk/reference-manual/faq/4/21.md | 28 + .../java-sdk/reference-manual/faq/4/3.md | 24 + .../java-sdk/reference-manual/faq/4/4.md | 26 + .../java-sdk/reference-manual/faq/4/5.md | 24 + .../java-sdk/reference-manual/faq/4/6.md | 26 + .../java-sdk/reference-manual/faq/4/7.md | 24 + .../java-sdk/reference-manual/faq/4/8.md | 24 + .../java-sdk/reference-manual/faq/4/9.md | 33 + .../java-sdk/reference-manual/faq/4/_index.md | 11 + .../java-sdk/reference-manual/faq/5/1.md | 29 + .../java-sdk/reference-manual/faq/5/10.md | 24 + .../java-sdk/reference-manual/faq/5/11.md | 28 + .../java-sdk/reference-manual/faq/5/12.md | 28 + .../java-sdk/reference-manual/faq/5/13.md | 24 + .../java-sdk/reference-manual/faq/5/14.md | 26 + .../java-sdk/reference-manual/faq/5/15.md | 24 + .../java-sdk/reference-manual/faq/5/16.md | 27 + .../java-sdk/reference-manual/faq/5/17.md | 26 + .../java-sdk/reference-manual/faq/5/18.md | 26 + .../java-sdk/reference-manual/faq/5/2.md | 24 + .../java-sdk/reference-manual/faq/5/20.md | 26 + .../java-sdk/reference-manual/faq/5/21.md | 25 + .../java-sdk/reference-manual/faq/5/22.md | 29 + .../java-sdk/reference-manual/faq/5/23.md | 27 + .../java-sdk/reference-manual/faq/5/24.md | 25 + .../java-sdk/reference-manual/faq/5/25.md | 24 + .../java-sdk/reference-manual/faq/5/26.md | 22 + .../java-sdk/reference-manual/faq/5/27.md | 24 + .../java-sdk/reference-manual/faq/5/28.md | 24 + .../java-sdk/reference-manual/faq/5/29.md | 24 + .../java-sdk/reference-manual/faq/5/3.md | 24 + .../java-sdk/reference-manual/faq/5/30.md | 24 + .../java-sdk/reference-manual/faq/5/31.md | 24 + .../java-sdk/reference-manual/faq/5/32.md | 24 + .../java-sdk/reference-manual/faq/5/33.md | 24 + .../java-sdk/reference-manual/faq/5/34.md | 24 + .../java-sdk/reference-manual/faq/5/35.md | 27 + .../java-sdk/reference-manual/faq/5/36.md | 24 + .../java-sdk/reference-manual/faq/5/37.md | 25 + .../java-sdk/reference-manual/faq/5/38.md | 24 + .../java-sdk/reference-manual/faq/5/39.md | 25 + .../java-sdk/reference-manual/faq/5/4.md | 26 + .../java-sdk/reference-manual/faq/5/40.md | 25 + .../java-sdk/reference-manual/faq/5/41.md | 24 + .../java-sdk/reference-manual/faq/5/42.md | 26 + .../java-sdk/reference-manual/faq/5/43.md | 24 + .../java-sdk/reference-manual/faq/5/5.md | 24 + .../java-sdk/reference-manual/faq/5/6.md | 24 + .../java-sdk/reference-manual/faq/5/7.md | 28 + .../java-sdk/reference-manual/faq/5/8.md | 24 + .../java-sdk/reference-manual/faq/5/9.md | 28 + .../java-sdk/reference-manual/faq/5/_index.md | 11 + .../java-sdk/reference-manual/faq/6/1.md | 26 + .../java-sdk/reference-manual/faq/6/10.md | 24 + .../java-sdk/reference-manual/faq/6/11.md | 24 + .../java-sdk/reference-manual/faq/6/12.md | 26 + .../java-sdk/reference-manual/faq/6/13.md | 25 + .../java-sdk/reference-manual/faq/6/14.md | 24 + .../java-sdk/reference-manual/faq/6/15.md | 24 + .../java-sdk/reference-manual/faq/6/16.md | 24 + .../java-sdk/reference-manual/faq/6/2.md | 34 + .../java-sdk/reference-manual/faq/6/3.md | 24 + .../java-sdk/reference-manual/faq/6/4.md | 22 + .../java-sdk/reference-manual/faq/6/5.md | 25 + .../java-sdk/reference-manual/faq/6/6.md | 27 + .../java-sdk/reference-manual/faq/6/7.md | 24 + .../java-sdk/reference-manual/faq/6/8.md | 25 + .../java-sdk/reference-manual/faq/6/9.md | 28 + .../java-sdk/reference-manual/faq/6/_index.md | 11 + .../java-sdk/reference-manual/faq/7/1.md | 25 + .../java-sdk/reference-manual/faq/7/2.md | 25 + .../java-sdk/reference-manual/faq/7/3.md | 26 + .../java-sdk/reference-manual/faq/7/4.md | 25 + .../java-sdk/reference-manual/faq/7/5.md | 26 + .../java-sdk/reference-manual/faq/7/6.md | 25 + .../java-sdk/reference-manual/faq/7/7.md | 25 + .../java-sdk/reference-manual/faq/7/_index.md | 11 + .../java-sdk/reference-manual/faq/81/1.md | 28 + .../java-sdk/reference-manual/faq/81/2.md | 25 + .../java-sdk/reference-manual/faq/81/3.md | 26 + .../java-sdk/reference-manual/faq/81/4.md | 30 + .../reference-manual/faq/81/_index.md | 18 + .../java-sdk/reference-manual/faq/99/0.md | 30 + .../java-sdk/reference-manual/faq/99/1.md | 27 + .../reference-manual/faq/99/_index.md | 11 + .../java-sdk/reference-manual/faq/_index.md | 18 + .../java-sdk/reference-manual/faq/intro.md | 53 + .../reference-manual/graalvm/_index.md | 223 ++++ .../graalvm/support-graalvm.md | 223 ++++ .../reference-manual/merics/_index.md | 11 + .../java-sdk/reference-manual/merics/meter.md | 331 ++++++ .../java-sdk/reference-manual/mesh/_index.md | 11 + .../java-sdk/reference-manual/mesh/mesh.md | 165 +++ .../metadata-center/_index.md | 11 + .../reference-manual/metadata-center/nacos.md | 118 +++ .../metadata-center/others.md | 84 ++ .../metadata-center/overview.md | 217 ++++ .../metadata-center/zookeeper.md | 178 ++++ .../reference-manual/performance/_index.md | 10 + .../performance/benchmarking.md | 50 + .../performance/page-benchmarking.md | 26 + .../performance/rpc-benchmarking.md | 63 ++ .../reference-manual/protocol/_index.md | 11 + .../reference-manual/protocol/dubbo.md | 129 +++ .../protocol/multi-protocols.md | 136 +++ .../protocol/others/_index.md | 11 + .../protocol/others/hessian.md | 87 ++ .../protocol/others/http.md.bak | 81 ++ .../protocol/others/memcached.md | 57 ++ .../reference-manual/protocol/others/redis.md | 58 ++ .../reference-manual/protocol/others/rmi.md | 108 ++ .../protocol/others/thrift.md | 49 + .../others/v3.2_rest_protocol_design.md | 645 ++++++++++++ .../protocol/others/webservice.md | 119 +++ .../reference-manual/protocol/overview.md | 48 + .../reference-manual/protocol/rest.md.bak | 815 +++++++++++++++ .../protocol/tripe-rest-manual.md | 969 ++++++++++++++++++ .../reference-manual/protocol/triple-3.3.md | 276 +++++ .../reference-manual/protocol/triple.md | 318 ++++++ .../reference-manual/protocol/triple.md.bak | 170 +++ .../java-sdk/reference-manual/qos/_index.md | 10 + .../qos/introduction/_index.md | 7 + .../qos/introduction/command.md | 57 ++ .../qos/introduction/default_metrics.md | 63 ++ .../qos/introduction/logger-management.md | 103 ++ .../qos/introduction/probe.md | 43 + .../qos/introduction/profiler.md | 83 ++ .../qos/introduction/router-snapshot.md | 119 +++ .../qos/introduction/security.md | 84 ++ .../qos/introduction/service-management.md | 84 ++ .../java-sdk/reference-manual/qos/overview.md | 211 ++++ .../java-sdk/reference-manual/qos/qos-list.md | 53 + .../reference-manual/registry/_index.md | 10 + .../registry/multiple-registry.md | 193 ++++ .../reference-manual/registry/nacos.md | 210 ++++ .../registry/others/_index.md | 10 + .../registry/others/consul.md | 53 + .../reference-manual/registry/others/etcd.md | 50 + .../registry/others/multicast.md | 61 ++ .../reference-manual/registry/others/redis.md | 94 ++ .../reference-manual/registry/overview.md | 89 ++ ...vice-discovery-application-vs-interface.md | 390 +++++++ .../reference-manual/registry/zookeeper.md | 213 ++++ .../reference-manual/routing-rule/_index.md | 7 + .../reference-manual/serialization/_index.md | 10 + .../serialization/dubbo/_index.md | 9 + .../serialization/dubbo/avro.md | 66 ++ .../serialization/dubbo/fastjson.md | 68 ++ .../serialization/dubbo/fastjson2.md | 73 ++ .../serialization/dubbo/fst.md | 154 +++ .../serialization/dubbo/gson.md | 67 ++ .../serialization/dubbo/hessian.md | 57 ++ .../serialization/dubbo/kryo.md | 158 +++ .../serialization/dubbo/msgpack.md | 72 ++ .../serialization/serialization-upgrade.md | 39 + .../serialization/serialization.md | 298 ++++++ .../serialization/triple/_index.md | 9 + .../serialization/triple/protobuf.md | 85 ++ .../serialization/triple/wrapper.md | 73 ++ .../java-sdk/reference-manual/spi/_index.md | 10 + .../spi/description/_index.md | 10 + .../reference-manual/spi/description/cache.md | 97 ++ .../spi/description/cluster.md | 92 ++ .../spi/description/compiler.md | 69 ++ .../spi/description/config-center.md | 111 ++ .../spi/description/container.md | 76 ++ .../spi/description/dispatcher.md | 76 ++ .../spi/description/exchanger.md | 105 ++ .../spi/description/exporter-listener.md | 79 ++ .../spi/description/extension-factory.md | 71 ++ .../spi/description/filter.md | 103 ++ .../spi/description/invoker-listener.md | 78 ++ .../spi/description/liveness.md | 81 ++ .../spi/description/load-balance.md | 79 ++ .../spi/description/logger-adapter.md | 98 ++ .../spi/description/merger.md | 81 ++ .../spi/description/metadata-report.md | 100 ++ .../spi/description/monitor.md | 89 ++ .../spi/description/networker.md | 73 ++ .../reference-manual/spi/description/page.md | 77 ++ .../spi/description/protocol.md | 167 +++ .../spi/description/proxy-factory.md | 79 ++ .../spi/description/qos-permission.md | 71 ++ .../spi/description/readiness.md | 83 ++ .../spi/description/registry.md | 219 ++++ .../spi/description/remoting.md | 136 +++ .../spi/description/router.md | 76 ++ .../spi/description/serialize.md | 86 ++ .../spi/description/startup.md | 82 ++ .../spi/description/status-checker.md | 78 ++ .../spi/description/telnet-handler.md | 91 ++ .../spi/description/threadpool.md | 74 ++ .../spi/description/validation.md | 89 ++ .../java-sdk/reference-manual/spi/overview.md | 25 + .../java-sdk/reference-manual/spi/spi-list.md | Bin 0 -> 27710 bytes .../upgrades-and-compatibility/_index.md | 11 + .../migration-service-discovery.md | 77 ++ .../migration-triple.md | 108 ++ .../migration-triple.md.bak | 346 +++++++ .../upgrades-and-compatibility/migration.md | 305 ++++++ .../migration.md.bak | 97 ++ .../version/2.x-to-3.x-compatibility-guide.md | 101 ++ .../version/3.0-to-3.1-compatibility-guide.md | 30 + .../version/3.1-to-3.2-compatibility-guide.md | 143 +++ .../version/3.2-to-3.3-compatibility-guide.md | 350 +++++++ .../version/_index.md | 11 + .../overview/mannual/java-sdk/tasks/_index.md | 10 + .../mannual/java-sdk/tasks/deploy/_index.md | 14 + .../deploy/deploy-on-kubernetes-service.md | 116 +++ .../tasks/deploy/deploy-on-kubernetes.md | 89 ++ .../java-sdk/tasks/deploy/deploy-on-vm.md | 120 +++ .../mannual/java-sdk/tasks/develop/_index.md | 10 + .../mannual/java-sdk/tasks/develop/api.md | 299 ++++++ .../java-sdk/tasks/develop/springboot.md | 207 ++++ .../java-sdk/tasks/extensibility/_index.md | 65 ++ .../java-sdk/tasks/extensibility/filter.md | 94 ++ .../java-sdk/tasks/extensibility/protocol.md | 188 ++++ .../java-sdk/tasks/extensibility/registry.md | 134 +++ .../java-sdk}/tasks/extensibility/router.md | 70 +- .../java-sdk/tasks/extensibility/spi.md | 66 ++ .../java-sdk/tasks/framework/_index.md | 9 + .../mannual/java-sdk/tasks/framework/async.md | 230 +++++ .../java-sdk/tasks/framework/attachment.md | 133 +++ .../framework/fault-tolerent-strategy.md | 107 ++ .../java-sdk/tasks/framework/filter.md | 136 +++ .../java-sdk/tasks/framework/generic.md | 149 +++ .../tasks/framework/lightweight-rpc.md | 109 ++ .../java-sdk/tasks/framework/more/_index.md | 9 + .../framework/more/callback-parameter.md | 127 +++ .../framework/more/concurrency-control.md | 92 ++ .../framework/more/config-connections.md | 104 ++ .../tasks/framework/more/echo-service.md | 41 + .../tasks/framework/more/events-notify.md | 113 ++ .../tasks/framework/more/explicit-target.md | 70 ++ .../tasks/framework/more/generic-impl.md | 78 ++ .../tasks/framework/more/local-call.md | 82 ++ .../tasks/framework/more/local-mock.md | 193 ++++ .../tasks/framework/more/local-stub.md | 63 ++ .../framework/more/parameter-validation.md | 200 ++++ .../java-sdk/tasks/framework/more/reactive.md | 241 +++++ .../framework/more/reference-config-cache.md | 54 + .../tasks/framework/more/result-cache.md | 122 +++ .../tasks/framework/more/router-snapshot.md | 89 ++ .../java-sdk/tasks/framework/more/set-host.md | 81 ++ .../tasks/framework/more/specify-ip.md | 105 ++ .../tasks/framework/threading-model.md | 425 ++++++++ .../java-sdk/tasks/framework/timeout.md | 79 ++ .../java-sdk/tasks/framework/version_group.md | 312 ++++++ .../mannual/java-sdk/tasks/gateway/_index.md | 8 + .../java-sdk/tasks/gateway/architecture.md | 41 + .../mannual/java-sdk/tasks/gateway/dubbo.md | 81 ++ .../mannual/java-sdk/tasks/gateway/triple.md | 256 +++++ .../mannual/java-sdk/tasks/mesh/_index.md | 44 + .../tasks/mesh/bookinfo-proxyless/_index.md | 48 + .../bookinfo-proxyless/security/_index.md | 92 ++ .../security/request-routing.md | 152 +++ .../mesh/bookinfo-proxyless/traffic/_index.md | 92 ++ .../traffic/request-routing.md | 152 +++ .../tasks/mesh/bookinfo-sidecar/_index.md | 48 + .../mesh/bookinfo-sidecar/security/_index.md | 92 ++ .../security/request-routing.md | 152 +++ .../mesh/bookinfo-sidecar/traffic/_index.md | 92 ++ .../traffic/request-routing.md | 152 +++ .../java-sdk/tasks/mesh/migration/_index.md | 43 + .../tasks/mesh/migration}/deploy-on-k8s.md | 120 +-- .../tasks/mesh/migration/dubbo-mesh.md | 302 ++++++ .../tasks/mesh/migration/proxyless.md | 275 +++++ .../java-sdk/tasks/observability/_index.md | 10 + .../java-sdk/tasks/observability/console.md | 112 ++ .../java-sdk/tasks/observability/grafana.md | 93 ++ .../java-sdk/tasks/observability/logging.md | 361 +++++++ .../tasks/observability/prometheus.md | 52 + .../tasks/observability/tracing/_index.md | 55 + .../tasks/observability/tracing/otlp.md | 135 +++ .../tasks/observability/tracing/skywalking.md | 83 ++ .../tasks/observability/tracing/tracing.md | 147 +++ .../tasks/observability/tracing/zipkin.md | 159 +++ .../java-sdk/tasks/protocols/_index.md | 12 + .../mannual/java-sdk/tasks/protocols/dubbo.md | 119 +++ .../java-sdk/tasks/protocols/protocol.md | 250 +++++ .../mannual/java-sdk/tasks/protocols/rest.md | 188 ++++ .../java-sdk/tasks/protocols/triple/_index.md | 12 + .../java-sdk/tasks/protocols/triple/grpc.md | 67 ++ .../java-sdk/tasks/protocols/triple/idl.md | 290 ++++++ .../tasks/protocols/triple/interface.md | 148 +++ .../tasks/protocols/triple/streaming.md | 325 ++++++ .../java-sdk/tasks/rate-limit/_index.md | 11 + .../adaptive-concurrency-control.md | 48 + .../tasks/rate-limit/concurrency-control.md | 101 ++ .../java-sdk/tasks/rate-limit/sentinel.md | 228 +++++ .../mannual/java-sdk/tasks/security/_index.md | 10 + .../mannual/java-sdk/tasks/security/auth.md | 51 + .../java-sdk/tasks/security/class-check.md | 223 ++++ .../mannual/java-sdk/tasks/security/tls.md | 64 ++ .../tasks/security/token-authorization.md | 59 ++ .../tasks/service-discovery/_index.md | 10 + .../tasks/service-discovery/kubernetes.md | 25 + .../tasks/service-discovery/loadbalance.md | 120 +++ .../java-sdk/tasks/service-discovery/nacos.md | 219 ++++ .../tasks/service-discovery/registry.md | 273 +++++ .../tasks/service-discovery/zookeeper.md | 218 ++++ .../tasks/traffic-management/_index.md | 118 +++ .../tasks/traffic-management/accesslog.md | 87 ++ .../tasks/traffic-management/architecture.md | 201 ++++ .../tasks/traffic-management/arguments.md | 88 ++ .../java-sdk/tasks/traffic-management/host.md | 69 ++ .../tasks/traffic-management/isolation.md | 138 +++ .../java-sdk/tasks/traffic-management/mock.md | 72 ++ .../tasks/traffic-management/region.md | 85 ++ .../tasks/traffic-management/retry.md | 75 ++ .../tasks/traffic-management/route.md | 56 + .../tasks/traffic-management/timeout.md | 72 ++ .../tasks/traffic-management/weight.md | 94 ++ .../java-sdk/tasks/trasaction/_index.md | 9 + .../trasaction/distributed-transaction.md | 159 +++ .../java-sdk/tasks/troubleshoot/_index.md | 10 + .../tasks/troubleshoot/no-provider.md | 601 +++++++++++ .../java-sdk/tasks/troubleshoot/profiler.md | 190 ++++ .../tasks/troubleshoot/request-failed.md | 166 +++ .../tasks/troubleshoot/start-failed.md | 253 +++++ .../en/overview/mannual/java-sdk/versions.md | 23 + .../en/overview/mannual/nodejs-sdk/_index.md | 7 + .../mannual/nodejs-sdk/quick-start.md | 186 ++++ .../en/overview/mannual/rust-sdk/_index.md | 10 + .../mannual/rust-sdk/java-interoperability.md | 78 ++ .../overview/mannual/rust-sdk/quick-start.md | 256 +++++ .../mannual/rust-sdk/router-module.md | 153 +++ .../mannual/rust-sdk/service-discovery.md | 100 ++ .../en/overview/mannual/rust-sdk/streaming.md | 389 +++++++ .../mannual/rust-sdk/unix-transport.md | 84 ++ content/en/overview/mannual/web-sdk/_index.md | 7 + .../overview/mannual/web-sdk/quick-start.md | 267 +++++ content/en/overview/notices/_index.md | 23 +- content/en/overview/notices/admin.md | 42 +- content/en/overview/notices/log4j.md | 50 +- content/en/overview/notices/protocol.md | 38 +- content/en/overview/notices/registry.md | 22 +- content/en/overview/notices/serialization.md | 46 +- content/en/overview/quickstart/_index.md | 38 - content/en/overview/quickstart/go.md | 6 - content/en/overview/quickstart/rust.md | 6 - .../en/overview/reference/Metrics/_index.md | 7 + .../reference/Metrics/standard_metrics.md | 194 ++++ content/en/overview/reference/_index.md | 51 + .../overview/reference/erlang-sdk/_index.md | 12 + .../reference/erlang-sdk/quick-start.md | 71 ++ .../reference/erlang-sdk/reference.md | 34 + .../reference/erlang-sdk/serialization.md | 36 + .../overview/reference/erlang-sdk/service.md | 40 + .../overview/reference/integrations/_index.md | 9 + .../reference/integrations/grafana.md | 72 ++ .../reference/integrations/higress.md | 48 + .../overview/reference/integrations/nacos.md | 50 + .../reference/integrations/prometheus.md | 52 + .../reference/integrations/skywalking.md | 18 + .../overview/reference/integrations/zipkin.md | 18 + .../reference/integrations/zookeeper.md | 92 ++ content/en/overview/reference/pixiu/_index.md | 12 + .../en/overview/reference/pixiu/dev/_index.md | 10 + .../reference/pixiu/dev/dubbo-pilot.md | 203 ++++ .../reference/pixiu/dev/filter-extension.md | 143 +++ .../en/overview/reference/pixiu/dev/trie.md | 147 +++ .../reference/pixiu/overview/_index.md | 12 + .../overview/reference/pixiu/overview/faq.md | 30 + .../reference/pixiu/overview/terminology.md | 44 + .../reference/pixiu/overview/what-is-pixiu.md | 48 + .../overview/reference/pixiu/user/_index.md | 12 + .../reference/pixiu/user/adapter/_index.md | 12 + .../reference/pixiu/user/adapter/dubbo.md | 12 + .../pixiu/user/adapter/springcloud.md | 12 + .../reference/pixiu/user/appendix/_index.md | 12 + .../http-to-dubbo-default-stragety.md | 327 ++++++ .../reference/pixiu/user/configurations.md | 160 +++ .../reference/pixiu/user/deployment.md | 90 ++ .../reference/pixiu/user/httpfilter/_index.md | 12 + .../reference/pixiu/user/httpfilter/dubbo.md | 113 ++ .../pixiu/user/httpfilter/hystrix.md | 19 + .../pixiu/user/httpfilter/ratelimit.md | 19 + .../reference/pixiu/user/listener/_index.md | 12 + .../reference/pixiu/user/listener/http.md | 53 + .../reference/pixiu/user/listener/http2.md | 19 + .../reference/pixiu/user/listener/tcp.md | 19 + .../reference/pixiu/user/listener/triple.md | 19 + .../pixiu/user/networkfilter/_index.md | 12 + .../pixiu/user/networkfilter/dubbo.md | 19 + .../pixiu/user/networkfilter/grpc.md | 105 ++ .../pixiu/user/networkfilter/http.md | 19 + .../reference/pixiu/user/quality/_index.md | 12 + .../pixiu/user/quality/performance.md | 19 + .../reference/pixiu/user/quality/stability.md | 19 + .../reference/pixiu/user/quickstart.md | 171 ++++ .../reference/pixiu/user/samples/_index.md | 12 + .../pixiu/user/samples/http_proxy.md | 75 ++ .../pixiu/user/samples/http_to_dubbo.md | 19 + .../reference/pixiu/user/samples/https.md | 19 + .../en/overview/reference/proposals/_index.md | 9 + .../en/overview/reference/proposals/admin.md | 110 ++ .../proposals/heuristic-flow-control.md | 234 +++++ .../overview/reference/proposals/metrics.md | 529 ++++++++++ .../reference/proposals/protocol-http.md | 658 ++++++++++++ .../proposals/registry-config-meta.md | 93 ++ .../reference/proposals/service-discovery.md | 90 ++ .../proposals/support-more-content-types.md | 172 ++++ .../overview/reference/protoc-installation.md | 73 ++ .../en/overview/reference/protocols/_index.md | 7 + .../en/overview/reference/protocols/http.md | 625 +++++++++++ .../en/overview/reference/protocols/tcp.md | 100 ++ .../reference/protocols/triple-spec.md | 329 ++++++ .../en/overview/reference/protocols/triple.md | 86 ++ content/en/overview/reference/setup/_index.md | 11 + .../en/overview/reference/setup/install.md | 209 ++++ content/en/overview/tasks/_index.md | 11 - content/en/overview/tasks/ecosystem/_index.md | 58 -- .../en/overview/tasks/ecosystem/rate-limit.md | 95 -- .../overview/tasks/ecosystem/transaction.md | 307 ------ .../en/overview/tasks/extensibility/_index.md | 100 -- .../en/overview/tasks/extensibility/filter.md | 11 - .../overview/tasks/extensibility/protocol.md | 278 ----- .../overview/tasks/extensibility/registry.md | 10 - .../en/overview/tasks/kubernetes/_index.md | 38 - content/en/overview/tasks/mesh/_index.md | 61 -- content/en/overview/tasks/mesh/dubbo-mesh.md | 301 ------ content/en/overview/tasks/mesh/proxyless.md | 270 ----- content/en/overview/tasks/migration/2to3.md | 44 - content/en/overview/tasks/migration/_index.md | 48 - .../tasks/migration/migration-triple.md | 38 - .../migration/service-discovery-samples.md | 78 -- .../tasks/traffic-management/_index.md | 88 -- .../tasks/traffic-management/isolation.md | 78 -- .../tasks/traffic-management/timeout.md | 79 -- .../traffic-management/traffic-condition.md | 63 -- .../tasks/traffic-management/traffic-gray.md | 104 -- .../traffic-management/traffic-routing.md | 66 -- .../tasks/traffic-management/weight.md | 49 - .../overview/tasks/traffic-management/zone.md | 63 -- content/en/overview/tasks/triple/_index.md | 48 - content/en/overview/tasks/triple/idl.md | 237 ----- content/en/overview/tasks/triple/streaming.md | 296 ------ content/en/overview/tasks/triple/wrap.md | 171 ---- content/en/overview/what/_index.md | 78 +- content/en/overview/what/advantages/_index.md | 9 + .../en/overview/what/advantages/governance.md | 61 ++ .../overview/what/advantages/performance.md | 67 ++ .../what/advantages/production-ready.md | 34 + .../en/overview/what/advantages/usability.md | 44 + content/en/overview/what/architecture.md | 124 --- .../en/overview/what/core-features/_index.md | 10 + .../overview/what/core-features/ecosystem.md | 46 + .../what/core-features/extensibility.md | 123 +++ .../what/core-features/load-balance.md | 105 ++ .../en/overview/what/core-features/more.md | 72 ++ .../what/core-features/observability.md | 60 ++ .../overview/what/core-features/protocols.md | 89 ++ .../overview/what/core-features/security.md | 109 ++ .../what/core-features/service-definition.md | 129 +++ .../core-features/service-definition.md.bak | 497 +++++++++ .../what/core-features/service-discovery.md | 73 ++ .../what/core-features/service-mesh.md | 90 ++ .../what/core-features/traffic/_index.md | 275 +++++ .../core-features/traffic/circuit-breaking.md | 43 + .../core-features/traffic/condition-rule.md | 79 ++ .../traffic/configuration-rule.md | 95 ++ .../core-features/traffic/introduction.md | 268 +++++ .../core-features/traffic/mesh-rule.md} | 3 +- .../what/core-features/traffic/script-rule.md | 64 ++ .../what/core-features/traffic/tag-rule.md | 62 ++ content/en/overview/what/dubbo3.md | 94 -- content/en/overview/what/ecosystem.md | 60 -- content/en/overview/what/extensibility.md | 100 -- content/en/overview/what/overview.md | 157 +-- content/en/overview/what/xyz-difference.md | 84 ++ 712 files changed, 56395 insertions(+), 4873 deletions(-) delete mode 100755 content/en/overview/core-features/_index.md delete mode 100644 content/en/overview/core-features/ecosystem.md delete mode 100644 content/en/overview/core-features/extensibility.md delete mode 100644 content/en/overview/core-features/load-balance.md delete mode 100644 content/en/overview/core-features/more.md delete mode 100644 content/en/overview/core-features/observability.md delete mode 100644 content/en/overview/core-features/protocols.md delete mode 100644 content/en/overview/core-features/security.md delete mode 100644 content/en/overview/core-features/service-definition.md delete mode 100644 content/en/overview/core-features/service-discovery.md delete mode 100644 content/en/overview/core-features/service-mesh.md delete mode 100755 content/en/overview/core-features/traffic/_index.md delete mode 100644 content/en/overview/core-features/traffic/condition-rule.md delete mode 100644 content/en/overview/core-features/traffic/configuration-rule.md delete mode 100644 content/en/overview/core-features/traffic/mesh-rule.md delete mode 100644 content/en/overview/core-features/traffic/script-rule.md delete mode 100644 content/en/overview/core-features/traffic/tag-rule.md create mode 100644 content/en/overview/home/_index.md delete mode 100755 content/en/overview/mannual/Golang.md delete mode 100644 content/en/overview/mannual/Java.md delete mode 100644 content/en/overview/mannual/Rust.md create mode 100644 content/en/overview/mannual/control-plane/_index.md create mode 100644 content/en/overview/mannual/control-plane/architecture.md create mode 100644 content/en/overview/mannual/control-plane/documentation.md create mode 100644 content/en/overview/mannual/control-plane/mock.md create mode 100644 content/en/overview/mannual/control-plane/search.md create mode 100644 content/en/overview/mannual/control-plane/test.md create mode 100755 content/en/overview/mannual/golang-sdk/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/introduction.md create mode 100755 content/en/overview/mannual/golang-sdk/quickstart/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/quickstart/microservices.md create mode 100644 content/en/overview/mannual/golang-sdk/quickstart/rpc.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/ecology.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/generic.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/nacos.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/sourcecode/3.0_feature.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/sourcecode/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/sourcecode/aop_and_extension.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/sourcecode/app_and_interface.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/sourcecode/architecture.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/sourcecode/generic-2.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/sourcecode/generic.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/sourcecode/protocol.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/sourcecode/registry.md create mode 100644 content/en/overview/mannual/golang-sdk/refer/use_dubbogo_cli.md create mode 100755 content/en/overview/mannual/golang-sdk/tutorial/_index.md create mode 100755 content/en/overview/mannual/golang-sdk/tutorial/configuration/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/configuration/file.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/configuration/remote.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/deploy2/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/deploy2/deploy.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/deploy2/graceful_shutdown.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/deploy2/istio.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/deploy2/proxyless_service_mesh.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/deploy2/traffic_management.md create mode 100755 content/en/overview/mannual/golang-sdk/tutorial/gateway/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/gateway/http_triple.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/gateway/pixiu-nacos-triple.md create mode 100755 content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_dubbo_non_protobuf.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_triple_protobuf.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/service-discovery.md create mode 100755 content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/call_grpc.md create mode 100755 content/en/overview/mannual/golang-sdk/tutorial/load-balance/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/load-balance/loadbalance.md create mode 100755 content/en/overview/mannual/golang-sdk/tutorial/observability/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/observability/logger.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/observability/rpc_metrics.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/observability/tracing.md create mode 100755 content/en/overview/mannual/golang-sdk/tutorial/rpc/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/rpc/attachments.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/rpc/error.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/rpc/filter.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/rpc/healthcheck.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/rpc/protocol.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/rpc/retry.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/rpc/start-check.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/rpc/streaming.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/rpc/timeout.md create mode 100755 content/en/overview/mannual/golang-sdk/tutorial/service-discovery/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/service-discovery/multi_registry.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/service-discovery/nacos.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/service-discovery/zookeeper.md create mode 100755 content/en/overview/mannual/golang-sdk/tutorial/traffic/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/traffic/router.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/traffic/sentinel.md create mode 100755 content/en/overview/mannual/golang-sdk/tutorial/transaction/_index.md create mode 100644 content/en/overview/mannual/golang-sdk/tutorial/transaction/seata.md create mode 100644 content/en/overview/mannual/golang-sdk/versions.md create mode 100755 content/en/overview/mannual/java-sdk/_index.md create mode 100755 content/en/overview/mannual/java-sdk/quick-start/_index.md create mode 100644 content/en/overview/mannual/java-sdk/quick-start/deploy.md create mode 100644 content/en/overview/mannual/java-sdk/quick-start/starter.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/_index.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/architecture/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/architecture/code-architecture.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/architecture/mesh.md.bak create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/develop.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/model.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/multi-instance.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/workflow.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/architecture/overall-architecture.md.bak create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/architecture/service-discovery.md.bak create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/architecture/service-invocation.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config-center/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config-center/apollo.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config-center/introduction.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config-center/nacos.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config-center/others.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config-center/zookeeper.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config/api/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config/api/api.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config/maven-plugin.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config/principle.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config/properties.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config/properties3.md.bak create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config/spring/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/config/spring/xml.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/1.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/10.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/11.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/12.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/13.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/14.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/15.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/16.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/17.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/18.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/19.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/2.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/20.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/21.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/22.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/23.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/24.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/25.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/26.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/27.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/28.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/29.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/3.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/4.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/5.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/6.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/7.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/8.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/9.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/99.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/0/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/1.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/10.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/11.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/12.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/13.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/14.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/15.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/16.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/17.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/18.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/19.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/20.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/21.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/22.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/26.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/27.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/28.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/29.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/3.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/30.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/31.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/32.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/33.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/34.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/35.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/36.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/37.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/38.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/39.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/4.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/40.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/41.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/42.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/5.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/6.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/7.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/8.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/1/9.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/faq/1/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/1.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/10.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/11.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/12.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/13.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/14.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/15.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/16.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/17.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/18.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/19.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/2.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/20.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/3.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/4.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/5.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/6.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/7.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/8.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/9.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/2/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/3/1.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/3/2.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/3/3.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/3/4.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/3/5.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/3/6.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/3/7.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/3/8.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/3/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/1.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/10.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/11.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/12.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/13.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/14.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/15.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/16.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/17.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/18.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/19.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/2.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/20.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/21.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/3.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/4.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/5.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/6.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/7.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/8.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/9.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/4/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/1.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/10.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/11.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/12.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/13.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/14.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/15.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/16.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/17.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/18.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/2.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/20.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/21.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/22.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/23.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/24.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/25.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/26.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/27.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/28.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/29.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/3.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/30.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/31.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/32.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/33.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/34.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/35.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/36.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/37.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/38.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/39.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/4.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/40.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/41.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/42.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/43.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/5.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/6.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/7.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/8.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/9.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/5/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/1.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/10.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/11.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/12.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/13.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/14.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/15.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/16.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/2.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/3.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/4.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/5.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/6.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/7.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/8.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/9.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/6/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/7/1.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/7/2.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/7/3.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/7/4.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/7/5.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/7/6.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/7/7.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/7/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/81/1.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/81/2.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/81/3.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/81/4.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/81/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/99/0.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/99/1.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/99/_index.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/faq/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/faq/intro.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/graalvm/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/graalvm/support-graalvm.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/merics/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/merics/meter.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/mesh/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/mesh/mesh.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/metadata-center/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/metadata-center/nacos.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/metadata-center/others.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/metadata-center/overview.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/metadata-center/zookeeper.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/performance/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/performance/benchmarking.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/performance/page-benchmarking.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/performance/rpc-benchmarking.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/protocol/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/dubbo.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/protocol/others/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/others/hessian.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/others/http.md.bak create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/others/memcached.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/others/redis.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/others/rmi.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/others/thrift.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/others/v3.2_rest_protocol_design.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/others/webservice.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/overview.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/rest.md.bak create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/triple-3.3.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md.bak create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/qos/_index.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/command.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/default_metrics.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/logger-management.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/probe.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/profiler.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/router-snapshot.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/security.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/service-management.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/qos/overview.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/qos/qos-list.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/registry/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/registry/multiple-registry.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/registry/nacos.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/registry/others/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/registry/others/consul.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/registry/others/etcd.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/registry/others/multicast.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/registry/others/redis.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/registry/overview.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/registry/service-discovery-application-vs-interface.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/registry/zookeeper.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/routing-rule/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/avro.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson2.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fst.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/gson.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/hessian.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/kryo.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/msgpack.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization-upgrade.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/protobuf.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/wrapper.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/spi/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/cache.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/cluster.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/compiler.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/config-center.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/container.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/dispatcher.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/exchanger.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/exporter-listener.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/extension-factory.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/filter.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/invoker-listener.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/liveness.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/load-balance.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/logger-adapter.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/merger.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/metadata-report.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/monitor.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/networker.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/page.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/protocol.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/proxy-factory.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/qos-permission.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/readiness.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/registry.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/remoting.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/router.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/serialize.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/startup.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/status-checker.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/telnet-handler.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/threadpool.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/description/validation.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/overview.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/spi/spi-list.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/_index.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md.bak create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md.bak create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/2.x-to-3.x-compatibility-guide.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.0-to-3.1-compatibility-guide.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.1-to-3.2-compatibility-guide.md create mode 100644 content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.2-to-3.3-compatibility-guide.md create mode 100755 content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/_index.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/deploy/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes-service.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-vm.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/develop/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/develop/api.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/develop/springboot.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/extensibility/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/extensibility/filter.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/extensibility/protocol.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/extensibility/registry.md rename content/en/overview/{ => mannual/java-sdk}/tasks/extensibility/router.md (54%) create mode 100644 content/en/overview/mannual/java-sdk/tasks/extensibility/spi.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/framework/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/async.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/attachment.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/fault-tolerent-strategy.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/filter.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/generic.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/lightweight-rpc.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/framework/more/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/callback-parameter.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/concurrency-control.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/config-connections.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/echo-service.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/events-notify.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/explicit-target.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/generic-impl.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/local-call.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/local-mock.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/local-stub.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/parameter-validation.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/reactive.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/reference-config-cache.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/result-cache.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/router-snapshot.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/set-host.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/more/specify-ip.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/threading-model.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/timeout.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/framework/version_group.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/gateway/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/gateway/architecture.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/gateway/dubbo.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/gateway/triple.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/mesh/_index.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/_index.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/request-routing.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/request-routing.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/_index.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/request-routing.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/request-routing.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/mesh/migration/_index.md rename content/en/overview/{tasks/kubernetes => mannual/java-sdk/tasks/mesh/migration}/deploy-on-k8s.md (51%) create mode 100644 content/en/overview/mannual/java-sdk/tasks/mesh/migration/dubbo-mesh.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/mesh/migration/proxyless.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/observability/_index.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/observability/console.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/observability/grafana.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/observability/logging.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/observability/prometheus.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/observability/tracing/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/observability/tracing/otlp.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/observability/tracing/skywalking.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/observability/tracing/tracing.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/observability/tracing/zipkin.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/protocols/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/protocols/dubbo.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/protocols/protocol.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/protocols/rest.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/protocols/triple/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/protocols/triple/grpc.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/protocols/triple/idl.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/protocols/triple/interface.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/protocols/triple/streaming.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/rate-limit/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/rate-limit/adaptive-concurrency-control.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/rate-limit/concurrency-control.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/rate-limit/sentinel.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/security/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/security/auth.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/security/class-check.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/security/tls.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/security/token-authorization.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/service-discovery/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/service-discovery/kubernetes.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/service-discovery/loadbalance.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/service-discovery/nacos.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/service-discovery/registry.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/service-discovery/zookeeper.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/traffic-management/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/traffic-management/accesslog.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/traffic-management/architecture.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/traffic-management/arguments.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/traffic-management/host.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/traffic-management/isolation.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/traffic-management/mock.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/traffic-management/region.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/traffic-management/retry.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/traffic-management/route.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/traffic-management/timeout.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/traffic-management/weight.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/trasaction/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/trasaction/distributed-transaction.md create mode 100755 content/en/overview/mannual/java-sdk/tasks/troubleshoot/_index.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/troubleshoot/no-provider.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/troubleshoot/profiler.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/troubleshoot/request-failed.md create mode 100644 content/en/overview/mannual/java-sdk/tasks/troubleshoot/start-failed.md create mode 100644 content/en/overview/mannual/java-sdk/versions.md create mode 100755 content/en/overview/mannual/nodejs-sdk/_index.md create mode 100644 content/en/overview/mannual/nodejs-sdk/quick-start.md create mode 100755 content/en/overview/mannual/rust-sdk/_index.md create mode 100644 content/en/overview/mannual/rust-sdk/java-interoperability.md create mode 100644 content/en/overview/mannual/rust-sdk/quick-start.md create mode 100644 content/en/overview/mannual/rust-sdk/router-module.md create mode 100644 content/en/overview/mannual/rust-sdk/service-discovery.md create mode 100644 content/en/overview/mannual/rust-sdk/streaming.md create mode 100644 content/en/overview/mannual/rust-sdk/unix-transport.md create mode 100755 content/en/overview/mannual/web-sdk/_index.md create mode 100644 content/en/overview/mannual/web-sdk/quick-start.md delete mode 100755 content/en/overview/quickstart/_index.md delete mode 100644 content/en/overview/quickstart/go.md delete mode 100644 content/en/overview/quickstart/rust.md create mode 100644 content/en/overview/reference/Metrics/_index.md create mode 100644 content/en/overview/reference/Metrics/standard_metrics.md create mode 100755 content/en/overview/reference/_index.md create mode 100755 content/en/overview/reference/erlang-sdk/_index.md create mode 100644 content/en/overview/reference/erlang-sdk/quick-start.md create mode 100644 content/en/overview/reference/erlang-sdk/reference.md create mode 100644 content/en/overview/reference/erlang-sdk/serialization.md create mode 100644 content/en/overview/reference/erlang-sdk/service.md create mode 100644 content/en/overview/reference/integrations/_index.md create mode 100644 content/en/overview/reference/integrations/grafana.md create mode 100644 content/en/overview/reference/integrations/higress.md create mode 100644 content/en/overview/reference/integrations/nacos.md create mode 100644 content/en/overview/reference/integrations/prometheus.md create mode 100644 content/en/overview/reference/integrations/skywalking.md create mode 100644 content/en/overview/reference/integrations/zipkin.md create mode 100644 content/en/overview/reference/integrations/zookeeper.md create mode 100755 content/en/overview/reference/pixiu/_index.md create mode 100755 content/en/overview/reference/pixiu/dev/_index.md create mode 100644 content/en/overview/reference/pixiu/dev/dubbo-pilot.md create mode 100644 content/en/overview/reference/pixiu/dev/filter-extension.md create mode 100644 content/en/overview/reference/pixiu/dev/trie.md create mode 100755 content/en/overview/reference/pixiu/overview/_index.md create mode 100755 content/en/overview/reference/pixiu/overview/faq.md create mode 100755 content/en/overview/reference/pixiu/overview/terminology.md create mode 100755 content/en/overview/reference/pixiu/overview/what-is-pixiu.md create mode 100755 content/en/overview/reference/pixiu/user/_index.md create mode 100755 content/en/overview/reference/pixiu/user/adapter/_index.md create mode 100644 content/en/overview/reference/pixiu/user/adapter/dubbo.md create mode 100644 content/en/overview/reference/pixiu/user/adapter/springcloud.md create mode 100755 content/en/overview/reference/pixiu/user/appendix/_index.md create mode 100644 content/en/overview/reference/pixiu/user/appendix/http-to-dubbo-default-stragety.md create mode 100755 content/en/overview/reference/pixiu/user/configurations.md create mode 100644 content/en/overview/reference/pixiu/user/deployment.md create mode 100755 content/en/overview/reference/pixiu/user/httpfilter/_index.md create mode 100644 content/en/overview/reference/pixiu/user/httpfilter/dubbo.md create mode 100644 content/en/overview/reference/pixiu/user/httpfilter/hystrix.md create mode 100644 content/en/overview/reference/pixiu/user/httpfilter/ratelimit.md create mode 100755 content/en/overview/reference/pixiu/user/listener/_index.md create mode 100644 content/en/overview/reference/pixiu/user/listener/http.md create mode 100644 content/en/overview/reference/pixiu/user/listener/http2.md create mode 100644 content/en/overview/reference/pixiu/user/listener/tcp.md create mode 100644 content/en/overview/reference/pixiu/user/listener/triple.md create mode 100755 content/en/overview/reference/pixiu/user/networkfilter/_index.md create mode 100644 content/en/overview/reference/pixiu/user/networkfilter/dubbo.md create mode 100644 content/en/overview/reference/pixiu/user/networkfilter/grpc.md create mode 100644 content/en/overview/reference/pixiu/user/networkfilter/http.md create mode 100755 content/en/overview/reference/pixiu/user/quality/_index.md create mode 100755 content/en/overview/reference/pixiu/user/quality/performance.md create mode 100644 content/en/overview/reference/pixiu/user/quality/stability.md create mode 100755 content/en/overview/reference/pixiu/user/quickstart.md create mode 100755 content/en/overview/reference/pixiu/user/samples/_index.md create mode 100644 content/en/overview/reference/pixiu/user/samples/http_proxy.md create mode 100644 content/en/overview/reference/pixiu/user/samples/http_to_dubbo.md create mode 100644 content/en/overview/reference/pixiu/user/samples/https.md create mode 100644 content/en/overview/reference/proposals/_index.md create mode 100644 content/en/overview/reference/proposals/admin.md create mode 100644 content/en/overview/reference/proposals/heuristic-flow-control.md create mode 100644 content/en/overview/reference/proposals/metrics.md create mode 100644 content/en/overview/reference/proposals/protocol-http.md create mode 100644 content/en/overview/reference/proposals/registry-config-meta.md create mode 100644 content/en/overview/reference/proposals/service-discovery.md create mode 100644 content/en/overview/reference/proposals/support-more-content-types.md create mode 100644 content/en/overview/reference/protoc-installation.md create mode 100644 content/en/overview/reference/protocols/_index.md create mode 100644 content/en/overview/reference/protocols/http.md create mode 100644 content/en/overview/reference/protocols/tcp.md create mode 100644 content/en/overview/reference/protocols/triple-spec.md create mode 100644 content/en/overview/reference/protocols/triple.md create mode 100755 content/en/overview/reference/setup/_index.md create mode 100644 content/en/overview/reference/setup/install.md delete mode 100755 content/en/overview/tasks/_index.md delete mode 100755 content/en/overview/tasks/ecosystem/_index.md delete mode 100644 content/en/overview/tasks/ecosystem/rate-limit.md delete mode 100644 content/en/overview/tasks/ecosystem/transaction.md delete mode 100644 content/en/overview/tasks/extensibility/_index.md delete mode 100644 content/en/overview/tasks/extensibility/filter.md delete mode 100644 content/en/overview/tasks/extensibility/protocol.md delete mode 100644 content/en/overview/tasks/extensibility/registry.md delete mode 100755 content/en/overview/tasks/kubernetes/_index.md delete mode 100755 content/en/overview/tasks/mesh/_index.md delete mode 100644 content/en/overview/tasks/mesh/dubbo-mesh.md delete mode 100644 content/en/overview/tasks/mesh/proxyless.md delete mode 100644 content/en/overview/tasks/migration/2to3.md delete mode 100755 content/en/overview/tasks/migration/_index.md delete mode 100644 content/en/overview/tasks/migration/migration-triple.md delete mode 100644 content/en/overview/tasks/migration/service-discovery-samples.md delete mode 100755 content/en/overview/tasks/traffic-management/_index.md delete mode 100644 content/en/overview/tasks/traffic-management/isolation.md delete mode 100644 content/en/overview/tasks/traffic-management/timeout.md delete mode 100644 content/en/overview/tasks/traffic-management/traffic-condition.md delete mode 100644 content/en/overview/tasks/traffic-management/traffic-gray.md delete mode 100644 content/en/overview/tasks/traffic-management/traffic-routing.md delete mode 100644 content/en/overview/tasks/traffic-management/weight.md delete mode 100644 content/en/overview/tasks/traffic-management/zone.md delete mode 100755 content/en/overview/tasks/triple/_index.md delete mode 100644 content/en/overview/tasks/triple/idl.md delete mode 100644 content/en/overview/tasks/triple/streaming.md delete mode 100644 content/en/overview/tasks/triple/wrap.md create mode 100644 content/en/overview/what/advantages/_index.md create mode 100644 content/en/overview/what/advantages/governance.md create mode 100644 content/en/overview/what/advantages/performance.md create mode 100644 content/en/overview/what/advantages/production-ready.md create mode 100644 content/en/overview/what/advantages/usability.md delete mode 100644 content/en/overview/what/architecture.md create mode 100755 content/en/overview/what/core-features/_index.md create mode 100644 content/en/overview/what/core-features/ecosystem.md create mode 100644 content/en/overview/what/core-features/extensibility.md create mode 100644 content/en/overview/what/core-features/load-balance.md create mode 100644 content/en/overview/what/core-features/more.md create mode 100644 content/en/overview/what/core-features/observability.md create mode 100644 content/en/overview/what/core-features/protocols.md create mode 100644 content/en/overview/what/core-features/security.md create mode 100644 content/en/overview/what/core-features/service-definition.md create mode 100644 content/en/overview/what/core-features/service-definition.md.bak create mode 100644 content/en/overview/what/core-features/service-discovery.md create mode 100644 content/en/overview/what/core-features/service-mesh.md create mode 100755 content/en/overview/what/core-features/traffic/_index.md create mode 100644 content/en/overview/what/core-features/traffic/circuit-breaking.md create mode 100644 content/en/overview/what/core-features/traffic/condition-rule.md create mode 100644 content/en/overview/what/core-features/traffic/configuration-rule.md create mode 100644 content/en/overview/what/core-features/traffic/introduction.md rename content/en/overview/{core-features/traffic/mesh-rule.md.bak => what/core-features/traffic/mesh-rule.md} (98%) create mode 100644 content/en/overview/what/core-features/traffic/script-rule.md create mode 100644 content/en/overview/what/core-features/traffic/tag-rule.md delete mode 100644 content/en/overview/what/dubbo3.md delete mode 100644 content/en/overview/what/ecosystem.md delete mode 100644 content/en/overview/what/extensibility.md create mode 100644 content/en/overview/what/xyz-difference.md diff --git a/content/en/overview/_index.md b/content/en/overview/_index.md index 15bab5c80153..36de6153402f 100755 --- a/content/en/overview/_index.md +++ b/content/en/overview/_index.md @@ -1,31 +1,8 @@ --- +aliases: + - /zh/overview/ +description: Dubbo 文档 +linkTitle: 文档 +title: Dubbo 文档 type: docs -title: "Overview" -linkTitle: "DOCS" -no_list: true -hide_summary: true -menu: - main: - weight: 1 --- - -Dubbo is an RPC service framework that includes multiple language implementations (Java, Golang, etc.), where you can view the core concepts of Dubbo, as well as the demos and user manuals implemented in each language. - -* **If you are new to Dubbo**, you can quickly learn about Dubbo through the following links: - * [What is Dubbo](what/overview) - * User Cases and Ecology - * Experience Dubbo via [**Quick Start**](quickstart/) -* Want to know more about Dubbo features and usage details? - * Select the corresponding [**Multilanguage SDK Implementation**](mannual/), and refer to **Advanced Features** or **Reference Manual** -* Veteran users who want to learn about **Dubbo 3.0** quickly - * [3.0 Feature List](what/dubbo3/) - * Check the corresponding [Multilingual SDK Implementation](mannual/) for upgrades and compatibility - -#### Related Links -Dubbo's multilingual implementation and documentation: - -Language | OS | Compilers/SDK | Reference Documentation | --- | -- | -- | -- | -Go | Windows, Linux, macOS | Go 1.13+ | [Go](../docs3-v2/golang-sdk) | -Java|Windows, Linux, macOS |Java 8+ | [Java](../docs3-v2/java-sdk/) | -Rust | Windwos, Linux, macOS | Rust 2021 edition | [Rust](../docs3-v2/rust-sdk) | diff --git a/content/en/overview/core-features/_index.md b/content/en/overview/core-features/_index.md deleted file mode 100755 index a248c51aa8ee..000000000000 --- a/content/en/overview/core-features/_index.md +++ /dev/null @@ -1,8 +0,0 @@ - ---- -type: docs -title: "Core Features" -linkTitle: "Features" -weight: 30 -no_list: true ---- \ No newline at end of file diff --git a/content/en/overview/core-features/ecosystem.md b/content/en/overview/core-features/ecosystem.md deleted file mode 100644 index fe04fcbf10dd..000000000000 --- a/content/en/overview/core-features/ecosystem.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -description: Microservices Ecosystem -feature: - description: | - One-stop microservice ecosystem adaptation: service registry, gateway, rate limiting and fallback, load balancing, consistent transactions, asynchronous messaging, tracing, and more. - title: Rich Ecosystem -linkTitle: Microservices Ecosystem -title: Microservices Ecosystem -type: docs -weight: 90 ---- - -The Dubbo community, along with numerous outstanding open-source projects, has established a rich microservices ecosystem support around Dubbo. This allows developers to opt for Dubbo as their development framework without worrying about subsequent service governance needs. From day one, Dubbo offers production-level solutions for every common issue. - -The table below shows the support for ecosystem components based on the latest Dubbo Java 3.2.x version, which will be continuously updated based on development progress. The completeness of components supported in each language may vary. For specifics, please refer to the detailed explanations in each [language reference manual](../../mannual/). - - - -| Feature | Component List | Component List | Component List | Component List | Component List | -|-------------------------------------|------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------| -| Service Discovery | [Zookeeper](/en/docs3-v2/java-sdk/reference-manual/registry/zookeeper/) | [Nacos](/en/docs3-v2/java-sdk/reference-manual/registry/nacos/) | [Kubernetes Service](/) | DNS​``oaicite:{"number":1,"invalid_reason":"Malformed citation 【Under Development】"}``​ | [More](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-registry-extensions) | -| Dynamic Configuration | [Zookeeper](/en/docs3-v2/java-sdk/reference-manual/config-center/zookeeper/) | [Nacos](/en/docs3-v2/java-sdk/reference-manual/config-center/nacos/) | [Apollo](/en/docs3-v2/java-sdk/reference-manual/config-center/apollo/) | Kubernetes​``oaicite:{"number":2,"invalid_reason":"Malformed citation 【Under Development】"}``​ | [More](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-configcenter-extensions) | -| Metadata Management | [Zookeeper](/en/docs3-v2/java-sdk/reference-manual/metadata-center/zookeeper/) | [Nacos](/en/docs3-v2/java-sdk/reference-manual/metadata-center/nacos/) | [Redis](/zh-cn/overview/mannual/java-sdk/reference-manual/metadata-center/redis/) | Kubernetes​``oaicite:{"number":3,"invalid_reason":"Malformed citation 【Under Development】"}``​ | [More](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-metadata-report-extensions) | -| RPC Protocols | [HTTP/2 (Triple)](/en/docs3-v2/java-sdk/reference-manual/protocol/triple/) | [TCP](/zh-cn/overview/reference/protocols/tcp/) | [HTTP/REST​``oaicite:{"number":4,"invalid_reason":"Malformed citation 【Alpha】"}``​](/en/docs3-v2/java-sdk/reference-manual/protocol/http) | [gRPC](/en/docs3-v2/java-sdk/reference-manual/protocol/triple) | [More](/en/docs3-v2/java-sdk/reference-manual/protocol/) | -| Visualization & Monitoring Platform | [Admin](/zh-cn/overview/tasks/observability/admin/) | [Grafana](/zh-cn/overview/tasks/observability/grafana/) | [Prometheus](/zh-cn/overview/tasks/observability/prometheus/) | - | - | -| Full-link Tracing | [Zipkin](/zh-cn/overview/tasks/observability/tracing/zipkin/) | [Skywalking](/zh-cn/overview/tasks/observability/tracing/skywalking/) | [OpenTelemetry](https://github.com/apache/dubbo-samples/tree/master/4-governance/dubbo-samples-spring-boot3-tracing#2-adding-micrometer-tracing-bridge-to-your-project) | - | - | -| Rate Limiting & Fallback | [Sentinel](/zh-cn/overview/tasks/rate-limit/sentinel) | [Resilience4j](/zh-cn/overview/tasks/rate-limit/resilience4j) | [Hystrix](/zh-cn/overview/tasks/rate-limit/hystrix) | - | - | -| Distributed Transactions | [Seata](/en/overview/tasks/ecosystem/transaction/) | - | - | - | - | -| Gateway | [Higress] | [APISIX](/zh-cn/overview/tasks/ecosystem/gateway/) | [Shenyu] | [Envoy](https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/network_filters/dubbo_proxy_filter) | - | -| Service Mesh | Istio​``oaicite:{"number":5,"invalid_reason":"Malformed citation 【Under Development】"}``​ | [Aeraka](https://www.aeraki.net/) | OpenSergo​``oaicite:{"number":6,"invalid_reason":"Malformed citation 【Under Development】"}``​ | Proxyless​``oaicite:{"number":7,"invalid_reason":"Malformed citation 【Alpha】"}``​ | More | - - -## Microservices Ecosystem Example Architecture - -{{< mse >}} - -{{< blocks/section color="white" height="auto" >}} -
-
-
-
-
-{{< /blocks/section >}} diff --git a/content/en/overview/core-features/extensibility.md b/content/en/overview/core-features/extensibility.md deleted file mode 100644 index 61b755a000fd..000000000000 --- a/content/en/overview/core-features/extensibility.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -description: Extensibility Adaptation -feature: - description: | - Everything is extendable. Customize behaviors of invocation and management (like Filters, Routers, Service Discovery, Configuration, etc.) to adapt to the open-source microservices ecosystem. - title: Extensibility -linkTitle: Extensibility Adaptation -title: Extensibility Adaptation -type: docs -weight: 50 ---- - -From its design, Dubbo is highly extendable. Through these extension points, you can: -* Intercept traffic and control its behavior. -* Fine-tune some of Dubbo's default strategies and implementations. -* Adapt Dubbo services to internal microservices clusters or other mainstream open-source components. - -## Everything is Extendable - -Dubbo's extensibility allows the project to be conveniently divided into various sub-modules, enabling hot plugging. Users can replace Dubbo's native implementation based on their needs to meet specific business requirements. - -![Admin Screenshot](/imgs/v3/advantages/extensibility.png) - -* **Protocol and Coding Extension**: Communication protocols, serialization protocols, etc. -* **Traffic Control Extension**: Cluster fault tolerance strategies, routing rules, load balancing, rate limiting, fallback, circuit breaking, etc. -* **Service Governance Extension**: Service registry, configuration center, metadata center, distributed transactions, full-link tracing, monitoring systems, etc. -* **Diagnostic and Tuning Extension**: Traffic statistics, thread pool strategies, logging, QoS maintenance commands, health checks, configuration loading, etc. - -## Microservices Ecosystem Based on Extension Points -Numerous extension points and abstractions form the foundation for Dubbo's integration with various microservices ecosystem components and the realization of microservices governance capabilities. - -* [Full-link Tracing](/zh-cn/overview/tasks/observability/tracing/) -* [Data Consistency](/zh-cn/overview/tasks/ecosystem/transaction/) -* [Rate Limiting & Fallback](/zh-cn/overview/core-features/traffic/circuit-breaking/) - -Dubbo's SDKs for various languages adopt the "microkernel + plugin" design pattern. Almost all core nodes in every process are defined as extension points. Officially released components are also released in the form of extension point implementations, so Dubbo can treat all official and third-party component extensions equally. -* Extensibility adaptation is key to realizing Dubbo's microservices ecosystem. Ecosystem components, such as full-link tracing and service registry implementations, are adapted based on extension points like Filter, Registry, and DynamicConfiguration. -* Extensibility adaptation offers users the highest flexibility, allowing developers to integrate with internal components and customize core capabilities as needed. - -![extensibility-echosystem.png](/imgs/v3/feature/extensibility/arc.png) - -The above are some core extension points within Dubbo, categorized by architectural levels: -* Protocol Communication Layer -* Traffic Control Layer -* Service Governance Layer - -## Protocol Communication Layer -As emphasized in the communication protocol section, Dubbo is not bound to any specific protocol. Users can select any combination of RPC and serialization protocols, such as Triple, gRPC, Dubbo2, REST, custom protocols, etc. - -![Protocol and Coding Principles](/imgs/v3/feature/extensibility/protocol.png) - -### Protocol -The Protocol extension point defines the corresponding RPC protocol. By utilizing this extension point, Dubbo can act as a unified microservices development and governance framework, allowing for flexibility in the underlying communication protocol. Officially supported are the most popular RPC communication protocols, and if you wish to use a company-specific RPC communication protocol, provide a custom extension implementation via Protocol. - -### Serialization -The Serialization extension point defines serialization protocol extensions. Officially, Dubbo offers serialization protocols like Fastjson, Protobuf, Hessian2, Kryo, and FST. - -## Traffic Control Layer -Dubbo pre-embeds a significant number of extension points in the service call link, allowing users to control the flow of runtime traffic and change the behavior of runtime calls. - -![Protocol and Coding Principles](/imgs/v3/feature/extensibility/traffic.png) - -### Filter -Filters, traffic interceptors in Dubbo, are based on the AOP design pattern. They preprocess and postprocess each service call, handling tasks like access logs, encryption/decryption, traffic statistics, parameter verification, etc. - -### Router -The Router is a key component for traffic control in Dubbo. It directs traffic that meets certain conditions to a specific group of address subsets, enabling various traffic control modes. - -### Load Balance -In Dubbo, Load Balance works after the router. It ensures that calls are evenly distributed across all machines in the address subset over a period of time. - -## Service Governance Layer -The classic Dubbo deployment architecture consists of a registry (service discovery), configuration center, and metadata center. - -![Service Governance Architecture](/imgs/v3/concepts/threecenters.png) - -This section primarily discusses Dubbo's service governance from an architectural and implementation perspective. - -### Registry -The registry is the foundation for Dubbo's service discovery capability, with official support for registries like Zookeeper, Nacos, Etcd, Consul, and Eureka. - -### Config Center -The configuration center is a key component for dynamically controlling Dubbo's behavior. All rules dispatched in [Traffic Management](../../../../zh-cn/overview/tasks/traffic-management) are first saved in the configuration center. - -### Metadata Center -In contrast to the configuration center, from a user's perspective, the metadata center is read-only. - -## Custom Extension Examples -The following examples demonstrate how to extend Dubbo to address practical problems. - -* [Custom RPC Protocol](/zh-cn/overview/tasks/extensibility/protocol/) -* [Custom Traffic Routing Rule](/zh-cn/overview/tasks/extensibility/router/) -* [Custom Registry](/zh-cn/overview/tasks/extensibility/registry/) -* [Custom Interceptor](/zh-cn/overview/tasks/extensibility/filter/) - -## More Extension Points -This article lists some of the commonly used extension points in Dubbo. However, there are many more extension points available for flexible customization. Each SDK for different languages may have variations in extension definitions and configuration methods. - -* [Java Extension Manual](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/) -* [Go Extension Manual](/zh-cn/overview/mannual/golang-sdk/preface/design/aop_and_extension/) -* [Java Extension Manual](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/) -* [Go Extension Manual](/zh-cn/overview/mannual/golang-sdk/preface/design/aop_and_extension/) diff --git a/content/en/overview/core-features/load-balance.md b/content/en/overview/core-features/load-balance.md deleted file mode 100644 index a903f5408c98..000000000000 --- a/content/en/overview/core-features/load-balance.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -description: Load Balancing -linkTitle: Load Balancing -title: Load Balancing -type: docs -weight: 20 ---- - -During cluster load balancing, Dubbo provides multiple balancing strategies, with the default being the `weighted random` strategy, which is a weight-based random load balancing strategy. - -In terms of implementation, Dubbo provides client-side load balancing, meaning the Consumer determines which Provider instance to send the request to using a load balancing algorithm. - -## Load Balancing Strategies -Currently, Dubbo has built-in the following load balancing algorithms, which can be enabled through configuration adjustments. - -| Algorithm | Characteristics | Remarks | -| :------------------------------- | :----------------------- | :-------------------------------------------------------------- | -| Weighted Random LoadBalance | Weighted Random | Default algorithm, default weights are the same. | -| RoundRobin LoadBalance | Weighted Round Robin | Inspired by Nginx's smooth weighted round-robin algorithm. | -| LeastActive LoadBalance | Least Active + Weighted Random | The principle of "the more capable, the more work". | -| Shortest-Response LoadBalance | Shortest Response + Weighted Random | Focuses more on response speed. | -| ConsistentHash LoadBalance | Consistent Hashing | Deterministic parameters lead to a deterministic provider, suitable for stateful requests.| -| P2C LoadBalance | Power of Two Choice | After randomly selecting two nodes, choose the one with fewer "connections".| -| Adaptive LoadBalance | Adaptive Load Balancing | Based on P2C algorithm, chooses the node with the least load. | - -### Weighted Random -* **Weighted Random**: The probability of random selection is set according to the weight. -* There's a high collision probability on a cross-section, but as the call volume grows, the distribution becomes more even. After probability-based weighting, it's also fairly even, which facilitates dynamic adjustment of provider weights. -* Downside: There's the problem of slow providers accumulating requests. - -### RoundRobin -* **Weighted Round Robin**: Calls nodes in a circular manner based on proportionate weights. -* Downside: There's the problem of slow providers accumulating requests. - -For the weighted round robin, if a node's weight is too large, there's the problem of concentrated calls in a short time span. - -### LeastActive -* **Weighted Least Active**: The provider with the fewest active calls is preferred. The fewer the active calls, the stronger the provider's processing ability. -* This ensures slower providers receive fewer requests, as slower providers will have a larger difference between requests sent and responses received. - -### ShortestResponse -* **Weighted Shortest Response**: Providers with faster response times handle more requests. -* Downside: This might lead to traffic concentrating too much on high-performance nodes. - -### ConsistentHash -* **Consistent Hashing**: Requests with the same parameters are always sent to the same provider. -* When a provider fails, the requests originally directed to that provider are spread across other providers based on virtual nodes, without causing major disruption. -* For details, refer to: [Consistent Hashing | WIKIPEDIA](http://en.wikipedia.org/wiki/Consistent_hashing) - -### P2C Load Balance -The Power of Two Choice algorithm is simple but classic. - -### Adaptive Load Balance -Adaptive, as the name suggests, is a self-adapting load balancing mechanism that always tries to forward requests to the least loaded node. - -## Configuration -Dubbo allows providers to configure a default load balancing strategy so that all consumers will use the strategy specified by the provider by default. Consumers can also specify their own load balancing strategies. If neither side has any configuration, the random load balancing strategy is used by default. - -Each application can configure different services to use different load balancing strategies and can even specify different strategies for different methods of the same service. - -For configuration details, refer to the implementations in different languages: -* [Java](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance/) -* [Golang](/zh-cn/overview/mannual/golang-sdk/) - -## Custom Extensions -Load balancing strategies support custom extension implementations. For details, please see [Dubbo's Extensibility](/en/overview/core-features/extensibility/). \ No newline at end of file diff --git a/content/en/overview/core-features/more.md b/content/en/overview/core-features/more.md deleted file mode 100644 index aff57e635259..000000000000 --- a/content/en/overview/core-features/more.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -description: Advanced Features Guide -linkTitle: More Advanced Features -title: More Advanced Features -type: docs -weight: 11 ---- - -As a microservice framework closely related to application development and aimed at providing enterprise-level service governance capabilities, Dubbo offers a variety of advanced features covering service call behavior control, service diagnostics and tuning, and service governance. - -Different language SDKs may have slight variations in feature implementation and configuration methods. For a specific list of features and usage, refer to the following documents: -* [Java](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/) -* [Golang](/zh-cn/overview/mannual/golang-sdk/tutorial/) - -## Controlling Service Invocation Behavior -* Service Versions -* Service Groups -* Group Aggregation -* Asynchronous Invocation -* Asynchronous Execution -* Streaming Communication -* Reactive Programming -* Generic Invocation -* Generic Implementation -* Passing Implicit Parameters in Call Chain -* RPC Call Context -* Invocation Event Notifications -* Server Callbacks to Client -* Subscribe Only -* Register Only -* Runtime Dynamic IP Specification -* Direct Provider Connection -* Startup Checks -* Local Invocation -* Parameter Validation -* Local Mocking -* Local Stubs -* Echo Tests -* Invocation Information Logging -* Delayed Exposure -* Cluster Fault Tolerance -* Service Degradation - -## Diagnostics and Tuning -* Port Protocol Multiplexing -* Thread Pool Isolation -* Multiple Protocols -* Multiple Registry Centers -* Request Latency Sampling -* Thread Models -* Service Reference Configuration Object Caching -* Route State Collection -* Load Balancing -* Simplified Registration Information -* Invocation Result Caching -* Concurrency Control -* Connection Control -* Delayed Connections -* Sticky Connections -* Graal VM Support -* Exporting Thread Stack Trace -* Kryo and FST Serialization -* Custom Service Container -* Graceful Shutdown -* Custom Host Address Exposure -* Consistent Hashing -* Logging Framework Adaptation and Runtime Management -* Kubernetes Lifecycle Probes - -These features are designed to provide more control and flexibility in a microservices environment. They can help improve system reliability, enhance performance, and ease the process of deploying, managing, and scaling applications. diff --git a/content/en/overview/core-features/observability.md b/content/en/overview/core-features/observability.md deleted file mode 100644 index 9fecaf24d573..000000000000 --- a/content/en/overview/core-features/observability.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -type: docs -title: "Observability" -linkTitle: "Observability" -weight: 60 -description: "" -feature: - title: Observability - description: > - Multi-dimensional observable indicators (Metrics, Tracing, Accesslog) help to understand the service running status, Admin console, Grafana, etc. help realize the visual display of data indicators. ---- - -Dubbo maintains observability metrics across multiple dimensions and supports various methods of visual monitoring. Observability metrics can be broadly categorized into three measurement dimensions: - -* **Admin.** The Admin console provides a visual representation of applications, services, instances, and dependency relationships within the cluster. It supports the issuance of traffic governance rules. Additionally, it offers tools such as service testing, mocking, and document management to enhance the efficiency of development and testing processes. - -* **Metrics.** Dubbo collects a range of traffic metrics such as QPS (Queries Per Second), RT (Response Time), successful requests, failed requests, and also includes various internal component statuses like thread pool count, service health status, and more. - -* **Tracing.** Dubbo has been adapted to work with mainstream industry-level distributed tracing tools, including Skywalking, Zipkin, and Jaeger. These tools all support the tracing of Dubbo services. - -* **Logging.** Dubbo supports adaptation to multiple logging frameworks. In the Java ecosystem, it provides support for various frameworks including Slf4j, Log4j2, Log4j, Logback, Jcl, etc. Users can choose the appropriate framework based on their business requirements. Additionally, Dubbo also supports Access Log to record request traces. - -## Admin -The Admin console provides a visual representation of applications, services, instances, and dependency relationships within the cluster. It supports the issuance of traffic governance rules. Additionally, it offers tools such as service testing, mocking, and document management to enhance the efficiency of development and testing processes. - -![Admin rendering](/imgs/v3/feature/observability/admin.jpg) - -* [Admin deployment and effect demonstration](#) - -## Metrics -At runtime, Dubbo collects core service metrics, including QPS (Queries Per Second), RT (Response Time), total invocations, successful invocations, and failure statistics, along with reasons for failures. Additionally, for more effective monitoring of service operation, Dubbo offers monitoring of essential component states such as thread pool count and service health status. - -You can visualize the metrics using Grafana. - -![Grafana rendering](/imgs/v3/feature/observability/grafana.png) - -* [Use Grafana for visualizing metrics](#) -* [How to Query Specific Metrics from Prometheus](#) - -## Tracing -Full link tracing holds significant value in monitoring the operational status of distributed systems. Dubbo achieves runtime pointcut tracing through Filter interceptors. By exporting trace data to prominent platforms like Zipkin, Skywalking, Jaeger, etc., comprehensive end-to-end tracking data analysis and visual representation can be accomplished. - -![Tracing rendering](/imgs/v3/feature/observability/tracing.png) - -With just a simple line of configuration, you can switch the backend implementation for tracing. Moreover, you have the flexibility to dynamically adjust Dubbo's tracing sampling rate through governance platforms like Dubbo Admin, which proves highly valuable for troubleshooting. - -* [Realize full-link tracking based on Skywalking](#) -* [Full link tracking based on Zipkin](#) - -## Logging -Access logs can assist in analyzing system traffic. In certain scenarios, enabling access logs can also be very helpful for troubleshooting issues. - -* [Enable Access Log](#) -* [Enable Access Log in running state](#) \ No newline at end of file diff --git a/content/en/overview/core-features/protocols.md b/content/en/overview/core-features/protocols.md deleted file mode 100644 index 616649a70870..000000000000 --- a/content/en/overview/core-features/protocols.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -type: docs -title: "Protocols" -linkTitle: "Protocols" -weight: 40 -description: "Protocols" -feature: - title: Multiple Protocols - description: > - Dubbo supports almost all the protocols from HTTP/2, gRPC, TCP, REST to Thrift, choose any RPC protocols you need with only one line of configuration. It also allow you to publish different protocols on a single port. ---- - -The Dubbo framework offers custom, high-performance RPC communication protocols: the HTTP/2-based Triple protocol and the TCP-based Dubbo2 protocol. Additionally, Dubbo supports any third-party communication protocols, such as officially supported ones like gRPC, Thrift, REST, JsonRPC, Hessian2, and more. Further protocols can be implemented through custom extensions. This is particularly useful for handling multi-protocol communication scenarios, which are common in microservices practices. - -**The Dubbo framework is not tied to any specific communication protocol. In its implementation, Dubbo's support for multiple protocols is highly flexible. It allows you to publish services that use different protocols within a single application. Furthermore, it supports exposing all protocols externally through the same port.** - -![protocols](/imgs/v3/feature/protocols/protocol1.png) - -Through Dubbo framework's support for multiple protocols, you can achieve: -* Seamlessly integrate any communication protocol into the Dubbo service governance system. All communication protocols under the Dubbo ecosystem can leverage Dubbo's programming model, service discovery, and traffic control advantages. For instance, in the case of gRPC over Dubbo, both service governance and programming APIs can be seamlessly integrated into the Dubbo ecosystem at zero cost. -* Compatibility with different technology stacks, allowing for a mix of different service frameworks and RPC frameworks in a business system. For example, some services may be developed using gRPC or Spring Cloud, while others use the Dubbo framework. Through Dubbo's support for multiple protocols, interoperability can be achieved seamlessly. -* Simplifying protocol migration. By coordinating multiple protocols with the registry center, you can quickly meet the company's needs for protocol migration. For example, migrating from a proprietary protocol to the Dubbo protocol, upgrading the Dubbo protocol itself, migrating from the Dubbo protocol to gRPC, or transitioning from HTTP to the Dubbo protocol, and so on. - -## HTTP/2 (Triple) -Triple protocol, introduced in Dubbo 3, is a communication protocol designed for the cloud-native era. It is based on HTTP/2 and fully compatible with the gRPC protocol. Triple natively supports streaming communication semantics. It can run on both HTTP/1 and HTTP/2 transport protocols, allowing you to directly access backend Dubbo services using tools like curl or a web browser. - -Since the introduction of the Triple protocol, Dubbo also supports service definition and data transmission based on Protocol Buffers. However, Triple's implementation is not bound to Interface Definition Language (IDL). For example, you can directly use Java Interface to define and publish Triple services. Triple possesses better gateway and proxy penetration capabilities, making it well-suited for deployment architectures involving cross-gateway and proxy communication, such as service meshes. - -Key features of the Triple protocol include: - -* Support for TLS encryption and plaintext data transmission -* Support for backpressure and flow control -* Support for streaming communication -* Simultaneous support for HTTP/1 and HTTP/2 transport protocols - -In terms of programming and communication models, the Triple protocol supports the following modes: - -* Client-side asynchronous request-response -* Server-side asynchronous request-response -* Client-side request streaming -* Server-side response streaming -* Bidirectional streaming communication - -Development Practice - -* For the usage of the Triple protocol, please refer to the [Triple Protocol Development Tasks](../../tasks/triple/) or the [Java SDK Example Documentation](../../../docs3-v2/java-sdk/reference-manual/protocol/triple/). -* [Triple Design Ideas and Protocol Specifications](/zh-cn/overview/reference/protocols/triple/) - -## Dubbo2 - -The Dubbo2 protocol is an RPC communication protocol built on top of the TCP transport layer protocol. Due to its compact, flexible, and high-performance characteristics, it gained widespread use during the Dubbo2 era. It served as a key communication solution for enterprises to build high-performance, large-scale microservice clusters. In the cloud-native era, we recommend using the Triple protocol for its greater generality and better penetration. - -The Dubbo2 protocol also has built-in support for HTTP, so you can use curl for quick service validation or debugging during development. - -* [Dubbo2 Protocol Development Tasks](../../../docs/v2.7/dev/impls/protocol/) -* [Dubbo2 Design Ideas and Protocol Specifications](/zh-cn/overview/reference/protocols/tcp/) - -## gRPC - -You can develop and manage microservices using Dubbo and then set up underlying communication using the gRPC protocol. But why do this instead of directly using the gRPC framework, and what advantages does it offer in comparison? The simple answer is that this is a common pattern for developing microservices using gRPC. Please read on for more details. - -gRPC is Google's open-source communication protocol based on HTTP/2. As we mentioned in our [Product Comparison](/zh-cn/overview/what/xyz-difference/) document, gRPC is positioned as a communication protocol and its implementation, making it a pure RPC framework. On the other hand, Dubbo is positioned as a microservices framework, providing solutions for microservices practices. Therefore, compared to Dubbo, gRPC lacks abstractions for microservices programming models, service governance, and other capabilities. - -Using the gRPC protocol (gRPC over Dubbo Framework) within the Dubbo ecosystem is a highly efficient and lightweight choice. It allows you to use the native gRPC protocol for communication while avoiding the complexity of customizing and developing based on gRPC (customizing and developing with gRPC is an inevitable step in many enterprise-scale practices, and the Dubbo framework handles this for developers, enabling them to use gRPC in the simplest way possible). - -[gRPC over Dubbo Example](/zh-cn/overview/tasks/protocols/grpc/) - -## REST - -A common communication pattern in the microservices domain is HTTP + JSON. This includes mainstream microservices frameworks like Spring Cloud and Microprofile, which default to using this communication pattern. Dubbo also provides support for programming and communication patterns based on HTTP. - -* [HTTP over Dubbo Example](/zh-cn/overview/tasks/protocols/web/) -* [Interoperability between Dubbo and Spring Cloud Ecosystems](/zh-cn/overview/tasks/protocols/springcloud/) - -## Other Communication Protocols - -In addition to the protocols mentioned above, you can also run the following protocols on top of Dubbo. For Dubbo, it only takes a simple configuration change to switch the underlying service communication protocol, without affecting other peripheral APIs and governance capabilities. - -* Hessian2 -* Thrift -* JsonRPC - -## Interoperability in Heterogeneous Microservice Ecosystems - -For practices related to protocol migration and coexistence of multi-protocol technology stacks, please refer to this [blog post](/zh-cn/blog/2023/01/05/dubbo-连接异构微服务体系-多协议多注册中心/). - -## Configuration Method - -For the configuration and usage methods of the protocols mentioned above, including how to configure `single-port multi-protocol` support, please refer to the following SDK documentation: - -* [Java](../../../docs3-v2/java-sdk/reference-manual/protocol/) -* [Golang](../../../docs3-v2/golang-sdk/preface/concept/protocol/) -* [Rust](../../../docs3-v2/rust-sdk/protocol/) - -## Custom Extensions - -In addition to the communication protocols officially supported, Dubbo supports extending support for new protocols. For specific details, please refer to [【Task】-【Extensibility】-【Protocol】](/zh-cn/overview/tasks/extensibility/protocol/). \ No newline at end of file diff --git a/content/en/overview/core-features/security.md b/content/en/overview/core-features/security.md deleted file mode 100644 index deeb6bb21559..000000000000 --- a/content/en/overview/core-features/security.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -type: docs -title: "Authentication" -linkTitle: "Authentication" -weight: 70 -description: | - Offers TLS-based transport layer authentication and encrypted communication, as well as request-based authorization, to help build a Zero Trust distributed microservices system. -feature: - title: Zero-trust Security - description: > - It supports TLS-based transmission link authentication and encrypted communication, as well as permission verification based on request identity, helping to build a zero-trust distributed microservice system. ---- - -Dubbo provides comprehensive mechanisms to build a secure microservices communication system, also known as a Zero Trust system. This includes: -* Preventing man-in-the-middle attacks by offering identity authentication (Authentication) and TLS-based encrypted communication. -* Controlling inter-service access authorization (Authorization) with mechanisms like mTLS and permission checks. - -This document will guide you through leveraging Dubbo's security features to build a Zero Trust system for your microservices, focusing on authentication, transparent encryption, authorization, and auditing. Since Zero Trust is a comprehensive approach, you may need another infrastructure, such as certificate management and security policy control. - -> **Note**: The scope of this document does not include certificate generation and distribution. We assume you already have an infrastructure in place for certificate management. Hence, we will focus on Dubbo's authentication and authorization mechanisms and processes. If you lack such infrastructure, we recommend using a service mesh architecture like Istio for certificate management and security policies. - -## Architecture - -A complete Zero Trust system comprises multiple components: - -* A Root Certificate Authority (CA) to manage keys and certificates. -* A security policy management and distribution center to send real-time policies to data plane components: - * Authentication policies - * Authorization policies - * Secure Naming Information -* Data plane components (Dubbo) responsible for identification, encryption, and policy enforcement. -* A suite of tools and ecosystems to complete security audits and data link monitoring. - -In a service mesh deployment like Istio, the control plane typically handles security policies and certificates, interacting with infrastructure like the Kubernetes API Server to distribute configuration data to Dubbo or other data plane components. - -Here is a comprehensive architecture diagram for Dubbo Zero Trust: - -![Authentication](/imgs/v3/feature/security/arch.png) - -## Authentication - -Dubbo provides two modes of authentication: - -* **Channel Authentication**: Dubbo supports TLS-based HTTP/2 and TCP communication. You can enable TLS through Channel Authentication API or control plane policies for server identity authentication and data link encryption. Additionally, you can enable mTLS for client-server mutual authentication. This is a service-to-service mode of authentication. -* **Request Authentication**: Dubbo offers APIs to attach user identity credentials (like JWT tokens) in the request context. Dubbo automatically recognizes these identity tokens for permission checks. You can also customize these tokens, like OAuth2 access tokens. This is an end-user mode of authentication, representing the identity of the user logged into the system. - -### Architecture - -In Istio mode, Dubbo's authentication mechanism automatically interfaces with the Istio control plane through xDS. Certificates and authentication policies generated by the Istio control plane are automatically sent to the Dubbo data plane, which applies them to all subsequent data communications. - -![Authentication](/imgs/v3/feature/security/auth-1.png) - -#### Dubbo mTLS Flow - -In Istio deployments, you can enable or disable Channel Authentication's mutual authentication through control plane policies. The workflow for mutual authentication is as follows: - -1. Istio sends authentication policies to enable mutual authentication. -2. The Dubbo client initiates a mutual TLS handshake with the server, performing a secure naming check to validate the server's identity. -3. A mutual mTLS link is established between the client and server for encrypted communication. -4. The Dubbo server recognizes the client's identity and checks whether it has the permission to access the corresponding resource. - -### Authentication Policies -For specific rules supported by Istio, Dubbo fully supports Istio-defined authentication policies. - -[Read More](https://istio.io/latest/docs/concepts/security/#authentication-policies) - -## Authorization - -Dubbo has abstracted an authorization extension mechanism but currently only supports the Istio system. Thus, its authorization capabilities are equivalent to those described in the official Istio documentation. - -[Read More](https://istio.io/latest/docs/concepts/security/#authorization) - -### Architecture - -Dubbo receives user-configured authorization policies from the Istio control plane through xDS. When a request reaches a Dubbo instance, the built-in authorization engine matches the request parameters and user identity against the policy. If the match is successful, access is granted; otherwise, it's denied. - -![Authorization](/imgs/v3/feature/security/authz-1.png) - -### Authorization Policies -For specific rules supported by Istio, Dubbo fully supports Istio-defined authorization policies. - -[Read More](https://istio.io/latest/docs/concepts/security/#authorization-policies) - -## Dubbo Authentication API - -Dubbo defines an authentication API. For general use cases, developers can enable TLS/mTLS through this API. However, in an Istio control plane deployment, Dubbo automatically recognizes the certificates and authentication policies sent by Istio, so no special configuration is needed on the Dubbo side. - -Whether or not you use the Istio control plane, JWT tokens for Request Authentication still need to be specified programmatically in Dubbo. - -For language-specific API definitions, please refer to the respective SDK documentation: -* [Java](/) -* [Go](/) -* [Rust](/) -* [Node.js](/) - -## Sample Tasks - -Please visit the following [Dubbo Task Examples](/) for hands-on practice with security policies. diff --git a/content/en/overview/core-features/service-definition.md b/content/en/overview/core-features/service-definition.md deleted file mode 100644 index 18bacab96ebe..000000000000 --- a/content/en/overview/core-features/service-definition.md +++ /dev/null @@ -1,151 +0,0 @@ ---- -type: docs -title: "Develop microservice with Dubbo" -linkTitle: "Microservice develop" -weight: 1 ---- -Dubbo addresses a series of challenges from development and deployment to governance and operations in enterprise microservices. Dubbo provides a full suite of services for developers, from project creation, development testing, to deployment, visual monitoring, traffic governance, and ecosystem integration. - -### Development - -* **Language Support**: Dubbo supports various programming languages including Java, Go, Rust, Node.js, and defines a set of paradigms for microservice development. A corresponding scaffold is available for quickly creating a microservice project skeleton. -* **Deployment**: Dubbo applications can be deployed in different environments including virtual machines, Docker containers, Kubernetes, and service mesh architectures. -* **Service Governance**: Dubbo provides capabilities like address discovery, load balancing, and traffic control. It also offers an Admin dashboard for visual control and a rich microservice ecosystem. - -#### Creating a Project -The [Dubbo Microservices Project Scaffold](https://start.dubbo.apache.org/bootstrap.html) can be used to quickly create a microservices project. The scaffold can generate a microservice project with necessary dependencies based on the features or components you want. - -#### Developing Services -**1. Define the Service** - -```java -public interface DemoService { - String hello(String arg); -} -``` - -**2. Implement Business Logic** - -```java -@DubboService -public class DemoServiceImpl implements DemoService { - public String hello(String arg) { - // your microservice logic here - } -} -``` - -#### Publishing Services -**1. Publish the Service Definition** - -The service provider needs to publish the service definition as a Jar package to the Maven central repository. - -**2. Expose the Service** - -Add Dubbo configuration and start the Dubbo server. - -```yaml -dubbo: - application: - name: dubbo-demo - protocol: - name: dubbo - port: -1 - registry: - address: zookeeper://127.0.0.1:2181 -``` - -#### Consuming Services - -First, consumers include the `DemoService` service definition dependency via Maven/Gradle. - -```xml - - org.apache.dubbo - dubbo-demo-interface - 3.2.0 - -``` - -Then, programmatically inject the remote Dubbo service instance. - -```java -@Bean -public class Consumer { - @DubboReference - private DemoService demoService; -} -``` - -### Deployment -Dubbo native services can be packaged and deployed to cloud-native infrastructures like Docker containers, Kubernetes, and service meshes. - -### Governance -For service governance, most applications just need to add the following configuration. Dubbo will then have address discovery and load balancing capabilities. - -```yaml -dubbo: - registry: - address: zookeeper://127.0.0.1:2181 -``` - -Deploy and open the [Dubbo Admin Dashboard](/zh-cn/overview/tasks/deploy/), and you will see the service deployment and invocation data. - -Dubbo Admin can also improve development and testing efficiency through additional capabilities like: -* Document management for regular services and IDL documents -* Service testing & service Mock -* Service status inquiry - -For more complex microservices scenarios, Dubbo also provides more advanced governance features, including: -* Traffic governance -* Dynamic configuration -* Rate limiting and degradation -* Data consistency -* Observability -* Multi-protocol -* Multiple registries -* Service mesh - -This guide provides an overview of the workflow for developing microservices with Dubbo. For detailed step-by-step instructions, please refer to: -* [Getting Started with Java Microservices](/en/overview/quickstart/) -* [Getting Started with Go Microservices](/en/overview/quickstart/go/) -* [Getting Started with Rust Microservices](/en/overview/quickstart/rust/) -* [Getting Started with Node.js Microservices](https://github.com/apache/dubbo-js) - - -### Deployment - -Dubbo's native services can be packaged and deployed in various cloud-native infrastructures and microservices architectures, including Docker containers, Kubernetes, and Service Mesh. - -For examples of deployment in different environments, refer to: -* [Deploying Dubbo services to Docker containers](/zh-cn/overview/tasks/deploy/deploy-on-docker) -* [Deploying Dubbo services to Kubernetes](/en/overview/tasks/kubernetes/) - -### Governance - -For service governance, most applications only need to add the following configuration, and the Dubbo application will have address discovery and load balancing capabilities. - -```yaml -dubbo: - registry: - address: zookeeper://127.0.0.1:2181 -``` - -Once deployed and the [Dubbo Admin Console](/zh-cn/overview/tasks/deploy) is opened, you can see the deployment and invocation data of services in the cluster. - -![Admin](/imgs/v3/what/admin.png) - -In addition, Dubbo Admin can also enhance R&D and testing efficiency through the following capabilities: -* Document management, providing general services and IDL document management. -* Service testing & Service Mock. -* Service status inquiry. - -For more complex microservices practice scenarios, Dubbo also offers many more advanced service governance features. For more details, please refer to the documentation, including: -* Traffic governance -* Dynamic configuration -* Rate limiting and degradation -* Data consistency -* Observability -* Multi-protocol -* Multi-registry centers -* Service Mesh \ No newline at end of file diff --git a/content/en/overview/core-features/service-discovery.md b/content/en/overview/core-features/service-discovery.md deleted file mode 100644 index e023efcc83cb..000000000000 --- a/content/en/overview/core-features/service-discovery.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -type: docs -title: "Service Discovery" -linkTitle: "Service Discovery" -weight: 10 -description: "" -feature: - title: Service Discovery - description: > - Service Discovery with customized design for large-scale cluster with millions of instances and rich builtin registry adaptations such as Nacos and Zookeeper and even more by supporting customized extensions. ---- - -Dubbo provides a Client-Based service discovery mechanism, relying on third-party registry components to coordinate the service discovery process. It supports popular registries like Nacos, Consul, and Zookeeper. - -Below is a basic workflow diagram for Dubbo's service discovery mechanism: - -![service-discovery](/imgs/v3/feature/service-discovery/arc.png) - -Service discovery involves three roles: providers, consumers, and the registry. In this setup, Dubbo provider instances register their URL addresses with the registry, which aggregates this data. Dubbo consumers read the address list from the registry and subscribe to changes. Whenever the address list changes, the registry notifies all subscribed consumer instances. - -## Service Discovery for Million-Scale Clusters -Unlike many other microservices frameworks, **Dubbo 3's service discovery is born out of Alibaba's large-scale e-commerce microservices cluster. Therefore, it significantly outperforms most mainstream open-source products in terms of performance, scalability, and ease of use.** It is the best choice for enterprises to build scalable microservices clusters for the future. - -![service-discovery](/imgs/v3/feature/service-discovery/arc2.png) - -* First, Dubbo's registry aggregates instance data at the application granularity level, allowing consumers to subscribe precisely according to their needs, thereby avoiding the performance bottleneck caused by full subscriptions in most open-source frameworks like Istio and Spring Cloud. -* Second, Dubbo SDK has heavily optimized the consumer-side address list processing, adding asynchronous notifications, caching, bitmap, and various parsing optimizations to avoid resource fluctuations commonly seen during address updates. -* Finally, in terms of feature richness and ease of use, besides synchronizing basic endpoint information like IP and port to consumers, Dubbo also synchronizes the metadata information of the server's RPC/HTTP services and their configurations to the consumer side, allowing for finer-grained collaboration between consumers and providers. - -### Efficient Address Push Implementation - -From the registry's perspective, it aggregates the instance addresses of the entire cluster based on the application name (`dubbo.application.name`). Each service-providing instance registers its own application name, instance IP:port address information (usually also containing a small amount of instance metadata, such as the machine's region, environment, etc.) with the registry. - -> Dubbo2's registry aggregates instance addresses at the service granularity, which is finer than application granularity and thus means more data transfer. This has led to some performance issues in large-scale clusters. -> For the inconsistency between the data models of Dubbo2 and Dubbo3, Dubbo3 provides a [smooth migration solution](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery/) that makes the model change transparent to users. - -![service-discovery](/imgs/v3/feature/service-discovery/registry-data.png) - -
-Each consumer service instance subscribes to the instance address list from the registry. Unlike some products that load all registry data (application + instance address) into local processes, Dubbo implements precise, on-demand address subscription. For example, if a consumer application depends on app1 and app2, it will only subscribe to the address list updates of app1 and app2, significantly reducing the burden of redundant data pushing and parsing. - -

-
- -![service-discovery](/imgs/v3/feature/service-discovery/subscription2.png) - -### Rich Metadata Configuration -In addition to interacting with the registry, Dubbo 3's complete address discovery process also has an additional metadata path, known as the Metadata Service. Instance addresses and metadata together form the effective address list on the consumer side. - -![service-discovery](/imgs/v3/feature/service-discovery/metadata.png) - -The complete workflow is shown above. First, the consumer receives the address (IP:port) information from the registry, then establishes a connection with the provider and reads the metadata configuration information from the Metadata Service. These two pieces of information together form the effective, service-oriented address list for Dubbo's consumer side. Both of these steps occur before the actual RPC service invocation takes place. - -> For the definition of MetadataService and a complete analysis of the service discovery process, please refer to [Detailed Application-Level Service Discovery]({{< relref "../../../blog/proposals/service-discovery/" >}}). - -> For data synchronization in microservices' service discovery models, REST has defined a very interesting maturity model. Interested readers can refer to the link here https://www.martinfowler.com/articles/richardsonMaturityModel.html. According to the article's 4-level maturity definition, Dubbo's current model based on interface granularity corresponds to the highest L4 level. - -## Configuration Methods -Dubbo service discovery extends support for multiple registry components, such as Nacos, Zookeeper, Consul, Redis, Kubernetes, etc. It can be switched through configuration and also supports authentication and namespace isolation configurations. For specific configuration methods, please refer to the SDK documentation: - -* [Java](/en/docs3-v2/java-sdk/reference-manual/registry) -* [Golang](/en/docs3-v2/golang-sdk/tutorial/develop/registry) -* [Rust](/en/docs3-v2/rust-sdk/) - -Dubbo also supports scenarios of multiple registries within a single application, such as dual registration, dual subscription, etc. This is very useful for implementing data exchange between different clusters and cluster migration. We will add `Best Practices` examples to future documentation to illustrate this part. - -## Custom Extensions -Registry adaptation supports custom extension implementation. For details, please refer to [Dubbo Extensibility](/en/overview/core-features/extensibility/). \ No newline at end of file diff --git a/content/en/overview/core-features/service-mesh.md b/content/en/overview/core-features/service-mesh.md deleted file mode 100644 index 21e50930b194..000000000000 --- a/content/en/overview/core-features/service-mesh.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -description: Service Mesh -feature: - description: | - Flexible data plane (Proxy & Proxyless) deployment options, seamlessly integrating with the Istio control plane governance ecosystem. - title: Service Mesh -linkTitle: Service Mesh -title: Service Mesh -type: docs -weight: 9 -working-in-progress: true ---- - -Dubbo Mesh is Dubbo's comprehensive microservices solution in a cloud-native context. It helps developers integrate Dubbo services with standard Kubernetes Native Service systems, enabling seamless connectivity with leading service mesh products like Istio. - -Below is the deployment architecture diagram for Dubbo Mesh. - -![Dubbo-Mesh](/imgs/v3/mesh/mix-mesh.png) - -* Control Plane: Istio serves as the unified control plane, providing cluster-wide capabilities like Kubernetes adaptation, service discovery, certificate management, observability, and traffic management. -* Data Plane: Dubbo application instances act as data plane components and support two deployment modes: - * Proxy Mode: Dubbo and Envoy are deployed in the same pod, and all traffic to and from Dubbo is intercepted and managed by Envoy. - * Proxyless Mode: Dubbo instances are deployed independently, communicating directly with each other and interacting directly with the control plane via the xDS protocol. - -For general content on service mesh architecture and why you might want to integrate with the Istio control plane, please refer to the [Istio official website](https://istio.io/). This document will focus on the Dubbo Mesh solution itself. - -## Dubbo Mesh - -### Proxy Mesh -In Proxy mode, Dubbo is deployed alongside a sidecar like Envoy. - -![dubbo-sidecar](/imgs/v3/mesh/dubbo-proxy.png) - -The architecture diagram above depicts Dubbo Proxy Mesh deployment: -* Dubbo and Envoy are deployed in the same pod, with Istio managing traffic and governance. -* Dubbo provides programming APIs and RPC communication capabilities for business applications, while other capabilities like address discovery, load balancing, and routing are delegated to Envoy, which intercepts all incoming and outgoing traffic. -* The control plane distributes configurations to Envoy via the xDS protocol, as indicated by the dashed lines in the diagram. - -In Proxy mode, using Dubbo3 communication layers like Triple, gRPC, and REST that are based on HTTP can result in better gateway penetration and performance. - -### Proxyless Mesh -In Proxyless mode, there are no proxy components like Envoy. Dubbo's processes are deployed independently and communicate directly. Istio's control plane interacts with Dubbo processes for governance via the xDS protocol. - -![dubbo-proxyless](/imgs/v3/mesh/dubbo-proxyless.png) - -In Proxyless mode, Dubbo deployment is basically the same as before, but the Dubbo3 SDKs directly implement xDS protocol parsing. - -#### Why Proxyless Mesh? - -While Proxy mode offers many advantages, such as smooth upgrades, multi-language support, and minimal business intrusion, it also introduces some challenges: -* Sidecar communication adds extra performance overhead, especially noticeable in complex network topologies. -* The presence of a sidecar complicates application lifecycle management. -* Not all environments can accommodate Sidecar deployment and request interception. - -In Proxyless mode, Dubbo processes continue to communicate directly: -* There is no additional Proxy-related overhead, making it more suitable for performance-sensitive applications. -* It simplifies legacy system migration. -* The architecture is simple and easy to manage. -* It is suitable for almost all deployment environments. - -## Sample Tasks -After acquiring sufficient theoretical knowledge, we recommend that you visit the following [examples](/en/overview/tasks/mesh) for hands-on practice. - -## Visualization -We recommend using [Dubbo Admin](/zh-cn/overview/tasks/deploy) as the visualization console for your Dubbo cluster. It is compatible with all Kubernetes, Mesh, and non-Mesh architecture deployments. - -Additionally, you can use [Istio's official recommended visualization tools](https://istio.io/latest/docs/tasks/observability/kiali/) to manage your Dubbo Mesh cluster. - -## Integration with Non-Istio Control Planes -Dubbo Mesh itself is not tied to any control plane product implementation. You can use Istio, Linkerd, Kuma, or any control plane product that supports the xDS protocol. The same applies to Sidecars. - -If you have already experienced the [Dubbo Mesh based on Istio](/) sample tasks and find that Istio meets your governance needs for Dubbo Mesh, then adopting Istio as your control plane is the preferred solution. - -If you find that Dubbo's capabilities are limited in Istio mode and need those capabilities, you may consider integrating Dubbo's control plane to replace Istio for better native Dubbo support and performance. For details, please refer to [Dubbo Mesh Sample Tasks based on Custom Dubbo Control Plane](/). - -> In short, this is a customized version of the control plane released by the Dubbo community based on Istio. For installation and capability differences of Dubbo's control plane, please refer to the sample task link above. diff --git a/content/en/overview/core-features/traffic/_index.md b/content/en/overview/core-features/traffic/_index.md deleted file mode 100755 index bdb76c1108b2..000000000000 --- a/content/en/overview/core-features/traffic/_index.md +++ /dev/null @@ -1,12 +0,0 @@ - ---- -type: docs -title: "流量管控" -linkTitle: "流量管控" -weight: 30 -no_list: true -feature: - title: Traffic Management - description: > - The traffic control strategy based on routing rules provided by Dubbo can help realize the service governance capabilities such as full-link grayscale, canary release, proportional traffic forwarding, dynamic adjustment of debugging time, and setting of retry times. ---- diff --git a/content/en/overview/core-features/traffic/condition-rule.md b/content/en/overview/core-features/traffic/condition-rule.md deleted file mode 100644 index 4fab76a60d2d..000000000000 --- a/content/en/overview/core-features/traffic/condition-rule.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -aliases: - - /en/overview/core-features/traffic/condition-rule/ -description: "" -linkTitle: Conditional Routing -title: Conditional Routing Rules -type: docs -weight: 1 ---- - - - -Conditional routing rules forward requests that meet specific conditions to a subset of destination instances. The rules match the request parameters of incoming traffic, and requests that meet the matching criteria are forwarded to a subset that contains a specific list of instance addresses. - -Here is an example of a conditional routing rule. - -Based on the following example rule, all invocations of the `getComment` method in the `org.apache.dubbo.samples.CommentService` service will be forwarded to a subset of addresses marked with `region=Hangzhou`. - - ```yaml - configVersion: v3.0 - scope: service - force: true - runtime: true - enabled: true - key: org.apache.dubbo.samples.CommentService - conditions: - - method=getComment => region=Hangzhou - ``` - - You can refer to specific example code for conditional routing [here](https://github.com/apache/dubbo-samples/tree/master/4-governance/dubbo-samples-configconditionrouter/src/main/java/org/apache/dubbo/samples/governance). -## ConditionRule -The body of a conditional routing rule defines the target service or application on which the routing rule will take effect, the traffic filtering conditions, and the behaviors in certain specific scenarios. - -| Field | Type | Description | Required | -| --- | --- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| --- | -| configVersion | string | The version of the condition rule definition, currently available version is `v3.0` | Yes | -| scope | string | Supports `service` and `application` scope rules. | Yes | -| key | string | The identifier of the target service or application that this rule is about to apply to.

- If `scope:service`is set, then `key`should be specified as the Dubbo service key that this rule targets to control.
- If `scope:application` is set, then `key`should be specified as the name of the application that this rule targets to control, application should always be a Dubbo Consumer. | Yes | -| enabled | bool | Whether enable this rule or not, set `enabled:false` to disable this rule. | Yes | -| conditions | string[] | The condition routing rule definition of this configuration. Check [Condition](./#condition) for details | Yes | -| force | bool | The behavior when the instance subset is empty after routing. `true` means return no provider exception while `false` means ignore this rule. | No | -| runtime | bool | Whether run routing rule for every rpc invocation or use routing cache if available. | No | - -## Condition - -The `Condition` serves as the body of a conditional routing rule and is of type string with a composite structure, such as `method=getComment => region=Hangzhou`. Here: - -* The conditions before the `=>` symbol indicate the request parameter matching conditions. The specified `matching conditions` are compared with the consumer's request context (URL) or even method parameters. When the consumer satisfies the matching conditions, the address subset filtering rules following the conditions will be applied to the consumer. -* The conditions after the `=>` symbol represent the address subset filtering conditions. The specified `filtering conditions` are compared with the provider instance addresses (URLs). The consumer can only access instances that meet the filtering conditions, ensuring that traffic is only sent to the subset of addresses that meet the conditions. - * If the matching conditions are empty, it means the rule applies to all requests, for example:`=> status != staging` - * If the filtering conditions are empty, it denies access from the corresponding requests, for example: `application = product =>` - -### Matching/Filtering Conditions - -**Parameter Support** -* Service invocation context, such as interface, method, group, version, etc. -* Request context, such as attachments[key] = value. -* Method parameters, such as arguments[0] = tom. -* Fields in the URL itself, such as protocol, host, port, etc. -* Additional parameters on the URL, such as application, organization, etc. -* Supports developer-defined extensions. - -**Condition Support** -* The equal sign (=) represents "match," for example: method = getComment. -* The not-equal sign (!=) represents "not match," for example: method != getComment. - -**Value Support** -* Multiple values separated by commas (,), for example: host != 10.20.153.10,10.20.153.11. -* Ending with an asterisk () denotes wildcard matching, for example: host != 10.20.. -* Starting with a dollar sign ($) indicates referencing consumer parameters, for example: region = $region. -* Integer value ranges, for example: userId = 1~100, userId = 101~. -* Supports developer-defined extensions. diff --git a/content/en/overview/core-features/traffic/configuration-rule.md b/content/en/overview/core-features/traffic/configuration-rule.md deleted file mode 100644 index 2572a54a7a1b..000000000000 --- a/content/en/overview/core-features/traffic/configuration-rule.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: docs -title: "动态配置规则" -linkTitle: "动态配置" -weight: 40 -description: "" ---- diff --git a/content/en/overview/core-features/traffic/mesh-rule.md b/content/en/overview/core-features/traffic/mesh-rule.md deleted file mode 100644 index ae020f1c73c1..000000000000 --- a/content/en/overview/core-features/traffic/mesh-rule.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "基于服务网格的路由规则" -linkTitle: "服务网格" -weight: 50 -description: "" ---- - diff --git a/content/en/overview/core-features/traffic/script-rule.md b/content/en/overview/core-features/traffic/script-rule.md deleted file mode 100644 index 688edcde229c..000000000000 --- a/content/en/overview/core-features/traffic/script-rule.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "脚本路由规则" -linkTitle: "脚本路由" -weight: 30 -description: "" ---- - diff --git a/content/en/overview/core-features/traffic/tag-rule.md b/content/en/overview/core-features/traffic/tag-rule.md deleted file mode 100644 index aa8f9eceb0eb..000000000000 --- a/content/en/overview/core-features/traffic/tag-rule.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "标签路由规则" -linkTitle: "标签路由" -weight: 20 -description: "" ---- - diff --git a/content/en/overview/demo/_index.md b/content/en/overview/demo/_index.md index df6c58e4d9e0..52a64b0f67b1 100644 --- a/content/en/overview/demo/_index.md +++ b/content/en/overview/demo/_index.md @@ -1,6 +1,6 @@ --- title: "Demo" -layout: "shortcodes/blocks/demo-en" +layout: "shortcodes/blocks/demo-zh" toc_hide: true --- - {{< blocks/demo-en >}} + {{< blocks/demo-zh >}} diff --git a/content/en/overview/home/_index.md b/content/en/overview/home/_index.md new file mode 100644 index 000000000000..faa0410eae51 --- /dev/null +++ b/content/en/overview/home/_index.md @@ -0,0 +1,72 @@ +--- +aliases: + - /zh/overview/home/ +content: + - 快速开始: + - description: "" + links: + - '[为什么需要 Dubbo](../what/)' + - '[概念与架构](../what/overview/)' + - '[对比 gRPC、Spring Cloud、Istio](../what/xyz-difference/)' + - '[核心特性](../what/advantages/)' + name: 了解 Dubbo + - description: "" + links: + - '[Java 微服务开发](../quickstart/java/)' + - '[Go 微服务开发](../quickstart/go/)' + - '[Rust 微服务开发](../quickstart/rust/)' + - '[Node.js 微服务开发](https://github.com/apache/dubbo-js)' + name: 尝试使用 Dubbo 开发微服务 + - name: "跟随示例学习 Dubbo" + description: "" + links: + - "[开发服务](../tasks/develop/)" + - "[部署服务](../tasks/deploy/)" + - "[流量管控](../tasks/traffic-management/)" + - "[观测服务](../tasks/observability/)" + - "[通信协议](../tasks/protocols/)" + - "[常见问题诊断](../tasks/troubleshoot/)" + - name: "生产环境的 Dubbo 微服务生态" + description: "" + links: + - "[服务发现&配置&元数据中心](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/)" + - "[HTTP 网关](../tasks/ecosystem/gateway/)" + - "[保证数据一致性](../tasks/ecosystem/transaction/)" + - "[Tracing 全链路追踪](../tasks/observability/tracing/)" + - "[自定义扩展](../tasks/extensibility/)" + - name: "SDK 参考手册" + description: "" + links: + - "[Java 参考手册](../mannual/java-sdk/)" + - "[Golang 参考手册](../mannual/golang-sdk/)" + - "[Rust 参考手册](../mannual/rust-sdk//)" + - "[Node 参考手册](https://github.com/apache/dubbo-js)" + - name: "关心 Dubbo3" + description: "" + links: + - "[Dubbo3 概述](../what/overview/)" + - "[gRPC & HTTP/2 通信协议](../reference/protocols/triple/)" + - "[应用级服务发现](../core-features/service-discovery/)" + - "[平滑迁移](../../docs3-v2/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide)" +description: "Apache Dubbo 是一款支持多语言的、易用的 web 和 rpc 框架,同时为构建企业级微服务提供服务发现、流量治理、可观测、认证鉴权等能力、工具与最佳实践。" +hide_feedback: true +hide_summary: true +linkTitle: 主页 +main_menu: true +toc_hide: true +menu: + main: + name: 文档 + weight: 1 +no_list: true +noedit: true +title: Dubbo 文档 +type: docs +weight: 1 +--- + +请跟随以下内容,快速了解 Apache Dubbo 的功能、特点与最佳实践吧! +
+
+ +{{% docs/document_box %}} diff --git a/content/en/overview/mannual/Golang.md b/content/en/overview/mannual/Golang.md deleted file mode 100755 index b8024ee9d030..000000000000 --- a/content/en/overview/mannual/Golang.md +++ /dev/null @@ -1,14 +0,0 @@ - ---- -type: docs -title: "Golang SDK" -linkTitle: "Golang" -description: "" -weight: 2 -manualLinkTarget: _blank -manualLinkRelref: ../../docs3-v2/golang-sdk/ -_build: { render: link } ---- - - - diff --git a/content/en/overview/mannual/Java.md b/content/en/overview/mannual/Java.md deleted file mode 100644 index d8afd3a153b2..000000000000 --- a/content/en/overview/mannual/Java.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -type: docs -title: "Java SDK" -linkTitle: "Java" -description: "" -weight: 1 -manualLinkRelref: ../../docs3-v2/java-sdk/ -manualLinkTarget: _blank -_build: { render: link } ---- - - - diff --git a/content/en/overview/mannual/Rust.md b/content/en/overview/mannual/Rust.md deleted file mode 100644 index b722e92f3180..000000000000 --- a/content/en/overview/mannual/Rust.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -type: docs -title: "Rust SDK" -linkTitle: "Rust" -description: "" -weight: 3 -manualLinkRelref: ../../docs3-v2/rust-sdk/ -manualLinkTarget: _blank -_build: { render: link } ---- - - - diff --git a/content/en/overview/mannual/_index.md b/content/en/overview/mannual/_index.md index 0d037c883210..b2af438234a2 100755 --- a/content/en/overview/mannual/_index.md +++ b/content/en/overview/mannual/_index.md @@ -1,50 +1,83 @@ - --- -type: docs -title: "SDK Manual" -linkTitle: "SDK Manual" -weight: 5 +aliases: + - /zh/overview/mannual/ + - /zh/docs3-v2/ + - /zh-cn/docs3-v2/ +always_unfold: true +description: Dubbo SDK 用户手册 +feature: + description: | + 提供 Java、Golang、Rust、Node.js、Python 等多语言 SDK 实现,支持基于 IDL 的跨语言服务定义和基于 Protobuf、Json 的数据编码 + title: 多语言 SDK +linkTitle: 用户手册 no_list: true +title: Dubbo SDK 用户手册 +type: docs +weight: 6 --- +> 本文档基于 Dubbo3 编写,由于 Dubbo3 完全兼容 2.7 版本用法,因此文档中的通用功能(除 3.x 版本特有功能外)同样适用于 2.7 版本用户。 +> +> 点此可查看 老版本文档 +> + {{< blocks/section color="white" height="auto">}}
-
- -
-
-
-
-

- Java SDK -

-

Java SDK

-
+
+
+
+
+

+ Java SDK +

+

Dubbo Java SDK 手册

-
-
-
-

- Golang SDK -

-

Golang SDK

-
+
+
+
+
+

+ Go SDK +

+

Dubbo Golang SDK 手册

-
-
-
-

- Rust SDK -

-

Rust SDK

-
+
+
+
+
+

+ Node.js +

+

Dubbo Node.js SDK 手册

-
+
+
+
+

+ Web SDK +

+

Dubbo Web SDK 手册

+
+
+
+
+
+
+

+ Rust SDK +

+

Dubbo Rust SDK 手册

+
+
+
+
+
{{< /blocks/section >}} diff --git a/content/en/overview/mannual/control-plane/_index.md b/content/en/overview/mannual/control-plane/_index.md new file mode 100644 index 000000000000..8421fd1f3f8d --- /dev/null +++ b/content/en/overview/mannual/control-plane/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/overview/reference/admin/ + - /zh-cn/overview/reference/admin/ +description: "" +linkTitle: 控制面 +title: Admin 控制台操作手册 +type: docs +weight: 20 +--- diff --git a/content/en/overview/mannual/control-plane/architecture.md b/content/en/overview/mannual/control-plane/architecture.md new file mode 100644 index 000000000000..d6b1eb5565b0 --- /dev/null +++ b/content/en/overview/mannual/control-plane/architecture.md @@ -0,0 +1,296 @@ +--- +aliases: + - /zh/overview/reference/admin/architecture/ + - /zh-cn/overview/reference/admin/architecture/ +description: "" +linkTitle: 架构与安装 +no_list: true +title: Admin 整体架构与安装步骤 +type: docs +weight: 1 +working_in_progress: true +--- + +回顾 [Dubbo 服务治理体系的总体架构](../../../what/overview/),Admin 是服务治理控制面中的一个核心组件,负责微服务集群的服务治理、可视化展示等。 + +## Admin 部署架构 + +![admin-core-components.png](/imgs/v3/reference/admin/admin-core-components.png) + +总体上来说,Admin 部署架构分为以下几个部分: +* Admin 主进程,包括服务发现元数据管理、可视化控制台、安全认证策略管控、其他定制化服务治理能力等组件。 +* 强依赖组件,包括 Mysql 数据库、注册/配置/元数据中心(可以是 Kubernetes、Nacos、Zookeeper 等) +* 可选依赖组件,包括 Prometheus、Grafana、Zipkin 等 + +## 安装 Admin + +### Dubboctl 安装 +#### Download +当前Dubboctl未正式发行,可按以下方式进行尝试。 +拉取Dubbo Admin并编译Dubboctl +```shell +git clone https://github.com/apache/dubbo-admin.git +cd dubbo-admin/cmd/dubboctl +go build -o dubboctl . +``` + +将 dubboctl 放入可执行路径 +```shell +ln -s dubbo-admin/cmd/dubboctl/dubboctl /usr/local/bin/dubboctl +``` +#### Install +安装过程会依次: + +1. 将用户自定义的配置profile以及set参数覆盖于默认profile,得到最终的profile +```yaml +# default profile +apiVersion: dubbo.apache.org/v1alpha1 +kind: DubboOperator +metadata: + namespace: dubbo-system +spec: + profile: default + namespace: dubbo-system + componentsMeta: + admin: + enabled: true + grafana: + enabled: true + repoURL: https://grafana.github.io/helm-charts + version: 6.52.4 + nacos: + enabled: true + zookeeper: + enabled: true + repoURL: https://charts.bitnami.com/bitnami + version: 11.1.6 + prometheus: + enabled: true + repoURL: https://prometheus-community.github.io/helm-charts + version: 20.0.2 + skywalking: + enabled: true + repoURL: https://apache.jfrog.io/artifactory/skywalking-helm + version: 4.3.0 + zipkin: + enabled: true + repoURL: https://openzipkin.github.io/zipkin + version: 0.3.0 +``` +建议使用自定义profile进行配置,在componentsMeta中开启或关闭组件,在components下配置各组件。其中components下各组件的配置值都是helm chart的values,各组件的具体配置请参考: +Grafana: https://github.com/grafana/helm-charts/blob/main/charts/grafana/README.md +Zookeeper: https://github.com/bitnami/charts/tree/main/bitnami/zookeeper/#installing-the-chart +Prometheus: https://github.com/prometheus-community/helm-charts/tree/main/charts +Skywalking: https://github.com/apache/skywalking-kubernetes/blob/master/chart/skywalking/README.md +Zipkin: https://github.com/openzipkin/zipkin-helm +```yaml +# customization profile +apiVersion: dubbo.apache.org/v1alpha1 +kind: DubboOperator +metadata: + namespace: dubbo-system +spec: + profile: default + namespace: dubbo-system + componentsMeta: + admin: + enabled: true + grafana: + enabled: true + version: 6.31.0 + prometheus: + enabled: false + components: + admin: + replicas: 3 + grafana: + testFramework: + enabled: false +``` +2. 根据profile拉取所需组件并生成manifest,目前Admin,Nacos已在本地,无需拉取;Grafana,Zookeeper,Prometheus,Skywalking,Zipkin将从官方chart库拉取,具体地址和版本可见上方default profile +3. 将manifest应用于k8s集群 +```shell +dubboctl manifest install # 使用默认 manifests 安装 + +# or + +dubboctl manifest generate | kubectl apply -f - +``` + +```shell +dubboctl install --set spec.components.admin.replicas=2 # 设置组件的配置 +``` + +```shell +dubboctl install --set spec.componentsMeta.admin.enabled=true, spec.componentsMeta.grafana.enabled=false +# 开启或关闭组件 +``` + +```shell +dubboctl install --set spec.componentsMeta.grafana.repoURL=https://grafana.github.io/helm-charts, spec.componentsMeta.grafana.version=6.31.0 +# 设置需远程拉取组件的仓库地址与版本 +``` + +检查安装效果 +```shell +kubectl get pod -n dubbo-system +``` + +#### 打开 Admin 控制台 +```shell +kubectl port-forward svc/dubbo-admin -n dubbo-system 38080:38080 +``` + +打开浏览器,访问: `http://127.0.0.1:38080/` + +### Helm 安装 + +获取图表 +``` +helm repo add https://charts.bitnami.com/bitnami +helm repo add https://prometheus-community.github.io/helm-charts +helm repo add https://grafana.github.io/helm-charts +helm repo add https://apache.jfrog.io/artifactory/skywalking-helm +helm repo add https://openzipkin.github.io/zipkin +``` +安装 zookeeper +```bash +helm install zookeeper bitnami/zookeeper -n dubbo-system +``` + +安装 prometheus +```bash +helm install prometheus prometheus-community/prometheus -n dubbo-system +``` + +安装 grafana +```bash +helm install grafana grafana/grafana -n dubbo-system +``` + +安装 skywalking +```bash +helm install skywalking skywalking/skywalking -n dubbo-system +``` + +安装 zipkin +``` +helm install zipkin openzipkin/zipkin -n dubbo-system +``` + +检查安装状态 +```shell +helm ls -n dubbo-system ;kubectl get pods -n dubbo-system --output wide +``` + +### VM 安装 +#### Download +下载 Dubbo Admin 发行版本 +```shell +curl -L https://dubbo.apache.org/installer.sh | VERSION=0.1.0 sh - +# Admin 要组织好发行版本 +``` + +将 dubboctl 放入可执行路径 +```shell +ln -s dubbo-admin-0.1.0/bin/dubbo-admin /usr/local/bin/dubbo-admin +``` +#### Run +```shell +dubbo-admin run -f override-configuration.yml +``` +## 配置手册 (Configuration) +配置用于控制 dubbo-admin 的行为 + + +```yaml +# Environment type. Available values are: "kubernetes" or "universal" +environment: universal # ENV: DUBBO_ENVIRONMENT +# Mode in which Dubbo CP is running. Available values are: "standalone", "global", "zone" +mode: standalone # ENV: DUBBO_MODE + +# Resource Store configuration +store: + # Type of Store used in the Control Plane. Available values are: "kubernetes", "postgres" or "memory" + type: memory # ENV: DUBBO_STORE_TYPE + + # Kubernetes Store configuration (used when store.type=kubernetes) + kubernetes: + # Namespace where Control Plane is installed to. + systemNamespace: dubbo-system # ENV: DUBBO_STORE_KUBERNETES_SYSTEM_NAMESPACE + + # Postgres Store configuration (used when store.type=postgres) + mysql: + # Host of the Postgres DB + host: 127.0.0.1 # ENV: DUBBO_STORE_POSTGRES_HOST + # Port of the Postgres DB + port: 15432 # ENV: DUBBO_STORE_POSTGRES_PORT + # User of the Postgres DB + user: dubbo # ENV: DUBBO_STORE_POSTGRES_USER + # Password of the Postgres DB + password: dubbo # ENV: DUBBO_STORE_POSTGRES_PASSWORD + # Database name of the Postgres DB + dbName: dubbo # ENV: DUBBO_STORE_POSTGRES_DB_NAME + # Connection Timeout to the DB in seconds + connectionTimeout: 5 # ENV: DUBBO_STORE_POSTGRES_CONNECTION_TIMEOUT + # Maximum number of open connections to the database + # `0` value means number of open connections is unlimited + maxOpenConnections: 50 # ENV: DUBBO_STORE_POSTGRES_MAX_OPEN_CONNECTIONS + # Maximum number of connections in the idle connection pool + # <0 value means no idle connections and 0 means default max idle connections + maxIdleConnections: 50 # ENV: DUBBO_STORE_POSTGRES_MAX_IDLE_CONNECTIONS + # TLS settings + tls: + # Mode of TLS connection. Available values are: "disable", "verifyNone", "verifyCa", "verifyFull" + mode: disable # ENV: DUBBO_STORE_POSTGRES_TLS_MODE + # Path to TLS Certificate of the client. Used in verifyCa and verifyFull modes + certPath: # ENV: DUBBO_STORE_POSTGRES_TLS_CERT_PATH + # Path to TLS Key of the client. Used in verifyCa and verifyFull modes + keyPath: # ENV: DUBBO_STORE_POSTGRES_TLS_KEY_PATH + # Path to the root certificate. Used in verifyCa and verifyFull modes. + caPath: # ENV: DUBBO_STORE_POSTGRES_TLS_ROOT_CERT_PATH + # MinReconnectInterval controls the duration to wait before trying to + # re-establish the database connection after connection loss. After each + # consecutive failure this interval is doubled, until MaxReconnectInterval + # is reached. Successfully completing the connection establishment procedure + # resets the interval back to MinReconnectInterval. + minReconnectInterval: "10s" # ENV: DUBBO_STORE_POSTGRES_MIN_RECONNECT_INTERVAL + # MaxReconnectInterval controls the maximum possible duration to wait before trying + # to re-establish the database connection after connection loss. + maxReconnectInterval: "60s" # ENV: DUBBO_STORE_POSTGRES_MAX_RECONNECT_INTERVAL +server: + port: 38080 +registry: + address: xxx +metadata-center: + address: xxx +config-center: + address: xxx +external-services: + prometheus: + # Prometheus service name is "metrics" and is in the "telemetry" namespace + # http://prometheus.:9090 + url: "http://metrics.telemetry:9090/" + tracing: + # Enabled by default. Kiali will anyway fallback to disabled if + # Jaeger is unreachable. + enabled: true + # Jaeger service name is "tracing" and is in the "telemetry" namespace. + # Make sure the URL you provide corresponds to the non-GRPC enabled endpoint + # if you set "use_grpc" to false. + in_cluster_url: 'http://tracing.telemetry:16685/jaeger' + use_grpc: true + # Public facing URL of Jaeger + url: 'http://my-jaeger-host/jaeger' + grafana: + enabled: true + # Grafana service name is "grafana" and is in the "telemetry" namespace. + in_cluster_url: 'http://grafana.telemetry:3000/' + # Public facing URL of Grafana + url: 'http://my-ingress-host/grafana' + +# 更多配置 +``` +#### 打开 Admin 控制台 + +打开浏览器,访问: `http://127.0.0.1:38080/` diff --git a/content/en/overview/mannual/control-plane/documentation.md b/content/en/overview/mannual/control-plane/documentation.md new file mode 100644 index 000000000000..e05ebf8b72fb --- /dev/null +++ b/content/en/overview/mannual/control-plane/documentation.md @@ -0,0 +1,17 @@ +--- +aliases: + - /zh/overview/reference/admin/documentation/ + - /zh-cn/overview/reference/admin/documentation/ +description: "" +linkTitle: 文档管理 +no_list: true +toc_hide: true +title: Admin 文档管理功能介绍 +type: docs +weight: 6 +working_in_progress: true +--- + +// TBD + + diff --git a/content/en/overview/mannual/control-plane/mock.md b/content/en/overview/mannual/control-plane/mock.md new file mode 100644 index 000000000000..582960435e70 --- /dev/null +++ b/content/en/overview/mannual/control-plane/mock.md @@ -0,0 +1,176 @@ +--- +aliases: + - /zh/overview/reference/admin/mock/ + - /zh-cn/overview/reference/admin/mock/ +description: "" +linkTitle: 服务Mock +no_list: true +title: Admin 服务 Mock 功能简介 +type: docs +weight: 4 +working_in_progress: true +--- + +Mock 功能是设计用来提升微服务研发与测试效率的,它可以短路 Consumer 侧发起的远程调用,提前返回预先设定好的 Mock 值,这样即使在没有 Provider 可用的情况下,消费端也能正常的推进开发、测试进程。除此之外,mock 也可用于快速模拟负责返回值的测试数据、模拟服务端异常等场景 + +需要注意的是,Mock 能力仅限用于测试环境,应避免将其用于生产环境。 + +# 设计背景 +在跨团队或是多应用开发时,在前期开发中往往会出现依赖的服务还未开发完成的情况,这样就会导致流程的阻塞,影响研发效率。基于这种情况,Dubbo Admin 提供了 mock 能力来解耦 Consumer 与 Provider 之间的依赖,以确保在 Provider 未就绪的情况下 Consumer 仍能正常开展测试,提高研发效率。 + +Dubbo 框架本身设计有服务降级(有时也称为 mock)能力,通过配置 `org.apache.dubbo.config.ReferenceConfig` 的 mock 字段(可设置为true或是对应接口的Mock实现)或动态配置规则,此时就可以启动服务降级能力。这种服务降级能力是为生产环境的限流降级准备的,虽然也可以用于本地开发测试场景,但灵活度并不高,基于提升开发效率的根本诉求,我们设计了基于 Admin 的服务降级能力。 + +Dubbo Admin 服务 mock 是一种更为轻量和便捷实现方式,主要用于开发测试阶段的,目标是提升微服务场景下的整体研发效率。需求详见:[Dubbo Admin Mock需求](https://github.com/apache/dubbo-admin/issues/757)。 + +## 架构设计 + +![admin-mock-architecture.png](/imgs/v3/reference/admin/console/mock-architecture.png) + +**实现 Mock 能力,Dubbo 框架与 Admin 侧要支持的能力** + +* Dubbo Admin + * 规则管理 + * 规则新增 + * 规则查询 + * 规则修改 + * 规则删除 + * 请求历史记录 + * Mock 请求数据查询 + * MockService Provider + * 根据规则生成 Mock 数据 + * 响应 Consumer Mock 请求 + * 保存请求和返回数据 +* Dubbo + * 根据 mock 开关配置,转发请求到 Admin 注册的 MockService + * 处理 mock 返回值并转换为匹配方法签名的强类型数据 + +**Mock 请求原理时序图** + +![admin-mock-workflow.png](/imgs/v3/reference/admin/console/mock-workflow.png) + +## 使用方式 + +1. 在 Consumer 应用中添加依赖 + + 开启 Mock 前,请确保在消费端应用中引入以下依赖: + + ```xml + + org.apache.dubbo.extensions + dubbo-mock-admin + ${version} + + ``` + + > 查看 [dubbo-mock-admin 的可用版本](/zh-cn/download/spi-extensions/) + +2. 配置 `-Denable.dubbo.admin.mock=true` 参数开启 Mock 并重启进程 +3. 打开 Admin 配置 Mock 规则 + + 用户可以通过在控制台上指定需要被 mock 的消费端IP、服务名和方法和具体的 mock 行为,实现对调用结果的 mock。 + + ![admin-mock](/imgs/v3/reference/admin/console/mock-rule-screenshot.png) + + 一些支持的规则类型与示例 + + ``` + 数字类型:123 + + 字符串:"hello, world!" + + 数组、列表:[1, 2, 3] + + 枚举:"ENUM_TYPE" + + Map、对象: + { + "prop1": "value1", + "prop2": ["a", "b", "c"] + } + + null: null + ``` + +4. 此时,消费端再次发起远程调用,就会得到预期 Mock 返回值。 + + > 注意事项 + > 1. Mock 仅限用于测试开发环境,因此为了确保核心依赖的稳定性,社区没有将 mock 组件打包在核心框架包中,用户可以自行决策是否将其作为应用的默认依赖在公司内推广 + > 2. 即使添加了 mock 二进制依赖,mock 功能也不会默认开启,需要设置 `-Denable.dubbo.admin.mock=true` 后才能开启。 + +## 实现原理 + +Consumer 调用发起的调用会被本地的 MockServiceFilter 拦截,如果 mock 开关开启,则 MockServiceFilter 将请求转发到 MockService (由 Dubbo Admin 发布的服务),MockService 根据请求的服务、方法等查询用户预先配置的 mock 规则,如果查询到则返回规则中的 mock 值,Consumer 收到 mock 值后调用成功返回。 + +### Mock 返回值如何定义? + +当前 Admin 支持录入 JSON 或者基本类型数据,如: + +* 返回数字值 (当方法签名返回值是数字类型) + +``` +123 +``` + +* 返回字符串 (当方法签名返回值是字符串类型) +``` +"hello, world!" +``` + +* 返回 JSON (当方法签名返回值是 Map 或对象类型) +``` +{ + "prop1": "value1", + "prop2": ["a", "b", "c"] +} +``` + +* 返回数组 (当方法签名返回值是数组或列表) +``` +[1, 2, 3] +``` + +### 消费端如何发起 MockService 调用? + +`dubbo-mock-admin` 将为消费端引入 MockServiceFilter 请求拦截器,如果用户打开 mock 开关,那么 Filter 会将请求转发到 Admin MockService 服务。 + +### Mock 值如何转换为原始类型值? + +MockService 支持返回标准 JSON 格式或者基本类型数据,消费端会基于 Dubbo 内置类型转换器将 JSON 等值转为原始对象类型。 + +### 未来优化点 +* 保存 Mock 开关到配置中心,用户可以通过 Admin 动态控制开关。 +* 开启 Mysql 数据库链接池 + +### 表结构设计 +Admin 依赖 Mysql 数据库存储用户配置的 mock 规则,具体的表结构设计如下。 + +#### Mock Rule + +```sql +CREATE TABLE `mock_rule` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', + `service_name` varchar(255) DEFAULT NULL COMMENT '服务名', + `method_name` varchar(255) DEFAULT NULL COMMENT '方法名', + `rule` text NULL DEFAULT COMMENT '规则', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='服务mock方法表'; +``` +#### Mock Log + +```sql +CREATE TABLE `mock_log` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id', + `method_id` int(11) DEFAULT NULL COMMENT '规则id', + `request` text COMMENT '请求数据', + `response` text COMMENT '返回值', + `created_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='mock请求记录表'; +``` + + + + diff --git a/content/en/overview/mannual/control-plane/search.md b/content/en/overview/mannual/control-plane/search.md new file mode 100644 index 000000000000..031f5289c8b9 --- /dev/null +++ b/content/en/overview/mannual/control-plane/search.md @@ -0,0 +1,55 @@ +--- +aliases: + - /zh/overview/reference/admin/search/ + - /zh-cn/overview/reference/admin/search/ +description: "" +linkTitle: 文档查询 +title: Admin 服务查询 +type: docs +weight: 2 +working_in_progress: true +--- + +Admin 支持可视化的展示 Dubbo 微服务集群的状态,方便用户从全局掌握集群的应用、服务和实例分布,Admin 还可以通过查询的方式了解某一个服务更详细的信息: +* 首页集群大盘,展示集群应用、服务、示例的总体分布,集群总体流量情况等 +* 支持根据应用名、服务名(可包含版本&分组)、实例 IP 查询详细信息 +* 支持服务名/应用名的自动补全 +* 支持查看单条服务实例的详情 + +## 首页大盘 + +![admin-dashboard](/imgs/v3/reference/admin/console/dashboard.png) + +## 根据 Dubbo 服务名查询 + +精确输入`接口名:版本` 查询服务 + +![admin-search-service](/imgs/v3/reference/admin/console/admin-search-service.png) + +通过 `*` 通配符模糊查询服务 + +![admin-search-service2](/imgs/v3/reference/admin/console/admin-search-service.png) + +## 根据应用名查询 + +输入应用名查询某应用关联的所有服务(包含提供和消费的服务) + +![admin-search-application](/imgs/v3/reference/admin/console/admin-search-application.png) + +## 根据实例 IP 名查询 + +输入实例 IP 查询某实例关联的所有服务(包含提供和消费的服务) + +![admin-search-ip](/imgs/v3/reference/admin/console/admin-search-ip.png) + +> 支持基于端口过滤服务 + +## 查看服务实例详情 + +在服务列表点击 `详情` 查看服务详细情况 + +![admin-search-service-detail](/imgs/v3/reference/admin/console/admin-search-service-detail.png) + + + + diff --git a/content/en/overview/mannual/control-plane/test.md b/content/en/overview/mannual/control-plane/test.md new file mode 100644 index 000000000000..ce4a83b3356c --- /dev/null +++ b/content/en/overview/mannual/control-plane/test.md @@ -0,0 +1,193 @@ +--- +aliases: + - /zh/overview/reference/admin/test/ + - /zh-cn/overview/reference/admin/test/ +description: "" +linkTitle: 服务测试 +no_list: true +title: Admin 服务测试功能简介 +type: docs +weight: 3 +working_in_progress: true +--- + +服务测试功能通常提供给 Dubbo 服务的开发者使用,用来对自己发布的服务进行自测。通过在 Admin 控制台上模拟真实的消费端进程,对服务提供者发起调用,并验证调用结果是否符合预期。 + +## 使用方式 + +### 准备用例 +1. 启动用例 + + 可以参考 [快速开始](../../../quickstart/java/) 启动一个简单的 Dubbo 服务,对于服务测试来说,只需要启动 provider 即可。 + +2. 查询服务 + + 完成服务端部署后,可以到 Admin 的 `服务测试` 页面查询对应的服务: + + ![testSearch](/imgs/blog/admin/testSearch.jpg) + + 这里的信息和元数据类似,包含方法名,参数类型和返回值信息,点击右边的标签就可以进入服务测试页面 + +### 执行服务测试 + +服务测试页面包含了两个 json 编辑器,参数类型的信息都是以 json 格式保存。 + +如以下示例所示,在左侧编辑器中填入对应的参数值(本例中数类型是 `String` ),填写完成后点击 `执行` 即可对服务端发起调用,调用结果展示在右边的编辑器中。 + +![testSuccess](/imgs/blog/admin/testSuccess.jpg) + +如果调用失败,会显示详细的失败原因,下面来看一下调用失败的例子: + +![testFail](/imgs/blog/admin/testFail.jpg) + +本例中,先关掉 Dubbo 服务提供者的进程,再执行服务测试,可以看到返回的结果是`找不到服务提供者`的异常。和普通调用一样,业务和框架的异常都会返回在结果中,方便业务排查。 + +### 复合类型参数的填写 + +考虑 `UserService` 中的以下方法和类型: + +```java +//org.apache.dubbo.demo.api.UserService +Result getUser(String name, UserInfoDO userInfoDO); +``` +```java +public class UserInfoDO { + private int id; + private LocationDO locationDO; + private DepartmentDO departmentDO; + + @Override + public String toString() { + return "UserInfoDO{" + + "id=" + id + + ", locationDO=" + locationDO.toString() + + ", departmentDO=" + departmentDO.toString() + + '}'; + } +} +``` + +```java +public class DepartmentDO { + + private String departName; + private LocationDO departLocation; + + @Override + public String toString() { + return "DepartmentDO{" + + "departName='" + departName + '\'' + + ", departLocation=" + departLocation.toString() + + '}'; + } +} +``` + +```java +public class LocationDO { + private String address; + private int postNum; + + @Override + public String toString() { + return "LocationDO{" + + "address='" + address + '\'' + + ", postNum=" + postNum + + '}'; + } +} +``` +参数是比较复杂的符合类型参数,服务测试的时候,会逐层展开填写每一个field的值,如下图所示: +![complex](/imgs/blog/admin/complex.jpg) +同样可以调用成功并且返回结果 + +## 原理 + +### 数据来源 + +服务测试中,最重要的就是完整的方法签名信息,和参数的类型信息,有了这些信息才能够一步步填入每个参数的值,拼装出完整的服务消费者。因此,使用服务测试的前提是在 Dubbo 中开启元数据中心(默认开启,Zookeeper、Nacos、Redis 等默认以注册中心做为元数据中心),Dubbo Admin 的方法签名和参数类型信息就是元数据中心来的: + +![medatada](/imgs/blog/admin/metadata.png) + +如图所示,服务端在运行的时候会将服务的元数据信息注册到元数据中心,格式如下: + +```json +{ + ... + "methods": [ + { + "name": "sayHello", + "parameterTypes": [ + "org.apache.dubbo.demo.model.User" + ], + "returnType": "org.apache.dubbo.demo.model.Result" + }, + ... + ], + "types": [ + { + "type": "char" + }, + { + "type": "long" + }, + { + "type": "org.apache.dubbo.demo.model.Result", + "properties": { + "msg": { + "type": "java.lang.String", + "properties": { + "value": { + "type": "char[]" + }, + "hash": { + "type": "int" + } + } + }, + "userName": { + "type": "java.lang.String", + "properties": { + "value": { + "type": "char[]" + }, + "hash": { + "type": "int" + } + } + } + } + }, + { + "type": "org.apache.dubbo.demo.model.User", + "properties": { + "id": { + "type": "java.lang.Long", + "properties": { + "value": { + "type": "long" + } + } + }, + "username": { + "type": "java.lang.Sring", + "properties": { + "value": { + "type": "char[]" + }, + "hash": { + "type": "int" + } + } + } + } + }, + ... + ] +} +``` +与服务测试相关的就是`methods`和`types`所包含的方法和类型信息,Dubbo Admin根据这些信息,将参数渲染到服务测试页面的Json Editor中,由用户来输入每个参数,每个成员变量的值。 + +### 泛化调用 + +有了参数类型,下一个问题就是怎么能够调用到服务端,在传统的Dubbo RPC调用中,客户端需要依赖服务端的API jar包 (参考 [Quick Start](https://github.com/apache/dubbo-samples/tree/master/1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-consumer) 中的消费端示例,这对于 Dubbo Admin 来说不太可能,因为服务的上下线是动态的,Dubbo Admin 无法动态增加 jar 包依赖,因此需要用到 Dubbo 中的[**泛化调用**](../../../mannual/java-sdk/advanced-features-and-usage/service/generic-reference/),指的是在没有服务端API接口的情况下,客户端直接通过 `GenericService` 接口来发起服务调用,返回值中的数据对象都用Map来表示。泛化调用在服务端不需要做特殊处理,只需要客户端发起即可。 diff --git a/content/en/overview/mannual/golang-sdk/_index.md b/content/en/overview/mannual/golang-sdk/_index.md new file mode 100755 index 000000000000..cfece42de572 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/ + - /zh-cn/docs3-v2/golang-sdk/ +description: Golang SDK 手册 +linkTitle: Golang SDK +title: Golang SDK +type: docs +weight: 2 +--- diff --git a/content/en/overview/mannual/golang-sdk/introduction.md b/content/en/overview/mannual/golang-sdk/introduction.md new file mode 100644 index 000000000000..61191e64c539 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/introduction.md @@ -0,0 +1,124 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/preface/ + - /zh-cn/docs3-v2/golang-sdk/preface/ + - /zh-cn/overview/mannual/golang-sdk/preface/ + - /zh-cn/overview/mannual/golang-sdk/preface/concept/ + - /zh-cn/overview/mannual/golang-sdk/preface/concept/protocol/ +description: Dubbo-go 框架 +linkTitle: 框架介绍 +title: 框架介绍 +type: docs +weight: 1 +--- + +## 什么是 dubbo-go +Dubbo-go 是 Apache Dubbo 的 go 语言实现,它完全遵循 Apache Dubbo 设计原则与目标,是 go 语言领域的一款优秀微服务开发框架。dubbo-go 提供: +* **API 与 RPC 协议**:帮助解决组件之间的 RPC 通信问题,提供基于 HTTP/1/2 的通信协议、streaming流式通信模型。 +* **丰富的微服务治理能力**:解决地址发现、流量管控、可观测性、全链路追踪、日志等微服务整体解决方案。 + +## 概念与架构 +以下是 dubbo-go 的整体架构图: +![dubbo-go architecture](/imgs/golang/architecture/arc.png) + +dubbo-go 总体上遵循 `框架内核+插件` 的的设计理念,左侧的 `框架内核` 定义了 dubbo-go 作为微服务框架的一些核心概念,右侧的 `插件` 部分则提供了核心概念扩展实现。 + +`框架内核` 可分为 4 个层次,从上到下依次为: +* API 层:dubbo-go 同时支持基于 IDL、interface/struct 的服务契约定义,兼顾跨语言与易用性诉求;支持基于纯 yaml 文件的微服务配置模式;提供了同步、异步、单次(unary)、流式(streaming) 等 RPC 通信与编码模型。 + +* 服务治理层:dubbo-go 内置了多维度的服务治理能力抽象,确保满足微服务开发与集群治理的核心诉求,这包括地址发现(Service Discovery)、负载均衡(Load Balancing)、可观测指标(Metrics)、流量管控(Traffic Management)、全链路追踪(Tracing)等。 + +* RPC 协议层:dubbo-go 实现的最核心的 RPC 协议是 - triple 协议,triple 可同时工作在 http1/2 之上 (支持 CURL 直接访问),兼容 gRPC;从设计上,dubbo-go 还提供了多协议发布服务的支持,你可以在一个进程内同时发布 triple、dubbo2、rest、jsonRPC 等多种不同通信协议的服务。 + +* 传输层:支持 HTTP1/2、TCP 传输层,兼顾性能与通用性,同时支持多种序列化方式。 + +`插件` 体系极大的丰富了 dubbo-go 功能与生态,社区内置提供了大量的内置扩展实现,同时,开发者可以非常容易的根据需求增加扩展实现。以下是一些典型的插件定义: + +* Protocol:dubbo-go 基于 protocol 插件内置提供了 triple、dubbo2、rest 等协议支持,通过扩展 protocol 可以为 dubbo-go 扩展更多协议 +* Service Discovery:支持 Nacos、Zookeeper、Polaris 等主流注册中心集成 +* Traffic Management:dubbo-go 支持 Dubbo 体系定义的流量规则,可以实现在运行期动态的调整服务行为如超时时间、重试次数、限流参数等,通过控制流量分布可以实现 A/B 测试、金丝雀发布、多版本按比例流量分配、条件匹配路由、黑白名单等 +* Metrics:提供 RPC 调用(RT、QPS、调用量、请求成功数、请求失败数、并发请求数等)、注册中心、元数据中心、配置中心交互统计等丰富的内置采集埋点,支持多维度的指标聚合 +* Logging:提供通用的日志采集接口定义,内置 Zap、Logrus 支持 +* Tracing:提供分布式链路追踪能力,通过此插件扩展可接入 Zipkin、Jaeger、Skywalking 等链路追踪系统。 + +下图是从内核源码视角,给出的框架核心组件以及组件之间的关联关系: + +![img](/imgs/docs3-v2/golang-sdk/concept/more/app_and_interface/dubbogo-concept.png) + +### RPC +#### Triple +基于 Dubbo 定义的 [triple 协议](/zh-cn/overview/reference/protocols/triple/),你可以轻松编写浏览器、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。作为 Apache Dubbo 多语言 RPC体系的一环,dubbo-go 提供了 triple 协议的完整实现,支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 API 来发布或调用这些服务。triple 协议让 dubbo-go 可以: +* **作为后端服务与 Dubbo 其他语言实现互通** +* **接收浏览器等标准 http 工具发起的请求** +* **与标准的 gRPC 体系互通** + +![dubbo多语言实现](/imgs/golang/architecture/language.png) + +请参考以下链接了解更多 dubbo-go 跨语言或跨产品的互通细节: +* [与 Dubbo 其他多语言体系互通 - 基于 triple+protobuf](../tutorial/interop-dubbo/) +* [与 Dubbo2 Java互通 - 基于 dubbo2+hessian2](../tutorial/interop-dubbo) +* [与 gRPC 体系互通](../tutorial/interop-grpc) + +#### 多协议支持 +除了 triple 协议之外,dubbo-go 支持更多的 RPC 协议和序列化方式: + +| 协议 | 协议名 (用于配置) | 序列化方式 | 默认序列化方式 | +| --------------- | ----------------- | :------------------------: | -------------- | +| Triple 【推荐】 | tri | pb/json/自定义 | pb | +| Dubbo | dubbo | hessian2 | hessian2 | +| jsonRPC | jsonrpc | json | json | +| REST | rest | json | json | + +#### Filter +如下图所示,filter 是一个类似 AOP 的请求拦截机制,每一次 RPC 请求都会被 filter 拦截 + +![dubbo多语言实现](/imgs/golang/architecture/filter.png) + +我们可以在 filter 实现中完成比如请求拦截、记录、预处理、后处理的事情。dubbo-go 的一些核心能力,比如超时时间、访问日志(ccesslog)、metrtics 等都是基于内置 filter 实现的。 + +#### Streaming + +![dubbo多语言实现](/imgs/golang/architecture/streaming.png) + +* Server streaming RPC:一次 server-streaming RPC 请求与 unary RPC 非常类似,不同之处在于,对于单次 client 请求 server 会返回一系列的流式响应。 + +* Client streaming RPC:一次 client-streaming RPC 请求与 unary RPC 非常类似,不同之处在于,client 会发送一系列的流式请求到 server,最终 server 针对所有收到的请求返回一条响应信息。 + +* Bidirectional streaming RPC:在双向流式 RPC 请求中,请求首先由 client 端发起,server 在收到请求信息(方法名、metadata等)后,可以选择立即发送 metadata 作为响应,或者一直等到 client 进一步发起流式请求数据。 + +### 服务治理 +dubbo-go 提供了完善的服务治理能力,包括地址发现、可观测、全链路追踪、流量管控等。你可以使用 dubbo-go 开发与管理微服务集群并实现与 Apache Dubbo 其他语言体系的互通。 + +#### 地址发现 +![img](/imgs/architecture.png) + +Dubbo-go 支持的注册中心类型如下,具体配置方式请参考使用教程 [地址发现](../tutorial/service-discovery/): + +| 注册中心 | 注册中心名(用于配置) | +| --------- | ---------------------- | +| Zookeeper | zookeeper | +| Nacos | nacos | +| Etcd | etcd | +| Polaris | polaris | + +#### 可观测 +dubbo-go 的可视化指标采集遵循 Apache Dubbo 定义的 [metrics 指标规范](/zh-cn/overview/reference/Metrics/standard_metrics/)。在实现 metrics 指标采集后,接下来就是如何可视化展示的问题,当前最常用的式导出到 Prometheus 并通过 Grafana 实现数据可视化展示。 + +具体启用方式请参考使用手册中的 [可视化观测](../tutorial/observability/)。 + +#### 全链路追踪 +dubbo-go 支持通过 Open Telemetry 接入 Zipkin、Jaeger、Skywalking 等全链路追踪系统。 + +具体启用方式请参考使用手册中的 [全链路追踪](../tutorial/tracing/)。 + +#### 流量管控 +dubbo-go 实现的流量治理规则完全遵循 Dubbo 框架设计的流量治理能力,可以通过以下链接了解更多详情: +* [Dubbo 流量治理规则设计](/zh-cn/overview/core-features/traffic/) +* [Dubbo 流量治理示例任务](/zh-cn/overview/tasks/traffic-management/) + + + + + + + diff --git a/content/en/overview/mannual/golang-sdk/quickstart/_index.md b/content/en/overview/mannual/golang-sdk/quickstart/_index.md new file mode 100755 index 000000000000..7e5d6fad4738 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/quickstart/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/quickstart/ + - /zh-cn/docs3-v2/golang-sdk/quickstart/ + - /zh/overview/quickstart/go/ + - /zh-cn/overview/quickstart/go/ +description: Dubbo-go 快速开始 +linkTitle: 快速开始 +title: 快速开始 +type: docs +weight: 2 +--- diff --git a/content/en/overview/mannual/golang-sdk/quickstart/microservices.md b/content/en/overview/mannual/golang-sdk/quickstart/microservices.md new file mode 100644 index 000000000000..8af303b021b5 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/quickstart/microservices.md @@ -0,0 +1,195 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/quickstart/ + - /zh-cn/docs3-v2/golang-sdk/quickstart/ +description: Dubbo-go 快速开始 +linkTitle: 开发微服务应用 +title: 开发微服务 +type: docs +weight: 2 +--- + +本示例演示了使用 dubbo-go 开发微服务应用,为应用增加包括服务发现、负载均衡、流量管控等微服务核心能力。 + +## 前置条件 +本示例我们继续使用 Protobuf 开发微服务应用,请参考 [开发 rpc server 和 rpc client](../rpc) 了解如何安装 protoc、protoc-gen-go-triple 等必须插件。 + +## 快速运行示例 +### 下载示例源码 +我们在 apache/dubbo-go-samples 仓库维护了一系列 dubbo-go 使用示例,用来帮助用户快速学习 dubbo-go 使用方式。 + +你可以 下载示例zip包并解压,或者克隆仓库: + +```shell +$ git clone --depth 1 https://github.com/apache/dubbo-go-samples +``` + +切换到快速开始示例目录: + +```shell +$ cd dubbo-go-samples/registry/nacos +``` + +### 启动 Nacos + +由于示例应用中启用了服务发现能力且使用 Nacos 作为注册中心,在运行示例之前需要先启动注册中心。请参考 [Nacos 本地安装](/zh-cn/overview/reference/integrations/nacos/) 了解如何快速安装和启动 Nacos。 + +### 运行 server +在 `go-server/cmd` 示例目录: + +运行以下命令,启动 server: + +```shell +$ go run server.go +``` + +使用 `cURL` 验证 server 正常启动: + +```shell +$ curl \ + --header "Content-Type: application/json" \ + --data '{"name": "Dubbo"}' \ + http://localhost:50051/greet.v1.GreetService/Greet + +Greeting: Hello world +``` + +### 运行 client + +打开一个新的 terminal,运行以下命令,启动 client + +```shell +$ go run client.go + +Greeting: Hello world +``` + +以上就是一个完整的 dubbo-go 微服务应用工作流程。 + +## 源码讲解 +关于 `dubbo-go-samples/registry/nacos` 示例源码,包括服务定义、代码生成、server/client 启动等均与上一篇 [rpc server & rpc client]() 类似,请点击以上链接查看具体解读。 + +**开发微服务最大的不同点在于:应用中增加了关于注册中心的配置,如下所示(以 server.go 为例):** + +```go +func main() { + ins, err := dubbo.NewInstance( + dubbo.WithName("dubbo_registry_nacos_server"), + dubbo.WithRegistry( + registry.WithNacos(), + registry.WithAddress("127.0.0.1:8848"), + ), + dubbo.WithProtocol( + protocol.WithTriple(), + protocol.WithPort(20000), + ), + ) + + srv, _ := ins.NewServer() + + greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{}) + + if err := srv.Serve(); err != nil { + logger.Error(err) + } +} +``` + +相比于开发 rpc 服务时我们直接声明 `server.NewServer(...)`,这里我们使用 `dubbo.newInstance(...)` 初始化了一些全局共享的微服务核心组件,包括应用名、注册中心、协议等: + +```go +ins, err := dubbo.NewInstance( + dubbo.WithName("dubbo_registry_nacos_server"), + dubbo.WithRegistry( + registry.WithNacos(), + registry.WithAddress("127.0.0.1:8848"), + ), + dubbo.WithProtocol( + protocol.WithTriple(), + protocol.WithPort(20000), + ), +) +``` + +然后,才是创建 `ins.NewServer()` 并为 server 实例注册服务 `greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{})`,最后通过 `srv.Serve()` 启动进程。 + +{{% alert title="关于 dubbo.Insance 说明" color="info" %}} +* 在开发 dubbo 微服务应用时,我们推荐使用 `dubbo.Instance` 来设置一些全局性的服务治理能力,如注册中心、协议、应用名、tracing、配置中心等。 +* `ins.NewServer()` 可以创建多个,通常当你需要在多个端口 [发布多个协议]() 时才需要这么做。 +{{% /alert %}} + +如果你要为应用添加更多服务治理能力,请参考以下内容: + +## 更多内容 +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ 服务发现与负载均衡 +

+

更多关于 Nacos、Zookeeper 等服务发现的使用方式,负载均衡策略配置等。

+
+
+
+
+
+
+

+ 流量管控 +

+

学习如何实现按比例流量分配、金丝雀发布、调整超时时间、流量灰度、服务降级等流量管控。

+
+
+
+
+
+
+

+ 监控服务状态 +

+

开启 Metrics 采集,通过 Prometheus、Grafana 可视化查看应用、服务、示例状态。

+
+
+
+
+
+
+

+ 全链路追踪 +

+

开启 OpenTelemetry 全链路追踪。

+
+
+
+
+
+
+

+ 网关 HTTP 接入 +

+

如何使用 Higress、Nginx 等网关产品,将前端 http 流量(北向流量)接入后端 dubbo-go 微服务集群。

+
+
+
+
+
+
+

+ 分布式事务 +

+

使用 Apache Seata 作为分布式事务解决方案,解决分布式数据一致性问题。

+
+
+
+
+
+
+{{< /blocks/section >}} + + + + diff --git a/content/en/overview/mannual/golang-sdk/quickstart/rpc.md b/content/en/overview/mannual/golang-sdk/quickstart/rpc.md new file mode 100644 index 000000000000..82d695fa4b09 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/quickstart/rpc.md @@ -0,0 +1,248 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/quickstart/ + - /zh-cn/docs3-v2/golang-sdk/quickstart/ + - /zh-cn/overview/mannual/golang-sdk/quickstart/quickstart_triple/ +description: Dubbo-go 快速开始 +linkTitle: 开发RPC服务 +title: 开发 RPC Server & RPC Client +type: docs +weight: 1 +--- + +基于 Dubbo 定义的 Triple 协议,你可以轻松编写浏览器、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。Dubbo Go SDK 支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 API 来发布或调用这些服务。 + +本示例演示了基于 Triple 协议的 RPC 通信模式,示例使用 Protocol Buffer 定义 RPC 服务,并演示了代码生成、服务发布和服务访问等过程。 + +## 前置条件 + +因为使用 Protocol Buffer 的原因,我们首先需要安装相关的代码生成工具,这包括 `protoc`、`protoc-gen-go`、`protoc-gen-go-triple`。 + +1. 安装 `protoc` + + 查看 Protocol Buffer Compiler 安装指南 + +2. 安装 `protoc` 插件 + + 接下来,我们安装插件 `protoc-gen-go`、`protoc-gen-go-triple`。 + + ```shell + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + go install dubbo.apache.org/dubbo-go/v3/cmd/protoc-gen-go-triple@v3.0.1 + ``` + + 确保 `protoc-gen-go`、`protoc-gen-go-triple` 在你的 `PATH` 中。这可以通过 `which protoc-gen-go` 验证,如果该命令不能正常工作的话,请执行以下命令: + + ```shell + [ -n "$(go env GOBIN)" ] && export PATH="$(go env GOBIN):${PATH}" + [ -n "$(go env GOPATH)" ] && export PATH="$(go env GOPATH)/bin:${PATH}" + ``` + +## 快速运行示例 +### 下载示例源码 +我们在 apache/dubbo-go-samples 仓库维护了一系列 dubbo-go 使用示例,用来帮助用户快速学习 dubbo-go 使用方式。 + +你可以 下载示例zip包并解压,或者克隆仓库: + +```shell +$ git clone --depth 1 https://github.com/apache/dubbo-go-samples +``` + +切换到快速开始示例目录: + +```shell +$ cd dubbo-go-samples/helloworld +``` + +### 运行 server +在 `go-server/cmd` 目录: + +运行以下命令,启动 server: + +```shell +$ go run server.go +``` + +使用 `cURL` 验证 server 已经正常启动: + +```shell +$ curl \ + --header "Content-Type: application/json" \ + --data '{"name": "Dubbo"}' \ + http://localhost:20000/greet.GreetService/Greet + +Greeting: Hello world +``` + +### 运行 client + +打开一个新的 terminal,运行以下命令,在 `go-client/cmd` 目录运行以下命令,启动 client + +```shell +$ go run client.go + +Greeting: Hello world +``` + +以上就是一个完整的 dubbo-go RPC 通信服务开发过程。 + +## 源码讲解 +接下来,我们将对 `dubbo-go-samples/helloworld` 示例进行源码层面的讲解。 + +### 定义服务 +示例使用 Protocol Buffer (IDL) 来定义 Dubbo 服务。 + +```protobuf +syntax = "proto3"; + +package greet; +option go_package = "github.com/apache/dubbo-go-samples/helloworld/proto;greet"; + +message GreetRequest { + string name = 1; +} + +message GreetResponse { + string greeting = 1; +} + +service GreetService { + rpc Greet(GreetRequest) returns (GreetResponse) {} +} +``` + +这个文件声明了一个叫做 `GreetService` 的服务,为这个服务定义了 Greet 方法以及它的请求参数 GreetRequest 和返回值 GreetResponse。 + +### 生成代码 + +在运行 server 或者 client 之前,我们需要使用 `protoc-gen-go`、`protoc-gen-go-triple` 生成相关的代码 + +```bash +protoc --go_out=. --go_opt=paths=source_relative \ + --go-triple_out=. --go-triple_opt=paths=source_relative \ + ./greet.proto +``` + +运行以上命令后,在目标目录中看到以下生成的文件: + +``` + proto + ├── greet.pb.go + ├── greet.proto + └── greet.triple.go +``` + +在 proto/greet/v1 包下有两部分内容: + +- `greet.pb.go` 是由谷歌标准的 `protoc-gen-go`生成,它包含 `GreetRequest`、`GreetResponse` 结构体和响应的编解码规则。 +- `greet.triple.go` 是由 Dubbo 自定义的插件`protoc-gen-go-triple`成,其中关键的信息包括生成的接口 `GreetService`、构造器等。 + +### 实现服务 + +接下来我们就需要添加业务逻辑了,实现 `greet.GreetService` 接口即可。 + +```go +type GreetTripleServer struct { +} + +func (srv *GreetTripleServer) Greet(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) { + resp := &greet.GreetResponse{Greeting: req.Name} + return resp, nil +} +``` + +### 启动 Server + +创建一个新的 Server,把我们上一步中实现的 `GreeterServer`注册给它,接下来就可以直接初始化和启动 Server 了,它将在指定的端口接收请求。 + +```go +func main() { + srv, err := server.NewServer( + server.WithServerProtocol( + protocol.WithPort(20000), + protocol.WithTriple(), + ), + ) + if err != nil { + panic(err) + } + + if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{}); err != nil { + panic(err) + } + + if err := srv.Serve(); err != nil { + logger.Error(err) + } +} +``` + +### 访问服务 + +最简单方式是使用 HTTP/1.1 POST 请求访问服务,参数则作以标准 JSON 格式作为 HTTP 负载传递。如下是使用 cURL 命令的访问示例: +```shell +curl \ + --header "Content-Type: application/json" \ + --data '{"name": "Dubbo"}' \ + http://localhost:20000/greet.GreetService/Greet +``` + +也可以使用 Dubbo client 请求服务,我们首先需要从生成代码即 `greet` 包中获取服务代理,为它指定 server 地址并初始化,之后就可以发起 RPC 调用了。 + +```go +func main() { + cli, err := client.NewClient( + client.WithClientURL("127.0.0.1:20000"), + ) + if err != nil { + panic(err) + } + + svc, err := greet.NewGreetService(cli) + if err != nil { + panic(err) + } + + resp, err := svc.Greet(context.Background(), &greet.GreetRequest{Name: "hello world"}) + if err != nil { + logger.Error(err) + } + logger.Infof("Greet response: %s", resp.Greeting) +} +``` + +以上即是 dubbo-go rpc 的基本工作原理! + +## 更多内容 +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ RPC 框架更多特性 +

+

学习 Streaming 通信模型、配置超时时间、传递headers等更多框架配置。

+
+
+
+
+
+
+

+ 服务发现等治理能力 +

+

学习如何使用 dubbo-go 开发微服务,引入服务发现、可观测性、流量管控等服务治理能力。

+
+
+
+
+
+
+{{< /blocks/section >}} + + + + diff --git a/content/en/overview/mannual/golang-sdk/refer/_index.md b/content/en/overview/mannual/golang-sdk/refer/_index.md new file mode 100644 index 000000000000..c881a44468f8 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/refer/ + - /zh-cn/docs3-v2/golang-sdk/refer/ + - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/config-center/ + - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/features/ +description: Dubbo-go 更多参考资料 +title: 参考手册 +type: docs +weight: 5 +--- diff --git a/content/en/overview/mannual/golang-sdk/refer/ecology.md b/content/en/overview/mannual/golang-sdk/refer/ecology.md new file mode 100644 index 000000000000..eeaa2d13b06a --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/ecology.md @@ -0,0 +1,64 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/refer/ecology/ + - /zh-cn/docs3-v2/golang-sdk/refer/ecology/ +description: Dubbo-go 生态组件 +title: 生态组件 +type: docs +weight: 1 +--- + +### Dubbo-go + +[github.com/apache/dubbo-go](https://github.com/apache/dubbo-go) + +Apache Dubbo Go 语言实现主仓库 + +### Dubbo-go-samples + +[github.com/apache/dubbo-go-samples](https://github.com/apache/dubbo-go-samples) + +dubbo-go 的使用示例: +* config-api: 使用 API 进行配置初始化 +* configcenter: 使用不同的配置中心,目前支持三种:zookeeper、apollo、和 nacos +* context: 如何使用上下文传递 attachment +* direct: 直连模式 +* game: 游戏服务例子 +* generic: 泛化调用 +* rpc: RPC 调用例子, 包含 Triple、Dubbo等协议以及跨语言/gRPC互通示例 +* helloworld: RPC调用入门例子 +* logger: 日志例子 +* registry: 展示与不同注册中心的对接,包含了 zk、nacos、etcd +* metrics: 数据上报 +* filter: 使用提供filter和自定义filter的例子 +* registry/servicediscovery:应用级服务发现例子 +* router: 路由例子 +* tracing: 链路追踪例子 + +### Dubbo-go-pixiu + +[github.com/apache/dubbo-go-pixiu](https://github.com/apache/dubbo-go-pixiu) + +dubbo-go-pixiu 网关支持以 dubbo 协议和 http 协议调用 dubbo/dubbo-go 集群 + +### Dubbo-getty + +[github.com/apache/dubbo-getty](https://github.com/apache/dubbo-getty) + +dubbo-getty 是一个Go语言异步网络 io 库,支持 tcp/udp/websocket 协议。 + +### Dubbo-go-hessian2 + +[github.com/apache/dubbo-go-hessian2](https://github.com/apache/dubbo-go-hessian2) + +Dubbo-go-hessian2 是一个Go语言 hessian2 序列化协议库 + +### Dubbogo-tools + +[github.com/dubbogo/tools](https://github.com/dubbogo/tools) + +包括 +- dubbo-cli 工具(废弃) +- imports-formatter Go语言 imports 块格式化工具 +- protoc-gen-triple PB编译插件 +- protoc-gen-dubbo3grpc PB编译插件 \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/refer/generic.md b/content/en/overview/mannual/golang-sdk/refer/generic.md new file mode 100644 index 000000000000..7a1217db900b --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/generic.md @@ -0,0 +1,162 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/preface/concept/generic/ + - /zh-cn/docs3-v2/golang-sdk/preface/concept/generic/ + - /zh-cn/overview/mannual/golang-sdk/preface/concept/generic/ +description: 泛化调用 +keywords: 泛化调用 +title: 泛化调用 +type: docs +weight: 2 +--- +{{% alert title="废弃警告" color="warning" %}} +dubbo-go 泛化调用仅适用于 dubbo2 协议,不适用 triple 协议 +{{% /alert %}} + +泛化调用是一种 Dubbo-Go 的特殊调用方式,它允许中间节点在没有接口信息的情况下传递调用信息,常被用于测试、网关的场景下。泛化调用支持 Dubbo 和 Triple 协议,但是目前序列化方案只支持 Hessian。 + +## 背景 + +为了便于理解,这篇文档中以网关使用场景介绍泛化调用。我们先来考虑普通调用(非泛化调用)。下图包含了 consumer 和 provider 两个关键角色(后文中用 endpoint 代表一个 consumer 或一个 provider),各自都有一份关于 org.apache.dubbo.sample.User 接口的定义。假定在调用行为中需要使用 org.apache.dubbo.sample.User 接口。 + +![img](/imgs/docs3-v2/golang-sdk/concept/rpc/generic/1631941941270-86ce9845-5a88-4cb5-8c8a-da8ae7eeb4d5.png) + +RPC 需要借助网络介质传输,因此数据不能以 go struct 形式传输,而必须以二进制形式传输。这就要求 consumer 端在传输前,需要将实现 org.apache.dubbo.sample.User 接口的结构体序列化为二进制格式。同样的,对于 provider 端,需要将二进制数据反序列化为结构体信息。**总之,普通调用要求接口信息在每一个 endpoint 必须有相同的定义,这样才能保证数据序列化和反序列化的结果与预期一致**。 + +在网关场景下,网关不可能存储全部接口定义。比如一个网关需要转发 100 个服务调用,每个服务需要的接口数量为 10 个,普通调用要求把 1000 个(100 * 10)接口定义提前全部存储在网关内,这显然是难以做到的。所以有没有一种方式可以既不需要提前存储接口定义,又能正确转发调用呢?答案是肯定的,这就是使用泛化调用的原因。 + +## 原理 + +泛化调用本质上就是把复杂结构转化为通用结构,这里说的通用结构是指 map、string 等,网关是可以顺利解析并传递这些通用结构的。 + +![img](/imgs/docs3-v2/golang-sdk/concept/rpc/generic/1632207075184-25939db4-f384-452e-a0b8-e1deff7971de.png) + +目前,Dubbo-go v3 只支持 Map 泛化方式(default)。我们以 User 接口为例,其定义如下所示。 + +```go +// definition +type User struct { + ID string + Name string + Age int32 +} + +func (u *User) JavaClassName() string { + return "org.apache.dubbo.sample.User" +} +``` + +假定调用一个服务需要一个 user 作为入参,其定义如下所示。 + +```go +// an instance of the User +user := &User{ + ID: "1", + Name: "Zhangsan", + Age: 20, +} +``` + +那么在使用 Map 泛化方式下,user 会被自动转换为 Map 格式,如下所示。 + +```go +usermap := map[interface{}]interface{} { + "iD": "1", + "name": "zhangsan", + "age": 20, + "class": "org.apache.dubbo.sample.User", +} +``` + +需要注意的是: + +- Map 泛化方式会自动将首字母小写,即 ID 会被转换为 iD,如果需要对齐 Dubbo-Java 请考虑将 ID 改为 Id; +- 在 Map 中会自动插入 class 字段,用于标识原有接口类。 + +## 使用 + +泛化调用对 provider 端是透明的,即 provider 端不需要任何显式配置就可以正确处理泛化请求。 + +### 基于 Dubbo URL 泛化调用 + +基于 Filter 泛化调用对 consumer 是透明的,典型应用场景是网关。这种方式需要要求 Dubbo URL 中包含泛化调用标识,如下所示。 + +```plain +dubbo://127.0.0.1:20000/org.apache.dubbo.sample.UserProvider?generic=true&... +``` + +这个 Dubbo URL 表达的语意是: + +- RPC 协议为 dubbo; +- org.apache.dubbo.sample.UserProvider 接口位于 127.0.0.1:20000; +- 使用泛化调用(generic=true)。 + +Consumer 端的 Filter 会自动根据 Dubbo URL 携带的配置自动将普通调用转化为泛化调用,但是需要注意的是,在这种方式下响应结果是以泛化格式返回,不会自动转化为相应的对象。举个例子,在 map 泛化方式下,如果需要返回 User 类,那么 consumer 获得的相应是一个 User 类对应的 map。 + +### 手动泛化调用 + +手动泛化调用发起的请求不经过 filter,所以需要 consumer 端显式地发起泛化调用,典型应用场景是测试。在 [dubbo-go-samples](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/generic) 中,为了便于测试都是采用手动调用的方式。 + +泛化调用不需要创建配置文件(dubbogo.yaml),但是需要在代码中手动配置注册中心、reference 等信息,初始化方法被封装到 newRefConf 方法中,如下所示。 + +```go +func newRefConf(appName, iface, protocol string) config.ReferenceConfig { + registryConfig := &config.RegistryConfig{ + Protocol: "zookeeper", + Address: "127.0.0.1:2181", + } + + refConf := config.ReferenceConfig{ + InterfaceName: iface, + Cluster: "failover", + Registry: []string{"zk"}, + Protocol: protocol, + Generic: "true", + } + + rootConfig := config.NewRootConfig(config.WithRootRegistryConfig("zk", registryConfig)) + _ = rootConfig.Init() + _ = refConf.Init(rootConfig) + refConf.GenericLoad(appName) + + return refConf +} +``` + +newRefConf 方法接收三个参数,分别是: + +- appName: 应用名; +- iface: 服务接口名; +- protocol: RPC 协议,目前只支持 dubbo 和 tri(triple 协议)。 + +在上述方法中,为了保持函数简单性,把注册中心设置为一个固定值,即使用在 127.0.0.1:2181 的 ZooKeeper 作为注册中心,在实践中可以根据实际情况自由定制。 + +我们可以很容易的获取一个 ReferenceConfig 实例,暂时命名为 refConf。 + +```go +refConf := newRefConf("example.dubbo.io", "org.apache.dubbo.sample.UserProvider", "tri") +``` + +接着我们可以对 org.apache.dubbo.sample.UserProvider 服务的 GetUser 方法发起泛化调用。 + +```go +resp, err := refConf. + GetRPCService().(*generic.GenericService). + Invoke( + context.TODO(), + "GetUser", + []string{"java.lang.String"}, + []hessian.Object{"A003"}, + ) +``` + +GenericService 的 Invoke 方法接收四个参数,分别是: + +- context; +- 方法名: 在这个例子中表示调用 GetUser 方法; +- 参数类型: GetUser 方法接收一个 string 类型的参数,如果目标方法接收多个参数,可以写为 `[]string{"type1", "type2", ...}`,如果目前方法是无参的,则需要填入一个空数组 `[]string{}`; +- 实参: 写法同参数类型,如果是无参函数,依然要填入一个空数组 `[]hessian.Object{}` 占位。 + +注意:在目前版本中,无参调用会出现崩溃问题。 + +相关阅读:[【Dubbo-go 服务代理模型】](https://blog.csdn.net/weixin_39860915/article/details/122738548) diff --git a/content/en/overview/mannual/golang-sdk/refer/nacos.md b/content/en/overview/mannual/golang-sdk/refer/nacos.md new file mode 100644 index 000000000000..c343fb0871a8 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/nacos.md @@ -0,0 +1,147 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/develop/registry/nacos/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/registry/nacos/ +description: 使用 Nacos 作为注册中心 +title: 使用 Nacos 作为注册中心 +type: docs +weight: 10 +--- + + + +## 1. 准备工作 + +- dubbo-go cli 工具和依赖工具已安装 +- 创建一个新的 demo 应用 + +## 2. 使用 grpc_cli 工具进行 Dubbo 服务调试 + +### 2.1 开启服务端 +示例:user.go: +```go +func (u *UserProvider) GetUser(ctx context.Context, userStruct *CallUserStruct) (*User, error) { + fmt.Printf("=======================\nreq:%#v\n", userStruct) + rsp := User{"A002", "Alex Stocks", 18, userStruct.SubInfo} + fmt.Printf("=======================\nrsp:%#v\n", rsp) + return &rsp, nil +} + +``` +服务端开启一个服务,名为GetUser,传入一个CallUserStruct的参数,返回一个User参数\ +CallUserStruct参数定义: +```go +type CallUserStruct struct { + ID string + Male bool + SubInfo SubInfo // 嵌套子结构 +} +func (cs CallUserStruct) JavaClassName() string { + return "com.ikurento.user.CallUserStruct" +} + +type SubInfo struct { + SubID string + SubMale bool + SubAge int +} + +func (s SubInfo) JavaClassName() string { + return "com.ikurento.user.SubInfo" +} + +``` +User结构定义: +```go +type User struct { + Id string + Name string + Age int32 + SubInfo SubInfo // 嵌套上述子结构SubInfo +} + +func (u *User) JavaClassName() string { + return "com.ikurento.user.User" +} +``` + +开启服务: + +`cd server `\ +`source builddev.sh`\ +`go run .` + +### 2.2 定义请求体(打解包协议) + +请求体定义为json文件,约定键值均为string\ +键对应go语言struct字段名例如"ID"、"Name" ,值对应"type@val"\ +其中type支持string int bool time,val使用string 来初始化,如果只填写type则初始化为零值。 +约定每个struct必须有JavaClassName字段,务必与server端严格对应 + +见userCall.json: +```json +{ + "ID": "string@A000", + "Male": "bool@true", + "SubInfo": { + "SubID": "string@A001", + "SubMale": "bool@false", + "SubAge": "int@18", + "JavaClassName":"string@com.ikurento.user.SubInfo" + }, + "JavaClassName": "string@com.ikurento.user.CallUserStruct" +} +``` +userCall.json将参数CallUserStruct的结构及子结构SubInfo都定义了出来,并且给请求参数赋值。 + +user.json 同理,作为返回值不需要赋初始值,但JavaClassName字段一定与server端严格对应 +```go +{ + "ID": "string", + "Name": "string", + "Age": "int", + "JavaClassName": "string@com.ikurento.user.User", + "SubInfo": { + "SubID": "string", + "SubMale": "bool", + "SubAge": "int", + "JavaClassName":"string@com.ikurento.user.SubInfo" + } +} +``` + +### 2.3 执行请求 +`dubbogo-cli call --h=localhost --p 20001 --proto=dubbo --i=com.ikurento.user.UserProvider --method=GetUser --sendObj="./userCall.json" --recvObj="./user.json"` + +cli端打印结果: +```log +2020/10/26 20:47:45 Created pkg: +2020/10/26 20:47:45 &{ID:A000 Male:true SubInfo:0xc00006ea20 JavaClassName:com.ikurento.user.CallUserStruct} +2020/10/26 20:47:45 SubInfo: +2020/10/26 20:47:45 &{SubID:A001 SubMale:false SubAge:18 JavaClassName:com.ikurento.user.SubInfo} + + +2020/10/26 20:47:45 Created pkg: +2020/10/26 20:47:45 &{ID: Name: Age:0 JavaClassName:com.ikurento.user.User SubInfo:0xc00006ec90} +2020/10/26 20:47:45 SubInfo: +2020/10/26 20:47:45 &{SubID: SubMale:false SubAge:0 JavaClassName:com.ikurento.user.SubInfo} + + +2020/10/26 20:47:45 connected to localhost:20001! +2020/10/26 20:47:45 try calling interface:com.ikurento.user.UserProvider.GetUser +2020/10/26 20:47:45 with protocol:dubbo + +2020/10/26 20:47:45 After 3ms , Got Rsp: +2020/10/26 20:47:45 &{ID:A002 Name:Alex Stocks Age:18 JavaClassName: SubInfo:0xc0001241b0} +2020/10/26 20:47:45 SubInfo: +2020/10/26 20:47:45 &{SubID:A001 SubMale:false SubAge:18 JavaClassName:}``` +``` +可看到详细的请求体赋值情况,以及返回结果和耗时。支持嵌套结构 + +server端打印结果 +``` +======================= +req:&main.CallUserStruct{ID:"A000", Male:true, SubInfo:main.SubInfo{SubID:"A001", SubMale:false, SubAge:18}} +======================= +``` +可见接收到了来自cli的数据 \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/3.0_feature.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/3.0_feature.md new file mode 100644 index 000000000000..1fde5e38933b --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/3.0_feature.md @@ -0,0 +1,80 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/preface/3.0_feature/ + - /zh-cn/docs3-v2/golang-sdk/preface/3.0_feature/ + - /zh-cn/overview/mannual/golang-sdk/preface/3.0_feature/ +description: Dubbo-go 3.0 新特性 +keywords: 新特性 +title: 新特性 +type: docs +weight: 3 +--- + + + + + + +![star](https://shields.io/github/stars/apache/dubbo-go?style=dark) + +## 1. Triple 协议 + +### 1.1 概述 + +![img](/imgs/docs3-v2/golang-sdk/concept/more/3.0_feature/tri.png) + +- 通信层面 + + Triple 协议,也称为Dubbo3协议,是基于HTTP2 + gRPC协议,增加特定字段和逻辑的扩展协议,保证了和**原生gRPC协议互通**。在此基础之上,Triple 新协议将更原生地支持 **Dubbo 服务治理能力**。并支持**流式RPC调用**。 + + 简单来说,可以理解为 Triple = gRPC + Dubbo + +- 序列化 + + Triple 协议使用高效的**PB序列化方式**,并在此基础之上增加序列化协议的**可扩展支持**。 + +- 用户开发习惯: + + Triple 服务在开发前需要**预定义.proto文件**,对于习惯在编码前先定义IDL的Go语言开发者带来便捷。不同于符合java编程习惯的,定义JavaClassName用于描述接口的 Dubbo-go 1.x版本。 + +- 跨语言互通性: + + 可与 Dubbo-Java 实现**跨语言互通**。 + + +## 2. 应用级服务发现 + +### 2.1 简介 + +![img](/imgs/docs3-v2/golang-sdk/concept/more/3.0_feature/disc.png) + +在服务注册阶段,服务端实例将应用级别的注册信息,主要包含从应用名到实例IP的映射注册到注册中心。在服务发现阶段,客户端实例,通过注册中心获取到需要请求的服务实例IP。进入服务自省阶段,服务自省过程为通过应用信息获取接口信息的过程。如上图,包含两种模式: + +1. remote模式:通过元数据中心(例如 zk )获取应用到接口元数据的映射 +2. local模式:直接通过服务端获取应用到接口元数据的映射(通过 Dubbo 协议针对 Metadata Service 发起 RPC 调用) + +经过服务自省后,客户端正式向对应实例发起调用。这样做最明显的好处是减少了注册中心的数据量,即注册中心只保存了应用级别的数据。 + +用户在使用 Dubbo-go 3.0的应用级服务发现能力时,可以仿照示例,直接在配置文件中配置服务自省模式和元数据中心信息,引入依赖,开启应用级别服务发现。 + +### 2.2 应用级服务发现介绍文章 + +[应用级服务发现解析](https://baijiahao.baidu.com/s?id=1669266413887039723&wfr=spider&for=pc) + +## 3. Mesh 路由规则 + +用户可定义路由文件: + +virtual_service.yaml + +![img](/imgs/docs3-v2/golang-sdk/concept/more/3.0_feature/virtual_service.png) + +以及 dist_rule.yml + +![img](/imgs/docs3-v2/golang-sdk/concept/more/3.0_feature/dest_rule.png) + +框架可根据路由文件针对特定的请求进行流量转发。 + +## 4. 相关文章 + +阿里云官方介绍文章:[《Dubbo 3.0 - 开启下一代云原生微服务》](https://developer.aliyun.com/article/770964?utm_content=g_1000175535) \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/_index.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/_index.md new file mode 100644 index 000000000000..2e93b505de11 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/sourcecode/ + - /zh-cn/docs3-v2/golang-sdk/sourcecode/ + - /zh-cn/overview/mannual/golang-sdk/sourcecode/ +description: Dubbo-go 源码解读 +title: 源码解读 +type: docs +weight: 4 +--- diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/aop_and_extension.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/aop_and_extension.md new file mode 100644 index 000000000000..d7bb5af3a3de --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/aop_and_extension.md @@ -0,0 +1,111 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/preface/design/aop_and_extension/ + - /zh-cn/docs3-v2/golang-sdk/preface/design/aop_and_extension/ + - /zh-cn/overview/mannual/golang-sdk/preface/design/aop_and_extension/ +description: AOP 与可扩展机制 +keywords: AOP 与可扩展机制 +title: AOP 与可扩展机制 +type: docs +--- + +## 1. extension 模块与 init 方法 + +### 1.1 接口与实现 + +golang 中的一个接口往往伴随多个实现类,dubbo-go 提供了针对接口实现类的可插拔可扩展机制。降低模块之间的耦合性,方便开发者引入、自定义组件。 + +### 1.2 golang 中的 init 方法 + +init 方法作为 golang 中特殊的方法,用户引入一组模块后,会在程序启动时率先执行这些模块内的init 方法,进行加载逻辑,该方法是dubbogo注册扩展组件的重要方式。 + +### 1.3 extension 模块 + +在框架源码中,有一个特殊的模块: common/extension ,这一模块负责缓存所有可扩展组件的实现。 + +以负载均衡模块为例:common/extension/loadbalance.go + +```go +package extension + +import ( + "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance" +) + +var loadbalances = make(map[string]func() loadbalance.LoadBalance) + +// SetLoadbalance sets the loadbalance extension with @name +// For example: random/round_robin/consistent_hash/least_active/... +func SetLoadbalance(name string, fcn func() loadbalance.LoadBalance) { + loadbalances[name] = fcn +} + +// GetLoadbalance finds the loadbalance extension with @name +func GetLoadbalance(name string) loadbalance.LoadBalance { + if loadbalances[name] == nil { + panic("loadbalance for " + name + " is not existing, make sure you have import the package.") + } + + return loadbalances[name]() +} +``` + +该模块包含Get 方法和Set方法。Get 返回实例化的 LoadBalance 接口,Set 方法用于注册工厂函数,map 用于缓存工厂函数。 + +当用户引入 _ "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance/random" 时,将会加载对应模块的init函数,调用 Set 方法注册唯一key和工厂函数和到上述map中。 + +cluster/loadbalance/random/loadbalance.go + +```go +package random + +import ( + "math/rand" +) + +import ( + "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance" + "dubbo.apache.org/dubbo-go/v3/common/constant" + "dubbo.apache.org/dubbo-go/v3/common/extension" + "dubbo.apache.org/dubbo-go/v3/protocol" +) + +func init() { + extension.SetLoadbalance(constant.LoadBalanceKeyRandom, NewRandomLoadBalance) +} +``` + +至此,当所有init方法执行完毕,可以通过 extension 模块 Get 方法来获取实例化对象。 + +### 1.4 imports 模块 + +dubbogo 将所有内置的模块全部放置在 imports/imports.go 内,用户在使用框架时,需要引入该模块,从而使用框架提供的基础能力。 + +```go +import ( + _ "dubbo.apache.org/dubbo-go/v3/imports" +) +``` + +## 2. 组件加载流程 + +1. 用户在代码中引入 _ "dubbo.apache.org/dubbo-go/v3/imports" + +2. 程序启动,init 函数被依次执行,注册工厂函数/实例化对象到 extension 模块。 + +3. 框架启动,加载配置,配置中获取需要加载的模块key,根据key获取实例化对象。 + +4. 用户也可以手动调用 extension 的 Get 方法,获取实例化对象并直接使用。 + +## 3. 自定义组件 + +在上述介绍的基础之上,开发人员可以效仿内置模块,编写自定义扩展组件。 + + +## 4. 面向切面编程的设计(AOP) + +在 Dubbo-go 服务框架中,许多接口是基于 AOP 的思路进行设计的。例如 Invoker、Filter、LoadBalance、Router。 + +这些接口的多种实现往往组成一组调用链,单个实现类只处理自己所关注的逻辑。 + +相关阅读:[【AOP wikipedia】](https://en.wikipedia.org/wiki/Aspect-oriented_programming) \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/app_and_interface.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/app_and_interface.md new file mode 100644 index 000000000000..80561c645b19 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/app_and_interface.md @@ -0,0 +1,74 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/preface/design/app_and_interface/ + - /zh-cn/docs3-v2/golang-sdk/preface/design/app_and_interface/ + - /zh-cn/overview/mannual/golang-sdk/preface/design/app_and_interface/ +description: Dubbo的应用和接口 +keywords: 基本概念 +title: Dubbo的应用和接口 +type: docs +--- + + + + + + +## Dubbogo 服务层级 + +Dubbogo 服务层级为两个级别:分别是应用级别(App Level)和接口级别(Interface Level),该服务分层与**框架配置**结构息息相关。 + +如下图所示,可以看到,应用级别的组件以浅红色标注,接口级别的组件以浅蓝色标注: + +![img](/imgs/docs3-v2/golang-sdk/concept/more/app_and_interface/dubbogo-concept.png) + +## 1. 应用级别组件 + +应用级别组件的特点:被当前应用的所有接口级别组件共用。 + +应用级别的主要组件如下: + +- 应用信息模块 + + 包含应用维度相关信息,包括应用名、版本号、数据上报方式等 + +- Consumer 模块 + + Consumer 模块负责客户端相关信息,包括一个或多个引用(Reference)结构,以及超时、客户端过滤器(consumer filter)等相关信息。 + +- Provider 模块 + + Provider 模块负责服务端相关信息,包括一个或多个服务(Service)结构、服务端过滤器(provider filter)等相关信息。 + +- 注册中心(Registry)模块 + + 注册中心模块负责定义好所要使用的一系列注册中心,例如框架支持的ZK、Nacos、ETCD等中间件。应用级别的注册模块只负责声明,由接口级别的组件进行引用,引用时以用户自定义的注册中心ID(registryID) 作为索引。 + +- 协议(Protocol)模块 + + 协议模块只存在于服务端。 + + 协议模块关心服务的暴露信息,例如协议名、服务监听IP、端口号等信息。协议模块属于应用级别,只负责声明,由接口级别的组件进行引用,引用时以用户自定义的协议ID(protocolID) 作为索引。 + +- 元数据中心模块 + + 元数据中心类似于注册中心模块,负责声明框架需要使用的元数据中心,从而将元数据成功上报。 + +- 配置中心模块 +- 路由模块 +- 日志模块 +- 监控模块 + +## 2. 接口级别组件 + +- 服务(Service)模块 + + 服务模块被使用于任何暴露的服务,声明接口暴露所需的信息,包括例如接口名、协议、序列化方式等,负责单个服务接口的暴露。 + +- 引用(Reference)模块 + + 引用模块被使用于需要调用的远程服务的客户端,其声明了需要请求接口所需的信息,包括例如接口名、协议、序列化方式等、负责特定协议的抽象,参与客户端的生成。 + +## 3. 说明 + +暴露的服务是接口级别的,一个用户定义的 Provider Struct/一个用户定义的Consumer Struct,对应一个Service/Reference 模块,一个应用可以同时存在Consumer 模块和 Provider 模块,因此可以同时存在多个Service/Reference 模块。 diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/architecture.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/architecture.md new file mode 100644 index 000000000000..261badbc9213 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/architecture.md @@ -0,0 +1,31 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/preface/design/architecture/ + - /zh-cn/docs3-v2/golang-sdk/preface/design/architecture/ + - /zh-cn/overview/mannual/golang-sdk/preface/design/architecture/ +description: 架构 +keywords: 架构 +title: 架构 +type: docs +--- + + + + + + +### 架构说明 + +![architecture](/imgs/docs3-v2/golang-sdk/concept/more/architecture/architecture.png) + +### 节点说明 + +* `Registry` : dubbo-go中负责服务注册与发现的注册中心 +* `Consumer` : 调用远程服务的服务消费方 +* `Provider` : 暴露服务的服务提供方 + +### 过程说明 +* `0. register` : 当服务提供方在启动的时候,会自动将自己的服务注册到注册中心 +* `1. subscribe` : 服务消费方会在启动的时候,向注册中心订阅自己所需要的服务 +* `2. notify` : 注册中心返回服务注册的信息给到服务消费方,当订阅的服务发生变更,会推送变更的数据给到消费方 +* `3. invoke` : 服务消费者根据从注册中心获得的服务地址,经过负载均衡算法选出一个合适的服务地址发起请求 \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic-2.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic-2.md new file mode 100644 index 000000000000..babff85cb72c --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic-2.md @@ -0,0 +1,112 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/develop/features/generic/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/features/generic/ + - /zh/docs3-v2/golang-sdk/tutorial/develop/features/generic-2/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/features/generic-2/ + - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/features/generic/ +description: 泛化调用 +title: 泛化调用 +type: docs +weight: 8 +--- + + + + + + +## 1. Dubbogo 泛化调用 Java Server + +使用 Triple 协议 + hessian2 序列化方案 + +可参考Dubbogo 3.0 [泛化调用文档](https://www.yuque.com/docs/share/f4e72670-74ab-45b9-bc0c-4b42249ed953?#) + +### 1.1 Java-Server启动 + +1. 传输结构定义 + +```java +package org.apache.dubbo; + +import java.io.Serializable; +import java.util.Date; + +public class User implements Serializable { + private String id; + + private String name; + + private int age; + + private Date time = new Date(); +} +``` + +2. 接口定义 + +```java +package org.apache.dubbo; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +//import org.apache.dubbo.rpc.filter.GenericFilter; + +public interface UserProvider { + User GetUser1(String userId); +} +``` + +### 1.2 Go-Client 泛化调用 + +此处展示以 API 的形式构造泛化接口引用 + +```go +// 初始化 Reference 配置 +refConf := config.NewReferenceConfigBuilder(). + SetInterface("org.apache.dubbo.UserProvider"). + SetRegistryIDs("zk"). + SetProtocol(tripleConst.TRIPLE). + SetGeneric(true). + SetSerialization("hessian2"). + Build() + +// 构造 Root 配置,引入注册中心模块 +rootConfig := config.NewRootConfigBuilder(). + AddRegistry("zk", config.NewRegistryConfigWithProtocolDefaultPort("zookeeper")). + Build() + +// Reference 配置初始化,因为需要使用注册中心进行服务发现,需要传入经过配置的 rootConfig +if err := refConf.Init(rootConfig); err != nil{ + panic(err) +} + +// 泛化调用加载、服务发现 +refConf.GenericLoad(appName) + +time.Sleep(time.Second) + +// 发起泛化调用 +resp, err := refConf.GetRPCService().(*generic.GenericService).Invoke( + context.TODO(), + "getUser1", + []string{"java.lang.String"}, + []hessian.Object{"A003"}, +) + +if err != nil { + panic(err) +} +logger.Infof("GetUser1(userId string) res: %+v", resp) +``` + +GenericService 的 Invoke 方法包括三个参数:context.Context, []string, []hessian.Object, + +其中第二个参数为对应参数的 Java 类名,例如java.lang.String、org.apache.dubbo.User,第三个参数为参数列表,hessian.Object 即为 interface。第二、第三个参数应与方法签名一致,按顺序对应。 + +获得map结构的返回结果 + +``` +INFO cmd/client.go:89 GetUser1(userId string) res: map[age:48 class:org.apache.dubbo.User id:A003 name:Joe sex:MAN time:2021-10-04 14:03:03.37 +0800 CST] +``` diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic.md new file mode 100644 index 000000000000..0b73538e8d5c --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic.md @@ -0,0 +1,107 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/develop/features/generic/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/features/generic/ +description: 泛化调用 +title: 泛化调用 +type: docs +weight: 7 +--- + + + + + + +## 1. Dubbo-go 泛化调用 Java Server + +使用 Triple 协议 + hessian2 序列化方案 + +### 1.1 Java-Server启动 + +1. 传输结构定义 + +```java +package org.apache.dubbo; + +import java.io.Serializable; +import java.util.Date; + +public class User implements Serializable { + private String id; + + private String name; + + private int age; + + private Date time = new Date(); +} +``` + +2. 接口定义 + +```java +package org.apache.dubbo; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +//import org.apache.dubbo.rpc.filter.GenericFilter; + +public interface UserProvider { + User GetUser1(String userId); +} +``` + +### 1.2 Go-Client 泛化调用 + +此处展示以 API 的形式构造泛化接口引用 + +```go +// 初始化 Reference 配置 +refConf := config.NewReferenceConfigBuilder(). + SetInterface("org.apache.dubbo.UserProvider"). + SetRegistryIDs("zk"). + SetProtocol(tripleConst.TRIPLE). + SetGeneric(true). + SetSerialization("hessian2"). + Build() + +// 构造 Root 配置,引入注册中心模块 +rootConfig := config.NewRootConfigBuilder(). + AddRegistry("zk", config.NewRegistryConfigWithProtocolDefaultPort("zookeeper")). + Build() + +// Reference 配置初始化,因为需要使用注册中心进行服务发现,需要传入经过配置的 rootConfig +if err := refConf.Init(rootConfig); err != nil{ + panic(err) +} + +// 泛化调用加载、服务发现 +refConf.GenericLoad(appName) + +time.Sleep(time.Second) + +// 发起泛化调用 +resp, err := refConf.GetRPCService().(*generic.GenericService).Invoke( + context.TODO(), + "getUser1", + []string{"java.lang.String"}, + []hessian.Object{"A003"}, +) + +if err != nil { + panic(err) +} +logger.Infof("GetUser1(userId string) res: %+v", resp) +``` + +GenericService 的 Invoke 方法包括三个参数:context.Context, []string, []hessian.Object, + +其中第二个参数为对应参数的 Java 类名,例如java.lang.String、org.apache.dubbo.User,第三个参数为参数列表,hessian.Object 即为 interface。第二、第三个参数应与方法签名一致,按顺序对应。 + +获得map结构的返回结果 + +``` +INFO cmd/client.go:89 GetUser1(userId string) res: map[age:48 class:org.apache.dubbo.User id:A003 name:Joe sex:MAN time:2021-10-04 14:03:03.37 +0800 CST] +``` \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/protocol.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/protocol.md new file mode 100644 index 000000000000..0b16486364ad --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/protocol.md @@ -0,0 +1,33 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/sourcecode/protocol/ + - /zh-cn/docs3-v2/golang-sdk/sourcecode/protocol/ +description: 网络协议源码解读 +title: 网络协议 +type: docs +weight: 1 +--- + + + + + + +对于 Dubbogo 微服务框架,网络协议为远程过程调用中负责网络通信的模块,负责应用层到网络层的数据序列化、打包、请求发起、网络端口监听等功能。Dubbogo 为协议抽象了一套接口如下: + +```go +type Protocol interface { + // Export service for remote invocation + Export(invoker Invoker) Exporter + // Refer a remote service + Refer(url *common.URL) Invoker + // Destroy will destroy all invoker and exporter, so it only is called once. + Destroy() +} +``` + +该接口包含三个方法。其中 Export 方法负责服务的暴露过程。入参 invoker 为dubbo 的概念,其封装了一个可以被调用的实例。在具体网络协议(例如Triple)实现的 Export 方法中,会针对特定的协议,将封装有一定逻辑的可调用实例 Invoker 以网络端口监听的形式暴露给外部服务,来自外部针对该网络端口的请求将会被 Export 方法开启的监听协程获取,进而根据网络协议进行拆解包和反序列化,得到解析后的请求数据。 + +Refer 方法负责服务的引用过程,其入参 url 为 dubbo 框架通用的结构,可以描述一个希望引用的服务,url 参数中包含了多个希望引用服务的参数,例如对应服务的接口名(interface),版本号(version),使用协议(protocol) 等等。在具体网络协议(例如Triple)实现的 Refer 方法中,会将特定的网络协议封装到 Invoker 可调用实例的方法中,用户层发起的 RPC 调用即可直接通过返回的 Invoker 对象,发起特定协议的网络请求。 + +Destroy 方法作用为销毁当前暴露的服务,用于服务下线场景。Dubbogo 框架有优雅下线机制,可以在服务进程终止前以监听信号的形式,下线所有已启动的服务。 \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/registry.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/registry.md new file mode 100644 index 000000000000..1017aad4ea03 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/registry.md @@ -0,0 +1,61 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/sourcecode/registry/ + - /zh-cn/docs3-v2/golang-sdk/sourcecode/registry/ +description: 注册中心源码解读 +title: 注册中心 +type: docs +weight: 1 +--- + + + + + + +Dubbogo 为注册中心抽象了一套接口如下: + +```go +// Registry Extension - Registry +type Registry interface { + common.Node + + // Register is used for service provider calling, register services + // to registry. And it is also used for service consumer calling, register + // services cared about, for dubbo's admin monitoring. + Register(url *common.URL) error + + // UnRegister is required to support the contract: + // 1. If it is the persistent stored data of dynamic=false, the + // registration data can not be found, then the IllegalStateException + // is thrown, otherwise it is ignored. + // 2. Unregister according to the full url match. + // url Registration information, is not allowed to be empty, e.g: + // dubbo://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin + UnRegister(url *common.URL) error + + // Subscribe is required to support the contract: + // When creating new registry extension, pls select one of the + // following modes. + // Will remove in dubbogo version v1.1.0 + // mode1: return Listener with Next function which can return + // subscribe service event from registry + // Deprecated! + // subscribe(event.URL) (Listener, error) + // Will replace mode1 in dubbogo version v1.1.0 + // mode2: callback mode, subscribe with notify(notify listener). + Subscribe(*common.URL, NotifyListener) error + + // UnSubscribe is required to support the contract: + // 1. If don't subscribe, ignore it directly. + // 2. Unsubscribe by full URL match. + // url Subscription condition, not allowed to be empty, e.g. + // consumer://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin + // listener A listener of the change event, not allowed to be empty + UnSubscribe(*common.URL, NotifyListener) error +} +``` + +该接口主要包含四个方法,分别是注册、反注册、订阅、取消订阅。顾名思义,概括了客户端和服务端与注册中心交互的动作。针对普通接口级服务注册发现场景,在Provider 服务启动时,会将自身服务接口信息抽象为一个 url,该 url 包含了客户端发起调用所需的所有信息(ip、端口、协议等),服务端的注册中心组件会将该 url 写入注册中心(例如zk)。客户端启动后,在服务引用 Refer 步骤会通过注册中心组件订阅(Subscribe)需要的服务信息,获取到的服务信息以异步事件更新的形式写入客户端缓存,从而在服务发现成功后,可以根据拿到的服务 url 参数,向对应服务提供者发起调用。 + +## \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/refer/use_dubbogo_cli.md b/content/en/overview/mannual/golang-sdk/refer/use_dubbogo_cli.md new file mode 100644 index 000000000000..1524b3def6a0 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/refer/use_dubbogo_cli.md @@ -0,0 +1,436 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/refer/use_dubbogo_cli/ + - /zh-cn/docs3-v2/golang-sdk/refer/use_dubbogo_cli/ +description: 使用 dubbogo-cli 工具 +title: 使用 dubbogo-cli 工具 +type: docs +weight: 3 +--- +{{% alert title="废弃警告" color="warning" %}} +自 dubbo-go 3.1.0 版本开始,本工具不再适用。本工具已经停止维护,未来将由 dubboctl 代替,请关注社区动态了解 dubboctl 最新进展。 +{{% /alert %}} + +## 1. 安装 + +dubbogo-cli 是 Apach/dubbo-go 生态的子项目,为开发者提供便利的应用模板创建、工具安装、接口调试等功能,以提高用户的研发效率。 + +执行以下指令安装dubbogo-cli 至 $GOPATH/bin + +``` +go install github.com/dubbogo/dubbogo-cli@latest +``` + +## 2. 功能概览 + +dubbogo-cli 支持以下能力 + +- 应用模板创建 + + ``` + dubbogo-cli newApp . + ``` + + 在当前目录下创建应用模板 + +- Demo 创建 + + ``` + dubbogo-cli newDemo . + ``` + + 在当前目录下创建 RPC 示例,包含一个客户端和一个服务端 + +- 编译、调试工具安装 + + ``` + dubbogo-cli install all + ``` + + 一键安装以下等工具至 $GOPATH/bin + + - protoc-gen-go-triple + + 用于 triple 协议接口编译 + + - imports-formatter + + 用于整理代码 import 块。 + + [import-formatte README](https://github.com/dubbogo/tools#imports-formatter) + + + +- 查看 dubbo-go 应用注册信息 + + - 查看 Zookeeper 上面的注册信息, 获取接口及方法列表 + + ```bash + $ dubbogo-cli show --r zookeeper --h 127.0.0.1:2181 + interface: com.dubbogo.pixiu.UserService + methods: [CreateUser,GetUserByCode,GetUserByName,GetUserByNameAndAge,GetUserTimeout,UpdateUser,UpdateUserByName] + ``` + + - 查看 Nacos 上面的注册信息 【功能开发中】 + + - 查看 Istio 的注册信息【功能开发中】 + +- 调试 Dubbo 协议接口 + +- 调试 Triple 协议接口 + +## 3. 功能详解 + +### 3.1 Demo 应用介绍 + +#### 3.1.1 Demo 创建 + +``` +dubbogo-cli newDemo . +``` + +在当前目录下创建Demo, 包含客户端和服务端,该 Demo 展示了基于一套接口,完成一次 RPC 调用。 + +该Demo 使用直连模式,无需依赖注册中心,server端暴露服务到本地20000端口,客户端发起调用。 + +```shell +. +├── api +│ ├── samples_api.pb.go +│ ├── samples_api.proto +│ └── samples_api_triple.pb.go +├── go-client +│ ├── cmd +│ │ └── client.go +│ └── conf +│ └── dubbogo.yaml +├── go-server +│ ├── cmd +│ │ └── server.go +│ └── conf +│ └── dubbogo.yaml +└── go.mod +``` + +#### 3.1.2 运行Demo + +开启服务端 + +``` +$ cd go-server/cmd +$ go run . +``` + +另一个终端开启客户端 + +``` +$ go mod tidy +$ cd go-client/cmd +$ go run . + +``` + +可看到打印日志 + +``` +INFO cmd/client.go:49 client response result: name:"Hello laurence" id:"12345" age:21 +``` + +### 3.2 应用模板介绍 + +#### 3.2.1 应用模板创建 + +``` +dubbogo-cli newApp . +``` + +在当前目录下创建应用模板: + +``` +. +├── Makefile +├── api +│ ├── api.pb.go +│ ├── api.proto +│ └── api_triple.pb.go +├── build +│ └── Dockerfile +├── chart +│ ├── app +│ │ ├── Chart.yaml +│ │ ├── templates +│ │ │ ├── _helpers.tpl +│ │ │ ├── deployment.yaml +│ │ │ ├── service.yaml +│ │ │ └── serviceaccount.yaml +│ │ └── values.yaml +│ └── nacos_env +│ ├── Chart.yaml +│ ├── templates +│ │ ├── _helpers.tpl +│ │ ├── deployment.yaml +│ │ └── service.yaml +│ └── values.yaml +├── cmd +│ └── app.go +├── conf +│ └── dubbogo.yaml +├── go.mod +├── go.sum +└── pkg + └── service + └── service.go + +``` + +#### 3.2.2 应用模板介绍 + +生成项目包括几个目录: + +- api:放置接口文件:proto文件和生成的.pb.go文件 +- build:放置镜像构建相关文件 +- chart:放置发布用 chart 仓库、基础环境chart 仓库:nacos、mesh(开发中) +- cmd:程序入口 +- conf:框架配置 +- pkg/service:RPC 服务实现 +- Makefile: + +- - 镜像、helm部署名: + +- - - IMAGE = $(your_repo)/$(namespace)/$(image_name) + TAG = 1.0.0 +- HELM_INSTALL_NAME = dubbo-go-app,helm 安装名,用于 helm install/uninstall 命令。 + +- - 提供脚本,例如: + +- - - make build # 打包镜像并推送 +- make buildx-publish # arm架构本地打包amd64镜像并推送,依赖 docker buildx +- make deploy # 通过 helm 发布应用 +- make remove # 删除已经发布的 helm 应用 +- make proto-gen # api下生成 pb.go 文件 + +- + +使用应用模板的开发流程 + +> 依赖环境:make、go、helm、kubectl、docker + +1. 通过 dubbogo-cli 生成模板 +2. 修改api/api.proto +3. make proto-gen +4. 开发接口 +5. 修改 makefile 内 IMAGE 镜像名和 HELM_INSTALL_NAME 发布名 +6. 打镜像并推送 +7. 修改chart/app/values 内与部署相关的value配置, 重点关注镜像部分。 + +``` +image: + repository: $(your_repo)/$(namespace)/$(image_name) + pullPolicy: Always + tag: "1.0.0" +``` + +8. make deploy, 使用 helm 发布应用。 + +### 3.3 以 gRPC 协议调试 dubbo-go 应用 + +#### 3.3.1 简介 + +grpc_cli 工具是 gRPC 生态用于调试服务的工具,在 server 开启[反射服务](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md)的前提下,可以获取到服务的 proto 文件、服务名、方法名、参数列表,以及发起 gRPC 调用。 + +Triple 协议兼容 gRPC 生态,并默认开启 gRPC 反射服务,因此可以直接使用 grpc_cli 调试 triple 服务。 + +#### 3.3.2 安装grpc_cli + +> 后续将由 dubbogo-cli 安装,目前需要用户手动安装 + +参考[grpc_cli 文档](https://github.com/grpc/grpc/blob/master/doc/command_line_tool.md) + +#### 3.3.3 使用 grpc_cli 对 Triple 服务进行调试 + +1. 查看 triple 服务的接口定义 + +```shell +$ grpc_cli ls localhost:20001 -l +filename: helloworld.proto +package: org.apache.dubbo.quickstart.samples; +service UserProvider { + rpc SayHello(org.apache.dubbo.quickstart.samples.HelloRequest) returns (org.apache.dubbo.quickstart.samples.User) {} + rpc SayHelloStream(stream org.apache.dubbo.quickstart.samples.HelloRequest) returns (stream org.apache.dubbo.quickstart.samples.User) {} +} +``` + +2. 查看请求参数类型 + +例如开发者期望测试上述端口的 SayHello 方法,尝试获取HelloRequest的具体定义,需要执行r如下指令,可查看到对应参数的定义。 + +```shell +$ grpc_cli type localhost:20001 org.apache.dubbo.quickstart.samples.HelloRequest +message HelloRequest { + string name = 1 [json_name = "name"]; +} +``` + +3. 请求接口 + +已经知道了请求参数的具体类型,可以发起调用来测试对应服务。查看返回值是否符合预期。 + +```shell +$ grpc_cli call localhost:20001 SayHello "name: 'laurence'" +connecting to localhost:20001 +name: "Hello laurence" +id: "12345" +age: 21 +Received trailing metadata from server: +accept-encoding : identity,gzip +adaptive-service.inflight : 0 +adaptive-service.remaining : 50 +grpc-accept-encoding : identity,deflate,gzip +Rpc succeeded with OK status +``` + +### 3.4 以 Dubbo 协议调试dubbo-go 应用 + +#### 3.4.1 开启 Dubbo 服务端 + +示例:user.go: + +``` +func (u *UserProvider) GetUser(ctx context.Context, userStruct *CallUserStruct) (*User, error) { + fmt.Printf("=======================\nreq:%#v\n", userStruct) + rsp := User{"A002", "Alex Stocks", 18, userStruct.SubInfo} + fmt.Printf("=======================\nrsp:%#v\n", rsp) + return &rsp, nil +} +``` + +服务端开启一个服务,名为GetUser,传入一个CallUserStruct的参数,返回一个User参数 +CallUserStruct参数定义: + +``` +type CallUserStruct struct { + ID string + Male bool + SubInfo SubInfo // 嵌套子结构 +} +func (cs CallUserStruct) JavaClassName() string { + return "com.ikurento.user.CallUserStruct" +} + +type SubInfo struct { + SubID string + SubMale bool + SubAge int +} + +func (s SubInfo) JavaClassName() string { + return "com.ikurento.user.SubInfo" +} +``` + +User结构定义: + +``` +type User struct { + Id string + Name string + Age int32 + SubInfo SubInfo // 嵌套上述子结构SubInfo +} + +func (u *User) JavaClassName() string { + return "com.ikurento.user.User" +} +``` + +开启服务: + +``` +cd server` +`source builddev.sh` +`go run . +``` + +#### 3.4.2 定义请求体 (适配于序列化协议) + +请求体定义为json文件,约定键值均为string +键对应go语言struct字段名例如"ID"、"Name" ,值对应"type@val" +其中type支持string int bool time,val使用string 来初始化,如果只填写type则初始化为零值。 约定每个struct必须有JavaClassName字段,务必与server端严格对应 + +见userCall.json: + +``` +{ + "ID": "string@A000", + "Male": "bool@true", + "SubInfo": { + "SubID": "string@A001", + "SubMale": "bool@false", + "SubAge": "int@18", + "JavaClassName":"string@com.ikurento.user.SubInfo" + }, + "JavaClassName": "string@com.ikurento.user.CallUserStruct" +} +``` + +userCall.json将参数CallUserStruct的结构及子结构SubInfo都定义了出来,并且给请求参数赋值。 + +user.json 同理,作为返回值不需要赋初始值,但JavaClassName字段一定与server端严格对应 + +``` +{ + "ID": "string", + "Name": "string", + "Age": "int", + "JavaClassName": "string@com.ikurento.user.User", + "SubInfo": { + "SubID": "string", + "SubMale": "bool", + "SubAge": "int", + "JavaClassName":"string@com.ikurento.user.SubInfo" + } +} +``` + +#### 3.4.3 调试端口 + +``` +./dubbo-go-cli -h=localhost -p=20001 -proto=dubbo -i=com.ikurento.user.UserProvider -method=GetUser -sendObj="./userCall.json" -recvObj="./user.json" +``` + +打印结果: + +``` +2020/10/26 20:47:45 Created pkg: +2020/10/26 20:47:45 &{ID:A000 Male:true SubInfo:0xc00006ea20 JavaClassName:com.ikurento.user.CallUserStruct} +2020/10/26 20:47:45 SubInfo: +2020/10/26 20:47:45 &{SubID:A001 SubMale:false SubAge:18 JavaClassName:com.ikurento.user.SubInfo} + + +2020/10/26 20:47:45 Created pkg: +2020/10/26 20:47:45 &{ID: Name: Age:0 JavaClassName:com.ikurento.user.User SubInfo:0xc00006ec90} +2020/10/26 20:47:45 SubInfo: +2020/10/26 20:47:45 &{SubID: SubMale:false SubAge:0 JavaClassName:com.ikurento.user.SubInfo} + + +2020/10/26 20:47:45 connected to localhost:20001! +2020/10/26 20:47:45 try calling interface:com.ikurento.user.UserProvider.GetUser +2020/10/26 20:47:45 with protocol:dubbo + +2020/10/26 20:47:45 After 3ms , Got Rsp: +2020/10/26 20:47:45 &{ID:A002 Name:Alex Stocks Age:18 JavaClassName: SubInfo:0xc0001241b0} +2020/10/26 20:47:45 SubInfo: +2020/10/26 20:47:45 &{SubID:A001 SubMale:false SubAge:18 JavaClassName:}``` +``` + +可看到详细的请求体赋值情况,以及返回结果和耗时。支持嵌套结构 + +server端打印结果 + +``` +======================= +req:&main.CallUserStruct{ID:"A000", Male:true, SubInfo:main.SubInfo{SubID:"A001", SubMale:false, SubAge:18}} +======================= +``` + +可见接收到了来自cli的数据 \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/tutorial/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/_index.md new file mode 100755 index 000000000000..6e598676b958 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/ + - /zh-cn/overview/mannual/golang-sdk/preface/samples/ +description: Dubbo-go 使用教程 +linkTitle: 使用教程 +title: 使用教程 +type: docs +weight: 3 +--- diff --git a/content/en/overview/mannual/golang-sdk/tutorial/configuration/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/configuration/_index.md new file mode 100755 index 000000000000..046fe925805a --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/configuration/_index.md @@ -0,0 +1,161 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/debugging/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ + - /zh-cn/overview/mannual/golang-sdk/refer/basic_concept/ + - /zh-cn/overview/mannual/golang-sdk/refer/config/ +description: "使用 dubbogo.yml 配置文件形式开发微服务应用。" +title: 配置文件 +type: docs +weight: 30 +--- + +## 1. 框架配置 + +Dubbo-go 框架需要依赖配置进行启动。配置中包含了开发者希望使用框架的各种能力。 + +### 配置格式 + +yaml + +### 配置路径 + +默认从 `../conf/dubbogo.yaml ` 加载框架配置 + +可通过指定环境变量:DUBBO_GO_CONFIG_PATH=$(your_config_path)/dubbogo.yaml 来修改配置文件路径。 + +### 配置根结构 + +位于 [dubbo.apache.org/dubbo-go/v3/config/root_config.go: RootConfig](https://github.com/apache/dubbo-go/blob/e00cf8d6fb2be3cd9c6e42cc3d6efa54e10229d3/config/root_config.go#L50) + +框架加载时,任何形式的配置都会被解析成 RootConfig,在 RootConfig.Init 方法中加载。 + +## 2. 配置API + +开发者可以使用 API 的形式构建配置,从而启动框架。该方法较适合 dubbo-go 作为第三方组件引入的情况。 + +## 3. 配置中心 + +开发者可以将配置放置在配置中心,从而便于配置的管理和修改。 + + + + + + + +## 根配置 + +## 客户端配置 + +## 服务端配置 + +## 注册中心配置 + +### 使用配置 API + +- 客户端使用配置 API 设置注册中心 + +可通过调用config.NewRegistryConfigWithProtocolDefaultPort方法,快速设置用于调试的注册中心,支持zookeeper(127.0.0.1:2181) 和nacos(127.0.0.1:8848) + +```go +rc := config.NewRootConfigBuilder(). + SetConsumer(config.NewConsumerConfigBuilder(). + SetRegistryIDs("zookeeperID"). // use defined registryID + Build()). + AddRegistry("zookeeperID", config.NewRegistryConfigWithProtocolDefaultPort("zookeeper")). + Build() +``` + +全部接口:可通过调用RegistryConfigBuilder提供的丰富接口进行配置。 + +```go +rc := config.NewRootConfigBuilder(). + SetConsumer(config.NewConsumerConfigBuilder(). + SetRegistryIDs("nacosRegistryID"). // use defined registryID + AddReference("GreeterClientImpl",/*...*/). + Build() + AddRegistry("nacosRegistryID", config.NewRegistryConfigBuilder(). + SetProtocol("nacos"). + SetAddress("127.0.0.1:8848"). + SetGroup("dubbo-go"). + SetNamespace("dubbo"). + SetUsername("admin"). + SetPassword("admin"). + SetTimeout("3s"). + Build()). + Build() +``` + +- 服务端使用配置 API 设置配置中心 + +简易接口 config.NewRegistryConfigWithProtocolDefaultPort + +```go +rc := config.NewRootConfigBuilder(). + SetProvider(config.NewProviderConfigBuilder(). + AddService("GreeterProvider", /*...*/). + SetRegistryIDs("registryKey"). // use defined registryID + Build()). + AddRegistry("registryKey", config.NewRegistryConfigWithProtocolDefaultPort("zookeeper")). + Build() +``` + +全部接口:可通过调用RegistryConfigBuilder提供的丰富接口进行配置。 + +```go +rc := config.NewRootConfigBuilder(). + SetProvider(config.NewProviderConfigBuilder(). + AddService("GreeterProvider",/*...*/) + SetRegistryIDs("registryKey"). // use defined registryID + Build()). + AddRegistry("registryKey", config.NewRegistryConfigBuilder(). + SetProtocol("nacos"). + SetAddress("127.0.0.1:8848"). + SetGroup("dubbo-go"). + SetNamespace("dubbo"). + SetUsername("admin"). + SetPassword("admin"). + SetTimeout("3s"). + Build()). + Build() +``` + +### + +## 网络协议 + +### 配置文件 + +### 使用配置 API + +- 客户端使用配置 API 设置网络协议 + +```go +rc := config.NewRootConfigBuilder(). + SetConsumer(config.NewConsumerConfigBuilder(). + AddReference("GreeterClientImpl", config.NewReferenceConfigBuilder(). + SetInterface("org.apache.dubbo.UserProvider"). + SetProtocol("tri"). // set reference protcol to triple + Build()). + Build()). + Build() +``` + +- 服务端使用配置 API 设置网络协议 + +```go +rc := config.NewRootConfigBuilder(). + SetProvider(config.NewProviderConfigBuilder(). + AddService("GreeterProvider", config.NewServiceConfigBuilder(). + SetInterface("org.apache.dubbo.UserProvider"). + SetProtocolIDs("tripleProtocolKey"). // use protocolID 'tripleProtocolKey' + Build()). + Build()). + AddProtocol("tripleProtocolKey", config.NewProtocolConfigBuilder(). // define protocol config with protocolID 'tripleProtocolKey' + SetName("tri"). // set service protocol to triple + Build()). + Build() +``` + +### diff --git a/content/en/overview/mannual/golang-sdk/tutorial/configuration/file.md b/content/en/overview/mannual/golang-sdk/tutorial/configuration/file.md new file mode 100644 index 000000000000..cbee4780d318 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/configuration/file.md @@ -0,0 +1,280 @@ +--- +description: 使用 dubbogo.yml 配置文件开发应用 +title: 使用 dubbogo.yml 配置文件开发应用 +linkTitle: 本地配置文件 +type: docs +weight: 1 +--- + +## 1.介绍 + +本文档演示如何在框架中使用 `yaml` 配置文件进行微服务开发,是相比于 `API` 的另一种微服务开发模式。你可以完全使用 `yml` 配置文件进行开发,也可以将部分全局配置放到配置文件,而只在 API 中完成服务定义。 + +这种模式下,一定要通过 `DUBBO_GO_CONFIG_PATH` 指定配置文件路径: + +```shell +export DUBBO_GO_CONFIG_PATH="../conf/dubbogo.yml" +``` + +## 2. 使用说明 + +可在此查看 完整示例源码。 + +### 2.1 运行示例 +```txt +. +├── go-client +│   ├── cmd +│   │   └── main.go +│   └── conf +│   └── dubbogo.yml +├── go-server +│   ├── cmd +│   │   └── main.go +│   └── conf +│   └── dubbogo.yml +└─── proto +    ├── greet.pb.go +    ├── greet.proto +    └── greet.triple.go + +``` +通过 IDL`./proto/greet.proto` 定义服务 使用triple协议 + + +#### build Proto +```bash +cd path_to_dubbogo-sample/config_yaml/proto +protoc --go_out=. --go-triple_out=. ./greet.proto +``` +#### Server +```bash +export DUBBO_GO_CONFIG_PATH="../conf/dubbogo.yml" +cd path_to_dubbogo-sample/config_yaml/go-server/cmd +go run . +``` +#### Client +```bash +export DUBBO_GO_CONFIG_PATH="../conf/dubbogo.yml" +cd path_to_dubbogo-sample/config_yaml/go-client/cmd +go run . +``` + +### 2.2 客户端使用说明 + +客户端定义的 `yaml` 文件: + +```yaml +# dubbo client yaml configure file +dubbo: + registries: + demoZK: + protocol: zookeeper + timeout: 3s + address: 127.0.0.1:2181 + consumer: + references: + GreetServiceImpl: + protocol: tri + interface: com.apache.dubbo.sample.Greeter + registry: demoZK + retries: 3 + timeout: 3000 +``` +通过 `dubbo.Load()` 调用进行文件的读取以及加载 + +```go +//... +func main() { + //... + if err := dubbo.Load(); err != nil { + //... + } + //... +} +``` + +### 2.3 服务端使用说明 + +服务端定义的 `yaml` 文件 +```yaml +# dubbo server yaml configure file +dubbo: + registries: + demoZK: + protocol: zookeeper + timeout: 10s + address: 127.0.0.1:2181 + protocols: + tripleProtocol: + name: tri + port: 20000 + provider: + services: + GreetTripleServer: + interface: com.apache.dubbo.sample.Greeter +``` + +通过 `dubbo.Load()` 调用进行文件的读取以及加载 + +```go +//... +func main() { + //... + if err := dubbo.Load(); err != nil { + //... + } + //... +} + +``` +## 3.示例详解 + +### 3.1服务端介绍 + +#### 服务端proto文件 + +源文件路径:dubbo-go-sample/context/proto/greet.proto + +```protobuf +syntax = "proto3"; + +package greet; + +option go_package = "github.com/apache/dubbo-go-samples/config_yaml/proto;greet"; + +message GreetRequest { + string name = 1; +} + +message GreetResponse { + string greeting = 1; +} + +service GreetService { + rpc Greet(GreetRequest) returns (GreetResponse) {} +} +``` + +#### 服务端handler文件 + +在服务端中,定义 GreetTripleServer: + +```go +type GreetServiceHandler interface { + Greet(context.Context, *GreetRequest) (*GreetResponse, error) +} +``` + +实现 GreetServiceHandler 接口,通过 `greet.SetProviderService(&GreetTripleServer{})` 进行注册 +,同样使用 `dubbo.Load()` 进行加载配置文件 + + +源文件路径:dubbo-go-sample/config_yaml/go-server/cmd/main.go + +```go + +package main + +import ( + "context" + "errors" + "fmt" + + "dubbo.apache.org/dubbo-go/v3" + _ "dubbo.apache.org/dubbo-go/v3/imports" + greet "github.com/apache/dubbo-go-samples/config_yaml/proto" +) + +type GreetTripleServer struct { +} + +func (srv *GreetTripleServer) Greet(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) { + name := req.Name + if name != "ConfigTest" { + errInfo := fmt.Sprintf("name is not right: %s", name) + return nil, errors.New(errInfo) + } + + resp := &greet.GreetResponse{Greeting: req.Name + "-Success"} + return resp, nil +} + +func main() { + greet.SetProviderService(&GreetTripleServer{}) + if err := dubbo.Load(); err != nil { + panic(err) + } + select {} +} +``` + +### 3.2 客户端介绍 + +在客户端中,定义greet.GreetServiceImpl实例,greet.SetConsumerService(svc)进行注册: +通过 `dubbo.Load()` 进行配置文件的加载 + +源文件路径:dubbo-go-sample/config_yaml/go-client/cmd/main.go + +```go +package main + +import ( + "context" + "dubbo.apache.org/dubbo-go/v3" + _ "dubbo.apache.org/dubbo-go/v3/imports" + greet "github.com/apache/dubbo-go-samples/config_yaml/proto" + "github.com/dubbogo/gost/log/logger" +) + +var svc = new(greet.GreetServiceImpl) + +func main() { + greet.SetConsumerService(svc) + if err := dubbo.Load(); err != nil { + panic(err) + } + req, err := svc.Greet(context.Background(), &greet.GreetRequest{Name: "ConfigTest"}) + if err != nil || req.Greeting != "ConfigTest-Success" { + panic(err) + } + logger.Info("ConfigTest successfully") +} + +``` + +### 3.3 案例效果 + +先启动服务端,再启动客户端,可以观察到客户端打印了`ConfigTest successfully`配置加载以及调用成功 + +``` +2024-03-11 15:47:29 INFO cmd/main.go:39 ConfigTest successfully + +``` + +## 4 更多配置 + +### 指定 Filter + +如果要指定多个 filter 时,可用 ',' 分隔 + +- Consumer 端 + + ```yaml + dubbo: + consumer: + filter: echo,token,tps,myCustomFilter # 可指定自定义filter + ``` + + +- Provider 端 + + ```yaml + dubbo: + provider: + services: + GreeterProvider: + filter: myCustomFilter,echo,tps + ``` + + diff --git a/content/en/overview/mannual/golang-sdk/tutorial/configuration/remote.md b/content/en/overview/mannual/golang-sdk/tutorial/configuration/remote.md new file mode 100644 index 000000000000..c68340283afa --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/configuration/remote.md @@ -0,0 +1,80 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/develop/config-center/remote_config/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/config-center/remote_config/ +description: 远程加载 dubbogo.yaml 配置文件 +title: 远程配置文件 +type: docs +weight: 3 +--- + +Dubbo 框架支持将配置文件 'dubbogo.yaml' 的内容预先放入配置中心,再通过远程加载的方式与本地配置合并,以此实现一些配置的动态和集中式管理。 + +{{% alert title="注意" color="primary" %}} +凡是正确配置了config-center 地址的应用,都会优先从配置中心加载整个配置文件。 +{{% /alert %}} + +可在此查看 完整示例源码地址,本文使用 zookeeper 演示,nacos 使用方法类似,并且在以上地址中有具体源码示例。 + +### 启用配置中心 +在 dubbo-go 应用通过 `dubbo.WithConfigCenter()` 启用配置中心: + +```go +ins, err := dubbo.NewInstance( + dubbo.WithConfigCenter( + config_center.WithZookeeper(), + config_center.WithDataID("dubbo-go-samples-configcenter-zookeeper-server"), + config_center.WithAddress("127.0.0.1:2181"), + config_center.WithGroup("dubbogo"), + ), +) +if err != nil { + panic(err) +} +``` + +在运行应用之前,提前将以下配置写入 zookeeper 集群,写入路径为 `/dubbo/config/dubbogo/dubbo-go-samples-configcenter-zookeeper-server`: + +```yaml +dubbo: + registries: + demoZK: + protocol: zookeeper + timeout: 3s + address: '127.0.0.1:2181' + protocols: + triple: + name: tri + port: 20000 +``` + +### 启动服务端并注册服务 + +```go +srv, err := ins.NewServer() +if err != nil { + panic(err) +} + +if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{}); err != nil { + panic(err) +} + +if err := srv.Serve(); err != nil { + logger.Error(err) +} +``` + +可以发现,应用已经读取了远端的 dubbogo.yml 文件,并连接到文件中配置的注册中心地址、协议及端口配置。 + +### 启动客户端 + +```shell +$ go run ./go-client/cmd/main.go +``` + +### 预期的输出 + +``` +Greet response: greeting:"hello world" +``` diff --git a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/_index.md new file mode 100644 index 000000000000..dfcdc5c34e96 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/ +description: "学习在 Kubernetes、Service Mesh(Kubernetes Service)、虚拟机(Zookeeper、Nacos)等场景部署 dubbo-go 应用。" +title: 部署应用 +type: docs +weight: 100 +toc_hide: true +--- diff --git a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/deploy.md b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/deploy.md new file mode 100644 index 000000000000..2e61d43a2c79 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/deploy.md @@ -0,0 +1,430 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/deploy/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/deploy/ +description: Istio 环境部署 Dubbo-go 应用 +title: Istio 环境部署 Dubbo-go 应用 +type: docs +weight: 2 +--- + +在本章节中,我们将使用应用模板快速创建一组 Dubbo-go Server和 Client 端应用,部署在 Istio 集群中;观察、调试和验证服务发现和调用成功。 + +## 1. 准备工作 + +- dubbo-go cli 工具和依赖工具已安装、grpc_cli (如需本地调试)。 +- docker、helm、kubectl 环境已安装。(arm 机器需支持 docker buildx) +- [任务【istio 环境部署】](../istio/) 已完成 + +## 2. 开发 server 端 Dubbo-go 应用 + +### 2.1 使用 dubbogo-cli 创建项目模板 + +```plain +$ mkdir mesh-app-server +$ cd mesh-app-server +$ dubbogo-cli newApp . +$ tree . +. +├── Makefile +├── api +│ └── api.proto +├── build +│ └── Dockerfile +├── chart +│ ├── app +│ │ ├── Chart.yaml +│ │ ├── templates +│ │ │ ├── _helpers.tpl +│ │ │ ├── deployment.yaml +│ │ │ ├── service.yaml +│ │ │ └── serviceaccount.yaml +│ │ └── values.yaml +│ └── nacos_env +│ ├── Chart.yaml +│ ├── templates +│ │ ├── _helpers.tpl +│ │ ├── deployment.yaml +│ │ └── service.yaml +│ └── values.yaml +├── cmd +│ └── app.go +├── conf +│ └── dubbogo.yaml +├── go.mod +├── go.sum +└── pkg + └── service + └── service.go +``` + +生成项目包括几个目录: + +- api:放置接口文件:proto文件和生成的pb.go文件 +- build:放置构建相关文件 +- chart:放置发布用 chart 仓库、基础环境chart 仓库:nacos、mesh(开发中) +- cmd:程序入口 +- conf:框架配置 +- pkg/service:RPC 服务实现 +- Makefile: + +- - 镜像、Helm 安装名称: + +- - ``` + IMAGE = $(your_repo)/$(namespace)/$(image_name) + TAG = 1.0.0 + HELM_INSTALL_NAME = dubbo-go-app + ``` + +- - 提供脚本,例如: + +- - - make build # 打包镜像并推送 + - make buildx-publish # arm架构本地打包amd64镜像并推送,依赖buildx + - make deploy # 通过 helm 发布应用 + - make remove # 删除已经发布的 helm 应用 + - make proto-gen # api下生成 pb.go 文件 + - ... + +### 2.2 开发和部署 Dubbo-go 应用: + +#### 开发应用 + +- 编译接口 + + 开发人员需要修改 proto 文件,本任务中直接使用默认接口即可。 + + ```bash + $ make proto-gen + protoc --go_out=./api --go-triple_out=./api ./api/api.proto + ``` + +- 拉取依赖 + + ```bash + $ go get dubbo.apache.org/dubbo-go/v3@3.0 + $ make tidy + go mod tidy + ``` + +- 编写业务逻辑 + + 修改 pkg/service/service.go 实现函数, 返回字符串中显示版本为 v1.0.0 + + ```go + func (s *GreeterServerImpl) SayHello(ctx context.Context, in *api.HelloRequest) (*api.User, error) { + return &api.User{Name: "Hello " + in.Name, Id: "v1.0.0"}, nil + } + ``` + +- 修改配置如下字段,从而使用xds协议作为注册中心 + + conf/dubbogo.yaml + + ```yaml + dubbo: + registries: + xds: + protocol: xds + address: istiod.istio-system.svc.cluster.local:15010 + protocols: + triple: + name: tri + port: 20000 + provider: + services: + GreeterServerImpl: + interface: "" # read from stub + + ``` + + 至此,应用开发完成。 + +#### 配置构建和部署参数 + +- 指定需要构建的镜像: + + 修改 Makefile 如下字段,指定好需要构建的镜像地址和版本。 + + 指定好需要通过 helm 安装的名称。 + + ``` + IMAGE = xxx/dubbo-go-server + TAG = 1.0.0 + HELM_INSTALL_NAME = dubbo-go-server-v1 + ``` + +- 指定需要部署的应用和镜像: + + 修改 chart/app/Chart.yaml 如下字段,指定当前应用名为 `dubbo-go-server`,部署时会创建一个名为 dubbo-go-server 的 service ,关联当前应用的所有版本。 + + ```yaml + apiVersion: v1 + name: dubbo-go-server + description: dubbo-go-server + ``` + + 修改 chart/app/values.yaml 如下字段,指定需要部署的镜像以及当前开发的应用版本 dubbogoAppVersion 为 v1。 + + 部署的镜像需要和上述构建的镜像一致。当前应用版本用于 mesh 流量规则控制。 + + ```yaml + image: + repository: xxx/dubbo-go-server + pullPolicy: Always + tag: "1.0.0" + + # Dubbo-go-mesh version control labels + version: + labels: + dubbogoAppVersion: v1 + ``` + + 至此,构建参数和发布参数都已指定好,可以进行构建和部署了。 + +#### 使用模板构建和部署 Dubbo-go 应用 + +- 构建、推送镜像 + + `$ make build ` (本地为 amd64机器) + + 或者 + + `$ make buildx-publish` (本地为 arm64机器,依赖 docker buildx 命令) + +- 发布 Dubbo-go 应用至集群 + + ```bash + $ make deploy + helm install dubbo-go-server-v1 ./chart/app + NAME: dubbo-go-server-v1 + LAST DEPLOYED: Thu Apr 7 11:19:42 2022 + NAMESPACE: default + STATUS: deployed + REVISION: 1 + TEST SUITE: None + $ helm list + NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION + dubbo-go-server-v1 default 1 2022-04-07 11:19:42.350553 +0800 CST deployed dubbo-go-server-0.0.1 1.16.0 + ``` + + 可看到通过 helm 部署成功 + + + +### 2.3 验证应用 + +#### 查看资源部署情况 + +查看部署好的 deployment ,版本为 v1。 + +```bash +$ kubectl get deployment +NAME READY UP-TO-DATE AVAILABLE AGE +dubbo-go-server-v1 1/1 1 1 26s +``` + +查看部署好的 service。 + +```bash +$ kubectl get svc +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +dubbo-go-server ClusterIP 192.168.216.253 20000/TCP 70s +``` + +#### (*可选)本地调试部署好的 Dubbo-go 应用 + +使用 kubectl port-forward Dubbo-go 应用到本地 + +```bash +$ kubectl port-forward svc/dubbo-go-server 20000 +Forwarding from 127.0.0.1:20000 -> 20000 +Forwarding from [::1]:20000 -> 20000 +``` + +使用 grpc_cli 调试集群内的应用,参考任务[【使用 grpc_cli 调试 Dubbo-go 应用】](/zh-cn/overview/mannual/golang-sdk/tutorial/debugging/grpc_cli/) + +```bash +$ grpc_cli ls localhost:20000 -l +filename: api/api.proto +package: api; +service Greeter { + rpc SayHello(api.HelloRequest) returns (api.User) {} + rpc SayHelloStream(stream api.HelloRequest) returns (stream api.User) {} +} +``` + +使用 grpc_cli 发起调用,测试接口 + +```bash +$ grpc_cli call localhost:20000 SayHello "name: 'laurence'" +connecting to localhost:20000 +name: "Hello laurence" +id: "v1.0.0" +Received trailing metadata from server: +accept-encoding : identity,gzip +grpc-accept-encoding : identity,deflate,gzip +Rpc succeeded with OK status +``` + +至此,我们成功开发了一个应用,把它部署在了 istio 集群内。 + +## 3. 开发 Client 端 Dubbo-go 应用 + +### 3.1 使用 dubbogo-cli 创建另一个项目模板 + +```bash +$ dubbogo-cli newApp . +``` + +### 3.2 开发和部署客户端 Dubbo-go 应用: + +#### 编写业务逻辑 + +- 修改 cmd/app.go 的 main 方法,针对下游接口每秒钟发起一次调用 + +```go +func main() { + client := &api.GreeterClientImpl{} + config.SetConsumerService(client) + if err := config.Load(); err != nil { + panic(err) + } + request := &api.HelloRequest{ + Name: "laurence", + } + + for{ + if rsp, err := client.SayHello(context.Background(), request); err != nil{ + logger.Errorf("call server error = %s", err) + }else{ + logger.Infof("call server response = %+v", rsp) + } + time.Sleep(time.Second) + } +} +``` + +- 修改如下配置文件,使用xds协议作为注册中心,加载名为 GreeterClientImpl 的客户端服务。 + + conf/dubbogo.yaml + + ```yaml + dubbo: + registries: + xds: + protocol: xds + address: istiod.istio-system.svc.cluster.local:15010 + consumer: + references: + GreeterClientImpl: + protocol: tri + interface: "" # read from stub + ``` + + 至此,应用开发完成。 + +#### 配置构建和部署参数 + +- 指定需要构建的镜像: + + 修改 Makefile 如下字段,指定好需要构建的镜像地址和版本。 + + 指定好需要通过 helm 安装的名称。 + + ``` + IMAGE = xxx/dubbo-go-client + TAG = 1.0.0 + HELM_INSTALL_NAME = dubbo-go-client + ``` + +- 指定需要部署的应用和镜像: + + 修改 chart/app/Chart.yaml 如下字段,指定当前应用名为 `dubbo-go-client`,部署时会创建一个名为 dubbo-go-client 的 service ,关联当前应用的所有版本。对于一个只有客户端的应用,可以不创建sevice,可以由开发者在模板中修改,本教程中我们默认创建。 + + ```yaml + apiVersion: v1 + name: dubbo-go-client + description: dubbo-go-client + ``` + + 修改 chart/app/values.yaml 如下字段,指定需要部署的镜像以及当前开发的应用版本 dubbogoAppVersion 为 v1。 + + 部署的镜像需要和上述构建的镜像一致。当前应用版本用于 mesh 流量规则控制。 + + ```yaml + image: + repository: xxx/dubbo-go-client + pullPolicy: Always + tag: "1.0.0" + + # Dubbo-go-mesh version control labels + version: + labels: + dubbogoAppVersion: v1 + ``` + + 至此,构建参数和发布参数都已指定好,可以进行构建和部署了。 + +#### 使用模板构建和部署 Dubbo-go 应用 + +- 构建、推送镜像 + + `$ make build ` (本地为 amd64机器) + + 或者 + + `$ make buildx-publish` (本地为 arm64机器,依赖 docker buildx 命令) + +- 发布 Dubbo-go Client 应用至集群 + + ```bash + $ make deploy + helm install dubbo-go-client ./chart/app + NAME: dubbo-go-client + LAST DEPLOYED: Thu Apr 7 11:49:55 2022 + NAMESPACE: default + STATUS: deployed + REVISION: 1 + TEST SUITE: None + $ helm list + NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION + dubbo-go-client default 1 2022-04-07 11:49:55.517898 +0800 CST deployed dubbo-go-client-0.0.1 1.16.0 + dubbo-go-server-v1 default 1 2022-04-07 11:23:18.397658 +0800 CST deployed dubbo-go-server-0.0.1 1.16.0 + ``` + + 可看到通过 helm 部署成功, 目前已经在集群中存在 Client 和 Server 两个应用。 + +### 3.3 验证应用 + +#### 查看资源部署情况 + +查看部署好的 client 和 server 两个 deployment。 + +```bash +$ kubectl get deployment +NAME READY UP-TO-DATE AVAILABLE AGE +dubbo-go-client-v1 1/1 1 1 22m +dubbo-go-server-v1 1/1 1 1 49m +``` + +查看客户端调用日志 + +```bash +$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs +... +2022-04-07T04:13:55.777Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T04:13:56.778Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T04:13:57.779Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T04:13:58.781Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T04:13:59.782Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T04:14:00.784Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T04:14:01.785Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +``` + +验证调用成功 + +## 4. 小结 + +dubbogo-cli 提供的应用模板可以方便地支持开发者进行镜像的构建、推送、部署。 + +在 Istio 环境中,server 应用将自身服务信息注册在 Isito 上,由客户端监听 xds 资源,查询 istio debug 端口进行接口级别的服务发现。开发人员无需关心 service名、主机名、集群名等概念,只需要引入接口,发起调用即可。 \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/graceful_shutdown.md b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/graceful_shutdown.md new file mode 100644 index 000000000000..40fca749bbf2 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/graceful_shutdown.md @@ -0,0 +1,66 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/governance/traffic/graceful_shutdown/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/traffic/graceful_shutdown/ +description: 本文主要介绍优雅下线的基本步骤和使用说明 +keywords: 优雅下线 +title: 优雅下线 +type: docs +--- + +# 优雅下线 + +## 背景 + +在稳定生产的过程中,容器调度完全由 k8s 管控,微服务治理完全由服务框架或者运维人员进行维护和管理。而在发布新版本,或者扩缩容的场景下,会终止旧的容器实例,并使用新的容器实例进行替换,对于承载高流量的线上生产环境,这个替换过程的衔接如果不合理,将在短时间内造成大量的错误请求,触发报警甚至影响正常业务。对于体量较大的厂家,发布过程出现问题所造成的损失会是巨大的。 +因此,优雅下线的诉求被提出。这要求服务框架在拥有稳定服务调用能力、传统服务治理能力的基础之上,应当提供服务下线过程中稳定的保障,从而减少运维成本,提高应用稳定性。 + +## 特性说明 + +在一次完整的RPC调用过程中,中间服务往往充当服务提供者和服务消费者两个角色。中间服务在接收到来自上游服务的请求之后,处理请求得到结果返回给上游服务,然后根据需要调用下游服务提供的接口使用下游服务。因此优雅下线功能需要兼顾服务作为服务提供者和服务消费者两侧的稳定性,具体可以分为以下几步: + +1. 向注册中心进行反注册,销毁在注册中心注册的服务信息 +2. 作为服务提供者,要等待一段时间,保证客户端成功更新服务信息以及上游任务请求处理完毕,然后拒绝接收新的请求 +3. 作为服务消费者,要等待一段时间,保证使用下游服务的请求得到响应,然后取消对注册中心的订阅 +4. 销毁对下游任务的引用,销毁对外提供服务暴露的端口 +5. 执行用户的自定义回调操作 + +通过以上步骤,可以保证dubbo-go服务实例安全平稳停止,不对进行中的业务产生影响。 + +> 注意:取消对注册中心的订阅不能在步骤1中执行,这是因为中间服务对下游服务发送请求的时候可能存在下游服务信息的变动 + +## 使用场景 + +对dubbo-go实例使用` kill pid `命令停止实例 + +## 使用方式 + +以下是在yaml配置文件中,用户可以自定义的配置 + +- 作为服务提供者,dubbo-go实例下线时需要等待客户端成功更新服务信息,这段时间在配置中对应的字段为consumer-update-wait-time,默认3s +- 作为服务提供者,dubbo-go实例下线时如果来自上游任务的请求暂未处理完毕,需要等待上游任务请求处理完毕。作为服务消费者,dubbo-go实例需要等待对下游的请求收到回复。这段时间在配置中对应的字段为step-timeout,默认3s +- 作为服务提供者,dubbo-go实例下线时如果来自上游任务的请求已经处理完毕,需要等待一段窗口时间,如果在窗口时间内没有接收到新的请求,再执行后续步骤。这段时间在配置中对应的字段为offline-request-window-timeout,默认0s +- 用户可以自定义是否开启优雅下线功能,在配置中对应的字段为internal-signal,默认开启。 +- dubbo-go实例在优雅下线过程中可能因为异常导致卡死,在配置中可以配置超时时间,实例在超时之后强制关闭。这在配置中对应的字段为timeout,默认60s + +```yaml +dubbo: + shutdown: + timeout:60 + step-timeout:3 + consumer-update-wait-time:3 + internal-signal:true + offline-request-window-timeout:0 +``` + +此外,如果用户希望在下线逻辑彻底结束后,执行一些自定义的回调操作,可以使用如下代码 + +```go +extension.AddCustomShutdownCallback(func() { + // 用户自定义操作 +}) +``` + +## 参考资料 + +[【Dubbo-go 优雅上下线的设计与实践】](https://developer.aliyun.com/article/860775) \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/istio.md b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/istio.md new file mode 100644 index 000000000000..5e7782f83edc --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/istio.md @@ -0,0 +1,40 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/istio/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/istio/ +description: 部署 Istio 环境 +title: 部署 Istio 环境 +type: docs +weight: 1 +--- + + + + + + +## 1. 准备工作 + +- docker、helm、kubectl 环境已安装。 +- dubbo-go cli 工具和依赖工具已安装 + +## 2. 部署 Istio 环境 + +1. 使用helm 安装 istio 基础 CRD 和 istiod 组件。也可以参考 [Istio 文档](https://istio.io/) 使用 istioctl 安装。 + +```bash +$ helm repo add istio https://istio-release.storage.googleapis.com/charts +$ kubectl create namespace istio-system +$ helm install istio-base istio/base -n istio-system +$ helm install istiod istio/istiod --namespace istio-system +``` + +2. 删除istio 水平扩展资源 + + *目前 dubbo-go 依赖单个 istiod 实例进行服务发现。 + +```bash +$ kubectl delete hpa istiod -n istio-system +``` + +安装完成后,可以在 istio-system 命名空间下看到一个 istiod pod 在正常运行。 \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/proxyless_service_mesh.md b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/proxyless_service_mesh.md new file mode 100644 index 000000000000..9ee8ff7bf1d2 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/proxyless_service_mesh.md @@ -0,0 +1,116 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/proxyless_service_mesh/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/proxyless_service_mesh/ +description: 无代理服务网格 +keywords: 无代理服务网格 +title: 无代理服务网格 +type: docs +--- + + + + + + +## 1. 什么是 Proxyless Service-Mesh (无代理服务网格) ? + +### 1.1 Service Mesh 简析 + +Istio 是当今最流行的开源服务网格。它由控制平面和数据平面构成,其架构如下,图片摘自 [istio官网](https://istio.io/) + +![使用 Istio 后](/imgs/docs3-v2/golang-sdk/concept/mesh/proxyless_service_mesh/service-mesh.svg) + +位于图中下半部分的控制平面负责配置、服务信息、证书等资源的下发。位于上半部分的数据平面关注业务之间的通信流量;传统服务网格通过代理的方式拦截所有的业务网络流量,代理需要感知到控制平面下发的配置资源,从而按照要求控制网络流量的走向。 + +在 Istiod 环境中,其控制平面是一个名为 istiod 的进程,网络代理是 envoy 。istiod 通过监听 K8S 资源 例如Service、Endpoint 等,获取服务信息,并将这些资源统一通过 XDS 协议下发给位于数据平面的网络代理。envoy 是一个独立的进程,以 sidecar(边车)的形式伴随业务应用 Pod 运行,他与应用进程共用同一个主机网络,并通过修改路由表的方式,劫持业务应用的网络流量。 + +Service Mesh 可以解决微服务场景下的众多问题,随着集群规模的扩大与业务复杂度的增长,基于原生 k8s 的容器编排方案将会难以应付,开发人员不得不面对巨大的服务治理挑战。而 Service Mesh 很好地解决了这一问题,它将服务治理需求封装在了控制平面与代理中,业务开发人员只需要关注于业务逻辑。在应用部署之后,只需要运维人员通过修改配置,即可实现例如故障恢复、负载均衡、灰度发布等功能,这极大地提高了研发和迭代效率。 + +Istio 的 sidecar 通过容器注入的形式伴随业务应用进程的整个生命周期,对于业务应用是毫无侵入的,这解决了业务应用可迁移、多语言、基础架构耦合等问题。但这也带来了高资源消耗、请求时延增长的问题。 + +Service 为服务治理提供了一个很好的思路,将基础架构与业务逻辑解耦,让应用开发人员只需关注业务。另一方面,由于 sidecar 的弊端,我们可以考虑使用 sdk 的形式,来替代 sidecar 支撑起数据平面。 + +### 1.2 Proxyless Service-Mesh + +无代理服务网格,是近几年提出的一个新的概念,isito、gRPC、brpc 等开源社区都在这一方向进行了探索和实践。无代理服务网格框架以 SDK 的形式被业务应用引入,负责服务之间的通信、治理。来自控制平面的配置直接下发至服务框架,由服务框架代替上述 sidecar 的功能。 + +![img](/imgs/docs3-v2/golang-sdk/concept/mesh/proxyless_service_mesh/894c0e52-9d34-4490-b49b-24973ef4aabc.png) + +服务框架(SDK)的主要能力可以概括为以下三点: + +1. 对接控制平面,监听配置资源。 +2. 对接应用,为开发者提供方便的接口。 +3. 对接网络,根据资源变动,响应流量规则。 + +### 1.3 Proxyless 的优缺点 + +优点: + +- 性能:无代理模式的网络调用为点对点的直接通信,网络时延会比代理模式小很多。 +- 稳定性:proxyless 的模式是单进程,拓扑简单,便于调试,稳定性高。 +- 框架集成:市面上已有众多 sdk 模式的服务框架,切换至 mesh 后便与复用框架已有能力 +- 资源消耗:没有 sidecar,资源消耗低 + +缺点: + +- 语言绑定:需要开发多种语言的 sdk +- 可迁移性低:无法通过切换 sidecar 的形式来无侵入地升级基础设施。 + +总体来讲,Proxyless 架构以其高性能、高稳定性的特点,更适合与生产环境使用。 + +## 2. Dubbo-go 与 Proxyless Service-Mesh + +### 2.1 Dubbo-go 在 Proxyless Service-Mesh 场景的设计 + +#### 服务注册发现 + +Dubbo-go 本身拥有可扩展的服务注册发现能力,我们为 service mesh 场景适配了注册中心的实现。开发人员可以将 dubbo-go 应用的信息注册在 istiod 控制平面上。客户端应用可以查询已经注册的接口数据,完成服务发现过程。 + +![img](/imgs/docs3-v2/golang-sdk/concept/mesh/proxyless_service_mesh/454d1e31-0be3-41fe-97ec-f52673ebf74f.png) + +1. 开发人员使用 dubbogo-cli 工具创建应用模板,发布 Deployment / Service 到集群中。 +2. 服务端拉取全量 CDS 和 EDS ,比对本机IP,拿到当前应用的的主机名。并将本应用的所有接口名到主机名的映射,注册在Istiod上面。 +3. 客户端从 istiod 拉取全量接口名到主机名的映射,缓存在本地。当需要发起调用时,查询本地缓存,将接口名转换为主机名,再通过CDS 和 EDS 拉取到当前 cluster 所对应的全量端点。 +4. 全量端点经过 Dubbo-go 内置的 Mesh Router,筛选出最终的端点子集,并按照配置的负载均衡策略进行请求。 + +开发人员全程只需要关注接口即可,完全无需关心主机名和端口信息。即服务端开发者只需要实现pb接口,使用框架暴露出来;客户端开发者只需要引入pb接口,直接发起调用即可。 + +#### 流量治理 + +Dubbo-go 拥有路由能力,通过 xds 协议客户端从 istiod 订阅路由配置,并实时更新至本地路由规则,从而实现服务的管理。Dubbo-go 兼容 istio 生态的流量治理规则,可以通过配置 Virtual Service 和 Destination Rule,将打标的流量路由至指定子集,也可以在灰度发布、切流等场景进行更深入地使用。 + +#### 云原生脚手架 + +dubbogo-cli 是 Apache/dubbo-go 生态的子项目,为开发者提供便利的应用模板创建、工具安装、接口调试等功能,以提高用户的研发效率。 + +详情可以参阅 [【dubbogo-cli 工具】](/zh-cn/overview/mannual/golang-sdk/refer/use_dubbogo_cli/) + +## 3. Dubbo-go-Mesh 的优势 + +### 3.1 接口级服务发现 + +前文介绍到了通过接口级服务注册发现的优势,即开发人员无需关心下游主机名和端口号,只需要引入接口存根,或实现接口,通过框架启动即可。 + +### 3.2 高性能 + +我们在 k8s 集群内部署 istio 环境,分别测试了 sidecar 模式的 gRPC 服务调用和 Proxyless 模式的 dubbo-go 应用服务调用。发现 proxyless 在请求耗时方面比 sidecar 模式少一个数量级,即性能提升十倍左右。 + +### 3.3 跨生态 + +Dubbo-go 是一个横跨多个生态的服务框架。 + +- mesh 生态 + + 开发人员可以使用 Dubbo-go 进行应用开发的同时,使用 istio 生态所提供的强大能力。 + +- gRPC 生态 + + - Dubbo-go 支持与 gRPC 服务互通,HTTP2 协议栈。 + - Dubbo-go 默认使用 pb 序列化方式,高性能。 + +- Dubbo 生态 + + - 多语言优势,可以实现 go-java 应用互通。 + - 兼容 pixiu 网关,方便地进行服务的暴露和协议转换。 + - 使用 Dubbo-go 生态组件。 \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/traffic_management.md b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/traffic_management.md new file mode 100644 index 000000000000..2340b4f02c72 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/traffic_management.md @@ -0,0 +1,425 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/traffic_management/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/traffic_management/ +description: 流量管理 +title: 流量管理 +type: docs +weight: 3 +--- + + + + + + +在本节中,我们将延续上一个任务[【在 Istio 环境部署 Dubbo-go 应用】](../deploy/)。 + +在之前的任务中,我们在集群中部署了一组 Dubbo-go Server和 Client 端应用,验证了服务发现和调用成功。在本节中,我们将创建新版本的 Server 端应用。通过配置 VirtualService 和 DestinationRule ,实现路由管理,和流量转移能力 + +## 1. 准备工作 + +- dubbo-go cli 工具和依赖工具已安装、grpc_cli (如需本地调试)。 +- docker、helm、kubectl 环境已安装。(arm 机器需支持 docker buildx) +- 任务[【在 Istio 环境部署 Dubbo-go 应用】](../deploy/)已完成 + +## 2. 开发多版本Dubbo-go 应用。 + +### 2.1 使用 dubbogo-cli 创建另一个项目模板 + +```bash +$ dubbogo-cli newApp . +``` + +### 2.2 开发和部署客户端 Dubbo-go 应用 v2: + +#### 编写业务逻辑 + +- 修改 package/service/service.go 的实现方法,返回版本号为 v2.0.0 + +```go +func (s *GreeterServerImpl) SayHello(ctx context.Context, in *api.HelloRequest) (*api.User, error) { + return &api.User{Name: "Hello " + in.Name, Id: "v2.0.0"}, nil +} +``` + +- 修改如下配置文件,使用xds协议作为注册中心,加载名为 GreeterServerImpl 的服务结构。 + + conf/dubbogo.yaml + + ```yaml + dubbo: + registries: + xds: + protocol: xds + address: istiod.istio-system.svc.cluster.local:15010 + protocols: + triple: + name: tri + port: 20000 + provider: + services: + GreeterServerImpl: + interface: "" # read from stub + + ``` + + 至此,应用开发完成。 + +#### 配置构建和部署参数 + +- 指定需要构建的镜像: + + 修改 Makefile 如下字段,指定好需要构建的镜像地址和版本,我们把镜像 tag 改为 2.0.0。 + + 指定好需要通过 helm 安装的名称。 + + ``` + IMAGE = xxx/dubbo-go-server + TAG = 2.0.0 + HELM_INSTALL_NAME = dubbo-go-server + ``` + +- 指定需要部署的应用和镜像: + + 修改 chart/app/Chart.yaml 如下字段,指定当前应用名为 `dubbo-go-server`,我们在创建v1版本服务的时候,已经有了该应用的 service,这次部署时模板将不会创建 service。 + + ```yaml + apiVersion: v1 + name: dubbo-go-server + description: dubbo-go-server + ``` + + 修改 chart/app/values.yaml 如下字段,指定需要部署的镜像为2.0.0,以及当前开发的应用版本 dubbogoAppVersion 为 v2。 + + 部署的镜像需要和上述构建的镜像一致。当前应用版本用于 mesh 流量规则控制。 + + ```yaml + image: + repository: xxx/dubbo-go-server + pullPolicy: Always + tag: "2.0.0" + + # Dubbo-go-mesh version control labels + version: + labels: + dubbogoAppVersion: v2 + ``` + + 至此,构建参数和发布参数都已指定好,可以进行构建和部署了。 + +#### 使用模板构建和部署 Dubbo-go 应用 + +- 构建、推送镜像 + + `$ make build ` (本地为 amd64机器) + + 或者 + + `$ make buildx-publish` (本地为 arm64机器,依赖 docker buildx 命令) + +- 发布 Dubbo-go Server v2 至集群 + + ```bash + $ make deploy + NAME: dubbo-go-server-v2 + LAST DEPLOYED: Thu Apr 7 12:29:28 2022 + NAMESPACE: default + STATUS: deployed + REVISION: 1 + TEST SUITE: None + $ helm list + NAME NAMESPACE REVISION UPDATED STATUS CHART dubbo-go-client default 1 2022-04-07 11:49:55.517898 +0800 CST deployed dubbo-go-client-0.0.1 1.16.0 + dubbo-go-server-v1 default 1 2022-04-07 11:23:18.397658 +0800 CST deployed dubbo-go-server-0.0.1 1.16.0 + dubbo-go-server-v2 default 1 2022-04-07 12:29:28.497476 +0800 CST deployed dubbo-go-client-0.0.1 1.16.0 + ``` + + 可看到通过 helm 部署成功, 目前已经在集群中存在一个 Client 应用,和 Server 的两个版本。 + +### 2.3 验证应用 + +#### 查看资源部署情况 + +查看部署好的 deployment ,server 包含了两个版本。 + +```bash +$ kubectl get deployment +NAME READY UP-TO-DATE AVAILABLE AGE +dubbo-go-client-v1 1/1 1 1 40m +dubbo-go-server-v2 1/1 1 1 77s +dubbo-go-server-v1 1/1 1 1 67m +``` + +查看部署好的 service。两个版本的deployment 共用同一个 service。 + +```bash +$ kubectl get svc +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +dubbo-go-client ClusterIP 192.168.8.176 20000/TCP 41m +dubbo-go-server ClusterIP 192.168.216.253 20000/TCP 67m +``` + +查看 Client 应用日志,验证请求调用到了两个版本的应用上。 + +```bash +$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs +... +2022-04-07T05:06:40.384Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0" +2022-04-07T05:06:41.386Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0" +2022-04-07T05:06:42.388Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:06:43.389Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0" +2022-04-07T05:06:44.390Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0" +2022-04-07T05:06:45.392Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:06:46.393Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:06:47.394Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:06:48.396Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0" +2022-04-07T05:06:49.397Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +``` + +至此,我们开发并且部署成功了多版本应用。 + +## 3. 配置请求路由 + +### 3.1 配置目标规则 + +执行以下命令以创建目标规则,该目标规则将 dubbo-go-server 细分为两个子集。v1和 v2 + +```bash +$ kubectl apply -f destinationrule.yaml +``` + +destinationrule.yaml 内容: + +```yaml +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: dubbo-go-server +spec: + host: dubbo-go-server + subsets: + - name: v1 + labels: + dubbogoAppVersion: v1 # 对应应用模板中 chart/app/values.yaml 中指定的版本标签 + - name: v2 + labels: + dubbogoAppVersion: v2 +``` + +### 3.2 应用 Virtual Service + +执行以下命令以创建路由,该路由将所有流量都路由至v1 版本应用。 + +```bash +$ kubectl apply -f virtualservice.yaml +``` + +virtualservice.yaml 内容 + +```yaml +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: dubbo-go-server +spec: + hosts: + - dubbo-go-server + http: + - route: + - destination: + host: dubbo-go-server + subset: v1 +``` + + + +### 3.3 验证路由生效 + +所有流量将流向 v1 版本应用。 + +```bash +$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs +... +2022-04-07T05:40:44.353Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:40:45.354Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:40:46.356Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:40:47.357Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:40:48.359Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:40:49.361Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" +``` + + + +## 4. 基于用户身份的路由 + +有了上述多版本应用路由的基础,我们可以通过一些策略,来进行灵活的流量管理。 + +### 4.1 为客户端应用增加用户身份标识 + +我们希望拥有 user: admin 标识的流量都可以体验 v2 新版本应用。 + +回到之前创建的 dubbo-go-client 项目,修改 cmd/app.go 的 main 函数,增加调用标识:`user: admin`。 + +```go +func main() { + client := &api.GreeterClientImpl{} + config.SetConsumerService(client) + if err := config.Load(); err != nil { + panic(err) + } + request := &api.HelloRequest{ + Name: "laurence", + } + + for{ + ctx := context.Background() + ctx = context.WithValue(ctx, constant.AttachmentKey, map[string]string{ + "user":"admin", // 使用上下文 context 为调用增加标识 + }) + + if rsp, err := client.SayHello(ctx, request); err != nil{ + logger.Errorf("call server error = %s", err) + }else{ + logger.Infof("call server response = %+v", rsp) + } + time.Sleep(time.Second) + } +} +``` + +- 构建、推送镜像,覆盖之前的提交。您也可以升级一下发布的镜像版本。 + + `$ make build ` (本地为 amd64机器) + + 或者 + + `$ make buildx-publish` (本地为 arm64机器,依赖 docker buildx 命令) + +- 删除 dubbo-go-client 应用 + + ``` + $ make remove + helm uninstall dubbo-go-client + release "dubbo-go-client" uninstalled + ``` + +- 重新发布应用。 + + `$ make deploy` + + 发布后,验证调用成功,由于前面进行了路由配置。所有流量都流向 v1 版本。 + + ```bash + $ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs + ... + 2022-04-07T05:40:44.353Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" + 2022-04-07T05:40:45.354Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" + 2022-04-07T05:40:46.356Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" + 2022-04-07T05:40:47.357Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" + 2022-04-07T05:40:48.359Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" + 2022-04-07T05:40:49.361Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" + ``` + +### 4.2 创建基于用户身份的路由 + +执行以下命令以修改/创建路由,该路由将所有请求头存在 user: admin 标识的流量都路由至 v2 版本。 + +```bash +$ kubectl apply -f virtualservice.yaml +``` + +virtualservice.yaml 内容 + +```yaml +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: dubbo-go-server +spec: + hosts: + - dubbo-go-server + http: + - match: + - headers: + user: + exact: admin + route: + - destination: + host: dubbo-go-server + subset: v2 + - route: + - destination: + host: dubbo-go-server + subset: v1 +``` + +### 4.3 验证路由生效 + +所有流量将流向 v2 版本应用。 + +```bash +$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs +... +2022-04-07T05:52:18.714Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" +2022-04-07T05:52:19.716Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" +2022-04-07T05:52:20.717Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" +2022-04-07T05:52:21.718Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" +2022-04-07T05:52:22.720Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" +2022-04-07T05:52:23.722Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" +2022-04-07T05:52:24.723Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" +``` + + + +## 5. 基于权重的路由 + +### 5.1 创建基于权重的路由 + +延续上述任务,我们执行以下命令以修改/创建路由,该路由将流量的 10% 导入新版本应用,进行灰度测试。 + +```bash +$ kubectl apply -f virtualservice.yaml +``` + +virtualservice.yaml 内容 + +```yaml +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: dubbo-go-server +spec: + hosts: + - dubbo-go-server + http: + - route: + - destination: + host: dubbo-go-server + subset: v1 + weight: 90 + - destination: + host: dubbo-go-server + subset: v2 + weight: 10 +``` + +### 5.2 验证路由生效 + +少数流量将流向 v2 版本。 + +```bash +$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs +... +2022-04-07T05:55:52.035Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:55:53.036Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:55:54.037Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:55:55.039Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:55:56.041Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:55:57.043Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:55:58.045Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:55:59.047Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:56:00.049Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:56:01.050Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" +2022-04-07T05:56:02.053Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" +2022-04-07T05:56:03.055Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" +``` \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/tutorial/gateway/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/gateway/_index.md new file mode 100755 index 000000000000..9f9030beab91 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/gateway/_index.md @@ -0,0 +1,7 @@ +--- +description: "通过 Higress、APISIX 等网关产品解决前端 http 流量接入后端 RPC 微服务问题。" +linkTitle: HTTP网关接入 +title: HTTP流量接入 +type: docs +weight: 61 +--- diff --git a/content/en/overview/mannual/golang-sdk/tutorial/gateway/http_triple.md b/content/en/overview/mannual/golang-sdk/tutorial/gateway/http_triple.md new file mode 100644 index 000000000000..ad53a36cbb06 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/gateway/http_triple.md @@ -0,0 +1,88 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/http_triple/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/http_triple/ +description: 接入 Ingress 流量 +title: 接入 Ingress 流量 +type: docs +weight: 1 +--- + + + + + + +## 1. 准备工作 + +- kubectl +- 一个 k8s 集群,配置好 kubeconfig + +## 2. 使用 HTTP 协议通过网关调用 Triple 应用 + +Dubbo-go-pixiu 网关支持调用 GO/Java 的 Dubbo 集群。在 Dubbo-go 3.0 的场景下,我们可以通过 Pixiu 网关,在集群外以 HTTP 协议请求 pixiu 网关,在网关层进行协议转换,进一步调用集群内的Dubbo-go 服务。 + +![image.png](/imgs/docs3-v2/golang-sdk/tasks/pixiu/http_triple/triple-pixiu.png) + +用户调用 Dubbo-go 服务的 path 为http://$(app_name)/$(service_name)/$(method)。 + +例如一个proto文件内有如下定义: + +```protobuf +package org.apache.dubbo.quickstart.samples; + +service UserProvider { + rpc SayHello (HelloRequest) returns (User) {} +} + +message HelloRequest { + string name = 1; +} +``` + +并在dubbo-go 服务启动时在dubbogo.yml 内配置应用名为my-dubbogo-app: + +```yaml +dubbo: + application: + name: my-dubbogo-app +``` + +pixiu 网关即可解析 path 为 my-dubbogo-app/org.apache.dubbo.quickstart.samples.UserProvider/SayHello 的路由,并转发至对应服务。来自外部HTTP 请求的 body 为 json 序列化的请求参数,例如 {"name":"test"}。 + +我们目前推荐使用 Nacos 作为注册中心。 + +用户可以在自己的集群里部署我们的demo,集群最好拥有暴露 lb 类型 service 的能力,从而可以在公网访问至集群内的服务,您也可以直接集群内进行请求。 + +针对您的集群,执行: + +```bash +$ kubectl apply -f https://raw.githubusercontent.com/dubbogo/triple-pixiu-demo/master/deploy/pixiu-triple-demo.yml +``` + +会在 dubbogo-triple-nacos 命名空间下创建如下资源,包含三个 triple-server,一个pixiu网关,一个 nacos server。并通过 Servcie 将服务暴露至公网。 + +```bash +namespace/dubbogo-triple-nacos created +service/dubbo-go-nacos created +deployment.apps/dubbogo-nacos-deployment created +deployment.apps/pixiu created +deployment.apps/server created +service/pixiu created +``` + +获取 pixiu 公网 ip 并进行调用 + +```pgsql +$ kubectl get svc -n dubbogo-triple-nacos +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +dubbo-go-nacos ClusterIP 192.168.123.204 8848/TCP 32s +pixiu LoadBalancer 192.168.156.175 30.XXX.XXX.XX 8881:30173/TCP 32s +``` + +通过curl 调用 demo 服务,并获得响应结果。 + +```bash +$ curl -X POST -d '{"name":"laurence"}' http://30.XXX.XXX.XX:8881/dubbogoDemoServer/org.apache.dubbo.laurence.samples.UserProvider/SayHello +{"name":"Hello laurence","id":"12345","age":21} +``` \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/tutorial/gateway/pixiu-nacos-triple.md b/content/en/overview/mannual/golang-sdk/tutorial/gateway/pixiu-nacos-triple.md new file mode 100644 index 000000000000..779cd6e8abf8 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/gateway/pixiu-nacos-triple.md @@ -0,0 +1,79 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/pixiu-nacos-triple/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/pixiu-nacos-triple/ +description: 使用 Pixiu 暴露 Dubbo-go 服务 +title: 使用 Pixiu 暴露 Dubbo-go 服务 +type: docs +weight: 9 +--- + + + + + + +Dubbo-go-pixiu 网关支持调用 GO/Java 的 Dubbo 集群。在 Dubbo-go 3.0 的场景下,我们可以通过 Pixiu 网关,在集群外以 HTTP 协议请求 pixiu 网关,在网关层进行协议转换,进一步调用集群内的Dubbo-go 服务。 + +![img](/imgs/docs3-v2/golang-sdk/samples/pixiu-nacos-triple/triple-pixiu.png) + +用户调用 Dubbo-go 服务的 path 为http://$(app_name)/$(service_name)/$(method) + +例如一个proto文件内有如下定义: + +```protobuf +package org.apache.dubbo.quickstart.samples; + +service UserProvider { + rpc SayHello (HelloRequest) returns (User) {} +} + +message HelloRequest { + string name = 1; +} +``` + +并在dubbo-go 服务启动时在dubbogo.yml 内配置应用名为my-dubbogo-app: + +```yaml +dubbo: + application: + name: my-dubbogo-app +``` + +pixiu 网关即可解析 path 为 http://my-dubbogo-app/org.apache.dubbo.quickstart.samples.UserProvider/SayHello 的路由,并转发至对应服务。来自外部HTTP 请求的 body 为 json 序列化的请求参数,例如 {"name":"test"}。 + +我们目前推荐使用 Nacos 作为注册中心。 + +用户可以在自己的集群里部署我们的demo,集群最好拥有暴露 lb 类型 service 的能力,从而可以在公网访问至集群内的服务,您也可以直接集群内进行请求。针对您的集群,执行: + +```bash +$ kubectl apply -f https://raw.githubusercontent.com/dubbogo/triple-pixiu-demo/master/deploy/pixiu-triple-demo.yml +``` + +会在 dubbogo-triple-nacos 命名空间下创建如下资源,包含三个 triple-server,一个pixiu网关,一个 nacos server。并通过 Servcie 将服务暴露至公网。 + +```plain +namespace/dubbogo-triple-nacos created +service/dubbo-go-nacos created +deployment.apps/dubbogo-nacos-deployment created +deployment.apps/pixiu created +deployment.apps/server created +service/pixiu created +``` + +获取 pixiu 公网 ip 并进行调用 + +```plain +$ kubectl get svc -n dubbogo-triple-nacos +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +dubbo-go-nacos ClusterIP 192.168.123.204 8848/TCP 32s +pixiu LoadBalancer 192.168.156.175 30.XXX.XXX.XX 8881:30173/TCP 32s +``` + +通过curl 调用 demo 服务,并获得响应结果。 + +```bash +$ curl -X POST -d '{"name":"laurence"}' http://30.XXX.XXX.XX:8881/dubbogoDemoServer/org.apache.dubbo.laurence.samples.UserProvider/SayHello +{"name":"Hello laurence","id":"12345","age":21} +``` \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/_index.md new file mode 100755 index 000000000000..cb383816a580 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/debugging/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ + - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/interflow/call_java/ +description: "实现 dubbo go 和 dubbo java 应用互通,包括服务发现、协议通信等。" +title: 与dubbo-java互通 +type: docs +weight: 90 +--- diff --git a/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_dubbo_non_protobuf.md b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_dubbo_non_protobuf.md new file mode 100644 index 000000000000..d181013f460d --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_dubbo_non_protobuf.md @@ -0,0 +1,77 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java/ +description: "如果您是 dubbo java 的老用户,可能您的 dubbo java 应用并没有使用 protobuf(直接使用 java interface 定义服务),这个时候您需要使用以下方式开发 dubbo go-client,来调用老版本的 dubbo 服务。" +title: 非protoubf模式协议互通(适用于老版本 dubbo java 应用) +linkTitle: 非protoubf模式协议互通 +type: docs +weight: 4 +--- + +{{% alert title="注意" color="warning" %}} +在阅读本文档之前,请记住我们推荐使用 protobuf+triple 的模式编写 java 和 go 语言互通的服务。本文仅当您已经有老版本 dubbo java 应用的情况下适用,否则的话请参考上一篇文档,使用 protobuf+triple 开发服务。 +{{% /alert %}} + + +可在此查看本文档 [完整示例源码](https://github.com/apache/dubbo-go-samples/tree/main/java_interop/non-protobuf-dubbo)。 + + +## go-client 调用 java-server +但如果您是 dubbo java 的老用户,可能您的 dubbo java 应用并没有使用 protobuf(直接使用 java interface 定义服务),这个时候您需要使用以下方式开发 dubbo go-client,来调用老版本的 dubbo 服务。 + +> 以下方案同时支持 triple(non-protobuf) 和 dubbo 协议,你只需要调整协议配置 `client.WithClientProtocolTriple()` 即可。 + +假设我们当前的 java 服务定义如下: + +```java +package org.apache.dubbo.samples.api; + +public interface GreetingsService { + String sayHi(String name); +} +``` + +我们需要这么编写 go-client,以实现服务调用: + +```go +// 生成共享 client,指定 +cliDubbo, _ := client.NewClient( + client.WithClientProtocolDubbo(), + client.WithClientSerialization(constant.Hessian2Serialization), +) + +// 生成服务代理,这里指定 java 服务全路径名 +connDubbo, _ := cliDubbo.Dial("org.apache.dubbo.samples.api.GreetingsService", client.WithURL("tri://localhost:50052")) + +var respDubbo string +// 发起调用,参数以数组形式指定(标准 json 格式,可参考 java 泛化调用) +connDubbo.CallUnary(context.Background(), []interface{}{"hello"}, &respDubbo, "SayHello") +``` + +接下来我们尝试运行示例: + +1. 运行 java server + +```java +./java/java-server/run.sh +``` + +检查服务运行正常: + +```shell +curl \ + --header "Content-Type: application/json" \ + --data '{"name": "Dubbo"}' \ + http://localhost:50052/org.apache.dubbo.sample.Greeter/sayHello +``` + +2. 运行 go client + +```go +go run go/go-server/cmd/client.go +``` + +## java-client 调用 go-server + +这种场景,意味着您要完全从头开发 go server 服务,这时我们建议是直接使用 protbuf 来开发 go server 服务,java client 侧也使用 protobuf 对新增服务发起调用。具体使用示例请参考上一篇文档。 diff --git a/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_triple_protobuf.md b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_triple_protobuf.md new file mode 100644 index 000000000000..f3d7e1fa350e --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_triple_protobuf.md @@ -0,0 +1,106 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java/ +description: “基于 protobuf 实现 dubbo-java 与 dubbo-go 的 triple 协议互通。” +title: 基于 protobuf 实现 triple 协议互通(适用于两边都用 protobuf 开发的场景) +linkTitle: protobuf+triple 协议互通 +type: docs +weight: 4 +--- + + +我们这里提供一个示例,演示如何使用 triple 协议实现 dubbo-java 和 dubbo-go 互通,可在此查看 [示例完整源码](https://github.com/apache/dubbo-go-samples/tree/main/java_interop/protobuf-triple)。 + +示例主要内容如下: +- go,go 语言实现的 rpc server 与 client +- java,java 语言实现的 rpc server 与 client + +## 共享 protobuf 服务定义 + +共享服务定义如下,请注意以下 `package`、`go_package `、`java_package` 的具体定义: + +```protobuf +//protoc --go_out=. --go_opt=paths=source_relative --go-triple_out=. greet.proto +syntax = "proto3"; +package org.apache.dubbo.sample; + +option go_package = "github.com/apache/dubbo-go-samples/java_interop/protobuf-triple/go/proto;proto"; +//package of go +option java_package = 'org.apache.dubbo.sample'; +option java_multiple_files = true; +option java_outer_classname = "HelloWorldProto"; +option objc_class_prefix = "WH"; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello(HelloRequest) returns (HelloReply); + // Sends a greeting via stream + // rpc SayHelloStream (stream HelloRequest) returns (stream HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} +``` + +## java-client调用go-server + +1. 首先启动 go server: + +```shell +go run go/go-server/cmd/server.go +``` + +运行以上命令后,go server 运行在 50052 端口,可通过以下命令测试服务运行正常: + +```shell +curl \ + --header "Content-Type: application/json" \ + --data '{"name": "Dubbo"}' \ + http://localhost:50052/org.apache.dubbo.sample.Greeter/sayHello +``` + +2. 启动 java client + +运行以下命令,启动 java 客户端,可以看到服务调用 go server 正常输出结果: + +```shell +./java/java-client/run.sh +``` + +## go-client调用java-server + +1. 启动 java server + +运行以下命令,启动 java 服务端: + +> 注意,请关闭之前启动的 go server,避免出现端口占用冲突。 + +```shell +./java/java-server/run.sh +``` + +可通过以下命令测试服务运行正常: + +```shell +curl \ + --header "Content-Type: application/json" \ + --data '{"name": "Dubbo"}' \ + http://localhost:50052/org.apache.dubbo.sample.Greeter/sayHello +``` + +2. 运行 go client + +运行以下命令启动 go 客户端,可以看到服务调用 java server 正常输出结果: + +```shell +go run go/go-client/cmd/client.go +``` diff --git a/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/service-discovery.md b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/service-discovery.md new file mode 100644 index 000000000000..183169109f9c --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/service-discovery.md @@ -0,0 +1,80 @@ +--- +description: "dubbo-java 和 dubbo-go 使用相同的服务发现模型,本文档演示如何基于应用级服务发现实现地址互通。" +title: 基于应用级服务发现实现地址互通 +linkTitle: 服务发现实现地址互通 +type: docs +weight: 6 +--- + +前面两篇示例我们演示了 dubbo java 和 dubbo go 在协议层面的互通能力,涵盖 triple 和 dubbo 两种协议, +* [非 protoubf 模式协议互通(triple 和 dubbo 协议)](../call_java_protocol_dubbo_non_protobuf) +* [protobuf+triple 协议互通(triple 协议)](../call_java_protocol_triple_protobuf) + +在本篇文档中,我们将演示 dubbo java 和 dubbo go 的服务发现互通能力,这样结合协议兼容性,我们就能实现完整的打通 dubbo java 和 dubbo go 微服务体系。 + + +本文档使用 Nacos 注册中心作为演示,可在此查看本文档 [示例完整源码](https://github.com/apache/dubbo-go-samples/tree/main/java_interop/service_discovery)。 + + +> before run the code , you should Follow this instruction to install and start Nacos server. + +## 应用级别服务发现 + +```shell +cd service +``` +**start java server** +```shell +cd java-server +sh run.sh +``` + +**start go client** +```shell +cd go-client +go run client.go + +``` + +#### go server <-> java client +**start go server** +```shell +cd go-server +go run server.go +``` +**start java client** +```shell +cd java-client +sh run.sh +``` + +## 接口级别服务发现(仅dubbo2用户关注) +### how to run +#### java server <-> go client +```shell +cd interface +``` +**start java server** +```shell +cd java-server +sh run.sh +``` + +**start go client** +```shell +cd go-client +go run client.go + +``` + +#### go server <-> java client +**start go server** +```shell +cd go-server +go run server.go +``` +**start java client** +```shell +cd java-client +sh run.sh +``` diff --git a/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/_index.md new file mode 100755 index 000000000000..e60338535880 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/debugging/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ + - /zh-cn/overview/mannual/golang-sdk/tutorial/debugging/grpc_cli/ +description: "实现 dubbo go 与谷歌官方版本 grpc 框架互通。" +title: 与grpc互通 +type: docs +weight: 100 +--- diff --git a/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/call_grpc.md b/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/call_grpc.md new file mode 100644 index 000000000000..1fcee98563f6 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/call_grpc.md @@ -0,0 +1,244 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/develop/interflow/call_grpc/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/interflow/call_grpc/ +description: 与 gRPC 应用互通 +title: 与 gRPC 应用互通 +type: docs +weight: 5 +--- + +## 1.介绍 + +triple 协议 100% 兼容 gRPC,本示例演示使用 dubbo-go 开发与 grpc 互调的应用,可在此查看 完整示例源码地址 + +## 2.如何互通 + +Dubbo-go的Triple协议能够兼容grpc协议 +在创建服务端时,可以设置`protocol.WithTriple()`使用Triple协议 + +```go + srv, err := server.NewServer( + server.WithServerProtocol( + protocol.WithPort(20000), + protocol.WithTriple(), + ), + ) +``` + +## 3.案例 + +### 3.1服务端介绍 + +#### 服务端proto文件 + +源文件路径:dubbo-go-sample/rpc/grpc/proto/greet.proto + +```protobuf +syntax = "proto3"; + +package greet; + +option go_package = "github.com/apache/dubbo-go-samples/rpc/grpc/proto;greet"; + +message GreetRequest { + string name = 1; +} + +message GreetResponse { + string greeting = 1; +} + +service GreetService { + rpc Greet(GreetRequest) returns (GreetResponse) {} +} +``` + +#### dubbo-go服务端 + +源文件路径:dubbo-go-sample/rpc/grpc/go-server/cmd/main.go + +```go +type GreetTripleServer struct { +} + +func (srv *GreetTripleServer) Greet(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) { + resp := &greet.GreetResponse{Greeting: "dubbo:" + req.Name} + return resp, nil +} + +func main() { + srv, err := server.NewServer( + server.WithServerProtocol( + protocol.WithPort(20000), + protocol.WithTriple(), + ), + ) + if err != nil { + panic(err) + } + + if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{}); err != nil { + panic(err) + } + + if err := srv.Serve(); err != nil { + logger.Error(err) + } +} +``` + +#### grpc服务端 + +源文件路径: dubbo-go-sample/rpc/grpc/grpc-server/cmd/main.go + +```go +type server struct { + pb.UnimplementedGreetServiceServer +} + +func (s *server) Greet(ctx context.Context, req *pb.GreetRequest) (*pb.GreetResponse, error) { + resp := &pb.GreetResponse{Greeting: "grpc:" + req.Name} + return resp, nil +} + +func main() { + lis, err := net.Listen("tcp", "127.0.0.1:20001") + if err != nil { + logger.Fatalf("failed to listen: %v", err) + } + s := grpc.NewServer() + pb.RegisterGreetServiceServer(s, &server{}) + logger.Infof("server listening at %v", lis.Addr()) + if err := s.Serve(lis); err != nil { + logger.Fatalf("failed to serve: %v", err) + } +} + +``` + +### 3.2客户端介绍 + +#### dubbo-go客户端 + +源文件路径:dubbo-go-sample/rpc/grpc/go-client/cmd/main.go + +```go +package main + +import ( + "context" + + "dubbo.apache.org/dubbo-go/v3/client" + _ "dubbo.apache.org/dubbo-go/v3/imports" + greet "github.com/apache/dubbo-go-samples/rpc/grpc/proto" + "github.com/dubbogo/gost/log/logger" +) + +func main() { + // test connect with dubbo + dubboCli, err := client.NewClient( + client.WithClientURL("127.0.0.1:20000"), + ) + if err != nil { + panic(err) + } + + svc, err := greet.NewGreetService(dubboCli) + if err != nil { + panic(err) + } + + resp, err := svc.Greet(context.Background(), &greet.GreetRequest{Name: "hello world"}) + if err != nil { + logger.Error(err) + } + logger.Infof("Greet response: %s", resp.Greeting) + + // test connect with grpc + grpcCli, err := client.NewClient( + client.WithClientURL("127.0.0.1:20001"), + ) + if err != nil { + panic(err) + } + svc, err = greet.NewGreetService(grpcCli) + if err != nil { + panic(err) + } + resp, err = svc.Greet(context.Background(), &greet.GreetRequest{Name: "hello world"}) + if err != nil { + logger.Error(err) + } + logger.Infof("Greet response: %s", resp.Greeting) +} +``` + +#### grpc客户端 + +源文件路径:dubbo-go-sample/rpc/grpc/grpc-client/cmd/main.go + +```go +package main + +import ( + "context" + "time" + + "github.com/dubbogo/gost/log/logger" + + pb "github.com/apache/dubbo-go-samples/rpc/grpc/proto" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +func main() { + // test connect with grpc + grpcConn, err := grpc.Dial("127.0.0.1:20001", grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + logger.Fatalf("did not connect: %v", err) + } + defer grpcConn.Close() + c := pb.NewGreetServiceClient(grpcConn) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + resp, err := c.Greet(ctx, &pb.GreetRequest{Name: "hello world"}) + if err != nil { + logger.Fatalf("could not greet: %v", err) + } + logger.Infof("Greet response: %s", resp.Greeting) + + // test connect with dubbo + dubboConn, err := grpc.Dial("127.0.0.1:20000", grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + logger.Fatalf("did not connect: %v", err) + } + defer dubboConn.Close() + c = pb.NewGreetServiceClient(dubboConn) + ctx, cancel = context.WithTimeout(context.Background(), time.Second) + defer cancel() + resp, err = c.Greet(ctx, &pb.GreetRequest{Name: "hello world"}) + if err != nil { + logger.Fatalf("could not greet: %v", err) + } + logger.Infof("Greet response: %s", resp.Greeting) +} +``` + +### 3.3案例效果 + +先启动dubbo-go服务端和grpc服务端,然后启动dubbo-go客户端和grpc客户端,观察控制台输出 + +Dubbo-go客户端输出: + +```shell +Greet response: dubbo:hello world +Greet response: grpc:hello world +``` + +grpc客户端输出: + +```shell +Greet response: grpc:hello world +Greet response: dubbo:hello world +``` diff --git a/content/en/overview/mannual/golang-sdk/tutorial/load-balance/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/load-balance/_index.md new file mode 100755 index 000000000000..04bf7fe15e90 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/load-balance/_index.md @@ -0,0 +1,6 @@ +--- +description: "框架支持的负载均衡策略与配置方法。" +title: 负载均衡 +type: docs +weight: 23 +--- diff --git a/content/en/overview/mannual/golang-sdk/tutorial/load-balance/loadbalance.md b/content/en/overview/mannual/golang-sdk/tutorial/load-balance/loadbalance.md new file mode 100644 index 000000000000..81bf94c7d4ec --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/load-balance/loadbalance.md @@ -0,0 +1,61 @@ +--- +description: "Dubbo 支持的消费端负载均衡策略及其使用方法。" +linkTitle: 负载均衡 +title: 负载均衡策略与配置细节 +type: docs +weight: 1 +--- + +Dubbo-go 内置了 client-based 负载均衡机制,如下是当前支持的负载均衡算法,结合上文提到的自动服务发现机制,消费端会自动使用 `Weighted Random LoadBalance 加权随机负载均衡策略` 选址调用。 + +如果要调整负载均衡算法,以下是 Dubbo 框架内置的负载均衡策略: + +| 算法 | 特性 | 备注 | 配置值 | +| :-------------------------- | :---------------------- | :---------------------------------------------- | :---------------------------------------------- | +| Weighted Random LoadBalance | 加权随机 | 默认算法,默认权重相同 | random (默认) | +| RoundRobin LoadBalance | 加权轮询 | 借鉴于 Nginx 的平滑加权轮询算法,默认权重相同 | roundrobin | +| LeastActive LoadBalance | 最少活跃优先 + 加权随机 | 背后是能者多劳的思想 | leastactive | +| Consistent Hash LoadBalance | 一致性哈希 | 确定的入参,确定的提供者,适用于有状态请求 | consistenthashing | +| P2C LoadBalance | Power of Two Choice | 随机选择两个节点后,继续选择“连接数”较小的那个节点。 | p2c | +| Interleaved Weighted Round Robin | 一种加权轮训算法 | https://en.wikipedia.org/wiki/Weighted_round_robin#Interleaved_WRR | interleavedweightedroundrobin | +| Alias Method Round Robin | | https://en.wikipedia.org/wiki/Alias_method | aliasmethod | + +## 全局配置 +Dubbo 框架的默认策略是 `random` 加权随机负载均衡。如果要调整策略,只需要设置 `loadbalance` 相应取值即可,每种负载均衡策略取值请参见文档最上方表格。 + +为所有服务调用指定全局配置: + +```go +cli, err := client.NewClient( + client.WithClientLoadBalance("roundrobin"), +) +``` + +或者一些常用的策略: + +```go +cli, err := client.NewClient( + client.WithClientLoadBalanceRoundRobin(), +) +``` + +## 接口级配置 +```go +cli, err := client.NewClient( + //... +) + +svc, err := greet.NewGreetService(cli, client.WithLoadBalance("roundrobin")) +``` + +或者一些常用的策略: + +```go +cli, err := client.NewClient( + //... +) + +svc, err := greet.NewGreetService(cli, client.WithLoadBalanceRoundRobin()) +``` + + diff --git a/content/en/overview/mannual/golang-sdk/tutorial/observability/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/observability/_index.md new file mode 100755 index 000000000000..3ebc15411dc7 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/observability/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/debugging/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ + - /zh-cn/overview/mannual/golang-sdk/tutorial/governance/monitor/ +description: "可视化查看应用内部状态,包括日志、metrics指标监控、全链路追踪等" +title: 可视化观测 +type: docs +weight: 40 +--- diff --git a/content/en/overview/mannual/golang-sdk/tutorial/observability/logger.md b/content/en/overview/mannual/golang-sdk/tutorial/observability/logger.md new file mode 100644 index 000000000000..3d5fd32cd1ab --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/observability/logger.md @@ -0,0 +1,77 @@ +--- +aliases: + - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/features/custom-logger/ +description: logger +title: 配置和管理框架日志 +linkTitle: 框架日志 +type: docs +weight: 1 +--- + +本示例演示如何配置 dubbo-go 框架日志组件,将框架运行态日志保存到指定的位置。可在此查看 完整示例源码地址。 + +{{% alert title="注意" color="info" %}} +这里配置的只是 dubbo-go 框架自身的日志组件行为,即框架内部使用的日志,不影响业务日志框架的使用! +{{% /alert %}} + +## 1. 日志配置 +如下所示,可以通过 `log.WithZap()`、`log.WithLevel("warn")` 设置 dubbo 框架日志行为: + +```go +ins, err := dubbo.NewInstance( + dubbo.WithLogger( + log.WithLevel("warn"), + log.WithZap(), + ), +) +``` + +## 2. 应用共享日志组件 +注意,这里配置的只是 dubbo-go 框架自身的日志组件行为(即框架内部使用的日志),不影响业务日志框架的使用! + +**通过以下方式,业务应用也可以选择复用这个日志组件:** + +```go +import app_logger "github.com/dubbogo/gost/log/logger" + +app_logger.Info("hello") +``` + +日志 Interface + +```go +type Logger interface { + Info(args ...interface{}) + Warn(args ...interface{}) + Error(args ...interface{}) + Debug(args ...interface{}) + Fatal(args ...interface{}) + + Infof(fmt string, args ...interface{}) + Warnf(fmt string, args ...interface{}) + Errorf(fmt string, args ...interface{}) + Debugf(fmt string, args ...interface{}) + Fatalf(fmt string, args ...interface{}) +} +``` + +{{% alert title="注意" color="info" %}} +日志API不可以在Init 阶段使用,否则可能会发生意料之外的问题。 +{{% /alert %}} + +## 2. 完全自定义日志 +当前 dubbo-go 框架支持 zap、logrus 两个日志框架,如果您想让 dubbo 框架内核使用其他日志框架打印日志,推荐以标准扩展形式增加支持,具体可参考核心库中内置的 [源码实现](https://github.com/apache/dubbo-go/tree/main/logger)。 + +## 3. 访问日志 + +可以通过以下方式配置开启访问日志: + +```go +srv, err := server.NewServer( + server.WithAccesslog("true"), + // server.WithAccesslog("default"), + // server.WithAccesslog("/your/path/to/store/the/log/logfile"), +) +``` + +对于 `true` 和 `default` 而言,访问日志会使用 Dubbo 中的 logger 组件打印出来。如果指定了具体的日志文件路径,则直接写入到该文件。 diff --git a/content/en/overview/mannual/golang-sdk/tutorial/observability/rpc_metrics.md b/content/en/overview/mannual/golang-sdk/tutorial/observability/rpc_metrics.md new file mode 100644 index 000000000000..79f58b00ddb2 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/observability/rpc_metrics.md @@ -0,0 +1,147 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/governance/monitor/rpc_metrics/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/monitor/rpc_metrics/ +description: "采集运行态 Metrics 指标并接入 Prometheus、Grafana 系统" +title: metrics监控 +type: docs +weight: 2 +--- + +Dubbo 支持采集运行态 Metrics 指标并接入 Prometheus、Grafana 系统,实现对微服务集群的可视化监控,以下是一个具体的使用示例,可查看 [示例完整源码](https://github.com/apache/dubbo-go-samples/tree/main/metrics)。 + +## Contents + +- server/main.go - is the main definition of the service, handler and rpc server +- client/main.go - is the rpc client +- proto - contains the protobuf definition of the API + +## How to run + +### Run server +```shell +go run ./go-server/cmd/main.go +``` + +test server work as expected: +```shell +curl \ + --header "Content-Type: application/json" \ + --data '{"name": "Dubbo"}' \ + http://localhost:20000/greet.GreetService/Greet +``` + +### Run client +```shell +go run ./go-client/cmd/main.go +``` + +## deploy to local +install prometheus and open prometheus config file `prometheus.yml`, write the config like this + +```yaml +global: + evaluation_interval: 15s + scrape_interval: 15s +scrape_configs: +- job_name: dubbo-provider + scrape_interval: 15s + scrape_timeout: 5s + metrics_path: /prometheus + static_configs: + - targets: ['localhost:9099'] +- job_name: dubbo-consumer + scrape_interval: 15s + scrape_timeout: 5s + metrics_path: /prometheus + static_configs: + - targets: ['localhost:9097'] +``` + +install grafana and open grafana web page like `localhost:3000` + +open: 【Home / Connections / Data sources】 + +click 【Add new data source】 + +select Prometheus + +enter 【Prometheus server URL】 like `http://localhost:9090` and click 【Save & test】 + +![datasource.png](/imgs/golang/metrics/dashboard.png) + +open 【Home / Dashboards 】click 【New】【import】and enter 19294 click Load + +![import](/imgs/golang/metrics/import.png) + +if your grafana can't access internet you can open `https://grafana.com/grafana/dashboards/19294-dubbo-observability/` and click 【Download JSON】 + +paste the JSON + +![json.png](/imgs/golang/metrics/import-json.png) + +![datasource.png](/imgs/golang/metrics/import-datasource.png) + +click 【Import】button and you will see the Dubbo Observability dashboard,enjoy it + +![databoard](/imgs/golang/metrics/dashboard.png) + +## Deploy to Kubernetes + +#### kube-prometheus + +install prometheus in k8s [kube-prometheus](https://github.com/prometheus-operator/kube-prometheus) + +Set `prometheus-service.yaml` type to NodePort + +1. add `dubboPodMoitor.yaml` to `kube-prometheus` `manifests` dir, The content is as follows + ```yaml +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: podmonitor + labels: + app: podmonitor + namespace: monitoring +spec: + namespaceSelector: + matchNames: + - dubbo-system + selector: + matchLabels: + app-type: dubbo + podMetricsEndpoints: + - port: metrics # ref to dubbo-app port name metrics + path: /prometheus +--- +# rbac +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: dubbo-system + name: pod-reader +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch"] + +--- +# rbac +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: pod-reader-binding + namespace: dubbo-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: pod-reader +subjects: + - kind: ServiceAccount + name: prometheus-k8s + namespace: monitoring +``` +2. `kubectl apply -f Deployment.yaml` +3. open prometheus web page such as http://localhost:9090/targets + ![podmonitor.png](/imgs/golang/metrics/podmonitor.png) + diff --git a/content/en/overview/mannual/golang-sdk/tutorial/observability/tracing.md b/content/en/overview/mannual/golang-sdk/tutorial/observability/tracing.md new file mode 100644 index 000000000000..7f2940334491 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/observability/tracing.md @@ -0,0 +1,85 @@ +--- +description: 全链路追踪 +title: 链路追踪 +linkTitle: 全链路追踪 +type: docs +weight: 3 +--- + +Dubbo-go 支持基于 [OpenTelemetry](https://opentelemetry.io/) 标准的全链路追踪埋点,同时支持通过以下 exporter 导出到不同的 tracing 后端系统。 + +- [Stdout exporter](./stdout) +- [Jaeger exporter](./jaeger) +- [Zipkin exporter](./zipkin) +- [OTLP-HTTP exporter](./otlp-http) +- [OTLP-gRPC exporter](./otlp-grpc) + +## 使用方式 + +请注意,仅支持通过 `dubbo.NewInstance` 方式创建 dubbo 应用时开启 tracing 功能,也就是我们快速开始中提到的 [微服务应用模式](),对于 [轻量 RPC API]() 暂时不支持开启 tracing。 + +## 示例详解 +可在此查看 完整示例源码地址。 + +使用 `dubbo.WithTracing()` 开启 tracing,可以通过多个参数控制 tracing 行为: + +```go +package main + +import ( + "dubbo.apache.org/dubbo-go/v3" + _ "dubbo.apache.org/dubbo-go/v3/imports" + "dubbo.apache.org/dubbo-go/v3/otel/trace" +) + +func main() { + instance, err := dubbo.NewInstance( + dubbo.WithTracing( + // add tracing options here + trace.WithEnabled(), // enable tracing feature + trace.WithStdoutExporter(), + trace.WithW3cPropagator(), + trace.WithAlwaysMode(), + trace.WithRatioMode(), // use ratio mode + trace.WithRatio(0.5), // sample ratio, only active when use ratio mode + ), + ) +} + +``` + +如果你在 `dubbo.WithTracing()` 调用中不指定任何 option 参数,则会使用默认行为: + +```yaml +# default tracing config +enable: false +exporter: stdout +endpoint: "" +propagator: w3c +sample-mode: ratio +sample-ratio: 0.5 +``` + +## TracingOptions详解 + +- enable: enable tracing or not + - `trace.WithEnabled()` means enable tracing +- exporter: tracing exporter backends, support stdout, jaeger, zipkin, otlp-http, otlp-grpc + - `trace.WithStdoutExporter()` + - `trace.WithJaegerExporter()` + - `trace.WithZipkinExporter()` + - `trace.WithOtlpHttpExporter()` + - `trace.WithOtlpGrpcExporter()` +- endpoint: exporter backend endpoint, for example, jaeger exporter's endpoint is `http://localhost:14268/api/traces` + - `trace.WithEndpoint(string)` +- propagator: context propagator type, support w3c, b3, more details you can see [here](https://opentelemetry.io/docs/concepts/context-propagation/) + - `trace.WithW3cPropagator()` + - `trace.WithB3Propagator()` zipkin exporter default use this +- sample-mode: sample mode, support ratio, always, never + - `trace.WithAlwaysMode()` + - `trace.WithNeverMode()` + - `trace.WithRatioMode()` +- sample-ratio: sample ratio, only used when sample-mode is ratio, range between 0 and 1 + - `trace.WithRatio(float64)` + + diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/_index.md new file mode 100755 index 000000000000..2ad00452f7bb --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/_index.md @@ -0,0 +1,9 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/debugging/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ +description: "rpc 框架通信常用的一些功能与配置方式,包括流式通信、超时时间、Filter拦截器、附加参数、健康检查等。" +title: RPC框架 +type: docs +weight: 10 +--- diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/attachments.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/attachments.md new file mode 100644 index 000000000000..30fd431ce455 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/attachments.md @@ -0,0 +1,181 @@ +--- +description: 传递附加参数 attachment +title: 传递附加参数 +type: docs +weight: 4 +--- + +**理解隐式参数传递的最直接方式 http header,它的工作方式与 http header 完全一致,在 GET 或 POST 请求体之外可以传递任意多个 header 参数**。而对于 RPC 调用而言,context就是在方法签名的参数之外提供附加参数传递能力,在实现原理上,对于不同的协议,attachment 的实现方式略有不同: +* 对于 triple 协议,attachment 会转换为标准的 http header 进行传输。 +* 对于 dubbo 协议,attachment 是编码在协议体的固定位置进行传输,具体请参见 dubbo 协议规范。、 + +![/user-guide/images/context.png](/imgs/user/context.png) + +{{% alert title="注意" color="primary" %}} +* 在使用 triple 协议时,由于 http header 的限制,仅支持小写的 ascii 字符 +* path, group, version, dubbo, token, timeout 等一些 key 是保留字段,传递 attachment 时应避免使用,尽量通过业务前缀等确保 key 的唯一性。 +{{% /alert %}} + +## 1.介绍 + +本文档演示如何在 Dubbo-go 框架中使用 context 上下文传递和读取附加参数,来实现上下文信息传递,可在此查看 完整示例源码地址 + +## 2.使用说明 +### 2.1客户端使用说明 + +在客户端中,使用下述方式传递字段, 示例中 key 为 `constant.AttachmentKey` 即 "attachment": + +```go + ctx := context.Background() + ctx = context.WithValue(ctx, constant.AttachmentKey, map[string]interface{}{ + "key1": "user defined value 1", + "key2": "user defined value 2" + }) +``` + +### 2.2服务端使用说明 + +在服务端中,使用下述方式获取字段, value的类型为 map[string]interface{}: +```go + attachments := ctx.Value(constant.AttachmentKey).(map[string]interface{}) + logger.Infof("Dubbo attachment key1 = %s", value1.([]string)[0]) + logger.Infof("Dubbo attachment key2 = %s", value2.([]string)[0]) +``` + +## 3.示例详解 + +### 3.1服务端介绍 + +#### 服务端proto文件 + +源文件路径:dubbo-go-sample/context/proto/greet.proto + +```protobuf +syntax = "proto3"; + +package greet; + +option go_package = "github.com/apache/dubbo-go-samples/context/proto;greet"; + +message GreetRequest { + string name = 1; +} + +message GreetResponse { + string greeting = 1; +} + +service GreetService { + rpc Greet(GreetRequest) returns (GreetResponse) {} +} +``` + +#### 服务端handler文件 + +源文件路径:dubbo-go-sample/context/go-server/main.go + +```go +package main + +import ( + "context" + "dubbo.apache.org/dubbo-go/v3/common/constant" + _ "dubbo.apache.org/dubbo-go/v3/imports" + "dubbo.apache.org/dubbo-go/v3/protocol" + "dubbo.apache.org/dubbo-go/v3/server" + greet "github.com/apache/dubbo-go-samples/context/proto" + "github.com/dubbogo/gost/log/logger" +) + +type GreetTripleServer struct { +} + +func (srv *GreetTripleServer) Greet(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) { + attachments := ctx.Value(constant.AttachmentKey).(map[string]interface{}) + if value1, ok := attachments["key1"]; ok { + logger.Infof("Dubbo attachment key1 = %s", value1.([]string)[0]) + } + if value2, ok := attachments["key2"]; ok { + logger.Infof("Dubbo attachment key2 = %s", value2.([]string)[0]) + } + + resp := &greet.GreetResponse{Greeting: req.Name} + return resp, nil +} + +func main() { + srv, err := server.NewServer( + server.WithServerProtocol( + protocol.WithPort(20000), + protocol.WithTriple(), + ), + ) + if err != nil { + panic(err) + } + + if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{}); err != nil { + panic(err) + } + + if err := srv.Serve(); err != nil { + logger.Error(err) + } +} +``` + +### 3.2客户端介绍 + +客户端client文件,创建客户端,在context写入变量,发起调用并打印结果 + +源文件路径:dubbo-go-sample/context/go-client/main.go + +```go +package main + +import ( + "context" + + "dubbo.apache.org/dubbo-go/v3/client" + "dubbo.apache.org/dubbo-go/v3/common/constant" + _ "dubbo.apache.org/dubbo-go/v3/imports" + greet "github.com/apache/dubbo-go-samples/context/proto" + "github.com/dubbogo/gost/log/logger" +) + +func main() { + cli, err := client.NewClient( + client.WithClientURL("127.0.0.1:20000"), + ) + if err != nil { + panic(err) + } + + svc, err := greet.NewGreetService(cli) + if err != nil { + panic(err) + } + + ctx := context.Background() + ctx = context.WithValue(ctx, constant.AttachmentKey, map[string]interface{}{ + "key1": "user defined value 1", + "key2": "user defined value 2", + }) + + resp, err := svc.Greet(ctx, &greet.GreetRequest{Name: "hello world"}) + if err != nil { + logger.Error(err) + } + logger.Infof("Greet response: %s", resp.Greeting) +} + +``` + +### 3.3 案例效果 + +先启动服务端,再启动客户端,可以观察到服务端打印了客户端通过context传递的参数值,说明参数被成功传递并获取 + +``` +2024-02-26 11:13:14 INFO logger/logging.go:42 Dubbo attachment key1 = [user defined value 1] +2024-02-26 11:13:14 INFO logger/logging.go:42 Dubbo attachment key2 = [user defined value 2] +``` diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/error.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/error.md new file mode 100644 index 000000000000..33f590772cfb --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/error.md @@ -0,0 +1,156 @@ +--- +aliases: + - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/protocol/exception_response/ +description: "当服务端请求处理失败时,dubbo 会支持返回 error 类型值,本示例演示如何处理异常类型返回值。" +title: 异常类型返回值 +linkTitle: 异常类型返回值 +type: docs +weight: 3 +--- + +## 1.介绍 + +本文档演示如何在 RPC 调用过程中处理 error 错误类型响应,可在此查看 完整示例源码地址。 + +## 2.示例详解 + +### 2.1 服务端 + +#### 服务端proto文件 + +源文件路径:dubbo-go-sample/error/proto/greet.proto + +```protobuf +syntax = "proto3"; + +package greet; + +option go_package = "github.com/apache/dubbo-go-samples/error/proto;greet"; + +message GreetRequest { + string name = 1; +} + +message GreetResponse { + string greeting = 1; +} + +service GreetService { + rpc Greet(GreetRequest) returns (GreetResponse) {} +} +``` + +#### 服务端handler文件 + +请注意,在本程序设计中,Greet方法只有接收到 `name="right name"` 时才会认为是正确请求,否则会返回错误。 + +源文件路径:dubbo-go-sample/context/go-server/main.go + +```go +package main + +import ( + "context" + "fmt" + "github.com/pkg/errors" + + _ "dubbo.apache.org/dubbo-go/v3/imports" + "dubbo.apache.org/dubbo-go/v3/protocol" + "dubbo.apache.org/dubbo-go/v3/server" + greet "github.com/apache/dubbo-go-samples/helloworld/proto" + "github.com/dubbogo/gost/log/logger" +) + +type GreetTripleServer struct { +} + +func (srv *GreetTripleServer) Greet(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) { + name := req.Name + if name != "right name" { + errInfo := fmt.Sprintf("name is not right: %s", name) + logger.Error(errInfo) + return nil, errors.New(errInfo) + } + + resp := &greet.GreetResponse{Greeting: req.Name} + return resp, nil +} + +func main() { + srv, err := server.NewServer( + server.WithServerProtocol( + protocol.WithPort(20000), + protocol.WithTriple(), + ), + ) + if err != nil { + panic(err) + } + + if err = greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{}); err != nil { + panic(err) + } + + if err = srv.Serve(); err != nil { + logger.Error(err) + } +} + +``` + +从 rpc 方法签名中,我们可以看到 `func (srv *GreetTripleServer) Greet(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error)` 包含 error 返回值。 + +### 2.2 客户端 + +客户端分别发起两次调用,一次是正确的请求,一次是错误的请求 + +源文件路径:dubbo-go-sample/context/go-client/main.go + +```go +package main + +import ( + "context" + + "dubbo.apache.org/dubbo-go/v3/client" + _ "dubbo.apache.org/dubbo-go/v3/imports" + greet "github.com/apache/dubbo-go-samples/helloworld/proto" + "github.com/dubbogo/gost/log/logger" +) + +func main() { + cli, err := client.NewClient( + client.WithClientURL("127.0.0.1:20000"), + ) + if err != nil { + panic(err) + } + + svc, err := greet.NewGreetService(cli) + if err != nil { + panic(err) + } + + resp, err := svc.Greet(context.Background(), &greet.GreetRequest{Name: "right name"}) + if err != nil { + logger.Error(err) + } + logger.Infof("call Greet success: %s", resp.Greeting) + + resp, err = svc.Greet(context.Background(), &greet.GreetRequest{Name: "wrong name"}) + if err != nil { + logger.Errorf("call Greet failed, err: %s", err.Error()) + } +} +``` + +### 2.3 案例效果 + +先启动服务端,再启动客户端,可以观察到客户端的第一次调用成功,第二次调用失败并且服务端返回了 error + +``` +2024-02-28 17:49:40 INFO logger/logging.go:42 call Greet success: [right name] +2024-02-28 17:49:40 ERROR logger/logging.go:52 call Greet failed, err: [Failed to invoke the method Greet in the service greet.GreetService. Tried 2 times of the providers [tri://:@127.0.0.1:20000/?interface=greet.GreetService&group=&version= tri://:@127.0.0.1:20000/?interface=greet.GreetService&group=&version= tri://:@127.0.0.1:20000/?interface=greet.GreetService&group=&version=] (3/1)from the registry tri://127.0.0.1:20000/greet.GreetService?app.version=&application=dubbo.io&async=false&bean.name=greet.GreetService&cluster=failover&config.tracing=&environment=&generic=&group=&interface=greet.GreetService&loadbalance=&metadata-type=local&module=sample&name=dubbo.io&organization=dubbo-go&owner=dubbo-go&peer=true&provided-by=&reference.filter=cshutdown®istry.role=0&release=dubbo-golang-3.2.0&remote.timestamp=&retries=&serialization=protobuf&side=consumer&sticky=false×tamp=1709113780&version= on the consumer 30.221.146.234 using the dubbo version 3.2.0. Last error is unknown: name is not right: wrong name.: unknown: name is not right: wrong name] +``` + + diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/filter.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/filter.md new file mode 100644 index 000000000000..999f21a90d12 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/filter.md @@ -0,0 +1,97 @@ +--- +aliases: + - /zh-cn/overview/mannual/golang-sdk/tutorial/governance/features/custom-filter/ +description: filter拦截器 +title: filter拦截器 +type: docs +weight: 7 +--- + +Filter 过滤器动态拦截请求(request)或响应(response)以转换或使用请求或响应中包含的信息。过滤器本身通常不会创建响应,而是提供可以“附加”到任何一次 RPC 请求的通用函数。Dubbo Filter 是可插拔的,我们可以在一次 RPC 请求中插入任意类型的、任意多个 Filter。 + +Filter 工作原理如下图所示: + + + + +## 使用方式 +### 1. Filter 拦截器概念 + +Filter 定义如下: + +```go +// Filter interface defines the functions of a filter +// Extension - Filter +type Filter interface { + // Invoke is the core function of a filter, it determines the process of the filter + Invoke(context.Context, protocol.Invoker, protocol.Invocation) protocol.Result + // OnResponse updates the results from Invoke and then returns the modified results. + OnResponse(context.Context, protocol.Result, protocol.Invoker, protocol.Invocation) protocol.Result +} +``` + +Filter 可以加载在 Consumer 端或者 Provider端。当加载在 Consumer 端,其Invoke函数调用的下游为网络层,OnResponse 为请求结束从网络层获取到返回结果后被调用。当加载在 Provider 端,其 Invoke 函数调用的下游为用户代码,OnResponse 为用户代码执行结束后向下传递至网络层前被调用。 + +Filter 采用面向切面设计的思路,通过对 Filter 的合理扩展,可以记录日志、设置数据打点,记录 invoker 所对应服务端性能,限流等等工作。 + +### 2. 框架预定义 Filter + +框架预定义了一系列filter,可以在配置中直接使用,其代码实现位于 [filter](https://github.com/apache/dubbo-go/tree/main/filter) + +- accesslog +- active +- sign: AuthConsumerFilter +- auth: AuthProviderFilter +- echo +- execute: ExecuteLimitFilter +- generic: GenericFilter +- generic_service: GenericServiceFilter +- pshutdown: GracefulShutdownProviderFilter +- cshutdown: GracefulShutdownConsumerFilter +- hystrix_consumer: HystrixConsumerFilter +- hystrix_provider: HystrixProviderFilter +- metrics +- seata +- sentinel-provider +- sentinel-consumer +- token +- tps +- tracing + +### 3. 默认加载Filter + +用户在配置文件中配置了自定义 Filter 加载策略时,框架将同时加载用户配置的 filters 和默认 filters,否则仅加载默认 filters。当前版本默认激活的 filter 列表如下: + +- Consumer: cshutdown +- Provider: echo, metrics, token, accesslog, tps, generic_service, executivete, pshutdown + +### 4. 自定义Filter + +用户可在代码中自定义 Filter,注册到框架上,并在配置中选择使用。 + +```go +func init() { + extension.SetFilter("myCustomFilter", NewMyClientFilter) +} + +func NewMyClientFilter() filter.Filter { + return &MyClientFilter{} +} + +type MyClientFilter struct { +} + +func (f *MyClientFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { + fmt.Println("MyClientFilter Invoke is called, method Name = ", invocation.MethodName()) + return invoker.Invoke(ctx, invocation) +} +func (f *MyClientFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, protocol protocol.Invocation) protocol.Result { + fmt.Println("MyClientFilter OnResponse is called") + return result +} +``` + +## 完整示例 +可通过以下链接学习如何使用 API 配置和启用 Filter 的 完整示例源码地址 + + diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/healthcheck.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/healthcheck.md new file mode 100644 index 000000000000..ec9b82a65f1f --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/healthcheck.md @@ -0,0 +1,95 @@ +--- +description: 健康检查 +title: 健康检查 +type: docs +weight: 3 +--- + +## 背景 + +Dubbo-go 内置了基于 triple 协议的健康检查服务,帮助用户管理和监测服务健康状态,可在此查看 完整示例源码。 + +## 使用方法 + +- 框架在通过 `instance` 启动后会自动向框架中注册健康检查服务 `grpc.health.v1.Health`,用于记录并对外暴露每个triple服务的健康状态。 +- 健康检查服务可以通过发起 http 请求检查框架中服务的状态,也可以通过客户端调用该健康检查服务,调用的接口为`grpc.health.v1.Health`,方法为 `check`。 + +## 1、通过客户端调用健康检查服务 + +启动 dubbo-go-samples/healthcheck/go-server 中的服务,通过下方客户端即可查看 `greet.GreetService` 的状态。 + +```go +package main + +import ( + "context" + "dubbo.apache.org/dubbo-go/v3/client" + _ "dubbo.apache.org/dubbo-go/v3/imports" + health "dubbo.apache.org/dubbo-go/v3/protocol/triple/health/triple_health" + "github.com/dubbogo/gost/log/logger" +) + +func main() { + cli, err := client.NewClient( + client.WithClientURL("tri://127.0.0.1:20000"), + ) + if err != nil { + panic(err) + } + svc, err := health.NewHealth(cli) + if err != nil { + panic(err) + } + check, err := svc.Check(context.Background(), &health.HealthCheckRequest{Service: "greet.GreetService"}) + if err != nil { + logger.Error(err) + } else { + logger.Info("greet.GreetService's health", check.String()) + } + watch, err := svc.Watch(context.Background(), &health.HealthCheckRequest{Service: "greet.GreetService"}) + if err != nil { + logger.Error(err) + } else { + if watch.Recv() { + logger.Info("greet.GreetService's health", watch.Msg().String()) + } + } +} +``` + +启动后会有以下输出 + +```sh +[greet.GreetService's health status:SERVING] +[greet.GreetService's health status:SERVING] +``` + +## 2.通过发起http请求检查服务健康状态 + +启动 dubbo-go-samples/healthcheck/go-server 中的服务,发起下方http请求即可查看 `greet.GreetService` 的状态: + +```http +POST /grpc.health.v1.Health/Check +Host: 127.0.0.1:20000 +Content-Type: application/json + +{"service":"greet.GreetService"} +``` + +将会有以下输出 + +```http +{ + "status": "SERVING" +} +``` + + +## 更多内容 +值得注意的是,当前框架中尚未建立完整的服务状态管理机制,dubbo-go 框架会将所有加载的服务设置为 `SERVING` 状态,但尚没有 `NOT SERVING` 设置机制(在满足某个特定条件的情况下将服务状态设置为 NOT SERVING)。 + +如果有需要,用户可通过扩展 dubbo-go 框架的方式,提供完整的服务状态管理能力,这样就可以查询到实时更新的服务状态,并根据服务状态进行流量转发。 + +部分参考资料: ++ https://github.com/grpc/grpc/blob/master/doc/health-checking.md ++ https://github.com/grpc/grpc-go/tree/master/health diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/protocol.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/protocol.md new file mode 100644 index 000000000000..d45d451e844b --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/protocol.md @@ -0,0 +1,143 @@ +--- +description: 配置通信协议 +title: 通信协议 +linkTitle: 通信协议 +type: docs +weight: 3 +--- + +Dubbo-go 框架内置提供了两款协议:triple、dubbo,除此之外,框架还提供了多种协议扩展接入方式。 +* triple,基于 HTTP/1、HTTP/2 的高性能通信协议,100% 兼容 gRPC,支持 Unary、Streming 等通信模式;支持发布 REST 风格的 HTTP 服务。 + * dubbo,基于 TCP 的高性能私有通信协议,缺点是通用性较差,更适合在 Dubbo SDK 间使用; + * 任意协议扩展,通过扩展 protocol 可以之前任意 RPC 协议,官方生态库提供 JsonRPC、thrift 等支持。 + +本篇文档中,我们将介绍关于 triple 协议的使用方式、如何实现与已有 dubbo2 系统的互相调用、扩展更多协议支持等。更多原理性介绍请参考 [协议规范](/zh-cn/overview/reference/protocols/triple-spec/) 或者 [dubbo java 中相关描述文档](/zh-cn/overview/mannual/java-sdk/tasks/protocols/protocol/)。 + +## triple 协议 +triple 协议支持使用 protobuf 和 non-protobuf 两种开发模式,我们 **推荐使用 protobuf 模式开发服务**。 + +目前我们大部分示例都是使用这个模式开发,可查看 [快速开始](/zh-cn/overview/mannual/golang-sdk/quickstart/rpc/) 学习完整开发示例,以下是基本步骤: + +1. 先使用 protobuf 定义服务 + +```protobuf +syntax = "proto3"; +package greet; +option go_package = "github.com/apache/dubbo-go-samples/helloworld/proto;greet"; + +message GreetRequest { + string name = 1; +} + +message GreetResponse { + string greeting = 1; +} + +service GreetService { + rpc Greet(GreetRequest) returns (GreetResponse) {} +} +``` + +2. [安装 protoc 插件](/zh-cn/overview/mannual/golang-sdk/quickstart/rpc/#前置条件),编译生成代码: +```shell +protoc --go_out=. --go_opt=paths=source_relative \ + --go-triple_out=. --go-triple_opt=paths=source_relative \ + proto/greet.proto +``` + +3. server 端发布服务 +```go +srv, err := server.NewServer( + server.WithServerProtocol( + protocol.WithPort(20000), + protocol.WithTriple(), + ), +) + +greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{}) +``` + +4. client 端调用服务 +```go +cli, err := client.NewClient( + client.WithClientURL("127.0.0.1:20000"), +) + +svc, err := greet.NewGreetService(cli) +resp, err := svc.Greet(context.Background(), &greet.GreetRequest{Name: "hello world"}) +``` + +## dubbo-java 体系互调 + +如果 java 和 go 都使用 triple+protobuf 模式,很明显他们是可以直接互调通信的。 + +但问题是很多 java 用户是使用的 triple non-protobuf 模式,还有一些老版本用户是使用的 dubbo tcp 协议。对于这部分业务,我们要可以使用 dubbo-go 框架的以下编码模式实现协议互调: + +1. 定义服务 + +直接使用 struct 定义服务: + +```go +type GreetProvider struct { +} + +func (*GreetProvider) SayHello(req string, req1 string, req2 string) (string, error) { + return req + req1 + req2, nil +} +``` + +2. server 发布服务 + +指定要发布的协议,可以是 dubbo、triple 或其他协议,请注意 `WithInterface("GreetProvider")` 要保持和 dubbo-java 侧的服务名一致(如保持 java 全路径名): + +```go +ins, err := dubbo.NewInstance( + dubbo.WithName("dubbo_server"), + dubbo.WithProtocol( + protocol.WithTriple(), + protocol.WithPort(20001)), +) + +srvDubbo, err := ins.NewServer() +if err != nil { + panic(err) +} +if err = srvDubbo.Register(&GreetProvider{}, nil, server.WithInterface("GreetProvider")); err != nil { + panic(err) +} +if err = srvDubbo.Serve(); err != nil { + logger.Error(err) +} +``` + +3. client 调用服务 + +指定要调用的协议,可以是 dubbo、triple 或其他协议,请注意 `WithInterface("GreetProvider")` 要保持和 dubbo-java 侧的服务名一致(如保持 java 全路径名): + +```go +cliDubbo, _ := client.NewClient( + client.WithClientProtocolTriple(), + client.WithClientSerialization(constant.Hessian2Serialization), +) + +connDubbo, _ := cliDubbo.Dial("GreetProvider") +ipanic(err) +} +var respDubbo string +if err = connDubbo.CallUnary(context.Background(), []interface{}{"hello", "new", "dubbo"}, &respDubbo, "SayHello"); err != nil { + logger.Errorf("GreetProvider.Greet err: %s", err) + return +} +``` + +## 协议扩展 + +Dubbo 框架支持协议扩展,目前官方生态支持的协议包括: +* triple +* dubbo +* jsonrpc + + +在一些场景下,你可以在一个应用内同时发布多个协议的服务,或者同时以不同的协议调用服务,这里有一个 [多协议发布的使用示例](https://github.com/apache/dubbo-go-samples/tree/main/multirpc) 供参考。 + + diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/retry.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/retry.md new file mode 100644 index 000000000000..f8d37d326dce --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/retry.md @@ -0,0 +1,185 @@ +--- +description: 请求重试 +title: 请求重试 +type: docs +weight: 3 +--- + +当一次服务调用失败时,我们可以让框架选择自动重试几次,这样能提高用户侧看到的请求成功率。在 failover cluster 模式下 dubbo-go 支持自动重试。 + +## 1.介绍 + +本示例演示如何在 client 端调用失败时配置重试功能,完整示例源码地址 + +## 2.如何使用重试功能 + +在使用 `client.NewClient()` 创建客户端时,可以使用 `client.WithClientRetries()` 方法设置重试次数。 + +```go +cli, err := client.NewClient( + client.WithClientURL("tri://127.0.0.1:20000"), + client.WithClientRetries(3), +) +``` + +或者,可以使用 `client.WithRequestTimeout()` 设置服务粒度的超时时间(以下配置对服务 `svc` 起作用)。 + +```go +svc, err := greet.NewGreetService(cli, client.WithClientRetries(5)) +``` + +也可以在调用发起时,使用 `client.WithCallRetries()` 指定重试次数 + +```go +resp, err := svc.Greet(context.Background(), &greet.GreetRequest{Name: "hello world"}, client.WithCallRetries(6)) +``` + +从上往下,以上三种方式的优先级逐步提高,`client.WithCallRetries()` 指定的重试次数优先级最高。 + + +## 3.示例解读 + +### 3.1服务端介绍 + +#### 服务端proto文件 + +源文件路径:dubbo-go-sample/retry/proto/greet.proto + +```protobuf +syntax = "proto3"; + +package greet; + +option go_package = "github.com/apache/dubbo-go-samples/retry/proto;greet"; + +message GreetRequest { + string name = 1; +} + +message GreetResponse { + string greeting = 1; +} + +service GreetService { + rpc Greet(GreetRequest) returns (GreetResponse) {} + rpc GreetTimeout(GreetRequest) returns (GreetResponse) {} +} +``` + +#### 服务端handler文件 + +`Greet`方法直接响应,`GreetRetry`方法用于模拟重试。 +```go +package main + +import ( + "context" + "github.com/pkg/errors" + + _ "dubbo.apache.org/dubbo-go/v3/imports" + "dubbo.apache.org/dubbo-go/v3/protocol" + "dubbo.apache.org/dubbo-go/v3/server" + greet "github.com/apache/dubbo-go-samples/retry/proto" + "github.com/dubbogo/gost/log/logger" +) + +type GreetTripleServer struct { + requestTime int +} + +func (srv *GreetTripleServer) Greet(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) { + resp := &greet.GreetResponse{Greeting: req.Name} + logger.Info("Not need retry, request success") + return resp, nil +} + +func (srv *GreetTripleServer) GreetRetry(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) { + if srv.requestTime < 3 { + srv.requestTime++ + logger.Infof("retry %d times", srv.requestTime) + return nil, errors.New("retry") + } + resp := &greet.GreetResponse{Greeting: req.Name} + logger.Infof("retry success, current request time is %d", srv.requestTime) + srv.requestTime = 0 + return resp, nil +} + +func main() { + srv, err := server.NewServer( + server.WithServerProtocol( + protocol.WithPort(20000), + ), + ) + if err != nil { + panic(err) + } + if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{ + requestTime: 0, + }); err != nil { + panic(err) + } + if err := srv.Serve(); err != nil { + logger.Error(err) + } +} + +``` + +### 3.2客户端介绍 + +客户端client文件,创建客户端,设置重试次数为3,分别请求`Greet`和`GreetRetry`,观察服务端日志输出。 + +```go +package main + +import ( + "context" + + "dubbo.apache.org/dubbo-go/v3/client" + _ "dubbo.apache.org/dubbo-go/v3/imports" + greet "github.com/apache/dubbo-go-samples/retry/proto" + "github.com/dubbogo/gost/log/logger" +) + +func main() { + cli, err := client.NewClient( + client.WithClientURL("tri://127.0.0.1:20000"), + client.WithClientRetries(3), + ) + if err != nil { + panic(err) + } + + svc, err := greet.NewGreetService(cli) + if err != nil { + panic(err) + } + + // request normal + resp, err := svc.Greet(context.Background(), &greet.GreetRequest{Name: "hello world"}) + if err != nil { + logger.Error(err) + } + logger.Infof("Greet response: %s", resp.Greeting) + + // request need retry + resp, err = svc.GreetRetry(context.Background(), &greet.GreetRequest{Name: "hello world"}) + if err != nil { + logger.Error(err) + } + logger.Infof("Greet response: %s", resp.Greeting) +} +``` + +### 3.3案例效果 + +先启动服务端,再启动客户端,访问`GreetRetry`时观察到服务端日志输出了重试次数。 + +``` +2024-01-23 22:39:11 INFO logger/logging.go:22 [Not need retry, request success] +2024-01-23 22:39:11 INFO logger/logging.go:42 retry [1] times +2024-01-23 22:39:11 INFO logger/logging.go:42 retry [2] times +2024-01-23 22:39:11 INFO logger/logging.go:42 retry [3] times +2024-01-23 22:39:11 INFO logger/logging.go:42 retry success, current request time is [3] +``` \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/start-check.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/start-check.md new file mode 100644 index 000000000000..3925a17a2b63 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/start-check.md @@ -0,0 +1,43 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/governance/health/start-check/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/health/start-check/ + - /zh-cn/overview/mannual/golang-sdk/tutorial/governance/health/start-check/ +description: "缺省会在启动时检查依赖的服务是否可用(注册中心是否有可用地址),不可用时会抛出异常,阻止应用初始化完成。" +keywords: 启动时检查 +title: 启动时检查 +type: docs +weight: 4 +--- + +Dubbo 框架缺省会在启动时检查依赖的服务是否可用(注册中心是否有可用地址),不可用时会抛出异常,阻止应用初始化完成,以便上线时,能及早发现问题,默认 check="true",并等待3s。 + +可以通过 check="false" 关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。 + +关闭 check 后,请注意 provider数量比较多时, consumer 订阅 provider 生成服务地址可能会有一定延迟,如果 consumer 一启动就对外提供服务,可能会造成"冷启动"。所以在这个时候,请对服务进行预热。 + +示例: + +```yaml +dubbo: + consumer: + check : false + reference: + myserivce: + check: true +``` + +或者 + +```go +cli, err := client.NewClient( + client.WithClientCheck(false), +) +``` + +或者 + +```go +svc, err := health.NewHealth(cli) +svc.Check(context.Background(), &health.HealthCheckRequest{Service: "greet.GreetService"}, client.WithCheck(false)) +``` diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/streaming.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/streaming.md new file mode 100644 index 000000000000..54d704db18d5 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/streaming.md @@ -0,0 +1,216 @@ +--- +description: 流式通信 streaming +title: 流式通信 +type: docs +weight: 1 +--- +Streaming 流式通信是 Dubbo3 新提供的一种 RPC 数据传输模式,适用于以下场景: + +- 接口需要发送大量数据,这些数据无法被放在一个 RPC 的请求或响应中,需要分批发送,但应用层如果按照传统的多次 RPC 方式无法解决顺序和性能的问题,如果需要保证有序,则只能串行发送 +- 流式场景,数据需要按照发送顺序处理, 数据本身是没有确定边界的 +- 推送类场景,多个消息在同一个调用的上下文中被发送和处理 + +Streaming 流式通信类型分为以下三种: +- SERVER_STREAM(服务端流) +- CLIENT_STREAM(客户端流) +- BIDIRECTIONAL_STREAM(双向流) + +## 1.介绍 + +本文档演示如何在 Dubbo-go 中使用流式通信,可在此查看 完整示例源码地址。 + +## 2.如何使用Dubbo-go流式通信 + +在proto文件中需要流式通信的方法的参数前面添加stream,使用proto-gen-triple生成相应文件 + +```protobuf +service GreetService { + rpc Greet(GreetRequest) returns (GreetResponse) {} + rpc GreetStream(stream GreetStreamRequest) returns (stream GreetStreamResponse) {} + rpc GreetClientStream(stream GreetClientStreamRequest) returns (GreetClientStreamResponse) {} + rpc GreetServerStream(GreetServerStreamRequest) returns (stream GreetServerStreamResponse) {} +} +``` + +编写服务端handler文件 + +源文件路径: dubbo-go-sample/streaming/go-server/cmd/server.go + +```go +type GreetTripleServer struct { +} + +func (srv *GreetTripleServer) Greet(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) { + resp := &greet.GreetResponse{Greeting: req.Name} + return resp, nil +} + +func (srv *GreetTripleServer) GreetStream(ctx context.Context, stream greet.GreetService_GreetStreamServer) error { + for { + req, err := stream.Recv() + if err != nil { + if triple.IsEnded(err) { + break + } + return fmt.Errorf("triple BidiStream recv error: %s", err) + } + if err := stream.Send(&greet.GreetStreamResponse{Greeting: req.Name}); err != nil { + return fmt.Errorf("triple BidiStream send error: %s", err) + } + } + return nil +} + +func (srv *GreetTripleServer) GreetClientStream(ctx context.Context, stream greet.GreetService_GreetClientStreamServer) (*greet.GreetClientStreamResponse, error) { + var reqs []string + for stream.Recv() { + reqs = append(reqs, stream.Msg().Name) + } + if stream.Err() != nil && !triple.IsEnded(stream.Err()) { + return nil, fmt.Errorf("triple ClientStream recv err: %s", stream.Err()) + } + resp := &greet.GreetClientStreamResponse{ + Greeting: strings.Join(reqs, ","), + } + + return resp, nil +} + +func (srv *GreetTripleServer) GreetServerStream(ctx context.Context, req *greet.GreetServerStreamRequest, stream greet.GreetService_GreetServerStreamServer) error { + for i := 0; i < 5; i++ { + if err := stream.Send(&greet.GreetServerStreamResponse{Greeting: req.Name}); err != nil { + return fmt.Errorf("triple ServerStream send err: %s", err) + } + } + return nil +} +``` + +编写客户端client文件 + +源文件路径: dubbo-go-sample/streaming/go-client/cmd/client.go + +```go +func main() { + cli, err := client.NewClient( + client.WithClientURL("tri://127.0.0.1:20000"), + ) + if err != nil { + panic(err) + } + + svc, err := greet.NewGreetService(cli) + if err != nil { + panic(err) + } + TestClient(svc) +} + +func TestClient(cli greet.GreetService) { + if err := testUnary(cli); err != nil { + logger.Error(err) + } + + if err := testBidiStream(cli); err != nil { + logger.Error(err) + } + + if err := testClientStream(cli); err != nil { + logger.Error(err) + } + + if err := testServerStream(cli); err != nil { + logger.Error(err) + } +} + +func testUnary(cli greet.GreetService) error { + logger.Info("start to test TRIPLE unary call") + resp, err := cli.Greet(context.Background(), &greet.GreetRequest{Name: "triple"}) + if err != nil { + return err + } + logger.Infof("TRIPLE unary call resp: %s", resp.Greeting) + return nil +} + +func testBidiStream(cli greet.GreetService) error { + logger.Info("start to test TRIPLE bidi stream") + stream, err := cli.GreetStream(context.Background()) + if err != nil { + return err + } + if sendErr := stream.Send(&greet.GreetStreamRequest{Name: "triple"}); sendErr != nil { + return err + } + resp, err := stream.Recv() + if err != nil { + return err + } + logger.Infof("TRIPLE bidi stream resp: %s", resp.Greeting) + if err := stream.CloseRequest(); err != nil { + return err + } + if err := stream.CloseResponse(); err != nil { + return err + } + return nil +} + +func testClientStream(cli greet.GreetService) error { + logger.Info("start to test TRIPLE client stream") + stream, err := cli.GreetClientStream(context.Background()) + if err != nil { + return err + } + for i := 0; i < 5; i++ { + if sendErr := stream.Send(&greet.GreetClientStreamRequest{Name: "triple"}); sendErr != nil { + return err + } + } + resp, err := stream.CloseAndRecv() + if err != nil { + return err + } + logger.Infof("TRIPLE client stream resp: %s", resp.Greeting) + return nil +} + +func testServerStream(cli greet.GreetService) error { + logger.Info("start to test TRIPLE server stream") + stream, err := cli.GreetServerStream(context.Background(), &greet.GreetServerStreamRequest{Name: "triple"}) + if err != nil { + return err + } + for stream.Recv() { + logger.Infof("TRIPLE server stream resp: %s", stream.Msg().Greeting) + } + if stream.Err() != nil { + return err + } + if err := stream.Close(); err != nil { + return err + } + return nil +} +``` + +## 3.运行效果 + +运行服务端和客户端,可以看到请求正常返回 + +``` +[start to test TRIPLE unary call] +TRIPLE unary call resp: [triple] +[start to test TRIPLE bidi stream] +TRIPLE bidi stream resp: [triple] +[start to test TRIPLE client stream] +TRIPLE client stream resp: [triple,triple,triple,triple,triple] +[start to test TRIPLE server stream] +TRIPLE server stream resp: [triple] +TRIPLE server stream resp: [triple] +TRIPLE server stream resp: [triple] +TRIPLE server stream resp: [triple] +TRIPLE server stream resp: [triple] +``` + diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/timeout.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/timeout.md new file mode 100644 index 000000000000..2b709287ffb1 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/timeout.md @@ -0,0 +1,155 @@ +--- +description: 配置超时时间 +title: 超时时间 +type: docs +weight: 2 +--- + +## 1.介绍 + +本示例演示如何在 Dubbo-go 客户端发起调用时设置请求超时时间。可在此查看 完整示例源码地址 + +## 2.如何设置请求超时时间 + +在创建客户端时,可以使用 `client.WithRequestTimeout()` 方法设置全局超时时间(所有使用改 client 的服务代理共享)。 + +```go + cli, err := client.NewClient( + client.WithClientURL("tri://127.0.0.1:20000"), + client.WithClientRequestTimeout(3 * time.Second), + ) +``` + +可以使用 `client.WithRequestTimeout()` 创建服务粒度的超时时间(以下服务代理 `svc` 发起的方法调用都使用这个时间)。 + +```go + svc, err := greet.NewGreetService(cli, client.WithRequestTimeout(5 * time.Second)) +``` + +也可以在调用发起时,使用 `client.WithCallRequestTimeout()` 指定一个超时时间 + +```go +resp, err := svc.GreetTimeout(context.Background(), &greet.GreetRequest{Name: "hello world"}, client.WithCallRequestTimeout(10 * time.Second)) +``` + +从上往下,以上三种方式的优先级逐步提高,`client.WithCallRequestTimeout()` 指定的超时时间优先级最高。 + +## 3.示例详解 + +### 3.1服务端介绍 + +#### 服务端proto文件 + +源文件路径:dubbo-go-sample/timeout/proto/greet.proto + +```protobuf +syntax = "proto3"; + +package greet; + +option go_package = "github.com/apache/dubbo-go-samples/timeout/proto;greet"; + +message GreetRequest { + string name = 1; +} + +message GreetResponse { + string greeting = 1; +} + +service GreetService { + rpc Greet(GreetRequest) returns (GreetResponse) {} + rpc GreetTimeout(GreetRequest) returns (GreetResponse) {} +} +``` + +#### 服务端handler文件 + +`Greet`方法直接响应,`GreetTimeout`方法等待五秒后响应(模拟超时)。 + +源文件路径:dubbo-go-sample/timeout/go-server/handler.go + +```go +package main + +import ( + "context" + "time" + + greet "github.com/apache/dubbo-go-samples/timeout/proto" +) + +type GreetTripleServer struct { +} + +func (srv *GreetTripleServer) Greet(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) { + resp := &greet.GreetResponse{Greeting: req.Name} + return resp, nil +} + +func (srv *GreetTripleServer) GreetTimeout(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) { + time.Sleep(5 * time.Second) + resp := &greet.GreetResponse{Greeting: req.Name} + return resp, nil +} +``` + +### 3.2客户端介绍 + +客户端client文件,创建客户端,设置超时时间为3s,分别请求`Greet`和`GreetTimeout`,输出响应结果。 + +源文件路径:dubbo-go-sample/timeout/go-client/client.go + +```go +package main + +import ( + "context" + "time" + + "dubbo.apache.org/dubbo-go/v3/client" + _ "dubbo.apache.org/dubbo-go/v3/imports" + greet "github.com/apache/dubbo-go-samples/timeout/proto" + "github.com/dubbogo/gost/log/logger" +) + +func main() { + cli, err := client.NewClient( + client.WithClientURL("tri://127.0.0.1:20000"), + client.WithClientRequestTimeout(3*time.Second), + ) + if err != nil { + panic(err) + } + + svc, err := greet.NewGreetService(cli) + if err != nil { + panic(err) + } + + // test timeout + resp, err := svc.GreetTimeout(context.Background(), &greet.GreetRequest{Name: "hello world"}) + if err != nil { + logger.Error("call [greet.GreetService.GreetTimeout] service timeout") + logger.Error(err) + } else { + logger.Infof("Greet response: %s", resp.Greeting) + } + + // test normal + resp, err = svc.Greet(context.Background(), &greet.GreetRequest{Name: "hello world"}) + if err != nil { + logger.Error(err) + } + logger.Infof("Greet response: %s", resp.Greeting) +} +``` + +### 3.3案例效果 + +先启动服务端,再启动客户端,可以观察到`GreetTimeout`请求响应超时,`Greet`请求响应正常 + +``` +[call [greet.GreetService.GreetTimeout] service timeout] +Greet response: [hello world] +``` diff --git a/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/_index.md new file mode 100755 index 000000000000..ebd30961f991 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/debugging/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ + - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/registry/ + - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/registry/service-discovery/ +description: "使用 Nacos、Zookeeper 等作为注册中心,实现地址变更的自动发现。" +title: 地址发现 +type: docs +weight: 20 +--- diff --git a/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/multi_registry.md b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/multi_registry.md new file mode 100644 index 000000000000..33e7090a585c --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/multi_registry.md @@ -0,0 +1,86 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/develop/registry/multi_registry/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/registry/multi_registry/ +description: 多注册中心 +title: 多注册中心 +type: docs +weight: 100 +--- + +一个 Dubbo 应用可以配置的多个接口维度的注册中心,多注册中心可用于集群隔离、迁移等多种场景,关于这部分更详细的说明可参考 Dubbo Java 多注册中心说明。 + +## API配置方式 + +```go +ins, _ := dubbo.NewInstance( + dubbo.WithRegistry( + registryWithID("nacos"), + registry.WithNacos(), + registry.WithAddress("127.0.0.1:8848"), + ), + dubbo.WithRegistry( + registryWithID("zookeeper"), + registry.WithZookeeper(), + registry.WithAddress("127.0.0.1:2181"), + ), +) + +``` + +指定某个 server 下的服务注册到哪个注册中心: +```go +// 指定 server 下的服务注册到 zookeeper 注册中心 +srv, _ := ins.NewServer(server.WithServerRegistryIDs([]string{"zookeeper"})) + +// 指定 server 下的服务注册到 nacos 注册中心 +srv2, _ := ins.NewServer(server.WithServerRegistryIDs([]string{"nacos"})) +``` + +指定某个特定服务注册到哪个注册中心: +```go +srv, _ := ins.NewServer() + +greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{}, server.WithRegistryIDs([]string{"zookeeper"})) +``` + +以上使用方式对 client 侧类似。 + +## YAML配置方式 + +修改服务端配置 go-server/conf/dubbogo.yaml, 同时将服务注册在两个注册中心上。 + +```yaml +dubbo: + registries: + zookeeper: # 指定 zookeeper 注册中心 + protocol: zookeeper + address: 127.0.0.1:2181 + nacos: # 指定 nacos 注册中心 + protocol: nacos + address: 127.0.0.1:8848 + protocols: + triple: + name: tri + port: 20000 +``` + +## 支持的注册中心 +* Nacos +* Zookeeper +* Polaris +* Kubernetes + +比如使用 Polaris 作为注册中心时,你需要指定以下内容,使用 API 或 YAML 配置文件均可以: + +```yaml +dubbo: + registries: + polarisMesh: + protocol: polaris + address: ${北极星服务端IP}:8091 + namespace: ${北极星命名空间信息} + token: ${北极星资源鉴权 token} # 如果北极星服务端开启了针对客户端的鉴权,则需要配置该参数 +``` + +对于 Kubernetes 注册中心的使用方式,请参考 [控制面](/zh-cn/overview/mannual/control-plane/) 文档。 \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/nacos.md b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/nacos.md new file mode 100644 index 000000000000..f5369961011d --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/nacos.md @@ -0,0 +1,58 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/develop/registry/nacos-2/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/registry/nacos-2/ +description: 使用 Nacos 作为注册中心 +title: 使用 Nacos 作为注册中心 +type: docs +weight: 10 +--- + + +This example shows dubbo-go's service discovery feature with Nacos as registry. + +## 使用方式 + +通过以下方式指定注册中心地址: + +```go +ins, _ := dubbo.NewInstance( + dubbo.WithName("dubbo_registry_nacos_server"), + dubbo.WithRegistry( + registry.WithNacos(), + registry.WithAddress("127.0.0.1:8848"), + ), + dubbo.WithProtocol( + protocol.WithTriple(), + protocol.WithPort(20000), + ), +) + +srv, err := ins.NewServer() +``` + +## How to run + +### Start Nacos server +Follow this instruction to [install and start Nacos server](/zh-cn/overview/reference/integrations/nacos/). + +### Run server +```shell +$ go run ./go-server/cmd/server.go +``` + +test rpc server work as expected: +```shell +$ curl \ + --header "Content-Type: application/json" \ + --data '{"name": "Dubbo"}' \ + http://localhost:20000/greet.GreetService/Greet +``` + +Open `https://localhost:8848/nacos/` with browser, check url address successfully registered into Nacos. + +### Run client +```shell +$ go run ./go-client/cmd/client.go +hello world +``` \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/zookeeper.md b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/zookeeper.md new file mode 100644 index 000000000000..257c969da340 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/zookeeper.md @@ -0,0 +1,68 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/develop/registry/zookeeper/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/registry/zookeeper/ +description: 使用 Zookeeper 作为注册中心 +title: 使用 Zookeeper 作为注册中心 +type: docs +weight: 11 +--- + + +This example shows dubbo-go's service discovery feature with Zookeeper as registry. + +## 使用方式 + +通过以下方式指定注册中心地址: + +```go +ins, _ := dubbo.NewInstance( + dubbo.WithName("dubbo_registry_nacos_server"), + dubbo.WithRegistry( + registry.WithZookeeper(), + registry.WithAddress("127.0.0.1:2181"), + ), + dubbo.WithProtocol( + protocol.WithTriple(), + protocol.WithPort(20000), + ), +) + +srv, err := ins.NewServer() +``` + +## How to run + +### Start Zookeeper server +This example relies on zookeeper as registry, follow the steps below to start a zookeeper server first. + +1. Start zookeeper with docker, run `docker run --rm -p 2181:2181 zookeeper` or `make -f $DUBBO_GO_SAMPLES_ROOT_PATH/build/Makefile docker-up`. +2. [Download and start zookeeper](https://zookeeper.apache.org/releases.html#download) locally on your machine. + +### Run server +```shell +$ go run ./go-server/cmd/server.go +``` + +test rpc server work as expected: +```shell +$ curl \ + --header "Content-Type: application/json" \ + --data '{"name": "Dubbo"}' \ + http://localhost:20000/greet.GreetService/Greet +``` + +check url address successfully registered into zookeeper: +```shell +# enter zookeeper bin directory, for example '$HOST_PATH/apache-zookeeper-3.5.9-bin/bin' +$ ./zkCli.sh +[zk: localhost:2181(CONNECTED) 0] ls /services/dubbo_registry_zookeeper_server +[30.221.147.198:20000] +``` + +### Run client +```shell +$ go run ./go-client/cmd/client.go +hello world +``` + diff --git a/content/en/overview/mannual/golang-sdk/tutorial/traffic/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/traffic/_index.md new file mode 100755 index 000000000000..7556e4519c4d --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/traffic/_index.md @@ -0,0 +1,9 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/debugging/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ +description: "通过下发路由规则实现流量管控,包括按比例流量转发、参数路由、灰度发布、动态调整超时时间等。" +title: 流量管控 +type: docs +weight: 60 +--- diff --git a/content/en/overview/mannual/golang-sdk/tutorial/traffic/router.md b/content/en/overview/mannual/golang-sdk/tutorial/traffic/router.md new file mode 100644 index 000000000000..31b2e5b3190f --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/traffic/router.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/tutorial/governance/traffic/mesh_router/ + - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/traffic/mesh_router/ + - /zh-cn/overview/mannual/golang-sdk/tutorial/governance/traffic/mesh_router/ +description: 路由规则 +title: 路由规则 +type: docs +weight: 1 +--- + diff --git a/content/en/overview/mannual/golang-sdk/tutorial/traffic/sentinel.md b/content/en/overview/mannual/golang-sdk/tutorial/traffic/sentinel.md new file mode 100644 index 000000000000..852b183f0ef5 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/traffic/sentinel.md @@ -0,0 +1,35 @@ +--- +description: "基于 Sentinel 的流量" +title: Sentinel限流降级 +type: docs +weight: 3 +--- + +Dubbo-go 中提供了内置的限流组件,用户可根据自己的业务场景调整限流值、限流后的行为等,具体可 [TpsLimiter](https://github.com/apache/dubbo-go/blob/main/filter/tps_limiter.go#L52) 定义与具体实现。用户可通过类似以下方式在服务端设置简单的限流策略: + +```go +server.WithTpsLimiter("method-service") // 目前支持 method-service、polaris 等几个实现 +server.WithTpsLimiterXxx() // 设置限流相关阈值,请根据具体方法填写 +//tps.limit.strategy: "slidingWindow" +//tps.limit.rejected.handler: "default" +//tps.limit.interval: 1000 +//tps.limit.rate: 3 +``` + +Dubbo-go 内置限流策略相对简单,对于一些更复杂的场景,我们建议通过使用 Sentinel 等专业的第三方框架可以实现更丰富、更灵活的限流策略。 + +可在此查看 [本示例完整源码](https://github.com/apache/dubbo-go-samples/tree/main/filter/sentinel),也可以参考 [Dubbo+Sentinel 的 Java 示例](/zh-cn/overview/mannual/java-sdk/tasks/rate-limit/sentinel/) 获得更多灵感。 + +## Provider 限流 + +### 基于 QpS 限流 + +### 基于并发任务数限流(当前在运行任务数) + +## Consumer 限流 + +### 熔断策略 + + + +### 基于并发请求数限流(未收到响应的请求数) \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/tutorial/transaction/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/transaction/_index.md new file mode 100755 index 000000000000..618f9655b669 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/transaction/_index.md @@ -0,0 +1,7 @@ +--- +description: "Dubbo 分布式事务解决方案。" +title: 分布式事务 +type: docs +weight: 62 +--- + diff --git a/content/en/overview/mannual/golang-sdk/tutorial/transaction/seata.md b/content/en/overview/mannual/golang-sdk/tutorial/transaction/seata.md new file mode 100644 index 000000000000..63fb1bfc8792 --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/tutorial/transaction/seata.md @@ -0,0 +1,18 @@ +--- +description: "使用 Seata 分布式事务解决方案解决 Dubbo 数据一致性问题。" +title: Seata分布式事务 +type: docs +weight: 1 +--- + +1. 先执行以下命令,启动 seata-server。 + + ```shell + cd ../dockercompose + docker-compose -f docker-compose.yml up -d seata-server + ``` + +2. 再执行 triple/client/cmd 和 triple/server/cmd 目录下的 main()方法。 + + +完整示例源码地址 \ No newline at end of file diff --git a/content/en/overview/mannual/golang-sdk/versions.md b/content/en/overview/mannual/golang-sdk/versions.md new file mode 100644 index 000000000000..e5e5c394f6bd --- /dev/null +++ b/content/en/overview/mannual/golang-sdk/versions.md @@ -0,0 +1,41 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/refer/compatible_version/ + - /zh-cn/docs3-v2/golang-sdk/refer/compatible_version/ + - /zh-cn/overview/mannual/golang-sdk/preface/refer/compatible_version/ +description: 依赖适配版本号 +title: 版本信息 +type: docs +weight: 1 +--- + +## 推荐版本 +当前网站文档适用于以下版本,如果您正使用 dubbo-go 其他版本,请参考对应历史版本文档。 + +| Go | Dubbo-go | protoc-gen-go-triple | 说明 | +| :--: | ------------ | -------------------- | -------------------- | +| 1.20 | v3.2.0-rc1(当前文档) | v3.0.0 | 当前最新稳定版本,推荐使用 | + +## 历史版本 + +### 3.x +查看 3.1.x 及之前版本文档: + +| Go | Dubbo-go | protoc-gen-go-triple | 说明 | +| :--: | ------------ | -------------------- | -------------------- | +| 1.16 | v3.1.1 | v3.0.0 | 请参考 README 说明,了解如何生成老版本兼容的服务 stub 代码 | +| 1.16 | v3.1.0 | v3.0.0 | 请参考 README 说明,了解如何生成老版本兼容的服务 stub 代码 | +| 1.16 | v3.0.4 | v3.0.0 | 请参考 README 说明,了解如何生成老版本兼容的服务 stub 代码 | +| 1.16 | v3.0.3 | v3.0.0 | 请参考 README 说明,了解如何生成老版本兼容的服务 stub 代码 | +| 1.16 | v3.0.2 | v3.0.0 | 请参考 README 说明,了解如何生成老版本兼容的服务 stub 代码 | +| 1.16 | v3.0.1 | v3.0.0 | 请参考 README 说明,了解如何生成老版本兼容的服务 stub 代码 | +| 1.16 | v3.0.0 | v1.0.5 | | +| 1.16 | v3.0.0-rc4-1 | v1.0.2 | | +| 1.16 | v3.0.0-rc3 | v1.0.0 | | + +### 1.x + +| Go | Dubbo-go | Triple | protoc-gen-go-triple | 说明 | +| :--: | ------------ | ------ | -------------------- | -------------------- | +| | v1.5.0 | v1.1.8 | v1.0.8 | 停止维护,请升级到最新 3.x 版本 | + diff --git a/content/en/overview/mannual/java-sdk/_index.md b/content/en/overview/mannual/java-sdk/_index.md new file mode 100755 index 000000000000..a2b522b0789d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/_index.md @@ -0,0 +1,34 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/ + - /zh-cn/docs3-v2/java-sdk/ +content: + - 快速开始: + - description: 快速体验 Dubbo Java 微服务开发 + name: '[Spring Boot 快速开发 Dubbo 服务](quick-start/starter/)' + - description: 配置参考手册 + name: '[配置参考手册](reference-manual/config/)' + - 高级特性: + - description: 扩展 Filter、Router 拦截流量 + name: '[扩展 Filter、Router 拦截流量](concepts-and-architecture/service-invocation/)' + - 参考手册: + - description: 注册中心配置指南 + name: '[注册中心配置指南](reference-manual/registry/)' + - 升级与兼容性: + - description: 版本迁移指南 + name: '[版本迁移指南](reference-manual/upgrades-and-compatibility/)' + - 历史版本文档: + - description: 历史版本文档 + name: '[2.x 及早期版本文档](/zh-cn/docsv2.7/)' +description: Java SDK 手册 +hide_feedback: true +hide_summary: true +linkTitle: Java SDK +no_list: true +title: Java SDK 手册 +type: docs +weight: 1 +--- + + +{{% docs/content_box %}} diff --git a/content/en/overview/mannual/java-sdk/quick-start/_index.md b/content/en/overview/mannual/java-sdk/quick-start/_index.md new file mode 100755 index 000000000000..cea661e66260 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/quick-start/_index.md @@ -0,0 +1,14 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/quick-start/ + - /zh-cn/docs3-v2/java-sdk/quick-start/ + - /zh/overview/quickstart/java/ + - /zh-cn/overview/quickstart/java/ + - /zh/overview/quickstart/ + - /zh-cn/overview/quickstart/ +description: "" +linkTitle: 快速入门 +title: 快速入门 +type: docs +weight: 2 +--- diff --git a/content/en/overview/mannual/java-sdk/quick-start/deploy.md b/content/en/overview/mannual/java-sdk/quick-start/deploy.md new file mode 100644 index 000000000000..2838acfdf28f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/quick-start/deploy.md @@ -0,0 +1,139 @@ +--- +description: 快速部署Dubbo应用 +linkTitle: 部署Dubbo应用 +title: 快速部署Dubbo应用 +type: docs +toc_hide: true +hide_summary: true +weight: 3 +--- + +在上一篇文章中,我们从头创建了一个 Dubbo 应用并详细介绍了它的代码结构,接下来,我们将学习部署这个 Dubbo 应用。 + +本文将以 Kubernetes 集群作为基础环境来讲解 Dubbo 应用的部署,部署架构如下图所示。 +![Dubbo+Kubernetes+Nacos 部署架构图]() + +{{% alert title="注意" color="info" %}} +在实际使用中,部署环境可能变化多样,包括 Kubernetes Service、服务网格(Service Mesh)、虚拟机等多种部署模式,请参考 [部署文档]() 了解更多详细内容。 +{{% /alert %}} + +## 前置条件 +Dubbo 社区提供了工具和解决方案来简化整个 Kubernetes 环境的打包与部署过程,所以开始前我们需要先安装相关工具。 + +1. 安装 dubboctl(如尚未安装) + ```sh + curl -L https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/release/downloadDubbo.sh | sh - + + cd dubbo-$version + export PATH=$PWD/bin:$PATH + ``` + + +## 部署应用 + +### 初始化微服务集群 + +1. dubboctl 安装完成之后,接下来通过以下命令初始化微服务部署环境 + + ```sh + dubboctl manifest install --profile=demo + ``` + + 作为演示目的,以上命令会一键安装 Zookeeper、Dubbo Control Plane、Prometheus、Grafana、Zipkin、Ingress 等组件,关于 `--profile=demo` 更多解释及配置请参见文档说明。 + +2. 检查环境准备就绪 + + ```sh + kubectl get services -n dubbo-system + ``` + +3. 最后,为目标 kubernetes namespace 开启自动注入模式,以便应用部署后能够自动连接到刚刚安装的 Zookeeper 注册中心等组件。 + + ```shell + kubectl label namespace dubbo-demo dubbo-injection=enabled --overwrite + ``` + +### 部署 Dubbo 应用 + +接下来我们为之前创建的应用打包镜像(请确保本地安装有 Docker 环境并且已经启动 Docker 进程),在应用根目录分别运行以下命令: + +```shell +dubboctl build --dockerfile=./Dockerfile +``` + +`build` 命令会将源码打包为镜像,并推送到远端仓库,取决于网络情况,可能需要一定时间等待命令执行完成。 + +接下来,我们需要生成部署应用的 Kubernetes 资源文件,运行以下命令: +```shell +dubboctl deploy +``` + +`deploy` 命令会使用刚刚 `build` 打包的镜像生成 Kubernetes 资源清单。命令执行成功后,在当前目录看到生成的 `kube.yaml` 文件,其中包括 deployment、service 等 kubernetes 资源定义。 + + +{{% alert title="注意" color="warning" %}} +本地构建可能会花费比较长时间,如您本地构建遇到问题,也可以使用以下命令跳过 `build` 过程。 + +```sh +dubboctl deploy --image=apache/dubbo-demo:quickstart_0.1 +# `--image` 指定使用官方预先准备好的示例镜像 +``` +{{% /alert %}} + +接下来,将应用部署到 Kubernetes 环境。 + +```shell +kubectl apply -f ./kube.yaml +``` + +检查部署状态 +```shell +kubectl get services -n dubbo-demo +``` + +## 访问应用 +部署成功后,可以通过以下方式检查应用状态。 + +{{< tabpane text=true >}} +{{< tab header="请根据情况选择:" disabled=true />}} +{{% tab header="本地 Kubernetes 集群" lang="en" %}} +
+ +1. 如果使用的本地 Kubernetes 集群,请使用以下方式访问应用验证部署状态: + + ```shell + dubboctl dashboard admin + ``` + +2. 以上命令会自动打开 admin 控制台,如果在您的环境下没有打开,请使用浏览器访问以下地址: + + http://localhost:38080/admin + +3. 通过 triple 协议,可以继续测试 Dubbo 服务,执行以下命令进行端口映射: + + ```shell + kubectl port-forward 50051:50051 + ``` + +4. 通过 curl 访问服务: + + ```shell + curl \ + --header "Content-Type: application/json" \ + --data '["Dubbo"]' \ + http://localhost:50051/com.example.demo.dubbo.api.DemoService/sayHello/ + ``` + +{{% /tab %}} + +{{% tab header="阿里云ACK" lang="zh-cn" %}} +
+ +对于云上托管的哦 Kubernetes 集群,可以使用以下方式验证,这里以阿里云 ACK 集群为例: + +ACK ingerss-controller 的访问方式...... + +{{% /tab %}} +{{< /tabpane >}} + + diff --git a/content/en/overview/mannual/java-sdk/quick-start/starter.md b/content/en/overview/mannual/java-sdk/quick-start/starter.md new file mode 100644 index 000000000000..214c15a55c31 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/quick-start/starter.md @@ -0,0 +1,178 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config/overview/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config/overview/ + - /zh-cn/overview/mannual/java-sdk/quick-start/spring-boot/ +description: 创建基于Spring Boot的Dubbo应用。 +linkTitle: 创建基于Spring Boot的Dubbo应用 +title: 创建基于Spring Boot的微服务应用 +type: docs +weight: 2 +--- + +以下文档将引导您从头创建一个基于 Spring Boot 的 Dubbo 应用,并为应用配置 Triple 通信协议、服务发现等微服务基础能力。 + +## 快速创建应用 +通过访问 start.dubbo.apache.org 在线服务创建 Dubbo 微服务应用。如下图所示依次添加组件,您可以在几十秒之内快速创建一个 Dubbo 应用。下载生成的示例应用并解压源码即可。 + +项目结构截图 + +{{% alert title="直接使用官方准备好的示例" color="info" %}} +您还可以直接下载官方预先准备好的示例项目: + +```shell +$ git clone -b main --depth 1 https://github.com/apache/dubbo-samples +$ cd dubbo-samples/11-quickstart +```` +{{% /alert %}} + +## 本地启动应用 +接下来,让我们尝试在本地启动应用。运行以下命令启动应用: + +```shell +./mvnw +``` + +{{% alert title="注意" color="warning" %}} +由于配置文件中启用了注册中心,为了能够成功启动应用,您需要首先在本地启动 NacosZookeeper 注册中心 server。 +{{% /alert %}} + + +在应用启动成功后,本地进程使用 Triple 协议在指定端口发布了服务,可直接使用 cURL 测试服务是否已经正常运行: + +```shell +curl \ + --header "Content-Type: application/json" \ + --data '["Dubbo"]' \ + http://localhost:50051/com.example.demo.dubbo.api.DemoService/sayHello/ +``` + +除了使用命令行之外,我们还可以在 IDE 中启动项目,调整示例或进行本地 debug。 + +## 源码解析 +将以上准备好的示例项目导入最喜欢的 IDE 开发工具(以 IntelliJ IDEA 为例),项目结构如下: + +项目结构截图 + +### Maven 依赖 +打开 pom.xml,可以看到示例项目中 Dubbo 相关核心依赖如下: + +```xml + + + + org.apache.dubbo + dubbo-bom + 3.3.0 + pom + import + + + + + + + org.apache.dubbo + dubbo-spring-boot-starter + + + org.apache.dubbo + dubbo-zookeeper-spring-boot-starter + + +``` + +其中,`dubbo-spring-boot-starter`、`dubbo-zookeeper-spring-boot-starter` 分别为我们引入了 Dubbo 内核框架与 Zookeeper 客户端相关的依赖组件,更多内容可以查看 [Dubbo 支持的 Spring Boot Starter 清单]() 。 + +### 服务定义 + +以下是基于 Java Interface 的标准 Dubbo 服务定义。 + +```java +public interface DemoService { + String sayHello(String name); +} +``` + +在 `DemoService` 中,定义了 `sayHello` 这个方法。后续服务端发布的服务,消费端订阅的服务都是围绕着 `DemoService` 接口展开的。 + +### 服务实现 + +定义了服务接口之后,可以在服务端这一侧定义对应的业务逻辑实现。 + +```java +@DubboService +public class DemoServiceImpl implements DemoService { + @Override + public String sayHello(String name) { + return "Hello " + name; + } +} +``` + +在`DemoServiceImpl` 类中添加了 `@DubboService` 注解,通过这个配置可以基于 Spring Boot 去发布 Dubbo 服务。 + +### 发起服务调用 +示例应用中有一个 consumer 包,用于模拟发起对 provider 服务的远程调用。 + +```java +@Component +public class Consumer implements CommandLineRunner { + @DubboReference + private DemoService demoService; + + @Override + public void run(String... args) throws Exception { + String result = demoService.sayHello("world"); + System.out.println("Receive result ======> " + result); + } +} +``` + +在 `Task` 类中,通过`@DubboReference` 从 Dubbo 获取了一个 RPC 订阅,这个 `demoService` 可以像本地调用一样直接调用: `demoService.sayHello("world")`。 + +{{% alert title="提示" color="primary" %}} +通常远程调用是跨进程的,示例项目为了方便开发,直接内置了一个 `@DubboReference` 调用。如果您想学习如何开发一个独立的 Consumer(客户端)进程,以便发起对 Dubbo 服务的远程调用,我们有一个 包含独立 consumer、provider 模块的示例项目 可供参考。 +{{% /alert %}} + +### 应用入口与配置文件 + +由于我们创建的是一个 Spring Boot 应用,Dubbo 相关配置信息都存放在 `application.yml` 配置文件中。基于以下配置,Dubbo 进程将在 50051 端口监听 triple 协议请求,同时,实例的 ip:port 信息将会被注册到 Zookeeper server。 + +```yaml +# application.yml +dubbo: + application: + name: dubbo-demo + protocol: + name: tri + port: 50051 + registry: + address: zookeeper://${zookeeper.address:127.0.0.1}:2181 +``` + +以下是整个应用的启动入口,`@EnableDubbo` 注解用来加载和启动 Dubbo 相关组件。 + +```java +@SpringBootApplication +@EnableDubbo +public class DemoApplication { + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } +} +``` + +## 发布服务定义到远端仓库 + +应用开发完成后,我们需要将服务定义发布到外部公开的或组织内部的 maven 仓库,以便调用这些服务的应用能够加载并使用这些服务。 + +如之前我们看到的,示例项目包含 api、service 两个模块,切换项目到 api 目录,以下命令即可完成发布动作: + +```shell +mvn clean deploy +``` + +## 更多内容 +- 接下来,可以 [快速部署 Dubbo 应用到微服务集群]() +- Dubbo 内置服务发现、负载均衡、流量管控规则等能力,学习 [如何配置更多服务治理能力]() diff --git a/content/en/overview/mannual/java-sdk/reference-manual/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/_index.md new file mode 100755 index 000000000000..8d05c7706e1e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/ +description: 参考手册 +linkTitle: 参考手册 +title: 参考手册 +type: docs +weight: 5 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/_index.md new file mode 100755 index 000000000000..920b0022d463 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/concepts-and-architecture/ + - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/ + - /zh-cn/overview/mannual/java-sdk/concepts-and-architecture/ +description: 概念和架构 +linkTitle: 源码架构 +title: 源码架构 +type: docs +weight: 100 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/code-architecture.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/code-architecture.md new file mode 100644 index 000000000000..42935d0889db --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/code-architecture.md @@ -0,0 +1,113 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/concepts-and-architecture/code-architecture/ + - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/code-architecture/ + - /zh-cn/overview/mannual/java-sdk/concepts-and-architecture/code-architecture/ +description: 本文将介绍 Dubbo 代码架构。 +linkTitle: 代码架构 +title: 代码架构 +type: docs +weight: 2 +--- + + + + + + + +## 整体设计 + +![/dev-guide/images/dubbo-framework.jpg](/imgs/dev/dubbo-framework.jpg) + +图例说明: + +* 图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口。 +* 图中从下至上分为十层,各层均为单向依赖,右边的黑色箭头代表层之间的依赖关系,每一层都可以剥离上层被复用,其中,Service 和 Config 层为 API,其它各层均为 SPI。 +* 图中绿色小块的为扩展接口,蓝色小块为实现类,图中只显示用于关联各层的实现类。 +* 图中蓝色虚线为初始化过程,即启动时组装链,红色实线为方法调用过程,即运行时调用链,紫色三角箭头为继承,可以把子类看作父类的同一个节点,线上的文字为调用的方法。 + +## 各层说明 + +* **Config 配置层**:对外配置接口,以 `ServiceConfig`, `ReferenceConfig` 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类 +* **Proxy 服务代理层**:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以 `ServiceProxy` 为中心,扩展接口为 `ProxyFactory` +* **Registry 注册中心层**:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 `RegistryFactory`, `Registry`, `RegistryService` +* **Cluster 路由层**:封装多个提供者的路由及负载均衡,并桥接注册中心,以 `Invoker` 为中心,扩展接口为 `Cluster`, `Directory`, `Router`, `LoadBalance` +* **Monitor 监控层**:RPC 调用次数和调用时间监控,以 `Statistics` 为中心,扩展接口为 `MonitorFactory`, `Monitor`, `MonitorService` +* **Protocol 远程调用层**:封装 RPC 调用,以 `Invocation`, `Result` 为中心,扩展接口为 `Protocol`, `Invoker`, `Exporter` +* **Exchange 信息交换层**:封装请求响应模式,同步转异步,以 `Request`, `Response` 为中心,扩展接口为 `Exchanger`, `ExchangeChannel`, `ExchangeClient`, `ExchangeServer` +* **Transport 网络传输层**:抽象 mina 和 netty 为统一接口,以 `Message` 为中心,扩展接口为 `Channel`, `Transporter`, `Client`, `Server`, `Codec` +* **Serialize 数据序列化层**:可复用的一些工具,扩展接口为 `Serialization`, `ObjectInput`, `ObjectOutput`, `ThreadPool` + +## 关系说明 + +* 在 RPC 中,Protocol 是核心层,也就是只要有 Protocol + Invoker + Exporter 就可以完成非透明的 RPC 调用,然后在 Invoker 的主过程上 Filter 拦截点。 +* 图中的 Consumer 和 Provider 是抽象概念,只是想让看图者更直观的了解哪些类分属于客户端与服务器端,不用 Client 和 Server 的原因是 Dubbo 在很多场景下都使用 Provider, Consumer, Registry, Monitor 划分逻辑拓扑节点,保持统一概念。 +* 而 Cluster 是外围概念,所以 Cluster 的目的是将多个 Invoker 伪装成一个 Invoker,这样其它人只要关注 Protocol 层 Invoker 即可,加上 Cluster 或者去掉 Cluster 对其它层都不会造成影响,因为只有一个提供者时,是不需要 Cluster 的。 +* Proxy 层封装了所有接口的透明化代理,而在其它层都以 Invoker 为中心,只有到了暴露给用户使用时,才用 Proxy 将 Invoker 转成接口,或将接口实现转成 Invoker,也就是去掉 Proxy 层 RPC 是可以 Run 的,只是不那么透明,不那么看起来像调本地服务一样调远程服务。 +* 而 Remoting 实现是 Dubbo 协议的实现,如果你选择 RMI 协议,整个 Remoting 都不会用上,Remoting 内部再划为 Transport 传输层和 Exchange 信息交换层,Transport 层只负责单向消息传输,是对 Mina, Netty, Grizzly 的抽象,它也可以扩展 UDP 传输,而 Exchange 层是在传输层之上封装了 Request-Response 语义。 +* Registry 和 Monitor 实际上不算一层,而是一个独立的节点,只是为了全局概览,用层的方式画在一起。 + +## 模块分包 + +![/dev-guide/images/dubbo-modules.jpg](/imgs/dev/dubbo-modules.jpg) + +模块说明: + +* **dubbo-common 公共逻辑模块**:包括 Util 类和通用模型。 +* **dubbo-remoting 远程通讯模块**:相当于 Dubbo 协议的实现,如果 RPC 用 RMI协议则不需要使用此包。 +* **dubbo-rpc 远程调用模块**:抽象各种协议,以及动态代理,只包含一对一的调用,不关心集群的管理。 +* **dubbo-cluster 集群模块**:将多个服务提供方伪装为一个提供方,包括:负载均衡, 容错,路由等,集群的地址列表可以是静态配置的,也可以是由注册中心下发。 +* **dubbo-registry 注册中心模块**:基于注册中心下发地址的集群方式,以及对各种注册中心的抽象。 +* **dubbo-monitor 监控模块**:统计服务调用次数,调用时间的,调用链跟踪的服务。 +* **dubbo-config 配置模块**:是 Dubbo 对外的 API,用户通过 Config 使用Dubbo,隐藏 Dubbo 所有细节。 +* **dubbo-container 容器模块**:是一个 Standlone 的容器,以简单的 Main 加载 Spring 启动,因为服务通常不需要 Tomcat/JBoss 等 Web 容器的特性,没必要用 Web 容器去加载服务。 + +整体上按照分层结构进行分包,与分层的不同点在于: + +* Container 为服务容器,用于部署运行服务,没有在层中画出。 +* Protocol 层和 Proxy 层都放在 rpc 模块中,这两层是 rpc 的核心,在不需要集群也就是只有一个提供者时,可以只使用这两层完成 rpc 调用。 +* Transport 层和 Exchange 层都放在 remoting 模块中,为 rpc 调用的通讯基础。 +* Serialize 层放在 common 模块中,以便更大程度复用。 + +## 依赖关系 + +![/dev-guide/images/dubbo-relation.jpg](/imgs/dev/dubbo-relation.jpg) + +图例说明: + +* 图中小方块 Protocol, Cluster, Proxy, Service, Container, Registry, Monitor 代表层或模块,蓝色的表示与业务有交互,绿色的表示只对 Dubbo 内部交互。 +* 图中背景方块 Consumer, Provider, Registry, Monitor 代表部署逻辑拓扑节点。 +* 图中蓝色虚线为初始化时调用,红色虚线为运行时异步调用,红色实线为运行时同步调用。 +* 图中只包含 RPC 的层,不包含 Remoting 的层,Remoting 整体都隐含在 Protocol 中。 + +## 调用链 + +展开总设计图的红色调用链,如下: + +![/dev-guide/images/dubbo-extension.jpg](/imgs/dev/dubbo-extension.jpg) + +## 暴露服务时序 + +展开总设计图右边服务提供方暴露服务的蓝色初始化链,时序图如下: + +![/dev-guide/images/dubbo-export.jpg](/imgs/dev/dubbo-export.jpg) + +## 引用服务时序 + +展开总设计图左边服务消费方引用服务的绿色初始化链,时序图如下: + +![/dev-guide/images/dubbo-refer.jpg](/imgs/dev/dubbo-refer.jpg) + +## 领域模型 + +在 Dubbo 的核心领域模型中: + +* Protocol 是服务域,它是 Invoker 暴露和引用的主功能入口,它负责 Invoker 的生命周期管理。 +* Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠拢,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。 +* Invocation 是会话域,它持有调用过程中的变量,比如方法名,参数等。 + +## 基本设计原则 + +* 采用 Microkernel + Plugin 模式,Microkernel 只负责组装 Plugin,Dubbo 自身的功能也是通过扩展点实现的,也就是 Dubbo 的所有功能点都可被用户自定义扩展所替换。 +* 采用 URL 作为配置信息的统一格式,所有扩展点都通过传递 URL 携带配置信息。 \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi.md new file mode 100644 index 000000000000..0d0487980895 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi.md @@ -0,0 +1,913 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/dubbo-spi/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/dubbo-spi/ +description: 本文介绍了 Dubbo SPI 的原理和实现细节 +linkTitle: 扩展点开发指南 +title: 扩展点开发指南 +type: docs +weight: 0 +--- + +## 1. Dubbo SPI 扩展简介 + +Dubbo 中的扩展机制与 JDK 标准的 SPI 扩展点 原理类似。Dubbo 对其做了一定的改造与加强: + +* JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。 +* 如果扩展点加载失败,JDK SPI 没给出详细信息,不方便定位问题,Dubbo SPI 在失败时记录真正的失败原因,并打印出来 +* 增加 [IOC](#23-ioc-机制)、[AOP](#24-aop-机制) 能力 +* 增加排序能力 +* 增加条件激活能力 +* 提供了一系列更灵活的 API,如[获取所有 SPI 扩展实现](./#21-按名称获取指定扩展类)、[根据名称查询某个扩展实现](./#211-获取所有拓展类)、根据类型查询扩展实现、查询匹配条件的扩展实现等。 + +### 1.1 SPI定义 + +Dubbo 中的 SPI 插件是标准的 Java Interface 定义,并且必须包含 `@org.apache.dubbo.common.extension.SPI` 注解: + +```java +@SPI(value = "dubbo", scope = ExtensionScope.FRAMEWORK) +public interface Protocol { + // ... +} +``` + +`@SPI` 注解的定义如下: + +```java +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface SPI { + /** + * default extension name + */ + String value() default ""; + + /** + * scope of SPI, default value is application scope. + */ + ExtensionScope scope() default ExtensionScope.APPLICATION; +} +``` + +### 1.2 SPI加载流程 + +Dubbo 加载扩展的整个流程如下: + +![//imgs/v3/concepts/extension-load.png](/imgs/v3/concepts/extension-load.png) + +主要步骤为 4 个: +* 读取并解析配置文件 +* 缓存所有扩展实现 +* 基于用户执行的扩展名,实例化对应的扩展实现 +* 进行扩展实例属性的 IOC 注入以及实例化扩展的包装类,实现 AOP 特性 + + +## 2. Dubbo SPI 源码分析 + +### 2.1 按名称获取指定扩展类 + +Dubbo 中,SPI 加载固定扩展类的入口是 ExtensionLoader 的 getExtension 方法,下面我们对拓展类对象的获取过程进行详细的分析。 + +```java +public T getExtension(String name) { + if (name == null || name.length() == 0) + throw new IllegalArgumentException("Extension name == null"); + if ("true".equals(name)) { + // 获取默认的拓展实现类 + return getDefaultExtension(); + } + // Holder,顾名思义,用于持有目标对象 + Holder holder = cachedInstances.get(name); + // 这段逻辑保证了只有一个线程能够创建 Holder 对象 + if (holder == null) { + cachedInstances.putIfAbsent(name, new Holder()); + holder = cachedInstances.get(name); + } + Object instance = holder.get(); + // 双重检查 + if (instance == null) { + synchronized (holder) { + instance = holder.get(); + if (instance == null) { + // 创建拓展实例 + instance = createExtension(name); + // 设置实例到 holder 中 + holder.set(instance); + } + } + } + return (T) instance; +} +``` + +上面代码的逻辑比较简单,首先检查缓存,缓存未命中则创建拓展对象。下面我们来看一下创建拓展对象的过程是怎样的。 + +```java +private T createExtension(String name, boolean wrap) { + // 从配置文件中加载所有的拓展类,可得到“配置项名称”到“配置类”的映射关系表 + Class clazz = getExtensionClasses().get(name); + // 如果没有该接口的扩展,或者该接口的实现类不允许重复但实际上重复了,直接抛出异常 + if (clazz == null || unacceptableExceptions.contains(name)) { + throw findException(name); + } + try { + T instance = (T) EXTENSION_INSTANCES.get(clazz); + // 这段代码保证了扩展类只会被构造一次,也就是单例的. + if (instance == null) { + EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance()); + instance = (T) EXTENSION_INSTANCES.get(clazz); + } + // 向实例中注入依赖 + injectExtension(instance); + + // 如果启用包装的话,则自动为进行包装. + // 比如我基于 Protocol 定义了 DubboProtocol 的扩展,但实际上在 Dubbo 中不是直接使用的 DubboProtocol, 而是其包装类 + // ProtocolListenerWrapper + if (wrap) { + + List> wrapperClassesList = new ArrayList<>(); + if (cachedWrapperClasses != null) { + wrapperClassesList.addAll(cachedWrapperClasses); + wrapperClassesList.sort(WrapperComparator.COMPARATOR); + Collections.reverse(wrapperClassesList); + } + + // 循环创建 Wrapper 实例 + if (CollectionUtils.isNotEmpty(wrapperClassesList)) { + for (Class wrapperClass : wrapperClassesList) { + Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class); + if (wrapper == null + || (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) { + // 将当前 instance 作为参数传给 Wrapper 的构造方法,并通过反射创建 Wrapper 实例。 + // 然后向 Wrapper 实例中注入依赖,最后将 Wrapper 实例再次赋值给 instance 变量 + instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); + } + } + } + } + // 初始化 + initExtension(instance); + return instance; + } catch (Throwable t) { + throw new IllegalStateException("Extension instance (name: " + name + ", class: " + + type + ") couldn't be instantiated: " + t.getMessage(), t); + } +} +``` + +createExtension 方法的逻辑稍复杂一下,包含了如下的步骤: + +1. 通过 getExtensionClasses 获取所有的拓展类 +2. 通过反射创建拓展对象 +3. 向拓展对象中注入依赖 +4. 将拓展对象包裹在相应的 Wrapper 对象中 +5. 初始化拓展对象 + +以上步骤中,第一个步骤是加载拓展类的关键,第三和第四个步骤是 Dubbo IOC 与 AOP 的具体实现。在接下来的章节中,将会重点分析 getExtensionClasses 方法的逻辑,以及简单介绍 Dubbo IOC 的具体实现。 + +#### 2.1.1 获取所有拓展类 + +我们在通过名称获取拓展类之前,首先需要根据配置文件解析出拓展项名称到拓展类的映射关系表(Map\<名称, 拓展类\>),之后再根据拓展项名称从映射关系表中取出相应的拓展类即可。相关过程的代码分析如下: + +```java +private Map> getExtensionClasses() { + // 从缓存中获取已加载的拓展类 + Map> classes = cachedClasses.get(); + // 双重检查 + if (classes == null) { + synchronized (cachedClasses) { + classes = cachedClasses.get(); + if (classes == null) { + // 加载拓展类 + classes = loadExtensionClasses(); + cachedClasses.set(classes); + } + } + } + return classes; +} +``` + +这里也是先检查缓存,若缓存未命中,则通过 synchronized 加锁。加锁后再次检查缓存,并判空。此时如果 classes 仍为 null,则通过 loadExtensionClasses 加载拓展类。下面分析 loadExtensionClasses 方法的逻辑。 + +```java +private Map> loadExtensionClasses() { + // 缓存默认的 SPI 扩展名 + cacheDefaultExtensionName(); + + Map> extensionClasses = new HashMap<>(); + + // 基于策略来加载指定文件夹下的文件 + // 目前有四种策略,分别读取 META-INF/services/ META-INF/dubbo/ META-INF/dubbo/internal/ META-INF/dubbo/external/ 这四个目录下的配置文件 + for (LoadingStrategy strategy : strategies) { + loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages()); + loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages()); + } + + return extensionClasses; +} +``` + +loadExtensionClasses 方法总共做了两件事情,一是对 SPI 注解进行解析,二是调用 loadDirectory 方法加载指定文件夹配置文件。SPI 注解解析过程比较简单,无需多说。下面我们来看一下 loadDirectory 做了哪些事情。 + +```java +private void loadDirectory(Map> extensionClasses, String dir, String type, + boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) { + // fileName = 文件夹路径 + type 全限定名 + String fileName = dir + type; + try { + Enumeration urls = null; + ClassLoader classLoader = findClassLoader(); + + // try to load from ExtensionLoader's ClassLoader first + if (extensionLoaderClassLoaderFirst) { + ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader(); + if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) { + urls = extensionLoaderClassLoader.getResources(fileName); + } + } + // 根据文件名加载所有的同名文件 + if (urls == null || !urls.hasMoreElements()) { + if (classLoader != null) { + urls = classLoader.getResources(fileName); + } else { + urls = ClassLoader.getSystemResources(fileName); + } + } + + if (urls != null) { + while (urls.hasMoreElements()) { + java.net.URL resourceURL = urls.nextElement(); + // 加载资源 + loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages); + } + } + } catch (Throwable t) { + logger.error("Exception occurred when loading extension class (interface: " + + type + ", description file: " + fileName + ").", t); + } +} +``` + +loadDirectory 方法先通过 classLoader 获取所有资源链接,然后再通过 loadResource 方法加载资源。我们继续跟下去,看一下 loadResource 方法的实现。 + +```java +private void loadResource(Map> extensionClasses, ClassLoader classLoader, + java.net.URL resourceURL, boolean overridden, String... excludedPackages) { + try { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) { + String line; + String clazz = null; + // 按行读取配置内容 + while ((line = reader.readLine()) != null) { + // 定位 # 字符 + final int ci = line.indexOf('#'); + if (ci >= 0) { + // 截取 # 之前的字符串,# 之后的内容为注释,需要忽略 + line = line.substring(0, ci); + } + line = line.trim(); + if (line.length() > 0) { + try { + String name = null; + // 以等于号 = 为界,截取键与值 + int i = line.indexOf('='); + if (i > 0) { + name = line.substring(0, i).trim(); + clazz = line.substring(i + 1).trim(); + } else { + clazz = line; + } + // 加载类,并通过 loadClass 方法对类进行缓存 + if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages)) { + loadClass(extensionClasses, resourceURL, Class.forName(clazz, true, classLoader), name, overridden); + } + } catch (Throwable t) { + IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t); + exceptions.put(line, e); + } + } + } + } + } catch (Throwable t) { + logger.error("Exception occurred when loading extension class (interface: " + + type + ", class file: " + resourceURL + ") in " + resourceURL, t); + } +} +``` + +loadResource 方法用于读取和解析配置文件,并通过反射加载类,最后调用 loadClass 方法进行其他操作。loadClass 方法用于主要用于操作缓存,该方法的逻辑如下: + +```java +private void loadClass(Map> extensionClasses, java.net.URL resourceURL, Class clazz, String name, + boolean overridden) throws NoSuchMethodException { + if (!type.isAssignableFrom(clazz)) { + throw new IllegalStateException("Error occurred when loading extension class (interface: " + + type + ", class line: " + clazz.getName() + "), class " + + clazz.getName() + " is not subtype of interface."); + } + // 检测目标类上是否有 Adaptive 注解 + if (clazz.isAnnotationPresent(Adaptive.class)) { + cacheAdaptiveClass(clazz, overridden); + } else if (isWrapperClass(clazz)) { + // 缓存包装类 + cacheWrapperClass(clazz); + } else { + // 进入到这里,表明只是该类只是一个普通的拓展类 + // 检测 clazz 是否有默认的构造方法,如果没有,则抛出异常 + clazz.getConstructor(); + if (StringUtils.isEmpty(name)) { + // 如果 name 为空,则尝试从 Extension 注解中获取 name,或使用小写的类名作为 name + name = findAnnotationName(clazz); + if (name.length() == 0) { + throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL); + } + } + + String[] names = NAME_SEPARATOR.split(name); + if (ArrayUtils.isNotEmpty(names)) { + // 如果类上有 Activate 注解,则使用 names 数组的第一个元素作为键, + // 存储 name 到 Activate 注解对象的映射关系 + cacheActivateClass(clazz, names[0]); + for (String n : names) { + // 存储 Class 到名称的映射关系 + cacheName(clazz, n); + // 存储 name 到 Class 的映射关系. + // 如果存在同一个扩展名对应多个实现类,基于 override 参数是否允许覆盖,如果不允许,则抛出异常. + saveInExtensionClass(extensionClasses, clazz, n, overridden); + } + } + } +} +``` + +如上,loadClass 方法操作了不同的缓存,比如 cachedAdaptiveClass、cachedWrapperClasses 和 cachedNames 等等。除此之外,该方法没有其他什么逻辑了。 + +到此,关于缓存类加载的过程就分析完了。整个过程没什么特别复杂的地方,大家按部就班的分析即可,不懂的地方可以调试一下。 + +### 2.2 加载自适应扩展类 + +先说明下自适应扩展类的使用场景。比如我们有需求,在调用某一个方法时,基于参数选择调用到不同的实现类,这和工厂方法有些类似,基于不同的参数,构造出不同的实例对象。在 Dubbo 中实现的思路和这个差不多,不过 Dubbo 的实现更加灵活,它的实现和策略模式有些类似。每一种扩展类相当于一种策略,基于 URL 消息总线,将参数传递给 ExtensionLoader,通过 ExtensionLoader 基于参数加载对应的扩展类,实现运行时动态调用到目标实例上。 + +自适应扩展类的含义是说,基于参数,在运行时动态选择到具体的目标类,然后执行。 + +在 Dubbo 中,很多拓展都是通过 SPI 机制进行加载的,比如 Protocol、Cluster、LoadBalance 等。有时,有些拓展并不想在框架启动阶段被加载,而是希望在拓展方法被调用时,根据运行时参数进行加载。这听起来有些矛盾。拓展未被加载,那么拓展方法就无法被调用(静态方法除外)。拓展方法未被调用,拓展就无法被加载。对于这个矛盾的问题,Dubbo 通过自适应拓展机制很好的解决了。自适应拓展机制的实现逻辑比较复杂,首先 Dubbo 会为拓展接口生成具有代理功能的代码。然后通过 javassist 或 jdk 编译这段代码,得到 Class 类。最后再通过反射创建代理类,整个过程比较复杂。 + +加载自适应扩展类的入口是 ExtensionLoader 的 getAdaptiveExtension 方法。 + +```java +public T getAdaptiveExtension() { + // 从缓存中获取自适应拓展 + Object instance = cachedAdaptiveInstance.get(); + if (instance == null) { + // 如果存在异常,则直接抛出 + if (createAdaptiveInstanceError != null) { + throw new IllegalStateException("Failed to create adaptive instance: " + + createAdaptiveInstanceError.toString(), + createAdaptiveInstanceError); + } + + synchronized (cachedAdaptiveInstance) { + instance = cachedAdaptiveInstance.get(); + // double check + if (instance == null) { + try { + // 创建自适应拓展 + // 这里分为两种情况:一种是存在 Adaptive 类,另一个是需要生成 Adaptive 类 + instance = createAdaptiveExtension(); + cachedAdaptiveInstance.set(instance); + } catch (Throwable t) { + createAdaptiveInstanceError = t; + throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t); + } + } + } + } + + return (T) instance; +} +``` + +getAdaptiveExtension 方法首先会检查缓存,缓存未命中,则调用 createAdaptiveExtension 方法创建自适应拓展。下面,我们看一下 createAdaptiveExtension 方法的代码。 + +```java +private T createAdaptiveExtension() { + try { + // 获取自适应拓展类,并通过反射实例化 + return injectExtension((T) getAdaptiveExtensionClass().newInstance()); + } catch (Exception e) { + throw new IllegalStateException("Can not create adaptive extension ..."); + } +} +``` +createAdaptiveExtension 方法的代码比较少,但却包含了三个逻辑,分别如下: + +1. 调用 getAdaptiveExtensionClass 方法获取自适应拓展 Class 对象 +2. 通过反射进行实例化 +3. 调用 injectExtension 方法向拓展实例中注入依赖 + +前两个逻辑比较好理解,第三个逻辑用于向自适应拓展对象中注入依赖。这个逻辑看似多余,但有存在的必要,这里简单说明一下。前面说过,Dubbo 中有两种类型的自适应拓展,一种是手工编码的,一种是自动生成的。手工编码的自适应拓展中可能存在着一些依赖,而自动生成的 Adaptive 拓展则不会依赖其他类。这里调用 injectExtension 方法的目的是为手工编码的自适应拓展注入依赖,这一点需要大家注意一下。关于 injectExtension 方法,前文已经分析过了,这里不再赘述。接下来,分析 getAdaptiveExtensionClass 方法的逻辑。 + +```java +private Class getAdaptiveExtensionClass() { + // 通过 SPI 获取所有的拓展类 + getExtensionClasses(); + // 检查缓存,若缓存不为空,则直接返回缓存 + if (cachedAdaptiveClass != null) { + return cachedAdaptiveClass; + } + // 创建自适应拓展类 + return cachedAdaptiveClass = createAdaptiveExtensionClass(); +} +``` + +getAdaptiveExtensionClass 方法同样包含了三个逻辑,如下: + +1. 调用 getExtensionClasses 获取所有的拓展类 +2. 检查缓存,若缓存不为空,则返回缓存 +3. 若缓存为空,则调用 createAdaptiveExtensionClass 创建自适应拓展类 + +这三个逻辑看起来平淡无奇,似乎没有多讲的必要。但是这些平淡无奇的代码中隐藏了着一些细节,需要说明一下。首先从第一个逻辑说起,getExtensionClasses 这个方法用于获取某个接口的所有实现类。比如该方法可以获取 Protocol 接口的 DubboProtocol、HttpProtocol、InjvmProtocol 等实现类。在获取实现类的过程中,如果某个实现类被 Adaptive 注解修饰了,那么该类就会被赋值给 cachedAdaptiveClass 变量。此时,上面步骤中的第二步条件成立(缓存不为空),直接返回 cachedAdaptiveClass 即可。如果所有的实现类均未被 Adaptive 注解修饰,那么执行第三步逻辑,创建自适应拓展类。相关代码如下: + +```java +private Class createAdaptiveExtensionClass() { + // 构建自适应拓展代码 + String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate(); + ClassLoader classLoader = findClassLoader(); + // 获取编译器实现类 + org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); + // 编译代码,生成 Class + return compiler.compile(code, classLoader); +} +``` + +createAdaptiveExtensionClass 方法用于生成自适应拓展类,该方法首先会生成自适应拓展类的源码,然后通过 Compiler 实例(Dubbo 默认使用 javassist 作为编译器)编译源码,得到代理类 Class 实例。接下来,我们把重点放在代理类代码生成的逻辑上,其他逻辑大家自行分析。 + +#### 2.2.1 自适应拓展类代码生成 + +AdaptiveClassCodeGenerator#generate 方法生成扩展类代码 +```java +public String generate() { + // 如果该接口中没有方法被 @Adaptive 注解修饰,直接抛出异常 + if (!hasAdaptiveMethod()) { + throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!"); + } + + StringBuilder code = new StringBuilder(); + // 生成包名、import、方法等. + code.append(generatePackageInfo()); + code.append(generateImports()); + code.append(generateClassDeclaration()); + + Method[] methods = type.getMethods(); + for (Method method : methods) { + code.append(generateMethod(method)); + } + code.append("}"); + + if (logger.isDebugEnabled()) { + logger.debug(code.toString()); + } + return code.toString(); +} + +``` + +#### 2.2.2 生成方法 + +上面代码中,生成方法的逻辑是最关键的,我们详细分析下。 +```java +private String generateMethod(Method method) { + String methodReturnType = method.getReturnType().getCanonicalName(); + String methodName = method.getName(); + // 生成方法内容 + String methodContent = generateMethodContent(method); + String methodArgs = generateMethodArguments(method); + String methodThrows = generateMethodThrows(method); + return String.format(CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent); +} +``` + +generateMethodContent 分析 + +```java +private String generateMethodContent(Method method) { + // 该方法上必须有 @Adaptive 注解修饰 + Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class); + StringBuilder code = new StringBuilder(512); + if (adaptiveAnnotation == null) { + // 没有 @Adaptive 注解修饰,生成异常信息 + return generateUnsupported(method); + } else { + // 获取 URL 在参数列表上的索引 + int urlTypeIndex = getUrlTypeIndex(method); + + if (urlTypeIndex != -1) { + // 如果参数列表上存在 URL,生成对 URL 进行空检查 + code.append(generateUrlNullCheck(urlTypeIndex)); + } else { + // 如果参数列表不存在 URL 类型的参数,那么就看参数列表上参数对象中是否包含 getUrl 方法 + // 有的话,生成 URL 空检查 + code.append(generateUrlAssignmentIndirectly(method)); + } + // 解析 Adaptive 注解上的 value 属性 + String[] value = getMethodAdaptiveValue(adaptiveAnnotation); + // 如果参数列表上有 Invocation 类型的参数,生成空检查并获取 methodName. + boolean hasInvocation = hasInvocationArgument(method); + + code.append(generateInvocationArgumentNullCheck(method)); + // 这段逻辑主要就是为了生成 extName(也就是扩展名) + // 分为多种情况: + // 1.defaultExtName 是否存在 + // 2.参数中是否存在 invocation 类型参数 + // 3.是否是为 protocol 生成代理 + // 为什么要对 protocol 单独考虑了?因为 URL 中有获取 protocol 值的方法 + code.append(generateExtNameAssignment(value, hasInvocation)); + // check extName == null? + code.append(generateExtNameNullCheck(value)); + + // 生成获取扩展(使用 ExtensionLoader.getExtension 方法) + code.append(generateExtensionAssignment()); + + // 生成返回语句 + code.append(generateReturnAndInvocation(method)); + } + + return code.toString(); +} +``` + +上面那段逻辑主要做了如下几件事: +1.检查方法上是否 Adaptive 注解修饰 +2.为方法生成代码的时候,参数列表上要有 URL(或参数对象中有 URL) +3.使用 ExtensionLoader.getExtension 获取扩展 +4.执行对应的方法 + +#### 2.2.3 附一个动态生成代码后的例子 + +```java +package org.apache.dubbo.common.extension.adaptive; + +import org.apache.dubbo.common.extension.ExtensionLoader; + + +public class HasAdaptiveExt$Adaptive implements org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt { + public java.lang.String echo(org.apache.dubbo.common.URL arg0, + java.lang.String arg1) { + // URL 空校验 + if (arg0 == null) { + throw new IllegalArgumentException("url == null"); + } + + org.apache.dubbo.common.URL url = arg0; + // 获取扩展名 + String extName = url.getParameter("has.adaptive.ext", "adaptive"); + // 扩展名空校验 + if (extName == null) { + throw new IllegalStateException( + "Failed to get extension (org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt) name from url (" + + url.toString() + ") use keys([has.adaptive.ext])"); + } + // 获取扩展 + org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt extension = (org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt) ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt.class) + .getExtension(extName); + // 执行对应的方法 + return extension.echo(arg0, arg1); + } +} + +``` + +### 2.3 IOC 机制 + +Dubbo IOC 是通过 setter 方法注入依赖。Dubbo 首先会通过反射获取到实例的所有方法,然后再遍历方法列表,检测方法名是否具有 setter 方法特征。若有,则通过 ObjectFactory 获取依赖对象,最后通过反射调用 setter 方法将依赖设置到目标对象中。整个过程对应的代码如下: + +```java +private T injectExtension(T instance) { + + if (objectFactory == null) { + return instance; + } + + try { + // 遍历目标类的所有方法 + for (Method method : instance.getClass().getMethods()) { + // 检测方法是否以 set 开头,且方法仅有一个参数,且方法访问级别为 public + if (!isSetter(method)) { + continue; + } + /** + * 检测是否有 DisableInject 注解修饰. + */ + if (method.getAnnotation(DisableInject.class) != null) { + continue; + } + + /** + * 检测是否实现了ScopeModelAware、ExtensionAccessorAware类,如果实现则不注入 + */ + if (method.getDeclaringClass() == ScopeModelAware.class) { + continue; + } + if (instance instanceof ScopeModelAware || instance instanceof ExtensionAccessorAware) { + if (ignoredInjectMethodsDesc.contains(ReflectUtils.getDesc(method))) { + continue; + } + } + + // 基本类型不注入 + Class pt = method.getParameterTypes()[0]; + if (ReflectUtils.isPrimitives(pt)) { + continue; + } + + try { + // 获取属性名,比如 setName 方法对应属性名 name + String property = getSetterProperty(method); + // 从 ObjectFactory 中获取依赖对象 + Object object = objectFactory.getExtension(pt, property); + if (object != null) { + // 注入 + method.invoke(instance, object); + } + } catch (Exception e) { + logger.error("Failed to inject via method " + method.getName() + + " of interface " + type.getName() + ": " + e.getMessage(), e); + } + + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return instance; +} +``` + +在上面代码中,objectFactory 变量的类型为 AdaptiveExtensionFactory,AdaptiveExtensionFactory 内部维护了一个 ExtensionFactory 列表,用于存储其他类型的 ExtensionFactory。Dubbo 目前提供了两种 ExtensionFactory,分别是 SpiExtensionFactory 和 SpringExtensionFactory。前者用于创建自适应的拓展,后者是用于从 Spring 的 IOC 容器中获取所需的拓展。这两个类的类的代码不是很复杂,这里就不一一分析了。 + +Dubbo IOC 目前仅支持 setter 方式注入,总的来说,逻辑比较简单易懂。 + +### 2.4 AOP 机制 + +Dubbo AOP 机制采用 wrapper 设计模式实现,要成为一个 AOP wrapper 类,必须同时满足以下几个条件: +1. wrapper 类必须实现 SPI 接口,如以下示例中的 `class QosProtocolWrapper implements Protocol` +2. 构造器 constructor 必须包含一个相同的 SPI 参数,如以下示例中 `QosProtocolWrapper(Protocol protocol)` +3. wrapper 类必须和普通的 SPI 实现一样写入配置文件,如以下示例 `resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol` + +```java +public class QosProtocolWrapper implements Protocol, ScopeModelAware { + private final Protocol protocol; + public QosProtocolWrapper(Protocol protocol) { + if (protocol == null) { + throw new IllegalArgumentException("protocol == null"); + } + this.protocol = protocol; + } +} +``` + +写入配置文件 `resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol`: + +```properties +qos=org.apache.dubbo.qos.protocol.QosProtocolWrapper +``` + +在通过 `getExtension(name)` 尝试获取并加载 SPI 扩展实例时,Dubbo 框架会判断所有满足以上 3 个条件的 wrapper 类实现,并将 wrapper 类按顺序包在实例外面,从而达到 AOP 拦截的效果。 + +以下是 wrapper 判断与加载的实现逻辑,你还可以使用 @Wrapper 注解来控制 wrapper 类的激活条件: + +```java +private T createExtension(String name, boolean wrap) { + Class clazz = getExtensionClasses().get(name); + T instance = (T) extensionInstances.get(clazz); + // ... + if (wrap) { // 如果调用方告知需要 AOP,即 wrap=true + List> wrapperClassesList = new ArrayList<>(); + if (cachedWrapperClasses != null) { + wrapperClassesList.addAll(cachedWrapperClasses); + wrapperClassesList.sort(WrapperComparator.COMPARATOR); + Collections.reverse(wrapperClassesList); + } + + if (CollectionUtils.isNotEmpty(wrapperClassesList)) { + for (Class wrapperClass : wrapperClassesList) { + // 通过 @Wrapper 注解判断当前 wrapper 类是否要生效 + Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class); + boolean match = (wrapper == null) + || ((ArrayUtils.isEmpty(wrapper.matches()) + || ArrayUtils.contains(wrapper.matches(), name)) + && !ArrayUtils.contains(wrapper.mismatches(), name)); + if (match) { + instance = injectExtension( + (T) wrapperClass.getConstructor(type).newInstance(instance)); + instance = postProcessAfterInitialization(instance, name); + } + } + } + } +} +``` + +### 2.5 Activate激活条件 + +可以使用 `@org.apache.dubbo.common.extension.Activate` 来控制 SPI 扩展实现在什么场景下加载生效。相比于任何场景下都生效,能精确的控制扩展实现的生效条件会让实现变得更灵活。 + +以下是一些使用场景示例: + +```java +// 不加 @Activate 注解,getActivateExtension() 时不会加载,其他 getExtension() 方法仍可正常加载 +public class MetricsProviderFilter implements Filter{} +``` + +```java +// 不加任何参数,表示在 getActivateExtension() 时无条件自动返回 +@Activate +public class MetricsProviderFilter implements Filter{} +``` + +```java +// group 支持 consumer、provider 两个固定值,getActivateExtension() 调用加载扩展点时自动过滤 +// provider 表示在提供者端会被加载;consumer 表示在消费者端会被加载 +@Activate(group="provider") +public class MetricsProviderFilter implements Filter{} +``` + +```java +// URL 参数中有 cache 这个 key 时,调用 getActivateExtension() 才会加载 +@Activate(value="cache") +public class MetricsProviderFilter implements Filter{} +``` + +```java +// URL 参数中有 cache 这个 key 并且值为 test 时,调用 getActivateExtension() 才会加载 +@Activate(value="cache:test") +public class MetricsProviderFilter implements Filter{} +``` + +以下是 `@Activate` 注解的具体定义: + +```java +/** + * Activate. This annotation is useful for automatically activate certain extensions with the given criteria, + * for examples: @Activate can be used to load certain Filter extension when there are + * multiple implementations. + *
    + *
  1. {@link Activate#group()} specifies group criteria. Framework SPI defines the valid group values. + *
  2. {@link Activate#value()} specifies parameter key in {@link URL} criteria. + *
+ * SPI provider can call {@link ExtensionLoader#getActivateExtension(URL, String, String)} to find out all activated + * extensions with the given criteria. + * + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +public @interface Activate { + /** + * Activate the current extension when one of the groups matches. The group passed into + * {@link ExtensionLoader#getActivateExtension(URL, String, String)} will be used for matching. + * + * @return group names to match + * @see ExtensionLoader#getActivateExtension(URL, String, String) + */ + String[] group() default {}; + + /** + * Activate the current extension when the specified keys appear in the URL's parameters. + *

+ * For example, given @Activate("cache, validation"), the current extension will be return only when + * there's either cache or validation key appeared in the URL's parameters. + *

+ * + * @return URL parameter keys + * @see ExtensionLoader#getActivateExtension(URL, String) + * @see ExtensionLoader#getActivateExtension(URL, String, String) + */ + String[] value() default {}; + + /** + * Absolute ordering info, optional + * + * Ascending order, smaller values will be in the front o the list. + * + * @return absolute ordering info + */ + int order() default 0; + + /** + * Activate loadClass when the current extension when the specified className all match + * @return className names to all match + */ + String[] onClass() default {}; +} +``` + +### 2.6 扩展点排序 + +排序同样使用 `@Activate` 注解设置,以下是使用示例,`order` 值越小加载优先级越高。 + +```java +@Activate(order=100) +public class FilterImpl1 implements Filter{} + +@Activate(order=200) +public class FilterImpl2 implements Filter{} +``` + +## 3. Dubbo SPI 扩展示例 + +### 3.1 加载固定扩展类 + +#### 3.1.1 编写 SPI 接口及实现类 + +不管是 Java SPI,还是 Dubbo 中实现的 SPI,都需要编写接口。不过 Dubbo 中的接口需要被 @SPI 注解修饰。 + +```java +@SPI +public interface DemoSpi { + void say(); +} + +public class DemoSpiImpl implements DemoSpi { + public void say() { + } +} +``` + +#### 3.1.2 将实现类放在特定目录下 + +从上面的代码可知,dubbo 在加载扩展类的时候,会从四个目录中读取。我们在 META-INF/dubbo 目录下新建一个以 DemoSpi 接口名为文件名的文件,内容如下: + + +```text +demoSpiImpl = com.xxx.xxx.DemoSpiImpl(为 DemoSpi 接口实现类的全类名) +``` + +#### 3.1.3 使用 + +```java +public class DubboSPITest { + + @Test + public void sayHello() throws Exception { + ExtensionLoader extensionLoader = + ExtensionLoader.getExtensionLoader(DemoSpi.class); + DemoSpi dmeoSpi = extensionLoader.getExtension("demoSpiImpl"); + optimusPrime.sayHello(); + } +} +``` + +### 3.2 加载自适应扩展类 + +这个以 Protocol 为例进行说明 + +#### 3.2.1 Protocol 接口(抽取部分核心方法) + +```java +@SPI("dubbo") +public interface Protocol { + @Adaptive + Exporter export(Invoker invoker) throws RpcException; + + @Adaptive + Invoker refer(Class type, URL url) throws RpcException; +} + +public class DubboProtocol extends AbstractProtocol { + ...... + @Override + public Invoker refer(Class type, URL url) throws RpcException { + return protocolBindingRefer(type, url); + } + + @Override + public Exporter export(Invoker invoker) throws RpcException { + ...... + return exporter; + } +} +``` + +#### 3.2.2 将实现类放在特定目录下 +在 dubbo 中,该配置路径 META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol +```text +dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol +``` + +需要说明一点的是,在 dubbo 中,并不是直接使用 DubboProtocol 的,而是使用的是其包装类。 + +#### 3.2.3 使用 + +```java +public class DubboAdaptiveTest { + + @Test + public void sayHello() throws Exception { + URL url = URL.valueOf("dubbo://localhost/test"); + Protocol adaptiveProtocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + adaptiveProtocol.refer(type, url); + } +} +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/mesh.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/architecture/mesh.md.bak new file mode 100644 index 000000000000..3a6b24400b7b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/mesh.md.bak @@ -0,0 +1,80 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/concepts-and-architecture/mesh/ + - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/mesh/ +description: 本文将介绍 Dubbo Mesh 架构设计。 +linkTitle: Dubbo Mesh +title: Dubbo Mesh +type: docs +weight: 5 +--- + + + + + + +Dubbo Mesh 从设计理念上更强调控制面的统一管控、标准化与治理能力,而在数据面给出了更多的选择,包括 Sidecar Mesh 与 Proxyless Mesh 等部署模式。多种部署模型给企业提供了更多选择,通过混合部署的模型,在实现服务治理控制面的共享的同时,可以更好的应对不同场景的部署要求(性能、部署复杂性等),适应复杂的基础设施环境并从总体上提升架构的可用性。 + +## 背景 +在云原生背景下,如果我们将 Service Mesh 理解为底层基础设施,则在 Mesh 架构中,以往耦合在业务进程中的微服务治理部分能力正被 Mesh 接管,传统微服务框架更注重 RPC 协议与编程模型。以下是时下流行的 Mesh 产品 Istio 的架构图: + +![istio](/imgs/v3/mesh/istio.jpg) + +在 Mesh 架构下 +* 统一的控制面提供证书管理、可观测性、流量治理等能力 +* Sidecar 让 SDK 更轻量、侵入性更小,更好的实现透明升级、流量拦截等 + +## Dubbo Mesh 总体架构 + +![istio](/imgs/v3/mesh/dubbo-mesh-arc.png) + +* 数据面基于 Triple 协议进行 RPC 通信; +* 地址发现模型采用应用级服务发现,支持超大规模实例集群的同时,提供更丰富的服务治理能力; +* Dubbo Mesh 控制面基于业界主流 Istio 扩展,支持 Dubbo 服务发现定制方案,同时提供更丰富的流量管控能力,; +* 数据面支持两种模式:ThinSDK + Sidecar(如 Envoy) 和 Proxyless; + + +> 对于 Dubbo2 老用户或已升级 Dubbo3 但尚未迁移新特性的用户,可以考虑参考其他 Mesh 开源社区(如 Aeraki)提供的 Dubbo 方案。 +> 但部分功能可能受限,同时会有一定的性能和容量瓶颈。 + +### Dubbo Sidecar Mesh +Dubbo 提供了 ThinSDK 的部署模式,在此模式下,Dubbo ThinSDK 将只提供面向业务应用的编程 API、RPC 传输通信能力,其余服务治理 +包括地址发现、负载均衡、路由寻址等都统一下沉到 Sidecar,Sidecar 负责与控制面直接通信并接收各种流量管控规则。以下是基本部署架构图,Dubbo ThinSDK 与 Sidecar 部署在同一个 Pod 或容器中,通过在外围部署一个独立的控制平面,实现对流量和治理的统一管控。控制面与 Sicecar 之间通过图中虚线所示的 xDS 协议进行配置分发,而 Dubbo 进程间的通信不再是直连模式,转而通过 Sidecar 代理,Sidecar 拦截所有进出流量,并完成路由寻址等服务治理任务。 + +![dubbo-sidecar](/imgs/v3/mesh/dubbo-sidecar.png) + +社区推荐选型 Envoy 作为 Sidecar,通信协议使用 Triple 以获得更好的网关穿透性与性能体验。对于暂时无法升级 Triple 的仍在使用 Dubbo2 协议用户来说,可参考 Envoy、Aeraki Mesh 提供的 Dubbo2 协议支持方案。 + +ThinSDK + Sidecar 模式的 Mesh 架构有很多优势,如平滑升级、多语言、业务侵入小等,但也带来了一些额外的问题,比如: +* Sidecar 通信带来了额外的性能损耗,这在复杂拓扑的网络调用中将变得尤其明显。 +* Sidecar 的存在让应用的声明周期管理变得更加复杂。 +* 部署环境受限,并不是所有的环境都能满足 Sidecar 部署与请求拦截要求。 + +详细方案设计与示例请参考 +* [Dubbo ThinSDK Proposal](/zh-cn/overview/tasks/mesh) +* [使用示例](/zh-cn/overview/tasks/mesh) + +### Dubbo Proxyless Mesh +作为 ThinSDK + Sidecar 模式的补充,Dubbo 社区自很早之前就做了 Dubbo 直接对接到控制面的设想与思考,也就是当前所说的 Proxyless Mesh 模式。Proxyless 模式使得微服务又回到了 2.x 时代的部署架构。如下图所示,和我们上面看的 Dubbo 经典服务治理模式非常相似,所以说这个模式并不新鲜, Dubbo 从最开始就是这么样的设计模式。但相比于 Mesh 架构,Dubbo2 并没有强调控制面的统一管控,而这点恰好是 Service Mesh 所强调的,强调对流量、可观测性、证书等的标准化管控与治理,也是 Mesh 理念先进的地方。 + +![dubbo-proxyless](/imgs/v3/mesh/dubbo-proxyless.png) + +通过不同语言版本的 Dubbo3 SDK 直接实现 xDS 协议解析,Dubbo 进程可以与控制面(Control Plane)直接通信,进而实现控制面对流量管控、服务治理、可观测性、安全等的统一管控,规避 Sidecar 模式带来的性能损耗与部署架构复杂性。 + +> Proxyless 模式同时支持 Dubbo2、Triple 协议,但只支持应用级服务发现的地址模型。 + +在 Dubbo3 Proxyless 架构模式下,Dubbo 进程将直接与控制面通信,Dubbo 进程之间也继续保持直连通信模式,我们可以看出 Proxyless 架构的优势: +* 没有额外的 Proxy 中转损耗,因此更适用于性能敏感应用 +* 更有利于遗留系统的平滑迁移 +* 架构简单,容易运维部署 +* 适用于几乎所有的部署环境 + +详细方案设计与示例请参考 +* [Dubbo Proxyless Mesh](/zh-cn/overview/tasks/mesh) +* [使用示例](/zh-cn/overview/tasks/mesh) + +### Dubbo 控制面治理规则 +TBD + +Dubbo SDK 提供了非常灵活的配置来控制服务治理行为,如接口粒度的服务地址发现能力、接口粒度的配置同步等,这些能力让应用的开发和部署更加灵活。而在通用的 Mesh 部署方案或产品下一些高级功能可能受限,从总体上影响了易用性与灵活性。为此 Dubbo 计划提供自研控制面产品,以最大化的在 Mesh 体系发挥 Dubbo3 能力。 \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/_index.md new file mode 100755 index 000000000000..8f62be7b075b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/_index.md @@ -0,0 +1,7 @@ +--- +description: "Dubbo 多实例、多应用设计原理、实现与使用方法。" +linkTitle: 多实例部署 +title: 多实例部署 +type: docs +weight: 100 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/develop.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/develop.md new file mode 100644 index 0000000000000000000000000000000000000000..347e5cc3013e7e5ce4a300228ea2357835d6b11a GIT binary patch literal 7392 zcmb_h>u=lE74K*M6xY4UQYc=XsA|DJ3= z=5Ji@{v|(He!EthEI9kKrPaaGtMSs}E*XA9X6DJ{T=`_Nyf#_f%@=onC>8Q#>Tzk| zzLP&F9en#se&}N^X{K)9H0`8uo(IOx@)B9vKt{#gSI)On#iJ#Z&)F_jRiSd>dn6=> zc{20RS$s>LPdU$qem$HduU;1SR$WD3eOFp5P@$g2Ja8;cZ*lfO8pP_BmgVjkX74Tg zJTGzr*o5=Uz^uTF%~mKK&e6lZ_enYK+_`f+*&cF!T5~qm$npfo6%VG#%n#1e_=R*j zX=*C??2ja*>*a6J`m9KRA(xwW^Q+CR$pKs_ph802nNEza3}zDfv~8A zqGC7@lEt7bi(xquQe+{hDTWx8WI;^GVL=MYaX}GvS%~UNG-Mc}p~xx~b52W|M#}Ei zyK)gx4omTvB!mo66Qs68#_H=zt6AG8EV3=P+Qjgw*ge)uoP{}+Nzz)cIj5ifX@R- zqbo%}+G_ST)h#GTLn1ww5se#y6axigQ8<_!k89D0oDfC1?GBSF$CM7v*_;6&*Svz* ztlT>)9xjlvMRKrD_TH5a9+JWW*>)`Q@N9HcKAP|9ZHHj4)@AeJCN1C(dri=Hby#HKSj2!JEsOcoDUEBS9IHW)I24g-WfovW$F z#Bs38J8w41>)$y$2jszOmckMa=;YTaR#!*Mg)K7t&Kb|cBIp5{l^$)7m6iVw_9Q6= zs0<2PGN`u@{yUhCNve$6~su*JDpos!&7h zDPr(Fpr=G7MLY|75jiABby*bDctjK=O^*xlcqk}D!=esR7KNB|p(n|a4$eaha|vJE zo%RPgq-?VP2-0rp&4CNA&w4Igz5M01p1%T+E?mEUrTgNAo88wwho`I8E`4$3GRJ+? z;A{_vn0-8n)phVGKpL|r%{JRZrTukqcQ$R73Tvg=5i;|jc>JvV^BjPM48LILYU08J zId4?4&tup)KM$5RCTPmuouK;v_Jk#gv6vhb1w9njrC<<3I%22*nz$mwBbp*;K|LA{ zO7Uw}QoAjp`in9s_S_sHT~todM= z^2yW6=p-oUkvsF7@JnW2f}Kl?Z=LBEeq*2+S}R;l*WPZxXRZLoD-UG`MN#4TNq6Dhd6{z(0TTvJiS9^=0GF_C(uJ#K^iD1 zSVI_!s(lMmK%pQbZ@{VEd1%m=3n!H)g?hEqCRGNj8ZBs$V$jT(3drIy%?1>Y+e3&Z zlz@hXK8>zJ*4dq)*@z*E)jOmGt#Jn*;l$t>*C&i+(;HNq-=2FS&_aYmVIiSu5kpaQ zA*{%*0*gLv`S=rZBMh znjE*Jj0{)qZPbXtZ_cAl=v8R8dcFWH7X|C=B<*jWJ%PypGY^gxZvLsJ8pM)M1Yg`+ zL2fLTDQ{Mt%Io*Z*i#7cru0Wce0GvT0n~HeJT7lS2n?0;_W+AtO1Z%rOWK-cY`0H? zQK-l0vuxw4VXL}otL}PtUpfhU)m40_I|Z$2N;BO4tEtl?TO(w81p<&_v~ky&7$IXL z(EW*YuG)r@KMBud>_-4P^Z|4g;sIt2co~~QdYYQfg~>|18GvvHH}YNG#?yUU#8spR1ZZh~s6U$~=Y49sfv>S;+e zo8>Pd6#i`W8<`YM-aWabZ#t)Wo;Tr-K?5qwpGNnI?_P&Vgu}4Yq%&r}Y8(8S#|IbE z)Bo`rD3XD!i*KVP`z=%Fvvnv%RGrDSYSa%iETz876aesdc6Pd!c9x-TAA5P5sX!Cg zc)tF|i%UQ`Xg^ao{yd+k)&Rz<72LCcZWkC=%&h(U9-|ljWd@)&*_LJ{>7tP`GJoKc z?x$=EtWeHgPjJOjp{TW=#;KD5qk|ov8iKydUeP@c)j|)-eah&}1mAwqN+#jX2QGhT zgk?L;?B|w!xi4)Gw0o*~XQ7Oll}^*bI}TW>_PT2c`ZoQkZgj$hlL1z-2C53tUG(7H zI_IIU>RpKLs$XmH3@A~*&s>#E`V3L^65KvhMXLVEw%7X@40e}Q3M|0kh5`)1jF(n! z>h>307{oBd{bjXwuZ3=H<>?N$YEZeXwt9{{{hf=+8~`ihf}xIUdkX5^C;Xj^nugQ3 zRnKb+P{msQamMD#`C(6D_2R`%%TP6h!!(tz~#qc9=ZUp7jKLO)<>V?CGQaB zoei89uz`xhDAEEaevm-RR~enbe$q$YLQ&s%;lBiNb%;jR2cG2x#7%wnK*8740CKM>DFcPG4 z$s{z*<&#Hbak;+tS!hw&>q51?#;>CVZ9|qmgBsL_@<CQa=xS+w ziY)CrPd7Q*XnQemden7rG$HtO>a1_oc#I~vm?njL{xrZbr2B>nn3bAZEWA(f?h)wi z$I?bMQPB~UxxgnK+fVSx->%(&{mS4JnI35>cOKQLK&F!#L-EpvUuj^87bt$0)+Pap zIV49E!%hvtu&1foErXNc6U~}9w}FzrnFG0d`a#bImnHN&i|VXN_Fj`w`ZWV^fa^XQ z1O9;YfYf3#u6=vu-!wAxtWnSjg;DtLFG3P1pUgY2*Pu^8e1H^$3%w3t-?C7A7mlH4 N^=F4bEu1*^^FKl2ok{=z literal 0 HcmV?d00001 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/model.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/model.md new file mode 100644 index 000000000000..3b5bc831856e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/model.md @@ -0,0 +1,178 @@ +--- +description: "Dubbo 多实例相关领域模型与概念" +linkTitle: 模型与概念 +title: 多实例相关的模型与概念定义 +type: docs +weight: 3 +--- + +## Dubbo 架构 + +JVM —— 虚拟机层 +目的:Dubbo 框架之间完全隔离(端口不能复用) + +Dubbo Framework —— 框架层 +目的:将需要全局缓存的进行复用(端口、序列化等) + +Application —— 应用层 +目的:隔离应用之间的信息,包括注册中心、配置中心、元数据中心 + +Services —— 模块层 +目的:提供热加载能力,可以按 ClassLoader、Spring Context 进行隔离上下文 + +## Dubbo 概念对齐 + +1. DubboBoorstrap + 1. 需要拆分 export/refer services、ServiceInstance、Metadata/Config 等 Client +2. ConfigManager + 1. 需要拆分应用级配置信息、模块级配置信息 +3. ApplicationModel + 1. 实际存储应用层信息,持有到 ConfigManager 应用级配置信息的引用 +4. ConsumerModel + 1. 实际存储接口信息,由 ModuleModel 持有引用 +5. ProviderModel + 1. 实际存储接口信息,由 ModuleModel 持有引用 +6. ExtensionLoader + 1. 需要根据不同层级 load 出不同的实例对象 +7. Registry + 1. 应用级别共享,需要确保多实例订阅正常(考虑单元化场景) +8. Router / Filter + 1. 模块级别共享 +9. Protocol / Remoting + 1. 框架级别共享,复用 IO,多应用间贡献 +10. Metadata + 1. 应用级别共享,考虑应用级服务发现 +11. QoS + 1. 框架级别共享,与 IO 有关 +12. Serialization + 1. 框架级别共享,与 IO 有关 +13. ConfigCenter + 1. 应用级别贡献 +14. ModuleModel(新) + 1. 实际存储模块层信息,持有接口级信息 +15. FrameworkModel(新) + 1. 实际存储框架层信息 + +## 配置存储梳理 + +### FrameworkModel +Qos、Protocol、Remoting、Serialization、ExtensionLoader + +### ApplicationModel +ConfigManager(应用级)、DubboBootstrap(类 Fluent API)、Registry、Metadata、ServiceInstance、ConfigCenter、ExtensionLoader + +### ModuleModel +ConsumerModel、ProviderModel、Router、Filter、ExtensionLoader + + +![](https://intranetproxy.alipay.com/skylark/lark/0/2021/jpeg/15256464/1628824598406-95556f0d-7817-4010-97a7-0f8e84a175cb.jpeg) +## Dubbo 流程梳理 + +### Model 创建 + +DefaultModel - FrameworkModel、ApplicationModel、ModuleModel + +1. 默认 Model 创建时机 +2. 用户自定义的 Model 的创建方式 + +### 消费端初始化 + +1. 消费端通过 ReferenceConfig 作为入口进行初始化配置相关信息,当前配置里面需要添加 ClassLoader 属性,ReferenceConfig 生成 ConsumerModel 注入到 ModuleModel +2. 组装的 URL 需要包含当前 ConsumerModel、ModuleModel、ApplicationModel、FrameworkModel(需要梳理全链路内 URL 转换逻辑,保证在中间不会被丢弃) +3. 组装链路上 Registry 为 ApplicationModel 域内的(订阅需要考虑订阅之间互相独立、多注册中心场景) ;Filter、Cluster、LoadBalance 为 ModuleModel 域内的 +4. Directory 需要持有包括详细信息的 ConsumerURL,序列化层需要传入配置信息 +5. ModuleModel 内三元组唯一,总是创建出同一个 proxy;ModuleModel 间允许重复三元组,proxy、invoker 均相互独立 + +### 服务端初始化 + +1. 服务端通过 ServiceConfig 作为入口进行初始化配置相关信息,当前配置里面需要添加 ClassLoader 属性,ServiceConfig 生成 ProviderModel 注入到 ModuleModel +2. 组装的 URL 需要包含当前 ProviderModel、ModuleModel、ApplicationModel、FrameworkModel(需要梳理全链路内 URL 转换逻辑,保证在中间不会被丢弃) +3. 组装链路上 Registry 为 ApplicationModel 域内的(订阅需要考虑服务之间互相独立、多注册中心场景) ;Filter 为 ModuleModel 域内的 +4. Protocol 层持有的三元组保证唯一,可以直接找到 ProviderModel(FrameworkModel 域内) + +### 地址推送流程 + +1. 注册中心监听需要确保三元组重复的订阅都能独立收到通知、相同三元组到注册中心的订阅链接可以进行复用 +2. 注册中心工作在 ApplicationModel 域,通过持有监听列表连接 ModuleModel 层,地址的处理为 ModuleModel 域内操作,如果服用地址通知需要保证通知内容不会被某个订阅所修改 +3. 每份地址通知根据不同 ModuleModel 独立创建 Invoker,Invoker 直接持有 ConsumerModel +4. Invoker 的底层 Protocol 层连接复用 TCP 连接 + +### 消费端调用链路 + +1. 消费端创建 invocation 时需要携带当前 ConsumerModel、ModuleModel、ApplicationModel、FrameworkModel (通过 consumerURL 携带),需要保证调用全链路 consumerURL 不丢失 + +### 服务端调用链路 + +1. 服务端收到请求后根据三元组定位 ProviderModel 及 invoker,进行反序列化时需要考虑 ClassLoader 切换 + +### 其他流程 + +1. 销毁流程 +2. QoS 聚合方式 + +## 代码改动 + +1. ExtensionLoader 依赖注入 +```java +ModuleModel.getExtensionFactory().getAdaptiveExtension(Protocol.class) +ApplicationModel.getExtensionFactory().getAdaptiveExtension(Protocol.class) +FrameworkModel.getExtensionFactory().getAdaptiveExtension(Protocol.class) + + +@SPI(scope = FRAMEWORK) +public interface Protocol { +} +``` + +- SPI 依赖注入 +2. DubboBootstrap -> 功能拆分(ModuleModel 维护生命周期) +```java +// 创建新应用实例,共享FrameworkModel +DubboBootstrap.newInstance(FrameworkModel) // SharedFrameworkModel -> NewApplicationModel + .addModule() // New ModuleModel + .addReference(ReferenceConfig) // 将服务配置挂到模块下 + .addReference(ReferenceConfig) + .addService(ServiceConfig) + .endModule() + .addModule() + .addReference(ReferenceConfig) + .addService(ServiceConfig) + .endModule() + .addRegistry() + .addConfigCenter() + .start() + +// 兼容旧的Bootstrap API,使用默认应用实例 +DubboBootstrap.getInstance() // DefaultFrameworkModel -> DefaultApplicationModel + .addReference(ReferenceConfig) // DefaultApplicationModel -> DefaultModuleModel + .addService(ServiceConfig) // DefaultApplicationModel -> DefaultModuleModel + .setRegistry() // DefaultApplicationModel + .start() + +// 新建应用实例 +DubboBootstrap.newInstance() // DefaultFrameworkModel -> NewApplicationModel + .addReference(ReferenceConfig) // NewApplicationModel -> DefaultModuleModel + .addService(ServiceConfig) // NewApplicationModel -> DefaultModuleModel + .setRegistry() // NewApplicationModel + .start() + +``` + +3. RefenceConfig、ServiceConfig + 1. ModuleModel 动态设置 + 2. 需要把 ExtensionLoader 初始化的地方下放到 setModuleModel + 3. consumerUrl 携带 ModuleModel +4. ModuleModel、ApplicationModel、FrameworkModel + 1. ModuleModel -> ConsumerModels、ProviderModels + 2. ApplicationModel -> ConfigManager(应用级的属性信息)、ModuleModels +5. ConsumerModel、ProviderModel +6. 注册中心需要支持多订阅 +7. Spring + + +1. ModuleModel、ApplicationModel、FrameworkModel(ExtensionLoader) +2. RefenceConfig、ServiceConfig(ConsumerModel、ProviderModel) +3. ExtensionLoader (Filter 改动) + + + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/multi-instance.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/multi-instance.md new file mode 100644 index 000000000000..b11036ba60d3 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/multi-instance.md @@ -0,0 +1,113 @@ +--- +description: "Dubbo 多实例、多应用设计原理、实现与使用方法。" +linkTitle: 多实例设计理念 +title: 多实例部署的设计理念 +type: docs +weight: 1 +--- + +## 背景 + +Java 提供的静态变量(static field)能力可以将持有对象引用的行为绑定到类上面来,这给开发者提供了巨大的便利。注入单例模式、工厂模式等设计模式的实现方案都依赖了静态变量的功能。通过使用静态变量,开发者可以在任何时间、任何地点简单地获取到所需要的对象信息。 +```java +public class Test { + public static Object obj; +} +Test.obj = xxx; +``` +在一直以来的 Dubbo 框架开发中,静态变量受到了广泛地应用,诸如使用一个全局共享的 ConfigManager 来存储全局配置信息、ServiceRepository 来存储服务信息,不论从中心化管理配置或者是参数获取的便利性的角度来说,这种设计都是最佳的。在 Dubbo 2.7 以前的所有版本,Dubbo 所需要的运行时配置信息都通过全局静态变量获取,通过 RPC 服务三元组(interface + version + group)的方式进行唯一定位。 + +但是随着 Dubbo 用户基数的不断扩大以及在阿里集团内由 Dubbo 作为内核的 HSF3 框架都对原来的这种设计模式提出了挑战。 + +对于开源用户,社区收到的诉求主要包括以下几点: + +1. 在同一个应用内能够创建多个三元组一样的订阅。这个行为在 Dubbo 2.7 中虽然没有做强限制,但是由于 Dubbo 很多参数是取自全局的,而这个获取的索引使用的就是三元组。如果用户创建了两个三元组一样的订阅,他们的参数会被相互覆盖,地址推送等功能也会收到很大的影响。 +2. Java 提供了自定义 ClassLoader 的机制可以自定义指定类的加载器来源,但是对于 Dubbo 来说并没有去支持多 ClassLoader 的场景,在动态代理生成和序列化场景下都不支持 ClassLoader 切换的行为。 +3. Dubbo 众多的测试用例都共享了同一份配置信息,导致在进行单元测试的时候极为容易造成环境污染的问题。 + +对于阿里集团内大规模落地来说,我们遇到的问题主要有: + +1. 阿里集团内有众多的中间件框架,这些框架提供了各种各样的类加载方式,同时业务方期望在同一应用内的配置等信息是相互隔离的。 +2. 一些业务方的定制逻辑需要支持动态热部署的模式,具体体现在动态对某个虚拟环境进行销毁,这需要 Dubbo 内的生命周期管理更加完善。 +3. 集团内有多个对 Spring 容器进行定制化开发的框架,需要 Dubbo 能够支持多个 Spring Context 独立管理生命周期的场景。 + +基于众多的这些原因,在八月初的时候我们决定对 Dubbo 的生命周期进行重构,经过一个月的紧张开发,目前社区版本已经完整支持了多实例化的功能,Dubbo 的生命周期也变得更加清晰。 + +## 设计 + +整个 Dubbo 多实例的设计我们按照了三层模型来配置,分别是 Framework 框架层、Application 应用层、Module 模块层。 +![image.png](https://cdn.nlark.com/yuque/0/2021/png/209479/1633766738924-498b5ac4-d96b-48f4-a55f-8cc946800bee.png#clientId=uc9c7eb9b-dec6-4&from=paste&height=446&id=ub35f4a80&originHeight=892&originWidth=2366&originalType=binary&ratio=1&size=483065&status=done&style=none&taskId=u01b03e88-733f-422b-94ea-cf45220737c&width=1183) +基于三层机制,我们可以将 Dubbo 按照一定规则进行隔离: + +1. Framework 与 Framework 之间完全隔离,相当于是使用了两个完全不同的 Dubbo 实例 +2. Application 与 Application 之间按照应用名进行隔离,但是相互有些地共享 Protocol、Serialization 层,目标是达到在同一个 dubbo 端口(20880)上可以承载多个应用,而每个应用独立上报地址信息。 +3. Module 与 Module 之间可以由用户自定义进行进行隔离,可以是热部署周期的一个状态、也可以是 Spring Context 的一个 Context。通过 Module,用户可以对 Dubbo 的生命周期粒度进行最小的管理。 + +为了实现 Dubbo 多实例化,Dubbo 框架内做的最多的变化是修改掉大部分的从静态变量中获取的参数的逻辑,最明显的逻辑是 Dubbo 内部用于参数传递的 URL 对象带上了 ScopeModel 状态,这个 ScopeModel 对应的就是上面提到的三层模型的具体数据承载对象。 + +## 使用方式 + +多实例重构版本之后的 Dubbo 对于大多数用户的使用来说是无感知的,改造后的 DubboBootstrap 已经变成一个独立的启动器,用户可以通过 DubboBootstrap 定制多实例的使用。 + +下面是使用多实例的一个简单的例子。 + +```java + ServiceConfig service = new ServiceConfig<>(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + + ReferenceConfig reference1 = new ReferenceConfig<>(); + reference1.setInterface(DemoService.class); + + ReferenceConfig reference2 = new ReferenceConfig<>(); + reference2.setInterface(DemoService.class); + + // 创建一个启动器(自动创建新 ApplicationModel) + DubboBootstrap bootstrap1 = DubboBootstrap.newInstance(); + // 指定应用名 + bootstrap1.application(new ApplicationConfig("dubbo-demo-app-1")) + .registry(new RegistryConfig("nacos://localhost:8848")) + // 创建一个模块 + .newModule() + // 在模块内发布服务 + .service(service) + .endModule() + // 创建一个模块 + .newModule() + // 在模块内订阅服务 + .reference(reference1) + .endModule() + .start(); + + // 创建一个启动器(自动创建新 ApplicationModel) + DubboBootstrap bootstrap2 = DubboBootstrap.newInstance(); + // 指定应用名 + bootstrap2.application(new ApplicationConfig("dubbo-demo-app-2")) + .registry(new RegistryConfig("nacos://localhost:8848")) + // 创建一个模块 + .newModule() + // 在模块内订阅服务 + .reference(reference2) + .endModule() + .start(); + + // stub1 与 stub2 是两个独立的订阅,互相隔离 + + // 订阅的 stub + DemoService stub1 = reference1.get(); + System.out.println(stub1.sayHello("Hello World!")); + + // 订阅的 stub + DemoService stub2 = reference2.get(); + System.out.println(stub2.sayHello("Hello World!")); + + bootstrap1.stop(); + bootstrap2.stop(); +``` + +这个例子对外发布了一个 DemoService 的服务,由 dubbo-demo-app-1 这个应用提供。同时我们创建了两个订阅,分别是在 dubbo-demo-app-1 应用和 dubbo-demo-app-2 应用中,然后我们去对两个订阅进行调用,得到预期的结果。 + +这里需要注意的是虽然两个订阅的服务信息是完全一致的,在多实例化改造后,这两个订阅对于消费端来说是完全隔离的,也就是在最新版本的 Dubbo 中是支持三元组一样的情况下通过变更参数来创建多个订阅的行为的了。 + + + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/workflow.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/workflow.md new file mode 100644 index 000000000000..73725af963b1 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/workflow.md @@ -0,0 +1,25 @@ +--- +description: "Dubbo 多实例启动流程与模块依赖关系。" +linkTitle: 启动流程与模块依赖关系 +title: 多实例启动流程与模块依赖关系 +type: docs +weight: 3 +--- + +1、应用启动流程 +初始化应用配置,启动内部模块,启动其它模块。 +应用启动方式包括:DubboBootstrap.start(), ApplicationModel.getDeployer().start() +![Dubbo start process.svg](https://cdn.nlark.com/yuque/0/2021/svg/2391732/1634895625292-99fdac6f-3371-4147-9ad5-9428296cb083.svg#clientId=u82d0d5c2-bff3-4&from=drop&id=u8db161d3&originHeight=2594&originWidth=1050&originalType=binary&ratio=1&size=64242&status=done&style=none&taskId=u8976fa81-5bc5-469a-ab4a-b4cda12cd6d) +2、模块启动流程 +上图中从ModuleDeployer.start() 开始,自动初始化应用配置,启动内部模块,然后启动当前模块。 +模块启动方式包括: +1) Spring context 加载dubbo xml配置或者注解 +2) 手工启动模块:ModuleModel.getDeployer().start() + +3、服务接口API方式启动 +ServiceConfig.export() 或者 ReferenceConfig.get() 先自动启动module,然后执行export/refer服务接口 + + + + + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol.md new file mode 100644 index 000000000000..06f9050534e9 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol.md @@ -0,0 +1,132 @@ +--- +description: "Dubbo 单端口多协议实现原理&源码解析。" +linkTitle: 单端口多协议 +title: 单端口多协议实现原理解析 +type: docs +weight: 1 +--- + +通过对protocol进行配置,dubbo3可以支持端口的协议复用。 +比如使用Triple协议启动端口复用后,可以在相同的端口上为服务增加 +Dubbo协议支持,以及Qos协议支持。这些协议的识别都是由一个统一的端口复用 +服务器进行处理的,可以用于服务的协议迁移,并且可以节约端口以及相关的资源,减少运维的复杂性。 + +![pu-server-image1](/imgs/blog/pu-server/pu-server-flow.png) + +- 在服务的创建阶段,通过从Config层获取到服务导出的协议配置从而创建不同的Protocol对象进行导出。在导出的过程 +中,如果不是第一次创建端口复用的Server,那么Exchanger会将Protcol层传递的数据保存到Server,用于后续处理该协议类型的消息。 + +- 当客户端的消息传递过来后,首先会通过Server传递给ProtocolDetector,如果完成了识别,那么就会标记该客户端为对应的协议。并通过WireProtocol配置对应的处理逻辑,最后交给ChannelOperator完成底层的IO框架和对应的Dubbo框架的处理逻辑的绑定。 + +- 以上的协议识别完成之后,Channel已经确定了如何处理远程的客户端消息,通过对应的ServerPipeline进行处理即可(在处理的过程中也会根据配置信息决定消息的处理线程)。 + +## 使用场景 +- 最常用的是用于服务发现。这允许应用程序通过网络发现服务,然后使用同一端口与它们通信,有助于降低网络通信的复杂性,并使其更易于管理。 + +- 可以用于负载平衡。这允许应用程序在多个远程服务或服务集群之间平衡负载,有助于提高服务的可扩展性、可靠性和可用性。 + +- 可以用于服务监控。这允许应用程序监视远程服务的运行状况,并在服务出现故障或变得不可用时发出警报,有助于确保服务的可用性并减少停机时间。 + +> 参考用例 +[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-port-unification](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-port-unification) + +## 使用方式 +在同一主机上部署多个服务或需要通过负载均衡器访问多个服务。 + +> 关于Dubbo支持的配置方式 [配置说明](/zh-cn/overview/mannual/java-sdk/reference-manual/config/) + +### 服务多协议导出 + +ext-protocol参数支持配置多个不同的协议,协议之间通过","进行分隔。 + +#### xml 配置 + +```xml + + + + + + +``` + +#### API 配置 + +```java +ProtocolConfig config = new ProtocolConfig(CommonConstants.TRIPLE, -1); + +config.setExtProtocol(CommonConstants.DUBBO+","); +``` + +#### yaml 配置 + +``` yaml +dubbo: + application: + name: dubbo-springboot-demo-provider + protocol: + name: tri + port: -1 + ext-protocol: dubbo, +``` + +#### properties 配置 +```properties +dubbo.protocol.name=tri +dubbo.protocol.ext-protocol=dubbo, +dubbo.protocol.port=20880 +``` + +### Qos接入 + +#### Qos模块导入 + +```xml + + org.apache.dubbo + dubbo-qos + +``` + +完成Qos模块的导入之后,相关的配置项可参考[Qos操作手册](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/overview/)进行配置。 + +默认情况下,基于端口复用的Qos服务在模块导入后是启动的。 + + + +### Qos使用 + +将Qos协议接入到端口复用的场景下,需要在建立连接之后,客户端先向服务端发送消息,对比将Qos协议通过单个端口提供服务,端口复用版的Qos协议在处理telnet连接的情况下需要用户执行一些操作,完成协议识别(二选一)。 + +1. 直接调用命令 + + 直接调用telnet支持的命令也可以完成识别,在用户不熟悉的情况下可以调用help指令完成识别 + + ![pu-server-image2](/imgs/blog/pu-server/qos-telnet-directcall.png) + +2. 发送telnet命令识别 + + 通过telnet命令建立连接之后,执行以下几个步骤: + + 1. 使用 crtl + "]" 进入到telnet交互界面(telnet默认的escape character) + 2. 调用 "send ayt" 向服务端发送特殊识别字段(为telnet协议的一个特殊字段) + 3. 回车完成消息发送并进入到dubbo的交互界面 + + ![pu-server-imgs3](/imgs/blog/pu-server/qos-telnet-sendayt.png) + + +### 服务引用 + +以[dubbo-samples-port-unification](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-port-unification)中的例子作为基础, 引用不同协议的服务和非端口复用情况下的配置是一致的,下面通过Consumer端的InvokerListener输出调用过程中的URL信息。 + +```java +ReferenceConfig reference = new ReferenceConfig<>(); +reference.setInterface(GreetingService.class); +reference.setListener("consumer"); +reference.setProtocol(this.protocol); +// reference.setProtocol(CommonConstants.DUBBO); +// reference.setProtocol(CommonConstants.TRIPLE); +``` + +![pu-server-imgs4](/imgs/blog/pu-server/reference-service.png) + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/overall-architecture.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/architecture/overall-architecture.md.bak new file mode 100644 index 000000000000..04457022e848 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/overall-architecture.md.bak @@ -0,0 +1,75 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture/ + - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture/ +description: 本文将介绍 Dubbo 总体架构。 +linkTitle: 总体架构 +title: 总体架构 +type: docs +weight: 1 +--- + +![dubbo-architucture](/imgs/user/dubbo-architecture.jpg) + +##### 节点角色说明 + +| 节点 | 角色说明 | +| ------------- | ------------- | +| `Provider` | 暴露服务的服务提供方 | +| `Consumer` | 调用远程服务的服务消费方 | +| `Registry` | 服务注册与发现的注册中心 | +| `Monitor` | 统计服务的调用次数和调用时间的监控中心 | +| `Container` | 服务运行容器 | + +##### 调用关系说明 + +0. 服务容器负责启动,加载,运行服务提供者。 +1. 服务提供者在启动时,向注册中心注册自己提供的服务。 +2. 服务消费者在启动时,向注册中心订阅自己所需的服务。 +3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。 +4. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。 +5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。 + +Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。 + +## 连通性 + +* 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小 +* 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示 +* 服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销 +* 服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销 +* 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外 +* 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者 +* 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表 +* 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者 + +## 健壮性 + +* 监控中心宕掉不影响使用,只是丢失部分采样数据 +* 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务 +* 注册中心对等集群,任意一台宕掉后,将自动切换到另一台 +* 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯 +* 服务提供者无状态,任意一台宕掉后,不影响使用 +* 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复 + +## 伸缩性 + +* 注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心 +* 服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者 + +## 升级性 + +当服务集群规模进一步扩大,带动IT治理结构进一步升级,需要实现动态部署,进行流动计算,现有分布式服务架构不会带来阻力。下图是未来可能的一种架构: + +![dubbo-architucture-futures](/imgs/user/dubbo-architecture-future.jpg) + +##### 节点角色说明 + +| 节点 | 角色说明 | +| ------------- | ------------- | +| `Deployer ` | 自动部署服务的本地代理 | +| `Repository` | 仓库用于存储服务应用发布包 | +| `Scheduler` | 调度中心基于访问压力自动增减服务提供者 | +| `Admin` | 统一管理控制台 | +| `Registry` | 服务注册与发现的注册中心 | +| `Monitor` | 统计服务的调用次数和调用时间的监控中心 | \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-discovery.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-discovery.md.bak new file mode 100644 index 000000000000..1e5b20b7a831 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-discovery.md.bak @@ -0,0 +1,68 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/concepts-and-architecture/service-discovery/ + - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/service-discovery/ +description: 本文将介绍 Dubbo 服务发现。 +linkTitle: 服务发现 +title: 服务发现 +type: docs +weight: 3 +--- + + + + + +服务发现,即消费端自动发现服务地址列表的能力,是微服务框架需要具备的关键能力,借助于自动化的服务发现,微服务之间可以在无需感知对端部署位置与 IP 地址的情况下实现通信。 + +### 实现方式 +实现服务发现的方式有很多种,Dubbo 提供的是一种 Client-Based 的服务发现机制,通常还需要部署额外的第三方注册中心组件来协调服务发现过程,如常用的 Nacos、Consul、Zookeeper 等,Dubbo 自身也提供了对多种注册中心组件的对接,用户可以灵活选择。 + +### 工作原理 +Dubbo 基于消费端的自动服务发现能力,其基本工作原理如下图: + +![//imgs/architecture.png](/imgs/architecture.png) + +服务发现的一个核心组件是注册中心,Provider 注册地址到注册中心,Consumer 从注册中心读取和订阅 Provider 地址列表。 +因此,要启用服务发现,需要为 Dubbo 增加注册中心配置: + +以 dubbo-spring-boot-starter 使用方式为例,增加 registry 配置 + +```properties +# application.properties +dubbo + registry + address: zookeeper://127.0.0.1:2181 +``` + +### 应用级服务发现简介 +概括来说,Dubbo3 引入的应用级服务发现主要有以下优势 +* 适配云原生微服务变革。云原生时代的基础设施能力不断向上释放,像 Kubernetes 等平台都集成了微服务概念抽象,Dubbo3 的应用级服务发现是适配各种微服务体系的通用模型。 +* 提升性能与可伸缩性。支持超大规模集群的服务治理一直以来都是 Dubbo 的优势,通过引入应用级服务发现模型,从本质上解决了注册中心地址数据的存储与推送压力,相应的 Consumer 侧的地址计算压力也成数量级下降;集群规模也开始变得可预测、可评估(与 RPC 接口数量无关,只与实例部署规模相关)。 + +下图是 Dubbo2 的服务发现模型:Provider 注册服务地址,Consumer 经过注册中心协调并发现服务地址,进而对地址发起通信,这是被绝大多数微服务框架的经典服务发现流程。而 Dubbo2 的特殊之处在于,它把 “RPC 接口”的信息也融合在了地址发现过程中,而这部分信息往往是和具体的业务定义密切相关的。 + +![//imgs/v3/concepts/servicediscovery_old.png](/imgs/v3/concepts/servicediscovery_old.png) + +而在接入云原生基础设施后,基础设施融入了微服务概念的抽象,容器化微服务被编排、调度的过程即完成了在基础设施层面的注册。如下图所示,基础设施既承担了注册中心的职责,又完成了服务注册的动作,而 “RPC 接口”这部分信息,由于与具体的业务相关,不可能也不适合被基础设施托管。 + +![//imgs/v3/concepts/servicediscovery_k8s.png](/imgs/v3/concepts/servicediscovery_k8s.png) + +在这样的场景下,对 Dubbo3 的服务注册发现机制提出了两个要求: +Dubbo3 需要在原有服务发现流程中抽象出通用的、与业务逻辑无关的地址映射模型,并确保这部分模型足够合理,以支持将地址的注册行为和存储委托给下层基础设施 +Dubbo3 特有的业务接口同步机制,是 Dubbo3 需要保留的优势,需要在 Dubbo3 中定义的新地址模型之上,通过框架内的自有机制予以解决。 + +这样设计的全新的服务发现模型,在架构兼容性、可伸缩性上都给 Dubbo3 带来了更大的优势。 + +![//imgs/v3/concepts/servicediscovery_mem.png](/imgs/v3/concepts/servicediscovery_mem.png) + +在架构兼容性上,如上文所述,Dubbo3 复用下层基础设施的服务抽象能力成为了可能;另一方面,如 Spring Cloud 等业界其它微服务解决方案也沿用这种模型, +在打通了地址发现之后,使得用户探索用 Dubbo 连接异构的微服务体系成为了一种可能。 + +Dubbo3 服务发现模型更适合构建可伸缩的服务体系,这点要如何理解? +这里先举个简单的例子,来直观的对比 Dubbo2 与 Dubbo3 在地址发现流程上的数据流量变化:假设一个微服务应用定义了 100 个接口(Dubbo 中的服务), +则需要往注册中心中注册 100 个服务,如果这个应用被部署在了 100 台机器上,那这 100 个服务总共会产生 100 * 100 = 10000 个虚拟节点;而同样的应用, +对于 Dubbo3 来说,新的注册发现模型只需要 1 个服务(只和应用有关和接口无关), 只注册和机器实例数相等的 1 * 100 = 100 个虚拟节点到注册中心。 +在这个简单的示例中,Dubbo 所注册的地址数量下降到了原来的 1 / 100,对于注册中心、订阅方的存储压力都是一个极大的释放。更重要的是, +地址发现容量彻底与业务 RPC 定义解耦开来,整个集群的容量评估对运维来说将变得更加透明:部署多少台机器就会有多大负载,不会像 Dubbo2 一样, +因为业务 RPC 重构就会影响到整个集群服务发现的稳定性。 \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-invocation.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-invocation.md new file mode 100644 index 000000000000..6b5a3f3317cf --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-invocation.md @@ -0,0 +1,159 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/concepts-and-architecture/service-invocation/ + - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/service-invocation/ + - /zh-cn/overview/mannual/java-sdk/concepts-and-architecture/service-invocation/ +description: 本文将介绍如何在 Dubbo Java 实现中自定义调用链路上核心的扩展点以满足您的需求。 +linkTitle: 服务调用 +title: 服务调用扩展点 +type: docs +weight: 4 +--- + + +![dubbo-architucture](/imgs/v3/concepts/invoke-arch.jpg) + +如上图所示,从服务调用的角度来看,Dubbo 在链路中提供了丰富的扩展点,覆盖了负载均衡方式、选址前后的拦截器、服务端处理拦截器等。 +简单来说 Dubbo 发起远程调用的时候,主要工作流程可以分为消费端和服务端两个部分。 + +消费端的工作流程如下: +- 通过 Stub 接收来自用户的请求,并且封装在 `Invocation` 对象中 +- 将 `Invocation` 对象传递给 `ClusterFilter`(**扩展点**)做选址前的请求预处理,如请求参数的转换、请求日志记录、限流等操作都是在此阶段进行的 +- 将 `Invocation` 对象传递给 `Cluster`(**扩展点**)进行集群调用逻辑的决策,如快速失败模式、安全失败模式等决策都是在此阶段进行的 + - `Cluster` 调用 `Directory` 获取所有可用的服务端地址信息 + - `Directory` 调用 `StateRouter`(**扩展点**,推荐使用) 和 `Router`(**扩展点**) 对服务端的地址信息进行路由筛选,此阶段主要是从全量的地址信息中筛选出本次调用允许调用到的目标,如基于打标的流量路由就是在此阶段进行的 + - `Cluster` 获得从 `Directory` 提供的可用服务端信息后,会调用 `LoadBalance` (**扩展点**)从多个地址中选择出一个本次调用的目标,如随机调用、轮询调用、一致性哈希等策略都是在此阶段进行的 + - `Cluster` 获得目标的 `Invoker` 以后将 `Invocation` 传递给对应的 `Invoker`,并等待返回结果,如果出现报错则执行对应的决策(如快速失败、安全失败等) +- 经过上面的处理,得到了带有目标地址信息的 `Invoker`,会再调用 `Filter`(**扩展点**)进行选址后的请求处理(由于在消费端侧创建的 `Filter` 数量级和服务端地址量级一致,如无特殊需要建议使用 `ClusterFilter` 进行扩展拦截,以提高性能) +- 最后 `Invocation` 会被通过网络发送给服务端 + +服务端的工作流程如下: +- 服务端通信层收到请求以后,会将请求传递给协议层构建出 `Invocation` +- 将 `Invocation` 对象传递给 `Filter` (**扩展点**)做服务端请求的预处理,如服务端鉴权、日志记录、限流等操作都是在此阶段进行的 +- 将 `Invocation` 对象传递给动态代理做真实的服务端调用 + +## Filter(拦截器) + +拦截器可以实现服务提供方和服务消费方调用过程拦截,Dubbo 本身的大多功能均基于此扩展点实现,每次远程方法执行,该拦截都会被执行,请注意对性能的影响。 +其中在消费端侧,`ClusterFilter` 用于选址前的拦截和 `Filter` 用于选址后的拦截。如无特殊需要使用 `ClusterFilter` 进行扩展拦截,以提高性能。 + +![filter-architucture](/imgs/v3/concepts/filter-arch.jpg) + +在 Dubbo 3 中,`Filter` 和 `ClusterFilter` 的接口签名被统一抽象到 `BaseFilter` 中,开发者可以分别实现 `Filter` 或 `ClusterFilter` 的接口来实现自己的拦截器。 +如果需要拦截返回状态,可以直接实现 `BaseFilter.Listener` 的接口,Dubbo 将自动识别,并进行调用。 + +```java +package org.apache.dubbo.rpc; + +public interface BaseFilter { + + Result invoke(Invoker invoker, Invocation invocation) throws RpcException; + + interface Listener { + + void onResponse(Result appResponse, Invoker invoker, Invocation invocation); + + void onError(Throwable t, Invoker invoker, Invocation invocation); + } +} +``` + +```java +package org.apache.dubbo.rpc; + +@SPI(scope = ExtensionScope.MODULE) +public interface Filter extends BaseFilter { +} +``` + +```java +package org.apache.dubbo.rpc.cluster.filter; + +@SPI(scope = ExtensionScope.MODULE) +public interface ClusterFilter extends BaseFilter { +} +``` + +特别的,如果需要在 Consumer 侧生效 `Filter` 或 `ClusterFilter`,需要增加 `@Activate` 注解,并且需要指定 `group` 的值为 `consumer`。 + +```java +@Activate(group = CommonConstants.CONSUMER) +``` + +如果需要在 Provider 侧生效 `Filter` 或 `ClusterFilter`,需要增加 `@Activate` 注解,并且需要指定 `group` 的值为 `provider`。 + +```java +@Activate(group = CommonConstants.PROVIDER) +``` + +> [调用拦截扩展方式](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/filter/) + +## Router(路由选址) + +路由选址提供从多个服务提供方中选择**一批**满足条件的目标提供方进行调用的能力。 +Dubbo 的路由主要需要实现 3 个接口,分别是负责每次调用筛选的 `route` 方法,负责地址推送后缓存的 `notify` 方法,以及销毁路由的 `stop` 方法。 +在 Dubbo 3 中推荐实现 `StateRouter` 接口,能够提供高性能的路由选址方式。 + +```java +package org.apache.dubbo.rpc.cluster.router.state; + +public interface StateRouter { + + BitList> route(BitList> invokers, URL url, Invocation invocation, + boolean needToPrintMessage, Holder> nodeHolder) throws RpcException; + + void notify(BitList> invokers); + + void stop(); +} +``` + +```java +package org.apache.dubbo.rpc.cluster; + +public interface Router extends Comparable { + + @Deprecated + List> route(List> invokers, URL url, Invocation invocation) throws RpcException; + + RouterResult> route(List> invokers, URL url, Invocation invocation, + boolean needToPrintMessage) throws RpcException; + + void notify(List> invokers); + + void stop(); +} +``` + +> [路由选址扩展方式](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/router/) + +## Cluster(集群规则) + +集群规则提供在有多个服务提供方时进行结果聚合、容错等能力。 + +```java +package org.apache.dubbo.rpc.cluster.support; + +public abstract class AbstractClusterInvoker implements ClusterInvoker { + + protected abstract Result doInvoke(Invocation invocation, List> invokers, + LoadBalance loadbalance) throws RpcException; +} +``` + + +> [集群规则扩展方式](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/cluster/) + +## LoadBalance(负载均衡) + +负载均衡提供从多个服务提供方中选择**一个**目标提供方进行调用的能力。 + +```java +package org.apache.dubbo.rpc.cluster; + +public interface LoadBalance { + + Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException; +} +``` +> [调用拦截扩展方式](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/filter/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/_index.md new file mode 100644 index 000000000000..2fa6d5b61c8e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/_index.md @@ -0,0 +1,31 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config-center/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config-center/ + - /zh-cn/overview/what/ecosystem/config-center/ +description: Dubbo 配置中心的基本使用和工作原理 +linkTitle: 配置中心 +title: 配置中心 +type: docs +weight: 6 +--- + + + + + + +配置中心 (config-center) 在 Dubbo 中可承担两类职责: + +1. [外部化配置](../config/principle/#33-外部化配置):启动配置的集中式存储 (简单理解为 dubbo.properties 的外部化存储)。 +2. 流量治理规则存储 + +请参考具体扩展实现了解如何启用配置中心。 + +值得注意的是 Dubbo 动态配置中心定义了两个不同层次的隔离选项,分别是 namespace 和 group。 +* namespace - 配置命名空间,默认值 `dubbo`。命名空间通常用于多租户隔离,即对不同用户、不同环境或完全不关联的一系列配置进行逻辑隔离,区别于物理隔离的点是不同的命名空间使用的还是同一物理集群。 +* group - 配置分组,默认值 `dubbo`。`group` 通常用于归类一组相同类型/目的的配置项,是对 `namespace` 下配置项的进一步隔离。 + +参考 [配置说明 - 配置项手册](../config/properties/#config-center) 了解 namespace 和 group 之外 config-center 开放的更多配置项。 + +> 为了兼容 2.6.x 版本配置,在使用 Zookeeper 作为注册中心,且没有显式配置配置中心的情况下,Dubbo 框架会默认将此 Zookeeper 用作配置中心,但将只作服务治理用途。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/apollo.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/apollo.md new file mode 100644 index 000000000000..c715537c2b80 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/apollo.md @@ -0,0 +1,119 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config-center/apollo/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config-center/apollo/ + - /zh-cn/overview/what/ecosystem/config-center/apollo/ +description: Apollo 配置中心的基本使用和工作原理。 +linkTitle: Apollo +title: Apollo +type: docs +weight: 4 +--- + +## 1 前置条件 +* 了解 [Dubbo 基本开发步骤](../../../quick-start/spring-boot/) +* 安装并启动 [Apollo](https://www.apolloconfig.com/#/zh/README) + +## 2 使用说明 +在此查看[完整示例代码](https://github.com/apache/dubbo-samples/tree/master/3-extensions/configcenter/dubbo-samples-configcenter-apollo) + +### 2.1 增加 Maven 依赖 + +```xml + + org.apache.dubbo + dubbo + 3.0.9 + + + com.ctrip.framework.apollo + apollo-openapi + 2.0.0 + + + com.ctrip.framework.apollo + apollo-client + 2.0.0 + +``` + +### 2.2 启用 Apollo 配置中心 +```xml + +``` + +或者 + +```yaml +dubbo + config-center + address: apollo://localhost:8080 +``` + +或者 + +```properties +dubbo.config-center.address=apollo://localhost:8080 +``` + +或者 + +```java +ConfigCenterConfig configCenter = new ConfigCenterConfig(); +configCenter.setAddress("apollo://localhost:8080"); +``` + +## 3 高级配置 +Apollo中的一个核心概念是命名空间 - namespace,和上面 Zookeeper、Nacos 的 namespace 概念不同,因此使用方式上也比较特殊些,建议充分了解 Apollo 自身的用法后再阅读以下文档内容。 + +但总的来说,对 Apollo 的适配而言: +* group 特用于外部化配置的隔离,参见 3.1 +* namespace 特用于流量治理规则隔离,参见 3.2 + +### 3.1 外部化配置 + +```xml + +``` + +config-center 的 `group` 决定了 Apollo 读取外部化配置 `dubbo.properties` 文件的位置: +1. 如果 group 为空,则默认从 `dubbo` namespace 读取配置,用户须将外部化配置写在 `dubbo` namespace 下。 +2. 如果 group 不为空 + 2.1 group 值为应用名,则从应用当前的 namespace 读取配置,用户须将外部化配置写在 Apollo 自动指定的应用默认 namespace 下。 + 2.2 group 值为任意值,则从对应的 namespace 读取配置,用户须将外部化配置写在该 namespace 下。 + +如以下示例是用的默认 group='dubbo' 的全局外部化配置,即该配置可被所有应用读取到。 +![apollo-configcenter-dubbo.png](/imgs/user/apollo-configcenter-dubbo.png) + +如果配置 group='应用名' 则是应用特有配置,只有该应用可以读取到。 + +> 关于外部化文件配置托管,相当于是把 `dubbo.properties` 配置文件的内容存储在了 Apollo 中。每个应用都可以通过关联共享的 `dubbo` namespace 继承公共配置, 进而可以单独覆盖个别配置项。 + +### 3.2 流量治理规则 +**流量治理规则一定都是全局共享的,因此每个应用内的 namespace 配置都应该保持一致。** + +```xml + +``` + +config-center 的 `namespace` 决定了 Apollo 存取 `流量治理规则` 的位置: +1. 如果 namespace 为空,则默认从 `dubbo` namespace 存取配置,须治理规则写在 `dubbo` namespace 下。 +2. 如果 namespace 不为空,则从对应的 namespace 值读取规则,须治理规则写在该 namespace 下。 + +如以下示例是通过 `namespace='governance'` 将流量治理规则放在了 `governance` namespace 下。 +![apollo-configcenter-governance-dubbo.png](/imgs/user/apollo-configcenter-governance-dubbo.png) + +### 3.3 更多 Apollo 特有配置 +当前 Dubbo 适配了 env、apollo.meta、apollo.cluster、apollo.id 等特有配置项,可通过 config-center 的扩展参数进行配置。 + +如 +```properties +dubbo.config-center.address=apollo://localhost:8080 +``` + +或者 + +```properties +dubbo.config-center.prameters.apollo.meta=xxx +dubbo.config-center.prameters.env=xxx +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/introduction.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/introduction.md new file mode 100644 index 000000000000..cd3edada6a13 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/introduction.md @@ -0,0 +1,29 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config-center/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config-center/ + - /zh-cn/overview/what/ecosystem/config-center/ +description: Dubbo 配置中心的基本使用和工作原理 +linkTitle: 配置中心概述 +title: 配置中心 +type: docs +weight: 1 +--- + + +配置中心 (config-center) 在 Dubbo 中可承担两类职责: + +1. [外部化配置](/zh-cn/overview/mannual/java-sdk/reference-manual/config/principle/#33-外部化配置):启动配置的集中式存储 (简单理解为 dubbo.properties 的外部化存储)。 +2. 流量治理规则存储 + +请参考具体扩展实现了解如何启用配置中心。 + +值得注意的是 Dubbo 动态配置中心定义了两个不同层次的隔离选项,分别是 namespace 和 group。 +* namespace - 配置命名空间,默认值 `dubbo`。命名空间通常用于多租户隔离,即对不同用户、不同环境或完全不关联的一系列配置进行逻辑隔离,区别于物理隔离的点是不同的命名空间使用的还是同一物理集群。 +* group - 配置分组,默认值 `dubbo`。`group` 通常用于归类一组相同类型/目的的配置项,是对 `namespace` 下配置项的进一步隔离。 + +参考 [配置说明 - 配置项手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#dubboconfig-center) 了解 namespace 和 group 之外 config-center 开放的更多配置项。 + +{{% alert title="使用注册中心作为默认配置中心" color="info" %}} +在使用 Zookeeper、Nacos 作为注册中心且没有显式配置配置中心的情况下,Dubbo 框架会默认将此 Zookeeper、Nacos 用作配置中心,用作服务治理用途。 +{{% /alert %}} diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/nacos.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/nacos.md new file mode 100644 index 000000000000..3bf51acfc078 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/nacos.md @@ -0,0 +1,116 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config-center/nacos/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config-center/nacos/ + - /zh-cn/overview/what/ecosystem/config-center/nacos/ +description: Nacos 配置中心的基本使用和工作原理。 +linkTitle: Nacos +title: Nacos +type: docs +weight: 3 +--- + +## 1 前置条件 +* 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/starter/) +* 安装并启动 [Nacos](/zh-cn/overview/reference/integrations/nacos/) + +> 当Dubbo使用`3.0.0`及以上版本时,需要使用Nacos `2.0.0`及以上版本。请参考 [nacos 注册中心](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/nacos/#12-nacos-版本) 了解 nacos 版本适配情况。 + +## 2 使用说明 + +### 2.1 增加 Maven 依赖 +如果项目已经启用 Nacos 作为注册中心,则无需增加任何额外配置。 + +如果未启用 Nacos 注册中心,则请参考 [为注册中心增加 Nacos 依赖](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/nacos/#11-增加依赖)。 + +### 2.2 启用 Nacos 配置中心 +```xml + +``` + +或者 + +```yaml +dubbo + config-center + address: nacos://127.0.0.1:8848 +``` + +或者 + +```properties +dubbo.config-center.address=nacos://127.0.0.1:8848 +``` + +或者 + +```java +ConfigCenterConfig configCenter = new ConfigCenterConfig(); +configCenter.setAddress("nacos://127.0.0.1:8848"); +``` + +`address` 格式请参考 [Nacos 注册中心 - 启用配置](../../registry/nacos/#22-配置并启用-nacos) + +## 3 高级配置 +如要开启认证鉴权,请参考 [Nacos 注册中心 - 启用认证鉴权](../../registry/nacos/#31-认证) + +### 3.1 外部化配置 +#### 3.1.1 全局外部化配置 +**1. 应用开启 config-center 配置** +```yaml +dubbo + config-center + address: nacos://127.0.0.1:2181 + config-file: dubbo.properties # optional +``` +`config-file` - 全局外部化配置文件 key 值,默认 `dubbo.properties`。`config-file` 代表将 Dubbo 配置文件存储在远端注册中心时,文件在配置中心对应的 key 值,通常不建议修改此配置项。 + +**2. Nacos Server 增加配置** + +![nacos-configcenter-global-properties.png](/imgs/user/nacos-configcenter-global-properties.png) + +dataId 是 `dubbo.properties`,group 分组与 config-center 保持一致,如未设置则默认填 `dubbo`。 + +#### 3.1.2 应用特有外部化配置 + +**1. 应用开启 config-center 配置** +```yaml +dubbo + config-center + address: nacos://127.0.0.1:2181 + app-config-file: dubbo.properties # optional +``` + +`app-config-file` - 当前应用特有的外部化配置文件 key 值,如 `app-name-dubbo.properties`,仅在需要覆盖全局外部化配置文件 `config-file` 时才配置。 + +**2. Nacos Server 增加配置** + +![nacos-configcenter-application-properties.png](/imgs/user/nacos-configcenter-application-properties.png) + +dataId 是 `dubbo.properties`,group 分组设置为应用名即 `demo-provider`。 + +### 3.2 设置 group 与 namespace +```yaml +dubbo + config-center + address: zookeeper://127.0.0.1:2181 + group: dubbo-cluster1 + namespace: dev1 +``` + +对配置中心而言,`group` 与 `namespace` 应该是全公司(集群)统一的,应该避免不同应用使用不同的值。 + +### 3.3 Nacos 扩展配置 +更多 Nacos sdk/server 支持的参数配置请参见 [Nacos 注册中心 - 更多配置](../../registry/nacos/#35-更多配置) + +## 4 流量治理规则 +对 Nacos 而言,所有流量治理规则和外部化配置都应该是全局可见的,因此相同逻辑集群内的应用都必须使用相同的 namespace 与 group。其中,namespace 的默认值是 `public`,group 默认值是 `dubbo`,应用不得擅自修改 namespace 与 group,除非能保持全局一致。 + +流量治理规则的增删改建议通过 dubbo-admin 完成,更多内容可查看 Dubbo 支持的流量治理能力。 + +![nacos-configcenter-governance.jpg](/imgs/user/nacos-configcenter-governance.png) + +流量治理规则有多种类型,不同类型的规则 dataId 的后缀是不同的: + +- configurators [覆盖规则](/zh-cn/overview/core-features/traffic/configuration-rule/) +- tag-router [标签路由](/zh-cn/overview/core-features/traffic/tag-rule/) 与 condition-router [条件路由](/zh-cn/overview/core-features/traffic/condition-rule/) \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/others.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/others.md new file mode 100644 index 000000000000..29fe7cc6ed6c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/others.md @@ -0,0 +1,54 @@ +--- +description: "更多配置中心扩展实现,包括 etcd、consul 等" +linkTitle: 扩展实现 +title: 更多配置中心扩展实现 +type: docs +weight: 4 +--- + +Dubbo 框架还默认提供了 etcd、consul 等配置中心适配实现。 + +## Etcd + +Etcd 配置中心由社区生态库维护,具体可参见 [](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-configcenter-extensions/dubbo-configcenter-etcd)。 + +增加依赖: + +```xml + + org.apache.dubbo.extensions + dubbo-configcenter-etcd + 3.3.0 + +``` + +调整配置: + +```yaml +dubbo + config-center + address: etcd://127.0.0.1:1111 +``` + + +## Consul + +Consul 配置中心由社区生态库维护,具体可参见 [](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-configcenter-extensions/dubbo-configcenter-consul)。 + +增加依赖: + +```xml + + org.apache.dubbo.extensions + dubbo-configcenter-consul + 3.3.0 + +``` + +调整配置: + +```yaml +dubbo + config-center + address: consul://127.0.0.1:1111 +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/zookeeper.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/zookeeper.md new file mode 100644 index 000000000000..a315d774cd12 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/zookeeper.md @@ -0,0 +1,99 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config-center/zookeeper/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config-center/zookeeper/ + - /zh-cn/overview/what/ecosystem/config-center/zookeeper/ +description: Zookeeper 配置中心的基本使用和工作原理。 +linkTitle: Zookeeper +title: Zookeeper +type: docs +weight: 2 +--- + + +## 1 前置条件 +* 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/starter/) +* 安装并启动 [Zookeeper](/zh-cn/overview/reference/integrations/zookeeper/) + +## 2 使用说明 +在此查看[完整示例代码](https://github.com/apache/dubbo-samples/tree/master/3-extensions/configcenter/dubbo-samples-configcenter-annotation) + +### 2.1 增加 Maven 依赖 +如果项目已经启用 Zookeeper 作为注册中心,则无需增加任何额外配置。 + +如果未使用 Zookeeper 注册中心,则请参考 [为注册中心增加 Zookeeper 相关依赖](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/zookeeper/#11-增加-maven-依赖)。 + +### 2.2 启用 Zookeeper 配置中心 +```xml + +``` + +或者 + +```yaml +dubbo + config-center + address: zookeeper://127.0.0.1:2181 +``` + +或者 + +```properties +dubbo.config-center.address=zookeeper://127.0.0.1:2181 +``` + +或者 + +```java +ConfigCenterConfig configCenter = new ConfigCenterConfig(); +configCenter.setAddress("zookeeper://127.0.0.1:2181"); +``` + +`address` 格式请参考 [zookeeper 注册中心 - 启用配置](../../registry/zookeeper/#13-配置并启用-zookeeper) + +## 3 高级配置 +如要开启认证鉴权,请参考 [zookeeper 注册中心 - 启用认证鉴权](../../registry/zookeeper/#21-认证与鉴权) + +### 3.1 定制外部化配置 key +**1. 启用外部化配置,并指定 key** +```yaml +dubbo + config-center + address: zookeeper://127.0.0.1:2181 + config-file: dubbo.properties +``` + +`config-file` - 外部化配置文件 key 值,默认 `dubbo.properties`。`config-file` 代表将 Dubbo 配置文件存储在远端注册中心时,文件在配置中心对应的 key 值,通常不建议修改此配置项。 + +**2. Zookeeper 配置中心增加配置** +外部化配置的存储结构如下图所示 + +![zk-configcenter.jpg](/imgs/user/zk-configcenter.jpg) + +- namespace,用于不同配置的环境隔离。 +- config,Dubbo约定的固定节点,不可更改,所有配置和流量治理规则都存储在此节点下。 +- dubbo 与 application,分别用来隔离全局配置、应用级别配置:dubbo 是默认 group 值,application 对应应用名 +- dubbo.properties,此节点的node value存储具体配置内容 + +> 这里是为了说明工作原理,建议使用 dubbo-admin 进行配置管理。 + +### 3.2 设置 group 与 namespace +```yaml +dubbo + config-center + address: zookeeper://127.0.0.1:2181 + group: dubbo-cluster1 + namespace: dev1 +``` + +对配置中心而言,`group` 与 `namespace` 应该是全公司(集群)统一的,应该避免不同应用使用不同的值,外部化配置和治理规则也应该存放在对应的 group 与 namespace。 + +## 4 流量治理规则 +所有流量治理规则默认都存储在 `/dubbo/config` 节点下,具体节点结构图如下。流量治理规则的增删改建议通过 dubbo-control-plane(dubbo-admin) 完成,更多内容可查看 Dubbo 支持的具体流量治理能力 + +![zk-configcenter-governance](/imgs/user/zk-configcenter-governance.jpg) + +- namespace,用于不同配置的环境隔离。 +- config,Dubbo 约定的固定节点,不可更改,所有配置和流量治理规则都存储在此节点下。 +- dubbo,所有服务治理规则都是全局性的,dubbo 为默认节点 +- configurators/tag-router/condition-router/migration,不同的服务治理规则类型,node value 存储具体规则内容 \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/config/_index.md new file mode 100644 index 000000000000..dd5549e51b71 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/config/overview/ +description: Dubbo 配置指南 +linkTitle: 配置说明 +title: 配置手册 +type: docs +weight: 1 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/api/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/config/api/_index.md new file mode 100644 index 000000000000..d6ab16f56a08 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/api/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config/ +description: Dubbo 配置指南 +linkTitle: 原生API +title: 配置手册 +type: docs +weight: 1 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/api/api.md b/content/en/overview/mannual/java-sdk/reference-manual/config/api/api.md new file mode 100644 index 000000000000..1f14a143ebc5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/api/api.md @@ -0,0 +1,389 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config/api/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config/api/ +description: 以 API 的方式来配置你的 Dubbo 应用 +linkTitle: API 配置 +title: API 配置 +type: docs +weight: 2 +--- + +作为一款 RPC 框架,Dubbo 定义了一套完善的 API 接口,我们可以基于原生 API 开发 Dubbo 应用,关于如何使用原生API开发轻量RPC、微服务应用等的具体示例可查看 [使用教程 - API开发模式](/zh-cn/overview/mannual/java-sdk/tasks/develop/api/) 中的示例。它的适用场景包括以下两类: +* **轻量 RPC Server & Client**,通常用于一些应用内、基础组件、中间件等内的简单远程调用场景 +* **微服务应用**,不依赖 Spring、Spring Boot 的情况下,直接用 API 开发微服务;同时,直接使用 API 对于一些网关或测试平台集成场景也可能比较有用。 + +目前的入口 API 主要有 `Bootstrap`、`ServiceConfig`、`ReferenceConfig` 等,分别用于不同场景下的 Dubbo 应用开发。 + +## Bootstrap API + +DubboBootstrap 实例代表一个 Dubbo 应用,是整个 Dubbo 应用的启动入口。在 DubboBootstrap 基础上,我们可以设置 protocol、service、registry、metrics 等来注册服务、连接注册中心等,这和我们在 Spring Boot 中调整 application.yml 或者 application.properties 文件是对等的作用。 + +官方推荐使用 DubboBootstrap.start() 作为应用的集中启动入口,但为了方便在进程启动后,在运行态单独发布一些服务,Dubbo 也允许直接调用 ServiceConfig.export() 或 ReferenceConfig.refer() 方法发布服务,这时 Service/Reference 会注册到默认的 DubboBootstrap 实例中,效果同调用 DubboBootstrap.service(...).start() 类似。 + +```java +import org.apache.dubbo.config.bootstrap.DubboBootstrap; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.ProviderConfig; +import org.apache.dubbo.config.ServiceConfig; +import com.xxx.DemoService; +import com.xxx.DemoServiceImpl; + +public class DemoProvider { + public static void main(String[] args) { + + ConfigCenterConfig configCenter = new ConfigCenterConfig(); + configCenter.setAddress("zookeeper://127.0.0.1:2181"); + + // 服务提供者协议配置 + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName("dubbo"); + protocol.setPort(12345); + protocol.setThreads(200); + + // 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口 + // 服务提供者暴露服务配置 + ServiceConfig demoServiceConfig = new ServiceConfig<>(); + demoServiceConfig.setInterface(DemoService.class); + demoServiceConfig.setRef(new DemoServiceImpl()); + demoServiceConfig.setVersion("1.0.0"); + + // 第二个服务配置 + ServiceConfig fooServiceConfig = new ServiceConfig<>(); + fooServiceConfig.setInterface(FooService.class); + fooServiceConfig.setRef(new FooServiceImpl()); + fooServiceConfig.setVersion("1.0.0"); + + ... + + // 通过DubboBootstrap简化配置组装,控制启动过程 + DubboBootstrap.getInstance() + .application("demo-provider") // 应用配置 + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) // 注册中心配置 + .protocol(protocol) // 全局默认协议配置 + .service(demoServiceConfig) // 添加ServiceConfig + .service(fooServiceConfig) + .start() // 启动Dubbo + .await(); // 挂起等待(防止进程退出) + } +} +``` + +```java +import org.apache.dubbo.config.bootstrap.DubboBootstrap; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.ProviderConfig; +import org.apache.dubbo.config.ServiceConfig; +import com.xxx.DemoService; +import com.xxx.DemoServiceImpl; + +public class DemoConsumer { + public static void main(String[] args) { + + // 引用远程服务 + ReferenceConfig demoServiceReference = new ReferenceConfig(); + demoServiceReference.setInterface(DemoService.class); + demoServiceReference.setVersion("1.0.0"); + + ReferenceConfig fooServiceReference = new ReferenceConfig(); + fooServiceReference.setInterface(FooService.class); + fooServiceReference.setVersion("1.0.0"); + + // 通过DubboBootstrap简化配置组装,控制启动过程 + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application("demo-consumer") // 应用配置 + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) // 注册中心配置 + .reference(demoServiceReference) // 添加ReferenceConfig + .reference(fooServiceReference) + .start(); // 启动Dubbo + + ... + + // 和本地bean一样使用demoService + // 通过Interface获取远程服务接口代理,不需要依赖ReferenceConfig对象 + DemoService demoService = DubboBootstrap.getInstance().getCache().get(DemoService.class); + demoService.sayHello("Dubbo"); + + FooService fooService = fooServiceReference.get(); + fooService.greeting("Dubbo"); + } + +} +``` + +### 基本配置 + +可以在 DubboBootstrap 中设置全局基本配置,包括应用配置、协议配置、注册中心、配置中心、元数据中心、模块、监控、SSL、provider 配置、consumer 配置等。 + +```java +// 注册中心 +RegistryConfig registry = new RegistryConfig(); +registry.setAddress("zookeeper://192.168.10.1:2181"); +... + +// 服务提供者协议配置 +ProtocolConfig protocol = new ProtocolConfig(); +protocol.setName("dubbo"); +protocol.setPort(12345); +protocol.setThreads(200); +... + +// 配置中心 +ConfigCenterConfig configCenter = new ConfigCenterConfig(); +configCenter.setAddress("zookeeper://192.168.10.2:2181"); +... + +// 元数据中心 +MetadataReportConfig metadataReport = new MetadataReportConfig(); +metadataReport.setAddress("zookeeper://192.168.10.3:2181"); +... + +// Metrics +MetricsConfig metrics = new MetricsConfig(); +metrics.setProtocol("dubbo"); +... + +// SSL +SslConfig ssl = new SslConfig(); +ssl.setServerKeyCertChainPath("/path/ssl/server-key-cert-chain"); +ssl.setServerPrivateKeyPath("/path/ssl/server-private-key"); +... + +// Provider配置(ServiceConfig默认配置) +ProviderConfig provider = new ProviderConfig(); +provider.setGroup("demo"); +provider.setVersion("1.0.0"); +... + +// Consumer配置(ReferenceConfig默认配置) +ConsumerConfig consumer = new ConsumerConfig(); +consumer.setGroup("demo"); +consumer.setVersion("1.0.0"); +consumer.setTimeout(2000); +... + +DubboBootstrap.getInstance() + .application("demo-app") + .registry(registry) + .protocol(protocol) + .configCenter(configCenter) + .metadataReport(metadataReport) + .module(new ModuleConfig("module")) + .metrics(metrics) + .ssl(ssl) + .provider(provider) + .consumer(consumer) + ... + .start(); + +``` + +### 方法级设置 + +```java +... + +// 方法级配置 +List methods = new ArrayList(); +MethodConfig method = new MethodConfig(); +method.setName("sayHello"); +method.setTimeout(10000); +method.setRetries(0); +methods.add(method); + +// 引用远程服务 +ReferenceConfig reference = new ReferenceConfig(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏 +... +reference.setMethods(methods); // 设置方法级配置 + +... +``` + +### 点对点直连 + +```java + +... + +// 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏 +ReferenceConfig reference = new ReferenceConfig(); +// 如果点对点直连,可以用reference.setUrl()指定目标地址,设置url后将绕过注册中心, +// 其中,协议对应provider.setProtocol()的值,端口对应provider.setPort()的值, +// 路径对应service.setPath()的值,如果未设置path,缺省path为接口名 +reference.setUrl("dubbo://10.20.130.230:20880/com.xxx.DemoService"); + +... +``` + +## ServiceConfig + +通过 ServiceConfig 可以直接发布服务,将服务接口注册到内存列表和注册中心。这对于一些需要动态发布服务的场景可能非常有用。 + +> 注意:对于普通的应用开发场景,我们更推荐使用 [DubboBootstrap API](#bootstrap-api)。 + +```java +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.ProviderConfig; +import org.apache.dubbo.config.ServiceConfig; +import com.xxx.DemoService; +import com.xxx.DemoServiceImpl; + +public class DemoProvider { + public static void main(String[] args) { + // 服务实现 + DemoService demoService = new DemoServiceImpl(); + + // 当前应用配置 + ApplicationConfig application = new ApplicationConfig(); + application.setName("demo-provider"); + + // 连接注册中心配置 + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("zookeeper://10.20.130.230:2181"); + + // 服务提供者协议配置 + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName("dubbo"); + protocol.setPort(12345); + protocol.setThreads(200); + + // 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口 + // 服务提供者暴露服务配置 + ServiceConfig service = new ServiceConfig(); // 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏 + service.setApplication(application); + service.setRegistry(registry); // 多个注册中心可以用setRegistries() + service.setProtocol(protocol); // 多个协议可以用setProtocols() + service.setInterface(DemoService.class); + service.setRef(demoService); + service.setVersion("1.0.0"); + + // 暴露及注册服务 + service.export(); + + // 挂起等待(防止进程退出) + System.in.read(); + } +} +``` + +## ReferenceConfig + +通过 ReferenceConfig 引用远程服务,从注册中心订阅服务接口。这对于一些需要动态发布服务的场景是可能会非常有用。 + +> 注意:对于普通应用开发,我们推荐使用 [DubboBootstrap API](#bootstrap-api)。 + +```java +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.ReferenceConfig; +import com.xxx.DemoService; + +public class DemoConsumer { + public static void main(String[] args) { + // 当前应用配置 + ApplicationConfig application = new ApplicationConfig(); + application.setName("demo-consumer"); + + // 连接注册中心配置 + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("zookeeper://10.20.130.230:2181"); + + // 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接 + // 引用远程服务 + ReferenceConfig reference = new ReferenceConfig(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏 + reference.setApplication(application); + reference.setRegistry(registry); // 多个注册中心可以用setRegistries() + reference.setInterface(DemoService.class); + reference.setVersion("1.0.0"); + + // 和本地bean一样使用demoService + // 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用 + DemoService demoService = reference.get(); + demoService.sayHello("Dubbo"); + } +} +``` + +## 多实例部署 + +多实例部署的背景起源于 Dubbo 在阿里集团内的大规模应用部署场景,阿里集团遇到的问题主要有: +1. 阿里集团内有众多的中间件框架,这些框架提供了各种各样的类加载方式,不同的业务方期望在同一应用内的配置等信息是相互隔离的。 +2. 一些业务方的定制逻辑需要支持动态热部署模式,具体体现在动态对某个虚拟环境进行销毁,这需要 Dubbo 内的生命周期管理更加完善。 +3. 阿里集团内有多个对 Spring 容器进行定制化开发的框架,需要 Dubbo 能够支持多个 Spring Context 独立管理生命周期的场景。 + +![多实例架构图](/imgs/v3/manual/java/multi-instance/arch.png) + + +整个 Dubbo 多实例的设计我们按照了三层模型来配置,分别是 Framework 框架层、Application 应用层、Module 模块层。 + +基于三层机制,我们可以将 Dubbo 按照一定规则进行隔离: +1. Framework 与 Framework 之间完全隔离,相当于是使用了两个完全不同的 Dubbo 实例 +2. Application 与 Application 之间按照应用名进行隔离,但是相互有些地共享 Protocol、Serialization 层,目标是达到在同一个 dubbo 端口(20880)上可以承载多个应用,而每个应用独立上报地址信息。 +3. Module 与 Module 之间可以由用户自定义进行进行隔离,可以是热部署周期的一个状态、也可以是 Spring Context 的一个 Context。通过 Module,用户可以对 Dubbo 的生命周期粒度进行最小的管理。 + +为了实现 Dubbo 多实例化,Dubbo 框架内做的最多的变化是修改掉大部分的从静态变量中获取的参数的逻辑,最明显的逻辑是 Dubbo 内部用于参数传递的 URL 对象带上了 ScopeModel 状态,这个 ScopeModel 对应的就是上面提到的三层模型的具体数据承载对象。 +关于多示例的更多实现原理、设计细节等,请参考 [源码架构 - 多实例设计与实现](/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/)。 + + +```java +ServiceConfig service = new ServiceConfig<>(); +service.setInterface(DemoService.class); +service.setRef(new DemoServiceImpl()); + +ReferenceConfig reference1 = new ReferenceConfig<>(); +reference1.setInterface(DemoService.class); + +ReferenceConfig reference2 = new ReferenceConfig<>(); +reference2.setInterface(DemoService.class); + +// 创建一个启动器(自动创建新 ApplicationModel) +DubboBootstrap bootstrap1 = DubboBootstrap.newInstance(); +// 指定应用名 +bootstrap1.application(new ApplicationConfig("dubbo-demo-app-1")) + .registry(new RegistryConfig("nacos://localhost:8848")) + // 创建一个模块 + .newModule() + // 在模块内发布服务 + .service(service) + .endModule() + // 创建一个模块 + .newModule() + // 在模块内订阅服务 + .reference(reference1) + .endModule() + .start(); + +// 创建一个启动器(自动创建新 ApplicationModel) +DubboBootstrap bootstrap2 = DubboBootstrap.newInstance(); +// 指定应用名 +bootstrap2.application(new ApplicationConfig("dubbo-demo-app-2")) + .registry(new RegistryConfig("nacos://localhost:8848")) + // 创建一个模块 + .newModule() + // 在模块内订阅服务 + .reference(reference2) + .endModule() + .start(); + +// stub1 与 stub2 是两个独立的订阅,互相隔离 + +// 订阅的 stub +DemoService stub1 = reference1.get(); +System.out.println(stub1.sayHello("Hello World!")); + +// 订阅的 stub +DemoService stub2 = reference2.get(); +System.out.println(stub2.sayHello("Hello World!")); + +bootstrap1.stop(); +bootstrap2.stop(); +``` + +这个例子对外发布了一个 DemoService 的服务,由 dubbo-demo-app-1 这个应用提供。同时我们创建了两个订阅,分别是在 dubbo-demo-app-1 应用和 dubbo-demo-app-2 应用中,然后我们去对两个订阅进行调用,得到预期的结果。 + +这里需要注意的是虽然两个订阅的服务信息是完全一致的,在多实例化改造后,这两个订阅对于消费端来说是完全隔离的,也就是在最新版本的 Dubbo 中是支持三元组一样的情况下通过变更参数来创建多个订阅的行为的了。 + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/maven-plugin.md b/content/en/overview/mannual/java-sdk/reference-manual/config/maven-plugin.md new file mode 100644 index 000000000000..fb8caed662dc --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/maven-plugin.md @@ -0,0 +1,179 @@ +--- +description: Dubbo Maven Plugin 的配置方式 +linkTitle: Maven Plugin 配置 +title: Dubbo Maven Plugin 的配置方式 +type: docs +weight: 3 +--- + +本文主要讲解 Dubbo Maven Plugin 的配置方式。 + +当前 Dubbo Maven Plugin 支持以下功能: +- Dubbo Maven Plugin For Protobuf:生成 Dubbo 服务接口的 Stub 代码 +- Dubbo Maven Plugin For Native Image:基于 AOT 机制,生成 Native Image 必要的 Metadata 信息 + +## Dubbo Maven Plugin For Protobuf + +### 如何使用 Dubbo Maven Plugin 生成 Protobuf Stub 代码 + +#### 1. 编写 .proto 文件 + +greeter.proto + +```protobuf +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.dubbo.demo"; +option java_outer_classname = "DemoServiceProto"; +option objc_class_prefix = "DEMOSRV"; + +package demoservice; + +// The demo service definition. +service DemoService { + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} + +``` + +#### 2. 引入 dubbo-maven-plugin 依赖 + +```xml + + + org.apache.dubbo + dubbo-maven-plugin + ${dubbo.version} + + + + compile + + + + +``` + +#### 3. 生成文件示例 + +```java +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dubbo.demo; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; + +public final class DemoServiceDubbo { + private static final AtomicBoolean registered = new AtomicBoolean(); + + private static Class init() { + Class clazz = null; + try { + clazz = Class.forName(DemoServiceDubbo.class.getName()); + if (registered.compareAndSet(false, true)) { + org.apache.dubbo.common.serialize.protobuf.support.ProtobufUtils.marshaller( + org.apache.dubbo.demo.HelloReply.getDefaultInstance()); + org.apache.dubbo.common.serialize.protobuf.support.ProtobufUtils.marshaller( + org.apache.dubbo.demo.HelloRequest.getDefaultInstance()); + } + } catch (ClassNotFoundException e) { +// ignore + } + return clazz; + } + + private DemoServiceDubbo() { + } + + public static final String SERVICE_NAME = "org.apache.dubbo.demo.DemoService"; + + /** + * Code generated for Dubbo + */ + public interface IDemoService extends org.apache.dubbo.rpc.model.DubboStub { + + static Class clazz = init(); + + org.apache.dubbo.demo.HelloReply sayHello(org.apache.dubbo.demo.HelloRequest request); + + CompletableFuture sayHelloAsync(org.apache.dubbo.demo.HelloRequest request); + + + } + +} + +``` + +### 配置列表 + +Dubbo Maven Plugin For Protobuf 支持以下配置: + +| 配置参数 | 必填 | 解释 | 默认值 | 示例 | +|----------------------|-------|--------------------------------------------------------|------------------------------------------------------------|---------------------------------------------------------------------------| +| dubboVersion | true | Dubbo 版本号,用于查找 dubbo-compiler 组件 | ${dubbo.version} | 3.3.0 | +| dubboGenerateType | true | 生成的文件类型 | tri | tri 或 tri-reactor | +| protocExecutable | false | 可执行的 protoc 路径,如不配置将自动从 Maven 仓库下载 | | protoc | +| protocArtifact | false | protoc 在 Maven 仓库中定位,用于下载 protoc 文件,如不配置将自动识别操作系统类型并下载 | | com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} | +| protoSourceDir | true | proto 文件目录 | ${basedir}/src/main/proto | ./proto | +| outputDir | true | 生成文件的目标目录 | ${project.build.directory}/generated-sources/protobuf/java | ${basedir}/src/main/java | +| protocPluginDirectory | false | 临时存储 protoc 的目录 | ${project.build.directory}/protoc-plugins | ./target/protoc-plugins | + +## Dubbo Maven Plugin For Native Image + +### 示例 + +```xml + + org.apache.dubbo + dubbo-maven-plugin + ${dubbo.version} + + com.example.nativedemo.NativeDemoApplication + + + + process-sources + + dubbo-process-aot + + + + +``` + + +### 配置列表 + +Dubbo Maven Plugin For Native Image 支持以下配置: + +| 配置参数 | 必填 | 解释 | 默认值 | 示例 | +|----------------------|-------|------|------------------------------------------------------------|---------------------------------------------------------------------------| +| mainClass | true | 启动类名 | | com.example.nativedemo.NativeDemoApplication | diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/principle.md b/content/en/overview/mannual/java-sdk/reference-manual/config/principle.md new file mode 100644 index 000000000000..cb1c396c7777 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/principle.md @@ -0,0 +1,578 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config/principle/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config/principle/ +description: Dubbo 配置方式和工作原理的深度解读,包括配置格式、设计思路、来源、加载流程等。 +linkTitle: 配置加载流程 +title: 配置工作原理 +type: docs +weight: 5 +--- + +本文主要讲解 Dubbo 配置相关的 API 与工作原理,学习 Dubbo 的多种配置源、每种配置源的具体配置方式、不同配置源之间的优先级与覆盖关系。 + +## 实现原理 + +为了更好地管理各种配置,Dubbo 抽象了一套结构化的配置组件,各组件总体以用途划分,分别控制不同作用域的行为。 + +![dubbo-config](/imgs/user/dubbo-config.jpg) + + +组件名称 | 描述 | 范围 | 是否必须配置 +------ | ------ | ------ | ------ +application | 指定应用名等应用级别相关信息 | 一个应用内只允许出现一个 | 必选 +service | 声明普通接口或实现类为 Dubbo 服务 | 一个应用内可以有 0 到多个 service | service/reference 至少一种 +reference | 声明普通接口为 Dubbo 服务 | 一个应用内可以有 0 到多个 reference | service/reference 至少一种 +protocol | 要暴露的 RPC 协议及相关配置如端口号等 | 一个应用可配置多个,一个 protocol 可作用于一组 service&reference | 可选,默认 dubbo +registry | 注册中心类型、地址及相关配置 | 一个应用内可配置多个,一个 registry 可作用于一组 service&reference| 必选 +config-center | 配置中心类型、地址及相关配置 | 一个应用内可配置多个,所有服务共享 | 可选 +metadata-report | 元数据中心类型、地址及相关配置 | 一个应用内可配置多个,所有服务共享 | 可选 +consumer | reference 间共享的默认配置 | 一个应用内可配置多个,一个 consumer 可作用于一组 reference | 可选 +provider | service 间共享的默认配置 | 一个应用内可配置多个,一个 provider 可作用于一组 service | 可选 +monitor | 监控系统类型及地址 | 一个应用内只允许配置一个 | 可选 +metrics | 数据采集模块相关配置 | 一个应用内只允许配置一个 | 可选 +ssl | ssl/tls 安全链接相关的证书等配置 | 一个应用内只允许配置一个 | 可选 +method | 指定方法级的配置 | service 和 reference 的子配置 | 可选 +argument | 某个方法的参数配置 | method的子配置 | 可选 + + +> 从实现原理层面,最终 Dubbo 所有的配置项都会被组装到 URL 中,以 URL 为载体在后续的启动、RPC 调用过程中传递,进而控制框架行为。如想了解更多,请参照 Dubbo 源码解析系列文档或 [Blog](/zh-cn/blog/2019/10/17/dubbo-中的-url-统一模型/#rpc调用)。 + +> 各组件支持的具体配置项及含义请参考 [配置项手册](../properties) + + +{{% alert title="注意" color="info" %}} +**背景** + +在每个dubbo应用中某些种类的配置类实例只能出现一次(比如`ApplicationConfig`、`MonitorConfig`、`MetricsConfig`、`SslConfig`、`ModuleConfig`),有些能出现多次(比如`RegistryConfig`、`ProtocolConfig`等)。 + +如果应用程序意外的扫描到了多个唯一配置类实例(比如用户在一个dubbo应用中错误了配置了两个`ApplicationConfig`),应该以哪种策略来处理这种情况呢?是直接抛异常?是保留前者忽略后者?是忽略前者保留后者?还是允许某一种形式的并存(比如后者的属性覆盖到前者上)? + +目前dubbo中的唯一配置类类型和以及某唯一配置类型找到多个实例允许的配置模式/策略如下。 + +**唯一配置类类型** + +`ApplicationConfig`、`MonitorConfig`、`MetricsConfig`、`SslConfig`、`ModuleConfig`。 + +前四个属于应用级别的,最后一个属于模块级别的。 + +**配置模式** + +- `strict`:严格模式。直接抛异常。 +- `override`:覆盖模式。忽略前者保留后者。 +- `ignore`:忽略模式。忽略后者保留前者。 +- `override_all`:属性覆盖模式。不管前者的属性值是否为空,都将后者的属性覆盖/设置到前者上。 +- `override_if_absent`:若不存在则属性覆盖模式。只有前者对应属性值为空,才将后者的属性覆盖/设置到前者上。 + +注:后两种还影响配置实例的属性覆盖。因为dubbo有多种配置方式,即存在多个配置源,配置源也有优先级。比如通过xml方式配置了一个`ServiceConfig`且指定属性`version=1.0.0`,同时我们又在外部配置(配置中心)中配置了`dubbo.service.{interface}.version=2.0.0`,在没有引入`config-mode`配置项之前,按照原有的配置源优先级,最终实例的`version=2.0.0`。但是引入了`config-mode`配置项之后,配置优先级规则也不再那么严格,即如果指定`config-mode为override_all`则为`version=2.0.0`,如果`config-mode为override_if_absent`则为`version=1.0.0`,`config-mode`为其他值则遵循原有配置优先级进行属性设值/覆盖。 + +**配置方式** + +配置的key为`dubbo.config.mode`,配置的值为如上描述的几种,默认的策略值为`strict`。下面展示了配置示例 + +```properties +# JVM -D +-Ddubbo.config.mode=strict + +# 环境变量 +DUBBO_CONFIG_MODE=strict + +# 外部配置(配置中心)、Spring应用的Environment、dubbo.properties +dubbo.config.mode=strict +``` +{{% /alert %}} + +### service 与 reference +`service` 与 `reference` 是 Dubbo 最基础的两个配置项,它们用来将某个指定的接口或实现类注册为 Dubbo 服务,并通过配置项控制服务的行为。 +* `service` 用于服务提供者端,通过 `service` 配置的接口和实现类将被定义为标准的 Dubbo 服务,从而实现对外提供 RPC 请求服务。 +* `reference` 用于服务消费者端,通过 `reference` 配置的接口将被定义为标准的 Dubbo 服务,生成的 proxy 可发起对远端的 RPC 请求。 + +> 一个应用中可以配置任意多个 `service` 与 `reference`。 + +### consumer 与 provider +* 当应用内有多个 `reference` 配置时,`consumer` 指定了这些 `reference` 共享的默认值,如共享的超时时间等以简化繁琐的配置,如某个 `reference` 中单独设置了配置项值则该 `reference` 中的配置优先级更高。 +* 当应用内有多个 `service` 配置时,`provider` 指定了这些 `service` 共享的默认值,如某个 `service` 中单独设置了配置项值则该 `service` 中的配置优先级更高。 + +> consumer 组件还可以对 reference 进行虚拟分组,不通分组下的 reference 可有不同的 consumer 默认值设定;如在 XML 格式配置中, 标签可通过嵌套在 标签之中实现分组。provider 与 service 之间也可以实现相同的效果。 + +## 配置方式 + +### 属性配置 +根据属性Key-value生成配置组件,类似SpringBoot的ConfigurationProperties,具体请参考[属性配置](../properties)。 + +属性配置的另外一个重要的功能特性是[属性覆盖](../principle/#32-属性覆盖),使用外部属性的值覆盖已创建的配置组件属性。 + +如果要将属性配置放到外部的配置中心,请参考[外部化配置](../principle/#33-外部化配置)。 + +除了外围驱动方式上的差异,Dubbo 的配置读取总体上遵循了以下几个原则: + +1. Dubbo 支持了多层级的配置,并按预定优先级自动实现配置间的覆盖,最终所有配置汇总到数据总线URL后驱动后续的服务暴露、引用等流程。 +2. 配置格式以 Properties 为主,在配置内容上遵循约定的 `path-based` 的[命名规范](../principle/#1-配置格式) + +### API 配置 +> 以Java编码的方式组织配置,包括Raw API和Bootstrap API,具体请参考[API配置](../api)。 + +```java +public static void main(String[] args) throws IOException { + ServiceConfig service = new ServiceConfig<>(); + service.setApplication(new ApplicationConfig("first-dubbo-provider")); + service.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234")); + service.setInterface(GreetingsService.class); + service.setRef(new GreetingsServiceImpl()); + service.export(); + System.out.println("first-dubbo-provider is running."); + System.in.read(); +} +``` + +### XML 配置 +> 以XML方式配置各种组件,支持与Spring无缝集成,具体请参考[XML配置](../xml)。 + +```xml + + + + + + + + + + + +``` + +### Annotation 配置 +> 以注解方式暴露服务和引用服务接口,支持与Spring无缝集成,具体请参考[Annotation配置](../annotation)。 + +```java + // AnnotationService服务实现 + + @DubboService + public class AnnotationServiceImpl implements AnnotationService { + @Override + public String sayHello(String name) { + System.out.println("async provider received: " + name); + return "annotation: hello, " + name; + } + } +``` + +```properties +## dubbo.properties + +dubbo.application.name=annotation-provider +dubbo.registry.address=zookeeper://127.0.0.1:2181 +dubbo.protocol.name=dubbo +dubbo.protocol.port=20880 +``` + +### Spring Boot 配置 +> 使用 Spring Boot 减少非必要配置,结合 Annotation 与 application.properties/application.yml 开发 Dubbo 应用,具体请参考[Annotation 配置](../annotation)。 + +```properties +## application.properties + +# Spring boot application +spring.application.name=dubbo-externalized-configuration-provider-sample + +# Base packages to scan Dubbo Component: @com.alibaba.dubbo.config.annotation.Service +dubbo.scan.base-packages=com.alibaba.boot.dubbo.demo.provider.service + +# Dubbo Application +## The default value of dubbo.application.name is ${spring.application.name} +## dubbo.application.name=${spring.application.name} + +# Dubbo Protocol +dubbo.protocol.name=dubbo +dubbo.protocol.port=12345 + +## Dubbo Registry +dubbo.registry.address=N/A + +## DemoService version +demo.service.version=1.0.0 +``` + +## 配置规范与来源 + +Dubbo 遵循一种 [path-based 的配置规范](../principle/),每一个配置组件都可以通过这种方式进行表达。而在配置的来源上,总共支持 6 种配置来源,即 Dubbo 会分别尝试从以下几个位置尝试加载配置数据: + +- JVM System Properties,JVM -D 参数 +- System environment,JVM进程的环境变量 +- Externalized Configuration,[外部化配置](../principle/#33-外部化配置),从配置中心读取 +- Application Configuration,应用的属性配置,从Spring应用的Environment中提取"dubbo"打头的属性集 +- API / XML /注解等编程接口采集的配置可以被理解成配置来源的一种,是直接面向用户编程的配置采集方式 +- 从classpath读取配置文件 dubbo.properties + + + + + + +> [dubbo-spring-boot-samples](https://github.com/apache/dubbo-spring-boot-project/tree/master/dubbo-spring-boot-samples) + +```properties + ## application.properties + + # Spring boot application + spring.application.name=dubbo-externalized-configuration-provider-sample + + # Base packages to scan Dubbo Component: @com.alibaba.dubbo.config.annotation.Service + dubbo.scan.base-packages=com.alibaba.boot.dubbo.demo.provider.service + + # Dubbo Application + ## The default value of dubbo.application.name is ${spring.application.name} + ## dubbo.application.name=${spring.application.name} + + # Dubbo Protocol + dubbo.protocol.name=dubbo + dubbo.protocol.port=12345 + + ## Dubbo Registry + dubbo.registry.address=N/A + + ## service default version + dubbo.provider.version=1.0.0 +``` +接下来,我们就围绕这个示例,分别从配置格式、配置来源、加载流程三个方面对 Dubbo 配置的工作原理进行分析。 + +## 1 配置格式 + +目前Dubbo支持的所有配置都是`.properties`格式的,包括`-D`、`Externalized Configuration`等,`.properties`中的所有配置项遵循一种`path-based`的配置格式。 + +在Spring应用中也可以将属性配置放到`application.yml`中,其树层次结构的方式可读性更好一些。 + +```properties +# 应用级配置(无id) +dubbo.{config-type}.{config-item}={config-item-value} + +# 实例级配置(指定id或name) +dubbo.{config-type}s.{config-id}.{config-item}={config-item-value} +dubbo.{config-type}s.{config-name}.{config-item}={config-item-value} + +# 服务接口配置 +dubbo.service.{interface-name}.{config-item}={config-item-value} +dubbo.reference.{interface-name}.{config-item}={config-item-value} + +# 方法配置 +dubbo.service.{interface-name}.{method-name}.{config-item}={config-item-value} +dubbo.reference.{interface-name}.{method-name}.{config-item}={config-item-value} + +# 方法argument配置 +dubbo.reference.{interface-name}.{method-name}.{argument-index}.{config-item}={config-item-value} + +``` + +### 1.1 应用级配置(无id) + +应用级配置的格式为:配置类型单数前缀,无id/name。 +```properties +# 应用级配置(无id) +dubbo.{config-type}.{config-item}={config-item-value} +``` + +类似 `application`、`monitor`、`metrics` 等都属于应用级别组件,因此仅允许配置单个实例;而 `protocol`、`registry` 等允许配置多个的组件,在仅需要进行单例配置时,可采用此节描述的格式。常见示例如下: + +```properties +dubbo.application.name=demo-provider +dubbo.application.qos-enable=false + +dubbo.registry.address=zookeeper://127.0.0.1:2181 + +dubbo.protocol.name=dubbo +dubbo.protocol.port=-1 +``` + +### 1.2 实例级配置(指定id或name) + +针对某个实例的属性配置需要指定id或者name,其前缀格式为:配置类型复数前缀 + id/name。适用于 `protocol`、`registry` 等支持多例配置的组件。 + +```properties +# 实例级配置(指定id或name) +dubbo.{config-type}s.{config-id}.{config-item}={config-item-value} +dubbo.{config-type}s.{config-name}.{config-item}={config-item-value} +``` + +* 如果不存在该id或者name的实例,则框架会基于这里列出来的属性创建配置组件实例。 +* 如果已存在相同id或name的实例,则框架会将这里的列出的属性作为已有实例配置的补充,详细请参考[属性覆盖](../principle#32-属性覆盖)。 +* 具体的配置复数形式请参考[单复数配置对照表](../principle#17-配置项单复数对照表) + +配置示例: + +```properties +dubbo.registries.unit1.address=zookeeper://127.0.0.1:2181 +dubbo.registries.unit2.address=zookeeper://127.0.0.1:2182 + +dubbo.protocols.dubbo.name=dubbo +dubbo.protocols.dubbo.port=20880 + +dubbo.protocols.hessian.name=hessian +dubbo.protocols.hessian.port=8089 +``` + +### 1.3 服务接口配置 + +```properties +dubbo.service.org.apache.dubbo.samples.api.DemoService.timeout=5000 +dubbo.reference.org.apache.dubbo.samples.api.DemoService.timeout=6000 +``` + +### 方法配置 + +方法配置格式: + +```properties +# 方法配置 +dubbo.service.{interface-name}.{method-name}.{config-item}={config-item-value} +dubbo.reference.{interface-name}.{method-name}.{config-item}={config-item-value} + +# 方法argument配置 +dubbo.reference.{interface-name}.{method-name}.{argument-index}.{config-item}={config-item-value} +``` + +方法配置示例: +```properties +dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.timeout=7000 +dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.oninvoke=notifyService.onInvoke +dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.onreturn=notifyService.onReturn +dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.onthrow=notifyService.onThrow +dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.0.callback=true +``` + +等价于XML配置: + +```xml + + + + + +``` + +### 1.4 参数配置 + +parameters参数为map对象,支持xxx.parameters=[{key:value},{key:value}]方式进行配置。 +```properties +dubbo.application.parameters=[{item1:value1},{item2:value2}] +dubbo.reference.org.apache.dubbo.samples.api.DemoService.parameters=[{item3:value3}] +``` + +### 1.5 传输层配置 + +triple协议采用Http2做底层通信协议,允许使用者自定义Http2的[6个settings参数](https://datatracker.ietf.org/doc/html/rfc7540#section-6.5.2) + +配置格式如下: + +```properties +# 通知对端header压缩索引表的上限个数 +dubbo.rpc.tri.header-table-size=4096 + +# 启用服务端推送功能 +dubbo.rpc.tri.enable-push=false + +# 通知对端允许的最大并发流数 +dubbo.rpc.tri.max-concurrent-streams=2147483647 + +# 声明发送端的窗口大小 +dubbo.rpc.tri.initial-window-size=1048576 + +# 设置帧的最大字节数 +dubbo.rpc.tri.max-frame-size=32768 + +# 通知对端header未压缩的最大字节数 +dubbo.rpc.tri.max-header-list-size=8192 +``` + +等价于yml配置: + +```yaml +dubbo: + rpc: + tri: + header-table-size: 4096 + enable-push: false + max-concurrent-streams: 2147483647 + initial-window-size: 1048576 + max-frame-size: 32768 + max-header-list-size: 8192 +``` + + + +### 1.6 属性与XML配置映射规则 + +可以将 xml 的 tag 名和属性名组合起来,用 ‘.’ 分隔。每行一个属性。 + +* `dubbo.application.name=foo` 相当于 `` +* `dubbo.registry.address=10.20.153.10:9090` 相当于 ` ` + +如果在 xml 配置中有超过一个的 tag,那么你可以使用 ‘id’ 进行区分。如果你不指定id,它将作用于所有 tag。 + +* `dubbo.protocols.rmi.port=1099` 相当于 ` ` +* `dubbo.registries.china.address=10.20.153.10:9090` 相当于 `` + +### 1.7 配置项单复数对照表 +复数配置的命名与普通单词变复数的规则相同: + +1. 字母y结尾时,去掉y,改为ies +2. 字母s结尾时,加es +3. 其它加s + +| Config Type | 单数配置 | 复数配置 | +| --------------------------------- | ------------------------------------------------------------ | ----------------------------------- | +| application | dubbo.application.xxx=xxx | dubbo.applications.{id}.xxx=xxx
dubbo.applications.{name}.xxx=xxx | +| protocol | dubbo.protocol.xxx=xxx | dubbo.protocols.{id}.xxx=xxx
dubbo.protocols.{name}.xxx=xxx | +| module | dubbo.module.xxx=xxx | dubbo.modules.{id}.xxx=xxx
dubbo.modules.{name}.xxx=xxx | +| registry | dubbo.registry.xxx=xxx | dubbo.registries.{id}.xxx=xxx | +| monitor | dubbo.monitor.xxx=xxx | dubbo.monitors.{id}.xxx=xxx | +| config-center | dubbo.config-center.xxx=xxx | dubbo.config-centers.{id}.xxx=xxx | +| metadata-report | dubbo.metadata-report.xxx=xxx | dubbo.metadata-reports.{id}.xxx=xxx | +| ssl | dubbo.ssl.xxx=xxx | dubbo.ssls.{id}.xxx=xxx | +| metrics | dubbo.metrics.xxx=xxx | dubbo.metricses.{id}.xxx=xxx | +| provider | dubbo.provider.xxx=xxx | dubbo.providers.{id}.xxx=xxx | +| consumer | dubbo.consumer.xxx=xxx | dubbo.consumers.{id}.xxx=xxx | +| service | dubbo.service.{interfaceName}.xxx=xxx | 无 | +| reference | dubbo.reference.{interfaceName}.xxx=xxx | 无 | +| method | dubbo.service.{interfaceName}.{methodName}.xxx=xxx
dubbo.reference.{interfaceName}.{methodName}.xxx=xxx | 无 | +| argument | dubbo.service.{interfaceName}.{methodName}.{arg-index}.xxx=xxx | 无 | + + +## 2 配置来源 + +Dubbo 默认支持 6 种配置来源: + +- JVM System Properties,JVM -D 参数 +- System environment,JVM进程的环境变量 +- Externalized Configuration,[外部化配置](#33-外部化配置),从配置中心读取 +- Application Configuration,应用的属性配置,从Spring应用的Environment中提取"dubbo"打头的属性集 +- API / XML /注解等编程接口采集的配置可以被理解成配置来源的一种,是直接面向用户编程的配置采集方式 +- 从classpath读取配置文件 dubbo.properties + +关于dubbo.properties属性: + +1. 如果在 classpath 下有超过一个 dubbo.properties 文件,比如,两个 jar 包都各自包含了 dubbo.properties,dubbo 将随机选择一个加载,并且打印错误日志。 +2. Dubbo 可以自动加载 classpath 根目录下的 dubbo.properties,但是你同样可以使用 JVM 参数来指定路径:`-Ddubbo.properties.file=xxx.properties`。 + +### 2.1 覆盖关系 + +如果通过多种配置来源指定了相同的配置项,则会出现配置项的互相覆盖,具体覆盖关系和优先级请参考下一小节。 + +## 3 配置加载流程 + +### 3.1 处理流程 + +Dubbo 配置加载大概分为两个阶段: + +![配置加载流程](/imgs/v3/config/config-load.svg) + +* 第一阶段为DubboBootstrap初始化之前,在Spring context启动时解析处理XML配置/注解配置/Java-config 或者是执行API配置代码,创建config bean并且加入到ConfigManager中。 +* 第二阶段为DubboBootstrap初始化过程,从配置中心读取外部配置,依次处理实例级属性配置和应用级属性配置,最后刷新所有配置实例的属性,也就是[属性覆盖](../principle#32-属性覆盖)。 + +### 3.2 属性覆盖 + +发生属性覆盖可能有两种情况,并且二者可能是会同时发生的: +1. 不同配置源配置了相同的配置项 +2. 相同配置源,但在不同层次指定了相同的配置项 + +#### 3.2.1 不同配置源 + +![覆盖关系](/imgs/blog/configuration.jpg) + +#### 3.2.1 相同配置源 + +属性覆盖是指用配置的属性值覆盖config bean实例的属性,类似Spring [PropertyOverrideConfigurer](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/PropertyOverrideConfigurer.html) 的作用。 + +> Property resource configurer that overrides bean property values in an application context definition. It pushes values from a properties file into bean definitions. +Configuration lines are expected to be of the following form: +> +> beanName.property=value + +但与`PropertyOverrideConfigurer`的不同之处是,Dubbo的属性覆盖有多个匹配格式,优先级从高到低依次是: + +```properties +#1. 指定id的实例级配置 +dubbo.{config-type}s.{config-id}.{config-item}={config-item-value} + +#2. 指定name的实例级配置 +dubbo.{config-type}s.{config-name}.{config-item}={config-item-value} + +#3. 应用级配置(单数配置) +dubbo.{config-type}.{config-item}={config-item-value} +``` + +属性覆盖处理流程: + +按照优先级从高到低依次查找,如果找到此前缀开头的属性,则选定使用这个前缀提取属性,忽略后面的配置。 + +![属性覆盖流程](/imgs/v3/config/properties-override.svg) + +### 3.3 外部化配置 + +外部化配置目的之一是实现配置的集中式管理,这部分业界已经有很多成熟的专业配置系统如 Apollo, Nacos 等,Dubbo 所做的主要是保证能配合这些系统正常工作。 + +外部化配置和其他本地配置在内容和格式上并无区别,可以简单理解为 `dubbo.properties` 的外部化存储,配置中心更适合将一些公共配置如注册中心、元数据中心配置等抽取以便做集中管理。 + +```properties +# 将注册中心地址、元数据中心地址等配置集中管理,可以做到统一环境、减少开发侧感知。 +dubbo.registry.address=zookeeper://127.0.0.1:2181 +dubbo.registry.simplified=true + +dubbo.metadata-report.address=zookeeper://127.0.0.1:2181 + +dubbo.protocol.name=dubbo +dubbo.protocol.port=20880 + +dubbo.application.qos.port=33333 +``` + +- 优先级 + 外部化配置默认较本地配置有更高的优先级,因此这里配置的内容会覆盖本地配置值,关于各配置形式间的[覆盖关系](#21-覆盖关系) 有单独一章说明。 + +- 作用域 + 外部化配置有全局和应用两个级别,全局配置是所有应用共享的,应用级配置是由每个应用自己维护且只对自身可见的。当前已支持的扩展实现有 Zookeeper、Apollo、Nacos。 + +#### 3.3.1 外部化配置使用方式 + +1. 增加 config-center 配置 + +```xml + +``` + +2. 在相应的配置中心(zookeeper、Nacos 等)增加全局配置项,如下以 Nacos 为例: + +![nacos-extenal-properties](/imgs/v3/config-center/nacos-extenal-properties.png) + +开启外部化配置后,registry、metadata-report、protocol、qos 等全局范围的配置理论上都不再需要在应用中配置,应用开发侧专注业务服务配置,一些全局共享的全局配置转而由运维人员统一配置在远端配置中心。 + +这样能做到的效果就是,应用只需要关心: +* 服务暴露、订阅配置 +* 配置中心地址 +当部署到不同的环境时,其他配置就能自动的被从对应的配置中心读取到。 + +举例来说,每个应用中 Dubbo 相关的配置只有以下内容可能就足够了,其余的都托管给相应环境下的配置中心: + +```yaml +dubbo + application + name: demo + config-center + address: nacos://127.0.0.1:8848 +``` + +#### 3.3.2 自行加载外部化配置 + +所谓 Dubbo 对配置中心的支持,本质上就是把 `.properties` 从远程拉取到本地,然后和本地的配置做一次融合。理论上只要 Dubbo 框架能拿到需要的配置就可以正常的启动,它并不关心这些配置是自己加载到的还是应用直接塞给它的,所以Dubbo还提供了以下API,让用户将自己组织好的配置塞给 Dubbo 框架(配置加载的过程是用户要完成的),这样 Dubbo 框架就不再直接和 Apollo 或 Zookeeper 做读取配置交互。 + +```java +// 应用自行加载配置 +Map dubboConfigurations = new HashMap<>(); +dubboConfigurations.put("dubbo.registry.address", "zookeeper://127.0.0.1:2181"); +dubboConfigurations.put("dubbo.registry.simplified", "true"); + +//将组织好的配置塞给Dubbo框架 +ConfigCenterConfig configCenter = new ConfigCenterConfig(); +configCenter.setExternalConfig(dubboConfigurations); +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/properties.md b/content/en/overview/mannual/java-sdk/reference-manual/config/properties.md new file mode 100644 index 000000000000..0dbbdf5f9c8d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/properties.md @@ -0,0 +1,804 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config/properties/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config/properties/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/dump/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/lazy-connect/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/simplify-registry-data/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/stickiness/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/delay-publish/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/preflight-check/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/registry-only/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/service-downgrade/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/subscribe-only/ +description: 包含 Dubbo 支持的所有配置组件及每个配置组件支持的所有配置项 +linkTitle: 配置项手册 +title: 配置项参考手册 +type: docs +weight: 6 +--- + + +## JVM(-D) 参数 + + +| JVM 参数 | 示例值 | 说明 | +| --- | --- | --- | +| dubbo.{config-name}.{property} | -Ddubbo.application.name="dubbo-demo"

-Ddubbo.registry.address="nacos://host:port"

-Ddubbo.protocol.port="20880"

...... | Dubbo支持 [所有的配置项](aaa) 以JVM参数格式指定。其中`config` 是指如 application、registry、protocol 等配置项,而`property`则是指每个配置项中的具体属性。 | +| dubbo.resolve.file | -Ddubbo.resolve.file=/home/ken/.../dubbo-resolve.properties | 在文件中指定每个接口的直连地址url,如:org.apache.dubbo.demo.DemoService=tri://127.0.0.1:50051/org.apache.dubbo.demo.DemoService?xxx=xxx | +| org.graalvm.nativeimage.imagecode || [https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java](https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java) | +| dubbo.properties.file | -Ddubbo.properties.file=foo.properties | 指定 properties 配置文件地址,可以是绝对路径或者classpath相对路径。默认值为 dubbo.properties | +| dubbo.jstack-dump.max-line | -Ddubbo.jstack-dump.max-line=20 | Dubbo 支持自动打印调用堆栈,这个参数可以控制堆栈行数,如示例中只会打印前20行堆栈 | +| dubbo.json-framework.prefer| -Ddubbo.json-framework.prefer=gson | 设置框架中 json 序列化的具体实现,目前可选实现有 `fastjson2`、`fastjson`、`gson`、`jackson`。默认情况,框架会自动查找可用实现,以上按顺序优先级依次降低 | +| dubbo.network.interface.ignored | -Ddubbo.network.interface.ignored=eth1,eth2 | 在多网卡环境下,当需要手动控制注册到注册中心的网卡地址时使用。用于排除某些网卡 | +| dubbo.network.interface.preferred | -Ddubbo.network.interface.ignored=eth0 | 在多网卡环境下,当需要手动控制注册到注册中心的网卡地址时使用。用于指定一个特定网卡 | +| sun.rmi.transport.tcp.responseTimeout | -Dsun.rmi.transport.tcp.responseTimeout=5000 | 用于设置 RMI 协议下的超时时间,单位ms | +| env | | Apollo 配置中心特有参数 | +| app.id | | Apollo 配置中心特有参数 | +| apollo.cluster | | Apollo 配置中心特有参数 | +| apollo.meta | | Apollo 配置中心特有参数 | +| dubbo.mapping.cache.filePath | -Ddubbo.mapping.cache.filePath=~/.dubbo/mapping/ | 用于设置`接口-应用`映射关系缓存文件,通常用于服务发现。文件绝对路径地址 | +| dubbo.mapping.cache.fileName | -Ddubbo.mapping.cache.fileName=dubbo-mapping | 用于设置`接口-应用`映射关系缓存文件,通常用于服务发现。文件名,如此示例最终会读取和存储在文件 dubbo-mapping.dubbo.cache | +| dubbo.mapping.cache.entrySize | -Ddubbo.mapping.cache.maxFileSize=300 | 用于设置`接口-应用`映射关系缓存文件,通常用于服务发现。文件名中内容最大条目数限制 | +| dubbo.mapping.cache.maxFileSize | -Ddubbo.mapping.cache.maxFileSize=104857600 | 用于设置`接口-应用`映射关系缓存文件,通常用于服务发现。文件最大占用空间限制,单位byte | +| dubbo.meta.cache.filePath | -Ddubbo.meta.cache.filePath=~/.dubbo/meta/ | 用于设置`metadata元数据`缓存文件,通常用于服务发现。文件绝对路径地址 | +| dubbo.meta.cache.fileName | -Ddubbo.meta.cache.fileName=dubbo-meta | 用于设置`metadata元数据`缓存文件,通常用于服务发现。文件名,如此示例最终会读取和存储在文件 dubbo-meta.dubbo.cache | +| dubbo.meta.cache.entrySize | -Ddubbo.meta.cache.maxFileSize=300 | 用于设置`metadata元数据`缓存文件,通常用于服务发现。文件名中内容最大条目数限制 | +| dubbo.meta.cache.maxFileSize | -Ddubbo.meta.cache.maxFileSize=104857600 | 用于设置`metadata元数据`缓存文件,通常用于服务发现。文件最大占用空间限制,单位byte | +| dubbo.application.use-secure-random-request-id | -Ddubbo.application.use-secure-random-request-id=true | 设置每次 rpc 调用 request id 的生成规则,是不是用随机值。如不设置则使用递增值。 | +| dubbo.protocol.default-close-timeout | -Ddubbo.protocol.default-close-timeout=10000 | 设置 tcp server 关闭等待时间,单位毫秒ms | +| dubbo.protocol.default-heartbeat | -Ddubbo.protocol.default-heartbeat=10000 | 设置发起心跳 heartbeat 的间隔,单位毫秒ms | +| dubbo.hessian.allowNonSerializable | | 是否允许对没有实现 Serializable 接口的类进行序列化,对hessian序列化有效 | +| dubbo.application.hessian2.whitelist | -Ddubbo.application.hessian2.whitelist=true | 设置是否启用白名单机制,对hessian序列化有效。如果设置 true,则继续配置下面的 allow 规则;否则,配置 deny 规则 | +| dubbo.application.hessian2.allow | -Ddubbo.application.hessian2.allow=org.apache.dubbo.*;com.company.* | 如果设置 true,则继续配置配置 allow 规则,参见文档说明 | +| dubbo.application.hessian2.deny | -Ddubbo.application.hessian2.deny=org.apache.dubbo.*;io.commons.* | 如果设置 false,则继续配置配置 deny 规则,参见文档说明 | +| dubbo.application.manual-register | -Ddubbo.application.manual-register=true | 设置之后,所有服务都不会被自动注册到注册中心,直到用户调用 online 等命令手动完成注册 | +| dubbo.compact.enable | | | +| dubbo.migration-file.enable | -Ddubbo.migration-file.enable=true | 在往应用级地址发现迁移时,是否启用规则文件读取 | +| dubbo.migration.file | -Ddubbo.migration.file=dubbo-migration.yaml | 指定往应用级地址发现迁移的规则文件路径,可以是绝对路径或者classpath相对路径。默认值为 dubbo-migration.yaml | +| dubbo.application.logger | -Ddubbo.application.logger=slf4j | 设置dubbo框架使用的日志组件,设置后,dubbo框架自身的日志将打印到这里(不影响应用自身);目前支持的 slf4j、log4j、log4j2 等,设置之后须确保相应的组件依赖已经加入应用。 | +| dubbo.properties.file | -Ddubbo.properties.file=foo.properties | 指定 properties 配置文件地址,可以是绝对路径或者classpath相对路径。默认值为 dubbo.properties | + + +## 环境变量 + +| 环境变量 | 示例值 | 说明 | +| --- | --- | --- | +| DUBBO_{CONFIG-NAME}.{PROPERTY} | DUBBO_APPLICATION_NAME="dubbo-demo"

DUBBO_REGISTRY_ADDRESS="nacos://host:port"

DUBBO_PROTOCOL_PORT="20880"

...... | Dubbo支持[所有的配置项](aaa)以环境变量格式指定。其中`CONFIG-NAME` 是指如 application、registry、protocol 等配置项,而 `PROPERTY`则是指每个配置项中的具体属性。 | +| DUBBO_DEFAULT_SERIALIZATION | DUBBO_DEFAULT_SERIALIZATION="hessan2" | 设置框架的默认序列化方式,如hessian2、fastjson2、msgpack等 | +| DUBBO2_COMPACT_ENABLE | DUBBO2_COMPAT_ENABLE="true" | | +| DUBBO_ENV_KEYS| DUBBO_LABELS="tag1=value1; tag2=value2" | `tag1=value1`会作为附加参数上报到地址 URL,作为系统环境变量可用于为实例打标等。 | +| DUBBO_LABELS | DUBBO_ENV_KEYS="DUBBO_TAG1, DUBBO_TAG2" | Dubbo 会读取 `DUBBO_TAG1`、`DUBBO_TAG2`两个环境变量,并将读取的值 value `DUBBO_TAG1=value` 作为附加参数上报到地址 URL。 | +| POD_NAMESPACE | | 用于 Kubernetes Service 场景,指定命名空间 | +| CLUSTER_DOMAIN | | 用于 Kubernetes Service 场景,指定集群名称,默认 default | +| DUBBO_IP_TO_REGISTRY | DUBBO_IP_TO_REGISTRY=30.123.45.187 | 指定注册到注册中心 URL 中的 ip 地址 | +| DUBBO_PORT_TO_REGISTRY | DUBBO_PORT_TO_REGISTRY=20880 | 指定注册到注册中心 URL 中的 port 端口号 | +| DUBBO_{PROTOCOL}_PORT_TO_REGISTRY | DUBBO_DUBBO_IP_TO_REGISTRY=30.123.45.187

DUBBO_TRI_IP_TO_REGISTRY=30.123.45.187 | 指定注册到注册中心 URL 中的 ip 地址,可以为不同协议指定不同 ip | +| DUBBO_{PROTOCOL}_PORT_TO_REGISTRY | DUBBO_DUBBO_PORT_TO_REGISTRY=20880

DUBBO_TRI_PORT_TO_REGISTRY=50051 | 指定注册到注册中心 URL 中的 port 端口,可以为不同协议指定不同 port | +| DUBBO_IP_TO_BIND | DUBBO_IP_TO_BIND=30.123.45.187 | 指定 tcp 监听绑定的 ip 地址 | +| DUBBO_PORT_TO_BIND | DUBBO_PORT_TO_BIND=20880 | 指定 tcp 监听绑定的 port 端口 | +| DUBBO_{PROTOCOL}_IP_TO_BIND | DUBBO_DUBBO_IP_TO_BIND=30.123.45.187

DUBBO_TRI_IP_TO_BIND=30.123.45.187 | 指定 tcp 监听绑定的 ip 地址,可以为不同协议指定不同 ip | +| DUBBO_{PROTOCOL}_PORT_TO_BIND | DUBBO_DUBBO_PORT_TO_BIND=20880

DUBBO_TRI_PORT_TO_BIND=50051 | 指定 tcp 监听绑定的 port 端口,可以为不同协议指定不同 port | +| dubbo.properties.file | dubbo.properties.file=foo.properties | 指定 properties 配置文件地址,可以是绝对路径或者classpath相对路径。默认值为 dubbo.properties | +| dubbo.migration.file | dubbo.migration.file=dubbo-migration.yaml | 指定应用级地址发现的迁移规则的文件地址,可以是绝对路径或者classpath相对路径。默认值为 dubbo-migration.yaml | + + +## 配置项手册 +不论您是使用 Spring Boot、XML、注解还是 API 编写 Dubbo 应用,都可以通过以下表格参考每一项的具体含义。 + +### dubbo.tracing.baggage.correlation +**Class:** `org.apache.dubbo.config.nested.BaggageConfig$Correlation` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| enabled| java.lang.Boolean| Whether to enable correlation of the baggage context with logging contexts.| true| | +| fields| java.util.List<java.lang.String>| List of fields that should be correlated with the logging context. That means that these fields would end up as key-value pairs in e.g. MDC.| | | +### dubbo.tracing.tracing-exporter.otlp-config +**Class:** `org.apache.dubbo.config.nested.ExporterConfig$OtlpConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| compression-method| java.lang.String| The method used to compress payloads. If unset, compression is disabled. Currently supported compression methods include "gzip" and "none".| none| | +| endpoint| java.lang.String| URL to the Otlp API.| | | +| headers| java.util.Map<java.lang.String,java.lang.String>| | | | +| timeout| java.time.Duration| The maximum time to wait for the collector to process an exported batch of spans. (seconds)| 10| | +### dubbo.tracing.tracing-exporter.zipkin-config +**Class:** `org.apache.dubbo.config.nested.ExporterConfig$ZipkinConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| connect-timeout| java.time.Duration| Connection timeout for requests to Zipkin. (seconds)| 1| | +| endpoint| java.lang.String| URL to the Zipkin API.| | | +| read-timeout| java.time.Duration| Read timeout for requests to Zipkin. (seconds)| 10| | +### dubbo.metrics.prometheus.exporter +**Class:** `org.apache.dubbo.config.nested.PrometheusConfig$Exporter` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| enable-http-service-discovery| java.lang.Boolean| Enable http service discovery for prometheus| | | +| enabled| java.lang.Boolean| Enable prometheus exporter| | | +| http-service-discovery-url| java.lang.String| Http service discovery url| | | +### dubbo.metrics.prometheus.pushgateway +**Class:** `org.apache.dubbo.config.nested.PrometheusConfig$Pushgateway` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| base-url| java.lang.String| Base URL for the Pushgateway| | | +| enabled| java.lang.Boolean| Enable publishing via a Prometheus Pushgateway| | | +| job| java.lang.String| Job identifier for this application instance| | | +| password| java.lang.String| Login password of the Prometheus Pushgateway| | | +| push-interval| java.lang.Integer| Frequency with which to push metrics| | | +| username| java.lang.String| Login user of the Prometheus Pushgateway| | | +### Unknown group +**Class:** `Unknown` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| dubbo.config-center.include-spring-env| java.lang.Boolean| Whether to include Spring Environment.| | | +| dubbo.config.mode| org.apache.dubbo.config.context.ConfigMode| Config processing mode. See <code>org.apache.dubbo.config.context.ConfigMode</code>.| | | +| dubbo.config.multiple| java.lang.Boolean| Whether to enable multiple configurations in Dubbo, allowing multiple configurations to be loaded and used, default value is <code>true</code>.| | | +| dubbo.config.override| java.lang.Boolean| Whether to allow configuration override in Dubbo, default value is <code>true</code>.| | | +| dubbo.enabled| java.util.Set<java.lang.String>| Whether enable autoconfiguration of dubbo, default value is <code>true</code>.| | | +| dubbo.env.keys| java.lang.String| The keys for specify environment-specific keys, allowing for differentiation and utilization of various runtime environments (e.g., development, testing, production), the multiple-value is delimited by comma.| | | +| dubbo.labels| java.lang.String| The labels for these service providers, enabling categorization and grouping, thereby enhancing their management and monitoring, the multiple-value is delimited by ';'.| | | +| dubbo.scan.base-packages| java.util.Set<java.lang.String>| The basePackages to scan, the multiple-value is delimited by comma @see EnableDubbo#scanBasePackages().| | | +### dubbo.tracing.baggage +**Class:** `org.apache.dubbo.config.nested.BaggageConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| enabled| java.lang.Boolean| Whether baggage is enabled or not.| true| | +| remote-fields| java.util.List<java.lang.String>| List of fields that are referenced the same in-process as it is on the wire. For example, the field "x-vcap-request-id" would be set as-is including the prefix.| | | +### dubbo.tracing.propagation +**Class:** `org.apache.dubbo.config.nested.PropagationConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| type| java.lang.String| Tracing context propagation type.| W3C| | +### dubbo.tracing.sampling +**Class:** `org.apache.dubbo.config.nested.SamplingConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| probability| java.lang.Float| Probability in the range from 0.0 to 1.0 that a trace will be sampled.| 0.1| | +### dubbo.tracing.tracing-exporter +**Class:** `org.apache.dubbo.config.nested.ExporterConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +### dubbo.rpc.tri +**Class:** `org.apache.dubbo.config.TripleConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| enable-push| java.lang.Boolean| Whether to enable push, default is false.| | | +| header-table-size| java.lang.String| The header table size.| | | +| initial-window-size| java.lang.String| Initial window size.| | | +| max-concurrent-streams| java.lang.String| Maximum concurrent streams.| | | +| max-frame-size| java.lang.String| Maximum frame size.| | | +| max-header-list-size| java.lang.String| Maximum header list size.| | | +### dubbo +**Class:** `org.apache.dubbo.spring.boot.autoconfigure.DubboConfigurationProperties` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| config-centers| java.util.Map<java.lang.String,org.apache.dubbo.config.ConfigCenterConfig>| Multiple configurations for ConfigCenterBean.| | | +| consumers| java.util.Map<java.lang.String,org.apache.dubbo.config.ConsumerConfig>| Multiple configurations for Consumer.| | | +| metadata-reports| java.util.Map<java.lang.String,org.apache.dubbo.config.MetadataReportConfig>| Multiple configurations for MetadataReportConfig.| | | +| metricses| java.util.Map<java.lang.String,org.apache.dubbo.config.MetricsConfig>| Multiple configurations for MetricsConfig.| | | +| modules| java.util.Map<java.lang.String,org.apache.dubbo.config.ModuleConfig>| Multiple configurations for Module.| | | +| monitors| java.util.Map<java.lang.String,org.apache.dubbo.config.MonitorConfig>| Multiple configurations for Monitor.| | | +| protocols| java.util.Map<java.lang.String,org.apache.dubbo.config.ProtocolConfig>| Multiple configurations for Protocol.| | | +| providers| java.util.Map<java.lang.String,org.apache.dubbo.config.ProviderConfig>| Multiple configurations for Provider.| | | +| registries| java.util.Map<java.lang.String,org.apache.dubbo.config.RegistryConfig>| Multiple configurations for Registry.| | | +| tracings| java.util.Map<java.lang.String,org.apache.dubbo.config.TracingConfig>| Multiple configurations for TracingConfig.| | | +### dubbo.application +**Class:** `org.apache.dubbo.config.ApplicationConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| architecture| java.lang.String| Architecture layer.| | | +| auto-trust-serialize-class| java.lang.Boolean| Whether to automatically trust serialized classes.| | | +| check-serializable| java.lang.Boolean| Whether to check serializable.| | | +| compiler| java.lang.String| Java compiler.| | | +| default| java.lang.Boolean| | | | +| dump-directory| java.lang.String| Directory for saving thread dump.| | | +| dump-enable| java.lang.Boolean| Whether to enable saving thread dump or not.| | | +| enable-empty-protection| java.lang.Boolean| Whether to enable protection against empty objects.| | | +| enable-file-cache| java.lang.Boolean| Whether to enable file caching.| | | +| environment| java.lang.String| Environment, e.g., dev, test, or production.| | | +| executor-management-mode| java.lang.String| Thread pool management mode: 'default' or 'isolation'.| | | +| id| java.lang.String| Identifier for this configuration.| | | +| liveness-probe| java.lang.String| Used to set extensions of the probe in QoS.| | | +| logger| java.lang.String| The type of log access.| | | +| mapping-retry-interval| java.lang.Integer| The retry interval of service name mapping.| | | +| meta-data| java.util.Map<java.lang.String,java.lang.String>| | | | +| metadata-service-port| java.lang.Integer| Metadata Service, used in Service Discovery.| | | +| metadata-service-protocol| java.lang.String| The protocol used for peer-to-peer metadata transmission.| | | +| metadata-type| java.lang.String| Metadata type, local or remote. If 'remote' is chosen, you need to specify a metadata center further.| | | +| monitor| org.apache.dubbo.config.MonitorConfig| Monitor center.| | | +| name| java.lang.String| The Application name.| | | +| need-refresh| java.lang.Boolean| Specifies if this configuration should be refreshed (true for refreshing).| true| | +| organization| java.lang.String| The application's organization (BU).| | | +| owner| java.lang.String| The application owner.| | | +| parameters| java.util.Map<java.lang.String,java.lang.String>| Customized parameters.| | | +| prefixes| java.util.List<java.lang.String>| | | | +| protocol| java.lang.String| The preferred protocol (name) of this application, convenient for places where it's hard to determine the preferred protocol.| | | +| qos-accept-foreign-ip| java.lang.Boolean| Should we accept foreign IP or not?| | | +| qos-accept-foreign-ip-compatible| java.lang.Boolean| | | | +| qos-accept-foreign-ip-whitelist| java.lang.String| When we disable accepting foreign IP, support specifying foreign IPs in the whitelist.| | | +| qos-accept-foreign-ip-whitelist-compatible| java.lang.String| | | | +| qos-anonymous-access-permission-level| java.lang.String| The anonymous (any foreign IP) access permission level, default is NONE, which means no access to any command.| | | +| qos-anonymous-access-permission-level-compatible| java.lang.String| | | | +| qos-anonymous-allow-commands| java.lang.String| The anonymous (any foreign IP) allowed commands, default is empty, which means no access to any command.| | | +| qos-check| java.lang.Boolean| Whether QoS should start successfully or not, will check qosEnable first.| | | +| qos-enable| java.lang.Boolean| Whether to enable Quality of Service (QoS) or not.| | | +| qos-enable-compatible| java.lang.Boolean| | | | +| qos-host| java.lang.String| The QoS host to listen.| | | +| qos-host-compatible| java.lang.String| | | | +| qos-port| java.lang.Integer| The QoS port to listen.| | | +| qos-port-compatible| java.lang.Integer| | | | +| readiness-probe| java.lang.String| The probe for checking the readiness of the application.| | | +| register-consumer| java.lang.Boolean| Used to control whether to register the instance with the registry or not. Set to 'false' only when the instance is a pure consumer.| | | +| register-mode| java.lang.String| Register mode.| | | +| registries| java.util.List<org.apache.dubbo.config.RegistryConfig>| Registry centers.| | | +| registry| org.apache.dubbo.config.RegistryConfig| | | | +| registry-ids| java.lang.String| The comma-separated list of registry IDs to which the service will be registered.| | | +| repository| java.lang.String| Repository.| | | +| scope-model| org.apache.dubbo.rpc.model.ScopeModel| The scope model of this config instance. <p> <b>NOTE:</b> the model maybe changed during config processing, the extension spi instance needs to be reinitialized after changing the model!| | | +| serialize-check-status| java.lang.String| The status of class serialization checking.| | | +| shutwait| java.lang.String| Config the shutdown wait.| | | +| startup-probe| java.lang.String| The probe for checking the startup of the application.| | | +| trust-serialize-class-level| java.lang.Integer| The trust level for serialized classes.| | | +| version| java.lang.String| The application version.| | | +### dubbo.config-center +**Class:** `org.apache.dubbo.config.ConfigCenterConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| address| java.lang.String| The address (URL or hostname) of the config center server.| | | +| app-config-file| java.lang.String| The properties file under 'configFile' is global shared, while '.properties' under this one is limited only to this application.| | | +| app-external-configuration| java.util.Map<java.lang.String,java.lang.String>| Application-specific external configuration for the config center.| | | +| check| java.lang.Boolean| Behavior when the initial connection attempt to the config center fails. 'true' means interrupt the whole process once a failure occurs. Default value is true.| | | +| cluster| java.lang.String| The config center cluster, its actual meaning may vary depending on the specific config center product.| | | +| config-file| java.lang.String| Key mapping for properties files. Most of the time, you do not need to change this parameter. Default value is CommonConstants.DEFAULT_DUBBO_PROPERTIES.| | | +| default| java.lang.Boolean| | | | +| external-configuration| java.util.Map<java.lang.String,java.lang.String>| External configuration for the config center.| | | +| group| java.lang.String| The group of the config center, often used to identify an isolated space for a batch of config items. Its actual meaning depends on the specific config center you use. Default value is CommonConstants.DUBBO.| | | +| highest-priority| java.lang.Boolean| If the config center should have the highest priority and override all other configurations. Deprecated and no longer used. Default value is true.| | Reason: null, use for replacement: null| +| id| java.lang.String| Identifier for this configuration.| | | +| meta-data| java.util.Map<java.lang.String,java.lang.String>| | | | +| namespace| java.lang.String| The namespace of the config center, generally used for multi-tenancy. Its actual meaning depends on the specific config center you use. Default value is CommonConstants.DUBBO.| | | +| need-refresh| java.lang.Boolean| Specifies if this configuration should be refreshed (true for refreshing).| true| | +| parameters| java.util.Map<java.lang.String,java.lang.String>| Additional parameters specific to your config center product can be added here. For example, with XML: <dubbo:config-center> <dubbo:parameter key="{your key}" value="{your value}" /> </dubbo:config-center>| | | +| password| java.lang.String| Password for authentication with the config center.| | | +| port| java.lang.Integer| The port number for the config center server.| | | +| prefixes| java.util.List<java.lang.String>| | | | +| protocol| java.lang.String| The protocol used for accessing the config center.| | | +| scope-model| org.apache.dubbo.rpc.model.ScopeModel| The scope model of this config instance. <p> <b>NOTE:</b> the model maybe changed during config processing, the extension spi instance needs to be reinitialized after changing the model!| | | +| timeout| java.lang.Long| The timeout for accessing the config center. Default value is 30000L.| | | +| username| java.lang.String| Username for authentication with the config center.| | | +### dubbo.consumer +**Class:** `org.apache.dubbo.config.ConsumerConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| actives| java.lang.Integer| Maximum concurrent invocations allowed.| | | +| application| org.apache.dubbo.config.ApplicationConfig| Application configuration for the service.| | Reason: null, use for replacement: null| +| async| java.lang.Boolean| Enable asynchronous invocation. Note that it is unreliable asynchronous, ignoring return values and not blocking threads.| | | +| auth| java.lang.Boolean| Enable service authentication.| | | +| cache| java.lang.String| Cache provider for caching return results. available options: lru, threadlocal, jcache etc.| | | +| callbacks| java.lang.Integer| Callback limits for the service.| | | +| check| java.lang.Boolean| Check if service provider exists, if not exists, it will be fast fail| | | +| client| java.lang.String| client type| | | +| cluster| java.lang.String| Cluster type for service.| | | +| config-center| org.apache.dubbo.config.ConfigCenterConfig| Configuration center settings.| | Reason: null, use for replacement: null| +| connections| java.lang.Integer| Connection limits: 0 for shared connection, otherwise specifying connections for the service.| | | +| corethreads| java.lang.Integer| Consumer threadpool core thread size| | | +| default| java.lang.Boolean| | | | +| exported-urls| java.util.List<org.apache.dubbo.common.URL>| | | | +| filter| java.lang.String| Filters for service exposure or reference (multiple filters can be separated by commas).| | | +| forks| java.lang.Integer| Forks for forking cluster.| | | +| generic| java.lang.String| Whether to use generic interface| | | +| group| java.lang.String| Group of the remote service referenced by the consumer/provider.| | | +| id| java.lang.String| Identifier for this configuration.| | | +| init| java.lang.Boolean| Whether to eagle-init| | | +| injvm| java.lang.Boolean| Whether to find reference's instance from the current JVM| | Reason: null, use for replacement: null| +| interface| java.lang.String| | | | +| layer| java.lang.String| Layer of service providers.| | | +| lazy| java.lang.Boolean| Lazy create connection| | | +| listener| java.lang.String| Listeners for service exposure or reference (multiple listeners can be separated by commas).| | | +| loadbalance| java.lang.String| Load balancing strategy for service invocation.| | | +| local| java.lang.String| Local implementation class name for the service interface.| | Reason: null, use for replacement: null| +| merger| java.lang.String| Merger for result data.| | | +| mesh-enable| java.lang.Boolean| enable mesh mode @since 3.1.0| | | +| meta-data| java.util.Map<java.lang.String,java.lang.String>| | | | +| metadata-report-config| org.apache.dubbo.config.MetadataReportConfig| Metadata report configuration.| | Reason: null, use for replacement: null| +| methods| java.util.List<org.apache.dubbo.config.MethodConfig>| Method-specific configuration.| | | +| mock| java.lang.String| Mock class name to be called when a service fails to execute. The mock doesn't support on the provider side, and it is executed when a non-business exception occurs after a remote service call.| | | +| module| org.apache.dubbo.config.ModuleConfig| Module configuration for the service.| | Reason: null, use for replacement: null| +| monitor| org.apache.dubbo.config.MonitorConfig| Service monitoring configuration.| | Reason: null, use for replacement: null| +| need-refresh| java.lang.Boolean| Specifies if this configuration should be refreshed (true for refreshing).| true| | +| onconnect| java.lang.String| Event handler for connection establishment.| | | +| ondisconnect| java.lang.String| Event handler for disconnection.| | | +| owner| java.lang.String| Owner of the service providers.| | | +| parameters| java.util.Map<java.lang.String,java.lang.String>| Customized parameters for configuration.| | | +| prefixes| java.util.List<java.lang.String>| | | | +| protocol| java.lang.String| Only the service provider of the specified protocol is invoked, and other protocols are ignored.| | | +| provided-by| java.lang.String| declares which app or service this interface belongs to| | | +| provider-namespace| java.lang.String| assign the namespace that provider belong to @since 3.1.1| | | +| provider-port| java.lang.Integer| By VirtualService and DestinationRule, envoy will generate a new route rule,such as 'demo.default.svc.cluster.local:80',the default port is 80. When you want to specify the provider port,you can use this config. @since 3.1.0| | | +| proxy| java.lang.String| Strategy for generating dynamic agents (options: "jdk" or "javassist").| | | +| queues| java.lang.Integer| Consumer threadpool queue size| | | +| reconnect| java.lang.String| | | | +| refer-async| java.lang.Boolean| Weather the reference is referred asynchronously @see ModuleConfig#referAsync @deprecated| | Reason: null, use for replacement: null| +| refer-background| java.lang.Boolean| Whether refer should run in background or not. @see ModuleConfig#setBackground(Boolean) @deprecated replace with {@link ModuleConfig#setBackground(Boolean)}| | Reason: null, use for replacement: null| +| refer-thread-num| java.lang.Integer| Thread num for asynchronous refer pool size| | | +| registries| java.util.List<org.apache.dubbo.config.RegistryConfig>| Registries where the service will be registered (use this or registryIds, not both).| | | +| registry| org.apache.dubbo.config.RegistryConfig| | | | +| registry-ids| java.lang.String| Registry IDs for service registration (use this or registries, not both).| | | +| retries| java.lang.Integer| Retry times for failed invocations.| | | +| router| java.lang.String| | | | +| scope| java.lang.String| Service scope ("local" implies searching in the current JVM only).| | | +| scope-model| org.apache.dubbo.rpc.model.ScopeModel| The scope model of this config instance. <p> <b>NOTE:</b> the model maybe changed during config processing, the extension spi instance needs to be reinitialized after changing the model!| | | +| sent| java.lang.Boolean| Acknowledge asynchronous-sent invocations.| | | +| shareconnections| java.lang.Integer| By default, a TCP long-connection communication is shared between the consumer process and the provider process. This property can be set to share multiple TCP long-connection communications. Note that only the dubbo protocol takes effect.| | | +| singleton| java.lang.Boolean| Use separate instances for services with the same serviceKey (applies when using ReferenceConfig and SimpleReferenceCache together). Directly calling ReferenceConfig.get() will not check this attribute.| | | +| sticky| java.lang.Boolean| | | | +| stub| java.lang.String| Local stub class name for the service interface.| | | +| tag| java.lang.String| Custom tag for the service configuration.| | | +| threadpool| java.lang.String| Consumer thread pool type: cached, fixed, limit, eager| | | +| threads| java.lang.Integer| Consumer threadpool thread size| | | +| timeout| java.lang.Integer| Timeout for remote invocation in milliseconds.| | | +| url-merge-processor| java.lang.String| Url Merge Processor Used to customize the URL merge of consumer and provider| | | +| validation| java.lang.String| Enable JSR303 standard annotation validation for method parameters.| | | +| version| java.lang.String| Version of the remote service referenced by the consumer/provider.| | | +### dubbo.metadata-report +**Class:** `org.apache.dubbo.config.MetadataReportConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| address| java.lang.String| The address of the metadata center.| | | +| check| java.lang.Boolean| Decide the behavior when the initial connection attempt fails, where 'true' means interrupt the whole process once it fails. The default value is true.| | | +| cluster| java.lang.Boolean| Whether to use a cluster configuration for the metadata center.| | | +| cycle-report| java.lang.Boolean| By default, the metadata store will store full metadata repeatedly every day.| | | +| default| java.lang.Boolean| | | | +| file| java.lang.String| The file path for saving the metadata center's dynamic list.| | | +| group| java.lang.String| The group for the metadata center, which is similar to the registry group.| | | +| id| java.lang.String| Identifier for this configuration.| | | +| meta-data| java.util.Map<java.lang.String,java.lang.String>| | | | +| need-refresh| java.lang.Boolean| Specifies if this configuration should be refreshed (true for refreshing).| true| | +| parameters| java.util.Map<java.lang.String,java.lang.String>| Customized parameters for the metadata center.| | | +| password| java.lang.String| The password used to log in to the metadata center.| | | +| port| java.lang.Integer| The default port for the metadata center.| | | +| prefixes| java.util.List<java.lang.String>| | | | +| protocol| java.lang.String| The protocol for the metadata center.| | | +| registry| java.lang.String| The registry ID for the metadata center.| | | +| report-definition| java.lang.Boolean| Whether to report definition.| | | +| report-metadata| java.lang.Boolean| Whether to report metadata.| | | +| retry-period| java.lang.Integer| The retry period in milliseconds when connecting to the metadata center.| | | +| retry-times| java.lang.Integer| The number of retry times when connecting to the metadata center.| | | +| scope-model| org.apache.dubbo.rpc.model.ScopeModel| The scope model of this config instance. <p> <b>NOTE:</b> the model maybe changed during config processing, the extension spi instance needs to be reinitialized after changing the model!| | | +| sync-report| java.lang.Boolean| Synchronization report, with the default value as asynchronous.| | | +| timeout| java.lang.Integer| The request timeout in milliseconds for the metadata center.| | | +| username| java.lang.String| The username used to log in to the metadata center.| | | +### dubbo.metrics +**Class:** `org.apache.dubbo.config.MetricsConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| collector-sync-period| java.lang.Integer| Collector synchronization period.| | | +| default| java.lang.Boolean| | | | +| enable-collector-sync| java.lang.Boolean| Whether to enable collector synchronization.| | | +| enable-jvm| java.lang.Boolean| Whether to enable JVM metrics collection.| | | +| enable-metadata| java.lang.Boolean| Whether to enable metadata metrics collection.| | | +| enable-metrics-init| java.lang.Boolean| Whether to enable metrics initialization.| | | +| enable-netty| java.lang.Boolean| Whether to enable Netty metrics collection.| | | +| enable-registry| java.lang.Boolean| Whether to enable registry metrics collection.| | | +| enable-rpc| java.lang.Boolean| Whether to enable RPC (Remote Procedure Call) metrics collection.| | | +| enable-threadpool| java.lang.Boolean| Whether to enable thread pool metrics collection.| | | +| export-metrics-service| java.lang.Boolean| Whether to export metrics service.| | | +| export-service-port| java.lang.Integer| Port used for exporting metrics services.| | | +| export-service-protocol| java.lang.String| Protocol used for metrics collection and export.| | | +| id| java.lang.String| Identifier for this configuration.| | | +| meta-data| java.util.Map<java.lang.String,java.lang.String>| | | | +| need-refresh| java.lang.Boolean| Specifies if this configuration should be refreshed (true for refreshing).| true| | +| port| java.lang.String| Deprecated: This parameter should no longer be used and will be removed in the future.| | | +| prefixes| java.util.List<java.lang.String>| | | | +| protocol| java.lang.String| Protocol used for metrics.| | | +| rpc-level| java.lang.String| The level of metrics collection, which can be "SERVICE" or "METHOD". The default is "METHOD".| | | +| scope-model| org.apache.dubbo.rpc.model.ScopeModel| The scope model of this config instance. <p> <b>NOTE:</b> the model maybe changed during config processing, the extension spi instance needs to be reinitialized after changing the model!| | | +| use-global-registry| java.lang.Boolean| Decide whether to use the global registry of Micrometer.| | | +### dubbo.module +**Class:** `org.apache.dubbo.config.ModuleConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| background| java.lang.Boolean| Whether to start the module in the background. If started in the background, it does not await finish on Spring ContextRefreshedEvent. @see org.apache.dubbo.config.spring.context.DubboDeployApplicationListener| | | +| check-reference-timeout| java.lang.Long| The timeout to check references.| | | +| default| java.lang.Boolean| | | | +| export-async| java.lang.Boolean| Whether the service is exported asynchronously.| | | +| export-thread-num| java.lang.Integer| The thread number for asynchronous export pool size.| | | +| id| java.lang.String| Identifier for this configuration.| | | +| meta-data| java.util.Map<java.lang.String,java.lang.String>| | | | +| monitor| org.apache.dubbo.config.MonitorConfig| Monitor center| | | +| name| java.lang.String| The module name| | | +| need-refresh| java.lang.Boolean| Specifies if this configuration should be refreshed (true for refreshing).| true| | +| organization| java.lang.String| The module's organization| | | +| owner| java.lang.String| The module owner| | | +| prefixes| java.util.List<java.lang.String>| | | | +| refer-async| java.lang.Boolean| Whether the reference is referred asynchronously.| | | +| refer-thread-num| java.lang.Integer| The thread number for asynchronous reference pool size.| | | +| registries| java.util.List<org.apache.dubbo.config.RegistryConfig>| Registry centers| | | +| registry| org.apache.dubbo.config.RegistryConfig| | | | +| scope-model| org.apache.dubbo.rpc.model.ScopeModel| The scope model of this config instance. <p> <b>NOTE:</b> the model maybe changed during config processing, the extension spi instance needs to be reinitialized after changing the model!| | | +| version| java.lang.String| The module version| | | +### dubbo.monitor +**Class:** `org.apache.dubbo.config.MonitorConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| address| java.lang.String| The monitor address| | | +| default| java.lang.Boolean| | | | +| group| java.lang.String| The monitor group| | | +| id| java.lang.String| Identifier for this configuration.| | | +| interval| java.lang.String| The monitor reporting interval| | | +| meta-data| java.util.Map<java.lang.String,java.lang.String>| | | | +| need-refresh| java.lang.Boolean| Specifies if this configuration should be refreshed (true for refreshing).| true| | +| parameters| java.util.Map<java.lang.String,java.lang.String>| Customized parameters| | | +| password| java.lang.String| The monitor password| | | +| prefixes| java.util.List<java.lang.String>| | | | +| protocol| java.lang.String| The protocol of the monitor. If the value is "registry" it will search the monitor address from the registry center. Otherwise, it will directly connect to the monitor center.| | | +| scope-model| org.apache.dubbo.rpc.model.ScopeModel| The scope model of this config instance. <p> <b>NOTE:</b> the model maybe changed during config processing, the extension spi instance needs to be reinitialized after changing the model!| | | +| username| java.lang.String| The monitor username| | | +| version| java.lang.String| The monitor version| | | +### dubbo.protocol +**Class:** `org.apache.dubbo.config.ProtocolConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| accepts| java.lang.Integer| The maximum acceptable connections.| | | +| accesslog| java.lang.String| The access log configuration.| | | +| alive| java.lang.Integer| The keep-alive time for threads in the thread pool (default unit is TimeUnit.MILLISECONDS).| | | +| buffer| java.lang.Integer| The buffer size.| | | +| charset| java.lang.String| The character set used for communication.| | | +| client| java.lang.String| The client implementation.| | | +| codec| java.lang.String| The protocol codec.| | | +| contextpath| java.lang.String| The context path for the service.| | | +| corethreads| java.lang.Integer| The core thread size of the thread pool.| | | +| default| java.lang.Boolean| | | | +| dispatcher| java.lang.String| The thread dispatch mode.| | | +| dispather| java.lang.String| | | Reason: null, use for replacement: null| +| exchanger| java.lang.String| The method of information exchange.| | | +| ext-protocol| java.lang.String| Extra protocol for this service, using Port Unification Server.| | | +| extension| java.lang.String| Additional extensions.| | | +| heartbeat| java.lang.Integer| The interval for sending heartbeats.| | | +| host| java.lang.String| The service's IP address (useful when there are multiple network cards available).| | | +| id| java.lang.String| Identifier for this configuration.| | | +| iothreads| java.lang.Integer| The fixed size of the IO thread pool.| | | +| json-check-level| java.lang.String| JSON check level for serialization.| | | +| keep-alive| java.lang.Boolean| Indicates whether it is a persistent connection.| | | +| meta-data| java.util.Map<java.lang.String,java.lang.String>| | | | +| name| java.lang.String| The name of the protocol.| | | +| need-refresh| java.lang.Boolean| Specifies if this configuration should be refreshed (true for refreshing).| true| | +| networker| java.lang.String| The networker implementation.| | | +| optimizer| java.lang.String| The optimizer used for dubbo protocol.| | | +| parameters| java.util.Map<java.lang.String,java.lang.String>| Custom parameters.| | | +| path| java.lang.String| | | Reason: null, use for replacement: null| +| payload| java.lang.Integer| The maximum payload length.| | | +| port| java.lang.Integer| The service's port number.| | | +| prefer-serialization| java.lang.String| Specifies the preferred serialization method for the consumer. If specified, the consumer will use this parameter first. If the Dubbo Sdk you are using contains the serialization type, the serialization method specified by the argument is used. <p> When this parameter is null or the serialization type specified by this parameter does not exist in the Dubbo SDK, the serialization type specified by serialization is used. If the Dubbo SDK if still does not exist, the default type of the Dubbo SDK is used. For Dubbo SDK >= 3.2, <code>preferSerialization</code> takes precedence over <code>serialization</code> <p> Supports multiple values separated by commas, e.g., "fastjson2,fastjson,hessian2".| | | +| prefixes| java.util.List<java.lang.String>| | | | +| prompt| java.lang.String| The command line prompt.| | | +| queues| java.lang.Integer| The length of the thread pool's queue.| | | +| register| java.lang.Boolean| Indicates whether the service should be registered.| | | +| scope-model| org.apache.dubbo.rpc.model.ScopeModel| The scope model of this config instance. <p> <b>NOTE:</b> the model maybe changed during config processing, the extension spi instance needs to be reinitialized after changing the model!| | | +| serialization| java.lang.String| The serialization method.| | | +| server| java.lang.String| The server implementation.| | | +| ssl-enabled| java.lang.Boolean| Indicates whether SSL is enabled.| | | +| status| java.lang.String| The status check configuration.| | | +| telnet| java.lang.String| Supported Telnet commands, separated by commas.| | | +| thread-pool-exhausted-listeners| java.lang.String| Listeners for exhausted thread pool.| | | +| threadpool| java.lang.String| The name of the thread pool.| | | +| threads| java.lang.Integer| The fixed size of the thread pool.| | | +| transporter| java.lang.String| The transporter used for communication.| | | +### dubbo.provider +**Class:** `org.apache.dubbo.config.ProviderConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| accepts| java.lang.Integer| The maximum number of acceptable connections.| | | +| accesslog| java.lang.String| Whether to export access logs to logs.| | | +| actives| java.lang.Integer| Maximum concurrent invocations allowed.| | | +| alive| java.lang.Integer| The keep-alive time of the thread pool, default unit: TimeUnit.MILLISECONDS.| | | +| application| org.apache.dubbo.config.ApplicationConfig| Application configuration for the service.| | Reason: null, use for replacement: null| +| async| java.lang.Boolean| Enable asynchronous invocation. Note that it is unreliable asynchronous, ignoring return values and not blocking threads.| | | +| auth| java.lang.Boolean| Enable service authentication.| | | +| buffer| java.lang.Integer| The size of the network I/O buffer.| | | +| cache| java.lang.String| Cache provider for caching return results. available options: lru, threadlocal, jcache etc.| | | +| callbacks| java.lang.Integer| Callback limits for the service.| | | +| charset| java.lang.String| The charset used for serialization.| | | +| client| java.lang.String| The client-side implementation model of the protocol.| | | +| cluster| java.lang.String| Cluster type for service.| | | +| codec| java.lang.String| The codec used by the protocol.| | | +| config-center| org.apache.dubbo.config.ConfigCenterConfig| Configuration center settings.| | Reason: null, use for replacement: null| +| connections| java.lang.Integer| Connection limits: 0 for shared connection, otherwise specifying connections for the service.| | | +| contextpath| java.lang.String| The context path of the service.| | | +| default| java.lang.Boolean| | | | +| delay| java.lang.Integer| The time delay to register the service (in milliseconds).| | | +| deprecated| java.lang.Boolean| Whether the service is deprecated.| | | +| dispatcher| java.lang.String| The mode of thread dispatching.| | | +| dispather| java.lang.String| | | Reason: null, use for replacement: null| +| document| java.lang.String| Document center for the service.| | | +| dynamic| java.lang.Boolean| Whether to register the service as a dynamic service on the registry. If true, the service will be enabled automatically after registration, and manual disabling is required to stop it.| | | +| exchanger| java.lang.String| The method of information exchange.| | | +| executes| java.lang.Integer| Max allowed executing times.| | | +| executor| java.util.concurrent.Executor| used for thread pool isolation between services| | | +| export| java.lang.Boolean| Whether to export the service.| | | +| export-async| java.lang.Boolean| Weather the service is export asynchronously @deprecated @see ModuleConfig#exportAsync| | Reason: null, use for replacement: null| +| export-background| java.lang.Boolean| Whether the export should run in the background or not. @deprecated Replace with {@link ModuleConfig#setBackground(Boolean)} @see ModuleConfig#setBackground(Boolean)| | Reason: null, use for replacement: null| +| export-thread-num| java.lang.Integer| The number of threads for the asynchronous export pool.| | Reason: null, use for replacement: null| +| exported-urls| java.util.List<org.apache.dubbo.common.URL>| | | | +| filter| java.lang.String| Filters for service exposure or reference (multiple filters can be separated by commas).| | | +| forks| java.lang.Integer| Forks for forking cluster.| | | +| group| java.lang.String| The service group.| | | +| host| java.lang.String| The IP addresses of the service (used when there are multiple network cards available).| | | +| id| java.lang.String| Identifier for this configuration.| | | +| interface| java.lang.String| | | | +| iothreads| java.lang.Integer| The size of the I/O thread pool (fixed size).| | | +| layer| java.lang.String| Layer of service providers.| | | +| listener| java.lang.String| Listeners for service exposure or reference (multiple listeners can be separated by commas).| | | +| loadbalance| java.lang.String| Load balancing strategy for service invocation.| | | +| local| java.lang.String| Local implementation class name for the service interface.| | Reason: null, use for replacement: null| +| merger| java.lang.String| Merger for result data.| | | +| meta-data| java.util.Map<java.lang.String,java.lang.String>| | | | +| metadata-report-config| org.apache.dubbo.config.MetadataReportConfig| Metadata report configuration.| | Reason: null, use for replacement: null| +| methods| java.util.List<org.apache.dubbo.config.MethodConfig>| Method-specific configuration.| | | +| mock| java.lang.String| Mock class name to be called when a service fails to execute. The mock doesn't support on the provider side, and it is executed when a non-business exception occurs after a remote service call.| | | +| module| org.apache.dubbo.config.ModuleConfig| Module configuration for the service.| | Reason: null, use for replacement: null| +| monitor| org.apache.dubbo.config.MonitorConfig| Service monitoring configuration.| | Reason: null, use for replacement: null| +| need-refresh| java.lang.Boolean| Specifies if this configuration should be refreshed (true for refreshing).| true| | +| networker| java.lang.String| The networker used by the protocol.| | | +| onconnect| java.lang.String| Event handler for connection establishment.| | | +| ondisconnect| java.lang.String| Event handler for disconnection.| | | +| owner| java.lang.String| Owner of the service providers.| | | +| parameters| java.util.Map<java.lang.String,java.lang.String>| Customized parameters for configuration.| | | +| path| java.lang.String| | | Reason: null, use for replacement: null| +| payload| java.lang.Integer| The maximum payload length.| | | +| port| java.lang.Integer| The port of the service.| | Reason: null, use for replacement: null| +| prefer-serialization| java.lang.String| Specifies the preferred serialization method for the consumer. If specified, the consumer will use this parameter first. If the Dubbo Sdk you are using contains the serialization type, the serialization method specified by the argument is used. <p> When this parameter is null or the serialization type specified by this parameter does not exist in the Dubbo SDK, the serialization type specified by serialization is used. If the Dubbo SDK if still does not exist, the default type of the Dubbo SDK is used. For Dubbo SDK >= 3.2, <code>preferSerialization</code> takes precedence over <code>serialization</code> <p> Supports multiple values separated by commas, e.g., "fastjson2,fastjson,hessian2".| | | +| prefixes| java.util.List<java.lang.String>| | | | +| prompt| java.lang.String| The command line prompt.| | | +| protocol| org.apache.dubbo.config.ProtocolConfig| | | | +| protocol-ids| java.lang.String| Id list of protocols the service will export with (use this or protocols, not both).| | | +| protocols| java.util.List<org.apache.dubbo.config.ProtocolConfig>| List of protocols the service will export with (use this or protocolIds, not both).| | | +| proxy| java.lang.String| Strategy for generating dynamic agents (options: "jdk" or "javassist").| | | +| queues| java.lang.Integer| The length of the thread pool queue.| | | +| register| java.lang.Boolean| Whether to register the service.| | | +| registries| java.util.List<org.apache.dubbo.config.RegistryConfig>| Registries where the service will be registered (use this or registryIds, not both).| | | +| registry| org.apache.dubbo.config.RegistryConfig| | | | +| registry-ids| java.lang.String| Registry IDs for service registration (use this or registries, not both).| | | +| retries| java.lang.Integer| Retry times for failed invocations.| | | +| scope| java.lang.String| Service scope ("local" implies searching in the current JVM only).| | | +| scope-model| org.apache.dubbo.rpc.model.ScopeModel| The scope model of this config instance. <p> <b>NOTE:</b> the model maybe changed during config processing, the extension spi instance needs to be reinitialized after changing the model!| | | +| sent| java.lang.Boolean| Acknowledge asynchronous-sent invocations.| | | +| serialization| java.lang.String| Serialization type for service communication.| | | +| server| java.lang.String| The server-side implementation model of the protocol.| | | +| singleton| java.lang.Boolean| Use separate instances for services with the same serviceKey (applies when using ReferenceConfig and SimpleReferenceCache together). Directly calling ReferenceConfig.get() will not check this attribute.| | | +| status| java.lang.String| The status check configuration.| | | +| stub| java.lang.String| Local stub class name for the service interface.| | | +| tag| java.lang.String| Custom tag for the service configuration.| | | +| telnet| java.lang.String| Supported telnet commands, separated by commas.| | | +| threadname| java.lang.String| The name of the thread pool.| | | +| threadpool| java.lang.String| The thread pool configuration.| | | +| threads| java.lang.Integer| The size of the thread pool (fixed size).| | | +| timeout| java.lang.Integer| Timeout for remote invocation in milliseconds.| | | +| token| java.lang.String| Whether to use a token for authentication.| | | +| transporter| java.lang.String| The transporter used by the protocol.| | | +| use-java-package-as-path| java.lang.Boolean| Whether to use java_package in IDL as path. Default use package. This param only available when service using native stub.| | | +| validation| java.lang.String| Enable JSR303 standard annotation validation for method parameters.| | | +| version| java.lang.String| The service version.| | | +| wait| java.lang.Integer| The wait time when stopping the service.| | | +| warmup| java.lang.Integer| Warm-up period for the service.| | | +| weight| java.lang.Integer| The service weight.| | | +### dubbo.registry +**Class:** `org.apache.dubbo.config.RegistryConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| accepts| java.lang.String| List of RPC protocols accepted by this registry, e.g., "dubbo,rest".| | | +| address| java.lang.String| Register center address.| | | +| check| java.lang.Boolean| Whether to check if the register center is available when booting up.| | | +| client| java.lang.String| Client implementation.| | | +| cluster| java.lang.String| Affects how traffic distributes among registries, useful when subscribing to multiple registries. Available options: - "zone-aware": A certain type of traffic always goes to one Registry according to where the traffic is originated.| | | +| default| java.lang.Boolean| | | | +| dynamic| java.lang.Boolean| Whether to allow dynamic service registration on the register center.| | | +| enable-empty-protection| java.lang.Boolean| Enable empty protection.| | | +| extra-keys| java.lang.String| After simplifying the registry, add some parameters individually, useful for providers. Example: extra-keys = "A, b, c, d". @since 2.7.0| | | +| file| java.lang.String| File for saving the register center dynamic list.| | | +| group| java.lang.String| The group that services registry belongs to.| | | +| id| java.lang.String| Identifier for this configuration.| | | +| meta-data| java.util.Map<java.lang.String,java.lang.String>| | | | +| need-refresh| java.lang.Boolean| Specifies if this configuration should be refreshed (true for refreshing).| true| | +| parameters| java.util.Map<java.lang.String,java.lang.String>| Customized parameters.| | | +| password| java.lang.String| Password to login the register center.| | | +| port| java.lang.Integer| Default port for the register center.| | | +| preferred| java.lang.Boolean| Always use this registry first if set to true, useful when subscribing to multiple registries.| | | +| prefixes| java.util.List<java.lang.String>| | | | +| protocol| java.lang.String| Protocol used for the register center.| | | +| register| java.lang.Boolean| Whether to allow exporting service on the register center.| | | +| register-mode| java.lang.String| Register mode.| | | +| scope-model| org.apache.dubbo.rpc.model.ScopeModel| The scope model of this config instance. <p> <b>NOTE:</b> the model maybe changed during config processing, the extension spi instance needs to be reinitialized after changing the model!| | | +| secure| java.lang.String| Security settings.| | | +| server| java.lang.String| Server implementation.| | | +| session| java.lang.Integer| Session timeout in milliseconds for the register center.| | | +| simplified| java.lang.Boolean| Simplify the registry, useful for both providers and consumers. @since 2.7.0| | | +| subscribe| java.lang.Boolean| Whether to allow subscribing to services on the register center.| | | +| timeout| java.lang.Integer| Connect timeout in milliseconds for the register center.| | | +| transport| java.lang.String| | | Reason: null, use for replacement: null| +| transporter| java.lang.String| Network transmission type.| | | +| use-as-config-center| java.lang.Boolean| Indicates whether the address works as a configuration center or not.| | | +| use-as-metadata-center| java.lang.Boolean| Indicates whether the address works as a remote metadata center or not.| | | +| username| java.lang.String| Username to login the register center.| | | +| version| java.lang.String| Version of the registry.| | | +| wait| java.lang.Integer| Wait time before stopping.| | Reason: null, use for replacement: null| +| weight| java.lang.Integer| Affects traffic distribution among registries, useful when subscribing to multiple registries. Takes effect only when no preferred registry is specified.| | | +| zone| java.lang.String| The region where the registry belongs, usually used to isolate traffics.| | | +### dubbo.rpc +**Class:** `org.apache.dubbo.spring.boot.autoconfigure.DubboConfigurationProperties$RpcConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +### dubbo.ssl +**Class:** `org.apache.dubbo.config.SslConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| ca-address| java.lang.String| Address for Certificate Authority (CA).| | | +| ca-cert-path| java.lang.String| Path to the CA certificate file.| | | +| client-key-cert-chain-path| java.lang.String| Path to the client's key certificate chain file.| | | +| client-key-cert-chain-path-stream| java.io.InputStream| Input stream for the client's key certificate chain (if provided).| | | +| client-key-password| java.lang.String| Password for the client's private key (if applicable).| | | +| client-private-key-path| java.lang.String| Path to the client's private key file.| | | +| client-private-key-path-stream| java.io.InputStream| Input stream for the client's private key (if provided).| | | +| client-trust-cert-collection-path| java.lang.String| Path to the client's trust certificate collection file.| | | +| client-trust-cert-collection-path-stream| java.io.InputStream| Input stream for the client's trust certificate collection (if provided).| | | +| default| java.lang.Boolean| | | | +| env-type| java.lang.String| Environment type for SSL configuration.| | | +| id| java.lang.String| Identifier for this configuration.| | | +| meta-data| java.util.Map<java.lang.String,java.lang.String>| | | | +| need-refresh| java.lang.Boolean| Specifies if this configuration should be refreshed (true for refreshing).| true| | +| oidc-token-path| java.lang.String| Path to the OIDC (OpenID Connect) token file.| | | +| prefixes| java.util.List<java.lang.String>| | | | +| scope-model| org.apache.dubbo.rpc.model.ScopeModel| The scope model of this config instance. <p> <b>NOTE:</b> the model maybe changed during config processing, the extension spi instance needs to be reinitialized after changing the model!| | | +| server-key-cert-chain-path| java.lang.String| Path to the server's key certificate chain file.| | | +| server-key-cert-chain-path-stream| java.io.InputStream| Input stream for the server's key certificate chain (if provided).| | | +| server-key-password| java.lang.String| Password for the server's private key (if applicable).| | | +| server-private-key-path| java.lang.String| Path to the server's private key file.| | | +| server-private-key-path-stream| java.io.InputStream| Input stream for the server's private key (if provided).| | | +| server-trust-cert-collection-path| java.lang.String| Path to the server's trust certificate collection file.| | | +| server-trust-cert-collection-path-stream| java.io.InputStream| Input stream for the server's trust certificate collection (if provided).| | | +### dubbo.tracing +**Class:** `org.apache.dubbo.config.TracingConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| default| java.lang.Boolean| | | | +| enabled| java.lang.Boolean| Indicates whether the feature is enabled (default is false).| false| | +| id| java.lang.String| Identifier for this configuration.| | | +| meta-data| java.util.Map<java.lang.String,java.lang.String>| | | | +| need-refresh| java.lang.Boolean| Specifies if this configuration should be refreshed (true for refreshing).| true| | +| prefixes| java.util.List<java.lang.String>| | | | +| scope-model| org.apache.dubbo.rpc.model.ScopeModel| The scope model of this config instance. <p> <b>NOTE:</b> the model maybe changed during config processing, the extension spi instance needs to be reinitialized after changing the model!| | | +### dubbo.metrics.aggregation +**Class:** `org.apache.dubbo.config.nested.AggregationConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| bucket-num| java.lang.Integer| The number of buckets for time window quantile.| | | +| enable-qps| java.lang.Boolean| Enable QPS (Queries Per Second) aggregation or not.| | | +| enable-request| java.lang.Boolean| Enable Request aggregation or not.| | | +| enable-rt| java.lang.Boolean| Enable Response Time aggregation or not.| | | +| enable-rt-pxx| java.lang.Boolean| Enable Response Time Percentile (Pxx) aggregation or not.| | | +| enabled| java.lang.Boolean| Enable aggregation or not.| | | +| qps-time-window-mill-seconds| java.lang.Integer| The time window in milliseconds for QPS (Queries Per Second) aggregation.| | | +| time-window-seconds| java.lang.Integer| The time window in seconds for time window quantile.| | | +### dubbo.metrics.histogram +**Class:** `org.apache.dubbo.config.nested.HistogramConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| +| buckets-ms| java.lang.Integer[]| Buckets in milliseconds for the histograms. Defines the histogram bucket boundaries.| | | +| distribution-statistic-expiry-min| java.lang.Integer| Expiry time in minutes for distribution statistics. After this time, the statistics are expired.| | | +| enabled| java.lang.Boolean| Whether histograms are enabled or not. Default is not enabled (false).| | | +| enabled-percentiles| java.lang.Boolean| Whether enabledPercentiles are enabled or not. Default is not enabled (false).| | | +| max-expected-ms| java.lang.Integer| Maximum expected value in milliseconds for the histograms. Values higher than this will be considered outliers.| | | +| min-expected-ms| java.lang.Integer| Minimum expected value in milliseconds for the histograms. Values lower than this will be considered outliers.| | | +| percentiles| java.lang.Double[]| Array of percentiles to be calculated for the histograms. Each percentile is a double value.| | | +### dubbo.metrics.prometheus +**Class:** `org.apache.dubbo.config.nested.PrometheusConfig` + +|Key|Type|Description|Default value|Deprecation| +|---|----|-----------|-------------|-----------| + + +### method + +方法级配置。 + +> 对应的配置类: `org.apache.dubbo.config.MethodConfig`。同时该标签为 `service` 或 `reference` 的子标签,用于控制到方法级。 + +比如: + +```xml + + + +``` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| name | | string | 必填 | | 标识 | 方法名 | 1.0.8以上版本 | +| timeout | <methodName>.timeout | int | 可选 | 缺省为的timeout | 性能调优 | 方法调用超时时间(毫秒) | 1.0.8以上版本 | +| retries | <methodName>.retries | int | 可选 | 缺省为<dubbo:reference>的retries | 性能调优 | 远程服务调用重试次数,不包括第一次调用,不需要重试请设为0 | 2.0.0以上版本 | +| loadbalance | <methodName>.loadbalance | string | 可选 | 缺省为的loadbalance | 性能调优 | 负载均衡策略,可选值:

* random - 随机;

* roundrobin - 轮询;

* leastactive - 最少活跃调用;

* consistenthash - 哈希一致 (2.1.0以上版本);

* shortestresponse - 最短响应 (2.7.7以上版本); | 2.0.0以上版本 | +| async | <methodName>.async | boolean | 可选 | 缺省为<dubbo:reference>的async | 性能调优 | 是否异步执行,不可靠异步,只是忽略返回值,不阻塞执行线程 | 1.0.9以上版本 | +| sent | <methodName>.sent | boolean | 可选 | true | 性能调优 | 异步调用时,标记sent=true时,表示网络已发出数据 | 2.0.6以上版本 | +| actives | <methodName>.actives | int | 可选 | 0 | 性能调优 | 每服务消费者最大并发调用限制 | 2.0.5以上版本 | +| executes | <methodName>.executes | int | 可选 | 0 | 性能调优 | 每服务每方法最大使用线程数限制- -,此属性只在<dubbo:method>作为<dubbo:service>子标签时有效 | 2.0.5以上版本 | +| deprecated | <methodName>.deprecated | boolean | 可选 | false | 服务治理 | 服务方法是否过时,此属性只在<dubbo:method>作为<dubbo:service>子标签时有效 | 2.0.5以上版本 | +| sticky | <methodName>.sticky | boolean | 可选 | false | 服务治理 | 设置true 该接口上的所有方法使用同一个provider.如果需要更复杂的规则,请使用路由 | 2.0.6以上版本 | +| return | <methodName>.return | boolean | 可选 | true | 性能调优 | 方法调用是否需要返回值,async设置为true时才生效,如果设置为true,则返回future,或回调onreturn等方法,如果设置为false,则请求发送成功后直接返回Null | 2.0.6以上版本 | +| oninvoke | attribute属性,不在URL中体现 | String | 可选 | | 性能调优 | 实例执行前拦截 | 2.0.6以上版本 | +| onreturn | attribute属性,不在URL中体现 | String | 可选 | | 性能调优 | 实例执行返回后拦截 | 2.0.6以上版本 | +| onthrow | attribute属性,不在URL中体现 | String | 可选 | | 性能调优 | 实例执行有异常拦截 | 2.0.6以上版本 | +| oninvokeMethod | attribute属性,不在URL中体现 | String | 可选 | | 性能调优 | 方法执行前拦截 | 2.0.6以上版本 | +| onreturnMethod | attribute属性,不在URL中体现 | String | 可选 | | 性能调优 | 方法执行返回后拦截 | 2.0.6以上版本 | +| onthrowMethod | attribute属性,不在URL中体现 | String | 可选 | | 性能调优 | 方法执行有异常拦截 | 2.0.6以上版本 | +| cache | <methodName>.cache | string/boolean | 可选 | | 服务治理 | 以调用参数为key,缓存返回结果,可选:lru, threadlocal, jcache等 | 2.1.0以上版本 | +| validation | <methodName>.validation | boolean | 可选 | | 服务治理 | 是否启用JSR303标准注解验证,如果启用,将对方法参数上的注解进行校验 | 2.1.0以上版本 | + +### argument + +方法参数配置。 + +> 对应的配置类: `org.apache.dubbo.config.ArgumentConfig`。该标签为 `method` 的子标签,用于方法参数的特征描述,比如 XML 格式: + +```xml + + + +``` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| index | | int | 必填 | | 标识 | 参数索引 | 2.0.6以上版本 | +| type | | String | 与index二选一 | | 标识 | 通过参数类型查找参数的index | 2.0.6以上版本 | +| callback | <metodName><index>.callback | boolean | 可选 | | 服务治理 | 参数是否为callback接口,如果为callback,服务提供方将生成反向代理,可以从服务提供方反向调用消费方,通常用于事件推送. | 2.0.6以上版本 | + +### parameter + +选项参数配置。 + +> 对应的配置类:`java.util.Map`。同时该标签为 `protocol` 或 `service` 或 `provider` 或 `reference` 或 `consumer` 或 `monitor` 或 `registry` 或 `metadata-config` 或 `config-center` 的子标签,用于配置自定义参数,该配置项将作为扩展点设置自定义参数使用。 + +比如: + +```xml + + + +``` + +或: + +```xml + +``` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| key | key | string | 必填 | | 服务治理 | 路由参数键 | 2.0.0以上版本 | +| value | value | string | 必填 | | 服务治理 | 路由参数值 | 2.0.0以上版本 | + + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/properties3.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/config/properties3.md.bak new file mode 100644 index 000000000000..dffc97376eb1 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/properties3.md.bak @@ -0,0 +1,578 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config/properties/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config/properties/ +description: 包含 Dubbo 支持的所有配置组件及每个配置组件支持的所有配置项 +linkTitle: 配置项手册 +title: 配置项参考手册 +type: docs +weight: 6 +--- + + +## JVM(-D) 参数 + +## 环境变量 + +## 配置项手册 +### application + +每个应用必须要有且只有一个 application 配置 + +> 对应的配置类:`org.apache.dubbo.config.ApplicationConfig` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| name | application | string | 必填 | | 服务治理 | 当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样,此参数不是匹配条件,你当前项目叫什么名字就填什么,和提供者消费者角色无关,比如:kylin应用调用了morgan应用的服务,则kylin项目配成kylin,morgan项目配成morgan,可能kylin也提供其它服务给别人使用,但kylin项目永远配成kylin,这样注册中心将显示kylin依赖于morgan | 2.7.0以上版本 | +| compiler | compiler | string | 可选 | javassist | 性能优化 | Java字节码编译器,用于动态类的生成,可选:jdk或javassist | 2.7.0以上版本 | +| logger | logger | string | 可选 | slf4j | 性能优化 | 日志输出方式,可选:slf4j,jcl,log4j,log4j2,jdk | 2.7.0以上版本 | +| owner | owner | string | 可选 | | 服务治理 | 应用负责人,用于服务治理,请填写负责人公司邮箱前缀 | 2.0.5以上版本 | +| organization | organization | string | 可选 | | 服务治理 | 组织名称(BU或部门),用于注册中心区分服务来源,此配置项建议不要使用autoconfig,直接写死在配置中,比如china,intl,itu,crm,asc,dw,aliexpress等 | 2.0.0以上版本 | +| architecture
| architecture
| string | 可选 | | 服务治理 | 用于服务分层对应的架构。如,intl、china。不同的架构使用不同的分层。 | 2.0.7以上版本 | +| environment | environment | string | 可选 | | 服务治理 | 应用环境,如:develop/test/product,不同环境使用不同的缺省值,以及作为只用于开发测试功能的限制条件 | 2.0.0以上版本 | +| version | application.version | string | 可选 | | 服务治理 | 当前应用的版本 | 2.7.0以上版本 | +| dumpDirectory | dump.directory | string | 可选 | | 服务治理 | 当进程出问题如线程池满时,框架自动dump文件的存储路径 | 2.7.0以上版本 | +| qosEnable | qos.enable | boolean | 可选 | | 服务治理 | 是否启用 qos 运维端口 | 2.7.0以上版本 | +| qosHost | qos.host | string | 可选 | | 服务治理 | 监听的网络接口地址,默认 0.0.0.0 | 2.7.3以上版本 | +| qosPort | qos.port | int | 可选 | | 服务治理 | 监听的网络端口 | 2.7.0以上版本 | +| qosAcceptForeignIp | qos.accept.foreign.ip | boolean | 可选 | | 服务治理 | 安全配置,是否接收除localhost本机访问之外的外部请求 | 2.7.0以上版本 | +| shutwait | dubbo.service.shutdown.wait | string | 可选 | | 服务治理 | 优雅停机时 shutdown 的等待时间(ms) | 2.7.0以上版本 | +| hostname | | string | 可选 | 本机主机名 | 服务治理 | 主机名 | 2.7.5以上版本 | +| registerConsumer | registerConsumer | boolean | 可选 | true | 服务治理 | 是否注册实例到注册中心。当时实例为纯消费者时才设置为`false` | 2.7.5以上版本 | +| repository | application.version | string | 可选 | | 服务治理 | 当前应用的版本 | 2.7.6以上版本 | +| enableFileCache | file.cache | boolean | 可选 | true | 服务治理 | 是否开启本地缓存 | 3.0.0以上版本 | +| protocol | | string | 可选 | dubbo | 服务治理 | 首选协议,适用于无法确定首选协议的时候 | 3.0.0以上版本 | +| metadataType | metadata-type |String| 可选 | local | 服务治理 | 应用级服务发现 metadata 传递方式,是以 Provider 视角而言的,Consumer 侧配置无效,可选值有:
* remote - Provider 把 metadata 放到远端注册中心,Consumer 从注册中心获取;
* local - Provider 把 metadata 放在本地,Consumer 从 Provider 处直接获取;| 2.7.5以上版本 | +| metadataServiceProtocol | metadata-service-protocol | string | 可选 | dubbo | 服务治理 | 如 metadataType 配置为 local,则该属性设置 MetadataService 服务所用的通信协议,默认为 dubbo| 3.0.0以上版本 | +| metadataServicePort | metadata-service-port | int | 可选 | | 服务治理 | 如 metadataType 配置为 local,则该属性设置 MetadataService 服务所用的端口号| 2.7.9以上版本 | +| livenessProbe | liveness-probe | string | 可选 | | 服务治理 | 概念和格式对应 k8s 体系 liveness probe | 3.0.0以上版本 | +| readinessProbe | readiness-probe | string | 可选 | | 服务治理 | 概念和格式对应 k8s 体系 readiness probe | 3.0.0以上版本 | +| startupProbe | startup-probe | string | 可选 | | 服务治理 | 概念和格式对应 k8s 体系 startup probe | 3.0.0以上版本 | +| registerMode | register-mode | string | 可选 | all | 服务治理 | 控制地址注册行为,应用级服务发现迁移用。
* instance 只注册应用级地址;
* interface 只注册接口级地址;
* all(默认) 同时注册应用级和接口级地址; | 3.0.0以上版本 | +| enableEmptyProtection | enable-empty-protection | boolean | 可选 | true | 服务治理 | 是否全局启用消费端的空地址列表保护,开启后注册中心的空地址推送将被忽略,默认 true | 3.0.0以上版本 | +| parameters | 无 | Map | 可选 | | 服务治理 | 扩展预留,可扩展定义任意参数,所有扩展参数都将原样反映在 URL 配置上 | 2.7.0以上版本 | + + +### service + +服务提供者暴露服务配置。 + +> 对应的配置类:`org.apache.dubbo.config.ServiceConfig` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| interface | | class | 必填 | | 服务发现 | 服务接口名 | 1.0.0以上版本 | +| ref | | object | 必填 | | 服务发现 | 服务对象实现引用 | 1.0.0以上版本 | +| version | version | string | 可选 | 0.0.0 | 服务发现 | 服务版本,建议使用两位数字版本,如:1.0,通常在接口不兼容时版本号才需要升级 | 1.0.0以上版本 | +| group | group | string | 可选 | | 服务发现 | 服务分组,当一个接口有多个实现,可以用分组区分 | 1.0.7以上版本 | +| path | <path> | string | 可选 | 缺省为接口名 | 服务发现 | 服务路径 (注意:1.0不支持自定义路径,总是使用接口名,如果有1.0调2.0,配置服务路径可能不兼容) | 1.0.12以上版本 | +| delay | delay | int | 可选 | 0 | 性能调优 | 延迟注册服务时间(毫秒) ,设为-1时,表示延迟到Spring容器初始化完成时暴露服务 | 1.0.14以上版本 | +| timeout | timeout | int | 可选 | 1000 | 性能调优 | 远程服务调用超时时间(毫秒) | 2.0.0以上版本 | +| retries | retries | int | 可选 | 2 | 性能调优 | 远程服务调用重试次数,不包括第一次调用,不需要重试请设为0 | 2.0.0以上版本 | +| connections | connections | int | 可选 | 100 | 性能调优 | 对每个提供者的最大连接数,rmi、http、hessian等短连接协议表示限制连接数,dubbo等长连接协表示建立的长连接个数 | 2.0.0以上版本 | +| loadbalance | loadbalance | string | 可选 | random | 性能调优 | 负载均衡策略,可选值:
* random - 随机;
* roundrobin - 轮询;
* leastactive - 最少活跃调用;
* consistenthash - 哈希一致 (2.1.0以上版本);
* shortestresponse - 最短响应 (2.7.7以上版本);| 2.0.0以上版本 | +| async | async | boolean | 可选 | false | 性能调优 | 是否缺省异步执行,不可靠异步,只是忽略返回值,不阻塞执行线程 | 2.0.0以上版本 | +| local | local | class/boolean | 可选 | false | 服务治理 | 设为true,表示使用缺省代理类名,即:接口名 + Local后缀,已废弃,请使用stub| 2.0.0以上版本 | +| stub | stub | class/boolean | 可选 | false | 服务治理 | 设为true,表示使用缺省代理类名,即:接口名 + Stub后缀,服务接口客户端本地代理类名,用于在客户端执行本地逻辑,如本地缓存等,该本地代理类的构造函数必须允许传入远程代理对象,构造函数如:public XxxServiceStub(XxxService xxxService) | 2.0.0以上版本 | +| mock | mock | class/boolean | 可选 | false | 服务治理 | 设为true,表示使用缺省Mock类名,即:接口名 + Mock后缀,服务接口调用失败Mock实现类,该Mock类必须有一个无参构造函数,与Local的区别在于,Local总是被执行,而Mock只在出现非业务异常(比如超时,网络异常等)时执行,Local在远程调用之前执行,Mock在远程调用后执行。 | 2.0.0以上版本 | +| token | token | string/boolean | 可选 | | 服务治理 | 令牌验证,为空表示不开启,如果为true,表示随机生成动态令牌,否则使用静态令牌,令牌的作用是防止消费者绕过注册中心直接访问,保证注册中心的授权功能有效,如果使用点对点调用,需关闭令牌功能 | 2.0.0以上版本 | +| registry | | string | 可选 | 缺省向所有registry注册 | 配置关联 | 向指定注册中心注册,在多个注册中心时使用,值为<dubbo:registry>的id属性,多个注册中心ID用逗号分隔,如果不想将该服务注册到任何registry,可将值设为N/A | 2.0.0以上版本 | +| provider | | string | 可选 | 缺省使用第一个provider配置 | 配置关联 | 指定provider,值为<dubbo:provider>的id属性 | 2.0.0以上版本 | +| deprecated | deprecated | boolean | 可选 | false | 服务治理 | 服务是否过时,如果设为true,消费方引用时将打印服务过时警告error日志 | 2.0.5以上版本 | +| dynamic | dynamic | boolean | 可选 | true | 服务治理 | 服务是否动态注册,如果设为false,注册后将显示后disable状态,需人工启用,并且服务提供者停止时,也不会自动取消册,需人工禁用。 | 2.0.5以上版本 | +| accesslog | accesslog | string/boolean | 可选 | false | 服务治理 | 设为true,将向logger中输出访问日志,也可填写访问日志文件路径,直接把访问日志输出到指定文件 | 2.0.5以上版本 | +| owner | owner | string | 可选 | | 服务治理 | 服务负责人,用于服务治理,请填写负责人公司邮箱前缀 | 2.0.5以上版本 | +| document | document | string | 可选 | | 服务治理 | 服务文档URL | 2.0.5以上版本 | +| weight | weight | int | 可选 | | 性能调优 | 服务权重 | 2.0.5以上版本 | +| executes | executes | int | 可选 | 0 | 性能调优 | 服务提供者每服务每方法最大可并行执行请求数 | 2.0.5以上版本 | +| actives | actives | int | 可选 | 0 | 性能调优 | 每服务消费者每服务每方法最大并发调用数 | 2.0.5以上版本 | +| proxy | proxy | string | 可选 | javassist | 性能调优 | 生成动态代理方式,可选:jdk/javassist | 2.0.5以上版本 | +| cluster | cluster | string | 可选 | failover | 性能调优 | 集群方式,可选:failover/failfast/failsafe/failback/forking/available/mergeable(2.1.0以上版本)/broadcast(2.1.0以上版本)/zone-aware(2.7.5以上版本) | 2.0.5以上版本 | +| filter | service.filter | string | 可选 | default | 性能调优 | 服务提供方远程调用过程拦截器名称,多个名称用逗号分隔 | 2.0.5以上版本 | +| listener | exporter.listener | string | 可选 | default | 性能调优 | 服务提供方导出服务监听器名称,多个名称用逗号分隔 | | +| protocol | | string | 可选 | | 配置关联 | 使用指定的协议暴露服务,在多协议时使用,值为<dubbo:protocol>的id属性,多个协议ID用逗号分隔 | 2.0.5以上版本 | +| layer | layer | string | 可选 | | 服务治理 | 服务提供者所在的分层。如:biz、dao、intl:web、china:acton。 | 2.0.7以上版本 | +| register | register | boolean | 可选 | true | 服务治理 | 该协议的服务是否注册到注册中心 | 2.0.8以上版本 | +| validation | validation | string | 可选 | | 服务治理 | 是否启用JSR303标准注解验证,如果启用,将对方法参数上的注解进行校验 | 2.7.0以上版本 | +| parameters | 无 | Map | 可选 | | 服务治理 | 扩展预留,可扩展定义任意参数,所有扩展参数都将原样反映在 URL 配置上 | 2.0.0以上版本 | + +### reference + + +服务消费者引用服务配置。 + +> 对应的配置类: `org.apache.dubbo.config.ReferenceConfig` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| id | | string | 必填 | | 配置关联 | 服务引用BeanId | 1.0.0以上版本 | +| interface | | class | 必填 | | 服务发现 | 服务接口名 | 1.0.0以上版本 | +| version | version | string | 可选 | | 服务发现 | 服务版本,与服务提供者的版本一致 | 1.0.0以上版本 | +| group | group | string | 可选 | | 服务发现 | 服务分组,当一个接口有多个实现,可以用分组区分,必需和服务提供方一致 | 1.0.7以上版本 | +| timeout | timeout | long | 可选 | 缺省使用<dubbo:consumer>的timeout | 性能调优 | 服务方法调用超时时间(毫秒) | 1.0.5以上版本 | +| retries | retries | int | 可选 | 缺省使用<dubbo:consumer>的retries | 性能调优 | 远程服务调用重试次数,不包括第一次调用,不需要重试请设为0 | 2.0.0以上版本 | +| connections | connections | int | 可选 | 缺省使用<dubbo:consumer>的connections | 性能调优 | 对每个提供者的最大连接数,rmi、http、hessian等短连接协议表示限制连接数,dubbo等长连接协表示建立的长连接个数 | 2.0.0以上版本 | +| loadbalance | loadbalance | string | 可选 | 缺省使用<dubbo:consumer>的loadbalance | 性能调优 | 负载均衡策略,可选值:
* random - 随机;
* roundrobin - 轮询;
* leastactive - 最少活跃调用;
* consistenthash - 哈希一致 (2.1.0以上版本);
* shortestresponse - 最短响应 (2.7.7以上版本); | 2.0.0以上版本 | +| async | async | boolean | 可选 | 缺省使用<dubbo:consumer>的async | 性能调优 | 是否异步执行,不可靠异步,只是忽略返回值,不阻塞执行线程 | 2.0.0以上版本 | +| generic | generic | boolean | 可选 | 缺省使用<dubbo:consumer>的generic | 服务治理 | 是否缺省泛化接口,如果为泛化接口,将返回GenericService | 2.0.0以上版本 | +| check | check | boolean | 可选 | 缺省使用<dubbo:consumer>的check | 服务治理 | 启动时检查提供者是否存在,true报错,false忽略 | 2.0.0以上版本 | +| url | url | string | 可选 | | 服务治理 | 点对点直连服务提供者地址,将绕过注册中心 | 1.0.6以上版本 | +| stub | stub | class/boolean | 可选 | | 服务治理 | 服务接口客户端本地代理类名,用于在客户端执行本地逻辑,如本地缓存等,该本地代理类的构造函数必须允许传入远程代理对象,构造函数如:public XxxServiceLocal(XxxService xxxService) | 2.0.0以上版本 | +| mock | mock | class/boolean | 可选 | | 服务治理 | 服务接口调用失败Mock实现类名,该Mock类必须有一个无参构造函数,与Local的区别在于,Local总是被执行,而Mock只在出现非业务异常(比如超时,网络异常等)时执行,Local在远程调用之前执行,Mock在远程调用后执行。 | Dubbo1.0.13及其以上版本支持 | +| cache | cache | string/boolean | 可选 | | 服务治理 | 以调用参数为key,缓存返回结果,可选:lru, threadlocal, jcache等 | Dubbo2.1.0及其以上版本支持 | +| validation | validation | boolean | 可选 | | 服务治理 | 是否启用JSR303标准注解验证,如果启用,将对方法参数上的注解进行校验 | Dubbo2.1.0及其以上版本支持 | +| proxy | proxy | boolean | 可选 | javassist | 性能调优 | 选择动态代理实现策略,可选:javassist, jdk | 2.0.2以上版本 | +| client | client | string | 可选 | | 性能调优 | 客户端传输类型设置,如Dubbo协议的netty或mina。 | Dubbo2.0.0以上版本支持 | +| registry | | string | 可选 | 缺省将从所有注册中心获服务列表后合并结果 | 配置关联 | 从指定注册中心注册获取服务列表,在多个注册中心时使用,值为<dubbo:registry>的id属性,多个注册中心ID用逗号分隔 | 2.0.0以上版本 | +| owner | owner | string | 可选 | | 服务治理 | 调用服务负责人,用于服务治理,请填写负责人公司邮箱前缀 | 2.0.5以上版本 | +| actives | actives | int | 可选 | 0 | 性能调优 | 每服务消费者每服务每方法最大并发调用数 | 2.0.5以上版本 | +| cluster | cluster | string | 可选 | failover | 性能调优 | 集群方式,可选:failover/failfast/failsafe/failback/forking/available/mergeable(2.1.0以上版本)/broadcast(2.1.0以上版本)/zone-aware(2.7.5以上版本) | 2.0.5以上版本 | +| connections | connections | int | 可选 | 100 | 性能调优 | 对每个提供者的最大连接数,rmi、http、hessian等短连接协议表示限制连接数,dubbo等长连接协表示建立的长连接个数 | 2.0.0以上版本 | +| filter | reference.filter | string | 可选 | default | 性能调优 | 服务消费方远程调用过程拦截器名称,多个名称用逗号分隔 | 2.0.5以上版本 | +| listener | invoker.listener | string | 可选 | default | 性能调优 | 服务消费方引用服务监听器名称,多个名称用逗号分隔 | 2.0.5以上版本 | +| layer | layer | string | 可选 | | 服务治理 | 服务调用者所在的分层。如:biz、dao、intl:web、china:acton。 | 2.0.7以上版本 | +| init | init | boolean | 可选 | false | 性能调优 | 是否在afterPropertiesSet()时饥饿初始化引用,否则等到有人注入或引用该实例时再初始化。 | 2.0.10以上版本 | +| protocol | protocol | string | 可选 | | 服务治理 | 只调用指定协议的服务提供方,其它协议忽略。 | 2.7.0以上版本 | +| client | client | string | 可选 | dubbo协议缺省为netty | 服务发现 | 协议的客户端实现类型,比如:dubbo协议的mina,netty等 | 2.7.0以上版本 | +| providerPort | provider-port | int | 可选 | | Service Mesh | 当dubbo.consumer.meshEnable=true,Dubbo默认会将请求转换成K8S标准格式,结合VirtualService和DestinationRule进行流量治理,此时consumer端可以感知到provider。如果不想使用VirtualService和DestinationRule,请设置providerPort,使consumer端感知provider暴露的服务端口 | 3.1.0以上版本 | +| unloadClusterRelated | unloadClusterRelated | boolean | 可选 | false | Service Mesh | 当dubbo.consumer.meshEnable=true,在Service Mesh模式下,设置为true,可在当前调用中卸载与Cluster相关的Directory、Router和Load Balance,将重试、负载平衡、超时和其他流量管理功能下放至Sidecar,使用VirtualService和DestinationRule进行流量治理 | 3.1.0以上版本 | +| parameters | 无 | Map | 可选 | | 服务治理 | 扩展预留,可扩展定义任意参数,所有扩展参数都将原样反映在 URL 配置上 | 2.0.0以上版本 | +| providedBy | provided-by | string | 可选 | | Service Mesh | 当dubbo.consumer.meshEnable=true,Dubbo默认会将请求转换成K8S标准格式,结合VirtualService和DestinationRule进行流量治理,此时consumer端可以感知到provider。该值应当与声明的`k8s service`一致 | 3.1.0以上版本 | +| providerNamespace | provider-namespace | string | 可选 | | Service Mesh | 当dubbo.consumer.meshEnable=true,Dubbo默认会将请求转换成K8S标准格式,结合VirtualService和DestinationRule进行流量治理,此时consumer端可以感知到provider。请设置providerNamespace,使consumer端按照此配置寻址provider dns,默认`default` | 3.1.2以上版本 | + + +### registry + +注册中心配置。 + +> 对应的配置类: `org.apache.dubbo.config.RegistryConfig`。同时如果有多个不同的注册中心,可以声明多个 `` 标签,并在 `` 或 `` 的 `registry` 属性指定使用的注册中心。 + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| id | | string | 可选 | | 配置关联 | 注册中心引用BeanId,可以在<dubbo:service registry="">或<dubbo:reference registry="">中引用此ID | 1.0.16以上版本 | +| address | <host:port> | string | 必填 | | 服务发现 | 注册中心服务器地址,如果地址没有端口缺省为9090,同一集群内的多个地址用逗号分隔,如:ip:port,ip:port,不同集群的注册中心,请配置多个<dubbo:registry>标签 | 1.0.16以上版本 | +| protocol | <protocol> | string | 可选 | dubbo | 服务发现 | 注册中心地址协议,支持`dubbo`, `multicast`, `zookeeper`, `redis`, `consul(2.7.1)`, `sofa(2.7.2)`, `etcd(2.7.2)`, `nacos(2.7.2)`等协议 | 2.0.0以上版本 | +| port | <port> | int | 可选 | 9090 | 服务发现 | 注册中心缺省端口,当address没有带端口时使用此端口做为缺省值 | 2.0.0以上版本 | +| username | <username> | string | 可选 | | 服务治理 | 登录注册中心用户名,如果注册中心不需要验证可不填 | 2.0.0以上版本 | +| password | <password> | string | 可选 | | 服务治理 | 登录注册中心密码,如果注册中心不需要验证可不填 | 2.0.0以上版本 | +| transport | registry.transporter | string | 可选 | netty | 性能调优 | 网络传输方式,可选mina,netty | 2.0.0以上版本 | +| timeout | registry.timeout | int | 可选 | 5000 | 性能调优 | 注册中心请求超时时间(毫秒) | 2.0.0以上版本 | +| session | registry.session | int | 可选 | 60000 | 性能调优 | 注册中心会话超时时间(毫秒),用于检测提供者非正常断线后的脏数据,比如用心跳检测的实现,此时间就是心跳间隔,不同注册中心实现不一样。 | 2.1.0以上版本 | +| zone | zone | string | 可选 | | 服务治理 | 注册表所属区域,通常用于流量隔离 | 2.7.5以上版本 +| file | registry.file | string | 可选 | | 服务治理 | 使用文件缓存注册中心地址列表及服务提供者列表,应用重启时将基于此文件恢复,注意:两个注册中心不能使用同一文件存储 | 2.0.0以上版本 | +| wait | registry.wait | int | 可选 | 0 | 性能调优 | 停止时等待通知完成时间(毫秒) | 2.0.0以上版本 | +| check | check | boolean | 可选 | true | 服务治理 | 注册中心不存在时,是否报错 | 2.0.0以上版本 | +| register | register | boolean | 可选 | true | 服务治理 | 是否向此注册中心注册服务,如果设为false,将只订阅,不注册 | 2.0.5以上版本 | +| subscribe | subscribe | boolean | 可选 | true | 服务治理 | 是否向此注册中心订阅服务,如果设为false,将只注册,不订阅 | 2.0.5以上版本 | +| dynamic | dynamic | boolean | 可选 | true | 服务治理 | 服务是否动态注册,如果设为false,注册后将显示为disable状态,需人工启用,并且服务提供者停止时,也不会自动取消注册,需人工禁用。 | 2.0.5以上版本 | +| group | group | string | 可选 | dubbo | 服务治理 | 服务注册分组,跨组的服务不会相互影响,也无法相互调用,适用于环境隔离。 | 2.0.5以上版本 | +| version | version | string | 可选 | | 服务发现 | 服务版本 | 1.0.0以上版本 | +| simplified | simplified | boolean | 可选 | false | 服务治理 | 注册到注册中心的URL是否采用精简模式的(与低版本兼容) | 2.7.0以上版本 | +| extra-keys | extraKeys | string | 可选 | | 服务治理 | 在simplified=true时,extraKeys允许你在默认参数外将额外的key放到URL中,格式:"interface,key1,key2"。 | 2.7.0以上版本 | +| useAsConfigCenter | | boolean | 可选 | | 服务治理 | 该注册中心是否作为配置中心使用 | 2.7.5以上版本 | +| useAsMetadataCenter | | boolean | 可选 | | 服务治理 | 该注册中心是否作为元数据中心使用 | 2.7.5以上版本 | +| accepts | accepts | string | 可选 | | 服务治理 | 该注册中心接收rpc协议列表,多协议用逗号隔开,例如dubbo,rest | 2.7.5以上版本 | +| preferred | preferred | boolean | 可选 | | 服务治理 | 是否作为首选注册中心。当订阅多注册中心时,如果设为true,该注册中心作为首选 | 2.7.5以上版本 | +| weight | weight | int | 可选 | | 性能调优 | 注册流量权重。使用多注册中心时,可通过该值调整注册流量的分布,当设置首选注册中心时该值不生效 | 2.7.5以上版本 | +| registerMode | register-mode | string | 可选 | all | 服务治理 | 控制地址注册行为,应用级服务发现迁移用。
* instance 只注册应用级地址;
* interface 只注册接口级地址;
* all(默认) 同时注册应用级和接口级地址; | 3.0.0以上版本 | +| enableEmptyProtection | enable-empty-protection | boolean | 可选 | true | 服务治理 | 是否全局启用消费端的空地址列表保护,开启后注册中心的空地址推送将被忽略,默认 true | 3.0.0以上版本 | +| parameters | 无 | Map | 可选 | | 服务治理 | 扩展预留,可扩展定义任意参数,所有扩展参数都将原样反映在 URL 配置上 | 2.0.0以上版本 | + +### config-center + +配置中心。 + +> 对应的配置类:`org.apache.dubbo.config.ConfigCenterConfig` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 描述 | 兼容性 | +| ---------------- | ---------------------- | ------------------- | -------- | ---------------- | ------------------------------------------------------------ | ------ | +| protocol | protocol | string | 可选 | zookeeper | 使用哪个配置中心:apollo、zookeeper、nacos等。
以zookeeper为例
1. 指定protocol,则address可以简化为`127.0.0.1:2181`;
2. 不指定protocol,则address取值为`zookeeper://127.0.0.1:2181` | 2.7.0以上版本 | +| address | address | string | 必填 | | 配置中心地址。
取值参见protocol说明 | 2.7.0以上版本 | +| highestPriority | highest-priority| boolean | 可选 | true | 来自配置中心的配置项具有最高优先级,即会覆盖本地配置项。 | 2.7.0以上版本 | +| namespace | namespace | string | 可选 | dubbo | 通常用于多租户隔离,实际含义视具体配置中心而不同。
如:
zookeeper - 环境隔离,默认值`dubbo`;
apollo - 区分不同领域的配置集合,默认使用`dubbo`和`application` | 2.7.0以上版本 | +| cluster | cluster | string | 可选 | | 含义视所选定的配置中心而不同。
如Apollo中用来区分不同的配置集群 | 2.7.0以上版本 | +| group | group | string | 可选 | dubbo | 含义视所选定的配置中心而不同。
nacos - 隔离不同配置集
zookeeper - 隔离不同配置集 | 2.7.0以上版本 | +| check | check | boolean | 可选 | true | 当配置中心连接失败时,是否终止应用启动。 | 2.7.0以上版本 | +| configFile | config-file | string | 可选 | dubbo.properties | 全局级配置文件所映射到的key
zookeeper - 默认路径/dubbo/config/dubbo/dubbo.properties
apollo - dubbo namespace中的dubbo.properties键 | 2.7.0以上版本 | +| appConfigFile | app-config-file | string | 可选 | | “configFile”是全局级共享的。此项仅限于此应用程序配置的属性 | 2.7.0以上版本 | +| timeout | timeout | int | 可选 | 3000ms | 获取配置的超时时间 | 2.7.0以上版本 | +| username | username | string | 可选 | | 如果配置中心需要做校验,用户名
Apollo暂未启用 | 2.7.0以上版本 | +| password | password | string | 可选 | | 如果配置中心需要做校验,密码
Apollo暂未启用 | 2.7.0以上版本 | +| parameters | parameters | Map | 可选 | | 扩展参数,用来支持不同配置中心的定制化配置参数 | 2.7.0以上版本 | +| includeSpringEnv |include-spring-env| boolean | 可选 | false | 使用Spring框架时支持,为true时,会自动从Spring Environment中读取配置。
默认依次读取
key为dubbo.properties的配置
key为dubbo.properties的PropertySource | 2.7.0以上版本 | + +### metadata-report-config + +元数据中心。 + +> 对应的配置类:`org.apache.dubbo.config.MetadataReportConfig` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 描述 | 兼容性 | +| --------------- | --------- | ------ | -------- | --------- | ------------------------------------------------------------ | ------ | +| address | address | string | 必填 | | 元数据中心地址。 | 2.7.0以上版本 | +| protocol | protocol | string | 可选 | zookeeper | 元数据中心协议:zookeeper、nacos、redis等。
以zookeeper为例
1. 指定protocol,则address可以简化为`127.0.0.1:2181`;
2. 不指定protocol,则address取值为`zookeeper://127.0.0.1:2181` | 2.7.13以上版本 | +| port | port | int | 可选 | | 元数据中心端口号。指定port,则address可简化,不用配置端口号 | 2.7.13以上版本 | +| username | username | string | 可选 | | 元数据中心需要做校验,用户名
Apollo暂未启用 | 2.7.0以上版本 | +| password | password | string | 可选 | | 元数据中心需要做校验,密码
Apollo暂未启用 | 2.7.0以上版本 | +| timeout | timeout | int | 可选 | | 获取元数据超时时间(ms) | 2.7.0以上版本 | +| group | group | string | 可选 | dubbo | 元数据分组,适用于环境隔离。与注册中心group意义相同 | 2.7.0以上版本 | +| retryTimes | retry-times| int | 可选 | 100 | 重试次数 | 2.7.0以上版本 | +| retryPeriod | retry-period | int | 可选 | 3000ms | 重试间隔时间(ms) | 2.7.0以上版本 | +| cycleReport | cycle-report | boolean| 可选 | true | 是否每天更新完整元数据 | 2.7.0以上版本 | +| syncReport | sync-report | boolean| 可选 | false | 是否同步更新元数据,默认为异步 | 2.7.0以上版本 | +| cluster | cluster | string | 可选 | | 含义视所选定的元数据中心而不同。
如Apollo中用来区分不同的配置集群 | 2.7.0以上版本 | +| file | file | string | 可选 | | 使用文件缓存元数据中心列表,应用重启时将基于此文件恢复,注意:两个元数据中心不能使用同一文件存储 | 2.7.0以上版本 | +| check | check | boolean | 可选 | true | 当元数据中心连接失败时,是否终止应用启动。 | 3.0.0以上版本 | +| reportMetadata | report-metadata | boolean | 可选 | false | 是否上报地址发现中的接口配置报元数据,`dubbo.application.metadata-type=remote` 该配置不起作用即一定会上报,`dubbo.application.metadata-type=local` 时是否上报由该配置值决定 | 3.0.0以上版本 | +| reportDefinition | report-definition | boolean | 可选 | true | 是否上报服务运维用元数据 | 3.0.0以上版本 | +| reportConsumerDefinition | report-consumer-definition | boolean | 可选 | true | 是否在消费端上报服务运维用元数据 | 3.0.0以上版本 | +| parameters | parameters | Map | 可选 | | 扩展参数,用来支持不同元数据中心的定制化配置参数 | 2.7.0以上版本 | + +### protocol + +服务提供者协议配置。 + +> 对应的配置类: `org.apache.dubbo.config.ProtocolConfig`。同时,如果需要支持多协议,可以声明多个 `` 标签,并在 `` 中通过 `protocol` 属性指定使用的协议。 + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| id | | string | 可选 | dubbo | 配置关联 | 协议BeanId,可以在<dubbo:service protocol="">中引用此ID,如果ID不填,缺省和name属性值一样,重复则在name后加序号。 | 2.0.5以上版本 | +| name | <protocol> | string | 必填 | dubbo | 性能调优 | 协议名称 | 2.0.5以上版本 | +| port | <port> | int | 可选 | dubbo协议缺省端口为20880,rmi协议缺省端口为1099,http和hessian协议缺省端口为80;如果没有配置port,则自动采用默认端口,如果配置为-1,则会分配一个没有被占用的端口。Dubbo 2.4.0+,分配的端口在协议缺省端口的基础上增长,确保端口段可控。 | 服务发现 | 服务端口 | 2.0.5以上版本 | +| host | <host> | string | 可选 | 自动查找本机IP | 服务发现 | -服务主机名,多网卡选择或指定VIP及域名时使用,为空则自动查找本机IP,-建议不要配置,让Dubbo自动获取本机IP | 2.0.5以上版本 | +| threadpool | threadpool | string | 可选 | fixed | 性能调优 | 线程池类型,可选:fixed/cached/limit(2.5.3以上)/eager(2.6.x以上) | 2.0.5以上版本 | +| threadname | threadname | string | 可选 | | 性能调优 | 线程池名称 | 2.7.6以上版本 | +| threads | threads | int | 可选 | 200 | 性能调优 | 服务线程池大小(固定大小) | 2.0.5以上版本 | +| corethreads | corethreads | int | 可选 | 200 | 性能调优 | 线程池核心线程大小 | 2.0.5以上版本 | +| iothreads | threads | int | 可选 | cpu个数+1 | 性能调优 | io线程池大小(固定大小) | 2.0.5以上版本 | +| accepts | accepts | int | 可选 | 0 | 性能调优 | 服务提供方最大可接受连接数 | 2.0.5以上版本 | +| payload | payload | int | 可选 | 8388608(=8M) | 性能调优 | 请求及响应数据包大小限制,单位:字节 | 2.0.5以上版本 | +| codec | codec | string | 可选 | dubbo | 性能调优 | 协议编码方式 | 2.0.5以上版本 | +| serialization | serialization | string | 可选 | dubbo协议缺省为hessian2,rmi协议缺省为java,http协议缺省为json | 性能调优 | 协议序列化方式,当协议支持多种序列化方式时使用,比如:dubbo协议的dubbo,hessian2,java,compactedjava,以及http协议的json等 | 2.0.5以上版本 | +| accesslog | accesslog | string/boolean | 可选 | | 服务治理 | 设为true,将向logger中输出访问日志,也可填写访问日志文件路径,直接把访问日志输出到指定文件 | 2.0.5以上版本 | +| path | <path> | string | 可选 | | 服务发现 | 提供者上下文路径,为服务path的前缀 | 2.0.5以上版本 | +| transporter | transporter | string | 可选 | dubbo协议缺省为netty | 性能调优 | 协议的服务端和客户端实现类型,比如:dubbo协议的mina,netty等,可以分拆为server和client配置 | 2.0.5以上版本 | +| server | server | string | 可选 | dubbo协议缺省为netty,http协议缺省为servlet | 性能调优 | 协议的服务器端实现类型,比如:dubbo协议的mina,netty等,http协议的jetty,servlet等 | 2.0.5以上版本 | +| client | client | string | 可选 | dubbo协议缺省为netty | 性能调优 | 协议的客户端实现类型,比如:dubbo协议的mina,netty等 | 2.0.5以上版本 | +| dispatcher | dispatcher | string | 可选 | dubbo协议缺省为all | 性能调优 | 协议的消息派发方式,用于指定线程模型,比如:dubbo协议的all, direct, message, execution, connection等 | 2.1.0以上版本 | +| queues | queues | int | 可选 | 0 | 性能调优 | 线程池队列大小,当线程池满时,排队等待执行的队列大小,建议不要设置,当线程池满时应立即失败,重试其它服务提供机器,而不是排队,除非有特殊需求。 | 2.0.5以上版本 | +| charset | charset | string | 可选 | UTF-8 | 性能调优 | 序列化编码 | 2.0.5以上版本 | +| buffer | buffer | int | 可选 | 8192 | 性能调优 | 网络读写缓冲区大小 | 2.0.5以上版本 | +| heartbeat | heartbeat | int | 可选 | 0 | 性能调优 | 心跳间隔,对于长连接,当物理层断开时,比如拔网线,TCP的FIN消息来不及发送,对方收不到断开事件,此时需要心跳来帮助检查连接是否已断开 | 2.0.10以上版本 | +| telnet | telnet | string | 可选 | | 服务治理 | 所支持的telnet命令,多个命令用逗号分隔 | 2.0.5以上版本 | +| register | register | boolean | 可选 | true | 服务治理 | 该协议的服务是否注册到注册中心 | 2.0.8以上版本 | +| contextpath | contextpath | String | 可选 | 缺省为空串 | 服务治理 | 上下文路径 | 2.0.6以上版本 | +| sslEnabled | ssl-enabled | boolean | 可选 | false | 服务治理 | 是否启用ssl | 2.7.5以上版本 | +| parameters | parameters | Map | 可选 | | 扩展参数 | 2.0.0以上版本 | + +### provider + +服务提供者缺省值配置。 + +> 对应的配置类: `org.apache.dubbo.config.ProviderConfig`。同时该标签为 `` 和 `` 标签的缺省值设置。 + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| id | | string | 可选 | dubbo | 配置关联 | 协议BeanId,可以在<dubbo:service proivder="">中引用此ID | 1.0.16以上版本 | +| protocol | <protocol> | string | 可选 | dubbo | 性能调优 | 协议名称 | 1.0.16以上版本 | +| host | <host> | string | 可选 | 自动查找本机IP | 服务发现 | 服务主机名,多网卡选择或指定VIP及域名时使用,为空则自动查找本机IP,建议不要配置,让Dubbo自动获取本机IP | 1.0.16以上版本 | +| threads | threads | int | 可选 | 200 | 性能调优 | 服务线程池大小(固定大小) | 1.0.16以上版本 | +| payload | payload | int | 可选 | 8388608(=8M) | 性能调优 | 请求及响应数据包大小限制,单位:字节 | 2.0.0以上版本 | +| path | <path> | string | 可选 | | 服务发现 | 提供者上下文路径,为服务path的前缀 | 2.0.0以上版本 | +| transporter | transporter | string | 可选 | dubbo协议缺省为netty | 性能调优 | 协议的服务端和客户端实现类型,比如:dubbo协议的mina,netty等,可以分拆为server和client配置 | 2.0.5以上版本 | +| server | server | string | 可选 | dubbo协议缺省为netty,http协议缺省为servlet | 性能调优 | 协议的服务器端实现类型,比如:dubbo协议的mina,netty等,http协议的jetty,servlet等 | 2.0.0以上版本 | +| client | client | string | 可选 | dubbo协议缺省为netty | 性能调优 | 协议的客户端实现类型,比如:dubbo协议的mina,netty等 | 2.0.0以上版本 | +| dispatcher | dispatcher | string | 可选 | dubbo协议缺省为all | 性能调优 | 协议的消息派发方式,用于指定线程模型,比如:dubbo协议的all, direct, message, execution, connection等 | 2.1.0以上版本 | +| codec | codec | string | 可选 | dubbo | 性能调优 | 协议编码方式 | 2.0.0以上版本 | +| serialization | serialization | string | 可选 | dubbo协议缺省为hessian2,rmi协议缺省为java,http协议缺省为json | 性能调优 | 协议序列化方式,当协议支持多种序列化方式时使用,比如:dubbo协议的dubbo,hessian2,java,compactedjava,以及http协议的json,xml等 | 2.0.5以上版本 | +| default | | boolean | 可选 | false | 配置关联 | 是否为缺省协议,用于多协议 | 1.0.16以上版本 | +| filter | service.filter | string | 可选 | | 性能调优 | 服务提供方远程调用过程拦截器名称,多个名称用逗号分隔 | 2.0.5以上版本 | +| listener | exporter.listener | string | 可选 | | 性能调优 | 服务提供方导出服务监听器名称,多个名称用逗号分隔 | 2.0.5以上版本 | +| threadpool | threadpool | string | 可选 | fixed | 性能调优 | 线程池类型,可选:fixed/cached/limit(2.5.3以上)/eager(2.6.x以上) | 2.0.5以上版本 | +| threadname | threadname | string | 可选 | | 性能调优 | 线程池名称 | 2.7.6以上版本 | +| accepts | accepts | int | 可选 | 0 | 性能调优 | 服务提供者最大可接受连接数 | 2.0.5以上版本 | +| version | version | string | 可选 | 0.0.0 | 服务发现 | 服务版本,建议使用两位数字版本,如:1.0,通常在接口不兼容时版本号才需要升级 | 2.0.5以上版本 | +| group | group | string | 可选 | | 服务发现 | 服务分组,当一个接口有多个实现,可以用分组区分 | 2.0.5以上版本 | +| delay | delay | int | 可选 | 0 | 性能调优 | 延迟注册服务时间(毫秒)- ,设为-1时,表示延迟到Spring容器初始化完成时暴露服务 | 2.0.5以上版本 | +| timeout | default.timeout | int | 可选 | 1000 | 性能调优 | 远程服务调用超时时间(毫秒) | 2.0.5以上版本 | +| retries | default.retries | int | 可选 | 2 | 性能调优 | 远程服务调用重试次数,不包括第一次调用,不需要重试请设为0 | 2.0.5以上版本 | +| connections | default.connections | int | 可选 | 0 | 性能调优 | 对每个提供者的最大连接数,rmi、http、hessian等短连接协议表示限制连接数,dubbo等长连接协表示建立的长连接个数 | 2.0.5以上版本 | +| loadbalance | default.loadbalance | string | 可选 | random | 性能调优 | 负载均衡策略,可选值:
* random - 随机;
* roundrobin - 轮询;
* leastactive - 最少活跃调用;
* consistenthash - 哈希一致 (2.1.0以上版本);
* shortestresponse - 最短响应 (2.7.7以上版本); | 2.0.5以上版本 | +| async | default.async | boolean | 可选 | false | 性能调优 | 是否缺省异步执行,不可靠异步,只是忽略返回值,不阻塞执行线程 | 2.0.5以上版本 | +| stub | stub | boolean | 可选 | false | 服务治理 | 设为true,表示使用缺省代理类名,即:接口名 + Local后缀。 | 2.0.5以上版本 | +| mock | mock | boolean | 可选 | false | 服务治理 | 设为true,表示使用缺省Mock类名,即:接口名 + Mock后缀。 | 2.0.5以上版本 | +| token | token | boolean | 可选 | | 服务治理 | 令牌验证,为空表示不开启,如果为true,表示随机生成动态令牌 | 2.0.5以上版本 | +| registry | registry | string | 可选 | 缺省向所有registry注册 | 配置关联 | 向指定注册中心注册,在多个注册中心时使用,值为<dubbo:registry>的id属性,多个注册中心ID用逗号分隔,如果不想将该服务注册到任何registry,可将值设为N/A | 2.0.5以上版本 | +| dynamic | dynamic | boolean | 可选 | true | 服务治理 | 服务是否动态注册,如果设为false,注册后将显示后disable状态,需人工启用,并且服务提供者停止时,也不会自动取消册,需人工禁用。 | 2.0.5以上版本 | +| accesslog | accesslog | string/boolean | 可选 | false | 服务治理 | 设为true,将向logger中输出访问日志,也可填写访问日志文件路径,直接把访问日志输出到指定文件 | 2.0.5以上版本 | +| owner | owner | string | 可选 | | 服务治理 | 服务负责人,用于服务治理,请填写负责人公司邮箱前缀 | 2.0.5以上版本 | +| document | document | string | 可选 | | 服务治理 | 服务文档URL | 2.0.5以上版本 | +| weight | weight | int | 可选 | | 性能调优 | 服务权重 | 2.0.5以上版本 | +| executes | executes | int | 可选 | 0 | 性能调优 | 服务提供者每服务每方法最大可并行执行请求数 | 2.0.5以上版本 | +| actives | default.actives | int | 可选 | 0 | 性能调优 | 每服务消费者每服务每方法最大并发调用数 | 2.0.5以上版本 | +| proxy | proxy | string | 可选 | javassist | 性能调优 | 生成动态代理方式,可选:jdk/javassist | 2.0.5以上版本 | +| cluster | default.cluster | string | 可选 | failover | 性能调优 | 集群方式,可选:failover/failfast/failsafe/failback/forking | 2.0.5以上版本 | +| deprecated | deprecated | boolean | 可选 | false | 服务治理 | 服务是否过时,如果设为true,消费方引用时将打印服务过时警告error日志 | 2.0.5以上版本 | +| queues | queues | int | 可选 | 0 | 性能调优 | 线程池队列大小,当线程池满时,排队等待执行的队列大小,建议不要设置,当线程池满时应立即失败,重试其它服务提供机器,而不是排队,除非有特殊需求。 | 2.0.5以上版本 | +| charset | charset | string | 可选 | UTF-8 | 性能调优 | 序列化编码 | 2.0.5以上版本 | +| buffer | buffer | int | 可选 | 8192 | 性能调优 | 网络读写缓冲区大小 | 2.0.5以上版本 | +| iothreads | iothreads | int | 可选 | CPU + 1 | 性能调优 | IO线程池,接收网络读写中断,以及序列化和反序列化,不处理业务,业务线程池参见threads配置,此线程池和CPU相关,不建议配置。 | 2.0.5以上版本 | +| alive | alive | int | 可选 | | 服务治理 | 线程池keepAliveTime,默认单位为ms | 2.0.5以上版本 | +| telnet | telnet | string | 可选 | | 服务治理 | 所支持的telnet命令,多个命令用逗号分隔 | 2.0.5以上版本 | +| wait | wait | int | 可选 | | 服务治理 | 停服务时等待时间 | 2.0.5以上版本 | +| contextpath | contextpath | String | 可选 | 缺省为空串 | 服务治理 | 上下文路径 | 2.0.6以上版本 | +| layer | layer | string | 可选 | | 服务治理 | 服务提供者所在的分层。如:biz、dao、intl:web、china:acton。 | 2.0.7以上版本 | +| parameters | parameters | Map | 可选 | | 服务治理 | 扩展参数 | 2.0.0以上版本 | + +### consumer + +服务消费者缺省值配置。 + +> 配置类: `org.apache.dubbo.config.ConsumerConfig` 。同时该标签为 `` 标签的缺省值设置。 + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| timeout | default.timeout | int | 可选 | 1000 | 性能调优 | 远程服务调用超时时间(毫秒) | 1.0.16以上版本 | +| retries | default.retries | int | 可选 | 2 | 性能调优 | 远程服务调用重试次数,不包括第一次调用,不需要重试请设为0,仅在cluster为failback/failover时有效 | 1.0.16以上版本 | +| loadbalance | default.loadbalance | string | 可选 | random | 性能调优 | 负载均衡策略,可选值:
* random - 随机;
* roundrobin - 轮询;
* leastactive - 最少活跃调用;
* consistenthash - 哈希一致 (2.1.0以上版本);
* shortestresponse - 最短响应 (2.7.7以上版本); | 1.0.16以上版本 | +| async | default.async | boolean | 可选 | false | 性能调优 | 是否缺省异步执行,不可靠异步,只是忽略返回值,不阻塞执行线程 | 2.0.0以上版本 | +| sent | default.sent | boolean | 可选 | true | 服务治理 | 异步调用时,标记sent=true时,表示网络已发出数据 | 2.0.6以上版本 | +| connections | default.connections | int | 可选 | 100 | 性能调优 | 每个服务对每个提供者的最大连接数,rmi、http、hessian等短连接协议支持此配置,dubbo协议长连接不支持此配置 | 1.0.16以上版本 | +| generic | generic | boolean | 可选 | false | 服务治理 | 是否缺省泛化接口,如果为泛化接口,将返回GenericService | 2.0.0以上版本 | +| check | check | boolean | 可选 | true | 服务治理 | 启动时检查提供者是否存在,true报错,false忽略 | 1.0.16以上版本 | +| proxy | proxy | string | 可选 | javassist | 性能调优 | 生成动态代理方式,可选:jdk/javassist | 2.0.5以上版本 | +| owner | owner | string | 可选 | | 服务治理 | 调用服务负责人,用于服务治理,请填写负责人公司邮箱前缀 | 2.0.5以上版本 | +| actives | default.actives | int | 可选 | 0 | 性能调优 | 每服务消费者每服务每方法最大并发调用数 | 2.0.5以上版本 | +| cluster | default.cluster | string | 可选 | failover | 性能调优 | 集群方式,可选:failover/failfast/failsafe/failback/forking/available/mergeable(2.1.0以上版本)/broadcast(2.1.0以上版本)/zone-aware(2.7.5以上版本) | 2.0.5以上版本 | +| filter | reference.filter | string | 可选 | | 性能调优 | 服务消费方远程调用过程拦截器名称,多个名称用逗号分隔 | 2.0.5以上版本 | +| listener | invoker.listener | string | 可选 | | 性能调优 | 服务消费方引用服务监听器名称,多个名称用逗号分隔 | 2.0.5以上版本 | +| registry | | string | 可选 | 缺省向所有registry注册 | 配置关联 | 向指定注册中心注册,在多个注册中心时使用,值为<dubbo:registry>的id属性,多个注册中心ID用逗号分隔,如果不想将该服务注册到任何registry,可将值设为N/A | 2.0.5以上版本 | +| layer | layer | string | 可选 | | 服务治理 | 服务调用者所在的分层。如:biz、dao、intl:web、china:acton。 | 2.0.7以上版本 | +| init | init | boolean | 可选 | false | 性能调优 | 是否在afterPropertiesSet()时饥饿初始化引用,否则等到有人注入或引用该实例时再初始化。 | 2.0.10以上版本 | +| cache | cache | string/boolean | 可选 | | 服务治理 | 以调用参数为key,缓存返回结果,可选:lru, threadlocal, jcache等 | 2.1.0及其以上版本支持 | +| validation | validation | boolean | 可选 | | 服务治理 | 是否启用JSR303标准注解验证,如果启用,将对方法参数上的注解进行校验 | 2.1.0及其以上版本支持 | +| version | version | string | 可选 | | 服务治理 | 在 Dubbo 中为同一个服务配置多个版本 | 2.2.0及其以上版本支持 | +| client | client | string | 可选 | dubbo协议缺省为netty | 性能调优 | 协议的客户端实现类型,比如:dubbo协议的mina,netty等 | 2.0.0以上版本 | +| threadpool | threadpool | string | 可选 | fixed | 性能调优 | 线程池类型,可选:fixed/cached/limit(2.5.3以上)/eager(2.6.x以上) | 2.0.5以上版本 | +| corethreads | corethreads | int | 可选 | 200 | 性能调优 | 线程池核心线程大小 | 2.0.5以上版本 | +| threads | threads | int | 可选 | 200 | 性能调优 | 服务线程池大小(固定大小) | 2.0.5以上版本 | +| queues | queues | int | 可选 | 0 | 性能调优 | 线程池队列大小,当线程池满时,排队等待执行的队列大小,建议不要设置,当线程池满时应立即失败,重试其它服务提供机器,而不是排队,除非有特殊需求。 | 2.0.5以上版本 | +| shareconnections | shareconnections | int | 可选 | 1 | 性能调优| 共享连接数。当connection参数设置为0时,会启用共享方式连接,默认只有一个连接。仅支持dubbo协议 | 2.7.0以上版本 | +| referThreadNum | | int | 可选 | | 性能优化 | 异步调用线程池大小 | 3.0.0以上版本 | +| meshEnable | mesh-enable| boolean | 可选 | false | Service Mesh | Dubbo Mesh模式的开关。开启后,可适配SideCar模式,将Dubbo服务调用转换为K8S标准调用。仅支持Triple协议,兼容GRPC。设置为true后,原生对接K8S,无需第三方注册中心,设置dubbo.registry.address=N/A即可 | 3.1.0以上版本 | +| parameters | parameters | Map | 可选 | | 服务治理 | 扩展参数 | 2.0.0以上版本 | + +### metrics + +指标配置。 + +> 配置类: `org.apache.dubbo.config.MetricsConfig` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| protocol | protocol | string | 可选 | prometheus | 性能调优 | 协议名称,默认使用prometheus | 3.0.0以上版本 | +| prometheus | | PrometheusConfig | 可选 | | 配置关联 | prometheus相关配置 | 3.0.0以上版本 | +| aggregation | | AggregationConfig | 可选 | | 配置关联 | 指标聚合相关配置 | 3.0.0以上版本 | + +- PrometheusConfig 对应类:`org.apache.dubbo.config.nested.PrometheusConfig` + +| 属性 | 类型 | 是否必填 | 缺省值 | 描述 | +| --- | --- | ---- | --- | --- | +| exporter.enabled | boolean | 可选 | | 是否启用prometheus exporter | +| exporter.enableHttpServiceDiscovery | boolean | 可选 | | 是否启用http服务发现 | +| exporter.httpServiceDiscoveryUrl | string | 可选 | | http服务发现地址 | +| exporter.metricsPort | int | 可选 | | 当使用pull方法时,暴露的端口号 | +| exporter.metricsPath | string | 可选 | | 当使用pull方法时,暴露指标的路径 | +| pushgateway.enabled | boolean | 可选 | | 是否可以通过prometheus的Pushgateway发布指标 | +| pushgateway.baseUrl | string | 可选 | | Pushgateway地址 | +| pushgateway.username | string | 可选 | | Pushgateway用户名 | +| pushgateway.password | string | 可选 | | Pushgateway密码 | +| pushgateway.pushInterval | int | 可选 | | 推送指标间隔时间 | + +- AggregationConfig 对应类:`org.apache.dubbo.config.nested.AggregationConfig` + +| 属性 | 类型 | 是否必填 | 缺省值 | 描述 | +| --- | --- | ---- | --- | --- | +| enabled | boolean | 可选 | | 是否开启本地指标聚合功能 | +| bucketNum | int | 可选 | | 时间窗口存储桶个数 | +| timeWindowSeconds | int | 可选 | | 时间窗口时长(s) | + +### tracing + +指标配置。 + +> 配置类: `org.apache.dubbo.config.TracingConfig` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| enabled | | boolean | 可选 | false | 服务治理 | 是否开启tracing相关功能 | 3.2.3以上版本 | +| sampling | | SamplingConfig | 可选 | | 性能调优 | tracing 采样相关配置 | 3.2.3以上版本 | +| propagation | | PropagationConfig | 可选 | | 服务治理 | tracing 传播协议相关配置 | 3.2.3以上版本 | +| tracingExporter | | ExporterConfig | 可选 | | 服务治理 | tracing 信息导出相关配置 | 3.2.3以上版本 | + +- SamplingConfig 对应类:`org.apache.dubbo.config.nested.SamplingConfig` + +| 属性 | 类型 | 是否必填 | 缺省值 | 描述 | +| --- | --- | ---- | --- | --- | +| probability | float | 可选 | 0.1 | 采样率 | + +- PropagationConfig 对应类:`org.apache.dubbo.config.nested.PropagationConfig` + +| 属性 | 类型 | 是否必填 | 缺省值 | 描述 | +| --- | --- | ---- | --- | --- | +| type | string | 可选 | W3C | 可选 B3/W3C | + +- ExporterConfig 对应类:`org.apache.dubbo.config.nested.ExporterConfig` + +| 属性 | 类型 | 是否必填 | 缺省值 | 描述 | +| --- | --- | ---- | --- | --- | +| zipkinConfig | ZipkinConfig | 可选 | | zipkin 作为 exporter 的配置信息 | +| otlpConfig | OtlpConfig | 可选 | | OTlp Colletcor 作为exporter的配置信息 | + +- ZipkinConfig 对应类:`org.apache.dubbo.config.nested.ExporterConfig.ZipkinConfig` + +| 属性 | 类型 | 是否必填 | 缺省值 | 描述 | +| --- | --- | ---- | --- | --- | +| endpoint | string | 可选 | | zipkin server 地址 | +| connectTimeout | duration | 可选 | 10s | 连接到 zipkin server 的超时时间 | +| readTimeout | duration | 可选 | 10s | zipkin server 读取超时时间 | + +- OtlpConfig 对应类:`org.apache.dubbo.config.nested.ExporterConfig.OtlpConfig` + +| 属性 | 类型 | 是否必填 | 缺省值 | 描述 | +| --- | --- | ---- | --- | --- | +| endpoint | string | 可选 | | zipkin server 地址 | +| timeout | duration | 可选 | 10s | 等待收集器处理导出的一批 spans 的最大时间 | +| compressionMethod | string | 可选 | none | 用于传输中压缩 tracing 信息的方法,支持 gzip/none | +| headers | Map | 可选 | | 向 OTlp Collector 上报信息时,添加自定义的 header 头 | + +### ssl + +TLS认证配置。 + +> 配置类: `org.apache.dubbo.config.SslConfig` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| serverKeyCertChainPath | server-key-cert-chain-path | string | 可选 | | 安全配置 | 服务端签名证书路径 | 2.7.5以上版本 | +| serverPrivateKeyPath | server-private-key-path | string | 可选 | | 安全配置 | 服务端私钥路径 | 2.7.5以上版本 | +| serverKeyPassword | server-key-password | string | 可选 | | 安全配置 | 服务端密钥密码 | 2.7.5以上版本 | +| serverTrustCertCollectionPath | server-trust-cert-collection-path | string | 可选 | | 安全配置 | 服务端信任证书路径 | 2.7.5以上版本 | +| clientKeyCertChainPath | client-key-cert-chain-path | string | 可选 | | 安全配置 | 客户端签名证书路径 | 2.7.5以上版本 | +| clientPrivateKeyPath | client-private-key-path | string | 可选 | | 安全配置 | 客户端私钥路径 | 2.7.5以上版本 | +| clientKeyPassword | client-key-password | string | 可选 | | 安全配置 | 客户端密钥密码 | 2.7.5以上版本 | +| clientTrustCertCollectionPath | client-trust-cert-collection-path | string | 可选 | | 安全配置 | 客户端信任证书路径 | 2.7.5以上版本 | + +### module + +模块信息配置。 + +> 对应的配置类 `org.apache.dubbo.config.ModuleConfig` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| name | module | string | 必填 | | 服务治理 | 当前模块名称,用于注册中心计算模块间依赖关系 | 2.2.0以上版本 | +| version | module.version | string | 可选 | | 服务治理 | 当前模块的版本 | 2.2.0以上版本 | +| owner | module.owner | string | 可选 | | 服务治理 | 模块负责人,用于服务治理,请填写负责人公司邮箱前缀 | 2.2.0以上版本 | +| organization | module.organization | string | 可选 | | 服务治理 | 组织名称(BU或部门),用于注册中心区分服务来源,此配置项建议不要使用autoconfig,直接写死在配置中,比如china,intl,itu,crm,asc,dw,aliexpress等 | 2.2.0以上版本 | +| background | background | boolean | 可选 | | 性能调优 | 是否开启后台启动模式。如果开启,无需等待spring ContextRefreshedEvent事件完成 | 3.0.0以上版本 | +| referAsync | referAsync | boolean | 可选 | | 性能调优 | 消费端是否开启异步调用 | 3.0.0以上版本 | +| referThreadNum | referThreadNum | int | 可选 | | 性能调优 | 异步调用线程池大小 | 3.0.0以上版本 | +| exportAsync | exportAsync | boolean | 可选 | | 性能调优 | 服务端是否开启导出 | 3.0.0以上版本 | +| exportThreadNum | exportThreadNum | int | 可选 | | 异步导出线程池大小 | | 3.0.0以上版本 | + +### monitor + +监控中心配置。 + +> 对应的配置类: `org.apache.dubbo.config.MonitorConfig` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| protocol | protocol | string | 可选 | dubbo | 服务治理 | 监控中心协议,如果为protocol="registry",表示从注册中心发现监控中心地址,否则直连监控中心。 | 2.0.9以上版本 | +| address | <url> | string | 可选 | | 服务治理 | 直连监控中心服务器地址,address="10.20.130.230:12080" | 1.0.16以上版本 | +| username | username | string | 可选 | | 服务治理 | 监控中心用户名 | 2.0.9以上版本 | +| password | password | string | 可选 | | 服务治理 | 监控中心密码 | 2.0.9以上版本 | +| group | group | string | 可选 | | 服务治理 | 分组 | 2.0.9以上版本 | +| version | version | string | 可选 | | 服务治理 | 版本号 | 2.0.9以上版本 | +| interval | interval | string | 可选 | | 服务治理 | 间隔时间 | 2.0.9以上版本 | +| parameters | parameters | Map | 可选 | | 自定义参数 | 2.0.0以上版本 | + +### method + +方法级配置。 + +> 对应的配置类: `org.apache.dubbo.config.MethodConfig`。同时该标签为 `service` 或 `reference` 的子标签,用于控制到方法级。 + +比如: + +```xml + + + +``` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| name | | string | 必填 | | 标识 | 方法名 | 1.0.8以上版本 | +| timeout | <methodName>.timeout | int | 可选 | 缺省为的timeout | 性能调优 | 方法调用超时时间(毫秒) | 1.0.8以上版本 | +| retries | <methodName>.retries | int | 可选 | 缺省为<dubbo:reference>的retries | 性能调优 | 远程服务调用重试次数,不包括第一次调用,不需要重试请设为0 | 2.0.0以上版本 | +| loadbalance | <methodName>.loadbalance | string | 可选 | 缺省为的loadbalance | 性能调优 | 负载均衡策略,可选值:
* random - 随机;
* roundrobin - 轮询;
* leastactive - 最少活跃调用;
* consistenthash - 哈希一致 (2.1.0以上版本);
* shortestresponse - 最短响应 (2.7.7以上版本); | 2.0.0以上版本 | +| async | <methodName>.async | boolean | 可选 | 缺省为<dubbo:reference>的async | 性能调优 | 是否异步执行,不可靠异步,只是忽略返回值,不阻塞执行线程 | 1.0.9以上版本 | +| sent | <methodName>.sent | boolean | 可选 | true | 性能调优 | 异步调用时,标记sent=true时,表示网络已发出数据 | 2.0.6以上版本 | +| actives | <methodName>.actives | int | 可选 | 0 | 性能调优 | 每服务消费者最大并发调用限制 | 2.0.5以上版本 | +| executes | <methodName>.executes | int | 可选 | 0 | 性能调优 | 每服务每方法最大使用线程数限制- -,此属性只在<dubbo:method>作为<dubbo:service>子标签时有效 | 2.0.5以上版本 | +| deprecated | <methodName>.deprecated | boolean | 可选 | false | 服务治理 | 服务方法是否过时,此属性只在<dubbo:method>作为<dubbo:service>子标签时有效 | 2.0.5以上版本 | +| sticky | <methodName>.sticky | boolean | 可选 | false | 服务治理 | 设置true 该接口上的所有方法使用同一个provider.如果需要更复杂的规则,请使用路由 | 2.0.6以上版本 | +| return | <methodName>.return | boolean | 可选 | true | 性能调优 | 方法调用是否需要返回值,async设置为true时才生效,如果设置为true,则返回future,或回调onreturn等方法,如果设置为false,则请求发送成功后直接返回Null | 2.0.6以上版本 | +| oninvoke | attribute属性,不在URL中体现 | String | 可选 | | 性能调优 | 实例执行前拦截 | 2.0.6以上版本 | +| onreturn | attribute属性,不在URL中体现 | String | 可选 | | 性能调优 | 实例执行返回后拦截 | 2.0.6以上版本 | +| onthrow | attribute属性,不在URL中体现 | String | 可选 | | 性能调优 | 实例执行有异常拦截 | 2.0.6以上版本 | +| oninvokeMethod | attribute属性,不在URL中体现 | String | 可选 | | 性能调优 | 方法执行前拦截 | 2.0.6以上版本 | +| onreturnMethod | attribute属性,不在URL中体现 | String | 可选 | | 性能调优 | 方法执行返回后拦截 | 2.0.6以上版本 | +| onthrowMethod | attribute属性,不在URL中体现 | String | 可选 | | 性能调优 | 方法执行有异常拦截 | 2.0.6以上版本 | +| cache | <methodName>.cache | string/boolean | 可选 | | 服务治理 | 以调用参数为key,缓存返回结果,可选:lru, threadlocal, jcache等 | 2.1.0以上版本 | +| validation | <methodName>.validation | boolean | 可选 | | 服务治理 | 是否启用JSR303标准注解验证,如果启用,将对方法参数上的注解进行校验 | 2.1.0以上版本 | + +### argument + +方法参数配置。 + +> 对应的配置类: `org.apache.dubbo.config.ArgumentConfig`。该标签为 `method` 的子标签,用于方法参数的特征描述,比如 XML 格式: + +```xml + + + +``` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| index | | int | 必填 | | 标识 | 参数索引 | 2.0.6以上版本 | +| type | | String | 与index二选一 | | 标识 | 通过参数类型查找参数的index | 2.0.6以上版本 | +| callback | <metodName><index>.callback | boolean | 可选 | | 服务治理 | 参数是否为callback接口,如果为callback,服务提供方将生成反向代理,可以从服务提供方反向调用消费方,通常用于事件推送. | 2.0.6以上版本 | + +### parameter + +选项参数配置。 + +> 对应的配置类:`java.util.Map`。同时该标签为 `protocol` 或 `service` 或 `provider` 或 `reference` 或 `consumer` 或 `monitor` 或 `registry` 或 `metadata-config` 或 `config-center` 的子标签,用于配置自定义参数,该配置项将作为扩展点设置自定义参数使用。 + +比如: + +```xml + + + +``` + +或: + +```xml + +``` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| --- | --- | ---- | --- | --- | --- | --- | --- | +| key | key | string | 必填 | | 服务治理 | 路由参数键 | 2.0.0以上版本 | +| value | value | string | 必填 | | 服务治理 | 路由参数值 | 2.0.0以上版本 | diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/_index.md new file mode 100644 index 000000000000..03dc67168db4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config/ +description: Dubbo 配置指南 +linkTitle: Spring +title: 配置手册 +type: docs +weight: 1 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot.md b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot.md new file mode 100644 index 000000000000..9558dde72565 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot.md @@ -0,0 +1,93 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config/annotation/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config/annotation/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/config/annotation/ +description: 以 Annotation、Spring Boot 开发 Dubbo 应用 +linkTitle: Spring Boot +title: Spring Boot +type: docs +weight: 3 +--- + +关于 Spring Boot 的注解、基本使用方法等请参考 [使用教程 - Spring Boot](/zh-cn/overview/mannual/java-sdk/tasks/develop/springboot/)。以下是 spring boot 支持的配置详情与 starter 列表。 + +## application.yaml + +以下是 Dubbo 框架支持的配置组件列表,可以在 Spring Boot 配置文件中指定所需配置。 + +### 配置示例 + +```yaml +dubbo: + application: + name: dubbo-springboot-demo-provider + logger: slf4j + protocol: + name: dubbo + port: 50052 + registry: + address: nacos://${nacos.address:127.0.0.1}:8848?username=nacos&password=nacos +``` + +### dubbo +* [**dubbo.application** - `org.apache.dubbo.config.ApplicationConfig`](../../properties#dubboapplication) +* [**dubbo.config-center** - `org.apache.dubbo.config.ConfigCenterConfig`](../../properties#dubboconfig-center) +* [**dubbo.consumer** - `org.apache.dubbo.config.ConsumerConfig`](../../properties#dubboconsumer) +* [**dubbo.metadata-report** - `org.apache.dubbo.config.MetadataReportConfig`](../../properties#dubbometadata-report) +* [**dubbo.protocol** - `org.apache.dubbo.config.ProtocolConfig`](../../properties#dubboprotocol) +* [**dubbo.provider** - `org.apache.dubbo.config.ProviderConfig`](../../properties#dubboprovider) +* [**dubbo.registry** - `org.apache.dubbo.config.RegistryConfig`](../../properties#dubboregistry) +* [**dubbo.metrics** - `org.apache.dubbo.config.MetricsConfig`](../../properties#dubbometrics) +* [**dubbo.tracing** - `org.apache.dubbo.config.TracingConfig`](../../properties#dubbotracing) +* [**dubbo.ssl** - `org.apache.dubbo.config.SslConfig`](../../properties#dubbossl) +* ~~[**dubbo.monitor** - `org.apache.dubbo.config.MonitorConfig`](../../properties#dubbomonitor)~~ +* ~~[**dubbo.module** - `org.apache.dubbo.config.ModuleConfig`](../../properties#dubbomodule)~~ + +### dubbo.metrics +* [**dubbo.metrics.aggregation** - `org.apache.dubbo.config.nested.AggregationConfig`](../../properties#dubbometricsaggregation) +* [**dubbo.metrics.histogram** - `org.apache.dubbo.config.nested.HistogramConfig`](../../properties#dubbometricshistogram) +* [**dubbo.metrics.prometheus** - `org.apache.dubbo.config.nested.PrometheusConfig`](../../properties#dubbometricsprometheus) +* [**dubbo.metrics.prometheus.exporter** - `org.apache.dubbo.config.nested.PrometheusConfig$Exporter`](../../properties#dubbometricsprometheusexporter) +* [**dubbo.metrics.prometheus.pushgateway** - `org.apache.dubbo.config.nested.PrometheusConfig$Pushgateway`](../../properties#dubbometricsprometheuspushgateway) + +### dubbo.tracing +* [**dubbo.tracing.baggage.correlation** - `org.apache.dubbo.config.nested.BaggageConfig$Correlation`](../../properties#dubbotracingbaggage.correlation) +* [**dubbo.tracing.tracing-exporter.otlp-config** - `org.apache.dubbo.config.nested.ExporterConfig$OtlpConfig`](../../properties#dubbotracingtracing-exporterotlp-config) +* [**dubbo.tracing.tracing-exporter.zipkin-config** - `org.apache.dubbo.config.nested.ExporterConfig$ZipkinConfig`](../../properties#dubbotracingtracing-exporterzipkin-config) +* [**dubbo.tracing.baggage** - `org.apache.dubbo.config.nested.BaggageConfig`](../../properties#dubbotracingbaggage) +* [**dubbo.tracing.propagation** - `org.apache.dubbo.config.nested.PropagationConfig`](../../properties#dubbotracingpropagation) +* [**dubbo.tracing.sampling** - `org.apache.dubbo.config.nested.SamplingConfig`](../../properties#dubbotracingsampling) +* [**dubbo.tracing.tracing-exporter** - `org.apache.dubbo.config.nested.ExporterConfig`](../../properties#dubbotracingtracing-exporter) + +## starter列表 + +### dubbo-spring-boot-starter +以下是一些 dubbo-spring-boot-starter 版本对应的 SpringBoot、JDK 依赖: + +| 版本 | 兼容 Spring Boot 范围 | +|-------|---------------| +| 3.3.x | [1.x ~ 3.x) | +| 3.2.x | [1.x ~ 3.x) | +| 3.1.x | [1.x ~ 2.x) | +| 2.7.x | [1.x ~ 2.x) | + +### 其他组件starter + +以下是 Dubbo 官方社区提供的 starter 列表(3.3.0+ 版本),方便在 Spring Boot 应用中快速使用: +* `dubbo-spring-boot-starter`,管理 dubbo 核心依赖,用于识别 application.properties 或 application.yml 中 `dubbo.` 开头的配置项,扫描 @DubboService 等注解。 +* `dubbo-spring-boot-starter3`,管理 dubbo 核心依赖,与 dubbo-spring-boot-starter 相同,支持 spring boot 3.2 版本。 +* `dubbo-nacos-spring-boot-starter`,管理 nacos-client 等依赖,使用 Nacos 作为注册中心、配置中心时引入。 +* `dubbo-zookeeper-spring-boot-starter`,管理 zookeeper、curator 等依赖,使用 Zookeeper 作为注册中心、配置中心时引入(Zookeeper server 3.4 及以下版本使用)。 +* `dubbo-zookeeper-curator5-spring-boot-starter`,管理 zookeeper、curator5 等依赖,使用 Zookeeper 作为注册中心、配置中心时引入。 +* `dubbo-sentinel-spring-boot-starter`,管理 sentinel 等依赖,使用 Sentinel 进行限流降级时引入。 +* `dubbo-seata-spring-boot-starter`,管理 seata 等依赖,使用 Seata 作为分布式事务解决方案时引入。 +* `dubbo-observability-spring-boot-starter`,加入该依赖将自动开启 Dubbo 内置的 metrics 采集,可用于后续的 Prometheus、Grafana 等监控系统。 +* `dubbo-tracing-brave-spring-boot-starter`,管理 brave/zipkin、micrometer 等相关相关依赖,使用 Brave/Zipkin 作为 Tracer,将 Trace 信息 export 到 Zipkin。 +* `dubbo-tracing-otel-otlp-spring-boot-starter`,管理 brave/zipkin、micrometer 等相关相关依赖,使用 OpenTelemetry 作为 Tracer,将 Trace 信息 export 到 OTlp Collector。 +* `dubbo-tracing-otel-zipkin-spring-boot-starter`,管理 brave/zipkin、micrometer 等相关相关依赖,使用 OpenTelemetry 作为 Tracer,将 Trace 信息 export 到 Zipkin。 + +{{% alert title="注意" color="info" %}} +* 关于每个 starter 适配的第三方组件版本,请查看 [组件版本映射表](/zh-cn/overview/mannual/java-sdk/versions/#版本说明)。 +* 每个 starter 都有对应的 application.yml 配置项,请跟随上文 [配置项列表](./#配置示例) 了解使用细节。 +{{% /alert %}} diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/xml.md b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/xml.md new file mode 100644 index 000000000000..1296a303ccae --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/xml.md @@ -0,0 +1,199 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/config/xml/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/config/xml/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/config/xml/ +description: 以 Spring XML 开发 Dubbo 应用 +linkTitle: XML 配置 +title: XML 配置 +type: docs +weight: 4 +--- + + +Dubbo 有基于 Spring Schema 扩展的自定义配置组件,XML 支持的配置项与 [配置参考手册](../properties) 中描述的一一对。本文使用的示例请参考 [dubbo-samples-spring-xml](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-spring-xml) + +## XML完整示例 +### 服务提供者 + +#### 定义服务接口 + +DemoService.java: + +```java +package org.apache.dubbo.demo; + +public interface DemoService { + String sayHello(String name); +} +``` + +#### 在服务提供方实现接口 + +DemoServiceImpl.java: + +```java +package org.apache.dubbo.demo.provider; +import org.apache.dubbo.demo.DemoService; + +public class DemoServiceImpl implements DemoService { + public String sayHello(String name) { + return "Hello " + name; + } +} +``` + +#### 用 Spring 配置声明暴露服务 + +```xml + + + + + + + + + + + + + + + +``` + +#### 加载 Spring 配置 + +```java +public class Application { + public static void main(String[] args) throws InterruptedException { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-demo-provider.xml"); + context.start(); + + System.out.println("dubbo service started"); + // to hang up main thread + new CountDownLatch(1).await(); + } +} +``` + +### 服务消费者 + +#### 通过 Spring 配置引用远程服务 + +```xml + + + + + + + + + + + +``` + +#### 加载 Spring 配置,并调用远程服务 + +```java +public class Application { + public static void main(String[] args) throws IOException { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-demo-consumer.xml"); + context.start(); + GreetingsService greetingsService = (GreetingsService) context.getBean("greetingsService"); + + String message = greetingsService.sayHi("dubbo"); + System.out.println("Receive result ======> " + message); + System.in.read(); + System.exit(0); + } +} +``` + +## 更多示例 + +### 版本与分组 + +```xml + + +``` + +### 集群容错 +配置 failover 重试次数: + +```xml + + + + + +``` + +### 多协议 + +```xml + + + + + + + + + +``` + +### 多注册中心 +```xml + + + + + + + + + + + +``` + +### 全局默认值 +指定全局默认超时时间,多所有服务生效: + +```xml + + +``` + +基于分组的默认值: + +```xml + + + + + + + + + +``` + + + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/1.md new file mode 100644 index 000000000000..b071c05bcc50 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/1.md @@ -0,0 +1,29 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/1/ +- /zh-cn/docs3-v2/java-sdk/faq/0/1/ +- /zh-cn/overview/mannual/java-sdk/faq/0/1/ +description: 0-1 - 线程池资源枯竭 +linkTitle: 0-1 - 线程池资源枯竭 +title: 0-1 - 线程池资源枯竭 +type: docs +weight: 1 +--- + + +服务端的线程资源耗尽了。 +默认情况下,Dubbo 服务端的业务线程数是 200 个。如果多个并发请求量超过了 200,就会拒绝新的请求,抛出此错误。 + +### 可能的原因 +1. Consumer 的并发请求量太大,导致 Provider 端创建的线程数量超限。 +2. 可能 Provider 端在执行业务的时候,由于业务调用外部应用接口,导致线程出现阻塞,从而导致线程池回收不了线程。 + +### 排查和解决步骤 +* 开启 Dubbo 的访问日志功能,排查是否有短时间内大量调用 RPC 服务的情况。 +* 通过 `jps` 和 `jstack` 指令检查线程池中各个线程的状态,看下是否有业务调用外部应用接口造成阻塞。 +* 如果是 Consumer 的并发请求量太大,那么调整 Provider 端的 `dubbo.provider.threads` 参数,将 Dubbo 的线程池的数目调大。 +* 如果 Provider 业务的 QPS 实在太大,目前的服务器数目处理不完,那么增加 Provider 端服务器的数量,让更多的服务器分担压力。 + + +> 这个错误码的 FAQ 页面参考了空冥同学的 [《Dubbo 常见错误及解决方法》](https://github.com/StabilityMan/StabilityGuide/blob/master/docs/diagnosis/plugin/rpc/%E7%B3%BB%E7%BB%9F%E7%A8%B3%E5%AE%9A%E6%80%A7%E2%80%94%E2%80%94Dubbo%E5%B8%B8%E8%A7%81%E9%94%99%E8%AF%AF%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95.md) 。 +所引文章通过 [CC-BY-4.0](http://creativecommons.org/licenses/by/4.0/) 协议赋予了汇编的权利。在此向原作者表示感谢。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/10.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/10.md new file mode 100644 index 000000000000..fa3c0a1e2f19 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/10.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/10/ +- /zh-cn/docs3-v2/java-sdk/faq/0/10/ +- /zh-cn/overview/mannual/java-sdk/faq/0/10/ +description: 0-10 - 当前调用不在支持 +linkTitle: 0-10 - 当前调用不在支持 +title: 0-10 - 当前调用不在支持 +type: docs +weight: 10 +--- + + + + + + + +### 可能的原因 + +当前调用的方法可能已经被弃用或声明了 `@Deprecated`,不影响执行结果。 + +### 排查和解决步骤 + +请使用其它可替代的 API 方法。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/11.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/11.md new file mode 100644 index 000000000000..2f34f5bb4c8c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/11.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/11/ +- /zh-cn/docs3-v2/java-sdk/faq/0/11/ +- /zh-cn/overview/mannual/java-sdk/faq/0/11/ +description: 0-11 - 服务停止失败 +linkTitle: 0-11 - 服务停止失败 +title: 0-11 - 服务停止失败 +type: docs +weight: 11 +--- + + + + + + + +### 可能的原因 + +连接没有及时关闭或内存不足,导致服务在停止时会出现一些异常。 + +### 排查和解决步骤 + +在响应内容完成后进行关闭连接。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/12.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/12.md new file mode 100644 index 000000000000..d698476b0604 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/12.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/12/ +- /zh-cn/docs3-v2/java-sdk/faq/0/12/ +- /zh-cn/overview/mannual/java-sdk/faq/0/12/ +description: 0-12 - 未知异常 +linkTitle: 0-12 - 未知异常 +title: 0-12 - 未知异常 +type: docs +weight: 12 +--- + + + + + +未知异常,一般为API使用或配置异常 + +### 可能的原因 + +转码异常、不支持的加解密方法等等 + +### 排查和解决步骤 + +可根据堆栈信息,进行业务代码行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/13.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/13.md new file mode 100644 index 000000000000..2fee987fd875 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/13.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/13/ +- /zh-cn/docs3-v2/java-sdk/faq/0/13/ +- /zh-cn/overview/mannual/java-sdk/faq/0/13/ +description: 0-13 - 指标收集器发生异常 +linkTitle: 0-13 - 指标收集器发生异常 +title: 0-13 - 指标收集器发生异常 +type: docs +weight: 13 +--- + + + + + + + +### 可能的原因 + +指标数据在推送过程中发生错误,推送的服务器连接不上或一些配置错误,目前支持 Prometheus。 + +### 排查和解决步骤 + +请参考配置项参考手册[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/14.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/14.md new file mode 100644 index 000000000000..c673e002ce44 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/14.md @@ -0,0 +1,27 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/14/ +- /zh-cn/docs3-v2/java-sdk/faq/0/14/ +- /zh-cn/overview/mannual/java-sdk/faq/0/14/ +description: 0-14 - 监控异常 +linkTitle: 0-14 - 监控异常 +title: 0-14 - 监控异常 +type: docs +weight: 14 +--- + + + + + +用来统计 RPC 调用次数和调用耗时时间,扩展接口为 MonitorFactory,对应的实现类为 DubboMonitorFactroy。 + + +### 可能的原因 + +用户可以实现该层的 MonitorFactory 扩展接口,实现自定义监控统计策略。 +在自定义监控统计策略的实现类,发生了业务运行时异常。 + +### 排查和解决步骤 + +检查 `org.apache.dubbo.monitor.MonitorFactory` 接口的业务类,实现方法可能存在代码逻辑错误。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/15.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/15.md new file mode 100644 index 000000000000..17c75ddd70d6 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/15.md @@ -0,0 +1,29 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/15/ +- /zh-cn/docs3-v2/java-sdk/faq/0/15/ +- /zh-cn/overview/mannual/java-sdk/faq/0/15/ +description: 0-15 - 加载扩展类时发生异常 +linkTitle: 0-15 - 加载扩展类时发生异常 +title: 0-15 - 加载扩展类时发生异常 +type: docs +weight: 15 +--- + + + + + + + +### 可能的原因 + +1. `clazz` 类并没有实现当前扩展点的接口类。 +2. 扩展名可能是个接口或者不存在。 + +### 排查和解决步骤 + +1. 检查扩展类声明,并没有与之相匹配的扩展实现类。 +2. 扩展实现类需实现扩展点接口类以及方法。 + +

diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/16.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/16.md new file mode 100644 index 000000000000..3ac1e2167b59 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/16.md @@ -0,0 +1,27 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/16/ +- /zh-cn/docs3-v2/java-sdk/faq/0/16/ +- /zh-cn/overview/mannual/java-sdk/faq/0/16/ +description: 0-16 - 没有可用的执行器 +linkTitle: 0-16 - 没有可用的执行器 +title: 0-16 - 没有可用的执行器 +type: docs +weight: 16 +--- + + + + + + + +### 可能的原因 + +内部执行器不可用,此时返回空。 + +### 排查和解决步骤 + +不需要进行干预,dubbo 内部会执行`createExecutorIfAbsent` 方法构建一个新的执行器。 + +

diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/17.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/17.md new file mode 100644 index 000000000000..8d4887f156e4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/17.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/17/ +- /zh-cn/docs3-v2/java-sdk/faq/0/17/ +- /zh-cn/overview/mannual/java-sdk/faq/0/17/ +description: 0-17 - 执行器在关闭时发生未知异常 +linkTitle: 0-17 - 执行器在关闭时发生未知异常 +title: 0-17 - 执行器在关闭时发生未知异常 +type: docs +weight: 17 +--- + + + + + + + +### 可能的原因 + +可能使用了自定义的执行器,在编写销毁方法时,产生了异常。 + +### 排查和解决步骤 + +检查是否自定义实现 `org.apache.dubbo.common.threadpool.manager.ExecutorRepository`,检查自定义的 `shutdown` 方法。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/18.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/18.md new file mode 100644 index 000000000000..846e60e60923 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/18.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/18/ +- /zh-cn/docs3-v2/java-sdk/faq/0/18/ +- /zh-cn/overview/mannual/java-sdk/faq/0/18/ +description: 0-18 - 线程池执行器被错误使用 +linkTitle: 0-18 - 线程池执行器被错误使用 +title: 0-18 - 线程池执行器被错误使用 +type: docs +weight: 18 +--- + + + + + + + +### 可能的原因 + +自定义设置了线程数量,系统内部发生了未知异常。 + +### 排查和解决步骤 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/19.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/19.md new file mode 100644 index 000000000000..aa8fe7ef0b1f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/19.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/19/ +- /zh-cn/docs3-v2/java-sdk/faq/0/19/ +- /zh-cn/overview/mannual/java-sdk/faq/0/19/ +description: 0-19 - 处理任务时发生异常 +linkTitle: 0-19 - 处理任务时发生异常 +title: 0-19 - 处理任务时发生异常 +type: docs +weight: 19 +--- + + + + + + + +### 可能的原因 + +自定义业务类处理逻辑不当。 + +### 排查和解决步骤 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/2.md new file mode 100644 index 000000000000..f3ce40d87e52 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/2.md @@ -0,0 +1,18 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/2/ +- /zh-cn/docs3-v2/java-sdk/faq/0/2/ +- /zh-cn/overview/mannual/java-sdk/faq/0/2/ +description: 0-2 - 非法属性值 +linkTitle: 0-2 - 非法属性值 +title: 0-2 - 非法属性值 +type: docs +weight: 2 +--- + + +### 可能的原因 +这个提示是指用户配置的值与属性本身所需的数据类型并不匹配。比如 `dubbo.comsumer.threads` 属性只能接受数值属性,但是用户所输入的值混入了字母。 + +### 排查和解决步骤 +根据[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/),查找出错的配置项,检查该项指定的类型,检查是否出现类型不一致的情况。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/20.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/20.md new file mode 100644 index 000000000000..e9c985b73a82 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/20.md @@ -0,0 +1,27 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/20/ +- /zh-cn/docs3-v2/java-sdk/faq/0/20/ +- /zh-cn/overview/mannual/java-sdk/faq/0/20/ +description: 0-20 - 存储堆栈信息时发生异常 +linkTitle: 0-20 - 存储堆栈信息时发生异常 +title: 0-20 - 存储堆栈信息时发生异常 +type: docs +weight: 20 +--- + + + + + + + +### 可能的原因 + +1. JVM设置了参数 `-XX:+DisableAttachMechanism` +2. 设置了系统不存在的堆栈转储路径,不存在情况,系统会尝试进行创建,创建时发生了 `SecurityException`, 可能是没有权限。 + +### 排查和解决步骤 + +1. 检查 JVM 是否设置了如上参数。 +2. 检查当前启动服务的账号,是否有权限进行创建文件夹。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/21.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/21.md new file mode 100644 index 000000000000..918053167e85 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/21.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/21/ +- /zh-cn/docs3-v2/java-sdk/faq/0/21/ +- /zh-cn/overview/mannual/java-sdk/faq/0/21/ +description: 0-21 - 构建的实例过多 +linkTitle: 0-21 - 构建的实例过多 +title: 0-21 - 构建的实例过多 +type: docs +weight: 21 +--- + + + + + + +### 可能的原因 + +一般指 `org.apache.dubbo.common.timer.HashedWheelTimer` 创建的实例过多。 + +### 排查和解决步骤 + +不影响实例的构建,可能存在内存泄露的风险。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/22.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/22.md new file mode 100644 index 000000000000..5067b58c45b5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/22.md @@ -0,0 +1,31 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/22/ +- /zh-cn/docs3-v2/java-sdk/faq/0/22/ +- /zh-cn/overview/mannual/java-sdk/faq/0/22/ +description: 0-22 - 输入输出流异常 +linkTitle: 0-22 - 输入输出流异常 +title: 0-22 - 输入输出流异常 +type: docs +weight: 22 +--- + + + + + + + +### 可能的原因 + +1. 读取不再可用的本地文件。 +2. 尝试读取/写入文件但没有权限。 +3. 尝试写入文件但磁盘空间不再可用。 + +### 排查和解决步骤 + +1. 检查本地文件是否存在。 +2. 检查文件权限。 +3. 检查磁盘空间。 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/23.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/23.md new file mode 100644 index 000000000000..1f3ed674cbb5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/23.md @@ -0,0 +1,29 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/23/ +- /zh-cn/docs3-v2/java-sdk/faq/0/23/ +- /zh-cn/overview/mannual/java-sdk/faq/0/23/ +description: 0-23 - 序列化数据转换异常 +linkTitle: 0-23 - 序列化数据转换异常 +title: 0-23 - 序列化数据转换异常 +type: docs +weight: 23 +--- + + + + + + + +### 可能的原因 + +1. 待序列化数据中存在循环引用,导致堆栈溢出。 +2. 引用的 jar 包版本低或存在兼容性问题。 + +### 排查和解决步骤 + +1. 如使用 FastJson,去掉 `SerializerFeature.DisableCircularReferenceDetec` +2. 检查下或升级版本进行尝试。 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/24.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/24.md new file mode 100644 index 000000000000..95cbc29440cf --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/24.md @@ -0,0 +1,27 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/24/ +- /zh-cn/docs3-v2/java-sdk/faq/0/24/ +- /zh-cn/overview/mannual/java-sdk/faq/0/24/ +description: 0-24 - 覆盖字段值异常 +linkTitle: 0-24 - 覆盖字段值异常 +title: 0-24 - 覆盖字段值异常 +type: docs +weight: 24 +--- + + + + + + + +### 可能的原因 + +1. 实体类未设置 setter/getter 方法。 +2. 可能存在嵌套的属性。 + +### 排查和解决步骤 + +1. 检查实体类并设置 setter/getter 方法。 +2. 根据堆栈信息,检查是否使用嵌套注解。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/25.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/25.md new file mode 100644 index 000000000000..6c7fb5aa52da --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/25.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/25/ +- /zh-cn/docs3-v2/java-sdk/faq/0/25/ +- /zh-cn/overview/mannual/java-sdk/faq/0/25/ +description: 0-25 - 加载映射错误 +linkTitle: 0-25 - 加载映射错误 +title: 0-25 - 加载映射错误 +type: docs +weight: 25 +--- + + + + + + + +### 可能的原因 + +文件访问权限不足 + +### 排查和解决步骤 + +检查文件权限。 +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/26.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/26.md new file mode 100644 index 000000000000..55d6d86991cd --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/26.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/26/ +- /zh-cn/docs3-v2/java-sdk/faq/0/26/ +- /zh-cn/overview/mannual/java-sdk/faq/0/26/ +description: 0-26 - 元数据发布服务时的警告信息 +linkTitle: 0-26 - 元数据发布服务时的警告信息 +title: 0-26 - 元数据发布服务时的警告信息 +type: docs +weight: 26 +--- + + + + + + +### 可能的原因 + +元数据在存储接口与应用的映射关系时,显示的提醒类消息。 + +### 排查和解决步骤 + +一般可根据堆栈信息进行分析,也可不处理。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/27.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/27.md new file mode 100644 index 000000000000..35e39155f99e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/27.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/27/ +- /zh-cn/docs3-v2/java-sdk/faq/0/27/ +- /zh-cn/overview/mannual/java-sdk/faq/0/27/ +description: 0-27 - 线程池隔离配置异常 +linkTitle: 0-27 - 线程池隔离配置异常 +title: 0-27 - 线程池隔离配置异常 +type: docs +weight: 27 +--- + + + + + + +### 可能的原因 + +未开启应用的线程池隔离能力,但是却在 `ServiceConfig` 中配置了隔离的线程池信息。 + +### 排查和解决步骤 + +配置开启应用的线程池隔离能力:`dubbo.application.executor-management-mode=isolation` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/28.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/28.md new file mode 100644 index 000000000000..1755794dd97e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/28.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/28/ +- /zh-cn/docs3-v2/java-sdk/faq/0/28/ +- /zh-cn/overview/mannual/java-sdk/faq/0/28/ +description: 0-28 - 操作了可能会引起危险的行为 +linkTitle: 0-28 - 危险的行为 +title: 0-28 - 操作了可能会引起危险的行为 +type: docs +weight: 28 +--- + + + + + + +### 可能的原因 + +你执行了以下操作之一: +* 尝试或已经调整了 accesslog 的输出位置 + +### 排查和解决步骤 + +请检查应用配置中的 `accesslog.fixed.path=true` 开关是否处于开启状态,如未开启则可忽略;如果当前是开启状态,则请确认是否 acesslog 路径切换的行为是否为可信任的人所执行,以避免可能的安全风险。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/29.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/29.md new file mode 100644 index 000000000000..8ccd185b72a0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/29.md @@ -0,0 +1,39 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/29/ +- /zh-cn/docs3-v2/java-sdk/faq/0/29/ +- /zh-cn/overview/mannual/java-sdk/faq/0/29/ +description: 0-29 - 未找到Tracer依赖 +linkTitle: 0-29 - 未找到Tracer依赖 +title: 0-29 - 未找到Tracer依赖 +type: docs +weight: 29 +--- + +### 可能的原因 + +你已在配置文件中开启了tracing,但未找到Tracer依赖。 + +目前Tracer支持两种,OpenTelemetry和Brave。 + +### 排查和解决步骤 + +选择一个Tracer依赖到你的项目中: + +```xml + + + io.micrometer + micrometer-tracing-bridge-otel + true + +``` + +```xml + + + io.micrometer + micrometer-tracing-bridge-brave + true + +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/3.md new file mode 100644 index 000000000000..9ef6a66efdec --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/3.md @@ -0,0 +1,41 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/3/ +- /zh-cn/docs3-v2/java-sdk/faq/0/3/ +- /zh-cn/overview/mannual/java-sdk/faq/0/3/ +description: 0-3 - 无法访问缓存路径 +linkTitle: 0-3 - 无法访问缓存路径 +title: 0-3 - 无法访问缓存路径 +type: docs +weight: 3 +--- + + + + + + +其它模块复用了 Common 层的基于文件的缓存机制(目前是元数据模块),而 Common 层的文件缓存机制无法访问它指定的目录。 + +``` +2022-08-29 00:35:00,189 ERROR [org.apache.dubbo.common.cache.FileCacheStoreFactory:?] - [DUBBO] Cache store path can't be created: , dubbo version: , current host: 10.0.1.1, error code: 0-3. This may be caused by inaccessible of cache path, go to https://dubbo.apache.org/faq/0/3 to find instructions. +java.nio.file.FileAlreadyExistsException: [Path] + at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:87) + at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103) + at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108) + at java.base/sun.nio.fs.WindowsFileSystemProvider.createDirectory(WindowsFileSystemProvider.java:521) + at java.base/java.nio.file.Files.createDirectory(Files.java:700) + at java.base/java.nio.file.Files.createAndCheckIsDirectory(Files.java:807) + at java.base/java.nio.file.Files.createDirectories(Files.java:753) + at org.apache.dubbo.common.cache.FileCacheStoreFactory.getInstance(FileCacheStoreFactory.java:90) + ... +``` + +### 可能的原因 +1. 多个 Dubbo 进程(或其他 Java 进程)使用了同一个缓存文件。 +2. 由于缓存文件所在目录的文件系统权限问题,导致读写失败。 + +### 排查和解决步骤 +1. 根据下面显示的实际异常找到访问不了的目录,确定下它的文件访问权限。 +2. 确定下是否有别的 Dubbo 实例正在访问这个路径。 +3. 尝试配置 **Java System Property(用 -D 配置的 Java 系统属性)** `dubbo.meta.cache.filePath` 和 `dubbo.mapping.cache.filePath`,将它指定成一个当前用户能够完全控制的目录下。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/4.md new file mode 100644 index 000000000000..81d308067bb2 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/4.md @@ -0,0 +1,58 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/4/ +- /zh-cn/docs3-v2/java-sdk/faq/0/4/ +- /zh-cn/overview/mannual/java-sdk/faq/0/4/ +description: 0-4 - 缓存条目超限 +linkTitle: 0-4 - 缓存条目超限 +title: 0-4 - 缓存条目超限 +type: docs +weight: 4 +--- + + + + + +其它模块复用了 Common 层的基于文件的缓存机制(目前是元数据模块),而 Common 层的文件缓存机制 “发觉” 条目超限。 + + +### 可能的原因 +用户不合理地配置了 **Java System Property** (用 -D 配置的 Java 系统属性) `dubbo.mapping.cache.entrySize` 或者 `dubbo.meta.cache.entrySize` + +**默认值** + + + + + + + + + + + + +
dubbo.mapping.cache.entrySizedubbo.meta.cache.entrySize
10000100
+ +### 排查和解决步骤 +1. 尝试重新配置上述 **Java System Property(用 -D 配置的 Java 系统属性)**。 +2. 如果确实没有配置这些 **System Property**,请到 [GitHub Issue Tracker](https://github.com/apache/dubbo/issues) 下发 Issue。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/5.md new file mode 100644 index 000000000000..61e8bf0472bd --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/5.md @@ -0,0 +1,33 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/5/ +- /zh-cn/docs3-v2/java-sdk/faq/0/5/ +- /zh-cn/overview/mannual/java-sdk/faq/0/5/ +description: 0-5 - 缓存文件大小超限 +linkTitle: 0-5 - 缓存文件大小超限 +title: 0-5 - 缓存文件大小超限 +type: docs +weight: 5 +--- + + + + + +其它模块复用了 Common 层的基于文件的缓存机制(目前是元数据模块),而 Common 层的文件缓存机制 “发觉” 文件大小超限。 + + +### 可能的原因 +1. 用户不合理地配置了 Java System Property (用 -D 配置的 Java 系统属性) `dubbo.mapping.cache.maxFileSize` 或者 `dubbo.meta.cache.maxFileSize` +2. 缓存文件因文件系统或磁盘错误而被破坏。 + + +> `dubbo.mapping.cache.maxFileSize` 和 `dubbo.meta.cache.maxFileSize` 没有显示默认值, +而根据 `org.apache.dubbo.common.cache.FileCacheStore.LimitedLengthBufferedWriter` 的逻辑而查到的最大文件大小的默认值为:`Long.MAX_VALUE` ( 263-1 ) 。 + + + +### 排查和解决步骤 +1. 尝试重新配置上述 **Java System Property(用 -D 配置的 Java 系统属性)**。 +2. 删除缓存文件夹重启 **Provider** 和 **Consumer** (缓存文件夹的位置一般在 `~/.dubbo`。如果配置了 `dubbo.meta.cache.filePath` 和 `dubbo.mapping.cache.filePath` 则为该路径)。 +3. 如果确实没有配置这些 **System Property**,请到 [GitHub Issue Tracker](https://github.com/apache/dubbo/issues) 下发 Issue。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/6.md new file mode 100644 index 000000000000..a96fca69ec2c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/6.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/6/ +- /zh-cn/docs3-v2/java-sdk/faq/0/6/ +- /zh-cn/overview/mannual/java-sdk/faq/0/6/ +description: 0-6 - 线程中断异常 +linkTitle: 0-6 - 线程中断异常 +title: 0-6 - 线程中断异常 +type: docs +weight: 6 +--- + + + + + + + +### 可能的原因 + +运行中的线程在处于 `wait、sleep、join` 时,被显示调用 `interrupt()` + +### 排查和解决步骤 + +正常运行的线程在调用了 `interrupt()` 方法后,将对当前线程中断状态设置为 true,但线程的执行并不会受到影响。 +可根据实际情况进行操作或检查业务代码有无被错误使用。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/7.md new file mode 100644 index 000000000000..22fa36806e0a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/7.md @@ -0,0 +1,27 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/7/ +- /zh-cn/docs3-v2/java-sdk/faq/0/7/ +- /zh-cn/overview/mannual/java-sdk/faq/0/7/ +description: 0-7 - 未找到反射类 +linkTitle: 0-7 - 未找到反射类 +title: 0-7 - 未找到反射类 +type: docs +weight: 7 +--- + + + + + + + +### 可能的原因 + +1. 一般是 `Class.forName(className)` 执行此方法时,找不到 `className` 当前类。 +2. 业务代码上显示排除了当前 `className` 类,导致加载时未找到。 + +### 排查和解决步骤 + +1. 检查 `Class.forName(className)` 中,`className` 是否存在。 +2. 排查业务代码,有没有使用配置或扫描注解 `exclude` 排除了一些类或包。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/8.md new file mode 100644 index 000000000000..0d2d78d8056e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/8.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/8/ +- /zh-cn/docs3-v2/java-sdk/faq/0/8/ +- /zh-cn/overview/mannual/java-sdk/faq/0/8/ +description: 0-8 - 反射失败 +linkTitle: 0-8 - 反射失败 +title: 0-8 - 反射失败 +type: docs +weight: 8 +--- + + + + + + + +### 可能的原因 + +在反射调用某方法时,未对当前方法设置正确的参数类型值,也就是参数类型不匹配。 + +### 排查和解决步骤 + +检查是否存在未正确设置相匹配的类型值。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/9.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/9.md new file mode 100644 index 000000000000..9746c1eb4a44 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/9.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/9/ +- /zh-cn/docs3-v2/java-sdk/faq/0/9/ +- /zh-cn/overview/mannual/java-sdk/faq/0/9/ +description: 0-9 - 通知事件失败 +linkTitle: 0-9 - 通知事件失败 +title: 0-9 - 通知事件失败 +type: docs +weight: 9 +--- + + + + + + + +### 可能的原因 + +自定义的监听器,在处理上产生了运行时异常。 + +### 排查和解决步骤 + +检查实现 `org.apache.dubbo.rpc.ExporterListener` 接口的业务类,实现方法可能存在代码逻辑错误。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/99.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/99.md new file mode 100644 index 000000000000..6c97fb8ef714 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/99.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/99/ +- /zh-cn/docs3-v2/java-sdk/faq/0/99/ +- /zh-cn/overview/mannual/java-sdk/faq/0/99/ +description: 0-99 - 调用了过时 (Deprecated) 的方法 +linkTitle: 0-99 - 调用了过时 (Deprecated) 的方法 +title: 0-99 - 调用了过时 (Deprecated) 的方法 +type: docs +weight: 99 +--- + + + + + + +### 可能的原因 + +用户调用了过时 (Deprecated) 的方法。 + +### 排查和解决步骤 + +检查用户代码有没有调用了什么在目前所用的版本声明为 @Deprecated 的方法,如果有则按照其对应方法替代,如无则忽略即可。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/_index.md new file mode 100644 index 000000000000..47f4da13de72 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/_index.md @@ -0,0 +1,18 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/0/ +- /zh-cn/docs3-v2/java-sdk/faq/0/ +- /zh-cn/overview/mannual/java-sdk/faq/0/_index/ +description: 0 - Common 层 +linkTitle: 0 - Common 层 +title: 0 - Common 层 +type: docs +weight: 1 +--- + + + + + + +这里主要是用于表示各个层通用的组件上所发生的错误。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/1.md new file mode 100644 index 000000000000..1008ca725924 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/1.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/1/ +- /zh-cn/docs3-v2/java-sdk/faq/1/1/ +- /zh-cn/overview/mannual/java-sdk/faq/1/1/ +description: 1-1 - 地址非法 +linkTitle: 1-1 - 地址非法 +title: 1-1 - 地址非法 +type: docs +weight: 1 +--- + + + + + + +此日志可以忽略,服务版本或分组不匹配。仅出现在 zookeeper 注册中心中,在 3.1.7 版本中已经取消此检查。 + +### 可能的原因 +1. Provider 端配置的 `service.group` 和 Consumer 端配置的 `reference.group` (即服务分组的配置)不匹配。 +2. Provider 端配置的 `service.version` 和 Consumer 端配置的 `reference.version` (即服务版本的配置)不匹配。 + +### 排查和解决步骤 +可以忽略,在 3.1.7 版本中已经取消此检查。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/10.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/10.md new file mode 100644 index 000000000000..569d0035c0b6 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/10.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/10/ +- /zh-cn/docs3-v2/java-sdk/faq/1/10/ +- /zh-cn/overview/mannual/java-sdk/faq/1/10/ +description: 1-10 - 读写注册中心服务缓存失败 +linkTitle: 1-10 - 读写注册中心服务缓存失败 +title: 1-10 - 读写注册中心服务缓存失败 +type: docs +weight: 10 +--- + + + + + + +### 可能的原因 +1. 多个 Dubbo 进程使用了同一个缓存文件。 +2. 在多注册中心的情况下,指定了多个注册中心使用同一文件存储。 + +### 排查和解决步骤 +该错误常与 1-9 错误共同出现。检查是否有多个 Dubbo 进程使用了同一个缓存文件或者是否指定多个注册中心使用同一缓存文件。 + +> 另请参阅 +[注册中心的配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#registry) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/11.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/11.md new file mode 100644 index 000000000000..27ac6ef07c89 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/11.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/11/ +- /zh-cn/docs3-v2/java-sdk/faq/1/11/ +- /zh-cn/overview/mannual/java-sdk/faq/1/11/ +description: 1-11 - 注册服务实例创建失败 +linkTitle: 1-11 - 注册服务实例创建失败 +title: 1-11 - 注册服务实例创建失败 +type: docs +weight: 11 +--- + + + + + + +### 可能的原因 +可能是 Registry 的 SPI/IOC 配置出错导致。 +### 排查和解决步骤 +该错误为 Dubbo 内部错误,如果您遇到可以在 github 创建 Issue 并提供错误信息以及复现步骤,我们将协助您解决问题。 + +> 另请参阅 +[Dubbo社区](https://github.com/apache/dubbo) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/12.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/12.md new file mode 100644 index 000000000000..7063e0382144 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/12.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/12/ +- /zh-cn/docs3-v2/java-sdk/faq/1/12/ +- /zh-cn/overview/mannual/java-sdk/faq/1/12/ +description: 1-12 - “注册服务” 的实例均已销毁 +linkTitle: 1-12 - “注册服务” 的实例均已销毁 +title: 1-12 - “注册服务” 的实例均已销毁 +type: docs +weight: 12 +--- + + + + + + +### 可能的原因 +在 Dubbo 优雅停机的过程中,通过调用 `AbstractRegistryFactory` 的 `destroyAll` 进行解注册。 + +销毁 `Registryprotocol` 的 `unexport` 的过程中,会通过 `AbstractRegistryFactory` 的 `getRegistry` 来试图获得已经被销毁的 registry ,这导致了 “注册服务” 的实例均已销毁。 + +### 排查和解决步骤 +> 另请参阅 +[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/13.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/13.md new file mode 100644 index 000000000000..40a20e7f6206 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/13.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/13/ +- /zh-cn/docs3-v2/java-sdk/faq/1/13/ +- /zh-cn/overview/mannual/java-sdk/faq/1/13/ +description: 1-13 - 执行重试任务失败 +linkTitle: 1-13 - 执行重试任务失败 +title: 1-13 - 执行重试任务失败 +type: docs +weight: 13 +--- + + + + + + +### 可能的原因 +1. 注册中心离线。 + +### 排查和解决步骤 + +1. 检查注册中心是否正常工作。 +2. 检查注册中心所在服务器及其网络是否正常工作。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/14.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/14.md new file mode 100644 index 000000000000..44c9cdeba35f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/14.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/14/ +- /zh-cn/docs3-v2/java-sdk/faq/1/14/ +- /zh-cn/overview/mannual/java-sdk/faq/1/14/ +description: 1-14 - 动态配置识别失败 +linkTitle: 1-14 - 动态配置识别失败 +title: 1-14 - 动态配置识别失败 +type: docs +weight: 14 +--- + + + + + + +### 可能的原因 + 在使用 dubbo admin 的服务治理功能进行动态配置时,配置文件的内容或者格式不正确会导致无法解析动态配置的内容,产生 1-14 错误。 +### 排查和解决步骤 + 请检查动态配置文件的内容或者格式是否正确。 + + +### 另请参阅 +> [配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/15.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/15.md new file mode 100644 index 000000000000..fd7cb427f5e5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/15.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/15/ +- /zh-cn/docs3-v2/java-sdk/faq/1/15/ +- /zh-cn/overview/mannual/java-sdk/faq/1/15/ +description: 1-15 - 销毁服务失败 +linkTitle: 1-15 - 销毁服务失败 +title: 1-15 - 销毁服务失败 +type: docs +weight: 15 +--- + + + + + + +### 可能的原因 + 在 RegistryDirectory 中销毁所有的 invoker 时抛出异常则可能触发 1-15 错误。 + +### 排查和解决步骤 +该错误为 Dubbo 内部错误,如果您遇到可以在 github 创建 Issue 并提供错误信息以及复现步骤,我们将协助您解决问题。 + + +> 另请参阅 [Dubbo 社区](https://github.com/apache/dubbo) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/16.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/16.md new file mode 100644 index 000000000000..de182f9073f5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/16.md @@ -0,0 +1,27 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/16/ +- /zh-cn/docs3-v2/java-sdk/faq/1/16/ +- /zh-cn/overview/mannual/java-sdk/faq/1/16/ +description: 1-16 - 存在不支持的类别 +linkTitle: 1-16 - 存在不支持的类别 +title: 1-16 - 存在不支持的类别 +type: docs +weight: 16 +--- + + + + + + +### 可能的原因 + 当注册中心的发生变化时,会 notify 对应的 listener。在 notify 的时候如果 category 非法,则会产生存在不支持的类别。 + + +### 排查和解决步骤 + 该错误为 Dubbo 内部错误,如果您遇到可以在 github 创建 Issue 并提供错误信息以及复现步骤,我们将协助您解决问题。 + + +> 另请参阅 +[Dubbo社区](https://github.com/apache/dubbo) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/17.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/17.md new file mode 100644 index 000000000000..5b11decd5c40 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/17.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/17/ +- /zh-cn/docs3-v2/java-sdk/faq/1/17/ +- /zh-cn/overview/mannual/java-sdk/faq/1/17/ +description: 1-17 - metadata Server 失效 +linkTitle: 1-17 - metadata Server 失效 +title: 1-17 - metadata Server 失效 +type: docs +weight: 17 +--- + + + + + + +### 可能的原因 +可能是 metadata 的相关参数配置出现问题,特别是 `metadataServiceProtocol` 和 `metadataServicePort`. + +### 排查和解决步骤 +1. 查看是否和未提供 metadata service 端口同时出现,如果同时出现优先尝试解决未提供 metadata service 端口。**(1-18 FAQ)** +2. 排查 `metadataServicePort` 端口号是否存在冲突问题。Provider 和 Consumer 所配置端口同时存在冲突,会产生 metadata Server 失效。 + +> 另请参阅 +[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/18.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/18.md new file mode 100644 index 000000000000..74223b62c157 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/18.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/18/ +- /zh-cn/docs3-v2/java-sdk/faq/1/18/ +- /zh-cn/overview/mannual/java-sdk/faq/1/18/ +description: 1-18 - 未提供 metadata service 端口 +linkTitle: 1-18 - 未提供 metadata service 端口 +title: 1-18 - 未提供 metadata service 端口 +type: docs +weight: 18 +--- + + + + + + +### 可能的原因 +可能是由于`metadataType`为 local 模式,且 `metadataServicePort` 配置出错。 + +### 排查和解决步骤 +1.检查 Provider 侧的 `metadataType` 属性值。 +2.检查 Provider 侧的 `metadataServicePort` 配置是否正确,特别注意是否和其他应用端口存在冲突。 + +> 另请参阅 +[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/19.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/19.md new file mode 100644 index 000000000000..0fc37b8b4270 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/19.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/19/ +- /zh-cn/docs3-v2/java-sdk/faq/1/19/ +- /zh-cn/overview/mannual/java-sdk/faq/1/19/ +description: 1-19 - K8S监听异常 +linkTitle: 1-19 - K8S监听异常 +title: 1-19 - K8S监听异常 +type: docs +weight: 19 +--- + + + + + + +### 可能的原因 + +1. K8S 自定义的资源类型,配置被修改或已被容器移除。 +2. K8S 容器与服务已断开连接。 + +### 排查和解决步骤 + +1. 检查自定义的资源类型,配置是否正确。语法或可请参考 K8S 的官方文档。 +2. 检查网络是否正常或端口映射是否正确。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/20.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/20.md new file mode 100644 index 000000000000..e7ceded9d8ef --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/20.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/20/ +- /zh-cn/docs3-v2/java-sdk/faq/1/20/ +- /zh-cn/overview/mannual/java-sdk/faq/1/20/ +description: 1-20 - K8S Pod不存在 +linkTitle: 1-20 - K8S Pod不存在 +title: 1-20 - K8S Pod不存在 +type: docs +weight: 20 +--- + + + + + + +### 可能的原因 +1. 控制器 Pending +2. Pod 可能不存在或已被容器移除。 + +### 排查和解决步骤 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/21.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/21.md new file mode 100644 index 000000000000..db786def449a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/21.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/21/ +- /zh-cn/docs3-v2/java-sdk/faq/1/21/ +- /zh-cn/overview/mannual/java-sdk/faq/1/21/ +description: 1-21 - K8S 无可用服务 +linkTitle: 1-21 - K8S 无可用服务 +title: 1-21 - K8S 无可用服务 +type: docs +weight: 21 +--- + + + + + + +### 可能的原因 + +1. 当前服务未正确加载。 +2. 配置的Pod确实不存在当前实例服务。 + +### 排查和解决步骤 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/22.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/22.md new file mode 100644 index 000000000000..a40dcae5873a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/22.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/22/ +- /zh-cn/docs3-v2/java-sdk/faq/1/22/ +- /zh-cn/overview/mannual/java-sdk/faq/1/22/ +description: 1-22 - K8S 配置地址错误 +linkTitle: 1-22 - K8S 配置地址错误 +title: 1-22 - K8S 配置地址错误 +type: docs +weight: 22 +--- + + + + + + +### 可能的原因 + +K8S url 配置错误,无法正常访问。 + +### 排查和解决步骤 + +检查 K8S url 配置信息,确保端口映射也可正常访问。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/26.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/26.md new file mode 100644 index 000000000000..b1d6cfcdd05c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/26.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/26/ +- /zh-cn/docs3-v2/java-sdk/faq/1/26/ +- /zh-cn/overview/mannual/java-sdk/faq/1/26/ +description: 1-26 - xDS 证书生成失败 +linkTitle: 1-26 - xDS 证书生成失败 +title: 1-26 - xDS 证书生成失败 +type: docs +weight: 26 +--- + + + + + + +### 可能的原因 + +系统可能不支持算法 `secp256r1` 和 `RSA` 生成证书。 + +### 排查和解决步骤 + +检测操作系统是否支持 `secp256r1` 和 `RSA` 算法。需下载对于的 dll 文件或 lib diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/27.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/27.md new file mode 100644 index 000000000000..55f37967e2c2 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/27.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/27/ +- /zh-cn/docs3-v2/java-sdk/faq/1/27/ +- /zh-cn/overview/mannual/java-sdk/faq/1/27/ +description: 1-27 - K8S监听异常 +linkTitle: 1-27 - K8S监听异常 +title: 1-27 - K8S监听异常 +type: docs +weight: 27 +--- + + + + + + +### 可能的原因 + +系统可能不支持算法 `secp256r1` 和 `RSA` 生成证书。 + +### 排查和解决步骤 + +检测操作系统是否支持 `secp256r1` 和 `RSA` 算法。需下载对于的 dll 文件或 lib diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/28.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/28.md new file mode 100644 index 000000000000..a3eeaf89dd2e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/28.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/28/ +- /zh-cn/docs3-v2/java-sdk/faq/1/28/ +- /zh-cn/overview/mannual/java-sdk/faq/1/28/ +description: 1-28 - xDS 存根错误 +linkTitle: 1-28 - xDS 存根错误 +title: 1-28 - xDS 存根错误 +type: docs +weight: 28 +--- + + + + + + +### 可能的原因 + +当前 pod 或已宕机。 + +### 排查和解决步骤 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/29.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/29.md new file mode 100644 index 000000000000..802658d09e25 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/29.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/29/ +- /zh-cn/docs3-v2/java-sdk/faq/1/29/ +- /zh-cn/overview/mannual/java-sdk/faq/1/29/ +description: 1-29 - xDS 读取文件失败 +linkTitle: 1-29 - xDS 读取文件失败 +title: 1-29 - xDS 读取文件失败 +type: docs +weight: 29 +--- + + + + + + +### 可能的原因 + +网络断开或目标文件此时已损坏。 + +### 排查和解决步骤 + +1. 网络是否正常。 +2. 可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/3.md new file mode 100644 index 000000000000..05d05db1d85b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/3.md @@ -0,0 +1,23 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/3/ +- /zh-cn/docs3-v2/java-sdk/faq/1/3/ +- /zh-cn/overview/mannual/java-sdk/faq/1/3/ +description: 1-3 - URL 销毁失败 +linkTitle: 1-3 - URL 销毁失败 +title: 1-3 - URL 销毁失败 +type: docs +weight: 3 +--- + + + + + + +### 可能的原因 +当`FrameworkExecutorRepository`被销毁以后,调用`CacheableFailbackRegistry.evictURLCache`会导致销毁失败,产生错误码。 + +### 排查和解决步骤 + +> 另请参阅 [配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/30.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/30.md new file mode 100644 index 000000000000..c2e83cc52d07 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/30.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/30/ +- /zh-cn/docs3-v2/java-sdk/faq/1/30/ +- /zh-cn/overview/mannual/java-sdk/faq/1/30/ +description: 1-30 - xDS 请求失败 +linkTitle: 1-30 - xDS 请求失败 +title: 1-30 - xDS 请求失败 +type: docs +weight: 30 +--- + + + + + + +### 可能的原因 + +1. 版本可能不一致或不兼容。 +2. 读取数据时超时。 +3. 参数配置有问题。 + +### 排查和解决步骤 + +1. 可根据第三方官网介绍进行适配。 +2. 确认是否是超时时间设置过短或服务端存在问题。 +3. 检测端口的映射关系是否正确。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/31.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/31.md new file mode 100644 index 000000000000..59cd265f6ae2 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/31.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/31/ +- /zh-cn/docs3-v2/java-sdk/faq/1/31/ +- /zh-cn/overview/mannual/java-sdk/faq/1/31/ +description: 1-31 - xDS 响应失败 +linkTitle: 1-31 - xDS 响应失败 +title: 1-31 - xDS 响应失败 +type: docs +weight: 31 +--- + + + + + + +### 可能的原因 + +1. 客户端服务已断开与服务端的连接。 +2. 服务端不可用或已脱机。 + +### 排查和解决步骤 + +1. 排查服务端是否已脱机或客户端的网络断开。 +2. 排查服务端服务是否正常,并可通过网络进行接口请求。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/32.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/32.md new file mode 100644 index 000000000000..0c2ab9d7cb20 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/32.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/32/ +- /zh-cn/docs3-v2/java-sdk/faq/1/32/ +- /zh-cn/overview/mannual/java-sdk/faq/1/32/ +description: 1-32 - xDS Channel 初始化失败 +linkTitle: 1-32 - xDS Channel 初始化失败 +title: 1-32 - xDS Channel 初始化失败 +type: docs +weight: 32 +--- + + + + + + +### 可能的原因 + +1. 版本可能不一致或不兼容。 +2. 读取数据时超时。 +3. 参数配置有问题。 + +### 排查和解决步骤 + +1. 可根据第三方官网介绍进行适配。 +2. 确认是否是超时时间设置过短或服务端存在问题。 +3. 检测端口的映射关系是否正确。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/33.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/33.md new file mode 100644 index 000000000000..06ee64f207fc --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/33.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/33/ +- /zh-cn/docs3-v2/java-sdk/faq/1/33/ +- /zh-cn/overview/mannual/java-sdk/faq/1/33/ +description: 1-33 - xDS 服务发现初始化失败 +linkTitle: 1-33 - xDS 服务发现初始化失败 +title: 1-33 - xDS 服务发现初始化失败 +type: docs +weight: 33 +--- + + + + + + +### 可能的原因 + +1. xDS 模式下的注册中心,地址配置错误。 +2. 防火墙及第三方防护软件,导致无法对外提供连接。 + +### 排查和解决步骤 + +1. 检查 xDS 配置是否正确,检查 Istio 状态是否正常。 +2. 检查防火墙配置或使用 cmd 的 `ping` 命令进行基本检测。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/34.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/34.md new file mode 100644 index 000000000000..12a92898a06a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/34.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/34/ +- /zh-cn/docs3-v2/java-sdk/faq/1/34/ +- /zh-cn/overview/mannual/java-sdk/faq/1/34/ +description: 1-34 - xDS 解析发生错误 +linkTitle: 1-34 - xDS 解析发生错误 +title: 1-34 - xDS 解析发生错误 +type: docs +weight: 34 +--- + + + + + + +### 可能的原因 + +xDS 协议内容存在错误。 + +### 排查和解决步骤 + +可根据堆栈打印的 Endpoints List 进行原因定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/35.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/35.md new file mode 100644 index 000000000000..b44713ebfc1d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/35.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/35/ +- /zh-cn/docs3-v2/java-sdk/faq/1/35/ +- /zh-cn/overview/mannual/java-sdk/faq/1/35/ +description: 1-35 - ZK 异常 +linkTitle: 1-35 - ZK 异常 +title: 1-35 - ZK 异常 +type: docs +weight: 35 +--- + + + + + + +### 可能的原因 + +1. ZK 无法连接里或连接超时。 +2. ZNode 在创建时已存在。 + +### 排查和解决步骤 + +1. 检查 ZK 配置 IP 和 端口号是否正确。可使用第三方工具 ZooInspector 进行连接测试。 +2. 根据堆栈提醒 ZNode 信息进行判断,是否可清理当前节点。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/36.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/36.md new file mode 100644 index 000000000000..e6c865194246 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/36.md @@ -0,0 +1,22 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/36/ +- /zh-cn/docs3-v2/java-sdk/faq/1/36/ +- /zh-cn/overview/mannual/java-sdk/faq/1/36/ +description: 1-36 - 未知异常 +linkTitle: 1-36 - 未知异常 +title: 1-36 - 未知异常 +type: docs +weight: 36 +--- + + + + + + +### 可能的原因 +该错误码的意义已经调整。对于 Dubbo 3.1.4、3.2.0-beta.3 及其之前的版本的该错误码的出错,请参考错误码 [99-0](/zh-cn/overview/mannual/java-sdk/faq/99/0/)。 + +### 排查和解决步骤 +(该错误码目前空缺) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/37.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/37.md new file mode 100644 index 000000000000..7251ac02312e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/37.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/37/ +- /zh-cn/docs3-v2/java-sdk/faq/1/37/ +- /zh-cn/overview/mannual/java-sdk/faq/1/37/ +description: 1-37 - Nacos 异常 +linkTitle: 1-37 - Nacos 异常 +title: 1-37 - Nacos 异常 +type: docs +weight: 37 +--- + + + + + + +### 可能的原因 + +Nacos 配置信息未正确配置。 + +### 排查和解决步骤 + +检查配置 Nacos 的 ip 和端口号是否正确,如果开启了 Nacos 的安全认证,检查用户名和密码配置是否正确。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/38.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/38.md new file mode 100644 index 000000000000..39140dc17469 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/38.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/38/ +- /zh-cn/docs3-v2/java-sdk/faq/1/38/ +- /zh-cn/overview/mannual/java-sdk/faq/1/38/ +description: 1-38 - Socket 连接异常 +linkTitle: 1-38 - Socket 连接异常 +title: 1-38 - Socket 连接异常 +type: docs +weight: 38 +--- + + + + + + +### 可能的原因 + +1. 连接被拒绝。 +2. 连接已经关闭。 + +### 排查和解决步骤 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/39.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/39.md new file mode 100644 index 000000000000..ec4c03a808e4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/39.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/39/ +- /zh-cn/docs3-v2/java-sdk/faq/1/39/ +- /zh-cn/overview/mannual/java-sdk/faq/1/39/ +description: 1-39 - 获取元数据失败 +linkTitle: 1-39 - 获取元数据失败 +title: 1-39 - 获取元数据失败 +type: docs +weight: 39 +--- + + + + + + +### 可能的原因 + +1. 元数据中心已与应用服务断开连接。 +2. 元数据中心的数据或已被修改。 + +### 排查和解决步骤 + +1. 检查网络通信是否正常,可使用一些简单的 cmd 命令进行检测,如 `ping` 等。 +2. 通过第三方工具进行连接,以及内容的查看。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/4.md new file mode 100644 index 000000000000..7ff6c3c87f59 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/4.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/4/ +- /zh-cn/docs3-v2/java-sdk/faq/1/4/ +- /zh-cn/overview/mannual/java-sdk/faq/1/4/ +description: 1-4 - 空地址 +linkTitle: 1-4 - 空地址 +title: 1-4 - 空地址 +type: docs +weight: 4 +--- + + + + + + +### 可能的原因 +1. registry.integration.RegistryDirectory 中的1-4错误是refreshInvoker过程中invokerUrls为空导致的,可以忽略。 +2. registry.support.CacheableFailbackRegistry 中的1-4错误可能是consumer和provider不匹配,并且关闭了“空保护”所导致。 + +### 排查和解决步骤 +1. 确保 Provider 和 Consumer 端的服务分组配置相对应。 +2. 确保 Provider 和 Consumer 端的服务版本配置相对应。 +3. 检查注册中心的`enable-empty-protection`是否为true(默认为true)。 + +> 另请参阅 +[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/40.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/40.md new file mode 100644 index 000000000000..8616825fdfc4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/40.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/40/ +- /zh-cn/docs3-v2/java-sdk/faq/1/40/ +- /zh-cn/overview/mannual/java-sdk/faq/1/40/ +description: 1-40 - 路由等待时间过长 +linkTitle: 1-40 - 路由等待时间过长 +title: 1-40 - 路由等待时间过长 +type: docs +weight: 40 +--- + + + + + + +### 可能的原因 + +路由计算的时间过长,导致地址通知无法等待到一个合适的时间进行地址更新。 + +### 排查和解决步骤 + +1. 检查应用 QPS,如果 QPS 非常高,这个是预期的日志 +2. 检查自定义路由的实现,排查是否有异常实现,例如死锁、死循环等 +3. 可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/41.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/41.md new file mode 100644 index 000000000000..70ed5ce565e5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/41.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/41/ +- /zh-cn/docs3-v2/java-sdk/faq/1/41/ +- /zh-cn/overview/mannual/java-sdk/faq/1/41/ +description: 1-41 - Istio 异常 +linkTitle: 1-41 - Istio 异常 +title: 1-41 - Istio 异常 +type: docs +weight: 41 +--- + + + + + + +### 可能的原因 + +获取 istio 的配置文件失败 + +### 排查和解决步骤 + +检查应用是否部署在 Kubernetes Pod 环境中,目前暂不支持 VM 部署。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/42.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/42.md new file mode 100644 index 000000000000..0ae6ae4e1c65 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/42.md @@ -0,0 +1,19 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/42/ +- /zh-cn/docs3-v2/java-sdk/faq/1/42/ +- /zh-cn/overview/mannual/java-sdk/faq/1/42/ +description: 1-42 - Nacos 存在低版本服务 +linkTitle: 1-42 - Nacos 存在低版本服务 +title: 1-42 - Nacos 存在低版本服务 +type: docs +weight: 42 +--- + +### 可能的原因 + +Nacos 注册中心订阅到了老版本的服务,通常是服务端 Dubbo 版本低于 2.7.3 导致的。 + +### 排查和解决步骤 + +升级服务端到最新稳定版本。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/5.md new file mode 100644 index 000000000000..0856e38ede3e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/5.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/5/ +- /zh-cn/docs3-v2/java-sdk/faq/1/5/ +- /zh-cn/overview/mannual/java-sdk/faq/1/5/ +description: 1-5 - 接收到没有任何参数的 URL +linkTitle: 1-5 - 接收到没有任何参数的 URL +title: 1-5 - 接收到没有任何参数的 URL +type: docs +weight: 5 +--- + + + + + + +### 可能的原因 +在调用 `CacheableFailbackRegistry.toUrlsWithoutEmpty` 时,若传入的参数 `Collectionproviders` 中存在某个 provider 其没有任何参数的话,就会接收到没有任何参数的 URL。 +### 排查和解决步骤 +该错误为 Dubbo 内部错误,如果您遇到可以在 github 创建 Issue 并提供错误信息以及复现步骤,我们将协助您解决问题。 + +> 另请参阅 +[Dubbo社区](https://github.com/apache/dubbo) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/6.md new file mode 100644 index 000000000000..c958f75f0418 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/6.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/6/ +- /zh-cn/docs3-v2/java-sdk/faq/1/6/ +- /zh-cn/overview/mannual/java-sdk/faq/1/6/ +description: 1-6 - 清空URL缓存出错 +linkTitle: 1-6 - 清空URL缓存出错 +title: 1-6 - 清空URL缓存出错 +type: docs +weight: 6 +--- + + + + + + +### 可能的原因 +在`CacheableFailbackRegistry.RemovalTask`清空 url 缓存时候出错将会触发清空 URL 缓存出错。 + +### 排查和解决步骤 +该错误为 Dubbo 内部错误,如果您遇到可以在 github 创建 **issues** 并提供错误信息以及复现步骤,我们将协助您解决问题。 + +> 另请参阅 +[Dubbo社区](https://github.com/apache/dubbo) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/7.md new file mode 100644 index 000000000000..03355ae06d72 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/7.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/7/ +- /zh-cn/docs3-v2/java-sdk/faq/1/7/ +- /zh-cn/overview/mannual/java-sdk/faq/1/7/ +description: 1-7 - 通知注册事件失败 +linkTitle: 1-7 - 读写注册中心服务缓存失败 +title: 1-7 - 通知注册事件失败 +type: docs +weight: 7 +--- + + + + + + +### 可能的原因 + +1. 在应用于基于 xDS 协议的相关平台时,在更新元数据时,需要通知 consumer ,如果某个 consumer 离线会导致通知失败,并移除对应 consumer 的 listener。 + +### 排查和解决步骤 + +> 另请参阅 +[注册中心-配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#registry) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/8.md new file mode 100644 index 000000000000..cfc916611eab --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/8.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/8/ +- /zh-cn/docs3-v2/java-sdk/faq/1/8/ +- /zh-cn/overview/mannual/java-sdk/faq/1/8/ +description: 1-8 - 销毁时注销(取消订阅)地址失败 +linkTitle: 1-8 - 销毁时注销(取消订阅)地址失败 +title: 1-8 - 销毁时注销(取消订阅)地址失败 +type: docs +weight: 8 +--- + + + + + + +### 可能的原因 +1. 可能是注册中心宕机导致造成的消费者注销或者取消订阅时出现错误。 +2. 可能是对应的 provider 未能成功发布。 + +### 排查和解决步骤 +1. 排查注册中心是否在正常运行。 +2. 排查 provider 是否成功发布。 +3. 排查 provider 的注册中心相关参数比如 `registry` `config-center` `metadata-report`是否配置正确。 + +> 另请参阅 +[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/9.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/9.md new file mode 100644 index 000000000000..8fbeab0ac0e0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/9.md @@ -0,0 +1,35 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/9/ +- /zh-cn/docs3-v2/java-sdk/faq/1/9/ +- /zh-cn/overview/mannual/java-sdk/faq/1/9/ +description: 1-9 - 读写注册中心服务缓存失败 +linkTitle: 1-9 - 读写注册中心服务缓存失败 +title: 1-9 - 读写注册中心服务缓存失败 +type: docs +weight: 9 +--- + + + + + + +### 可能的原因 +1. 多个 Dubbo 进程(或其他 Java 进程)使用了同一个缓存文件。 +2. 由于缓存文件所在目录的文件系统权限问题,导致读写失败。 +3. `dubbo.registry.file` 的值输入错误。 +4. 不小心指定了两个注册中心使用同一文件存储。 + +> **提示:** +如未指定 `dubbo.registry.file`,则注册中心服务缓存路径默认为 `~/.dubbo` 目录 +(其中 `~` 为用户的 HOME 目录) + +### 排查和解决步骤 +1. 检查 `dubbo.registry.file` 的值有无拼写错误。 +2. 检查是否有其它进程使用了同一份缓存文件。 +3. 如果指定了 `dubbo.registry.file`,那么检查下它在文件系统的权限。 +4. 排查是否出现了“两个注册中心使用了同一文件存储” 这一情况,如果出现则调整。 + +> 另请参阅 +[注册中心的配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#registry) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/_index.md new file mode 100755 index 000000000000..9dd655306eb2 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/_index.md @@ -0,0 +1,18 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/1/ +- /zh-cn/docs3-v2/java-sdk/faq/1/ +- /zh-cn/overview/mannual/java-sdk/faq/1/_index/ +description: 1 - 注册中心层 +linkTitle: 1 - 注册中心层 +title: 1 - 注册中心层 +type: docs +weight: 1 +--- + + + + + + +这里主要是用于表示注册中心层上所发生的错误。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/1.md new file mode 100644 index 000000000000..1b9d9fcdaa66 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/1.md @@ -0,0 +1,18 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/1/ +- /zh-cn/docs3-v2/java-sdk/faq/2/1/ +- /zh-cn/overview/mannual/java-sdk/faq/2/1/ +description: 2-1 - 路由选址执行失败 +linkTitle: 2-1 - 路由选址执行失败 +title: 2-1 - 路由选址执行失败 +type: docs +weight: 1 +--- + + + + + + +## 路由选址执行失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/10.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/10.md new file mode 100644 index 000000000000..3c62a2dee2d0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/10.md @@ -0,0 +1,27 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/10/ +- /zh-cn/docs3-v2/java-sdk/faq/2/10/ +- /zh-cn/overview/mannual/java-sdk/faq/2/10/ +description: 2-10 - 调用服务提供方失败 +linkTitle: 2-10 - 调用服务提供方失败 +title: 2-10 - 调用服务提供方失败 +type: docs +weight: 10 +--- + + + + + + +### 可能的原因 + +* Dubbo 调用服务提供方失败,并开始重试。 +* Dubbo 重试调用服务提供方持续失败。 +* Dubbo 重试调用服务提供方达到上限。 + +### 排查和解决步骤 +1. 检查消费方提供方之间网络连接耗时等网络资源。 +2. 通过 telnet 等手段检查提供方对应端口是否能正常响应。 +3. 检查提供方程序是否运行正常。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/11.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/11.md new file mode 100644 index 000000000000..251d5ea348b0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/11.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/11/ +- /zh-cn/docs3-v2/java-sdk/faq/2/11/ +- /zh-cn/overview/mannual/java-sdk/faq/2/11/ +description: 2-11 - 标签路由规则不合法 +linkTitle: 2-11 - 标签路由规则不合法 +title: 2-11 - 标签路由规则不合法 +type: docs +weight: 11 +--- + + + + + + +### 可能的原因 + +* 用户配置的标签路由规则不合法。 +* 用户配置的标签路由地址不合法。 + +### 排查和解决步骤 +> 参照社区标签路由配置规范,检查标签路由配置。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/12.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/12.md new file mode 100644 index 000000000000..094d23481627 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/12.md @@ -0,0 +1,23 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/12/ +- /zh-cn/docs3-v2/java-sdk/faq/2/12/ +- /zh-cn/overview/mannual/java-sdk/faq/2/12/ +description: 2-12 - 标签路由获取提供方应用名为空 +linkTitle: 2-12 - 标签路由获取提供方应用名为空 +title: 2-12 - 标签路由获取提供方应用名为空 +type: docs +weight: 12 +--- + + + + + + +### 可能的原因 + +* 标签路由从推送提供方地址列表中获取提供方应用名为空。 + +### 排查和解决步骤 +> 该异常为 Dubbo 框架自身异常,请在社区提 Issue ,提供环境现场信息及复现步骤。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/13.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/13.md new file mode 100644 index 000000000000..874df2431a5c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/13.md @@ -0,0 +1,23 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/13/ +- /zh-cn/docs3-v2/java-sdk/faq/2/13/ +- /zh-cn/overview/mannual/java-sdk/faq/2/13/ +description: 2-13 - 接收加载mesh的路由规则失败 +linkTitle: 2-13 - 接收加载mesh的路由规则失败 +title: 2-13 - 接收加载mesh的路由规则失败 +type: docs +weight: 13 +--- + + + + + + +### 可能的原因 + +* mesh 路由配置的规则不合法,加载异常。 + +### 排查和解决步骤 +> 检查 mesh 路由规则配置。[mesh示例](/zh-cn/overview/tasks/mesh/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/14.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/14.md new file mode 100644 index 000000000000..8f248c5424cf --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/14.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/14/ +- /zh-cn/docs3-v2/java-sdk/faq/2/14/ +- /zh-cn/overview/mannual/java-sdk/faq/2/14/ +description: 2-14 - 脚本路由执行失败 +linkTitle: 2-14 - 脚本路由执行失败 +title: 2-14 - 脚本路由执行失败 +type: docs +weight: 14 +--- + + + + + + +### 可能的原因 + +* 脚本路由规则不合法,导致规则解析失败。 +* Dubbo 框架执行脚本失败。 + +### 排查和解决步骤 +检查脚本是否按照规范编写。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/15.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/15.md new file mode 100644 index 000000000000..1c23e9f5bbc4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/15.md @@ -0,0 +1,23 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/15/ +- /zh-cn/docs3-v2/java-sdk/faq/2/15/ +- /zh-cn/overview/mannual/java-sdk/faq/2/15/ +description: 2-15 - 路由规则解析失败 +linkTitle: 2-15 - 路由规则解析失败 +title: 2-15 - 路由规则解析失败 +type: docs +weight: 15 +--- + + + + + + +### 可能的原因 + +* 用户配置的路由规则不合法。 + +### 排查和解决步骤 +排查配置的路由规则。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/16.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/16.md new file mode 100644 index 000000000000..803c1281e95b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/16.md @@ -0,0 +1,22 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/16/ +- /zh-cn/docs3-v2/java-sdk/faq/2/16/ +- /zh-cn/overview/mannual/java-sdk/faq/2/16/ +description: 2-16 - 请求重试多次失败 +linkTitle: 2-16 - 请求重试多次失败 +title: 2-16 - 请求重试多次失败 +type: docs +weight: 16 +--- + + + + + + +### 可能的原因 +提供方异常,导致消费方重试多次失败。 + +### 排查和解决步骤 +排查提供方健康状况。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/17.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/17.md new file mode 100644 index 000000000000..70117de72fdc --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/17.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/17/ +- /zh-cn/docs3-v2/java-sdk/faq/2/17/ +- /zh-cn/overview/mannual/java-sdk/faq/2/17/ +description: 2-17 - mock请求失败 +linkTitle: 2-17 - mock请求失败 +title: 2-17 - mock请求失败 +type: docs +weight: 17 +--- + + + + + + +### 可能的原因 +* 配置了强制 mock,提示性日志。 +* 执行 mock 请求异常。 + +### 排查和解决步骤 +1. 检查是否配置了强制 mock。 +2. 检查 mock 响应是否正常。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/18.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/18.md new file mode 100644 index 000000000000..9a308e1d626b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/18.md @@ -0,0 +1,23 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/18/ +- /zh-cn/docs3-v2/java-sdk/faq/2/18/ +- /zh-cn/overview/mannual/java-sdk/faq/2/18/ +description: 2-18 - mesh路由规则未被监听 +linkTitle: 2-18 - mesh路由规则未被监听 +title: 2-18 - mesh路由规则未被监听 +type: docs +weight: 18 +--- + + + + + + +### 可能的原因 + +mesh 下发了路由规则,但是该规则未被监听。 + +### 排查和解决步骤 +检查 mesh 路由规则配置是否符合规范。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/19.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/19.md new file mode 100644 index 000000000000..0e87796e5f84 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/19.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/19/ +- /zh-cn/docs3-v2/java-sdk/faq/2/19/ +- /zh-cn/overview/mannual/java-sdk/faq/2/19/ +description: 2-19 - 异步请求失败 +linkTitle: 2-19 - 异步请求失败 +title: 2-19 - 异步请求失败 +type: docs +weight: 19 +--- + + + + + + +### 可能的原因 + +1. 提供方异常,导致消费方异步请求失败。 +2. 网络异常,导致消费方异步请求失败。 + +### 排查和解决步骤 +1. 排查提供方健康状况。 +2. 排查网络状况。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/2.md new file mode 100644 index 000000000000..5f105ca07c43 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/2.md @@ -0,0 +1,32 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/2/ +- /zh-cn/docs3-v2/java-sdk/faq/2/2/ +- /zh-cn/overview/mannual/java-sdk/faq/2/2/ +description: 2-2 - 没有可用的 Provider(地址找不到) +linkTitle: 2-2 - 没有可用的 Provider(地址找不到) +title: 2-2 - 没有可用的 Provider(地址找不到) +type: docs +weight: 2 +--- + + + + + + +### 可能的原因 +* Provider 服务没启动,或者注册中心(比如 ZooKeeper,Nacos,Consul)宕机了。 +* Dubbo 的服务配置有误差,必须保证服务名,组别 (默认是 Dubbo),version 三者都正确。 +* 访问的环境有误:通常我们会有开发环境、测试环境、线上生产环境等多套环境。有时候发布的服务到了测试环境,而访问调用时却走了开发环境。 + +### 排查和解决步骤 +1. 访问注册中心的 Ops 系统,查询对应的服务是否有提供者列表;同时检查调用者应用所在服务器的日志(一般每种注册服务的客户端都会有对应的日志记录),查看是否有地址信息的推送/拉取记录。 +2. 如无,则表明发布者发布服务失败,检查发布者的应用启动是否成功。 +3. 如有服务,则检查调用者应用所连接的注册中心,确认跟预期的环境要匹配。 +4. 如上述都没有问题,检查是否配置了路由过滤的规则等。 + + +> 这个错误码的 FAQ 页面参考了空冥同学的 [《Dubbo 常见错误及解决方法》](https://github.com/StabilityMan/StabilityGuide/blob/master/docs/diagnosis/plugin/rpc/%E7%B3%BB%E7%BB%9F%E7%A8%B3%E5%AE%9A%E6%80%A7%E2%80%94%E2%80%94Dubbo%E5%B8%B8%E8%A7%81%E9%94%99%E8%AF%AF%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95.md) 。 + +> 所引文章通过 [CC-BY-4.0](http://creativecommons.org/licenses/by/4.0/) 协议赋予了汇编的权利。在此向原作者表示感谢。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/20.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/20.md new file mode 100644 index 000000000000..473387bdb455 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/20.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/20/ +- /zh-cn/docs3-v2/java-sdk/faq/2/20/ +- /zh-cn/overview/mannual/java-sdk/faq/2/20/ +description: 2-20 - 获取分组结果合并时失败 +linkTitle: 2-20 - 获取分组结果合并时失败 +title: 2-20 - 获取分组结果合并时失败 +type: docs +weight: 20 +--- + + + + + + +### 可能的原因 + +获取分组结果合并时失败。 + +### 排查和解决步骤 + +返回结果时,可能出现业务逻辑上的运行时异常,可根据控制台指定的代码行数进行回溯定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/3.md new file mode 100644 index 000000000000..a4c092c54a1c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/3.md @@ -0,0 +1,23 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/3/ +- /zh-cn/docs3-v2/java-sdk/faq/2/3/ +- /zh-cn/overview/mannual/java-sdk/faq/2/3/ +description: 2-3 - 路由关闭失败 +linkTitle: 2-3 - 路由关闭失败 +title: 2-3 - 路由关闭失败 +type: docs +weight: 3 +--- + + + + + + +### 可能的原因 + +* 用户自定义路由未按规范编写。 + +### 排查和解决步骤 +> 参照社区SPI扩展使用手册,检查用户自定义路由 [《SPI 扩展使用手册》](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/4.md new file mode 100644 index 000000000000..06678cdfa875 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/4.md @@ -0,0 +1,23 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/4/ +- /zh-cn/docs3-v2/java-sdk/faq/2/4/ +- /zh-cn/overview/mannual/java-sdk/faq/2/4/ +description: 2-4 - Merger接口加载失败 +linkTitle: 2-4 - Merger接口加载失败 +title: 2-4 - Merger接口加载失败 +type: docs +weight: 4 +--- + + + + + + +### 可能的原因 + +* Dubbo 提供了聚合下游所有提供方响应的 SPI 扩展 Merger 接口,Dubbo 在加载用户在自定义扩展 Merger 接口时,加载配置失败。 + +### 排查和解决步骤 +> 参照社区 SPI 扩展使用手册,检查用户自定义扩展 Merger 接口实现 [《SPI 扩展使用手册》](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/5.md new file mode 100644 index 000000000000..c26e667df976 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/5.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/5/ +- /zh-cn/docs3-v2/java-sdk/faq/2/5/ +- /zh-cn/overview/mannual/java-sdk/faq/2/5/ +description: 2-5 - 筛选提供方失败 +linkTitle: 2-5 - 筛选提供方失败 +title: 2-5 - 筛选提供方失败 +type: docs +weight: 5 +--- + + + + + + +### 可能的原因 + +* Dubbo 在负载均衡时会从提供方列表中最终选择一个提供方发起调用,在选择过程中提供方列表变动,发生读写冲突,导致筛选异常。 +* Dubbo 重试机制在调用提供方失败时,会重新筛选另一个提供方发起调用,重新筛选过程发生异常。 + +### 排查和解决步骤 +1. 检查注册中心提供方列表,与对应提供方可用性。 +2. 在社区提 Issue,提供环境现场信息及复现步骤。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/6.md new file mode 100644 index 000000000000..f48e4b4122c9 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/6.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/6/ +- /zh-cn/docs3-v2/java-sdk/faq/2/6/ +- /zh-cn/overview/mannual/java-sdk/faq/2/6/ +description: 2-6 - 条件路由筛选提供方列表为空 +linkTitle: 2-6 - 条件路由筛选提供方列表为空 +title: 2-6 - 条件路由筛选提供方列表为空 +type: docs +weight: 6 +--- + + + + + + +### 可能的原因 + +* 条件路由提供方过滤条件为空。 +* 条件路由在强制降级下筛选提供方列表仍为空。 + +### 排查和解决步骤 +> 参照社区请求路由示例,调整条件路由配置。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/7.md new file mode 100644 index 000000000000..84d576f3e2e8 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/7.md @@ -0,0 +1,23 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/7/ +- /zh-cn/docs3-v2/java-sdk/faq/2/7/ +- /zh-cn/overview/mannual/java-sdk/faq/2/7/ +description: 2-7 - 条件路由执行异常 +linkTitle: 2-7 - 条件路由执行异常 +title: 2-7 - 条件路由执行异常 +type: docs +weight: 7 +--- + + + + + + +### 可能的原因 + +* 条件路由规则未按照规范配置,导致执行条件路由筛选时执行异常。 + +## 排查和解决步骤 +> 参照社区请求路由示例。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/8.md new file mode 100644 index 000000000000..1d3b1bb140a9 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/8.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/8/ +- /zh-cn/docs3-v2/java-sdk/faq/2/8/ +- /zh-cn/overview/mannual/java-sdk/faq/2/8/ +description: 2-8 - 提供方返回异常响应 +linkTitle: 2-8 - 提供方返回异常响应 +title: 2-8 - 提供方返回异常响应 +type: docs +weight: 8 +--- + + + + + + +### 可能的原因 + +* 提供方自身处理结果抛出异常。 + +### 排查和解决步骤 + +检查提供方程序是否正常。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/9.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/9.md new file mode 100644 index 000000000000..91b910b44f39 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/9.md @@ -0,0 +1,23 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/9/ +- /zh-cn/docs3-v2/java-sdk/faq/2/9/ +- /zh-cn/overview/mannual/java-sdk/faq/2/9/ +description: 2-9 - 增加超时检查任务失败 +linkTitle: 2-9 - 增加超时检查任务失败 +title: 2-9 - 增加超时检查任务失败 +type: docs +weight: 9 +--- + + + + + + +### 可能的原因 + +* Dubbo 框架会对请求调用增加一个超时检查任务,增加超时检查任务失败。 + +### 排查和解决步骤 +> 该异常为 Dubbo 框架自身异常,请在社区提 Issue ,提供环境现场信息及复现步骤。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/_index.md new file mode 100644 index 000000000000..a5266b171a98 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/_index.md @@ -0,0 +1,11 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/2/ +- /zh-cn/docs3-v2/java-sdk/faq/2/ +- /zh-cn/overview/mannual/java-sdk/faq/2/_index/ +description: 2 - 路由层 +linkTitle: 2 - 路由层 +title: 2 - 路由层 +type: docs +weight: 2 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/1.md new file mode 100644 index 000000000000..f9b7a9e56537 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/1.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/3/1/ +- /zh-cn/docs3-v2/java-sdk/faq/3/1/ +- /zh-cn/overview/mannual/java-sdk/faq/3/1/ +description: 3-1 - 将地址转换成 Invoker 失败 +linkTitle: 3-1 - 将地址转换成 Invoker 失败 +title: 3-1 - 将地址转换成 Invoker 失败 +type: docs +weight: 1 +--- + + + + + + +### 可能的原因 + +1. 客户端配置的协议与服务端配置的协议并不匹配。(如客户端配置的协议是 Dubbo 协议,但服务端只能提供 Rest 协议的服务) +2. 注册中心(或配置中心)不可靠,推送了并不合法的数据。 + + + +### 排查和解决步骤 + +1. 检查提供方和消费方双方的协议配置。 +2. 更新注册中心的版本。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/2.md new file mode 100644 index 000000000000..dfff87e88304 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/2.md @@ -0,0 +1,27 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/3/2/ +- /zh-cn/docs3-v2/java-sdk/faq/3/2/ +- /zh-cn/overview/mannual/java-sdk/faq/3/2/ +description: 3-2 - 发布或推送服务失败 +linkTitle: 3-2 - 发布或推送服务失败 +title: 3-2 - 发布或推送服务失败 +type: docs +weight: 2 +--- + + + + + + +### 可能的原因 + +1. 注册中心无法连接。 +2. 注册中心无法对外提供服务。 + +### 排查和解决步骤 + +1. 服务与注册中心网络是否正常。 +2. 注册中心是否正常启动,并可通过第三方工具进行连接。 +3. 服务引用的版本与注册中心的版本是否存在版本兼容性问题。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/3.md new file mode 100644 index 000000000000..37d9e7ed482b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/3.md @@ -0,0 +1,22 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/3/3/ +- /zh-cn/docs3-v2/java-sdk/faq/3/3/ +- /zh-cn/overview/mannual/java-sdk/faq/3/3/ +description: 3-3 - 通过Javassist生成字节码失败 +linkTitle: 3-3 - 通过Javassist生成字节码失败 +title: 3-3 - 通过Javassist生成字节码失败 +type: docs +weight: 3 +--- + + + + + + +### 可能的原因 +该错误码的意义已经调整。对于 Dubbo 3.1.4、3.2.0-beta.3 及其之前的版本的该错误码的出错,请参考错误码 [3-8](/zh-cn/overview/mannual/java-sdk/faq/3/8/)。 + +### 排查和解决步骤 +(该错误码目前空缺) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/4.md new file mode 100644 index 000000000000..2f21d8c4ad12 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/4.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/3/4/ +- /zh-cn/docs3-v2/java-sdk/faq/3/4/ +- /zh-cn/overview/mannual/java-sdk/faq/3/4/ +description: 3-4 - 客户端发送请求超时 +linkTitle: 3-4 - 客户端发送请求超时 +title: 3-4 - 客户端发送请求超时 +type: docs +weight: 4 +--- + + + + + + +### 可能的原因 + +1. 客户端连接数过高,响应较慢, 无法及时向服务端发出请求。 +2. 网络的一些原因。 + +### 排查和解决步骤 + +1. 网络是否正常。 +2. 可通过一些第三方的工具或者`jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/5.md new file mode 100644 index 000000000000..52a566957684 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/5.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/3/5/ +- /zh-cn/docs3-v2/java-sdk/faq/3/5/ +- /zh-cn/overview/mannual/java-sdk/faq/3/5/ +description: 3-5 - 异步响应出现异常 +linkTitle: 3-5 - 异步响应出现异常 +title: 3-5 - 异步响应出现异常 +type: docs +weight: 5 +--- + + + + + + +### 可能的原因 + +1. 业务逻辑确实出现运行时异常。 +2. 网络原因,连接被拒绝。 + +### 排查和解决步骤 + +1. 业务代码请根据堆栈提示行,回溯定位排查。 +2. 检查服务提供方的网络是否正常。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/6.md new file mode 100644 index 000000000000..d1f8acf060b1 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/6.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/3/6/ +- /zh-cn/docs3-v2/java-sdk/faq/3/6/ +- /zh-cn/overview/mannual/java-sdk/faq/3/6/ +description: 3-6 - 代理执行服务发生异常 +linkTitle: 3-6 - 代理执行服务发生异常 +title: 3-6 - 代理执行服务发生异常 +type: docs +weight: 6 +--- + + + + + + +### 可能的原因 + +1. 当前服务参数已显示入参 `deprecated`。 +2. 泛型声明类可能出现此提醒。 + +### 排查和解决步骤 + +1. 确认URL中是否存在显示入参 `deprecated=true` +2. 泛型声明类如果出现此错误,会试图创建没有实际接口类的代理。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/7.md new file mode 100644 index 000000000000..92a96644c68e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/7.md @@ -0,0 +1,29 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/3/7/ +- /zh-cn/docs3-v2/java-sdk/faq/3/7/ +- /zh-cn/overview/mannual/java-sdk/faq/3/7/ +description: 3-7 - 服务端响应结果超时 +linkTitle: 3-7 - 服务端响应结果超时 +title: 3-7 - 服务端响应结果超时 +type: docs +weight: 7 +--- + + + + + +服务端未在客户端设定的时间内获得响应。 + +### 可能的原因 + +1. 服务端的业务处理逻辑较复杂,无法在有效时间内响应。 +2. 服务端与客户端的连接断开,网络丢包。 +3. 服务端负荷过高。 + +### 排查和解决步骤 + +1. 检查服务端的业务处理能力是否确实存在性能瓶颈。 +2. 网络是否正常。 +3. 可通过一些第三方的工具或者`jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/8.md new file mode 100644 index 000000000000..7a6a6980fc8b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/8.md @@ -0,0 +1,30 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/3/8/ +- /zh-cn/docs3-v2/java-sdk/faq/3/8/ +- /zh-cn/overview/mannual/java-sdk/faq/3/8/ +description: 3-8 - 代理失败 +linkTitle: 3-8 - 代理失败 +title: 3-8 - 代理失败 +type: docs +weight: 8 +--- + + + + + + +生成动态代理失败。 + +### 可能的原因 + +1. 存在动态类加载 +2. 类格式异常 + +### 排查和解决步骤 + +1. 如果日志中提示 `Fallback to use JDK proxy success`, +则意味着 Dubbo 自动回落到 JDK 代理后成功创建动态代理了,如果程序正常运行,则可以忽略 +2. 如果日志中提示 `Fallback to use JDK proxy is also failed`, +请根据异常堆栈信息检查对应的类加载情况是否正常,可以通过 arthas 等工具辅助排查 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/_index.md new file mode 100644 index 000000000000..80fec2c10bf4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/_index.md @@ -0,0 +1,11 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/3/ +- /zh-cn/docs3-v2/java-sdk/faq/3/ +- /zh-cn/overview/mannual/java-sdk/faq/3/_index/ +description: 3 - 动态代理层 +linkTitle: 3 - 动态代理层 +title: 3 - 动态代理层 +type: docs +weight: 3 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/1.md new file mode 100644 index 000000000000..98f5bdcc6d75 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/1.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/1/ +- /zh-cn/docs3-v2/java-sdk/faq/4/1/ +- /zh-cn/overview/mannual/java-sdk/faq/4/1/ +description: 4-1 - 不支持的协议 +linkTitle: 4-1 - 不支持的协议 +title: 4-1 - 不支持的协议 +type: docs +weight: 1 +--- + + + + + + +### 可能的原因 +这种情况可能出现在自定义 Protocol 的场景下。Dubbo 的 SPI 机制找不到 URL 中所指定的 Protocol。 + + +### 排查和解决步骤 +1. 确定 Consumer 中有服务端所用到的 Protocol 的依赖。 +2. 确定 Protocol 的依赖包的 SPI 配置文件的名字没有写错。 + +> 另请参阅 +[Dubbo SPI 概述](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/overview/) +[协议扩展说明](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/protocol/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/10.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/10.md new file mode 100644 index 000000000000..dc740749ab94 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/10.md @@ -0,0 +1,37 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/10/ +- /zh-cn/docs3-v2/java-sdk/faq/4/10/ +- /zh-cn/overview/mannual/java-sdk/faq/4/10/ +description: 4-10 - Triple 序列化结果失败 +linkTitle: 4-10 - Triple 序列化结果失败 +title: 4-10 - Triple 序列化结果失败 +type: docs +weight: 10 +--- + + + + + + +### 可能的原因 + +一般为内部错误。 +见于三种log格式: +1. 在序列化并且发送数据时发生异常,日志格式为 `Serialize triple request failed, service=%s method=%s` +2. 接收到response的reset code时触发,日志格式为:`Triple Client received remote reset errorCode=xxx` +3. 处理response时有异常情况时触发,日志格式为: `Meet Exception on ClientResponseHandler, status code is:xxx` + +### 排查和解决步骤 + +针对第一种错误,是在调用{service}#{method}方法过程中出现的,具体对应到sendMessage,并且该日志与`java.util.concurrent.ExecutionException: org.apache.dubbo.rpc.StatusRpcException: INTERNAL : Serialize request failed`同时出现,排查{method}方法参数中自定义类是否实现序列化接口导致序列化失败 + +针对第二种错误,是Provider端处理发生错误,排查Provider端服务,排查方式参考第一种错误 + +针对第三种错误,仅单元测试使用到,目前用户侧不会出现 + +其次可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 + +> 同时请在社区提交Issue,帮助我们更好的完善Triple +> 直接点击右上角 **提交项目问题** 按钮即可快速链接至Github页面 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/11.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/11.md new file mode 100644 index 000000000000..37704d641f78 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/11.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/11/ +- /zh-cn/docs3-v2/java-sdk/faq/4/11/ +- /zh-cn/overview/mannual/java-sdk/faq/4/11/ +description: 4-11 - 发起请求失败 +linkTitle: 4-11 - 发起请求失败 +title: 4-11 - 发起请求失败 +type: docs +weight: 11 +--- + + + + + + +### 可能的原因 + +1. 服务方已关闭。 +2. 调用方的 IP 不在服务方的白名单内。 +3. 请求具体的地址服务不存在。 + +### 排查和解决步骤 + +1. 检查服务方启动运行情况。 +2. 检查或使用第三方工具,测试网络环境是否可正常连接。 +3. 根据堆栈的 serviceName, 在管理平台里查看或模拟调用,看是否正常。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/12.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/12.md new file mode 100644 index 000000000000..5eff33dc1d4c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/12.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/12/ +- /zh-cn/docs3-v2/java-sdk/faq/4/12/ +- /zh-cn/overview/mannual/java-sdk/faq/4/12/ +description: 4-12 - 创建Triple流失败 +linkTitle: 4-12 - 创建Triple流失败 +title: 4-12 - 创建Triple流失败 +type: docs +weight: 12 +--- + + + + + + +### 可能的原因 + +一般为内部错误。 + +### 排查和解决步骤 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 + +> 同时请在社区提交Issue。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/13.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/13.md new file mode 100644 index 000000000000..864b916ed2dc --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/13.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/13/ +- /zh-cn/docs3-v2/java-sdk/faq/4/13/ +- /zh-cn/overview/mannual/java-sdk/faq/4/13/ +description: 4-13 - 服务端超时 +linkTitle: 4-13 - 服务端超时 +title: 4-13 - 服务端超时 +type: docs +weight: 13 +--- + + + + + + +### 可能的原因 + +1. 服务端逻辑处理相对耗时。 +2. 服务端负载请求过高,无法响应。 +3. 当前的超时参数设置阈值与现实情况相差较大。 + +### 排查和解决步骤 + +1. 根据接口名称查看是否存在耗时处理情况。 +2. 可监控服务器状态,及服务端调用的服务调用情况。 +3. 尝试将超时参数调大一些。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/14.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/14.md new file mode 100644 index 000000000000..cccf9cb31405 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/14.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/14/ +- /zh-cn/docs3-v2/java-sdk/faq/4/14/ +- /zh-cn/overview/mannual/java-sdk/faq/4/14/ +description: 4-14 - 响应结果失败 +linkTitle: 4-14 - 响应结果失败 +title: 4-14 - 响应结果失败 +type: docs +weight: 14 +--- + + + + + + +### 可能的原因 + +1. 服务端管道可能因网络原因暂时断开。 +2. 当前使用版本较低或可检查当前的参数配置,是否启用 `send.reconnect=true`, 高版本默认为 true。 + +### 排查和解决步骤 + +1. 检查直连网络是否通畅,有无丢包现象。 +2. 检查上述参数值,或尝试使用高版本。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/15.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/15.md new file mode 100644 index 000000000000..c41c4bc44f63 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/15.md @@ -0,0 +1,22 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/15/ +- /zh-cn/docs3-v2/java-sdk/faq/4/15/ +- /zh-cn/overview/mannual/java-sdk/faq/4/15/ +description: 4-15 - 客户端流监听器 +linkTitle: 4-15 - 客户端流监听器 +title: 4-15 - 客户端流监听器 +type: docs +weight: 15 +--- + + + + + + +### 可能的原因 + +当收到服务端的响应之后,客户端流监听器会输出此信息,用于提醒。 + +### 排查和解决步骤 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/16.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/16.md new file mode 100644 index 000000000000..54cffeeac61f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/16.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/16/ +- /zh-cn/docs3-v2/java-sdk/faq/4/16/ +- /zh-cn/overview/mannual/java-sdk/faq/4/16/ +description: 4-16 - 服务已关闭 +linkTitle: 4-16 - 服务已关闭 +title: 4-16 - 服务已关闭 +type: docs +weight: 16 +--- + + + + + + +### 可能的原因 + +在错误的状态下继续调用 `org.apache.dubbo.rpc.protocol.tri.service.TriHealthImpl#enterTerminalState` 或者 `org.apache.dubbo.rpc.protocol.ReferenceCountInvokerWrapper#invoke`,在调用时已经是 terminal 或 destory状态。 + +### 排查和解决步骤 + +多次调用上述方法会进行提醒。一般仅用于单元测试。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/17.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/17.md new file mode 100644 index 000000000000..f0add9767594 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/17.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/17/ +- /zh-cn/docs3-v2/java-sdk/faq/4/17/ +- /zh-cn/overview/mannual/java-sdk/faq/4/17/ +description: 4-17 - 关闭所有调用程序时发生错误 +linkTitle: 4-17 - 关闭所有调用程序时发生错误 +title: 4-17 - 关闭所有调用程序时发生错误 +type: docs +weight: 17 +--- + + + + + + +### 可能的原因 + +一般为内部错误。 + +### 排查和解决步骤 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 + +> 同时请在社区提交issue. diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/18.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/18.md new file mode 100644 index 000000000000..b29fd3250bba --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/18.md @@ -0,0 +1,22 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/18/ +- /zh-cn/docs3-v2/java-sdk/faq/4/18/ +- /zh-cn/overview/mannual/java-sdk/faq/4/18/ +description: 4-18 - 无法从调用中获取服务模型 +linkTitle: 4-18 - 无法从调用中获取服务模型 +title: 4-18 - 无法从调用中获取服务模型 +type: docs +weight: 18 +--- + + + + + + +### 可能的原因 + +当前仅用于单元测试场景,服务模型默认会进行初始化。 + +### 排查和解决步骤 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/19.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/19.md new file mode 100644 index 000000000000..a474cc14ab7f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/19.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/19/ +- /zh-cn/docs3-v2/java-sdk/faq/4/19/ +- /zh-cn/overview/mannual/java-sdk/faq/4/19/ +description: 4-19 - 参数值有出错的可能 +linkTitle: 4-19 - 参数值有出错的可能 +title: 4-19 - 参数值有出错的可能 +type: docs +weight: 19 +--- + + + + + + +### 可能的原因 +这个错误码提示参数值可能不再正确。 + +目前出现在同一个协议同时监听多个端口下。由于设计限制,单个协议只能监听一个端口,否则端口配置会被覆盖掉。 + +### 排查和解决步骤 +调整协议和端口的监听关系。 + +> 该错误码的意义已经调整。对于 Dubbo 3.1.4、3.2.0-beta.3 及其之前的版本的该错误码的出错,请参考错误码 [0-2](/zh-cn/overview/mannual/java-sdk/faq/0/2/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/2.md new file mode 100644 index 000000000000..97c6fdf4fbb2 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/2.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/2/ +- /zh-cn/docs3-v2/java-sdk/faq/4/2/ +- /zh-cn/overview/mannual/java-sdk/faq/4/2/ +description: 4-2 - 序列化优化器初始发生错误 +linkTitle: 4-2 - 序列化优化器初始发生错误 +title: 4-2 - 序列化优化器初始发生错误 +type: docs +weight: 2 +--- + + + + + + +### 可能的原因 + +当前使用了 Kryo 和 FST 的序列化配置。 + +### 排查和解决步骤 + +[Kryo 和 FST 序列化](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/serialization/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/20.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/20.md new file mode 100644 index 000000000000..b51fad776fa7 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/20.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/20/ +- /zh-cn/docs3-v2/java-sdk/faq/4/20/ +- /zh-cn/overview/mannual/java-sdk/faq/4/20/ +description: 4-20 - 数据解码失败 +linkTitle: 4-20 - 数据解码失败 +title: 4-20 - 数据解码失败 +type: docs +weight: 20 +--- + + + + + + +### 可能的原因 + +只发生在解码阶段,可能服务方和调用方的dubbo版本不匹配。 + +### 排查和解决步骤 + +检查当前使用的 dubbo 版本,尽量保持一致或向下兼容的高版本。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/21.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/21.md new file mode 100644 index 000000000000..d765a4654adf --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/21.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/21/ +- /zh-cn/docs3-v2/java-sdk/faq/4/21/ +- /zh-cn/overview/mannual/java-sdk/faq/4/21/ +description: 4-21 - 检测到不安全的序列化数据 +linkTitle: 4-21 - 检测到不安全的序列化数据 +title: 4-21 - 检测到不安全的序列化数据 +type: docs +weight: 21 +--- + + + + + + +### 可能的原因 + +当前服务端可能受到攻击或者是 Dubbo 内置的类检查逻辑没有扫描到您所定义的类。 + +### 排查和解决步骤 + +1. 如果请求源是攻击源,请及时进行安全加固。 +2. 如果请求源是预期的,请在 `security/serialize.allowlist` 资源文件中声明您所使用的类名,Dubbo 将自动将其加载到安全列表中。请参考 [类检查机制](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/) 一文。 + + +> 当前 Dubbo 可以工作在监控模式和限制模式下。监控模式只打印日志,不进行拦截;限制模型将进行拦截。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/3.md new file mode 100644 index 000000000000..6836b47ad2fd --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/3.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/3/ +- /zh-cn/docs3-v2/java-sdk/faq/4/3/ +- /zh-cn/overview/mannual/java-sdk/faq/4/3/ +description: 4-3 - 接口引用调用失败 +linkTitle: 4-3 - 接口引用调用失败 +title: 4-3 - 接口引用调用失败 +type: docs +weight: 3 +--- + + + + + + +### 可能的原因 + +根据指定的协议参数,未找到暴露的服务接口或方法。 + +### 排查和解决步骤 + +可根据接口 URL 及方法名称,确认服务端是否存在。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/4.md new file mode 100644 index 000000000000..4342b3057e04 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/4.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/4/ +- /zh-cn/docs3-v2/java-sdk/faq/4/4/ +- /zh-cn/overview/mannual/java-sdk/faq/4/4/ +description: 4-4 - 非安全序列化方式 +linkTitle: 4-4 - 非安全序列化方式 +title: 4-4 - 非安全序列化方式 +type: docs +weight: 4 +--- + + + + + + +### 可能的原因 + +当前在使用非安全的序列化器, 并不推荐。具体配置为:`serialization="java"` + +> Java 序列化是不安全的。Dubbo 团队不推荐任何人使用它。如果你仍然想使用它,请遵循 [JEP 290](https://openjdk.java.net/jeps/290) 来设置序列化过滤器,以防止反序列化泄露。 + +### 排查和解决步骤 + +修改`serialization`的参数值. 将 protocol 内的序列化参数值修改为其他,如hessian2,fastjson2等。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/5.md new file mode 100644 index 000000000000..ccf8ef49de8c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/5.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/5/ +- /zh-cn/docs3-v2/java-sdk/faq/4/5/ +- /zh-cn/overview/mannual/java-sdk/faq/4/5/ +description: 4-5 - 流关闭异常 +linkTitle: 4-5 - 流关闭异常 +title: 4-5 - 流关闭异常 +type: docs +weight: 5 +--- + + + + + + +### 可能的原因 + +提示信息,不影响程序的执行结果。 + +### 排查和解决步骤 + +可通过一些第三方的工具或者`jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/6.md new file mode 100644 index 000000000000..423246a3566c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/6.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/6/ +- /zh-cn/docs3-v2/java-sdk/faq/4/6/ +- /zh-cn/overview/mannual/java-sdk/faq/4/6/ +description: 4-6 - 反序列化失败 +linkTitle: 4-6 - 反序列化失败 +title: 4-6 - 反序列化失败 +type: docs +weight: 6 +--- + + + + + + +### 可能的原因 + +发生在使用自定义的序列化方式的时候,在自定义 SPI `org.apache.dubbo.common.serialize.Serialization` 序列化方法在使用时发生错误。 + +### 排查和解决步骤 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,获取引起错误的对象内容,再配合自定义实现进行修改。 + +> 参考 [序列化扩展](https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/serialize/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/7.md new file mode 100644 index 000000000000..a0ce8627b22e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/7.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/7/ +- /zh-cn/docs3-v2/java-sdk/faq/4/7/ +- /zh-cn/overview/mannual/java-sdk/faq/4/7/ +description: 4-7 - 关闭客户端时发生错误 +linkTitle: 4-7 - 关闭客户端时发生错误 +title: 4-7 - 关闭客户端时发生错误 +type: docs +weight: 7 +--- + + + + + + +### 可能的原因 + +见于各种 `Connect Client` 进行`close`或者`destory`的时候报错,不影响最终效果。 + +### 排查和解决步骤 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/8.md new file mode 100644 index 000000000000..70aa8aafeb22 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/8.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/8/ +- /zh-cn/docs3-v2/java-sdk/faq/4/8/ +- /zh-cn/overview/mannual/java-sdk/faq/4/8/ +description: 4-8 - 关闭服务端时发生错误 +linkTitle: 4-8 - 关闭服务端时发生错误 +title: 4-8 - 关闭服务端时发生错误 +type: docs +weight: 8 +--- + + + + + + +### 可能的原因 + +与4-7相似,都是发生在close时。 + +### 排查和解决步骤 + +可通过一些第三方的工具或者`jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/9.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/9.md new file mode 100644 index 000000000000..83c0a2a92fa6 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/9.md @@ -0,0 +1,33 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/9/ +- /zh-cn/docs3-v2/java-sdk/faq/4/9/ +- /zh-cn/overview/mannual/java-sdk/faq/4/9/ +description: 4-9 - 解析失败 +linkTitle: 4-9 - 解析失败 +title: 4-9 - 解析失败 +type: docs +weight: 9 +--- + + + + + + +### 可能的原因 + +一般为参数值不符合规则,在强转时发生错误。 +如: + +```java +String timeoutString = httpMetadata.headers().getFirst(TripleHeaderEnum.SERVICE_TIMEOUT.getHeader()); +Long timeout = Long.parseLong(timeoutString); + +Long timeout = GrpcUtils.parseTimeoutToMills(timeoutString); +invocation.put(CommonConstants.TIMEOUT_KEY, timeout); +``` + +### 排查和解决步骤 + +根据堆栈信息提示的 key 名称进行相对应的配置修改到符合转换规则即可。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/_index.md new file mode 100644 index 000000000000..c4a3bc2cbb77 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/_index.md @@ -0,0 +1,11 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/4/ +- /zh-cn/docs3-v2/java-sdk/faq/4/ +- /zh-cn/overview/mannual/java-sdk/faq/4/_index/ +description: 4 - 协议层 +linkTitle: 4 - 协议层 +title: 4 - 协议层 +type: docs +weight: 4 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/1.md new file mode 100644 index 000000000000..df344c117184 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/1.md @@ -0,0 +1,29 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/1/ +- /zh-cn/docs3-v2/java-sdk/faq/5/1/ +- /zh-cn/overview/mannual/java-sdk/faq/5/1/ +description: 5-1 - 配置中心连接失败 +linkTitle: 5-1 - 配置中心连接失败 +title: 5-1 - 配置中心连接失败 +type: docs +weight: 1 +--- + + + + + + +### 可能的原因 + +1. 配置中心所在的服务器关机或宕机。 +2. IP 或者端口号写错。 +3. 防火墙错误拦截了配置中心的端口。 + + +### 排查和解决步骤 + +1. 检查配置中心 IP 以及端口的配置。 +2. 检查服务器是否开机,是否正常工作。 +3. 检查防火墙等是否放行配置中心所用的端口。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/10.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/10.md new file mode 100644 index 000000000000..786a46ca1b80 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/10.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/10/ +- /zh-cn/docs3-v2/java-sdk/faq/5/10/ +- /zh-cn/overview/mannual/java-sdk/faq/5/10/ +description: 5-10 - 服务的注册接口应用程序映射失败 +linkTitle: 5-10 - 服务的注册接口应用程序映射失败 +title: 5-10 - 服务的注册接口应用程序映射失败 +type: docs +weight: 10 +--- + + + + + + +### 可能的原因 + +服务暴露的服务元数据与应用程序不匹配,或被篡改。 + +### 排查和解决步骤 + +检查配置中心的元数据内容是否与应用程序内的匹配。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/11.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/11.md new file mode 100644 index 000000000000..a197e837788d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/11.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/11/ +- /zh-cn/docs3-v2/java-sdk/faq/5/11/ +- /zh-cn/overview/mannual/java-sdk/faq/5/11/ +description: 5-11 - 注册实例错误 +linkTitle: 5-11 - 注册实例错误 +title: 5-11 - 注册实例错误 +type: docs +weight: 11 +--- + + + + + + +### 可能的原因 + +1. 配置中心的服务无法连接。 +2. 配置的协议、IP、端口不正确。 +3. 使用配置中心客户端版本与服务端版本冲突,无法建立有效连接。 + +### 排查和解决步骤 + +1. 检查配置中心的服务状态是否正常。 +2. 检查配置的协议、IP、端口不正确。 +3. 检查使用的配置中心客户端版本与服务端版本是否兼容。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/12.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/12.md new file mode 100644 index 000000000000..6bf125d511f7 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/12.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/12/ +- /zh-cn/docs3-v2/java-sdk/faq/5/12/ +- /zh-cn/overview/mannual/java-sdk/faq/5/12/ +description: 5-12 - 刷新实例和元数据错误 +linkTitle: 5-12 - 刷新实例和元数据错误 +title: 5-12 - 刷新实例和元数据错误 +type: docs +weight: 12 +--- + + + + + + +### 可能的原因 + +1. 配置中心的服务无法连接。 +2. 配置的协议、IP、端口不正确。 +3. 使用配置中心客户端版本与服务端版本冲突,无法建立有效连接。 + +### 排查和解决步骤 + +1. 检查配置中心的服务状态是否正常。 +2. 检查配置的协议、IP、端口不正确。 +3. 检查使用的配置中心客户端版本与服务端版本是否兼容。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/13.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/13.md new file mode 100644 index 000000000000..89a8208887ee --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/13.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/13/ +- /zh-cn/docs3-v2/java-sdk/faq/5/13/ +- /zh-cn/overview/mannual/java-sdk/faq/5/13/ +description: 5-13 - 无法销毁模型 +linkTitle: 5-13 - 无法销毁模型 +title: 5-13 - 无法销毁模型 +type: docs +weight: 13 +--- + + + + + + +### 可能的原因 + +自定义销毁方法,业务处理上存在异常。 + +### 排查和解决步骤 + +检查自定义销毁方法,业务处理逻辑是否存在运行时异常。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/14.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/14.md new file mode 100644 index 000000000000..7047387317aa --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/14.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/14/ +- /zh-cn/docs3-v2/java-sdk/faq/5/14/ +- /zh-cn/overview/mannual/java-sdk/faq/5/14/ +description: 5-14 - 模型启动错误 +linkTitle: 5-14 - 模型启动错误 +title: 5-14 - 模型启动错误 +type: docs +weight: 14 +--- + + + + + + +### 可能的原因 + +1. 服务在等待发布或订阅时,连接被断开。 +2. 网络连接超时。 + +### 排查和解决步骤 + +1. 检查应用服务器与配置中心的连接是否正常。 +2. 检查网络连接是否存在超时等。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/15.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/15.md new file mode 100644 index 000000000000..07c8d6271341 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/15.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/15/ +- /zh-cn/docs3-v2/java-sdk/faq/5/15/ +- /zh-cn/overview/mannual/java-sdk/faq/5/15/ +description: 5-15 - 模型引用错误 +linkTitle: 5-15 - 模型引用错误 +title: 5-15 - 模型引用错误 +type: docs +weight: 15 +--- + + + + + + +### 可能的原因 + +Dubbo 核心处理类的方法被错误使用或被篡改。 + +### 排查和解决步骤 + +检查应用程序上是否存在错误使用或反编译修改情况。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/16.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/16.md new file mode 100644 index 000000000000..cdc9a8359d58 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/16.md @@ -0,0 +1,27 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/16/ +- /zh-cn/docs3-v2/java-sdk/faq/5/16/ +- /zh-cn/overview/mannual/java-sdk/faq/5/16/ +description: 5-16 - 无法找到任何有效的协议 +linkTitle: 5-16 - 无法找到任何有效的协议 +title: 5-16 - 无法找到任何有效的协议 +type: docs +weight: 16 +--- + + + + + + +### 可能的原因 + +配置的协议不支持。 + +### 排查和解决步骤 + +目前支持的协议有 dubbo、rmi、hessian、http、webservice、thrift、redis 等。 + +> 另请参阅 +[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/17.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/17.md new file mode 100644 index 000000000000..d1ede8cecc09 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/17.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/17/ +- /zh-cn/docs3-v2/java-sdk/faq/5/17/ +- /zh-cn/overview/mannual/java-sdk/faq/5/17/ +description: 5-17 - 参数值格式错误 +linkTitle: 5-17 - 参数值格式错误 +title: 5-17 - 参数值格式错误 +type: docs +weight: 17 +--- + + + + + + +### 可能的原因 + +1. 属性配置值长度过长,一般设置在 200 个字符以内。 +2. 属性配置值格式错误,目前支持数字、 -、 _ 等 + +### 排查和解决步骤 + +1. 检查属性配置值内容是否过长,具体参考提示信息进行修改。 +2. 检查属性配置值内容是否包含特殊字符,如 @#$%^& 等,具体请参考提示信息进行修改。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/18.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/18.md new file mode 100644 index 000000000000..c137314a55d6 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/18.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/18/ +- /zh-cn/docs3-v2/java-sdk/faq/5/18/ +- /zh-cn/overview/mannual/java-sdk/faq/5/18/ +description: 5-18 - 通知注册事件失败 +linkTitle: 5-18 - 通知注册事件失败 +title: 5-18 - 通知注册事件失败 +type: docs +weight: 18 +--- + + + + + + +### 可能的原因 + +1. 通知已发送,业务处理逻辑上出现意外错误。 +2. 配置中心无法连接,超时错误。 + +### 排查和解决步骤 + +1. 检查自定义业务逻辑实现,是否存在运行时异常。 +2. 检查配置中心是否能够正常连接。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/2.md new file mode 100644 index 000000000000..385495293313 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/2.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/2/ +- /zh-cn/docs3-v2/java-sdk/faq/5/2/ +- /zh-cn/overview/mannual/java-sdk/faq/5/2/ +description: 5-2 - 注册/注销关闭钩子方法失败 +linkTitle: 5-2 - 注册/注销关闭钩子方法失败 +title: 5-2 - 注册/注销关闭钩子方法失败 +type: docs +weight: 2 +--- + + + + + + +### 可能的原因 + +自定义钩子方法,业务处理逻辑存在异常。 + +### 排查和解决步骤 + +检查自定义钩子方法,业务处理逻辑是否存在运行时异常。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/20.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/20.md new file mode 100644 index 000000000000..0b82a0959863 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/20.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/20/ +- /zh-cn/docs3-v2/java-sdk/faq/5/20/ +- /zh-cn/overview/mannual/java-sdk/faq/5/20/ +description: 5-20 - 停止 dubbo 模块时发生错误 +linkTitle: 5-20 - 停止 dubbo 模块时发生错误 +title: 5-20 - 停止 dubbo 模块时发生错误 +type: docs +weight: 20 +--- + + + + + + +### 可能的原因 + +1. 自定义实现销毁方法,可能存在业务逻辑运行时异常。 +2. 未优雅停止服务,可能存在业务逻辑未处理完成情况。 + +### 排查和解决步骤 + +1. 检查自定义实现销毁方法,业务逻辑。 +2. 检查停止服务时,是否存在耗时的业务处理逻辑。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/21.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/21.md new file mode 100644 index 000000000000..b6f968603615 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/21.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/21/ +- /zh-cn/docs3-v2/java-sdk/faq/5/21/ +- /zh-cn/overview/mannual/java-sdk/faq/5/21/ +description: 5-21 - 服务销毁时发生异常错误 +linkTitle: 5-21 - 服务销毁时发生异常错误 +title: 5-21 - 服务销毁时发生异常错误 +type: docs +weight: 21 +--- + + + + + + + +### 可能的原因 + +服务发现实例已销毁完成 + +> 当前方法在 3.1 版本已停止使用 + +### 排查和解决步骤 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/22.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/22.md new file mode 100644 index 000000000000..bd25b3026531 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/22.md @@ -0,0 +1,29 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/22/ +- /zh-cn/docs3-v2/java-sdk/faq/5/22/ +- /zh-cn/overview/mannual/java-sdk/faq/5/22/ +description: 5-22 - 注册中心在初始化时发生错误 +linkTitle: 5-22 - 注册中心在初始化时发生错误 +title: 5-22 - 注册中心在初始化时发生错误 +type: docs +weight: 22 +--- + + + + + + + +### 可能的原因 + +1. 注册中心的地址配置错误。 +2. 配置的地址信息无法通过网络正常连接。 +3. 配置中心客户端的版本与实际服务端的版本不符,存在兼容性异常。 + +### 排查和解决步骤 + +1. 检查配置地址是否正确。 +2. 检查网络是否通畅并可通过第三方客户端进行连接。 +3. 检查是否存在兼容性匹配问题,可参考第三方网站进行版本适配。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/23.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/23.md new file mode 100644 index 000000000000..33c9226637c3 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/23.md @@ -0,0 +1,27 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/23/ +- /zh-cn/docs3-v2/java-sdk/faq/5/23/ +- /zh-cn/overview/mannual/java-sdk/faq/5/23/ +description: 5-23 - 等待导出/引用服务发生异常 +linkTitle: 5-23 - 等待导出/引用服务发生异常 +title: 5-23 - 等待导出/引用服务发生异常 +type: docs +weight: 23 +--- + + + + + + + +### 可能的原因 + +导出/引用服务时,注册中心异常停止或无法对外提供正常服务。 + +### 排查和解决步骤 + +检查注册中心的是否可正常连接,并检查当前客户端版本是否与服务端兼容匹配。 + +> 导出/引用单方法内都对异常做了处理,理论上此异常不会被抛出。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/24.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/24.md new file mode 100644 index 000000000000..433294bf3f79 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/24.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/24/ +- /zh-cn/docs3-v2/java-sdk/faq/5/24/ +- /zh-cn/overview/mannual/java-sdk/faq/5/24/ +description: 5-24 - 异步等待引用服务发生异常 +linkTitle: 5-24 - 异步等待引用服务发生异常 +title: 5-24 - 异步等待引用服务发生异常 +type: docs +weight: 24 +--- + + + + + + + +### 可能的原因 + +注册中心异常停止或无法对外提供正常服务。 + +### 排查和解决步骤 + +检查注册中心的是否可正常连接,并检查当前客户端版本是否与服务端兼容匹配。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/25.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/25.md new file mode 100644 index 000000000000..e4b50ef41959 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/25.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/25/ +- /zh-cn/docs3-v2/java-sdk/faq/5/25/ +- /zh-cn/overview/mannual/java-sdk/faq/5/25/ +description: 5-25 - 自定义实现发生未定义异常 +linkTitle: 5-25 - 自定义实现发生未定义异常 +title: 5-25 - 自定义实现发生未定义异常 +type: docs +weight: 25 +--- + + + + + + +### 可能的原因 + +自定义实现的 `org.apache.dubbo.rpc.Protocol` 协议,在方法调用 destory 时发生业务逻辑异常。 + +### 排查和解决步骤 + +检查自定义实现类代码的 `destory` 方法。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/26.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/26.md new file mode 100644 index 000000000000..102de19e7eea --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/26.md @@ -0,0 +1,22 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/26/ +- /zh-cn/docs3-v2/java-sdk/faq/5/26/ +- /zh-cn/overview/mannual/java-sdk/faq/5/26/ +description: 5-26 - 元数据已导出 +linkTitle: 5-26 - 元数据已导出 +title: 5-26 - 元数据已导出 +type: docs +weight: 26 +--- + + + + + + +### 可能的原因 + +元数据在当前 JVM 已被导出。 + +### 排查和解决步骤 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/27.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/27.md new file mode 100644 index 000000000000..7bd71b15855b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/27.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/27/ +- /zh-cn/docs3-v2/java-sdk/faq/5/27/ +- /zh-cn/overview/mannual/java-sdk/faq/5/27/ +description: 5-27 - 内部类API被错误使用 +linkTitle: 5-27 - 内部类API被错误使用 +title: 5-27 - 内部类API被错误使用 +type: docs +weight: 27 +--- + + + + + + +### 可能的原因 + +`org.apache.dubbo.config.ReferenceConfig` 和 `org.apache.dubbo.common.config.ReferenceCache` 或被定义为非单例模式。 + +### 排查和解决步骤 + +检查自定义注解或配置,将核心应用类定以了为非单例模式,检查 `scope` 配置。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/28.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/28.md new file mode 100644 index 000000000000..eca8853e7dc4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/28.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/28/ +- /zh-cn/docs3-v2/java-sdk/faq/5/28/ +- /zh-cn/overview/mannual/java-sdk/faq/5/28/ +description: 5-28 - 未发现可用注解 +linkTitle: 5-28 - 未发现可用注解 +title: 5-28 - 未发现可用注解 +type: docs +weight: 28 +--- + + + + + + +### 可能的原因 + +扫描包配置下未发现可靠注解。主要为 `@DubboService` 或 `@Service` + +### 排查和解决步骤 + +检查当前使用的版本,2.7.7 之前将扫描 `@Service` 注解,之后为 `@DubboService` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/29.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/29.md new file mode 100644 index 000000000000..f38389bab21c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/29.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/29/ +- /zh-cn/docs3-v2/java-sdk/faq/5/29/ +- /zh-cn/overview/mannual/java-sdk/faq/5/29/ +description: 5-29 - 扫描包未配置 +linkTitle: 5-29 - 扫描包未配置 +title: 5-29 - 扫描包未配置 +type: docs +weight: 29 +--- + + + + + + +### 可能的原因 + +`@EnableDubbo.scanBasePackages` 注解参数值未配置。 + +### 排查和解决步骤 + +`@EnableDubbo.scanBasePackages` 配置即可。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/3.md new file mode 100644 index 000000000000..c3184a57622c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/3.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/3/ +- /zh-cn/docs3-v2/java-sdk/faq/5/3/ +- /zh-cn/overview/mannual/java-sdk/faq/5/3/ +description: 5-3 - 销毁方法调用时发生意外错误 +linkTitle: 5-3 - 销毁方法调用时发生意外错误 +title: 5-3 - 销毁方法调用时发生意外错误 +type: docs +weight: 3 +--- + + + + + + +### 可能的原因 + +自定义销毁方法,业务处理上存在异常。 + +### 排查和解决步骤 + +检查自定义销毁方法,业务处理逻辑是否存在运行时异常。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/30.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/30.md new file mode 100644 index 000000000000..febece4c989a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/30.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/30/ +- /zh-cn/docs3-v2/java-sdk/faq/5/30/ +- /zh-cn/overview/mannual/java-sdk/faq/5/30/ +description: 5-30 - 声明bean定义重复 +linkTitle: 5-30 - 声明bean定义重复 +title: 5-30 - 声明bean定义重复 +type: docs +weight: 30 +--- + + + + + + +### 可能的原因 + +声明的对象 id 或名称重复。 + +### 排查和解决步骤 + +根据控制台输出的全限定类名称,名称修改唯一即可。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/31.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/31.md new file mode 100644 index 000000000000..06d67461fa83 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/31.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/31/ +- /zh-cn/docs3-v2/java-sdk/faq/5/31/ +- /zh-cn/overview/mannual/java-sdk/faq/5/31/ +description: 5-31 - 状态检查错误 +linkTitle: 5-31 - 状态检查错误 +title: 5-31 - 状态检查错误 +type: docs +weight: 31 +--- + + + + + + +### 可能的原因 + +当前运行的服务器状态,系统 CPU 使用率过高或内存等指标太低 + +### 排查和解决步骤 + +检查当前服务器的内存使用状态,及 CPU 使用率等其他指标,可能存在宕机的危险。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/32.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/32.md new file mode 100644 index 000000000000..03eed30c2f1f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/32.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/32/ +- /zh-cn/docs3-v2/java-sdk/faq/5/32/ +- /zh-cn/overview/mannual/java-sdk/faq/5/32/ +description: 5-32 - Apollo 断开连接时发生错误 +linkTitle: 5-32 - Apollo 断开连接时发生错误 +title: 5-32 - Apollo 断开连接时发生错误 +type: docs +weight: 32 +--- + + + + + + +### 可能的原因 + +Apollo 配置中心可能已关闭或者网络已断开。 + +### 排查和解决步骤 + +检查 Apollo 服务端服务状态,及网络间是否可正常通信。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/33.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/33.md new file mode 100644 index 000000000000..c6cd6f5465eb --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/33.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/33/ +- /zh-cn/docs3-v2/java-sdk/faq/5/33/ +- /zh-cn/overview/mannual/java-sdk/faq/5/33/ +description: 5-33 - Apollo 配置更新事件发生异常 +linkTitle: 5-33 - Apollo 配置更新事件发生异常 +title: 5-33 - Apollo 配置更新事件发生异常 +type: docs +weight: 33 +--- + + + + + + +### 可能的原因 + +Apollo 配置 API 使用错误。 + +### 排查和解决步骤 + +请参考动态配置中心使用文档中关于 Apollo 部分的描述。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/34.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/34.md new file mode 100644 index 000000000000..1dc2c83c3403 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/34.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/34/ +- /zh-cn/docs3-v2/java-sdk/faq/5/34/ +- /zh-cn/overview/mannual/java-sdk/faq/5/34/ +description: 5-34 - NACOS 发生错误 +linkTitle: 5-34 - NACOS 发生错误 +title: 5-34 - NACOS 发生错误 +type: docs +weight: 34 +--- + + + + + + +### 可能的原因 + +NACOS 配置 API 使用错误。 + +### 排查和解决步骤 + +请参考动态配置中心使用文档中关于 NACOS 部分的描述。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/35.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/35.md new file mode 100644 index 000000000000..6afe4a7879f2 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/35.md @@ -0,0 +1,27 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/35/ +- /zh-cn/docs3-v2/java-sdk/faq/5/35/ +- /zh-cn/overview/mannual/java-sdk/faq/5/35/ +description: 5-35 - 容器初始化失败 +linkTitle: 5-35 - 容器初始化失败 +title: 5-35 - 容器初始化失败 +type: docs +weight: 35 +--- + + + + + + +## 可能的原因 + +未定义接口的 `org.apache.dubbo.container.Container` SPI 实现。 + +附:目前在`org.apache.dubbo.container.Main` 类中测试使用。 + +## 排查和解决步骤 + + +

diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/36.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/36.md new file mode 100644 index 000000000000..6b337d196bf0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/36.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/36/ +- /zh-cn/docs3-v2/java-sdk/faq/5/36/ +- /zh-cn/overview/mannual/java-sdk/faq/5/36/ +description: 5-36 - 过滤器校验时发生错误 +linkTitle: 5-36 - 过滤器校验时发生错误 +title: 5-36 - 过滤器校验时发生错误 +type: docs +weight: 36 +--- + + + + + + +### 可能的原因 + +自定义过滤器扩展类中重写的 `invoke` 方法,发生业务代码异常。 + +### 排查和解决步骤 +1. 使用 ps -eaf |grep <错误服务> +2. 可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/37.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/37.md new file mode 100644 index 000000000000..e216f007259b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/37.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/37/ +- /zh-cn/docs3-v2/java-sdk/faq/5/37/ +- /zh-cn/overview/mannual/java-sdk/faq/5/37/ +description: 5-37 - 动态配置监听处理发生错误 +linkTitle: 5-37 - 动态配置监听处理发生错误 +title: 5-37 - 动态配置监听处理发生错误 +type: docs +weight: 37 +--- + + + + + +文件发生变化时,监听事件处理失败 + +### 可能的原因 + +文件权限发生变化或目录权限发生变化。 + +### 排查和解决步骤 + +可根据控制台的堆栈信息,进行代码定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/38.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/38.md new file mode 100644 index 000000000000..e1a911575d5c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/38.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/38/ +- /zh-cn/docs3-v2/java-sdk/faq/5/38/ +- /zh-cn/overview/mannual/java-sdk/faq/5/38/ +description: 5-38 - 配置参数未定义 +linkTitle: 5-38 - 配置参数未定义 +title: 5-38 - 配置参数未定义 +type: docs +weight: 38 +--- + + + + + + +### 可能的原因 + +配置参数未定义 + +### 排查和解决步骤 + +多为测试用例中使用,可根据提示明细,进行参数的设置。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/39.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/39.md new file mode 100644 index 000000000000..9ed6c90f3236 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/39.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/39/ +- /zh-cn/docs3-v2/java-sdk/faq/5/39/ +- /zh-cn/overview/mannual/java-sdk/faq/5/39/ +description: 5-39 - Dubbo配置bean初始化器发生错误 +linkTitle: 5-39 - Dubbo配置bean初始化器发生错误 +title: 5-39 - Dubbo配置bean初始化器发生错误 +type: docs +weight: 39 +--- + + + + + + +### 可能的原因 + +源代码或被修改 + +### 排查和解决步骤 + +检查业务代码未对核心类进行源码修改或加载的顺序修改。 +如:`org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/4.md new file mode 100644 index 000000000000..f557175c9c96 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/4.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/4/ +- /zh-cn/docs3-v2/java-sdk/faq/5/4/ +- /zh-cn/overview/mannual/java-sdk/faq/5/4/ +description: 5-4 - 服务接口中找不到方法 +linkTitle: 5-4 - 服务接口中找不到方法 +title: 5-4 - 服务接口中找不到方法 +type: docs +weight: 4 +--- + + + + + + +### 可能的原因 + +1. 消费端调用的接口名#方法不存在。 +2. 服务端未正确的暴露当前接口。 + +### 排查和解决步骤 + +1. 检查消费端调用的接口名#方法是否存在。 +2. 检查服务端暴露的服务列表内是否存在。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/40.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/40.md new file mode 100644 index 000000000000..ca79402f4e1d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/40.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/40/ +- /zh-cn/docs3-v2/java-sdk/faq/5/40/ +- /zh-cn/overview/mannual/java-sdk/faq/5/40/ +description: 5-40 - Dubbo配置bean未找到 +linkTitle: 5-40 - Dubbo配置bean未找到 +title: 5-40 - Dubbo配置bean未找到 +type: docs +weight: 40 +--- + + + + + + +### 可能的原因 + +源代码或被修改 + +### 排查和解决步骤 + +检查业务代码未对核心类进行源码修改或加载的顺序修改。 +如:`org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/41.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/41.md new file mode 100644 index 000000000000..5167fc20cfed --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/41.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/41/ +- /zh-cn/docs3-v2/java-sdk/faq/5/41/ +- /zh-cn/overview/mannual/java-sdk/faq/5/41/ +description: 5-41 - SSL证书读取失败 +linkTitle: 5-41 - SSL证书读取失败 +title: 5-41 - SSL证书读取失败 +type: docs +weight: 41 +--- + + + + + + +### 可能的原因 + +SSL 证书配置异常 + +### 排查和解决步骤 + +检查 SSL 证书的配置,查看对应文件是否存在 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/42.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/42.md new file mode 100644 index 000000000000..e32b4a65ef2b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/42.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/42/ +- /zh-cn/docs3-v2/java-sdk/faq/5/42/ +- /zh-cn/overview/mannual/java-sdk/faq/5/42/ +description: 5-42 - Dubbo 证书签发失败 +linkTitle: 5-42 - Dubbo 证书签发失败 +title: 5-42 - Dubbo 证书签发失败 +type: docs +weight: 42 +--- + + + + + + +### 可能的原因 + +Dubbo 请求远程 CA 签发证书失败 + +### 排查和解决步骤 + +- 检查 CA 连接配置 +- 检查 CA 运行状态 +- 检查 CA 日志 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/43.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/43.md new file mode 100644 index 000000000000..4ac65c40416f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/43.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/43/ +- /zh-cn/docs3-v2/java-sdk/faq/5/43/ +- /zh-cn/overview/mannual/java-sdk/faq/5/43/ +description: 5-43 - Dubbo 证书签发连接不安全 +linkTitle: 5-43 - Dubbo 证书签发连接不安全 +title: 5-43 - Dubbo 证书签发连接不安全 +type: docs +weight: 43 +--- + + + + + + +### 可能的原因 + +Dubbo 与远程 CA 的连接不安全 + +### 排查和解决步骤 + +- 检查 Dubbo 进程是否已经正确配置了 CA 证书信息以及 OIDC(OpenID Connect)的 Token 获取方式 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/5.md new file mode 100644 index 000000000000..b1fc2889a647 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/5.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/5/ +- /zh-cn/docs3-v2/java-sdk/faq/5/5/ +- /zh-cn/overview/mannual/java-sdk/faq/5/5/ +description: 5-5 - 无法获得env变量 +linkTitle: 5-5 - 无法获得env变量 +title: 5-5 - 无法获得env变量 +type: docs +weight: 5 +--- + + + + + + +### 可能的原因 + +环境变量无法获取。 + +### 排查和解决步骤 + +检查提示的变量名,是否配置并可以正常读取加载。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/6.md new file mode 100644 index 000000000000..45dd63782dfe --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/6.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/6/ +- /zh-cn/docs3-v2/java-sdk/faq/5/6/ +- /zh-cn/overview/mannual/java-sdk/faq/5/6/ +description: 5-6 - 接口类型的属性冲突 +linkTitle: 5-6 - 接口类型的属性冲突 +title: 5-6 - 接口类型的属性冲突 +type: docs +weight: 6 +--- + + + + + + +### 可能的原因 + +泛化定义配置不正确。 + +### 排查和解决步骤 + +检查泛化定义是否正确。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/7.md new file mode 100644 index 000000000000..5041addb585f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/7.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/7/ +- /zh-cn/docs3-v2/java-sdk/faq/5/7/ +- /zh-cn/overview/mannual/java-sdk/faq/5/7/ +description: 5-7 - 取消导出时发生意外错误 +linkTitle: 5-7 - 取消导出时发生意外错误 +title: 5-7 - 取消导出时发生意外错误 +type: docs +weight: 7 +--- + + + + + + +### 可能的原因 + +1. 配置中心的服务无法连接。 +2. 配置的协议、IP、端口不正确。 +3. 使用配置中心客户端版本与服务端版本冲突,无法建立有效连接。 + +### 排查和解决步骤 + +1. 检查配置中心的服务状态是否正常。 +2. 检查配置的协议、IP、端口不正确。 +3. 检查使用的配置中心客户端版本与服务端版本是否兼容。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/8.md new file mode 100644 index 000000000000..c0966beb4828 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/8.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/8/ +- /zh-cn/docs3-v2/java-sdk/faq/5/8/ +- /zh-cn/overview/mannual/java-sdk/faq/5/8/ +description: 5-8 - 协议将使用随机可用端口 +linkTitle: 5-8 - 协议将使用随机可用端口 +title: 5-8 - 协议将使用随机可用端口 +type: docs +weight: 8 +--- + + + + + + +### 可能的原因 + +协议指定的端口被占用,随机选择端口进行启动。 + +### 排查和解决步骤 + +检查当前配置端口是否被其它应用程序占用。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/9.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/9.md new file mode 100644 index 000000000000..57a333eb4a18 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/9.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/9/ +- /zh-cn/docs3-v2/java-sdk/faq/5/9/ +- /zh-cn/overview/mannual/java-sdk/faq/5/9/ +description: 5-9 - 服务配置导出失败 +linkTitle: 5-9 - 服务配置导出失败 +title: 5-9 - 服务配置导出失败 +type: docs +weight: 9 +--- + + + + + + +### 可能的原因 + +1. 配置中心的服务无法连接。 +2. 配置的协议、IP、端口不正确。 +3. 使用配置中心客户端版本与服务端版本冲突,无法建立有效连接。 + +### 排查和解决步骤 + +1. 检查配置中心的服务状态是否正常。 +2. 检查配置的协议、IP、端口不正确。 +3. 检查使用的配置中心客户端版本与服务端版本是否兼容。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/_index.md new file mode 100644 index 000000000000..26a7bcd20484 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/_index.md @@ -0,0 +1,11 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/5/ +- /zh-cn/docs3-v2/java-sdk/faq/5/ +- /zh-cn/overview/mannual/java-sdk/faq/5/_index/ +description: 5 - 配置(中心)层 +linkTitle: 5 - 配置(中心)层 +title: 5 - 配置(中心)层 +type: docs +weight: 5 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/1.md new file mode 100644 index 000000000000..96c7734da080 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/1.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/1/ +- /zh-cn/docs3-v2/java-sdk/faq/6/1/ +- /zh-cn/overview/mannual/java-sdk/faq/6/1/ +description: 6-1 - 服务端连接失败 +linkTitle: 6-1 - 服务端连接失败 +title: 6-1 - 服务端连接失败 +type: docs +weight: 1 +--- + + + + + +网络通信层,在连接服务提供者服务时失败 + +### 可能的原因 + +服务提供者的网络异常断开或受防火墙及第三方工具的拦截,无法对外提供服务。 + +### 排查和解决步骤 + +1. 如果为 rest 连接,检查请求的服务端配置是否正确。 +2. 检查网络通信是否正常,可使用一些简单的 cmd 命令进行检测,如 `ping` 等。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/10.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/10.md new file mode 100644 index 000000000000..ac18c5ea06d4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/10.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/10/ +- /zh-cn/docs3-v2/java-sdk/faq/6/10/ +- /zh-cn/overview/mannual/java-sdk/faq/6/10/ +description: 6-10 - 超过有效载荷限制异常 +linkTitle: 6-10 - 超过有效载荷限制异常 +title: 6-10 - 超过有效载荷限制异常 +type: docs +weight: 10 +--- + + + + + + +### 可能的原因 + +> 默认 `payload=8M`,请检查各项配置 + +### 排查和解决步骤 + +各组件支持的具体配置项及含义请参考 [配置项手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/11.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/11.md new file mode 100644 index 000000000000..e8a385ec43eb --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/11.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/11/ +- /zh-cn/docs3-v2/java-sdk/faq/6/11/ +- /zh-cn/overview/mannual/java-sdk/faq/6/11/ +description: 6-11 - 字符集不被支持 +linkTitle: 6-11 - 字符集不被支持 +title: 6-11 - 字符集不被支持 +type: docs +weight: 11 +--- + + + + + + +## 可能的原因 + +> 默认 `UTF-8` 字符集 + +## 排查和解决步骤 + +结果会最终以 `UTF-8` 字符集进行处理。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/12.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/12.md new file mode 100644 index 000000000000..58b4d27d0b98 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/12.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/12/ +- /zh-cn/docs3-v2/java-sdk/faq/6/12/ +- /zh-cn/overview/mannual/java-sdk/faq/6/12/ +description: 6-12 - ZK客户端销毁时发生错误 +linkTitle: 6-12 - ZK客户端销毁时发生错误 +title: 6-12 - ZK客户端销毁时发生错误 +type: docs +weight: 12 +--- + + + + + + + +### 可能的原因 + +客户端与服务端连接已被拒绝 +客户端在销毁时,可能服务端正在进行选举或者其他操作,导致发生的异常。 + +### 排查和解决步骤 + +关闭方法,可针对堆栈信息进行查询。一般可不处理。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/13.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/13.md new file mode 100644 index 000000000000..76c1392b058f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/13.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/13/ +- /zh-cn/docs3-v2/java-sdk/faq/6/13/ +- /zh-cn/overview/mannual/java-sdk/faq/6/13/ +description: 6-13 - 流关闭异常 +linkTitle: 6-13 - 流关闭异常 +title: 6-13 - 流关闭异常 +type: docs +weight: 13 +--- + + + + + + + +### 可能的原因 + +当前流已关闭 `Stream is closed` 或流关闭时,其他线程正在读取。 + +### 排查和解决步骤 + +一般为代码关闭流的顺序上发生了颠倒。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/14.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/14.md new file mode 100644 index 000000000000..07bd31411399 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/14.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/14/ +- /zh-cn/docs3-v2/java-sdk/faq/6/14/ +- /zh-cn/overview/mannual/java-sdk/faq/6/14/ +description: 6-14 - 服务端响应失败 +linkTitle: 6-14 - 服务端响应失败 +title: 6-14 - 服务端响应失败 +type: docs +weight: 14 +--- + + + + + + +### 可能的原因 + +在服务端与客户端交互发生数据时,客户端异常关闭。 + +### 排查和解决步骤 + +客户端异常终止或服务器宕机。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/15.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/15.md new file mode 100644 index 000000000000..565f47239166 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/15.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/15/ +- /zh-cn/docs3-v2/java-sdk/faq/6/15/ +- /zh-cn/overview/mannual/java-sdk/faq/6/15/ +description: 6-15 - 跳过未读完的流数据 +linkTitle: 6-15 - 跳过未读完的流数据 +title: 6-15 - 跳过未读完的流数据 +type: docs +weight: 15 +--- + + + + + + +### 可能的原因 + +解码时,如流中还有未读数据时会跳过未读完的流 + +### 排查和解决步骤 + +解码时会把数据全部一次性读取 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/16.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/16.md new file mode 100644 index 000000000000..4ed6d440761d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/16.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/16/ +- /zh-cn/docs3-v2/java-sdk/faq/6/16/ +- /zh-cn/overview/mannual/java-sdk/faq/6/16/ +description: 6-16 - 重连时发生异常 +linkTitle: 6-16 - 重连时发生异常 +title: 6-16 - 重连时发生异常 +type: docs +weight: 16 +--- + + + + + + +### 可能的原因 + +每次发生重连时提示,网络不稳定造成的延迟重连。 + +### 排查和解决步骤 + +检查是否有网络丢包情况。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/2.md new file mode 100644 index 000000000000..425161657877 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/2.md @@ -0,0 +1,34 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/2/ +- /zh-cn/docs3-v2/java-sdk/faq/6/2/ +- /zh-cn/overview/mannual/java-sdk/faq/6/2/ +description: 6-2 - 客户端超时 +linkTitle: 6-2 - 客户端超时 +title: 6-2 - 客户端超时 +type: docs +weight: 2 +--- + + + + + +超时是调用端发生在请求发出后,无法在指定的时间内获得对应的响应。 + +### 可能的原因 +1. 服务端确实处理比较慢,无法在指定的时间返回结果,调用端就自动返回一个超时的异常响应来结束此次调用。 +2. 服务端如果响应的比较快,但当客户端 Load 很高,负载压力很大的时候,会因为客户端请求发不出去、响应卡在 TCP Buffer 等问题,造成超时。因为客户端接收到服务端发来的数据或者请求服务端的数据,都会在系统层面排队,如果系统负载比较高,在内核态的时间占比就会加长,从而造成客户端获取到值时已经超时。 +3. 通常是业务处理太慢,可在服务提供方机器上执行:`jstack [PID] > jstack.log` 分析线程都卡在哪个方法调用上,这里就是慢的原因。如果不能调优性能,请调高 timeout 阈值。 + + +### 排查和解决步骤 + +1. 两边可能有 GC,检查服务端和客户端 GC 日志,耗时很长的 GC,会导致超时。超时的发生很可能意味着调用端或者服务端的资源(CPU,内存或者网络)出现了瓶颈,需要检查服务端的问题还是调用端的问题来排除 GC 抖动等嫌疑。 +2. 检查服务端的网络质量,比如重传率来排除网络嫌疑。 +3. 借助链路跟踪的分析服务(比如阿里的 [ARMS](https://help.aliyun.com/document_detail/63796.html) ,开源的 [OpenTracing](https://github.com/opentracing/opentracing-java) +系的实现 [Zipkin](https://github.com/openzipkin/zipkin) 、[SkyWalking](https://github.com/apache/skywalking) 等)来分析下各个点的耗时情况。 + + +> 这个错误码的 FAQ 页面参考了空冥同学的 [《Dubbo 常见错误及解决方法》](https://github.com/StabilityMan/StabilityGuide/blob/master/docs/diagnosis/plugin/rpc/%E7%B3%BB%E7%BB%9F%E7%A8%B3%E5%AE%9A%E6%80%A7%E2%80%94%E2%80%94Dubbo%E5%B8%B8%E8%A7%81%E9%94%99%E8%AF%AF%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95.md) 。 +所引文章通过 [CC-BY-4.0](http://creativecommons.org/licenses/by/4.0/) 协议赋予了汇编的权利。在此向原作者表示感谢。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/3.md new file mode 100644 index 000000000000..cc612f74e92d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/3.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/3/ +- /zh-cn/docs3-v2/java-sdk/faq/6/3/ +- /zh-cn/overview/mannual/java-sdk/faq/6/3/ +description: 6-3 - 网络连接关闭失败 +linkTitle: 6-3 - 网络连接关闭失败 +title: 6-3 - 网络连接关闭失败 +type: docs +weight: 3 +--- + + + + + + +### 可能的原因 + +非优雅关闭服务,此时服务端可能在对外输出流未完成。 + +### 排查和解决步骤 + +一般为提示类警告信息,不影响后续的程序执行。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/4.md new file mode 100644 index 000000000000..40a49072c93a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/4.md @@ -0,0 +1,22 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/4/ +- /zh-cn/docs3-v2/java-sdk/faq/6/4/ +- /zh-cn/overview/mannual/java-sdk/faq/6/4/ +description: 6-4 - 网络通讯层未知异常 +linkTitle: 6-4 - 网络通讯层未知异常 +title: 6-4 - 网络通讯层未知异常 +type: docs +weight: 4 +--- + + + + + + +### 可能的原因 +> 该错误码的意义已经调整。对于 Dubbo 3.1.4、3.2.0-beta.3 及其之前的版本的该错误码的出错,请参考错误码 [99-0](/zh-cn/overview/mannual/java-sdk/faq/99/0/)。 + +### 排查和解决步骤 +(该错误码目前空缺) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/5.md new file mode 100644 index 000000000000..8cf5c6c41ed1 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/5.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/5/ +- /zh-cn/docs3-v2/java-sdk/faq/6/5/ +- /zh-cn/overview/mannual/java-sdk/faq/6/5/ +description: 6-5 - 网络连接断开失败 +linkTitle: 6-5 - 网络连接断开失败 +title: 6-5 - 网络连接断开失败 +type: docs +weight: 5 +--- + + + + + + + +### 可能的原因 + +超时是调用端发生在请求发出后,无法在指定的时间内获得对应的响应,出现客户端主动断开连接 + +### 排查和解决步骤 + +一般为提示类警告信息,不影响后续的程序执行。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/6.md new file mode 100644 index 000000000000..07f50c01f853 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/6.md @@ -0,0 +1,27 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/6/ +- /zh-cn/docs3-v2/java-sdk/faq/6/6/ +- /zh-cn/overview/mannual/java-sdk/faq/6/6/ +description: 6-6 - 不支持的消息 +linkTitle: 6-6 - 不支持的消息 +title: 6-6 - 不支持的消息 +type: docs +weight: 6 +--- + + + + + + + +### 可能的原因 + +返回的数据序列化错误,或超出序列化最大值 + +### 排查和解决步骤 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 + +各组件支持的具体配置项及含义请参考 [配置项手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/7.md new file mode 100644 index 000000000000..137a8002f48c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/7.md @@ -0,0 +1,24 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/7/ +- /zh-cn/docs3-v2/java-sdk/faq/6/7/ +- /zh-cn/overview/mannual/java-sdk/faq/6/7/ +description: 6-7 - 线程连接数超限警告 +linkTitle: 6-7 - 服务端连接失败 +title: 6-7 - 线程连接数超限警告 +type: docs +weight: 7 +--- + + + + + + +### 可能的原因 + +连接数超过限制时的提醒消息,配置或连接数超过配置数的警告提醒。 + +### 排查和解决步骤 + +默认配置项 `connect.queue.warning.size=1000`,可通过配置进行调整。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/8.md new file mode 100644 index 000000000000..cce08265ad13 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/8.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/8/ +- /zh-cn/docs3-v2/java-sdk/faq/6/8/ +- /zh-cn/overview/mannual/java-sdk/faq/6/8/ +description: 6-8 - 返回数据解码失败 +linkTitle: 6-8 - 返回数据解码失败 +title: 6-8 - 返回数据解码失败 +type: docs +weight: 8 +--- + + + + + + + +### 可能的原因 + +返回数据格式错误或解码失败 + +### 排查和解决步骤 + +可通过 debug/warn 日志模式,输出具体服务类名称和返回的消息及堆栈信息。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/9.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/9.md new file mode 100644 index 000000000000..9ad290c6237d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/9.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/9/ +- /zh-cn/docs3-v2/java-sdk/faq/6/9/ +- /zh-cn/overview/mannual/java-sdk/faq/6/9/ +description: 6-9 - 序列号ID存在重复 +linkTitle: 6-9 - 服务端连接失败 +title: 6-9 - 序列号ID存在重复 +type: docs +weight: 9 +--- + + + + + + + +### 可能的原因 + +1. 返回了一个空对象。 +2. 自定义序列号类,`org.apache.dubbo.common.serialize.Serialization#getContentTypeId` 与系统内置存在重复, +此时在加载时,以首个加载到的 SPI 实例为准。其他项将跳过。 + +### 排查和解决步骤 + +1. 检查返回结果。 +2. 内置值可参考类 `org.apache.dubbo.common.serialize.Constants` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/_index.md new file mode 100644 index 000000000000..c998a9712a62 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/_index.md @@ -0,0 +1,11 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/6/ +- /zh-cn/docs3-v2/java-sdk/faq/6/ +- /zh-cn/overview/mannual/java-sdk/faq/6/_index/ +description: 6 - 网络传输层 +linkTitle: 6 - 网络传输层 +title: 6 - 网络传输层 +type: docs +weight: 6 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/1.md new file mode 100644 index 000000000000..2757de9f90cb --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/1.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/7/1/ +- /zh-cn/docs3-v2/java-sdk/faq/7/1/ +- /zh-cn/overview/mannual/java-sdk/faq/7/1/ +description: 7-1 - QOS 已关闭 +linkTitle: 7-1 - QOS 已关闭 +title: 7-1 - QOS 已关闭 +type: docs +weight: 1 +--- + + + + + + +### 可能的原因 + +QOS 已关闭 + +### 排查和解决步骤 + + +> 请参考[QOS 操作手册](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/2.md new file mode 100644 index 000000000000..06dfa2b102ff --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/2.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/7/2/ +- /zh-cn/docs3-v2/java-sdk/faq/7/2/ +- /zh-cn/overview/mannual/java-sdk/faq/7/2/ +description: 7-2 - QOS 已开启 +linkTitle: 7-2 - QOS 已开启 +title: 7-2 - QOS 已开启 +type: docs +weight: 2 +--- + + + + + + +### 可能的原因 + +QOS 已开启,默认为开启状态。 + +### 排查和解决步骤 + + +> 请参考[QOS 操作手册](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/3.md new file mode 100644 index 000000000000..f9175cf1a4db --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/3.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/7/3/ +- /zh-cn/docs3-v2/java-sdk/faq/7/3/ +- /zh-cn/overview/mannual/java-sdk/faq/7/3/ +description: 7-3 - 设置超时时间的警告百分比值 +linkTitle: 7-3 - 设置超时时间的警告百分比值 +title: 7-3 - 设置超时时间的警告百分比值 +type: docs +weight: 3 +--- + + + + + + +## 可能的原因 + +QOS 设置超时时间的警告百分比值, 默认为0.75。修改后,控制台会打印此消息。 + +## 排查和解决步骤 + + +请参考 QOS 操作手册[性能采样命令](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/profiler/)。 +

diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/4.md new file mode 100644 index 000000000000..fd8fc540bee9 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/4.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/7/4/ +- /zh-cn/docs3-v2/java-sdk/faq/7/4/ +- /zh-cn/overview/mannual/java-sdk/faq/7/4/ +description: 7-4 - QOS 服务启动失败 +linkTitle: 7-4 - QOS 服务启动失败 +title: 7-4 - QOS 服务启动失败 +type: docs +weight: 4 +--- + + + + + + +### 可能的原因 + +QOS 参数值未正确设置。主要参数有 `qos.host` 和 `qos.port` + +### 排查和解决步骤 + + +> 请参考QOS 操作手册[QOS 概述](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/overview/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/5.md new file mode 100644 index 000000000000..b9726dd07e8d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/5.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/7/5/ +- /zh-cn/docs3-v2/java-sdk/faq/7/5/ +- /zh-cn/overview/mannual/java-sdk/faq/7/5/ +description: 7-5 - QOS 命令未找到 +linkTitle: 7-5 - QOS 命令未找到 +title: 7-5 - QOS 命令未找到 +type: docs +weight: 5 +--- + + + + + + +### 可能的原因 + +QOS 命令拼写错误。 + +## 排查和解决步骤 + +QOS 命令不存在。 + +> 请参考 QOS 操作手册[基础命令手册](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/command/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/6.md new file mode 100644 index 000000000000..83c49e4df379 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/6.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/7/6/ +- /zh-cn/docs3-v2/java-sdk/faq/7/6/ +- /zh-cn/overview/mannual/java-sdk/faq/7/6/ +description: 7-6 - QOS 发生未知异常 +linkTitle: 7-6 - QOS 发生未知异常 +title: 7-6 - QOS 发生未知异常 +type: docs +weight: 6 +--- + + + + + + +### 可能的原因 + +QOS 发生未知异常 + +### 排查和解决步骤 + +1. 检查当前请求的服务是否可正常访问。 +2. 可能由于某些原因,未能正确加载或返回 `CommandContext` 实例。可根据控制台的错误提醒信息,进行排查定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/7.md new file mode 100644 index 000000000000..5ac45a2ee3bb --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/7.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/7/7/ +- /zh-cn/docs3-v2/java-sdk/faq/7/7/ +- /zh-cn/overview/mannual/java-sdk/faq/7/7/ +description: 7-7 - QOS 无权限访问 +linkTitle: 7-7 - QOS 无权限访问 +title: 7-7 - QOS 无权限访问 +type: docs +weight: 7 +--- + + + + + + +### 可能的原因 + +本次 QoS 请求无权限访问对应的资源,通常出现在有恶意攻击的场景下 + +### 排查和解决步骤 + +检查请求是否是预期发生的,如果非预期请检查是否有恶意攻击源。 +> 如果是预期的,请参考 [QoS 安全](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/overview/#%E5%AE%89%E5%85%A8) 一文配置对应的权限信息。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/_index.md new file mode 100644 index 000000000000..6b3aef9e5110 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/_index.md @@ -0,0 +1,11 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/7/ +- /zh-cn/docs3-v2/java-sdk/faq/7/ +- /zh-cn/overview/mannual/java-sdk/faq/7/_index/ +description: 7 - QoS 插件模块 +linkTitle: 7 - QoS 插件模块 +title: 7 - QoS 插件模块 +type: docs +weight: 7 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/1.md new file mode 100644 index 000000000000..c57fa729d91b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/1.md @@ -0,0 +1,28 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/81/1/ +- /zh-cn/docs3-v2/java-sdk/faq/81/1/ +- /zh-cn/overview/mannual/java-sdk/faq/81/1/ +description: 81-1 - ZK 启动异常 +linkTitle: 81-1 - ZK 启动异常 +title: 81-1 - ZK 启动异常 +type: docs +weight: 1 +--- + + + + + + +### 可能的原因 + +1. zk 的服务端版本与客户端版本存在不兼容问题,无法进行连接。 +2. zk 服务未正常启动或防火墙等原因不能对外提供服务。 + +### 排查和解决步骤 + +1. 确认客户端版本与服务端版本一致。 +2. zk 能够正常启动或对外能够提供正常服务。 + +可通过一些第三方的工具或者`jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/2.md new file mode 100644 index 000000000000..d6b530687d25 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/2.md @@ -0,0 +1,25 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/81/2/ +- /zh-cn/docs3-v2/java-sdk/faq/81/2/ +- /zh-cn/overview/mannual/java-sdk/faq/81/2/ +description: 81-2 - ZK 销毁异常 +linkTitle: 81-2 - ZK 销毁异常 +title: 81-2 - ZK 销毁异常 +type: docs +weight: 2 +--- + + + + + + +### 可能的原因 + +当前实例已销毁完成。 +网络或已断开。 + +### 排查和解决步骤 + +可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/3.md new file mode 100644 index 000000000000..56acd1c8048a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/3.md @@ -0,0 +1,26 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/81/3/ +- /zh-cn/docs3-v2/java-sdk/faq/81/3/ +- /zh-cn/overview/mannual/java-sdk/faq/81/3/ +description: 81-3 - 通过url无法下载文件 +linkTitle: 81-3 - 通过url无法下载文件 +title: 81-3 - 通过url无法下载文件 +type: docs +weight: 3 +--- + + + + + + +### 可能的原因 + +1. url 映射文件不存在。 +2. url 无法连接。 + +### 排查和解决步骤 + +1. 检查 url 映射文件是否存在。 +2. 通过浏览器或其他工具,能否正常访问。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/4.md new file mode 100644 index 000000000000..1fb0738db147 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/4.md @@ -0,0 +1,30 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/81/4/ +- /zh-cn/docs3-v2/java-sdk/faq/81/4/ +- /zh-cn/overview/mannual/java-sdk/faq/81/4/ +description: 81-4 - 嵌入式ZooKeeper运行异常 +linkTitle: 81-4 - 嵌入式ZooKeeper运行异常 +title: 81-4 - 嵌入式ZooKeeper运行异常 +type: docs +weight: 4 +--- + + + + + + +### 可能的原因 + +1. ZooKeeper 服务运行异常或宕机。 +2. Zookeeper 客户端版本与服务端启动版本不兼容,无法连接。 +3. 应用服务器与 ZooKeeper 服务连接中断。 +4. 受限防火墙或第三方防护工具。 + +### 排查和解决步骤 + +1. 检查 ZooKeeper 服务及所在服务器健康状态。 +2. 检查 Zookeeper 客户端版本与服务端启动版本是否存在兼容问题,保持版本一致。 +3. 检查应用服务器与 ZooKeeper 服务端口是否通畅。 +4. 检查防火墙或第三方防护工具设置,是否已禁止。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/_index.md new file mode 100644 index 000000000000..3afa03d52492 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/_index.md @@ -0,0 +1,18 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/81/ +- /zh-cn/docs3-v2/java-sdk/faq/81/ +- /zh-cn/overview/mannual/java-sdk/faq/81/_index/ +description: 81 - 单元测试辅助模块(注册中心) +linkTitle: 81 - 单元测试辅助模块(注册中心) +title: 81 - 单元测试辅助模块(注册中心) +type: docs +weight: 81 +--- + + + + + + +这里主要是 `dubbo-test` 模块中用于测试注册中心模块的代码的相关错误码。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/99/0.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/99/0.md new file mode 100644 index 000000000000..fa86ec7a4f07 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/99/0.md @@ -0,0 +1,30 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/99/0/ +- /zh-cn/docs3-v2/java-sdk/faq/99/0/ +- /zh-cn/overview/mannual/java-sdk/faq/99/0/ +description: 99-0 - 内部未知错误 +linkTitle: 99-0 - 内部未知错误 +title: 99-0 - 内部未知错误 +type: docs +weight: 1 +--- + + + + + +Dubbo 内部的未知错误。 + +### 可能的原因 +未知错误 + +### 排查和解决步骤 +1. 保护现场。将日志文件保存下来,尽可能记录下发生故障当时的情况。(此时可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息。) +2. 如果在这个错误码之前有其它的错误码的日志记录,那么请先查看一下那个错误码的记录。 +3. 检查配置文件是否有误。 +4. 如果是修改了代码引入了这个错误,尝试回滚到上一个版本。 +5. 如果都没解决,请尽可能做出一个复现该问题的最小 Demo,之后到 [GitHub Issue Tracker](https://github.com/apache/dubbo/issues) 下发 Issue。 + +> 另请参阅 +[配置项手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/99/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/99/1.md new file mode 100644 index 000000000000..56fb31b83cea --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/99/1.md @@ -0,0 +1,27 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/99/1/ +- /zh-cn/docs3-v2/java-sdk/faq/99/1/ +- /zh-cn/overview/mannual/java-sdk/faq/99/1/ +description: 99-1 - 程序被打断 +linkTitle: 99-1 - 程序被打断 +title: 99-1 - 程序被打断 +type: docs +weight: 2 +--- + + + + + +Dubbo 内部的未知错误。 + +### 可能的原因 + +程序收到来自 JVM 层面的打断通知,被迫停止阻塞等待 + +### 排查和解决步骤 + +此异常通常发生在线程池关闭或者应用关闭的过程中。 +请检查是否影响业务正常使用,如无影响可以忽略,如果有影响请参照对应的排查手册。 +更多的排查思路可以参考 [99-0](../0/) 一文。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/99/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/99/_index.md new file mode 100644 index 000000000000..54769f408c6f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/99/_index.md @@ -0,0 +1,11 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/99/ +- /zh-cn/docs3-v2/java-sdk/faq/99/ +- /zh-cn/overview/mannual/java-sdk/faq/99/_index/ +description: 99 - 其它未知错误 +linkTitle: 99 - 其它未知错误 +title: 99 - 其它未知错误 +type: docs +weight: 99 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/_index.md new file mode 100755 index 000000000000..d1a247a7db2b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/_index.md @@ -0,0 +1,18 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/ +- /zh-cn/docs3-v2/java-sdk/faq/ +- /zh-cn/overview/mannual/java-sdk/faq/_index/ +description: 错误码 FAQ +linkTitle: 错误码 FAQ +title: 错误码 FAQ +type: docs +weight: 199 +--- + + + + + + +这里主要是提供 Java SDK 中各个错误码的可能原因和解决方法。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/intro.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/intro.md new file mode 100644 index 000000000000..b6603302232c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/intro.md @@ -0,0 +1,53 @@ +--- +aliases: +- /zh/docs3-v2/java-sdk/faq/intro/ +- /zh-cn/docs3-v2/java-sdk/faq/intro/ +- /zh-cn/overview/mannual/java-sdk/faq/intro/ +- /zh-cn/overview/java-sdk/reference-manual/faq/intro/ +description: 错误码机制的介绍 +linkTitle: 错误码机制的介绍 +title: 错误码机制的介绍 +type: docs +weight: 0 +--- + + + + + + +### 背景 +Dubbo 内部依赖的 Logger 抽象层提供了日志输出能力,但是大部分的异常日志都没有附带排查说明,导致用户看到异常后无法进行处理。 + +为了解决这个问题,自 Dubbo 3.1 版本开始,引入了错误码机制。其将官方文档中的错误码 FAQ 与日志框架连接起来。在日志抽象输出异常的同时附带输出对应的官网文档链接,引导用户进行自主排查。 + +### 错误码格式 +`[Cat]-[X]` + +> 两个空格均为数字。其中第一个数字为类别,第二个数字为具体错误码。 + +### 提示显示的格式 +``` +This may be caused by ..., go to https://dubbo.apache.org/faq/[Cat]/[X] to find instructions. +``` +> 另外在这句话后可以指定补充的信息(即 extendedInformation)。 + +### 显示的实例 +``` +[31/07/22 02:43:07:796 CST] main WARN support.AbortPolicyWithReport: [DUBBO] Thread pool is EXHAUSTED! Thread Name: Test, Pool Size: 0 (active: 0, core: 1, max: 1, largest: 0), Task: 0 (completed: 0), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://10.20.130.230:20880!, dubbo version: , current host: 10.20.130.230, error code: 0-1. This may be caused by too much client requesting provider, go to https://dubbo.apache.org/faq/0/1 to find instructions. +``` + +> 用户只需点击链接即可根据错误码查找到原因。 + +### Logger 接口支持 +为确保兼容性,Dubbo 3.1 基于原本的 Logger 抽象,构建了一个新的接口 `ErrorTypeAwareLogger`。 + +warn 等级的方法进行了扩展如下 +``` +void warn(String code, String cause, String extendedInformation, String msg); +void warn(String code, String cause, String extendedInformation, String msg, Throwable e); +``` + +其中 code 指错误码,cause 指可能的原因(即 caused by... 后面所接的文字),extendedInformation 作为补充信息,直接附加在 caused by 这句话的后面。 + +> 对于 error 级别也做了相同的扩展。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/graalvm/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/graalvm/_index.md new file mode 100644 index 000000000000..035bda8d933b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/graalvm/_index.md @@ -0,0 +1,223 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/graalvm/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/graalvm/ +description: "" +hide_summary: true +linkTitle: GraalVM +title: Dubbo 集成 Graalvm参考手册 +type: docs +weight: 9 +--- + + + + + + +dubbo3.0支持native-image文档 + +## 概述 + +本文档将介绍将dubbo3.0项目接入GraalVM,进行native-image编译为二进制的流程。 + +关于GraalVm的更多信息可以阅读 https://www.graalvm.org/docs/getting-started/container-images/ 此文档。 + +## 使用样例 + +在编译我们的dubbo项目之前,需要确保我们正基于graalVm的环境。 + +1. 安装GraalVM + +进入https://www.graalvm.org/ 官网根据自己的系统选取最新版本安装: + +![img](/imgs/blog/dubbo3.0-graalvm-support/graalvmgw.jpg) + +安装完成后,修改配置JAVA_HOME的路径,生效后查看本地jdk可以看到如下: + +![img](/imgs/blog/dubbo3.0-graalvm-support/graalvm_env.jpg) +这里我们使用的基于jdk1.8版本的GraalVM。 + +- 安装native-image,只需执行gu install native-image即可。 + +1. 拉取dubbo代码,切换到[apache:3.0](https://github.com/apache/dubbo)分支。 +2. 手动执行生成SPI代码。 + +由于目前编译native-image不支持代码动态生成编译,所以有关代码动态生成的部分需要我们手动先生成,这里提供了工具函数: + +![img](/imgs/blog/dubbo3.0-graalvm-support/code_generator.jpg) +执行CodeGenerator即可在dubbo-native模块下生成SPI代码。 + +1. 在根目录下执行install + +``` +MacdeMacBook-pro-3:incubator-dubbo mac$ pwd + +/Users/mac/Documents/Mi/project/incubator-dubbo + +MacdeMacBook-pro-3:incubator-dubbo mac$ mvn clean package install -Dmaven.test.skip=true +``` + +1. 编译demo项目 + +这里我们提供了可直接进行编译的示例项目,dubbo-demo/dubbo-demo-native。上面步骤install完成后,先到dubbo-demo-native的provider下,执行native-image编译: + +``` + mvn clean package -P native -Dmaven.test.skip=true +``` + +这里由于我们在maven中引入了native-image插件,所以直接-P native即可执行该插件。 + +![img](/imgs/blog/dubbo3.0-graalvm-support/native_image_build.jpg) +编译成功后可以在target下看到已经生成的二进制文件,本地启动一个zookeeper,直接执行该二进制,可见启动成功如下: + +![img](/imgs/blog/dubbo3.0-graalvm-support/run_provider.jpg) +consumer端同样执行编译,在consumer的target下也会生成二进制文件:demo-native-consumer,执行该二进制可以看到调用结果如下: + +![img](/imgs/blog/dubbo3.0-graalvm-support/run_consumer.jpg) +### 具体步骤 + +实际上在这个demo下我们做了一些工作来确保项目可以编译执行,主要有以下几个步骤 + +- 引入dubbo-native依赖 + +``` + + + org.apache.dubbo + + dubbo-native + + ${project.version} + + +``` + +该模块下有我们生成的SPI代码。 + +- 引入native-image插件 + +``` + + + org.graalvm.nativeimage + + native-image-maven-plugin + + 21.0.0.2 + + + + + + + + native-image + + + + package + + + + + + + + false + + demo-native-provider + + org.apache.dubbo.demo.graalvm.provider.Application + + + + --no-fallback + + --initialize-at-build-time=org.slf4j.MDC + + --initialize-at-build-time=org.slf4j.LoggerFactory + + --initialize-at-build-time=org.slf4j.impl.StaticLoggerBinder + + --initialize-at-build-time=org.apache.log4j.helpers.Loader + + --initialize-at-build-time=org.apache.log4j.Logger + + --initialize-at-build-time=org.apache.log4j.helpers.LogLog + + --initialize-at-build-time=org.apache.log4j.LogManager + + --initialize-at-build-time=org.apache.log4j.spi.LoggingEvent + + --initialize-at-build-time=org.slf4j.impl.Log4jLoggerFactory + + --initialize-at-build-time=org.slf4j.impl.Log4jLoggerAdapter + + --initialize-at-build-time=org.eclipse.collections.api.factory.Sets + + --initialize-at-run-time=io.netty.channel.epoll.Epoll + + --initialize-at-run-time=io.netty.channel.epoll.Native + + --initialize-at-run-time=io.netty.channel.epoll.EpollEventLoop + + --initialize-at-run-time=io.netty.channel.epoll.EpollEventArray + + --initialize-at-run-time=io.netty.channel.DefaultFileRegion + + --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventArray + + --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventLoop + + --initialize-at-run-time=io.netty.channel.kqueue.Native + + --initialize-at-run-time=io.netty.channel.unix.Errors + + --initialize-at-run-time=io.netty.channel.unix.IovArray + + --initialize-at-run-time=io.netty.channel.unix.Limits + + --initialize-at-run-time=io.netty.util.internal.logging.Log4JLogger + + --initialize-at-run-time=io.netty.channel.unix.Socket + + --initialize-at-run-time=io.netty.channel.ChannelHandlerMask + + + + --report-unsupported-elements-at-runtime + + --allow-incomplete-classpath + + --enable-url-protocols=http + + -H:+ReportExceptionStackTraces + + + + + + +``` + +其中定义了生成的镜像名以及一些构建镜像的参数。 + +- 挂载native-image-agent + +由于我们需要将一些反射、JNI等类先指定出来,我们需要先使用该agent以正常方式运行一遍生成这些类的json形式的信息。 + +在启动参数中添加: + +``` +-agentlib:native-image-agent=config-output-dir=/tmp/config/,config-write-period-secs=300,config-write-initial-delay-secs=5 +``` + +以正常方式启动,在项目的resources下建立文件夹META-INF.native-image,把在本地目录中生成的文件粘进去: + +![img](/imgs/blog/dubbo3.0-graalvm-support/resources.jpg) +(可能会有缺漏没有生成的类信息,需要根据编译或运行时的报错信息手动添加。) + + + +**完成以上几步后就可以进行项目的编译了。** \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/graalvm/support-graalvm.md b/content/en/overview/mannual/java-sdk/reference-manual/graalvm/support-graalvm.md new file mode 100644 index 000000000000..947998df91a5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/graalvm/support-graalvm.md @@ -0,0 +1,223 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/support-graalvm/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/support-graalvm/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/support-graalvm/ +description: "Dubbo AOT 技术详解,如何使用 GraalVM Native Image 实现 Dubbo 应用静态化。" +linkTitle: 支持 GraalVM Native Image +title: "Dubbo AOT -- 如何使用 GraalVM Native Image 实现 Dubbo 应用静态化" +type: docs +weight: 40 +--- + +在 Dubbo 3.3.0 版本中,我们正式发布了 Dubbo AOT 静态化解决方案。本文档将介绍将介绍如何借助 Dubbo AOT 技术将应用接入 GraalVM Native Image,将应用编译为 Native 二进制包的流程以及目前支持的组件。 + +{{% alert title="Dubbo GraalVM 适配文档可能更新滞后" color="warning" %}} +由于 Dubbo AOT 技术发展迅速,本文档内容可能无法总是保持及时更新,请结合以下内容了解最新内容与使用方式: +* 示例项目源码 +* 博客文章与演讲 + +关于 GraalVm 的更多信息可以阅读 https://www.graalvm.org/docs/getting-started/container-images/ 此文档。 +{{% /alert %}} + +## 使用场景 +- 本机映像编译:将应用程序预编译为本机映像,缩短启动时间并减少内存使用。 + +- 语言互操作:GraalVM 能够用多种语言编写代码,在同一应用程序中进行互操作。 + +- 优化:GraalVM 为用 Java、JavaScript 和其他语言编写的应用程序提供优化,提高 Dubbo 应用程序的性能。 + +- Polyglot 调试:GraalVM 能够在同一会话中调试用多种语言编写的代码,对复杂 Dubbo 应用程序中的问题进行故障排除时非常有用。 + +- Java 运行时:可以在 GraalVM 上运行,提供更快、更高效的 Java 运行时环境。 + +- 开发微服务:可以与 GraalVM 结合,创建高性能、低资源利用率的微服务。 + +## 使用方式 +在编译我们的dubbo项目之前,需要确保我们正基于graalVm的环境。 + +### 第一步:安装GraalVM +1. 在Graalvm官网根据自己的系统选取对应Graalvm版本:https://www.graalvm.org/downloads/ +2. 根据官方文档安装native-image:https://www.graalvm.org/latest/reference-manual/native-image/#install-native-image + +### 第二步:配置profiles + +其中包括maven-compiler-plugin、spring-boot-maven-plugin、native-maven-plugin、dubbo-maven-plugin,修改dubbo-maven-plugin中的mainClass为所需的启动类全路径。(其中API使用方式无需添加spring-boot-maven-plugin依赖。) + +```xml + + + native + + + + maven-compiler-plugin + + 17 + true + true + + + + org.springframework.boot + spring-boot-maven-plugin + + + process-aot + + process-aot + + + + + + org.graalvm.buildtools + native-maven-plugin + 0.9.25 + + ${project.build.outputDirectory} + + true + + 22.3 + + + + add-reachability-metadata + + add-reachability-metadata + + + + + + org.apache.dubbo + dubbo-maven-plugin + ${dubbo.version} + + com.example.nativedemo.NativeDemoApplication + + + + process-sources + + dubbo-process-aot + + + + + + + + +``` + + + +### 第三步:在Pom依赖中添加native相关的依赖: + +**其中API使用方式无需添加dubbo-config-spring6依赖**。 + +```xml + + org.apache.dubbo + dubbo-config-spring6 + ${dubbo.version} + + + org.apache.dubbo + dubbo-native + ${dubbo.version} + +``` + +### 第四步:配置应用 + +示例配置如下: + +```yaml +dubbo: + application: + name: ${spring.application.name} + logger: slf4j + protocol: + name: dubbo + port: -1 + serialization: fastjson2 + registry: + id: zk-registry + address: zookeeper://127.0.0.1:2181 + config-center: + address: zookeeper://127.0.0.1:2181 + metadata-report: + address: zookeeper://127.0.0.1:2181 + provider: + serialization: fastjson2 + consumer: + serialization: fastjson2 +``` + +### 第五步:编译 + +在项目根路径下执行以下编译命令: + +- API方式直接执行 + +``` + mvn clean install -P native -Dmaven.test.skip=true +``` + +- 注解和xml方式(Springboot3集成的方式) + +```shell + mvn clean install -P native native:compile -Dmaven.test.skip=true +``` + +### 第六步:执行二进制文件即可 + +二进制文件在target/目录下,一般以工程名称为二进制包的名称,比如target/native-demo + +## 支持的组件以及对应的版本 + +### 日志组件 + +| 组件名称 | 所需的插件 | 插件版本 | 备注 | +| ---------------------- | ------------------------ | ---------------------- | ------------------- | +| Apache Commons Logging | native-maven-plugin | 0.9.24 及其以上 | | +| JDK Logger | native-maven-plugin | 0.9.24 及其以上 | | +| slf4j | spring-boot-maven-plugin | 3.x.x (用最新版本即可) | | +| Log4j | native-maven-plugin | 0.10.0 及其以上 | | +| Log4j2 | | | | + +### 序列化组件 + +| 组件名称 | 所需的插件 | 插件版本 | 备注 | +| ------------ | ------------------- |-------------| ---------------------------- | +| FastJson2 | dubbo-maven-plugin | 3.3.0 及其以上 | | +| JDK | native-maven-plugin | 0.9.24 及其以上 | | +| Hessian-Lite | | | 对JDK 17支持不友好,暂不支持 | + +### 注册中心组件 + +| 组件名称 | 所需的插件 | 插件版本 | 备注 | +| --------- | ------------------ | ------------------------------- | ------------------------ | +| Zookeeper | dubbo-maven-plugin | 3.3.0 | 仅支持Zookeeper Curator5 | + +### 元数据中心组件 + +| 组件名称 | 所需的插件 | 插件版本 | 备注 | +| --------- | ------------------ | ------------------------------- | ------------------------ | +| Zookeeper | dubbo-maven-plugin | 3.3.0 | 仅支持Zookeeper Curator5 | + +### 配置中心组件 + +| 组件名称 | 所需的插件 | 插件版本 | 备注 | +| --------- | ------------------ |-------| ------------------------ | +| Zookeeper | dubbo-maven-plugin | 3.3.0 | 仅支持Zookeeper Curator5 | + +### 可观测性组件 + +| 组件名称 | 所需的插件 | 插件版本 | 备注 | +| ---------- | ---------- | -------- | ---- | +| Micrometer | | | | + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/merics/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/merics/_index.md new file mode 100644 index 000000000000..40b7c93713bc --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/merics/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/mesh/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/mesh/ +description: Dubbo Mesh 使用指南 +linkTitle: Mesh手册 +title: Mesh手册 +type: docs +weight: 98 +toc_hide: true +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/merics/meter.md b/content/en/overview/mannual/java-sdk/reference-manual/merics/meter.md new file mode 100644 index 000000000000..efe8534aa980 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/merics/meter.md @@ -0,0 +1,331 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/observability/meter/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/observability/meter/ +description: "开启 Metrics 指标埋点" +hide_summary: true +linkTitle: Metrics +no_list: true +title: Metrics +type: docs +weight: 1 +--- + + +## 概述 + +Dubbo Metrics 的总体设计请参考 [可观测性 Metrics Proposal](/zh-cn/overview/reference/proposals/metrics/)。 + +以下是 Dubbo Java 相关的具体实现与使用方式讲解。 + +## 使用方式 +要为 Dubbo 进程开启指标采集,需要在项目中引入相关依赖并增加配置。以 Spring Boot 项目为例,增加以下 spring-boot-starter 依赖到项目中,即会自动开启指标采集。 + +```xml + + + org.apache.dubbo + dubbo-spring-boot-observability-starter + 3.2.0 + +``` + +* 完整示例请参见 dubbo-samples-metrics-spring-boot +* 完整配置参数请参见 [Metrics 配置项手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties//) + +## 实现原理解析 + +### 代码结构与工作流程 +- 移除原来与 Metrics 相关的类 +- 创建新模块 dubbo-metrics/dubbo-metrics-api、dubbo-metrics/dubbo-metrics-prometheus,MetricsConfig 作为该模块的配置类 +- 使用micrometer,在Collector中使用基本类型代表指标,如Long、Double等,并在dubbo-metrics-api中引入micrometer,由micrometer对内部指标进行转换 + +以下是 Dubbo 实现中的关键组件及数据流转过程 + +![img.png](/imgs/docs3-v2/java-sdk/observability/dataflow.png) + +### 指标上报接口 +根据上图架构,指标接口是 Dubbo 对外暴露指标数据的出口,以下是指标接口的具体定义: + +> 另外,该 Service 还作为一些 [智能自适应流量调度算法](/zh-cn/overview/reference/proposals/heuristic-flow-control/) 的数据来源 + +```java +public interface MetricsService { + + /** + * Default {@link MetricsService} extension name. + */ + String DEFAULT_EXTENSION_NAME = "default"; + + /** + * The contract version of {@link MetricsService}, the future update must make sure compatible. + */ + String VERSION = "1.0.0"; + + /** + * Get metrics by prefixes + * + * @param categories categories + * @return metrics - key=MetricCategory value=MetricsEntityList + */ + Map> getMetricsByCategories(List categories); + + /** + * Get metrics by interface and prefixes + * + * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) + * @param categories categories + * @return metrics - key=MetricCategory value=MetricsEntityList + */ + Map> getMetricsByCategories(String serviceUniqueName, List categories); + + /** + * Get metrics by interface、method and prefixes + * + * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) + * @param methodName methodName + * @param parameterTypes method parameter types + * @param categories categories + * @return metrics - key=MetricCategory value=MetricsEntityList + */ + Map> getMetricsByCategories(String serviceUniqueName, String methodName, Class[] parameterTypes, List categories); +} +``` + +其中 MetricsCategory 设计如下: +```java +public enum MetricsCategory { + RT, + QPS, + REQUESTS, +} +``` + +MetricsEntity 设计如下 +```java +public class MetricsEntity { + private String name; + private Map tags; + private MetricsCategory category; + private Object value; +} +``` + +### 指标采集埋点 + +Dubbo 是通过扩展 Filter SPI 扩展点实现对请求调用指标进行拦截的,目前在消费端和提供端分别增加了 Filter 扩展实现 +* MetricsFilter 提供端请求指标埋点 +* MetricsClusterFilter 消费端请求指标埋点 + +以下是 MetricsFilter 的实现源码,注意 try-catch-finally 处理。 + +```java +@Activate(group = PROVIDER, order = -1) +public class MetricsFilter implements Filter, ScopeModelAware { + @Override + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + collector.increaseTotalRequests(interfaceName, methodName, group, version); + collector.increaseProcessingRequests(interfaceName, methodName, group, version); + Long startTime = System.currentTimeMillis(); + try { + Result invoke = invoker.invoke(invocation); + collector.increaseSucceedRequests(interfaceName, methodName, group, version); + return invoke; + } catch (RpcException e) { + collector.increaseFailedRequests(interfaceName, methodName, group, version); + throw e; + } finally { + Long endTime = System.currentTimeMillis(); + Long rt = endTime - startTime; + collector.addRT(interfaceName, methodName, group, version, rt); + collector.decreaseProcessingRequests(interfaceName, methodName, group, version); + } + } +} + +``` + +### 指标统计单位 +以下五个属性是指标统计的基本单位(应用、服务、方法的组合),也是源代码 MetricsCollector 中 Map 数据结构的 key + +```java +public class MethodMetric { + private String applicationName; + private String interfaceName; + private String methodName; + private String group; + private String version; +} +``` + +### 基础指标 + +dubbo-common 模块下的 MetricsCollector 负责存储所有指标数据 + +```java +public class DefaultMetricsCollector implements MetricsCollector { + private Boolean collectEnabled = false; + private final List listeners = new ArrayList<>(); + private final ApplicationModel applicationModel; + private final String applicationName; + + private final Map totalRequests = new ConcurrentHashMap<>(); + private final Map succeedRequests = new ConcurrentHashMap<>(); + private final Map failedRequests = new ConcurrentHashMap<>(); + private final Map processingRequests = new ConcurrentHashMap<>(); + + private final Map lastRT = new ConcurrentHashMap<>(); + private final Map minRT = new ConcurrentHashMap<>(); + private final Map maxRT = new ConcurrentHashMap<>(); + private final Map avgRT = new ConcurrentHashMap<>(); + private final Map totalRT = new ConcurrentHashMap<>(); + private final Map rtCount = new ConcurrentHashMap<>(); + } +``` + +### 本地指标聚合 + +本地聚合指将一些简单的指标通过计算获取各分位数指标的过程。 + +#### 开启本地聚合 + +收集指标时,默认只收集基础指标,而一些单机聚合指标则需要开启服务柔性或者本地聚合后另起线程计算。 + +```properties +dubbo.metrics.enable=true +``` + +另外,还可以设置一些更多的指标 + +```properties +dubbo.metrics.aggregation.enable=true +dubbo.metrics.aggregation.bucket-num=5 +dubbo.metrics.aggregation.time-window-seconds=10 +``` + +#### 具体指标 +[具体指标](/zh-cn/overview/reference/metrics/standard_metrics/) 请参考 Dubbo Metrics 总体设计文档。 + +#### 聚合收集器实现 + +```java +public class AggregateMetricsCollector implements MetricsCollector, MetricsListener { + private int bucketNum; + private int timeWindowSeconds; + + private final Map totalRequests = new ConcurrentHashMap<>(); + private final Map succeedRequests = new ConcurrentHashMap<>(); + private final Map failedRequests = new ConcurrentHashMap<>(); + private final Map qps = new ConcurrentHashMap<>(); + private final Map rt = new ConcurrentHashMap<>(); + + private final ApplicationModel applicationModel; + + private static final Integer DEFAULT_COMPRESSION = 100; + private static final Integer DEFAULT_BUCKET_NUM = 10; + private static final Integer DEFAULT_TIME_WINDOW_SECONDS = 120; + +//在构造函数中解析配置信息 + + public AggregateMetricsCollector(ApplicationModel applicationModel) { + this.applicationModel = applicationModel; + ConfigManager configManager = applicationModel.getApplicationConfigManager(); + MetricsConfig config = configManager.getMetrics().orElse(null); + if (config != null && config.getAggregation() != null && Boolean.TRUE.equals(config.getAggregation().getEnabled())) { + // only registered when aggregation is enabled. + registerListener(); + + AggregationConfig aggregation = config.getAggregation(); + this.bucketNum = aggregation.getBucketNum() == null ? DEFAULT_BUCKET_NUM : aggregation.getBucketNum(); + this.timeWindowSeconds = aggregation.getTimeWindowSeconds() == null ? DEFAULT_TIME_WINDOW_SECONDS : aggregation.getTimeWindowSeconds(); + } + } +} +``` + +如果开启了本地聚合,则通过 spring 的 BeanFactory 添加监听,将 AggregateMetricsCollector 与 DefaultMetricsCollector 绑定,实现一种生存者消费者的模式,DefaultMetricsCollector 中使用监听器列表,方便扩展 + +```java +private void registerListener() { + applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).addListener(this); +} +``` + +### 指标聚合原理 +滑动窗口 +假设我们初始有6个bucket,每个窗口时间设置为2分钟 +每次写入指标数据时,会将数据分别写入6个bucket内,每隔两分钟移动一个bucket并且清除原来bucket内的数据 +读取指标时,读取当前current指向的bucket,以达到滑动窗口的效果 +具体如下图所示,实现了当前 bucket 内存储了配置中设置的 bucket 生命周期内的数据,即近期数据 +![img_1.png](/imgs/docs3-v2/java-sdk/observability/aggre.png) + +在每个bucket内,使用**TDigest 算法**计算分位数指标 + +> **TDigest 算法**(极端分位精确度高,如p1 p99,中间分位精确度低,如p50),相关资料如下 +> +> - https://op8867555.github.io/posts/2018-04-09-tdigest.html +> - https://blog.csdn.net/csdnnews/article/details/116246540 +> - 开源实现:https://github.com/tdunning/t-digest + +代码实现如下,除了 TimeWindowQuantile 用来计算分位数指标外,另外提供了 TimeWindowCounter 来收集时间区间内的指标数量 +```java +public class TimeWindowQuantile { + private final double compression; + private final TDigest[] ringBuffer; + private int currentBucket; + private long lastRotateTimestampMillis; + private final long durationBetweenRotatesMillis; + + public TimeWindowQuantile(double compression, int bucketNum, int timeWindowSeconds) { + this.compression = compression; + this.ringBuffer = new TDigest[bucketNum]; + for (int i = 0; i < bucketNum; i++) { + this.ringBuffer[i] = TDigest.createDigest(compression); + } + + this.currentBucket = 0; + this.lastRotateTimestampMillis = System.currentTimeMillis(); + this.durationBetweenRotatesMillis = TimeUnit.SECONDS.toMillis(timeWindowSeconds) / bucketNum; + } + + public synchronized double quantile(double q) { + TDigest currentBucket = rotate(); + return currentBucket.quantile(q); + } + + public synchronized void add(double value) { + rotate(); + for (TDigest bucket : ringBuffer) { + bucket.add(value); + } + } + + private TDigest rotate() { + long timeSinceLastRotateMillis = System.currentTimeMillis() - lastRotateTimestampMillis; + while (timeSinceLastRotateMillis > durationBetweenRotatesMillis) { + ringBuffer[currentBucket] = TDigest.createDigest(compression); + if (++currentBucket >= ringBuffer.length) { + currentBucket = 0; + } + timeSinceLastRotateMillis -= durationBetweenRotatesMillis; + lastRotateTimestampMillis += durationBetweenRotatesMillis; + } + return ringBuffer[currentBucket]; + } +} +``` + +### 指标推送 + +指标推送只有用户在设置了 `dubbo.metrics.protocol=prometheus` 参数后才开启,若只开启指标聚合,则默认不推送指标。 + +#### Prometheus Pull Service Discovery + +目前 Dubbo Admin 内置了 prometheus http_sd service discovery 实例地址发现机制,Admin 默认会使用 `qos 端口`、 `/metrics` 作为这样 Admin 就能够将所有示例地址汇聚后以标准 http_sd 的方式同步给 Prometheus Server。 + +具体配置方式如下 + + +其中,address、port、url 均是可选项,如不配置则 Admin 使用默认约定值。 + +> 用户直接在Dubbo配置文件中配置Prometheus Pushgateway的地址即可,如,其中interval代表推送间隔 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/mesh/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/mesh/_index.md new file mode 100644 index 000000000000..40b7c93713bc --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/mesh/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/mesh/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/mesh/ +description: Dubbo Mesh 使用指南 +linkTitle: Mesh手册 +title: Mesh手册 +type: docs +weight: 98 +toc_hide: true +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/mesh/mesh.md b/content/en/overview/mannual/java-sdk/reference-manual/mesh/mesh.md new file mode 100644 index 000000000000..99075a8ca4ae --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/mesh/mesh.md @@ -0,0 +1,165 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/mesh/mesh/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/mesh/mesh/ +description: 描述如何对Dubbo mesh proxyless模式进行debug。 +linkTitle: Debug参考文档 +title: Debug参考文档 +type: docs +weight: 2 +--- + + + + + + +## 前置环境准备 + +* docker环境 +* kubernetes环境(推荐docker desktop,图形化界面,还内嵌了一个小型的Kubernetes环境,后文演示也是基于docker desktop) +* istio环境 +* dubbo-samples代码,master分支即可 +* dubbo 版本 >= 3.1.0 +搭建 Kubernetes 环境 +目前 Dubbo 仅支持在 Kubernetes 环境下的 Mesh 部署,所以在运行启动本示例前需要先搭Kubernetes 环境。(建议采用docker desktop进行搭建,直接就可以运行一个kubernetes环境) +https://docs.docker.com/desktop/install/mac-install/ + +## 搭建 Kubernetes 环境 + +目前 Dubbo 仅支持在 Kubernetes 环境下的 Mesh 部署,所以在运行启动本示例前需要先搭Kubernetes 环境。(建议采用docker desktop进行搭建,直接就可以运行一个kubernetes环境) +https://docs.docker.com/desktop/install/mac-install/ + +## 搭建 Istio 环境 + +搭建 Istio 环境参考文档: +Istio 安装文档(https://istio.io/latest/docs/setup/getting-started/) +注:安装 Istio 的时候需要开启 first-party-jwt 支持(使用 istioctl 工具安装的时候加上 --set values.global.jwtPolicy=first-party-jwt 参数),否则将导致客户端认证失败的问题。 +附安装命令参考: + +```java +curl -L https://istio.io/downloadIstio | sh - +cd istio-1.xx.x +export PATH=$PWD/bin:$PATH +istioctl install --set profile=demo --set values.global.jwtPolicy=first-party-jwt -y +``` + +## 构建dubbo和dubbo-samples环境 + +进入dubbo-dependencies-bom,更改grpc版本为1.41.0 + +```java +1.41.0 +``` + +进入dubbo-samples-xds目录,新增配置: + +```java +dubbo.application.metadataServiceProtocol=dubbo +``` + +打包dubbo代码,切换到dubbo根目录,执行以下命令进行打包: + +```java +mvn clean package -DskipTests +``` + +切换到dubbo-samples代码,在dubbo-samples-xds的pom文件中引入刚打包好的dubbo代码。 +接下来修改debug模式,以dubbo-xds-consumer为例: +更改dubbo-samples-consumer的docker file并更改调试模式为suspend=y, 更改后的docker file文件如下: + +```java +FROM openjdk:8-jdk +ADD ./target/dubbo-samples-xds-consumer-1.0-SNAPSHOT.jar dubbo-samples-xds-consumer-1.0-SNAPSHOT.jar +EXPOSE 31000 +CMD java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=31000 /dubbo-samples-xds-consumer-1.0-SNAPSHOT.jar +``` + +随后执行以下命令进行打包: + +```java +cd dubbo-samples/dubbo-samples-xds +mvn clean package -DskipTests +``` + +## 构建docker镜像 + +```java +cd ./dubbo-samples-xds-provider/ +# dubbo-samples-xds/dubbo-samples-xds-provider/Dockerfile +docker build -t apache/dubbo-demo:dubbo-samples-xds-provider_0.0.1 . +cd ../dubbo-samples-xds-consumer/ +# dubbo-samples-xds/dubbo-samples-xds-consumer/Dockerfile +docker build -t apache/dubbo-demo:dubbo-samples-xds-consumer_0.0.1 . +cd ../ +``` + +## 创建K8s namespace + +```java +# 初始化命名空间 +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-xds/deploy/Namespace.yml + +# 切换命名空间 +kubens dubbo-demo +``` + +如果kubens切换不成功,安装下kubectl即可 +## 部署容器 + +```java +cd ./dubbo-samples-xds-provider/src/main/resources/k8s +# dubbo-samples-xds/dubbo-samples-xds-provider/src/main/resources/k8s/Deployment.yml +# dubbo-samples-xds/dubbo-samples-xds-provider/src/main/resources/k8s/Service.yml +kubectl apply -f Deployment.yml +kubectl apply -f Service.yml +cd ../../../../../dubbo-samples-xds-consumer/src/main/resources/k8s +# dubbo-samples-xds/dubbo-samples-xds-consumer/src/main/resources/k8s/Deployment.yml +kubectl apply -f Deployment.yml +cd ../../../../../ +``` + +成功执行上述命令后的docker desktop containers页面长这样,其中dubbo-samples一共出现数个containers,包含consumer和provider: + +![docker-desktop.png](/imgs/user/docker-desktop.png) + + + +查看k8s_server_dubbo-samples-xds-provider-XXX日志,出现如下日志: + +```java +Dec 28, 2022 8:42:48 AM org.apache.dubbo.config.deploy.DefaultApplicationDeployer info +INFO: [DUBBO] Dubbo Application[1.1](dubbo-samples-xds-provider) is ready., dubbo version: 1.0-SNAPSHOT, current host: 10.1.5.64 +Dec 28, 2022 8:42:49 AM org.apache.dubbo.registry.xds.util.protocol.AbstractProtocol info +INFO: [DUBBO] receive notification from xds server, type: type.googleapis.com/envoy.config.listener.v3.Listener, dubbo version: 1.0-SNAPSHOT, current host: 10.1.5.64 +Dec 28, 2022 8:42:53 AM org.apache.dubbo.registry.xds.util.protocol.AbstractProtocol info +INFO: [DUBBO] receive notification from xds server, type: type.googleapis.com/envoy.config.listener.v3.Listener, dubbo version: 1.0-SNAPSHOT, current host: 10.1.5.64 +dubbo service started +``` + +![xds-provider-log.png](/imgs/user/xds-provider-log.png) + +查看k8s_server_dubbo-samples-xds-consumer-XXX日志,发现其正等待debug连接: +![xds-consumer-listener.png](/imgs/user/xds-consumer-listener.png) +打开命令终端,输入命令查看可用并处于Running状态的pods: + +```java +kubectl get pods +``` +![k8s-pods.png](/imgs/user/k8s-pods.png) + +输入以下命令将pods的端口映射到本地: + +```java +kubectl port-forward dubbo-samples-xds-consumer-64c6c6f444-kk2vr 31000:31000 +``` + +![port-forward.png](/imgs/user/port-forward.png) + +切换到idea,edit configuration,debugger mode选择attach to remote JVM,port选择上面docker file expose的端口,module classpath选择dubbo-samples-xds-consumer,并点击debug,即可成功连接 +![remote-debug.png](/imgs/user/remote-debug.png) + +可以看到断点已经成功进来了: +![xds-debug-success.png](/imgs/user/xds-debug-success.png) +此时查看k8s_server_dubbo-samples-xds-consumer-XXX的日志可以看到已经成功在运行: +![xds-consumer-debug-success-log.png](/imgs/user/xds-consumer-debug-success-log.png) \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/_index.md new file mode 100644 index 000000000000..81b2a134a551 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/metadata-center/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/metadata-center/ + - /zh-cn/overview/what/ecosystem/metadata-center/ +description: Dubbo 元数据中心基本使用与工作原理 +linkTitle: 元数据中心 +title: 元数据中心 +type: docs +weight: 7 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/nacos.md b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/nacos.md new file mode 100644 index 000000000000..04a6817adb63 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/nacos.md @@ -0,0 +1,118 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/metadata-center/nacos/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/metadata-center/nacos/ + - /zh-cn/overview/what/ecosystem/metadata-center/nacos/ +description: Nacos 元数据中心基本使用与工作原理 +linkTitle: Nacos +title: Nacos +type: docs +weight: 2 +--- + +## 1 预备工作 +- 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/spring-boot/) +- 参考 [Nacos](/zh-cn/overview/reference/integrations/nacos/) 启动 Nacos server + +> 当Dubbo使用`3.0.0`及以上版本时,需要使用Nacos `2.0.0`及以上版本 + +## 2 使用说明 +Dubbo 融合 Nacos 成为元数据中心的操作步骤非常简单,大致分为 `增加 Maven 依赖` 以及 `配置元数据中心` 两步。 +> 如果元数据地址(dubbo.metadata-report.address)也不进行配置,会使用注册中心的地址来用作元数据中心。 + +### 2.1 增加 Maven 依赖 +如果项目已经启用 Nacos 作为注册中心,则无需增加任何额外配置。 + +如果未启用 Nacos 注册中心,则请参考 [为注册中心增加 Nacos 依赖](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/nacos/#12-nacos-版本)。 + +### 2.2 启用 Nacos 配置中心 +```xml + +``` + +或者 + +```yaml +dubbo + metadata-report + address: nacos://127.0.0.1:8848 +``` + +或者 + +```properties +dubbo.metadata-report.address=nacos://127.0.0.1:8848 +``` + +或者 + +```java +MetadataReportConfig metadataConfig = new MetadataReportConfig(); +metadataConfig.setAddress("nacos://127.0.0.1:8848"); +``` + +`address` 格式请参考 [Nacos 注册中心 - 启用配置](../../registry/nacos/#22-配置并启用-nacos) + +## 3 高级配置 + +完整配置参数请参考 [metadata-report-config](../../config/properties/#metadata-report-config)。 + +## 4 工作原理 + +### 4.1 [服务运维元数据](../overview/#2-服务运维元数据) + +在 Nacos 的控制台上可看到服务提供者、消费者注册的服务运维相关的元数据信息: + +![image-dubbo-metadata-nacos-1.png](/imgs/blog/dubbo-metadata-nacos-1.png) + +在 Nacos 中,本身就存在配置中心这个概念,正好用于元数据存储。在配置中心的场景下,存在命名空间- namespace 的概念,在 namespace 之下,还存在 group 概念。即通过 namespace 和 group 以及 dataId 去定位一个配置项,在不指定 namespace 的情况下,默认使用 ```public``` 作为默认的命名空间。 + +```properties +Provider: namespace: 'public', dataId: '{service name}:{version}:{group}:provider:{application name}', group: 'dubbo' +Consumer: namespace: 'public', dataId: '{service name}:{version}:{group}:consumer:{application name}', group: 'dubbo' +``` +当 version 或者 group 不存在时`:` 依然保留: +```properties +Provider: namespace: 'public', dataId: '{service name}:::provider:{application name}', group: 'dubbo' +Consumer: namespace: 'public', dataId: '{service name}:::consumer:{application name}', group: 'dubbo' +``` + +Providers接口元数据详情 (通过 `report-definition=true` 控制此部分数据是否需要上报): + +![image-dubbo-metadata-nacos-3.png](/imgs/blog/dubbo-metadata-nacos-3.png) + +Consumers接口元信息详情(通过 `report-consumer-definition=true` 控制是否上报,默认 false): + +![image-dubbo-metadata-nacos-4.png](/imgs/blog/dubbo-metadata-nacos-4.png) + +### 4.2 [地址发现 - 接口-应用映射](../overview//#11-接口---应用映射关系) +在上面提到,service name 和 application name 可能是一对多的,在 nacos 中,使用单个 key-value 进行保存,多个 application name 通过英文逗号`,`隔开。由于是单个 key-value 去保存数据,在多客户端的情况下可能会存在并发覆盖的问题。因此,我们使用 nacos 中 publishConfigCas 的能力去解决该问题。在 nacos 中,使用 publishConfigCas 会让用户传递一个参数 casMd5,该值的含义是之前配置内容的 md5 值。不同客户端在更新之前,先去查一次 nacos 的 content 的值,计算出 md5 值,当作本地凭证。在更新时,把凭证 md5 传到服务端比对 md5 值, 如果不一致说明在此期间被其他客户端修改过,重新获取凭证再进行重试(CAS)。目前如果重试6次都失败的话,放弃本次更新映射行为。 + +Nacos api: +```java +ConfigService configService = ... +configService.publishConfigCas(key, group, content, ticket); +``` + +映射信息位于 namespace: 'public', dataId: '{service name}', group: 'mapping'. + +![nacos-metadata-report-service-name-mapping.png](/imgs/user/nacos-metadata-report-service-name-mapping.png) + +### 4.3 [地址发现 - 接口配置元数据](../overview/#12-接口配置元数据) + +要开启远程接口配置元数据注册,需在应用中增加以下配置,因为默认情况下 Dubbo3 应用级服务发现会启用服务自省模式,并不会注册数据到元数据中心。 + +```properties + dubbo.application.metadata-type=remote + ``` + +或者,在自省模式下仍开启中心化元数据注册 + +```properties +dubbo.application.metadata-type=local +dubbo.metadata-report.report-metadata=true +``` + +Nacos server 中的元数据信息详情如下: + +![image-dubbo-metadata-nacos-2.png](/imgs/blog/dubbo-metadata-nacos-2.png) \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/others.md b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/others.md new file mode 100644 index 000000000000..b3fe43c42530 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/others.md @@ -0,0 +1,84 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/metadata-center/redis/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/metadata-center/redis/ + - /zh-cn/overview/what/ecosystem/metadata-center/redis/ +description: "更多元数据中心扩展实现,包括 redis、etcd、consul 等" +linkTitle: 扩展实现 +title: 更多元数据中心扩展实现 +type: docs +weight: 4 +--- + +Dubbo 框架还默认提供了 redis、etcd、consul 等元数据中心适配实现 + +## Redis + +Redis 实现由主干库提供内置实现,但需要增加以下依赖: + +```xml + + + redis.clients + jedis + 3.10.0 + + +``` + +```yaml +dubbo + metadata-report + address: redis://127.0.0.1:1111 +``` + +或者 + +```properties +dubbo.metadata-report.address=redis://127.0.0.1:1111 +``` + +## Etcd + +Etcd 元数据中心由社区生态库维护,具体可参见 [](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-metadata-report-extensions/dubbo-metadata-report-etcd)。 + +增加依赖: + +```xml + + org.apache.dubbo.extensions + dubbo-metadata-report-etcd + 3.3.0 + +``` + +调整配置: + +```yaml +dubbo + metadata-report + address: etcd://127.0.0.1:1111 +``` + + +## Consul + +Consul 元数据中心由社区生态库维护,具体可参见 [](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-metadata-report-extensions/dubbo-metadata-report-consul)。 + +增加依赖: + +```xml + + org.apache.dubbo.extensions + dubbo-metadata-report-consul + 3.3.0 + +``` + +调整配置: + +```yaml +dubbo + metadata-report + address: consul://127.0.0.1:1111 +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/overview.md b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/overview.md new file mode 100644 index 000000000000..daf98308059c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/overview.md @@ -0,0 +1,217 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/metadata-center/overview/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/metadata-center/overview/ +description: 元数据中心概述 +linkTitle: 元数据中心概述 +title: 元数据中心概述 +type: docs +weight: 1 +--- + + +元数据中心为 Dubbo 中的两类元数据提供了存取能力 +- 1 地址发现元数据,用于应用级服务发现 +- 2 服务运维元数据,用于外围运维系统如可视化控制台进行服务查询、测试等。 + +## 1 地址发现元数据 +Dubbo3 中引入了 [应用级服务发现机制](/zh-cn/overview/core-features/service-discovery/#面向百万实例集群的服务发现机制) 用来解决异构微服务体系互通与大规模集群实践的性能问题,应用级服务发现将全面取代 2.x 时代的接口级服务发现。 +同时为了保持 Dubbo 面向服务/接口的易用性、服务治理的灵活性,Dubbo 围绕应用级服务发现构建了一套元数据机制,即 `接口 - 应用映射关系` 与 `接口配置元数据`。 + +### 1.1 接口 - 应用映射关系 +Dubbo 一直以来都能做到精确的地址发现,即只订阅 Consumer 声明要关心的服务及相关的地址列表,相比于拉取/订阅全量地址列表,这样做有很好的性能优势。 +在应用级服务发现模型中,想做到精确地址订阅并不容易,因为 Dubbo Consumer 只声明了要消费的接口列表,Consumer 需要能够将接口转换为 Provider 应用名才能进行精准服务订阅, + +为此,Dubbo 需要在元数据中心维护这一份 `接口名->应用名` 的对应关系,Dubbo3 中通过 provider 启动的时候主动向元数据中心上报实现。 +接口 (service name) - 应用 (Provider application name) 的映射关系可以是一对多的,即一个 service name 可能会对应多个不同的 application name。 + +以 zookeeper 为例,映射关系保存在以下位置: + +```shell +$ ./zkCli.sh +$ get /dubbo/mapping/org.apache.dubbo.demo.DemoService +$ demo-provider,two-demo-provider,dubbo-demo-annotation-provider +``` + +*① 节点路径是 `/dubbo/mapping/{interface name}`* + +*② 多个应用名通过英文逗号 `,` 隔开* + +### 1.2 接口配置元数据 + +`接口级配置元数据`是作为地址发现的补充,相比于 Spring Cloud 等地址发现模型只能同步 ip、port 信息,Dubbo 的服务发现机制可以同步接口列表、接口定义、接口级参数配置等信息。 +这部分内容根据当前应用的自身信息、以及接口信息计算而来,并且从性能角度出发,还根据元数据生成 revision,以实现不同机器实例间的元数据聚合。 + +> 可通过设置 `dubbo.metadata-report.report-metadata=false` 关闭元数据上报。 + +以 Zookeeper 为例,接口配置元数据保存在以下位置,如果多个实例生成的 revision 相同,则最终会共享同一份元数据配置: + +`/dubbo/metadata/{application name}/{revision}` + +```shell script +[zk: localhost:2181(CONNECTED) 33] get /dubbo/metadata/demo-provider/da3be833baa2088c5f6776fb7ab1a436 +``` + +```json +{ + "app":"demo-provider", + "revision":"da3be833baa2088c5f6776fb7ab1a436", + "services":{ + "org.apache.dubbo.demo.DemoService:dubbo":{ + "name":"org.apache.dubbo.demo.DemoService", + "protocol":"dubbo", + "path":"org.apache.dubbo.demo.DemoService", + "params":{ + "side":"provider", + "release":"", + "methods":"sayHello,sayHelloAsync", + "deprecated":"false", + "dubbo":"2.0.2", + "pid":"38298", + "interface":"org.apache.dubbo.demo.DemoService", + "service-name-mapping":"true", + "timeout":"3000", + "generic":"false", + "metadata-type":"remote", + "delay":"5000", + "application":"demo-provider", + "dynamic":"true", + "REGISTRY_CLUSTER":"registry1", + "anyhost":"true", + "timestamp":"1626887121829" + } + }, + "org.apache.dubbo.demo.RestDemoService:1.0.0:rest":{ + "name":"org.apache.dubbo.demo.RestDemoService", + "version":"1.0.0", + "protocol":"rest", + "path":"org.apache.dubbo.demo.RestDemoService", + "params":{ + "side":"provider", + "release":"", + "methods":"getRemoteApplicationName,sayHello,hello,error", + "deprecated":"false", + "dubbo":"2.0.2", + "pid":"38298", + "interface":"org.apache.dubbo.demo.RestDemoService", + "service-name-mapping":"true", + "version":"1.0.0", + "timeout":"5000", + "generic":"false", + "revision":"1.0.0", + "metadata-type":"remote", + "delay":"5000", + "application":"demo-provider", + "dynamic":"true", + "REGISTRY_CLUSTER":"registry1", + "anyhost":"true", + "timestamp":"1626887120943" + } + } + } +} +``` + +## 2 服务运维元数据 + +Dubbo 上报的服务运维元数据通常为各种运维系统所用,如服务测试、网关数据映射、服务静态依赖关系分析等。 + +各种第三方系统可直接读取并使用这部分数据,具体对接方式可参见本章提及的几个第三方系统。 + +> 可通过设置 `dubbo.metadata-report.report-definition=false` 关闭元数据上报。 + +### 2.1 Provider 上报的元数据 +provider端存储的元数据内容如下: + +```json +{ + "parameters": { + "side": "provider", + "methods": "sayHello", + "dubbo": "2.0.2", + "threads": "100", + "interface": "org.apache.dubbo.samples.metadatareport.configcenter.api.AnnotationService", + "threadpool": "fixed", + "version": "1.1.1", + "generic": "false", + "revision": "1.1.1", + "valid": "true", + "application": "metadatareport-configcenter-provider", + "default.timeout": "5000", + "group": "d-test", + "anyhost": "true" + }, + "canonicalName": "org.apache.dubbo.samples.metadatareport.configcenter.api.AnnotationService", + "codeSource": "file:/Users/cvictory/workspace/work-mw/dubbo-samples/dubbo-samples-metadata-report/dubbo-samples-metadata-report-configcenter/target/classes/", + "methods": [{ + "name": "sayHello", + "parameterTypes": ["java.lang.String"], + "returnType": "java.lang.String" + }], + "types": [{ + "type": "java.lang.String", + "properties": { + "value": { + "type": "char[]" + }, + "hash": { + "type": "int" + } + } + }, { + "type": "int" + }, { + "type": "char" + }] +} +``` + +*① `parameters` 为服务配置与参数详情。* + +*② `types` 为服务定义信息。* + +##### Consumer 上报的元数据: + +```json +{ + "valid": "true", + "side": "consumer", + "application": "metadatareport-configcenter-consumer", + "methods": "sayHello", + "default.timeout": "6666", + "dubbo": "2.0.2", + "interface": "org.apache.dubbo.samples.metadatareport.configcenter.api.AnnotationService", + "version": "1.1.1", + "revision": "1.1.1", + "group": "d-test" +} +``` + +*Consumer 进程订阅时使用的配置元数据。* + +## 3 元数据上报工作机制 + +元数据上报默认是一个异步的过程,为了更好的控制异步行为,元数据配置组件 (metadata-report) 开放了两个配置项: +* 失败重试 +* 每天定时重试刷新 + +### 3.1 retrytimes 失败重试 +失败重试可以通过 retrytimes (重试次数。默认 100),retryperiod(重试周期。默认 3000ms)进行设置。 + +### 3.2 定时刷新 +默认开启,可以通过设置 cycleReport=false 进行关闭。 + +### 3.3 完整的配置项 + +```properties +dubbo.metadata-report.address=zookeeper://127.0.0.1:2181 +dubbo.metadata-report.username=xxx ##非必须 +dubbo.metadata-report.password=xxx ##非必须 +dubbo.metadata-report.retry-times=30 ##非必须,default值100 +dubbo.metadata-report.retry-period=5000 ##非必须,default值3000 +dubbo.metadata-report.cycle-report=false ##非必须,default值true +dubbo.metadata-report.sync.report=false ##非必须,default值为false +``` +> 如果元数据地址(dubbo.metadata-report.address)也不进行配置,会判断注册中心的协议是否支持元数据中心,如果支持,会使用注册中心的地址来用作元数据中心。 + +请参见 [metadata-report](../../spi/description/metadata-report/) 了解如何扩展自定义第三方实现。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/zookeeper.md b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/zookeeper.md new file mode 100644 index 000000000000..d169b3e15840 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/zookeeper.md @@ -0,0 +1,178 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/metadata-center/zookeeper/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/metadata-center/zookeeper/ + - /zh-cn/overview/what/ecosystem/metadata-center/zookeeper/ +description: Zookeeper 元数据中心基本使用与工作原理 +linkTitle: Zookeeper +title: Zookeeper +type: docs +weight: 3 +--- + + +## 1 预备工作 +- 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/spring-boot/) +- 安装并启动 [Zookeeper](/zh-cn/overview/reference/integrations/zookeeper/) + +## 2 使用说明 + +### 2.1 增加 Maven 依赖 +如果项目已经启用 Zookeeper 作为注册中心,则无需增加任何额外配置。 + +如果未使用 Zookeeper 注册中心,则请参考 [为注册中心增加 Zookeeper 相关依赖](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/zookeeper/#11-增加-maven-依赖)。 + +### 2.2 启用 Zookeeper 配置中心 +```xml + +``` + +或者 + +```yaml +dubbo + metadata-report + address: zookeeper://127.0.0.1:2181 +``` + +或者 + +```properties +dubbo.metadata-report.address=zookeeper://127.0.0.1:2181 +``` + +或者 + +```java +MetadataReportConfig metadataConfig = new MetadataReportConfig(); +metadataConfig.setAddress("zookeeper://127.0.0.1:2181"); +``` + +`address` 格式请参考 [zookeeper 注册中心 - 启用配置](../../registry/zookeeper/#22-配置并启用-zookeeper) + +## 3 高级配置 + +完整配置参数请参考 [metadata-report-config](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#dubbometadata-report)。 + +## 4 工作原理 + +### 4.1 [服务运维元数据](../overview/#2-服务运维元数据) + +Zookeeper 基于树形结构进行数据存储,它的元数据信息位于以下节点: +```text +Provider: /dubbo/metadata/{interface name}/{version}/{group}/provider/{application name} +Consumer: /dubbo/metadata/{interface name}/{version}/{group}/consumer/{application name} +``` + +当 version 或者 group 不存在时,version 路径和 group 路径会取消,路径如下: +```text +Provider: /dubbo/metadata/{interface name}/provider/{application name} +Consumer: /dubbo/metadata/{interface name}/consumer/{application name} +``` + +通过 zkCli get 操作查看数据. + +Provider node: +```shell script +[zk: localhost:2181(CONNECTED) 8] get /dubbo/metadata/org.apache.dubbo.demo.DemoService/provider/demo-provider +{"parameters":{"side":"provider","interface":"org.apache.dubbo.demo.DemoService","metadata-type":"remote","application":"demo-provider","dubbo":"2.0.2","release":"","anyhost":"true","delay":"5000","methods":"sayHello,sayHelloAsync","deprecated":"false","dynamic":"true","timeout":"3000","generic":"false"},"canonicalName":"org.apache.dubbo.demo.DemoService","codeSource":"file:/Users/apple/IdeaProjects/dubbo/dubbo-demo/dubbo-demo-interface/target/classes/","methods":[{"name":"sayHelloAsync","parameterTypes":["java.lang.String"],"returnType":"java.util.concurrent.CompletableFuture"},{"name":"sayHello","parameterTypes":["java.lang.String"],"returnType":"java.lang.String"}],"types":[{"type":"java.util.concurrent.CompletableFuture","properties":{"result":"java.lang.Object","stack":"java.util.concurrent.CompletableFuture.Completion"}},{"type":"java.lang.Object"},{"type":"java.lang.String"},{"type":"java.util.concurrent.CompletableFuture.Completion","properties":{"next":"java.util.concurrent.CompletableFuture.Completion","status":"int"}},{"type":"int"}]} +cZxid = 0x25a9b1 +ctime = Mon Jun 28 21:35:17 CST 2021 +mZxid = 0x25a9b1 +mtime = Mon Jun 28 21:35:17 CST 2021 +pZxid = 0x25a9b1 +cversion = 0 +dataVersion = 0 +aclVersion = 0 +ephemeralOwner = 0x0 +dataLength = 1061 +numChildren = 0 +``` + +Consumer node: +```shell script +[zk: localhost:2181(CONNECTED) 10] get /dubbo/metadata/org.apache.dubbo.demo.DemoService/consumer/demo-consumer +{"side":"consumer","interface":"org.apache.dubbo.demo.DemoService","metadata-type":"remote","application":"demo-consumer","dubbo":"2.0.2","release":"","sticky":"false","check":"false","methods":"sayHello,sayHelloAsync"} +cZxid = 0x25aa24 +ctime = Mon Jun 28 21:57:43 CST 2021 +mZxid = 0x25aa24 +mtime = Mon Jun 28 21:57:43 CST 2021 +pZxid = 0x25aa24 +cversion = 0 +dataVersion = 0 +aclVersion = 0 +ephemeralOwner = 0x0 +dataLength = 219 +numChildren = 0 +``` + +### 4.2 [地址发现 - 接口-应用名映射](../overview/#11-接口---应用映射关系) +在Dubbo 3.0 中,默认使用了服务自省机制去实现服务发现,关于服务自省可以查看[服务自省](https://mercyblitz.github.io/2020/05/11/Apache-Dubbo-%E6%9C%8D%E5%8A%A1%E8%87%AA%E7%9C%81%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/) + +简而言之,服务自省机制需要能够通过 interface name 去找到对应的 application name,这个关系可以是一对多的,即一个 service name 可能会对应多个不同的 application name。在 3.0 中,元数据中心提供此项映射的能力。 + + +##### Zookeeper +在上面提到,service name 和 application name 可能是一对多的,在 zookeeper 中,使用单个 key-value 进行保存,多个 application name 通过英文逗号`,`隔开。由于是单个 key-value 去保存数据,在多客户端的情况下可能会存在并发覆盖的问题。因此,我们使用 zookeeper 中的版本机制 version 去解决该问题。在 zookeeper 中,每一次对数据进行修改,dataVersion 都会进行增加,我们可以利用 version 这个机制去解决多个客户端同时更新映射的并发问题。不同客户端在更新之前,先去查一次 version,当作本地凭证。在更新时,把凭证 version 传到服务端比对 version, 如果不一致说明在此期间被其他客户端修改过,重新获取凭证再进行重试(CAS)。目前如果重试6次都失败的话,放弃本次更新映射行为。 + +Curator api. +```java +CuratorFramework client = ... +client.setData().withVersion(ticket).forPath(path, dataBytes); +``` + +映射信息位于: +```text +/dubbo/mapping/{service name} +``` + +通过 zkCli get 操作查看数据. + +```shell script +[zk: localhost:2181(CONNECTED) 26] get /dubbo/mapping/org.apache.dubbo.demo.DemoService +demo-provider,two-demo-provider,dubbo-demo-annotation-provider +cZxid = 0x25a80f +ctime = Thu Jun 10 01:36:40 CST 2021 +mZxid = 0x25a918 +mtime = Fri Jun 11 18:46:40 CST 2021 +pZxid = 0x25a80f +cversion = 0 +dataVersion = 2 +aclVersion = 0 +ephemeralOwner = 0x0 +dataLength = 62 +numChildren = 0 +``` + +### 4.3 [地址发现 - 接口配置元数据](../overview/#12-接口配置元数据) + +要开启远程接口配置元数据注册,需在应用中增加以下配置,因为默认情况下 Dubbo3 应用级服务发现会启用服务自省模式,并不会注册数据到元数据中心。 + +```properties + dubbo.application.metadata-type=remote + ``` + +或者,在自省模式下仍开启中心化元数据注册 + +```properties +dubbo.application.metadata-type=local +dubbo.metadata-report.report-metadata=true +``` + +Zookeeper 的应用级别元数据位于 /dubbo/metadata/{application name}/{revision} + +```shell script +[zk: localhost:2181(CONNECTED) 33] get /dubbo/metadata/demo-provider/da3be833baa2088c5f6776fb7ab1a436 +{"app":"demo-provider","revision":"da3be833baa2088c5f6776fb7ab1a436","services":{"org.apache.dubbo.demo.DemoService:dubbo":{"name":"org.apache.dubbo.demo.DemoService","protocol":"dubbo","path":"org.apache.dubbo.demo.DemoService","params":{"side":"provider","release":"","methods":"sayHello,sayHelloAsync","deprecated":"false","dubbo":"2.0.2","pid":"38298","interface":"org.apache.dubbo.demo.DemoService","service-name-mapping":"true","timeout":"3000","generic":"false","metadata-type":"remote","delay":"5000","application":"demo-provider","dynamic":"true","REGISTRY_CLUSTER":"registry1","anyhost":"true","timestamp":"1626887121829"}},"org.apache.dubbo.demo.RestDemoService:1.0.0:rest":{"name":"org.apache.dubbo.demo.RestDemoService","version":"1.0.0","protocol":"rest","path":"org.apache.dubbo.demo.RestDemoService","params":{"side":"provider","release":"","methods":"getRemoteApplicationName,sayHello,hello,error","deprecated":"false","dubbo":"2.0.2","pid":"38298","interface":"org.apache.dubbo.demo.RestDemoService","service-name-mapping":"true","version":"1.0.0","timeout":"5000","generic":"false","revision":"1.0.0","metadata-type":"remote","delay":"5000","application":"demo-provider","dynamic":"true","REGISTRY_CLUSTER":"registry1","anyhost":"true","timestamp":"1626887120943"}}}} +cZxid = 0x25b336 +ctime = Thu Jul 22 01:05:55 CST 2021 +mZxid = 0x25b336 +mtime = Thu Jul 22 01:05:55 CST 2021 +pZxid = 0x25b336 +cversion = 0 +dataVersion = 0 +aclVersion = 0 +ephemeralOwner = 0x0 +dataLength = 1286 +numChildren = 0 +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/performance/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/performance/_index.md new file mode 100755 index 000000000000..3796c3466da1 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/performance/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/performance/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/performance/ +description: Dubbo 基准测试性能参考指南 +linkTitle: 性能Benchmark +title: 性能参考手册 +type: docs +weight: 8 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/performance/benchmarking.md b/content/en/overview/mannual/java-sdk/reference-manual/performance/benchmarking.md new file mode 100644 index 000000000000..1c2e5a6a23b9 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/performance/benchmarking.md @@ -0,0 +1,50 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/performance/benchmarking/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/performance/benchmarking/ +description: "" +linkTitle: 应用级服务发现基准 +title: 应用级服务发现基准测试 +type: docs +weight: 1 +--- + +## 1 Benchmark 结论 + +对比 2.x 版本,Dubbo3 版本 + +- 服务发现资源利用率显著提升。 + - 对比接口级服务发现,单机常驻内存下降 50%,地址变更期 GC 消耗下降一个数量级 (百次 -> 十次) + - 对比应用级服务发现,单机常驻内存下降 75%,GC 次数趋零 + + +以下是详细压测过程与数据 + +## 2 应用级服务发现(地址推送链路) + +此部分压测数据是由工商银行 Dubbo 团队基于内部生产数据给出,压测过程模拟了“生产环境地址+zookeeper”的服务发现架构。 + +### 2.1 环境 + +| | 描述 | +| ------------ | ------------------------------------------------------------ | +| **压测数据** | 提供者
500运行实例✖️8interface✖️5protocol,即每个提供者向注册中心注册40个URL,总计20000个URL,每个URL字符长度约1k。

注册中心
2个独立zookeeper注册中心,服务提供者消费者采用并行配置。

消费者
配置1c2g,xmx=768,开启GC,从2个注册中心订阅,每5秒调用一次服务。运行20小时。 | +| **压测环境** | Java version "1.8.0"
Java(TM) SE Runtime Enviroment (build pxa6480sr3fp12-20160919_01(SR3 FP12))
IBM J9 VM (Build 2.8, JRE 1.8.0 Linux amd64-64 Compressed References 20160915_318796, JIT enabled, AOT enabled) | + + +### 2.2 数据分析 + +![//imgs/v3/performance/registry-mem.svg](/imgs/v3/performance/registry-mem.svg) + +
图一 服务发现模型内存占用变化

+ +- Dubbo3 接口级服务发现模型,常驻内存较 2.x 版本下降约 50% +- Dubbo3 应用级服务发现模型,常驻内存较 2.x 版本下降约 75% + + +![//imgs/v3/performance/registry-gc.svg](/imgs/v3/performance/registry-gc.svg) + +
图二 服务发现模型 GC 变化

+ +- Dubbo3 接口级服务发现模型,YGC 次数 2.x 版本大幅下降,从数百次下降到十几次 +- Dubbo3 应用级服务发现模型,FGC 次数 2.x 版本大幅下降,从数百次下降到零次 \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/performance/page-benchmarking.md b/content/en/overview/mannual/java-sdk/reference-manual/performance/page-benchmarking.md new file mode 100644 index 000000000000..97d3c6594f9d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/performance/page-benchmarking.md @@ -0,0 +1,26 @@ +--- +description: "" +linkTitle: RPC 控制台 +title: RPC 基准测试 控制台 +type: html +weight: 1 +--- + + + + + + + dubbo-benchmark + + + + + + + +
+ + + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/performance/rpc-benchmarking.md b/content/en/overview/mannual/java-sdk/reference-manual/performance/rpc-benchmarking.md new file mode 100644 index 000000000000..9caad23222f1 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/performance/rpc-benchmarking.md @@ -0,0 +1,63 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/performance/rpc-benchmarking/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/performance/rpc-benchmarking/ +description: "" +linkTitle: RPC 基准 +title: RPC 协议 Triple&Dubbo 基准测试 +type: docs +weight: 1 +--- + + + + + + +- Dubbo3 的 _Dubbo协议 _实现与 Dubbo2 版本在性能上基本持平。 +- 由于 Triple协议 本身是基于 HTTP/2 构建,因此在单条链路上的 RPC 调用并未比基于 TCP 的 Dubbo2 有提升,反而在某些调用场景出现一定下降。但 _Triple协议 _更大的优势在于网关穿透性、通用性,以及 Stream 通信模型带来的总体吞吐量提升。 +- Triple 预期在网关代理场景下一定会有更好的性能表现,鉴于当前压测环境,本轮 benchmark 暂未提供。 + +## 1.1 环境 + + +| | 描述 | +| ------------ | ------------------------------------------------------------ | +| **机器** | 4C8G Linux JDK 1.8(Provider)4C8G Linux JDK 1.8 (Consumer) | +| **压测用例** | RPC 方法类型包括:无参无返回值、普通pojo返回值、pojo列表返回值

2.7 版本 Dubbo 协议(Hessian2 序列化)
3.0 版本 Dubbo 协议(Hessian2 序列化)
3.0 版本 Dubbo 协议(Protobuf 序列化)
3.0 版本 Triple 协议(Protobuf 序列化)
3.0 版本 Triple 协议(Protobuf 套 Hessian2 序列化) | +| **压测方法** | 单链接场景下,消费端起 32 并发线程(当前机器配置 qps rt 较均衡的并发数),持续压后采集压测数据
压测数据通过 https://github.com/apache/dubbo-benchmark 得出 | + +
+ +## 1.2 数据分析 + +| | **Dubbo + Hessian2
2.7** | **Dubbo + Hessian2
3.0** | **Dubbo + Protobuf
3.0** | **Triple + Protobuf
3.0** | **Triple + Protobuf(Hessian)
3.0** | +| ------------------ | ----------------------------- | ----------------------------- | ----------------------------- | ------------------------------ | --------------------------------------- | +| **无参方法** | 30333 ops/s
2.5ms P99 | 30414 ops/s
2.4ms P99 | 24123 ops/s
3.2ms P99 | 7016 ops/s
8.7ms P99 | 6635 ops/s
9.1ms P99 | +| **pojo返回值** | 8984 ops/s
6.1 ms P99 | 12279 ops/s
5.7 ms P99 | 21479 ops/s
3.0 ms P99 | 6255 ops/s
8.9 ms P99 | 6491 ops/s
10 ms P99 | +| **pojo列表返回值** | 1916 ops/s
34 ms P99 | 2037 ops/s
34 ms P99 | 12722 ops/s
7.7 ms P99 | 6920 ops/s
9.6 ms P99 | 2833 ops/s
27 ms P99 | + +### 1.2.1 Dubbo 协议不同版本实现对比 + +![//imgs/v3/performance/rpc-dubbo.svg](/imgs/v3/performance/rpc-dubbo.svg) + +
图三 Dubbo协议在不同版本的实现对比
+ +- 就 Dubbo RPC + Hessian 的默认组合来说,Dubbo3 与 Dubbo2 在性能上在不同调用场景下基本持平 + +### 1.2.2 Dubbo协议 vs Triple协议 + +![//imgs/v3/performance/rpc-triple.svg](/imgs/v3/performance/rpc-triple.svg) + +
图四 Triple vs Dubbo
+ +- 单纯看 Consumer <-> Provider 的点对点调用,可以看出 Triple 协议本身并不占优势,同样使用 Protobuf 序列化方式,Dubbo RPC 协议总体性能还是要优于 Triple。

+- Triple 实现在 3.0 版本中将会得到持续优化,但不能完全改变在某些场景下“基于 HTTP/2 的 RPC 协议”对比“基于 TCP 的 RPC 协议”处于劣势的局面 + +### 1.2.3 补充网关场景 + +TBD

+ +### 1.2.4 模拟 Stream 通信场景的吞吐量提升 + +TBD \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/_index.md new file mode 100755 index 000000000000..9289bb67279a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/ + - /zh/overview/what/ecosystem/protocol/ +description: Dubbo RPC 协议指南 +linkTitle: RPC协议 +title: RPC 协议 +type: docs +weight: 2 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/dubbo.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/dubbo.md new file mode 100644 index 000000000000..5d67a7415400 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/dubbo.md @@ -0,0 +1,129 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/dubbo/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/dubbo/ + - /zh/overview/what/ecosystem/protocol/dubbo/ +description: "本文描述 Dubbo 协议 java 实现的特点与具体实现细节" +linkTitle: dubbo +title: Dubbo协议 +type: docs +weight: 3 +--- + +Dubbo 缺省协议采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。dubbo RPC是dubbo体系中最核心的一种高性能、高吞吐量的远程调用方式,我喜欢称之为多路复用的TCP长连接调用。 + + +主要用于两个dubbo系统之间作远程调用,特别适合高并发、小数据的互联网场景。反之,Dubbo 缺省协议不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。 + +* **长连接:避免了每次调用新建TCP连接,提高了调用的响应速度。** +* **多路复用:单个TCP连接可交替传输多个请求和响应的消息,降低了连接的等待闲置时间,从而减少了同样并发数下的网络连接数,提高了系统吞吐量。** + + +![dubbo-protocol.jpg](/imgs/user/dubbo-protocol.jpg) + +* Transporter: mina, netty, grizzy +* Serialization: dubbo, hessian2, java, json +* Dispatcher: all, direct, message, execution, connection +* ThreadPool: fixed, cached + + +缺省协议,使用基于 netty `3.2.5.Final` 和 hessian2 `3.2.1-fixed-2(Alibaba embed version)` 的 tbremoting 交互。 + +* 连接个数:单连接 +* 连接方式:长连接 +* 传输协议:TCP +* 传输方式:NIO 异步传输 +* 序列化:Hessian 二进制序列化 +* 适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用 dubbo 协议传输大文件或超大字符串。 +* 适用场景:常规远程服务方法调用 + +**约束** + +* 参数及返回值需实现 `Serializable` 接口 +* 参数及返回值不能自定义实现 `List`, `Map`, `Number`, `Date`, `Calendar` 等接口,只能用 JDK 自带的实现,因为 hessian 会做特殊处理,自定义实现类中的属性值都会丢失。 +* Hessian 序列化,只传成员属性值和值的类型,不传方法或静态变量,兼容情况由**吴亚军提供** + +| 数据通讯 | 情况 | 结果 | +| ------------- | ------------- | ------------- | +| A->B | 类A多一种 属性(或者说类B少一种 属性)| 不抛异常,A多的那 个属性的值,B没有,其他正常 | +| A->B | 枚举A多一种 枚举(或者说B少一种 枚举)| A使用多 出来的枚举进行传输 | 抛异常 | +| A->B | 枚举A多一种 枚举(或者说B少一种 枚举)| A不使用 多出来的枚举进行传输 | 不抛异常,B正常接 收数据 | +| A->B | A和B的属性 名相同,但类型不相同 | 抛异常 | +| A->B | serialId 不相同 | 正常传输 | + +接口增加方法,对客户端无影响,如果该方法不是客户端需要的,客户端不需要重新部署。输入参数和结果集中增加属性,对客户端无影响,如果客户端并不需要新属性,不用重新部署。 + +输入参数和结果集属性名变化,对客户端序列化无影响,但是如果客户端不重新部署,不管输入还是输出,属性名变化的属性值是获取不到的。 + +{{% alert title="总结" color="info" %}} +- 服务器端和客户端对领域对象并不需要完全一致,而是按照最大匹配原则。 +- 会抛异常的情况:枚举值一边多一种,一边少一种,正好使用了差别的那种,或者属性名相同,类型不同。 +{{% /alert %}} + +## 使用方式 + +### 配置协议 + +```xml + +``` + +### 设置默认协议 + +```xml + +``` + +### 设置某个服务的协议 + +```xml + +``` + +### 多端口 + +```xml + + +``` + +### 配置协议选项 + +```xml + +``` + +### 多连接配置 + +Dubbo 协议缺省每服务每提供者每消费者使用单一长连接,如果数据量较大,可以使用多个连接。 + +```xml + + +``` + +* `` 或 `` 表示该服务使用 JVM 共享长连接。**缺省** +* `` 或 `` 表示该服务使用独立长连接。 +* `` 或`` 表示该服务使用独立两条长连接。 + +为防止被大量连接撑挂,可在服务提供方限制大接收连接数,以实现服务提供方自我保护。 + +```xml + +``` + +## 常见问题 + +### Q1 为什么要消费者比提供者个数多? + +因 dubbo 协议采用单一长连接,假设网络为千兆网卡 **1024Mbit=128MByte**,根据测试经验数据每条连接最多只能压满 7MByte(不同的环境可能不一样,供参考),理论上 1 个服务提供者需要 20 个服务消费者才能压满网卡。 + +### Q2 为什么不能传大包? + +因 dubbo 协议采用单一长连接,如果每次请求的数据包大小为 500KByte,假设网络为千兆网卡 **1024Mbit=128MByte**,每条连接最大 7MByte (不同的环境可能不一样),单个服务提供者的 TPS(每秒处理事务数)最大为:128MByte / 500KByte = 262。单个消费者调用单个服务提供者的 TPS (每秒处理事务数)最大为:7MByte / 500KByte = 14。如果能接受,可以考虑使用,否则网络将成为瓶颈。 + +### Q3 为什么采用异步单一长连接? + +因为服务的现状大都是服务提供者少,通常只有几台机器,而服务的消费者多,可能整个网站都在访问该服务,比如 Morgan 的提供者只有 6 台提供者,却有上百台消费者,每天有 1.5 亿次调用,如果采用常规的 hessian 服务,服务提供者很容易就被压跨,通过单一连接,保证单一消费者不会压死提供者,长连接,减少连接握手验证等,并使用异步 IO,复用线程池,防止 C10K 问题。 + + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols.md new file mode 100644 index 000000000000..123c5265cbb1 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols.md @@ -0,0 +1,136 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-protocols/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-protocols/ + - /zh-cn/overview/tasks/protocols/multi-protocols/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-protocols +description: 在 Dubbo 中配置多协议 +linkTitle: 多协议 +title: 多协议 +type: docs +weight: 4 +--- + +区别于普通的 RPC 框架,Dubbo 作为一款微服务框架提供了非常灵活的协议支持,它不绑定一个单一通信协议。因此你**可以发布在一个进程中同时发布多个 RPC 协议、调用不同的 RPC 协议**。接下来我们就详细介绍多协议的具体使用场景与使用方式。 + +## 使用场景 +有很多场景可能会用到不同的协议,包括安全性、性能、与第三方系统互调等业务诉求。本文我们不分析具体的业务需求,而是从 Dubbo 框架提供的多协议能力出发分析框架能提供的多协议能力: + +* 作为服务提供者(provider),同一个服务发布为多个协议,供不同消费端调用 +* 作为服务提供者(provider),多个服务分别发布为不同协议,供不同消费端调用 +* 作为服务消费者(consumer),指定以某个特定协议调用某一个服务 + +## 使用方式 + +### 同一个服务发布为多个协议 + +如果使用 Spring Boot,可以修改 application.yml 或 application.properties 如下: +```yaml +dubbo: + protocols: + - id: dubbo-id + name: dubbo + port: 20880 + - id: tri-id + name: tri + port: 50051 +``` + +对于 Spring XML: + +```xml + + +``` + +接下来为服务配置(默认不配置的情况下,服务会发布到以上所有协议配置): + +```java +@DubboService(protocol="dubbo-id,triple-id") +private DemoServiceImpl implements DemoService {} +``` + +### 多个服务分别发布为不同协议 + +如果使用 Spring Boot,可以修改 application.yml 或 application.properties 如下: +```yaml +dubbo: + protocols: + - id: dubbo-id + name: dubbo + port: 20880 + - id: tri-id + name: tri + port: 50051 +``` + +接下来为不同的服务分别配置不同的协议引用: + +```java +@DubboService(protocol="dubbo-id") +private DemoServiceImpl implements DemoService {} +``` + +```java +@DubboService(protocol="triple-id") +private GreetingServiceImpl implements GreetingService {} +``` + +### 指定协议调用服务 + +对于消费端而言,直接在声明引用的时候指定要调用的协议关键字就可以了: + +```java +@DubboReference(protocol="dubbo") +private DemoService demoService; +``` + +```java +@DubboReference(protocol="tri") +private GreetingService greetingService; +``` + +## 不同的实现方式 + +### 多端口多协议 +多协议发布是指为同一个服务同时提供多种协议访问方式,多协议可以是任意两个或多个协议的组合,比如下面的配置将同时发布了 dubbo、triple 协议: + +```yaml +dubbo: + protocols: + - name: tri + port: 50051 + - name: dubbo + port: 20880 +``` + +基于以上配置,如果应用中有服务 DemoService,则既可以通过 dubbo 协议访问 DemoService,也可以通过 triple 协议访问 DemoService,其工作原理图如下: + +多协议 + +1. 提供者实例同时监听两个端口 20880 和 50051 +2. 同一个实例,会在注册中心注册两条地址 url +3. 不同的消费端可以选择以不同协议调用同一个提供者发布的服务 + +对于消费端而言,如果用户没有明确配置,默认情况下框架会自动选择 `dubbo` 协议调用。Dubbo 框架支持配置通过哪个协议访问服务,如 `@DubboReference(protocol="tri")`,或者在 application.yml 配置文件中指定全局默认值: + +```yaml +dubbo: + consumer: + protocol: tri +``` + +### 单端口多协议 + +除了以上发布多个端口、注册多条 url 到注册中心的方式。对于 dubbo、triple 这两个内置协议,框架提供了在单个端口上同时发布 dubbo 和 triple 协议的能力。这对于老用户来说是一个非常重要的能力,因为它可以做到不增加任何负担的情况下,让使用 dubbo 协议的用户可以额外发布 triple 协议,这样当所有的应用都实现多协议发布之后,我们就可以设置消费端去通过 triple 协议发起调用了。 + +单端口多协议 + +单端口多协议的基本配置如下: + + ```yaml + dubbo: + protocol: + name: dubbo + ext-protocol: tri + ``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/_index.md new file mode 100755 index 000000000000..ae16b6a99d5a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/ + - /zh/overview/what/ecosystem/protocol/ +description: Dubbo RPC 协议指南 +linkTitle: 扩展实现 +title: Dubbo 提供的更多 RPC 扩展协议实现 +type: docs +weight: 100 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/hessian.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/hessian.md new file mode 100644 index 000000000000..e22981e1813b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/hessian.md @@ -0,0 +1,87 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/hessian/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/hessian/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/hessian/ +description: Hessian协议 +linkTitle: Hessian协议 +title: Hessian协议 +type: docs +weight: 10 +--- + + + + +## 特性说明 +Hessian 协议用于集成 Hessian 的服务,Hessian 底层采用 Http 通讯,采用 Servlet 暴露服务,Dubbo 缺省内嵌 Jetty 作为服务器实现。 + +[Hessian](http://hessian.caucho.com) 是 Caucho 开源的一个 RPC 框架,其通讯效率高于 WebService 和 Java 自带的序列化。 + +* 连接个数:多连接 +* 连接方式:短连接 +* 传输协议:HTTP +* 传输方式:同步传输 +* 序列化:Hessian二进制序列化 +* 适用范围:传入传出参数数据包较大,提供者比消费者个数多,提供者压力较大,可传文件。 +* 适用场景:页面传输,文件传输,或与原生hessian服务互操作。 + +Dubbo 的 Hessian 协议可以和原生 Hessian 服务互操作,即: + +* 提供者用 Dubbo 的 Hessian 协议暴露服务,消费者直接用标准 Hessian 接口调用, +* 或者提供方用标准 Hessian 暴露服务,消费方用 Dubbo 的 Hessian 协议调用。 + +#### 约束 +* 参数及返回值需实现 `Serializable` 接口。 +* 参数及返回值不能自定义实现 `List`, `Map`, `Number`, `Date`, `Calendar` 等接口,只能用 JDK 自带的实现,因为 hessian 会做特殊处理,自定义实现类中的属性值都会丢失。 + +## 使用场景 +hessian是一个轻量级的RPC服务,是基于Binary-RPC协议实现的,序列化与反序列化实例。 + + +## 使用方式 + +### 依赖 + +从 Dubbo 3 开始,Hessian 协议已经不再内嵌在 Dubbo 中,需要单独引入独立的[模块](/zh-cn/download/spi-extensions/#dubbo-rpc)。 +```xml + + org.apache.dubbo.extensions + dubbo-rpc-hessian + 3.3.0 + +``` + +```xml + + com.caucho + hessian + 4.0.7 + +``` + +### 定义 hessian 协议 +```xml + +``` + +### 设置默认协议 +```xml + +``` + +### 设置 service 协议 +```xml + +``` + +### 多端口 +```xml + + +``` + +### 直连 +```xml + +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/http.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/http.md.bak new file mode 100644 index 000000000000..b06415fe1389 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/http.md.bak @@ -0,0 +1,81 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/http/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/http/ + - /zh/overview/what/ecosystem/protocol/http/ +description: HTTP协议 +linkTitle: HTTP协议 +title: HTTP协议 +type: docs +weight: 6 +--- + + + + + + + +## 特性说明 +基于 HTTP 表单的远程调用协议,采用 Spring 的 HttpInvoker 实现,`2.3.0` 以上版本支持。 + +* 连接个数:多连接 +* 连接方式:短连接 +* 传输协议:HTTP +* 传输方式:同步传输 +* 序列化:表单序列化 +* 适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。 +* 适用场景:需同时给应用程序和浏览器 JS 使用的服务。 + +#### 约束 +* 参数及返回值需符合 Bean 规范 + +## 使用场景 + +http短连接,协议标准化且易读,容易对接外部系统,适用于上层业务模块。 + +## 使用方式 + +从 Dubbo 3 开始,Http 协议已经不再内嵌在 Dubbo 中,需要单独引入独立的[模块](/zh-cn/download/spi-extensions/#dubbo-rpc)。 +```xml + + org.apache.dubbo.extensions + dubbo-rpc-http + 3.3.0 + +``` + +### 配置协议 +```xml + +``` + +### 配置 Jetty Server (默认) +```xml + +``` + +### 配置 Servlet Bridge Server (推荐使用) +```xml + +``` + +### 配置 DispatcherServlet + +```xml + + dubbo + org.apache.dubbo.remoting.http.servlet.DispatcherServlet + 1 + + + dubbo + /* + +``` + +{{% alert title="注意" color="primary" %}} +如果使用 servlet 派发请求 +* 协议的端口 `` 必须与 servlet 容器的端口相同, +* 协议的上下文路径 `` 必须与 servlet 应用的上下文路径相同。 +{{% /alert %}} diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/memcached.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/memcached.md new file mode 100644 index 000000000000..6e861e7ec71a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/memcached.md @@ -0,0 +1,57 @@ +--- +aliases: + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/memcached/ +description: Memcached 协议 +linkTitle: Memcached 协议 +title: Memcached 协议 +type: docs +weight: 5 +--- + + + +基于 memcached [^1] 实现的 RPC 协议。 + +{{% alert title="提示" color="primary" %}} +`2.3.0` 以上版本支持 +{{% /alert %}} + +## 注册 memcached 服务的地址 + +```java +RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); +Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); +registry.register(URL.valueOf("memcached://10.20.153.11/com.foo.BarService?category=providers&dynamic=false&application=foo&group=member&loadbalance=consistenthash")); +``` + +## 在客户端引用 + +在客户端使用 [^2]: + +```xml + +``` + +或者,点对点直连: + +```xml + +``` + +也可以使用自定义接口: + +```xml + +``` + +方法名建议和 memcached 的标准方法名相同,即:get(key), set(key, value), delete(key)。 + +如果方法名和 memcached 的标准方法名不相同,则需要配置映射关系 [^3]: + +```xml + +``` + +[^1]: [Memcached](http://memcached.org/) 是一个高效的 KV 缓存服务器 +[^2]: 不需要感知 Memcached 的地址 +[^3]: 其中 "p:xxx" 为 spring 的标准 p 标签 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/redis.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/redis.md new file mode 100644 index 000000000000..677e3dc8735e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/redis.md @@ -0,0 +1,58 @@ +--- +aliases: + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/redis/ +description: Redis 协议 +linkTitle: Redis 协议 +title: Redis 协议 +type: docs +weight: 4 +--- + + + + +基于 Redis [^1] 实现的 RPC 协议。 + +{{% alert title="提示" color="primary" %}} +`2.3.0` 以上版本支持 +{{% /alert %}} + +## 注册 redis 服务的地址 + +```java +RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); +Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); +registry.register(URL.valueOf("redis://10.20.153.11/com.foo.BarService?category=providers&dynamic=false&application=foo&group=member&loadbalance=consistenthash")); +``` + +## 在客户端引用 + +在客户端使用 [^2]: + +```xml + +``` + +或者,点对点直连: + +```xml + +``` + +也可以使用自定义接口: + +```xml + +``` + +方法名建议和 redis 的标准方法名相同,即:get(key), set(key, value), delete(key)。 + +如果方法名和 redis 的标准方法名不相同,则需要配置映射关系 [^3]: + +```xml + +``` + +[^1]: [Redis](http://redis.io) 是一个高效的 KV 存储服务器 +[^2]: 不需要感知 Redis 的地址 +[^3]: 其中 "p:xxx" 为 spring 的标准 p 标签 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/rmi.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/rmi.md new file mode 100644 index 000000000000..191f6463e2d0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/rmi.md @@ -0,0 +1,108 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/rmi/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/rmi/ + - /zh/overview/what/ecosystem/protocol/rmi/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/rmi/ +description: Rmi协议 +linkTitle: Rmi协议 +title: Rmi协议 +type: docs +weight: 8 +--- + + + + + + +## 特性说明 +RMI 协议采用 JDK 标准的 `java.rmi.*` 实现,采用阻塞式短连接和 JDK 标准序列化方式。 + +* 连接个数:多连接 +* 连接方式:短连接 +* 传输协议:TCP +* 传输方式:同步传输 +* 序列化:Java 标准二进制序列化 +* 适用范围:传入传出参数数据包大小混合,消费者与提供者个数差不多,可传文件。 +* 适用场景:常规远程服务方法调用,与原生RMI服务互操作 + +#### 约束 + +* 参数及返回值需实现 `Serializable` 接口 +* dubbo 配置中的超时时间对 RMI 无效,需使用 java 启动参数设置:`-Dsun.rmi.transport.tcp.responseTimeout=3000`,参见下面的 RMI 配置 + + +## 使用场景 + +是 Java 的一组拥护开发分布式应用程序的 API,实现了不同操作系统之间程序的方法调用。 + +## 使用方式 + +### 引入依赖 + +从 Dubbo 3 开始,RMI 协议已经不再内嵌在 Dubbo 中,需要单独引入独立的[模块](/zh-cn/download/spi-extensions/#dubbo-rpc)。 +```xml + + org.apache.dubbo.extensions + dubbo-rpc-rmi + 3.3.0 + +``` + +```sh +java -Dsun.rmi.transport.tcp.responseTimeout=3000 +``` +> 更多 RMI 优化参数请查看 [JDK 文档](https://docs.oracle.com/javase/6/docs/technotes/guides/rmi/sunrmiproperties.html) + +### 接口说明 +如果服务接口继承了 `java.rmi.Remote` 接口,可以和原生 RMI 互操作,即: + +* 提供者用 Dubbo 的 RMI 协议暴露服务,消费者直接用标准 RMI 接口调用, +* 或者提供方用标准 RMI 暴露服务,消费方用 Dubbo 的 RMI 协议调用。 + +如果服务接口没有继承 `java.rmi.Remote` 接口: + +* 缺省 Dubbo 将自动生成一个 `com.xxx.XxxService$Remote` 的接口,并继承 `java.rmi.Remote` 接口,并以此接口暴露服务, +* 但如果设置了 ``,将不生成 `$Remote` 接口,而使用 Spring 的 `RmiInvocationHandler` 接口暴露服务,和 Spring 兼容。 + +**定义 RMI 协议** + +```xml + +``` + +**设置默认协议** + +```xml + +``` + +**设置某个服务的协议** + +```xml + +``` + +**多端口** + +```xml + + + + +``` + +**Spring 兼容性** + +```xml + +``` + +{{% alert title="注意" color="primary" %}} +- **如果正在使用 RMI 提供服务给外部访问,** 公司内网环境应该不会有攻击风险。 + +- **同时应用里依赖了老的 common-collections 包的情况下,** dubbo 不会依赖这个包,请排查自己的应用有没有使用。 + +- **存在反序列化安全风险。** 请检查应用:将 commons-collections3 请升级到 [3.2.2](https://commons.apache.org/proper/commons-collections/release_3_2_2.html);将 commons-collections4 请升级到 [4.1](https://commons.apache.org/proper/commons-collections/release_4_1.html)。新版本的 commons-collections 解决了该问题。 +{{% /alert %}} diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/thrift.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/thrift.md new file mode 100644 index 000000000000..028ddbf24c5a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/thrift.md @@ -0,0 +1,49 @@ +--- +aliases: + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/thrift/ +description: Thrift 协议 +linkTitle: Thrift 协议 +title: Thrift 协议 +type: docs +weight: 4 +--- + + + + +当前 dubbo 支持的 thrift 协议是对 thrift 原生协议 [^1] 的扩展,在原生协议的基础上添加了一些额外的头信息,比如 service name,magic number 等。 + +{{% alert title="提示" color="primary" %}} +`2.3.0` 以上版本支持 +{{% /alert %}} + +使用 dubbo thrift 协议同样需要使用 thrift 的 idl compiler 编译生成相应的 java 代码,后续版本中会在这方面做一些增强。 + +## 依赖 + +```xml + + org.apache.thrift + libthrift + 0.8.0 + +``` + +## 配置 + +所有服务共用一个端口 [^2]: + +```xml + +``` + +## 使用 + +可以参考 [dubbo 项目中的示例代码](https://github.com/apache/dubbo/tree/master/dubbo-rpc/dubbo-rpc-thrift/src/test/java/org/apache/dubbo/rpc/protocol/thrift) + +## 常见问题 + +* Thrift 不支持 null 值,即:不能在协议中传递 null 值 + +[^1]: [Thrift](http://thrift.apache.org) 是 Facebook 捐给 Apache 的一个 RPC 框架 +[^2]: 与原生Thrift不兼容 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/v3.2_rest_protocol_design.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/v3.2_rest_protocol_design.md new file mode 100644 index 000000000000..025ecc665590 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/v3.2_rest_protocol_design.md @@ -0,0 +1,645 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ + - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ + - zh-cn/overview/mannual/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ +description: 本文将介绍 Dubbo 的 Rest 协议。 +linkTitle: Rest 协议 +title: Rest 协议 +type: docs +weight: 6 +--- + +{{% alert title="注意" color="warning" %}} +从 Dubbo 3.3 版本开始,Rest 协议已移至 Extensions 库,由 Triple 协议来对 Rest 提供更全面的支持,具体参见 [Triple Rest用户手册](../../tripe-rest-manual/), +如需继续使用原 Rest 协议,可引入对应 [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) 库依赖 +{{% /alert %}} + +更加轻量,具有dubbo风格的rest,微服务体系互通(Springcloud Alibaba) + +1.注解解析 + +2.报文编解码 + +3.restClient + +4.restServer(netty) + +支持程度: + +content-type   text json xml form(后续会扩展) + +注解 + +param,header,body,pathvariable (spring mvc & resteasy) + +## Http 协议报文 + + POST /test/path? HTTP/1.1 + Host: localhost:8080 + Connection: keep-alive + Content-type: application/json + + + {"name":"dubbo","age":10,"address":"hangzhou"} + + + +### dubbo http(header) + + // service key header + path: com.demo.TestInterface + group: demo + port: 80 + version: 1.0.0 + + // 保证长连接 + Keep-Alive,Connection: keep-alive + Keep-alive: 60 + + // RPCContext Attachment + userId: 123456 + + +## 目前支持粒度: + +| 数据位置 | content-type | spring注解 | resteasy注解 | +| --- | --- | --- | --- | +| body | 无要求 | ReuqestBody |  无注解即为body | +| querystring(?test=demo) | 无要求 | RequestParam | QueryParam | +| header | 无要求 | RequestHeader | PathParam | +| form | application/x-www-form-urlencoded | RequestParam ReuqestBody | FormParam | +| path | 无要求 | PathVariable | PathParam | +| method | 无要求 | PostMapping GetMapping | GET POST | +| url | | PostMapping GetMapping path属性 | Path | +| content-type | | PostMapping GetMapping consumers属性 | Consumers | +| Accept | | PostMapping GetMapping produces属性 | Produces | + +## rest注解解析(ServiceRestMetadataResolver) + + JAXRSServiceRestMetadataResolver + + SpringMvcServiceRestMetadataResolver + +ServiceRestMetadata + + public class ServiceRestMetadata implements Serializable { + + private String serviceInterface; // com.demo.TestInterface + + private String version;// 1.0.0 + + private String group;// demo + + private Set meta;// method 元信息 + + private int port;// 端口 for provider service key + + private boolean consumer;// consumer 标志 + + /** + * make a distinction between mvc & resteasy + */ + private Class codeStyle;// + + /** + * for provider + */ + private Map pathToServiceMap; + + /** + * for consumer + */ + private Map> methodToServiceMa + +RestMethodMetadata + + public class RestMethodMetadata implements Serializable { + + private MethodDefinition method; // method 定义信息(name ,pramType,returnType) + + private RequestMetadata request;// 请求元信息 + + private Integer urlIndex; + + private Integer bodyIndex; + + private Integer headerMapIndex; + + private String bodyType; + + private Map> indexToName; + + private List formParams; + + private Map indexToEncoded; + + private ServiceRestMetadata serviceRestMetadata; + + private List argInfos; + + private Method reflectMethod; + + /** + * make a distinction between mvc & resteasy + */ + private Class codeStyle; + + +ArgInfo + + public class ArgInfo { + /** + * method arg index 0,1,2,3 + */ + private int index; + /** + * method annotation name or name + */ + private String annotationNameAttribute; + + /** + * param annotation type + */ + private Class paramAnnotationType; + + /** + * param Type + */ + private Class paramType; + + /** + * param name + */ + private String paramName; + + /** + * url split("/") String[n] index + */ + private int urlSplitIndex; + + private Object defaultValue; + + private boolean formContentType; + +RequestMeatadata + + public class RequestMetadata implements Serializable { + + private static final long serialVersionUID = -240099840085329958L; + + private String method;// 请求method + + private String path;// 请求url + + + private Map> params // param参数?拼接 + + private Map> headers// header; + + private Set consumes // content-type; + + private Set produces // Accept; + +### Consumer 代码: + +refer: + + @Override + protected Invoker protocolBindingRefer(final Class type, final URL url) throws RpcException { + + // restClient spi创建 + ReferenceCountedClient refClient = + clients.computeIfAbsent(url.getAddress(), key -> createReferenceCountedClient(url, clients)); + + refClient.retain(); + + // resolve metadata + Map> metadataMap = MetadataResolver.resolveConsumerServiceMetadata(type, url); + + ReferenceCountedClient finalRefClient = refClient; + Invoker invoker = new AbstractInvoker(type, url, new String[]{INTERFACE_KEY, GROUP_KEY, TOKEN_KEY}) { + @Override + protected Result doInvoke(Invocation invocation) { + try { + // 获取 method的元信息 + RestMethodMetadata restMethodMetadata = metadataMap.get(invocation.getMethodName()).get(ParameterTypesComparator.getInstance(invocation.getParameterTypes())); + + RequestTemplate requestTemplate = new RequestTemplate(invocation, restMethodMetadata.getRequest().getMethod(), url.getAddress(), getContextPath(url)); + + HttpConnectionCreateContext httpConnectionCreateContext = new HttpConnectionCreateContext(); + // TODO dynamic load config + httpConnectionCreateContext.setConnectionConfig(new HttpConnectionConfig()); + httpConnectionCreateContext.setRequestTemplate(requestTemplate); + httpConnectionCreateContext.setRestMethodMetadata(restMethodMetadata); + httpConnectionCreateContext.setInvocation(invocation); + httpConnectionCreateContext.setUrl(url); + + // http 信息构建拦截器 + for (HttpConnectionPreBuildIntercept intercept : httpConnectionPreBuildIntercepts) { + intercept.intercept(httpConnectionCreateContext); + } + + + CompletableFuture future = finalRefClient.getClient().send(requestTemplate); + CompletableFuture responseFuture = new CompletableFuture<>(); + AsyncRpcResult asyncRpcResult = new AsyncRpcResult(responseFuture, invocation); + // response 处理 + future.whenComplete((r, t) -> { + if (t != null) { + responseFuture.completeExceptionally(t); + } else { + AppResponse appResponse = new AppResponse(); + try { + int responseCode = r.getResponseCode(); + MediaType mediaType = MediaType.TEXT_PLAIN; + + if (400 < responseCode && responseCode < 500) { + throw new HttpClientException(r.getMessage()); + } else if (responseCode >= 500) { + throw new RemoteServerInternalException(r.getMessage()); + } else if (responseCode < 400) { + mediaType = MediaTypeUtil.convertMediaType(r.getContentType()); + } + + + Object value = HttpMessageCodecManager.httpMessageDecode(r.getBody(), + restMethodMetadata.getReflectMethod().getReturnType(), mediaType); + appResponse.setValue(value); + Map headers = r.headers() + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0))); + appResponse.setAttachments(headers); + responseFuture.complete(appResponse); + } catch (Exception e) { + responseFuture.completeExceptionally(e); + } + } + }); + return asyncRpcResult; + } catch (RpcException e) { + if (e.getCode() == RpcException.UNKNOWN_EXCEPTION) { + e.setCode(getErrorCode(e.getCause())); + } + throw e; + } + } + + @Override + public void destroy() { + super.destroy(); + invokers.remove(this); + destroyInternal(url); + } + }; + invokers.add(invoker); + return invoker; + +### provider 代码: + +export: + + public Exporter export(final Invoker invoker) throws RpcException { + URL url = invoker.getUrl(); + final String uri = serviceKey(url); + Exporter exporter = (Exporter) exporterMap.get(uri); + if (exporter != null) { + // When modifying the configuration through override, you need to re-expose the newly modified service. + if (Objects.equals(exporter.getInvoker().getUrl(), invoker.getUrl())) { + return exporter; + } + } + + + // TODO addAll metadataMap to RPCInvocationBuilder metadataMap + Map metadataMap = MetadataResolver.resolveProviderServiceMetadata(url.getServiceModel().getProxyObject().getClass(),url); + + PathAndInvokerMapper.addPathAndInvoker(metadataMap, invoker); + + + final Runnable runnable = doExport(proxyFactory.getProxy(invoker, true), invoker.getInterface(), invoker.getUrl()); + exporter = new AbstractExporter(invoker) { + @Override + public void afterUnExport() { + exporterMap.remove(uri); + if (runnable != null) { + try { + runnable.run(); + } catch (Throwable t) { + logger.warn(PROTOCOL_UNSUPPORTED, "", "", t.getMessage(), t); + } + } + } + }; + exporterMap.put(uri, exporter); + return exporter; + } + +RestHandler + + private class RestHandler implements HttpHandler { + + @Override + public void handle(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException, ServletException { + // 有servlet reuqest 和nettyRequest + RequestFacade request = RequestFacadeFactory.createRequestFacade(servletRequest); + RpcContext.getServiceContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort()); + // dispatcher.service(request, servletResponse); + + Pair build = null; + try { + // 根据请求信息创建 RPCInvocation + build = RPCInvocationBuilder.build(request, servletRequest, servletResponse); + } catch (PathNoFoundException e) { + servletResponse.setStatus(404); + } + + Invoker invoker = build.getSecond(); + + Result invoke = invoker.invoke(build.getFirst()); + + // TODO handling exceptions + if (invoke.hasException()) { + servletResponse.setStatus(500); + } else { + + try { + Object value = invoke.getValue(); + String accept = request.getHeader(RestConstant.ACCEPT); + MediaType mediaType = MediaTypeUtil.convertMediaType(accept); + // TODO write response + HttpMessageCodecManager.httpMessageEncode(servletResponse.getOutputStream(), value, invoker.getUrl(), mediaType); + servletResponse.setStatus(200); + } catch (Exception e) { + servletResponse.setStatus(500); + } + + + } + + // TODO add Attachment header + + + } + } + +RPCInvocationBuilder + + { + + + private static final ParamParserManager paramParser = new ParamParserManager(); + + + public static Pair build(RequestFacade request, Object servletRequest, Object servletResponse) { + + // 获取invoker + Pair invokerRestMethodMetadataPair = getRestMethodMetadata(request); + + RpcInvocation rpcInvocation = createBaseRpcInvocation(request, invokerRestMethodMetadataPair.getSecond()); + + ProviderParseContext parseContext = createParseContext(request, servletRequest, servletResponse, invokerRestMethodMetadataPair.getSecond()); + // 参数构建 + Object[] args = paramParser.providerParamParse(parseContext); + + rpcInvocation.setArguments(args); + + return Pair.make(rpcInvocation, invokerRestMethodMetadataPair.getFirst()); + + } + + private static ProviderParseContext createParseContext(RequestFacade request, Object servletRequest, Object servletResponse, RestMethodMetadata restMethodMetadata) { + ProviderParseContext parseContext = new ProviderParseContext(request); + parseContext.setResponse(servletResponse); + parseContext.setRequest(servletRequest); + + Object[] objects = new Object[restMethodMetadata.getArgInfos().size()]; + parseContext.setArgs(Arrays.asList(objects)); + parseContext.setArgInfos(restMethodMetadata.getArgInfos()); + + + return parseContext; + } + + private static RpcInvocation createBaseRpcInvocation(RequestFacade request, RestMethodMetadata restMethodMetadata) { + RpcInvocation rpcInvocation = new RpcInvocation(); + + + int localPort = request.getLocalPort(); + String localAddr = request.getLocalAddr(); + int remotePort = request.getRemotePort(); + String remoteAddr = request.getRemoteAddr(); + + String HOST = request.getHeader(RestConstant.HOST); + String GROUP = request.getHeader(RestConstant.GROUP); + + String PATH = request.getHeader(RestConstant.PATH); + String VERSION = request.getHeader(RestConstant.VERSION); + + String METHOD = restMethodMetadata.getMethod().getName(); + String[] PARAMETER_TYPES_DESC = restMethodMetadata.getMethod().getParameterTypes(); + + rpcInvocation.setParameterTypes(restMethodMetadata.getReflectMethod().getParameterTypes()); + + + rpcInvocation.setMethodName(METHOD); + rpcInvocation.setAttachment(RestConstant.GROUP, GROUP); + rpcInvocation.setAttachment(RestConstant.METHOD, METHOD); + rpcInvocation.setAttachment(RestConstant.PARAMETER_TYPES_DESC, PARAMETER_TYPES_DESC); + rpcInvocation.setAttachment(RestConstant.PATH, PATH); + rpcInvocation.setAttachment(RestConstant.VERSION, VERSION); + rpcInvocation.setAttachment(RestConstant.HOST, HOST); + rpcInvocation.setAttachment(RestConstant.REMOTE_ADDR, remoteAddr); + rpcInvocation.setAttachment(RestConstant.LOCAL_ADDR, localAddr); + rpcInvocation.setAttachment(RestConstant.REMOTE_PORT, remotePort); + rpcInvocation.setAttachment(RestConstant.LOCAL_PORT, localPort); + + Enumeration attachments = request.getHeaders(RestConstant.DUBBO_ATTACHMENT_HEADER); + + while (attachments != null && attachments.hasMoreElements()) { + String s = attachments.nextElement(); + + String[] split = s.split("="); + + rpcInvocation.setAttachment(split[0], split[1]); + } + + + // TODO set path,version,group and so on + return rpcInvocation; + } + + + private static Pair getRestMethodMetadata(RequestFacade request) { + String path = request.getRequestURI(); + String version = request.getHeader(RestConstant.VERSION); + String group = request.getHeader(RestConstant.GROUP); + int port = request.getIntHeader(RestConstant.REST_PORT); + + return PathAndInvokerMapper.getRestMethodMetadata(path, version, group, port); + } + + + } + +## 编码示例 + +API + +mvc: + + @RestController() + @RequestMapping("/demoService") + public interface DemoService { + @RequestMapping(value = "/hello", method = RequestMethod.GET) + Integer hello(@RequestParam Integer a, @RequestParam Integer b); + + @RequestMapping(value = "/error", method = RequestMethod.GET) + String error(); + + @RequestMapping(value = "/say", method = RequestMethod.POST, consumes = MediaType.TEXT_PLAIN_VALUE) + String sayHello(@RequestBody String name); + } + +resteasy: + + @Path("/demoService") + public interface RestDemoService { + @GET + @Path("/hello") + Integer hello(@QueryParam("a")Integer a,@QueryParam("b") Integer b); + + @GET + @Path("/error") + String error(); + + @POST + @Path("/say") + @Consumes({MediaType.TEXT_PLAIN}) + String sayHello(String name); + + boolean isCalled(); + } + +impl(service) + + @DubboService() + public class RestDemoServiceImpl implements RestDemoService { + private static Map context; + private boolean called; + + + @Override + public String sayHello(String name) { + called = true; + return "Hello, " + name; + } + + + public boolean isCalled() { + return called; + } + + @Override + public Integer hello(Integer a, Integer b) { + context = RpcContext.getServerAttachment().getObjectAttachments(); + return a + b; + } + + + @Override + public String error() { + throw new RuntimeException(); + } + + public static Map getAttachments() { + return context; + } + } + +## 流程图 + +**Consumer**   + +![image](https://static.dingtalk.com/media/lQLPJxLOtqTxs9TNA5rNBQCwci8F2QYiGAYD5sSyd4BVAA_1280_922.png) + +**Provider(RestServer)** + +![image](https://static.dingtalk.com/media/lQLPJxZcNUm4M9TNA1_NBMuwZUu6IC3FeYAD5sSydYADAA_1227_863.png) + +## 场景 : + +**非dubbo体系互通(Springcloud alibaba  互通)** + +互通条件: + +| | 协议 | Dubbo | SpringCloud Alibaba | 互通 | +| --- | --- | --- | --- | --- | +| 通信协议 | rest | spring web/resteasy  编码风格 | 集成feignclient,ribbon (spring web 编码风格) | 是 | +| | triple | | | | +| | dubbo | | | | +| | grpc | | | | +| | hessian | | | | +| 注册中心 | zookeeper | | | | +| | nacos | 支持 | 支持 | 应用级别注册 | + +### 2.dubbo 双注册  + + 完成应用级别注册,(dubo2-dubbo3 过度),dubbo版本升级 + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/0ceca951-f467-4ab3-9b71-8e7d52e5e7d1.png) + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/6bcc7aed-1d22-470f-b185-efbab32df1e5.png) + +### 3.多协议发布 + +配置: + + + +### 4.跨语言 + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/1bdf8f91-9666-4c20-9aea-8396c745f554.png) + +### 5.多协议交互 + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/af72e3df-05d5-42a2-a333-618be7ec6cb8.png) + +### 6.协议迁移 + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/36d30183-8d5f-494c-8ebb-b57403c88661.png) + +rest编码风格 + +Http协议更通用跨语言调用 + +dubbo rest 对其他http服务 进行调用 + +其他httpclient 对dubbo rest进行调用 + +dubbo restServer 可以与其他web服务,浏览器等客户端直接进行http交互 + +## consumer TODOLIST(功能已经初步实现,可以调通解析response) + +1. org/apache/dubbo/rpc/protocol/rest/RestProtocol.java:157  dynamic load config + +2.org/apache/dubbo/remoting/http/factory/AbstractHttpClientFactory.java:50 load config  HttpClientConfig + +3.org/apache/dubbo/rpc/protocol/rest/annotation/metadata/MetadataResolver.java:52  support Dubbo style service + +4.org/apache/dubbo/remoting/http/restclient/HttpClientRestClient.java:120  TODO config + +5.org/apache/dubbo/remoting/http/restclient/HttpClientRestClient.java:140 TODO close judge + +6.org/apache/dubbo/rpc/protocol/rest/message/decode/MultiValueCodec.java:35  TODO java bean  get set convert + +## provider TODOLIST(待实现) + +基于netty实现支持http协议的NettyServer + +无注解协议定义 + +官网场景补充 + +## Rest使用说明文档及demo: diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/webservice.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/webservice.md new file mode 100644 index 000000000000..6da21d39eedc --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/webservice.md @@ -0,0 +1,119 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/webservice/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/webservice/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/webservice/ +description: Webservice协议 +linkTitle: Webservice协议 +title: Webservice协议 +type: docs +weight: 11 +--- + +## 特性说明 +基于 WebService 的远程调用协议,基于 [Apache CXF](http://cxf.apache.org) 的 `frontend-simple` 和 `transports-http` 实现。`2.3.0` 以上版本支持。 + +CXF 是 Apache 开源的一个 RPC 框架,由 Xfire 和 Celtix 合并而来。 +* 连接个数:多连接 +* 连接方式:短连接 +* 传输协议:HTTP +* 传输方式:同步传输 +* 序列化:SOAP 文本序列化 +* 适用场景:系统集成,跨语言调用 + +可以和原生 WebService 服务互操作,即: + +* 提供者用 Dubbo 的 WebService 协议暴露服务,消费者直接用标准 WebService 接口调用, +* 或者提供方用标准 WebService 暴露服务,消费方用 Dubbo 的 WebService 协议调用。 +#### 约束 +* 参数及返回值需实现 `Serializable` 接口 +* 参数尽量使用基本类型和 POJO + +## 使用场景 +发布一个服务(对内/对外),不考虑客户端类型,不考虑性能,建议使用webservice。服务端已经确定使用webservice,客户端不能选择,必须使用webservice。 +## 使用方式 +### 依赖 + +从 Dubbo 3 开始,Webservice 协议已经不再内嵌在 Dubbo 中,需要单独引入独立的[模块](/zh-cn/download/spi-extensions/#dubbo-rpc)。 +```xml + + org.apache.dubbo.extensions + dubbo-rpc-webservice + 3.3.0 + +``` + +```xml + + org.apache.cxf + cxf-rt-frontend-simple + 2.6.1 + + + org.apache.cxf + cxf-rt-transports-http + 2.6.1 + +``` + +### 配置协议 +```xml + +``` + +### 配置默认协议 +```xml + +``` + +### 配置服务协议 +```xml + +``` + +### 多端口 +```xml + + +``` + +### 直连 +```xml + +``` + +### WSDL +``` +http://10.20.153.10:8080/com.foo.HelloWorld?wsdl +``` + +### Jetty Server (默认) + +```xml + +``` + +### Servlet Bridge Server (推荐) +```xml + +``` + +### 配置 DispatcherServlet +```xml + + dubbo + org.apache.dubbo.remoting.http.servlet.DispatcherServlet + 1 + + + dubbo + /* + +``` +{{% alert title="注意" color="primary" %}} + 如果使用 servlet 派发请求: + + 协议的端口 `` 必须与 servlet 容器的端口相同。 + + 协议的上下文路径 `` 必须与 servlet 应用的上下文路径相同。 +{{% /alert %}} diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/overview.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/overview.md new file mode 100644 index 000000000000..c9c60b3e953b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/overview.md @@ -0,0 +1,48 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/overview/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/overview/ +description: 协议概述 +linkTitle: 协议概述 +title: 协议概述 +type: docs +weight: 1 +--- + +Dubbo 作为一款 RPC 框架内置了高效的 RPC 通信协议,帮助解决服务间的编码与通信问题,目前支持的协议包括: + * triple,基于 HTTP/1、HTTP/2 的高性能通信协议,100% 兼容 gRPC,支持 Unary、Streming 等通信模式;支持发布 REST 风格的 HTTP 服务。 + * dubbo,基于 TCP 的高性能私有通信协议,缺点是通用性较差,更适合在 Dubbo SDK 间使用; + * 任意协议扩展,通过扩展 protocol 可以之前任意 RPC 协议,官方生态库提供 JsonRPC、thrift 等支持。 + +## 协议选型 + +**开发者该如何确定使用哪一种协议那?** 以下是我们从使用场景、性能、编程易用性、多语言互通等方面对多个主流协议的对比分析: + +| 协议 | 性能 | 网关友好 | 流式通信 | 多语言支持 | 编程API | 说明 | +| --- | --- | --- | --- | --- | --- | --- | +| triple | 高 | 高 | 支持,客户端流、服务端流、双向流 | 支持(Java、Go、Node.js、JavaScript、Rust) | Java Interface、Protobuf(IDL) | 在多语言兼容、性能、网关、Streaming、gRPC 等方面最均衡的协议实现,官方推荐。
支持 `application/json` 格式 payload http 直接访问。 | +| dubbo | 高 | 低 | 不支持 | 支持(Java、Go) | Java Interface | 性能最高的私有协议,但前端流量接入、多语言支持等成本较高 | + +以下是 triple、dubbo 两个主要协议的具体开发、配置、运行态信息: + | 协议名称 | 配置值 | 服务定义方式 | 默认端口 | 传输层协议 | 序列化协议 | 是否默认 | + | --- | --- | --- | --- | --- | --- | --- | + | **triple** | tri | - Java Interface
- Java Interface+SpringWeb注解
- Java Interface+JaxRS注解
- Protobuf(IDL) | 50051 | HTTP/1、HTTP/2 | Protobuf Binary、Protobuf-json | 否 | + | **dubbo** | dubbo | - Java Interface | 20880 | TCP | Hessian、Fastjson2、JSON、JDK、Avro、Kryo 等 | **是** | + + {{% alert title="注意" color="warning" %}} + * 自 3.3 版本开始,triple 协议支持以 rest 风格发布标准的 http 服务,因此框架中实际已不存在独立的 rest protocol 扩展实现, + * 考虑到对过往版本的兼容性,当前 Dubbo 各个发行版本均默认使用 `dubbo` 通信协议。**对于新用户而言,我们强烈建议在一开始就明确配置使用 `triple` 协议**,老用户也尽快参考文档 [实现协议的平滑迁移](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/migration)。 + {{% /alert %}} + +## 多协议扩展 +以下是当前 Dubbo 官方生态库提供的拓展协议实现。如果要扩展更多自定义协议,请参考 [SPI 扩展手册](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/) 或 [使用教程 - 协议扩展](/zh-cn/overview/mannual/java-sdk/tasks/extensibility/protocol/)。 + +| 协议 | 配置值 | 说明 | +| --- | --- | --- | +| Hessian | hessian | Hessian 定义的 RPC 通信协议,具体查看 [hessian协议](../others/hessian/) | +| Spring HTTP | http | Spring 定义的基于 HTTP 的私有协议,具体查看 [hessian协议](../others/hessian/) | +| Apache Thrift | thrift | Thrift 协议,具备高性能、支持多语言的特点,具体查看 [Thrift协议](../others/thrift/) | +| JsonRPC | jsonrpc | 具体查看 [JsonRPC](../others/jsonrpc/) | +| RMI | rmi | 具体查看 [RMI协议](../others/rmi/) | +| WebService | webservice | 具体查看 [WebService协议](../others/webservice/) | + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/rest.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/protocol/rest.md.bak new file mode 100644 index 000000000000..e53ad674b3a8 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/rest.md.bak @@ -0,0 +1,815 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/rest/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/rest/ +description: Rest协议 +linkTitle: rest +title: Rest协议 +type: docs +weight: 4 +--- + +# JSON 兼容性检查 + + +## 特性说明 +`Dubbo`目前支持使用`Rest`协议进行服务调用,`Rest`协议默认会使用`JSON`作为序列化方式,但`JSON`并不支持`Java`的一些特殊用法,如`接口`和`抽象类`等。 + +`Dubbo 3.3`版本在服务发布流程中增加了`服务接口JSON兼容性检测`功能, 可以确保服务接口传输对象是否可以被`JSON`序列化, 进一步提升`Rest`服务接口的正确性。 + +## 使用场景 +使用`Rest`作为通信协议,`JSON`作为序列化方式时,对服务接口进行兼容性检查,确保服务接口传输对象可以正确地被`JSON`序列化。 + +## 使用方式 + +当使用`Rest`协议作为通信协议,`JSON`作为序列化方式时,可以在`xml`文件中通过配置`protocol`的`json-check-level`属性来配置`JSON兼容性检查`的级别。 + +目前有`3`种级别,每种级别的具体含义如下: + +* `disabled`:表示`不开启JSON兼容性检查`,此时不会对接口进行兼容性检查。 +* `warn`:表示`开启JSON兼容性检查`,如果出现不兼容的情况,将会以`warn`级别的日志形式将不兼容的接口名称打印输出到终端。 +* `strict`:表示`开启JSON兼容性检查`,如果出现不兼容的情况,将会在启动时抛出`IllegalStateException`异常,终止启动流程,同时会将不兼容的接口名称存放在异常信息中。 + +> 如果没有通过`json-check-level`指定兼容性检查级别,则默认是`warn`告警级别。 + +### 使用示例 + +```xml + + + + + + + + + + + + + + + + + + + + + + +``` + + + + + +基于标准的 Java REST API——JAX-RS 2.0(Java API for RESTful Web Services 的简写)实现的 REST 调用支持 + +## 特性说明 +此协议提供通过 web 访问服务的简单方式,将服务与其他基于 web 的应用程序集成。 +支持 JSON、XML 和 Text 格式的请求和响应,发布和使用服务的便捷方式,也提供了服务版本控制、服务过滤、服务元数据和服务参数, 实现 Dubbo 框架的灵活性和可伸缩性。 + +## 使用场景 +将 Dubbo 服务公开为 RESTful API,与微服务和现有 RESTful 系统集成,实现与非 Java 客户端的互操作性,并促进混合通信。 + +## 使用方式 + +### 快速入门 + +在 dubbo 中开发一个 REST 风格的服务会比较简单,下面以一个注册用户的简单服务为例说明。 + +这个服务要实现的功能是提供如下 URL(注:这个URL不是完全符合 REST 的风格,但是更简单实用) +``` +http://localhost:8080/users/register +``` +而任何客户端都可以将包含用户信息的 JSON 字符串 POST 到以上 URL 来完成用户注册。 + +首先,开发服务的接口 + +```java +public class UserService { + void registerUser(User user); +} +``` + +然后,开发服务的实现 + +```java +@Path("users") +public class UserServiceImpl implements UserService { + + @POST + @Path("register") + @Consumes({MediaType.APPLICATION_JSON}) + public void registerUser(User user) { + // save the user... + } +} +``` +上面的实现非常简单,但是由于该 REST 服务是要发布到指定 URL 上,供任意语言的客户端甚至浏览器来访问,所以这里额外添加了几个 JAX-RS 的标准 annotation 来做相关的配置。 + +@Path("users"):指定访问 UserService 的 URL 相对路径是 /users,即 http://localhost:8080/users + +@Path("register"):指定访问 registerUser() 方法的 URL 相对路径是 /register,再结合上一个 @Path为UserService 指定的路径,则调用 UserService.register() 的完整路径为 http://localhost:8080/users/register + +@POST:指定访问 registerUser()用HTTP POST方法 + +@Consumes({MediaType.APPLICATION_JSON}):指定 registerUser() 接收 JSON 格式的数据。REST 框架会自动将 JSON 数据反序列化为 User 对象 + +最后,在 spring 配置文件中添加此服务,即完成所有服务开发工作 + + ```xml + + + + + + + + +``` + +### REST 服务提供端 + +下面我们扩充“快速入门”中的UserService,进一步展示在dubbo中REST服务提供端的开发要点。 + +### HTTP POST/GET 的实现 + +REST 服务中虽然建议使用 HTTP 协议中四种标准方法 POST、DELETE、PUT、GET 来分别实现常见的“增删改查”,但实际中,我们一般情况直接用POST来实现“增改”,GET 来实现“删查”即可(DELETE 和 PUT 甚至会被一些防火墙阻挡)。 + +前面已经简单演示了 POST 的实现,在此,我们为 UserService 添加一个获取注册用户资料的功能,来演示 GET 的实现。 + +这个功能就是要实现客户端通过访问如下不同 URL 来获取不同 ID 的用户资料 + +``` +http://localhost:8080/users/1001 +http://localhost:8080/users/1002 +http://localhost:8080/users/1003 +``` + +当然,也可以通过其他形式的URL来访问不同 ID 的用户资料,例如 + +``` +http://localhost:8080/users/load?id=1001 +``` + +JAX-RS 本身可以支持所有这些形式。但是上面那种在 URL 路径中包含查询参数的形式(http://localhost:8080/users/1001) 更符合 REST 的一般习惯,所以更推荐大家来使用。下面我们就为 UserService 添加一个 getUser() 方法来实现这种形式的 URL 访问 + +```java +@GET +@Path("{id : \\d+}") +@Produces({MediaType.APPLICATION_JSON}) +public User getUser(@PathParam("id") Long id) { + // ... +} +``` + +@GET:指定用 HTTP GET 方法访问 + +@Path("{id : \\d+}"):根据上面的功能需求,访问 getUser() 的 URL 应当是 “http://localhost:8080/users/ + 任意数字",并且这个数字要被做为参数传入 getUser() 方法。 这里的 annotation 配置中,@Path中间的 {id: xxx} 指定 URL 相对路径中包含了名为id参数,而它的值也将被自动传递给下面用 @PathParam("id") 修饰的方法参数 id。{id:后面紧跟的\\d+ 是一个正则表达式,指定了 id 参数必须是数字。 + +@Produces({MediaType.APPLICATION_JSON}):指定getUser()输出JSON格式的数据。框架会自动将User对象序列化为JSON数据。 + +### Annotation + +在 Dubbo 中开发 REST 服务主要都是通过 JAX-RS的annotation 来完成配置的,在上面的示例中,我们都是将 annotation 放在服务的实现类中。但其实,我们完全也可以将 annotation 放到服务的接口上,这两种方式是完全等价的,例如: + +```java +@Path("users") +public interface UserService { + + @GET + @Path("{id : \\d+}") + @Produces({MediaType.APPLICATION_JSON}) + User getUser(@PathParam("id") Long id); +} +``` + +在一般应用中,我们建议将 annotation 放到服务实现类,这样 annotation 和 java 实现代码位置更接近,更便于开发和维护。另外更重要的是,我们一般倾向于避免对接口的污染,保持接口的纯净性和广泛适用性。 + +但是,如后文所述,如果我们要用 dubbo 直接开发的消费端来访问此服务,则 annotation 必须放到接口上。 + +如果接口和实现类都同时添加了 annotation,则实现类的 annotation 配置会生效,接口上的 annotation 被直接忽略。 + +### 多数据格式支持 + +在 dubbo 中开发的 REST 服务可以同时支持传输多种格式的数据,以给客户端提供最大的灵活性。其中我们目前对最常用的 JSON 和 XML 格式特别添加了额外的功能。 + +比如,我们要让上例中的getUser()方法支持分别返回 JSON 和 XML 格式的数据,只需要在 annotation 中同时包含两种格式即可 + +```java +@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) +User getUser(@PathParam("id") Long id); +``` + +或者也可以直接用字符串(还支持通配符)表示 MediaType + +```java +@Produces({"application/json", "text/xml"}) +User getUser(@PathParam("id") Long id); +``` + +如果所有方法都支持同样类型的输入输出数据格式,则我们无需在每个方法上做配置,只需要在服务类上添加 annotation 即可 + +```java +@Path("users") +@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) +@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) +public class UserServiceImpl implements UserService { + // ... +} + +``` + +在一个 REST 服务同时对多种数据格式支持的情况下,根据 JAX-RS 标准,一般是通过HTTP中的MIME header(content-type和accept)来指定当前想用的是哪种格式的数据。 + +但是在 dubbo 中,我们还自动支持目前业界普遍使用的方式,即用一个 URL 后缀(.json和.xml)来指定想用的数据格式。例如,在添加上述 annotation后,直接访问 http://localhost:8888/users/1001.json 则表示用 json 格式,直接访问 http://localhost:8888/users/1002.xml 则表示用 xml 格式,比用 HTTP Header 更简单直观。Twitter、微博等的 REST API 都是采用这种方式。 +如果你既不加 HTTP header,也不加后缀,则 dubbo 的 REST 会优先启用在以上 annotation 定义中排位最靠前的那种数据格式。 + +> 注意:这里要支持 XML 格式数据,在 annotation 中既可以用 MediaType.TEXT_XML,也可以用 MediaType.APPLICATION_XML,但是 TEXT_XML 是更常用的,并且如果要利用上述的 URL 后缀方式来指定数据格式,只能配置为 TEXT_XML 才能生效。 + +### 中文字符支持 + +为了在 dubbo REST 中正常输出中文字符,和通常的 Java web 应用一样,我们需要将 HTTP 响应的 contentType 设置为 UTF-8编码。 + +基于 JAX-RS 的标准用法,我们只需要做如下 annotation 配置即可: + +```java +@Produces({"application/json; charset=UTF-8", "text/xml; charset=UTF-8"}) +User getUser(@PathParam("id") Long id); +``` + +为了方便用户,我们在 dubbo REST 中直接添加了一个支持类,来定义以上的常量,可以直接使用,减少出错的可能性。 + +```java +@Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8}) +User getUser(@PathParam("id") Long id); +``` + +### XML 数据格式 + +由于 JAX-RS 的实现一般都用标准的 JAXB(Java API for XML Binding)来序列化和反序列化 XML 格式数据,所以我们需要为每一个要用 XML 传输的对象添加一个类级别的 JAXB annotation,否则序列化将报错。例如为 getUser() 中返回的 User 添加如下 + +```java +@XmlRootElement +public class User implements Serializable { + // ... +} +``` + +此外,如果service方法中的返回值是Java的 primitive类型(如int,long,float,double等),最好为它们添加一层wrapper对象,因为JAXB不能直接序列化primitive类型。 + +例如,我们想让前述的registerUser()方法返回服务器端为用户生成的ID号: + +```java +long registerUser(User user); +``` + +由于 primitive 类型不被 JAXB 序列化支持,所以添加一个 wrapper 对象: + +```java +@XmlRootElement +public class RegistrationResult implements Serializable { + + private Long id; + + public RegistrationResult() { + } + + public RegistrationResult(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} +``` + +并修改 service 方法: + +```java +RegistrationResult registerUser(User user); +``` + +这样不但能够解决 XML 序列化的问题,而且使得返回的数据都符合 XML 和 JSON 的规范。例如,在 JSON中,返回的将是如下形式 + +```javascript +{"id": 1001} +``` + +如果不加 wrapper,JSON 返回值将直接是 + +``` +1001 +``` + +而在 XML 中,加 wrapper 后返回值将是: + +```xml + + 1002 + +``` + +这种 wrapper 对象其实利用所谓 Data Transfer Object(DTO)模式,采用 DTO 还能对传输数据做更多有用的定制。 + +### 定制序列化 + +如上所述,REST 的底层实现会在 service 的对象和 JSON/XML 数据格式之间自动做序列化/反序列化。但有些场景下,如果觉得这种自动转换不满足要求,可以对其做定制。 + +Dubbo 中的 REST 实现是用 JAXB 做 XML 序列化,用 Jackson 做 JSON 序列化,所以在对象上添加 JAXB 或 Jackson 的 annotation 即可以定制映射。 + +例如,定制对象属性映射到 XML 元素的名字: + +```java +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class User implements Serializable { + + @XmlElement(name="username") + private String name; +} +``` + +定制对象属性映射到 JSON 字段的名字: + +```java +public class User implements Serializable { + + @JsonProperty("username") + private String name; +} +``` + +更多资料请参考 JAXB 和 Jackson 的官方文档,或自行 google。 + +### REST Server 的实现 + +目前在 dubbo 中,我们支持5种嵌入式 rest server 的实现,并同时支持采用外部应用服务器来做 rest server 的实现。rest server 可以通过如下配置实现: + +```xml + +``` + +以上配置选用了嵌入式的 jetty 来做 rest server,同时,如果不配置 server 属性,rest 协议默认也是选用 jetty。jetty 是非常成熟的 java servlet 容器,并和 dubbo 已经有较好的集成(目前5种嵌入式 server 中只有 jetty 和后面所述的 tomcat、tjws,与 dubbo 监控系统等完成了无缝的集成),所以,如果你的 dubbo 系统是单独启动的进程,你可以直接默认采用 jetty 即可。 + + +```xml + +``` + +以上配置选用了嵌入式的 tomcat 来做 rest server。在嵌入式 tomcat 上,REST 的性能比 jetty 上要好得多(参见后面的基准测试),建议在需要高性能的场景下采用 tomcat。 + +```xml + +``` + +以上配置选用嵌入式的 netty 来做 rest server。(TODO more contents to add) + +```xml + (tjws is now deprecated) + +``` + +以上配置选用嵌入式的 tjws 或 Sun HTTP server 来做 rest server。这两个 server 实现非常轻量级,非常方便在集成测试中快速启动使用,当然也可以在负荷不高的生产环境中使用。 注:tjws目前已经被deprecated掉了,因为它不能很好的和servlet 3.1 API工作。 + +如果你的 dubbo 系统不是单独启动的进程,而是部署到了 Java 应用服务器中,则建议你采用以下配置 + +```xml + +``` + +通过将 server 设置为 servlet,dubbo 将采用外部应用服务器的 servlet 容器来做 rest server。同时,还要在 dubbo 系统的 web.xml 中添加如下配置 + +```xml + + + contextConfigLocation + /WEB-INF/classes/META-INF/spring/dubbo-demo-provider.xml + + + + org.apache.dubbo.remoting.http.servlet.BootstrapListener + + + + org.springframework.web.context.ContextLoaderListener + + + + dispatcher + org.apache.dubbo.remoting.http.servlet.DispatcherServlet + 1 + + + + dispatcher + /* + + +``` + +即必须将 dubbo 的 BootstrapListener 和 DispatherServlet 添加到 web.xml,以完成 dubbo 的 REST 功能与外部 servlet 容器的集成。 + +> 注意:如果你是用 spring 的 ContextLoaderListener 来加载 spring,则必须保证 BootstrapListener 配置在 ContextLoaderListener 之前,否则 dubbo 初始化会出错。 + +其实,这种场景下你依然可以坚持用嵌入式 server,但外部应用服务器的 servlet 容器往往比嵌入式 server 更加强大(特别是如果你是部署到更健壮更可伸缩的 WebLogic,WebSphere 等),另外有时也便于在应用服务器做统一管理、监控等等。 + +### 获取 Context 信息 + +在远程调用中,值得获取的上下文信息可能有很多种,这里特别以获取客户端 IP 为例。 + +在 dubbo 的 REST 中,我们有两种方式获取客户端 IP。 + +第一种方式,用 JAX-RS 标准的 @Context annotation + +```java +public User getUser(@PathParam("id") Long id, @Context HttpServletRequest request) { + System.out.println("Client address is " + request.getRemoteAddr()); +} +``` + +用 Context 修饰 getUser() 的一个方法参数后,就可以将当前的 HttpServletRequest 注入进来,然后直接调用 servlet api 获取 IP。 + +> 注意:这种方式只能在将server设置为 tjws、tomcat、jetty 或者 servlet 的时候才能工作,因为只有这几种 server 的实现才提供了 servlet 容器。另外,标准的JAX-RS还支持用@Context修饰service类的一个实例字段来获取HttpServletRequest,但在dubbo中我们没有对此作出支持。 + +第二种方式,用 dubbo 中常用的 RpcContext + +```java +public User getUser(@PathParam("id") Long id) { + System.out.println("Client address is " + RpcContext.getContext().getRemoteAddressString()); +} +``` + +> 注意:这种方式只能在设置 server="jetty" 或者 server="tomcat" 或者 server="servlet" 或者 server="tjws" 的时候才能工作。另外,目前 dubbo 的 RpcContext 是一种比较有侵入性的用法,未来我们很可能会做出重构。 + +如果你想保持你的项目对 JAX-RS 的兼容性,未来脱离 dubbo 也可以运行,请选择第一种方式。如果你想要更优雅的服务接口定义,请选用第二种方式。 + +此外,在最新的 dubbo rest 中,还支持通过 RpcContext 来获取 HttpServletRequest和 HttpServletResponse,以提供更大的灵活性来方便用户实现某些复杂功能,比如在 dubbo 标准的 filter 中访问 HTTP Header。用法示例如下 + +```java +if (RpcContext.getContext().getRequest() != null && RpcContext.getContext().getRequest() instanceof HttpServletRequest) { + System.out.println("Client address is " + ((HttpServletRequest) RpcContext.getContext().getRequest()).getRemoteAddr()); +} + +if (RpcContext.getContext().getResponse() != null && RpcContext.getContext().getResponse() instanceof HttpServletResponse) { + System.out.println("Response object from RpcContext: " + RpcContext.getContext().getResponse()); +} +``` + +> 注意:为了保持协议的中立性,RpcContext.getRequest()和RpcContext.getResponse()返回的仅仅是一个Object类,而且可能为null。所以,你必须自己做null和类型的检查。 + +> 注意:只有在设置server="jetty"或者server="tomcat"或者server="servlet"的时候,你才能通过以上方法正确的得到HttpServletRequest和HttpServletResponse,因为只有这几种server实现了servlet容器。 + +为了简化编程,在此你也可以用泛型的方式来直接获取特定类型的 request/response: + +```java +if (RpcContext.getContext().getRequest(HttpServletRequest.class) != null) { + System.out.println("Client address is " + RpcContext.getContext().getRequest(HttpServletRequest.class).getRemoteAddr()); +} + +if (RpcContext.getContext().getResponse(HttpServletResponse.class) != null) { + System.out.println("Response object from RpcContext: " + RpcContext.getContext().getResponse(HttpServletResponse.class)); +} +``` + +如果 request/response 不符合指定的类型,这里也会返回 null。 + +### 端口号和 Context Path + +dubbo 中的 rest 协议默认将采用80端口,如果想修改端口,直接配置: + +```xml + +``` + +另外,如前所述,我们可以用 @Path 来配置单个 rest 服务的 URL 相对路径。但其实,我们还可以设置一个所有 rest 服务都适用的基础相对路径,即 java web 应用中常说的 context path。 + +只需要添加如下 contextpath 属性即可: + +```xml + +``` + +以前面代码为例: + +```java +@Path("users") +public class UserServiceImpl implements UserService { + + @POST + @Path("register") + @Consumes({MediaType.APPLICATION_JSON}) + public void registerUser(User user) { + // save the user... + } +} +``` + +现在 registerUser() 的完整访问路径 + +``` +http://localhost:8888/services/users/register +``` + +注意:如果你是选用外部应用服务器做 rest server,即配置 + +```xml + +``` + +则必须保证这里设置的 port、contextpath,与外部应用服务器的端口、DispatcherServlet 的上下文路径(即 webapp path 加上 servlet url pattern)保持一致。例如,对于部署为 tomcat ROOT 路径的应用,这里的 contextpath 必须与 web.xml 中 DispacherServlet 的`` 完全一致: + +```xml + + dispatcher + /services/* + +``` + +### 线程数和 IO 线程数 + +可以为 rest 服务配置线程池大小 + +```xml + +``` + +> 注意:目前线程池的设置只有当server="netty"或者server="jetty"或者server="tomcat"的时候才能生效。另外,如果server="servlet",由于这时候启用的是外部应用服务器做rest server,不受dubbo控制,所以这里的线程池设置也无效。 + +如果是选用 netty server,还可以配置 Netty 的 IO worker 线程数 + +```xml + +``` + +### 配置长连接 + +Dubbo 中的 rest 服务默认都是采用 http 长连接来访问,如果想切换为短连接,直接配置 + +```xml + +``` + +> 注意:这个配置目前只对 server="netty"和server="tomcat" 才能生效。 + +### 最大 HTTP 连接数 + +可以配置服务器提供端所能同时接收的最大 HTTP 连接数,防止 REST server 被过多连接撑爆,以作为一种最基本的自我保护机制 + +```xml + +``` + +当然,由于这个配置针对消费端生效的,所以也可以在消费端配置 + +```xml + +``` + +但是,通常我们建议配置在服务提供端提供此类配置。按照 dubbo 官方文档的说法:“Provider 上尽量多配置 Consumer 端的属性,让 Provider 实现者一开始就思考 Provider 服务特点、服务质量的问题。” + +> 注意:如果 dubbo 的 REST 服务是发布给非 dubbo 的客户端使用,则这里 `` 上的配置完全无效,因为这种客户端不受 dubbo 控制。 + + +### Annotation 取代部分 Spring XML 配置 + +以上所有的讨论都是基于 dubbo 在 spring 中的 xml 配置。但是,dubbo/spring 本身也支持用 annotation 来作配置,所以我们也可以按dubbo官方文档中的步骤,把相关 annotation 加到 REST 服务的实现中,取代一些 xml 配置,例如 + +```java +@Service(protocol = "rest") +@Path("users") +public class UserServiceImpl implements UserService { + + @Autowired + private UserRepository userRepository; + + @POST + @Path("register") + @Consumes({MediaType.APPLICATION_JSON}) + public void registerUser(User user) { + // save the user + userRepository.save(user); + } +} +``` + +annotation 的配置更简单更精确,通常也更便于维护(当然现代IDE都可以在xml中支持比如类名重构,所以就这里的特定用例而言,xml 的维护性也很好)。而 xml 对代码的侵入性更小一些,尤其有利于动态修改配置,特别是比如你要针对单个服务配置连接超时时间、每客户端最大连接数、集群策略、权重等等。另外,特别对复杂应用或者模块来说,xml 提供了一个中心点来涵盖的所有组件和配置,更一目了然,一般更便于项目长时期的维护。 + +当然,选择哪种配置方式没有绝对的优劣,和个人的偏好也不无关系。 + +### 添加自定义的 Filter、Interceptor + +Dubbo 的 REST 也支持 JAX-RS 标准的 Filter 和 Interceptor,以方便对 REST 的请求与响应过程做定制化的拦截处理。 + +其中,Filter 主要用于访问和设置 HTTP 请求和响应的参数、URI 等等。例如,设置 HTTP 响应的 cache header: + +```java +public class CacheControlFilter implements ContainerResponseFilter { + + public void filter(ContainerRequestContext req, ContainerResponseContext res) { + if (req.getMethod().equals("GET")) { + res.getHeaders().add("Cache-Control", "someValue"); + } + } +} +``` + +Interceptor 主要用于访问和修改输入与输出字节流,例如,手动添加 GZIP 压缩 + +```java +public class GZIPWriterInterceptor implements WriterInterceptor { + + @Override + public void aroundWriteTo(WriterInterceptorContext context) + throws IOException, WebApplicationException { + OutputStream outputStream = context.getOutputStream(); + context.setOutputStream(new GZIPOutputStream(outputStream)); + context.proceed(); + } +} +``` + +在标准 JAX-RS 应用中,我们一般是为 Filter 和 Interceptor 添加 @Provider annotation,然后 JAX-RS runtime 会自动发现并启用它们。而在 dubbo 中,我们是通过添加XML配置的方式来注册 Filter 和 Interceptor: + +```xml + +``` + +在此,我们可以将 Filter、Interceptor 和 DynamicFeature 这三种类型的对象都添加到 `extension` 属性上,多个之间用逗号分隔。(DynamicFeature 是另一个接口,可以方便我们更动态的启用 Filter 和 Interceptor,感兴趣请自行 google。) + +当然,dubbo 自身也支持 Filter 的概念,但我们这里讨论的 Filter 和 Interceptor 更加接近协议实现的底层,相比 dubbo 的 filter,可以做更底层的定制化。 + +> 注:这里的 XML 属性叫 extension,而不是叫 interceptor 或者 filter,是因为除了 Interceptor 和 Filter,未来我们还会添加更多的扩展类型。 + +如果 REST 的消费端也是 dubbo 系统(参见下文的讨论),则也可以用类似方式为消费端配置 Interceptor 和 Filter。但注意,JAX-RS 中消费端的 Filter 和提供端的 Filter 是两种不同的接口。例如前面例子中服务端是 ContainerResponseFilter 接口,而消费端对应的是 ClientResponseFilter: + +```java +public class LoggingFilter implements ClientResponseFilter { + + public void filter(ClientRequestContext reqCtx, ClientResponseContext resCtx) throws IOException { + System.out.println("status: " + resCtx.getStatus()); + System.out.println("date: " + resCtx.getDate()); + System.out.println("last-modified: " + resCtx.getLastModified()); + System.out.println("location: " + resCtx.getLocation()); + System.out.println("headers:"); + for (Entry> header : resCtx.getHeaders().entrySet()) { + System.out.print("\t" + header.getKey() + " :"); + for (String value : header.getValue()) { + System.out.print(value + ", "); + } + System.out.print("\n"); + } + System.out.println("media-type: " + resCtx.getMediaType().getType()); + } +} +``` + +### 添加自定义的 Exception 处理 + +Dubbo 的 REST 也支持 JAX-RS 标准的 ExceptionMapper,可以用来定制特定 exception 发生后应该返回的 HTTP 响应。 + +```java +public class CustomExceptionMapper implements ExceptionMapper { + + public Response toResponse(NotFoundException e) { + return Response.status(Response.Status.NOT_FOUND).entity("Oops! the requested resource is not found!").type("text/plain").build(); + } +} +``` + +和 Interceptor、Filter 类似,将其添加到 XML 配置文件中即可启用 + +```xml + +``` + +### HTTP 日志输出 + +Dubbo rest 支持输出所有 HTTP 请求/响应中的 header 字段和 body 消息体。 + +在 XML 配置中添加如下自带的 REST filter: + +```xml + +``` + +然后配置在 logging 配置中至少为 org.apache.dubbo.rpc.protocol.rest.support 打开 INFO 级别日志输出,例如,在 log4j.xml 中配置 + +```xml + + + + +``` + +当然,你也可以直接在 ROOT logger 打开 INFO 级别日志输出 + +```xml + + + + +``` + +然后在日志中会有类似如下的内容输出 + +``` +The HTTP headers are: +accept: application/json;charset=UTF-8 +accept-encoding: gzip, deflate +connection: Keep-Alive +content-length: 22 +content-type: application/json +host: 192.168.1.100:8888 +user-agent: Apache-HttpClient/4.2.1 (java 1.5) +``` + +``` +The contents of request body is: +{"id":1,"name":"dang"} +``` + +打开 HTTP 日志输出后,除了正常日志输出的性能开销外,也会在比如 HTTP 请求解析时产生额外的开销,因为需要建立额外的内存缓冲区来为日志的输出做数据准备。 + +### 输入参数的校验 + +dubbo 的 rest 支持采用 Java 标准的 bean validation annotation(JSR 303) 来做输入校验 http://beanvalidation.org/ + +为了和其他 dubbo 远程调用协议保持一致,在 rest 中作校验的 annotation 必须放在服务的接口上,例如 + +```java +public interface UserService { + + User getUser(@Min(value=1L, message="User ID must be greater than 1") Long id); +} + +``` + +当然,在很多其他的 bean validation 的应用场景都是将 annotation 放到实现类而不是接口上。把 annotation 放在接口上至少有一个好处是,dubbo 的客户端可以共享这个接口的信息,dubbo 甚至不需要做远程调用,在本地就可以完成输入校验。 + +然后按照 dubbo 的标准方式在 XML 配置中打开验证: + +```xml + +``` + +在 dubbo 的其他很多远程调用协议中,如果输入验证出错,是直接将 `RpcException` 抛向客户端,而在 rest 中由于客户端经常是非 dubbo,甚至非 java 的系统,所以不便直接抛出 Java 异常。因此,目前我们将校验错误以 XML 的格式返回 + +```xml + + + getUserArgument0 + User ID must be greater than 1 + 0 + + +``` + +稍后也会支持其他数据格式的返回值。至于如何对验证错误消息作国际化处理,直接参考 bean validation 的相关文档即可。 + +如果你认为默认的校验错误返回格式不符合你的要求,可以如上面章节所述,添加自定义的 ExceptionMapper 来自由的定制错误返回格式。需要注意的是,这个 ExceptionMapper 必须用泛型声明来捕获 dubbo 的 RpcException,才能成功覆盖 dubbo rest 默认的异常处理策略。为了简化操作,其实这里最简单的方式是直接继承 dubbo rest 的 RpcExceptionMapper,并覆盖其中处理校验异常的方法即可 + +```java +public class MyValidationExceptionMapper extends RpcExceptionMapper { + + protected Response handleConstraintViolationException(ConstraintViolationException cve) { + ViolationReport report = new ViolationReport(); + for (ConstraintViolation cv : cve.getConstraintViolations()) { + report.addConstraintViolation(new RestConstraintViolation( + cv.getPropertyPath().toString(), + cv.getMessage(), + cv.getInvalidValue() == null ? "null" : cv.getInvalidValue().toString())); + } + // 采用json输出代替xml输出 + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(report).type(ContentType.APPLICATION_JSON_UTF_8).build(); + } +} +``` + +然后将这个 ExceptionMapper 添加到 XML 配置中即可: + +```xml + +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual.md new file mode 100644 index 000000000000..db1bca0760a2 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual.md @@ -0,0 +1,969 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/rest/manual/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/rest/manual/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/rest/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/http/ +description: "本文是Triple Rest的用户使用手册" +linkTitle: triple-rest用户手册 +title: Triple Rest 用户手册 +type: docs +weight: 7 +--- + +{{% alert title="注意" color="warning" %}} +从 Dubbo 3.3 版本开始,原 Rest 协议已移至 Extensions 库,由 Triple 协议来对 Rest 提供更全面的支持,如需继续使用原 Rest 协议, +可引入对应 [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) 库依赖 +{{% /alert %}} + +## 前言 + +从 Dubbo 3.3 版本开始,Triple 协议重用已有的 HTTP 协议栈,实现了全面的 REST 风格服务导出能力。无需使用泛化或网关层协议转换,无需配置,用户即可通过 HTTP 协议去中心化直接访问后端的 Triple +协议服务。同时,针对高级 REST 用法,如路径定制、输出格式定制和异常处理,提供了丰富的注解和 +SPI 扩展支持。其主要特性包括: + +- **Triple协议融合** + 重用Triple原有HTTP协议栈, 无需额外配置或新增端口,即可同时支持 HTTP/1、HTTP/2 和 HTTP/3 协议的访问。 +- **去中心化** + 可直接对外暴露 Rest API,不再依赖网关应用进行流量转发,从而提升性能,并降低因网关引发的稳定性风险。安全问题可通过应用内部扩展解决,这一实践已在淘宝内部的 MTOP 中得到验证。 +- **支持已有servlet设施** + 支持 Servlet API 和 Filter,用户可以重用现有基于 Servlet API 的安全组件。通过实现一个 Servlet Filter,即可集成 OAuth 和 Spring Security 等安全框架。 +- **多种方言** + 考虑到大部分用户习惯使用 SpringMVC 或 JAX-RS 进行 REST API 开发,Triple Rest 允许继续沿用这些方式定义服务,并支持大部分扩展和异常处理机制(具备原框架 80% 以上的功能)。对于追求轻量级的用户,可使用 + Basic 方言,Triple 的开箱即用 + REST 访问能力即基于此方言导出服务。 +- **扩展能力强** + 提供超过 20 个 扩展点,用户不仅可以轻松实现自定义方言,还能灵活定制参数获取、类型转换、错误处理等逻辑。 +- **开箱即用** + REST 能力开箱即用,只需启用 Triple 协议,即具备 REST 直接访问服务能力。 +- **高性能路由** + 路由部分采用优化的 [Radix Tree](https://github.com/apache/dubbo/blob/3.3/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java) 和 + Zero Copy 技术,提升路由性能。 +- **OpenAPI无缝集成(TBD)** + 即将完成 OpenAPI 集成,开箱即用支持导出 OpenAPI Schema, 引入 Swagger 依赖可直接使用 Web UI 来进行服务测试。有了 OpenAPI Schema + 可使用 [Postman](https://www.postman.com/)、[Apifox](https://apifox.com/) 等API工具来管理和测试 + API,利用 OpenAPI 生态可轻松实现跨语言调用。未来会进一步支持 Schema First 的方式,先和前端团队一起定义 OpenAPI, 前端基于 OpenAPI 来生成调用代码和 Mock,后端基于 OpenAPI 来生成 Stub + 来开发服务,极大提升协同效率。 + + +## 快速开始 + +让我们从一个简单的例子开始了解 Triple Rest。您可以直接下载已有的示例项目以快速上手,假设您已经安装好 Java、Maven 和 Git + + +### 下载并运行示例 + +```bash +# 获取示例代码 +git clone --depth=1 https://github.com/apache/dubbo-samples.git +cd dubbo-samples/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-basic +# 直接运行 +mvn spring-boot:run +# 或打包后运行 +mvn clean package -DskipTests +java -jar target/dubbo-samples-triple-rest-basic-1.0.0-SNAPSHOT.jar +``` + +当然,也可以直接用IDE导入工程后直接执行 +`org.apache.dubbo.rest.demo.BasicRestApplication#main` 来运行,并通过下断点 debug 的方式来深入理解原理。 + + +### 示例代码 + +```java +// 服务接口 +package org.apache.dubbo.rest.demo; + +import org.apache.dubbo.remoting.http12.rest.Mapping; +import org.apache.dubbo.remoting.http12.rest.Param; + +public interface DemoService { + String hello(String name); + + @Mapping(path = "/hi", method = HttpMethods.POST) + String hello(User user, @Param(value = "c", type = ParamType.Header) int count); +} + +// 服务实现 +@DubboService +public class DemoServiceImpl implements DemoService { + @Override + public String hello(String name) { + return "Hello " + name; + } + + @Override + public String hello(User user, int count) { + return "Hello " + user.getTitle() + ". " + user.getName() + ", " + count; + } +} + +// 模型 +@Data +public class User { + private String title; + private String name; +} +``` + + + +### 测试基本服务 + +```bash +curl -v "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hello?name=world" +# 输出如下 +#> GET /org.apache.dubbo.rest.demo.DemoService/hello?name=world HTTP/1.1 +#> Host: 127.0.0.1:8081 +#> User-Agent: curl/8.7.1 +#> Accept: */* +#> +#* Request completely sent off +#< HTTP/1.1 200 OK +#< content-type: application/json +#< alt-svc: h2=":8081" +#< content-length: 13 +#< +#"Hello world" +``` + +代码讲解:
可以看到输出了 "Hello world" ,有双引号是因为默认输出 content-type 为 application/json
通过这个例子可以了解 Triple 默认将服务导出到 +`/{serviceInterface}/{methodName}`路径,并支持通过url方式传递参数 + + +### 测试高级服务 + +```bash +curl -v -H "c: 3" -d 'name=Yang' "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr" +# 输出如下 +#> POST /org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr HTTP/1.1 +#> Host: 127.0.0.1:8081 +#> User-Agent: curl/8.7.1 +#> Accept: */* +#> c: 3 +#> Content-Length: 9 +#> Content-Type: application/x-www-form-urlencoded +#> +#* upload completely sent off: 9 bytes +#< HTTP/1.1 200 OK +#< content-type: text/plain +#< alt-svc: h2=":8081" +#< content-length: 17 +#< +#Hello Mr. Yang, 3 +``` + +代码讲解:
可以看到输出 Hello Mr. Yang, 3 ,没有双引号是因为通过指定后缀 txt 的方式要求用 `text/plain` 输出
通过这个例子可以了解如何通过 Mapping 注解来定制路径,通过 Param +注解来定制参数来源,并支持通过 post body 或 +url方式传递参数,详细说明参见: [Basic使用指南](#GdlnC) + + +### 观察日志 + +可以通过打开 debug 日志的方式来了解rest的启动和响应请求过程 + +```yaml +logging: + level: + "org.apache.dubbo.rpc.protocol.tri": debug + "org.apache.dubbo.remoting": debug +``` + +打开后可以观察到 Rest 映射注册和请求响应过程 + +``` +# 注册mapping +DEBUG o.a.d.r.p.t.TripleProtocol : [DUBBO] Register triple grpc mapping: 'org.apache.dubbo.rest.demo.DemoService' -> invoker[tri://192.168.2.216:8081/org.apache.dubbo.rest.demo.DemoService] + INFO .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] BasicRequestMappingResolver resolving rest mappings for ServiceMeta{interface=org.apache.dubbo.rest.demo.DemoService, service=DemoServiceImpl@2a8f6e6} at url [tri://192.168.2.216:8081/org.apache.dubbo.rest.demo.DemoService] +DEBUG .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Register rest mapping: '/org.apache.dubbo.rest.demo.DemoService/hi' -> mapping=RequestMapping{name='DemoServiceImpl#hello', path=PathCondition{paths=[org.apache.dubbo.rest.demo.DemoService/hi]}, methods=MethodsCondition{methods=[POST]}}, method=MethodMeta{method=org.apache.dubbo.rest.demo.DemoService.hello(User, int), service=DemoServiceImpl@2a8f6e6} +DEBUG .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Register rest mapping: '/org.apache.dubbo.rest.demo.DemoService/hello' -> mapping=RequestMapping{name='DemoServiceImpl#hello~S', path=PathCondition{paths=[org.apache.dubbo.rest.demo.DemoService/hello]}}, method=MethodMeta{method=org.apache.dubbo.rest.demo.DemoService.hello(String), service=DemoServiceImpl@2a8f6e6} + INFO .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Registered 2 REST mappings for service [DemoServiceImpl@44627686] at url [tri://192.168.2.216:8081/org.apache.dubbo.rest.demo.DemoService] in 11ms + +# 请求响应 +DEBUG .a.d.r.p.t.r.m.RestRequestHandlerMapping : [DUBBO] Received http request: DefaultHttpRequest{method='POST', uri='/org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr', contentType='application/x-www-form-urlencoded'} +DEBUG .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Matched rest mapping=RequestMapping{name='DemoServiceImpl#hello', path=PathCondition{paths=[/org.apache.dubbo.rest.demo.DemoService/hi]}, methods=MethodsCondition{methods=[POST]}}, method=MethodMeta{method=org.apache.dubbo.rest.demo.DemoService.hello(User, int), service=DemoServiceImpl@2a8f6e6} +DEBUG .a.d.r.p.t.r.m.RestRequestHandlerMapping : [DUBBO] Content-type negotiate result: request='application/x-www-form-urlencoded', response='text/plain' +DEBUG .d.r.h.AbstractServerHttpChannelObserver : [DUBBO] Http response body is: '"Hello Mr. Yang, 3"' +DEBUG .d.r.h.AbstractServerHttpChannelObserver : [DUBBO] Http response headers sent: {:status=[200], content-type=[text/plain], alt-svc=[h2=":8081"], content-length=[17]} +``` + + + +## 通用功能 + + + +### 路径映射 + +兼容 SpringMVC 和 JAX-RS 的映射方式,相关文档: + +- [Spring Mapping Requests](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-uri-templates) +- [Spring PathPattern](https://docs.spring.io/spring-framework/docs/6.1.12/javadoc-api/org/springframework/web/util/pattern/PathPattern.html) +- [Spring AntPathMatcher](https://docs.spring.io/spring-framework/docs/6.1.12/javadoc-api/org/springframework/util/AntPathMatcher.html) +- [JAX-RS Path and regular expression mappings](https://docs.jboss.org/resteasy/docs/6.2.7.Final/userguide/html/ch04.html) + +还支持通过实现 SPI `org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver` 来自定义路径映射 + + +#### 支持的模式 + +1. `books` 字符串常量,最基本的类型,匹配一个固定的段 +2. `?` 匹配一个字符 +3. `*` 匹配路径段中的零个或多个字符 +4. `**` 匹配直到路径末尾的零个或多个路径段 +5. `{spring}` 匹配一个路径段并将其捕获为名为 "spring" 的变量 +6. `{spring:[a-z]+}` 使用正则表达式 `[a-z]+` 匹配路径段,并将其捕获为名为 "spring" 的路径变量 +7. `{*spring}` 匹配直到路径末尾的零个或多个路径段,并将其捕获为名为 "spring" 的变量,如果写 `{*}` 表示不捕获 + + +#### 示例(来自Spring文档) + +- `/pages/t?st.html` — 匹配 `/pages/test.html` 以及 `/pages/tXst.html`,但不匹配 `/pages/toast.html` +- `/resources/*.png` — 匹配 `resources` 目录中的所有 `.png` 文件 +- `com/**/test.jsp` — 匹配 `com` 路径下的所有 `test.jsp` 文件 +- `org/springframework/**/*.jsp` — 匹配 `org/springframework` 路径下的所有 `.jsp` 文件 +- `/resources/**` — 匹配 `/resources/` 路径下的所有文件,包括 `/resources/image.png` 和 `/resources/css/spring.css` +- `/resources/{*path}` — 匹配 `/resources/` 下的所有文件,以及 `/resources`,并将其相对路径捕获在名为 "path" 的变量中;例如, + `/resources/image.png` 会匹配到 "path" → "/image.png",`/resources/css/spring.css` 会匹配到 "path" → "/css/spring.css" +- `/resources/{filename:\\w+}.dat` — 匹配 `/resources/spring.dat` 并将值 "spring" 分配给 `filename` 变量 +- `/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}` — 匹配 `/example-2.1.5.html` 则 `name` 为 `example`, + `version` 为 `2.1.5`,`ext` 为 `.html` + +小技巧如果使用正则不希望跨段可以使用 `{name:[^/]+}` 来匹配 + + +#### 映射匹配完整流程 + +具体的匹配处理代码:[DefaultRequestMappingRegistry.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java#L196) [RequestMapping.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java#L127) + +1. 使用 `PathUtils.normalize` 对路径进行清洗,去掉诸如 `/one/../` `/one/./` 之类间接路径,保证一定已 `/` 开头 +2. 检查 `http method` 是否匹配 +3. 检查 `path` 是否匹配 +4. 检查 `paramter` 是否匹配(JAX-RS不支持) +5. 检查 `header` 是否匹配 +6. 检查 `content-type` 是否匹配(Consumes) +7. 检查 `accept` 是否匹配 (Produces) +8. 检查 `serviceGroup` 和 `serviceVersion` 是否匹配 +9. 检查 `method` 首字母签名是否匹配 +10. 未找到任何匹配项,如果尾 `/` 匹配开启并且路径 `/` 结尾则去掉尾 `/` 尝试从第2步开始匹配 +11. 未找到任何匹配项,如果扩展名匹配开启并且扩展名被支持,则去掉扩展名尝试从第2步开始匹配 +12. 如果最后一段路径包含 `~` 表示开启 method 首字母签名匹配,尝试从第2步开始匹配 +13. 如果候选项为0,匹配结束,返回null +14. 如果候选项为0,匹配结束,返回命中项 +15. 如果不止一个候选项,对候选项进行排序 +16. 对第一项和第二项进行顺序比较 +17. 结果为0表示无法确认最终匹配项,抛异常失败 +18. 第一项胜出,匹配结束,返回命中项 + + +#### 路径重复问题 + +与 Spring 不同,Spring 在路径完全相同时会直接报错并阻止启动,而 Triple Rest 具备开箱即用的特性,为了避免影响现有服务,默认只会打印 WARN 日志。在运行时,如果最终无法确定最高优先级的映射,才会抛出错误。 + + +### 入参类型 + +不同方言支持的入参类型不同,详情请参见各方言使用指南。
还支持通过实现 SPI +`org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver` 来自定义入参解析 + + +#### 通用类型参数 + +| 名称 | 说明 | Basic 注解 | SpringMVC注解 | JAX-RS注解 | 数组或集合处理方式 | Map处理方式 | +|----------------|---------------|-----------------------------|-------------------|--------------|----------------|-----------------| +| Param | Query或Form的参数 | @Param | @RequestParam | - | 多值 | 所有参数的Map | +| Query | url上带的参数 | - | - | @QueryParam | 多值 | 所有Query参数的Map | +| Form | form表单带的参数 | - | - | @FormParam | 多值 | 所有Form参数的Map | +| Header | HTTP头 | @Param(type=Header) | @RequestHeader | @HeaderParam | 多值 | 所有Header参数的Map | +| Cookie | Cookie值 | @Param(type=Cookie) | @CookieValue | @CookieParam | 多值 | 所有Cookie参数的Map | +| Attribute | Request属性 | @Param(type=Attribute) | @RequestAttribute | - | 多值 | 所有Attribute的Map | +| Part | Multipart文件 | @Param(type=Part) | @RequestHeader | @HeaderParam | 多值 | 所有Part的Map | +| Body | 请求body | @Param(type=Body) | @RequestBody | @Body | 尝试解析为数组或集合 | 尝试解析为目标类型 | +| PathVariable | path变量 | @Param(type=PathVariable) | @PathVariable | @PathParam | 单值数组或集合 | 单值Map | +| MatrixVariable | matrix变量 | @Param(type=MatrixVariable) | @MatrixVariable | @MatrixParam | 多值 | 单值Map | +| Bean | java bean | 无需注解 | @ModelAttribute | @BeanParam | 尝试解析为Bean数组或集合 | - | + + + +#### 特殊类型参数 + +| 类型 | 说明 | 激活条件 | +|-----------------------------------------------|---------------------------|-------------------| +| org.apache.dubbo.remoting.http12.HttpRequest | HttpRequest对象 | 默认激活 | +| org.apache.dubbo.remoting.http12.HttpResponse | HttpResponse对象 | 默认激活 | +| org.apache.dubbo.remoting.http12.HttpMethods | 请求Http方法 | 默认激活 | +| java.util.Locale | 请求Locale | 默认激活 | +| java.io.InputStream | 请求输入流 | 默认激活 | +| java.io.OutputStream | 响应输出流 | 默认激活 | +| javax.servlet.http.HttpServletRequest | Servlet HttpRequest对象 | 引入Servlet API jar | +| javax.servlet.http.HttpServletResponse | Servlet HttpResponse对象 | 同上 | +| javax.servlet.http.HttpSession | Servlet HttpSession对象 | 同上 | +| javax.servlet.http.Cookie | Servlet Cookie对象 | 同上 | +| java.io.Reader | Servlet Request Reader对象 | 同上 | +| java.io.Writer | Servlet Response Writer对象 | 同上 | + + + +#### 无注解参数 + +不同方言处理方式不同,请参见各方言使用说明 + + +#### 无入参方式获取 HTTP 输入输出参数 + +可通过 `RpcContext` 来获取 + +```java +// Dubbo http req/resp +HttpRequest request = RpcContext.getServiceContext().getRequest(HttpRequest.class); +HttpResponse response = RpcContext.getServiceContext().getRequest(HttpResponse.class); +// Servlet http req/resp +HttpServletRequest request = RpcContext.getServiceContext().getRequest(HttpServletRequest.class); +HttpServletResponse response = RpcContext.getServiceContext().getRequest(HttpServletResponse.class); +``` + +拿到request之后,通过 attribute +可以访问一些内置属性,参见:[RestConstants.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestConstants.java#L40) + + +### 参数类型转换 + +默认支持大部分从 String 到目标类型的参数类型转换,主要包括以下几大类: + +- Jdk内置类型,包括基础类型和日期、Optional等 +- 数组类型 +- 集合类型 +- Map类型 + +同时也完整支持泛型类型,包括复杂嵌套,具体地实现代码参见: [GeneralTypeConverter.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/GeneralTypeConverter.java)
+还支持通过实现SPI +`org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter` 来自定义参数类型转换 + +| Source Type | Target Type | Description | Default Value | +|-------------|-------------------------|----------------------------------|---------------| +| `String` | `double` | Converts to a double | 0.0d | +| `String` | `float` | Converts to a float | 0.0f | +| `String` | `long` | Converts to a long | 0L | +| `String` | `int` | Converts to an integer | 0 | +| `String` | `short` | Converts to a short | 0 | +| `String` | `char` | Converts to a character | 0 | +| `String` | `byte` | Converts to a byte | 0 | +| `String` | `boolean` | Converts to a boolean | false | +| `String` | `BigInteger` | Converts to a BigInteger | null | +| `String` | `BigDecimal` | Converts to a BigDecimal | null | +| `String` | `Date` | Converts to a Date | null | +| `String` | `Calendar` | Converts to a Calendar | null | +| `String` | `Timestamp` | Converts to a Timestamp | null | +| `String` | `Instant` | Converts to an Instant | null | +| `String` | `ZonedDateTime` | Converts to a ZonedDateTime | null | +| `String` | `LocalDate` | Converts to a LocalDate | null | +| `String` | `LocalTime` | Converts to a LocalTime | null | +| `String` | `LocalDateTime` | Converts to a LocalDateTime | null | +| `String` | `ZoneId` | Converts to a ZoneId | null | +| `String` | `TimeZone` | Converts to a TimeZone | null | +| `String` | `File` | Converts to a File | null | +| `String` | `Path` | Converts to a Path | null | +| `String` | `Charset` | Converts to a Charset | null | +| `String` | `InetAddress` | Converts to an InetAddress | null | +| `String` | `URI` | Converts to a URI | null | +| `String` | `URL` | Converts to a URL | null | +| `String` | `UUID` | Converts to a UUID | null | +| `String` | `Locale` | Converts to a Locale | null | +| `String` | `Currency` | Converts to a Currency | null | +| `String` | `Pattern` | Converts to a Pattern | null | +| `String` | `Class` | Converts to a Class | null | +| `String` | `byte[]` | Converts to a byte array | null | +| `String` | `char[]` | Converts to a char array | null | +| `String` | `OptionalInt` | Converts to an OptionalInt | null | +| `String` | `OptionalLong` | Converts to an OptionalLong | null | +| `String` | `OptionalDouble` | Converts to an OptionalDouble | null | +| `String` | `Enum class` | Enum.valueOf | null | +| `String` | `Array` or `Collection` | Split by comma | null | +| `String` | `Specified class` | Try JSON String to Object | null | +| `String` | `Specified class` | Try construct with single String | null | +| `String` | `Specified class` | Try call static method `valueOf` | null | + + + +### 支持的Content-Type + +默认支持以下 Content-Type,提供相应的编码和解码功能。
还支持通过实现SPI +`org.apache.dubbo.remoting.http12.message.(HttpMessageDecoderFactory|HttpMessageEncoderFactory)`来扩展 + +| Media Type | Description | +|-------------------------------------|----------------------------| +| `application/json` | JSON format | +| `application/xml` | XML format | +| `application/yaml` | YAML format | +| `application/octet-stream` | Binary data | +| `application/grpc` | gRPC format | +| `application/grpc+proto` | gRPC with Protocol Buffers | +| `application/x-www-form-urlencoded` | URL-encoded form data | +| `multipart/form-data` | Form data with file upload | +| `text/json` | JSON format as text | +| `text/xml` | XML format as text | +| `text/yaml` | YAML format as text | +| `text/css` | CSS format | +| `text/javascript` | JavaScript format as text | +| `text/html` | HTML format | +| `text/plain` | Plain text | + + + +### 内容协商 + +支持完善的内容协商机制,可根据映射或输入来协商输出的 Content-Type,具体流程如下: + +1. 尝试读取 Mapping 指定的 mediaType,获取 Produces指定的 mediaType 列表,并将通配符匹配到合适的 Media Type。例如Spring的: + `@RequestMapping(produces = "application/json")` +2. 尝试通过 Accept 头查找 mediaType,解析请求的 `Accept` 头,并将通配符匹配到合适的 Media Type。例如: + `Accept: application/json` +3. 尝试通过 format 参数查找 mediaType,读取 format 参数值,做为文件后缀匹配到合适的 Media Type。例如 `/hello?format=yml` +4. 尝试通过请求路径的扩展名查找 mediaType,扩展名做为文件后缀匹配到合适的 Media Type。例如 `/hello.txt` +5. 尝试读取请求的 Content-Type 头做为 Media Type(两种form类型除外)。例如 `Content-Type: application/json` +6. 使用 `application/json` 兜底 + + +### CORS支持 + +提供完整的CORS支持,通过配置全局参数即可启用,默认行为和SpringMVC一致,同时在SpringMVC方言中,也支持通过 +`@CrossOrigin` 来做精细化配置。
支持的CORS 配置项参见:[8.4CORS配置](#NLQqj) + + +### 自定义HTTP输出 + +很多场景需要对HTTP输出进行定制,比如做302跳转,写Http头,为此 Triple Rest提供以下通用方案,同时也支持各方言的特定写法,详情参见各方言使用指南 + +- 返回值设置为: `org.apache.dubbo.remoting.http12.HttpResult` 可通过 `HttpResult#builder` 来构建 +- 抛出Payload异常: + `throws new org.apache.dubbo.remoting.http12.exception.HttpResultPayloadException(HttpResult)` 示例代码: + +```java +throw new HttpResult.found("https://a.com"). + +toPayload(); +``` + +此异常已避免填充错误栈,对性能无太大影响,并且不用考虑返回值逻辑,推荐用这个方式来定制输出 + +- 获取 HttpResponse 后自定义,实例代码: + +```java +HttpResponse response = RpcContext.getServiceContext().getRequest(HttpResponse.class); + +response. + +sendRedirect("https://a.com"); +response. + +setStatus(404); +response. + +outputStream(). + +write(data); +// 写完输出建议 commit 来避免被其他扩展改写 +response. + +commit(); +``` + +如果只是增加 `http header` 推荐用这个方式 + + +### 自定义JSON解析和输出 +支持Jackson、fastjson2、fastjson和gson等多种JSON框架,使用前请确保对应jar依赖已被引入 + +#### 指定使用的JSON框架 +```properties +dubbo.protocol.triple.rest.json-framework=jackson +``` + +#### 通过 JsonUtil SPI 定制 +可通过实现 SPI `org.apache.dubbo.common.json.JsonUtil` 方式来自定义JSON处理,具体可以参考 [org/apache/dubbo/common/json/impl](https://github.com/apache/dubbo/tree/3.3/dubbo-common/src/main/java/org/apache/dubbo/common/json/impl) 已有实现,建议继承现有实现并重写 + + +### 异常处理 + +未被处理的异常最终被转换成 `ErrorResponse` 类编码后输出: + +```java + +@Data +public class ErrorResponse { + /** + * http status code + */ + private String status; + + /** + * exception message + */ + private String message; +} +``` + +注意对于500及以上错误,为避免泄露服务端内部信息,默认只会输出 message "Internal Server Error",如果需要自定义 message 可创建继承自 +`org.apache.dubbo.remoting.http12.exception.HttpStatusException` 异常并重写 +`getDisplayMessage` 方法。
提供了以下通用方法来定制异常处理: + +- 参考 [9.2自定义异常返回结果](#zFD9A) 使用SPI 自定义全局异常处理 +- 使用 Dubbo的 Filter SPI 来加工转换异常,如果需要访问 Http 上下文,可继承 `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilterAdapter` +- 使用 SPI `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter` 来转换异常,使用上更轻量并提供路径匹配配置能力 + +注意后2项只能拦截 invoke 链中出现的异常,如果在路径匹配阶段出现异常,只有有方法1能处理 + + +## Basic使用指南 + +示例参见:[dubbo-samples-triple-rest/dubbo-samples-triple-rest-basic](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-basic) + + +### 路径映射 + +Basic做为开箱即用 Rest 映射,默认会将方法映射到: `/{contextPath}/{serviceInterface}/{methodName}` ,其中 +`/{contextPath}` 如果协议没有配置会忽略,即为:`/{serviceInterface}/{methodName}`
映射的自定义通过注解 +`org.apache.dubbo.remoting.http12.rest.Mapping` 来支持,属性说明如下: + +| 配置名 | 说明 | 默认行为 | +|------------|-------------------------------------|-------------| +| `value` | 映射的 URL 路径,可以是一个或多个路径。 | 空数组 | +| `path` | 映射的 URL 路径,与 `value` 相同,可以是一个或多个路径。 | 空数组 | +| `method` | 支持的 HTTP 方法列表,例如 `GET`、`POST` 等。 | 空数组(支持所有方法) | +| `params` | 请求必须包含的参数列表。 | 空数组 | +| `headers` | 请求必须包含的头部列表。 | 空数组 | +| `consumes` | 处理请求的内容类型(Content-Type),可以是一个或多个类型。 | 空数组 | +| `produces` | 生成响应的内容类型(Content-Type),可以是一个或多个类型。 | 空数组 | +| `enabled` | 是否启用该映射。 | `true`(启用) | + +- 属性支持用占位符方式配置:`@Mapping("${prefix}/hi")` +- 如果不希望特定服务或方法被 rest 导出,可以通过设置 `@Mapping(enabled = false)` 解决 + + +### 入参类型 + +通用入参见:[3.2入参类型](#kmCzf) + + +#### 无注解参数 + +Basic +的无注解参数由类:[FallbackArgumentResolver.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java#L41) +支持,具体处理流程如下:
![rest-arg.jpg](/imgs/v3/manual/java/protocol/rest-arg.jpg) + + +## SpringMVC使用指南 + +示例参见:[dubbo-samples-triple-rest/dubbo-samples-triple-rest-springmvc](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-springmvc) + + +### 路径映射 + +直接参考SpringMVC文档即可,支持绝大多数特性,[Mapping Requests :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-uri-templates)
+注意无需 +`@Controller` 或 `@RestController` 注解,除了 `@RequestMapping` 还支持新的 `@HttpExchange` + + +### 入参类型 + + + +#### 通用入参 + +参见:[3.2入参类型](#kmCzf) + + +#### 注解类型参数 + +参见 [3.2.1通用类型参数](#dCgzz) + + +#### 特殊类型参数 + +| 类型 | 说明 | 激活条件 | +|----------------------------------------------------------|--------------------|---------------| +| org.springframework.web.context.request.WebRequest | WebRequest对象 | 引入SpringWeb依赖 | +| org.springframework.web.context.request.NativeWebRequest | NativeWebRequest对象 | 同上 | +| org.springframework.http.HttpEntity | Http实体 | 同上 | +| org.springframework.http.HttpHeaders | Http头 | 同上 | +| org.springframework.util.MultiValueMap | 多值Map | 同上 | + + + +#### 无注解参数 + +- 如果是基本类型 ( + 根据 [TypeUtils#isSimpleProperty](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java#L105) + 判断),直接从Parameter中获取 +- 如果非基本类型,使用 [@ModelAttribute :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/modelattrib-method-args.html) + 来绑定复杂 bean 类型参数 + + +### 参数类型转换 + +优先使用 Spring 的 `org.springframework.core.convert.ConversionService` 来转换参数,如果应用为spring boot应用则默认使用 +`mvcConversionService` 否则使用 +`org.springframework.core.convert.support.DefaultConversionService#getSharedInstance` 获取共享 +`ConversionService`
如果 `ConversionService` 不支持则会回退到通用类型转换:[3.3参数类型转换](#I56vX) + + +### 异常处理 + +除了支持 [3.8异常处理](#XeDPr) 中提到的方式,还支持 Spring +`@ExceptionHandler` 注解方式,[Exceptions :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-exceptionhandler.html) +,注意通过这种方式仅能处理方法调用时抛出的异常,其他异常无法捕获 + + +### CORS配置 + +除了支持 [8.4CORS配置](#NLQqj) 全局配置,还支持 Spring +`@CrossOrigin` 来精细化配置,[CORS :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc-cors.html#mvc-cors-controller) + + +### 自定义HTTP输出 + +支持以下 Spring 自定义方式: + +1. 使用 `@ResponseStatus` 注解 +2. 返回 `org.springframework.http.ResponseEntity` 对象 + + +### 支持的扩展 + +- org.springframework.web.servlet.HandlerInterceptor
使用方式类似 [7.1使用 Filter 扩展](#xCEi3) + + +## JAX-RS使用指南 + +示例参见:[dubbo-samples-triple-rest/dubbo-samples-triple-rest-jaxrs](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-jaxrs) + + +### 路径映射 + +Service需要显式添加注解@Path,方法需要添加@GET、@POST、@HEAD等请求方法注解
+直接参考Resteasy文档即可,支持绝大多数特性,[Chapter 4. Using @Path and @GET, @POST, etc](https://docs.jboss.org/resteasy/docs/6.2.7.Final/userguide/html/ch04.html) + + +### 入参类型 + + + +#### 通用入参 + +参见:[3.2入参类型](#kmCzf) + + +#### 注解类型参数 + +| 注解 | 参数位置 | 说明 | +|--------------|-------------|--------------------------------| +| @QueryParam | querystring | ?a=a&b=b对应的参数 | +| @HeaderParam | header | | +| @PathParam | path |
| +| @FormParam | form | body为key1=value2&key2=value2格式 | +| 无注解 | body | 不显式使用注解 | + + + +#### 特殊类型参数 + +| 类型 | 说明 | 激活条件 | +|---------------------------------|----------|------------| +| javax.ws.rs.core.Cookie | Cookie对象 | 引入Jax-rs依赖 | +| javax.ws.rs.core.Form | 表单对象 | 同上 | +| javax.ws.rs.core.HttpHeaders | Http头 | 同上 | +| javax.ws.rs.core.MediaType | 媒体类型 | 同上 | +| javax.ws.rs.core.MultivaluedMap | 多值Map | 同上 | +| javax.ws.rs.core.UriInfo | Uri信息 | 同上 | + + + +#### 无注解参数 + +- 如果是基本类型 ( + 根据 [TypeUtils#isSimpleProperty](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java#L105) + 判断),直接从Parameter中获取 +- 如果非基本类型, 将其视为请求体 (body)来解码对象 + + +### 参数类型转换 + +可通过扩展自定义参数转换,扩展接口: + +``` +org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver +javax.ws.rs.ext.ParamConverterProvider +``` + + + +### 异常处理 + +可通过扩展自定义异常处理,扩展接口: + +``` +javax.ws.rs.ext.ExceptionMapper +org.apache.dubbo.remoting.http12.ExceptionHandler +``` + + + +### CORS配置 + +支持 [8.4CORS配置](#NLQqj) 全局配置 + + +### 自定义HTTP输出 + +支持以下 Jaxrs 自定义方式: + +- 返回 `javax.ws.rs.core.Response` 对象 + + +### 支持的扩展 + +1. javax.ws.rs.container.ContainerRequestFilter
请求过滤器,允许在请求到达资源方法之前对请求进行预处理。 +2. javax.ws.rs.container.ContainerResponseFilter
响应过滤器,允许在响应离开资源方法之后对响应进行后处理。 +3. javax.ws.rs.ext.ExceptionMapper
异常映射器,将抛出的异常映射为HTTP响应。 +4. javax.ws.rs.ext.ParamConverterProvider
参数转换器,允许将请求参数转换为资源方法的参数类型。 +5. javax.ws.rs.ext.ReaderInterceptor
读取拦截器,允许在读取请求实体时进行拦截和处理。 +6. javax.ws.rs.ext.WriterInterceptor
写入拦截器,允许在写入响应实体时进行拦截和处理。 + + +## Servlet使用指南 + +同时低版本javax和高版本jakarta servlet API,jakarta API 优先级更高,只需要引入jar即可使用HttpServletRequest和HttpServletResponse作为参数 + + +### 使用 Filter 扩展 + +方法1,实现 `Filter` 接口和 `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension` 接口,然后注册SPI + +```java +import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension; + +import javax.servlet.Filter; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class DemoFilter implements Filter, RestExtension { + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { + chain.doFilter(request, response); + } + + @Override + public String[] getPatterns() { + return new String[]{"/demo/**", "!/demo/one"}; + } + + @Override + public int getPriority() { + return -200; + } +} +``` + +方法2,实现 `Supplier` 接口和 `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension` 接口,然后注册SPI + +```java +public class DemoFilter implements Supplier, RestExtension { + + private final Filter filter = new SsoFilter(); + + @Override + public Filter get() { + return filter; + } +} +``` + +这种方式对于重用已有 Filter 非常方便,甚至可以从 Spring Context 中获取 Filter 实例并注册 + +```java +public class DemoFilter implements Supplier, RestExtension { + + private final Filter filter = new SsoFilter(); + + public DemoFilter(FrameworkModel frameworkModel) { + SpringExtensionInjector injector = SpringExtensionInjector.get(frameworkModel.defaultApplication()); + filter = injector.getInstance(SsoFilter.class, null); + } + + @Override + public Filter get() { + return filter; + } +} +``` + + + +### HttpSession支持 + +实现 SPI `org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.HttpSessionFactory` + + +### 尚不支持的特性 + +- Filter 中 wrap request 和 response对象不会生效,原因是 Rest支持的 过滤器种类很多,使用wrapper会导致反复嵌套,处理过于复杂 +- 不支持 `request.getRequestDispatcher` + + +### 安全配置 + +当 REST 服务直接暴露在公网时,存在被攻击的安全风险。因此在暴露服务之前,需要充分评估风险并选择合适的认证方式来保证安全性。Triple 提供了多种安全认证机制,同时用户也可以自行实现相应的扩展来对访问进行安全校验。 + +#### Basic 认证 + +要启用 Basic 认证,请修改以下配置: + +```yaml +dubbo: + provider: + auth: true + authenticator: basic + username: admin + password: admin +``` + +启用后,所有 HTTP 请求都需要通过 Basic 认证才能访问。 + +如果是 RPC 调用,还需要在消费者端配置相应的用户名和密码: + +```yaml +dubbo: + consumer: + auth: true + authenticator: basic + username: admin + password: admin +``` + +这样配置后,provider 和 consumer 之间的通信将使用 Basic 认证来保证安全性。请确保在生产环境中使用强密码,并考虑采用 HTTPS 来加密传输。 + +### 认证扩展 +#### 实现自定义 Authenticator +可通过 SPI `org.apache.dubbo.auth.spi.Authenticator` 来自定义认证,并通过配置 dubbo.provider.authenticator 来选择启用的 Authenticator + +#### 实现 HTTP 请求过滤 +可通过 SPI `org.apache.dubbo.rpc.HeaderFilter` 或 `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter` 来自定义 HTTP 过滤器逻辑 + +## 全局参数配置 + + + +### 大小写敏感 + +配置名:`dubbo.protocol.triple.rest.case-sensitive-match`
是否路径匹配应区分大小写。如果启用,映射到 `/users` 的方法不会匹配到 +`/Users`
默认为 `true` + + +### 尾匹配 + +配置名:`dubbo.protocol.triple.rest.trailing-slash-match`
是否路径匹配应匹配带有尾部斜杠的路径。如果启用,映射到 +`/users` 的方法也会匹配到 `/users/`
默认为 `true` + + +### 扩展名匹配 + +配置名:`dubbo.protocol.triple.rest.suffix-pattern-match`
是否路径匹配使用后缀模式匹配(.*) ,如果启用,映射到 +`/users` 的方法也会匹配到 `/users.*` ,后缀内容协商会被同时启用,媒体类型从URL后缀推断,例如 `.json` 对应 +`application/json`
默认为 `true` + + +### CORS配置 + +| 配置名 | 说明 | 默认值 | +|-----------------------------------------------------|-------------------------------------------------------|-------------------------| +| `dubbo.protocol.triple.rest.cors.allowed-origins` | 允许跨域请求的来源列表,可以是具体域名或特殊值 `*` 代表所有来源。 | 未设置(不允许任何来源) | +| `dubbo.protocol.triple.rest.cors.allowed-methods` | 允许的 HTTP 方法列表,例如 `GET`、`POST`、`PUT` 等,特殊值 `*` 代表所有方法。 | 未设置(仅允许 `GET` 和 `HEAD`) | +| `dubbo.protocol.triple.rest.cors.allowed-headers` | 预检请求中允许的请求头列表,特殊值 `*` 代表所有请求头。 | 未设置 | +| `dubbo.protocol.triple.rest.cors.exposed-headers` | 实际响应中可以暴露给客户端的响应头列表,特殊值 `*` 代表所有响应头。 | 未设置 | +| `dubbo.protocol.triple.rest.cors.allow-credentials` | 是否支持用户凭证。 | 未设置(不支持用户凭证) | +| `dubbo.protocol.triple.rest.cors.max-age` | 预检请求的响应可以被客户端缓存的时间(以秒为单位)。 | 未设置 | + + + +## 高级使用指南 + + + +### 支持的扩展点汇总 + +1. javax.servlet.Filter
Servlet API过滤器。 +2. org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.HttpSessionFactory
用于在Servlet API中支持 HttpSession。 +3. javax.ws.rs.container.ContainerRequestFilter
用于在JAX-RS中实现请求过滤器,允许在请求到达资源方法之前对请求进行预处理。 +4. javax.ws.rs.container.ContainerResponseFilter
用于在JAX-RS中实现响应过滤器,允许在响应离开资源方法之后对响应进行后处理。 +5. javax.ws.rs.ext.ExceptionMapper
用于在JAX-RS中实现异常映射器,将抛出的异常映射为HTTP响应。 +6. javax.ws.rs.ext.ParamConverterProvider
用于在JAX-RS中提供参数转换器,允许将请求参数转换为资源方法的参数类型。 +7. javax.ws.rs.ext.ReaderInterceptor
用于在JAX-RS中实现读取拦截器,允许在读取请求实体时进行拦截和处理。 +8. javax.ws.rs.ext.WriterInterceptor
用于在JAX-RS中实现写入拦截器,允许在写入响应实体时进行拦截和处理。 +9. org.springframework.web.servlet.HandlerInterceptor
用于在Spring MVC中实现处理器拦截器。 +10. org.apache.dubbo.remoting.http12.ExceptionHandler
提供异常自定义处理机制。 +11. org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory
提供HTTP消息的适配和转换功能。 +12. org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory
提供HTTP消息的解码功能。 +13. org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory
提供HTTP消息的编码功能。 +14. org.apache.dubbo.rpc.HeaderFilter
用于在Dubbo RPC中实现头部过滤器,允许对请求和响应的头部进行过滤和处理。 +15. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestHeaderFilterAdapter
头部过滤器适配器,提供访问http输入输出能力。 +16. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilterAdapter
Dubbo Filter Rest适配器,提供访问http输入输出能力。 +17. org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping
用于在Dubbo Triple中实现请求映射能力。 +18. org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver
用于解析REST请求映射。 +19. org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit
提供REST相关的工具和实用程序。 +20. org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter
提供参数的类型转换功能。 +21. org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver
提供参数的解析功能。 +22. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter
提供REST请求和响应的过滤功能。 +23. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter
提供RestExtension的adapt能力,将已有filter接口映射到RestFilter接口。 + + +### 自定义异常返回结果 + +通过 SPI `org.apache.dubbo.remoting.http12.ExceptionHandler` 来自定义异常处理逻辑 + +```java +public interface ExceptionHandler { + /** + * Resolves the log level for a given throwable. + */ + default Level resolveLogLevel(E throwable) { + return null; + } + + /** + * Handle the exception and return a result. + */ + default T handle(E throwable, RequestMetadata metadata, MethodDescriptor descriptor) { + return null; + } +} +``` + +实现 SPI 并将泛型 E 指定为需要处理的异常类型 + +- resolveLogLevel
Dubbo框架内部会打印Rest处理异常日志,可以通过实现这个方法来自定义需要打印的日志级别或忽略日志。 +- handle
如果返回结果不是 null ,则将直接输出返回结果,可以通过返回 + `org.apache.dubbo.remoting.http12.HttpResult` 来定制输出的 headers 和 status code。 + + +### 打开debug日志 + +```yaml +logging: + level: + "org.apache.dubbo.rpc.protocol.tri": debug + "org.apache.dubbo.remoting": debug +``` + +开启 debug 日志会输出详细的启动日志和请求响应日志,便于排查问题。 + + +### 打开verbose输出 + +```yaml +dubbo: + protocol: + triple: + verbose: true +``` + +开启 verbose 输出会将内部错误堆栈返回给调用方,并输出更多错误日志,便于排查问题。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple-3.3.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple-3.3.md new file mode 100644 index 000000000000..ff73d7ec5d9e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple-3.3.md @@ -0,0 +1,276 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/3.3/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/3.3/ +description: "本文介绍 triple 协议在 3.3 版本中的新特性" +linkTitle: tripe-3.3新特性 +title: Tripe 3.3 新特性 +type: docs +weight: 5 +--- + + + +## 全新的 Rest 支持 + + + +### 特性 + +在3.3版本中,基于现有 HTTP 协议栈,triple实现了全面的 REST 风格服务导出能力,无需使用泛化或网关层协议转换,无需配置,用户即可通过 HTTP 协议去中心化直接访问后端的 Triple 协议服务。同时,针对高级 +REST 用法,如路径定制、输出格式定制和异常处理,提供了丰富的注解和 +SPI 扩展支持。其主要特性包括: + +- **Triple协议融合** + 重用Triple原有HTTP协议栈, 无需额外配置或新增端口,即可同时支持 HTTP/1、HTTP/2 和 HTTP/3 协议的访问。 +- **去中心化** + 可直接对外暴露 Rest API,不再依赖网关应用进行流量转发,从而提升性能,并降低因网关引发的稳定性风险。安全问题可通过应用内部扩展解决,这一实践已在淘宝内部的 MTOP 中得到验证。 +- **支持已有servlet设施** + 支持 Servlet API 和 Filter,用户可以重用现有基于 Servlet API 的安全组件。通过实现一个 Servlet Filter,即可集成 OAuth 和 Spring Security 等安全框架。 +- **多种方言** + 考虑到大部分用户习惯使用 SpringMVC 或 JAX-RS 进行 REST API 开发,Triple Rest 允许继续沿用这些方式定义服务,并支持大部分扩展和异常处理机制(具备原框架 80% 以上的功能)。对于追求轻量级的用户,可使用 + Basic 方言,Triple 的开箱即用 + REST 访问能力即基于此方言导出服务。 +- **扩展能力强** + 提供超过 20 个 扩展点,用户不仅可以轻松实现自定义方言,还能灵活定制参数获取、类型转换、错误处理等逻辑。 +- **开箱即用** + REST 能力开箱即用,只需启用 Triple 协议,即具备 REST 直接访问服务能力。 +- **高性能路由** + 路由部分采用优化的 [Radix Tree](https://github.com/apache/dubbo/blob/3.3/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java) 和 + Zero Copy 技术,提升路由性能。 +- **OpenAPI无缝集成(TBD)** + 即将完成 OpenAPI 集成,开箱即用支持导出 OpenAPI Schema, 引入 Swagger 依赖可直接使用 Web UI 来进行服务测试。有了 OpenAPI Schema + 可使用 [Postman](https://www.postman.com/)、[Apifox](https://apifox.com/) 等API工具来管理和测试 + API,利用 OpenAPI 生态可轻松实现跨语言调用。未来会进一步支持 Schema First 的方式,先和前端团队一起定义 OpenAPI, 前端基于 OpenAPI 来生成调用代码和 Mock,后端基于 OpenAPI 来生成 Stub + 来开发服务,极大提升协同效率。 + + +### 示例 + + + +###### 示例代码 + +```java +package org.apache.dubbo.rest.demo; + +import org.apache.dubbo.remoting.http12.rest.Mapping; +import org.apache.dubbo.remoting.http12.rest.Param; + +// 服务接口 +public interface DemoService { + String hello(String name); + + @Mapping(path = "/hi", method = HttpMethods.POST) + String hello(User user, @Param(value = "c", type = ParamType.Header) int count); +} + +// 服务实现 +@DubboService +public class DemoServiceImpl implements DemoService { + @Override + public String hello(String name) { + return "Hello " + name; + } + + @Override + public String hello(User user, int count) { + return "Hello " + user.getTitle() + ". " + user.getName() + ", " + count; + } +} + +// 模型 +@Data +public class User { + private String title; + private String name; +} +``` + + + +###### 下载运行示例 + +```bash +# 获取示例代码 +git clone --depth=1 https://github.com/apache/dubbo-samples.git +cd dubbo-samples/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-basic +# 运行 +mvn spring-boot:run +``` + + + +###### curl测试 + +```bash +curl -v "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hello?name=world" +# 输出如下 +#> GET /org.apache.dubbo.rest.demo.DemoService/hello?name=world HTTP/1.1 +#> +#< HTTP/1.1 200 OK +#< content-type: application/json +#< content-length: 13 +#< +#"Hello world" +# +# 代码讲解 +# 可以看到输出了 "Hello world" ,有双引号是因为默认输出 content-type 为 application/json +# 通过这个例子可以了解 Triple 默认将服务导出到 /{serviceInterface}/{methodName}路径,并支持通过url方式传递参数 + +curl -v -H "c: 3" -d 'name=Yang' "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr" +# 输出如下 +#> POST /org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr HTTP/1.1 +#> c: 3 +#> Content-Length: 9 +#> Content-Type: application/x-www-form-urlencoded +#> +#< HTTP/1.1 200 OK +#< content-type: text/plain +#< content-length: 17 +#< +#Hello Mr. Yang, 3 +# +# 代码讲解 +# 可以看到输出 Hello Mr. Yang, 3 ,没有双引号是因为通过指定后缀 txt 的方式要求用 text/plain 输出 + #通过这个例子可以了解如何通过 Mapping 注解来定制路径,通过 Param 注解来定制参数来源,并支持通过 post body 或 url方式传递参数 +``` + + + +### 详情文档 + +请访问用户手册:[Tripe Rest Manual](../tripe-rest-manual/) + + +## 支持Servlet接入 + +在3.3版本中,可复用Spring Boot已有servlet监听端口来接入 HTTP 流量, 无需Netty监听新端口,简化部署,降低维护成本。通过减少对外部端口的依赖,有助于轻松通过企业防火墙和网关,简化网络部署,增强企业级应用的可维护性和安全性。 + + +### 示例 + + + +###### 下载运行示例 + +```bash +# 获取样例代码 +git clone --depth=1 https://github.com/apache/dubbo-samples.git +cd dubbo-samples/2-advanced/dubbo-samples-triple-servlet +# 直接运行 +mvn spring-boot:run +``` + + + +###### curl测试 + +```shell +curl --http2-prior-knowledge -v 'http://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world' +# 输出如下 +#* [HTTP/2] [1] OPENED stream for http://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world +#* [HTTP/2] [1] [:method: GET] +#* [HTTP/2] [1] [:scheme: http] +#* [HTTP/2] [1] [:authority: localhost:50052] +#* [HTTP/2] [1] [:path: /org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world] +#> +#* Request completely sent off +#< HTTP/2 200 +#< content-type: application/json +#< date: Sun, 25 Aug 2024 03:38:12 GMT +#< +#"Hello world" +``` + + + +### 详情文档 + +请访问:[how-to-enable-servlet-support-for-triple](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-servlet#how-to-enable-servlet-support-for-triple) +了解如何配置并启用 servlet 支持 + + +## 支持HTTP/3协议 + + + +### 特性 + +在3.3版本中,triple实现了对HTTP/3协议的支持,rpc 请求和 rest 请求均可通过 HTTP/3 协议传输,使用 HTTP/3 可以带来一下好处: + +- **提升性能** + 支持 HTTP/3 后,利用 QUIC 协议降低延迟,加快请求响应速度,特别是在高延迟或复杂网络环境中,能够显著提升服务的整体性能。 +- **增强可靠性** + HTTP/3 通过多路复用和连接迁移避免队头阻塞,即使在网络状况不佳时,也能保持连接的稳定性,确保服务的可靠交付。 +- **提高安全性** + HTTP/3 强制要求 TLS1.3 加密,相比传统HTTP/2 可选加密,提供了更安全的通信保障。 +- **适应弱网络环境** + 在高丢包率或带宽不稳定的情况下,HTTP/3 能够维持较高地连接质量和服务性能,提升在弱网络环境中的性能。 + +由于 HTTP/3 基于 QUIC 协议(UDP),可能会被防火墙或网关阻止。因此,triple 实现了 HTTP/3 协商能力并默认启用。连接首先通过 HTTP/2 建立,如果成功且服务端返回表示支持 HTTP/3 +的[Alt-Svc](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Alt-Svc) 头,客户端将自动切换到HTTP/3 + + +### 示例 + + + +###### 下载运行示例 + +```bash +# 获取样例代码 +git clone --depth=1 https://github.com/apache/dubbo-samples.git +cd dubbo-samples/2-advanced/dubbo-samples-triple-http3 +# 直接运行 +mvn spring-boot:run +``` + + + +###### curl测试 + +请注意,curl 需要升级到支持 HTTP/3 的新版本, 参见:[https://curl.se/docs/http3.html](https://curl.se/docs/http3.html) + +```shell + +curl --http3 -vk 'https://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world' +# 输出如下 +#* QUIC cipher selection: TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256 +#* Skipped certificate verification +#* using HTTP/3 +#* [HTTP/3] [0] OPENED stream for https://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world +#* [HTTP/3] [0] [:method: GET] +#* [HTTP/3] [0] [:scheme: https] +#* [HTTP/3] [0] [:authority: localhost:50052] +#* [HTTP/3] [0] [:path: /org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world] +#> +#* Request completely sent off +#< HTTP/3 200 +#< content-type: application/json +#< +#"Hello world" +``` + + + +### 性能对比 + +#### 丢包率对 QPS 的影响 + +![http3-qps.jpg](/imgs/v3/manual/java/protocol/http3-qps.jpg) + +#### 丢包率对 RT 的影响 + +![http3-rt.jpg](/imgs/v3/manual/java/protocol/http3-rt.jpg) + + + +### 架构图 + +![http3-arch.jpg](/imgs/v3/manual/java/protocol/http3-arch.jpg) + +### 详情文档 + +请访问:[how-to-enable-http3-support-for-triple](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-http3#how-to-enable-http3-support-for-triple) +了解如何配置并启用 HTTP/3 支持 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md new file mode 100644 index 000000000000..5fccb7b7b3a8 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md @@ -0,0 +1,318 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/grpc/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/guide/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/migration + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/overview/ + - /zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/protobufinterface/ + - /zh-cn/overview/mannual/java-sdk/tasks/gateway/triple/ +description: "本文 triple 在 dubbo java 实现中的一些具体细节,配置方式、性能指标等" +linkTitle: triple +title: 协议概述 +type: docs +weight: 2 +--- + +请参考文档其他部分了解 [triple 协议规范规范](/zh-cn/overview/reference/protocols/triple-spec/) 和 [基本使用方式](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/)。本文只展开 triple 协议 Java 实现中的一些具体细节内容。 + +## 编程模式 +使用 triple 协议时,开发者可以使用 `Java Interface`、`Protobuf(IDL)` 两种方式定义 RPC 服务,两种服务定义方式的协议能力是对等的,仅影响开发者的编程体验、序列化方式,具体选用那种开发模式,取决于使用者的业务背景。 + +### Java接口 +**适合于 Dubbo 老用户、没有跨语言诉求的开发团队,具备学习成本低的优势,[Dubbo2 老用户可以零成本切换到该协议]()**。 + +服务定义范例: +```java +public interface DemoService { + String sayHello(String name); +} +``` + +这种模式下,序列化方式可以选用 Hessian、JSON、Kryo、JDK、自定义扩展等任意编码协议。在使用体验上,可以说与老版本 dubbo 协议没有任何区别,只需要改一个 protocol 配置项即可,因此对于 dubbo 协议迁移到 triple 也会更平滑。 + +请通过【进阶学习 - 通信协议】查看 [java Interface + Triple 协议的具体使用示例]()。 + +### Protobuf + +使用 Protobuf(IDL) 的方式定义服务,**适合于当前或未来有跨语言诉求的开发团队,同一份 IDL 服务可同时用于 Java/Go/Node.js 等多语言微服务开发,劣势是学习成本较高**。 + +```Protobuf +syntax = "proto3"; +option java_multiple_files = true; +package org.apache.dubbo.springboot.demo.idl; + +message GreeterRequest { + string name = 1; +} +message GreeterReply { + string message = 1; +} + +service Greeter{ + rpc greet(GreeterRequest) returns (GreeterReply); +} +``` + +通过 [Dubbo 提供的 protoc 编译插件](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/#生成的代码无法编译),将以上 IDL 服务定义预编译为相关 stub 代码,其中就包含 Dubbo 需要的 Interface 接口定义,因此在后续编码上区别并不大,只不过相比于前面的用户自定义 Java Interface 模式,这里由插件自动帮我们生成 Interface 定义。 + +```java +// Generated by dubbo protoc plugin +public interface Greeter extends org.apache.dubbo.rpc.model.DubboStub { + String JAVA_SERVICE_NAME = "org.apache.dubbo.springboot.demo.idl.Greeter"; + String SERVICE_NAME = "org.apache.dubbo.springboot.demo.idl.Greeter"; + + org.apache.dubbo.springboot.demo.idl.GreeterReply greet(org.apache.dubbo.springboot.demo.idl.GreeterRequest request); + // more generated codes here... +} +``` + +Protobuf 模式支持序列化方式有 Protobuf Binary、Protobuf JSON 两种模式。最后,请通过【进阶学习 - 通信协议】查看 [Protobuf (IDL) + Triple 协议的具体使用示例]()。 + +#### 3. 我该使用哪种编程模式,如何选择? + +| | 是 | 否 | +| --- | --- | --- | +| 公司的业务是否有用 Java 之外的其他语言,跨语言互通的场景是不是普遍? | Protobuf | Java 接口 | +| 公司里的开发人员是否熟悉 Protobuf,愿意接受 Protobuf 的额外成本吗? | Protobuf | Java 接口 | +| 是否有标准 gRPC 互通诉求? | Protobuf | Java 接口 | +| 是不是 Dubbo2 老用户,想平滑迁移到 triple 协议? | Java 接口 | Protobuf | + +## Streaming流式通信 +#### 流实现原理 + +`Triple`协议的流模式 + +- 从协议层来说,`Triple` 是建立在 `HTTP2` 基础上的,所以直接拥有所有 `HTTP2` 的能力,故拥有了分 `streaming` 和全双工的能力。 + +- 框架层来说,`org.apache.dubbo.common.stream.StreamObserver` 作为流的接口提供给用户,用于入参和出参提供流式处理。框架在收发 stream data 时进行相应的接口调用, 从而保证流的生命周期完整。 + +#### 适用场景 +Streaming 是 Dubbo3 新提供的一种调用类型,在以下场景时建议使用流的方式: + +- 接口需要发送大量数据,这些数据无法被放在一个 RPC 的请求或响应中,需要分批发送,但应用层如果按照传统的多次 RPC 方式无法解决顺序和性能的问题,如果需要保证有序,则只能串行发送 +- 流式场景,数据需要按照发送顺序处理, 数据本身是没有确定边界的 +- 推送类场景,多个消息在同一个调用的上下文中被发送和处理 + +Stream 分为以下三种。 + +##### SERVER_STREAM(服务端流) +服务端流式 RPC 类似于 Unary RPC,不同之处在于服务端会响应客户端的请求并返回消息流。在发送完所有消息后(通常是多条消息),服务端会发送状态信息(状态代码和可选状态消息)和可选的尾部元数据给客户端,这写状态信息发送完后服务器端流就结束了。一旦客户端通过 StreamObserver 接收到了以上所有了服务器消息,流就完成了。 + +服务端流 + +##### CLIENT_STREAM(客户端流) +客户端流式 RPC 类似于 Unary RPC,不同之处在于客户端向服务器发送消息流(通常包含多条消息)而不是单个消息。服务器以单个消息(以及其状态详细信息和可选的尾部元数据)进行响应 - 通常但不一定是在接收到所有客户端消息之后。 + +客户端流 + +##### BIDIRECTIONAL_STREAM(双向流) +在双向流 RPC 中,客户端发起方法调用,服务端则接收客户端调用中的元数据、方法名称和截止日期,这样就启动了一次完整的双向流通道。服务器可以选择返回其初始元数据,或者等待客户端开始流式传输消息。 + +客户端和服务器端的流处理是特定于应用程序的。由于这两个流是独立的,客户端和服务器可以按任何顺序读取和写入消息。例如,服务器可以等到收到客户端的所有消息后再写消息,或者服务器和客户端可以玩“乒乓球”——服务器收到一个请求,然后发回一个响应,然后客户端根据响应发送另一个请求等等。 + +双向流 + +{{% alert title="流的语义保证" color="primary" %}} +- 提供消息边界,可以方便地对消息单独处理 +- 严格有序,发送端的顺序和接收端顺序一致 +- 全双工,发送不需要等待 +- 支持取消和超时 +{{% /alert %}} + +关于 Streaming 的具体使用示例,请参见 [Streaming 流式通信](../triple/streaming/)。 + +## REST 支持 +通过为 Java 接口增加注解,可以发布 rest 风格的 triple 服务,可在这里查看 具体代码示例 + +{{% alert title="流的语义保证" color="info" %}} +目前 rest 协议仅支持 `Java 接口` 服务定义模式,相比于 dubbo 和 triple 协议,rest 场景下我们需要为 Interface 增加注解,支持 Spring MVC、JAX_RS 两种注解。 +{{% /alert %}} + +如果你记得 triple 协议原生支持 cURL 访问,即类似 `org.apache.dubbo.springboot.demo.idl.Greeter/greet` 的访问模式。通过增加以上注解后,即可为 triple 服务额外增加 REST 风格访问支持,如 `demo/greet` 的 GET 请求。 + +### Spring Web注解 +Spring MVC 服务定义范例: +```java +@RestController +@RequestMapping("/demo") +public interface DemoService { + @GetMapping(value = "/hello") + String sayHello(); +} +``` + +### JAX-RS注解 +JAX-RS 服务定义范例: +```java +@Path("/demo") +public interface DemoService { + @GET + @Path("/hello") + String sayHello(); +} +``` + +## 异常类型传递 +Provider 端产生的业务异常需要作为响应值返回给 Consumer 客户端,消费端可以使用 `try catch` 捕获可能抛出的异常: + +```java +try { + greeterProxy.echo(REQUEST_MSG); +} catch (YourCustomizedException e) { + e.printStackTrace(); + } catch (RpcException e) { + e.printStackTrace(); +} +``` + +Dubbo 框架会在 provider 侧根据如下流程发送异常类型响应,不是所有业务异常都能原样返回,对于无法处理的异常类型,都会被框架封装成 `RpcException` 类型返回: + +![triple-exception](/imgs/blog/2022/12/19/triple/2.jpeg) + +## 附录 +### Protobuf与Java原生数据类型对比 + +对于计划从 Java 接口完全迁移到 Protobuf 的用户而言,这里的信息可供参考,用以了解类型迁移可能面临的限制,Protobuf 描述语言是否能完全描述 Java 数据类型。 + +本文对比了Protobuf和Java Interface这2种IDL的差异,帮助Dubbo协议开发者了解Protobuf,为后续转到Triple协议和Grpc协议做铺垫。 + +#### 1. 数据类型 + +##### 1.1. 基本类型 + +| ptoto类型 | java类型 | +| ---- | ---- | +double | double +float | float +int32 | int +int64 | long +uint32 | int[注] +uint64 | long[注] +sint32 | int +sint64 | long +fixed32 | int[注] +fixed64 | long[注] +sfixed32 | int +sfixed64 | long +bool | boolean +string | String +bytes | ByteString + +{{% alert title="注意" color="primary" %}} +在Java中,无符号的32位和64位整数使用它们的有符号对数来表示,顶部位只存储在符号位中。 +{{% /alert %}} + +#### 2. 复合类型 + +##### 2.1. 枚举 + +* 原始pb代码 + +```java. +enum TrafficLightColor { + TRAFFIC_LIGHT_COLOR_INVALID = 0; + TRAFFIC_LIGHT_COLOR_UNSET = 1; + TRAFFIC_LIGHT_COLOR_GREEN = 2; + TRAFFIC_LIGHT_COLOR_YELLOW = 3; + TRAFFIC_LIGHT_COLOR_RED = 4; +} +``` + +* 生成的java代码 + +![image](/imgs/docs/advanced/protobufinterface/124234531-b96c2c80-db46-11eb-8155-a77dbe059f07.png) + +> 枚举是常量,因此采用大写 +##### 2.2. 数组 + +* 原始pb代码 + +```java +message VipIDToRidReq { + repeated uint32 vipID = 1; +} +``` + +* 生成的java代码 + +![image](/imgs/docs/advanced/protobufinterface/124234564-c4bf5800-db46-11eb-94fc-a056af6089cb.png) + +> 底层实际上是1个ArrayList +##### 2.3. 集合 + +PB不支持无序、不重复的集合,只能 ``借用数组实现``,需要 ``自行去重``。 + +##### 2.4. 字典 + +* 原始pb代码 + +```java +message BatchOnlineRes { + map onlineMap = 1;//在线状态 +} +``` + +* 生成的java代码 + +![image](/imgs/docs/advanced/protobufinterface/124234654-e4568080-db46-11eb-9700-b30022ebee21.png) + +##### 2.5. 嵌套 + +* 原始pb代码 + +```java +message BatchAnchorInfoRes { + map list = 1; //用户信息map列表 +} +/* +* 对应接口的功能: 批量或单个获取用户信息 +*/ +message AnchorInfo { + uint32 ownerUid = 1 [json_name="uid"]; //用户id + string nickName = 2 [json_name="nn"]; //用户昵称 + string smallAvatar = 3 [json_name="savt"]; //用户头像全路径-小 + string middleAvatar = 4 [json_name="mavt"]; //用户头像全路径-中 + string bigAvatar = 5 [json_name="bavt"]; //用户头像全路径-大 + string avatar = 6 [json_name="avt"]; //用户头像 +} +``` + +* 生成的java代码 + +![image](/imgs/docs/advanced/protobufinterface/124234723-f89a7d80-db46-11eb-82d0-a8aee5322098.png) + +#### 3. 字段默认值 + +* 对于字符串,默认值为空字符串。 +* 对于字节,默认值为空字节。 +* 对于bools,默认值为false。 +* 对于数字类型,默认值为零。 +* 对于枚举,默认值为第一个定义的枚举值,它必须为0。 +* 对于消息字段,未设置字段。 它的确切值是语言相关的。 有关详细信息,请参阅生成的代码指南。 + +#### 4. 整体结构 + +| Feature | Java Interface | Protobuf | 备注 | +| ---- | ---- | ---- | ---- | +| 方法重载 | √ | × | | +| 泛型/模板化 | √ | × | | +| 方法继承 | √ | × | | +| 嵌套定义 | √ | 部分支持 | PB仅支持message和enum嵌套 | +| import文件 | √ | √ | | +| 字段为null | √ | × | | +| 多个入参 | √ | × | PB仅支持单入参 | +| 0个入参 | √ | × | PB必须有入参 | +| 0个出参 | √ | × | PB必须有出参 | +| 入参/出参为抽象类 | √ | × | PB的入参/出参必须为具象类 | +| 入参/出参为接口 | √ | × | PB的入参/出参必须为具象类 | +| 入参/出参为基础类型 | √ | × | PB的入参/出参必须为结构体 | + +#### 5. 社区资料 +* 社区主页地址:https://developers.google.cn/protocol-buffers/ +* 社区开源地址:https://github.com/google/protobuf +* 相关jar的maven:https://search.maven.org/search?q=com.google.protobuf + + + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md.bak new file mode 100644 index 000000000000..40727de64178 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md.bak @@ -0,0 +1,170 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/ +description: 协议概述 +linkTitle: triple +title: 协议概述 +type: docs +weight: 2 +--- + + +## 概述说明 + +`Triple` 协议的格式和原理请参阅 [RPC 通信协议](/zh-cn/docs/concepts/rpc-protocol/) + +根据 Triple 设计的目标,`Triple` 协议有以下优势 + +- 具备跨语言交互的能力,传统的多语言多 SDK 模式和 Mesh 化跨语言模式都需要一种更通用易扩展的数据传输协议。 +- 提供更完善的请求模型,除了支持传统的 Request/Response 模型(Unary 单向通信),还支持 Stream(流式通信) 和 Bidirectional(双向通信)。 +- 易扩展、穿透性高,包括但不限于 Tracing / Monitoring 等支持,也应该能被各层设备识别,网关设施等可以识别数据报文,对 Service Mesh 部署友好,降低用户理解难度。 +- 完全兼容 grpc,客户端/服务端可以与原生grpc客户端打通。 +- 可以复用现有 grpc 生态下的组件, 满足云原生场景下的跨语言、跨环境、跨平台的互通需求。 + +当前使用其他协议的 Dubbo 用户,框架提供了兼容现有序列化方式的迁移能力,在不影响线上已有业务的前提下,迁移协议的成本几乎为零。 + +### GRPC +需要新增对接 grpc 服务的 Dubbo 用户,可以直接使用 Triple 协议来实现打通,不需要单独引入 grpc client 来完成,不仅能保留已有的 Dubbo 易用性,也能降低程序的复杂度和开发运维成本,不需要额外进行适配和开发即可接入现有生态。 + +### 网关接入 +对于需要网关接入的 Dubbo 用户,Triple 协议提供了更加原生的方式,让网关开发或者使用开源的 grpc 网关组件更加简单。网关可以选择不解析 payload ,在性能上也有很大提高。在使用 Dubbo 协议时,语言相关的序列化方式是网关的一个很大痛点,而传统的 HTTP 转 Dubbo 的方式对于跨语言序列化几乎是无能为力的。同时,由于 Triple 的协议元数据都存储在请求头中,网关可以轻松的实现定制需求,如路由和限流等功能。 + + +## 常见问题 + +### Q1 +protobuf 类找不到 + +由于 Triple 协议底层需要依赖 protobuf 协议进行传输,即使定义的服务接口不使用 protobuf 也需要在环境中引入 protobuf 的依赖。 + +```xml + + com.google.protobuf + protobuf-java + 3.19.4 + +``` + + + + + +Dubbo3 提供了 Triple(Dubbo3)、Dubbo2 协议,这是 Dubbo 框架的原生协议。除此之外,Dubbo3 也对众多第三方协议进行了集成,并将它们纳入 Dubbo 的编程与服务治理体系, +包括 gRPC、Thrift、JsonRPC、Hessian2、REST 等。以下重点介绍 Triple 与 Dubbo2 协议。 + +## 协议说明 + +Triple 协议是 Dubbo3 推出的主力协议。Triple 意为第三代,通过 Dubbo1.0/ Dubbo2.0 两代协议的演进,以及云原生带来的技术标准化浪潮,Dubbo3 新协议 Triple 应运而生。 + +### RPC 协议 + +协议是 RPC 的核心,它规范了数据在网络中的传输内容和格式。除必须的请求、响应数据外,通常还会包含额外控制数据,如单次请求的序列化方式、超时时间、压缩方式和鉴权信息等。 + +协议的内容包含三部分 +- 数据交换格式: 定义 RPC 的请求和响应对象在网络传输中的字节流内容,也叫作序列化方式 +- 协议结构: 定义包含字段列表和各字段语义以及不同字段的排列方式 +- 协议通过定义规则、格式和语义来约定数据如何在网络间传输。一次成功的 RPC 需要通信的两端都能够按照协议约定进行网络字节流的读写和对象转换。如果两端对使用的协议不能达成一致,就会出现鸡同鸭讲,无法满足远程通信的需求。 + +![协议选择](/imgs/v3/concepts/triple-protocol.png) + +RPC 协议的设计需要考虑以下内容: +- 通用性: 统一的二进制格式,跨语言、跨平台、多传输层协议支持 +- 扩展性: 协议增加字段、升级、支持用户扩展和附加业务元数据 +- 性能:As fast as it can be +- 穿透性:能够被各种终端设备识别和转发:网关、代理服务器等 + 通用性和高性能通常无法同时达到,需要协议设计者进行一定的取舍。 + +### HTTP/1.1 协议 + +比于直接构建于 TCP 传输层的私有 RPC 协议,构建于 HTTP 之上的远程调用解决方案会有更好的通用性,如WebServices 或 REST 架构,使用 HTTP + JSON 可以说是一个事实标准的解决方案。 + +选择构建在 HTTP 之上,有两个最大的优势: + +- HTTP 的语义和可扩展性能很好的满足 RPC 调用需求。 +- 通用性,HTTP 协议几乎被网络上的所有设备所支持,具有很好的协议穿透性。 + +但也存在比较明显的问题: + +- 典型的 Request – Response 模型,一个链路上一次只能有一个等待的 Request 请求。会产生 HOL。 +- Human Readable Headers,使用更通用、更易于人类阅读的头部传输格式,但性能相当差 +- 无直接 Server Push 支持,需要使用 Polling Long-Polling 等变通模式 + +### gRPC 协议 +上面提到了在 HTTP 及 TCP 协议之上构建 RPC 协议各自的优缺点,相比于 Dubbo 构建于 TCP 传输层之上,Google 选择将 gRPC 直接定义在 HTTP/2 协议之上。 +gRPC 的优势由HTTP2 和 Protobuf 继承而来。 + +- 基于 HTTP2 的协议足够简单,用户学习成本低,天然有 server push/ 多路复用 / 流量控制能力 +- 基于 Protobuf 的多语言跨平台二进制兼容能力,提供强大的统一跨语言能力 +- 基于协议本身的生态比较丰富,k8s/etcd 等组件的天然支持协议,云原生的事实协议标准 + +但是也存在部分问题 + +- 对服务治理的支持比较基础,更偏向于基础的 RPC 功能,协议层缺少必要的统一定义,对于用户而言直接用起来并不容易。 +- 强绑定 protobuf 的序列化方式,需要较高的学习成本和改造成本,对于现有的偏单语言的用户而言,迁移成本不可忽视 + +### Triple 协议 +最终我们选择了兼容 gRPC ,以 HTTP2 作为传输层构建新的协议,也就是 Triple。 + +容器化应用程序和微服务的兴起促进了针对负载内容优化技术的发展。 客户端中使用的传统通信协议( RESTFUL或其他基于 HTTP 的自定义协议)难以满足应用在性能、可维护性、扩展性、安全性等方便的需求。一个跨语言、模块化的协议会逐渐成为新的应用开发协议标准。自从 2017 年 gRPC 协议成为 CNCF 的项目后,包括 k8s、etcd 等越来越多的基础设施和业务都开始使用 gRPC 的生态,作为云原生的微服务化框架, Dubbo 的新协议也完美兼容了 gRPC。并且,对于 gRPC 协议中一些不完善的部分, Triple 也将进行增强和补充。 + +那么,Triple 协议是否解决了上面我们提到的一系列问题呢? + +- 性能上: Triple 协议采取了 metadata 和 payload 分离的策略,这样就可以避免中间设备,如网关进行 payload 的解析和反序列化,从而降低响应时间。 +- 路由支持上,由于 metadata 支持用户添加自定义 header ,用户可以根据 header 更方便的划分集群或者进行路由,这样发布的时候切流灰度或容灾都有了更高的灵活性。 +- 安全性上,支持双向TLS认证(mTLS)等加密传输能力。 +- 易用性上,Triple 除了支持原生 gRPC 所推荐的 Protobuf 序列化外,使用通用的方式支持了 Hessian / JSON 等其他序列化,能让用户更方便的升级到 Triple 协议。对原有的 Dubbo 服务而言,修改或增加 Triple 协议 只需要在声明服务的代码块添加一行协议配置即可,改造成本几乎为 0。 + +## 最终选择协议 + +![Triple 协议通信方式](/imgs/v3/concepts/triple.png) + +现状 + +- 1、完整兼容grpc、客户端/服务端可以与原生grpc客户端打通 + +- 2、目前已经经过大规模生产实践验证,达到生产级别 + +特点与优势 + +- 1、具备跨语言互通的能力,传统的多语言多 SDK 模式和 Mesh 化跨语言模式都需要一种更通用易扩展的数据传输格式。 + +- 2、提供更完善的请求模型,除了支持传统的 Request/Response 模型(Unary 单向通信),还支持 Stream(流式通信) 和 Bidirectional(双向通信)。 + +- 3、易扩展、穿透性高,包括但不限于 Tracing / Monitoring 等支持,也应该能被各层设备识别,网关设施等可以识别数据报文,对 Service Mesh 部署友好,降低用户理解难度。 + +- 4、多种序列化方式支持、平滑升级 + +- 5、支持 Java 用户无感知升级,不需要定义繁琐的 IDL 文件,仅需要简单的修改协议名便可以轻松升级到 Triple 协议 + +### Triple 协议内容介绍 + +基于 grpc 协议进行进一步扩展 + +- Service-Version → "tri-service-version" {Dubbo service version} +- Service-Group → "tri-service-group" {Dubbo service group} +- Tracing-ID → "tri-trace-traceid" {tracing id} +- Tracing-RPC-ID → "tri-trace-rpcid" {_span id _} +- Cluster-Info → "tri-unit-info" {cluster infomation} + +其中 Service-Version 跟 Service-Group 分别标识了 Dubbo 服务的 version 跟 group 信息,因为grpc的 path 申明了 service name 跟 method name,相比于 Dubbo 协议,缺少了version 跟 group 信息;Tracing-ID、Tracing-RPC-ID 用于全链路追踪能力,分别表示 tracing id 跟 span id 信息;Cluster-Info 表示集群信息,可以使用其构建一些如集群划分等路由相关的灵活的服务治理能力。 + +### Triple Streaming + +Triple协议相比传统的unary方式,多了目前提供的Streaming RPC的能力 + +- Streaming 用于什么场景呢? + +在一些大文件传输、直播等应用场景中, consumer或provider需要跟对端进行大量数据的传输,由于这些情况下的数据量是非常大的,因此是没有办法可以在一个RPC的数据包中进行传输,因此对于这些数据包我们需要对数据包进行分片之后,通过多次RPC调用进行传输,如果我们对这些已经拆分了的RPC数据包进行并行传输,那么到对端后相关的数据包是无序的,需要对接收到的数据进行排序拼接,相关的逻辑会非常复杂。但如果我们对拆分了的RPC数据包进行串行传输,那么对应的网络传输RTT与数据处理的时延会是非常大的。 + +为了解决以上的问题,并且为了大量数据的传输以流水线方式在consumer与provider之间传输,因此Streaming RPC的模型应运而生。 + +通过Triple协议的Streaming RPC方式,会在consumer跟provider之间建立多条用户态的长连接,Stream。同一个TCP连接之上能同时存在多个Stream,其中每条Stream都有StreamId进行标识,对于一条Stream上的数据包会以顺序方式读写。 + + +{{% alert title="总结" color="info" %}} +在API领域,最重要的趋势是标准化技术的崛起。Triple 协议是 Dubbo3 推出的主力协议。它采用分层设计,其数据交换格式基于Protobuf (Protocol Buffers) 协议开发,具备优秀的序列化/反序列化效率,当然还支持多种序列化方式,也支持众多开发语言。在传输层协议,Triple 选择了 HTTP/2,相较于 HTTP/1.1,其传输效率有了很大提升。此外HTTP/2作为一个成熟的开放标准,具备丰富的安全、流控等能力,同时拥有良好的互操作性。Triple 不仅可以用于Server端服务调用,也可以支持浏览器、移动App和IoT设备与后端服务的交互,同时 Triple协议无缝支持 Dubbo3 的全部服务治理能力。 + +在Cloud Native的潮流下,跨平台、跨厂商、跨环境的系统间互操作性的需求必然会催生基于开放标准的RPC技术,而gRPC顺应了历史趋势,得到了越来越广泛地应用。在微服务领域,Triple协议的提出与落地,是 Dubbo3 迈向云原生微服务的一大步。 +{{% /alert %}} + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/_index.md new file mode 100755 index 000000000000..f2ed9eafcb95 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/qos/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/ +description: Dubbo QOS 操作指南 +linkTitle: 单机运维命令(QOS) +title: QOS 操作手册 +type: docs +weight: 99 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/_index.md new file mode 100755 index 000000000000..173601f4eaaf --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/_index.md @@ -0,0 +1,7 @@ +--- +description: "QoS 命令详解,包含对每个命令的使用方法、效果的详细说明" +linkTitle: 部分命令详解 +title: 包含对每个命令的使用方法、效果的详细说明 +type: docs +weight: 99 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/command.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/command.md new file mode 100644 index 000000000000..53abb18c3e3b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/command.md @@ -0,0 +1,57 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/qos/command/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/command/ +description: 基础命令手册 +linkTitle: 基础命令手册 +title: 基础命令手册 +type: docs +weight: 2 +--- + + + + + +基础命令功能提供了一系列的基础命令。 + +### help 命令 + +显示更多命令 +``` +//列出所有命令 +dubbo>help + +//列出单个命令的具体使用情况 +dubbo>help online ++--------------+----------------------------------------------------------------------------------+ +| COMMAND NAME | online | ++--------------+----------------------------------------------------------------------------------+ +| EXAMPLE | online dubbo | +| | online xx.xx.xxx.service | ++--------------+----------------------------------------------------------------------------------+ + +dubbo> +``` + +### version 命令 + +显示当前运行的 Dubbo 的版本号 + +``` +dubbo>version +dubbo version "3.0.10-SNAPSHOT" + +dubbo> +``` + +### quit 命令 + +退出命令状态 + +``` +dubbo>quit +BYE! +Connection closed by foreign host. + +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/default_metrics.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/default_metrics.md new file mode 100644 index 000000000000..1ce36706f368 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/default_metrics.md @@ -0,0 +1,63 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/qos/logger-management/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/logger-management/ +description: 当用户未接入 prometheus 时可以使用默认的监控指标命令 +linkTitle: 默认监控指标命令 +title: 默认监控指标命令 +type: docs +weight: 10 +--- + + +### 查询所有监控指标 + +命令:`metrics_default` + +示例: +```bash +> telnet 127.0.0.1 22222 +> metrics_default +``` + +输出: +``` +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>metrics_default +dubbo.registry.directory.num.disable.total{application.module.id=1.1,application.name=dubbo-springboot-demo-provider,application.version=,git.commit.id=,hostname=hujundeMacBook-Pro.local,interface=dubbo-springboot-demo-provider/org.apache.dubbo.metrics.service.MetricsService:1.0.0,ip=10.224.214.80,} 0.0 +dubbo.register.rt.milliseconds.max{application.module.id=1.1,application.name=dubbo-springboot-demo-provider,application.version=,git.commit.id=,hostname=hujundeMacBook-Pro.local,ip=10.224.214.80,} 153.0 + +``` + +### 根据关键词查询监控指标 + +命令:`metrics_default {applicationName} {keyword}` + +applicationName: 应用名称 +keyword: 关键词 + +示例: +```bash +> telnet 127.0.0.1 22222 +> metrics_default dubbo-springboot-demo-provider registry +``` + +输出: +``` +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo> metrics_default dubbo-springboot-demo-provider registry +dubbo.registry.subscribe.num.total{application.module.id=1.1,application.name=dubbo-springboot-demo-provider,application.version=,git.commit.id=,hostname=hujundeMacBook-Pro.local,ip=10.224.214.80,} 0.0 +dubbo.registry.directory.num.disable.total{application.module.id=1.1,application.name=dubbo-springboot-demo-provider,application.version=,git.commit.id=,hostname=hujundeMacBook-Pro.local,interface=dubbo-springboot-demo-provider/org.apache.dubbo.metrics.service.MetricsService:1.0.0,ip=10.224.214.80,} 0.0 +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/logger-management.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/logger-management.md new file mode 100644 index 000000000000..3f1f155c1fb4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/logger-management.md @@ -0,0 +1,103 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/qos/logger-management/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/logger-management/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/logger-management/ +description: 在 Dubbo 中运行时动态切换使用的日志框架 +linkTitle: 日志框架运行时管理 +title: 日志框架运行时管理 +type: docs +weight: 5 +--- + + + + + +{{% alert title="注意" color="primary" %}} + +自 `3.0.10` 开始,dubbo-qos 运行时管控支持查询日志配置以及动态修改使用的日志框架和日志级别。 + +通过 dubbo-qos 修改的日志配置不进行持久化存储,在应用重启后将会失效。 +{{% /alert %}} + +### 查询日志配置 + +命令:`loggerInfo` + +示例: +```bash +> telnet 127.0.0.1 22222 +> loggerInfo +``` + +输出: +``` +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>loggerInfo +Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: INFO +``` + +### 修改日志级别 + +命令:`switchLogLevel {level}` + +level: `ALL`, `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `OFF` + +示例: +```bash +> telnet 127.0.0.1 22222 +> switchLogLevel WARN +``` + +输出: +``` +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>loggerInfo +Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: INFO +dubbo>switchLogLevel WARN +OK +dubbo>loggerInfo +Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: WARN``` +``` + +### 修改日志输出框架 + +命令:`switchLogger {loggerAdapterName}` + +loggerAdapterName: `slf4j`, `jcl`, `log4j`, `jdk`, `log4j2` + +示例: +```bash +> telnet 127.0.0.1 22222 +> switchLogger slf4j +``` + +输出: +``` +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>loggerInfo +Available logger adapters: [jcl, slf4j, log4j, jdk]. Current Adapter: [log4j]. Log level: INFO +dubbo>switchLogger slf4j +OK +dubbo>loggerInfo +Available logger adapters: [jcl, slf4j, log4j, jdk]. Current Adapter: [slf4j]. Log level: INFO +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/probe.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/probe.md new file mode 100644 index 000000000000..dbb0cd0301d9 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/probe.md @@ -0,0 +1,43 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/qos/probe/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/probe/ +description: 框架状态命令 +linkTitle: 框架状态命令 +title: 框架状态命令 +type: docs +weight: 4 +--- + +### startup 命令 + +检测当前框架是否已经启动完毕 + +``` +dubbo>startup +true + +dubbo> +``` + +### ready 命令 + +检测当前框架是否能正常提供服务(可能是临时下线) + +``` +dubbo>ready +true + +dubbo> +``` + +### live 命令 + +检测当前框架是否正常运行(可能是永久异常) + +``` +dubbo>live +true + +dubbo> +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/profiler.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/profiler.md new file mode 100644 index 000000000000..b92ad9bab81d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/profiler.md @@ -0,0 +1,83 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/qos/profiler/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/profiler/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/qos/profiler/ +description: 性能采样命令 +linkTitle: 性能采样命令 +title: 性能采样命令 +type: docs +weight: 7 +--- + + + + + + +性能采样功能可以对 Dubbo 处理链路上的各处耗时进行检测,在出现超时的时候 `( usageTime / timeout > profilerWarnPercent * 100 )` 通过日志记录调用的耗时。 + +此功能分为 `simple profiler` 和 `detail profiler` 两个模式,其中 `simple profiler` 模式默认开启,`detail profiler` 模式默认关闭。 +`detail profiler` 相较 `simple profiler` 模式多采集了每个 filter 的处理耗时、协议上的具体耗时等。 +在 `simple profiler` 模式下如果发现 Dubbo 框架内部存在耗时长的情况,可以开启 `detail profiler` 模式,以便更好地排查问题。 + +> [请求耗时采样](../../../advanced-features-and-usage/performance/profiler/) + +### enableSimpleProfiler 命令 + +开启 `simple profiler` 模式,默认开启 + +``` +dubbo>enableSimpleProfiler +OK + +dubbo> +``` + +### disableSimpleProfiler 命令 + +关闭 `simple profiler` 模式,关闭后 `detail profiler` 也将不启用 + +``` +dubbo>disableSimpleProfiler +OK + +dubbo> +``` + +### enableDetailProfiler 命令 + +开启 `detail profiler` 模式,默认关闭,需要开启 `simple profiler` 模式才会真实开启 + +``` +dubbo>enableDetailProfiler +OK. This will cause performance degradation, please be careful! + +dubbo> +``` + +### disableDetailProfiler 命令 + +关闭 `detail profiler` 模式,关闭后不影响 `simple profiler` + +``` +dubbo>disableDetailProfiler +OK + +dubbo> +``` + +### setProfilerWarnPercent 命令 + +设置超时时间的警告百分比 + +命令:`setProfilerWarnPercent {profilerWarnPercent}` + +profilerWarnPercent: 超时时间的警告百分比,取值范围 0.0 ~ 1.0,默认值为 0.75 + +``` +dubbo>setProfilerWarnPercent 0.75 +OK + +dubbo> +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/router-snapshot.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/router-snapshot.md new file mode 100644 index 000000000000..4c5c3e165189 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/router-snapshot.md @@ -0,0 +1,119 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/qos/router-snapshot/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/router-snapshot/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/qos/router-snapshot/ +description: 路由状态命令 +linkTitle: 路由状态命令 +title: 路由状态命令 +type: docs +weight: 8 +--- + + + + + + +Dubbo 的很多流量治理能力是基于 Router 进行实现的,在生产环境中,如果出现流量结果不符合预期的情况,可以通过路由状态命令来查看路由的状态,以此来定位可能存在的问题。 + +> [路由状态采集](../../../advanced-features-and-usage/performance/router-snapshot/) + +### getRouterSnapshot 命令 + +获取当前的每层路由的分组状态。(仅支持 StateRouter) + +命令:`getRouterSnapshot {serviceName}` + +`serviceName` 为需要采集的服务名,支持匹配 + +``` +dubbo>getRouterSnapshot com.dubbo.dubbointegration.BackendService +com.dubbo.dubbointegration.BackendService@2c2e824a +[ All Invokers:2 ] [ Valid Invokers: 2 ] + +MockInvokersSelector Total: 2 +[ Mocked -> Empty (Total: 0) ] +[ Normal -> 172.18.111.187:20880,172.18.111.183:20880 (Total: 2) ] + ↓ +StandardMeshRuleRouter not support + ↓ +TagStateRouter not support + ↓ +ServiceStateRouter not support + ↓ +AppStateRouter not support + ↓ +TailStateRouter End + + +dubbo> +``` + +### enableRouterSnapshot 命令 + +开启路由结果采集模式 + +命令:`enableRouterSnapshot {serviceName}` + +`serviceName` 为需要采集的服务名,支持匹配 + +``` +dubbo>enableRouterSnapshot com.dubbo.* +OK. Found service count: 1. This will cause performance degradation, please be careful! + +dubbo> +``` + +### disableRouterSnapshot 命令 + +关闭路由结果采集模式 + +命令:`disableRouterSnapshot {serviceName}` + +`serviceName` 为需要采集的服务名,支持匹配 + +``` +dubbo>disableRouterSnapshot com.dubbo.* +OK. Found service count: 1 + +dubbo> +``` + +### getEnabledRouterSnapshot 命令 + +获取当前已经开启采集的服务 + +``` +dubbo>getEnabledRouterSnapshot +com.dubbo.dubbointegration.BackendService + +dubbo> +``` + +### getRecentRouterSnapshot 命令 + +通过 qos 命令获取历史的路由状态。(最多存储 32 个结果) + +``` +dubbo>getRecentRouterSnapshot +1658224330156 - Router snapshot service com.dubbo.dubbointegration.BackendService from registry 172.18.111.184 on the consumer 172.18.111.184 using the dubbo version 3.0.9 is below: +[ Parent (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) ] Input: 172.18.111.187:20880,172.18.111.183:20880 -> Chain Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ MockInvokersSelector (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ StandardMeshRuleRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ TagStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ ServiceStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ AppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + +1658224330156 - Router snapshot service com.dubbo.dubbointegration.BackendService from registry 172.18.111.184 on the consumer 172.18.111.184 using the dubbo version 3.0.9 is below: +[ Parent (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) ] Input: 172.18.111.187:20880,172.18.111.183:20880 -> Chain Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ MockInvokersSelector (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ StandardMeshRuleRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ TagStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ ServiceStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ AppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + +··· + +dubbo> +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/security.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/security.md new file mode 100644 index 000000000000..85197b145afb --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/security.md @@ -0,0 +1,84 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/qos/security/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/security/ +description: 序列化安全审计 +linkTitle: 序列化安全审计 +title: 序列化安全审计 +type: docs +weight: 9 +--- + + + + + + +Dubbo 支持通过 QoS 命令实时查看当前的配置信息以及可信/不可信类列表。目前共支持两个命令:`serializeCheckStatus` 查看当前配置信息,`serializeWarnedClasses` 查看实时的告警列表。 + +### `serializeCheckStatus` 命令 + +通过控制台直接访问: +```bash +> telnet 127.0.0.1 22222 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>serializeCheckStatus +CheckStatus: WARN + +CheckSerializable: true + +AllowedPrefix: +... + +DisAllowedPrefix: +... + + +dubbo> +``` + +通过 http 请求 json 格式结果: +```bash +> curl http://127.0.0.1:22222/serializeCheckStatus +{"checkStatus":"WARN","allowedPrefix":[...],"checkSerializable":true,"disAllowedPrefix":[...]} +``` + +### `serializeWarnedClasses` 命令 + +通过控制台直接访问: +```bash +> telnet 127.0.0.1 22222 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>serializeWarnedClasses +WarnedClasses: +io.dubbo.test.NotSerializable +io.dubbo.test2.NotSerializable +io.dubbo.test2.OthersSerializable +org.apache.dubbo.samples.NotSerializable + + +dubbo> +``` + +通过 http 请求 json 格式结果: +```bash +> curl http://127.0.0.1:22222/serializeWarnedClasses +{"warnedClasses":["io.dubbo.test2.NotSerializable","org.apache.dubbo.samples.NotSerializable","io.dubbo.test.NotSerializable","io.dubbo.test2.OthersSerializable"]} +``` +{{% alert title="注意" color="primary" %}} +建议及时关注 `serializeWarnedClasses` 的结果,通过返回结果是否非空来判断是否受到攻击。 + +[Dubbo 类检查机制](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/)。 +{{% /alert %}} diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/service-management.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/service-management.md new file mode 100644 index 000000000000..afbe235871cd --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/service-management.md @@ -0,0 +1,84 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/qos/service-management/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/service-management/ +description: 服务管理命令 +linkTitle: 服务管理命令 +title: 服务管理命令 +type: docs +weight: 3 +--- + + + + +服务管理功能提供了一系列的命令对 Dubbo 服务进行管理。 + +## 服务管理 + +### ls 命令 + +列出消费者和提供者 + +``` +dubbo>ls +As Provider side: ++------------------------------------------------------------------------+---------------------+ +| Provider Service Name | PUB | ++------------------------------------------------------------------------+---------------------+ +|DubboInternal - UserRead/org.apache.dubbo.metadata.MetadataService:1.0.0| | ++------------------------------------------------------------------------+---------------------+ +| com.dubbo.dubbointegration.UserReadService |nacos-A(Y)/nacos-I(Y)| ++------------------------------------------------------------------------+---------------------+ +As Consumer side: ++-----------------------------------------+-----------------+ +| Consumer Service Name | NUM | ++-----------------------------------------+-----------------+ +|com.dubbo.dubbointegration.BackendService|nacos-AF(I-2,A-2)| ++-----------------------------------------+-----------------+ + +``` + +列出 dubbo 的所提供的服务和消费的服务,以及消费的服务地址数。 + +{{% alert title="注意" color="primary" %}} +- 带有 `DubboInternal` 前缀的服务是 Dubbo 内置的服务,默认不向注册中心中注册。 +- 服务发布状态中的 `nacos-A(Y)` 第一部分是对应的注册中心名,第二部分是注册的模式(`A` 代表应用级地址注册,`I` 代表接口级地址注册),第三部分代表对应模式是否已经注册 +- 服务订阅状态中的 `nacos-AF(I-2,A-2)` 第一部分是对应的注册中心名,第二部分是订阅的模式(`AF` 代表双订阅模式,`FA` 代表仅应用级订阅,`FI` 代表仅接口级订阅),第三部分中前半部分代表地址模式来源(`A` 代表应用级地址,`I` 代表接口级地址)后半部分代表对应的地址数量 +{{% /alert %}} + +## 上线 + +### online 命令 + +Online 上线服务命令 + +当使用延迟发布功能的时候(通过设置 org.apache.dubbo.config.AbstractServiceConfig#register 为 false),后续需要上线的时候,可通过 Online 命令 +``` +//上线所有服务 +dubbo>online +OK + +//根据正则,上线部分服务 +dubbo>online com.* +OK +``` + +## 下线 + + +### offline 命令 + +下线服务命令 + +由于故障等原因,需要临时下线服务保持现场,可以使用 Offline 下线命令。 + +``` +//下线所有服务 +dubbo>offline +OK + +//根据正则,下线部分服务 +dubbo>offline com.* +OK +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/overview.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/overview.md new file mode 100644 index 000000000000..2bdc5d25367a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/overview.md @@ -0,0 +1,211 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/qos/overview/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/overview/ +description: "QoS 命令的设计目的、使用方法说明,包括如何开启、关闭 qos 命令等,支持 HTTP/Telnet 访问方式," +linkTitle: QOS 概述 +title: QOS 概述 +type: docs +weight: 1 +--- + + +## 如何使用 +QoS 提供了一些启动参数,来对启动进行配置,他们主要包括: + +| 参数 | 说明 | 默认值 | +|---------------------------------|----------------|-----------| +| qos-enable | 是否启动QoS | true | +| qos-port | 启动QoS绑定的端口 | 22222 | +| qos-accept-foreign-ip | 是否允许远程访问 | false | +| qos-accept-foreign-ip-whitelist | 支持的远端主机ip地址(段) | (无) | +| qos-anonymous-access-permission-level | 支持的匿名访问的权限级别 | PUBLIC(1) | + +> 注意,从2.6.4/2.7.0开始,qos-accept-foreign-ip默认配置改为false,如果qos-accept-foreign-ip设置为true,有可能带来安全风险,请仔细评估后再打开。 + +### telnet 与 http 协议 + +telnet 模块现在同时支持 http 协议和 telnet 协议,方便各种情况的使用 +示例: +``` +➜ ~ telnet localhost 22222 +Trying ::1... +telnet: connect to address ::1: Connection refused +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ████████▄ ███ █▄ ▀█████████▄ ▀█████████▄ ▄██████▄ + ███ ▀███ ███ ███ ███ ███ ███ ███ ███ ███ + ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ + ███ ███ ███ ███ ▄███▄▄▄██▀ ▄███▄▄▄██▀ ███ ███ + ███ ███ ███ ███ ▀▀███▀▀▀██▄ ▀▀███▀▀▀██▄ ███ ███ + ███ ███ ███ ███ ███ ██▄ ███ ██▄ ███ ███ + ███ ▄███ ███ ███ ███ ███ ███ ███ ███ ███ + ████████▀ ████████▀ ▄█████████▀ ▄█████████▀ ▀██████▀ + + +dubbo>ls +As Provider side: ++----------------------------------+---+ +| Provider Service Name |PUB| ++----------------------------------+---+ +|org.apache.dubbo.demo.DemoService| N | ++----------------------------------+---+ +As Consumer side: ++---------------------+---+ +|Consumer Service Name|NUM| ++---------------------+---+ + +dubbo> +``` + +### 端口 +新版本的 telnet 端口 与 dubbo 协议的端口是不同的端口,默认为 `22222` + +可以通过配置文件`dubbo.properties` 修改: +``` +dubbo.application.qos-port=33333 +``` +或者 + +可以通过设置 JVM 参数: +``` +-Ddubbo.application.qos-port=33333 +``` + +### 安全 +默认情况下,dubbo 接收任何主机发起的命令 + +可以通过配置文件`dubbo.properties` 修改: +``` +dubbo.application.qos-accept-foreign-ip=false +``` + +或者 + +可以通过设置 JVM 参数: +``` +-Ddubbo.application.qos-accept-foreign-ip=false +``` +拒绝远端主机发出的命令,只允许服务本机执行。 + +同时可以通过设置`qos-accept-foreign-ip-whitelist`来指定支持的远端主机ip地址(段),多个ip地址(段)之间用**逗号**分隔,如: + +配置文件`dubbo.properties` +``` +dubbo.application.qos-accept-foreign-ip-whitelist=123.12.10.13, 132.12.10.13/24 +``` +设置 JVM 参数: +``` +-Ddubbo.application.qos-accept-foreign-ip-whitelist=123.12.10.13,132.12.10.13/24 +``` + +### 权限 +为了对生命周期探针的默认支持,QoS 提供了匿名访问的能力以及对权限级别的设置,目前支持的权限级别有: +- PUBLIC(1) + 默认支持匿名访问的命令权限级别,目前只支持生命周期探针相关的命令 +- PROTECTED(2) + 命令默认的权限级别 +- PRIVATE(3) + 保留的最高权限级别,目前未支持 +- NONE(4) + 最低权限级别,即不支持匿名访问 + +> 权限级别 `PRIVATE`> `PROTECTED`> `PUBLIC`> `NONE`, 高级别权限可访问同级别和低级别权限命令。 +当前以下命令权限为`PUBLIC`, 其它命令默认权限别为`PROTECTED`。 + +| 命令 | 权限等级 | +|---------------------------------------|-------------------| +| Live | PUBLIC (1) | +| Startup | PUBLIC (1) | +| Ready | PUBLIC (1) | +| Quit | PUBLIC (1)| + +默认情况下,dubbo 允许匿名主机发起匿名访问,只有`PUBLIC`权限级别的命令可以执行,其他更高权限的命令会被拒绝。 + +**关闭匿名访问** +可以通过设置`qos-anonymous-access-permission-level=NONE`来关闭匿名访问。 + +**设置权限级别** +可以通过配置文件`dubbo.properties` 修改: +``` +dubbo.application.qos-anonymous-access-permission-level=PROTECTED +``` +或者 + +可以通过设置 JVM 参数: +``` +-Ddubbo.application.qos-anonymous-access-permission-level=PROTECTED +``` +来允许匿名访问更高级别的权限的命令。 + + +``` +➜ ~ curl "localhost:22222/ls?arg1=xxx&arg2=xxxx" +As Provider side: ++----------------------------------+---+ +| Provider Service Name |PUB| ++----------------------------------+---+ +|org.apache.dubbo.demo.DemoService| N | ++----------------------------------+---+ +As Consumer side: ++---------------------+---+ +|Consumer Service Name|NUM| ++---------------------+---+ +``` +## 配置方式 +> 优先顺序: **系统属性 > dubbo.properties > XML/Spring-boot 自动装配** + +### 系统属性 +``` +-Ddubbo.application.qos-enable=true +-Ddubbo.application.qos-port=33333 +-Ddubbo.application.qos-accept-foreign-ip=false +-Ddubbo.application.qos-accept-foreign-ip-whitelist=123.12.10.13,132.12.10.13/24 +-Ddubbo.application.qos-anonymous-access-permission-level=PUBLIC +``` + +### dubbo.properties +在项目的`src/main/resources`目录下添加 dubbo.properties文件,内容如下: +``` +dubbo.application.qos-enable=true +dubbo.application.qos-port=33333 +dubbo.application.qos-accept-foreign-ip=false +dubbo.application.qos-accept-foreign-ip-whitelist=123.12.10.13, 132.12.10.13/24 +dubbo.application.qos-anonymous-access-permission-level=PUBLIC +``` + +### XML +如果要通过 XML 配置响应的QoS相关的参数,可以进行如下配置: +```xml + + + + + + + + + + + + + + +``` + +### spring-boot 自动装配 +如果是 spring-boot 的应用,可以在`application.properties`或者`application.yml`上配置: + +``` +dubbo.application.qos-enable=true +dubbo.application.qos-port=33333 +dubbo.application.qos-accept-foreign-ip=false +dubbo.application.qos-accept-foreign-ip-whitelist=123.12.10.13, 132.12.10.13/24 +dubbo.application.qos-anonymous-access-permission-level=NONE + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/qos-list.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/qos-list.md new file mode 100644 index 000000000000..7be8be1602f8 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/qos-list.md @@ -0,0 +1,53 @@ +--- +aliases: + - /zh-cn/overview/mannual/java-sdk/reference-manual/qos/command/ +description: "QoS 命令列表、命令大全。" +linkTitle: 命令列表 +title: QoS 命令列表,命令大全 +type: docs +weight: 2 +--- + +| QoS 命令 | 说明 | telnet 用法示例 | http 用法示例 | +| --- | --- | --- | --- | +| cd | 设定服务上下文,cd 之后所有的命令都是针对该服务 | cd org.demo.DemoService | http://localhost:22222/cd?service=org.demo.DemoService | +| count | 展示服务或方法调用次数。暂时只支持 dubbo 协议,不支持 triple 协议;RpcStatus 实现依赖 Active/Limit Filter,需改造 | count org.demo.DemoService

count org.demo.DemoService methodName | http://localhost:22222/count?service=org.demo.DemoService&method=methodName | +| disableDetailProfiler | 关闭 RPC 调用 profiler 工具(细粒度版本) | disableDetailProfiler | http://localhost:22222/disableDetailProfiler | +| disableRouterSnapshot | 关闭 RPC 请求 Router 路由结果跟踪 | disableRouterSnapshot | http://localhost:22222/disableRouterSnapshot | +| disableSimpleProfiler | 关闭 RPC 调用 profiler 工具(粗粒度版) | disableSimpleProfiler | http://localhost:22222/disableSimpleProfiler | +| enableDetailProfiler | 开启 RPC 调用 profiler 工具(细粒度版本) | enableDetailProfiler | http://localhost:22222/enableDetailProfiler | +| enableRouterSnapshot | 开启 RPC 请求 Router 路由结果跟踪,有助于跟踪路由规则执行是否符合预期 | enableRouterSnapshot org.demo.DemoService | http://localhost:22222/enableRouterSnapshot?service=org.demo.DemoService | +| enableSimpleProfiler | 开启 RPC 调用 profiler 工具(粗粒度版) | enableSimpleProfiler | http://localhost:22222/enableSimpleProfiler | +| getAddress | 查看某个服务的有效 ip 地址列表 | getAddress org.demo.DemoService | http://localhost:22222/getAddress?service=org.demo.DemoService | +| getConfig | dump 当前应用的有效配置 | getConfig | http://localhost:22222/getConfig | +| getEnabledRouterSnapshot | 查看当前 “启用 Router 路由结果跟踪” 的服务列表 | getEnabledRouterSnapshot | http://localhost:22222/getEnabledRouterSnapshot | +| getRecentRouterSnapshot | 查看最近 32 条 “Router 路由结果跟踪” 数据 | getRecentRouterSnapshot | http://localhost:22222/getRecentRouterSnapshot | +| gracefulShutdown | 从注册中心下线当前 ip 实例注册的所有服务,与offline的区别是,该命令会同时通过 tcp 连接告知所有消费方停止调用此实例。

如要恢复,请执行 online 上线所有服务 | gracefulShutdown | http://localhost:22222/gracefulShutdown | +| help | 帮助命令 | help | http://localhost:22222/help | +| invoke | 调用某个 RPC 服务 | invoke org.demo.DemoService.methodName(1234, "abcd", {"prop":"value"}) | ? | +| live | 检查当前进程/服务是否存活,可配置为 kubernetes liveness | live | http://localhost:22222/live | +| loggerInfo | 查看当前日志 logger 配置 | loggerInfo | http://localhost:22222/loggerInfo | +| ls | 查看当前所有服务列表 | ls | http://localhost:22222/ls | +| metrics | 查看 metrics 指标,需开启metrics 统计才能看到数据。什么粒度? | metrics | http://localhost:22222/metrics | +| metrics_default | 查看 metrics 指标 ,需开启metrics 统计才能看到数据。什么粒度? | metrics_default | http://localhost:22222/metrics_default | +| offline | 从注册中心下线某个或多个服务(包含应用级和接口级地址) | offline

offline org.demo.DemoService | http://localhost:22222/offline

http://localhost:22222/offline?service=org.demo.DemoService | +| offlineApp | 从注册中心下线某个或多个服务(仅应用级) | offlineApp

offlineApp org.demo.DemoService | http://localhost:22222/offlineApp?service=org.demo.DemoService | +| offlineInterface | 从注册中心下线某个或多个服务(仅接口级) | offlineInterface

offlineInterface org.demo.DemoService | http://localhost:22222/offlineInterface?service=org.demo.DemoService | +| online | 将一个或多个服务注册到注册中心(包含应用级和接口级地址) | online

online org.demo.DemoService | http://localhost:22222/online?service=org.demo.DemoService | +| onlineApp | 将一个或多个服务注册到注册中心(仅应用级) | onlineApp

onlineApp org.demo.DemoService | http://localhost:22222/onlineApp?service=org.demo.DemoService | +| onlineInterface | 将一个或多个服务注册到注册中心(仅接口级) | onlineInterface

onlineInterface org.demo.DemoService | http://localhost:22222/onlineInterface?service=org.demo.DemoService | +| ps | 查看当前进程信息,包括监听的端口等 | ps | http://localhost:22222/ps | +| publishMetadata | 发布或更新当前应用Metadata数据(可用于手动更新应用级服务发现元数据)。publishMetadata 10 表示延迟 10s 发布。在3.3.0之前版本的命令为 publish-metadata | publishMetadata

publishMetadata 10 | http://localhost:22222/publishMetadata | +| pwd | 查看当前服务上下文,与 cd 配合使用 | pwd | http://localhost:22222/pwd | +| quit | 退出当前 telnet 命令 | quit | 无 | +| ready | 检查当前进程/服务是否准备就绪对外服务,可配置为 kubernetes readiness | ready | http://localhost:22222/ready | +| select | 调用方法?和invoke的关系? | ? | http://localhost:22222/? | +| serializeCheckStatus | 检查当前在序列化白名单中的类列表 | serializeCheckStatus | http://localhost:22222/serializeCheckStatus | +| serializeWarnedClasses | 检查当前在序列化警告名单中的类列表 | serializeWarnedClasses | http://localhost:22222/serializeWarnedClasses | +| setProfilerWarnPercent | 控制序列化报警频率(仅限在警告名单中的类) | setProfilerWarnPercent 0.75 | http://localhost:22222/setProfilerWarnPercent?k=0.75 | +| shutdown | 尝试关闭当前 Dubbo 应用(销毁所有资源,重启前无法恢复) | shutdown | http://localhost:22222/shutdown | +| startup | 检查当前进程/服务是否已经正常启动,可配置为 kubernetes startup | startup | http://localhost:22222/startup | +| switchLogLevel | 动态调整日志级别 | switchLogLevel debug | http://localhost:22222/switchLogLevel?k=debug | +| switchLogger | 切换日志logger组件。可用 logger 组件,可通过 loggerInfo 查看(切换前请务必确保应用已经加入相关组件依赖) | switchLogger log4j2 | http://localhost:22222/switchLogger?k=log4j2 | +| version | 查看当前使用的 Dubbo 框架版本 | version | http://localhost:22222/version | + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/_index.md new file mode 100755 index 000000000000..7d24bc99fd54 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/others/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/others/ +description: 注册中心 +linkTitle: 注册中心与服务发现 +title: 注册中心、服务发现与负载均衡 +type: docs +weight: 5 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/multiple-registry.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/multiple-registry.md new file mode 100644 index 000000000000..9c0a9e842745 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/multiple-registry.md @@ -0,0 +1,193 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/registry/multiple-registry/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/registry/multiple-registry/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-registry/ +description: 本文介绍了 Dubbo 的多注册中心支持及使用场景,如何通过多注册/多订阅实现跨区域服务部署、服务迁移等,也描述了同机房有限等跨机房流量调度的实现方式。 +linkTitle: 多注册中心 +title: 多注册中心 +type: docs +weight: 6 +--- + +## 1 关联服务与多注册中心 + +### 1.1 全局默认注册中心 + +Dubbo 注册中心和服务是独立配置的,通常开发者不用设置服务和注册中心组件之间的关联关系,Dubbo 框架会将自动执行以下动作: +* 对于所有的 Service 服务,向所有全局默认注册中心注册服务地址。 +* 对于所有的 Reference 服务,从所有全局默认注册中心订阅服务地址。 + +```yml +# application.yml (Spring Boot) +dubbo + registries + beijingRegistry + address: zookeeper://localhost:2181 + shanghaiRegistry + address: zookeeper://localhost:2182 +``` + +```java +@DubboService +public class DemoServiceImpl implements DemoService {} + +@DubboService +public class HelloServiceImpl implements HelloService {} +``` + +以上以 Spring Boot 开发为例(XML、API 方式类似)配置了两个全局默认注册中心 beijingRegistry 和 shanghaiRegistry,服务 DemoService 与 HelloService 会分别注册到两个默认注册中心。 + +除了上面讲到的框架自动为服务设置全局注册中心之外,有两种方式可以灵活调整服务与多注册中心间的关联。 + +### 1.2 设置全局默认注册中心 +```yml +# application.yml (Spring Boot) +dubbo + registries + beijingRegistry + address: zookeeper://localhost:2181 + default: true + shanghaiRegistry + address: zookeeper://localhost:2182 + default: false +``` + +`default` 用来设置全局默认注册中心,默认值为 `true` 即被视作全局注册中心。未指定注册中心 id 的服务将自动注册或订阅全局默认注册中心。 + +### 1.3 显示关联服务与注册中心 + +通过在 Dubbo 服务定义组件上增加 registry 配置,将服务与注册中心关联起来。 + +```java +@DubboServiceregistry = {"beijingRegistry"} +public class DemoServiceImpl implements DemoService {} + +@DubboServiceregistry = {"shanghaiRegistry"} +public class HelloServiceImpl implements HelloService {} +``` + +增加以上配置后,DemoService 将只注册到 beijingRegistry,而 HelloService 将注册到 shanghaiRegistry。 + +## 2 多注册中心订阅 + +服务订阅由于涉及到地址聚合和路由选址,因此逻辑会更加复杂一些。从单个服务订阅的视角,如果存在多注册中心订阅的情况,则可以根据注册中心间的地址是否聚合分为两种场景。 + +### 2.1 多注册中心地址不聚合 + +```xml + + +``` + +如以上所示独立配置的注册中心组件,地址列表在消费端默认是完全隔离的,负载均衡选址要经过两步: +1. 注册中心集群间选址,选定一个集群 +2. 注册中心集群内选址,在集群内进行地址筛选 + +![multi-registris-no-aggregation](/imgs/v3/registry/no-aggregation.png) + +下面我们着重分析下如何控制 **注册中心集群间选址**,可选的策略有如下几种 +**随机** +每次请求都随机的分配到一个注册中心集群 + +> 随机的过程中会有可用性检查,即每个集群要确保至少有一个地址可用才有可能被选到。 + +**preferred 优先** +```xml + + +``` +如果有注册中心集群配置了 `preferred="true"`,则所有流量都会被路由到这个集群。 + +**weighted** +```xml + + +``` + +基于权重的随机负载均衡,以上集群间会有大概 10:1 的流量分布。 + +**同 zone 优先** +```xml + + +``` + +```java +RpcContext.getContext().setAttachment("registry_zone", "qingdao"); +``` + +根据 Invocation 中带的流量参数或者在当前节点通过 context 上下文设置的参数,流量会被精确的引导到对应的集群。 + +除了通过 RpcContext 参数设置 zone 外,还可以通过扩展 `org.apache.dubbo.rpc.ZoneDetector` 实现,以更灵活的方式确定当前请求的 zone 归属。RuleConverter + +### 2.2 多注册中心地址聚合 +```xml + +``` + +这里增加了一个特殊的 multiple 协议开头的注册中心,其中: +* `multiple://127.0.0.1:2181` 并没有什么具体含义,只是一个特定格式的占位符,地址可以随意指定 +* `reference-registry` 指定了要聚合的注册中心集群的列表,示例中有两个集群,分别是 `zookeeper://address11?backup=address12,address13` 和 `zookeeper://address21?backup=address22,address23`,其中还特别指定了集群分隔符 `separator=";"` + +如下图所示,不同注册中心集群的地址会被聚合到一个地址池后在消费端做负载均衡或路由选址。 + +![multi-registris-aggregation](/imgs/v3/registry/aggregation.png) + +在 3.1.0 版本及之后,还支持每个注册中心集群上设置特定的 attachments 属性,以实现对该注册中心集群下的地址做特定标记,后续配合 Router 组件扩展如 TagRouter 等就可以实现跨机房间的流量治理能力。 + +```xml + +``` + +增加 `attachments=zone=hangzhou,tag=middleware` 后,所有来自该注册中心的 URL 地址将自动携带 `zone` 和 `tag` 两个标识,方便消费端更灵活的做流量治理。 + +## 3 场景示例 + +### 3.1 场景一:跨区域注册服务 + +比如:中文站有些服务来不及在青岛部署,只在杭州部署,而青岛的其它应用需要引用此服务,就可以将服务同时注册到两个注册中心。 + +```xml + + + + +``` + +### 3.2 场景二:根据业务实现隔离 + +CRM 有些服务是专门为国际站设计的,有些服务是专门为中文站设计的。 + +```xml + + + + + + + +``` + +### 3.3 场景三:根据业务调用服务 + +CRM 需同时调用中文站和国际站的 PC2 服务,PC2 在中文站和国际站均有部署,接口及版本号都一样,但连的数据库不一样。 + +```xml + + + + + + + +``` + +如果只是测试环境临时需要连接两个不同注册中心,使用竖号分隔多个不同注册中心地址: + +```xml + + + + +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/nacos.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/nacos.md new file mode 100644 index 000000000000..98edcb84973d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/nacos.md @@ -0,0 +1,210 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ +description: "通过示例演示如何使用 Nacos 作为注册中心实现自动服务发现。" +linkTitle: nacos +title: 使用 Nacos 作为注册中心实现自动服务发现 +type: docs +weight: 4 +--- + +本示例演示 Nacos 作为注册中心实现自动服务发现,示例基于 Spring Boot 应用展开,可在此查看 [完整示例代码](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-nacos) + +## 1 基本配置 + +### 1.1 增加依赖 + +对于 Spring Boot 应用,可以使用如下 spring-boot-starter: +```xml + + org.apache.dubbo + dubbo-spring-boot-starter + 3.3.0 + + + org.apache.dubbo + dubbo-nacos-spring-boot-starter + 3.3.0 + +``` + +非 Spring Boot 用户,可以自行增加 dubbo、nacos-client 依赖: +```xml + + + org.apache.dubbo + dubbo + 3.3.0 + + + com.alibaba.nacos + nacos-client + 2.1.0 + + +``` + +### 1.2 Nacos 版本 +Nacos 版本映射关系: +| Dubbo | 推荐 Nacos 版本 | Nacos 兼容范围 | +| --- | --- | --- | +| 3.3.0 | 2.3.0 | 2.x | +| 3.2.21 | 2.1.0 | 2.x | +| 3.1.11 | 2.0.9 | 2.x | +| 3.0.10 | 2.0.9 | 2.x | +| 2.7.21 | 1.x最新版本 | 1.x | +| 2.6.0 | 1.x最新版本 | 1.x | + +### 1.3 配置并启用 Nacos + +```yaml +# application.yml (Spring Boot) +dubbo + registry + address: nacos://localhost:8848 +``` +或 +```properties +# dubbo.properties +dubbo.registry.address=nacos://localhost:8848 +``` +或 +```xml + +``` + +## 2 高级配置 + +### 2.1 认证 + +```yaml +# application.yml (Spring Boot) +dubbo + registry + address: nacos://localhost:8848?username=nacos&password=nacos +``` + +或 + +```properties +# dubbo.properties +dubbo.registry.address: nacos://nacos:nacos@localhost:8848 +``` + +### 2.2 自定义命名空间 + +```yaml +# application.yml (Spring Boot) +dubbo: + registry: + address: nacos://localhost:8848?namespace=5cbb70a5-xxx-xxx-xxx-d43479ae0932 +``` + +或者 + +```yaml +# application.yml (Spring Boot) +dubbo: + registry: + address: nacos://localhost:8848 + parameters.namespace: 5cbb70a5-xxx-xxx-xxx-d43479ae0932 +``` + +### 2.3 自定义分组 + +```yaml +# application.yml +dubbo: + registry: + address: nacos://localhost:8848 + group: dubbo +``` + +> 如果不配置的话,group 是由 Nacos 默认指定。group 和 namespace 在 Nacos 中代表不同的隔离层次,通常来说 namespace 用来隔离不同的用户或环境,group 用来对同一环境内的数据做进一步归组。 + +### 2.4 注册接口级消费者 +Dubbo 3.0.0 版本以后,增加了是否注册消费者的参数,如果需要将消费者注册到 nacos 注册中心上,需要将参数(register-consumer-url)设置为true,默认是false。 +```yaml +# application.yml +dubbo: + registry: + address: nacos://localhost:8848?register-consumer-url=true +``` +或者 +```yaml +# application.yml +dubbo: + registry: + address: nacos://localhost:8848 + parameters.register-consumer-url: true +``` + +### 2.5 更多配置 + +参数名 | 中文描述| 默认值 +---|---|--- +username|连接Nacos Server的用户名|nacos +paasword|连接Nacos Server的密码|nacos +backup|备用地址|空 +namespace|命名空间的ID|public +group|分组名称|DEFAULT_GROUP +register-consumer-url|是否注册消费端|false +com.alibaba.nacos.naming.log.filename|初始化日志文件名|naming.log +endpoint|连接Nacos Server指定的连接点,可参考[文档](https://nacos.io/zh-cn/blog/address-server.html)|空 +endpointPort|连接Nacos Server指定的连接点端口,可以参考[文档](https://nacos.io/zh-cn/blog/address-server.html)|空 +endpointQueryParams|endpoint查参数询|空 +isUseCloudNamespaceParsing|是否解析云环境中的namespace参数|true +isUseEndpointParsingRule|是否开启endpoint 参数规则解析|true +namingLoadCacheAtStart|启动时是否优先读取本地缓存|true +namingCacheRegistryDir|指定缓存子目录,位置为 .../nacos/{SUB_DIR}/naming|空 +namingClientBeatThreadCount|客户端心跳的线程池大小|机器的CPU数的一半 +namingPollingThreadCount|客户端定时轮询数据更新的线程池大小|机器的CPU数的一半 +namingRequestDomainMaxRetryCount|client通过HTTP向Nacos Server请求的重试次数|3 +namingPushEmptyProtection|在服务没有有效(健康)实例时,是否开启保护,开启后则会使用旧的服务实例|false +push.receiver.udp.port|客户端UDP的端口|空 + +在nacos-server@`1.0.0`版本后,支持客户端通过上报一些包含特定的元数据的实例到服务端来控制实例的一些行为。 + +参数名 | 中文描述| 默认值 +---|---|--- +preserved.heart.beat.timeout|该实例在不发送心跳后,从健康到不健康的时间(毫秒)|15000 +preserved.ip.delete.timeout|该实例在不发送心跳后,被服务端下掉该实例的时间(毫秒)|30000 +preserved.heart.beat.interval|该实例在客户端上报心跳的间隔时间(毫秒)|5000 +preserved.instance.id.generator|该实例的id生成策略,值为`snowflake`时,从0开始增加|simple +preserved.register.source|注册实例注册时服务框架类型(例如Dubbo,Spring Cloud等)|空 + + 这些参数都可以类似 `namespace` 的方式通过通过参数扩展配置到 Nacos,如 + + ```properties + dubbo.registry.parameters.preserved.heart.beat.timeout=5000 + ``` + +## 3 工作原理 + +在前面的一节中,我们讲解了应用级服务发现与接口级服务发现的区别,以下是两种模式在 Nacos 实现中的具体存储结构。 + +### 3.1 Dubbo2 注册数据 + +随后,重启您的 Dubbo 应用,Dubbo 的服务提供和消费信息在 Nacos 控制台中可以显示: + +![dubbo-registry-nacos-1.png](/imgs/blog/dubbo-registry-nacos-1.png) + +如图所示,服务名前缀为 `providers:` 的信息为服务提供者的元信息,`consumers:` 则代表服务消费者的元信息。点击“**详情**”可查看服务状态详情: + +![image-dubbo-registry-nacos-2.png](/imgs/blog/dubbo-registry-nacos-2.png) + +### 3.2 Dubbo3 注册数据 +应用级服务发现的 "服务名" 为应用名 + +> Dubbo3 默认采用 "应用级服务发现 + 接口级服务发现" 的双注册模式,因此会发现应用级服务(应用名)和接口级服务(接口名)同时出现在 Nacos 控制台,可以通过配置 `dubbo.registry.register-mode=instance/interface/all` 来改变注册行为。 + +### 3.3 客户端缓存 + +### 3.4 心跳检测 + +### 3.5 + + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/_index.md new file mode 100755 index 000000000000..11c5e2e0865b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/others/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/others/ +description: 注册中心 +linkTitle: 扩展实现 +title: 注册中心、服务发现与负载均衡 +type: docs +weight: 100 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/consul.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/consul.md new file mode 100644 index 000000000000..406b76ed516a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/consul.md @@ -0,0 +1,53 @@ +--- +description: Consul 注册中心的基本使用和工作原理。 +linkTitle: Consul +title: Consul +type: docs +weight: 5 +--- + + +## 前置条件 +* 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/starter/) +* 安装并启动 [Consul](http://consul.io) 服务 + +## 使用说明 + +### 添加依赖 + +从 Dubbo3 开始,consul 注册中国适配已经不再内嵌在 Dubbo 中,使用前需要单独引入独立的[模块](/zh-cn/download/spi-extensions/#dubbo-registry)。 + +```xml + + org.apache.dubbo.extensions + dubbo-registry-consul + 3.3.0 + +``` + +### 基本配置 +```xml + +``` + +或 + +```xml + +``` + +或 + +```xml + +``` + +或 + +```xml + +``` + +## 使用场景 + +使用 Consul 作为共享注册中心实现,可用于 [Dubbo 与 Spring Cloud 体系的互通或迁移](/zh-cn/blog/2023/10/07/微服务最佳实践零改造实现-spring-cloud-apache-dubbo-互通/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/etcd.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/etcd.md new file mode 100644 index 000000000000..aa8475231df5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/etcd.md @@ -0,0 +1,50 @@ +--- +description: Etcd 注册中心的基本使用和工作原理。 +linkTitle: Etcd +title: Etcd +type: docs +weight: 5 +--- + + + +## 前置条件 +* 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/starter/) +* 安装并启动 Etcd 服务 + +## 使用说明 + +### 添加依赖 + +从 Dubbo3 开始,etcd 注册中心适配已经不再内嵌在 Dubbo 中,使用前需要单独引入独立的[模块](/zh-cn/download/spi-extensions/#dubbo-registry)。 + +```xml + + org.apache.dubbo.extensions + dubbo-registry-etcd + 3.3.0 + +``` + +### 基本配置 +```xml + +``` + +或 + +```xml + +``` + +或 + +```xml + +``` + +或 + +```xml + +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/multicast.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/multicast.md new file mode 100644 index 000000000000..6abd7d91df08 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/multicast.md @@ -0,0 +1,61 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/registry/multicast/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/registry/multicast/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/registry/multicast/ +description: Multicast 广播注册中心(限开发阶段使用)。 +linkTitle: Multicast +title: Multicast +type: docs +weight: 4 +--- + + + + + + +Multicast 注册中心不需要启动任何中心节点,只要广播地址一样,就可以互相发现。 + +![/user-guide/images/multicast.jpg](/imgs/user/multicast.jpg) + +## 1 使用说明 + +```xml + +``` + +或 + +```xml + +``` +#### 注意: +为了减少广播量,Dubbo 缺省使用单播发送提供者地址信息给消费者。 +如果一个机器上同时启了多个消费者进程,消费者需声明 `unicast=false`,否则只会有一个消费者能收到消息; 当服务者和消费者运行在同一台机器上,消费者同样需要声明`unicast=false`,否则消费者无法收到消息,导致No provider available for the service异常: + +```xml + + + +``` + +或 + +```xml + + + +``` + + +## 2 工作原理 + +### 2.1 基本流程 +0. 提供方启动时广播自己的地址 +1. 消费方启动时广播订阅请求 +2. 提供方收到订阅请求时,单播自己的地址给订阅者,如果设置了 `unicast=false`,则广播给订阅者 +3. 消费方收到提供方地址时,连接该地址进行 RPC 调用。 + +### 2.2 使用限制 +组播受网络结构限制,只适合小规模应用或开发阶段使用。组播地址段: 224.0.0.0 - 239.255.255.255 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/redis.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/redis.md new file mode 100644 index 000000000000..8a05e862de48 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/redis.md @@ -0,0 +1,94 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/registry/redis/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/registry/redis/ + - /zh-cn/overview/what/ecosystem/registry/redis/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/registry/redis/ +description: Redis 注册中心的基本使用和工作原理。 +linkTitle: Redis +title: Redis +type: docs +weight: 5 +--- + + + +## 前置条件 +* 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/starter/) +* 安装并启动 [Redis](http://redis.io) 服务 + +## 使用说明 + +### 添加依赖 + +从 Dubbo3 开始,redis 注册中心适配已经不再内嵌在 Dubbo 中,使用前需要单独引入独立的[模块](/zh-cn/download/spi-extensions/#dubbo-registry)。 + +```xml + + org.apache.dubbo.extensions + dubbo-registry-redis + 3.3.0 + +``` + +### 基本配置 +```xml + +``` + +或 + +```xml + +``` + +或 + +```xml + +``` + +或 + +```xml + +``` + +### 其他配置项 + +* 可通过 `` 设置 redis 中 key 的前缀,缺省为 `dubbo`。 +* 可通过 `` 设置 redis 集群策略,缺省为 `failover`: + * `failover`: 只写入和读取任意一台,失败时重试另一台,需要服务器端自行配置数据同步 + * `replicate`: 在客户端同时写入所有服务器,只读取单台,服务器端不需要同步,注册中心集群增大,性能压力也会更大 + + +## 工作原理 + +基于 Redis [^1] 实现的注册中心。 + +Redis 过期数据通过心跳的方式检测脏数据,服务器时间必须同步,并且对服务器有一定压力,否则过期检测会不准确 + +![/user-guide/images/dubbo-redis-registry.jpg](/imgs/user/dubbo-redis-registry.jpg) + +使用 Redis 的 Key/Map 结构存储数据结构: + +* 主 Key 为服务名和类型 +* Map 中的 Key 为 URL 地址 +* Map 中的 Value 为过期时间,用于判断脏数据,脏数据由监控中心删除 [^3] + +使用 Redis 的 Publish/Subscribe 事件通知数据变更: + +* 通过事件的值区分事件类型:`register`, `unregister`, `subscribe`, `unsubscribe` +* 普通消费者直接订阅指定服务提供者的 Key,只会收到指定服务的 `register`, `unregister` 事件 +* 监控中心通过 `psubscribe` 功能订阅 `/dubbo/*`,会收到所有服务的所有变更事件 + +调用过程: + +0. 服务提供方启动时,向 `Key:/dubbo/com.foo.BarService/providers` 下,添加当前提供者的地址 +1. 并向 `Channel:/dubbo/com.foo.BarService/providers` 发送 `register` 事件 +2. 服务消费方启动时,从 `Channel:/dubbo/com.foo.BarService/providers` 订阅 `register` 和 `unregister` 事件 +3. 并向 `Key:/dubbo/com.foo.BarService/consumers` 下,添加当前消费者的地址 +4. 服务消费方收到 `register` 和 `unregister` 事件后,从 `Key:/dubbo/com.foo.BarService/providers` 下获取提供者地址列表 +5. 服务监控中心启动时,从 `Channel:/dubbo/*` 订阅 `register` 和 `unregister`,以及 `subscribe` 和`unsubsribe `事件 +6. 服务监控中心收到 `register` 和 `unregister` 事件后,从 `Key:/dubbo/com.foo.BarService/providers` 下获取提供者地址列表 +7. 服务监控中心收到 `subscribe` 和 `unsubsribe` 事件后,从 `Key:/dubbo/com.foo.BarService/consumers` 下获取消费者地址列表 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/overview.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/overview.md new file mode 100644 index 000000000000..2fe82a1643fa --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/overview.md @@ -0,0 +1,89 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/registry/overview/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/registry/overview/ +description: "" +linkTitle: 注册中心概述 +title: 注册中心概述 +type: docs +weight: 1 +--- + + +注册中心是 Dubbo 服务治理的核心组件,Dubbo 依赖注册中心的协调实现服务(地址)发现,自动化的服务发现是微服务实现动态扩缩容、负载均衡、、流量治理的基础。Dubbo 的服务发现机制经历了 Dubbo2 时代的接口级服务发现、Dubbo3 时代的应用级服务发现,具体可参见 [服务发现机制](/zh-cn/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/) 解析了解具体演进过程。 + +![service-discovery](/imgs/v3/feature/service-discovery/arc.png) + +## 基本使用 +开发应用时可以指定 Dubbo 注册中心(registry)组件,配置很简单,只需指定注册中心的集群地址即可: + +以 Spring Boot 开发为例,在 application.yml 增加 registry 配置项目 + +```yaml +dubbo + registry + address: {protocol}://{cluster-address} +``` +其中,protocol 为选择的配置中心类型,cluster-address 为访问注册中心的集群地址,如 + +`address: nacos://localhost:8848` + +如需集群格式地址可使用 backup 参数 + +`address: nacos://localhost:8848?backup=localshot:8846,localshot:8847` + +{{% alert title="流的语义保证" color="info" %}} +3.3.0 及之后的版本可不配置注册中心。而在 3.3.0 版本之前的 Dubbo 应用必须指定注册中心配置,即使不启用注册中心也要配置(可通过设置地址为空 address='N/A' )。 +{{% /alert %}} + +每个注册中心组件有自己特有的配置,可以用来控制命名空间、分组、鉴权等,具体可以参考 [registry 配置参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#registry)或通过 parameters 参数进行扩展。 + +## 配置中心与元数据中心 +配置中心、元数据中心是实现 Dubbo 高阶服务治理能力会依赖的组件,如流量管控规则等,相比于注册中心通常这两个组件的配置是可选的。 + +需要注意的是,**对于部分注册中心类型(如 Zookeeper、Nacos 等),Dubbo 会默认同时将其用作元数据中心和配置中心(建议保持默认开启状态)。** + +```yaml +dubbo + registry + address: nacos://localhost:8848 +``` + +框架解析后的默认行为: + +```yaml +dubbo + registry + address: nacos://localhost:8848 + config-center + address: nacos://localhost:8848 + metadata-report + address: nacos://localhost:8848 +``` + +如果您不想使用 nacos 作为配置中心,可以通过以下两个参数来调整或控制默认行为: + +```yaml +dubbo + registry + address: nacos://localhost:8848 + use-as-config-center: false + use-as-metadata-report: false + config-center + address: apollo://localhost:8848 +``` + +## 注册中心生态 +Dubbo 目前支持的主流注册中心实现包括: +* Zookeeper +* Nacos +* Redis +* Consul +* Etcd +* 更多实现 + +同时也支持 Kubernetes、Mesh 体系的服务发现,具体请参考 [使用教程 - kubernetes部署](http://localhost:1313/zh-cn/overview/mannual/java-sdk/tasks/deploy/) + +另外,[Dubbo 扩展生态](https://github.com/apache/dubbo-spi-extensions) 还提供了 Consul、Eureka、Etcd 等注册中心扩展实现。也欢迎通过 [registry spi 扩展](../../spi/) 贡献更多的注册中心实现到 Dubbo 生态。 + +Dubbo 还支持在一个应用中 [指定多个注册中心](../multiple-registry/),并将服务根据注册中心分组,这样做使得服务分组管理或服务迁移变得更容易。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/service-discovery-application-vs-interface.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/service-discovery-application-vs-interface.md new file mode 100644 index 000000000000..577d06b2cd9e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/service-discovery-application-vs-interface.md @@ -0,0 +1,390 @@ +--- +description: "本文介绍了 Dubbo 应用级服务发现与接口级服务发现的详细设计与实现。" +linkTitle: 应用级vs接口级 +title: 应用级服务发现 vs 接口级服务发现 +type: docs +weight: 6 +--- + +Dubbo3 目前支持,其中接口级服务发现 + +## 应用级服务发现 + +### 设计目标 +* 显著降低服务发现过程的资源消耗,包括提升注册中心容量上限、降低消费端地址解析资源占用等,使得 Dubbo3 框架能够支持更大规模集群的服务治理,实现无限水平扩容。 +* 适配底层基础设施服务发现模型,如 Kubernetes、Service Mesh 等。 + +### 对比接口级 +![interface-arc](/imgs/blog/proposals/discovery/arc.png) + +我们从 Dubbo 最经典的工作原理图说起,Dubbo 从设计之初就内置了服务地址发现的能力,Provider 注册地址到注册中心,Consumer 通过订阅实时获取注册中心的地址更新,在收到地址列表后,consumer 基于特定的负载均衡策略发起对 provider 的 RPC 调用。 + +在这个过程中: +* 每个 Provider 通过特定的 key 向注册中心注册本机可访问地址; +* 注册中心通过这个 key 对 provider 实例地址进行聚合; +* Consumer 通过同样的 key 从注册中心订阅,以便及时收到聚合后的地址列表; + +![interface-data1](/imgs/blog/proposals/discovery/interface-data1.png) + +这里,我们对接口级地址发现的内部数据结构进行详细分析。 + +首先,看右下角 provider 实例内部的数据与行为。Provider 部署的应用中通常会有多个 Service,也就是 Dubbo2 中的服务,每个 service 都可能会有其独有的配置,我们所讲的 service 服务发布的过程,其实就是基于这个服务配置生成地址 URL 的过程,生成的地址数据如图所示;同样的,其他服务也都会生成地址。 + +然后,看一下注册中心的地址数据存储结构,注册中心以 service 服务名为数据划分依据,将一个服务下的所有地址数据都作为子节点进行聚合,子节点的内容就是实际可访问的ip地址,也就是我们 Dubbo 中 URL,格式就是刚才 provider 实例生成的。 + +![interface-data2](/imgs/blog/proposals/discovery/interface-data2.png) + +这里把 URL 地址数据划分成了几份: +* 首先是实例可访问地址,主要信息包含 ip port,是消费端将基于这条数据生成 tcp 网络链接,作为后续 RPC 数据的传输载体 +* 其次是 RPC 元数据,元数据用于定义和描述一次 RPC 请求,一方面表明这条地址数据是与某条具体的 RPC 服务有关的,它的版本号、分组以及方法相关信息,另一方面表明 +* 下一部分是 RPC 配置数据,部分配置用于控制 RPC 调用的行为,还有一部分配置用于同步 Provider 进程实例的状态,典型的如超时时间、数据编码的序列化方式等。 +* 最后一部分是自定义的元数据,这部分内容区别于以上框架预定义的各项配置,给了用户更大的灵活性,用户可任意扩展并添加自定义元数据,以进一步丰富实例状态。 + +结合以上两页对于 Dubbo2 接口级地址模型的分析,以及最开始的 Dubbo 基本原理图,我们可以得出这么几条结论: +* 第一,地址发现聚合的 key 就是 RPC 粒度的服务 +* 第二,注册中心同步的数据不止包含地址,还包含了各种元数据以及配置 +* 得益于 1 与 2,Dubbo 实现了支持应用、RPC 服务、方法粒度的服务治理能力 + +这就是一直以来 Dubbo2 在易用性、服务治理功能性、可扩展性上强于很多服务框架的真正原因。 + +![interface-defect](/imgs/blog/proposals/discovery/interface-defect.png) + +一个事物总是有其两面性,Dubbo2 地址模型带来易用性和强大功能的同时,也给整个架构的水平可扩展性带来了一些限制。这个问题在普通规模的微服务集群下是完全感知不到的,而随着集群规模的增长,当整个集群内应用、机器达到一定数量时,整个集群内的各个组件才开始遇到规模瓶颈。在总结包括阿里巴巴、工商银行等多个典型的用户在生产环境特点后,我们总结出以下两点突出问题(如图中红色所示): +* 首先,注册中心集群容量达到上限阈值。由于所有的 URL 地址数据都被发送到注册中心,注册中心的存储容量达到上限,推送效率也随之下降。 +* 而在消费端这一侧,Dubbo2 框架常驻内存已超 40%,每次地址推送带来的 cpu 等资源消耗率也非常高,影响正常的业务调用。 + +为什么会出现这个问题?我们以一个具体 provider 示例进行展开,来尝试说明为何应用在接口级地址模型下容易遇到容量问题。 +青蓝色部分,假设这里有一个普通的 Dubbo Provider 应用,该应用内部定义有 10 个 RPC Service,应用被部署在 100 个机器实例上。这个应用在集群中产生的数据量将会是 “Service 数 * 机器实例数”,也就是 10 * 100 = 1000 条。数据被从两个维度放大: +* 从地址角度。100 条唯一的实例地址,被放大 10 倍 +* 从服务角度。10 条唯一的服务元数据,被放大 100 倍 + +### 详细设计 + +![app-principle](/imgs/blog/proposals/discovery/app-principle.png) + +面对这个问题,在 Dubbo3 架构下,我们不得不重新思考两个问题: +* 如何在保留易用性、功能性的同时,重新组织 URL 地址数据,避免冗余数据的出现,让 Dubbo3 能支撑更大规模集群水平扩容? +* 如何在地址发现层面与其他的微服务体系如 Kubernetes、Spring Cloud 打通? + +![app-data1](/imgs/blog/proposals/discovery/app-data1.png) + +Dubbo3 的应用级服务发现方案设计本质上就是围绕以上两个问题展开。其基本思路是:地址发现链路上的聚合元素也就是我们之前提到的 Key 由服务调整为应用,这也是其名称叫做应用级服务发现的由来;另外,通过注册中心同步的数据内容上做了大幅精简,只保留最核心的 ip、port 地址数据。 + +![app-data2](/imgs/blog/proposals/discovery/app-data2.png) + +这是升级之后应用级地址发现的内部数据结构进行详细分析。 +对比之前接口级的地址发现模型,我们主要关注橙色部分的变化。首先,在 provider 实例这一侧,相比于之前每个 RPC Service 注册一条地址数据,一个 provider 实例只会注册一条地址到注册中心;而在注册中心这一侧,地址以应用名为粒度做聚合,应用名节点下是精简过后的 provider 实例地址; + +![app-metadataservice](/imgs/blog/proposals/discovery/app-metadataservice.png) + +应用级服务发现的上述调整,同时实现了地址单条数据大小和总数量的下降,但同时也带来了新的挑战:我们之前 Dubbo2 强调的易用性和功能性的基础损失了,因为元数据的传输被精简掉了,如何精细的控制单个服务的行为变得无法实现。 + +针对这个问题,Dubbo3 的解法是引入一个内置的 MetadataService 元数据服务,由中心化推送转为 Consumer 到 Provider 的点对点拉取,在这个模式下,元数据传输的数据量将不在是一个问题,因此可以在元数据中扩展出更多的参数、暴露更多的治理数据。 + +![app-metadataservice](/imgs/blog/proposals/discovery/app-workflow.png) + +这里我们个重点看消费端 Consumer 的地址订阅行为,消费端从分两步读取地址数据,首先是从注册中心收到精简后的地址,随后通过调用 MetadataService 元数据服务,读取对端的元数据信息。在收到这两部分数据之后,消费端会完成地址数据的聚合,最终在运行态还原出类似 Dubbo2 的 URL 地址格式。因此从最终结果而言,应用级地址模型同时兼顾了地址传输层面的性能与运行层面的功能性。 + +以上就是的应用级服务发现背景、工作原理部分的所有内容。 + + +## 接口级服务发现 + +接口级服务发现在 Dubbo3 实现中被继续保留了下来,并且继续作为框架默认的服务发现模型,这主要是考虑对于老版本的兼容性。在未来版本中,我们会将默认模型切换为应用级别服务发现。 + +{{% alert title="解决接口级服务发现性能问题" color="info" %}} +如果您的集群规模足够大,已经遇到了接口级服务发现中的性能瓶颈问题,并且您暂时无法切换到应用级服务发现。可以暂时通过简化 URL 参数达到性能优化的目的。 +{{% /alert %}} + +### URL参数简化 +**设计目标与宗旨:** +1. 期望简化进入注册中心的 provider 和 consumer 配置数量。 +2. 期望将部分配置项以其他形式存储。这些配置项需要满足:不在服务调用链路上,同时这些配置项不在注册中心的核心链路上(服务查询,服务列表)。 + +Dubbo provider 中的服务配置项有接近 [30 个配置项](/zh-cn/docs/references/xml/dubbo-parameter)。 排除注册中心服务治理需要之外,很大一部分配置项是 provider 自己使用,不需要透传给消费者。这部分数据不需要进入注册中心,而只需要以 key-value 形式持久化存储。 + +Dubbo consumer 中的配置项也有 [20+个配置项](/zh-cn/docs/references/xml/dubbo-consumer)。在注册中心之中,服务消费者列表中只需要关注 application,version,group,ip,dubbo 版本等少量配置,其他配置也可以以 key-value 形式持久化存储。 +这些数据是以服务为维度注册进入注册中心,导致了数据量的膨胀,进而引发注册中心 (如 zookeeper) 的网络开销增大,性能降低。 + +{{% alert title="注意" color="warning" %}} +简化注册中心的配置,只在 2.7 之后的版本中进行支持。 +{{% /alert %}} + +以下是开启 provider 或者 consumer 简化配置之后,URL 中默认保留的配置项: + +**provider 侧:** + +| 源码静态变量 | URL Key | 说明 | +| ------ |---------------| ------ | +| APPLICATION_KEY | application | | +| CODEC_KEY | codec | | +| EXCHANGER_KEY | exchanger | | +| SERIALIZATION_KEY | serialization | | +| CLUSTER_KEY | cluster | | +| CONNECTIONS_KEY | connections | | +| DEPRECATED_KEY | deprecated | | +| GROUP_KEY | group | | +| LOADBALANCE_KEY | loadbalance | | +| MOCK_KEY | mock | | +| PATH_KEY | path | | +| TIMEOUT_KEY | timeout | | +| TOKEN_KEY | token | | +| VERSION_KEY | version | | +| WARMUP_KEY | warmup | | +| WEIGHT_KEY | weight | | +| DUBBO_VERSION_KEY | dubbo | | +| RELEASE_KEY | release | | +| SIDE_KEY | side | | + + +**consumer 侧:** + +| 源码静态变量 | URL Key | 说明 | +| ------ | ------ | ------ | +| APPLICATION_KEY | application | | +| VERSION_KEY | version | | +| GROUP_KEY | group | | +| DUBBO_VERSION_KEY | dubbo | | + +下面我们通过示例介绍如何开启 URL 简化模式使,所有内容都可以 [在 sample 中查看源码](https://github.com/dubbo/dubbo-samples/tree/master)。 + +#### 如何开启URL精简(示例使用方式) + +我们接下来从没开启 URL 精简的示例开始,分别对比开启 URL 精简的 Provider 和开启 URL 精简的 Consumer + +##### 未开启 URL 精简的示例 + +工程源码 [dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-nosimple](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-nosimple)。注意,跑 sample 前,先跑下 ZKClean 进行配置项清理。 + +dubbo-provider.xml + +``` + + + + +``` + +启动 provider 的 main 方法之后,查看 zookeeper 的叶子节点(路径为:/dubbo/org.apache.dubbo.samples.simplified.registry.nosimple.api.DemoService/providers 目录下)的内容 + +``` +dubbo://30.5.124.158:20880/org.apache.dubbo.samples.simplified.registry.nosimple.api.DemoService +?anyhost=true +&application=simplified-registry-xml-provider +&async=true +&dubbo=2.0.2 +&executes=4500 +&generic=false +&group=dubbo-simple +&interface=org.apache.dubbo.samples.simplified.registry.nosimple.api.DemoService +&methods=sayHello +&owner=vict +&pid=2767 +&retries=7 +&revision=1.2.3 +&side=provider +&timeout=5300 +×tamp=1542361152795 +&valid=true +&version=1.2.3 +``` + +从中能看到有:`executes`, `retries`, `owner`, `timeout`。但是这些字段不是每个都需要传递给 dubbo ops 或者 dubbo consumer。 同样的,consumer 也有这个问题,可以在例子中启动 Consumer 的 main 方法进行查看。 + + +##### 开启 URL 精简的示例 (XML模式) + +工程源码 [dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-xml](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-xml)。注意,跑 sample 前,先跑下 ZKClean 进行配置项清理。 + + +```properties +dubbo.registry.simplified=true +dubbo.registry.extra-keys=retries,owner +``` +和上面的 **现有功能 sample** 进行对比,上面的 sample 中,executes, retries, owner, timeout 四个配置项都进入了注册中心。但是本实例不是,配置情况分为: + +* 配置:dubbo.registry.simplified=true, 默认情况下,timeout 在默认的配置项列表,所以还是会进入注册中心; +* 配置:dubbo.registry.extra-keys=retries,owner , 所以 retries,owner 也会进入注册中心。 + +**1. provider 端** + +```xml + + + + + + + + +``` +得到的 zookeeper 的叶子节点的值 +``` +dubbo://30.5.124.149:20880/org.apache.dubbo.samples.simplified.registry.nosimple.api.DemoService +?application=simplified-registry-xml-provider +&dubbo=2.0.2 +&group=dubbo-simple +&owner=vict +&retries=7 +&timeout=5300 +×tamp=1542594503305 +&version=1.2.3 +``` + +**2. consumer 端** + +* 配置:dubbo.registry.simplified=true +* 默认情况:application,version,group,dubbo 在默认的配置项列表,所以还是会进入注册中心。 +```xml + + + + + + + + + + +``` +得到的 zookeeper 的叶子节点的值 +``` +consumer://30.5.124.149/org.apache.dubbo.samples.simplified.registry.nosimple.api.DemoService +?actives=6 +&application=simplified-registry-xml-consumer +&category=consumers +&check=false +&dubbo=2.0.2 +&group=dubbo-simple +&owner=vvv +&version=1.2.3 +``` + +##### 开启 URL 精简的示例(API 模式) + +工程源码 [dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-annotation](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-annotation)。注意,跑 sample 前,先跑下 ZKClean 进行配置项清理。 + +和上面 sample 中的 dubbo.properties 的效果是一致的。 + +* 默认情况:timeout 在默认的配置项列表,所以还是会进入注册中心; +* 配置: retries,owner 作为额外的 key 进入注册中心 , 所以 retries,owner 也会进入注册中心。 + + +**1. provider 端 bean 配置** + +```java +// 等同于dubbo.properties配置,用@Bean形式进行配置 +@Bean +public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("zookeeper://127.0.0.1:2181"); + registryConfig.setSimplified(true); + registryConfig.setExtraKeys("retries,owner"); + return registryConfig; +} +``` + +```java +// 暴露服务 +@Service(version = "1.1.8", group = "d-test", executes = 4500, retries = 7, owner = "victanno", timeout = 5300) +public class AnnotationServiceImpl implements AnnotationService { + @Override + public String sayHello(String name) { + System.out.println("async provider received: " + name); + return "annotation: hello, " + name; + } +} +``` + +**2. Consumer 配置** + +和上面 sample 中 **consumer 端配置** 是一样的。 + +默认情况: application,version,group,dubbo 在默认的配置项列表,所以还是会进入注册中心。 + +#### consumer 端 bean 配置 +```java +@Bean +public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("zookeeper://127.0.0.1:2181"); + registryConfig.setSimplified(true); + return registryConfig; + } +``` + +消费服务 + +```java +@Component("annotationAction") +public class AnnotationAction { + + @Reference(version = "1.1.8", group = "d-test", owner = "vvvanno", retries = 4, actives = 6, timeout = 4500) + private AnnotationService annotationService; + public String doSayHello(String name) { + return annotationService.sayHello(name); + } +} +``` + +> 注意: 如果一个应用中既有 provider 又有 consumer,那么配置需要合并成如下 + +```java +@Bean +public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("zookeeper://127.0.0.1:2181"); + registryConfig.setSimplified(true); + //只对provider生效 + registryConfig.setExtraKeys("retries,owner"); + return registryConfig; +} +``` + +### 定制URL参数 + +上面降到了两种控制 URL 中出现的参数的方法。 + +第一种是使用 `dubbo.properties`: + +```properties +dubbo.registry.simplified=true +dubbo.registry.extra-keys=retries,owner +``` + +第二种是通过 `RegistryConfig` 进行设置: + +```java +registryConfig.setSimplified(true); +registryConfig.setExtraKeys("retries,owner"); +``` + +还有第三种方法,就是通过扩展 `org.apache.dubbo.registry.integration.ServiceURLCustomizer` SPI,可以非常灵活的增加或减少 URL 中的参数: + +```java +@SPI(scope = APPLICATION) +public interface ServiceURLCustomizer extends Prioritized { + /** + * Customizes {@link URL the service url} + * + * @param serviceURL {@link URL the service url} + * @return new service url + */ + URL customize(URL serviceURL, ApplicationModel applicationModel); +} +``` + + + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/zookeeper.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/zookeeper.md new file mode 100644 index 000000000000..7e779fb8a3b5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/zookeeper.md @@ -0,0 +1,213 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ +description: "通过示例演示如何使用 Zookeepoer 作为注册中心实现自动服务发现。" +linkTitle: zookeeper +title: 使用 Zookeeper 作为注册中心实现自动服务发现 +type: docs +weight: 3 +--- + +本示例演示 Zookeeper 作为注册中心实现自动服务发现,示例基于 Spring Boot 应用展开,可在此查看 [完整示例代码](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-zookeeper) + +## 1 基本配置 +### 1.1 增加 Maven 依赖 +添加 dubbo、zookeeper 等依赖。`dubbo-spring-boot-starter` 将自动为应用增加 Zookeeper 相关客户端的依赖,减少用户使用 Zookeeper 成本,如使用中遇到版本兼容问题,用户也可以选择自行添加 Curator、Zookeeper Client 等依赖。 + +对于 Spring Boot 应用而言,可使用如下依赖: +```xml + + org.apache.dubbo + dubbo-spring-boot-starter + ${dubbo.version} + + + + org.apache.dubbo + dubbo-zookeeper-curator5-spring-boot-starter + ${dubbo.version} + + +``` + +其中,dubbo-zookeeper-spring-boot-starter 或 `dubbo-zookeeper-curator5-spring-boot-starter` 负责管理 zookeeper 相关依赖。 + + +{{% alert title="注意" color="info" %}} +如果您不使用 Spring Boot,也可以使用以下方式管理依赖 + +```xml + + + org.apache.dubbo + dubbo + ${dubbo.version} + + + + + org.apache.dubbo + dubbo-dependencies-zookeeper + ${dubbo.version} + pom + + + +``` +{{% /alert %}} + +### 1.2 选择 Zookeeper 版本 + +由于 Dubbo 使用 Curator 作为与 Zookeeper Server 交互的编程客户端,因此,要特别注意 Zookeeper Server 与 Dubbo 版本依赖的兼容性。 + +Dubbo 提供了 Zookeeper 依赖的辅助管理组件,开发者可根据当前使用的 Zookeeper Server 版本选择依赖版本: + +**1. 如果您是 Dubbo3 3.3 版本及以上用户,请根据如下表格选择组件:** + +| **Zookeeper Server 版本** | **Dubbo 依赖** | **Dubbo Starter 依赖(SpringBoot用户)** | +| --- | --- | --- | +| 3.4.x 及以下 | dubbo-dependencies-zookeeper | dubbo-zookeeper-spring-boot-starter | +| 3.5.x 及以上 | dubbo-dependencies-zookeeper-curator5 | dubbo-zookeeper-curator5-spring-boot-starter | + +**2. 如果您是 Dubbo3 3.2 及以下、Dubbo2 2.7.x 用户:** + +| **Zookeeper Server 版本** | **Dubbo 依赖** | **Dubbo Starter 依赖(SpringBoot用户)** | +| --- | --- | --- | +| 3.4.x 及以下 | dubbo-dependencies-zookeeper | 不支持(自行管理) | +| 3.5.x 及以上 | 不支持(自行管理) | 不支持(自行管理) | + +{{% alert title="注意" color="info" %}} +* Dubbo 3.3.0 版本开始正式支持 JDK 17,如果您使用 JDK 17,则必须选用 dubbo-dependencies-zookeeper-curator5 或 dubbo-zookeeper-curator5-spring-boot-starter 依赖,对应的 Zookeeper Server 推荐是 3.8.0 版本及以上。 +* 如果是自行管理 zookeeper 依赖,则须确保在项目中引入正确的 zookeeper、curator 版本依赖,可参考 Dubbo 3.3.0 版本中的 `dubbo-dependencies-zookeeper` 或 `dubbo-dependencies-zookeeper-curator5` 组件是如何实现的。 +{{% /alert %}} + + +### 1.3 配置并启用 Zookeeper +```yaml +# application.yml +dubbo + registry + address: zookeeper://localhost:2181 +``` +或 +```properties +# dubbo.properties +dubbo.registry.address=zookeeper://localhost:2181 +``` +或 +```xml + +``` + +`address` 是启用 zookeeper 注册中心唯一必须指定的属性,而在生产环境下,`address` 通常被指定为集群地址,如 + +`address=zookeeper://10.20.153.10:2181?backup=10.20.153.11:2181,10.20.153.12:2181` + +protocol 与 address 分开配置的模式也可以,如 + +`` + +## 2 高级配置 +### 2.1 认证与鉴权 + +如果 Zookeeper 开启认证,Dubbo 支持指定 username、password 的方式传入身份标识。 + +```yaml +# application.yml +dubbo + registry + address: zookeeper://localhost:2181 + username: hello + password: 1234 +``` + +也可以直接将参数扩展在 address 上 `address=zookeeper://hello:1234@localhost:2181` + +### 2.2 分组隔离 +通过指定 `group` 属性,可以在同一个 Zookeeper 集群内实现微服务地址的逻辑隔离。比如可以在一套集群内隔离出多套开发环境,在地址发现层面实现隔离。 + +```yaml +# application.yml +dubbo + registry + address: zookeeper://localhost:2181 + group: daily1 +``` + +### 2.3 其他扩展配置 +配置连接、会话过期时间 +```yaml +# application.yml +dubbo + registry + address: zookeeper://localhost:2181 + timeout: 30 * 1000* # 连接超时时间,默认 30s + session: 60 * 1000* # 会话超时时间,默认 60s +``` + +Zookeeper 注册中心还支持其他一些控制参数,具体可参见[Registry 配置项手册](../../config/properties#registry) + +## 3 工作原理 +在前面的一节中,我们讲解了应用级服务发现与接口级服务发现的区别,在 Zookeeper 实现中,它们的存储结构也存在较大差异。总体来说,Zookeeper 注册中心实现支持以下高可用能力: + +* 当提供者出现断电等异常停机时,注册中心能自动删除提供者信息 +* 当注册中心重启时,能自动恢复注册数据,以及订阅请求 +* 当会话过期时,能自动恢复注册数据,以及订阅请求 +* 当设置 `registry.check=false` 时,记录失败注册和订阅请求,后台定时重试 + +### 3.1 接口级节点结构 + +![/user-guide/images/zookeeper.jpg](/imgs/user/zookeeper.jpg) + +流程: +* 服务提供者启动时: 向 `/dubbo/com.foo.BarService/providers` 目录下写入自己的 URL 地址。 +* 服务消费者启动时: 订阅 `/dubbo/com.foo.BarService/providers` 目录下的提供者 URL 地址。并向 `/dubbo/com.foo.BarService/consumers` 目录下写入自己的 URL 地址 +* 监控中心启动时: 订阅 `/dubbo/com.foo.BarService` 目录下的所有提供者和消费者 URL 地址。 + +可通过 `registry.group` 设置 zookeeper 的根节点,不配置将使用默认的 `/dubbo` 根节点。 + +### 3.2 应用级节点结构 + +#### 3.2.1 地址列表 + + +应用级服务发现的地址结构比接口级更精简,它以应用名为粒度分发地址列表。服务提供者启动时,向 `/services/app` 目录下写入自己的 URL 地址,相比于接口级别的 URL,应用级别的 URL 更简单,只包含一些实例级别的参数,如 `tri://ip:port?region=hangzhou`。 + +可通过 `registry.group` 设置 zookeeper 的根节点,如设置 `registry.group=dubbo` 后,地址根节点变为 `/dubbo`。不配置将使用默认的 `/services` 根节点。在与 Spring Cloud Gateway 共用情况下,使用 `/services` 根节点会导致 dubbo 地址被 gateway 消费,此时可考虑设置独立 group。 + +{{% alert title="注意" color="info" %}} +在应用级服务发现模型中,接口级别的配置信息由消费者与提供者之间自行协商同步,不再由注册中心负责同步,从而大大减少了注册中心地址同步压力。 +{{% /alert %}} + +#### 3.2.2 接口应用映射 +在应用级服务发现中,zookeeper 注册中心还会存储一份额外的元数据,用于解决 `接口名到应用名` 之间的映射关系,其存储结构如下: + + + +service1 节点的 value 值是应用列表,可通过 `get /dubbo/mapping/service1` 查看:app1,app2 + +#### 3.2.3 元数据 +如果您用的是应用级服务发现的集中式元数据模式(默认是点对点的元数据模式,可通过 `dubbo.registry.metadata-type=remote` 开启)。在开启集中式元数据模式后,zookeeper 中还会发现以下节点内容: + + + +每个 revision 下是该应用的部署元数据信息,包含完整的接口服务列表及其配置信息。 + + + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/routing-rule/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/routing-rule/_index.md new file mode 100755 index 000000000000..840914e19f5b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/routing-rule/_index.md @@ -0,0 +1,7 @@ +--- +description: "Dubbo 路由规则详解,包括条件路由、动态配置、标签路由等,可以使用这些路由规则实现流量按比例转发、金丝雀发布、流量灰度、权重调整等能力。" +linkTitle: 路由规则 +title: 路由规则 +type: docs +weight: 99 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/_index.md new file mode 100644 index 000000000000..f084c4cd4e2a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/overview/what/ecosystem/serialization/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/serialization/ +description: "Dubbo 序列化使用指南" +linkTitle: 序列化协议 +title: 序列化 +type: docs +weight: 1 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/_index.md new file mode 100644 index 000000000000..b0a1217260b0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/_index.md @@ -0,0 +1,9 @@ +--- +aliases: + - /zh/overview/what/ecosystem/serialization/ +description: "dubbo 协议支持的序列化协议" +linkTitle: dubbo +title: dubbo 协议支持的序列化 +type: docs +weight: 3 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/avro.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/avro.md new file mode 100644 index 000000000000..685c34c98160 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/avro.md @@ -0,0 +1,66 @@ +--- +aliases: + - /zh/overview/what/ecosystem/serialization/avro/ + - /zh-cn/overview/what/ecosystem/serialization/avro/ +description: "本文介绍 Avro 序列化" +linkTitle: Avro +title: Avro +type: docs +weight: 5 +--- + + + +## 1 介绍 + +Avro是一种远程过程调用和数据序列化框架,是在Apache的Hadoop项目之内开发的。它使用JSON来定义数据类型和通讯协议,使用压缩二进制格式来序列化数据。它主要用于Hadoop,它可以为持久化数据提供一种序列化格式,并为Hadoop节点间及从客户端程序到Hadoop服务的通讯提供一种电报格式。 + + +## 2 使用方式 + +### 2.1 添加依赖 + +```xml + + + org.apache.dubbo.extensions + dubbo-serialization-avro + 3.3.0 + + + org.apache.avro + avro + 1.11.1 + + +``` + +### 2.2 配置启用 + + +```yaml +# application.yml (Spring Boot) +dubbo: + protocol: + serialization: avro +``` +或 +```properties +# dubbo.properties +dubbo.protocol.serialization=avro + +# or +dubbo.consumer.serialization=avro + +# or +dubbo.reference.com.demo.DemoService.serialization=avro +``` +或 +```xml + + + + + + + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson.md new file mode 100644 index 000000000000..344d72ce39c4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson.md @@ -0,0 +1,68 @@ +--- +aliases: + - /zh/overview/what/ecosystem/serialization/fastjson/ + - /zh-cn/overview/what/ecosystem/serialization/fastjson/ +description: "本文介绍 Fastjson 序列化" +linkTitle: Fastjson +title: Fastjson +type: docs +weight: 4 +--- + + + +## 1 介绍 + +Fastjson 是一个 Java 库,可用于将 Java 对象转换为其 JSON 表示形式。它还可用于将 JSON 字符串转换为等效的 Java 对象。 Fastjson 可以处理任意 Java 对象,包括您没有源代码的预先存在的对象。 + +## 2 使用方式 + +### 2.1 添加依赖 + +```xml + + + org.apache.dubbo.extensions + dubbo-serialization-fastjson + 3.3.0 + + + com.alibaba + fastjson + 1.2.83 + + +``` + +### 2.2 配置启用 + + +```yaml +# application.yml (Spring Boot) +dubbo: + protocol: + serialization: fastjson +``` +或 +```properties +# dubbo.properties +dubbo.protocol.serialization=fastjson + +# or +dubbo.consumer.serialization=fastjson + +# or +dubbo.reference.com.demo.DemoService.serialization=fastjson +``` +或 +```xml + + + + + + + +``` + +## 3 支持的rpc协议 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson2.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson2.md new file mode 100644 index 000000000000..1ab5961dad38 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson2.md @@ -0,0 +1,73 @@ +--- +aliases: + - /zh/overview/what/ecosystem/serialization/fastjson2/ + - /zh-cn/overview/what/ecosystem/serialization/fastjson2/ +description: "本文介绍 Fastjson2 序列化" +linkTitle: Fastjson2 +title: Fastjson2 +type: docs +weight: 3 +--- + + + +## 1 介绍 + +`FASTJSON v2`是`FASTJSON`项目的重要升级,目标是为下一个十年提供一个高性能的`JSON`库。通过同一套`API`, + +- 支持`JSON/JSONB`两种协议,[`JSONPath`](https://alibaba.github.io/fastjson2/jsonpath_cn) 是一等公民。 +- 支持全量解析和部分解析。 +- 支持`Java`服务端、客户端`Android`、大数据场景。 +- 支持`Kotlin` [https://alibaba.github.io/fastjson2/kotlin_cn](https://alibaba.github.io/fastjson2/kotlin_cn) +- 支持`JSON Schema` [https://alibaba.github.io/fastjson2/json_schema_cn](https://alibaba.github.io/fastjson2/json_schema_cn) +- 支持`Android 8+` +- 支持`Graal Native-Image` +- 支持 `JSON Schema` [https://alibaba.github.io/fastjson2/json_schema_cn](https://alibaba.github.io/fastjson2/json_schema_cn) + +## 2 使用方式 + +### 2.1 添加依赖 + +```xml + + + com.alibaba.fastjson2 + fastjson2 + 2.0.23 + + +``` + +注:Fastjson2 序列化仅 Dubbo > 3.1.0 版本支持。在 Dubbo > 3.2.0 中将替代 Hessian 作为默认序列化方式。 + +### 2.2 配置启用 + + +```yaml +# application.yml (Spring Boot) +dubbo: + protocol: + serialization: fastjson2 +``` +或 +```properties +# dubbo.properties +dubbo.protocol.serialization=fastjson2 + +# or +dubbo.consumer.serialization=fastjson2 + +# or +dubbo.reference.com.demo.DemoService.serialization=fastjson2 +``` +或 +```xml + + + + + + + +``` + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fst.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fst.md new file mode 100644 index 000000000000..3a3096fb2f0b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fst.md @@ -0,0 +1,154 @@ +--- +aliases: + - /zh/overview/what/ecosystem/serialization/fst/ + - /zh-cn/overview/what/ecosystem/serialization/fst/ +description: "本文介绍 FST 序列化" +linkTitle: FST +title: FST +type: docs +weight: 6 +--- + +## 1 介绍 + +FST序列化全称是Fast Serialization,它是对Java序列化的替换实现。既然前文中提到Java序列化的两点严重不足,在FST中得到了较大的改善,FST的特征如下: + +1. 比JDK提供的序列化提升了10倍,体积也减少 3-4 倍多 +2. 支持堆外Maps,和堆外Maps的持久化 +3. 支持序列化为JSON + +## 2 使用方式 + +### 2.1 添加依赖 + +```xml + + + org.apache.dubbo.extensions + dubbo-serialization-fst + 3.3.0 + + + de.ruedigermoeller + fst + 3.0.3 + + +``` + +### 2.2 配置启用 + + +```yaml +# application.yml (Spring Boot) +dubbo: + protocol: + serialization: fst +``` +或 +```properties +# dubbo.properties +dubbo.protocol.serialization=fst + +# or +dubbo.consumer.serialization=fst + +# or +dubbo.reference.com.demo.DemoService.serialization=fst +``` +或 +```xml + + + + + + + +``` + +## 3 注册被序列化类 + +要让Kryo和FST完全发挥出高性能,最好将那些需要被序列化的类注册到dubbo系统中,实现如下 + +**回调接口** +```java +public class SerializationOptimizerImpl implements SerializationOptimizer { + + public Collection getSerializableClasses() { + List classes = new LinkedList(); + classes.add(BidRequest.class); + classes.add(BidResponse.class); + classes.add(Device.class); + classes.add(Geo.class); + classes.add(Impression.class); + classes.add(SeatBid.class); + return classes; + } +} +``` + +然后在XML配置中添加: + +```xml + +``` + +在注册这些类后,序列化的性能可能被大大提升,特别针对小数量的嵌套对象的时候。 + +当然,在对一个类做序列化的时候,可能还级联引用到很多类,比如Java集合类。 + +针对这种情况,我们已经自动将JDK中的常用类进行了注册,所以你不需要重复注册它们(当然你重复注册了也没有任何影响)。 + +包括 +``` +GregorianCalendar +InvocationHandler +BigDecimal +BigInteger +Pattern +BitSet +URI +UUID +HashMap +ArrayList +LinkedList +HashSet +TreeSet +Hashtable +Date +Calendar +ConcurrentHashMap +SimpleDateFormat +Vector +BitSet +StringBuffer +StringBuilder +Object +Object[] +String[] +byte[] +char[] +int[] +float[] +double[] +``` + +由于注册被序列化的类仅仅是出于性能优化的目的,所以即使你忘记注册某些类也没有关系。 + +事实上,即使不注册任何类,Kryo和FST的性能依然普遍优于hessian和dubbo序列化。 + +> 当然,有人可能会问为什么不用配置文件来注册这些类?这是因为要注册的类往往数量较多,导致配置文件冗长;而且在没有好的IDE支持的情况下,配置文件的编写和重构都比java类麻烦得多;最后,这些注册的类一般是不需要在项目编译打包后还需要做动态修改的。 + +> 另外,有人也会觉得手工注册被序列化的类是一种相对繁琐的工作,是不是可以用annotation来标注,然后系统来自动发现并注册。但这里annotation的局限是,它只能用来标注你可以修改的类,而很多序列化中引用的类很可能是你没法做修改的(比如第三方库或者JDK系统类或者其他项目的类)。另外,添加annotation毕竟稍微的“污染”了一下代码,使应用代码对框架增加了一点点的依赖性。 + +> 除了annotation,我们还可以考虑用其它方式来自动注册被序列化的类,例如扫描类路径,自动发现实现Serializable接口(甚至包括Externalizable)的类并将它们注册。当然,我们知道类路径上能找到Serializable类可能是非常多的,所以也可以考虑用package前缀之类来一定程度限定扫描范围。 + +> 当然,在自动注册机制中,特别需要考虑如何保证服务提供端和消费端都以同样的顺序(或者ID)来注册类,避免错位,毕竟两端可被发现然后注册的类的数量可能都是不一样的。 + +### 无参构造函数和Serializable接口 + +如果被序列化的类中不包含无参的构造函数,则在Kryo的序列化中,性能将会大打折扣,因为此时我们在底层将用Java的序列化来透明的取代Kryo序列化。所以,尽可能为每一个被序列化的类添加无参构造函数是一种最佳实践(当然一个java类如果不自定义构造函数,默认就有无参构造函数)。 + +另外,Kryo和FST本来都不需要被序列化的类实现Serializable接口,但我们还是建议每个被序列化类都去实现它,因为这样可以保持和Java序列化以及dubbo序列化的兼容性,另外也使我们未来采用上述某些自动注册机制带来可能。 + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/gson.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/gson.md new file mode 100644 index 000000000000..cbadc5f3e9a2 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/gson.md @@ -0,0 +1,67 @@ +--- +aliases: + - /zh/overview/what/ecosystem/serialization/gson/ + - /zh-cn/overview/what/ecosystem/serialization/gson/ +description: "本文介绍 Gson 序列化" +linkTitle: Gson +title: Gson +type: docs +weight: 7 +--- + + + +## 1 介绍 + +Gson是Google公司发布的一个开放源代码的Java库,主要用途为序列化Java对象为JSON字符串,或反序列化JSON字符串成Java对象。 + +## 2 使用方式 + +### 2.1 添加依赖 + +```xml + + + org.apache.dubbo.extensions + dubbo-serialization-gson + 3.3.0 + + + com.google.code.gson + gson + 2.10.1 + + +``` + +### 2.2 配置启用 + + +```yaml +# application.yml (Spring Boot) +dubbo: + protocol: + serialization: gson +``` +或 +```properties +# dubbo.properties +dubbo.protocol.serialization=gson + +# or +dubbo.consumer.serialization=gson + +# or +dubbo.reference.com.demo.DemoService.serialization=gson +``` +或 +```xml + + + + + + + +``` + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/hessian.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/hessian.md new file mode 100644 index 000000000000..2a98ff40eca4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/hessian.md @@ -0,0 +1,57 @@ +--- +aliases: + - /zh/overview/what/ecosystem/serialization/hessian/ + - /zh-cn/overview/what/ecosystem/serialization/hessian/ +description: "本文介绍 Hessian 序列化" +linkTitle: Hessian +title: Hessian +type: docs +weight: 2 +--- + + + +## 1 介绍 + +Hessian序列化是一种支持动态类型、跨语言、基于对象传输的网络协议,Java对象序列化的二进制流可以被其他语言(如,c++,python)。特性如下: + +1. 自描述序列化类型。不依赖外部描述文件或者接口定义,用一个字节表示常用的基础类型,极大缩短二进制流。 +2. 语言无关,支持脚本语言 +3. 协议简单,比Java原生序列化高效 +4. 相比hessian1,hessian2中增加了压缩编码,其序列化二进制流大小是Java序列化的50%,序列化耗时是Java序列化的30%,反序列化耗时是Java序列化的20%。 + +## 2 使用方式 + +在 Dubbo 框架中,当使用 dubbo 通信协议时,默认使用 Hessian2 作为序列化。 + +### 2.1 配置启用 + + +```yaml +# application.yml (Spring Boot) +dubbo: + protocol: + serialization: hessian2 +``` +或 +```properties +# dubbo.properties +dubbo.protocol.serialization=hessian2 + +# or +dubbo.consumer.serialization=hessian2 + +# or +dubbo.reference.com.demo.DemoService.serialization=hessian2 +``` +或 +```xml + + + + + + + +``` + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/kryo.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/kryo.md new file mode 100644 index 000000000000..b9fb5fd37de0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/kryo.md @@ -0,0 +1,158 @@ +--- +aliases: + - /zh/overview/what/ecosystem/serialization/kryo/ + - /zh-cn/overview/what/ecosystem/serialization/kryo/ +description: "本文介绍 Kryo 序列化" +linkTitle: Kryo +title: Kryo +type: docs +weight: 8 +--- + + + + +## 1 介绍 + +Kryo是一种非常成熟的序列化实现,已经在Twitter、Groupon、Yahoo以及多个著名开源项目(如Hive、Storm)中广泛的使用。 + +## 2 使用方式 + +### 2.1 添加依赖 + +```xml + + + org.apache.dubbo.extensions + dubbo-serialization-kryo + 1.0.1 + + + com.esotericsoftware + kryo + 5.4.0 + + + de.javakaffee + kryo-serializers + 0.45 + + +``` + +### 2.2 配置启用 + + +```yaml +# application.yml (Spring Boot) +dubbo: + protocol: + serialization: kryo +``` +或 +```properties +# dubbo.properties +dubbo.protocol.serialization=kryo + +# or +dubbo.consumer.serialization=kryo + +# or +dubbo.reference.com.demo.DemoService.serialization=kryo +``` +或 +```xml + + + + + + + +``` + + +## 3 注册被序列化类 + +要让Kryo和FST完全发挥出高性能,最好将那些需要被序列化的类注册到dubbo系统中,实现如下 + +**回调接口** +```java +public class SerializationOptimizerImpl implements SerializationOptimizer { + + public Collection getSerializableClasses() { + List classes = new LinkedList(); + classes.add(BidRequest.class); + classes.add(BidResponse.class); + classes.add(Device.class); + classes.add(Geo.class); + classes.add(Impression.class); + classes.add(SeatBid.class); + return classes; + } +} +``` + +然后在XML配置中添加: + +```xml + +``` + +在注册这些类后,序列化的性能可能被大大提升,特别针对小数量的嵌套对象的时候。 + +当然,在对一个类做序列化的时候,可能还级联引用到很多类,比如Java集合类。 + +针对这种情况,我们已经自动将JDK中的常用类进行了注册,所以你不需要重复注册它们(当然你重复注册了也没有任何影响)。 + +包括 +``` +GregorianCalendar +InvocationHandler +BigDecimal +BigInteger +Pattern +BitSet +URI +UUID +HashMap +ArrayList +LinkedList +HashSet +TreeSet +Hashtable +Date +Calendar +ConcurrentHashMap +SimpleDateFormat +Vector +BitSet +StringBuffer +StringBuilder +Object +Object[] +String[] +byte[] +char[] +int[] +float[] +double[] +``` + +由于注册被序列化的类仅仅是出于性能优化的目的,所以即使你忘记注册某些类也没有关系。 + +事实上,即使不注册任何类,Kryo和FST的性能依然普遍优于hessian和dubbo序列化。 + +> 当然,有人可能会问为什么不用配置文件来注册这些类?这是因为要注册的类往往数量较多,导致配置文件冗长;而且在没有好的IDE支持的情况下,配置文件的编写和重构都比java类麻烦得多;最后,这些注册的类一般是不需要在项目编译打包后还需要做动态修改的。 + +> 另外,有人也会觉得手工注册被序列化的类是一种相对繁琐的工作,是不是可以用annotation来标注,然后系统来自动发现并注册。但这里annotation的局限是,它只能用来标注你可以修改的类,而很多序列化中引用的类很可能是你没法做修改的(比如第三方库或者JDK系统类或者其他项目的类)。另外,添加annotation毕竟稍微的“污染”了一下代码,使应用代码对框架增加了一点点的依赖性。 + +> 除了annotation,我们还可以考虑用其它方式来自动注册被序列化的类,例如扫描类路径,自动发现实现Serializable接口(甚至包括Externalizable)的类并将它们注册。当然,我们知道类路径上能找到Serializable类可能是非常多的,所以也可以考虑用package前缀之类来一定程度限定扫描范围。 + +> 当然,在自动注册机制中,特别需要考虑如何保证服务提供端和消费端都以同样的顺序(或者ID)来注册类,避免错位,毕竟两端可被发现然后注册的类的数量可能都是不一样的。 + +### 无参构造函数和Serializable接口 + +如果被序列化的类中不包含无参的构造函数,则在Kryo的序列化中,性能将会大打折扣,因为此时我们在底层将用Java的序列化来透明的取代Kryo序列化。所以,尽可能为每一个被序列化的类添加无参构造函数是一种最佳实践(当然一个java类如果不自定义构造函数,默认就有无参构造函数)。 + +另外,Kryo和FST本来都不需要被序列化的类实现Serializable接口,但我们还是建议每个被序列化类都去实现它,因为这样可以保持和Java序列化以及dubbo序列化的兼容性,另外也使我们未来采用上述某些自动注册机制带来可能。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/msgpack.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/msgpack.md new file mode 100644 index 000000000000..89c23d009dcc --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/msgpack.md @@ -0,0 +1,72 @@ +--- +aliases: + - /zh/overview/what/ecosystem/serialization/msgpack/ + - /zh-cn/overview/what/ecosystem/serialization/msgpack/ +description: "本文介绍 MessagePack 序列化" +linkTitle: MessagePack +title: MessagePack +type: docs +weight: 9 +--- + + + +## 1 介绍 + +MessagePack是一种计算机数据交换格式。它是一种二进制形式,用于表示简单的数据结构,如数组和关联数组。MessagePack 旨在尽可能紧凑和简单。 + +## 2 使用方式 + +### 2.1 添加依赖 + +```xml + + + org.apache.dubbo.extensions + dubbo-serialization-msgpack + 3.3.0 + + + org.msgpack + msgpack-core + 0.9.3 + + + + org.msgpack + jackson-dataformat-msgpack + 0.9.3 + + +``` + +### 2.2 配置启用 + + +```yaml +# application.yml (Spring Boot) +dubbo: + protocol: + serialization: msgpack +``` +或 +```properties +# dubbo.properties +dubbo.protocol.serialization=msgpack + +# or +dubbo.consumer.serialization=msgpack + +# or +dubbo.reference.com.demo.DemoService.serialization=msgpack +``` +或 +```xml + + + + + + + +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization-upgrade.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization-upgrade.md new file mode 100644 index 000000000000..bfdb578304fa --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization-upgrade.md @@ -0,0 +1,39 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/serialization-upgrade/ + - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/serialization-upgrade/ + - /zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/serialization-upgrade/ +description: 无损升级序列化协议指南 +linkTitle: 序列化协议升级 +title: 序列化协议升级 +type: docs +weight: 5 +--- + + + + + +在 `3.1.0` 版本中,Dubbo 默认支持的序列化协议新增对 Fastjson2 的支持。部分用户可能会考虑在现有的系统中对序列化协议进行升级,但服务端和客户端版本的差异可能导致客户端并不支持服务端的序列化协议。 + +在 `3.2.0` 版本中, Dubbo 的服务端引入新的配置 `prefer-serialization`,该特性可以完美解决服务端序列化升级过程中可能带来的风险。 + + +### 最佳实践 + +序列化协议升级,需要分两步走: + +* **首先需要推动服务端的序列化协议升级,同时在服务端的暴露配置中需要添加 `prefer-serialization` 配置。** +> 比如:升级前的序列化协议是 hessian2,升级之后的序列化协议是 Fastjson2 那么在服务端的暴露配置中就应该添加如下所示的配置。 + +```yaml +dubbo.provider.prefer-serialization=fastjson2,hessian2 +dubbo.provider.serialization=hessian2 +``` +* **其次,客户端需要升级至和服务端相同版本** + +### 实现原理 + +dubbo 客户端序列化协议是根据服务端的注册配置来选择的(即服务端的`serialization`配置)。在请求阶段 dubbo 会把客户端的序列化协议组装到请求头上,服务端在进行反序列化时会根据请求头来确定反序列化协议。所以,如果服务端和客户端的版本不一致就可能会出现客户端序列化不了的情况。 + +为了解决这个情况,`3.2.0` 在客户端序列化的时候会优先使用 `prefer-serialization` 配置的协议,如果不支持 `prefer-serialization` 相关的协议,才会使用 `serialization` 配置的协议。(可以把 `serialization` 理解为一个兜底的配置) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization.md new file mode 100644 index 000000000000..ef2199fed071 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization.md @@ -0,0 +1,298 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/serialization/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/serialization/ +description: 在 Dubbo 中使用高效的 Java 序列化(Kryo 和 FST) +linkTitle: 序列化概述 +title: Dubbo 序列化机制介绍 +type: docs +weight: 1 +--- + +## 支持的协议列表 +以下是 Dubbo 框架支持的序列化协议列表,根据 `triple`、`dubbo` RPC 通信协议进行分类。 + +| RPC协议 | 编程模式 | 序列化协议 | 配置方式 | JDK版本 | 说明 | +| --- | --- | --- | --- | --- | --- | +| **triple** | IDL | protobuf、
protobuf-json | 默认值 | 8, 17, 21 | 使用 IDL 时的默认序列化方式,client 也可以选择 protobuf-json 序列化通信,无需额外配置 | +| | Java接口 | protobuf-wrapper | serialization="hessian" | 8, 17, 21 | 这种模式下采用的是两次序列化模式,即数据先被 hessian 序列化,再由 protobuf 序列化。

为了支持与 IDL 同等的调用模型,易用性较好但性能略有下降 | +| **dubbo** | Java接口 | hessian | 默认值,serialization="hessian" | 8, 17, 21 | dubbo 协议默认序列化方式,具备兼容性好、高性能、跨语言的优势(java、go、c/c++、php、python、.net) | +| | Java接口 | protostuff | serialization="protostuff" | 8 | A java serialization library with built-in support for forward-backward compatibility (schema evolution) and validation. | +| | Java接口 | gson | serialization="gson" | 8, 17, 21 | 谷歌推出的一款 json 序列化库 | +| | Java接口 | avro | serialization="avro" | 8, 17, 21 | 一款 Java 高性能序列化库 | +| | Java接口 | msgpack | serialization="msgpack" | 8, 17, 21 | 具备兼容性好,提供多语言(Java、C/C++、Python等)实现等优势| +| | Java接口 | kryo | serialization="kryo" | 8, 17, 21 | Kryo是一种非常成熟的序列化实现,已经在Twitter、Groupon、Yahoo以及多个著名开源项目(如Hive、Storm)中广泛的使用。 | +| | Java接口 | fastjson2 | serialization="fastjson2" | 8, 17, 21 | fastjson | +| | Java接口 | 更多扩展| | | [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-serialization-extensions) | + +## 性能对比报告 + +序列化对于远程调用的响应速度、吞吐量、网络带宽消耗等起着至关重要的作用,是我们提升分布式系统性能的最关键因素之一。 + +具体请查看 [参考手册 - 性能基准报告](/zh-cn/overview/mannual/java-sdk/reference-manual/performance/)。 + +## 切换序列化协议 + +{{% alert title="注意" color="info" %}} +本文档适用的典型场景是 Dubbo 老用户:用户已经有大量系统运行在 Dubbo 之上,由于一些场景需要,必须将使用多年的序列化升级一个新的序列化协议。 +{{% /alert %}} + +在 `3.2.0` 及之后版本中, Dubbo 的服务端引入新的配置 `prefer-serialization`,该特性可以通过协商的方式将整个系统的序列化协议平滑的升级到一个全新协议。 + +### 切换步骤 + +序列化协议升级,需要分两步走: + +**1. 需要推动服务端的序列化协议升级,同时在服务端的暴露配置中需要添加 `prefer-serialization` 配置。** + +比如:升级前的序列化协议是 hessian2,升级的目标序列化协议是 Fastjson2 那么在服务端的暴露配置中就应该添加如下所示的配置: + +Spring Boot 应用 `application.properties` 配置文件中增加如下内容: + +```properties +dubbo.provider.prefer-serialization=fastjson2,hessian2 #这里定义了新的协议协商顺序 +dubbo.provider.serialization=hessian2 #这是之前的序列化协议 +``` + +或者,如果使用 xml 配置的话: + +```xml + +``` + +**2. 客户端和服务端都需要增加新的序列化实现必要依赖** + +如以上示例所示,需要确保消费端和提供端都增加 fastjson2 依赖: +```xml + + com.alibaba.fastjson2 + fastjson2 + ${fastjson2.version} + +``` + +{{% alert title="警告" color="warning" %}} +要使自动协商生效,需要确保: +* 消费者端、提供者端都是 3.2.x 及以上版本,否则配置不生效(继续使用老序列化协议) +* 消费者端、提供者端都加上了必须的序列化实现包依赖,否则不生效(继续使用老序列化协议,个别极端场景可能报错)。 +{{% /alert %}} + +### 实现原理 + +dubbo 客户端序列化协议是根据服务端的注册配置来选择的(即服务端的`serialization`配置)。在请求阶段 dubbo 会把客户端的序列化协议组装到请求头上,服务端在进行反序列化时会根据请求头来确定反序列化协议。所以,如果服务端和客户端的版本不一致就可能会出现客户端序列化不了的情况。 + +为了解决这个情况,`3.2.0` 在客户端序列化的时候会优先使用 `prefer-serialization` 配置的协议,如果不支持 `prefer-serialization` 相关的协议,才会使用 `serialization` 配置的协议。(可以把 `serialization` 理解为一个兜底的配置) + + +## 安全性 + +以上所有序列化方式中,protobuf 序列化具有最高的安全性,而对于其他序列化机制而言,我们要防止因为任意类序列化反序列化引发的 RCE 攻击。 + +### 类检查机制 +Dubbo 中的类检查机制可以以类似黑白名单的形式来保证序列化安全。该机制保证服务提供方和服务消费方类之间的兼容性和安全,防止由于类版本不匹配、方法签名不兼容或缺少类而可能发生的潜在问题。 + +{{% alert title="注意" color="warning" %}} +* Dubbo >= 3.1.6 引入此检查机制,对用户透明。 +* 目前序列化检查支持 Hessian2、Fastjson2 序列化以及泛化调用,其他的序列化方式暂不支持。 +* **3.1 版本中默认为 `WARN` 告警级别,3.2 版本中默认为 `STRICT` 严格检查级别,如您遇到问题可通过以下指引降低检查级别。** +{{% /alert %}} + + +#### 检查模式 +检查模式分为三个级别:`STRICT` 严格检查,`WARN` 告警,`DISABLE` 禁用。 +`STRICT` 严格检查:禁止反序列化所有不在允许序列化列表(白名单)中的类。 +`WARN` 告警:仅禁止序列化所有在不允许序列化列表中(黑名单)的类,同时在反序列化不在允许序列化列表(白名单)中类的时候通过日志进行告警。 +`DISABLE` 禁用:不进行任何检查。 + +> 3.1 版本中默认为 `WARN` 告警级别,3.2 版本中默认为 `STRICT` 严格检查级别,如您遇到问题可通过以下指引降低检查级别。 + +通过 ApplicationConfig 配置: +```java +ApplicationConfig applicationConfig = new ApplicationConfig(); +applicationConfig.setSerializeCheckStatus("STRICT"); +``` + +通过 Spring XML 配置: +```xml + +``` + +通过 Spring Properties / dubbo.properties 配置: +```properties +dubbo.application.serialize-check-status=STRICT +``` + +通过 System Property 配置: +```properties +-Ddubbo.application.serialize-check-status=STRICT +``` + +配置成功后可以在日志中看到如下的提示: +``` +INFO utils.SerializeSecurityManager: [DUBBO] Serialize check level: STRICT +``` + +注:在同一个进程(Dubbo Framework Model)下的多个应用如果同时配置不同的检查模式,最终会生效“最宽松”的级别。如两个 Spring Context 同时启动,一个配置为 `STRICT`,另外一个配置为 `WARN`,则最终生效 `WARN` 级别的配置。 + +#### Serializable 接口检查 + +Serializable 接口检查模式分为两个级别:`true` 开启,`false` 关闭。开启检查后会拒绝反序列化所有未实现 `Serializable` 的类。 + +Dubbo 中默认配置为 `true` 开启检查。 + +通过 ApplicationConfig 配置: +```java +ApplicationConfig applicationConfig = new ApplicationConfig(); +applicationConfig.setCheckSerializable(true); +``` + +通过 Spring XML 配置: +```xml + +``` + +通过 Spring Properties / dubbo.properties 配置: +```properties +dubbo.application.check-serializable=true +``` + +通过 System Property 配置: +```properties +-Ddubbo.application.check-serializable=true +``` + +配置成功后可以在日志中看到如下的提示: +``` +INFO utils.SerializeSecurityManager: [DUBBO] Serialize check serializable: true +``` + +注 1:在同一个进程(Dubbo Framework Model)下的多个应用如果同时配置不同的 Serializable 接口检查模式,最终会生效“最宽松”的级别。如两个 Spring Context 同时启动,一个配置为 `true`,另外一个配置为 `false`,则最终生效 `false` 级别的配置。 +注 2:目前暂未打通 Hessian2、Fastjson2 内置的 `Serializable` 检查配置。对于泛化调用,仅需要配置 `dubbo.application.check-serializable` 即可修改检查配置;对于 Hessian2 序列化,需要同时修改 `dubbo.application.check-serializable` 和 `dubbo.hessian.allowNonSerializable` 两个配置;对于 Fastjson2 序列化,目前暂不支持修改。 + +#### 自动扫描相关配置 + +Dubbo 类自动扫描机制共有两个配置项:`AutoTrustSerializeClass` 是否启用自动扫描和 `TrustSerializeClassLevel` 类信任层级。 + +简单来说,在开启类自动扫描之后,Dubbo 会通过 `ReferenceConfig` 和 `ServiceConfig` 自动扫描接口所有可能会用到的相关类,并且递归信任其所在的 package。 `TrustSerializeClassLevel` 类信任层级可以用来限制最终信任的 package 层级。如 `io.dubbo.test.pojo.User` 在 `TrustSerializeClassLevel` 配置为 `3` 的时候,最终会信任 `io.dubbo.test` 这个 package 下所有的类。 + +Dubbo 中默认配置 `AutoTrustSerializeClass` 为 `true` 启用扫描, `TrustSerializeClassLevel` 为 `3`。 + +通过 ApplicationConfig 配置: +```java +ApplicationConfig applicationConfig = new ApplicationConfig(); +applicationConfig.setAutoTrustSerializeClass(true); +applicationConfig.setTrustSerializeClassLevel(3); +``` + +通过 Spring XML 配置: +```xml + +``` + +通过 Spring Properties / dubbo.properties 配置: +```properties +dubbo.application.auto-trust-serialize-class=true +dubbo.application.trust-serialize-class-level=3 +``` + +通过 System Property 配置: +```properties +-Ddubbo.application.auto-trust-serialize-class=true +-Ddubbo.application.trust-serialize-class-level=3 +``` + +配置成功后可以通过 QoS 命令检查当前已经加载的可信类结果是否符合预期。 + +注:开启检查之后在启动的过程中会有一定的性能损耗。 + +#### 可信/不可信类自定义配置 + +除了 Dubbo 自动扫描类之外,也支持通过资源文件的方式配置可信/不可信类列表。 + +配置方式:在资源目录(resource)下定义以下文件。 + +```properties +# security/serialize.allowlist +io.dubbo.test +``` + +```properties +# security/serialize.blockedlist +io.dubbo.block +``` + +配置成功以后可以在日志看到以下提示: +```properties +INFO utils.SerializeSecurityConfigurator: [DUBBO] Read serialize allow list from file:/Users/albumen/code/dubbo-samples/99-integration/dubbo-samples-serialize-check/target/classes/security/serialize.allowlist +INFO utils.SerializeSecurityConfigurator: [DUBBO] Read serialize blocked list from file:/Users/albumen/code/dubbo-samples/99-integration/dubbo-samples-serialize-check/target/classes/security/serialize.blockedlist +``` + +配置优先级为:用户自定义可信类 = 框架内置可信类 > 用户自定义不可信类 = 框架内置不可信类 > 自动类扫描可信类。 + +#### 审计方式 + +Dubbo 支持通过 QoS 命令实时查看当前的配置信息以及可信/不可信类列表。目前共支持两个命令:`serializeCheckStatus` 查看当前配置信息,`serializeWarnedClasses` 查看实时的告警列表。 + +1. `serializeCheckStatus` 查看当前配置信息 + +通过控制台直接访问: +```bash +> telnet 127.0.0.1 22222 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>serializeCheckStatus +CheckStatus: WARN + +CheckSerializable: true + +AllowedPrefix: +... + +DisAllowedPrefix: +... + + +dubbo> +``` + +通过 http 请求 json 格式结果: +```bash +> curl http://127.0.0.1:22222/serializeCheckStatus +{"checkStatus":"WARN","allowedPrefix":[...],"checkSerializable":true,"disAllowedPrefix":[...]} +``` + +2. `serializeWarnedClasses` 查看实时的告警列表 + +通过控制台直接访问: +```bash +> telnet 127.0.0.1 22222 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>serializeWarnedClasses +WarnedClasses: +io.dubbo.test.NotSerializable +io.dubbo.test2.NotSerializable +io.dubbo.test2.OthersSerializable +org.apache.dubbo.samples.NotSerializable + + +dubbo> +``` + +通过 http 请求 json 格式结果: +```bash +> curl http://127.0.0.1:22222/serializeWarnedClasses +{"warnedClasses":["io.dubbo.test2.NotSerializable","org.apache.dubbo.samples.NotSerializable","io.dubbo.test.NotSerializable","io.dubbo.test2.OthersSerializable"]} +``` + +> 建议及时关注 `serializeWarnedClasses` 的结果,通过返回结果是否非空来判断是否受到攻击。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/_index.md new file mode 100644 index 000000000000..d01699b5915b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/_index.md @@ -0,0 +1,9 @@ +--- +aliases: + - /zh/overview/what/ecosystem/serialization/ +description: "triple 协议支持的序列化协议" +linkTitle: triple +title: triple 协议支持的序列化 +type: docs +weight: 2 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/protobuf.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/protobuf.md new file mode 100644 index 000000000000..0a5f298a1e9c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/protobuf.md @@ -0,0 +1,85 @@ +--- +aliases: + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/idl/ +description: "本文介绍 protobuf 序列化,如何在 triple 协议场景下使用 protobuf、json 序列化。" +linkTitle: Protobuf +title: 如何在 triple 协议场景下使用 protobuf、json 序列化 +type: docs +weight: 1 +--- + +## 1 介绍 + +Protobuf(Protocol Buffers) 是由 Google 开发的一种轻量级、高效的数据交换格式,它被用于结构化数据的序列化、反序列化和传输。 相比于XML 和JSON 等文本格式,Protobuf 具有更小的数据体积、更快的解析速度和更强的可扩展性。 + +## 2 使用方式 +**在使用 [Protobuf(IDL) 开发 triple 通信服务](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/) 的时候,dubbo server 将自动启用 protobuf、protobuf-json 序列化模式支持。** + +### 2.1 添加依赖 +使用 triple + protobuf 模式,必须添加以下依赖: + +```xml + + + com.google.protobuf + protobuf-java + 3.19.6 + + > + + com.google.protobuf + protobuf-java-util + 3.19.6 + + +``` + +### 2.2 配置启用 +只要是基于 [Protobuf(IDL) 开发模式进行 triple 协议通信](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/) ,就会使用 protobuf 序列化,只要定义 protobuf 文件并启用 triple 协议即可。 + +当使用 cURL 访问 triple 服务时,是会启用 protobuf-json 序列化模式 + +```shell +curl \ + --header "Content-Type: application/json" \ + --data '{"name":"Dubbo"}' \ + http://localhost:50052/org.apache.dubbo.samples.tri.unary.Greeter/greet/ +``` + +protobuf 服务定义示例: + +```protobuf +syntax = "proto3"; +option java_multiple_files = true; +package org.apache.dubbo.samples.tri.unary; + +message GreeterRequest { + string name = 1; +} +message GreeterReply { + string message = 1; +} + +service Greeter{ + rpc greet(GreeterRequest) returns (GreeterReply); +} +``` + + +协议配置: + +```yaml +# application.yml (Spring Boot) +dubbo: + protocol: + name: tri +``` +或 +```properties +# dubbo.properties +dubbo.protocol.name=tri +``` + +或 +```xml + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/wrapper.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/wrapper.md new file mode 100644 index 000000000000..fbf99f95373d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/wrapper.md @@ -0,0 +1,73 @@ +--- +aliases: + - /zh/overview/what/ecosystem/serialization/fastjson/ + - /zh-cn/overview/what/ecosystem/serialization/fastjson/ +description: "本文介绍基于 Java 接口模式开发 triple 服务时,底层的序列化机制实现。" +linkTitle: Protobuf Wrapper +title: 基于 Java 接口模式开发 triple 服务时,底层的序列化机制实现 +type: docs +weight: 2 +--- + +## 1 介绍 + +Dubbo 实现的 triple 协议易用性更好(不绑定 Protobuf),开发者可以继续使用 Java 接口 直接定义服务。对于期望平滑升级、没有多语言业务或者不熟悉 Protobuf 的用户而言,Java 接口方式是最简单的使用 triple 的方式。 + +以下介绍这种协议模式下的底层序列化细节:框架会用一个内置的 protobuf 对象将 request 和 response 进行包装(wrapper),**也就是对象会被序列化两次,第一次是使用如 `serialization=hessian` 指定的方式进行序列化,第二次是用 protobuf wrapper 对第一步中序列化后的 byte[] 进行包装后传输**。 + + +## 2 使用方式 + +**在使用 [Java 接口方式开发 triple 通信服务](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/) 的时候,dubbo server 将自动启用 protobuf、protobuf-json 序列化模式支持。** + +### 2.1 添加依赖 + +使用 triple 协议,必须先添加如下依赖: + +```xml + + + com.google.protobuf + protobuf-java + 3.19.6 + + > + + com.google.protobuf + protobuf-java-util + 3.19.6 + + +``` + +### 2.2 配置启用 +只要是基于 [Java 接口方式模式使用 triple 协议](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/) ,就会使用 protobuf wrapper 序列化,只要定义 Java 接口并启用 triple 协议即可: + +通过 Java 接口定义 Dubbo 服务: +```java +public interface GreetingsService { + String sayHi(String name); +} +``` + + +配置使用 triple 协议(如果要设置底层使用的序列化协议,需要继续设置 serialization,如 hessian、msgpack 等): + +```yaml +# application.yml (Spring Boot) +dubbo: + protocol: + name: tri + serialization: hessian +``` +或 +```properties +# dubbo.properties +dubbo.protocol.name=tri +dubbo.protocol.serialization=hessian +``` + +或 +```xml + + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/_index.md new file mode 100755 index 000000000000..fb4874fe8a70 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/ +description: Dubbo SPI 扩展使用指南 +linkTitle: SPI插件扩展点 +title: SPI 插件扩展点使用手册 +type: docs +weight: 9 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/_index.md new file mode 100644 index 000000000000..d2046ecac384 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/ +description: "Dubbo SPI 插件定义及使用详细介绍。" +linkTitle: 部分重点SPI使用说明 +title: Dubbo SPI 插件定义及使用详细介绍 +type: docs +weight: 3 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cache.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cache.md new file mode 100644 index 000000000000..353a84f2c543 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cache.md @@ -0,0 +1,97 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/cache/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/cache/ +description: 缓存扩展 +linkTitle: 缓存扩展 +title: 缓存扩展 +type: docs +weight: 24 +--- + + + + + + +## 扩展说明 + +用请求参数作为 key,缓存返回结果。 + +## 扩展接口 + +`org.apache.dubbo.cache.CacheFactory` + +## 扩展配置 + +```xml + + + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.cache.support.lru.LruCacheFactory` +* `org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory` +* `org.apache.dubbo.cache.support.jcache.JCacheFactory` + + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxCacheFactory.java (实现CacheFactory接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.cache.CacheFactory (纯文本文件,内容为:xxx=com.xxx.XxxCacheFactory) +``` + +XxxCacheFactory.java: + +```java +package com.xxx; + +import org.apache.dubbo.cache.CacheFactory; + +public class XxxCacheFactory implements CacheFactory { + public Cache getCache(URL url, String name) { + return new XxxCache(url, name); + } +} +``` + +XxxCache.java: + +```java +package com.xxx; + +import org.apache.dubbo.cache.Cache; + +public class XxxCache implements Cache { + public Cache(URL url, String name) { + // ... + } + public void put(Object key, Object value) { + // ... + } + public Object get(Object key) { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.cache.CacheFactory: + +```properties +xxx=com.xxx.XxxCacheFactory +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cluster.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cluster.md new file mode 100644 index 000000000000..548c26cd652a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cluster.md @@ -0,0 +1,92 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/cluster/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/cluster/ +description: 集群扩展 +linkTitle: 集群扩展 +title: 集群扩展 +type: docs +weight: 5 +--- + + + + + + +## 扩展说明 + +当有多个服务提供方时,将多个服务提供方组织成一个集群,并伪装成一个提供方。 + +## 扩展接口 + +`org.apache.dubbo.rpc.cluster.Cluster` + +## 扩展配置 + +```xml + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper` +* `org.apache.dubbo.rpc.cluster.support.FailoverCluster` +* `org.apache.dubbo.rpc.cluster.support.FailfastCluster` +* `org.apache.dubbo.rpc.cluster.support.FailsafeCluster` +* `org.apache.dubbo.rpc.cluster.support.FailbackCluster` +* `org.apache.dubbo.rpc.cluster.support.ForkingCluster` +* `org.apache.dubbo.rpc.cluster.support.AvailableCluster` +* `org.apache.dubbo.rpc.cluster.support.MergeableCluster` +* `org.apache.dubbo.rpc.cluster.support.BroadcastCluster` +* `org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxCluster.java (实现Cluster接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.rpc.cluster.Cluster (纯文本文件,内容为:xxx=com.xxx.XxxCluster) +``` + +XxxCluster.java: + +```java +package com.xxx; + +import org.apache.dubbo.rpc.cluster.Cluster; +import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker; +import org.apache.dubbo.rpc.cluster.Directory; +import org.apache.dubbo.rpc.cluster.LoadBalance; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Result; +import org.apache.dubbo.rpc.RpcException; + +public class XxxCluster implements Cluster { + public Invoker merge(Directory directory) throws RpcException { + return new AbstractClusterInvoker(directory) { + public Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { + // ... + } + }; + } +} +``` + +META-INF/dubbo/org.apache.dubbo.rpc.cluster.Cluster: + +```properties +xxx=com.xxx.XxxCluster +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/compiler.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/compiler.md new file mode 100644 index 000000000000..de8fd9f8b625 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/compiler.md @@ -0,0 +1,69 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/compiler/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/compiler/ +description: 编译器扩展 +linkTitle: 编译器扩展 +title: 编译器扩展 +type: docs +weight: 13 +--- + + + + + + +## 扩展说明 + +Java 代码编译器,用于动态生成字节码,加速调用。 + +## 扩展接口 + +`org.apache.dubbo.common.compiler.Compiler` + +## 扩展配置 + +自动加载 + +## 已知扩展 + +* `org.apache.dubbo.common.compiler.support.JdkCompiler` +* `org.apache.dubbo.common.compiler.support.JavassistCompiler` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxCompiler.java (实现Compiler接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.common.compiler.Compiler (纯文本文件,内容为:xxx=com.xxx.XxxCompiler) +``` + +XxxCompiler.java: + +```java +package com.xxx; + +import org.apache.dubbo.common.compiler.Compiler; + +public class XxxCompiler implements Compiler { + public Object getExtension(Class type, String name) { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.common.compiler.Compiler: + +```properties +xxx=com.xxx.XxxCompiler +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/config-center.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/config-center.md new file mode 100644 index 000000000000..549365c263d4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/config-center.md @@ -0,0 +1,111 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/config-center/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/config-center/ +description: 配置中心扩展 +linkTitle: 配置中心扩展 +title: 配置中心扩展 +type: docs +weight: 13 +--- + + + + + + +## 设计目的 + +配置中心的核心功能是作为 Key-Value 存储,Dubbo 框架告知配置中心其关心的 key,配置中心返回该key对应的 value 值。 + +按照应用场景划分,配置中心在 Dubbo 框架中主要承担以下职责: + +- 作为外部化配置中心,即存储 dubbo.properties 配置文件,此时,key 值通常为文件名如 dubbo.properties,value 则为配置文件内容。 +- 存储单个配置项,如各种开关项、常量值等。 +- 存储服务治理规则,此时key通常按照 "服务名+规则类型" 的格式来组织,而 value 则为具体的治理规则。 + +为了进一步实现对 key-value 的分组管理,Dubbo 的配置中心还加入了 namespace、group 的概念,这些概念在很多专业的第三方配置中心中都有体现,通常情况下,namespace 用来隔离不同的租户,group 用来对同一租户的key集合做分组。 + +当前,Dubbo 配置中心实现了对 Zookeeper、Nacos、Etcd、Consul、Apollo 的对接,接下来我们具体看一下 Dubbo 抽象的配置中心是怎么映射到具体的第三方实现中的。 + +## 扩展接口 + +* `org.apache.dubbo.configcenter.DynamicConfigurationFactory` +* `org.apache.dubbo.configcenter.DynamicConfiguration` + +## 已知扩展 + +* `org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfigurationFactory` +* `org.apache.dubbo.configcenter.support.nacos.NacosDynamicConfigurationFactory` +* `org.apache.dubbo.configcenter.support.etcd.EtcdDynamicConfigurationFactory` +* `org.apache.dubbo.configcenter.consul.ConsulDynamicConfigurationFactory` +* `org.apache.dubbo.configcenter.support.apollo.ApolloDynamicConfigurationFactory` +* `org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfigurationFactory` + +## 实现原理 + +### Zookeeper + +zookeeper提供了一个树状的存储模型,其实现原理如下: + +![image-20190127225608553](/imgs/dev/configcenter_zk_model.jpg) + +namespace, group, key 等分别对应不同层级的 ZNode 节点,而 value 则作为根 ZNode 节点的值存储。 + +1. 外部化配置中心 dubbo.properties + + ![image-20190127225608553](/imgs/dev/configcenter_zk_properties.jpg) + + 上图展示了两个不同作用域的 dubbo.properties 文件在 zookeeper 中的存储结构: + - 命名空间namespace都为:dubbo + - 分组 group:全局级别为 dubbo,所有应用共享;应用级别为应用名 demo-provider,只对该应用生效 + - key:dubbo.properties + +2. 单个配置项 + + ![image-20190127225608553](/imgs/dev/configcenter_zk_singleitem.jpg) + + 设置优雅停机事件为15000: + - 命名空间 namespace:dubbo + - 分组 group:dubbo + - key:dubbo.service.shutdown.wait + - value:15000 + +3. 服务治理规则 + + ![image-20190127225608553](/imgs/dev/configcenter_zk_rule.jpg) + + 上图展示了一条应用级别的条件路由规则: + + - 命名空间 namespace:dubbo + - 分组 group:dubbo + - key:governance-conditionrouter-consumer.condition-router,其中 governance-conditionrouter-consumer 为应用名,condition-router 代表条件路由 + + + > 注意: + > + > Dubbo同时支持应用、服务两种粒度的服务治理规则,对于这两种粒度,其key取值规则如下: + > * 应用粒度 {应用名 + 规则后缀}。如: `demo-application.configurators`、`demo-application.tag-router`等 + > * 服务粒度 {服务接口名:[服务版本]:[服务分组] + 规则后缀},其中服务版本、服务分组是可选的,如果它们有配置则在key中体现,没被配置则用":"占位。如 + > `org.apache.dubbo.demo.DemoService::.configurators`、`org.apache.dubbo.demo.DemoService:1.0.0:group1.configurators` + +### Etcd & Consul + +Etcd 和 Consul 本质上也是一种类似 zookeeper 的树状存储结构,实现请参考 zookeeper。 + +### Nacos + +Nacos 作为一个专业的第三方配置中心,拥有专门为配置中心设计的存储结构,包括内置的 namespace、group、dataid 等概念。并且这几个概念基本上与 Dubbo 框架抽象的配置中心是一一对应的。 + +与 Zookeeper 实现的对应关系如下: + +![image-20190127225608553](/imgs/dev/configcenter_nacos_model.jpg) + +参考上文关于 zookeeper 实现中描述的示例,这里的 dataid 可能为: +* 外部化配置中心:dubbo.properties +* 单个配置项:dubbo.service.shutdown.wait +* 服务治理规则:org.apache.dubbo.demo.DemoService:1.0.0:group1.configurators + +### Apollo + +Apollo 与 Nacos 类似,请参考动态配置中心使用文档中关于 Apollo 部分的描述。 \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/container.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/container.md new file mode 100644 index 000000000000..f39a47b3aa05 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/container.md @@ -0,0 +1,76 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/container/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/container/ +description: 容器扩展 +linkTitle: 容器扩展 +title: 容器扩展 +type: docs +weight: 22 +--- + + + + + + +## 扩展说明 + +服务容器扩展,用于自定义加载内容。 + +## 扩展接口 + +`org.apache.dubbo.container.Container` + +## 扩展配置 + +```sh +java org.apache.dubbo.container.Main spring jetty log4j +``` + +## 已知扩展 + +* `org.apache.dubbo.container.spring.SpringContainer` +* `org.apache.dubbo.container.spring.JettyContainer` +* `org.apache.dubbo.container.spring.Log4jContainer` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxContainer.java (实现Container接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.container.Container (纯文本文件,内容为:xxx=com.xxx.XxxContainer) +``` + +XxxContainer.java: + +```java +package com.xxx; + +org.apache.dubbo.container.Container; + + +public class XxxContainer implements Container { + public Status start() { + // ... + } + public Status stop() { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.container.Container: + +```properties +xxx=com.xxx.XxxContainer +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/dispatcher.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/dispatcher.md new file mode 100644 index 000000000000..bf983cdf5da4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/dispatcher.md @@ -0,0 +1,76 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/dispatcher/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/dispatcher/ +description: 消息派发扩展 +linkTitle: 消息派发扩展 +title: 消息派发扩展 +type: docs +weight: 14 +--- + + + + + + +## 扩展说明 + +通道信息派发器,用于指定线程池模型。 + +## 扩展接口 + +`org.apache.dubbo.remoting.Dispatcher` + +## 扩展配置 + +```xml + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.remoting.transport.dispatcher.all.AllDispatcher` +* `org.apache.dubbo.remoting.transport.dispatcher.direct.DirectDispatcher` +* `org.apache.dubbo.remoting.transport.dispatcher.message.MessageOnlyDispatcher` +* `org.apache.dubbo.remoting.transport.dispatcher.execution.ExecutionDispatcher` +* `org.apache.dubbo.remoting.transport.dispatcher.connection.ConnectionOrderedDispatcher` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxDispatcher.java (实现Dispatcher接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.remoting.Dispatcher (纯文本文件,内容为:xxx=com.xxx.XxxDispatcher) +``` + +XxxDispatcher.java: + +```java +package com.xxx; + +import org.apache.dubbo.remoting.Dispatcher; + +public class XxxDispatcher implements Dispatcher { + public Group lookup(URL url) { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.remoting.Dispatcher: + +```properties +xxx=com.xxx.XxxDispatcher +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exchanger.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exchanger.md new file mode 100644 index 000000000000..9d082b744132 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exchanger.md @@ -0,0 +1,105 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/exchanger/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/exchanger/ +description: 信息交换扩展 +linkTitle: 信息交换扩展 +title: 信息交换扩展 +type: docs +weight: 18 +--- + + + + + + +## 扩展说明 + +基于传输层之上,实现 Request-Response 信息交换语义。 + +## 扩展接口 + +* `org.apache.dubbo.remoting.exchange.Exchanger` +* `org.apache.dubbo.remoting.exchange.ExchangeServer` +* `org.apache.dubbo.remoting.exchange.ExchangeClient` + +## 扩展配置 + +```xml + + + +``` + +## 已知扩展 + +`org.apache.dubbo.remoting.exchange.exchanger.HeaderExchanger` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxExchanger.java (实现Exchanger接口) + |-XxxExchangeServer.java (实现ExchangeServer接口) + |-XxxExchangeClient.java (实现ExchangeClient接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.remoting.exchange.Exchanger (纯文本文件,内容为:xxx=com.xxx.XxxExchanger) +``` + +XxxExchanger.java: + +```java +package com.xxx; + +import org.apache.dubbo.remoting.exchange.Exchanger; + + +public class XxxExchanger implements Exchanger { + public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException { + return new XxxExchangeServer(url, handler); + } + public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException { + return new XxxExchangeClient(url, handler); + } +} +``` + +XxxExchangeServer.java: + +```java + +package com.xxx; + +import org.apache.dubbo.remoting.exchange.ExchangeServer; + +public class XxxExchangeServer impelements ExchangeServer { + // ... +} +``` + +XxxExchangeClient.java: + +```java +package com.xxx; + +import org.apache.dubbo.remoting.exchange.ExchangeClient; + +public class XxxExchangeClient impelments ExchangeClient { + // ... +} +``` + +META-INF/dubbo/org.apache.dubbo.remoting.exchange.Exchanger: + +```properties +xxx=com.xxx.XxxExchanger +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exporter-listener.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exporter-listener.md new file mode 100644 index 000000000000..c8850e39d00e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exporter-listener.md @@ -0,0 +1,79 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/exporter-listener/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/exporter-listener/ +description: 暴露监听扩展 +linkTitle: 暴露监听扩展 +title: 暴露监听扩展 +type: docs +weight: 4 +--- + + + + + + +## 扩展说明 + +当有服务暴露时,触发该事件。 + +## 扩展接口 + +`org.apache.dubbo.rpc.ExporterListener` + +## 扩展配置 + +```xml + + + + +``` + +## 已知扩展 + +`org.apache.dubbo.registry.directory.RegistryExporterListener` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxExporterListener.java (实现ExporterListener接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.rpc.ExporterListener (纯文本文件,内容为:xxx=com.xxx.XxxExporterListener) +``` + +XxxExporterListener.java: + +```java +package com.xxx; + +import org.apache.dubbo.rpc.ExporterListener; +import org.apache.dubbo.rpc.Exporter; +import org.apache.dubbo.rpc.RpcException; + + +public class XxxExporterListener implements ExporterListener { + public void exported(Exporter exporter) throws RpcException { + // ... + } + public void unexported(Exporter exporter) throws RpcException { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.rpc.ExporterListener: + +```properties +xxx=com.xxx.XxxExporterListener +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/extension-factory.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/extension-factory.md new file mode 100644 index 000000000000..1c78b29bcf9d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/extension-factory.md @@ -0,0 +1,71 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/extension-factory/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/extension-factory/ +description: 扩展点加载扩展 +linkTitle: 扩展点加载扩展 +title: 扩展点加载扩展 +type: docs +weight: 11 +--- + + + + + + +## 扩展说明 + +扩展点本身的加载容器,可从不同容器加载扩展点。 + +## 扩展接口 + +`org.apache.dubbo.common.extension.ExtensionFactory` + +## 扩展配置 + +```xml + +``` + +## 已知扩展 + +* `org.apache.dubbo.common.extension.factory.SpiExtensionFactory` +* `org.apache.dubbo.config.spring.extension.SpringExtensionFactory` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxExtensionFactory.java (实现ExtensionFactory接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.common.extension.ExtensionFactory (纯文本文件,内容为:xxx=com.xxx.XxxExtensionFactory) +``` + +XxxExtensionFactory.java: + +```java +package com.xxx; + +import org.apache.dubbo.common.extension.ExtensionFactory; + +public class XxxExtensionFactory implements ExtensionFactory { + public Object getExtension(Class type, String name) { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.common.extension.ExtensionFactory: + +```properties +xxx=com.xxx.XxxExtensionFactory +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/filter.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/filter.md new file mode 100644 index 000000000000..003cab1ae9f0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/filter.md @@ -0,0 +1,103 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/filter/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/filter/ +description: 调用拦截扩展 +linkTitle: 调用拦截扩展 +title: 调用拦截扩展 +type: docs +weight: 2 +--- + + + + + + +## 扩展说明 + +服务提供方和服务消费方调用过程拦截,Dubbo 本身的大多功能均基于此扩展点实现,每次远程方法执行,该拦截都会被执行,请注意对性能的影响。 + +约定: + +* 用户自定义 filter 默认在内置 filter 之后。 +* 特殊值 `default`,表示缺省扩展点插入的位置。比如:`filter="xxx,default,yyy"`,表示 `xxx` 在缺省 filter 之前,`yyy` 在缺省 filter 之后。 +* 特殊符号 `-`,表示剔除。比如:`filter="-foo1"`,剔除添加缺省扩展点 `foo1`。比如:`filter="-default"`,剔除添加所有缺省扩展点。 +* provider 和 service 同时配置的 filter 时,累加所有 filter,而不是覆盖。比如:`` 和 ``,则 `xxx`,`yyy`,`aaa`,`bbb` 均会生效。如果要覆盖,需配置:`` + +## 扩展接口 + +`org.apache.dubbo.rpc.Filter` + +## 扩展配置 + +```xml + + + + + + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.rpc.filter.EchoFilter` +* `org.apache.dubbo.rpc.filter.GenericFilter` +* `org.apache.dubbo.rpc.filter.GenericImplFilter` +* `org.apache.dubbo.rpc.filter.TokenFilter` +* `org.apache.dubbo.rpc.filter.AccessLogFilter` +* `org.apache.dubbo.rpc.filter.CountFilter` +* `org.apache.dubbo.rpc.filter.ActiveLimitFilter` +* `org.apache.dubbo.rpc.filter.ClassLoaderFilter` +* `org.apache.dubbo.rpc.filter.ContextFilter` +* `org.apache.dubbo.rpc.filter.ConsumerContextFilter` +* `org.apache.dubbo.rpc.filter.ExceptionFilter` +* `org.apache.dubbo.rpc.filter.ExecuteLimitFilter` +* `org.apache.dubbo.rpc.filter.DeprecatedFilter` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxFilter.java (实现Filter接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.rpc.Filter (纯文本文件,内容为:xxx=com.xxx.XxxFilter) +``` + +XxxFilter.java: + +```java +package com.xxx; + +import org.apache.dubbo.rpc.Filter; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Result; +import org.apache.dubbo.rpc.RpcException; + +public class XxxFilter implements Filter { + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + // before filter ... + Result result = invoker.invoke(invocation); + // after filter ... + return result; + } +} +``` + +META-INF/dubbo/org.apache.dubbo.rpc.Filter: + +```properties +xxx=com.xxx.XxxFilter +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/invoker-listener.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/invoker-listener.md new file mode 100644 index 000000000000..7b45af6d0285 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/invoker-listener.md @@ -0,0 +1,78 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/invoker-listener/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/invoker-listener/ +description: 引用监听扩展 +linkTitle: 引用监听扩展 +title: 引用监听扩展 +type: docs +weight: 3 +--- + + + + + + +## 扩展说明 + +当有服务引用时,触发该事件。 + +## 扩展接口 + +`org.apache.dubbo.rpc.InvokerListener` + +## 扩展配置 + +```xml + + + + +``` + +## 已知扩展 + +`org.apache.dubbo.rpc.listener.DeprecatedInvokerListener` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxInvokerListener.java (实现InvokerListener接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.rpc.InvokerListener (纯文本文件,内容为:xxx=com.xxx.XxxInvokerListener) +``` + +XxxInvokerListener.java: + +```java +package com.xxx; + +import org.apache.dubbo.rpc.InvokerListener; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.RpcException; + +public class XxxInvokerListener implements InvokerListener { + public void referred(Invoker invoker) throws RpcException { + // ... + } + public void destroyed(Invoker invoker) throws RpcException { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.rpc.InvokerListener: + +```properties +xxx=com.xxx.XxxInvokerListener +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/liveness.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/liveness.md new file mode 100644 index 000000000000..1ffebef09fb8 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/liveness.md @@ -0,0 +1,81 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/liveness/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/liveness/ +description: Liveness 存活探针 +linkTitle: 存活探针 +title: Liveness 存活探针 +type: docs +weight: 12 +--- + + + + + + +## 扩展说明 + + +拓展应用存活的检测点。 + + +## 扩展接口 + + +`org.apache.dubbo.qos.probe.LivenessProbe` + + +## 扩展配置 + + +Dubbo QOS `live` 命令自动发现 + + +## 已知扩展 + + +暂无默认实现 + + +## 扩展示例 + + +Maven 项目结构: + + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxLivenessProbe.java (实现LivenessProbe接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.qos.probe.LivenessProbe (纯文本文件,内容为:xxx=com.xxx.XxxLivenessProbe) +``` + + +XxxLivenessProbe.java: + + +```java +package com.xxx; + +public class XxxLivenessProbe implements LivenessProbe { + + public boolean check() { + // ... + } +} +``` + + +META-INF/dubbo/org.apache.dubbo.qos.probe.LivenessProbe: + + +``` +xxx=com.xxx.XxxLivenessProbe +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/load-balance.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/load-balance.md new file mode 100644 index 000000000000..787dbb191688 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/load-balance.md @@ -0,0 +1,79 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/load-balance/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/load-balance/ +description: 负载均衡扩展 +linkTitle: 负载均衡扩展 +title: 负载均衡扩展 +type: docs +weight: 7 +--- + + + + + + +## 扩展说明 + +从多个服务提供方中选择一个进行调用 + +## 扩展接口 + +`org.apache.dubbo.rpc.cluster.LoadBalance` + +## 扩展配置 + +```xml + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance` +* `org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance` +* `org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance` +* `org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance` +* `org.apache.dubbo.rpc.cluster.loadbalance.ShortestResponseLoadBalance` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxLoadBalance.java (实现LoadBalance接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.rpc.cluster.LoadBalance (纯文本文件,内容为:xxx=com.xxx.XxxLoadBalance) +``` + +XxxLoadBalance.java: + +```java +package com.xxx; + +import org.apache.dubbo.rpc.cluster.LoadBalance; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.RpcException; + +public class XxxLoadBalance implements LoadBalance { + public Invoker select(List> invokers, Invocation invocation) throws RpcException { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.rpc.cluster.LoadBalance: + +```properties +xxx=com.xxx.XxxLoadBalance +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/logger-adapter.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/logger-adapter.md new file mode 100644 index 000000000000..3af5b930e55a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/logger-adapter.md @@ -0,0 +1,98 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/logger-adapter/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/logger-adapter/ +description: 日志适配扩展 +linkTitle: 日志适配扩展 +title: 日志适配扩展 +type: docs +weight: 26 +--- + + + + + + +## 扩展说明 + +日志输出适配扩展点。 + +## 扩展接口 + +`org.apache.dubbo.common.logger.LoggerAdapter` + +## 扩展配置 + +```xml + +``` + +或者: + +```sh +-Ddubbo:application.logger=xxx +``` + +## 已知扩展 + +* `org.apache.dubbo.common.logger.slf4j.Slf4jLoggerAdapter` +* `org.apache.dubbo.common.logger.jcl.JclLoggerAdapter` +* `org.apache.dubbo.common.logger.log4j.Log4jLoggerAdapter` +* `org.apache.dubbo.common.logger.log4j2.Log4j2LoggerAdapter` +* `org.apache.dubbo.common.logger.jdk.JdkLoggerAdapter` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxLoggerAdapter.java (实现LoggerAdapter接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.common.logger.LoggerAdapter (纯文本文件,内容为:xxx=com.xxx.XxxLoggerAdapter) +``` + +XxxLoggerAdapter.java: + +```java +package com.xxx; + +import org.apache.dubbo.common.logger.LoggerAdapter; + +public class XxxLoggerAdapter implements LoggerAdapter { + public Logger getLogger(URL url) { + // ... + } +} +``` + +XxxLogger.java: + +```java +package com.xxx; + +import org.apache.dubbo.common.logger.Logger; + +public class XxxLogger implements Logger { + public XxxLogger(URL url) { + // ... + } + public void info(String msg) { + // ... + } + // ... +} +``` + +META-INF/dubbo/org.apache.dubbo.common.logger.LoggerAdapter: + +```properties +xxx=com.xxx.XxxLoggerAdapter +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/merger.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/merger.md new file mode 100644 index 000000000000..d93cea80c243 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/merger.md @@ -0,0 +1,81 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/merger/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/merger/ +description: 合并结果扩展 +linkTitle: 合并结果扩展 +title: 合并结果扩展 +type: docs +weight: 8 +--- + + + + + + +## 扩展说明 + +合并返回结果,用于分组聚合。 + +## 扩展接口 + +`org.apache.dubbo.rpc.cluster.Merger` + +## 扩展配置 + +```xml + +``` + +## 已知扩展 + +* `org.apache.dubbo.rpc.cluster.merger.ArrayMerger` +* `org.apache.dubbo.rpc.cluster.merger.ListMerger` +* `org.apache.dubbo.rpc.cluster.merger.SetMerger` +* `org.apache.dubbo.rpc.cluster.merger.MapMerger` +* `org.apache.dubbo.rpc.cluster.merger.ByteArrayMerger` +* `org.apache.dubbo.rpc.cluster.merger.CharArrayMerger` +* `org.apache.dubbo.rpc.cluster.merger.ShortArrayMerger` +* `org.apache.dubbo.rpc.cluster.merger.IntArrayMerger` +* `org.apache.dubbo.rpc.cluster.merger.LongArrayMerger` +* `org.apache.dubbo.rpc.cluster.merger.FloatArrayMerger` +* `org.apache.dubbo.rpc.cluster.merger.DoubleArrayMerger` +* `org.apache.dubbo.rpc.cluster.merger.BooleanArrayMerger` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxMerger.java (实现Merger接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.rpc.cluster.Merger (纯文本文件,内容为:xxx=com.xxx.XxxMerger) +``` + +XxxMerger.java: + +```java +package com.xxx; + +import org.apache.dubbo.rpc.cluster.Merger; + +public class XxxMerger implements Merger { + public T merge(T... results) { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.rpc.cluster.Merger: + +```properties +xxx=com.xxx.XxxMerger +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/metadata-report.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/metadata-report.md new file mode 100644 index 000000000000..0671d93ee4ea --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/metadata-report.md @@ -0,0 +1,100 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/metadata-report/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/metadata-report/ +description: 元数据中心扩展 +linkTitle: 元数据中心扩展 +title: 元数据中心扩展 +type: docs +weight: 13 +--- + + + + + + +## 设计目的 +请参见 [元数据中心手册](../../../metadata-center/overview/) + +## 扩展接口 + +* `org.apache.dubbo.metadata.store.MetadataReportFactory` +* `org.apache.dubbo.metadata.store.MetadataReport` + +## 已知扩展 + +## 实现原理 + +### SPI定义 + +参考:org.apache.dubbo.metadata.store.MetadataReportFactory,org.apache.dubbo.metadata.store.MetadataReport + +```java +@SPI("redis") +public interface MetadataReportFactory { + @Adaptive({"protocol"}) + MetadataReport getMetadataReport(URL url); +} +``` + + + +### 自定义元数据的存储 + +下面以Redis存储为例进行说明。 + +新建一个project,需要支持以下修改: + +#### 扩展AbstractMetadataReport + +```java +public class RedisMetadataReport extends AbstractMetadataReport { + private final static Logger logger = LoggerFactory.getLogger(RedisMetadataReport.class); + final JedisPool pool; + + public RedisMetadataReport(URL url) { + super(url); + pool = new JedisPool(new JedisPoolConfig(), url.getHost(), url.getPort()); + } + @Override + protected void doStoreProviderMetadata(ProviderMetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) { + this.storeMetadata(providerMetadataIdentifier, serviceDefinitions); + } + @Override + protected void doStoreConsumerMetadata(ConsumerMetadataIdentifier consumerMetadataIdentifier, String value) { + this.storeMetadata(consumerMetadataIdentifier, value); + } + private void storeMetadata(MetadataIdentifier metadataIdentifier, String v) { + try (Jedis jedis = pool.getResource()) { + jedis.set(metadataIdentifier.getIdentifierKey() + META_DATA_SOTRE_TAG, v); + } catch (Throwable e) { + logger.error("Failed to put " + metadataIdentifier + " to redis " + v + ", cause: " + e.getMessage(), e); + throw new RpcException("Failed to put " + metadataIdentifier + " to redis " + v + ", cause: " + e.getMessage(), e); + } + } +} +``` + +#### 扩展 AbstractMetadataReportFactory + +```java +public class RedisMetadataReportFactory extends AbstractMetadataReportFactory { + @Override + public MetadataReport createMetadataReport(URL url) { + return new RedisMetadataReport(url); + } +} +``` + +#### 增加 MetadataReportFactory + +> META-INF/dubbo/internal/org.apache.dubbo.metadata.store.MetadataReportFactory + +```properties +redis=org.apache.dubbo.metadata.store.redis.RedisMetadataReportFactory +``` + +只要将上面的修改和project打包成jar包,然后配置元数据中心的url:redis://10.20.153.10:6379。 + +至此,一个自定义的元数据存储就可以运行了。 \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/monitor.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/monitor.md new file mode 100644 index 000000000000..7cc50bc1ca35 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/monitor.md @@ -0,0 +1,89 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/monitor/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/monitor/ +description: 监控中心扩展 +linkTitle: 监控中心扩展 +title: 监控中心扩展 +type: docs +weight: 10 +--- + + + + + + +## 扩展说明 + +负责服务调用次和调用时间的监控。 + +## 扩展接口 + +* `org.apache.dubbo.monitor.MonitorFactory` +* `org.apache.dubbo.monitor.Monitor` + +## 扩展配置 + +```xml + + +``` + +## 已知扩展 + +org.apache.dubbo.monitor.support.dubbo.DubboMonitorFactory + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxMonitorFactoryjava (实现MonitorFactory接口) + |-XxxMonitor.java (实现Monitor接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.monitor.MonitorFactory (纯文本文件,内容为:xxx=com.xxx.XxxMonitorFactory) +``` + +XxxMonitorFactory.java: + +```java +package com.xxx; + +import org.apache.dubbo.monitor.MonitorFactory; +import org.apache.dubbo.monitor.Monitor; +import org.apache.dubbo.common.URL; + +public class XxxMonitorFactory implements MonitorFactory { + public Monitor getMonitor(URL url) { + return new XxxMonitor(url); + } +} +``` + +XxxMonitor.java: + +```java +package com.xxx; + +import org.apache.dubbo.monitor.Monitor; + +public class XxxMonitor implements Monitor { + public void count(URL statistics) { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.monitor.MonitorFactory: + +```properties +xxx=com.xxx.XxxMonitorFactory +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/networker.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/networker.md new file mode 100644 index 000000000000..082bb1476b12 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/networker.md @@ -0,0 +1,73 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/networker/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/networker/ +description: 组网扩展 +linkTitle: 组网扩展 +title: 组网扩展 +type: docs +weight: 19 +--- + + + + + + +## 扩展说明 + +对等网络节点组网器。 + +## 扩展接口 + +`org.apache.dubbo.remoting.p2p.Networker` + +## 扩展配置 + +```xml + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.remoting.p2p.support.MulticastNetworker` +* `org.apache.dubbo.remoting.p2p.support.FileNetworker` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxNetworker.java (实现Networker接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.remoting.p2p.Networker (纯文本文件,内容为:xxx=com.xxx.XxxNetworker) +``` + +XxxNetworker.java: + +```java +package com.xxx; + +import org.apache.dubbo.remoting.p2p.Networker; + +public class XxxNetworker implements Networker { + public Group lookup(URL url) { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.remoting.p2p.Networker: + +```properties +xxx=com.xxx.XxxNetworker +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/page.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/page.md new file mode 100644 index 000000000000..10e6b03a8991 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/page.md @@ -0,0 +1,77 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/page/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/page/ +description: 对等网络节点组网器扩展 +linkTitle: 对等网络节点组网器扩展 +title: 对等网络节点组网器扩展 +type: docs +weight: 19 +--- + + + + + + + + +## 扩展说明 + +对等网络节点组网器。 + +## 扩展接口 + +`org.apache.dubbo.container.page.PageHandler` + +## 扩展配置 + +```xml + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.container.page.pages.HomePageHandler` +* `org.apache.dubbo.container.page.pages.StatusPageHandler` +* `org.apache.dubbo.container.page.pages.LogPageHandler` +* `org.apache.dubbo.container.page.pages.SystemPageHandler` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxPageHandler.java (实现PageHandler接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.container.page.PageHandler (纯文本文件,内容为:xxx=com.xxx.XxxPageHandler) +``` + +XxxPageHandler.java: + +```java +package com.xxx; + +import org.apache.dubbo.container.page.PageHandler; + +public class XxxPageHandler implements PageHandler { + public Group lookup(URL url) { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.container.page.PageHandler: + +```properties +xxx=com.xxx.XxxPageHandler +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/protocol.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/protocol.md new file mode 100644 index 000000000000..54a209b69fb7 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/protocol.md @@ -0,0 +1,167 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/protocol/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/protocol/ +description: 协议扩展 +linkTitle: 协议扩展 +title: 协议扩展 +type: docs +weight: 1 +--- + + + + + + +## 扩展说明 + +RPC 协议扩展,封装远程调用细节。 + +契约: + +* 当用户调用 `refer()` 所返回的 `Invoker` 对象的 `invoke()` 方法时,协议需相应执行同 URL 远端 `export()` 传入的 `Invoker` 对象的 `invoke()` 方法。 +* 其中,`refer()` 返回的 `Invoker` 由协议实现,协议通常需要在此 `Invoker` 中发送远程请求,`export()` 传入的 `Invoker` 由框架实现并传入,协议不需要关心。 + +{{% alert title="注意" color="primary" %}} +* 协议不关心业务接口的透明代理,以 `Invoker` 为中心,由外层将 `Invoker` 转换为业务接口。 +* 协议不一定要是 TCP 网络通讯,比如通过共享文件,IPC 进程间通讯等。 +{{% /alert %}} + +## 扩展接口 + +* `org.apache.dubbo.rpc.Protocol` +* `org.apache.dubbo.rpc.Exporter` +* `org.apache.dubbo.rpc.Invoker` + +```java +public interface Protocol { + /** + * 暴露远程服务:
+ * 1. 协议在接收请求时,应记录请求来源方地址信息:RpcContext.getContext().setRemoteAddress();
+ * 2. export()必须是幂等的,也就是暴露同一个URL的Invoker两次,和暴露一次没有区别。
+ * 3. export()传入的Invoker由框架实现并传入,协议不需要关心。
+ * + * @param 服务的类型 + * @param invoker 服务的执行体 + * @return exporter 暴露服务的引用,用于取消暴露 + * @throws RpcException 当暴露服务出错时抛出,比如端口已占用 + */ + Exporter export(Invoker invoker) throws RpcException; + + /** + * 引用远程服务:
+ * 1. 当用户调用refer()所返回的Invoker对象的invoke()方法时,协议需相应执行同URL远端export()传入的Invoker对象的invoke()方法。
+ * 2. refer()返回的Invoker由协议实现,协议通常需要在此Invoker中发送远程请求。
+ * 3. 当url中有设置check=false时,连接失败不能抛出异常,需内部自动恢复。
+ * + * @param 服务的类型 + * @param type 服务的类型 + * @param url 远程服务的URL地址 + * @return invoker 服务的本地代理 + * @throws RpcException 当连接服务提供方失败时抛出 + */ + Invoker refer(Class type, URL url) throws RpcException; + +} +``` + +## 扩展配置 + +```xml + + + + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol` +* `org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol` +* `org.apache.dubbo.rpc.protocol.rmi.RmiProtocol` +* `org.apache.dubbo.rpc.protocol.http.HttpProtocol` +* `org.apache.dubbo.rpc.protocol.http.hessian.HessianProtocol` +* `org.apache.dubbo.rpc.support.MockProtocol` + +## 扩展示例 + +Maven项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxProtocol.java (实现Protocol接口) + |-XxxExporter.java (实现Exporter接口) + |-XxxInvoker.java (实现Invoker接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.rpc.Protocol (纯文本文件,内容为:xxx=com.xxx.XxxProtocol) +``` + +XxxProtocol.java: + +```java +package com.xxx; + +import org.apache.dubbo.rpc.Protocol; + +public class XxxProtocol implements Protocol { + public Exporter export(Invoker invoker) throws RpcException { + return new XxxExporter(invoker); + } + public Invoker refer(Class type, URL url) throws RpcException { + return new XxxInvoker(type, url); + } +} +``` + +XxxExporter.java: + +```java +package com.xxx; + +import org.apache.dubbo.rpc.support.AbstractExporter; + +public class XxxExporter extends AbstractExporter { + public XxxExporter(Invoker invoker) throws RemotingException{ + super(invoker); + // ... + } + public void unexport() { + super.unexport(); + // ... + } +} +``` + +XxxInvoker.java: + +```java +package com.xxx; + +import org.apache.dubbo.rpc.support.AbstractInvoker; + +public class XxxInvoker extends AbstractInvoker { + public XxxInvoker(Class type, URL url) throws RemotingException{ + super(type, url); + } + + @Override + protected Result doInvoke(Invocation invocation) throws Throwable { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.rpc.Protocol: + +```properties +xxx=com.xxx.XxxProtocol +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/proxy-factory.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/proxy-factory.md new file mode 100644 index 000000000000..2e09cd55bcd0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/proxy-factory.md @@ -0,0 +1,79 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/proxy-factory/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/proxy-factory/ +description: 动态代理扩展 +linkTitle: 动态代理扩展 +title: 动态代理扩展 +type: docs +weight: 12 +--- + + + + + + +## 扩展说明 + +将 `Invoker` 接口转换成业务接口。 + +## 扩展接口 + +`org.apache.dubbo.rpc.ProxyFactory` + +## 扩展配置 + +```xml + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.rpc.proxy.JdkProxyFactory` +* `org.apache.dubbo.rpc.proxy.JavassistProxyFactory` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxProxyFactory.java (实现ProxyFactory接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.rpc.ProxyFactory (纯文本文件,内容为:xxx=com.xxx.XxxProxyFactory) +``` + +XxxProxyFactory.java: + +```java +package com.xxx; + +import org.apache.dubbo.rpc.ProxyFactory; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.RpcException; + + +public class XxxProxyFactory implements ProxyFactory { + public T getProxy(Invoker invoker) throws RpcException { + // ... + } + public Invoker getInvoker(T proxy, Class type, URL url) throws RpcException { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.rpc.ProxyFactory: + +```properties +xxx=com.xxx.XxxProxyFactory +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/qos-permission.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/qos-permission.md new file mode 100644 index 000000000000..3a51baff1a1f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/qos-permission.md @@ -0,0 +1,71 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/qos-permission/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/qos-permission/ +description: QoS匿名访问权限验证扩展 +linkTitle: QoS匿名访问权限验证扩展 +title: QoS匿名访问权限验证扩展 +type: docs +weight: 27 +--- + + + + + + +## 扩展说明 + +QoS匿名访问权限验证扩展点。 + +## 扩展接口 + +`org.apache.dubbo.qos.permission.PermissionChecker` + +## 扩展配置 + + +Dubbo QoS `dubbo.application.qos-anonymous-access-permission-level` 匿名访问权限校验。 + +## 默认实现 + +`org.apache.dubbo.qos.permission.DefaultAnonymousAccessPermissionChecker` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxPermissionChecker.java (实现PermissionChecker接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.qos.permission.PermissionChecker` (纯文本文件,内容为:qosPermissionChecker=com.xxx.XxxPermissionChecker) +``` + +XxxPermissionChecker.java: + +```java +package com.xxx.qos.permission; + +import org.apache.dubbo.qos.permission.PermissionChecker; + +public class XxxAnonymousAccessPermissionChecker implements PermissionChecker { + + @Override + public boolean access(CommandContext commandContext, PermissionLevel defaultCmdRequiredPermissionLevel) { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.qos.permission.PermissionChecker: + +```properties +qosPermissionChecker=com.xxx.XxxPermissionChecker +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/readiness.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/readiness.md new file mode 100644 index 000000000000..5b4b7efd3701 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/readiness.md @@ -0,0 +1,83 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/readiness/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/readiness/ +description: Readiness 就绪探针 +linkTitle: 就绪探针 +title: Readiness 就绪探针 +type: docs +weight: 12 +--- + + + + + + +## 扩展说明 + + +拓展应用就绪的检测点。 + + +## 扩展接口 + + +`org.apache.dubbo.qos.probe.ReadinessProbe` + + +## 扩展配置 + + +Dubbo QOS `ready`  命令自动发现 + + +## 已知扩展 + + +- `org.apache.dubbo.qos.probe.impl.BootstrapReadinessProbe` +- `org.apache.dubbo.qos.probe.impl.ProviderReadinessProbe` + + + +## 扩展示例 + + +Maven 项目结构: + + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxReadinessProbe.java (实现ReadinessProbe接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.qos.probe.ReadinessProbe (纯文本文件,内容为:xxx=com.xxx.XxxReadinessProbe) +``` + + +XxxReadinessProbe.java: + + +```java +package com.xxx; + +public class XxxReadinessProbe implements ReadinessProbe { + + public boolean check() { + // ... + } +} +``` + + +META-INF/dubbo/org.apache.dubbo.qos.probe.ReadinessProbe: + + +``` +xxx=com.xxx.XxxReadinessProbe +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/registry.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/registry.md new file mode 100644 index 000000000000..78204216d265 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/registry.md @@ -0,0 +1,219 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/registry/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/registry/ +description: 注册中心扩展 +linkTitle: 注册中心扩展 +title: 注册中心扩展 +type: docs +weight: 9 +--- + + + + + + +## 扩展说明 + +负责服务的注册与发现。 + +## 扩展接口 + +* `org.apache.dubbo.registry.RegistryFactory` +* `org.apache.dubbo.registry.Registry` + +## 扩展配置 + +```xml + + + + + + +``` + +## 扩展契约 + +RegistryFactory.java: + +```java +public interface RegistryFactory { + /** + * 连接注册中心. + * + * 连接注册中心需处理契约:
+ * 1. 当设置check=false时表示不检查连接,否则在连接不上时抛出异常。
+ * 2. 支持URL上的username:password权限认证。
+ * 3. 支持backup=10.20.153.10备选注册中心集群地址。
+ * 4. 支持file=registry.cache本地磁盘文件缓存。
+ * 5. 支持timeout=1000请求超时设置。
+ * 6. 支持session=60000会话超时或过期设置。
+ * + * @param url 注册中心地址,不允许为空 + * @return 注册中心引用,总不返回空 + */ + Registry getRegistry(URL url); +} +``` + +RegistryService.java: + +```java +public interface RegistryService { // Registry extends RegistryService + /** + * 注册服务. + * + * 注册需处理契约:
+ * 1. 当URL设置了check=false时,注册失败后不报错,在后台定时重试,否则抛出异常。
+ * 2. 当URL设置了dynamic=false参数,则需持久存储,否则,当注册者出现断电等情况异常退出时,需自动删除。
+ * 3. 当URL设置了category=overrides时,表示分类存储,缺省类别为providers,可按分类部分通知数据。
+ * 4. 当注册中心重启,网络抖动,不能丢失数据,包括断线自动删除数据。
+ * 5. 允许URI相同但参数不同的URL并存,不能覆盖。
+ * + * @param url 注册信息,不允许为空,如:dubbo://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin + */ + void register(URL url); + + /** + * 取消注册服务. + * + * 取消注册需处理契约:
+ * 1. 如果是dynamic=false的持久存储数据,找不到注册数据,则抛IllegalStateException,否则忽略。
+ * 2. 按全URL匹配取消注册。
+ * + * @param url 注册信息,不允许为空,如:dubbo://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin + */ + void unregister(URL url); + + /** + * 订阅服务. + * + * 订阅需处理契约:
+ * 1. 当URL设置了check=false时,订阅失败后不报错,在后台定时重试。
+ * 2. 当URL设置了category=overrides,只通知指定分类的数据,多个分类用逗号分隔,并允许星号通配,表示订阅所有分类数据。
+ * 3. 允许以interface,group,version,classifier作为条件查询,如:interface=com.alibaba.foo.BarService&version=1.0.0
+ * 4. 并且查询条件允许星号通配,订阅所有接口的所有分组的所有版本,或:interface=*&group=*&version=*&classifier=*
+ * 5. 当注册中心重启,网络抖动,需自动恢复订阅请求。
+ * 6. 允许URI相同但参数不同的URL并存,不能覆盖。
+ * 7. 必须阻塞订阅过程,等第一次通知完后再返回。
+ * + * @param url 订阅条件,不允许为空,如:consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin + * @param listener 变更事件监听器,不允许为空 + */ + void subscribe(URL url, NotifyListener listener); + + /** + * 取消订阅服务. + * + * 取消订阅需处理契约:
+ * 1. 如果没有订阅,直接忽略。
+ * 2. 按全URL匹配取消订阅。
+ * + * @param url 订阅条件,不允许为空,如:consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin + * @param listener 变更事件监听器,不允许为空 + */ + void unsubscribe(URL url, NotifyListener listener); + + /** + * 查询注册列表,与订阅的推模式相对应,这里为拉模式,只返回一次结果。 + * + * @see org.apache.dubbo.registry.NotifyListener#notify(List) + * @param url 查询条件,不允许为空,如:consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin + * @return 已注册信息列表,可能为空,含义同{@link org.apache.dubbo.registry.NotifyListener#notify(List)}的参数。 + */ + List lookup(URL url); + +} +``` + +NotifyListener.java: + +```java +public interface NotifyListener { + /** + * 当收到服务变更通知时触发。 + * + * 通知需处理契约:
+ * 1. 总是以服务接口和数据类型为维度全量通知,即不会通知一个服务的同类型的部分数据,用户不需要对比上一次通知结果。
+ * 2. 订阅时的第一次通知,必须是一个服务的所有类型数据的全量通知。
+ * 3. 中途变更时,允许不同类型的数据分开通知,比如:providers, consumers, routes, overrides,允许只通知其中一种类型,但该类型的数据必须是全量的,不是增量的。
+ * 4. 如果一种类型的数据为空,需通知一个empty协议并带category参数的标识性URL数据。
+ * 5. 通知者(即注册中心实现)需保证通知的顺序,比如:单线程推送,队列串行化,带版本对比。
+ * + * @param urls 已注册信息列表,总不为空,含义同{@link org.apache.dubbo.registry.RegistryService#lookup(URL)}的返回值。 + */ + void notify(List urls); + +} +``` + +## 已知扩展 + +`org.apache.dubbo.registry.support.dubbo.DubboRegistryFactory` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxRegistryFactoryjava (实现RegistryFactory接口) + |-XxxRegistry.java (实现Registry接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.registry.RegistryFactory (纯文本文件,内容为:xxx=com.xxx.XxxRegistryFactory) +``` + +XxxRegistryFactory.java: + +```java +package com.xxx; + +import org.apache.dubbo.registry.RegistryFactory; +import org.apache.dubbo.registry.Registry; +import org.apache.dubbo.common.URL; + +public class XxxRegistryFactory implements RegistryFactory { + public Registry getRegistry(URL url) { + return new XxxRegistry(url); + } +} +``` + +XxxRegistry.java: + +```java +package com.xxx; + +import org.apache.dubbo.registry.Registry; +import org.apache.dubbo.registry.NotifyListener; +import org.apache.dubbo.common.URL; + +public class XxxRegistry implements Registry { + public void register(URL url) { + // ... + } + public void unregister(URL url) { + // ... + } + public void subscribe(URL url, NotifyListener listener) { + // ... + } + public void unsubscribe(URL url, NotifyListener listener) { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.registry.RegistryFactory: + +```properties +xxx=com.xxx.XxxRegistryFactory +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/remoting.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/remoting.md new file mode 100644 index 000000000000..9184f8516b3b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/remoting.md @@ -0,0 +1,136 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/remoting/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/remoting/ +description: 网络传输扩展 +linkTitle: 网络传输扩展 +title: 网络传输扩展 +type: docs +weight: 17 +--- + + + + + + +## 扩展说明 + +远程通讯的服务器及客户端传输实现。 + +## 扩展接口 + +* `org.apache.dubbo.remoting.Transporter` +* `org.apache.dubbo.remoting.Server` +* `org.apache.dubbo.remoting.Client` + +## 扩展配置 + +```xml + + + + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.remoting.transport.transporter.netty.NettyTransporter` +* `org.apache.dubbo.remoting.transport.transporter.mina.MinaTransporter` +* `org.apache.dubbo.remoting.transport.transporter.grizzly.GrizzlyTransporter` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxTransporter.java (实现Transporter接口) + |-XxxServer.java (实现Server接口) + |-XxxClient.java (实现Client接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.remoting.Transporter (纯文本文件,内容为:xxx=com.xxx.XxxTransporter) +``` + +XxxTransporter.java: + +```java +package com.xxx; + +import org.apache.dubbo.remoting.Transporter; + +public class XxxTransporter implements Transporter { + public Server bind(URL url, ChannelHandler handler) throws RemotingException { + return new XxxServer(url, handler); + } + public Client connect(URL url, ChannelHandler handler) throws RemotingException { + return new XxxClient(url, handler); + } +} +``` + +XxxServer.java: + +```java +package com.xxx; + +import org.apache.dubbo.remoting.transport.transporter.AbstractServer; + +public class XxxServer extends AbstractServer { + public XxxServer(URL url, ChannelHandler handler) throws RemotingException{ + super(url, handler); + } + protected void doOpen() throws Throwable { + // ... + } + protected void doClose() throws Throwable { + // ... + } + public Collection getChannels() { + // ... + } + public Channel getChannel(InetSocketAddress remoteAddress) { + // ... + } +} +``` + +XxxClient.java: + +```java +package com.xxx; + +import org.apache.dubbo.remoting.transport.transporter.AbstractClient; + +public class XxxClient extends AbstractClient { + public XxxServer(URL url, ChannelHandler handler) throws RemotingException{ + super(url, handler); + } + protected void doOpen() throws Throwable { + // ... + } + protected void doClose() throws Throwable { + // ... + } + protected void doConnect() throws Throwable { + // ... + } + public Channel getChannel() { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.remoting.Transporter: + +```properties +xxx=com.xxx.XxxTransporter +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/router.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/router.md new file mode 100644 index 000000000000..c1facf97912a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/router.md @@ -0,0 +1,76 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/router/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/router/ +description: 路由扩展 +linkTitle: 路由扩展 +title: 路由扩展 +type: docs +weight: 6 +--- + + + + + + +## 扩展说明 + +从多个服务提供方中选择一个进行调用。 + +## 扩展接口 + +* `org.apache.dubbo.rpc.cluster.RouterFactory` +* `org.apache.dubbo.rpc.cluster.Router` + +## 已知扩展 + +* `org.apache.dubbo.rpc.cluster.router.ScriptRouterFactory` +* `org.apache.dubbo.rpc.cluster.router.FileRouterFactory` +* `org.apache.dubbo.rpc.cluster.router.condition.config.AppRouterFactory` +* `org.apache.dubbo.rpc.cluster.CacheableRouterFactory` +* `org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory` +* `org.apache.dubbo.rpc.cluster.router.mock.MockRouterFactory` +* `org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouterFactory` +* `org.apache.dubbo.rpc.cluster.router.tag.TagRouterFactory` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxRouterFactory.java (实现RouterFactory接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.rpc.cluster.RouterFactory (纯文本文件,内容为:xxx=com.xxx.XxxRouterFactory) + +``` + +XxxRouterFactory.java: + +```java +package com.xxx; + +import org.apache.dubbo.rpc.cluster.RouterFactory; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.RpcException; + +public class XxxRouterFactory implements RouterFactory { + public Router getRouter(URL url) { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.rpc.cluster.RouterFactory: + +```properties +xxx=com.xxx.XxxRouterFactory +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/serialize.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/serialize.md new file mode 100644 index 000000000000..4c8a8f2d477a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/serialize.md @@ -0,0 +1,86 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/serialize/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/serialize/ +description: 序列化扩展 +linkTitle: 序列化扩展 +title: 序列化扩展 +type: docs +weight: 16 +--- + + + + + + +## 扩展说明 + +将对象转成字节流,用于网络传输,以及将字节流转为对象,用于在收到字节流数据后还原成对象。 + +## 扩展接口 + +* `org.apache.dubbo.common.serialize.Serialization` +* `org.apache.dubbo.common.serialize.ObjectInput` +* `org.apache.dubbo.common.serialize.ObjectOutput` + +## 扩展配置 + +```xml + + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.common.serialize.dubbo.DubboSerialization` +* `org.apache.dubbo.common.serialize.hessian.Hessian2Serialization` +* `org.apache.dubbo.common.serialize.java.JavaSerialization` +* `org.apache.dubbo.common.serialize.java.CompactedJavaSerialization` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxSerialization.java (实现Serialization接口) + |-XxxObjectInput.java (实现ObjectInput接口) + |-XxxObjectOutput.java (实现ObjectOutput接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.common.serialize.Serialization (纯文本文件,内容为:xxx=com.xxx.XxxSerialization) +``` + +XxxSerialization.java: + +```java +package com.xxx; + +import org.apache.dubbo.common.serialize.Serialization; +import org.apache.dubbo.common.serialize.ObjectInput; +import org.apache.dubbo.common.serialize.ObjectOutput; + + +public class XxxSerialization implements Serialization { + public ObjectOutput serialize(Parameters parameters, OutputStream output) throws IOException { + return new XxxObjectOutput(output); + } + public ObjectInput deserialize(Parameters parameters, InputStream input) throws IOException { + return new XxxObjectInput(input); + } +} +``` + +META-INF/dubbo/org.apache.dubbo.common.serialize.Serialization: + +```properties +xxx=com.xxx.XxxSerialization +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/startup.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/startup.md new file mode 100644 index 000000000000..14e90e26d9b5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/startup.md @@ -0,0 +1,82 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/startup/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/startup/ +description: Startup 启动探针 +linkTitle: 启动探针 +title: Startup 启动探针 +type: docs +weight: 12 +--- + + + + + + +## 扩展说明 + + +拓展应用启动的检测点。 + + +## 扩展接口 + + +`org.apache.dubbo.qos.probe.StartupProbe` + + +## 扩展配置 + + +Dubbo QOS `startup`   命令自动发现 + + +## 已知扩展 + + +- `org.apache.dubbo.qos.probe.impl.BootstrapLivenessProbe` + + + +## 扩展示例 + + +Maven 项目结构: + + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxStartupProbe.java (实现StartupProbe接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.qos.probe.StartupProbe (纯文本文件,内容为:xxx=com.xxx.XxxStartupProbe) +``` + + +XxxStartupProbee.java: + + +```java +package com.xxx; + +public class XxxStartupProbe implements StartupProbe { + + public boolean check() { + // ... + } +} +``` + + +META-INF/dubbo/org.apache.dubbo.qos.probe.StartupProbe: + + +``` +xxx=com.xxx.XxxStartupProbe +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/status-checker.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/status-checker.md new file mode 100644 index 000000000000..19a4fabf7fbd --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/status-checker.md @@ -0,0 +1,78 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/status-checker/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/status-checker/ +description: 状态检查扩展 +linkTitle: 状态检查扩展 +title: 状态检查扩展 +type: docs +weight: 21 +--- + + + + + + +## 扩展说明 + +检查服务依赖各种资源的状态,此状态检查可同时用于 telnet 的 status 命令和 hosting 的 status 页面。 + +## 扩展接口 + +`org.apache.dubbo.common.status.StatusChecker` + +## 扩展配置 + +```xml + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.common.status.support.MemoryStatusChecker` +* `org.apache.dubbo.common.status.support.LoadStatusChecker` +* `org.apache.dubbo.rpc.dubbo.status.ServerStatusChecker` +* `org.apache.dubbo.rpc.dubbo.status.ThreadPoolStatusChecker` +* `org.apache.dubbo.registry.directory.RegistryStatusChecker` +* `org.apache.dubbo.rpc.config.spring.status.SpringStatusChecker` +* `org.apache.dubbo.rpc.config.spring.status.DataSourceStatusChecker` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxStatusChecker.java (实现StatusChecker接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.common.status.StatusChecker (纯文本文件,内容为:xxx=com.xxx.XxxStatusChecker) +``` + +XxxStatusChecker.java: + +```java +package com.xxx; + +import org.apache.dubbo.common.status.StatusChecker; + +public class XxxStatusChecker implements StatusChecker { + public Status check() { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.common.status.StatusChecker: + +```properties +xxx=com.xxx.XxxStatusChecker +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/telnet-handler.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/telnet-handler.md new file mode 100644 index 000000000000..262c98fd3082 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/telnet-handler.md @@ -0,0 +1,91 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/telnet-handler/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/telnet-handler/ +description: Telnet 命令扩展 +linkTitle: Telnet 命令扩展 +title: Telnet 命令扩展 +type: docs +weight: 20 +--- + + + + + + +## 扩展说明 + +所有服务器均支持 telnet 访问,用于人工干预。 + +## 扩展接口 + +`org.apache.dubbo.remoting.telnet.TelnetHandler` + +## 扩展配置 + +```xml + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.remoting.telnet.support.ClearTelnetHandler` +* `org.apache.dubbo.remoting.telnet.support.ExitTelnetHandler` +* `org.apache.dubbo.remoting.telnet.support.HelpTelnetHandler` +* `org.apache.dubbo.remoting.telnet.support.StatusTelnetHandler` +* `org.apache.dubbo.rpc.dubbo.telnet.ListTelnetHandler` +* `org.apache.dubbo.rpc.dubbo.telnet.ChangeTelnetHandler` +* `org.apache.dubbo.rpc.dubbo.telnet.CurrentTelnetHandler` +* `org.apache.dubbo.rpc.dubbo.telnet.InvokeTelnetHandler` +* `org.apache.dubbo.rpc.dubbo.telnet.TraceTelnetHandler` +* `org.apache.dubbo.rpc.dubbo.telnet.CountTelnetHandler` +* `org.apache.dubbo.rpc.dubbo.telnet.PortTelnetHandler` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxTelnetHandler.java (实现TelnetHandler接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.remoting.telnet.TelnetHandler (纯文本文件,内容为:xxx=com.xxx.XxxTelnetHandler) +``` + +XxxTelnetHandler.java: + +```java +package com.xxx; + +import org.apache.dubbo.remoting.telnet.TelnetHandler; + +@Help(parameter="...", summary="...", detail="...") + +public class XxxTelnetHandler implements TelnetHandler { + public String telnet(Channel channel, String message) throws RemotingException { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.remoting.telnet.TelnetHandler: + +```properties +xxx=com.xxx.XxxTelnetHandler +``` + +## 命令用法 + +```sh +telnet 127.0.0.1 20880 +dubbo> xxx args +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/threadpool.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/threadpool.md new file mode 100644 index 000000000000..d73ecf0a0907 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/threadpool.md @@ -0,0 +1,74 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/threadpool/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/threadpool/ +description: 线程池扩展 +linkTitle: 线程池扩展 +title: 线程池扩展 +type: docs +weight: 15 +--- + + + + + + +## 扩展说明 + +服务提供方线程池实现策略,当服务器收到一个请求时,需要在线程池中创建一个线程去执行服务提供方业务逻辑。 + +## 扩展接口 + +`org.apache.dubbo.common.threadpool.ThreadPool` + +## 扩展配置 + +```xml + + + +``` + +## 已知扩展 + +* `org.apache.dubbo.common.threadpool.FixedThreadPool` +* `org.apache.dubbo.common.threadpool.CachedThreadPool` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxThreadPool.java (实现ThreadPool接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.common.threadpool.ThreadPool (纯文本文件,内容为:xxx=com.xxx.XxxThreadPool) +``` + +XxxThreadPool.java: + +```java +package com.xxx; + +import org.apache.dubbo.common.threadpool.ThreadPool; +import java.util.concurrent.Executor; + +public class XxxThreadPool implements ThreadPool { + public Executor getExecutor() { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.common.threadpool.ThreadPool: + +```properties +xxx=com.xxx.XxxThreadPool +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/validation.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/validation.md new file mode 100644 index 000000000000..39804cf4f2cf --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/validation.md @@ -0,0 +1,89 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/description/validation/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/validation/ +description: 验证扩展 +linkTitle: 验证扩展 +title: 验证扩展 +type: docs +weight: 25 +--- + + + + + + +## 扩展说明 + +参数验证扩展点。 + +## 扩展接口 + +`org.apache.dubbo.validation.Validation` + +## 扩展配置 + +```xml + + + +``` + +## 已知扩展 + +`org.apache.dubbo.validation.support.jvalidation.JValidation` + +## 扩展示例 + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxValidation.java (实现Validation接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.validation.Validation (纯文本文件,内容为:xxx=com.xxx.XxxValidation) +``` + +XxxValidation.java: + +```java +package com.xxx; + +import org.apache.dubbo.validation.Validation; + +public class XxxValidation implements Validation { + public Object getValidator(URL url) { + // ... + } +} +``` + +XxxValidator.java: + +```java +package com.xxx; + +import org.apache.dubbo.validation.Validator; + +public class XxxValidator implements Validator { + public XxxValidator(URL url) { + // ... + } + public void validate(Invocation invocation) throws Exception { + // ... + } +} +``` + +META-INF/dubbo/org.apache.dubbo.validation.Validation: + +```properties +xxx=com.xxx.XxxValidation +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/overview.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/overview.md new file mode 100644 index 000000000000..9ebf6e85627a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/overview.md @@ -0,0 +1,25 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/spi/overview/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/overview/ +description: Dubbo 通过 SPI 机制提供了非常灵活的可扩展性 +linkTitle: SPI 概述 +title: Dubbo SPI 概述 +type: docs +weight: 1 +--- + +使用 IoC 容器帮助管理组件的生命周期、依赖关系注入等是很多开发框架的常用设计,Dubbo 中内置了一个轻量版本的 IoC 容器,用来管理框架内部的插件,实现包括插件实例化、生命周期、依赖关系自动注入等能力。 + +感兴趣的读者可以了解: +* [Dubbo SPI 扩展体系的工作原理](/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/) +* [Dubbo SPI 扩展使用示例](/zh-cn/overview/mannual/java-sdk/tasks/extensibility/spi/) + +Dubbo 插件体系与 IoC 容器具有以下特点: +* **[核心组件均被定义为插件](../spi-list/),用户或二次开发者扩展非常简单。** 在无需改造框架内核的情况下,用户可以基于自身需求扩展如负载均衡、注册中心、通信协议、路由等策略。 +* **平等对待第三方扩展实现。** Dubbo 中所有内部实现和第三方实现都是平等的,用户可以基于自身业务需求替换 Dubbo 提供的原生实现。 +* **[插件依赖支持自动注入(IoC)](/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#23-ioc-机制)。** 如果插件实现依赖其他插件属性,则 Dubbo 框架会完成该依赖对象的自动注入,支持属性、构造函数等方式。 +* **[插件扩展实现支持 AOP 能力](/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#24-aop-机制)。** 框架可以自动发现扩展类的包装类,通过包装器模式对插件进行 AOP 增强。 +* **[支持插件自动激活](/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#25-activate激活条件)。** 通过为插件实现指定激活条件(通过注解参数等),框架可在运行时自动根据当前上下文决策是否激活该插件实现。 +* **[支持插件扩展排序](/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#26-扩展点排序)。** + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/spi-list.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/spi-list.md new file mode 100644 index 0000000000000000000000000000000000000000..a82b65c5ecb109f3970706b265a424970ff9ac94 GIT binary patch literal 27710 zcmdsA>vI&>mEX_$E4uKPEEP4eliJ!M>r{k*m;`KABD+=D+N!i>T2h*<-^FHU^ zX>V_DOWN6l=VWq@n?7tDIGXS2agFZNCk%gOuCP8COkVNFroP*n3KqwL2X6{%&x>=H zBH#Nwwk2_b_lSDM(_i&t(oBV!@|yMfAlf#@Qf9p z96Sh0x3&4BZwuSk{h3vN=3?pTa4`RMaBG|w}HlyK7tJCn;Evd`!2bQUbqp3mB5Cf#?y$mRx9 z_J;=stn=-kImulA;eY$ZFEZzU-OsCM<#X<@5B#RB?Y;Mms@dq?dq(lbf`4t>zqTCA zFBI0M3maF6Tkbt5y%=e0``kEqka$qhh&b`!L4$7lmlr_D((0?=&a}K$T-qq?TwzMe zTfy#7@M<%-zlcHU7Dfa!VSt)XeB*k3rj@Z0{kEAT_BRvmz<`@JQ&zgq?C#I!lI~~e zk6ia`rYN+Pzm?zEZw16s!*WlUEB{ zb3n0pV>y@{3g#z`*zp+`Oap%4PcUeC^lEW?g&1%AnSXhiQ52}vLm=1h*;X>+x+&8> zXQy-K8FAw@ZX7$`Z{@Q&J9*N zF>EIk+iitXdrIPz{V z=bV+Zjo{nm($g;)T|fb?5ll^Lc8UrL zv_NnJ-wrdap>mBscAW$>JZILE*x8Z&O6$;vrUn@d;cCYOng6+zA?%?+&vu3AGH=oYM0P>?!*%G`r+QEuvD|NbddFYtS9={-6N--4TP|hScTL>e48z zUx9KXXGK`<3W^B(#&?(x$a*~bs<3lE_xgOD}#Jw0G7)5U8&wH!`5XZLv)x!`(fPD>M~S>SWH zOv{Ch>0tV?Kl5dA<0&r{ySDYjO3jc+Ib{C_95u};b=8$mMHyYuO-*koybLF608Ypojr55r0)!Aj8HMvvWZ zopbPj+iO(MYZ}M#g?(N)2#4_k%sUxj8V`T)0B+jI_1i{oYS8$s-%c9|+sj!F{&mwy zhp1@`*mf>!#tZvj+$=c~J+^t$fp=tQvp~AXhImDN)8NaY;C1NMgV4}x(iy=BpwBtm z=+EUcU?f@?HkA}Zoc(wHmPR&s7;uw*2hu<{7amJTuo4I@Ny;}-GXJgxrP9JPqg$Cw z%1JOk5`Kh1yC798bH__iW49_KeivL+XTQ`Z|8}rG`RQvhb|wA!t?C7+0^}#N0vd@Q zYzbgly<9%CANGf#rB~}OfqI}q0MyOuC8z-8C$j(&+ILKT>5V1rOv)WJJ3^5=D(*z| z{!x*W;W*NtT}A8{RZyIgiP~RsM}!~mPmKmwzV;{X`%ka_+aEK!+_flb-02_TaJDuWlzCkrR<*`QG?}0 z|NiX;MCAvX5_O-xASqxg*jmrB#?JnPlTA zGr094@aNj(cWe>LDqF%UA8zkBTZq7kUCTFM8Hj)|QpN}wZ%Jwc? zz@Xy)h%aMahD$)6eUIzr-~n41QwY@&^`}rg-8na-#7>TfA>ll5#)>U_@!pz0`t468 zMWyp{$Wh1)9a04%xdPBnxSbUKBc15qMZPIakh1^6ci_$-b;(Oisnn-ei!V3*2Ukdr zMPf|~oEQhpz+PxYT2khNA0P`ysXUHSPJGgd9P&D5Mvzdx{ffrhyzb9V5JN$^2n}U) zXFM#aam2RL64c0GbvR0{Wmdduh9uyz;s^m5A#QtgpCa5nr_r2ruV*1YfzOVlm4V+6 z+A~P4i*aNk9MP0W1o|(=D4hgj@?f5_3}W#(buO6?jK*9ZvLJY2dl!qn2)%&YY&2IXvhLl&1 z8A)ayDqLoPn0A#74pQTT5XsA(LOq>GBWkfy2%AJgW`3Ec&<32M?Mb4F4E>a0=lil= zP?@TLk?*2l%SM34lOS0}YycMCZ|Ds^<`kl|0+C#M6C{bh7>d(wHV1z*fye?89kNfc z$cnt_J3yBF8DukSsm%F{VDf2cajK3~P;L^j59gabBphMQge^IaN=Ld=1lAqtw2O2a zBF=d1qKaUTY1%!~SSm$;n1fJw*7D13CDU&rlpMB10qg zF#~~i4=He!458Ejtt@HwOg|h9^It-CYe5x@0#P)*0h|60EeI*Z%#LIdERa=R0|p zT)$e_o)4+G=QMy8TGlDiynnpVYMddal;`n|J04_~QeWi2#o{e*PK`qsMNN(1GK67zDA6>pcnx`X@|SUZ~^u)XiLCW&MsaEZ!S z)j*&)d=7v84PcIODP=-bS-Yclua!@cW{N>sTD{i&2Tj5*nTI=WQQ2!SBww9eUerH> z;lkRX8p_mS?}{uQ95R)gWpmjO!?cxvBmOac)Hs5)Osa>qLAh8AR43HaYy2wRqt*BD+?B{k^f`&Qc(_E_gUzS{(yp zND@NK#2w?TO=TkC>Y~sggiCNJ!fNP#e_{+?FPJX4|Cqcglm*wGmBqNsXNAq_($G}! za6P!X!b`y4YI#NR6MYPj{ivf++`LP!$Hd!UeuHuy0z^uHUtQrT1X!38vK@;Q!&T2R zRb_W2^ERS1QzfjH2rf5c^4aYPUZ-|y%+PBuT^UL0hz@F^LL?8!a>G$4n{dzB-e9#j z)Z>63RvhX>^}WP`l+)}KbUsr{(p-xLU)WyzfSa^GbkayNQ4XC&DwYs?qVWkiV1>nJ z^&C4mSPUML{)z|Y(L*;Eb0)YTAa-;od@nSid=s#=q#%G68ARf=2^ZuXjf-k6>(;^*n z;X-2u{?V4Aip*Tb(PWmef;Qn*y<8VP5!Vob>LLq*;(YeIjytJn_CfPl6;HA_R^;nA z^}wAO-18!$z*w;+Mv8q#bYl3UBM2X1!Rm0723;|bM5PLYsLR$uNQB86_ofINmTm84 z3dNVCR1XRv_~c>(D_AkuhwVxB3Uv?B`v!U%ksL!JuzdSD*YBeE6gEeZXa}<*UXuMs zNQE`%F{(1;nuO9cDK+>p@}Ir3Fjt`p8_NY8A}FEaVyV2wO%CGLu`IVcrFwu)r~Z6kOwPLQ;^iPqTVgup$9 ziuLO2(9sl$Ox@BCNc}51ToGWv6%?kj_{~mnWr!Q**yF5~NA?L=%Ie!!s?Z2Q6pv84 zOBi1ui&j1KgVY8;JZo@s0<{}|<{@%{b)+dFakY``yNAg5^lBNo(K=xC%*JtBz zo&I5V)0C~!XHiWiS$$;+MJy`xi&)Uednv>JVoLQSczi>|eQXw~J6GfZb^OEvDHVly z5|$TzHh3Nn7Z+D3vAcV}coUtD)OG`dOWrztT{%$c$yo8;E$D*cw-iB;@UO1NqJkyE z(jcIS^@Sp&QsF4VT*{Qnb!kLEFj|bas_0{aKJ8*KDq=F#L#Li~RjgAlGBI7JJCW88 zUJp~=dSwwL`-kUaKr2u~OoZm|GDz=<4r&18!_tnNOVN_6*j*_8mJaO z)-bY1U6gM$yGCCjDR^?xe}21k`6B8Kg#FeA^vmy${=q=~w*kuM2hC5da~86BNPYfZ zT~$FCgL^b1j?8+-L6uICpg9Hpz{`t-3aK$b;j zr~Ii6e_=u9kFds5>y-QwQcnIvGzBO8qteRXpk63kzxN8g^o5;Wa0WAz@mBz3$cjuv zPvFVo@N4v%6AuaJ9jX~gdTb8Bh64ZP17xgZs81tcTG_ZZGU|`Lrk;J?SFtsR41>{? zNx<`^%&h@)4Fx2Xj+_{)1SO15f94sb6R0C_h}w`VsKq=&nZ`$7aX5)tDg8lBNq?5U z%%3%8{5Xn8OsD8e^%+#@beYWoNW`NO>6P{3@D7t%OCnYYQ3_a)ImJ*fGW&89Cl*M?8?S{>ljGw&M5Ehj~31NkbLm+tgh*_;{-j9ky$#VFUR@qj}N7i$fg;Cx8y z94ucznafHZv9Ol_(f#K}>D2=2gy@bfEiTrQhyjp(7$>WQLenB$`+5rqrvO0@Ltu8H zT<#83!qf=u$h)nh{t?=)C|@jt6|8HNJwyeI=hS#flm)W>>?IVT4J((!mJF&p9_kn4 z8NtKF^0O(X8c122&BY?K|8Jf_D|xyKjEXs$_sWB?jUx_*O3tW>6WwXhI0~sRU7B*C zP|>!b%_S7mAq>(5($X?>t@QdWbdGQruToIBc^&>=N#xae?*Tj#UII~k;G8E9*@Te4 zqrD+cLPNAiB9iE;YGG~R0qQ{SQ}|h*=jJmX9#8^zfHoyHUVtpOX}7upU_;nrE-CCh zm5DZva|Pdhw{@@ae4^=;3aNXTQK3_ao3TCzDCHs9St>Za3h{hFo#XNmXiabl^{UL$ z=Dou9n9{iN0j@}aB;}z=l&Lt&1d4-E$YL!$<=hmTLsrs77{zJnMSr(77b|`m!q{)C zuu@(wOrG%K@h_P^J;pobwWi$EE7a9Hm1Bi(mzzi0Cd_u1-Xb~hvZ^PCiCkd;#8w`y zBl)e;(@SW((@qS;mtBG%mspThVDy6!i-$Im56{_RlZyQVl8;2Da(I>;_*JFxS1dW$ z$>cAM!_huPbh79 zedyr8exwe0Q6I^7Ek`Y{#DJacH}g3sWuEb@1Ui`jBY7uCdfzysrTZWj3 zVz(#5d=oA9P;^z#GgIl5b~KR%9UDs;KG7hAsGr*Ntn>%wNAjW?L?#bg-0Di18b+WK zAyvbjwW7C}_v?!j3BrxN09YS2P?Zw_I>mb{bZo-rD4Lv@B^aEFj4vnx(F&iyK?68g zKt9r#CJ~Sn>-0M3?WB2}J}aPXM3Zos)(ArKX`jdb7di*wMAl6SVjh!sy1Dy0A|&c8 zhVtBv;*-ro^;ye0>L&y0G=IJoE+1L!x%T_qel+lh>RT=DaTD%R1VBbHs?g%FU6$wcgA!*~HVz z5!!!)%FPgh5S|`3#h>2fC6iHO6SET6z!5PlR8;logc$H}r)=yCZ^`xtqWlH?ua%U5 z97Lu7bpFEMSn#(-jO;O$T$Zx9UYP>x>)6zCWa zWt@4IciRUK*Rbba8wS#Yy!)Gr9HJr_eV#i&*@)JW$qGo6s*ALRHUW;0F5=c+E`afX z?Gm?`KGB9dA9Rz0XA8ZcI$gTNpCMIrzlkJ_@^K*wQIbeQshU&xVe%_3E;Ci)%%X+? zyVX4#RXW`xTMrs3eNi%~L9i)ZAhHiah+}a=I?$g?hG^CZAkh~F3bp8Ig^L(m4maeH z5)?771W-_k5tpnnft^39j;)5Gvm3rzS{Ga4J{7iJm00BSB37 zf3OF!=h3rpID=~FX9L?#4;s7y74uZo&B0}gkC?tj#~%!|Fb5m69K7&JW^r^8)5~Ut z7zir(#!?U>6UZQnCKxt@9B0Sd?hr@dKuzX2$RN_k*%U!mDl9r2!&9bVWvR4^lWypU zuez9Nlsc+ru0*WjOR-agTk)EE&)ICsq)pP181&4^Zj@bz3+qpK33y4cW{d{QzFx5C zll8Tt3STgr*s$B(eUdF!)!aOnq*U{QnljexT*51WQ&QTw?xRdDk|h7|rV_QkxD&^j zr0ta4S&Zct|HXHg$t}s9XyQ(^{^SQOJ&HbgB-tq0*3#ohB(RI!aX1whf6M)_~Yqed`c6k5WPUV`J1MrQ~emjlL>m#3^W z6j^Jevd`0zHOTTElNYVMM#sFEAK~MOlSYBNC3xwb_dhU^d&vSk@iuZSbbTzH0M|sy zLe1%3f3TzWeh2GE4gfHIfCKgQ(mNYA0dk``x7Ie5T`~!05W;alhb- z35c>djjRj1Q89(U4%co93)m9uXaW*DJt08*MgJWlS|259BWZ+CO`3rk%`hDH6hkwp z%l(dUln%y_!|iDdflyqM8|wo$cn4#3wXoVX#1UX|nH$H9Wpl^Wkr8_bC~g!fk$WF( z0Ih`-lKN{7!?9Y^S+p0 z(y6)F5`bPR4qHVc3V|eVA>l)W>gMT0sU#Lc-iQex!f2d_&C8|NbS6#MO8)jS!erpWDQw;xVd$1|PE*J_g4j4= ze40FqV|;HJJqSB`@<|-vM<!Hh^DP5 zRW&gyDHqchB!P!E5i@rq$Cd6o;~qzIZY~N&Gq~vltWP}nRCW^T7$Tf=Y&!H(6||#_ z&e=rTlrBVAo>{N9OVCCe`M%8kw1^v*9hw0u&>WB}WQwH{tr$^ce_WbtU=;B?JkJ`8 z!qX5Z&MzOu)@Dk$kzQ%aXJJ9n#Mx;S+9F!zdLgA;vknHLlO*a7#D}$*`jEX(addqa zF8?PzbV3-pMQEm{#0Bqy3zc^r0XT=FiLg7H!fvdFyu|$Kzc{%g6NKiV{;n#Awaygu zIBkee;ibe`t0!f12vue5n!eo;9;Zm>-l$+!LE7|v@&$0#oOIG68&T8<^>Ah2yAzNO z96V^JXm-{(+Bd8-x#i}>fqXcwiK>jCGDW0E#jkVp*q%%rTdfWQu|7Yz=eMP%`IOk? z_xSiD8ekO4b>OaWG8{Um9%}~|=qQ|oPB$~y!Vn?qSz&hf3pNy_IQ1y9`iOCwz#l4C z@h(;kEj`U&gYPS96R;>0iksk5`de}g=9GD4ajH8148S2iDP0#SxR67(RP?~fO^>2_ z3~h?`4pd`um+$Gfk$AK_<0c)U8svKlg(aIXO{USU6)%M$@zd$o!qYq|UJlMXqQXH<~yu+4cq;bnQSiPwPv0K7!^q zb)+<%^@zhf`DC-;{s^3o=rIN0FI10lFcSBBL{9Mx8z+9-dFm*PyLeUnh6G;X6C8DW z8gC@wf$MN%738Y=lXlaC18zRcY3De6bVr1&(_x^P$Kr^kd_D042RNafsJ`B7sY3cNRx#=pQ&>cbGemxj9MtayZ0;WmNpy5LM3}T;aWl zeDnv^6}Ra(TTUq3aB1p@}2=J4^KqK-9HD!ITmvP7$s> zxE}2;!43RS)C+x_MR+y=+V8MK1;-ZC52(-)YS{E$HIs<1uvd`us5te6t8{uNHWmt- zTIf^FFZb>9DmC1aT@P7sP&#ROl;5q3bY1l--cTppd<>op6I2Zd1vcIHVpL8d0E=nI Zkz#`$SN^G|@JLzdeTn`Xt)<%9{tuLDwtfHr literal 0 HcmV?d00001 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/_index.md new file mode 100755 index 000000000000..16e43cb651e0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/ + - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/ + - /zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/ +description: 升级和兼容性 +linkTitle: 升级和兼容性 +title: 升级和兼容性 +type: docs +weight: 200 +--- diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery.md new file mode 100644 index 000000000000..21fad0da0910 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery.md @@ -0,0 +1,77 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/ + - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/ + - /zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/ +description: 本文具体说明了用户在升级到 Dubbo3 之后,如何快速开启应用级服务发现新特性,从接口级服务发现平滑迁移到应用级服务发现。 +linkTitle: 升级到应用级服务发现 +title: 升级到应用级服务发现 +type: docs +weight: 3 +--- + +{{% alert title="请注意" color="warning" %}} +* 本文档内容并不是升级 Dubbo3 必须的,您完全可以只升级框架并使用 [框架的服务发现默认行为](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery/#启用应用级服务发现)。 +* 本文档更适用于 Dubbo2 老用户,用于了解在升级到 Dubbo3 版本后,框架中的服务发现模型切换过程与工作原理。新用户请直接 [配置启用应用级服务发现](/zh-cn/overview/mannual/java-sdk/tasks/service-discovery/nacos/#13-配置并启用-nacos)。 +{{% /alert %}} + +对于 Dubbo2 老用户而言,在升级 Dubbo3 时有以下两个选择,而决策的考虑因素仅有一个:性能。 +1. 如果您的集群规模不算大,之前使用 Dubbo2 未遇到任何地址推送等性能问题,完全可以继续使用接口级别服务发现 +2. 如果您集群规模较大,之前使用 Dubbo2 遇到服务发现负载飙高等问题,则建议迁移到新的应用级服务发现 + +基于以上决策结论,请在升级 Dubbo3 框架时调整以下配置。 + +## 继续使用接口级服务发现 + +在升级到 Dubbo3 框架时,您需要调整应用配置如下,(仅仅是一个配置项调整,提供者应用必须配置、消费者应用可选): + +```xml + +``` + +或者 + +```yaml +dubbo: + application: + name: xxx + register-mode: interface #表示继续使用老版本服务发现模型,可选值 interface、instance、all +``` + +或者,以上是全局默认配置,可以根据每个注册中心来单独配置 + +```xml + +``` + +或者 + +```yaml +dubbo: + registry: + address: nacos://localhost:8848 + register-mode: interface #表示继续使用老版本服务发现模型,可选值 interface、instance、all +``` + +## 启用应用级服务发现(默认) +对于老用户而言,如果要启用应用级服务发现,就需要一个平滑迁移的过程。这时需要让新升级的 Dubbo3 应用进行双注册双订阅(当前框架默认行为,因此用户无需修改任何配置,以下内容均会自行发生,注意:未来版本可能切换为应用级单注册单订阅),以确保新老服务发现模型都能兼顾。 + +{{% alert title="请注意" color="warning" %}} +对于新用户而言,可以直接配置 `dubbo.application.register-mode=instance`,即在一开始就配置仅使用应用级服务发现。 +{{% /alert %}} + +### 提供者端注册行为 +在默认情况下,Dubbo3 框架会同时注册接口级、应用级两种服务发现地址,因此,集群中的新老应用都能够正常的发现改应用地址,并正常发起调用。如下图所示: + + +dubbo应用级服务发现 + +### 消费者端订阅行为 +在默认情况下,Dubbo3 框架具备同时发现 Dubbo2 与 Dubbo3 地址列表的能力。在默认情况下,如果集群中存在可以消费的 Dubbo3 的地址,将自动消费 Dubbo3 的地址,如果不存在新地址则自动消费 Dubbo2 的地址(Dubbo3 提供了开关来控制这个行为),具体如下图所示: + +dubbo应用级服务发现 + +### 状态收敛 + +关于以上双注册、双订阅行为的更多详细解释,以及如何尽快完成服务发现模型的收敛,请参考博客文章 [Dubbo3 服务发现平滑迁移步骤与原理](/zh-cn/blog/2024/05/13/如果从接口级服务发现平滑迁移到应用级服务发现/)。 + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md new file mode 100644 index 000000000000..de08662063f0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md @@ -0,0 +1,108 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/ + - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/ + - /zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/migration-triple/ +description: "如何平滑的从 dubbo 协议升级到 triple 协议。" +linkTitle: 升级到triple协议 +title: 升级到triple协议 +type: docs +weight: 2 +--- + +{{% alert title="请注意" color="warning" %}} +* 本文档内容并不是升级 Dubbo3 必须的,您完全可以只升级框架并继续使用 dubbo 通信协议。 +* 如果您是 Dubbo 新用户,强烈建议直接 [使用 triple 协议](/zh-cn/overview/mannual/java-sdk/tasks/protocol/) 即可。 +{{% /alert %}} + +本文档适合服务已经运行在 dubbo 协议之上的老用户,请先参考上一篇文档 [如何从 Dubbo2 升级到 Dubbo3](../migration/) 完成框架版本升级,然后遵循以下步骤以最小改动平滑迁移到 triple 协议。 + +以下是协议升级的架构图,展示了平滑升级过程中不同 Dubbo 应用的状态: + + +dubbo协议迁移到tirple协议 + +按先后顺序,升级基本步骤如下: +1. Provider 提供者侧配置单端口双协议(dubbo、triple)发布 +2. Provider 提供者侧配置首选协议为 triple(此时,提供者注册的URL地址为 `dubbo://host:port/DemoService?preferred-protocol=tri`) +3. Consumer 消费者升级,根据情况不同有以下两种方式: + * 升级消费者到 3.3 版本,消费者会根据 `preferred-protocol=tri` 优先调用 triple 协议 + * 无法升级到 3.3 版本的消费者应用,可以配置 `@DubboReference(protocol="tri")` 调用 triple 协议 +4. 推动所有应用升级到最新 Dubbo3 版本,最终所有流量都是 triple 协议 + +{{% alert title="请注意" color="warning" %}} +请注意,以上提到的单端口多协议、识别 `preferred-protocol` 首选协议等功能,需要 Dubbo 3.3.0+ 版本! +{{% /alert %}} + +### 步骤一:提供者双协议发布 +假设我们有以下应用配置,即在 20880 端口发布 dubbo 协议: +```yaml +dubbo: + protocol: + name: dubbo + port: 20880 +``` + +我们需要增加两个配置项,如下所示: + +```yaml +dubbo: + protocol: + name: dubbo + port: 20880 + ext-protocol: tri + preferred-protocol: tri +``` + +其中, +* `ext-protocol: tri` 指定在原 20880 端口上额外发布 triple 协议,即单端口双协议发布。 +* `preferred-protocol: tri` 会随注册中心同步到 Consumer 侧,告诉 consumer 优先使用 triple 协议调用 + +{{% alert title="注意" color="warning" %}} +`preferred-protocol: tri` 配置仅在 3.3.0 及之后版本支持,所以即使 provider 配置了这个选项,对于 3.3.0 版本即之前的 consumer 消费端并不会生效,还是会调用 dubbo 协议。 +{{% /alert %}} + +### 步骤二:消费端切换协议 +提供端完成步骤一配置并重启后,消费端根据版本与配置不同,可能处于以下三种状态之一: + +**1. 消费端是 3.3.0 及之后版本** + +此类消费端会自动识别提供者 url 上的 `preferred-protocol: tri` 标记,如果发现此标记,则消费端自动使用 triple 协议调用服务,否则继续使用 dubbo 协议。 + +**2. 消费端是 2.x 或 3.3.0 之前版本** + +由于低版本 Dubbo 框架不能识别 `preferred-protocol: tri` 参数,因此这部分消费者不受提供者端多协议发布的任何影响,继续调用 dubbo 协议。 + +**3. 消费端是 2.x 或 3.3.0 之前版本,且额外指定要调用的协议** + +与第 2 种情况基本一致,只是这时用户可以明确的为某些服务指定使用哪种 rpc 协议,如: + +```java +@DubboReference(protocol="tri") +private DemoService demoService; +``` + +或者 + +```xml + +``` + +在配置了 `protocol="tri"` 后,服务的调用会使用 triple 协议。需要注意的是,在配置 `protocol="tri"` 之前,一定要确保提供端已经发布了 triple 协议支持,否则调用将会失败。 + +{{% alert title="注意" color="warning" %}} +* 从以上三种情况可知,协议升级过程对消费端完全无感,消费端不会因提供端的多协议配置而出现任何通信障碍。 +* 对于消费端,最简单的协议切换方式就是通过 `preferred-protocol=tri` 进行自动切换,需要两边版本都升级到 3.3.0+ 才支持。 +{{% /alert %}} + +### 步骤三:完全收敛到triple协议 +步骤一、二操作起来非常简单,并且保证了过程平滑,通过单端口双协议、消费端自动切换保证了整个升级过程的平滑。 + +平滑升级意味着我们要经历一个中间态,即在某一段时间内,集群内 dubbo 协议、triple 协议共存(有些服务间通信是dubbo协议、有些服务间通信是triple协议)。如何才能推进达成终态目标那,即所有服务调用都使用 triple 协议?我们推荐使用以下两种方式达成目标: +* 推进集群内所有 Dubbo 应用都升级到 3.3.x 最新版本,这样消费端就能自动切换到 triple 协议 +* 通过 Dubbo 框架的指标埋点,观察某个应用(作为provider)是否仍在处理 dubbo 流量,对这部分应用的上下游进行治理 + +{{% alert title="注意" color="info" %}} +对于 Dubbo 框架而言,集群内 dubbo 协议和 triple 协议共存的状态并不存在任何技术问题,不同的服务调用使用不同协议也很正常,因此双协议共存的中间态是完全可以接受的。但有时候为了整体方案统一,我们可能需要达成单一通信协议的终态目标。 +{{% /alert %}} + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md.bak new file mode 100644 index 000000000000..910d130944ea --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md.bak @@ -0,0 +1,346 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/ + - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/ +description: Triple 协议迁移指南 +linkTitle: Dubbo 协议迁移至 Triple 协议 +title: Dubbo 协议迁移至 Triple 协议 +type: docs +weight: 7 +--- + + +## Triple 协议介绍 + +根据 Triple 设计的目标,`Triple` 协议有以下优势: + +- 具备跨语言交互的能力,传统的多语言多 SDK 模式和 Mesh 化跨语言模式都需要一种更通用易扩展的数据传输协议。 +- 提供更完善的请求模型,除了支持传统的 Request/Response 模型(Unary 单向通信),还支持 Stream(流式通信) 和 Bidirectional(双向通信)。 +- 易扩展、穿透性高,包括但不限于 Tracing / Monitoring 等支持,也应该能被各层设备识别,网关设施等可以识别数据报文,对 Service Mesh 部署友好,降低用户理解难度。 +- 完全兼容 grpc,客户端/服务端可以与原生grpc客户端打通。 +- 可以复用现有 grpc 生态下的组件, 满足云原生场景下的跨语言、跨环境、跨平台的互通需求。 + +当前使用其他协议的 Dubbo 用户,框架提供了兼容现有序列化方式的迁移能力,在不影响线上已有业务的前提下,迁移协议的成本几乎为零。 + +需要新增对接 Grpc 服务的 Dubbo 用户,可以直接使用 Triple 协议来实现打通,不需要单独引入 grpc client 来完成,不仅能保留已有的 Dubbo 易用性,也能降低程序的复杂度和开发运维成本,不需要额外进行适配和开发即可接入现有生态。 + +对于需要网关接入的 Dubbo 用户,Triple 协议提供了更加原生的方式,让网关开发或者使用开源的 grpc 网关组件更加简单。网关可以选择不解析 payload ,在性能上也有很大提高。在使用 Dubbo 协议时,语言相关的序列化方式是网关的一个很大痛点,而传统的 HTTP 转 Dubbo 的方式对于跨语言序列化几乎是无能为力的。同时,由于 Triple 的协议元数据都存储在请求头中,网关可以轻松的实现定制需求,如路由和限流等功能。 + +> `Triple` 协议的格式和原理请参阅 [RPC 通信协议](/zh-cn/docs/concepts/rpc-protocol/) + +## Dubbo2 协议迁移流程 + +Dubbo2 的用户使用 dubbo 协议 + 自定义序列化,如 hessian2 完成远程调用。 + +而 Grpc 的默认仅支持 Protobuf 序列化,对于 Java 语言中的多参数以及方法重载也无法支持。 + +Dubbo3的之初就有一条目标是完美兼容 Dubbo2,所以为了 Dubbo2 能够平滑升级, Dubbo 框架侧做了很多工作来保证升级的无感,目前默认的序列化和 Dubbo2 保持一致为`hessian2`。 + +所以,如果决定要升级到 Dubbo3 的 `Triple` 协议,只需要修改配置中的协议名称为 `tri` (注意: 不是triple)即可。 + +接下来我们我们以一个使用 Dubbo2 协议的[工程](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration) 来举例,如何一步一步安全的升级。 + +1. 仅使用 `dubbo` 协议启动 `provider` 和 `consumer`,并完成调用。 +2. 使用 `dubbo` 和 `tri` 协议 启动`provider`,以 `dubbo` 协议启动 `consumer`,并完成调用。 +3. 仅使用 `tri` 协议 启动 `provider`和 `consumer`,并完成调用。 + +### 定义服务 + +1. 定义接口 +```java +public interface IWrapperGreeter { + + //... + + /** + * 这是一个普通接口,没有使用 pb 序列化 + */ + String sayHello(String request); + +} +``` + +2. 实现类如下 +```java +public class IGreeter2Impl implements IWrapperGreeter { + + @Override + public String sayHello(String request) { + return "hello," + request; + } +} +``` + +### 仅使用 triple 协议 + +当所有的 consuemr 都升级至支持 `Triple` 协议的版本后,provider 可切换至仅使用 `Triple` 协议启动 + +结构如图所示: +![strust](/imgs/v3/migration/tri/migrate-only-tri-strust.png) + +[Provider](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationTriProvider.java) +和 [Consumer](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationTriConsumer.java) 完成调用,输出如下: + +![result](/imgs/v3/migration/tri/dubbo3-tri-migration-tri-tri-result.png) + +### 仅使用 dubbo 协议 + +为保证兼容性,我们先将部分 provider 升级到 `dubbo3` 版本并使用 `dubbo` 协议。 + +使用 `dubbo` 协议启动一个 [`Provider`](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboProvider.java) 和 [`Consumer`](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboConsumer.java) ,完成调用,输出如下: +![result](/imgs/v3/migration/tri/dubbo3-tri-migration-dubbo-dubbo-result.png) + +### 同时使用两协议 + +对于线上服务的升级,不可能一蹴而就同时完成 provider 和 consumer 升级, 需要按步操作,保证业务稳定。 +第二步, provider 提供双协议的方式同时支持 dubbo + tri 两种协议的客户端。 + +结构如图所示: +![strust](/imgs/v3/migration/tri/migrate-dubbo-tri-strust.png) + +> 按照推荐升级步骤,provider 已经支持了tri协议,所以 dubbo3的 consumer 可以直接使用 tri 协议 + +使用`dubbo`协议和`triple`协议启动[`Provider`](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothProvider.java)和[`Consumer`](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothConsumer.java),完成调用,输出如下: + +![result](/imgs/v3/migration/tri/dubbo3-tri-migration-both-dubbo-tri-result.png) + + +### 实现原理 + +通过上面介绍的升级过程,我们可以很简单的通过修改协议类型来完成升级。框架是怎么帮我们做到这些的呢? + +通过对 `Triple` 协议的介绍,我们知道Dubbo3的 `Triple` 的数据类型是 `protobuf` 对象,那为什么非 `protobuf` 的 java 对象也可以被正常传输呢。 + +这里 Dubbo3 使用了一个巧妙的设计,首先判断参数类型是否为 `protobuf` 对象,如果不是。用一个 `protobuf` 对象将 `request` 和 `response` 进行 wrapper,这样就屏蔽了其他各种序列化带来的复杂度。在 `wrapper` 对象内部声明序列化类型,来支持序列化的扩展。 + +wrapper 的`protobuf`的 IDL如下: +```proto +syntax = "proto3"; + +package org.apache.dubbo.triple; + +message TripleRequestWrapper { + // hessian4 + // json + string serializeType = 1; + repeated bytes args = 2; + repeated string argTypes = 3; +} + +message TripleResponseWrapper { + string serializeType = 1; + bytes data = 2; + string type = 3; +} +``` + +对于请求,使用`TripleRequestWrapper`进行包装,对于响应使用`TripleResponseWrapper`进行包装。 + +> 对于请求参数,可以看到 args 被`repeated`修饰,这是因为需要支持 java 方法的多个参数。当然,序列化只能是一种。序列化的实现沿用 Dubbo2 实现的 spi + + +## 多语言用户 + +使用 `protobuf` 建议新服务均使用该方式,对于 Dubbo3 和 Triple 来说,主推的是使用 `protobuf` 序列化,并且使用 `proto` 定义的 `IDL` 来生成相关接口定义。以 `IDL` 做为多语言中的通用接口约定,加上 `Triple` 与 `Grpc` 的天然互通性,可以轻松地实现跨语言交互,例如 Go 语言等。 + +将编写好的 `.proto` 文件使用 `dubbo-compiler` 插件进行编译并编写实现类,完成方法调用: + +![result](/imgs/v3/migration/tri/dubbo3-tri-migration-tri-tri-result.png) + +从上面升级的例子我们可以知道,`Triple` 协议使用 `protbuf` 对象序列化后进行传输,所以对于本身就是 `protobuf` 对象的方法来说,没有任何其他逻辑。 + +使用 `protobuf` 插件编译后接口如下: +```java +public interface PbGreeter { + + static final String JAVA_SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; + static final String SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; + + static final boolean inited = PbGreeterDubbo.init(); + + org.apache.dubbo.sample.tri.GreeterReply greet(org.apache.dubbo.sample.tri.GreeterRequest request); + + default CompletableFuture greetAsync(org.apache.dubbo.sample.tri.GreeterRequest request){ + return CompletableFuture.supplyAsync(() -> greet(request)); + } + + void greetServerStream(org.apache.dubbo.sample.tri.GreeterRequest request, org.apache.dubbo.common.stream.StreamObserver responseObserver); + + org.apache.dubbo.common.stream.StreamObserver greetStream(org.apache.dubbo.common.stream.StreamObserver responseObserver); +} +``` + +## Triple 新特性 Stream 流 +Stream 是 Dubbo3 新提供的一种调用类型,在以下场景时建议使用流的方式: + +- 接口需要发送大量数据,这些数据无法被放在一个 RPC 的请求或响应中,需要分批发送,但应用层如果按照传统的多次 RPC 方式无法解决顺序和性能的问题,如果需要保证有序,则只能串行发送 +- 流式场景,数据需要按照发送顺序处理, 数据本身是没有确定边界的 +- 推送类场景,多个消息在同一个调用的上下文中被发送和处理 + +Stream 分为以下三种: +- SERVER_STREAM(服务端流) +![SERVER_STREAM](/imgs/v3/migration/tri/migrate-server-stream.png) +- CLIENT_STREAM(客户端流) +![CLIENT_STREAM](/imgs/v3/migration/tri/migrate-client-stream.png) +- BIDIRECTIONAL_STREAM(双向流) +![BIDIRECTIONAL_STREAM](/imgs/v3/migration/tri/migrate-bi-stream.png) + +> 由于 `java` 语言的限制,BIDIRECTIONAL_STREAM 和 CLIENT_STREAM 的实现是一样的。 + +在 Dubbo3 中,流式接口以 `SteamObserver` 声明和使用,用户可以通过使用和实现这个接口来发送和处理流的数据、异常和结束。 + +> 对于 Dubbo2 用户来说,可能会对StreamObserver感到陌生,这是Dubbo3定义的一种流类型,Dubbo2 中并不存在 Stream 的类型,所以对于迁移场景没有任何影响。 + +流的语义保证 +- 提供消息边界,可以方便地对消息单独处理 +- 严格有序,发送端的顺序和接收端顺序一致 +- 全双工,发送不需要等待 +- 支持取消和超时 + +## 非 PB 序列化的流 +1. api +```java +public interface IWrapperGreeter { + + StreamObserver sayHelloStream(StreamObserver response); + + void sayHelloServerStream(String request, StreamObserver response); +} +``` + +> Stream 方法的方法入参和返回值是严格约定的,为防止写错而导致问题,Dubbo3 框架侧做了对参数的检查, 如果出错则会抛出异常。 +> 对于 `双向流(BIDIRECTIONAL_STREAM)`, 需要注意参数中的 `StreamObserver` 是响应流,返回参数中的 `StreamObserver` 为请求流。 + +2. 实现类 +```java +public class WrapGreeterImpl implements WrapGreeter { + + //... + + @Override + public StreamObserver sayHelloStream(StreamObserver response) { + return new StreamObserver() { + @Override + public void onNext(String data) { + System.out.println(data); + response.onNext("hello,"+data); + } + + @Override + public void onError(Throwable throwable) { + throwable.printStackTrace(); + } + + @Override + public void onCompleted() { + System.out.println("onCompleted"); + response.onCompleted(); + } + }; + } + + @Override + public void sayHelloServerStream(String request, StreamObserver response) { + for (int i = 0; i < 10; i++) { + response.onNext("hello," + request); + } + response.onCompleted(); + } +} +``` + +3. 调用方式 +```java +delegate.sayHelloServerStream("server stream", new StreamObserver() { + @Override + public void onNext(String data) { + System.out.println(data); + } + + @Override + public void onError(Throwable throwable) { + throwable.printStackTrace(); + } + + @Override + public void onCompleted() { + System.out.println("onCompleted"); + } +}); + + +StreamObserver request = delegate.sayHelloStream(new StreamObserver() { + @Override + public void onNext(String data) { + System.out.println(data); + } + + @Override + public void onError(Throwable throwable) { + throwable.printStackTrace(); + } + + @Override + public void onCompleted() { + System.out.println("onCompleted"); + } +}); +for (int i = 0; i < n; i++) { + request.onNext("stream request" + i); +} +request.onCompleted(); +``` + +## Protobuf 序列化的流 + +对于 `Protobuf` 序列化方式,推荐编写 `IDL` 使用 `compiler` 插件进行编译生成。生成的代码大致如下: +```java +public interface PbGreeter { + + static final String JAVA_SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; + static final String SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; + + static final boolean inited = PbGreeterDubbo.init(); + + //... + + void greetServerStream(org.apache.dubbo.sample.tri.GreeterRequest request, org.apache.dubbo.common.stream.StreamObserver responseObserver); + + org.apache.dubbo.common.stream.StreamObserver greetStream(org.apache.dubbo.common.stream.StreamObserver responseObserver); +} +``` + +## 流的实现原理 + +`Triple`协议的流模式是怎么支持的呢? + +- 从协议层来说,`Triple` 是建立在 `HTTP2` 基础上的,所以直接拥有所有 `HTTP2` 的能力,故拥有了分 `stream` 和全双工的能力。 + +- 框架层来说,`StreamObserver` 作为流的接口提供给用户,用于入参和出参提供流式处理。框架在收发 stream data 时进行相应的接口调用, 从而保证流的生命周期完整。 + +## Triple 与应用级注册发现 + +关于 Triple 协议的应用级服务注册和发现和其他语言是一致的,可以通过下列内容了解更多。 + +- [服务发现](/zh-cn/docs/concepts/service-discovery/) +- [应用级地址发现迁移指南](/zh-cn/docs/migration/migration-service-discovery/) + +## 与 GRPC 互通 + +通过对于协议的介绍,我们知道 `Triple` 协议是基于 `HTTP2` 并兼容 `GRPC`。为了保证和验证与`GRPC`互通能力,Dubbo3 也编写了各种从场景下的测试。详细的可以通过[这里](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/README.MD) 了解更多。 + + +{{% alert title="未来: Everything on Stub" color="primary" %}} + +用过 `Grpc` 的同学应该对 `Stub` 都不陌生。 +Grpc 使用 `compiler` 将编写的 `proto` 文件编译为相关的 protobuf 对象和相关 rpc 接口。默认的会同时生成几种不同的 `stub` + +- blockingStub +- futureStub +- reactorStub +- ... + +`stub` 用一种统一的使用方式帮我们屏蔽了不同调用方式的细节。不过目前 `Dubbo3` 暂时只支持传统定义接口并进行调用的使用方式。 + +在不久的未来,`Triple` 也将实现各种常用的 `Stub`,让用户写一份`proto`文件,通过 `comipler` 可以在任意场景方便的使用,请拭目以待。 +{{% /alert %}} diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md new file mode 100644 index 000000000000..3cee46083f52 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md @@ -0,0 +1,305 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/migration/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/migration/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/ +description: "从 dubbo2 升级到 dubbo3:涵盖 2.6.x、2.5.x、2.7.x 等版本升级。" +linkTitle: 升级到Dubbo3 +title: 从 dubbo2 升级到 dubbo3(涵盖 2.5.x、2.6.x、2.7.x 等版本) +type: docs +weight: 1 +--- + +总体来说,Dubbo2 升级到 Dubbo3 后的核心能力都是兼容的,对于 90% 以上的常规用户而言(指未做深度 SPI 扩展或源码定制的用户),可以非常简单的完成升级。 + +## 2.7.x 升级 Dubbo3 + +### 步骤一:升级核心依赖 + +首先,在应用中增加 bom 依赖管理: + +```xml + + + + org.apache.dubbo + dubbo-dependencies-bom + 3.3.0 + pom + import + + + +``` + +如果您之前用的是 `org.apache.dubbo:dubbo` 依赖,请升级到以下版本(如果项目中还有其它 dubbo 子模块依赖,请一并升级版本号): + +```xml + + org.apache.dubbo + dubbo + +``` + +如果之前的应用是 Spring Boot,建议使用以下 starter 依赖方式并升级到最新版本(如果之前未使用 starter,请删除所有老的 dubbo 模块依赖,直接使用以下配置即可): + +```xml + + org.apache.dubbo + dubbo-spring-boot-starter + +``` + +{{% alert title="Dubbo3 相关的 Spring、Spring Boot 版本升级说明" color="warning" %}} +Dubbo3 支持的 Spring、Spring Boot 版本兼容范围非常广: +* 既支持 Spring 3.x ~ Spring 5.x 相关版本,同时也支持 Spring Boot 1.x ~ Spring Boot 2.x 版本。如果遇到应用无法升级高版本 Spring、Spring Boot 的情况下,可排掉 `dubbo-spring-boot-starter` 或 `dubbo` 中传递的高版本 Spring 依赖,指定项目可接受的 Spring 版本依赖即可。 +* Spring Boot 3.x 和 Spring 6 版本由于需要 JDK 17 及以上版本,请参考 [Dubbo Spring Boot 手册]() 了解详情。 +{{% /alert %}} + +### 步骤二:升级其它组件依赖 +1. Nacos 注册中心 + + 如果您使用的是 Nacos 注册中心,在升级到 Dubbo3 之前,请先确保 Nacos Server 升级到 2.x 版本。除了 Nacos Server 之外,我们还需要升级应用侧的 Nacos Client 依赖。 + + 如果是 Spring Boot 应用,则可删除 nacos-client 依赖,直接使用 starter: + + ```xml + + org.apache.dubbo + dubbo-nacos-spring-boot-starter + + ``` + + 如果您当前不是 Spring Boot 应用,则直接更新 nacos-client 到 2.x 即可: + + ```xml + + com.alibaba + nacos-client + 2.3.0 + + ``` + +2. Zookeeper 注册中心 + + 如果是 Spring Boot 应用,则可删除之前老的 Zookeeper 相关依赖,直接使用 starter: + + ```xml + + org.apache.dubbo + dubbo-zookeeper-curator5-spring-boot-starter + + ``` + + 请注意,以上 `dubbo-zookeeper-curator5-spring-boot-starter` 请搭配 Zookeeper Server 3.8.0+ 版本使用。如果您当前正在使用的 Zookeeper Server 版本是 3.4.x 版本,则使用以下 starter: + + ```xml + + org.apache.dubbo + dubbo-zookeeper-spring-boot-starter + + ``` + + 如果不是 Spring Boot 应用,则可以使用以下依赖(推荐,需确保 Zookeeper Server 3.8.0 版本及以上): + + ```xml + + org.apache.dubbo + dubbo-dependencies-zookeeper-curator5 + + ``` + + 或者(对于 Zookeeper Server 3.4.x 版本用户) + + ```xml + + org.apache.dubbo + dubbo-dependencies-zookeeper + + ``` + {{% alert title="Zookeeper升级注意事项" color="warning" %}} + 请注意在使用以上方式管理 zookeeper 客户端依赖时,请清理项目中的其它 zookeper、curator 等依赖,完全使用 dubbo 提供的版本。 + {{% /alert %}} + +3. 其它组件升级 + + 除了注册中心之外,如果您有用到 Dubbo 的其它特性并且依赖第三方组件支持此特性,则您需要根据具体情况升级相应的组件版本,以确保组件能配合 Dubbo3 工作。 + +{{% alert title="查看依赖的三方组件版本" color="info" %}} +目的是确认项目中的三方依赖可以与 Dubbo3 正常工作(保持API兼容性)。正常来说,Dubbo 应用中并不会有非常多的第三方组件依赖,所以只要按需确认即可,另外,您可以参考 [Dubbo3 版本依赖的组件版本]() 确认合适的组件版本。 +{{% /alert %}} + +### 步骤三:兼容性检查 +{{% alert title="哪些用户需要做兼容性检查" color="info" %}} +对于大部分常规用户来说,可以跳过这个环节,通常是当前对 Dubbo 有深度定制的用户需要关注(SPI 扩展或源码定制)! +{{% /alert %}} + +#### 检查点一:是否有 SPI 扩展 + +1. 以下 SPI 扩展点在 Dubbo3 中已被移除,如有使用请注意: + + * 事件总线。出于事件管理的复杂度原因,EventDispatcher 和 EventListener 在 Dubbo 3.x 的支持已经删除。如果有对应扩展机制的使用请考虑重构为对应 Dubbo 功能的扩展。 + +2. 以下 SPI 扩展点的内部工作机制做了实现优化,可按需调整: + + * Filter 拦截器机制。可以基于 Filter 拦截器对请求进行拦截处理,在 2.7 中支持在路由选址后再对请求进行拦截处理。Dubbo3 中新增了 `ClusterFilter` SPI 定义,相比于之前的 `Filter` 扩展点,`ClusterFilter` 可以在很大程度上降低内存的占用,对与超大规模集群有较大的收益。 + +如果您有一些 Consumer 侧的拦截器是基于 Filter 扩展实现的,如果没有和远端的 IP 地址强绑定的逻辑,我们建议您将对应的 `org.apache.dubbo.rpc.Filter` SPI 扩展点迁移到 `org.apache.dubbo.rpc.cluster.filter.ClusterFilter` 这个新的 SPI 扩展点。 + +{{% alert title="警告" color="info" %}} +`org.apache.dubbo.rpc.Filter` 与 `org.apache.dubbo.rpc.cluster.filter.ClusterFilter` 在 Dubbo3 中同时支持,ClusterFilter 适配可按需调整,之前老的 Filter 实现都会继续生效,无需担心。 +{{% /alert %}} + +#### 检查点二:是否存在源码定制 +如果您正在使用的 Dubbo 框架包含一些私有源码定制(通过 javagent 或者 asm 等通过运行时对 Dubbo 的修改也在此范围内),则直接升级到开源 Dubbo3 版本可能有兼容性风险。对于这种非标准行为,Dubbo 无法保证其先前的兼容性,需要用户在升级前对所有源码修改进行检查,确保这部分内容完成对 Dubbo3 版本的适配后再升级上线。 + +> 此类问题可通过一些字节码层面的工具实现,如将进程 metaspace 内容遍历导出,过滤出 Dubbo 所有相关类及调用,以识别业务中、二方包中等直接依赖或增强 Dubbo 框架内部源码的位置。判断这些源码调用在 Dubbo3 内部是否仍然存在,以决策下一步升级动作。 + +### 步骤四:上线验证 +1. 灰度发布 +Dubbo 3 升级对于发布流程没有做特殊限制,按照正常业务发布即可。 +由于 Dubbo 是进行跨大版本的变更升级,发布中请尽可能多分批次发布,同时拉大第一批和第二批发布的时间间隔,做好充足的观察。 +发布过程中,我们建议您先升级应用的下游(也即是服务提供者),在验证服务处理正常以后再继续后续发布。 + +2. 观测应用指标 +在发布的过程中,有以下几个纬度的指标可以判断升级是否出现问题。 + +- 机器的 CPU、内存使用情况 +- 接口请求成功率 +- 接口请求 RT +- 日志的报错信息 +- 自定义扩展行为是否符合预期 + +## 2.6.x 及以下版本升级 Dubbo3 + +以下内容是针对 2.6.x、2.5.x 及以下版本用户的,帮助了解如何升级到 Dubbo3 版本。对于这些版本的用户而言,80% 的用户都是可以通过替换依赖实现平滑升级的,按以下步骤升级并做好检查即可。 + +### 步骤一:升级核心依赖 + +首先,必须升级之前老的 `com.alibaba:dubbo` 依赖坐标升级为 `org.apache.dubbo:dubbo`。 + +如下所示,将 `com.alibaba:dubbo` 依赖 + +```xml + + com.alibaba + dubbo + 2.6.5 + +``` + +替换为 `org.apache.dubbo:dubbo` 依赖,其它配置文件不用修改,如下所示: + +```xml + + 3.3.0 + + + + + org.apache.dubbo + dubbo-dependencies-bom + ${dubbo.version} + pom + import + + + + + + + org.apache.dubbo + dubbo + + +``` + +如果您是 Spring Boot 应用,则也可以使用 `org.apache.dubbo:dubbo-spring-boot-starter` 替换上面的 `org.apache.dubbo:dubbo` 依赖: + +```xml + + + org.apache.dubbo + dubbo-spring-boot-starter + + +``` + +### 步骤二:升级其它组件依赖 + +您需要升级注册中心(Nacos、Zookeeper或其它)等第三方组件,具体升级方法和目标版本请参考本文前面一节的 [2.7.x 版本升级到 Dubbo3](./#步骤二升级其它组件依赖) 中的详细说明,两者操作方法完全一样。 + +{{% alert title="请务必注意第三方组件的版本" color="info" %}} +* 对于很多 Dubbo 2.6.x 及以下的老用户来说,可能用到的组件(如注册中心)都是比较老的版本,这时升级到 Dubbo3 之前请仔细分析一下都有哪些功能和核心依赖组件,以评估组件升级到的目标版本。 +* 对于部分 Zookeeper 用户而言,如果 Zookeeper 版本较老,建议先升级 Zookeeper Server 到 3.8.x 及以上版本,再使用 Dubbo3 的 `dubbo-zookeeper-curator5-spring-boot-starter` 管理依赖,如上文 [2.7.x 升级](./#步骤二升级其它组件依赖) 一节中所述。 +{{% /alert %}} + +### 步骤三:兼容性检查 +如果升级依赖后出现API或SPI扩展相关的编译错误,请参考下文。如果您的 Dubbo 用法中有很多 SPI 扩展实现、内部 API 调用、或者改了一些内核源码,则需要重点关注这一部分的兼容性检查。 + +#### 检查点一:包名改造 + Dubbo3 与 2.6.x 及以下版本最大的一个区别就是坐标、包名的变化: + +1. Maven 坐标 GAV + +**groupId 由 `com.alibaba` 改为 `org.apache.dubbo`** + +2. package + +**package 前缀由 `com.alibaba.dubbo.*` 改为 `org.apache.dubbo.*`** + + +Maven坐标升级比较直观,只需要修改相应的pom文件就可以了;而package变更则可能会带来编译问题,但好在 Dubbo3 版本继续保留了绝大部分常用基础 API 和 SPI 的 `com.alibaba.dubbo` 适配支持,因此理论上升级 pom 后项目仍可直接编译成功。 + +#### 检查点二:API编程接口 + +- 注解 + +| 注解 | 推荐的新注解 | 说明 | +| --------------------- | ------------------ | ------------------ | +| @Reference | @DubboReference | 消费端服务引用注解 | +| @Service | @DubboService | 提供端服务暴露注解 | +| @EnableDubbo | @EnableDubbo | | +| 其他常用Spring注解API | 其他常用Spring注解API | | + + + +- 编程API + +| API | 说明 | +| ----------------- | ----------------------------- | +| ReferenceConfig | Service配置采集和引用编程接口 | +| ServiceConfig | Service配置采集和暴露编程接口 | +| ApplicationConfig | Application配置采集API | +| RegistryConfig | 注册中心配置采集API | +| ConsumerConfig | 消费端默认配置采集API | +| ProviderConfig | 提供端默认配置采集API | +| ProtocolConfig | RPC协议配置采集API | +| ArgumentConfig | 服务参数级配置采集API | +| MethodConfig | 服务方法级配置采集API | +| ModuleConfig | 服务治理Module配置采集API | +| MonitorConfig | 监控配置采集API | +| RpcContext | 编程上下文API | + + +#### 检查点三:SPI扩展 + +如果公司内部有维护的自定义SPI扩展库,在业务工程升级到 Dubbo3 上线之前,请务必先确保扩展库与 Dubbo3 的兼容性。如果发现有兼容性问题,建议通过修改包名引用的方式(从实现 `com.alibaba.dubbo.*` 包名类到实现 `org.apache.dubbo.*` 包名类 )完成升级,并重新打包。 + + + +| SPI扩展点 | 说明 | +| ------------- | ------------------------------------------------------------ | +| Registry | 包括`RegistryFactory`, `Registry` ,`RegistryService`等扩展点 | +| Protocol | RPC协议扩展 | +| Serialization | 序列化协议扩展 | +| Cluster | 集群容错策略扩展,如Failover, Failfast等 | +| Loadbalance | 负载均衡策略扩展 | +| Transporter | 传输框架扩展,如Netty等 | +| Monitor | 监控中心扩展,包括MonitorFactory, Monitor, MonitorService等 | +| Router | 路由规则扩展 | +| Filter | 拦截器扩展 | + +### 步骤四:上线验证 + +参考本文前面一节的 [2.7.x 版本升级到 Dubbo3](./#步骤四上线验证) 中讲到的验证方法。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md.bak new file mode 100644 index 000000000000..36d71387bb14 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md.bak @@ -0,0 +1,97 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/migration/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/migration/ +description: Dubbo2 协议迁移 +linkTitle: Dubbo2 协议迁移 +title: Dubbo2 协议迁移 +type: docs +weight: 10 +--- + +## 迁移流程说明 + +Dubbo2 的用户使用 dubbo 协议 + 自定义序列化,如 hessian2 完成远程调用。 + +而 Grpc 的默认仅支持 Protobuf 序列化,对于 Java 语言中的多参数以及方法重载也无法支持。 + +Dubbo3 的之初就有一条目标是完美兼容 Dubbo2,所以为了 Dubbo2 能够平滑升级, Dubbo 框架侧做了很多工作来保证升级的无感,目前默认的序列化和 Dubbo2 保持一致为 `hessian2`。 + +所以,如果决定要升级到 Dubbo3 的 `Triple` 协议,只需要修改配置中的协议名称为 `tri` (注意: 不是 triple )即可。 + +接下来我们以一个使用 Dubbo2 协议的[工程](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration)来举例,如何一步一步安全的升级。 + +1. 仅使用 `dubbo` 协议启动 `provider` 和 `consumer`,并完成调用。 +2. 仅使用 `tri` 协议启动 `provider` 和 `consumer`,并完成调用。 +3. 使用 `dubbo` 协议和 `tri` 协议 启动 `provider`,以 `dubbo` 协议启动 `consumer`,并完成调用。 + +### 定义服务 + +1. 定义接口 +```java +public interface IWrapperGreeter { + + //... + + /** + * 这是一个普通接口,没有使用 pb 序列化 + */ + String sayHello(String request); + +} +``` + +2. 实现类示例 +```java +public class IGreeter2Impl implements IWrapperGreeter { + + @Override + public String sayHello(String request) { + return "hello," + request; + } +} +``` + +### 仅使用 dubbo 协议 + +为保证兼容性,我们先将部分 provider 升级到 `dubbo3` 版本并使用 `dubbo` 协议。 + +使用 `dubbo` 协议启动一个 [`Provider`](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboProvider.java) 和 [`Consumer`](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboConsumer.java) 完成调用。 + +{{% alert title="输出结果" color="info" %}} +![result](/imgs/v3/migration/tri/dubbo3-tri-migration-dubbo-dubbo-result.png) +{{% /alert %}} + +### 仅使用 triple 协议 + +当所有的 consumer 都升级至支持 `Triple` 协议的版本后,provider 可切换至仅使用 `Triple` 协议启动 + +结构如图所示: +![strust](/imgs/v3/migration/tri/migrate-only-tri-strust.png) + +[Provider](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationTriProvider.java) +和 [Consumer](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationTriConsumer.java) 完成调用。 + + +{{% alert title="输出结果" color="info" %}} +![result](/imgs/v3/migration/tri/dubbo3-tri-migration-tri-tri-result.png) +{{% /alert %}} + +### 同时使用 dubbo 和 triple 协议 + +对于线上服务的升级,不可能一蹴而就同时完成 provider 和 consumer 升级, 需要按步操作, + +**第一步:保证业务稳定。** + +**第二步:provider 提供双协议的方式同时支持 dubbo + tri 两种协议的客户端。** + +结构如图所示: +![strust](/imgs/v3/migration/tri/migrate-dubbo-tri-strust.png) + +> 按照推荐升级步骤,provider 已经支持了 tri 协议,所以 dubbo3 的 consumer 可以直接使用 tri 协议 + +使用 `dubbo` 协议和 `triple` 协议启动[`Provider`](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothProvider.java)和[`Consumer`](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothConsumer.java) 完成调用。 + +{{% alert title="输出结果" color="info" %}} +![result](/imgs/v3/migration/tri/dubbo3-tri-migration-both-dubbo-tri-result.png) +{{% /alert %}} diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/2.x-to-3.x-compatibility-guide.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/2.x-to-3.x-compatibility-guide.md new file mode 100644 index 000000000000..10e9f39b5422 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/2.x-to-3.x-compatibility-guide.md @@ -0,0 +1,101 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide/ + - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide/ + - /zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide/ +description: Dubbo 3 升级与兼容性指南 +linkTitle: 2.x 升级至 3.x +title: 2.x 升级至 3.x +type: docs +weight: 1 +--- + +## 升级到 Dubbo 3.X 的收益 +Dubbo3 依旧保持了 2.x 的经典架构,以解决微服务进程间通信为主要职责,通过丰富的服务治理(如地址发现、流量管理等)能力来更好的管控微服务集群;Dubbo3 对原有框架的升级是全面的,体现在核心 Dubbo 特性的几乎每个环节,通过升级实现了稳定性、性能、伸缩性、易用性的全面提升。 + +![architecture-1](/imgs/v3/concepts/architecture-1.png) + +- **通用的通信协议。** 全新的 RPC 协议应摒弃私有协议栈,以更通用的 HTTP/2 协议为传输层载体,借助 HTTP 协议的标准化特性,解决流量通用性、穿透性等问题,让协议能更好的应对前后端对接、网关代理等场景;支持 Stream 通信模式,满足不同业务通信模型诉求的同时给集群带来更大的吞吐量。 +- **面向百万集群实例,集群高度可伸缩。** 随着微服务实践的推广,微服务集群实例的规模也在不停的扩展,这得益于微服务轻量化、易于水平扩容的特性,同时也给整个集群容量带来了负担,尤其是一些中心化的服务治理组件;Dubbo3 需要解决实例规模扩展带来的种种资源瓶颈问题,实现真正的无限水平扩容。 +- **全面拥抱云原生。** + + +## Dubbo 3.0 新特性 +Dubbo 3.0 提供的新特性包括: + +* **新的地址发现模型(应用级服务发现)。** + * 查看[应用级服务发现迁移示例](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/)。 + * 查看[应用级服务发现的迁移步骤](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery/) + * 查看[应用级服务发现地址迁移规则说明](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) +* **下一代基于 HTTP/2 的 Triple 协议。** + * 查看[Triple 协议迁移步骤](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/migration-triple/) + * 查看 [Triple 协议使用方式](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/guide/) + * 查看 [Triple 协议设计与实现](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/overview/)。 +* **统一的路由规则。** + * 查看[统一路由规则设计与实现](/zh-cn/overview/tasks/traffic-management/) + + +## 升级前的兼容性检查 +在跨版本升级的过程中,存在的风险点从大到小分别有:直接修改 Dubbo 源码 -> 基于 Dubbo SPI 扩展点进行扩展 -> 基于 API 或者 Spring 的使用方式。 + +### 1. 直接修改 Dubbo 源码 +对于直接修改 Dubbo 源码这部分的需要修改方自行判断是否在高版本中正常工作,对于这种非标准行为,Dubbo 无法保证其先前的兼容性。此外,通过 javagent 或者 asm 等通过运行时对 Dubbo 的修改也在此范围内。此类修改大部分可以通过后文提供的扫描工具检测出来。 + +### 2. SPI 扩展 +#### 不兼容项 +对于 SPI 扩展的,除了应用级服务方向和 EventDispatcher 两个机制在 3.x 中做了破坏性的修改,在 2.7.x 中提供的绝大多数的扩展在 3.x 中也都提供。此部分需要关注的有两个方面: + +- 事件总线:出于事件管理的复杂度原因,EventDispatcher 和 EventListener 在 Dubbo 3.x 的支持已经删除。如果有对应扩展机制的使用请考虑重构为对应 Dubbo 功能的扩展。 +- 应用级服务发现:Dubbo 2.7 中的应用级服务发现的整体机制在 Dubbo 3.x 中已经被完整重构,功能的性能与稳定性有了很大程度上的提高。因此我们建议您不要使用 Dubbo 2.7 中的应用级服务发现机制,如果有对应的扩展可以在升级到 Dubbo 3.x 之后基于新的代码重新验证实现(绝大多数应用级服务发现的 API 是向前兼容的)。 + +#### 优化项(可选) +此外,Dubbo 3.x 中对部分扩展点的工作机制进行了优化,可以较大程度上提升应用的性能。 + +- 1)拦截器机制 + +Dubbo 中可以基于 Filter 拦截器对请求进行拦截处理。在 Dubbo 2.7 中支持在路由选址后再对请求进行拦截处理。Dubbo 3.x 中抽象了全新的 ClusterFilter 机制,可以在很大程度上降低内存的占用,对与超大规模集群有较大的收益。 +如果您有一些 Consumer 侧的拦截器是基于 Filter 机制实现的,如果没有和远端的 IP 地址强绑定的逻辑,我们建议您将对应的 `org.apache.dubbo.rpc.Filter` SPI 扩展点迁移到 `org.apache.dubbo.rpc.cluster.filter.ClusterFilter` 这个新的 SPI 扩展点。两个接口的方法定义是完全一样的。 + +- 2)Router -> StateRouter + +Dubbo 中提供了 Router 这个可以动态进行选址路由的能力,同时绝大多数的服务治理能力也都是基于这个 Router 扩展点实现的。在 Dubbo 3.x 中,Dubbo 在 Router 的基础上抽象了全新的 StateRouter 机制,可以在选址性能以及内存占用上有大幅优化。关于 StateRouter 的更多介绍我们会在后续的文档中发布。 + +### 3. API / Spring 使用 +对于基于 API 或者 Spring 的使用,Dubbo 3.x 和 2.7.x 的使用方式是对齐的,在 Dubbo 3.x 中对部分无效的配置进行了强校验,这部分异常会在启动过程中直接报错,请按照提示修改即可。 + +## 升级流程 +### 1. 依赖升级 +如果使用 Nacos 作为注册中心,由于 Nacos 特性支持的原因,在升级到 Dubbo 3.x 之前需要将 Nacos Server 升级到 2.x(参考文档 [https://nacos.io/zh-cn/docs/v2/upgrading/2.0.0-upgrading.html](https://nacos.io/zh-cn/docs/v2/upgrading/2.0.0-upgrading.html)),然后再将应用的 Nacos Client 也对应升级。如果使用 Zookeeper 注册中心则不需要处理。 +如果您是使用 Spring Cloud Alibaba Dubbo 进行接入的,由于 Dubbo 部分内部 API 进行了变更,请升级到 xxx。 + +Dubbo 依赖请升级到最新的 3.1.3 版本,Dubbo 和对应的 springboot starter GAV 如下所示。 +```xml + + org.apache.dubbo + dubbo + 3.1.3 + + + + org.apache.dubbo + dubbo-spring-boot-starter + 3.1.3 + +``` +### 2. 灰度升级 +Dubbo 3 升级对于发布流程没有做特殊限制,按照正常业务发布即可。 +由于 Dubbo 是进行跨大版本的变更升级,发布中请尽可能多分批次发布,同时拉大第一批和第二批发布的时间间隔,做好充足的观察。 +发布过程中,我们建议您先升级应用的下游(也即是服务提供者),在验证服务处理正常以后再继续后续发布。 + +### 3. 升级观测指标 +在发布的过程中,有以下几个纬度的指标可以判断升级是否出现问题。 + +- 机器的 CPU、内存使用情况 +- 接口请求成功率 +- 接口请求 RT +- 日志的报错信息 +- 自定义扩展行为是否符合预期 + +## 注意事项 +### 1. 应用级服务发现 +由于 Dubbo 2.7 的应用级服务发现模型存在设计上的问题,在 Dubbo 3.x 中做了大量格式上的修改,所以 2.7.x 和 3.x 的应用级服务发现可能存在无法互相订阅调用的可能性。虽然 Dubbo 会剔除识别不了的实例,但是从稳定性的角度出发,如果您在 2.7.x 中开启了应用级服务发现特性(在 2.7.x 中非默认注册),我们建议先在 2.7.x 中关闭,待升级到 3.x 之后再开启。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.0-to-3.1-compatibility-guide.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.0-to-3.1-compatibility-guide.md new file mode 100644 index 000000000000..19838ce8ad34 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.0-to-3.1-compatibility-guide.md @@ -0,0 +1,30 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/3.0-to-3.1-compatibility-guide/ + - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/3.0-to-3.1-compatibility-guide/ +description: Dubbo 3.1 升级与兼容性指南 +linkTitle: 3.0 升级至 3.1 +title: 3.0 升级至 3.1 +type: docs +weight: 2 +--- + + + + + + +## 功能修改点 + +### 1. Nacos Group 对齐(应用级服务发现) + +在 Dubbo 2.7.x 中,配置在 Nacos Registry URL 上的 group 值是对齐 Nacos 注册中心中的 group 分组的。(group 可以当成类似 namespace 的软隔离) + +在 Dubbo 3.0.x 中,配置在 Nacos Registry URL 上的 group 默认不使用,全部使用 DEFAULT_GROUP。(group 不再提供隔离功能) + +在 Dubbo 3.1.x 中,配置在 Nacos Registry URL 上的 group 值将会重新对齐 Nacos 注册中心中的 group 分组的。 + +注意事项: + +1. 请检查注册中心 URL 上是否已经配置了 group 属性,如果是的话需要检查服务端和消费端的 group 是否都一致,如果不一致请修改为一致 +2. 如果不希望 group 重新对齐到 Nacos 注册中心中的 group 分组,可以配置 `dubbo.nacos-service-discovery.use-default-group=false` 全局属性值忽略该功能 \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.1-to-3.2-compatibility-guide.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.1-to-3.2-compatibility-guide.md new file mode 100644 index 000000000000..87ffcbbf8ba0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.1-to-3.2-compatibility-guide.md @@ -0,0 +1,143 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/3.1-to-3.2-compatibility-guide/ + - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/3.1-to-3.2-compatibility-guide/ +description: Dubbo 3.2 升级与兼容性指南 +linkTitle: 3.1 升级至 3.2 +title: 3.1 升级至 3.2 +type: docs +weight: 3 +--- + +对于绝大多数的用户,升级到 Dubbo 3.2.0 是完全平滑的,仅需要修改依赖包版本即可。 + +```xml + + org.apache.dubbo + dubbo + 3.2.0 + +``` + +或者 + +```xml + + org.apache.dubbo + dubbo-spring-boot-starter + 3.2.0 + +``` + +# 兼容性 CheckList + +## 1. 序列化检查模式(重要!!!) + +在 Dubbo 3.2.0 版本中,Dubbo 将默认开启序列化白名单的强校验,以提升 Dubbo 的安全性,避免远程命令执行的问题。 +对于一些使用了泛型等可能存在扫描不全或者是**服务规模较大**的用户,我们建议您添加 `-Ddubbo.application.serialize-check-status=WARN` 配置。 +观察一段时间后(通过日志、QoS 命令),如果没有触发安全告警,则可以配置强校验模式。 + +关于自定义白名单的配置,可以参考官网的 [文档 / SDK 手册 / Java SDK / 高级特性和用法 / 提升安全性 / 类检查机制](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/) 一文进行配置。 + +#### Q1:为什么要开启序列化白名单的强校验? + +由于 Java 本身机制的问题,Dubbo 支持的非 IDL 序列化天然允许访问任意类,这将可能导致远程命令执行(RCE)风险。 + +#### Q2:升级到 3.2 的最佳实践是什么? + +我们建议**所有用户**在升级 Dubbo 3.2.0 版本前添加 `-Ddubbo.application.serialize-check-status=WARN` 配置以保证最佳的兼容性。否则可能导致线上数据异常的情况! + +--- + +## 2. 默认序列化切换 + +Dubbo 3.2.0 版本开始默认序列化方式从 `hessian2` 切换为 `fastjson2`,对于升级到 3.2.0 的应用,Dubbo 会自动尝试采用 `fastjson2` 进行序列化。 + +#### Q1:会不会影响和低版本的 Dubbo 互通? + +不会。与低版本互通仍使用 `hessian-lite`。原理可参考[序列化协议升级指南](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/serialization-upgrade/)一文。 + +#### Q2:为什么要切换默认序列化方式? + +`fastjson2` 是一款高性能的序列化框架,性能优于 `hessian2`,原生支持 JDK17、Native 等,以及完全向前兼容 `hessian2` 所有功能。 +由于 `hessian-lite` 在未来维护难度越来越大,我们决定将默认序列化方式从 `hessian2` 切换为 `fastjson2`。 + +#### Q3:和原生的 JSON 是什么关系? + +Dubbo 中使用 `fastjson2` 的 JSONB 格式,而不是原生的 JSON 格式。JSONB 格式和JSON格式对应,能完全表示JSON,是一种二进制格式。 +具体协议格式可以参考:[JSONB 格式](https://github.com/alibaba/fastjson2/wiki/jsonb_format_cn) + +#### Q4:如果我不想使用 `fastjson2`,怎么办? + +如果你不想使用 `fastjson2`,可以配置 `prefer-serialization` 为 `hessian2` 覆盖默认配置。(如 `dubbo.provider.prefer-serialization=fastjson2,hessian2`) 如果没有特殊的需求,我们不建议仍继续使用 `hessian2`。 + +--- + +## 3. 默认关闭推空保护 + +Dubbo 3.2.0 版本开始默认关闭推空保护,即使注册中心推送空地址,Dubbo 也将不会保留最后一批 provider 信息。 +如果需要开启推空保护,可以配置 `dubbo.application.enable-empty-protection` 为 `true`。 + +#### Q1:关闭推空保护对我有什么影响? + +在绝大部分场景下没有影响。 +推空保护的目的是在注册中心出现故障并且主动推送空地址的时候,Dubbo 保留最后一批 provider 信息,以保证服务可用。 +但是在大多数注册中心出现故障的时候,注册中心也不会推送空地址,只有一些特殊情况才会出现。 +但如果开启推空保护,将对 Dubbo 的 Fallback 逻辑、心跳逻辑等造成较大的影响,给开发使用 Dubbo 带来困扰。 + +#### Q2:我想开启推空保护,怎么办? + +如果在生产上为了高可用,需要开启推空保护,可以配置 `dubbo.application.enable-empty-protection` 为 `true`。 +目前已知开启推空保护会导致服务端应用从 `2.6.x`、`2.7.x` 等仅支持接口级服务发现的版本升级到 `3.x` 之后回滚到原来版本出现异常,极端场景下会导致服务调用失败。 +此外,开启推空保护后在服务端地址真的为空的时候出现较多的心跳异常、日志异常等。 + +--- + +## 4. 传递依赖变更 + +* Dubbo 3.2.0 版本开始默认不再在 `dubbo-all` 中 shade `hessian-lite` 的代码,而是使用传递依赖传递。如果你的应用中不需要使用 `hessian-lite`,可以将 `hessian-lite` 从依赖中移除。 +* Dubbo 3.2.0 版本开始在 `dubbo-all` 中不再传递 `gson`、`fastjson` 依赖,如果你的应用中需要使用 `gson`、`fastjson`,请手动将 `gson`、`fastjson` 依赖添加到应用中。 +* Dubbo 3.2.0 版本在 `dubbo-all` 中传递 `fastjson2` 依赖。 + +--- + +## 5. 默认内部序列化工具切换 + +Dubbo 3.2.0 版本开始默认**内部**序列化工具从 `fastjson` 切换为 `fastjson2`。 + +#### Q1:会不会影响 RPC 请求流量? + +不会。内部序列化工具为 Dubbo 内部解析参数时使用,非 RPC 传输序列化协议。 + +#### Q2:为什么要切换默认内部序列化工具? + +Dubbo 3.2.0 版本开始默认传递依赖不再传递 `fastjson` 和 `gson`。出于兼容性考虑,默认内部序列化工具切换为 `fastjson2`。 + +#### Q3:如果我的环境中没有 `fastjson2`,怎么办? + +Dubbo 支持多种序列化框架自动切换,如果你的环境中没有 `fastjson2`,Dubbo 会自动尝试切换到 `fastsjon` 或 `gson`。 + +#### Q4:我想指定 Dubbo 内部序列化工具,怎么办? + +可以配置 `dubbo.json-framework.prefer` 参数,如 `-Ddubbo.json-framework.prefer=gson`。 + +--- + +## 6. Triple 协议支持传递自定义异常 + +Dubbo 3.2.0 版本开始 Triple 协议支持回传自定义异常,而不是只能回传 `RpcException`。如果服务接口会抛出异常的,在 Dubbo 3.2.0 版本以后将默认按照 Dubbo 协议一样回传自定义异常对象。 + +--- + +## 7. Triple 协议版本号对齐 + +Dubbo 3.2.0 版本开始,Triple 协议的通信要求客户端和服务端的版本号和分组一致,否则会找不到服务。与原生 gRPC SDK 互通时,Dubbo 侧不能配置分组和版本号。 + +#### Q1:Dubbo 3.2.0 以前是怎么样的? + +1)Triple 会认为空版本号和 1.0.0 版本号一致,如果您的服务端和客户端版本号不一致,但是都是空版本号或者都是 1.0.0 版本号,是可以正常通信的。 +2)对于没有匹配到版本号的服务,Triple 会尝试匹配任意版本号的服务,如果匹配到任意版本号的服务,也是可以正常通信的。 + +#### Q2:如何保证和原来行为是对齐的? + +通过配置 `-Ddubbo.rpc.tri.ignore-1.0.0-version=true -Ddubbo.rpc.tri.resolve-fallback-to-default=true` 可以实现和 Dubbo 3.2.0 以前的行为。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.2-to-3.3-compatibility-guide.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.2-to-3.3-compatibility-guide.md new file mode 100644 index 000000000000..889828aa2c87 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.2-to-3.3-compatibility-guide.md @@ -0,0 +1,350 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/3.2-to-3.3-compatibility-guide/ + - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/3.2-to-3.3-compatibility-guide/ +description: Dubbo 3.3 升级与兼容性指南 +linkTitle: 3.2 升级至 3.3 +title: 3.2 升级至 3.3 +type: docs +weight: 4 + +--- + + +对于绝大多数的用户,升级到 Dubbo 3.3.0 是完全平滑的,仅需要修改依赖包版本即可。 + +```xml + + org.apache.dubbo + dubbo + 3.3.0 + +``` + +或者 + +```xml + + org.apache.dubbo + dubbo-spring-boot-starter + 3.3.0 + +``` + +# 兼容性 CheckList + +## 1. 默认序列化切换 + +Dubbo 3.3.0 版本开始默认序列化方式从 `fastjson2` 切换为 `hessian2`,对于升级到 3.3.0 的应用,Dubbo 会自动尝试采用 `hessian2` 进行序列化。 + +### Q1:为什么要切换默认序列化方式? + +`hessian2` 为 Dubbo 3.1.x 及以下版本中默认的序列化,长期的生产验证了其稳定性和兼容性,在评估了向前兼容性和长期可维护性后,Dubbo 团队决定将 `hessian-lite` 升级到最新 `hessian4` 主干版本,以支持 JDK17 和 JDK21。 + +升级到 Dubbo 3.3.0 以后,依赖的 `hessian-lite` 版本将同步升级为 `4.0.x`,主要包含以下修改: +- 同步 hessian 到上游 4.0.66 版本 +- 修复 JDK17 及 JDK21 下类可见性带来的兼容性问题 +- 支持 Record、ImmutableCollections 等 JDK9+ 特性 + +### Q2:会不会影响和低版本的 Dubbo 互通? + +部分场景下可能会有影响,具体如下: + +1. Dubbo 3.3.x Consumer 与 Dubbo 3.2.x Provider 互通时默认使用 Dubbo 3.2.x 中 `fastjson2` 优先的策略,无兼容性问题 +2. Dubbo 3.3.x Consumer 与 Dubbo 3.1.x 及以下版本 Provider 互通时默认使用 Dubbo 3.2.x 中 `fastjson2` 优先的策略,无兼容性问题 +3. Dubbo 3.2.x Consumer 与 Dubbo 3.3.x Provider 互通时默认使用 Dubbo 3.3.x 中 `hessian2` 优先的策略,此时由于 Dubbo 3.2.x Consumer 中携带的 `hessian2` 为低版本的,在 JDK >= 17 的场景下可能会出现兼容性问题,建议按照 Q3 中的最佳实践进行升级。 +4. Dubbo 3.1.x 及以下版本 Consumer 与 Dubbo 3.3.x Provider 互通时默认使用 Dubbo 3.3.x 中 `hessian2` 优先的策略,此时由于 Dubbo 3.1.x 及以下版本 Consumer 中携带的 `hessian2` 为低版本的,在 JDK >= 17 的场景下可能会出现兼容性问题,建议按照 Q3 中的最佳实践进行升级。 + +原理可参考[序列化协议升级指南](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/serialization-upgrade/)一文。 + +### Q3:升级序列化最佳实践是什么? + +1. 从 Dubbo 3.2.x 升级到 3.3.x 时,建议配置 `prefer-serialization` 为 `fastjson2,hessian2` 保持与 3.2.x 一致,待全集群升级完毕后在删除该配置,使用 `hessian2` 序列化 +2. 从 Dubbo 3.1.x 及以下版本升级到 3.3.x 时,无需配置 `prefer-serialization`,但需要注意避免与 JDK 升级一起进行,以免出现兼容性问题 + +### Q4:如果我仍想使用 `fastjson2`,怎么办? + +如果你不想使用 `hessian2`,可以配置 `prefer-serialization` 为 `fastjson2` 覆盖默认配置。(如 `dubbo.provider.prefer-serialization=fastjson2,hessian2`) + +--- + +## 2. 使用 `register=false` 不注册时将无法通过 QoS 手动注册 + +如果注册中心配置中配置了 `dubbo.registry.register=false` 或者指定服务配置 `dubbo.provider.register=false`: + +1. 在 Dubbo 3.2.x 及以前版本中,默认 Dubbo 不自动注册,使用 QoS 命令(`curl http://127.0.0.1:22222/online` )可以实现注册 +2. 在 Dubbo 3.3.x 中,默认 Dubbo 不自动注册,**使用 QoS 命令也无法注册** + +### Q1: 为什么要做这个调整? + +为了避免有的用户使用优雅上下线和隔离环境配置预期不一致,造成跨环境错误注册的情况,将 `register=false` 定义为**永远不注册**,`delay=-1` 且 `-Ddubbo.application.manual-register=true` 定义为**延迟到手动注册**。 + +### Q2: 实现优雅上线的最佳实践是什么? + +简单来说需要完成两个配置:`delay=-1` 且 `-Ddubbo.application.manual-register=true` + +`delay=-1` 实现指定服务允许优雅上线: +1. 如果需要对全部的服务都进行优雅上线,可以在 `dubbo.provider.delay=-1` 配置 +2. 如果只需要对部分服务进行优雅上线,可以在指定服务配置 `delay=-1` + +`-Ddubbo.application.manual-register=true` 实现手动注册: +对于需要进行优雅上线的机器,配置 `-Ddubbo.application.manual-register=true` JVM 参数 + +完善启动脚本: +对于需要进行优雅上线的机器,启动脚本中在启动结束后,主动调用 QoS 命令 `curl http://127.0.0.1:22222/online` 进行注册 + +考虑因素: +1. 全局一套代码,无论是线上环境、测试环境均对需要优雅上线的服务进行配置 `delay=-1` +2. 仅对线上环境进行 `-Ddubbo.application.manual-register=true` 配置,测试环境不配置,保证测试环境的服务能够自动注册 + +--- + +## 3. Nacos 兼容订阅默认关闭 + +从 Dubbo 3.3.x 版本开始,将不再订阅 Dubbo 2.7.3 及以前版本的兼容服务名,如果仍需要订阅,请配置 `-Dnacos.subscribe.legacy-name=true`。 + +### Q1: 为什么要做这个调整? + +在 Dubbo 2.7.3 及以前版本中,Dubbo 服务注册到 Nacos 时,订阅格式为 `providers(:{interfaceName})(:{version})(:{group})`,其中每个字段如果本身未空,会连带前面的 `:` 也一起省略,导致订阅名字不唯一,无法精确订阅。 + +如: + +1. 接口名:`com.foo.BarService`,版本:`1.0.0`,分组:`baz`,订阅名字为 `providers:com.foo.BarService:1.0.0:baz` +2. 接口名:`com.foo.BarService`,版本:空,分组:`baz`,订阅名字为 `providers:com.foo.BarService:baz` +3. 接口名:`com.foo.BarService`,版本:`baz`,分组:空,订阅名字为 `providers:com.foo.BarService:baz` + +如上,2 和 3 的订阅名字是一样的,但实际上是不同的服务。 + +为了解决这个问题,Dubbo 2.7.4 及以后版本中,订阅名字将会变为 `providers:({interfaceName}):({group}):({version})`,保证订阅名字的唯一性。 + +如: + +1. 接口名:`com.foo.BarService`,版本:`1.0.0`,分组:`baz`,订阅名字为 `providers:com.foo.BarService:1.0.0:baz` +2. 接口名:`com.foo.BarService`,版本:空,分组:`baz`,订阅名字为 `providers:com.foo.BarService::baz` +3. 接口名:`com.foo.BarService`,版本:`baz`,分组:空,订阅名字为 `providers:com.foo.BarService:baz:` + + +--- + +## 4. Dubbo Spring Boot Starters 更新 + +在 Dubbo 3.3.x 中,Dubbo Spring Boot Starters 为了方便依赖管理,提供了更多的 Starter 依赖。 + +此外:**为了遵循 Spring 规范的命名规范,从 3.3.0 版本开始,可观测相关 Starter 的 artifactId 从 `dubbo-spring-boot-observability-starter` 更名为 `dubbo-observability-spring-boot-starter`。** + +### Q1: Dubbo 3.3.x 版本中的 Starter 有哪些? +以下是 Dubbo 官方社区提供的 starter 列表(3.3.0+ 版本),方便在 Spring Boot 应用中快速使用: +* `dubbo-spring-boot-starter`,管理 dubbo 核心依赖,用于识别 application.properties 或 application.yml 中 `dubbo.` 开头的配置项,扫描 @DubboService 等注解。 +* `dubbo-spring-boot-starter3`,管理 dubbo 核心依赖,与 dubbo-spring-boot-starter 相同,支持 spring boot 3.2 版本。 +* `dubbo-nacos-spring-boot-starter`,管理 nacos-client 等依赖,使用 Nacos 作为注册中心、配置中心时引入。 +* `dubbo-zookeeper-spring-boot-starter`,管理 zookeeper、curator 等依赖,使用 Zookeeper 作为注册中心、配置中心时引入(Zookeeper server 3.4 及以下版本使用)。 +* `dubbo-zookeeper-curator5-spring-boot-starter`,管理 zookeeper、curator5 等依赖,使用 Zookeeper 作为注册中心、配置中心时引入。 +* `dubbo-sentinel-spring-boot-starter`,管理 sentinel 等依赖,使用 Sentinel 进行限流降级时引入。 +* `dubbo-seata-spring-boot-starter`,管理 seata 等依赖,使用 Seata 作为分布式事务解决方案时引入。 +* `dubbo-observability-spring-boot-starter`,加入该依赖将自动开启 Dubbo 内置的 metrics 采集,可用于后续的 Prometheus、Grafana 等监控系统。 +* `dubbo-tracing-brave-spring-boot-starter`,管理 brave/zipkin、micrometer 等相关相关依赖,使用 Brave/Zipkin 作为 Tracer,将 Trace 信息 export 到 Zipkin。 +* `dubbo-tracing-otel-otlp-spring-boot-starter`,管理 brave/zipkin、micrometer 等相关相关依赖,使用 OpenTelemetry 作为 Tracer,将 Trace 信息 export 到 OTlp Collector。 +* `dubbo-tracing-otel-zipkin-spring-boot-starter`,管理 brave/zipkin、micrometer 等相关相关依赖,使用 OpenTelemetry 作为 Tracer,将 Trace 信息 export 到 Zipkin。 + + +--- + +## 5. 迁移 dubbo-compiler 和 dubbo-native-plugin 到 dubbo-maven-plugin + +在 3.3 版本中,Dubbo 移除了 dubbo-native-plugin,同时 dubbo-native-plugin 相关的功能都将迁移至 dubbo-maven-plugin。此外,在 dubbo-maven-plugin 中也新增了对 dubbo-compiler 的支持。 + +更多过于 dubbo-maven-plugin 的说明请参考[配置详情](/zh-cn/overview/mannual/java-sdk/reference-manual/config/maven-plugin/)。 + +### Q1:为什么要做这个迁移和调整? + +1. 为了提升用户的使用体验,后续dubbo有关maven的插件能力都将统一使用dubbo-maven-plugin来提供。方便Dubbo用户使用和接入。而不需要一个特性对应一个插件,导致用户需要依赖多个plugin。 +2. 更加有利于后续Dubbo提供maven plugin能力时的维护和特性增强。 + +### Q2:如何迁移配置? + +1. 使用 Native Image 时,原配置为: +```xml + + + org.apache.dubbo + dubbo-maven-plugin + ${dubbo.version} + + com.example.nativedemo.NativeDemoApplication + + + + process-sources + + dubbo-process-aot + + + + +``` + +需要替换为: +```xml + + org.apache.dubbo + dubbo-maven-plugin + ${dubbo.version} + + org.apache.dubbo.registry.consumer.NativeDemoConsumerRegistryApplication + + + + process-sources + + dubbo-process-aot + + + + +``` + +注:仅需要替换 `artifactId` + +2. 使用 Triple + Protobuf 时,原配置为: +```xml + + + + kr.motd.maven + os-maven-plugin + 1.6.1 + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.6.1 + + com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} + + grpc-java + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} + + + + dubbo + org.apache.dubbo + dubbo-compiler + ${dubbo.compiler.version} + org.apache.dubbo.gen.tri.Dubbo3TripleGenerator + + + + + + + compile + + + + + + +``` + +可以直接替换为: +```xml + + + + org.apache.dubbo + dubbo-maven-plugin + ${dubbo.version} + + + + compile + + + + + + +``` + +注:无需引入 `os-maven-plugin` 和 `protobuf-maven-plugin`,仅需要引入 `dubbo-maven-plugin` 即可。 + +--- + +## 6. 移除原 REST 协议支持 + +在 Dubbo 3.3.x 中,Triple 协议支持了 Provider 侧原生 REST 协议的所有特性,同时移除了原 REST 协议实现的支持。 + +1. 如果仅使用 REST 协议作为服务提供者,请修改协议名字为 `tri`,使用方式无需改变,详见 [Triple 3.3新特性](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple-3.3/) 和 [Triple REST 用户手册](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual/) +2. 如果需要使用 REST 协议作为服务消费者,可以添加以下依赖提供能力兼容 + +```xml + + org.apache.dubbo.extensions + dubbo-rpc-rest + 3.3.0 + +``` + +--- + +## 7. JDK 序列化 + +由于 JDK 原生序列化中,如果不手动添加配置,存在大量的反序列化漏洞,为了提升 Dubbo 的安全性,Dubbo 3.3.x 版本中默认不支持 JDK 序列化。 + +如果需要使用 JDK 序列化,可以添加以下依赖提供能力兼容,但请注意,**这可能会引入安全风险**。 + +```xml + + org.apache.dubbo.extensions + dubbo-serialization-jdk + 3.3.0 + +``` + +--- + +## 8. 传递依赖变更 + +在 Dubbo 3.3.x 中,默认不再传递以下依赖,如有需要请按需引入: + +```xml + + org.springframework + spring-core + + + org.springframework + spring-beans + + + org.springframework + spring-context + + + com.alibaba.spring + spring-context-support + +``` + +同时,新增传递以下依赖: + +```xml + + com.google.protobuf + protobuf-java + + + com.google.protobuf + protobuf-java-util + +``` + +注:Dubbo 从 3.3.x 开始不再依赖 `com.alibaba.spring:spring-context-support` 实现自身能力,如果需要请自行引入。 + +--- + +## 9. Zookeeper 3.4 支持移除 + +由于 Zookeeper 3.4.x 已经 EOL 4 年多了,为了降低 Dubbo 的维护成本,Dubbo 3.3.x 版本中移除了对 Zookeeper 3.4.x 的支持,请迁移 Curator (如有)到 5.x 版本。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/_index.md new file mode 100755 index 000000000000..7ce0943a83b5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/version/ + - /zh-cn/docs3-v2/java-sdk/version/ + - /zh-cn/overview/mannual/java-sdk/version/ +description: "Dubbo 各个版本变更记录(release note),跨版本升级兼容性说明。" +linkTitle: 版本变更记录 +title: 版本变更记录 +type: docs +weight: 100 +--- diff --git a/content/en/overview/mannual/java-sdk/tasks/_index.md b/content/en/overview/mannual/java-sdk/tasks/_index.md new file mode 100755 index 000000000000..39d273ea7063 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/overview/tasks/ + - /zh-cn/overview/tasks/ +description: "" +linkTitle: 使用教程 +title: 跟随示例任务学习 Dubbo +type: docs +weight: 4 +--- diff --git a/content/en/overview/mannual/java-sdk/tasks/deploy/_index.md b/content/en/overview/mannual/java-sdk/tasks/deploy/_index.md new file mode 100644 index 000000000000..cb40bbb75b1d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/deploy/_index.md @@ -0,0 +1,14 @@ +--- +aliases: + - /zh/overview/tasks/deploy/ + - /zh-cn/overview/tasks/deploy/ +description: "学习在 Kubernetes、Service Mesh(Kubernetes Service)、虚拟机(Zookeeper、Nacos)等场景部署 Dubbo 应用。" +feature: + description: | + 一键拉起服务治理体系,屏蔽底层跨平台的微服务基础设施复杂度,支持虚拟机、Docker、Kubernetes、服务网格等多种部署模式。 + title: 灵活部署模式 +linkTitle: 打包部署 +title: 打包并部署应用 +type: docs +weight: 5 +--- diff --git a/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes-service.md b/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes-service.md new file mode 100644 index 000000000000..3423f24dcc7b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes-service.md @@ -0,0 +1,116 @@ +--- +aliases: + - /zh/overview/tasks/deploy/deploy-on-vm/ + - /zh-cn/overview/tasks/deploy/deploy-on-vm/ +description: "部署 Dubbo 应用到服务网格(Service Mesh),基于 Kubernetes Service 与控制面。" +linkTitle: 服务网格 +title: 部署 Dubbo 应用到虚拟机环境 +type: docs +weight: 3 +--- +这种模式将 Dubbo Service 与 Kubernetes Service 概念映射起来,不再需要 Nacos 等传统注册中心,而是由 Kubernetes APISERVER 承担注册中心指责。 + + + +## 安装 Control Plane +在这个模式下,我们需要安装 `dubbo-control-plane` +> 这里是要用 istio 配合一起工作(提供xds推送能力),还是dubbo-control-plane自己实现xds server? + +```yaml +dubboctl manifests install --profile=control-plane +``` + +## 部署应用 +### 打包镜像 +### 定义 YAML +请查看 dubbo-samples 了解示例 + +```yaml +kind: service +``` + +```yaml +kind: deployment +``` + +### 优雅上下线 + +配置 probe +配置 pre-stop + +### 观测服务状态 + +## 与 Service Mesh 的区别 + + + + + + + + +## 特性说明 +[Pod 的生命周期](https://kubernetes.io/zh/docs/concepts/workloads/pods/pod-lifecycle/) 与服务调度息息相关,通过对 Kubernetes 官方探针的实现,能够使 Dubbo3 乃至整个应用的生命周期与 Pod 的生命周期,在 Pod 的整个生命周期中,影响到 Pod 的就只有健康检查这一部分, 我们可以通过配置 liveness probe(存活探针)和 readiness probe(可读性探针)来影响容器的生命周期。 + +通过 Dubbo3 的 SPI 机制,在内部实现多种“探针”,基于 Dubbo3 QOS 运维模块的 HTTP 服务,使容器探针能够获取到应用内对应探针的状态。另外,SPI 的实现机制也利于用户自行拓展内部“探针”,使整个应用的生命周期更有效的进行管控。 + +**三种探针对应的 SPI 接口** + +- livenessProbe: `org.apache.dubbo.qos.probe.LivenessProbe` +- readinessProbe: `org.apache.dubbo.qos.probe.ReadinessProbe` +- startupProbe: `org.apache.dubbo.qos.probe.StartupProbe` + +接口将自动获取当前应用所有 SPI 的实现,对应接口的 SPI 实现均成功就绪则接口返回成功。 + +Dubbo3 SPI 更多扩展的介绍见 [Dubbo SPI扩展](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/) + +## 使用场景 +`liveness probe` 来确定你的应用程序是否正在运行,查看是否存活。 + +`readiness probe` 来确定容器是否已经就绪可以接收流量过来,是否准备就绪,是否可以开始工作。 + +`startup probe` 来确定容器内的应用程序是否已启动,如果提供了启动探测则禁用所有其他探测,直到它成功为止,如果启动探测失败则杀死容器,容器将服从其重启策略。如果容器没有提供启动探测,则默认状态为成功。 + +## 使用方式 + +### 存活检测 + +对于 livenessProbe 存活检测,由于 Dubbo3 框架本身无法获取到应用的存活状态,因此本接口无默认实现,且默认返回成功。开发者可以根据 SPI 定义对此 SPI 接口进行拓展,从应用层次对是否存活进行判断。 + +关于 [liveness 存活探针](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/liveness/) 扩展示例 +### 就绪检测 + +对于 readinessProbe 就绪检测,目前 Dubbo3 默认提供了两个检测维度,一是对 Dubbo3 服务自身是否启停做判断,另外是对所有服务是否存在已注册接口,如果所有服务均已从注册中心下线(可以通过 QOS 运维进行操作)将返回未就绪的状态。 + +关于 [readiness 就绪探针](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/readiness/) 扩展示例 + +### 启动检测 + +对于 startupProbe 启动检测,目前 Dubbo3 默认提供了一个检测维度,即是在所有启动流程(接口暴露、注册中心写入等)均结束后返回已就绪状态。 + +关于 [startup 启动探针](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/startup/) 扩展示例 + +### 参考示例 +```yaml +livenessProbe: + httpGet: + path: /live + port: 22222 + initialDelaySeconds: 5 + periodSeconds: 5 +readinessProbe: + httpGet: + path: /ready + port: 22222 + initialDelaySeconds: 5 + periodSeconds: 5 +startupProbe: + httpGet: + path: /startup + port: 22222 + failureThreshold: 30 + periodSeconds: 10 +``` +> QOS 当计算节点检测到内存压力时,kuberentes 会 BestEffort -> Burstable -> Guaranteed 依次驱逐 Pod。 + +目前三种探针均有对应的接口,路径为 QOS 中的命令,端口信息请根据 QOS 配置进行对应修改(默认端口为 22222)。其他参数请参考 [Kubernetes官方文档说明](https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/)。 diff --git a/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes.md b/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes.md new file mode 100644 index 000000000000..56fe5149adf5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes.md @@ -0,0 +1,89 @@ +--- +aliases: + - /zh/overview/tasks/deploy/deploy-on-vm/ + - /zh-cn/overview/tasks/deploy/deploy-on-vm/ +description: "部署 Dubbo 应用到 Kubernetes 环境,使用 Nacos 或者 Zookeeper 等作为注册中心。" +linkTitle: Kubernetes +title: 部署 Dubbo 应用到 Kubernetes 环境 +type: docs +weight: 2 +--- +这种模式与传统的非 Kubernetes 部署并无太大差异,如下图所示,仍然使用 Nacos 或者 Zookeeper 等作为注册中心,只不过将 Kubernetes 作为应用生命周期调度的底层平台。 + + + +## 安装 Nacos +在 Kubernetes 模式下,我们推荐使用 `dubboctl` 快速安装 Nacos、dubbo-control-plane、prometheus 等组件: + +```yaml +$ dubboctl install --profile=demo +``` + +{{% alert title="提示" color="primary" %}} +1. 请查看 dubboctl 了解更多细节 +2. 您也可以在此了解 Nacos 官方提供的 Kubernetes 集群安装方案 +{{% /alert %}} + + +## 部署应用 +我们仍然以 [快速开始]() 中的项目为例,演示应用打包部署的具体步骤。 + +首先,克隆示例项目到本地: +```shell +$ git clone -b main --depth 1 https://github.com/apache/dubbo-samples +```` + +切换到示例目录: +```shell +$ cd dubbo-samples/11-quickstart +``` + +### 打包镜像 +```shell +$ dubboctl build +# 具体写一下推送到 docker 仓库 +``` + +### 部署 + +```shell +$ dubboctl deploy +``` + +以下是生成的完整 Kubernetes manifests: + +```yaml + +``` + +执行以下命令,将应用部署到 Kubernetes 集群: +```shell +$ kubectl apply -f xxx.yml +``` + +### 查看部署状态 +如果之前已经使用 `dubboctl` 安装 dubbo-control-plane,则可以通过以下方式查看服务部署情况: + +```shell +$ kubectl port-forward +``` + +访问 `http://xxx` 查看服务部署详情。 + +### 优雅上下线 +如上面的架构图所示,我们仍然使用 Nacos 作为注册中心,因此,与传统 Linux 部署模式类似,控制实例发布到注册中心、实例从注册中心摘除的时机,是我们实现优雅上下线的关键: +1. 上线阶段,通过 [延迟发布]() 机制控制实例注册到注册中心的时机,通过开启 [消费端预热]() 确保流量缓慢的被转发到新节点上。 +2. 下线阶段,通过配置 `prestop` 确保先从注册中心摘除实例注册信息,之后再进入进程销毁过程。 + +优雅下线摘除实例的示例配置: + +```yaml +preStop: + exec: + command: ["/bin/sh","-c","curl /offline; sleep 10"] +``` + +{{% alert title="提示" color="primary" %}} +在这个模式下,由于 Dubbo 服务的发布与注销与注册中心强关联,因此与 Kubernetes 中的 liveness、readiness 关联并不大。在下一篇文档中,我们会讲到 Kubernetes Service 部署模式下如何配置 liveness、readiness。 +{{% /alert %}} + diff --git a/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-vm.md b/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-vm.md new file mode 100644 index 000000000000..695f09958df5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-vm.md @@ -0,0 +1,120 @@ +--- +aliases: + - /zh/overview/tasks/deploy/deploy-on-vm/ + - /zh-cn/overview/tasks/deploy/deploy-on-vm/ +description: "传统基于 Zookeeper、Nacos 的注册中心部署架构,部署 Dubbo 应用到虚拟机环境" +linkTitle: 传统注册中心 +title: 传统基于 Zookeeper、Nacos 的注册中心部署架构,部署 Dubbo 应用到虚拟机环境 +type: docs +weight: 1 +--- + +下图是使用 Nacos、Zookeeper 作为注册中心的典型 Dubbo 微服务部署架构。 + + + +## 安装 Nacos +请参考以下文档了解如何在本地 [安装 Nacos]()。 + +## 部署应用 +我们仍然以 [快速开始]() 中的项目为例,演示应用打包部署的具体步骤。 + +克隆示例项目到本地: +```shell +$ git clone -b main --depth 1 https://github.com/apache/dubbo-samples +```` + +切换到示例目录: +```shell +$ cd dubbo-samples/11-quickstart +``` + +以下是两种打包部署模式: + +### 方式一:本地进程 + +本地打包进程: +```shell +$ mvn clean package +``` + +启动 Dubbo 进程: +```shell +$ java -jar ./quickstart-service/target/quickstart-service-0.0.1-SNAPSHOT.jar +``` + +{{% alert title="提示" color="primary" %}} +为了程序正常运行,请确保 `application.yml` 文件中的注册中心地址已经正确指向你想要的注册中心。 +{{% /alert %}} + +### 方式二:docker容器 + +```shell +$ docker build -f ./Dockerfile -t quickstart +``` + +```shell +$ docker run quickstart -p port1:port2 +# 对于一些端口或连接注册中心的细节要写清楚 +``` + +{{% alert title="提示" color="primary" %}} +Docker 容器环境下,不同容器间用于网络通信的地址需要特别关注,因此你可能需要设置 Dubbo 进程监听或者注册到注册中心的地址,请参考以下链接了解更多内容。 + +见 [dubbo 通过环境变量设置 host](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-docker) + +有些部署场景需要动态指定服务注册的地址,如 docker bridge 网络模式下要指定注册宿主机 ip 以实现外网通信。dubbo 提供了两对启动阶段的系统属性,用于设置对外通信的ip、port地址。 + +* **DUBBO_IP_TO_REGISTRY**:注册到注册中心的 ip 地址 +* **DUBBO_PORT_TO_REGISTRY**:注册到注册中心的 port 端口 +* **DUBBO_IP_TO_BIND**:监听 ip 地址 +* **DUBBO_PORT_TO_BIND**:监听 port 端口 + +以上四个配置项均为可选项,如不配置 dubbo 会自动获取 ip 与端口,请根据具体的部署场景灵活选择配置。 +dubbo 支持多协议,如果一个应用同时暴露多个不同协议服务,且需要为每个服务单独指定 ip 或 port,请分别在以上属性前加协议前缀。 如: + +* **HESSIAN_DUBBO_PORT_TO_BIND**:hessian 协议绑定的 port +* **DUBBO_DUBBO_PORT_TO_BIND**:dubbo 协议绑定的 port +* **HESSIAN_DUBBO_IP_TO_REGISTRY**:hessian 协议注册的 ip +* **DUBBO_DUBBO_IP_TO_REGISTRY**:dubbo 协议注册的 ip + +PORT_TO_REGISTRY 或 IP_TO_REGISTRY 不会用作默认 PORT_TO_BIND 或 IP_TO_BIND,但是反过来是成立的。如: + +* 设置 `PORT_TO_REGISTRY=20881` 和 `IP_TO_REGISTRY=30.5.97.6`,则 `PORT_TO_BIND` 和 `IP_TO_BIND` 不受影响 +* 设置 `PORT_TO_BIND=20881` 和 `IP_TO_BIND=30.5.97.6`,则默认 `PORT_TO_REGISTRY=20881` 且 `IP_TO_REGISTRY=30.5.97.6` + +{{% /alert %}} + +### 查看部署状态 +安装并运行 dubbo-control-plane,查看本地服务部署状态: + +1. 下载安装包 + + ```shell + $ curl -L https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/release/downloadDubbo.sh | sh - + $ cd dubbo-$version/bin + ``` + +2. 运行以下命令,启动 dubbo-control-plane 进程 + ```shell + $ ./dubbo-cp run + ``` + +{{% alert title="提示" color="primary" %}} +为了 dubbo-control-plane 正常运行,请修改 `conf/dubbo-cp.yml` 以确保其指向你想要的注册中心。 +{{% /alert %}} + +访问 `http://xxx` 查看服务部署详情。 + +### 优雅上下线 +在使用传统注册中心的情况下,我们需要控制实例发布到注册中心、实例从注册中心摘除的时机,以实现优雅上下线: +1. 上线阶段,通过 [延迟发布]() 机制控制实例注册到注册中心的时机,通过开启 [消费端预热]() 确保流量缓慢的被转发到新节点上。 +2. 下线阶段,通过配置 `prestop` 确保先从注册中心摘除实例注册信息,之后再进入进程销毁过程。 + +在下线之前,建议调用以下 http 端口,先从注册中心摘除实例,然后再尝试停止进程 + +```shell +$ curl http://offline +$ sleep 10 +$ kill dubbo-pid +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/tasks/develop/_index.md b/content/en/overview/mannual/java-sdk/tasks/develop/_index.md new file mode 100755 index 000000000000..9520e800ed8a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/develop/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/overview/tasks/develop/ + - /zh-cn/overview/tasks/develop/ +description: 演示 Dubbo 框架提供的微服务开发 API 与编程模式 +linkTitle: 快速创建应用 +title: 快速创建应用 +type: docs +weight: 1 +--- diff --git a/content/en/overview/mannual/java-sdk/tasks/develop/api.md b/content/en/overview/mannual/java-sdk/tasks/develop/api.md new file mode 100644 index 000000000000..a927377b58a3 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/develop/api.md @@ -0,0 +1,299 @@ +--- +description: 作为一款 RPC 框架,Dubbo 定义了一套完善的 API 接口,我们可以基于原生 API 开发 RPC 服务和微服务应用 +linkTitle: 纯 API 开发模式 +title: 使用原生 API 开发 Dubbo 应用 +type: docs +weight: 2 +--- + +你可能已经注意到了,文档中大部分的功能、示例都是基于 Spring Boot 模式编写的,但 Spring Boot 或 Spring 仅仅是 Dubbo 适配的一种应用或者微服务开发模式。**作为一款 RPC 框架,Dubbo 定义了一套完善的 API 接口,我们可以基于原生 API 开发 Dubbo 应用**,纯 API 可以实现的业务场景包括: +* **轻量 RPC Server & Client**,通常用于一些应用内、基础组件、中间件等内的简单远程调用场景 +* **微服务应用**,不依赖 Spring 的情况下,直接用 API 开发微服务 + +## API 概览 +```java +public class Application { + public static void main(String[] args) { + DubboBootstrap.getInstance() + .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051)) + .service(ServiceBuilder.newBuilder().ref(new DemoServiceImpl()).build()) + .start() + .await(); + } +} +``` + +以上是启动 Dubbo RPC Server 的一段代码示例,`DubboBootstrap` 实例代表一个 Dubbo 应用,是整个 Dubbo 应用的启动入口。在 DubboBootstrap 基础上,我们可以设置 `protocol`、`service`、`registry`、`metrics` 等来注册服务、连接注册中心等,这和我们在 Spring Boot 中调整 application.yml 或者 application.properties 文件是对等的作用。 + +官方推荐使用 `DubboBootstrap.start()` 作为应用的集中启动入口,但为了方便在进程启动后,在运行态单独发布一些服务,Dubbo 框架也允许直接调用 `ServiceConfig.export()` 或 `ReferenceConfig.refer()` 方法发布单个服务,这时 Service/Reference 会注册到默认的 DubboBootstrap 实例中,效果同调用 `DubboBootstrap.service(...).start()` 类似。 + +以下是开发中会常用到的一些组件,完整组件定义及详细参数说明请参见 [参考手册 - 配置项手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#配置项手册): + +| API 组件 | 全局唯一 | 核心方法或属性 | 说明 | +| --- | --- | --- | --- | +| DubboBootstrap | 是(多应用场景除外) | start()、stop() | DubboBootstrap 实例代表一个 Dubbo 应用,是整个 Dubbo 应用的启动入口。 | +| ApplicationConfig | 是 | name | 应用名及应用级别的一些全局配置 | +| MetricsConfig | 是 | protocol、prometheus、tracing | Metrics、tracing 采集相关配置 | +| ProtocolConfig | 否。多协议场景服务通过 id 关联 | id、name、port、serialization、threadpool | RPC 协议端口、序列化协议、运行时行为配置 | +| RegistrtyConfig | 否。多注册中心场景服务通过 id 关联 | id、address、protocol、group | 注册中心实现、地址、订阅等配置 | +| ConfigCenterConfig | 否。多配置中心场景服务通过 id 关联 | id、address、protocol、group、namespace | 配置中心实现、地址、分组隔离等配置 | +| MetadataReportConfig | 否。多元数据中心场景服务通过 id 关联 | id、address、protocol、group、namespace | 元数据中心实现、地址、分组隔离等配置 | +| ProviderConfig | 否 | 参考 ServiceConfig | 作为多个ServiceConfig的默认值 | +| ConsumerConfig | 否 | 参考 ReferenceConfig | 作为多个ReferenceConfig的默认值 | +| ServiceConfig | 否 | - 方法:export()
- 属性: interfaceClass、ref、group、version、timeout、retry | 一个 ServiceConfig 实例代表一个 RPC 服务 | +| ReferenceConfig | 否 | - 方法:refer()
- 属性:interfaceClass、group、version、timeout、retry、cluster、loadbalance | 一个 ReferenceConfig 实例代表一个 RPC 服务 | +| MethodConfig | 否 | name、oninvoke、onreturn、onthrow | ServiceConfig/ReferenceConfig 内嵌的方法级别配置 | +| ArgumentConfig | 否 | index、type、callback | MethodConfig 内嵌的参数级别配置 | + +## 轻量 RPC 示例 +本示例演示如何使用轻量 Dubbo SDK 开发 RPC Server 与 Client,示例使用 Java Interface 方式定义、发布和访问 RPC 服务,底层使用 Triple 协议通信。本示例完整代码请参见 dubbo-samples。 + +基于 Dubbo 定义的 Triple 协议,你可以轻松编写浏览器、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。Dubbo Java SDK 支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 API 来发布或调用这些服务。 + +### Maven 依赖 + +在基于 Dubbo RPC 编码之前,您只需要在项目添加一个非常轻量的 `dubbo`依赖包即可,以 Maven 为例: +```xml + + org.apache.dubbo + dubbo + 3.3.0 + +``` + +### 定义服务 + +定义一个名为 `DemoService`的标准 Java 接口作为 Dubbo 服务(Dubbo 还支持[基于 IDL 的服务定义模式](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/))。 + +```java +public interface DemoService { + String sayHello(String name); +} +``` + +实现 `DemoService` 接口并编写业务逻辑代码。 + +```java +public class DemoServiceImpl implements DemoService { + @Override + public String sayHello(String name) { + return "Hello " + name + ", response from provider."; + } +} +``` + +### 注册服务并启动 Server + +启动 server 并在指定端口监听 RPC 请求,在此之前,我们向 server 注册了以下信息: + +- 使用 `Triple` 作为通信 RPC 协议与并监听端口 `50051` +- 注册 Dubbo 服务到 `DemoService` server + +```java +public class Application { + public static void main(String[] args) { + DubboBootstrap.getInstance() + .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051)) + .service(ServiceBuilder.newBuilder().ref(new DemoServiceImpl()).build()) + .start() + .await(); + } +} +``` + +### 访问服务 + +最简单方式是使用 HTTP/1.1 POST 请求访问服务,参数则以标准 JSON 格式作为 HTTP 负载传递。如下是使用 cURL 命令的访问示例: + +```shell +curl \ + --header "Content-Type: application/json" \ + --data '["Dubbo"]' \ + http://localhost:50051/org.apache.dubbo.demo.DemoService/sayHello +``` + +> 参数必须以数组格式进行传递,如果有多个参数,则格式类似 `["param1", {"param2-field": "param2-value"}, ...]`,具体请参见 triple 协议规范。 + +接下来,您也可以使用标准的 Dubbo client 请求服务,指定 server 地址即可发起 RPC 调用,其格式为 `protocol://ip:host` + +```java +public class Application { + public static void main(String[] args) { + DemoService demoService = + ReferenceBuilder.newBuilder() + .interfaceClass(DemoService.class) + .url("tri://localhost:50051") + .build() + .get(); + + String message = demoService.sayHello("dubbo"); + System.out.println(message); + } +} +``` + +恭喜您, 以上即是 Dubbo Java RPC 通信的基本使用方式! 🎉 + + +### 更多示例 +除了以上简单使用场景之外,开发者还可以发布多个服务、直接调用 ServiceConfig/ReferenceConfig 发布/订阅单个服务等。 + +#### 发布多个服务 +以下示例注册并发布任意多个服务 FooService、BarService,这些服务都将使用 providerConfig 中配置的默认超时时间,省去多个服务重复配置的烦恼。 + +```java +public static void main(String[] args) { + ProviderConfig providerConfig = new ProviderConfig(); + providerConfig.setTimeout(5000); + + ProtocolConfig protocolConfig = new ProtocolConfig(CommonConstants.TRIPLE, 50051); + + DubboBootstrap.getInstance() + .protocol(protocolConfig) + .provider(providerConfig) + .service(ServiceBuilder.newBuilder().ref(new FooServiceImpl()).build()) + .service(ServiceBuilder.newBuilder().ref(new BarServiceImpl()).build()) + .start() + .await(); +} +``` + +#### 发布单个服务 +直接调用 ServiceConfig.export() 发布服务,适用于运行态动态发布或订阅一个服务,对于 ReferenceConfig 同理。对于正常的应用启动流程,推荐使用 DubboBootstrap 而非直接调用 ServiceConfig.export() 发布单个服务。 + +1. 通过 ServiceConfig 发布服务 +```java +public static void main(String[] args) { + ServiceConfig demoServiceConfig = new ServiceConfig<>(); + demoServiceConfig.setInterface(DemoService.class); + demoServiceConfig.setRef(new DemoServiceImpl()); + demoServiceConfig.setVersion("1.0.0"); + + demoServiceConfig.export(); // this service will be registered to the default instance of DubboBootstrap.getInstance() +} +``` + +2. 通过 ReferenceConfig 订阅服务 + +```java +private DemoService referService() { + ReferenceConfig reference = new ReferenceConfig<>(); + reference.setInterfaceClass(DemoService.class); + + ReferenceCache cache = SimpleReferenceCache.getCache(); + try { + return cache.get(reference); + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } +} +``` + +由于 ReferenceConfig.get() 创建的代理对象持有连接、地址等大量资源,因此建议缓存复用,Dubbo 官方提供了 SimpleReferenceCache 实现参考实现。关于 SimpleReferenceCache 更多内容,请参考 [RPC 框架](/zh-cn/overview/mannual/java-sdk/tasks/framework/more/reference-config-cache/)。 + +#### 获得引用代理 +使用 DubboBootstrap 作为启动入口,订阅服务并获得代理对象。 + +```java +public static void main(String[] args) { + ReferenceConfig reference = + ReferenceBuilder.newBuilder() + .interfaceClass(GreetingsService.class) + .build(); + DubboBootstrap.getInstance().reference(reference).start(); + GreetingsService service = reference.get(); +} +``` + +## 微服务示例 +### 注册中心和应用名 +相比于 RPC server、RPC client,基于 API 的微服务应用开发需要配置应用名、注册中心。 + +```java +public static void main(String[] args) { + DubboBootstrap.getInstance() + .application() + .registry(new RegistryConfig("nacos://127.0.0.1:8848")) + .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051)) + .service(ServiceBuilder.newBuilder().ref(new DemoServiceImpl()).build()) + .service(ServiceBuilder.newBuilder().ref(new FooServiceImpl()).build()) + .start() + .await(); +} +``` + +### 多个注册中心 +多个注册中心可指定不同的 id,服务通过 id 关联注册中心实例。如下示例中,GreetingsService 发布到 bjRegistry,DemoService 发布到 hzRegistry。 + +```java +public static void main(String[] args) { + RegistryConfig bjRegistry = new RegistryConfig(); + bjRegistry.setId("bj"); + bjRegistry.setAddress("nacos://127.0.0.1:8848"); + + RegistryConfig hzRegistry = new RegistryConfig(); + hzRegistry.setId("hz"); + hzRegistry.setAddress("nacos://127.0.0.2:8848"); + + DubboBootstrap.getInstance() + .registry(bjRegistry) + .registry(hzRegistry) + .service(ServiceBuilder.newBuilder().registryIds("bj").interfaceClass(GreetingsService.class).ref(new GreetingsServiceImpl()).build()) + .service(ServiceBuilder.newBuilder().registryIds("hz").interfaceClass(DemoService.class).ref(new DemoServiceImpl()).build()) + .start() + .await(); +} +``` + +### 发布单个服务 +直接调用 ServiceConfig.export() 发布服务,适用于运行态动态发布或订阅一个服务,对于 ReferenceConfig 同理。对于正常的应用启动流程,推荐使用 DubboBootstrap 而非直接调用 ServiceConfig.export() 发布单个服务。 + +{{% alert title="注意" color="primary" %}} + +{{% /alert %}} + +1. 通过 ServiceConfig 发布服务 +```java +public static void main(String[] args) { + RegistryConfig hzRegistry = new RegistryConfig(); + hzRegistry.setId("hz"); + hzRegistry.setAddress("nacos://127.0.0.2:8848"); + + ServiceConfig demoServiceConfig = new ServiceConfig<>(); + demoServiceConfig.setInterface(DemoService.class); + demoServiceConfig.setRef(new DemoServiceImpl()); + demoServiceConfig.setVersion("1.0.0"); + + demoServiceConfig.setRegistry(hzRegistry); + + demoServiceConfig.export(); // this service will be registered to the default instance of DubboBootstrap.getInstance() +} +``` + +2. 通过 ReferenceConfig 订阅服务 + +```java +private DemoService referService() { + RegistryConfig hzRegistry = new RegistryConfig(); + hzRegistry.setId("hz"); + hzRegistry.setAddress("nacos://127.0.0.2:8848"); + + ReferenceConfig reference = new ReferenceConfig<>(); + reference.setInterfaceClass(DemoService.class); + + reference.setRegistry(hzRegistry) + + ReferenceCache cache = SimpleReferenceCache.getCache(); + try { + return cache.get(reference); + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } +} +``` + +## 更多内容 + +- Triple 协议完全兼容 gRPC,您可以参考这里了解如何 [使用 IDL 编写 gRPC 兼容的服务](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/),或者 [使用其他通信协议](/zh-cn/overview/mannual/java-sdk/tasks/protocols/) +- 作为 RPC 框架,Dubbo 支持异步调用、连接管理、context上下文等,请参考 [RPC 框架核心功能](/zh-cn/overview/mannual/java-sdk/tasks/framework/) +- 使用 [Dubbo Spring Boot 开发微服务应用](/zh-cn/overview/mannual/java-sdk/tasks/develop/springboot/) diff --git a/content/en/overview/mannual/java-sdk/tasks/develop/springboot.md b/content/en/overview/mannual/java-sdk/tasks/develop/springboot.md new file mode 100644 index 000000000000..555ad30b27d3 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/develop/springboot.md @@ -0,0 +1,207 @@ +--- +description: Dubbo 提供了对 Spring 框架的完整支持,我们推荐使用官方提供的丰富的 `dubbo-spring-boot-starter` 高效开发 Dubbo 微服务应用。 +linkTitle: Spring Boot Starter +title: Spring Boot +type: docs +weight: 1 +--- + +Dubbo 提供了对 Spring 框架的完整支持,我们推荐使用官方提供的 `dubbo-spring-boot-starter` 高效开发 Dubbo 微服务应用。 + +## 创建项目 +创建 Dubbo 应用最快捷的方式就是使用官方项目脚手架工具 - start.dubbo.apache.org 在线服务。它可以帮助开发者创建 Spring Boot 结构应用,自动管理 `dubbo-spring-boot-starter` 等依赖和必要配置。 + +另外,Jetbrain 官方也提供了 Apache Dubbo 项目插件,可用于快速创建 Dubbo Spring Boot 项目,能力与 start.dubbo.apache.org 对等,具体安装使用请查看 [博客文章](/zh-cn/blog/2023/10/23/intellij-idea%EF%B8%8Fapache-dubboidea官方插件正式发布/) + +## dubbo-spring-boot-starter +在 [快速开始](/zh-cn/overview/mannual/java-sdk/quick-start/) 中,我们已经详细介绍了典型的 Dubbo Spring Boot 工程源码及其项目结构,不熟悉的开发者可以前往查看。 + +`dubbo-spring-boot-starter` 可为项目引入 dubbo 核心依赖,自动扫描 dubbo 相关配置与注解。 + +### Maven 依赖 + +使用 Dubbo Spring Boot Starter,首先引入以下 Maven 依赖 + +```xml + + + + org.apache.dubbo + dubbo-bom + 3.3.0 + pom + import + + + +``` + +然后,在相应模块的 pom 中增加必要的 starter 依赖: +```xml + + + org.apache.dubbo + dubbo-spring-boot-starter + + + org.apache.dubbo + dubbo-zookeeper-spring-boot-starter + + +``` + +`dubbo-spring-boot-starter` 和 `dubbo-zookeeper-spring-boot-starter` 是官方提供的 starter,提供了 Spring Boot 的集成适配,它们的版本号与 Dubbbo 主框架版本号完全一致。 + +### application.yml 配置文件 +以下是一个示例文件配置 + +```yaml +dubbo: + application: + name: dubbo-springboot-demo-provider + logger: slf4j + protocol: + name: triple + port: -1 + registry: + address: zookeeper://127.0.0.1:2181 +``` + +除 service、reference 之外的组件都可以在 application.yml 文件中设置,具体可参考 [配置列表](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#applicationyaml)。 + +service、reference 组件也可以通过 `id` 与 application 中的全局组件做关联,以下面配置为例。如果要扩展 service 或 reference 的注解配置,则需要增加 `dubbo.properties` 配置文件或使用其他非注解如 Java Config 方式,具体请看下文 [扩展注解的配置](#扩展注解配置)。 + +```yaml +dubbo: + application: + name: dubbo-springboot-demo-provider + protocol: + name: triple + port: -1 + registry: + id: zk-registry + address: zookeeper://127.0.0.1:2181 +``` + +通过注解将 service 关联到上文定义的特定注册中心(通过id关联) +```java +@DubboService(registry="zk-registry") +public class DemoServiceImpl implements DemoService {} +``` + +通过 Java Config 配置进行关联也是同样道理 +```java +@Configuration +public class ProviderConfiguration { + @Bean + public ServiceConfig demoService() { + ServiceConfig service = new ServiceConfig(); + service.setRegistry("zk-registry"); + return service; + } +} +``` + +### Dubbo 注解 +* `application.properties` 或 `application.yml` 配置文件。 +* `@DubboService`、`@DubboReference` 与 `EnableDubbo` 注解。其中 `@DubboService` 与 `@DubboReference` 用于标记 Dubbo 服务,`EnableDubbo` 启动 Dubbo 相关配置并指定 Spring Boot 扫描包路径。 + +#### @DubboService 注解 + +> `@Service` 注解从 3.0 版本开始就已经废弃,改用 `@DubboService`,以区别于 Spring 的 `@Service` 注解 + +定义好 Dubbo 服务接口后,提供服务接口的实现逻辑,并用 `@DubboService` 注解标记,就可以实现 Dubbo 的服务暴露 + +```java +@DubboService +public class DemoServiceImpl implements DemoService {} +``` + +如果要设置服务参数,`@DubboService` 也提供了常用参数的设置方式。如果有更复杂的参数设置需求,则可以考虑使用其他设置方式 +```java +@DubboService(version = "1.0.0", group = "dev", timeout = 5000) +public class DemoServiceImpl implements DemoService {} +``` + +#### @DubboReference 注解 + +> `@Reference` 注解从 3.0 版本开始就已经废弃,改用 `@DubboReference`,以区别于 Spring 的 `@Reference` 注解 + +```java +@Component +public class DemoClient { + @DubboReference + private DemoService demoService; +} +``` + +`@DubboReference` 注解将自动注入为 Dubbo 服务代理实例,使用 demoService 即可发起远程服务调用 + +#### @EnableDubbo 注解 +`@EnableDubbo` 注解必须配置,否则将无法加载 Dubbo 注解定义的服务,`@EnableDubbo` 可以定义在主类上 + +```java +@SpringBootApplication +@EnableDubbo +public class ProviderApplication { + public static void main(String[] args) throws Exception { + SpringApplication.run(ProviderApplication.class, args); + } +} +``` + +Spring Boot 注解默认只会扫描 main 类所在的 package,如果服务定义在其它 package 中,需要增加配置 `EnableDubbo(scanBasePackages = {"org.apache.dubbo.springboot.demo.provider"})` + +#### 扩展注解配置 +虽然可以通过 `@DubboService` 和 `DubboReference` 调整配置参数(如下代码片段所示),但总体来说注解是为易用性设计的,其提供的仅仅是 80% 场景下常用的配置项。在这种情况下,如果有更复杂的参数设置需求,可以使用 `Java Config` 或 `dubbo.properties` 两种方式。 + +```java +@DubboService(version = "1.0.0", group = "dev", timeout = 5000) +@DubboReference(version = "1.0.0", group = "dev", timeout = 5000) +``` + +#### 使用 Java Config 代替注解 + +注意,Java Config 是 `DubboService` 或 `DubboReference` 的替代方式,对于有复杂配置需求的服务建议使用这种方式。 + +```java +@Configuration +public class ProviderConfiguration { + @Bean + public ServiceBean demoService() { + ServiceBean service = new ServiceBean(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + service.setGroup("dev"); + service.setVersion("1.0.0"); + Map parameters = new HashMap<>(); + service.setParameters(parameters); + return service; + } +} +``` + + +#### 通过 dubbo.properties 补充配置 +对于使用 `DubboService` 或 `DubboReference` 的场景,可以通过在项目 resources 目录下增加 dubbo.properties 文件作为配置补充,[具体格式](../principle/#1-配置格式)这里有更详细解释。 + +```properties +dubbo.service.org.apache.dubbo.springboot.demo.DemoService.timeout=5000 +dubbo.service.org.apache.dubbo.springboot.demo.DemoService.parameters=[{myKey:myValue},{anotherKey:anotherValue}] +dubbo.reference.org.apache.dubbo.springboot.demo.DemoService.timeout=6000 +``` + +> properties 格式配置目前结构性不太强,比如体现在 key 字段冗余较多,后续会考虑提供对于 yaml 格式的支持。 + +## 更多微服务开发模式 +* [纯 API 开发模式](../api/) +* 其他 Spring 开发模式 + * [Spring XML](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/xml/) + +## Dubbo 与 Spring Cloud 的关系 +Dubbo 与 Spring Cloud 是两套平行的微服务开发与解决方案,两者都提供了微服务定义、发布、治理的相关能力,对于微服务开发者来说,我们建议在开发之初就确定好 Apache Dubbo 与 Spring Cloud 之间的选型,尽量避免两个不同体系在同一集群中出现,以降低集群维护复杂度。而对于一些确需两套体系共存的场景,为了解决相互之间的通信问题,我们提供了 [Dubbo 与 Spring Cloud 异构微服务体系互通最佳实践](/zh-cn/blog/2023/10/07/微服务最佳实践零改造实现-spring-cloud-apache-dubbo-互通/) 解决方案。 + + Dubbo 与 Spring Boot 是互补的关系,Dubbo 在 Spring Boot 体系之上提供了完整的微服务开发、治理能力,关于这一点我们在另一篇文章中有更详尽的说明:[Dubbo、Spring Cloud 与 Istio](/zh-cn/overview/what/xyz-difference/)。 + + + diff --git a/content/en/overview/mannual/java-sdk/tasks/extensibility/_index.md b/content/en/overview/mannual/java-sdk/tasks/extensibility/_index.md new file mode 100755 index 000000000000..2778fcca2b18 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/extensibility/_index.md @@ -0,0 +1,65 @@ +--- +aliases: + - /zh/overview/tasks/extensibility/ + - /zh-cn/overview/tasks/extensibility/ +description: 演示 Dubbo 扩展能力特性的使用方式。 +linkTitle: 自定义扩展 +no_list: true +title: 自定义扩展 +type: docs +weight: 6 +--- + +通过如下任务项分别来介绍 Dubbo 的扩展特性。 + +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ 自定义过滤器 +

+

通过SPI机制动态加载自定义过滤器,可以对返回的结果进行统一的处理、验证等,减少对开发人员的打扰。

+
+
+
+
+
+
+

+ 自定义路由 +

+

在服务调用的过程中根据实际使用场景自定义路由策略,可以有效的改善服务吞吐量和耗时。

+
+
+
+
+
+
+

+ 自定义协议 +

+

针对不同的异构系统可以使用自定义传输协议,为系统之间的整合屏蔽了协议之间的差异。 +

+
+
+
+
+
+
+

+ 自定义注册中心 +

+

将不同注册中心中的服务都纳入到 Dubbo 体系中,自定义注册中心是打通异构服务体系之间的利刃。 +

+
+
+
+
+
+
+ +{{< /blocks/section >}} diff --git a/content/en/overview/mannual/java-sdk/tasks/extensibility/filter.md b/content/en/overview/mannual/java-sdk/tasks/extensibility/filter.md new file mode 100644 index 000000000000..14f20f0d1397 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/extensibility/filter.md @@ -0,0 +1,94 @@ +--- +aliases: + - /zh/overview/tasks/extensibility/filter/ + - /zh-cn/overview/tasks/extensibility/filter/ +description: 在本文中,我们来了解如何扩展自定义的过滤器实现:一个可以对返回的结果进行统一的处理、验证等统一 Filter 处理器,减少对开发人员的打扰。 +linkTitle: Filter +no_list: true +title: Filter +type: docs +weight: 2 +--- + +在 [RPC框架 - Filter请求拦截](../../framework/filter/) 一节中,我们了解了 Filter 的工作机制,以及 Dubbo 框架提供的一些内置 Filter 实现。在本文中,我们来了解如何扩展自定义的过滤器实现:一个可以对返回的结果进行统一的处理、验证等统一 Filter 处理器,减少对开发人员的打扰。 + +本示例的完整源码请参见 [dubbo-samples-extensibility](https://github.com/apache/dubbo-samples/blob/master/10-task/dubbo-samples-extensibility/)。除了本示例之外,Dubbo 核心仓库 apache/dubbo 以及扩展库 [apache/dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-filter-extensions/) 中的众多 Filter 实现,都可以作为扩展参考实现。 + +## 任务详情 + +对所有调用Provider服务的请求在返回的结果的后面统一添加`'s customized AppendedFilter`。 + +## 实现方式 + +在Provider中自定义一个Filter,在Filter中修改返回结果。 + +#### 代码结构 +```properties +src + |-main + |-java + |-org + |-apache + |-dubbo + |-samples + |-extensibility + |-filter + |-provider + |-AppendedFilter.java (实现Filter接口) + |-resources + |-META-INF + |-application.properties (Dubbo Provider配置文件) + |-dubbo + |-org.apache.dubbo.rpc.Filter (纯文本文件) +``` +#### 代码详情 +```java +package org.apache.dubbo.samples.extensibility.filter.provider; + +import org.apache.dubbo.rpc.Filter; +import org.apache.dubbo.rpc.Result; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.AsyncRpcResult; + +public class AppendedFilter implements Filter { + + @Override + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + Result result= invoker.invoke(invocation); + // Obtain the returned value + Result appResponse = ((AsyncRpcResult) result).getAppResponse(); + // Appended value + appResponse.setValue(appResponse.getValue()+"'s customized AppendedFilter"); + return result; + } +} +``` + +#### SPI配置 +在`resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter`文件中添加如下配置: +```properties +appended=org.apache.dubbo.samples.extensibility.filter.provider.AppendedFilter +``` + +#### 配置文件 +在`resources/application.properties`文件中添加如下配置,激活刚才的自定义 Filter 实现: +```properties +# Apply AppendedFilter +dubbo.provider.filter=appended +``` + +{{% alert title="注意" color="warning" %}} +除了通过配置激活 Filter 实现之外,还可以通过为实现类增加 @Activate 注解,以在满足某些条件时自动激活 Filter 实现,如: +```java +@Activate(group="provider") +public class AppendedFilter implements Filter {} +``` +这个 Filter 实现将在 Provider 提供者端自动被激活。 +{{% /alert %}} + +## 运行结果 +以**使用本地IDE**的方式来运行任务,结果如下: + +![dubbo-samples-extensibility-filter-output.jpg](/imgs/v3/tasks/extensibility/dubbo-samples-extensibility-filter-output.jpg) diff --git a/content/en/overview/mannual/java-sdk/tasks/extensibility/protocol.md b/content/en/overview/mannual/java-sdk/tasks/extensibility/protocol.md new file mode 100644 index 000000000000..0679b645872e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/extensibility/protocol.md @@ -0,0 +1,188 @@ +--- +aliases: + - /zh/overview/tasks/extensibility/protocol/ + - /zh-cn/overview/tasks/extensibility/protocol/ +description: 本文讲解如何通过扩展 `org.apache.dubbo.rpc.Protocol` SPI,提供自定义的 RPC 协议实现。 +linkTitle: Protocol +no_list: true +title: Protocol +type: docs +weight: 2 +--- + +在 [通信协议](/zh-cn/overview/mannual/java-sdk/tasks/protocols/) 一章中,我们了解了 Dubbo 内置的几个核心 RPC 协议 `dubbo`、`rest`、和`tri` 以及它们的使用方式。本文讲解如何通过扩展 `org.apache.dubbo.rpc.Protocol` SPI,提供自定义的 RPC 协议实现。 + +自定义一套私有协议有两种方式,第一种是对原有的协议进行包装,添加一些特定的业务逻辑。另外一种是完全自定义一套协议。前者实现简单,在`dubbo`中也是有广泛的使用,比如:`ProtocolFilterWrapper`, `QosProtocolWrapper`, `ProtocolListenerWrapper`等。后者实现相对复杂,但却具有最大的灵活性,比如 Dubbo 框架内置的协议 `dubbo`、`triple` 协议都可以算作这种实现方式。 + +本示例的完整源码请参见 [dubbo-samples-extensibility](https://github.com/apache/dubbo-samples/blob/master/10-task/dubbo-samples-extensibility/)。除了本示例之外,Dubbo 核心仓库 apache/dubbo 以及扩展库 [apache/dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-protocol-extensions/) 中的众多 Protocol 实现,都可以作为扩展参考实现: + +```properties +# Dubbo对外支持的常用协议 +dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol +tri=org.apache.dubbo.rpc.protocol.tri.TripleProtocol +``` + +## 任务详情 + +基于现有的`dubbo`协议来实现自定义协议`edubbo`。 + +## 实现方式 + +通过对`dubbo`协议进行包装来实现`edubbo`协议。 + +#### 代码结构 + +##### Common + +```properties +src + |-main + |-java + |-org + |-apache + |-dubbo + |-samples + |-extensibility + |-protocol + |-common + |-EnhancedProtocol.java (实现Protocol接口) +``` + +##### Provider +```properties +src + |-main + |-java + |-org + |-apache + |-dubbo + |-samples + |-extensibility + |-protocol + |-provider + |-ExtensibilityProtocolProviderApplication.java + |-ExtensibilityProtocolServiceImpl.java + |-resources + |-META-INF + |-application.properties (Dubbo Provider配置文件) + |-dubbo + |-org.apache.dubbo.rpc.Protocol (纯文本文件) +``` + +##### Consumer +```properties +src + |-main + |-java + |-org + |-apache + |-dubbo + |-samples + |-extensibility + |-protocol + |-consumer + |-ExtensibilityProtocolConsumerApplication.java + |-ExtensibilityProtocolConsumerTask.java + |-resources + |-META-INF + |-application.properties (Dubbo Consumer配置文件) + |-dubbo + |-org.apache.dubbo.rpc.Protocol (纯文本文件) +``` + +#### 代码详情 +```java +package org.apache.dubbo.samples.extensibility.protocol.common; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.rpc.Protocol; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.Exporter; +import org.apache.dubbo.rpc.ProtocolServer; +import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol; + +import java.util.List; + +public class EnhancedProtocol implements Protocol { + + public EnhancedProtocol(FrameworkModel frameworkModel) { + this.protocol = new DubboProtocol(frameworkModel); + } + + private final Protocol protocol; + + @Override + public int getDefaultPort() { + return this.protocol.getDefaultPort(); + } + + @Override + public Exporter export(Invoker invoker) throws RpcException { + // do something + return this.protocol.export(invoker); + } + + @Override + public Invoker refer(Class type, URL url) throws RpcException { + // do something + return this.protocol.refer(type, url); + } + + @Override + public void destroy() { + this.protocol.destroy(); + } + + @Override + public List getServers() { + return protocol.getServers(); + } +} +``` + +#### SPI配置 + +##### Provider + +在`resources/META-INF/dubbo/org.apache.dubbo.rpc.Protocol`文件中添加如下配置: +```properties +edubbo=org.apache.dubbo.samples.extensibility.protocol.common.EnhancedProtocol +``` + +##### Consumer + +在`resources/META-INF/dubbo/org.apache.dubbo.rpc.Protocol`文件中添加如下配置: +```properties +edubbo=org.apache.dubbo.samples.extensibility.protocol.common.EnhancedProtocol +``` + +#### 配置文件 + +##### Provider + +在`resources/application.properties`文件中添加如下配置: +```properties +# 自定义协议 +dubbo.provider.protocol=edubbo +``` + +##### Consumer + +在`resources/application.properties`文件中添加如下配置: +```properties +# 自定义协议 +dubbo.consumer.protocol=edubbo +``` + +## 运行结果 +以**使用本地IDE**的方式来运行任务,结果如下: + +#### 注册协议 + +![dubbo-samples-extensibility-protocol-output2.jpg](/imgs/v3/tasks/extensibility/dubbo-samples-extensibility-protocol-output2.jpg) + +#### 输出结果 + +![dubbo-samples-extensibility-protocol-output1.png](/imgs/v3/tasks/extensibility/dubbo-samples-extensibility-protocol-output1.png) diff --git a/content/en/overview/mannual/java-sdk/tasks/extensibility/registry.md b/content/en/overview/mannual/java-sdk/tasks/extensibility/registry.md new file mode 100644 index 000000000000..8bef424e5038 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/extensibility/registry.md @@ -0,0 +1,134 @@ +--- +aliases: + - /zh/overview/tasks/extensibility/registry/ + - /zh-cn/overview/tasks/extensibility/registry/ +description: 本文讲解如何通过扩展 `org.apache.dubbo.registry.client.ServiceDiscovery` SPI,提供自定义的注册中心实现。 +linkTitle: Registry +no_list: true +title: Registry +type: docs +weight: 3 +--- + +在 [服务发现](/zh-cn/overview/mannual/java-sdk/tasks/protocols/) 一章中,我们了解了 Dubbo 内置的几个核心注册中心实现 `Nacos`、`Zookeeper` 的使用方式与工作原理。本文讲解如何通过扩展 `org.apache.dubbo.registry.client.ServiceDiscovery` 和 `org.apache.dubbo.registry.nacos.NacosServiceDiscoveryFactory` SPI,提供自定义的注册中心实现。 + +本示例的完整源码请参见 [dubbo-registry-etcd](https://github.com/apache/dubbo-spi-extensions/tree/3.2.0/dubbo-registry-extensions/dubbo-registry-etcd3)。除了本示例之外,Dubbo 核心仓库 apache/dubbo 以及扩展库 apache/dubbo-spi-extensions 中的众多注册中心扩展实现,都可以作为扩展参考实现: + +```properties +# Dubbo对外支持的常用注册中心实现 +nacos=org.apache.dubbo.registry.nacos.NacosServiceDiscoveryFactory +zookeeper=org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscoveryFactory +``` + +## 任务详情 +通过扩展 SPI 实现基于的 etcd 注册中心。 + +## 实现方式 + +#### 代码详情 +首先,通过继承 `AbstractServiceDiscoveryFactory` 实现 `ServiceDiscoveryFactory` 接口 + +```java +public class EtcdServiceDiscoveryFactory extends AbstractServiceDiscoveryFactory { + + @Override + protected ServiceDiscovery createDiscovery(URL registryURL) { + return new EtcdServiceDiscovery(applicationModel, registryURL); + } + +} +``` + +`EtcdServiceDiscovery` 的一些关键方法与实现如下: + +```java +public class EtcdServiceDiscovery extends AbstractServiceDiscovery { + + private final Set services = new ConcurrentHashSet<>(); + private final Map childListenerMap = new ConcurrentHashMap<>(); + + EtcdClient etcdClient; + + public EtcdServiceDiscovery(ApplicationModel applicationModel, URL registryURL) { + super(applicationModel, registryURL); + EtcdTransporter etcdTransporter = applicationModel.getExtensionLoader(EtcdTransporter.class).getAdaptiveExtension(); + + etcdClient = etcdTransporter.connect(registryURL); + + etcdClient.addStateListener(state -> { + if (state == StateListener.CONNECTED) { + try { + recover(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + }); + + this.registryURL = registryURL; + } + + @Override + public void doRegister(ServiceInstance serviceInstance) { + try { + String path = toPath(serviceInstance); + etcdClient.putEphemeral(path, new Gson().toJson(serviceInstance)); + services.add(serviceInstance.getServiceName()); + } catch (Throwable e) { + throw new RpcException("Failed to register " + serviceInstance + " to etcd " + etcdClient.getUrl() + + ", cause: " + (OptionUtil.isProtocolError(e) + ? "etcd3 registry may not be supported yet or etcd3 registry is not available." + : e.getMessage()), e); + } + } + + @Override + protected void doUnregister(ServiceInstance serviceInstance) { + try { + String path = toPath(serviceInstance); + etcdClient.delete(path); + services.remove(serviceInstance.getServiceName()); + } catch (Throwable e) { + throw new RpcException("Failed to unregister " + serviceInstance + " to etcd " + etcdClient.getUrl() + ", cause: " + e.getMessage(), e); + } + } + + @Override + public void addServiceInstancesChangedListener(ServiceInstancesChangedListener listener) throws NullPointerException, IllegalArgumentException { + for (String serviceName : listener.getServiceNames()) { + registerServiceWatcher(serviceName, listener); + } + } + + @Override + public List getInstances(String serviceName) { + List children = etcdClient.getChildren(toParentPath(serviceName)); + if (CollectionUtils.isEmpty(children)) { + return Collections.emptyList(); + } + List list = new ArrayList<>(children.size()); + for (String child : children) { + ServiceInstance serviceInstance = new Gson().fromJson(etcdClient.getKVValue(child), DefaultServiceInstance.class); + list.add(serviceInstance); + } + return list; + } +} +``` + +#### SPI配置 + +在 `resources/META-INF/dubbo/org.apache.dubbo.registry.client.ServiceDiscoveryFactory` 文件中添加如下配置: + +```properties +etcd=org.apache.dubbo.registry.etcd.EtcdServiceDiscoveryFactory +``` + +## 使用方式 + +要开启 etcd 作为注册中心,修改应用中的 `resources/application.properties` 文件中的 registry 配置如下: + +```properties +dubbo.registry.address=etcd://host:port +``` + diff --git a/content/en/overview/tasks/extensibility/router.md b/content/en/overview/mannual/java-sdk/tasks/extensibility/router.md similarity index 54% rename from content/en/overview/tasks/extensibility/router.md rename to content/en/overview/mannual/java-sdk/tasks/extensibility/router.md index 9aa60460a94c..816303ec22ba 100644 --- a/content/en/overview/tasks/extensibility/router.md +++ b/content/en/overview/mannual/java-sdk/tasks/extensibility/router.md @@ -1,7 +1,8 @@ --- aliases: - - /en/overview/tasks/extensibility/router/ -description: Custom Routing Strategy + - /zh/overview/tasks/extensibility/router/ + - /zh-cn/overview/tasks/extensibility/router/ +description: 本文讲解如何通过扩展 Router 实现自定义路由策略,可以根据业务场景的特点来实现特定的路由方式。 linkTitle: Router no_list: true title: Router @@ -9,43 +10,19 @@ type: docs weight: 4 --- -By creating custom routers, you can implement specific routing methods based on the characteristics of your business scenario. +通过自定义路由,可以根据业务场景的特点来实现特定的路由方式。本示例 router 扩展实现源码请参见 [dubbo-samples-extensibility](https://github.com/apache/dubbo-samples/blob/master/10-task/dubbo-samples-extensibility/)。 -## Prerequisites +## 开始之前 -Choose one of the two deployment and running methods -### Based on Kubernetes -* Install [Kubernetes](https://kubernetes.io/docs/tasks/tools/) environment -* Modify the configuration file in [Provider](https://github.com/apache/dubbo-samples/blob/master/10-task/dubbo-samples-extensibility/dubbo-samples-extensibility-router-provider/src/main/resources/application.properties) to enable the address of nacos deployed in Kubernetes - ```properties - # (The configuration remains the same as in the original documentation) - ``` -* Modify the configuration file in [Consumer](https://github.com/apache/dubbo-samples/blob/master/10-task/dubbo-samples-extensibility/dubbo-samples-extensibility-filter-consumer/src/main/resources/application.properties) to enable the address of nacos deployed in Kubernetes - ```properties - # (The configuration remains the same as in the original documentation) - ``` -* Deploy [Extensibility Router Task](https://github.com/apache/dubbo-samples/blob/master/10-task/dubbo-samples-extensibility/deploy/All.yml) +## 任务详情 -### Using Local IDE -* Deploy [Nacos](https://nacos.io/en-us/) version 2.2.0 -* Modify the configuration file in [Provider](https://github.com/apache/dubbo-samples/blob/master/10-task/dubbo-samples-extensibility/dubbo-samples-extensibility-filter-provider/src/main/resources/application.properties) to enable the local nacos address - ```properties - # (The configuration remains the same as in the original documentation) - ``` -* Modify the configuration file in [Consumer](https://github.com/apache/dubbo-samples/blob/master/10-task/dubbo-samples-extensibility/dubbo-samples-extensibility-filter-consumer/src/main/resources/application.properties) to enable the local nacos address - ```properties - # (The configuration remains the same as in the original documentation) - ``` +对所有的请求都使用第一提供服务的Provider,如果该Provider下线,则从新选择一个新的Provider。 -## Task Details +## 实现方式 -The task is to stick to the first Provider that starts providing the service. If that Provider goes offline, choose a new Provider. +在Consumer中自定义一个Router,在Router中将第一次调用的Provider保存下来,如果后续有请求调用且Provider列表中包含第一次调用时使用的Provider,则继续使用第一次调用时使用的Provider,否则重新选去一个Provider。 -## Implementation Method - -Create a custom router in the Consumer. In this router, save the Provider that was used for the first invocation. For subsequent invocations, if the list of Providers includes the one used during the first invocation, continue to use it; otherwise, choose a new Provider. - -#### Code Structure +#### 代码结构 ```properties src |-main @@ -58,15 +35,15 @@ src |-router |-consumer |-router - |-StickFirstStateRouter.java (Implement StateRouter interface) - |-StickFirstStateRouterFactory.java (Implement StateRouterFactory interface) + |-StickFirstStateRouter.java (实现StateRouter接口) + |-StickFirstStateRouterFactory.java (实现StateRouterFactory接口) |-resources |-META-INF - |-application.properties (Dubbo Consumer configuration file) + |-application.properties (Dubbo Consumer配置文件) |-dubbo - |-org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory (Plain text file) + |-org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory (纯文本文件) ``` -#### Code Details +#### 代码详情 + StickFirstStateRouter ```java @@ -153,23 +130,20 @@ public class StickFirstStateRouterFactory implements StateRouterFactory { } ``` -#### SPI Configuration -Add the following configuration to the `resources/META-INF/dubbo/org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory` file: +#### SPI配置 +在`resources/META-INF/dubbo/org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory`文件中添加如下配置: ```properties stickfirst=org.apache.dubbo.samples.extensibility.router.consumer.router.StickFirstStateRouterFactory ``` -#### Configuration File -Add the following configuration to the `resources/application.properties` file: +#### 配置文件 +在`resources/application.properties`文件中添加如下配置: ```properties -# Configure custom router +# 配置自定义路由 dubbo.consumer.router=stickfirst ``` -## Execution Results - -Run the task using the **Using Local IDE** method, and the results are as follows: +## 运行结果 +以**使用本地IDE**的方式来运行任务,结果如下: ![dubbo-samples-extensibility-router-output.png](/imgs/v3/tasks/extensibility/dubbo-samples-extensibility-router-output.png) - -To summarize, Dubbo's extensibility allows you to create custom routers, providing a way to customize the routing logic based on your business requirements. This tutorial demonstrates how to create a "Stick to the First Provider" routing strategy, which can be useful for optimizing network traffic and reducing latency. \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/tasks/extensibility/spi.md b/content/en/overview/mannual/java-sdk/tasks/extensibility/spi.md new file mode 100644 index 000000000000..724fe31266c5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/extensibility/spi.md @@ -0,0 +1,66 @@ +--- +description: "Dubbo 的 SPI 插件扩展机制说明,讲解自定义 SPI 扩展的基本步骤。" +linkTitle: 如何自定义扩展 +title: "自定义 SPI 扩展的基本步骤" +type: docs +weight: 1 +--- + +下面以 `RPC 协议插件` 为例,说明如何利用 Dubbo 提供的 SPI 插件提供一个自定义的 RPC 协议实现。如果想了解 SPI 机制的工作原理以及框架内置的 SPI 扩展点列表,请查看 [参考手册 - SPI扩展](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/overview)。 + +## 1. 提供 SPI 插件实现类 +提供一个 Java 类实现 `org.apache.dubbo.rpc.Protocol` 接口。 + +```java +package com.spi.demo; +import org.apache.dubbo.rpc.Protocol; + +@Activate +public class CustomizedProtocol implements Protocol { + // ... +} +``` + +## 2. 在指定文件配置实现类 + +在应用 `resources/META-INF/services/` 目录下添加 `org.apache.dubbo.rpc.Protocol` 文件,文件中增加如下配置: + +```properties +customized=com.spi.demo.CustomizedProtocol +``` + +{{% alert title="配置注意事项" color="info" %}} +* 文件名必须为 SPI 插件定义的 package 全路径名,具体取决于你要扩展的 SPI 定义,如示例中的 `resources/META-INF/services/org.apache.dubbo.rpc.Protocol`。 +* 文件中的内容必须是 `key=value` 形式,其中 `key` 可随便定义,但建议增加特定前缀以避免与 Dubbo 内置实现重名,`value` 必须设置为扩展类实现的全路径名。 +{{% /alert %}} + +## 3. 通过配置启用自定义协议实现 + +在应用中修改协议配置,告诉 Dubbo 框架使用自定义协议: + +```yaml +# 使用 Spring Boot,可修改 application.yml 或 application.properties +dubbo + protocol + name: customized +``` + +或者 + +```java +ProtocolConfig protocol = new ProtocolConfig(); +protocol.setName("cutomized"); +``` + +## 4. 更多示例 + +如果你想了解更完整示例,请查看本目录下的其他示例: +* [自定义协议扩展](../protocol) +* [自定义拦截器扩展](../filter) +* [自定义注册中心扩展](../registry) +* [自定义路由器扩展](../router) + + + + + diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/_index.md b/content/en/overview/mannual/java-sdk/tasks/framework/_index.md new file mode 100755 index 000000000000..041f348d7aa8 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/_index.md @@ -0,0 +1,9 @@ +--- +description: "Dubbo 是一款轻量的 RPC 框架,提供 Java、Go、Node.js、Javascript 等语言支持,帮助开发者构建浏览器、gRPC 兼容的 HTTP API。" +linkTitle: RPC框架 +title: Dubbo 作为轻量 RPC 框架解决组件通信问题 +type: docs +weight: 6 +--- + +{{% docs/section_list %}} \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/async.md b/content/en/overview/mannual/java-sdk/tasks/framework/async.md new file mode 100644 index 000000000000..4bc64491a2f5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/async.md @@ -0,0 +1,230 @@ +--- +aliases: + - /zh/overview/tasks/develop/async/ + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/async-call/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-call/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-execute-on-provider/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async/ +description: 某些情况下希望dubbo接口异步调用,避免不必要的等待。 +linkTitle: 异步调用 +title: 异步调用 +type: docs +weight: 3 +--- + +Dubbo 异步调用分为 Provider 端异步调用和 Consumer 端异步两种模式。 +* Consumer 端异步是指发起 RPC 调用后立即返回,调用线程继续处理其他业务逻辑,当响应结果返回后通过回调函数通知消费端结果。 +* Provider 端异步执行将阻塞的业务从 Dubbo 内部线程池切换到业务自定义线程,避免Dubbo线程池的过度占用,有助于避免不同服务间的互相影响。 + +以下是消费端 consumer 异步调用的工作示例图: + +![/user-guide/images/future.jpg](/imgs/user/future.jpg) + +Provider 端异步执行和 Consumer 端异步调用是相互独立的,你可以任意正交组合两端配置。 ++ Consumer同步 - Provider同步 ++ Consumer异步 - Provider同步 ++ Consumer同步 - Provider异步 ++ Consumer异步 - Provider异步 + +本文档演示的完整示例源码请参见: +* [Consumer 服务调用异步](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-async/dubbo-samples-async-simple-boot) +* [Provider 服务执行异步](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-async/dubbo-samples-async-provider) +* [定义 CompletableFuture 方法签名的服务](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-async/dubbo-samples-async-original-future) + +## Provider异步 + +### 1 使用CompletableFuture + +接口定义: +```java +public interface AsyncService { + /** + * 同步调用方法 + */ + String invoke(String param); + /** + * 异步调用方法 + */ + CompletableFuture asyncInvoke(String param); +} + +``` +服务实现: +```java +@DubboService +public class AsyncServiceImpl implements AsyncService { + + @Override + public String invoke(String param) { + try { + long time = ThreadLocalRandom.current().nextLong(1000); + Thread.sleep(time); + StringBuilder s = new StringBuilder(); + s.append("AsyncService invoke param:").append(param).append(",sleep:").append(time); + return s.toString(); + } + catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + return null; + } + + @Override + public CompletableFuture asyncInvoke(String param) { + // 建议为supplyAsync提供自定义线程池 + return CompletableFuture.supplyAsync(() -> { + try { + // Do something + long time = ThreadLocalRandom.current().nextLong(1000); + Thread.sleep(time); + StringBuilder s = new StringBuilder(); + s.append("AsyncService asyncInvoke param:").append(param).append(",sleep:").append(time); + return s.toString(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + return null; + }); + } +} + +``` +通过 return CompletableFuture.supplyAsync() ,业务执行已从 Dubbo 线程切换到业务线程,避免了对 Dubbo 线程池的阻塞。 + +### 2 使用AsyncContext + +Dubbo 提供了一个类似 Servlet 3.0 的异步接口AsyncContext,在没有 CompletableFuture 签名接口的情况下,也可以实现 Provider 端的异步执行。 + +接口定义: +```java +public interface AsyncService { + String sayHello(String name); +} + +``` + +服务实现: + +```java +public class AsyncServiceImpl implements AsyncService { + public String sayHello(String name) { + final AsyncContext asyncContext = RpcContext.startAsync(); + new Thread(() -> { + // 如果要使用上下文,则必须要放在第一句执行 + asyncContext.signalContextSwitch(); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + // 写回响应 + asyncContext.write("Hello " + name + ", response from provider."); + }).start(); + return null; + } +} + +``` + +## Consumer异步 + +### 1 使用CompletableFuture +```java +@DubboReference +private AsyncService asyncService; + +@Override +public void run(String... args) throws Exception { + //调用异步接口 + CompletableFuture future1 = asyncService.asyncInvoke("async call request1"); + future1.whenComplete((v, t) -> { + if (t != null) { + t.printStackTrace(); + } else { + System.out.println("AsyncTask Response-1: " + v); + } + }); + //两次调用并非顺序返回 + CompletableFuture future2 = asyncService.asyncInvoke("async call request2"); + future2.whenComplete((v, t) -> { + if (t != null) { + t.printStackTrace(); + } else { + System.out.println("AsyncTask Response-2: " + v); + } + }); + //consumer异步调用 + CompletableFuture future3 = CompletableFuture.supplyAsync(() -> { + return asyncService.invoke("invoke call request3"); + }); + future3.whenComplete((v, t) -> { + if (t != null) { + t.printStackTrace(); + } else { + System.out.println("AsyncTask Response-3: " + v); + } + }); + + System.out.println("AsyncTask Executed before response return."); +} +``` + +### 2 使用 RpcContext +在注解中配置: + +```java +@DubboReference(async="true") +private AsyncService asyncService; +``` + +也可以指定方法级别的异步配置: + +```java +@DubboReference(methods = {@Method(name = "sayHello", timeout = 5000)}) +private AsyncService asyncService; +``` + +接下来的调用即会是异步的: + +```java +// 此调用会立即返回null +asyncService.sayHello("world"); +// 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future +CompletableFuture helloFuture = RpcContext.getServiceContext().getCompletableFuture(); +// 为Future添加回调 +helloFuture.whenComplete((retValue, exception) -> { + if (exception == null) { + System.out.println(retValue); + } else { + exception.printStackTrace(); + } +}); +``` + +或者,也可以这样做异步调用 +```java +CompletableFuture future = RpcContext.getServiceContext().asyncCall( + () -> { + asyncService.sayHello("oneway call request1"); + } +); + +future.get(); +``` + +**异步总是不等待返回**,你也可以设置是否等待消息发出 +- `sent="true"` 等待消息发出,消息发送失败将抛出异常。 +- `sent="false"` 不等待消息发出,将消息放入 IO 队列,即刻返回。 + +```java +@DubboReference(methods = {@Method(name = "sayHello", timeout = 5000, sent = true)}) +private AsyncService asyncService; +``` + +如果你只是想异步,完全忽略返回值,可以配置 `return="false"`,以减少 Future 对象的创建和管理成本 +```java +@DubboReference(methods = {@Method(name = "sayHello", timeout = 5000, return = false)}) +private AsyncService asyncService; +``` + + diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/attachment.md b/content/en/overview/mannual/java-sdk/tasks/framework/attachment.md new file mode 100644 index 000000000000..56e11f64a8c0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/attachment.md @@ -0,0 +1,133 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/attachment/ + - /zh/overview/tasks/develop/context/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/attachment/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/context/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/attachment/ +description: 通过 Dubbo 中的 Attachment 在服务消费方和提供方之间隐式传递参数 +linkTitle: 传递附加参数 +title: 调用链路传递隐式参数 +type: docs +weight: 5 +--- + +在不修改方法签名与参数定义的情况下,可以通过 `RpcContext` 上的 `setAttachment` 和 `getAttachment` 在服务消费方和提供方之间进行参数的隐式传递。隐式参数传递支持以下两个方向: +* 从消费方到提供方,也就是在请求发起时,在方法参数之外通过 attachment 传递附加参数。 +* 从提供方到消费方,也就是在响应结果返回时,在响应结果之外通过 attachment 传递附加参数。 + +**理解隐式参数传递的最直接方式 http header,它的工作方式与 http header 完全一致,在 GET 或 POST 请求体之外可以传递任意多个 header 参数**。在实现原理上,对于不同的协议,attachment 的实现方式略有不同: +* 对于 triple 协议,attachment 会转换为标准的 http header 进行传输。 +* 对于 dubbo 协议,attachment 是编码在协议体的固定位置进行传输,具体请参见 dubbo 协议规范。 + +![/user-guide/images/context.png](/imgs/user/context.png) + +{{% alert title="注意" color="primary" %}} +* 在使用 triple 协议时,由于 http header 的限制,仅支持小写的 ascii 字符 +* path, group, version, dubbo, token, timeout 一些 key 是保留字段,传递 attachment 时应避免使用,尽量通过业务前缀等确保 key 的唯一性。 +{{% /alert %}} + +## 消费端隐式参数 +本文示例完整源码可在以下链接查看 [dubbo-samples-attachment](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-attachment) + +### 设置隐式参数 + +```java +RpcContext.getClientAttachment().setAttachment("index", "1"); // 隐式传参,后面的远程调用都会隐式将这些参数发送到服务器端,类似cookie,比如用于框架集成 +xxxService.xxx(); // 远程调用 +// ... +``` + +### 读取隐式参数 + +```java +public class XxxServiceImpl implements XxxService { + + public void xxx() { + // 获取客户端隐式传入的参数,比如用于框架集成 + String index = RpcContext.getServerAttachment().getAttachment("index"); + } +} +``` + +## 提供端隐式参数 + +### 设置隐式参数 + +```java +public class XxxServiceImpl implements XxxService { + + public void xxx() { + String index = xxx; + RpcContext.getServerContext().setAttachment("result", index); + } +} +``` + +### 读取隐式参数 + +```java +xxxService.xxx(); // 远程调用 +String result = RpcContext.getServerContext().getAttachment("result"); +// ... +``` + +{{% alert title="参数透传问题" color="warning" %}} +请注意!`setAttachment` 设置的 KV 对,在完成下面一次远程调用会被清空,即多次远程调用要多次设置!这一点与 Dubbo2 中的行为是不一致的! + +比如,对于 Dubbo2 而言,在 A 端设置的参数,调用 B 以后,如果 B 继续调用了 C,原来在 A 中设置的参数也会被带到 C 端过去(造成参数污染的问题)。对于 Dubbo3,B 调用 C 时的上下文是干净的,不会包含最开始在 A 中设置的参数。 + +Dubbo3 提供的了支持参数透传的能力。通过实现以下 SPI 用户可以自行指定需要透传的参数,`select` 的结果(可以从 RpcClientAttachment 获取当前所有参数)将作为需要透传的键值对传递到下一跳,如果返回 null 则表示不透传参数。 + +```java +@SPI +public interface PenetrateAttachmentSelector { + + /** + * Select some attachments to pass to next hop. + * These attachments can fetch from {@link RpcContext#getServerAttachment()} or user defined. + * + * @return attachment pass to next hop + */ + Map select(); + +} +``` +{{% /alert %}} + +{{% alert title="关于老版本 API" color="warning" %}} +老版本 Dubbo2 用户已经熟悉了使用 RpcContext 设置 attachment 隐式参数: + +```java +RpcContext.getContext().setAttachment("index", "1"); +String index = RpcContext.getContext().getAttachment("index"); +``` + +以上 RpcContext API 在 Dubbo3 中仍能正常工作。Dubbo3 之所以引入以上新版本 API 是为了支持提供端隐式参数、解决参数透传等问题,如果用户只是简单的使用消费端隐式参数,没有其他他书需求则可以继续使用老版本 RpcContext API。 + +{{% /alert %}} + +## 内部实现原理 + +上下文信息是 RPC 框架很重要的一个功能,使用 RpcContext 可以为单次调用指定不同配置。如分布式链路追踪场景,其实现原理就是在全链路的上下文中维护一个 traceId,Consumer 和 Provider 通过传递 traceId 来连接一次RPC调用,分别上报日志后可以在追踪系统中串联并展示完整的调用流程。这样可以更方便地发现异常、定位问题。 + +Dubbo 中的 RpcContext 是一个 ThreadLocal 的临时状态记录器,当接收到 RPC 请求,或发起 RPC 请求时,RpcContext 的状态都会变化。比如:**A 调 B,B 调 C,则 B 机器上,在 B 调 C 之前,RpcContext 记录的是 A 和 B 的信息,在 B 调 C 之后,RpcContext 记录的是 B 和 C 的信息。** + +因此,RpcContext 被拆分为四大模块(ServerContext、ClientAttachment、ServerAttachment 和 ServiceContext)。 + +它们分别承担了不同的职责: +- ServiceContext:在 Dubbo 内部使用,用于传递调用链路上的参数信息,如 invoker 对象等 +- ClientAttachment:在 Client 端使用,往 ClientAttachment 中写入的参数将被传递到 Server 端 +- ServerAttachment:在 Server 端使用,从 ServerAttachment 中读取的参数是从 Client 中传递过来的 +- ServerContext:在 Client 端和 Server 端使用,用于从 Server 端回传 Client 端使用,Server 端写入到 ServerContext 的参数在调用结束后可以在 Client 端的 ServerContext 获取到 + +![/imgs/v3/concepts/rpccontext.png](/imgs/v3/concepts/rpccontext.png) + +如上图所示,消费端发起调用的时候可以直接通过 Method Invoke 向远程的服务发起调用,同时消费端往 RpcClientAttachment 写入的数据会连同 Invoke 的参数信息写入到 Invocation 中。 +消费端的 Invocation 经过序列化后通过网络传输发送给服务端,服务端解析 Invocation 生成 Method Invoke 的参数和 RpcServerAttachment,然后发起真实调用。 +在服务端处理结束之后,Method Response 结果会连同 RpcServiceContext 一起生成 Result 对象。 +服务端的 Result 结果对象经过序列化后通过网络传输发送回消费端,消费端解析 Result 生成 Method Response 结果和 RpcServiceContext,返回真实调用结果和上下文给消费端。 + +1、Dubbo系统间调用时,想传递一些通用参数,可通过Dubbo提供的扩展如Filter等实现统一的参数传递 + +2、Dubbo系统间调用时,想传递接口定义之外的参数,可在调用接口前使用setAttachment传递参数。 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/fault-tolerent-strategy.md b/content/en/overview/mannual/java-sdk/tasks/framework/fault-tolerent-strategy.md new file mode 100644 index 000000000000..52b96762d6c4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/fault-tolerent-strategy.md @@ -0,0 +1,107 @@ +--- +aliases: + - /zh/docsv2.7/user/examples/fault-tolerent-strategy/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/fault-tolerent-strategy/ +description: 集群调用失败时,Dubbo 提供的容错方案 +linkTitle: 集群容错(重试) +title: 集群容错 +type: docs +weight: 8 +--- + +## 背景 +在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。 + +![cluster](/imgs/user/cluster.jpg) + +各节点关系: + +* 这里的 `Invoker` 是 `Provider` 的一个可调用 `Service` 的抽象,`Invoker` 封装了 `Provider` 地址及 `Service` 接口信息 +* `Directory` 代表多个 `Invoker`,可以把它看成 `List` ,但与 `List` 不同的是,它的值可能是动态变化的,比如注册中心推送变更 +* `Cluster` 将 `Directory` 中的多个 `Invoker` 伪装成一个 `Invoker`,对上层透明,伪装过程包含了容错逻辑,调用失败后,重试另一个 +* `Router` 负责从多个 `Invoker` 中按路由规则选出子集,比如读写分离,应用隔离等 +* `LoadBalance` 负责从多个 `Invoker` 中选出具体的一个用于本次调用,选的过程包含了负载均衡算法,调用失败后,需要重选 + +## 集群容错模式 + +可以自行扩展集群容错策略,参见:[集群扩展](../../../dev/impls/cluster) + +### Failover Cluster + +失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 `retries="2"` 来设置重试次数(不含第一次)。 + +重试次数配置如下: + +```xml + +``` + +或 + +```xml + +``` + +或 + +```xml + + + +``` + +{{% alert title="提示" color="primary" %}} +该配置为缺省配置 +{{% /alert %}} + +### Failfast Cluster + +快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。 + +### Failsafe Cluster + +失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。 + +### Failback Cluster + +失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。 + +### Forking Cluster + +并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 `forks="2"` 来设置最大并行数。 + +### Broadcast Cluster + +广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。 + +现在广播调用中,可以通过 broadcast.fail.percent 配置节点调用失败的比例,当达到这个比例后,BroadcastClusterInvoker +将不再调用其他节点,直接抛出异常。 broadcast.fail.percent 取值在 0~100 范围内。默认情况下当全部调用失败后,才会抛出异常。 +broadcast.fail.percent 只是控制的当失败后是否继续调用其他节点,并不改变结果(任意一台报错则报错)。broadcast.fail.percent 参数 +在 dubbo2.7.10 及以上版本生效。 + +Broadcast Cluster 配置 broadcast.fail.percent。 + +broadcast.fail.percent=20 代表了当 20% 的节点调用失败就抛出异常,不再调用其他节点。 + +```text +@reference(cluster = "broadcast", parameters = {"broadcast.fail.percent", "20"}) +``` + + +{{% alert title="提示" color="primary" %}} +`2.1.0` 开始支持 +{{% /alert %}} + +### 集群模式配置 + +按照以下示例在服务提供方和消费方配置集群模式 + +```xml + +``` + +或 + +```xml + +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/filter.md b/content/en/overview/mannual/java-sdk/tasks/framework/filter.md new file mode 100644 index 000000000000..9578e81a9e75 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/filter.md @@ -0,0 +1,136 @@ +--- +aliases: + - /zh/overview/tasks/develop/async/ + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/async-call/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-call/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-execute-on-provider/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async/ +description: 使用 Filter 过滤器动态拦截请求(request)或响应(response)以转换或使用请求或响应中包含的信息。 +linkTitle: Filter拦截器 +title: 使用 Filter 过滤器动态拦截请求(request)或响应(response) +type: docs +weight: 3 +--- + +Filter 过滤器动态拦截请求(request)或响应(response)以转换或使用请求或响应中包含的信息。过滤器本身通常不会创建响应,而是提供可以“附加”到任何一次 RPC 请求的通用函数。Dubbo Filter 是可插拔的,我们可以在一次 RPC 请求中插入任意类型的、任意多个 Filter。 + +Filter 工作原理如下图所示: + + + +可以通过 Filter 实现的一些典型能力如下: +* 记录请求参数、响应结果等到日志文件 +* 为 RPC 请求添加认证或校验逻辑 +* 在发送或执行请求之前,格式化请求体或 header 参数 +* 压缩响应结果 +* 对请求数据进行埋点,统计调用耗时、成功、失败次数等 +* 监测并发执行的请求数量,实现限流降级能力 + +## 使用方式 +如上图所示,Dubbo 代理会自动加载 Filter 实现并将它们组装到调用链路。Filter 是一个标准的 SPI 定义,框架按照一定的激活规则自动加载 Filter 实现。 + +```java +@SPI(scope = ExtensionScope.MODULE) +public interface Filter extends BaseFilter {} +``` + +Filter 的默认激活状态可在定义中通过 `@Activate` 注解设置,如以下定义表示该 Filter 在提供者端执行 RPC 请求时自动开启(在消费端不开启)。`@Activate` 支持多种条件控制,包括 classpath 下有某个类的定义时开启,URL 中有哪个参数值时开启等,具体可参见 [SPI 扩展 Activate 介绍]()。 + +```java +@Activate(group = PROVIDER) +public class AccessLogFilter implements Filter {} +``` + +### 关闭自动加载 +如想关闭某个 filter 加载,在不修改 Filter 定义的情况下,可通过以下几种配置关闭。 + +全局关闭 filter,所有 rpc 调用均不启用 filter +```yaml +dubbo: + consumer: + filter: "-accesslog,-tps" +``` + +某个服务调用过程不执行 filter +```java +@DubboReference(filter="-accesslog,-tps") +private DemoService demoService; +``` + +### 开启自动加载 +如想开启某个 filter 加载,在不修改 Filter 定义的情况下,可通过以下几种配置开启。 + +全局开启 filter,所有 rpc 调用均启用 filter +```yaml +dubbo: + consumer: + filter: "accesslog,tps" +``` + +某个服务调用过程执行该 filter +```java +@DubboReference(filter="accesslog,tps") +private DemoService demoService; +``` + +## 内置实现 +以下是 Dubbo 框架中内置的一些 Filter 实现,作为某些功能的底层实现原理,大部分情况下用户不需要关心这些 Filter 实现。这里列出来作为参考,方便用户了解如何开启某个特定功能,以及他们背后的工作原理: + + + +## 具体定义 +以下是关于 Filter 过滤器具体定义与实现的一些细节,对于扩展 Filter 的用户可作为参考。 + +### Filter定义 +Dubbo Filter 的定义如下: +```java +public interface BaseFilter { + /** + * Always call invoker.invoke() in the implementation to hand over the request to the next filter node. + */ + Result invoke(Invoker invoker, Invocation invocation) throws RpcException; + + /** + * This callback listener applies to both synchronous and asynchronous calls, please put logics that need to be executed + * on return of rpc result in onResponse or onError respectively based on it is normal return or exception return. + *

+ * There's something that needs to pay attention on legacy synchronous style filer refactor, the thing is, try to move logics + * previously defined in the 'finally block' to both onResponse and onError. + */ + interface Listener { + + /** + * This method will only be called on successful remote rpc execution, that means, the service in on remote received + * the request and the result (normal or exceptional) returned successfully. + */ + void onResponse(Result appResponse, Invoker invoker, Invocation invocation); + + /** + * This method will be called on detection of framework exceptions, for example, TimeoutException, NetworkException + * Exception raised in Filters, etc. + */ + void onError(Throwable t, Invoker invoker, Invocation invocation); + } +} +``` + +基于以上 BaseFilter 定义,Dubbo 定义了两个 SPI 接口:ClusterFilter 与 Filter。这两个 SPI 实现能实现的效果基本是一致的,之所以定义两个主要是出于性能优化考虑,建议用户关注 Filter SPI 即可,仅在有严苛性能需求的情况下(如集群 provider 提供者实例数量庞大)才关注 ClusterFilter。 + + + +```java +@SPI(scope = ExtensionScope.MODULE) +public interface Filter extends BaseFilter {} +``` + +```java +@SPI(scope = ExtensionScope.MODULE) +public interface ClusterFilter extends BaseFilter {} +``` + +### 扩展Filter + +可参考 [使用教程 - 自定义扩展]() 学习具体示例。 + + + diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/generic.md b/content/en/overview/mannual/java-sdk/tasks/framework/generic.md new file mode 100644 index 000000000000..125f609039fe --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/generic.md @@ -0,0 +1,149 @@ +--- +aliases: + - /zh/overview/tasks/develop/generic/ + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-reference/ + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-service/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-service/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-reference/ + - /zh-cn/overview/mannual/java-sdk/tasks/framework/more/generic/ +description: 泛化调用,用于在调用方没有服务方提供的 API(SDK)的情况下,对服务方进行调用 +linkTitle: 泛化调用 +title: 泛化调用 +type: docs +weight: 9 +--- + + {{% alert title="注意" color="warning" %}} + 泛化调用适用于老版本 dubbo 通信协议,如果您使用的是 3.3 及之后版本的 triple 协议,请直接使用 triple 自带的 http application/json 能力直接发起服务调用,相关示例可参考 [网关接入说明](/zh-cn/overview/mannual/java-sdk/tasks/gateway/triple/)。 + {{% /alert %}} + +泛化调用(客户端泛化调用)是指在调用方没有服务提供方 API(SDK)的情况下,对服务方进行调用,并且可以正常拿到调用结果。调用方没有接口及模型类元,知道服务的接口的全限定类名和方法名的情况下,可以通过泛化调用调用对应接口。 + +## 使用场景 + +泛化调用可通过一个通用的 GenericService 接口对所有服务发起请求。典型使用场景如下: + +1. 网关服务:如果要搭建一个网关服务,那么服务网关要作为所有 RPC 服务的调用端。但是网关本身不应该依赖于服务提供方的接口 API(这样会导致每有一个新的服务发布,就需要修改网关的代码以及重新部署),所以需要泛化调用的支持。 + +2. 测试平台:如果要搭建一个可以测试 RPC 调用的平台,用户输入分组名、接口、方法名等信息,就可以测试对应的 RPC 服务。那么由于同样的原因(即会导致每有一个新的服务发布,就需要修改网关的代码以及重新部署),所以平台本身不应该依赖于服务提供方的接口 API。所以需要泛化调用的支持。 + +## 使用方式 + +本示例的完整源码请参考 [dubbo-samples-generic-call](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-generic/dubbo-samples-generic-call/)。 + +示例中有以下 Dubbo 服务定义和实现 + +服务接口定义: + +```java +public interface HelloService { + String sayHello(String name); + CompletableFuture sayHelloAsync(String name); + CompletableFuture sayHelloAsyncComplex(String name); + CompletableFuture> sayHelloAsyncGenericComplex(String name); +} +``` + +服务具体实现并发布: + +```java +@DubboService +public class HelloServiceImpl implements HelloService { + + @Override + public String sayHello(String name) { + return "sayHello: " + name; + } + + @Override + public CompletableFuture sayHelloAsync(String name) { + // ... + } + + @Override + public CompletableFuture sayHelloAsyncComplex(String name) { + // ... + } + + @Override + public CompletableFuture> sayHelloAsyncGenericComplex(String name) { + // ... + } +} +``` + +### API 调用方式 + +针对以上 Dubbo 服务,我们可以通过泛化调用 API 直接发起调用。 + +```java +private GenericService genericService; + +public static void main(String[] args) throws Exception { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("generic-call-consumer"); + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("zookeeper://127.0.0.1:2181"); + + ReferenceConfig referenceConfig = new ReferenceConfig<>(); + referenceConfig.setInterface("org.apache.dubbo.samples.generic.call.api.HelloService"); + applicationConfig.setRegistry(registryConfig); + referenceConfig.setApplication(applicationConfig); + referenceConfig.setGeneric("true"); + // do not wait for result, 'false' by default + referenceConfig.setAsync(true); + referenceConfig.setTimeout(7000); + + genericService = referenceConfig.get(); +} + +public static void invokeSayHello() throws InterruptedException { + Object result = genericService.$invoke("sayHello", new String[]{"java.lang.String"}, new Object[]{"world"}); + CountDownLatch latch = new CountDownLatch(1); + + CompletableFuture future = RpcContext.getContext().getCompletableFuture(); + future.whenComplete((value, t) -> { + System.err.println("invokeSayHello(whenComplete): " + value); + latch.countDown(); + }); + + System.err.println("invokeSayHello(return): " + result); + latch.await(); +} +``` + +1. 在设置 `ReferenceConfig` 时,使用 `setGeneric("true")` 来开启泛化调用 +2. 配置完 `ReferenceConfig` 后,使用 `referenceConfig.get()` 获取到 `GenericService` 类的实例 +3. 使用其 `$invoke` 方法获取结果 +4. 其他设置与正常服务调用配置一致即可 + +### Spring 调用方式 +Spring 中服务暴露与服务发现有多种使用方式,如 xml,注解。这里以 xml 为例。 + +1. 生产者端无需改动 + +2. 消费者端原有的 `dubbo:reference` 标签加上 `generic=true` 的属性。 + +``` xml + +``` + +3. 获取到 Bean 容器,通过 Bean 容器拿到 `GenericService` 实例。 + +4. 调用 `$invoke` 方法获取结果 + +``` java + + private static GenericService genericService; + + public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/generic-impl-consumer.xml"); + context.start(); + //服务对应bean的名字由xml标签的id决定 + genericService = context.getBean("helloService"); + //获得结果 + Object result = genericService.$invoke("sayHello", new String[]{"java.lang.String"}, new Object[]{"world"}); + } +``` + diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/lightweight-rpc.md b/content/en/overview/mannual/java-sdk/tasks/framework/lightweight-rpc.md new file mode 100644 index 000000000000..56956e7b0809 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/lightweight-rpc.md @@ -0,0 +1,109 @@ +--- +description: 使用轻量的 Java SDK 开发 RPC Server 和 Client +linkTitle: Server与Client +title: 使用轻量的 Java SDK 开发 RPC Server 和 Client +type: docs +weight: 1 +--- +本示例演示如何使用轻量 Dubbo SDK 开发 RPC Server 与 Client,示例使用 Java Interface 方式定义、发布和访问 RPC 服务,底层使用 Triple 协议通信。本示例完整代码请参见 dubbo-samples。 + +基于 Dubbo 定义的 Triple 协议,你可以轻松编写浏览器、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。Dubbo Java SDK 支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 API 来发布或调用这些服务。 + +## Maven 依赖 + +在基于 Dubbo RPC 编码之前,您只需要在项目添加一个非常轻量的 `dubbo`依赖包即可,以 Maven 为例: +```xml + + org.apache.dubbo + dubbo + 3.3.0 + + + + +``` + +## 定义服务 + +定义一个名为 `DemoService`的标准 Java 接口作为 Dubbo 服务(Dubbo 还支持[基于 IDL 的服务定义模式](/zh-cn/overview/mannual/java-sdk/quick-start/))。 + +```java +public interface DemoService { + String sayHello(String name); +} +``` + +实现 `DemoService` 接口并编写业务逻辑代码。 + +```java +public class DemoServiceImpl implements DemoService { + @Override + public String sayHello(String name) { + return "Hello " + name + ", response from provider."; + } +} +``` + +## 注册服务并启动 Server + +启动 server 并在指定端口监听 RPC 请求,在此之前,我们向 server 注册了以下信息: + +- 使用 `Triple` 作为通信 RPC 协议与并监听端口 `50051` +- 注册 Dubbo 服务到 `DemoService` server + +```java +public class Application { + public static void main(String[] args) { + DubboBootstrap.getInstance() + .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051)) + .service(ServiceBuilder.newBuilder().ref(new DemoServiceImpl()).build()) + .start() + .await(); + } +} +``` + +## 访问服务 + +最简单方式是使用 HTTP/1.1 POST 请求访问服务,参数则以标准 JSON 格式作为 HTTP 负载传递。如下是使用 cURL 命令的访问示例: + +```shell +curl \ + --header "Content-Type: application/json" \ + --data '["Dubbo"]' \ + http://localhost:50051/org.apache.dubbo.demo.DemoService/sayHello +``` + +> 参数必须以数组格式进行传递,如果有多个参数,则格式类似 `["param1", {"param2-field": "param2-value"}, ...]`,具体请参见 triple 协议规范。 + +接下来,您也可以使用标准的 Dubbo client 请求服务,指定 server 地址即可发起 RPC 调用,其格式为 `protocol://ip:host` + +```java +public class Application { + public static void main(String[] args) { + DemoService demoService = + ReferenceBuilder.newBuilder() + .interfaceClass(DemoService.class) + .url("tri://localhost:50051") + .build() + .get(); + + String message = demoService.sayHello("dubbo"); + System.out.println(message); + } +} +``` + +恭喜您, 以上即是 Dubbo Java RPC 通信的基本使用方式! 🎉 + +## 更多内容 + +- Triple 协议完全兼容 gRPC,您可以参考这里了解如何 [使用 IDL 编写 gRPC 兼容的服务](/zh-cn/overview/mannual/java-sdk/quick-start/),或者 [使用其他通信协议]() +- 作为 RPC 框架,Dubbo 支持异步调用、连接管理、context上下文等,请参考 [RPC 框架核心功能]() +- 您可以继续 [使用 API 为应用添加更多微服务治理能力](),但我们更推进您使用 [Dubbo Spring Boot 开发微服务应用](../../microservice/develop/) diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/_index.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/_index.md new file mode 100755 index 000000000000..79d44c4720f4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/_index.md @@ -0,0 +1,9 @@ +--- +description: "Dubbo 是一款轻量的 RPC 框架,提供 Java、Go、Node.js、Javascript 等语言支持,帮助开发者构建浏览器、gRPC 兼容的 HTTP API。" +linkTitle: 更多特性 +title: Dubbo 作为轻量 RPC 框架解决组件通信问题 +type: docs +weight: 100 +--- + +{{% docs/section_list %}} \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/callback-parameter.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/callback-parameter.md new file mode 100644 index 000000000000..2c6ff26c124e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/callback-parameter.md @@ -0,0 +1,127 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/callback-parameter/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/callback-parameter/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/callback-parameter/ +description: 通过参数回调从服务器端调用客户端逻辑 +linkTitle: 服务端对客户端进行回调 +title: 服务端对客户端进行回调 +type: docs +weight: 9 +--- + + + + + +## 特性说明 +参数回调方式与调用本地 callback 或 listener 相同,只需要在 Spring 的配置文件中声明哪个参数是 callback 类型即可。Dubbo 将基于长连接生成反向代理,这样就可以从服务器端调用客户端逻辑。可以参考 [dubbo 项目中的示例代码](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-callback)。 + +## 使用场景 +回调函数通知客户端执行结果,或发送通知,在方法执行时间比较长时,类似异步调用,审批工作流中回调客户端审批结果。 + +## 使用方式 +### 服务接口示例 + +CallbackService.java +```java +package com.callback; + +public interface CallbackService { + void addListener(String key, CallbackListener listener); +} +``` + +CallbackListener.java +```java +package com.callback; + +public interface CallbackListener { + void changed(String msg); +} +``` + +### 服务提供者接口实现示例 + +```java +package com.callback.impl; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.callback.CallbackListener; +import com.callback.CallbackService; + +public class CallbackServiceImpl implements CallbackService { + + private final Map listeners = new ConcurrentHashMap(); + + public CallbackServiceImpl() { + Thread t = new Thread(new Runnable() { + public void run() { + while(true) { + try { + for(Map.Entry entry : listeners.entrySet()){ + try { + entry.getValue().changed(getChanged(entry.getKey())); + } catch (Throwable t) { + listeners.remove(entry.getKey()); + } + } + Thread.sleep(5000); // 定时触发变更通知 + } catch (Throwable t) { // 防御容错 + t.printStackTrace(); + } + } + } + }); + t.setDaemon(true); + t.start(); + } + + public void addListener(String key, CallbackListener listener) { + listeners.put(key, listener); + listener.changed(getChanged(key)); // 发送变更通知 + } + + private String getChanged(String key) { + return "Changed: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); + } +} +``` + +### 服务提供者配置示例 + +```xml + + + + + + + + +``` + +### 服务消费者配置示例 + +```xml + +``` + +### 服务消费者调用示例 + +```java +ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:consumer.xml"); +context.start(); + +CallbackService callbackService = (CallbackService) context.getBean("callbackService"); + +callbackService.addListener("foo.bar", new CallbackListener(){ + public void changed(String msg) { + System.out.println("callback1:" + msg); + } +}); +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/concurrency-control.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/concurrency-control.md new file mode 100644 index 000000000000..8c4d1764acff --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/concurrency-control.md @@ -0,0 +1,92 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/concurrency-control/ +description: Dubbo 中的并发控制 +linkTitle: 并发控制 +title: 并发控制 +type: docs +weight: 28 +--- + + +## 功能说明 +多种并发控制功能,帮助用户管理其应用程序和服务。 + +## 使用场景 +限制从同一客户端到同一服务的并发请求数,防止恶意请求使服务器过载,确保服务的稳定性,并防止使用过多资源。 + +控制某些服务的最大并发请求数,确保其他服务的资源可用性。系统过载和确保系统稳定性。 + +允许在需求增加时更平滑地扩展服务。 + +确保服务在高峰使用时间保持可靠和稳定。 + +这种方式要求用户准确的预先评估系统能处理的并发数,而准确的评估系统处理能力并不是一件容易的事情,因此 Dubbo 还提供了自适应限流模式,根据系统负载自动识别系统健康程度并进行限流保护,可以在此 [查看使用文档](../adaptive-concurrency-control)。 + +## 使用方式 +### 样例一 + +> 限制 `com.foo.BarService` 的每个方法,服务器端并发执行(或占用线程池线程数)不能超过 10 个 + +```xml + +``` + +### 样例二 + +> 限制 `com.foo.BarService` 的 `sayHello` 方法,服务器端并发执行(或占用线程池线程数)不能超过 10 个 + +```xml + + + +``` +### 样例三 + +> 限制 `com.foo.BarService` 的每个方法,每客户端并发执行(或占用连接的请求数)不能超过 10 个 + +```xml + +``` + +**或** + +```xml + +``` + +### 样例四 + +> 限制 `com.foo.BarService` 的 `sayHello` 方法,每客户端并发执行(或占用连接的请求数)不能超过 10 个 + +```xml + + + +``` + +或 + +```xml + + + +``` + +> 如果 `` 和 `` 都配了actives,`` 优先,参见:[配置的覆盖策略](/zh-cn/overview/mannual/java-sdk/reference-manual/config/principle/)。 + +### Load Balance 均衡 + +配置服务的客户端的 `loadbalance` 属性为 `leastactive`,此 Loadbalance 会调用并发数最小的 Provider(Consumer端并发数)。 + +```xml + +``` + +**或** + +```xml + +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/config-connections.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/config-connections.md new file mode 100644 index 000000000000..d7d0fa5d650e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/config-connections.md @@ -0,0 +1,104 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/config-connections/ + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/stickiness/ + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/lazy-connect/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/config-connections/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/stickiness/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/lazy-connect/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/config-connections/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/config-connections/ +description: Dubbo 中服务端和客户端的连接控制 +linkTitle: 连接控制 +title: 连接控制 +type: docs +weight: 29 +--- + + + + + +## 功能说明 +连接控制功能可以使用户能够控制和管理进出服务器连接数,限制连接数并设置超时,以确保 Dubbo 系统的稳定性和性能,还允许用户根据 IP 地址、端口和协议配置不同级别的访问控制,保护系统免受恶意流量的影响,并降低服务中断的风险,此外提供了一种监视当前流量和连接状态的方法。 + +## 使用场景 +1. 服务器过载时减少连接数:当服务器过载时,使用 Dubbo 通过设置最大连接限制来减少连接数减少服务器上的负载并防止其崩溃。 +2. 减少服务器受到攻击时的连接数:Dubbo 可以限制服务器受到攻击的连接数防止恶意连接充斥服务器并导致服务器崩溃。 +3. 限制特定服务的连接数:Dubbo 可以限制特定服务连接数防止服务过载过多的请求并确保及时响应所有请求。 +4. 限制来自单个IP地址的连接数:Dubbo 可以限制来自单个地址的连接数降低来自单个IP地址的恶意活动的风险。 + +## 使用方式 +### 服务端连接控制 + +限制服务器端接受的连接不能超过 10 个 [^1]: + +```xml + +``` + +或 + +```xml + +``` + +### 客户端连接控制 + +限制客户端服务使用连接不能超过 10 个 [^2]: + +```xml + +``` + +或 + +```xml + +``` + +如果 `` 和 `` 都配了 connections,`` 优先,参见:[配置的覆盖策略](/zh-cn/overview/mannual/java-sdk/reference-manual/config/principle/) + +[^1]: 因为连接在 Server上,所以配置在 Provider 上 +[^2]: 如果是长连接,比如 Dubbo 协议,connections 表示该服务对每个提供者建立的长连接数 + + + + +## 功能说明 +允许消费者在提供者接收请求之前向提供者发送请求,消费者等待提供者准备就绪,然后将发送消费者者的请求,当消费者需要连接到提供者,提供者尚未准备好接受请求时,确保在正确的时间发送请求,防止消费者被速度慢或不可用的提供程序阻止。 + +## 使用场景 +粘滞连接用于有状态服务,尽可能让客户端总是向同一提供者发起调用,除非该提供者挂了,再连另一台。 + +粘滞连接将自动开启 [延迟连接](../lazy-connect),以减少长连接数。 + +## 使用方式 +```xml + +``` + +Dubbo 支持方法级别的粘滞连接,如果你想进行更细粒度的控制,还可以这样配置。 + +```xml + + + +``` + + + + + +## 功能说明 +当消费者请求服务时,实际使用服务时才建立真正的连接,避免不必要的连接来减少延迟并提高系统稳定性。 + +## 使用场景 +延迟连接用于减少长连接数。当有调用发起时,再创建长连接。 + +## 使用方式 +```xml + +``` + +> 该配置只对使用长连接的 dubbo 协议生效。 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/echo-service.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/echo-service.md new file mode 100644 index 000000000000..9e727ce84040 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/echo-service.md @@ -0,0 +1,41 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/echo-service/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/echo-service/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/echo-service/ +description: 通过回声测试检测 Dubbo 服务是否可用 +linkTitle: 回声测试 +title: 回声测试 +type: docs +weight: 3 +--- + + + +## 特性说明 +回声测试用于检测服务是否可用,回声测试按照正常请求流程执行,能够测试整个调用是否通畅,可用于监控。执行回声测试,客户端发送一个包含特定值(如字符串)的请求。服务器应使用相同的值进行响应,从而验证请求是否已成功接收和处理。如果响应与请求不匹配,则表示服务运行不正常,应进一步调查。要求 Dubbo 服务器正在运行,并且服务器和客户端之间具有网络连接。在客户端,必须配置 Dubbo 客户端以连接到服务器,客户端将向服务器发送请求,然后服务器应返回与请求相同的响应。 + + +## 使用场景 +测试验证是否可以调用服务以及响应是否正确,对于在尝试在生产环境中使用服务之前验证服务特别有用。 +echo 测试是验证 Dubbo 服务基本功能的一种简单有效的方法,在将服务部署到生产环境之前执行此测试非常重要,以确保服务按预期工作。 + +## 使用方式 + +本示例完整源码请参考 [dubbo-samples-echo](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-echo)。 + +所有服务自动实现 `EchoService` 接口,只需将任意服务引用强制转型为 `EchoService`,即可使用。 + +如有以下 Dubbo proxy 实例: + +```java +@DubboReference +private DemoService demoService; +``` + +### 代码示例 +```java +EchoService echoService = (EchoService) demoService; + +String status = (String) echoService.$echo("OK"); +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/events-notify.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/events-notify.md new file mode 100644 index 000000000000..7cd69d3dc947 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/events-notify.md @@ -0,0 +1,113 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/events-notify/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/events-notify/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/events-notify/ +description: 在调用前后出现异常时的事件通知 +linkTitle: 调用触发事件通知 +title: 调用触发事件通知 +type: docs +weight: 8 +--- + +## 特性说明 +在调用之前、调用之后、出现异常时,会触发 `oninvoke`、`onreturn`、`onthrow` 三个事件,可以配置当事件发生时,通知哪个类的哪个方法。 + + +## 使用场景 + +调用服务方法前我们可以记录开始时间,调用结束后统计整个调用耗费,发生异常时我们可以告警或打印错误日志或者调用服务前后记录请求日志、响应日志等。 + +>参考用例 +[dubbo-samples-notify](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-notify) + +## 使用方式 + +### 服务提供者与消费者共享服务接口 + +```java +interface IDemoService { + public Person get(int id); +} +``` +### 服务提供者实现 + +```java +class NormalDemoService implements IDemoService { + public Person get(int id) { + return new Person(id, "charles`son", 4); + } +} +``` + +### 服务提供者配置 + +```xml + + + + +``` +### 服务消费者 Callback 接口 + +```java +interface Notify { + public void onreturn(Person msg, Integer id); + public void onthrow(Throwable ex, Integer id); +} +``` + +### 服务消费者 Callback 实现 + +```java +class NotifyImpl implements Notify { + public Map ret = new HashMap(); + public Map errors = new HashMap(); + + public void onreturn(Person msg, Integer id) { + System.out.println("onreturn:" + msg); + ret.put(id, msg); + } + + public void onthrow(Throwable ex, Integer id) { + errors.put(id, ex); + } +} +``` + +### 服务消费者 Callback 配置 + +两者叠加存在以下几种组合情况: + +* 异步回调模式:`async=true onreturn="xxx"` +* 同步回调模式:`async=false onreturn="xxx"` +* 异步无回调 :`async=true` +* 同步无回调 :`async=false` + +`callback` 与 `async` 功能正交分解,`async=true` 表示结果是否马上返回,`async=false` 默认,`onreturn` 表示是否需要回调。 +```xml + + + + +``` + + +### 测试代码 + +```java +IDemoService demoService = (IDemoService) context.getBean("demoService"); +NotifyImpl notify = (NotifyImpl) context.getBean("demoCallback"); +int requestId = 2; +Person ret = demoService.get(requestId); +Assert.assertEquals(null, ret); +//for Test:只是用来说明callback正常被调用,业务具体实现自行决定. +for (int i = 0; i < 10; i++) { + if (!notify.ret.containsKey(requestId)) { + Thread.sleep(200); + } else { + break; + } +} +Assert.assertEquals(requestId, notify.ret.get(requestId).getId()); +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/explicit-target.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/explicit-target.md new file mode 100644 index 000000000000..68441fa858f5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/explicit-target.md @@ -0,0 +1,70 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/explicit-target/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/explicit-target/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/explicit-target/ +description: Dubbo 中点对点的直连方式 +linkTitle: 直连提供者 +title: 直连提供者 +type: docs +weight: 5 +--- + + +在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,点对点直连方式,将以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点对点,不影响 B 接口从注册中心获取列表。 + +![/user-guide/images/dubbo-directly.jpg](/imgs/user/dubbo-directly.jpg) + +如果是线上需求需要点对点,可在 `reference` 节点中配置 url 指向提供者,将绕过注册中心,多个地址用分号隔开,配置如下: + +## 注解配置方式 + +```java +@DubboReference(url="tri://localhost:50051") +private XxxService xxxService +``` + +## xml配置方式 + +```xml + +``` + +## 更多配置方式 +{{% alert title="注意" color="warning" %}} +请注意以下配置方式是为了兼容老版本 Dubbo2 而保留,在部分 Dubbo3 版本中可能存在问题,请尽量使用文档前面推荐的配置方式。 +{{% /alert %}} + +### 通过 -D 参数指定 + +在 JVM 启动参数中加入-D参数映射服务地址,如: + +```sh +java -Dcom.alibaba.xxx.XxxService=dubbo://localhost:20890 +``` + +{{% alert title="提示" color="primary" %}} +key 为服务名,value 为服务提供者 url,此配置优先级最高,`1.0.15` 及以上版本支持 +{{% /alert %}} + +### 通过文件映射 + +如果服务比较多,也可以用文件映射,用 `-Ddubbo.resolve.file` 指定映射文件路径,此配置优先级高于 `` 中的配置 [^3],如: + +```sh +java -Ddubbo.resolve.file=xxx.properties +``` + +然后在映射文件 `xxx.properties` 中加入配置,其中 key 为服务名,value 为服务提供者 URL: + +```properties +com.alibaba.xxx.XxxService=dubbo://localhost:20890 +``` + +{{% alert title="提示" color="primary" %}} +`1.0.15` 及以上版本支持,`2.0` 以上版本自动加载 ${user.home}/dubbo-resolve.properties文件,不需要配置 +{{% /alert %}} + +{{% alert title="注意" color="warning" %}} +为了避免复杂化线上环境,不要在线上使用这个功能,只应在测试阶段使用。 +{{% /alert %}} diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/generic-impl.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/generic-impl.md new file mode 100644 index 000000000000..21fa093de477 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/generic-impl.md @@ -0,0 +1,78 @@ +--- +aliases: + - /zh/overview/tasks/develop/generic/ + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-reference/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-reference/ +description: 泛化实现,用于在提供方没有 API(SDK)的情况下,对外提供和发布服务 +linkTitle: 泛化实现 +title: 泛化实现 +type: docs +weight: 1 +--- + +{{% alert title="注意" color="warning" %}} +请注意区分上一篇文档介绍的 [泛化调用](../generic),泛化调用是给消费端用的,而泛化实现是给提供端用的。 +{{% /alert %}} + +泛接口实现方式主要用于服务器端没有 API 接口及模型类元的情况,参数及返回值中的所有 POJO 均用 Map 表示,通常用于框架集成,比如:实现一个通用的远程服务 Mock 框架,可通过实现 GenericService 接口处理所有服务请求。 + +## 使用场景 +* 注册服务: 服务提供者在服务注册表中注册服务,例如 Zookeeper,服务注册表存储有关服务的信息,例如其接口、实现类和地址。 + +* 部署服务: 服务提供商将服务部署在服务器并使其对消费者可用。 + +* 调用服务: 使用者使用服务注册表生成的代理调用服务,代理将请求转发给服务提供商,服务提供商执行服务并将响应发送回消费者。 + +* 监视服务:提供者和使用者可以使用 Dubbo 框架监视服务,允许他们查看服务的执行情况,并在必要时进行调整。 + + +## 使用方式 +本示例的完整源码请参考 [dubbo-samples-generic-impl](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-generic/dubbo-samples-generic-impl/)。 + +在 Java 代码中实现 `GenericService` 接口 + +```java +package com.foo; +public class MyGenericService implements GenericService { + + public Object $invoke(String methodName, String[] parameterTypes, Object[] args) throws GenericException { + if ("sayHello".equals(methodName)) { + return "Welcome " + args[0]; + } + } +} +``` + +### 通过 Spring 暴露泛化实现 + +在 Spring XML 配置申明服务的实现 + +```xml + + +``` + +### 通过 API 方式暴露泛化实现 + +```java +... +// 用org.apache.dubbo.rpc.service.GenericService可以替代所有接口实现 +GenericService xxxService = new XxxGenericService(); + +// 该实例很重量,里面封装了所有与注册中心及服务提供方连接,请缓存 +ServiceConfig service = new ServiceConfig(); +// 弱类型接口名 +service.setInterface("com.xxx.XxxService"); +// if you need to set different version for service +service.setVersion("1.0.0"); +// 指向一个通用服务实现 +service.setRef(xxxService); + +// 暴露及注册服务 +service.export(); +``` + +1. 在设置 `ServiceConfig` 时,使用`setGeneric("true")`来开启泛化调用 +2. 在设置 `ServiceConfig` 时,使用 setRef 指定实现类时,要设置一个 `GenericService` 的对象。而不是真正的服务实现类对象 +3. 其他设置与正常 Api 服务启动一致即可 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/local-call.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/local-call.md new file mode 100644 index 000000000000..07e3c9afb6d2 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/local-call.md @@ -0,0 +1,82 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/local-call/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/local-call/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/local-call/ +description: 在 Dubbo 中进行本地调用 +linkTitle: 本地调用 +title: 本地调用 +type: docs +weight: 22 +--- + +## 特性说明 +本地调用使用了 injvm 协议,是一个伪协议,它不开启端口,不发起远程调用,只在 JVM 内直接关联,但执行 Dubbo 的 Filter 链。 + +## 使用场景 + +当我们需要调用远程服务时,远程服务并没有开发完成,使用 injvm 协议在本地实现类似服务,调用此服务时可以调用我们本地的实现服务。 + +## 使用方式 + +### 定义 injvm 协议 +```xml + +``` + +### 设置默认协议 + +```xml + +``` + +### 设置服务协议 + +```xml + +``` + +### 优先使用 injvm + +```xml + + +``` + +**或** + +```xml + + +``` + +{{% alert title="注意" color="warning" %}} +**Dubbo 从 `2.2.0` 每个服务默认都会在本地暴露,无需进行任何配置即可进行本地引用,如果不希望服务进行远程暴露,只需要在 provider 将 protocol 设置成 injvm 即可。** +{{% /alert %}} + + +### 自动暴露 + +从 `2.2.0` 开始,每个服务默认都会在本地暴露。在引用服务的时候,默认优先引用本地服务。如果希望引用远程服务可以使用一下配置强制引用远程服务。 + +```xml + +``` + + +### 动态配置调用行为 + +从`3.2`开始,Dubbo提供api可以让用户在使用中动态地去配置单一次调用时为本地调用或者远程调用,当没配置的时候将默认优先引用本地服务 + +**配置单一次调用为远程调用** + +```java +RpcContext.getServiceContext().setLocalInvoke(false); +``` + +**配置单一次调用为本地调用** + +```java +RpcContext.getServiceContext().setLocalInvoke(true); +``` + diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/local-mock.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/local-mock.md new file mode 100644 index 000000000000..812828e7b0bf --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/local-mock.md @@ -0,0 +1,193 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/local-mock/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/local-mock/ + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/local-mock/ +description: 了解如何在 Dubbo 中利用本地伪装实现服务降级 +linkTitle: 服务降级 +title: 服务讲解(本地伪装) +type: docs +weight: 10 +--- + +## 特性说明 + +在 Dubbo3 中有一种机制可以实现轻量级的服务降级,也就是本地伪装。 + +Mock 是 Stub 的一个子集,便于服务提供方在客户端执行容错逻辑,因经常需要在出现 RpcException (比如网络失败,超时等)时进行容错,而在出现业务异常(比如登录用户名密码错误)时不需要容错, +如果用 Stub,可能就需要捕获并依赖 RpcException 类,而用 Mock 就可以不依赖 RpcException,因为它的约定就是只有出现 RpcException 时才执行。 + +## 使用场景 + +本地伪装常被用于服务降级。比如某验权服务,当服务提供方全部挂掉后,假如此时服务消费方发起了一次远程调用,那么本次调用将会失败并抛出一个 `RpcException` 异常。为了避免出现这种直接抛出异常的情况出现,那么客户端就可以利用本地伪装来提供 Mock 数据返回授权失败。 + +其他使用场景包括: +- 某服务或接口负荷超出最大承载能力范围,需要进行降级应急处理,避免系统崩溃 +- 调用的某非关键服务或接口暂时不可用时,返回模拟数据或空,业务还能继续可用 +- 降级非核心业务的服务或接口,腾出系统资源,尽量保证核心业务的正常运行 +- 某上游基础服务超时或不可用时,执行能快速响应的降级预案,避免服务整体雪崩 + +## 使用方式 + +完整示例源码请参见 [dubbo-samples-mock](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-mock) + +### 开启 Mock 配置 + +在 Spring XML 配置文件中按以下方式配置: + +```xml + +``` + +或 + +```xml + +``` + +在工程中提供 Mock 实现 [^2]: +在 interface 旁放一个 Mock 实现,它实现 BarService 接口,并有一个无参构造函数。同时,如果没有在配置文件中显式指定 Mock 类的时候,那么需要保证 Mock 类的全限定类名是 `原全限定类名+Mock` 的形式,例如 `com.foo.BarServiceMock`,否则将会 Mock 失败。 +```java +package com.foo; +public class BarServiceMock implements BarService { + public String sayHello(String name) { + // 你可以伪造容错数据,此方法只在出现RpcException时被执行 + return "容错数据"; + } +} +``` + +### 使用 return 关键字 Mock 返回值 + +使用 `return` 来返回一个字符串表示的对象,作为 Mock 的返回值。合法的字符串可以是: +- *empty*:代表空,返回基本类型的默认值、集合类的空值、自定义实体类的空对象,如果返回值是一个实体类,那么此时返回的将会是一个属性都为默认值的空对象而不是 `null`。 +- *null*:返回 `null` +- *true*:返回 `true` +- *false*:返回 `false` +- *JSON 字符串*:返回反序列化 JSON 串后所得到的对象 + +举个例子,如果服务的消费方经常需要 try-catch 捕获异常,如: + +```java +public class DemoService { + + public Offer findOffer(String offerId) { + Offer offer = null; + try { + offer = offerService.findOffer(offerId); + } catch (RpcException e) { + logger.error(e); + } + + return offer; + } +} +``` + +那么请考虑改为 Mock 实现,并在 Mock 实现中 `return null`。如果只是想简单的忽略异常,在 `2.0.11` 以上版本可用: + +```xml + +``` + +### 使用 throw 关键字 Mock 抛出异常 + +使用 `throw` 来返回一个 Exception 对象,作为 Mock 的返回值。 + +当调用出错时,抛出一个默认的 RPCException: + +```xml + + +``` + +当调用出错时,抛出指定的 Exception: + +自定义异常必须拥有一个入参为 `String` 的构造函数,该构造函数将用于接受异常信息。 +```xml + + +``` + +### 使用 force 和 fail 关键字来配置 Mock 的行为 + +`force:` 代表强制使用 Mock 行为,在这种情况下不会走远程调用。 + +`fail:` 与默认行为一致,只有当远程调用发生错误时才使用 Mock 行为。也就是说,配置的时候其实是可以不使用 `fail` 关键字的,直接使用 `throw` 或者 `return` 就可以了。 + +`force:` 和 `fail:` 都支持与 `throw` 或者 `return` 组合使用。 + +强制返回指定值: + +```xml + + +``` + +强制抛出指定异常: + +```xml + + +``` + +调用失败时返回指定值: +```xml + + + + + +``` + +调用失败时抛出异常 + +```xml + + + + + +``` + +### 在方法级别配置 Mock + +Mock 可以在方法级别上指定,假定 `com.foo.BarService` 上有好几个方法,我们可以单独为 `sayHello()` 方法指定 Mock 行为。 + +具体配置如下所示,在本例中,只要 `sayHello()` 被调用到时,强制返回 "fake": + +```xml + + + + +``` + +### 配合 dubbo-admin 使用 + +* 应用消费端引入 `dubbo-mock-admin`依赖 + +* 应用消费端启动时设置 JVM 参数,`-Denable.dubbo.admin.mock=true` + +* 启动 dubbo-admin,在服务 Mock-> 规则配置菜单下设置 Mock 规则 + +以服务方法的维度设置规则,设置返回模拟数据,动态启用/禁用规则 + + +### 使用专业限流组件 + +如果您有更高级、专业的限流诉求,我们推荐使用专业的限流降级组件如 [Sentinel](https://sentinelguard.io/zh-cn/docs/open-source-framework-integrations.html),以达到最佳体验。参考示例实践:[微服务治理/限流降级](/zh-cn/overview/mannual/java-sdk/tasks/rate-limit/) + +服务降级是指服务在非正常情况下进行降级应急处理。 + + +{{% alert title="注意事项" color="primary" %}} + +Dubbo 启动时会检查配置,当 mock 属性值配置有误时会启动失败,可根据错误提示信息进行排查 + +- 配置格式错误,如 `return+null` 会报错,被当做 mock 类型处理,`return` 后面可省略不写或者跟空格后再跟返回值 +- 类型找不到错误,如自定义 mock 类、throw 自定义异常,请检查类型是否存在或是否有拼写错误 +{{% /alert %}} + diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/local-stub.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/local-stub.md new file mode 100644 index 000000000000..ed48ef9e9560 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/local-stub.md @@ -0,0 +1,63 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/local-stub/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/local-stub/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/local-stub/ +description: 了解 Dubbo 中本地存根在客户端执行部分逻辑的使用 +linkTitle: 本地存根 +title: 本地存根 +type: docs +weight: 11 +--- + +## 特性说明: + +远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑。 + +![/user-guide/images/stub.jpg](/imgs/user/stub.jpg) + +## 使用场景 +做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub [^1],然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。 + +## 使用方式 + +完整示例源码请参见 [dubbo-samples-stub](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-stub) + +### spring 配置文件配置 + +```xml + +``` + +或 + +```xml + +``` + +### 提供 Stub 的实现 [^2] + +```java +package com.foo; +public class BarServiceStub implements BarService { + private final BarSer vice barService; + + // 构造函数传入真正的远程代理对象 + public BarServiceStub(BarService barService){ + this.barService = barService; + } + + public String sayHello(String name) { + // 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等 + try { + return barService.sayHello(name); + } catch (Exception e) { + // 你可以容错,可以做任何AOP拦截事项 + return "容错数据"; + } + } +} +``` + +[^1]: Stub 必须有可传入 Proxy 的构造函数。 +[^2]: 在 interface 旁边放一个 Stub 实现,它实现 BarService 接口,并有一个传入远程 BarService 实例的构造函数。 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/parameter-validation.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/parameter-validation.md new file mode 100644 index 000000000000..13b6fb2f51bf --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/parameter-validation.md @@ -0,0 +1,200 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/parameter-validation/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/parameter-validation/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/parameter-validation/ +description: 在 Dubbo 中进行参数校验 +linkTitle: 参数校验 +title: 参数校验 +type: docs +weight: 100 +--- + +## 特性说明 +参数验证功能是基于 [JSR303](https://jcp.org/en/jsr/detail?id=303) 实现的,用户只需标识 JSR303 标准的验证 annotation,并通过声明 filter 来实现验证。 + +#### Maven 依赖 + +```xml + + javax.validation + validation-api + 1.0.0.GA + + + org.hibernate + hibernate-validator + 4.2.0.Final + +``` + +## 使用场景 + +服务端在向外提供接口服务时,解决各种接口参数校验问题。 + +> 参考用例 +[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-validation](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-validation) + +## 使用方式 + +### 参数标注示例 + +```java +import java.io.Serializable; +import java.util.Date; + +import javax.validation.constraints.Future; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Past; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; + +public class ValidationParameter implements Serializable { + private static final long serialVersionUID = 7158911668568000392L; + + @NotNull // 不允许为空 + @Size(min = 1, max = 20) // 长度或大小范围 + private String name; + + @NotNull(groups = ValidationService.Save.class) // 保存时不允许为空,更新时允许为空 ,表示不更新该字段 + @Pattern(regexp = "^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$") + private String email; + + @Min(18) // 最小值 + @Max(100) // 最大值 + private int age; + + @Past // 必须为一个过去的时间 + private Date loginDate; + + @Future // 必须为一个未来的时间 + private Date expiryDate; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public Date getLoginDate() { + return loginDate; + } + + public void setLoginDate(Date loginDate) { + this.loginDate = loginDate; + } + + public Date getExpiryDate() { + return expiryDate; + } + + public void setExpiryDate(Date expiryDate) { + this.expiryDate = expiryDate; + } +} +``` + +### 分组验证示例 + +```java +public interface ValidationService { // 缺省可按服务接口区分验证场景,如:@NotNull(groups = ValidationService.class) + @interface Save{} // 与方法同名接口,首字母大写,用于区分验证场景,如:@NotNull(groups = ValidationService.Save.class),可选 + void save(ValidationParameter parameter); + void update(ValidationParameter parameter); +} +``` + +### 关联验证示例 + +```java +import javax.validation.GroupSequence; + +public interface ValidationService { + @GroupSequence(Update.class) // 同时验证Update组规则 + @interface Save{} + void save(ValidationParameter parameter); + + @interface Update{} + void update(ValidationParameter parameter); +} +``` + +### 参数验证示例 + +```java +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public interface ValidationService { + void save(@NotNull ValidationParameter parameter); // 验证参数不为空 + void delete(@Min(1) int id); // 直接对基本类型参数验证 +} +``` + +### 在客户端验证参数 + +```xml + +``` + +### 在服务器端验证参数 + +```xml + +``` + +> **Dubbo 默认支持 hibernate-validator 版本 <=6.x,若使用 hibernate-validator 7.x 版本,请将 validation 参数声明为 jvalidationNew** + +### 验证异常信息 + +```java +import javax.validation.ConstraintViolationException; +import javax.validation.ConstraintViolationException; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import org.apache.dubbo.examples.validation.api.ValidationParameter; +import org.apache.dubbo.examples.validation.api.ValidationService; +import org.apache.dubbo.rpc.RpcException; + +public class ValidationConsumer { + public static void main(String[] args) throws Exception { + String config = ValidationConsumer.class.getPackage().getName().replace('.', '/') + "/validation-consumer.xml"; + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(config); + context.start(); + ValidationService validationService = (ValidationService)context.getBean("validationService"); + // Error + try { + parameter = new ValidationParameter(); + validationService.save(parameter); + System.out.println("Validation ERROR"); + } catch (RpcException e) { // 抛出的是RpcException + ConstraintViolationException ve = (ConstraintViolationException) e.getCause(); // 里面嵌了一个ConstraintViolationException + Set> violations = ve.getConstraintViolations(); // 可以拿到一个验证错误详细信息的集合 + System.out.println(violations); + } + } +} +``` + +> **验证方式可扩展,扩展方式参见开发者手册中的 [验证扩展](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/validation)** diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/reactive.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/reactive.md new file mode 100644 index 000000000000..edf3d626596c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/reactive.md @@ -0,0 +1,241 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/reactive/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/reactive/ +description: 使用 Reactive API 操作 Triple 流式调用 +linkTitle: 响应式编程 +title: 响应式编程 +type: docs +weight: 100 +--- + +{{% alert title="过时风险提醒" color="warning" %}} +请注意,本文档描述的 Reactive 响应式使用方法可能存在过时的情况,请随时参考 apache/dubbo-samples 中的最新 reactive 示例了解用法。 +{{% /alert %}} + +## 特性说明 + +此特性基于 Triple 协议和 Project Reactor 实现,`3.1.0` 版本以上支持。用户仅需编写 IDL 文件,并指定 protobuf 插件的相应 Generator,即可生成并使用支持响应式API的 Stub 代码。 + +有四种调用模式,分别是 OneToOne、OneToMany、ManyToOne、ManyToMany,分别对应 Unary调用、服务端流、客户端流、双向流。在 Reactor 的实现中,One 对应 Mono,Many 对应 Flux。 + + + +Reactive Stream 提供了一套标准的异步流处理 API, 在能够让应用写出事件驱动的程序的同时,也通过 BackPressure 的方式保证了节点的稳定。Triple 协议在通信协议层面为 Dubbo 框架增加了流式场景的支持,在此基础上能够实现上层包括大文件传输和推送机制的业务需求。 + +Dubbo + Reactive Stream Stub 的组合模式可以给用户带来最方便的流式使用方式以及全链路异步性能提升。 + +> 参考用例 +[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-triple-reactor](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple-reactor) + +## 使用场景 + +系统需要处理大量并发请求而不会使任何服务器过载。大量用户提供实时数据的系统,希望确保系统能够处理负载而不会崩溃或变慢。 + +## 使用方式 + +Triple 使用及配置可参考 [IDL 方式使用 Triple](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/idl/),并确保 Dubbo 版本 >= 3.1.0。 + +### 添加必要的依赖 + +若要使用 Reactor Triple,需要额外添加如下依赖。 + +```xml + + org.reactivestreams + reactive-streams + + + io.projectreactor + reactor-core + +``` + +### 设置 protobuf Maven 插件 + +仅需将 mainClass 修改为 `org.apache.dubbo.gen.tri.reactive.ReactorDubbo3TripleGenerator`,并确保 `${compiler.version}` >= 3.1.0 + +```xml + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.6.1 + + com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} + + grpc-java + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} + + + + dubbo + org.apache.dubbo + dubbo-compiler + ${compiler.version} + org.apache.dubbo.gen.tri.reactive.ReactorDubbo3TripleGenerator + + + + + + + compile + + + + + + +``` + +### 编写并编译 IDL 文件 + +IDL 文件编写与原生的 Triple 协议完全一致,编译后默认会在 `target/generated-sources/protobuf/java` 目录下看到相应代码。 + +```protobuf +syntax = "proto3"; + +option java_multiple_files = true; + +package org.apache.dubbo.samples.triple.reactor; + +// The request message containing the user's name. +message GreeterRequest { + string name = 1; +} + +// The response message containing the greetings +message GreeterReply { + string message = 1; +} + +service GreeterService { + + rpc greetOneToOne(GreeterRequest) returns (GreeterReply); + + rpc greetOneToMany(GreeterRequest) returns (stream GreeterReply); + + rpc greetManyToOne(stream GreeterRequest) returns (GreeterReply); + + rpc greetManyToMany(stream GreeterRequest) returns (stream GreeterReply); +} +``` + +### 使用示例 + +1. 添加服务端接口实现 + +```java +package org.apache.dubbo.samples.triple.reactor.impl; + +import org.apache.dubbo.samples.triple.reactor.DubboGreeterServiceTriple; +import org.apache.dubbo.samples.triple.reactor.GreeterReply; +import org.apache.dubbo.samples.triple.reactor.GreeterRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; + +public class GreeterServiceImpl extends DubboGreeterServiceTriple.GreeterServiceImplBase { + + private static final Logger LOGGER = LoggerFactory.getLogger(GreeterServiceImpl.class); + + @Override + public Flux greetManyToMany(Flux request) { + return request.doOnNext(req -> LOGGER.info("greetManyToMany get data: {}", req)) + .map(req -> GreeterReply.newBuilder().setMessage(req.getName() + " -> server get").build()) + .doOnNext(res -> LOGGER.info("greetManyToMany response data: {}", res)); + } +} +``` + +2. 添加服务端接口启动类 + +```java +package org.apache.dubbo.samples.triple.reactor; + +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.ServiceConfig; +import org.apache.dubbo.config.bootstrap.DubboBootstrap; +import org.apache.dubbo.samples.triple.reactor.impl.GreeterServiceImpl; + +public class ReactorServer { + + private static final int PORT = 50052; + + public static void main(String[] args) { + ServiceConfig reactorService = new ServiceConfig<>(); + reactorService.setInterface(GreeterService.class); + reactorService.setRef(new GreeterServiceImpl()); + + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application(new ApplicationConfig("tri-reactor-stub-server")) + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) + .protocol(new ProtocolConfig(CommonConstants.TRIPLE, PORT)) + .service(reactorService) + .start(); + } +} +``` + +3. 添加客户端启动类和消费程序 + +```java +package org.apache.dubbo.samples.triple.reactor; + +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ReferenceConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.bootstrap.DubboBootstrap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.IOException; + +public class ReactorConsumer { + + private static final Logger LOGGER = LoggerFactory.getLogger(ReactorConsumer.class); + + private final GreeterService greeterService; + + public ReactorConsumer() { + ReferenceConfig referenceConfig = new ReferenceConfig<>(); + referenceConfig.setInterface(GreeterService.class); + referenceConfig.setProtocol(CommonConstants.TRIPLE); + referenceConfig.setProxy(CommonConstants.NATIVE_STUB); + referenceConfig.setTimeout(10000); + + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application(new ApplicationConfig("tri-reactor-stub-server")) + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) + .reference(referenceConfig) + .start(); + GreeterService greeterService = referenceConfig.get(); + } + + public static void main(String[] args) throws IOException { + ReactorConsumer reactorConsumer = new ReactorConsumer(); + reactorConsumer.consumeManyToMany(); + System.in.read(); + } + + private void consumeManyToMany() { + greeterService.greetManyToMany(Flux.range(1, 10) + .map(num -> + GreeterRequest.newBuilder().setName(String.valueOf(num)).build()) + .doOnNext(req -> LOGGER.info("consumeManyToMany request data: {}", req))) + .subscribe(res -> LOGGER.info("consumeManyToMany get response: {}", res)); + } +} +``` + +4. 启动服务端 + +5. 启动消费者端 \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/reference-config-cache.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/reference-config-cache.md new file mode 100644 index 000000000000..7ff4e2c057a4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/reference-config-cache.md @@ -0,0 +1,54 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/reference-config-cache/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/reference-config-cache/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/reference-config-cache/ +description: 在 Dubbo 中缓存 ReferenceConfig +linkTitle: 服务引用配置对象缓存 +title: 服务引用配置对象缓存 +type: docs +weight: 50 +--- + + + + + +## 功能说明 + +`ReferenceConfig` 实例很重,封装了与注册中心的连接以及与提供者的连接,需要缓存。否则重复生成 `ReferenceConfig` 可能造成性能问题并且会有内存和连接泄漏。在 API 方式编程时,容易忽略此问题。 + +因此,自 `2.4.0` 版本开始, dubbo 提供了简单的工具类 `ReferenceConfigCache`用于缓存 `ReferenceConfig` 实例。 + +## 使用场景 + +网关等存在动态创建订阅的场景,由于 ReferenceConfig 本身很重,会创建特别多的中间对象,而 proxy 本身是可以复用的,所以通过 ReferenceConfigCache 可以缓存这部分的属性。 + +## 使用方式 + +### 消除并销毁 +消除 Cache 中的 `ReferenceConfig`,将销毁 `ReferenceConfig` 并释放对应的资源。 +```java +ReferenceConfig reference = new ReferenceConfig(); +reference.setInterface(XxxService.class); +reference.setVersion("1.0.0"); +...... +ReferenceConfigCache cache = ReferenceConfigCache.getCache(); +// cache.get方法中会缓存 Reference对象,并且调用ReferenceConfig.get方法启动ReferenceConfig +XxxService xxxService = cache.get(reference); +// 注意! Cache会持有ReferenceConfig,不要在外部再调用ReferenceConfig的destroy方法,导致Cache内的ReferenceConfig失效! +// 使用xxxService对象 +xxxService.sayHello(); +``` +```java +ReferenceConfigCache cache = ReferenceConfigCache.getCache(); +cache.destroy(reference); +``` +缺省 `ReferenceConfigCache` 把相同服务 Group、接口、版本的 `ReferenceConfig` 认为是相同,缓存一份。即以服务 Group、接口、版本为缓存的 Key。 + +### 修改策略 +可以修改这个策略,在 `ReferenceConfigCache.getCache` 时,传一个 `KeyGenerator`。详见 `ReferenceConfigCache` 类的方法。 +```java +KeyGenerator keyGenerator = new ... +ReferenceConfigCache cache = ReferenceConfigCache.getCache(keyGenerator); +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/result-cache.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/result-cache.md new file mode 100644 index 000000000000..acda287196cb --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/result-cache.md @@ -0,0 +1,122 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/result-cache/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/result-cache/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/result-cache/ +description: 通过缓存结果加速访问速度 +linkTitle: 调用结果缓存 +title: 调用结果缓存 +type: docs +weight: 50 +--- + +## 功能说明 + +Dubbo支持了服务端结果缓存和客户端结果缓存。 + +#### 缓存类型 + +目前Dubbo3.0版本及高于其的版本都支持以下几种内置的缓存策略: + +* `lru` 基于最近最少使用原则删除多余缓存,保持最热的数据被缓存。 +* `lfu`基于淘汰使用频次最低的原则来实现缓存策略。 +* `expiring`基于过期时间原则来实现缓存策略。 +* `threadlocal` 当前线程缓存,比如一个页面渲染,用到很多 portal,每个 portal 都要去查用户信息,通过线程缓存,可以减少这种多余访问。 +* `jcache` 与 [JSR107](http://jcp.org/en/jsr/detail?id=107%27) 集成,可以桥接各种缓存实现。 + +缓存类型可扩展 [缓存扩展](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/cache) + +关于 [示例代码](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-cache) + +## 使用场景 + +结果缓存,用于加速热门数据的访问速度,Dubbo 提供声明式缓存,以减少用户加缓存的工作量。 + +## 使用方式 +### 客户端缓存 + +Dubbo中对RPC调用结果缓存支持接口粒度和方法粒度的配置控制。 + +**接口粒度** + +xml配置方式: + +```xml + +``` + +注解配置方式: + +```java +@DubboReference(cache = "lru") +private DemoService demoService; +``` + +**方法粒度** + +```xml + + + +``` + +注解配置方式: + +```java +@DubboReference(methods = {@Method(name="sayHello",cache = "lru")}) +private DemoService demoService; +``` + +### 服务端缓存 + +**接口粒度** + +xml配置方式: + +```xml + + +``` + +注解配置方式: + +```java +@DubboService(cache = "lru") +public class DemoServiceImpl implements DemoService { + + private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class); + @Override + public String sayHello(String name) { + logger.info("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); + return "Hello " + name; + + } + +} +``` + +**方法粒度** + +```xml + + + + +``` + +注解配置方式: + +```java +@DubboService(methods = {@Method(name="sayHello",cache = "lru")}) +public class DemoServiceImpl implements DemoService { + + private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class); + @Override + public String sayHello(String name) { + logger.info("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); + return "Hello " + name; + + } + +} +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/router-snapshot.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/router-snapshot.md new file mode 100644 index 000000000000..c1c823274e9d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/router-snapshot.md @@ -0,0 +1,89 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/router-snapshot/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/router-snapshot/ +description: 路由状态采集 +linkTitle: 路由状态采集 +title: 路由状态采集 +type: docs +weight: 50 +--- + + + + + +## 功能说明 +路由状态收集功能可用于识别可能影响服务性能的任何潜在问题,识别可能阻碍服务尽可能高效使用的任何潜在瓶颈或问题,确保服务平稳运行,用户在尝试访问服务时不会遇到任何问题,允许用户检查路由的状态是启用还是禁用,确保仅使用授权的服务,并且访问仅限于具有适当授权的人员。 + +## 使用场景 + +Dubbo 的很多流量治理能力是基于 Router 进行实现的,在生产环境中,如果出现流量结果不符合预期的情况,可以通过路由状态命令来查看路由的状态,以此来定位可能存在的问题。 + +## 使用方式 + +### 查看路由缓存状态 + +Dubbo 在收到地址变更的时候,会将地址信息推送给所有的 `Router`,这些 `Router` 可以在此阶段提前计算路由的分组,缓存起来,以避免在调用时需要遍历所有的提供者计算分组参数。 +在 Dubbo 3 中引入的 `StateRouter` 提供了通过 qos 命令工具实时获取每个路由的状态的能力。 + +运维人员可以通过 `getRouterSnapshot` 命令获取路由的状态。具体命令使用方式可以参考 [getRouterSnapshot 命令](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/qos-list/) 文档。 + +**注:此功能仅支持 `StateRoute`,且 `StateRouter` 需要基于 `AbstractStateRouter` 实现 `doBuildSnapshot` 接口。** + +### 查看实际请求的路由计算结果 + +Dubbo 3 中默认在路由筛选后为空的时候打印路由计算的节点状态。运维人员可以通过日志判断每个路由的计算结果是否符合预期。 + +#### 日志格式 + +``` +No provider available after route for the service 服务 from registry 注册中心地址 on the consumer 消费端IP using the dubbo version 3.0.7. Router snapshot is below: +[ Parent (Input: 当前节点输入地址数) (Current Node Output: 当前节点计算结果数) (Chain Node Output: 当前节点和后级节点交集结果数) ] Input: 输入的地址示例(显示最多 5 个) -> Chain Node Output: 当前节点输出的地址示例(显示最多 5 个) + [ 路由名称 (Input: 当前节点输入地址数) (Current Node Output: 当前节点计算结果数) (Chain Node Output: 当前节点和后级节点交集结果数) Router message: 路由日志 ] Current Node Output: 当前节点输出的地址示例(显示最多 5 个) + [ 路由名称 (Input: 当前节点输入地址数) (Current Node Output: 当前节点计算结果数) (Chain Node Output: 当前节点和后级节点交集结果数) Router message: 路由日志 ] Current Node Output: 当前输入的地址示例(显示最多 5 个) +``` + +#### 注意: +- 路由日志需要依赖路由实现判断 `needToPrintMessage` 参数,并在需要时写入 `messageHolder` 路由日志 +- 由于多级路由结果是结果取交集的,所以当前节点计算结果数可能和后级取交后为空 + +#### 日志示例 + +``` +[19/07/22 07:42:46:046 CST] main WARN cluster.RouterChain: [DUBBO] No provider available after route for the service org.apache.dubbo.samples.governance.api.DemoService from registry 30.227.64.173 on the consumer 30.227.64.173 using the dubbo version 3.0.7. Router snapshot is below: +[ Parent (Input: 2) (Current Node Output: 2) (Chain Node Output: 0) ] Input: 30.227.64.173:20881,30.227.64.173:20880 -> Chain Node Output: Empty + [ MockInvokersSelector (Input: 2) (Current Node Output: 2) (Chain Node Output: 0) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 30.227.64.173:20881,30.227.64.173:20880 + [ StandardMeshRuleRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 0) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 30.227.64.173:20881,30.227.64.173:20880 + [ TagStateRouter (Input: 2) (Current Node Output: 0) (Chain Node Output: 0) Router message: FAILOVER: return all Providers without any tags ] Current Node Output: Empty, dubbo version: 3.0.7, current host: 30.227.64.173 +``` + +#### 开启路由全采样 + +在一些特殊情况下,请求可能调用到错误的服务端,但是因为选址非空,所以无法看到路由的过程信息,此时可以 [通过 qos 开启路由全采样](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/router-snapshot/)。通过 qos 的 `getRecentRouterSnapshot` 命令可以远程获取最近的路由快照。 + +``` +dubbo>getRecentRouterSnapshot +1658224330156 - Router snapshot service com.dubbo.dubbointegration.BackendService from registry 172.18.111.184 on the consumer 172.18.111.184 using the dubbo version 3.0.9 is below: +[ Parent (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) ] Input: 172.18.111.187:20880,172.18.111.183:20880 -> Chain Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ MockInvokersSelector (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ StandardMeshRuleRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ TagStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ ServiceStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ AppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + +1658224330156 - Router snapshot service com.dubbo.dubbointegration.BackendService from registry 172.18.111.184 on the consumer 172.18.111.184 using the dubbo version 3.0.9 is below: +[ Parent (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) ] Input: 172.18.111.187:20880,172.18.111.183:20880 -> Chain Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ MockInvokersSelector (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ StandardMeshRuleRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ TagStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ ServiceStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ AppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + +··· + +dubbo> +``` + +#### 注意: +由于日志框架不匹配导致的日志为空可以参考[日志框架适配及运行时管理](../../others/logger-management/)动态修改日志输出框架。 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/set-host.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/set-host.md new file mode 100644 index 000000000000..8ab9cad87a89 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/set-host.md @@ -0,0 +1,81 @@ +--- +aliases: + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/set-host/ +description: 自定义 Dubbo 服务对外暴露的主机地址 +linkTitle: 主机配置 +title: 主机配置 +type: docs +weight: 37 +--- + + + +## 背景 + +在 Dubbo 中, Provider 启动时主要做两个事情,一是启动 server,二是向注册中心注册服务。启动 server 时需要绑定 socket,向注册中心注册服务时也需要发送 socket 唯一标识服务地址。 + +1. `dubbo`中不设置`host`时默认`host`是什么? +2. 那在`dubbo`中如何指定服务的`host`,我们是否可以用hostname或domain代替IP地址作为`host`? +3. 在使用docker时,有时需要设置端口映射,此时,启动server时绑定的socket和向注册中心注册的socket使用不同的端口号,此时又该如何设置? + +## 示例 +#### dubbo 中不设置 host 时默认 host 是什么 + +一般的 dubbo 协议配置如下: +``` xml + ... + + ... +``` + +可以看到,只配置了端口号,没有配置 host,此时设置的 host 又是什么呢? + +查看代码发现,在 `org.apache.dubbo.config.ServiceConfig#findConfigedHosts()` 中,通过 `InetAddress.getLocalHost().getHostAddress()` 获取默认 host。其返回值如下: + +1. 未联网时,返回 127.0.0.1 +2. 在阿里云服务器中,返回私有地址,如: 172.18.46.234 +3. 在本机测试时,返回公有地址,如: 30.5.10.11 + +#### 那在 dubbo 中如何指定服务的 socket? + +除此之外,可以通过 `dubbo.protocol` 或 `dubbo.provider `的 `host` 属性对 `host` 进行配置,支持IP地址和域名,如下: + +``` xml + ... + + ... +``` + +#### 在使用 docker 时,有时需要设置端口映射,此时,启动 server 时绑定的 socket 和向注册中心注册的 socket 使用不同的端口号,此时又该如何设置? + +见 [dubbo 通过环境变量设置 host](https://github.com/dubbo/dubbo-samples/tree/master/2-advanced/dubbo-samples-docker) + +有些部署场景需要动态指定服务注册的地址,如 docker bridge 网络模式下要指定注册宿主机 ip 以实现外网通信。dubbo 提供了两对启动阶段的系统属性,用于设置对外通信的ip、port地址。 + +* **DUBBO_IP_TO_REGISTRY**:注册到注册中心的 ip 地址 +* **DUBBO_PORT_TO_REGISTRY**:注册到注册中心的 port 端口 +* **DUBBO_IP_TO_BIND**:监听 ip 地址 +* **DUBBO_PORT_TO_BIND**:监听 port 端口 + +以上四个配置项均为可选项,如不配置 dubbo 会自动获取 ip 与端口,请根据具体的部署场景灵活选择配置。 +dubbo 支持多协议,如果一个应用同时暴露多个不同协议服务,且需要为每个服务单独指定 ip 或 port,请分别在以上属性前加协议前缀。 如: + +* **HESSIAN_DUBBO_PORT_TO_BIND**:hessian 协议绑定的 port +* **DUBBO_DUBBO_PORT_TO_BIND**:dubbo 协议绑定的 port +* **HESSIAN_DUBBO_IP_TO_REGISTRY**:hessian 协议注册的 ip +* **DUBBO_DUBBO_IP_TO_REGISTRY**:dubbo 协议注册的 ip + +PORT_TO_REGISTRY 或 IP_TO_REGISTRY 不会用作默认 PORT_TO_BIND 或 IP_TO_BIND,但是反过来是成立的。如: + +* 设置 `PORT_TO_REGISTRY=20881` 和 `IP_TO_REGISTRY=30.5.97.6`,则 `PORT_TO_BIND` 和 `IP_TO_BIND` 不受影响 +* 设置 `PORT_TO_BIND=20881` 和 `IP_TO_BIND=30.5.97.6`,则默认 `PORT_TO_REGISTRY=20881` 且 `IP_TO_REGISTRY=30.5.97.6` + +## 总结 + + 1. 可以通过`dubbo.protocol`或`dubbo.provider`的`host`属性对`host`进行配置,支持IP地址和域名.但此时注册到注册中心的IP地址和监听IP地址是同一个值 + 2. 为了解决在虚拟环境或局域网内consumer无法与provider通信的问题,可以通过环境变量分别设置注册到注册中心的IP地址和监听IP地址,其优先级高于`dubbo.protocol`或`dubbo.provider`的`host`配置 + +## 参考 + + 1. [Proposal: support hostname or domain in service discovery.](https://github.com/apache/dubbo/issues/2043) + 2. [dubbo通过环境变量设置host](https://github.com/dubbo/dubbo-samples/tree/master/2-advanced/dubbo-samples-docker) diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/specify-ip.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/specify-ip.md new file mode 100644 index 000000000000..3a2ede78ad72 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/specify-ip.md @@ -0,0 +1,105 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip/ +description: 在发起 Dubbo 调用之前指定本次调用的目标 IP +linkTitle: 运行时动态指定 IP 调用 +title: 动态指定 IP 调用 +type: docs +weight: 4 +--- + + +## 特性说明 + +在发起 RPC 请求的时候,需要指定本次调用的服务端,常用的场景包括消息回调、流量隔离等。 + +## 使用方式 + +### 插件依赖 + +首先,需要添加以下插件依赖到项目中 + +```xml + + org.apache.dubbo.extensions + dubbo-cluster-specify-address-dubbo3 + 3.3.0 + +``` + +适配 Dubbo 2 版本 + +```xml + + org.apache.dubbo.extensions + dubbo-cluster-specify-address-dubbo2 + 1.0.0 + +``` + +### 调用示例 + +```java +ReferenceConfig referenceConfig = new ReferenceConfig<>(); +// ... init +DemoService demoService = referenceConfig.get(); + +// for invoke +// 1. find 10.10.10.10:20880 exist +// 2. if not exist, create a invoker to 10.10.10.10:20880 if `needToCreate` is true (only support in Dubbo 3.x's implementation) +UserSpecifiedAddressUtil.setAddress(new Address("10.10.10.10", 20880, true)); +demoService.sayHello("world"); + + +// for invoke +// 1. find 10.10.10.10:any exist +// 2. if not exist, create a invoker to 10.10.10.10:20880 if `needToCreate` is true (only support in Dubbo 3.x's implementation) +UserSpecifiedAddressUtil.setAddress(new Address("10.10.10.10", 0, true)); +demoService.sayHello("world"); +``` + +### 参数说明 + +指定 IP 调用的参数围绕 `Address` 对象展开。参数类型参考如下: + +```java +package org.apache.dubbo.rpc.cluster.specifyaddress; + +public class Address implements Serializable { + // ip - priority: 3 + private String ip; + + // ip+port - priority: 2 + private int port; + + // address - priority: 1 + private URL urlAddress; + + private boolean needToCreate = false; + + // ignore setter and getter +} +``` + +1. `urlAddress` 为最高优先级,如果指定了目标的 URL 地址,会优先使用该地址。(不再匹配后续) +2. ip + port(非 0 端口) 为第二优先级,会从注册中心已经推送的地址中进行匹配。(不再匹配后续) +3. ip 为第三优先级,会从注册中心已经推送的地址中进行匹配。 + +特别的,如果指定了 `needToCreate` 为 `true`,将会自动根据传入的参数构建一个 invoker。对于通过指定 ip ( + port ) 方式指定的地址, +将会自动使用注册中心中第一个地址的参数为模板进行创建;如果无地址将基于 Dubbo 协议自动创建。 +如需定制创建 invoker 的逻辑请实现 `org.apache.dubbo.rpc.cluster.specifyaddress.UserSpecifiedServiceAddressBuilder` SPI 接口。(此功能仅**Dubbo 3 实现支持**) + +在构建完 `Address` 参数每次请求前通过 `UserSpecifiedAddressUtil` 工具类传给 Dubbo 框架。 + +```java +package org.apache.dubbo.rpc.cluster.specifyaddress; + +public class UserSpecifiedAddressUtil { + + public static void setAddress(Address address) { ... } + +} +``` + +> **必须每次都设置,而且设置后必须马上发起调用**,如果出现拦截器报错(Dubbo 框架内 remove 此值是在选址过程进行的)建议设置 null 以避免 ThreadLocal 内存泄漏导致影响后续调用。 \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/threading-model.md b/content/en/overview/mannual/java-sdk/tasks/framework/threading-model.md new file mode 100644 index 000000000000..868e8d4a962e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/threading-model.md @@ -0,0 +1,425 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/consumer/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/consumer/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/threading-model/consumer/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/threading-model/ +description: Dubbo 消费端线程池模型用法 +linkTitle: 线程模型 +title: 消费端线程模型,提供者端线程模型 +type: docs +weight: 2 +--- + +## 消费端线程模型 + +对 2.7.5 版本之前的 Dubbo 应用,尤其是一些消费端应用,当面临需要消费大量服务且并发数比较大的大流量场景时(典型如网关类场景),经常会出现消费端线程数分配过多的问题,具体问题讨论可参见 [Need a limited Threadpool in consumer side #2013](https://github.com/apache/dubbo/issues/2013) + +改进后的消费端线程池模型,通过复用业务端被阻塞的线程,很好的解决了这个问题。 + +**老的线程池模型** + +![消费端线程池.png](/imgs/user/consumer-threadpool0.png) + +我们重点关注 Consumer 部分: + +1. 业务线程发出请求,拿到一个 Future 实例。 +2. 业务线程紧接着调用 future.get 阻塞等待业务结果返回。 +3. 当业务数据返回后,交由独立的 Consumer 端线程池进行反序列化等处理,并调用 future.set 将反序列化后的业务结果置回。 +4. 业务线程拿到结果直接返回 + +**当前线程池模型** + +![消费端线程池新.png](/imgs/user/consumer-threadpool1.png) + +1. 业务线程发出请求,拿到一个 Future 实例。 +2. 在调用 future.get() 之前,先调用 ThreadlessExecutor.wait(),wait 会使业务线程在一个阻塞队列上等待,直到队列中被加入元素。 +3. 当业务数据返回后,生成一个 Runnable Task 并放入 ThreadlessExecutor 队列 +4. 业务线程将 Task 取出并在本线程中执行:反序列化业务数据并 set 到 Future。 +5. 业务线程拿到结果直接返回 + +这样,相比于老的线程池模型,由业务线程自己负责监测并解析返回结果,免去了额外的消费端线程池开销。 + +## 提供端线程模型 +Dubbo协议的和Triple协议目前的线程模型还并没有对齐,下面分开介绍Triple协议和Dubbo协议的线程模型。 + +### Dubbo协议 + +介绍Dubbo协议的Provider端线程模型之前,先介绍Dubbo对channel上的操作抽象成了五种行为: + +- 建立连接:connected,主要是的职责是在channel记录read、write的时间,以及处理建立连接后的回调逻辑,比如dubbo支持在断开后自定义回调的hook(onconnect),即在该操作中执行。 +- 断开连接:disconnected,主要是的职责是在channel移除read、write的时间,以及处理端开连接后的回调逻辑,比如dubbo支持在断开后自定义回调的hook(ondisconnect),即在该操作中执行。 +- 发送消息:sent,包括发送请求和发送响应。记录write的时间。 +- 接收消息:received,包括接收请求和接收响应。记录read的时间。 +- 异常捕获:caught,用于处理在channel上发生的各类异常。 + +Dubbo框架的线程模型与以上这五种行为息息相关,Dubbo协议Provider线程模型可以分为五类,也就是AllDispatcher、DirectDispatcher、MessageOnlyDispatcher、ExecutionDispatcher、ConnectionOrderedDispatcher。 + +#### 配置方式 +| 线程模型 | 配置值 | +| ---- | -- | +All Dispatcher | all +Direct Dispatcher | direct +Execution Dispatcher | execution +Message Only Dispatcher | message +Connection Ordered Dispatcher | connection + +拿 application.yaml 的配置方式举例:在protocol下配置dispatcher: all,即可把dubbo协议的线程模型调整为All Dispatcher + +```yaml +dubbo: + application: + name: dubbo-springboot-demo-provider + protocol: + name: dubbo + port: -1 + dispatcher: all + registry: + id: zk-registry + address: zookeeper://127.0.0.1:2181 +``` + +#### All Dispatcher + +下图是All Dispatcher的线程模型说明图: + +![dubbo-provider-alldispatcher](/imgs/v3/feature/performance/threading-model/dubbo-provider-alldispatcher.png) + +- 在IO线程中执行的操作有: + 1. sent操作在IO线程上执行。 + 2. 序列化响应在IO线程上执行。 +- 在Dubbo线程中执行的操作有: + 1. received、connected、disconnected、caught都是在Dubbo线程上执行的。 + 2. 反序列化请求的行为在Dubbo中做的。 + +#### Direct Dispatcher + +下图是Direct Dispatcher的线程模型说明图: + +![dubbo-provider-directDispatcher](/imgs/v3/feature/performance/threading-model/dubbo-provider-directDispatcher.png) + +- 在IO线程中执行的操作有: + 1. received、connected、disconnected、caught、sent操作在IO线程上执行。 + 2. 反序列化请求和序列化响应在IO线程上执行。 +- 1. 并没有在Dubbo线程操作的行为。 + +#### Execution Dispatcher + +下图是Execution Dispatcher的线程模型说明图: + +![dubbo-provider-ExecutionDispatcher](/imgs/v3/feature/performance/threading-model/dubbo-provider-executionDispatcher.png) + +- 在IO线程中执行的操作有: + 1. sent、connected、disconnected、caught操作在IO线程上执行。 + 2. 序列化响应在IO线程上执行。 +- 在Dubbo线程中执行的操作有: + 1. received都是在Dubbo线程上执行的。 + 2. 反序列化请求的行为在Dubbo中做的。 + +#### Message Only Dispatcher + +在Provider端,Message Only Dispatcher和Execution Dispatcher的线程模型是一致的,所以下图和Execution Dispatcher的图一致,区别在Consumer端。见下方Consumer端的线程模型。 + +下图是Message Only Dispatcher的线程模型说明图: + +![dubbo-provider-ExecutionDispatcher](/imgs/v3/feature/performance/threading-model/dubbo-provider-executionDispatcher.png) + +- 在IO线程中执行的操作有: + 1. sent、connected、disconnected、caught操作在IO线程上执行。 + 2. 序列化响应在IO线程上执行。 +- 在Dubbo线程中执行的操作有: + 1. received都是在Dubbo线程上执行的。 + 2. 反序列化请求的行为在Dubbo中做的。 + +#### Connection Ordered Dispatcher + +下图是Connection Ordered Dispatcher的线程模型说明图: + +![dubbbo-provider-connectionOrderedDispatcher](/imgs/v3/feature/performance/threading-model/dubbbo-provider-connectionOrderedDispatcher.png) + +- 在IO线程中执行的操作有: + 1. sent操作在IO线程上执行。 + 2. 序列化响应在IO线程上执行。 +- 在Dubbo线程中执行的操作有: + 1. received、connected、disconnected、caught都是在Dubbo线程上执行的。但是connected和disconnected两个行为是与其他两个行为通过线程池隔离开的。并且在Dubbo connected thread pool中提供了链接限制、告警灯能力。 + 2. 反序列化请求的行为在Dubbo中做的。 + + +### Triple协议 + +下图为Triple协议 Provider端的线程模型 + +![triple-provider](/imgs/v3/feature/performance/threading-model/triple-provider.png) + +Triple协议Provider线程模型目前还比较简单,目前序列化和反序列化操作都在Dubbo线程上工作,而IO线程并没有承载这些工作。 + + +## 线程池隔离 +一种新的线程池管理方式,使得提供者应用内各个服务的线程池隔离开来,互相独立,某个服务的线程池资源耗尽不会影响其他正常服务。支持线程池可配置化,由用户手动指定。 + +使用线程池隔离来确保 Dubbo 用于调用远程方法的线程与微服务用于执行其任务的线程是分开的。可以通过防止线程阻塞或相互竞争来帮助提高系统的性能和稳定性。 + +目前可以以 API、XML、Annotation 的方式进行配置 + +**配置参数** +- `ApplicationConfig` 新增 `String executor-management-mode` 参数,配置值为 `default` 和 `isolation` ,默认为 `default`。 + - `executor-management-mode = default` 使用原有 **以协议端口为粒度、服务间共享** 的线程池管理方式 + - `executor-management-mode = isolation` 使用新增的 **以服务三元组为粒度、服务间隔离** 的线程池管理方式 +- `ServiceConfig` 新增 `Executor executor` 参数,**用以服务间隔离的线程池**,可以由用户配置化、提供自己想要的线程池,若没有指定,则会根据协议配置(`ProtocolConfig`)信息构建默认的线程池用以服务隔离。 + +> `ServiceConfig` 新增 `Executor executor` 配置参数只有指定`executor-management-mode = isolation` 才生效。 +#### API +```java + public void test() { + // provider app + DubboBootstrap providerBootstrap = DubboBootstrap.newInstance(); + + ServiceConfig serviceConfig1 = new ServiceConfig(); + serviceConfig1.setInterface(DemoService.class); + serviceConfig1.setRef(new DemoServiceImpl()); + serviceConfig1.setVersion(version1); + // set executor1 for serviceConfig1, max threads is 10 + NamedThreadFactory threadFactory1 = new NamedThreadFactory("DemoService-executor"); + ExecutorService executor1 = Executors.newFixedThreadPool(10, threadFactory1); + serviceConfig1.setExecutor(executor1); + + ServiceConfig serviceConfig2 = new ServiceConfig(); + serviceConfig2.setInterface(HelloService.class); + serviceConfig2.setRef(new HelloServiceImpl()); + serviceConfig2.setVersion(version2); + // set executor2 for serviceConfig2, max threads is 100 + NamedThreadFactory threadFactory2 = new NamedThreadFactory("HelloService-executor"); + ExecutorService executor2 = Executors.newFixedThreadPool(100, threadFactory2); + serviceConfig2.setExecutor(executor2); + + ServiceConfig serviceConfig3 = new ServiceConfig(); + serviceConfig3.setInterface(HelloService.class); + serviceConfig3.setRef(new HelloServiceImpl()); + serviceConfig3.setVersion(version3); + // Because executor is not set for serviceConfig3, the default executor of serviceConfig3 is built using + // the threadpool parameter of the protocolConfig ( FixedThreadpool , max threads is 200) + serviceConfig3.setExecutor(null); + + // It takes effect only if [executor-management-mode=isolation] is configured + ApplicationConfig applicationConfig = new ApplicationConfig("provider-app"); + applicationConfig.setExecutorManagementMode("isolation"); + + providerBootstrap + .application(applicationConfig) + .registry(registryConfig) + // export with tri and dubbo protocol + .protocol(new ProtocolConfig("tri", 20001)) + .protocol(new ProtocolConfig("dubbo", 20002)) + .service(serviceConfig1) + .service(serviceConfig2) + .service(serviceConfig3); + + providerBootstrap.start(); + } +``` + +#### XML +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` +#### Annotation +```java +@Configuration +@EnableDubbo(scanBasePackages = "org.apache.dubbo.config.spring.isolation.spring.annotation.provider") +public class ProviderConfiguration { + @Bean + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("zookeeper://127.0.0.1:2181"); + return registryConfig; + } + + // NOTE: we need config executor-management-mode="isolation" + @Bean + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig("provider-app"); + + applicationConfig.setExecutorManagementMode("isolation"); + return applicationConfig; + } + + // expose services with dubbo protocol + @Bean + public ProtocolConfig dubbo() { + ProtocolConfig protocolConfig = new ProtocolConfig("dubbo"); + return protocolConfig; + } + + // expose services with tri protocol + @Bean + public ProtocolConfig tri() { + ProtocolConfig protocolConfig = new ProtocolConfig("tri"); + return protocolConfig; + } + + // customized thread pool + @Bean("executor-demo-service") + public Executor demoServiceExecutor() { + return new DemoServiceExecutor(); + } + + // customized thread pool + @Bean("executor-hello-service") + public Executor helloServiceExecutor() { + return new HelloServiceExecutor(); + } +} +``` +```java +// customized thread pool +public class DemoServiceExecutor extends ThreadPoolExecutor { + public DemoServiceExecutor() { + super(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(), + new NamedThreadFactory("DemoServiceExecutor")); + } +} +``` + +```java +// customized thread pool +public class HelloServiceExecutor extends ThreadPoolExecutor { + public HelloServiceExecutor() { + super(100, 100, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(), + new NamedThreadFactory("HelloServiceExecutor")); + } +} +``` +```java +// "executor-hello-service" is beanName +@DubboService(executor = "executor-demo-service", version = "1.0.0", group = "Group1") +public class DemoServiceImplV1 implements DemoService { + + @Override + public String sayName(String name) { + return "server name"; + } + + @Override + public Box getBox() { + return null; + } +} + +``` + +```java +// not set executor for this service, the default executor built using threadpool parameter of the protocolConfig +@DubboService(version = "3.0.0", group = "Group3") +public class HelloServiceImplV2 implements HelloService { + private static final Logger logger = LoggerFactory.getLogger(HelloServiceImplV2.class); + + @Override + public String sayHello(String name) { + return "server hello"; + } +} + +``` + +```java +@DubboService(executor = "executor-hello-service", version = "2.0.0", group = "Group2") +public class HelloServiceImplV3 implements HelloService { + private static final Logger logger = LoggerFactory.getLogger(HelloServiceImplV3.class); + + @Override + public String sayHello(String name) { + return "server hello"; + } +} +``` + + + +## 线程池状态导出 +dubbo 通过 Jstack 自动导出线程堆栈来保留现场,方便排查问题。 + +默认策略 + +* 导出路径: user.home标识的用户主目录 +* 导出间隔: 最短间隔允许每隔10分钟导出一次 +* 导出开关: 默认打开 + +当业务线程池满时,我们需要知道线程都在等待哪些资源、条件,以找到系统的瓶颈点或异常点。 + +#### 导出开关控制 +```properties +# dubbo.properties +dubbo.application.dump.enable=true +``` +```xml + +``` + +```yaml +dubbo: + application: + name: dubbo-springboot-demo-provider + dump-enable: false +``` + + + +#### 导出路径 + +```properties +# dubbo.properties +dubbo.application.dump.directory=/tmp +``` + +```xml + +``` + +```yaml +dubbo: + application: + name: dubbo-springboot-demo-provider + dump-directory: /tmp +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/timeout.md b/content/en/overview/mannual/java-sdk/tasks/framework/timeout.md new file mode 100644 index 000000000000..cbad6a8863a6 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/timeout.md @@ -0,0 +1,79 @@ +--- +aliases: + - /zh/overview/tasks/develop/async/ + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/async-call/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-call/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-execute-on-provider/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async/ +description: 某些情况下希望dubbo接口异步调用,避免不必要的等待。 +linkTitle: 超时时间 +title: 为服务调用指定 timeout 超时时间 +type: docs +weight: 3 +--- + +为 RPC 调用设置超时时间可以提升集群整体稳定性,避免无限等待响应结果导致的资源占用(比如大量长期无响应的请求占用线程池等)。在调用没有响应的情况下,比如 5s 之后,Dubbo 框架就会自动终止调用等待过程(抛出 TimeoutException),释放此次调用占用的资源。 + +## 使用方式 +有多种方式可以配置 rpc 调用超时时间,从粗粒度的全局默认值,到特定服务、特定方法级别的独立配置: + +配置全局默认超时时间为 5s(不配置的情况下,所有服务的默认超时时间是 1s)。 +```yaml +dubbo: + provider: + timeout: 5000 +``` + +在消费端,指定 DemoService 服务调用的超时时间为 5s +```java +@DubboReference(timeout=5000) +private DemoService demoService; +``` + +在提供端,指定 DemoService 服务调用的超时时间为 5s(可作为所有消费端的默认值,如果消费端有指定则优先级更高) +```java +@DubboService(timeout=5000) +public class DemoServiceImpl implements DemoService{} +``` + +在消费端,指定 DemoService sayHello 方法调用的超时时间为 5s +```java +@DubboReference(methods = {@Method(name = "sayHello", timeout = 5000)}) +private DemoService demoService; +``` + +在提供端,指定 DemoService sayHello 方法调用的超时时间为 5s(可作为所有消费端的默认值,如果消费端有指定则优先级更高) +```java +@DubboService(methods = {@Method(name = "sayHello", timeout = 5000)}) +public class DemoServiceImpl implements DemoService{} +``` + +以上配置形式的优先级从高到低依次为:`方法级别配置 > 服务级别配置 > 全局配置 > 默认值`。 + +## Deadline 机制 + + +我们来分析一下以上调用链路以及可能出现的超时情况: +* A 调用 B 设置了超时时间 5s,因此 `B -> C -> D` 总计耗时不应该超过 5s,否则 A 就会收到超时异常 +* 在任何情形下,只要 A 等待 5s 没有收到响应,整个调用链路就可以被终止了(如果此时 C 正在运行,则 `C -> D` 就没有发起的意义了) +* 理论上 `B -> C`、`C -> D` 都有自己独立的超时时间设置,超时计时也是独立计算的,它们不知道 A 作为调用发起方是否超时 + +在 Dubbo 框架中,`A -> B` 的调用就像一个开关,一旦启动,在任何情形下整个 `A -> B -> C -> D` 调用链路都会被完整执行下去,即便调用方 A 已经超时,后续的调用动作仍会继续。这在一些场景下是没有意义的,尤其是链路较长的情况下会带来不必要的资源消耗,deadline 就是设计用来解决这个问题,通过在调用链路中传递 deadline(deadline初始值等于超时时间,随着时间流逝而减少)可以确保调用链路只在有效期内执行,deadline 消耗殆尽之后,调用链路中其他尚未执行的任务将被取消。 + +因此 deadline 机制就是将 ` B -> C -> D` 当作一个整体看待,这一系列动作必须在 5s 之内完成。随着时间流逝 deadline 会从 5s 逐步扣减,后续每一次调用实际可用的超时时间即是当前 deadline 值,比如 `C` 收到请求时已经过去了 3s,则 `C -> D` 的超时时间只剩下 2s。 + + + +deadline 机制默认是关闭的,如果要启用 deadline 机制,需要配置以下参数: +```yaml +dubbo: + provider: + timeout: 5000 + parameters.enable-timeout-countdown: true +``` + +也可以指定某个服务调用开启 deadline 机制: +```java +@DubboReference(timeout=5000, parameters={"enable-timeout-countdown", "true"}) +private DemoService demoService; +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/version_group.md b/content/en/overview/mannual/java-sdk/tasks/framework/version_group.md new file mode 100644 index 000000000000..f0c7d7976367 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/framework/version_group.md @@ -0,0 +1,312 @@ +--- +aliases: + - /zh/overview/tasks/develop/version_group/ + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/service-group/ + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-versions/ + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/version_group/ + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/group-merger/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/service-group/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/service-version/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-versions/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/group-merger/ +description: "" +linkTitle: 版本与分组 +title: 版本与分组 +type: docs +weight: 4 +--- + +Dubbo服务中,接口并不能唯一确定一个服务,只有 `接口+分组+版本号` 的三元组才能唯一确定一个服务。 + +* 当同一个接口针对不同的业务场景、不同的使用需求或者不同的功能模块等场景,可使用服务分组来区分不同的实现方式。同时,这些不同实现所提供的服务是可并存的,也支持互相调用。 +* 当接口实现需要升级又要保留原有实现的情况下,即出现不兼容升级时,我们可以使用不同版本号进行区分。 + +本文示例完整源码可在以下链接查看: +* [dubbo-samples-group](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-group) +* [dubbo-samples-version](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-version) +* [dubbo-samples-merge](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-merge) + +## 使用方式 +使用 @DubboService 注解,配置 `group` 参数和 `version` 参数: + +接口定义: +```java +public interface DevelopService { + String invoke(String param); +} +``` + +接口实现1: +```java +@DubboService(group = "group1", version = "1.0") +public class DevelopProviderServiceV1 implements DevelopService{ + @Override + public String invoke(String param) { + StringBuilder s = new StringBuilder(); + s.append("ServiceV1 param:").append(param); + return s.toString(); + } +} +``` +接口实现2: +```java +@DubboService(group = "group2", version = "2.0") +public class DevelopProviderServiceV2 implements DevelopService{ + @Override + public String invoke(String param) { + StringBuilder s = new StringBuilder(); + s.append("ServiceV2 param:").append(param); + return s.toString(); + } +} +``` + +客户端接口调用: + +> 使用 @DubboReference 注解,添加 group 参数和 version 参数 + +```java +@DubboReference(group = "group1", version = "1.0") +private DevelopService developService; + +@DubboReference(group = "group2", version = "2.0") +private DevelopService developServiceV2; + +@Override +public void run(String... args) throws Exception { + //调用DevelopService的group1分组实现 + System.out.println("Dubbo Remote Return ======> " + developService.invoke("1")); + //调用DevelopService的另一个实现 + System.out.println("Dubbo Remote Return ======> " + developServiceV2.invoke("2")); +} +``` + +#### 服务消费端(注解配置) + +使用 @DubboReference 注解,添加 group 参数 + +```java +@DubboReference(group = "demo") +private DemoService demoService; + +@DubboReference(group = "demo2") +private DemoService demoService2; + +//group值为*,标识匹配任意服务分组 +@DubboReference(group = "*") +private DemoService demoService2; +``` + +同样启动 Dubbo 服务后,可在注册中心看到相同服务名不同分组的引用者,以 Nacos 作为注册中心为例,显示如下内容: +![image-service-group-2.png](/imgs/blog/service-group-2.png) + +#### 服务提供端( xml 配置) + +使用 标签,添加 group 参数 + +```xml + + + ... + + + +... + +``` + +启动 Dubbo 服务,可在注册中心看到相同服务名不同分组的服务,以 Nacos 作为注册中心为例,显示如下内容: + +![image-service-group-1.png](/imgs/blog/service-group-1.png) + +#### 服务消费端( xml 配置) + +使用 注解,添加 group 参数 + +```xml + + + ... + + + + + + + + ... + +``` + +同样启动 Dubbo 服务后,可在注册中心看到相同服务名不同分组的引用者,以 Nacos 作为注册中心为例,显示如下内容: + +![image-service-group-2.png](/imgs/blog/service-group-2.png) + +#### 服务提供端( API 配置) + +使用 org.apache.dubbo.config.ServiceConfig 类,添加 group 参数 + +```java +// ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口 +// 请自行缓存,否则可能造成内存和连接泄漏 +ServiceConfig service = new ServiceConfig<>(); +service.setInterface(DemoService.class); +service.setGroup("demo"); +... + +ServiceConfig service2 = new ServiceConfig<>(); +service.setInterface(DemoService.class); +service.setGroup("demo2"); +... +``` + +启动 Dubbo 服务,可在注册中心看到相同服务名不同分组的服务,以 Nacos 作为注册中心为例,显示如下内容: + +![image-service-group-1.png](/imgs/blog/service-group-1.png) + +#### 服务消费端( API 配置) + +使用 org.apache.dubbo.config.ReferenceConfig,添加 group 参数 + +```java +// ReferenceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口 +// 请自行缓存,否则可能造成内存和连接泄漏 +ReferenceConfig reference = new ReferenceConfig<>(); +reference.setInterface(DemoService.class); +reference.setGroup("demo"); +... + +ReferenceConfig reference2 = new ReferenceConfig<>(); +reference2.setInterface(DemoService.class); +reference2.setGroup("demo2"); +... + +ReferenceConfig reference3 = new ReferenceConfig<>(); +reference3.setInterface(DemoService.class); +reference3.setGroup("*"); +... + +``` +同样启动 Dubbo 服务后,可在注册中心看到相同服务名不同分组的引用者,以 Nacos 作为注册中心为例,显示如下内容: +![image-service-group-2.png](/imgs/blog/service-group-2.png) + + +> 总是 **只调** 一个可用组的实现 + + +## 分组聚合 +通过分组对结果进行聚合并返回聚合后的结果,比如菜单服务,用 group 区分同一接口的多种实现,现在消费方需从每种 group 中调用一次并返回结果,对结果进行合并之后返回,这样就可以实现聚合菜单项。 + +相关代码可以参考 [dubbo 项目中的示例](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-merge) + +将多个服务提供者分组作为一个提供者进行访问。应用程序能够像访问一个服务一样访问多个服务,并允许更有效地使用资源。 + +### 搜索所有分组 + +```xml + +``` + +### 合并指定分组 + +```xml + +``` +### 指定方法合并 + +指定方法合并结果,其它未指定的方法,将只调用一个 Group + +```xml + + + +``` +### 某个方法不合并 + +某个方法不合并结果,其它都合并结果 + +```xml + + + +``` +### 指定合并策略 + +指定合并策略,缺省根据返回值类型自动匹配,如果同一类型有两个合并器时,需指定合并器的名称 [合并结果扩展](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/merger) + +```xml + + + +``` +### 指定合并方法 + +指定合并方法,将调用返回结果的指定方法进行合并,合并方法的参数类型必须是返回结果类型本身 + +```xml + + + +``` + +{{% alert title="提示" color="primary" %}} +`2.1.0` 开始支持 +{{% /alert %}} + + + + + +## 跨版本升级 +**按照以下的步骤进行版本迁移** + +1. 在低压力时间段,先升级一半提供者为新版本 +2. 再将所有消费者升级为新版本 +3. 然后将剩下的一半提供者升级为新版本 + +#### 配置 +- 新老版本服务提供者 +- 新老版本服务消费者 + +当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。 + +>参考用例 +[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-version](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-version) + +### 服务提供者 +老版本服务提供者配置 +```xml + +``` +新版本服务提供者配置 +```xml + +``` +### 服务消费者 +老版本服务消费者配置 +```xml + +``` +新版本服务消费者配置 +```xml + +``` +### 不区分版本 +如果不需要区分版本,可以按照以下的方式配置 +```xml + +``` + + diff --git a/content/en/overview/mannual/java-sdk/tasks/gateway/_index.md b/content/en/overview/mannual/java-sdk/tasks/gateway/_index.md new file mode 100755 index 000000000000..ba7223d607c8 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/gateway/_index.md @@ -0,0 +1,8 @@ +--- +description: "如果通过 Higress、APISIX 等网关产品解决前端 http 流量接入后端 RPC 微服务问题。" +linkTitle: HTTP网关接入 +title: HTTP流量接入 +type: docs +weight: 8 +--- + diff --git a/content/en/overview/mannual/java-sdk/tasks/gateway/architecture.md b/content/en/overview/mannual/java-sdk/tasks/gateway/architecture.md new file mode 100644 index 000000000000..0191c1602934 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/gateway/architecture.md @@ -0,0 +1,41 @@ +--- +description: | + 本文讲述前端 http 流量接入后端 Dubbo 微服务的的基本架构,包括移动端、浏览器、桌面应用、异构的微服务体系等。 +linkTitle: 基本架构 +title: 前端 http 流量接入 Dubbo 后端微服务体系的基础架构 +type: docs +weight: 1 +--- + +不论你开发的是什么样的产品(电子商城、管理系统、手机 app 等),绝大多数下产品的流量入口都会是 http,用户可能通过浏览器、手机移动设备、桌面软件等来访问产品。在这种情况下,如何将后端开发的 Dubbo 微服务集群接入前端访问设备就成为一个需要解决的问题,其实也就是 http 与 rpc 之间的转换与连接问题。 + +总的来说,有中心化和去中心化两种架构模式。其中,中心化接入模式更具通用性,对后端 rpc 协议、前端网关没有太多特殊要求,但保证中心化应用的性能、稳定性是一个较大的挑战;去中心化模式由于不需要维护入口应用,因此可适应更大流量、更大规模的集群。 + +## 中心化接入方式 +中心化接入方式的架构图如下: +* 在后端服务与前端设备之间有一层网关,负责流量过滤、路由、限流等流量管理工作 +* 在后端集群中有一个连接 http 与 dubbo 服务的 “统一微服务入口应用”(通常也叫做 BFF,即Backend for Frontend)。 + + + +BFF 应用通常可以使用 Spring Web 等常用框架开发,应用发布一系列的 http 服务,接收网关或前端设备流量,同时负责按需发起 dubbo 调用。 + +{{% alert title="注意" color="info" %}} +`dubbo`、`triple` 协议都支持这种接入架构。另外,在配置 BFF 应用调用 dubbo 服务时,可以使用普通的 dubbo 配置方式,也可以使用泛化调用等方式: +* 配置接入 dubbo 协议时,使用 [泛化调用]() 的优势是可以避免对服务二进制包的依赖,实现配置动态生效的效果。 +* 配置接入 triple 协议时,可以使用 http 调用方式,同样可避免对服务二进制包的依赖,实现配置动态生效的效果。 +{{% /alert %}} + +## 去中心化接入方式 +与中心化架构相比,此方式并没有太大的差异,唯一的区别在于不需要额外的 BFF 应用,我们可以在网关直接调用后端 dubbo 服务。 + +但这种方式对网关有特别要求。如果后端是 dubbo 协议的话,则要求网关具备 `http -> dubbo` 协议转换的能力,但你会在接下来的文档中发现,我们可以通过多协议发布绕过协议转换,让网关直接通过 http 访问后端服务;如果后端是 triple 协议,就会更简单了,因为 triple 协议支持 application/json 格式的 http 请求。 + + + +## 总结 +使用不同的协议也会影响架构选择,triple 协议由于原生支持 HTTP 访问,因此对两种架构方式都可以无差别支持,并且接入原理上也会更简单直接。而 dubbo 协议作为 Dubbo2 时代主推的协议,由于是基于 tcp 的二进制协议,因此在接入方式上存在一些不同。 + +我们将在接下来的两篇文档中介绍 dubbo、triple 两种协议的具体前端流量接入方式,文档同样适用于中心化、去中心化架构。 + + diff --git a/content/en/overview/mannual/java-sdk/tasks/gateway/dubbo.md b/content/en/overview/mannual/java-sdk/tasks/gateway/dubbo.md new file mode 100644 index 000000000000..8909d162335e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/gateway/dubbo.md @@ -0,0 +1,81 @@ +--- +aliases: + - /zh/overview/tasks/ecosystem/gateway/ + - /zh-cn/overview/tasks/ecosystem/gateway/ +description: | + 本文介绍借助 Apache Higress 实现 Dubbo Service 服务代理,后端服务使用 dubbo 通信协议。 +linkTitle: dubbo协议 +title: 通过网关将 http 流量接入 Dubbo 后端服务 +type: docs +weight: 2 +--- + +由于 dubbo 协议是基于 TCP 的二进制私有协议,因此更适合作为后端微服务间的高效 RPC 通信协议,这也导致 dubbo 协议对于前端流量接入不是很友好。在 Dubbo 框架中,有两种方式可以帮助开发者解决这个问题: +* **多协议发布【推荐】**,为 dubbo 协议服务暴露 rest 风格的 http 协议访问方式,这种模式架构上会变得非常简单,通用的网关产品即可支持。 +* **通过网关实现 `http->dubbo` 协议转换**,这种方式需要将 http 协议转换为后端服务能识别的 dubbo 协议,要求网关必须支持 dubbo 协议。 + +## 同时发布 http、dubbo 协议 +**如果我们能让一个服务同时发布 dubbo、http 协议,这样后端调用是基于高效的 dubbo 二进制协议,同时浏览器、web服务等前端设施也可以用 http 协议访问到相同的服务。** 好消息是,Dubbo 框架支持为同一个服务发布多个协议,并且支持客户端通过同一个端口以不同的协议访问服务,如下所示: + + + +为了实现同时发布 dubbo、http 协议,我们只需要在配置文件中增加一行配置即可: + +```yaml +dubbo: + protocol: + dubbo: dubbo + port: 20880 + ext-protocol: tri +``` + +增加 `ext-protocol: tri` 配置后,进程就可以在 20880 端口上提供 http 服务了,这点我们从之前的 triple 协议中有过具体了解了,启用应用后就可以在 20880 端口访问: + +```shell +curl \ + --header "Content-Type: application/json" \ + --data '["Dubbo"]' \ + http://localhost:20880/org.apache.dubbo.protocol.multiple.demo.DemoService/sayHello +``` + +此时,网关就可以直接以 http 方式接入后端 dubbo 服务,任何 http 网关都可以非常容易接入,操作非常简洁明了。 + +{{% alert title="注意" color="info" %}} +另外,关于 dubbo、triple 多协议发布的完整示例源码和讲解可参见 [dubbo+rest 双协议发布的示例](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols/)。 +{{% /alert %}} + +如果你对 `/org.apache.dubbo.protocol.multiple.demo.DemoService/sayHello` 格式的前端访问路径不满意,可以选择发布 rest 风格的 http 接口,我们只需要在接口上增加注解即可(目前支持 Spring Web、JAX-RS 两种注解)。如下所示,假设我们已经有一个名为 DemoService 的 dubbo 服务,只需要增加以下注解: + +```java +@RestController +@RequestMapping("/triple") +public interface DemoService { + @GetMapping(value = "/demo") + String sayHello(); +} +``` + +这样,就能发布同时支持 dubbo、rest 两种协议的服务,对于 http 网关接入更为简单便捷,唯一成本是需要改造接口增加注解。 + +为 dubbo 协议服务增加了 http 访问方式之后,就可以很容易的将 dubbo 服务接入网关了,具体可以参见下一小节中的 [triple 协议网关接入](/zh-cn/overview/mannual/java-sdk/tasks/gateway/triple/) 示例,那里有详细的说明。 + +## http 转 dubbo 协议 +{{% alert title="注意" color="warning" %}} +如果您使用的是 Dubbo3 3.3.x 版本,在决定考虑此方案之前,我们强烈推荐您仔细评估本文前一节的 `多协议发布方案`。除非您因为某些特殊原因真的无法接受多协议发布带来的应用改造成本(实际上只是改一行配置而已),否则这个方案应该作为第二选择。 +{{% /alert %}} + +如果要从网关接入后端 dubbo 服务,则前端的 HTTP 流量要经过一层 `http -> dubbo` 的协议转换才能实现正常调用 + + + +如上图所示,从浏览器、手机或者 Web 服务器发送的 HTTP 请求,经过网关进行 http 到 dubbo 协议转换,网关最终转发 dubbo 协议到后端微服务集群。因此,我们需要一个支持 dubbo 协议转换的网关,来帮助实现协议转发,以下是该架构下网关需要实现的几个关键点: +* **协议转换**,支持 http 到 dubbo 的协议转换,包括参数映射。 +* **自动地址发现**,支持 Nacos、Zookeeper、Kubernetes 等主流注册中心,动态感知后端 dubbo 实例变化。 +* **结合 dubbo 协议的路由**,如在发起 dubbo 协议调用时,支持按照特定规则地址筛选、传递附加参数到 dubbo 后端服务。 + +目前市面上支持 dubbo 协议接入、且对以上三点提供比较完善支持的开源网关产品众多,包括大家 Higress、Apache APISIX、Apache Shenyu 等。接下来,让我们通过一些示例来了解网关产品搭配 Dubbo 的具体使用方法吧: +* [使用 Higress 代理 Dubbo 流量]({{< relref "../../../../../../blog/integration/how-to-proxy-dubbo-in-higress" >}}) +* [使用 Apache APISIX 代理 Dubbo 流量]({{< relref "../../../../../../blog/integration/how-to-proxy-dubbo-in-apache-apisix" >}}) +* [使用 Apache Shenyu 代理 Dubbo 流量]({{< relref "../../../../../../blog/integration/how-to-proxy-dubbo-in-apache-shenyu" >}}) + +如果您并没有使用现成的网关产品,而是使用自建的流量转换组件,您很有可能使用到了 Dubbo 框架中的 [**泛化调用**](/zh-cn/overview/mannual/java-sdk/tasks/framework/more/generic/) 机制,具体请参考相关文档了解详情。 diff --git a/content/en/overview/mannual/java-sdk/tasks/gateway/triple.md b/content/en/overview/mannual/java-sdk/tasks/gateway/triple.md new file mode 100644 index 000000000000..ef5ebe542cf4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/gateway/triple.md @@ -0,0 +1,256 @@ +--- +aliases: + - /zh/overview/tasks/ecosystem/gateway/ + - /zh-cn/overview/tasks/ecosystem/gateway/ +description: | + 通过 Higress 云原生网关实现 Dubbo Service 代理,支持 triple 协议。 +linkTitle: triple协议 +title: 通过网关将 http 流量接入 Dubbo 后端服务 +type: docs +weight: 3 +--- + +在 [triple协议规范](/zh-cn/overview/reference/protocols/triple-spec/) 中我们曾详细介绍了 triple 对于浏览器、网关的友好性设计,其中非常重要的一点是 triple 同时支持跑在 HTTP/1、HTTP/2 上: +* 在后端服务之间使用高效的 triple 二进制协议。 +* 对于前端接入层,则支持所有标准 HTTP 工具如 cURL 等以标准 `application/json` 、`application/yaml` 等格式请求后端服务。 + +接下来我们就看一下,对于前端 HTTP 流量而言,如何通过一些通用的网关产品快速接入后端的 triple 微服务体系。 + +{{% alert title="注意" color="warning" %}} +使用 triple 协议后,不再需要泛化调用、`http -> dubbo` 协议转换等步骤,任何主流的网关设备都可以通过 http 流量直接访问后端 triple 协议服务。 +具体参见 [发布 REST 风格的服务](../../protocols/rest/) +{{% /alert %}} + +## 原生 HTTP 接入 + + + +如上图所示,从浏览器、手机或 Web 服务器过来的 HTTP 请求,网关可直接转发给后端 Dubbo 服务,后端服务之间则继续走 triple 二进制协议。**由于进出网关的都是标准的 HTTP 流量,网关不需要做任何的私有协议转换工作,不需要任何定制化逻辑,只需专注于流量路由等职责即可。** + +在真正的生产环境下,**唯一需要网关解决的只剩下地址发现问题,即如何动态感知后端 triple 服务的实例变化?** 好消息是,目前几款主流的开源网关产品如 Apache APISIX、Higress 等普遍支持以 Nacos、Zookeeper、Kubernetes 作为 upstream 数据源。 + +以下我们以 `Higress + Nacos + Dubbo` 的典型用法为例,详细说明整套机制的工作流程。 + + + +### 启动示例应用 + +本示例完整源码请参见 [dubbo-samples-gateway-higress-triple](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-triple)。 + +该示例中定义并发布了一个定义为 `org.apache.dubbo.samples.gateway.api.DemoService` 的 triple 服务: + +```java +public interface DemoService { + String sayHello(String name); +} +``` + +接下来,我们演示如何启动 Dubbo 服务,并使用 Higress 网关转发请求到后端服务。 + +### 接入 Higress 网关 + +接下来,我们具体演示 Higress 网关接入应用的具体步骤。包括部署 Dubbo 应用、Nacos 注册中心、Higress 网关等。 + +#### 安装 Higress 和 Nacos + +以下示例部署在 Kubernetes 环境,因此请确保您已经连接到一个可用 Kubernetes 集群。 + +1. 安装 Higress,参考 [Higress安装部署文档](https://higress.io/zh-cn/docs/ops/deploy-by-helm) + +2. 安装 Nacos,运行 + +```shell +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-triple/deploy/nacos/Nacos.yaml +``` + +#### 启动 Dubbo 应用 + +将以上示例应用打包为 docker image 后(这里我们使用官方示例提前打包好的镜像),以标准 Kubernetes Deployment 形式启动应用: + +```shell +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-triple/deploy/provider/Deployment.yaml +``` + +具体的部署文件定义如下: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gateway-higress-triple-provider + namespace: default + labels: + app: gateway-higress-triple-provider +spec: + replicas: 1 + selector: + matchLabels: + app: gateway-higress-triple-provider + template: + metadata: + labels: + app: gateway-higress-triple-provider + spec: + containers: + - name: gateway-higress-triple-provider + image: docker.io/allenyi/higress-triple:2.0.0 + imagePullPolicy: IfNotPresent + ports: + # 与容器暴露的端口一致 + - containerPort: 50052 + env: + # 配置Nacos注册中心地址,对应Dubbo服务配置中的${nacos.address:127.0.0.1} + - name: NACOS_ADDRESS + value: nacos-server.default.svc.cluster.local +``` + +#### 通过 Higress 转发请求到 Dubbo 服务 + +Higress 可以通过 McpBridge 来对接 Nacos 作为服务来源,在 K8s 集群中 apply 以下资源来配置 McpBridge: + +```shell +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-triple/deploy/mcp/mcpbridge.yaml +``` + +以上安装的 McpBridge 资源的具体定义如下: + +```yaml +apiVersion: networking.higress.io/v1 +kind: McpBridge +metadata: + name: nacos-service-resource + namespace: higress-system +spec: + registries: + - domain: nacos-server.default.svc.cluster.local + nacosGroups: + - DEFAULT_GROUP + name: nacos-service-resource + port: 8848 + type: nacos2 +``` + +> 更多详细配置参考[McpBridge配置说明](https://higress.io/zh-cn/docs/user/mcp-bridge) + + +接下来我们创建如下 Ingress,从而创建一条指向 Dubbo 服务的 HTTP 路由: + +```shell +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-triple/deploy/ingress/Ingress.yaml +``` + +这样,path 前缀为 `/org.apache.dubbo.samples.gateway.api.DemoService` 的请求就会被路由到我们刚刚创建的 Dubbo 服务上。 + +以上 apply 安装的具体资源定义如下: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + higress.io/destination: gateway-higress-triple-provider.DEFAULT-GROUP.public.nacos + name: demo + namespace: default #与应用部署namespace保持一致 +spec: + ingressClassName: higress + rules: + - http: + paths: + - backend: + resource: + apiGroup: networking.higress.io + kind: McpBridge + name: default + path: /org.apache.dubbo.samples.gateway.api.DemoService + pathType: Prefix +``` + +注意这里通过注解 higress.io/destination 指定路由最终要转发到的目标服务: `gateway-higress-triple-provider`,gateway-higress-triple-provider 为刚刚启动 Dubbo 服务的应用名(这里依赖 Dubbo3 默认注册的应用粒度地址列表)。 + +对于 Nacos 来源的服务,这里的目标服务格式为:“服务名称.服务分组.命名空间ID.nacos”,注意这里需要遵循 DNS 域名格式,因此服务分组中的下划线'_'被转换成了横杠'-'。命名空间未指定时,这里默认值为"public"。 + +> 更多流量治理相关配置参考[Ingress Annotation 配置说明](https://higress.io/zh-cn/docs/user/annotation)和[通过Ingress Annotation实现高阶流量治理](https://higress.io/zh-cn/docs/user/annotation-use-case) + +### 请求验证 + +通过 cURL 访问 Higress,可以实现对 triple 后端服务的调用: + +```shell +$ curl "localhost/org.apache.dubbo.samples.gateway.api.DemoService/sayHello?name=HigressTriple" + +"Hello HigressTriple" +``` + +{{% alert title="注意" color="info" %}} +这里要运行 `kubectl port-forward service/higress-gateway -n higress-system 80:80 443:443` 将集群内的 Higress 暴露出来才可访问。 +{{% /alert %}} + +`/org.apache.dubbo.samples.gateway.api.DemoService/sayHello/` 这种根据 Java 路径名与方法直接暴露的访问路径,虽然可以很容易调通,但对于前端来说并不友好。接下来我们一起看一下如何发布 REST 风格的 HTTP 服务。 + +## REST 风格接口 + +在前面的示例中,如类似 `http://127.0.0.1:9080/triple/demo/hello` 会是更符合前端使用的访问方式,要做到这一点,我们可以通过在 Higress 等网关配置 uri rewrite 重写,实现前端 `/triple/demo/hello` 到后端 `/org.apache.dubbo.samples.gateway.api.DemoService/sayHello/` 的映射。 + +除了配置网关 rewrite 重新规则之外,**Dubbo 框架还为 triple 服务暴露 REST 风格的 HTTP 访问路径提供了内置支持**,具体使用方式取决于你使用的是基于 [protobuf 的服务定义模式](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/),还是基于 [java 接口的服务定义模式](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/interface/): +* Java 接口模式,通过直接为 java 接口增加注解可以同时发布 REST 风格服务,目前支持 Spring Web 与 JAX-RS 两套注解标准。 +* Protobuf 模式,通过使用 grpc-gateway 可发布 REST 风格服务。 + +### 为服务定义增加注解 +通过为 Java 接口增加以下任意一种注解,即可发布 triple 二进制、REST 风格的服务。这样配置之后,对于同一个服务,你既可以使用标准二进制 triple 格式访问服务,也可以使用 REST HTTP 方式以 JSON 格式访问服务。 + +Spring Web 风格注解: +```java +@RequestMapping("/triple/demo") +public interface DemoService { + + @RequestMapping(method = RequestMethod.GET, value = "/hello") + String sayHello(@RequestParam("name") String name); + +} +``` + +{{% alert title="注意" color="info" %}} +关于接口注解 +* 在之前的示例 [dubbo-samples-gateway-higress-triple](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-triple) 中已经启用,可查看源码了解实际用法。 +* 在[【进阶学习 - 协议 - rest】](/zh-cn/overview/mannual/java-sdk/tasks/protocols/rest/)一节中有详细的说明和使用示例,也可以前往查看。 +{{% /alert %}} + +这时我们的路由前缀配置如下,Nacos 地址配置与之前保持一致,path 前缀改为访问更为友好的 `/triple/demo`: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + higress.io/destination: gateway-higress-triple-provider.DEFAULT-GROUP.public.nacos + name: demo + namespace: default +spec: + ingressClassName: higress + rules: + - http: + paths: + - backend: + resource: + apiGroup: networking.higress.io + kind: McpBridge + name: default + path: /triple/demo + pathType: Prefix +``` + +可以使用 `/triple/demo/hello` 访问服务: + +```shell +$ curl "localhost/triple/demo/hello?name=HigressTriple" + +"Hello HigressTriple" +``` + +{{% alert title="注意" color="info" %}} +本文描述内容,仅适用于 Dubbo 3.3.0 之后发布的 triple 协议版本。 +{{% /alert %}} + +## 参考连接 +* [使用 Apache APISIX 代理 triple 协议流量](/zh-cn/blog/2024/04/22/使用-apache-apisix-代理-dubbo-服务triple协议/) +* [Higress 实现基于 http 协议微服务发现与路由配置](https://higress.io/zh-cn/docs/user/spring-cloud) \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/_index.md new file mode 100755 index 000000000000..ccce599fb53b --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/_index.md @@ -0,0 +1,44 @@ +--- +aliases: + - /zh/overview/tasks/mesh/ + - /zh-cn/overview/tasks/mesh/ +description: '演示多种部署形态的 Dubbo Mesh 解决方案,以及 Dubbo Mesh 如何帮助用户实现架构的平滑迁移。 ' +linkTitle: 服务网格 +no_list: true +title: 服务网格 +toc_hide: true +type: docs +weight: 70 +--- + + + +{{< blocks/section color="white" height="auto">}} +

+
+
+
+
+

+ Istio & Envoy 示例 +

+

演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系。

+
+
+
+
+
+
+

+ Istio & Proxyless 示例 +

+

演示 Dubbo Proxyless 接入 Istio 服务网格体系。

+
+
+
+
+
+
+ +{{< /blocks/section >}} diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/_index.md new file mode 100755 index 000000000000..7b5fde9e4b20 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/_index.md @@ -0,0 +1,48 @@ +--- +aliases: + - /zh/overview/tasks/mesh/bookinfo-proxyless/ + - /zh-cn/overview/tasks/mesh/bookinfo-proxyless/ +description: 通过完整的 Bookinfo 示例操作演示 Dubbo Proxyless 接入 Istio 服务网格体系。 +linkTitle: Proxyless Bookinfo +no_list: true +title: Proxyless Bookinfo 示例 +type: docs +weight: 70 +--- + + + +通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系。 + +{{< blocks/section color="white" height="auto">}} +{{< /blocks/section >}} + +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ Traffic Management +

+

Tasks that demonstrates how to use Istio's traffic routing features.

+
+
+
+
+
+
+

+ Security +

+

Demonstrates how to secure Dubbo proxyless mesh.

+
+
+
+
+
+
+ +{{< /blocks/section >}} diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/_index.md new file mode 100755 index 000000000000..c289f9e83829 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/_index.md @@ -0,0 +1,92 @@ +--- +aliases: + - /zh/overview/tasks/mesh/bookinfo-proxyless/security/ + - /zh-cn/overview/tasks/mesh/bookinfo-proxyless/security/ +description: Envoy Security Bookinfo 示例。 +linkTitle: security +no_list: true +title: Envoy Bookinfo 认证鉴权示例 +type: docs +weight: 20 +--- + + + +通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系,如何配置认证鉴权体系。 + +{{< blocks/section color="white" height="auto">}} +{{< /blocks/section >}} + +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ Request Routing +

+

This task shows you how to configure dynamic request routing to multiple versions of a microservice.

+
+
+
+
+
+
+

+ Traffic Shifting +

+

Shows you how to migrate traffic from an old to new version of a service.

+
+
+
+
+
+
+

+ TCP Traffic Shifting +

Shows you how to migrate TCP traffic from an old to new version of a TCP service.

+

+

+
+
+
+
+
+
+

+ Request Timeouts +

This task shows you how to set up request timeouts in Envoy using Istio.

+

+

+
+
+
+
+
+
+

+ Mirroring +

This task demonstrates the traffic mirroring/shadowing capabilities of Istio.

+

+

+
+
+
+
+
+
+

+ Locality Load Balancing +

This series of tasks demonstrate how to configure locality load balancing in Istio.

+

+

+
+
+
+
+
+
+ +{{< /blocks/section >}} diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/request-routing.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/request-routing.md new file mode 100644 index 000000000000..331e4113dee0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/request-routing.md @@ -0,0 +1,152 @@ +--- +aliases: + - /zh/overview/tasks/mesh/bookinfo-proxyless/security/request-routing/ + - /zh-cn/overview/tasks/mesh/bookinfo-proxyless/security/request-routing/ +description: This task shows you how to route requests dynamically to multiple versions of a microservice. +linkTitle: Request Routing +title: Request Routing +toc_hide: true +type: docs +weight: 1 +--- + + + +Before you begin +Setup Istio by following the instructions in the Installation guide. + +Deploy the Bookinfo sample application. + +Review the Traffic Management concepts doc. + +About this task +The Istio Bookinfo sample consists of four separate microservices, each with multiple versions. Three different versions of one of the microservices, reviews, have been deployed and are running concurrently. To illustrate the problem this causes, access the Bookinfo app’s /productpage in a browser and refresh several times. The URL is http://$GATEWAY_URL/productpage, where $GATEWAY_URL is the External IP address of the ingress, as explained in the Bookinfo doc. + +You’ll notice that sometimes the book review output contains star ratings and other times it does not. This is because without an explicit default service version to route to, Istio routes requests to all available versions in a round robin fashion. + +The initial goal of this task is to apply rules that route all traffic to v1 (version 1) of the microservices. Later, you will apply a rule to route traffic based on the value of an HTTP request header. + +Route to version 1 +To route to one version only, you configure route rules that send traffic to default versions for the microservices. + +If you haven’t already, follow the instructions in define the service versions. +Run the following command to create the route rules: +Istio classicGateway API +Istio uses virtual services to define route rules. Run the following command to apply virtual services that will route all traffic to v1 of each microservice: + +$ kubectl apply -f @samples/bookinfo/networking/virtual-service-all-v1.yaml@ +Because configuration propagation is eventually consistent, wait a few seconds for the virtual services to take effect. + +Display the defined routes with the following command: +Istio classicGateway API +$ kubectl get virtualservices -o yaml +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - details + http: + - route: + - destination: + host: details + subset: v1 +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - productpage + http: + - route: + - destination: + host: productpage + subset: v1 +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - ratings + http: + - route: + - destination: + host: ratings + subset: v1 +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v1 +You can also display the corresponding subset definitions with the following command: + +$ kubectl get destinationrules -o yaml +You have configured Istio to route to the v1 version of the Bookinfo microservices, most importantly the reviews service version 1. + +Test the new routing configuration +You can easily test the new configuration by once again refreshing the /productpage of the Bookinfo app in your browser. Notice that the reviews part of the page displays with no rating stars, no matter how many times you refresh. This is because you configured Istio to route all traffic for the reviews service to the version reviews:v1 and this version of the service does not access the star ratings service. + +You have successfully accomplished the first part of this task: route traffic to one version of a service. + +Route based on user identity +Next, you will change the route configuration so that all traffic from a specific user is routed to a specific service version. In this case, all traffic from a user named Jason will be routed to the service reviews:v2. + +This example is enabled by the fact that the productpage service adds a custom end-user header to all outbound HTTP requests to the reviews service. + +Istio also supports routing based on strongly authenticated JWT on ingress gateway, refer to the JWT claim based routing for more details. + +Remember, reviews:v2 is the version that includes the star ratings feature. + +Run the following command to enable user-based routing: +Istio classicGateway API +$ kubectl apply -f @samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml@ +You can confirm the rule is created using the following command: + +$ kubectl get virtualservice reviews -o yaml +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +... +spec: + hosts: + - reviews + http: + - match: + - headers: + end-user: + exact: jason + route: + - destination: + host: reviews + subset: v2 + - route: + - destination: + host: reviews + subset: v1 +On the /productpage of the Bookinfo app, log in as user jason. + +Refresh the browser. What do you see? The star ratings appear next to each review. + +Log in as another user (pick any name you wish). + +Refresh the browser. Now the stars are gone. This is because traffic is routed to reviews:v1 for all users except Jason. + +You have successfully configured Istio to route traffic based on user identity. + +Understanding what happened +In this task, you used Istio to send 100% of the traffic to the v1 version of each of the Bookinfo services. You then set a rule to selectively send traffic to version v2 of the reviews service based on a custom end-user header added to the request by the productpage service. + +Note that Kubernetes services, like the Bookinfo ones used in this task, must adhere to certain restrictions to take advantage of Istio’s L7 routing features. Refer to the Requirements for Pods and Services for details. + +In the traffic shifting task, you will follow the same basic pattern you learned here to configure route rules to gradually send traffic from one version of a service to another. + +Cleanup +Remove the application route rules: +Istio classicGateway API +$ kubectl delete -f @samples/bookinfo/networking/virtual-service-all-v1.yaml@ +If you are not planning to explore any follow-on tasks, refer to the Bookinfo cleanup instructions to shutdown the application. diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/_index.md new file mode 100755 index 000000000000..6eca306ef193 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/_index.md @@ -0,0 +1,92 @@ +--- +aliases: + - /zh/overview/tasks/mesh/bookinfo-proxyless/traffic/ + - /zh-cn/overview/tasks/mesh/bookinfo-proxyless/traffic/ +description: Envoy Traffic Management Bookinfo 示例。 +linkTitle: Traffic Management +no_list: true +title: Envoy Bookinfo 流量管控示例 +type: docs +weight: 10 +--- + + + +通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系,如何进行流量管理。 + +{{< blocks/section color="white" height="auto">}} +{{< /blocks/section >}} + +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ Request Routing +

+

This task shows you how to configure dynamic request routing to multiple versions of a microservice.

+
+
+
+
+
+
+

+ Traffic Shifting +

+

Shows you how to migrate traffic from an old to new version of a service.

+
+
+
+
+
+
+

+ TCP Traffic Shifting +

Shows you how to migrate TCP traffic from an old to new version of a TCP service.

+

+

+
+
+
+
+
+
+

+ Request Timeouts +

This task shows you how to set up request timeouts in Envoy using Istio.

+

+

+
+
+
+
+
+
+

+ Mirroring +

This task demonstrates the traffic mirroring/shadowing capabilities of Istio.

+

+

+
+
+
+
+
+
+

+ Locality Load Balancing +

This series of tasks demonstrate how to configure locality load balancing in Istio.

+

+

+
+
+
+
+
+
+ +{{< /blocks/section >}} diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/request-routing.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/request-routing.md new file mode 100644 index 000000000000..0dbdd0fd657f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/request-routing.md @@ -0,0 +1,152 @@ +--- +aliases: + - /zh/overview/tasks/mesh/bookinfo-proxyless/traffic/request-routing/ + - /zh-cn/overview/tasks/mesh/bookinfo-proxyless/traffic/request-routing/ +description: This task shows you how to route requests dynamically to multiple versions of a microservice. +linkTitle: Request Routing +title: Request Routing +toc_hide: true +type: docs +weight: 1 +--- + + + +Before you begin +Setup Istio by following the instructions in the Installation guide. + +Deploy the Bookinfo sample application. + +Review the Traffic Management concepts doc. + +About this task +The Istio Bookinfo sample consists of four separate microservices, each with multiple versions. Three different versions of one of the microservices, reviews, have been deployed and are running concurrently. To illustrate the problem this causes, access the Bookinfo app’s /productpage in a browser and refresh several times. The URL is http://$GATEWAY_URL/productpage, where $GATEWAY_URL is the External IP address of the ingress, as explained in the Bookinfo doc. + +You’ll notice that sometimes the book review output contains star ratings and other times it does not. This is because without an explicit default service version to route to, Istio routes requests to all available versions in a round robin fashion. + +The initial goal of this task is to apply rules that route all traffic to v1 (version 1) of the microservices. Later, you will apply a rule to route traffic based on the value of an HTTP request header. + +Route to version 1 +To route to one version only, you configure route rules that send traffic to default versions for the microservices. + +If you haven’t already, follow the instructions in define the service versions. +Run the following command to create the route rules: +Istio classicGateway API +Istio uses virtual services to define route rules. Run the following command to apply virtual services that will route all traffic to v1 of each microservice: + +$ kubectl apply -f @samples/bookinfo/networking/virtual-service-all-v1.yaml@ +Because configuration propagation is eventually consistent, wait a few seconds for the virtual services to take effect. + +Display the defined routes with the following command: +Istio classicGateway API +$ kubectl get virtualservices -o yaml +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - details + http: + - route: + - destination: + host: details + subset: v1 +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - productpage + http: + - route: + - destination: + host: productpage + subset: v1 +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - ratings + http: + - route: + - destination: + host: ratings + subset: v1 +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v1 +You can also display the corresponding subset definitions with the following command: + +$ kubectl get destinationrules -o yaml +You have configured Istio to route to the v1 version of the Bookinfo microservices, most importantly the reviews service version 1. + +Test the new routing configuration +You can easily test the new configuration by once again refreshing the /productpage of the Bookinfo app in your browser. Notice that the reviews part of the page displays with no rating stars, no matter how many times you refresh. This is because you configured Istio to route all traffic for the reviews service to the version reviews:v1 and this version of the service does not access the star ratings service. + +You have successfully accomplished the first part of this task: route traffic to one version of a service. + +Route based on user identity +Next, you will change the route configuration so that all traffic from a specific user is routed to a specific service version. In this case, all traffic from a user named Jason will be routed to the service reviews:v2. + +This example is enabled by the fact that the productpage service adds a custom end-user header to all outbound HTTP requests to the reviews service. + +Istio also supports routing based on strongly authenticated JWT on ingress gateway, refer to the JWT claim based routing for more details. + +Remember, reviews:v2 is the version that includes the star ratings feature. + +Run the following command to enable user-based routing: +Istio classicGateway API +$ kubectl apply -f @samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml@ +You can confirm the rule is created using the following command: + +$ kubectl get virtualservice reviews -o yaml +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +... +spec: + hosts: + - reviews + http: + - match: + - headers: + end-user: + exact: jason + route: + - destination: + host: reviews + subset: v2 + - route: + - destination: + host: reviews + subset: v1 +On the /productpage of the Bookinfo app, log in as user jason. + +Refresh the browser. What do you see? The star ratings appear next to each review. + +Log in as another user (pick any name you wish). + +Refresh the browser. Now the stars are gone. This is because traffic is routed to reviews:v1 for all users except Jason. + +You have successfully configured Istio to route traffic based on user identity. + +Understanding what happened +In this task, you used Istio to send 100% of the traffic to the v1 version of each of the Bookinfo services. You then set a rule to selectively send traffic to version v2 of the reviews service based on a custom end-user header added to the request by the productpage service. + +Note that Kubernetes services, like the Bookinfo ones used in this task, must adhere to certain restrictions to take advantage of Istio’s L7 routing features. Refer to the Requirements for Pods and Services for details. + +In the traffic shifting task, you will follow the same basic pattern you learned here to configure route rules to gradually send traffic from one version of a service to another. + +Cleanup +Remove the application route rules: +Istio classicGateway API +$ kubectl delete -f @samples/bookinfo/networking/virtual-service-all-v1.yaml@ +If you are not planning to explore any follow-on tasks, refer to the Bookinfo cleanup instructions to shutdown the application. diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/_index.md new file mode 100755 index 000000000000..5d1be6f6d536 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/_index.md @@ -0,0 +1,48 @@ +--- +aliases: + - /zh/overview/tasks/mesh/bookinfo-sidecar/ + - /zh-cn/overview/tasks/mesh/bookinfo-sidecar/ +description: 通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系。 +linkTitle: Envoy Bookinfo +no_list: true +title: Envoy Bookinfo 示例 +type: docs +weight: 70 +--- + + + +通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系。 + +{{< blocks/section color="white" height="auto">}} +{{< /blocks/section >}} + +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ Traffic Management +

+

Tasks that demonstrates how to use Istio's traffic routing features.

+
+
+
+
+
+
+

+ Security +

+

Demonstrates how to secure Dubbo mesh.

+
+
+
+
+
+
+ +{{< /blocks/section >}} diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/_index.md new file mode 100755 index 000000000000..a3f7360997dd --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/_index.md @@ -0,0 +1,92 @@ +--- +aliases: + - /zh/overview/tasks/mesh/bookinfo-sidecar/security/ + - /zh-cn/overview/tasks/mesh/bookinfo-sidecar/security/ +description: Envoy Security Bookinfo 示例。 +linkTitle: security +no_list: true +title: Envoy Bookinfo 认证鉴权示例 +type: docs +weight: 20 +--- + + + +通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系,如何配置认证鉴权体系。 + +{{< blocks/section color="white" height="auto">}} +{{< /blocks/section >}} + +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ Request Routing +

+

This task shows you how to configure dynamic request routing to multiple versions of a microservice.

+
+
+
+
+
+
+

+ Traffic Shifting +

+

Shows you how to migrate traffic from an old to new version of a service.

+
+
+
+
+
+
+

+ TCP Traffic Shifting +

Shows you how to migrate TCP traffic from an old to new version of a TCP service.

+

+

+
+
+
+
+
+
+

+ Request Timeouts +

This task shows you how to set up request timeouts in Envoy using Istio.

+

+

+
+
+
+
+
+
+

+ Mirroring +

This task demonstrates the traffic mirroring/shadowing capabilities of Istio.

+

+

+
+
+
+
+
+
+

+ Locality Load Balancing +

This series of tasks demonstrate how to configure locality load balancing in Istio.

+

+

+
+
+
+
+
+
+ +{{< /blocks/section >}} diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/request-routing.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/request-routing.md new file mode 100644 index 000000000000..1fe3ef2259e6 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/request-routing.md @@ -0,0 +1,152 @@ +--- +aliases: + - /zh/overview/tasks/mesh/bookinfo-sidecar/security/request-routing/ + - /zh-cn/overview/tasks/mesh/bookinfo-sidecar/security/request-routing/ +description: This task shows you how to route requests dynamically to multiple versions of a microservice. +linkTitle: Request Routing +title: Request Routing +toc_hide: true +type: docs +weight: 1 +--- + + + +Before you begin +Setup Istio by following the instructions in the Installation guide. + +Deploy the Bookinfo sample application. + +Review the Traffic Management concepts doc. + +About this task +The Istio Bookinfo sample consists of four separate microservices, each with multiple versions. Three different versions of one of the microservices, reviews, have been deployed and are running concurrently. To illustrate the problem this causes, access the Bookinfo app’s /productpage in a browser and refresh several times. The URL is http://$GATEWAY_URL/productpage, where $GATEWAY_URL is the External IP address of the ingress, as explained in the Bookinfo doc. + +You’ll notice that sometimes the book review output contains star ratings and other times it does not. This is because without an explicit default service version to route to, Istio routes requests to all available versions in a round robin fashion. + +The initial goal of this task is to apply rules that route all traffic to v1 (version 1) of the microservices. Later, you will apply a rule to route traffic based on the value of an HTTP request header. + +Route to version 1 +To route to one version only, you configure route rules that send traffic to default versions for the microservices. + +If you haven’t already, follow the instructions in define the service versions. +Run the following command to create the route rules: +Istio classicGateway API +Istio uses virtual services to define route rules. Run the following command to apply virtual services that will route all traffic to v1 of each microservice: + +$ kubectl apply -f @samples/bookinfo/networking/virtual-service-all-v1.yaml@ +Because configuration propagation is eventually consistent, wait a few seconds for the virtual services to take effect. + +Display the defined routes with the following command: +Istio classicGateway API +$ kubectl get virtualservices -o yaml +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - details + http: + - route: + - destination: + host: details + subset: v1 +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - productpage + http: + - route: + - destination: + host: productpage + subset: v1 +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - ratings + http: + - route: + - destination: + host: ratings + subset: v1 +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v1 +You can also display the corresponding subset definitions with the following command: + +$ kubectl get destinationrules -o yaml +You have configured Istio to route to the v1 version of the Bookinfo microservices, most importantly the reviews service version 1. + +Test the new routing configuration +You can easily test the new configuration by once again refreshing the /productpage of the Bookinfo app in your browser. Notice that the reviews part of the page displays with no rating stars, no matter how many times you refresh. This is because you configured Istio to route all traffic for the reviews service to the version reviews:v1 and this version of the service does not access the star ratings service. + +You have successfully accomplished the first part of this task: route traffic to one version of a service. + +Route based on user identity +Next, you will change the route configuration so that all traffic from a specific user is routed to a specific service version. In this case, all traffic from a user named Jason will be routed to the service reviews:v2. + +This example is enabled by the fact that the productpage service adds a custom end-user header to all outbound HTTP requests to the reviews service. + +Istio also supports routing based on strongly authenticated JWT on ingress gateway, refer to the JWT claim based routing for more details. + +Remember, reviews:v2 is the version that includes the star ratings feature. + +Run the following command to enable user-based routing: +Istio classicGateway API +$ kubectl apply -f @samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml@ +You can confirm the rule is created using the following command: + +$ kubectl get virtualservice reviews -o yaml +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +... +spec: + hosts: + - reviews + http: + - match: + - headers: + end-user: + exact: jason + route: + - destination: + host: reviews + subset: v2 + - route: + - destination: + host: reviews + subset: v1 +On the /productpage of the Bookinfo app, log in as user jason. + +Refresh the browser. What do you see? The star ratings appear next to each review. + +Log in as another user (pick any name you wish). + +Refresh the browser. Now the stars are gone. This is because traffic is routed to reviews:v1 for all users except Jason. + +You have successfully configured Istio to route traffic based on user identity. + +Understanding what happened +In this task, you used Istio to send 100% of the traffic to the v1 version of each of the Bookinfo services. You then set a rule to selectively send traffic to version v2 of the reviews service based on a custom end-user header added to the request by the productpage service. + +Note that Kubernetes services, like the Bookinfo ones used in this task, must adhere to certain restrictions to take advantage of Istio’s L7 routing features. Refer to the Requirements for Pods and Services for details. + +In the traffic shifting task, you will follow the same basic pattern you learned here to configure route rules to gradually send traffic from one version of a service to another. + +Cleanup +Remove the application route rules: +Istio classicGateway API +$ kubectl delete -f @samples/bookinfo/networking/virtual-service-all-v1.yaml@ +If you are not planning to explore any follow-on tasks, refer to the Bookinfo cleanup instructions to shutdown the application. diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/_index.md new file mode 100755 index 000000000000..0d89f84427f3 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/_index.md @@ -0,0 +1,92 @@ +--- +aliases: + - /zh/overview/tasks/mesh/bookinfo-sidecar/traffic/ + - /zh-cn/overview/tasks/mesh/bookinfo-sidecar/traffic/ +description: Envoy Traffic Management Bookinfo 示例。 +linkTitle: Traffic Management +no_list: true +title: Envoy Bookinfo 流量管控示例 +type: docs +weight: 10 +--- + + + +通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系,如何进行流量管理。 + +{{< blocks/section color="white" height="auto">}} +{{< /blocks/section >}} + +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ Request Routing +

+

This task shows you how to configure dynamic request routing to multiple versions of a microservice.

+
+
+
+
+
+
+

+ Traffic Shifting +

+

Shows you how to migrate traffic from an old to new version of a service.

+
+
+
+
+
+
+

+ TCP Traffic Shifting +

Shows you how to migrate TCP traffic from an old to new version of a TCP service.

+

+

+
+
+
+
+
+
+

+ Request Timeouts +

This task shows you how to set up request timeouts in Envoy using Istio.

+

+

+
+
+
+
+
+
+

+ Mirroring +

This task demonstrates the traffic mirroring/shadowing capabilities of Istio.

+

+

+
+
+
+
+
+
+

+ Locality Load Balancing +

This series of tasks demonstrate how to configure locality load balancing in Istio.

+

+

+
+
+
+
+
+
+ +{{< /blocks/section >}} diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/request-routing.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/request-routing.md new file mode 100644 index 000000000000..c2e66be1380d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/request-routing.md @@ -0,0 +1,152 @@ +--- +aliases: + - /zh/overview/tasks/mesh/bookinfo-sidecar/traffic/request-routing/ + - /zh-cn/overview/tasks/mesh/bookinfo-sidecar/traffic/request-routing/ +description: This task shows you how to route requests dynamically to multiple versions of a microservice. +linkTitle: Request Routing +title: Request Routing +toc_hide: true +type: docs +weight: 1 +--- + + + +Before you begin +Setup Istio by following the instructions in the Installation guide. + +Deploy the Bookinfo sample application. + +Review the Traffic Management concepts doc. + +About this task +The Istio Bookinfo sample consists of four separate microservices, each with multiple versions. Three different versions of one of the microservices, reviews, have been deployed and are running concurrently. To illustrate the problem this causes, access the Bookinfo app’s /productpage in a browser and refresh several times. The URL is http://$GATEWAY_URL/productpage, where $GATEWAY_URL is the External IP address of the ingress, as explained in the Bookinfo doc. + +You’ll notice that sometimes the book review output contains star ratings and other times it does not. This is because without an explicit default service version to route to, Istio routes requests to all available versions in a round robin fashion. + +The initial goal of this task is to apply rules that route all traffic to v1 (version 1) of the microservices. Later, you will apply a rule to route traffic based on the value of an HTTP request header. + +Route to version 1 +To route to one version only, you configure route rules that send traffic to default versions for the microservices. + +If you haven’t already, follow the instructions in define the service versions. +Run the following command to create the route rules: +Istio classicGateway API +Istio uses virtual services to define route rules. Run the following command to apply virtual services that will route all traffic to v1 of each microservice: + +$ kubectl apply -f @samples/bookinfo/networking/virtual-service-all-v1.yaml@ +Because configuration propagation is eventually consistent, wait a few seconds for the virtual services to take effect. + +Display the defined routes with the following command: +Istio classicGateway API +$ kubectl get virtualservices -o yaml +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - details + http: + - route: + - destination: + host: details + subset: v1 +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - productpage + http: + - route: + - destination: + host: productpage + subset: v1 +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - ratings + http: + - route: + - destination: + host: ratings + subset: v1 +- apiVersion: networking.istio.io/v1beta1 + kind: VirtualService + ... + spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v1 +You can also display the corresponding subset definitions with the following command: + +$ kubectl get destinationrules -o yaml +You have configured Istio to route to the v1 version of the Bookinfo microservices, most importantly the reviews service version 1. + +Test the new routing configuration +You can easily test the new configuration by once again refreshing the /productpage of the Bookinfo app in your browser. Notice that the reviews part of the page displays with no rating stars, no matter how many times you refresh. This is because you configured Istio to route all traffic for the reviews service to the version reviews:v1 and this version of the service does not access the star ratings service. + +You have successfully accomplished the first part of this task: route traffic to one version of a service. + +Route based on user identity +Next, you will change the route configuration so that all traffic from a specific user is routed to a specific service version. In this case, all traffic from a user named Jason will be routed to the service reviews:v2. + +This example is enabled by the fact that the productpage service adds a custom end-user header to all outbound HTTP requests to the reviews service. + +Istio also supports routing based on strongly authenticated JWT on ingress gateway, refer to the JWT claim based routing for more details. + +Remember, reviews:v2 is the version that includes the star ratings feature. + +Run the following command to enable user-based routing: +Istio classicGateway API +$ kubectl apply -f @samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml@ +You can confirm the rule is created using the following command: + +$ kubectl get virtualservice reviews -o yaml +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +... +spec: + hosts: + - reviews + http: + - match: + - headers: + end-user: + exact: jason + route: + - destination: + host: reviews + subset: v2 + - route: + - destination: + host: reviews + subset: v1 +On the /productpage of the Bookinfo app, log in as user jason. + +Refresh the browser. What do you see? The star ratings appear next to each review. + +Log in as another user (pick any name you wish). + +Refresh the browser. Now the stars are gone. This is because traffic is routed to reviews:v1 for all users except Jason. + +You have successfully configured Istio to route traffic based on user identity. + +Understanding what happened +In this task, you used Istio to send 100% of the traffic to the v1 version of each of the Bookinfo services. You then set a rule to selectively send traffic to version v2 of the reviews service based on a custom end-user header added to the request by the productpage service. + +Note that Kubernetes services, like the Bookinfo ones used in this task, must adhere to certain restrictions to take advantage of Istio’s L7 routing features. Refer to the Requirements for Pods and Services for details. + +In the traffic shifting task, you will follow the same basic pattern you learned here to configure route rules to gradually send traffic from one version of a service to another. + +Cleanup +Remove the application route rules: +Istio classicGateway API +$ kubectl delete -f @samples/bookinfo/networking/virtual-service-all-v1.yaml@ +If you are not planning to explore any follow-on tasks, refer to the Bookinfo cleanup instructions to shutdown the application. diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/_index.md new file mode 100755 index 000000000000..ed0ca6513731 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/_index.md @@ -0,0 +1,43 @@ +--- +aliases: + - /zh/overview/tasks/mesh/migration/ + - /zh-cn/overview/tasks/mesh/migration/ +description: 演示 Dubbo Mesh 如何帮助用户实现架构的平滑迁移。 +linkTitle: Dubbo2 平滑迁移 +no_list: true +title: 传统 Dubbo 微服务集群如何平滑迁移到 Istio 服务网格体系 +type: docs +weight: 70 +--- + + + +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ 地址同步问题 +

+

如何解决地址同步问题?

+
+
+
+
+
+
+

+ 协议识别问题 +

+

如何解决 Dubbo2+hessian2 协议问题?

+
+
+
+
+
+
+ +{{< /blocks/section >}} diff --git a/content/en/overview/tasks/kubernetes/deploy-on-k8s.md b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/deploy-on-k8s.md similarity index 51% rename from content/en/overview/tasks/kubernetes/deploy-on-k8s.md rename to content/en/overview/mannual/java-sdk/tasks/mesh/migration/deploy-on-k8s.md index 1e3340d1736b..1dd6ba058287 100644 --- a/content/en/overview/tasks/kubernetes/deploy-on-k8s.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/deploy-on-k8s.md @@ -1,128 +1,130 @@ --- +aliases: + - /zh/overview/tasks/mesh/migration/deploy-on-k8s/ + - /zh-cn/overview/tasks/mesh/migration/deploy-on-k8s/ +description: 该示例演示了直接以 API-SERVER 为注册中心,将 Dubbo 应用部署到 Kubernetes 并复用 Kubernetes Native Service 的使用示例。 此示例的局限在于需要授予每个 Dubbo 应用访问 API-SERVER 特定资源的权限,同时直接访问和监听 API-SERVER 对中小集群来说并没有什么问题, 但对于较大规模集群而言可能给 API-SERVER 的稳定性带来一定的考验。除此之外,可以考虑配合 Dubbo 控制面将 Dubbo 应用部署到 Kuberntes 的方案, 该方案无需授予 Dubbo 应用访问 API-SERVER 的权限,也无需为 API-SERVER 引连接过多数据面造成的稳定性而担心。 +linkTitle: 协议识别 +title: 协议识别 type: docs -title: "Deploying to Kubernetes" -linkTitle: "Native K8S Service based on API-SERVER" weight: 2 -description: "This example demonstrates the usage example of deploying Dubbo application to Kubernetes and reusing Kubernetes Native Service directly using API-SERVER as the registration center. -The limitation of this example is that each Dubbo application needs to be granted permission to access specific resources of the API-SERVER. At the same time, direct access and monitoring of the API-SERVER is not a problem for small and medium clusters. -However, for larger-scale clusters, it may bring certain challenges to the stability of API-SERVER. In addition, you can consider deploying Dubbo applications to Kuberntes with the Dubbo control plane. -This solution does not need to grant the Dubbo application permission to access the API-SERVER, nor does it need to worry about the stability caused by the API-SERVER connecting too many data planes. " --- -You can follow the steps below to easily deploy the Dubbo service to the Kubernetes cluster. Check out the [full code sample address](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry /dubbo-samples-kubernetes) -## 1 Overall Objective -* Deploy Dubbo application to Kubernetes -* Realize service discovery based on Kubernetes built-in Service -* Connect Dubbo application to Kubernetes life cycle +可以按照下文步骤,将 Dubbo 服务轻松部署到 Kubernetes 集群,此查看文章用到的 [完整代码示例地址](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-kubernetes) -## 2 Basic process +## 1 总体目标 -1. Create a Dubbo - Application ( [dubbo-samples-kubernetes](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-kubernetes) ) -2. Build the container image and push it to the mirror warehouse ( [dubbo-demo example image](https://hub.docker.com/r/apache/dubbo-demo) ) -3. Deploy Dubbo Provider and Dubbo Consumer to Kubernetes respectively -4. Verify that service discovery and calling are normal +* 部署 Dubbo 应用到 Kubernetes +* 基于 Kubernetes 内置 Service 实现服务发现 +* 将 Dubbo 应用对接到 Kubernetes 生命周期 -## 3 detailed steps +## 2 基本流程 -### 3.1 Environmental requirements +1. 创建一个 Dubbo + 应用( [dubbo-samples-kubernetes](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-kubernetes) ) +2. 构建容器镜像并推送到镜像仓库( [dubbo-demo 示例例镜像](https://hub.docker.com/r/apache/dubbo-demo) ) +3. 分别部署 Dubbo Provider 与 Dubbo Consumer 到 Kubernetes +4. 验证服务发现与调用正常 -Please ensure that the following environment is installed locally to provide container runtime, Kubernetes cluster and access tools +## 3 详细步骤 + +### 3.1 环境要求 + +请确保本地安装如下环境,以提供容器运行时、Kubernetes集群及访问工具 * [Docker](https://www.docker.com/get-started/) * [Minikube](https://minikube.sigs.k8s.io/docs/start/) * [Kubectl](https://kubernetes.io/docs/tasks/tools/) * [Kubens(optional)](https://github.com/ahmetb/kubectx) -Start the local Kubernetes cluster with the following command +通过以下命令启动本地 Kubernetes 集群 ```shell minikube start ``` -Check that the cluster is up and running with kubectl, and that kubectl is bound to the default local cluster +通过 kubectl 检查集群正常运行,且 kubectl 绑定到默认本地集群 ```shell kubectl cluster-info ``` -### 3.2 Preconditions +### 3.2 前置条件 -Since the sample Dubbo projects are all deployed in Pods and interact with API-SERVER, there are corresponding permission requirements. Here we create an independent ServiceAccount and bind the necessary Roles. All Dubbo Kubernetes later -All resources will use the newly created ServiceAccount here. +由于示例 Dubbo 项目均部署在 Pod 中且与 API-SERVER 有交互,因此有相应的权限要求,我们这里创建独立 ServiceAccount 并绑定必须的 Roles,后面所有的 Dubbo Kubernetes +资源都将使用这里新建的 ServiceAccount。 -Through the following commands, we have created an independent Namespace `dubbo-demo` and ServiceAccount `dubbo-sa`. +通过以下命令我们创建了独立的 Namespace `dubbo-demo` 与 ServiceAccount `dubbo-sa`。 ```shell -# Initialize namespace and account +# 初始化命名空间和账号 kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-kubernetes/dubbo-samples-apiserver-provider/src/main/resources/k8s/ServiceAccount.yml -# switch namespace +# 切换命名空间 kubens dubbo-demo ``` -### 3.3 Deploy to Kubernetes +### 3.3 部署到 Kubernetes -#### 3.3.1 Deploy Provider +#### 3.3.1 部署 Provider ```shell -# Deploy the Service +# 部署 Service kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-kubernetes/dubbo-samples-apiserver-provider/src/main/resources/k8s/Service.yml -# Deploy Deployment +# 部署 Deployment kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-kubernetes/dubbo-samples-apiserver-provider/src/main/resources/k8s/Deployment.yml ``` -The above command creates a Service named `dubbo-samples-apiserver-provider`, note that the service name here is the same as the dubbo application name in the project. +以上命令创建了一个名为 `dubbo-samples-apiserver-provider` 的 Service,注意这里的 service name 与项目中的 dubbo 应用名是一样的。 -Then Deployment deploys a 3-copy pod instance, and the Provider is started. -You can check the startup log with the following command. +接着 Deployment 部署了一个 3 副本的 pod 实例,至此 Provider 启动完成。 +可以通过如下命令检查启动日志。 ```shell -# View pod list +# 查看 pod 列表 kubectl get pods -l app=dubbo-samples-apiserver-provider -# View pod deployment logs +# 查看 pod 部署日志 kubectl logs your-pod-id ``` -#### 3.3.2 Deploy Consumer +#### 3.3.2 部署 Consumer ```shell -# Deploy the Service +# 部署 Service kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-kubernetes/dubbo-samples-apiserver-consumer/src/main/resources/k8s/Service.yml -# Deploy Deployment +# 部署 Deployment kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-kubernetes/dubbo-samples-apiserver-consumer/src/main/resources/k8s/Deployment.yml ``` -Deploying consumer and provider is the same, here also keep K8S Service and Dubbo consumer name consistent: dubbo-samples-apiserver-consumer. +部署 consumer 与 provider 是一样的,这里也保持了 K8S Service 与 Dubbo consumer 名字一致: dubbo-samples-apiserver-consumer。 -Check the startup log, the consumer completes the consumption of the provider service. +检查启动日志,consumer 完成对 provider 服务的消费。 ```shell -# View pod list +# 查看 pod 列表 kubectl get pods -l app=dubbo-samples-apiserver-consumer -# View pod deployment logs +# 查看 pod 部署日志 kubectl logs your-pod-id ``` -You can see the log output as follows: +可以看到日志输出如下: ```java -[22/04/22 01:10:24:024UTC]main INFO deploy.DefaultApplicationDeployer:[DUBBO]Dubbo Application[1.1](dubbo-samples-apiserver-consumer) is ready.,dubbo version:3.0.7,current host :172.17.0.6 - result: hello, Kubernetes Api Server +[22/04/22 01:10:24:024UTC]main INFO deploy.DefaultApplicationDeployer:[DUBBO]Dubbo Application[1.1](dubbo-samples-apiserver-consumer)is ready.,dubbo version:3.0.7,current host:172.17.0.6 + result:hello,Kubernetes Api Server ``` -### 3.4 Modify the project and package it (can be skipped) +### 3.4 修改项目并打包(可跳过) -The sample project and related images are ready, this section is only for users who need to modify the sample and see the deployment effect. Check here [full code sample address](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-kubernetes) +示例项目及相关镜像均已就绪,此小节仅面向需要修改示例并查看部署效果的用户。在此查看[完整代码示例地址](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-kubernetes) -Set the Dubbo project to use Kubernetes as the registration center. Here, DEFAULT_MASTER_HOST specifies the default API-SERVER cluster address kubernetes.default.srv, and also specifies -namespace, trustCerts two parameters +设置 Dubbo 项目使用 Kubernetes 作为注册中心,这里通过 DEFAULT_MASTER_HOST指定使用默认 API-SERVER 集群地址 kubernetes.default.srv,同时还指定了 +namespace、trustCerts 两个参数 ```properties dubbo.application.name=dubbo-samples-apiserver-provider @@ -135,25 +137,25 @@ dubbo.application.qosAcceptForeignIp=true dubbo.provider.token=true ``` -If you want to package the image locally, you can use the jib-maven-plugin plugin to package the image +如果要在本地打包镜像,可通过 jib-maven-plugin 插件打包镜像 ```shell -# Package and push the image +# 打包并推送镜像 mvn compile jib:build ``` -> The Jib plugin will automatically package and publish the image. Note that for local development, you need to change the docker registry organization apache/dubbo-demo in the jib plug-in configuration to an organization with your own authority (including dubboteam in other kubernetes manifests to ensure that kubernetes deploys your own customized image) , if you encounter jib plug-in authentication problems, please refer to [corresponding link](https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md#what-should-i-do-when-the- registry-responds-with-unauthorized) to configure docker registry authentication information. -> You can specify `mvn compile jib:build -Djib.to.auth.username=x -Djib.to.auth.password=x -Djib.from.auth.username=x -Djib.from.auth directly on the command line .username=x`, or use docker-credential-helper. +> Jib 插件会自动打包并发布镜像。注意,本地开发需将 jib 插件配置中的 docker registry 组织 apache/dubbo-demo 改为自己有权限的组织(包括其他 kubernetes manifests 中的 dubboteam 也要修改,以确保 kubernetes 部署的是自己定制后的镜像),如遇到 jib 插件认证问题,请参考[相应链接](https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md#what-should-i-do-when-the-registry-responds-with-unauthorized)配置 docker registry 认证信息。 +> 可以通过直接在命令行指定 `mvn compile jib:build -Djib.to.auth.username=x -Djib.to.auth.password=x -Djib.from.auth.username=x -Djib.from.auth.username=x`,或者使用 docker-credential-helper. -## 4 Best Practices +## 4 最佳实践 TBD * rediness probe * liveness probe -* ci/cd access to Skalfold +* ci/cd 接入 Skalfold -## 5 Appendix k8s manifests +## 5 附录 k8s manifests ServiceAccount.yml @@ -318,4 +320,4 @@ spec: port: 22222 failureThreshold: 30 periodSeconds: 10 -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/dubbo-mesh.md b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/dubbo-mesh.md new file mode 100644 index 000000000000..2160c8358e30 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/dubbo-mesh.md @@ -0,0 +1,302 @@ +--- +aliases: + - /zh/overview/tasks/mesh/migration/dubbo-mesh/ + - /zh-cn/overview/tasks/mesh/migration/dubbo-mesh/ +description: 本示例演示了如何使用 Istio+Envoy 的 Service Mesh 部署模式开发 Dubbo3 服务。Dubbo3 服务使用 Triple 作为通信协议,通信过程经过 Envoy 数据面拦截,同时使用标准 Istio 的流量治理能力治理 Dubbo。 +linkTitle: 地址同步 +title: 地址同步 +type: docs +weight: 1 +--- + + + +遵循以下步骤,可以轻松掌握如何开发符合 Service Mesh 架构的 Dubbo 服务,并将其部署到 Kubernetes 并接入 Istio 的流量治理体系。在此查看 [完整示例源码](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-mesh-k8s) + +## 1 总体目标 + +* 部署 Dubbo 应用到 Kubernetes +* Istio 自动注入 Envoy 并实现流量拦截 +* 基于 Istio 规则进行流量治理 + +## 2 基本流程与工作原理 +这个示例演示了如何将 Dubbo 开发的应用部署在 Istio 体系下,以实现 Envoy 对 Dubbo 服务的自动代理,示例总体架构如下图所示。 + +![thinsdk](/imgs/v3/mesh/thinsdk-envoy.png) + +完成示例将需要的步骤如下: + +1. 创建一个 Dubbo 应用( [dubbo-samples-mesh-k8s](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-mesh-k8s) ) +2. 构建容器镜像并推送到镜像仓库( [本示例官方镜像](https://hub.docker.com/r/apache/dubbo-demo) ) +3. 分别部署 Dubbo Provider 与 Dubbo Consumer 到 Kubernetes 并验证 Envoy 代理注入成功 +4. 验证 Envoy 发现服务地址、正常拦截 RPC 流量并实现负载均衡 +5. 基于 Istio VirtualService 实现按比例流量转发 + +## 3 详细步骤 + +### 3.1 环境要求 + +请确保本地安装如下环境,以提供容器运行时、Kubernetes集群及访问工具 + +* [Docker](https://www.docker.com/get-started/) +* [Minikube](https://minikube.sigs.k8s.io/docs/start/) +* [Kubectl](https://kubernetes.io/docs/tasks/tools/) +* [Istio](https://istio.io/latest/docs/setup/getting-started/) +* [Kubens(optional)](https://github.com/ahmetb/kubectx) + +通过以下命令启动本地 Kubernetes 集群 + +```shell +minikube start +``` + +通过 kubectl 检查集群正常运行,且 kubectl 绑定到默认本地集群 + +```shell +kubectl cluster-info +``` + +### 3.2 创建独立命名空间并开启自动注入 + +通过以下命令为示例项目创建独立的 Namespace `dubbo-demo`,同时开启 sidecar 自动注入。 + +```shell +# 初始化命名空间 +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/Namespace.yml + +# 切换命名空间 +kubens dubbo-demo + +# dubbo-demo 开启自动注入 +kubectl label namespace dubbo-demo istio-injection=enabled + +``` + +### 3.3 部署到 Kubernetes + +#### 3.3.1 部署 Provider + +```shell +# 部署 Service +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/provider/Service.yml + +# 部署 Deployment +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/provider/Deployment.yml +``` + +以上命令创建了一个名为 `dubbo-samples-mesh-provider` 的 Service,注意这里的 service name 与项目中的 dubbo 应用名是一样的。 + +接着 Deployment 部署了一个 2 副本的 pod 实例,至此 Provider 启动完成。 + +可以通过如下命令检查启动日志。 + +```shell +# 查看 pod 列表 +kubectl get pods -l app=dubbo-samples-mesh-provider + +# 查看 pod 部署日志 +kubectl logs your-pod-id +``` + +这时 pod 中应该有一个 dubbo provider 容器实例,同时还有一个 Envoy Sidecar 容器实例。 + +#### 3.3.2 部署 Consumer + +```shell +# 部署 Service +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/consumer/Service.yml + +# 部署 Deployment +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/consumer/Deployment.yml +``` + +部署 consumer 与 provider 是一样的,这里也保持了 K8S Service 与 Dubbo consumer application name(在 [dubbo.properties](https://github.com/apache/dubbo-samples/blob/master/3-extensions/registry//dubbo-samples-mesh-k8s/dubbo-samples-mesh-consumer/src/main/resources/spring/dubbo-consumer.properties) 中定义) 一致: `dubbo.application.name=dubbo-samples-mesh-consumer`。 + +> Dubbo Consumer 服务声明中还指定了消费的 Provider 服务(应用)名 `@DubboReference(version = "1.0.0", providedBy = "dubbo-samples-mesh-provider", lazy = true)` + +### 3.4 检查 Provider 和 Consumer 正常通信 + +继执行 3.3 步骤后, 检查启动日志,查看 consumer 完成对 provider 服务的消费。 + +```shell +# 查看 pod 列表 +kubectl get pods -l app=dubbo-samples-mesh-consumer + +# 查看 pod 部署日志 +kubectl logs your-pod-id + +# 查看 pod isitio-proxy 日志 +kubectl logs your-pod-id -c istio-proxy +``` + +可以看到 consumer pod 日志输出如下( Triple 协议被 Envoy 代理负载均衡): + +```bash +==================== dubbo invoke 0 end ==================== +[10/08/22 07:07:36:036 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello,service mesh, response from provider-v1: 172.18.96.22:50052, client: 172.18.96.22, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" + +==================== dubbo invoke 1 end ==================== +[10/08/22 07:07:42:042 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello,service mesh, response from provider-v1: 172.18.96.18:50052, client: 172.18.96.18, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" + +``` + +consumer istio-proxy 日志输出如下: + +```shell +[2022-07-15T05:35:14.418Z] "POST /org.apache.dubbo.samples.Greeter/greet HTTP/2" 200 +- via_upstream - "-" 19 160 2 1 "-" "-" "6b8a5a03-5783-98bf-9bee-f93ea6e3d68e" +"dubbo-samples-mesh-provider:50052" "172.17.0.4:50052" +outbound|50052||dubbo-samples-mesh-provider.dubbo-demo.svc.cluster.local 172.17.0.7:52768 10.101.172.129:50052 172.17.0.7:38488 - default +``` + +可以看到 provider pod 日志输出如下: + +```shell +[10/08/22 07:08:47:047 UTC] tri-protocol-50052-thread-8 INFO impl.GreeterImpl: Server test dubbo tri mesh received greet request name: "service mesh" + +[10/08/22 07:08:57:057 UTC] tri-protocol-50052-thread-9 INFO impl.GreeterImpl: Server test dubbo tri mesh received greet request name: "service mesh" +``` + +provider istio-proxy 日志输出如下: + +```shell +[2022-07-15T05:25:34.061Z] "POST /org.apache.dubbo.samples.Greeter/greet HTTP/2" 200 +- via_upstream - "-" 19 162 1 1 "-" "-" "201e6976-da10-96e1-8da7-ad032e58db47" +"dubbo-samples-mesh-provider:50052" "172.17.0.10:50052" + inbound|50052|| 127.0.0.6:47013 172.17.0.10:50052 172.17.0.7:60244 + outbound_.50052_._.dubbo-samples-mesh-provider.dubbo-demo.svc.cluster.local default +``` + +### 3.5 流量治理 - VirtualService 实现按比例流量转发 + +部署 v2 版本的 demo provider +```shell +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/provider/Deployment-v2.yml +``` + +设置 VirtualService 与 DestinationRule,观察流量按照 4:1 的比例分别被引导到 provider v1 与 provider v2 版本。 +```shell +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/traffic/virtual-service.yml +``` + +从消费端日志输出中,观察流量分布效果如下图: + +```java +==================== dubbo invoke 100 end ==================== +[10/08/22 07:15:58:058 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello,service mesh, response from provider-v1: 172.18.96.18:50052, client: 172.18.96.18, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" + +==================== dubbo invoke 101 end ==================== +[10/08/22 07:16:03:003 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello,service mesh, response from provider-v1: 172.18.96.22:50052, client: 172.18.96.22, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" + +==================== dubbo invoke 102 end ==================== +[10/08/22 07:16:08:008 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello,service mesh, response from provider-v1: 172.18.96.18:50052, client: 172.18.96.18, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" + +==================== dubbo invoke 103 end ==================== +[10/08/22 07:16:13:013 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello,service mesh, response from provider-v2: 172.18.96.6:50052, client: 172.18.96.6, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" + +==================== dubbo invoke 104 end ==================== +[10/08/22 07:16:18:018 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello,service mesh, response from provider-v1: 172.18.96.22:50052, client: 172.18.96.22, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" + +==================== dubbo invoke 105 end ==================== +[10/08/22 07:16:24:024 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello,service mesh, response from provider-v1: 172.18.96.18:50052, client: 172.18.96.18, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" + +==================== dubbo invoke 106 end ==================== +[10/08/22 07:16:29:029 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello,service mesh, response from provider-v1: 172.18.96.22:50052, client: 172.18.96.22, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" + +==================== dubbo invoke 107 end ==================== +[10/08/22 07:16:34:034 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello,service mesh, response from provider-v1: 172.18.96.18:50052, client: 172.18.96.18, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" + +==================== dubbo invoke 108 end ==================== +[10/08/22 07:16:39:039 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello,service mesh, response from provider-v1: 172.18.96.22:50052, client: 172.18.96.22, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" + +==================== dubbo invoke 109 end ==================== +[10/08/22 07:16:44:044 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello,service mesh, response from provider-v1: 172.18.96.18:50052, client: 172.18.96.18, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" + + +``` + +### 3.6 查看 dashboard +Istio 官网查看 [如何启动 dashboard](https://istio.io/latest/docs/setup/getting-started/#dashboard)。 + +## 4 修改示例 + +> 1. 修改示例并非必须步骤,本小节是为想要调整代码并查看部署效果的读者准备的。 +> 2. 注意项目源码存储路径一定是英文,否则 protobuf 编译失败。 + +修改 Dubbo Provider 配置 `dubbo-provider.properties` + +```properties +# provider +dubbo.application.name=dubbo-samples-mesh-provider +dubbo.application.metadataServicePort=20885 +dubbo.registry.address=N/A +dubbo.protocol.name=tri +dubbo.protocol.port=50052 +dubbo.application.qosEnable=true +# 为了使 Kubernetes 集群能够正常访问到探针,需要开启 QOS 允许远程访问,此操作有可能带来安全风险,请仔细评估后再打开 +dubbo.application.qosAcceptForeignIp=true +``` + +修改 Dubbo Consumer 配置 `dubbo-consumer.properties` + +```properties +# consumer +dubbo.application.name=dubbo-samples-mesh-consumer +dubbo.application.metadataServicePort=20885 +dubbo.registry.address=N/A +dubbo.protocol.name=tri +dubbo.protocol.port=20880 +dubbo.consumer.timeout=30000 +dubbo.application.qosEnable=true +# 为了使 Kubernetes 集群能够正常访问到探针,需要开启 QOS 允许远程访问,此操作有可能带来安全风险,请仔细评估后再打开 +dubbo.application.qosAcceptForeignIp=true +# 标记开启 mesh sidecar 代理模式 +dubbo.consumer.meshEnable=true +``` + +完成代码修改后,通过项目提供的 Dockerfile 打包镜像 + +```shell +# 打包并推送镜像 +mvn compile jib:build +``` + +> Jib 插件会自动打包并发布镜像。注意,本地开发需将 jib 插件配置中的 docker registry 组织 apache/dubbo-demo 改为自己有权限的组织(包括其他 kubernetes manifests 中的 dubboteam 也要修改,以确保 kubernetes 部署的是自己定制后的镜像),如遇到 jib 插件认证问题,请参考[相应链接](https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md#what-should-i-do-when-the-registry-responds-with-unauthorized)配置 docker registry 认证信息。 +> 可以通过直接在命令行指定 `mvn compile jib:build -Djib.to.auth.username=x -Djib.to.auth.password=x -Djib.from.auth.username=x -Djib.from.auth.username=x`,或者使用 docker-credential-helper. + +## 5 常用命令 + +```shell +# dump current Envoy configs +kubectl exec -it ${your pod id} -c istio-proxy curl http://127.0.0.1:15000/config_dump > config_dump + +# 进入 istio-proxy 容器 +kubectl exec -it ${your pod id} -c istio-proxy -- /bin/bash + +# 查看容器日志 +kubectl logs ${your pod id} -n ${your namespace} + +kubectl logs ${your pod id} -n ${your namespace} -c istio-proxy + +# 开启自动注入sidecar +kubectl label namespace ${your namespace} istio-injection=enabled --overwrite + +# 关闭自动注入sidecar +kubectl label namespace ${your namespace} istio-injection=disabled --overwrite +``` +## 6 注意事项 +1. 示例中,生产者消费者都属于同一个namespace;如果需要调用不同的namespace的提供者,需要按如下配置(**dubbo版本>=3.1.2**): + +注解方式: +```java + @DubboReference(providedBy = "istio-demo-dubbo-producer",providerPort = 20885, providerNamespace = "istio-demo") + +``` +xml方式 +```xml + +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/proxyless.md b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/proxyless.md new file mode 100644 index 000000000000..d6a0b18d8584 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/proxyless.md @@ -0,0 +1,275 @@ +--- +aliases: + - /zh/overview/tasks/mesh/migration/proxyless/ + - /zh-cn/overview/tasks/mesh/migration/proxyless/ +description: "" +linkTitle: 其他问题? +title: 其他问题? +type: docs +weight: 3 +--- + + + +Proxyless 模式是指 Dubbo 直接与 Istiod 通信,通过 xDS 协议实现服务发现和服务治理等能力。 +本示例中将通过一个简单的示例来演示如何使用 Proxyless 模式。 + +[示例地址](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-xds) + +## 代码架构 + +本小节中主要介绍本文所使用的示例的代码架构,通过模仿本示例中的相关配置改造已有的项目代码可以使已有的项目快速跑在 Proxyless Mesh 模式下。 + +### 1. 接口定义 + +为了示例足够简单,这里使用了一个简单的接口定义,仅对参数做拼接进行返回。 + +```java +public interface GreetingService { + String sayHello(String name); +} +``` + +### 2. 接口实现 + +```java +@DubboService(version = "1.0.0") +public class AnnotatedGreetingService implements GreetingService { + @Override + public String sayHello(String name) { + System.out.println("greeting service received: " + name); + return "hello, " + name + "! from host: " + NetUtils.getLocalHost(); + } +} +``` + +### 3. 客户端订阅方式 + +**由于原生 xDS 协议无法支持获取从接口到应用名的映射,因此需要配置 `providedBy` 参数来标记此服务来自哪个应用。** + +未来我们将基于 Dubbo Mesh 的控制面实现自动的[服务映射](/zh-cn/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/)关系获取,届时将不需要独立配置参数即可将 Dubbo 运行在 Mesh 体系下,敬请期待。 + +```java +@Component("annotatedConsumer") +public class GreetingServiceConsumer { + @DubboReference(version = "1.0.0", providedBy = "dubbo-samples-xds-provider") + private GreetingService greetingService; + public String doSayHello(String name) { + return greetingService.sayHello(name); + } +} +``` + +### 4. 服务端配置 + +服务端配置注册中心为 istio 的地址,协议为 xds。 + +我们建议将 `protocol` 配置为 tri 协议(全面兼容 grpc 协议),以获得在 istio 体系下更好的体验。 + +为了使 Kubernetes 感知到应用的状态,需要配置 `qosAcceptForeignIp` 参数,以便 Kubernetes 可以获得正确的应用状态,[对齐生命周期](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/dubbo-kubernetes-probe/)。 + +```properties +dubbo.application.name=dubbo-samples-xds-provider +dubbo.application.metadataServicePort=20885 +dubbo.registry.address=xds://istiod.istio-system.svc:15012 +dubbo.protocol.name=tri +dubbo.protocol.port=50052 +dubbo.application.qosAcceptForeignIp=true +``` + +### 5. 客户端配置 + +客户端配置注册中心为 istio 的地址,协议为 xds。 + +```properties +dubbo.application.name=dubbo-samples-xds-consumer +dubbo.application.metadataServicePort=20885 +dubbo.registry.address=xds://istiod.istio-system.svc:15012 +dubbo.application.qosAcceptForeignIp=true +``` + +## 快速开始 + +### Step 1: 搭建 Kubernetes 环境 + +目前 Dubbo 仅支持在 Kubernetes 环境下的 Mesh 部署,所以在运行启动本示例前需要先搭建 Kubernetes 环境。 + +搭建参考文档: + +> [minikube(https://kubernetes.io/zh-cn/docs/tutorials/hello-minikube/)](https://kubernetes.io/zh-cn/docs/tutorials/hello-minikube/) +> +> [kubeadm(https://kubernetes.io/zh-cn/docs/setup/production-environment/tools/)](https://kubernetes.io/zh-cn/docs/setup/production-environment/tools/) +> +> [k3s(https://k3s.io/)](https://k3s.io/) + +### Step 2: 搭建 Istio 环境 + +搭建 Istio 环境参考文档: + +[Istio 安装文档(https://istio.io/latest/docs/setup/getting-started/)](https://istio.io/latest/docs/setup/getting-started/) + +注:安装 Istio 的时候**需要开启 [first-party-jwt 支持](https://istio.io/latest/docs/ops/best-practices/security/#configure-third-party-service-account-tokens)(使用 `istioctl` 工具安装的时候加上 `--set values.global.jwtPolicy=first-party-jwt` 参数)**,否则将导致客户端认证失败的问题。 + +附安装命令参考: + +```bash +curl -L https://istio.io/downloadIstio | sh - +cd istio-1.xx.x +export PATH=$PWD/bin:$PATH +istioctl install --set profile=demo --set values.global.jwtPolicy=first-party-jwt -y +``` + +### Step 3: 拉取代码并构建 + +```bash +git clone https://github.com/apache/dubbo-samples.git +cd dubbo-samples/dubbo-samples-xds +mvn clean package -DskipTests +``` + +### Step 4: 构建镜像 + +由于 Kubernetes 采用容器化部署,需要将代码打包在镜像中再进行部署。 + +```bash +cd ./dubbo-samples-xds-provider/ +# dubbo-samples-xds/dubbo-samples-xds-provider/Dockerfile +docker build -t apache/dubbo-demo:dubbo-samples-xds-provider_0.0.1 . +cd ../dubbo-samples-xds-consumer/ +# dubbo-samples-xds/dubbo-samples-xds-consumer/Dockerfile +docker build -t apache/dubbo-demo:dubbo-samples-xds-consumer_0.0.1 . +cd ../ +``` + +### Step 5: 创建namespace + +```bash +# 初始化命名空间 +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-xds/deploy/Namespace.yml + +# 切换命名空间 +kubens dubbo-demo +``` + +### Step 6: 部署容器 + +```bash +cd ./dubbo-samples-xds-provider/src/main/resources/k8s +# dubbo-samples-xds/dubbo-samples-xds-provider/src/main/resources/k8s/Deployment.yml +# dubbo-samples-xds/dubbo-samples-xds-provider/src/main/resources/k8s/Service.yml +kubectl apply -f Deployment.yml +kubectl apply -f Service.yml +cd ../../../../../dubbo-samples-xds-consumer/src/main/resources/k8s +# dubbo-samples-xds/dubbo-samples-xds-consumer/src/main/resources/k8s/Deployment.yml +kubectl apply -f Deployment.yml +cd ../../../../../ +``` + +查看 consumer 的日志可以观察到如下的日志: +``` +result: hello, xDS Consumer! from host: 172.17.0.5 +result: hello, xDS Consumer! from host: 172.17.0.5 +result: hello, xDS Consumer! from host: 172.17.0.6 +result: hello, xDS Consumer! from host: 172.17.0.6 +``` + +## 常见问题 + +1. 配置独立的 Istio 集群 `clusterId` + +通常在 Kubernetes 体系下 Istio 的 `clusterId` 是 `Kubernetes`,如果你使用的是自建的 istio 生产集群或者云厂商提供的集群则可能需要配置 `clusterId`。 + +配置方式:指定 `ISTIO_META_CLUSTER_ID` 环境变量为所需的 `clusterId`。 + +参考配置: +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dubbo-samples-xds-consumer +spec: + selector: + matchLabels: + demo: consumer + replicas: 2 + template: + metadata: + labels: + demo: consumer + spec: + containers: + - env: + - name: ISTIO_META_CLUSTER_ID + value: Kubernetes + - name: dubbo-samples-xds-provider + image: xxx +``` + +`clusterId` 获取方式: +> kubectl describe pod -n istio-system istiod-58b4f65df9-fq2ks +> 读取环境变量中 `CLUSTER_ID` 的值 + +2. Istio 认证失败 + +由于当前 Dubbo 版本还不支持 istio 的 `third-party-jwt` 认证,所以需要配置 `jwtPolicy` 为 `first-party-jwt`。 + +3. providedBy + +由于当前 Dubbo 版本受限于 istio 的通信模型无法获取接口所对应的应用名,因此需要配置 `providedBy` 参数来标记此服务来自哪个应用。 +未来我们将基于 Dubbo Mesh 的控制面实现自动的[服务映射](/zh-cn/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/)关系获取,届时将不需要独立配置参数即可将 Dubbo 运行在 Mesh 体系下,敬请期待。 + +4. protocol name + +Proxyless 模式下应用级服务发现通过 `Kubernetes Native Service` 来进行应用服务发现,而由于 istio 的限制,目前只支持 `http` 协议和 `grpc` 协议的流量拦截转发,所以 `Kubernetes Service` 在配置的时候需要指定 `spec.ports.name` 属性为 `http` 或者 `grpc` 开头。 +因此我们建议使用 triple 协议(完全兼容 grpc 协议)。此处即使 `name` 配置为 `grpc` 开头,但是实际上是 `dubbo` 协议也可以正常服务发现,但是影响流量路由的功能。 + +参考配置: +```yaml +apiVersion: v1 +kind: Service +metadata: + name: dubbo-samples-xds-provider +spec: + clusterIP: None + selector: + demo: provider + ports: + - name: grpc-tri + protocol: TCP + port: 50052 + targetPort: 50052 +``` + +5. metadataServicePort + +由于 Dubbo 3 应用级服务发现的元数据无法从 istio 中获取,需要走服务自省模式。这要求了 `Dubbo MetadataService` 的端口在全集群的是统一的。 + +参考配置: +```properties +dubbo.application.metadataServicePort=20885 +``` + +未来我们将基于 Dubbo Mesh 的控制面实现自动的[服务元数据](/zh-cn/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/)获取,届时将不需要独立配置参数即可将 Dubbo 运行在 Mesh 体系下,敬请期待。 + +6. qosAcceptForeignIp + +由于 Kubernetes probe 探活机制的工作原理限制,探活请求的发起方不是 `localhost`,所以需要配置 `qosAcceptForeignIp` 参数开启允许全局访问。 + +```properties +dubbo.application.qosAcceptForeignIp=true +``` + +注:qos 端口存在危险命令,请先评估网络的安全性。即使 qos 不开放也仅影响 Kubernetes 无法获取 Dubbo 的生命周期状态。 + +7. 不需要开启注入 + +Proxyless 模式下 pod 不需要再开启 envoy 注入,请确认 namespace 中没有 `istio-injection=enabled` 的标签。 + +8. 明文连接istiod + +Proxyless 模式下默认通过ssl方式连接istiod,同时也支持通过明文的方式连接istiod。 + +明文连接参考配置: +```properties +dubbo.registry.secure=plaintext +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/_index.md b/content/en/overview/mannual/java-sdk/tasks/observability/_index.md new file mode 100755 index 000000000000..e01bba132fd0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/observability/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/overview/tasks/observability/ + - /zh-cn/overview/tasks/observability/ +description: 基于 Admin、Metrics、Grafana 等可视化的观测集群状态。 +linkTitle: 观测服务 +title: 观测服务 +type: docs +weight: 4 +--- diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/console.md b/content/en/overview/mannual/java-sdk/tasks/observability/console.md new file mode 100755 index 000000000000..8cd477158c51 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/observability/console.md @@ -0,0 +1,112 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/observability/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/observability/ +description: 可观测性 +linkTitle: 控制台 +title: 可观测性 +type: docs +weight: 1 +--- + +管理 Dubbo 最直接的方式就是通过 Dubbo 控制面(即 dubbo-control-plane)提供的可视化界面,之前我们在[【快速开始 - 部署 Dubbo 应用】]()一文的最后,也有用到它查看服务启动后的状态。 + +**`dubbo-control-plane` 支持可视化的展示、监控集群状态,还支持实时下发流量管控规则。** + +## 安装控制台 +为了体验效果,我们首先需要安装 dubbo-control-plane,以下是在 Linux 环境下安装 dubbo-control-plane 的具体步骤: +1. 下载 & 解压 + ```shell + curl -L https://dubbo.apache.org/releases/downloadDubbo.sh | sh - + + cd dubbo-$version + export PATH=$PWD/bin:$PATH + ``` +2. 安装 + ```shell + dubbo-cp run --mode universal --config conf/dubbo.yml + ``` + 注意,`conf/dubbo.yml` 配置需要按需调整,指向你要连接的注册中心等后台服务,具体请查看 dubbo-control-plane 架构中依赖的后台服务。 +3. 访问 `http://xxx` 即可打开控制台页面。 + ![页面截图]() + +{{% alert title="注意" color="info" %}} +* 请查看文档了解 dubbo-control-plane 详细安装步骤,包括多个平台的安装方法与配置指导。 +* 对于 Kubernetes 环境下的 Dubbo 服务开发(包括 dubbo-control-plane 安装),我们有专门的章节说明,对于 Kubernetes 环境下的开发者可以去参考。 +{{% /alert %}} + +## 功能介绍 +Admin 控制台提供了从开发、测试到流量治理等不同层面的丰富功能,功能总体上可分为以下几类: +* 服务状态与依赖关系查询 +* 服务在线测试与文档管理 +* 集群状态监控 +* 实例诊断 +* 流量管控 + +### 服务状态与依赖关系查询 +服务状态查询以接口为维度展示 dubbo 集群信息,包含服务提供者、消费者信息和服务的元数据等。元数据包含了服务定义、方法名和参数列表等信息。Admin 支持最新版本 dubbo3 所提供的应用级发现模型,以统一的页面交互展示了应用级&接口级地址信息,并以特殊的标记对记录进行区分。 + +#### 基于服务名查询 +![img](/imgs/v3/tasks/observability/admin/1-search-by-service.png) + +#### 基于应用名查询 +![img](/imgs/v3/tasks/observability/admin/1-search-by-appname.png) + +#### 基于实例地址查询 +![img](/imgs/v3/tasks/observability/admin/1-search-by-ip.png) + +#### 服务实例详情 +![img](/imgs/v3/tasks/observability/admin/1-service-detail.png) + +### 服务在线测试与文档管理 +#### 服务测试 +服务测试相,主要用于模拟服务消费方,验证 Dubbo 服务的使用方式与正确性。 + +![img](/imgs/v3/tasks/observability/admin/2-service-test2.png) + +![img](/imgs/v3/tasks/observability/admin/2-service-test.png) + +#### 服务 Mock +服务Mock通过无代码嵌入的方式将Consumer对Provider的请求进行拦截,动态的对Consumer的请求进行放行或返回用户自定义的Mock数据。从而解决在前期开发过程中,Consumer所依赖的Provider未准备就绪时,造成Consumer开发方的阻塞问题。 +只需要以下两步,即可享受服务Mock功能带来的便捷: + +第一步: +Consumer应用引入服务Mock依赖,添加JVM启动参数-Denable.dubbo.admin.mock=true开启服务Mock功能。 +```xml + + org.apache.dubbo.extensions + dubbo-mock-admin + ${version} + +``` + +第二步:在Dubbo Admin中配置对应的Mock数据。 + +![img](/imgs/v3/tasks/observability/admin/2-service-mock.png) + +#### 服务文档管理 +Admin 提供的接口文档,相当于 swagger 对于 RESTful 风格的 Web 服务的作用。使用该功能可以有效的管理 Dubbo 接口文档。 + +![img](/imgs/v3/tasks/observability/admin/2-service-doc.png) + +### 集群状态监控 +#### 首页大盘 +TBD + +#### Grafana +![img](/imgs/v3/tasks/observability/admin/3-grafana.png) + +#### Tracing +![img](/imgs/v3/tasks/observability/admin/3-tracing-zipkin.png) + +### 流量管控 +Admin 提供了四种路由规则的可视化管理支持,分别是条件路由规则、标签路由规则、动态配置规则、脚本路由规则,所提供的功能可以轻松实现黑白名单、灰度环境隔离、多套测试环境、金丝雀发布等服务治理诉求。接下来以条件路由为例,可以可视化的创建条件路由规则。 + +#### 条件路由 + +条件路由可以编写一些自定义路由规则实现服务治理的需求比如同区域优先、参数路由、黑白名单、读写分离等。路由规则在发起一次RPC调用前起到过滤目标服务器地址的作用,过滤后的地址列表,将作为消费端最终发起RPC调用的备选地址。 + +![img](/imgs/v3/tasks/observability/admin/4-traffic-management.png) + +请参考 [流量管控任务](../../traffic-management/) 中关于如何进行路由规则配置的更多详细描述。 + diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/grafana.md b/content/en/overview/mannual/java-sdk/tasks/observability/grafana.md new file mode 100644 index 000000000000..517ba25cba4c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/observability/grafana.md @@ -0,0 +1,93 @@ +--- +aliases: + - /zh/overview/tasks/observability/grafana/ + - /zh-cn/overview/tasks/observability/grafana/ +description: "" +linkTitle: Grafana +no_list: true +title: 使用 Grafana 可视化查看集群 Metrics 指标 +type: docs +weight: 3 +--- + +指标可视化页面目前推荐的方式是使用 Grafana 来配置 Dubbo 的可观测性监控大盘。 + +## 在您开始之前 +- 一个可以访问的 Kubernetes 集群 +- 正确安装并配置 [普罗米修斯服务](/zh-cn/overview/reference/integrations/prometheus/#安装) +- 安装 [Grafana](/zh-cn/overview/reference/integrations/grafana/) +- 部署 [示例应用](https://github.com/apache/dubbo-samples/tree/master/4-governance/dubbo-samples-metrics-spring-boot) 并开启指标采集 + +## 确认组件正常运行 + +### Kubernetes +确保 Prometheus 正常运行 + +```sh +$ kubectl -n dubbo-system get svc prometheus +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +prometheus ClusterIP 10.0.250.230 9090/TCP 180s +``` + +确保 Grafana 正常运行 + +```sh +$ kubectl -n dubbo-system get svc grafana +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +grafana ClusterIP 10.0.244.130 3000/TCP 180s +``` + +## 部署示例 + +```yaml +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/4-governance/dubbo-samples-metrics-spring-boot/Deployment.yml +``` + +等待示例应用正常运行,通过以下命令确认应用状态: +```yaml +kubectl -n dubbo-demo get deployments +``` + +## 查看 Grafana 可视化面板 + +示例程序启动后会自动模拟服务调用,只需等待一会能在 Grafana 中可视化的看到 Metrics 指标。 +1. 如果是通过 [Dubbo 控制面](../../../reference/admin/architecture/) 安装的 Grafana,则可以访问 Admin 控制台并在左侧菜单中找到 Grafana 可视化监控入口 + +2. 如果是独立安装的 Grafana 组件,则可以直接访问 Grafana 可视化控制台地址: + +```sh +$ kubectl port-forward service/grafana 3000:3000 +``` + +在浏览器打开 Grafana 控制台:http://localhost:3000 + +### 服务统计视图 +支持基于应用、实例粒度的统计视图,同时对于每一种指标统计粒度,你还可以进一步查看: + +1. 提供者流量视图 + +![grafana-dashboard-1.png](/imgs/v3/advantages/grafana-dashboard-1.png) + +2. 消费者流量视图 + +![grafana-dashboard-1.png](/imgs/v3/advantages/grafana-dashboard-1.png) + +3. 注册中心视图 + +TBD + +4. 配置中心视图 + +TBD + +### JVM 实例视图 + +![grafana-dashboard-2.png](/imgs/v3/advantages/grafana-dashboard-2.png) + +### 关于 Dubbo 官方提供的 Grafana Dashboard + +Dubbo 提供了丰富的指标面板,以上视图面板均可以在 Grafana 官方面板库中找到:您可以直接导入如下模版,并配置好数据源即可。 + +**Apache Dubbo Observability Dashboard:** [https://grafana.com/grafana/dashboards/18469](https://grafana.com/grafana/dashboards/18469) + +**JVM (Micrometer) Dashboard:** [https://grafana.com/grafana/dashboards/4701](https://grafana.com/grafana/dashboards/4701) diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/logging.md b/content/en/overview/mannual/java-sdk/tasks/observability/logging.md new file mode 100644 index 000000000000..b3f919c9862f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/observability/logging.md @@ -0,0 +1,361 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/observability/logging/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/observability/logging/ +description: Dubbo 框架的日志配置, +hide_summary: true +linkTitle: 日志管理 +no_list: true +title: 日志管理 +type: docs +weight: 3 +--- + +## 支持的日志框架 +Dubbo 支持以下日志框架,用户可根据业务应用实际使用的日志框架进行配置。 + +| 第三方日志框架 | 优先级 | 说明 | +| ------------------------------------- | ------------------------------------------ | ------------------------------------------ | +| Log4j | 最高(默认就用这个) | log4j 的直接适配,需要增加 log4j-core、log4j-api 依赖与 log4j.properties | +| SLF4J | 次高(当前推荐) | 可支持 log4j、log4j2、logback 等实现。如 logback 可添加slf4j-api、logback-classic、logback-core 依赖与 logback.xml | +| Log4j2 | 次低 | log4j2 的直接适配,需要增加 log4j2-core 依赖与 log4j2.xml 配置 | +| Common Logging(jcl就是common logging) | 次低(Log4j和SLF4J在项目中均没有就用这个) | 较少项目使用 | +| JDK log | 最低(最后的选择) | 较少项目使用 | + +{{% alert title="注意" color="warning" %}} +无论使用哪种日志框架,除了 Dubbo 侧配置外,还需要确保应用中加入正确的日志框架依赖和配置文件。 +{{% /alert %}} + +### 使用 slf4j +对于 spring boot 用户,通过在 `application.yaml` 或 `application.properties` 增加以下配置,开启 slf4j 日志: + +```yaml +dubbo: + application: + logger: slf4j +``` + +```properties +dubbo.application.logger=slf4j +``` + +除此之外,还可以使用使用 JVM 参数进行设置: +```shell +java -Ddubbo.application.logger=slf4j +``` + +#### 使用 slf4j-log4j2 提供日志输出 + +增加依赖: + +```xml + + + org.slf4j + slf4j-api + 1.7.30 + + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.14.1 + + + + org.apache.logging.log4j + log4j-core + 2.14.1 + + + + org.apache.logging.log4j + log4j-api + 2.14.1 + +``` + +配置一个name是"org.apache.dubbo"的logger就可以了,然后关联到对应的appender。如下: + +```xml + + + + + + %d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n + + + + + + + + + + +``` + +#### 使用 slf4j-logback 提供日志输出 + +增加依赖: + +```xml + + + org.slf4j + slf4j-api + 1.7.30 + + + + + ch.qos.logback + logback-classic + 1.2.3 + + + + ch.qos.logback + logback-core + 1.2.3 + +``` + +增加 logback 配置文件: + +```xml + + + + UTF-8 + ${LOG_HOME_DUBBO}/MTP-DUBBO.log + + ${LOG_HOME_DUBBO}/DEMO-%d{yyyy-MM-dd}.%i-DUBBO.zip + 30 + + 100MB + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + true + + + + + +``` + + +### 使用 log4j +对于 spring boot 用户,通过在 `application.yaml` 或 `application.properties` 增加以下配置,开启 log4j 日志: +```yaml +dubbo: + application: + logger: log4j +``` + +使用 log4j2: +```yaml +dubbo: + application: + logger: log4j2 +``` + +## 访问日志-accesslog + +如果想记录每一次请求的详细信息,可开启访问日志,类似于 apache/tomcat server 的访问日志。 + +在 `application.yaml` 文件中,可以通过以下方式,开启访问日志,日志内容将输出到当前应用正在使用的日志框架(如 log4j、logback 等)。 +```yaml +dubbo: + provider: + accesslog: true +``` + +也可以指定访问日志输出到指定文件: + +```yaml +dubbo: + provider: + accesslog: /home/dubbo/foo/bar.log +``` + +{{% alert title="注意" color="warning" %}} +无论要动态开启或关闭访问日志,请参考 [流量管控](../../traffic-management/accesslog/) 一节的具体说明。 +{{% /alert %}} + +## 动态修改日志级别 +自 3.3 版本开始,Dubbo 框架支持通过 http 或 telnet 命令,在运行态动态修改日志配置(级别、框架等)。以下是使用示例,关于 telnet 命令的更多内容,可查看 [qos 命令指南](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/qos-list/)。 + +1. 查询日志配置 + 命令:`loggerInfo` + + **示例** + ```bash + > telnet 127.0.0.1 22222 + > loggerInfo + ``` + + **输出** + ``` + Trying 127.0.0.1... + Connected to localhost. + Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / + /____/ \____//____//____/ \____/ + dubbo>loggerInfo + Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: INFO + ``` + +2. 修改日志级别 + 命令:`switchLogLevel {level}` + + level: `ALL`, `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `OFF` + + **示例** + ```bash + > telnet 127.0.0.1 22222 + > switchLogLevel WARN + ``` + + **输出** + ``` + Trying 127.0.0.1... + Connected to localhost. + Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / + /____/ \____//____//____/ \____/ + dubbo>loggerInfo + Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: INFO + dubbo>switchLogLevel WARN + OK + dubbo>loggerInfo + Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: WARN``` + ``` + +3. 修改日志输出框架 + 命令:`switchLogger {loggerAdapterName}` + + loggerAdapterName: `slf4j`, `jcl`, `log4j`, `jdk`, `log4j2` + + **示例** + ```bash + > telnet 127.0.0.1 22222 + > switchLogger slf4j + ``` + + **输出** + ``` + Trying 127.0.0.1... + Connected to localhost. + Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / + /____/ \____//____//____/ \____/ + dubbo>loggerInfo + Available logger adapters: [jcl, slf4j, log4j, jdk]. Current Adapter: [log4j]. Log level: INFO + dubbo>switchLogger slf4j + OK + dubbo>loggerInfo + Available logger adapters: [jcl, slf4j, log4j, jdk]. Current Adapter: [slf4j]. Log level: INFO + ``` + +## 工作原理 + +在 Dubbo 框架内所有的日志输出都是通过 LoggerFactory 这个静态工厂类来获得 Logger 的对象实体,并且抽离了一个 LoggerAdapter 用于对接第三方日志框架,所以就有了JDKLoggerAdapter, Log4jLoggerAdapter, SLF4JLoggerAdapter等一些实现子类,分别对接了不同 Log 第三方实现。既然 Dubbo 能够支持这么多log实现,那么这些实现在 Dubbo 中优先级是在呢么样的呢?这里的优先级是指未配置指定的 logger 提供方的情况下,由 Dubbo 框架自己选择。 + +Dubbo 日志的调用方式,针对不同的日志打印系统,采用统一的 API 调用及输出,如: + +```java +/** + * ChannelListenerDispatcher + */ +public class ChannelHandlerDispatcher implements ChannelHandler { + + private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ChannelHandlerDispatcher.class); +``` + +Dubbo 采用的日志输出方式是首先从 dubbo.application.logger 系统变量中获取属性值,来判断到底采用哪种日志输出方式,如果没设置则按照默认的加载顺序加载相应的日志输出类,直到成功加载: + +顺序为:log4jLogger > slf4jLogger > JclLogger > JdkLogger + +LoggerFactory 在类加载过程中变量的初始化过程: + +```java +// search common-used logging frameworks +static { + String logger = System.getProperty("dubbo.application.logger", ""); + switch (logger) { + case Slf4jLoggerAdapter.NAME: + setLoggerAdapter(new Slf4jLoggerAdapter()); + break; + case JclLoggerAdapter.NAME: + setLoggerAdapter(new JclLoggerAdapter()); + break; + case Log4jLoggerAdapter.NAME: + setLoggerAdapter(new Log4jLoggerAdapter()); + break; + case JdkLoggerAdapter.NAME: + setLoggerAdapter(new JdkLoggerAdapter()); + break; + case Log4j2LoggerAdapter.NAME: + setLoggerAdapter(new Log4j2LoggerAdapter()); + break; + default: + List> candidates = Arrays.asList( + Log4jLoggerAdapter.class, + Slf4jLoggerAdapter.class, + Log4j2LoggerAdapter.class, + JclLoggerAdapter.class, + JdkLoggerAdapter.class + ); + boolean found = false; + // try to use the first available adapter + for (Class clazz : candidates) { + try { + LoggerAdapter loggerAdapter = clazz.getConstructor().newInstance(); + loggerAdapter.getLogger(LoggerFactory.class); + if (loggerAdapter.isConfigured()) { + setLoggerAdapter(loggerAdapter); + found = true; + break; + } + } catch (Exception | LinkageError ignored) { + // ignore + } + } + if (found) { + break; + } + + System.err.println("Dubbo: Unable to find a proper configured logger to log out."); + for (Class clazz : candidates) { + try { + LoggerAdapter loggerAdapter = clazz.getConstructor().newInstance(); + loggerAdapter.getLogger(LoggerFactory.class); + setLoggerAdapter(loggerAdapter); + found = true; + break; + } catch (Throwable ignored) { + // ignore + } + } + if (found) { + System.err.println("Dubbo: Using default logger: " + loggerAdapter.getClass().getName() + ". " + + "If you cannot see any log, please configure -Ddubbo.application.logger property to your preferred logging framework."); + } else { + System.err.println("Dubbo: Unable to find any available logger adapter to log out. Dubbo logs will be ignored. " + + "Please configure -Ddubbo.application.logger property and add corresponding logging library to classpath."); + } + } +} +``` + +上面这段静态块是在LoggerFactory里面,说明只要LoggerFactory类一加载就会去选择对应的日志提供方。大家可能会发现对日志的提供方其实是可以通过配置来指定的,因为静态块一开始是从当前jvm环境中获取dubbo.application.logger,这个参数是同java -Ddubbo.application.logger=xxxx去指定的,如果是放在容器里面,就需要配置在容器启动的jvm参数里面。 diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/prometheus.md b/content/en/overview/mannual/java-sdk/tasks/observability/prometheus.md new file mode 100644 index 000000000000..8c01c21322b6 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/observability/prometheus.md @@ -0,0 +1,52 @@ +--- +aliases: + - /zh/overview/tasks/observability/prometheus/ + - /zh-cn/overview/tasks/observability/prometheus/ +description: "" +linkTitle: Prometheus +no_list: true +title: 从 Prometheus 查询 Metrics 监控指标 +type: docs +weight: 2 +--- + +## 准备条件 + +本文演示如何在 Kubernetes 环境下部署 Prometheus 并实现对 Dubbo 集群的监控数据统计与查询,你需要完成或具备以下内容: + +* 本地或远端 Kubernetes 集群 +* 确保 [Prometheus 正确安装](/zh-cn/overview/reference/integrations/prometheus/#安装) +* 部署 [示例应用](https://github.com/apache/dubbo-samples/tree/master/4-governance/dubbo-samples-metrics-spring-boot) 并开启指标采集 +* 使用 Prometheus dashboard 查询数据指标 + +## 确保 Prometheus 正确运行 + +验证 Prometheus 已经正确部署 + +```yaml +kubectl -n dubbo-system get svc prometheus-server +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +prometheus-server ClusterIP 10.109.160.254 9090/TCP 4m +``` + +## 部署示例 + +```yaml +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/4-governance/dubbo-samples-metrics-spring-boot/Deployment.yml +``` + +等待示例应用正常运行,通过以下命令确认应用状态: +```yaml +kubectl -n dubbo-demo get deployments +``` + +## 查询 Prometheus + +获得 Prometheus 访问地址 `kubectl port-forward service/prometheus-server 9090:9090`, +打开浏览器,访问 localhost:9090/graph 即可打开 Prometheus 控制台。 + +接下来,执行 Prometheus 查询命令。可以在此确认 [Dubbo 支持的 Metrics 指标](/zh-cn/overview/reference/metrics/standard_metrics/)。 + +**1. 在 “Expression” 一览,输入 `dubbo_consumer_qps_total`,返回以下结果** + +![img](/imgs/v3/tasks/observability/prometheus.png) diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/_index.md b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/_index.md new file mode 100755 index 000000000000..575b24ef82bd --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/_index.md @@ -0,0 +1,55 @@ +--- +aliases: + - /zh/overview/tasks/observability/tracing/ + - /zh-cn/overview/tasks/observability/tracing/ +description: "" +linkTitle: 全链路追踪 +no_list: true +title: 全链路追踪 +type: docs +weight: 5 +--- + + +{{< blocks/section color="white" height="auto">}} +
+
+ +
+
+
+
+

+ Zipkin 全链路追踪 +

+

演示如果通过 Zipkin 实现对 Dubbo 服务的全链路追踪。 +

+
+
+
+
+
+
+

+ Skywalking 全链路追踪 +

+

演示如果通过 Skywalking 实现对 Dubbo 服务的全链路追踪。 +

+
+
+
+
+
+
+

+ OTlp 全链路追踪 +

+

演示如果通过 OpenTelemetry 的 Otlp Collector 实现对 Dubbo 服务的全链路追踪。 +

+
+
+
+
+
+
+{{< /blocks/section >}} diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/otlp.md b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/otlp.md new file mode 100644 index 000000000000..99d5e1e63cdf --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/otlp.md @@ -0,0 +1,135 @@ +--- +aliases: + - /zh/overview/tasks/observability/tracing/otlp/ + - /zh-cn/overview/tasks/observability/tracing/otlp/ +description: "这个案例展示了在 Dubbo 项目中以 OpenTelemetry 作为 Tracer,将 Trace 信息上报到 Otlp Collector,再由 collector 转发至 Zipkin、Jagger。" +linkTitle: OpenTelemetry +no_list: true +title: OTlp +type: docs +weight: 2 +--- + +## 概述 + +这个案例展示了在 Dubbo 项目中以 OpenTelemetry 作为 Tracer,将 Trace 信息上报到 Otlp Collector,再由 collector 转发至 Zipkin、Jagger。[代码地址](https://github.com/conghuhu/dubbo-samples/tree/master/4-governance/dubbo-samples-tracing/dubbo-samples-spring-boot-tracing-otel-otlp) + +有三部分组成: + +- dubbo-samples-spring-boot-tracing-otel-oltp-interface +- dubbo-samples-spring-boot-tracing-otel-oltp-provider +- dubbo-samples-spring-boot-tracing-otel-oltp-consumer + +## 案例架构图 + +![案例架构图](/imgs/v3/tasks/observability/tracing/otlp/demo_arch.png) + +## 快速开始 + +### 安装 & 启动 Otlp Collector + +按照 [OpenTelemetry Collector Quick Start](https://OpenTelemetry.io/docs/collector/getting-started/) 去启动 otlp collector. + +### 启动 Provider + +直接运行`org.apache.dubbo.springboot.demo.provider.ProviderApplication` directly from IDE. + +### 启动 Consumer + +Start `org.apache.dubbo.springboot.demo.consumer.ConsumerApplication` directly from IDE. + +### 查看 Trace 信息 + +在浏览器中打开zipkin看板 `http://localhost:9411/zipkin/` : + +![zipkin.png](/imgs/v3/tasks/observability/tracing/otlp/zipkin_search.png) + +![zipkin.png](/imgs/v3/tasks/observability/tracing/otlp/zipkin_detail.png) + +在浏览器中打开Jaeger看板 `http://localhost:16686/search` : + +![jaeger_search.png](/imgs/v3/tasks/observability/tracing/otlp/jaeger_search.png) + +![jaeger_detail.png](/imgs/v3/tasks/observability/tracing/otlp/jaeger_detail.png) + +## 如何在SpringBoot项目中使用 + +### 1. 在你的项目中添加依赖 + +对于 SpringBoot 项目,你可以使用`dubbo-spring-boot-tracing-otel-otlp-starter` : + +```xml + + + + org.apache.dubbo + dubbo-spring-boot-tracing-otel-otlp-starter + +``` + +### 2. 配置 + +#### application.yml + +```yaml +dubbo: + tracing: + enabled: true # default is false + sampling: + probability: 0.5 # sampling rate, default is 0.1 + propagation: + type: W3C # W3C/B3 default is W3C + tracing-exporter: + otlp-config: + endpoint: http://localhost:4317 + timeout: 10s # default is 10s + compression-method: none # none/gzip The method used to compress payloads, default is "none" + headers: # customized added headers, default is empty + auth: admin + +# tracing info output to logging +logging: + level: + root: info + pattern: + console: '[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2} [%X{traceId:-}, %X{spanId:-}]: %m%n' +``` + +## 如何基于Dubbo API使用 + +### 1. 在你的项目中添加依赖 + +```xml + + + org.apache.dubbo + dubbo-tracing + + + + io.micrometer + micrometer-tracing-bridge-otel + + + + io.opentelemetry + opentelemetry-exporter-otlp + +``` + +### 2. 配置 + +```java +TracingConfig tracingConfig = new TracingConfig(); +// 开启dubbo tracing +tracingConfig.setEnabled(true); +// 设置采样率 +tracingConfig.setSampling(new SamplingConfig(1.0f)); +// 设置Propagation,默认为W3C,可选W3C/B3 +tracingConfig.setPropagation(new PropagationConfig("W3C")); +// 设置trace上报 +ExporterConfig exporterConfig = new ExporterConfig(); +// 设置将trace上报到Zipkin +exporterConfig.setZipkin(new ExporterConfig.OtlpConfig("http://localhost:4317", Duration.ofSeconds(10), "none")); +tracingConfig.setExporter(exporterConfig); +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/skywalking.md b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/skywalking.md new file mode 100644 index 000000000000..c49b1e889863 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/skywalking.md @@ -0,0 +1,83 @@ +--- +aliases: + - /zh/overview/tasks/observability/tracing/skywalking/ + - /zh-cn/overview/tasks/observability/tracing/skywalking/ +description: "本文演示如何将 Dubbo 接入 Skywalking 全链路监控体系" +linkTitle: Skywalking +no_list: true +title: Skywalking +type: docs +weight: 4 +--- + +本文演示如何将 Dubbo 接入 Skywalking 全链路监控体系,完整示例请参考 dubbo-samples-tracing-skywalking。依赖的 Skywalking Agent 版本为 [skywalking micrometer-1.10 api](https://skywalking.apache.org/docs/skywalking-java/next/en/setup/service-agent/java-agent/application-toolkit-micrometer-1.10/). + +## 1. 添加 Micrometer Observation 依赖到你的项目 +为了能够将 Micrometer 及相关 Metrics 依赖添加到 classpath,需要增加 `dubbo-metrics-api` 依赖,如下所示: + +```xml + + + org.apache.dubbo + dubbo-metrics-api + +``` + +## 2. 添加 Skywalking Micrometer-1.10 Api 到项目 + +为了将 Dubbo Micrometer tracing 数据集成到 Skywalking,需要添加以下依赖。 + +```xml + + org.apache.skywalking + apm-toolkit-micrometer-1.10 + +``` + +## 3. 配置 ObservationRegistry + +```java +@Configuration +public class ObservationConfiguration { + @Bean + ApplicationModel applicationModel(ObservationRegistry observationRegistry) { + ApplicationModel applicationModel = ApplicationModel.defaultModel(); + observationRegistry.observationConfig() + .observationHandler(new ObservationHandler.FirstMatchingCompositeObservationHandler( + new SkywalkingSenderTracingHandler(), new SkywalkingReceiverTracingHandler(), + new SkywalkingDefaultTracingHandler() + )); + applicationModel.getBeanFactory().registerBean(observationRegistry); + return applicationModel; + } +} +``` +## 4. 启动 Skywalking OAP +请参考这里了解如何 [设置 Skywalking OAP](https://skywalking.apache.org/docs/main/latest/en/setup/backend/backend-setup/) + +```shell +bash startup.sh +``` + +## 5. 启动示例 Demo (skywalking-agent) +首先,我们假设你已经有一个注册中心来协调地址发现,具体可参见示例里指向的注册中心配置。 + +之后,启动 Provider 和 Consumer 并确保 skywalking-agent 参数被正确设置,skywalking-agent 确保数据可以被正确的上报到后台系统。 + +* 考虑到 skywalking-agent 本身也有内置的 Dubbo 拦截器,为了确保示例能使用 Dubbo 自带的 Micrometer 集成,我们需要你删除 skywalking-agent 自带的拦截器,直接将 `plugins` 目录删除即可 +* 配置 Skywalking OAP 服务器地址,在以下文件中配置 OAP 地址 `/path/to/skywalking-agent/agent.config`,对应的参数项为 `collector.backend_service`。 + +```shell +java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar -jar dubbo-samples-spring-boot-tracing-skwalking-provider-1.0-SNAPSHOT.jar +``` + +```shell +java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar -jar dubbo-samples-spring-boot-tracing-skwalking-consumer-1.0-SNAPSHOT.jar +``` + +## 6. 示例效果 +在浏览器中打开 `[skywalking-webapp](http://localhost:8080/)` 查看效果 + +![skywalking-trace-result-1](/imgs/v3/tasks/observability/tracing/skywalking-trace-result-1.png) +![skywalking-trace-result-2](/imgs/v3/tasks/observability/tracing/skywalking-trace-result-2.png) +![skywalking-trace-result-2](/imgs/v3/tasks/observability/tracing/skywalking-trace-result-3.png) diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/tracing.md b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/tracing.md new file mode 100644 index 000000000000..9ea7be95c37f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/tracing.md @@ -0,0 +1,147 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/observability/tracing/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/observability/tracing/ +description: Dubbo 内置了全链路追踪能力,你可以通过引入 spring-boot-starter 或者相关依赖开启链路跟踪能力,通过将跟踪数据导出到一些主流实现如 Zipkin、Skywalking、Jaeger 等后端系统,可以实现全链路跟踪数据的分析与可视化展示。 +hide_summary: true +linkTitle: 链路追踪 +no_list: true +title: 全链路追踪使用与实现说明 +type: docs +weight: 1 +--- + +Dubbo 内置了全链路追踪能力,你可以通过引入 spring-boot-starter 或者相关依赖开启链路跟踪能力,通过将跟踪数据导出到一些主流实现如 Zipkin、Skywalking、Jaeger 等后端系统,可以实现全链路跟踪数据的分析与可视化展示。 + +Dubbo 目前借助 Micrometer Observation 完成 Tracing 的所有埋点工作,依赖 Micrometer 提供的各种 Bridge 适配,我们可以实现将 Tracing 导入各种后端系统,具体工作原理如下。 + +![micrometer-bridge](/imgs/docs3-v2/java-sdk/observability/micrometer-bridge.png) + +## 使用方式 + +以 Dubbo Spring Boot 应用为例,通过加入如下依赖即可开启链路追踪,并使用 zipkin exporter bridge 将链路追踪数据导入 Zipkin 后端系统。 + +```xml + + org.apache.dubbo + dubbo-spring-boot-tracing-otel-zipkin-starter + 3.2.1-SNAPSHOT + +``` + +更多完整示例请参见: +* [使用 Zipkin 实现 Dubbo 全链路追踪](/zh-cn/overview/tasks/observability/tracing/zipkin/) +* [使用 Skywalking 实现 Dubbo 全链路追踪](/zh-cn/overview/tasks/observability/tracing/skywalking/) + +## 关联日志 + +Dubbo Tracing 还实现了与日志系统的自动关联,即将 tracing-id、span-id 等信息自动置入日志 MDC 上下文,你只需要设置日志输出格式中包含类似 `%X{traceId:-},%X{spanId:-}]`,即可实现业务日志与 tracing 系统的自动关联,具体可参见 [Tracing 日志上下文配置示例](https://github.com/apache/dubbo-samples/blob/master/4-governance/dubbo-samples-tracing/dubbo-samples-spring-boot-tracing-otel-otlp/provider/src/main/resources/application.yml)。 + +## 工作原理 +### Tracing相关概念 + +- Span:基本工作单元。例如,发送 RPC 是一个新的 span,发送对 RPC 的响应也是如此。Span还有其他数据,例如description、带时间戳的事件、键值注释(标签)、导致它们的跨度的 ID 和进程 ID(通常是 IP 地址)。跨度可以启动和停止,并且它们会跟踪它们的时间信息。创建跨度后,您必须在将来的某个时间点停止它。 + +- Trace:一组形成树状结构的跨度。例如,如果您运行分布式大数据存储,则可能会通过请求形成跟踪PUT。 + +- Annotation/Event : 用于及时记录一个事件的存在。 + +- Tracing context:为了使分布式跟踪工作,跟踪上下文(跟踪标识符、跨度标识符等)必须通过进程(例如通过线程)和网络传播。 + +- Log correlation:部分跟踪上下文(例如跟踪标识符、跨度标识符)可以填充到给定应用程序的日志中。然后可以将所有日志收集到一个存储中,并通过跟踪 ID 对它们进行分组。这样就可以从所有按时间顺序排列的服务中获取单个业务操作(跟踪)的所有日志。 + +- Latency analysis tools:一种收集导出跨度并可视化整个跟踪的工具。允许轻松进行延迟分析。 + +- Tracer: 处理span生命周期的库(Dubbo 目前支持 OpenTelemetry 和 Brave)。它可以通过 Exporter 创建、启动、停止和报告 Spans 到外部系统(如 Zipkin、Jagger 等)。 + +- Exporter: 将产生的 Trace 信息通过 http 等接口上报到外部系统,比如上报到 Zipkin。 + +### SpringBoot Starters + +对于 SpringBoot 用户,Dubbo 提供了 Tracing 相关的 starters,自动装配 Micrometer 相关的配置代码,且用户可自由选择 Tracer 和Exporter。 + +#### OpenTelemetry 作为 Tracer,将 Trace 信息 export 到 Zipkin + +```yml + + org.apache.dubbo + dubbo-spring-boot-tracing-otel-zipkin-starter + ${version} + +``` + +#### OpenTelemetry 作为 Tracer,将 Trace 信息 export 到 OTlp Collector + +```yml + + org.apache.dubbo + dubbo-spring-boot-tracing-otel-otlp-starter + ${version} + +``` + +#### Brave 作为 Tracer,将 Trace 信息 export 到 Zipkin + +```yml + + org.apache.dubbo + dubbo-spring-boot-tracing-brave-zipkin-starter + ${version} + +``` + +#### 自由组装 Tracer 和 Exporter + +如果用户基于 Micrometer 有自定义的需求,想将 Trace 信息上报至其他外部系统观测,可参照如下自由组装 Tracer 和 Exporter: + +```yml + + + org.apache.dubbo + dubbo-spring-boot-observability-starter + ${version} + + + + io.micrometer + micrometer-tracing-bridge-otel + ${version} + + + + io.opentelemetry + opentelemetry-exporter-zipkin + ${version} + +``` + +```yml + + + org.apache.dubbo + dubbo-spring-boot-observability-starter + ${version} + + + + io.micrometer + micrometer-tracing-bridge-brave + ${version} + + + + io.zipkin.reporter2 + zipkin-reporter-brave + ${version} + +``` + +后续还会补齐更多的 starters,如 Jagger、SkyWalking等。 + +### Dubbo Bootstrap API + +对于像非 SpringBoot 的项目,可以使用 Dubbo API 使用Tracing。 + +详细案例可参考[代码地址](https://github.com/conghuhu/dubbo-samples/tree/master/4-governance/dubbo-samples-tracing/dubbo-sample-api-tracing-otel-zipkin) + + diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/zipkin.md b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/zipkin.md new file mode 100644 index 000000000000..42c00fe3496e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/zipkin.md @@ -0,0 +1,159 @@ +--- +aliases: + - /zh/overview/tasks/observability/tracing/zipkin/ + - /zh-cn/overview/tasks/observability/tracing/zipkin/ +description: "这个示例演示了 Dubbo 集成 Zipkin 全链路追踪的基础示例" +linkTitle: Zipkin +no_list: true +title: Zipkin +type: docs +weight: 3 +--- + +这个示例演示了 Dubbo 集成 Zipkin 全链路追踪的基础示例,完整代码请参考 dubbo-samples-tracing-zipkin,此示例共包含三部分内容: + +* dubbo-samples-spring-boot3-tracing-provider +* dubbo-samples-spring-boot3-tracing-consumer +* dubbo-samples-spring-boot3-tracing-interface + +## 快速开始 + +### 安装 & 启动 Zipkin + +参考 [Zipkin's quick start](https://zipkin.io/pages/quickstart.html) 安装 Zipkin。 + +这里我们使用 Docker 来演示如何快速的启动 Zipkin 服务。 + +```bash +docker run -d -p 9411:9411 --name zipkin openzipkin/zipkin +``` + +紧接着,你可以通过如下链接确认 Zipkin 正常工作 `[http://localhost:9411](http://localhost:9411)` + +![zipkin_home](/imgs/v3/tasks/observability/tracing/zipkin_home.png) + +### 安装 & 启动 Nacos + +跟随 [Nacos's quick start](https://nacos.io/zh-cn/docs/v2/quickstart/quick-start.html) 快速安装并启动 Nacos。 + +### 启动示例 Provider + +在 IDE 中直接运行 `org.apache.dubbo.springboot.demo.provider.ProviderApplication`。 + +### 启动示例 Consumer + +在 IDE 中直接运行 `org.apache.dubbo.springboot.demo.consumer.ConsumerApplication`。 + +### 检查监控效果 + +在浏览器中打开 `http://localhost:9411/zipkin/` 查看效果。 + +![zipkin.png](/imgs/v3/tasks/observability/tracing/zipkin.png) + +## 如何在SpringBoot项目中使用 Dubbo Tracing + +### 1. 添加 Dubbo Tracing 相关的 Starter 依赖 + +从下面两个 starter 中选择一个加入到你的项目中,区别在于 Tracer 的选型不一样,一个是 Opentelemetry,一个是 Brave: + +```xml + + + org.apache.dubbo + dubbo-spring-boot-tracing-otel-zipkin-starter + +``` + +```xml + + + org.apache.dubbo + dubbo-spring-boot-tracing-brave-zipkin-starter + +``` + +### 2. 配置 + +在application.yml中添加如下配置: + +```yaml +dubbo: + tracing: + enabled: true # 默认为false + sampling: + probability: 0.5 # 采样率, 默认是 0.1 + propagation: + type: W3C # 传播器类型:W3C/B3 默认是W3C + tracing-exporter: + zipkin-config: + endpoint: http://localhost:9411/api/v2/spans + connect-timeout: 1s # 建立连接超时时间, 默认为1s + read-timeout: 10s # 传递数据超时时间, 默认为10s + +# tracing信息输出到logging +logging: + pattern: + level: '%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]' +``` + +## 扩展 + +### 选择合适的Sender + +Zipkin 的 Sender,是 Exporter 将埋点后的数据进行上报的客户端实现,全部实现可[参考](https://github.com/openzipkin/zipkin-reporter-java) + +Sender 有很多种实现: + +* URLConnectionSender 通过 Java 自带的 HTTP 客户端上报 +* OkHttpSender 通过 OKHttp3 上报 +* KafkaSender 通过 Kafka 消息队列上报 +* ActiveMQSender 通过 ActiveMQ 消息队列上报 +* RabbitMQSender 通过 RabbitMQ 消息队列上报 + +Dubbo Tracing 相关的 starter 目前默认是使用 OKHttpSender,也支持 URLConnectionSender,如果想通过 URLConnectionSender 向 Zipkin 发送 Spans,可直接在 pom 中添加如下依赖: + +```xml + + io.zipkin.reporter2 + zipkin-sender-urlconnection + +``` + +配置 Zipkin 的 endpoint、connectTimeout、readTimeout + +```yaml +dubbo: + tracing: + enabled: true # 默认为false + tracing-exporter: + zipkin-config: + endpoint: http://localhost:9411/api/v2/spans + connect-timeout: 1s # 建立连接超时时间, 默认为1s + read-timeout: 10s # 传递数据超时时间, 默认为10s +``` + +如果想使用其他类型的 Sender ,需要用户在项目中手动注入对应的 Bean,并配置对应的属性,如 KafkaSender: + +```java +@Configuration +public class KafkaSenderConfiguration { + + @Bean + KafkaSender kafkaSender(){ + KafkaSender.Builder builder = KafkaSender.newBuilder(); + builder.bootstrapServers("127.0.0.0.1:9092"); + builder.topic("zipkin"); + builder.encoding(Encoding.JSON); + return builder.build(); + } + +} +``` + +### SpringBoot2案例 + +dubbo-tracing相关的使用在SpringBoot2与3中区别不大,SpringBoot2的案例可参考[代码地址](https://github.com/conghuhu/dubbo-samples/tree/master/4-governance/dubbo-samples-tracing/dubbo-samples-spring-boot-tracing-zipkin)。 + +### 非SpringBoot项目案例 + +对于非SpringBoot项目,也可以使用 Dubbo Bootstrap 的 api 方式使用 tracing,详细案例可参考[代码地址](https://github.com/conghuhu/dubbo-samples/tree/master/4-governance/dubbo-samples-tracing/dubbo-sample-api-tracing-otel-zipkin) diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/_index.md b/content/en/overview/mannual/java-sdk/tasks/protocols/_index.md new file mode 100755 index 000000000000..d4009fbfd385 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/overview/tasks/protocols/ + - /zh-cn/overview/tasks/protocols/ + - /zh-cn/overview/mannual/java-sdk/tasks/protocol/ +description: 演示 Dubbo 多协议的应用场景 +hide: true +linkTitle: 通信协议 +title: 通信协议 +type: docs +weight: 2 +--- diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/dubbo.md b/content/en/overview/mannual/java-sdk/tasks/protocols/dubbo.md new file mode 100644 index 000000000000..057591a935ff --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/dubbo.md @@ -0,0 +1,119 @@ +--- +aliases: + - /zh/overview/tasks/protocols/dubbo/ + - /zh-cn/overview/tasks/protocols/dubbo/ +description: "演示了如何开发基于 `dubbo` 协议通信的服务。" +linkTitle: dubbo协议 +title: "基于 TCP 的 RPC 通信协议 - dubbo" +type: docs +weight: 2 +--- + +本示例演示了如何开发基于 `dubbo` 协议通信的服务,可在此查看 [本示例的完整代码](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-dubbo): + +{{% alert title="注意" color="info" %}} +为了保证老版本兼容性,Dubbo 3.3.0 及之前版本的默认协议都是 `dubbo`。但如果您是新用户,正在考虑使用 Dubbo 构建一套全新的微服务系统,我们推荐您在应用中明确配置使用 `triple` 协议。 +{{% /alert %}} + +## 运行示例 +你可以跟随以下步骤,尝试运行本文档对应的示例源码。 + +首先,可通过以下命令下载示例源码 +```shell +git clone --depth=1 https://github.com/apache/dubbo-samples.git +``` + +进入示例源码目录: +```shell +cd dubbo-samples/2-advanced/dubbo-samples-dubbo +``` + +使用 maven 打包示例: +```shell +mvn clean install -DskipTests +``` + +### 启动提供者 +运行以下命令启动提供者: + +```shell +java -jar ./dubbo-samples-dubbo-provider/target/dubbo-samples-dubbo-provider-1.0-SNAPSHOT.jar +``` + +### 启动消费者 +运行以下命令: + +```shell +java -jar ./dubbo-samples-dubbo-consumer/target/dubbo-samples-dubbo-consumer-1.0-SNAPSHOT.jar +``` + +## 源码讲解 + +### 定义服务 +首先是服务定义,使用 `dubbo` 协议时,我们首选需要通过 Java Interface 定义 Dubbo 服务。 +```java +public interface DemoService { + String sayHello(String name); +} +``` + +### 服务提供者 +其次,对于提供者一侧而言,需要提供服务的具体实现。 +```java +@DubboService +public class DemoServiceImpl implements DemoService { + @Override + public String sayHello(String name) { + return "Hello " + name; + } +} +``` + +配置使用 `dubbo` 协议: +```yaml +dubbo: + protocol: + name: dubbo + port: 20880 +``` + +### 服务消费者 + +配置服务引用,如下所示: +```java +@Component +public class Task implements CommandLineRunner { + @DubboReference(url = "dubbo://127.0.0.1:20880/org.apache.dubbo.protocol.dubbo.demo.DemoService") + private DemoService demoService; +} +``` + +接下来,就可以发起对远程服务的 RPC 调用了: +```java +demoService.sayHello("world"); +``` + +## 更多协议配置 + +### 序列化 +消费者与提供者之间的调用使用 dubbo 协议,**方法参数默认数据编码格式(即序列化)是 hessian2**,同时你也可以设置使用其他任意序列化协议,序列化不影响 dubbo 协议的正常工作(只会对编码性能有一些影响)。 + +```yaml +dubbo: + protocol: + name: dubbo + port: 20880 + serialization: fastjson2 +``` + +{{% alert title="注意" color="info" %}} +自 3.2.0 版本开始,Dubbo 增加了序列化协议的自动协商机制,如果满足条件 `两端都为 Dubbo3 特定版本 + 存在 Fastjson2 相关依赖`,则会自动使用 fastjson2 序列化协议,否则使用 hessian2 协议,协商对用户透明无感。 + +由于 Dubbo2 默认序列化协议是 hessian2,对于部分有拦截rpc调用payload的场景,比如sidecar等对链路payload有拦截与解析,在升级过程中需留意兼容性问题,其他用户不用担心。 +{{% /alert %}} + +### 共享连接 +对 dubbo 协议实现来说,**消费端机器A与提供者机器B之间默认是使用的同一个链接**,即不论在 A 与 B 之间有多少服务调用,默认都始终使用同一个 tcp 连接。当然,Dubbo 框架提供了方法可以让您调整 A 与 B 之间的 tcp 连接数。 + +此外,dubbo 协议还支持配置如 payload 限制、序列化、连接数、连接超时时间、心跳等,具体请参见[【参考手册 - dubbo协议】](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/dubbo/)。 + diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/protocol.md b/content/en/overview/mannual/java-sdk/tasks/protocols/protocol.md new file mode 100755 index 000000000000..40a7e7a3ec5a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/protocol.md @@ -0,0 +1,250 @@ +--- +description: "提供不同场景下的协议选型(triple、dubbo)指南,包含每个协议的基本配置方式、默认端口、适用场景等。" +linkTitle: 选择 RPC 协议 +title: Dubbo 支持的 RPC 通信协议 +type: docs +weight: 1 +--- + +Dubbo 作为一款 RPC 框架内置了高效的 RPC 通信协议,帮助解决服务间的编码与通信问题,目前支持的协议包括: + * triple,基于 HTTP/1、HTTP/2 的高性能通信协议,100% 兼容 gRPC,支持 Unary、Streming 等通信模式;支持发布 REST 风格的 HTTP 服务。 + * dubbo,基于 TCP 的高性能私有通信协议,缺点是通用性较差,更适合在 Dubbo SDK 间使用; + * 任意协议扩展,通过扩展 protocol 可以之前任意 RPC 协议,官方生态库提供 JsonRPC、thrift 等支持。 + +## 协议概览 + +### 使用哪个协议? + +**开发者该如何确定使用哪一种协议那?** 以下是我们从使用场景、性能、编程易用性、多语言互通等方面对多个主流协议的对比分析: + +| 协议 | 性能 | 网关友好 | 流式通信 | 多语言支持 | 编程API | 说明 | +| --- | --- | --- | --- | --- | --- | --- | +| triple | 高 | 高 | 支持,客户端流、服务端流、双向流 | 支持(Java、Go、Node.js、JavaScript、Rust) | Java Interface、Protobuf(IDL) | 在多语言兼容、性能、网关、Streaming、gRPC 等方面最均衡的协议实现,官方推荐。 | +| dubbo | 高 | 低 | 不支持 | 支持(Java、Go) | Java Interface | 性能最高的私有协议,但前端流量接入、多语言支持等成本较高 | +| rest | 低 | 高 | 不支持 | 支持 | Java Interface | rest 协议在前端接入、互通等方面具备最高的灵活性,但对比 rpc 存在性能、弱类型等缺点。**注意,rest 在 dubbo3 中仅是 triple 协议的一种发布形式** | + +{{% alert title="注意" color="warning" %}} +自 3.3 版本开始,triple 协议支持以 rest 风格发布标准的 http 服务,因此框架中实际已不存在独立的 rest protocol 扩展实现。只是在文档说明上,我们依然选择将 triple 与 rest 作为独立的协议实现分开讲解,请大家注意。 +{{% /alert %}} + +### 协议默认值 +以下是几个主要协议的具体开发、配置、运行态信息: + | 协议名称 | 配置值 | 服务定义方式 | 默认端口 | 传输层协议 | 序列化协议 | 是否默认 | + | --- | --- | --- | --- | --- | --- | --- | + | **triple** | tri | - Java Interface
- Protobuf(IDL) | 50051 | HTTP/1、HTTP/2 | Protobuf Binary、Protobuf JSON | 否 | + | **dubbo** | dubbo | - Java Interface | 20880 | TCP | Hessian、Fastjson2、JSON、JDK、Avro、Kryo 等 | **是** | + | **rest** | tri 或 rest | - Java Interface + SpringMVC
- Java Interface + JAX-RS | 50051 | HTTP/1、HTTP/2 | JSON | 否 | + + {{% alert title="注意" color="info" %}} + 考虑到对过往版本的兼容性,当前 Dubbo 各个发行版本均默认使用 `dubbo` 通信协议。**对于新用户而言,我们强烈建议在一开始就明确配置使用 `triple` 协议**,老用户也尽快参考文档 [实现协议的平滑迁移](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/)。 + {{% /alert %}} + +接下来,我们一起看以下几个协议的基本使用方式。 + +## Triple 协议 +### 基本配置 +通过以下配置启用 triple 协议,默认端口为 50051,如果设置 `port: -1` 则会随机选取端口(从 50051 自增,直到找到第一个可用端口)。 + +```yaml +dubbo: + protocol: + name: tri + port: 50051 +``` + +### 服务定义方式 +使用 triple 协议时,开发者可以使用 `Java Interface`、`Protobuf(IDL)` 两种方式定义 Dubbo RPC 服务,两种服务定义模式下的协议能力是对等的,仅影响开发者的编程体验,具体选用那种开发模式,取决于使用者的业务背景。 + +#### 1. Java Interface +即通过声明一个 Java 接口的方式定义服务,我们在快速开始一节中看到的示例即是这种模式,**适合于没有跨语言诉求的开发团队,具备学习成本低的优势,Dubbo2 老用户可以零成本切换协议**。 + +服务定义范例: + +```java +public interface DemoService { + String sayHello(String name); +} +``` + +可以说只设置 `protocol="tri"` 就可以了,其他与老版本 dubbo 协议开发没有任何区别。请通过【进阶学习 - 通信协议】查看 [java Interface + Triple 协议的具体使用示例](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/interface/)。 + +#### 2. Protobuf(IDL) +使用 Protobuf(IDL) 的方式定义服务,**适合于当前或未来有跨语言诉求的开发团队,同一份 IDL 服务可同时用于 Java/Go/Node.js 等多语言微服务开发,劣势是 protobuf 学习成本较高**。 + +```Protobuf +syntax = "proto3"; +option java_multiple_files = true; +package org.apache.dubbo.springboot.demo.idl; + +message GreeterRequest { + string name = 1; +} +message GreeterReply { + string message = 1; +} + +service Greeter{ + rpc greet(GreeterRequest) returns (GreeterReply); +} +``` + +通过 Dubbo 提供的 protoc 编译插件,将以上 IDL 服务定义预编译为相关 stub 代码,其中就包含 Dubbo 需要的 Interface 接口定义,因此在后续编码上区别并不大,只不过相比于前面的用户自定义 Java Interface 模式,这里由插件自动帮我们生成 Interface 定义。 + +```java +// Generated by dubbo protoc plugin +public interface Greeter extends org.apache.dubbo.rpc.model.DubboStub { + String JAVA_SERVICE_NAME = "org.apache.dubbo.springboot.demo.idl.Greeter"; + String SERVICE_NAME = "org.apache.dubbo.springboot.demo.idl.Greeter"; + + org.apache.dubbo.springboot.demo.idl.GreeterReply greet(org.apache.dubbo.springboot.demo.idl.GreeterRequest request); + // more generated codes here... +} +``` + +Protobuf 模式支持的序列化方式有 Protobuf、Protobuf-json 两种模式。请通过【进阶学习 - 通信协议】查看 [Protobuf (IDL) + Triple 协议的具体使用示例](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/)。 + +#### 3. 我该使用哪种编程模式,如何选择? + +| | 是 | 否 | +| --- | --- | --- | +| 公司的业务是否有用 Java 之外的其他语言,跨语言互通的场景是不是普遍? | Protobuf | Java 接口 | +| 公司里的开发人员是否熟悉 Protobuf,愿意接受 Protobuf 的额外成本吗? | Protobuf | Java 接口 | +| 是否有标准 gRPC 互通诉求? | Protobuf | Java 接口 | +| 是不是 Dubbo2 老用户,想零改造迁移到 triple 协议? | Java 接口 | Protobuf | + +### HTTP 接入方式 +triple 协议支持标准 HTTP 工具的直接访问,因此前端组件如浏览器、网关等接入非常边便捷,同时服务测试也变得更简单。 + +当服务启动后,可以使用 cURL 命令直接访问: +```shell +curl \ + --header "Content-Type: application/json" \ + --data '["Dubbo"]' \ + http://localhost:50052/org.apache.dubbo.springboot.demo.idl.Greeter/greet/ +``` + +以上默认使用 `org.apache.dubbo.springboot.demo.idl.Greeter/greet` 这种 HTTP 访问路径,且仅支持 post 方法,如果你想对外发布 REST 风格服务,请参考下文 REST 协议小节。 + +也可参考[【使用教程 - 前端网关接入】](/zh-cn/overview/mannual/java-sdk/tasks/gateway/triple/) + +## Dubbo 协议 +### 基本配置 +通过以下配置启用 dubbo 协议,默认端口为 20880,如果设置 `port: -1` 则会随机选取端口(从 20880 自增,直到找到第一个可用端口)。 + +```yaml +dubbo: + protocol: + name: dubbo + port: 20880 +``` + +### 服务定义方式 +dubbo 协议支持使用 `Java Interface` 方式定义 Dubbo RPC 服务,即通过声明一个 Java 接口的方式定义服务。序列化方式可以选用 Hessian、Fastjson2、JSON、Kryo、JDK、自定义扩展等任意编码协议,默认序列化协议为 Fastjson2。 + +```java +public interface DemoService { + String sayHello(String name); +} +``` + +{{% alert title="注意" color="info" %}} +自 3.2.0 版本开始,Dubbo 增加了序列化协议的自动协商机制,如果满足条件 `两端都为 Dubbo3 特定版本 + 存在 Fastjson2 相关依赖`,则会自动使用 fastjson2 序列化协议,否则使用 hessian2 协议,协商对用户透明无感。 + +由于 Dubbo2 默认序列化协议是 hessian2,对于部分有拦截rpc调用payload的场景,比如sidecar等对链路payload有拦截与解析,在升级过程中需留意兼容性问题。 +{{% /alert %}} + +* 关于 dubbo 协议的具体使用示例请参见【进阶学习 - 通信协议】中的 [dubbo 协议示例](/zh-cn/overview/mannual/java-sdk/tasks/protocols/dubbo/)。 + +### HTTP 接入方式 +由于 dubbo 协议无法支持 http 流量直接接入,因此需要有一层网关实现前端 http 协议到后端 dubbo 协议的转换过程(`http -> dubbo`)。Dubbo 框架提供了 `泛化调用` 能力,可以让网关在无服务接口定义的情况下对后端服务发起调用。 + + + +目前社区有很多开源网关产品(Higress、Shenyu、APISIX、Tengine等)支持 `http -> dubbo` 的,它们大部分都提供了可视化界面配置参数映射(泛化调用),同时还支持基于 Nacos、Zookeeper 等主流注册中心的自动地址发现,具体请查看 [【使用教程 - HTTP网关接入】](/zh-cn/overview/mannual/java-sdk/tasks/gateway/dubbo/)。 + +## REST 协议 +在本文前面我们曾提到,自 3.3 版本开始 triple 协议支持以 rest 风格发布标准的 http 服务,因此,如果我们发布 rest 风格的服务等同于使用 triple 协议,只不过,我们要在服务定义上加入特定的注解(Spring Web、JAX-RS)。 + +```yaml +dubbo: + protocol: + name: tri + port: 50051 +``` + +{{% alert title="注意" color="info" %}} +对于老版本的 rest 用户配置是 `name: rest`,用户可以选择将改为 `name: tri`。即使不修改也没有问题,Dubbo 框架会自动将 rest 转换为 triple 协议实现。 +{{% /alert %}} + +所以说,rest 只是 triple 协议的一种特殊的发布形式,为了实现 rest 格式发布,我们需要为服务接口定义增加注解。 + +### 注解 +目前 rest 协议仅支持 `Java 接口` 服务定义模式,相比于 dubbo 和 triple 协议,rest 场景下我们需要为 Interface 增加注解,支持 Spring MVC、JAX_RS 两种注解。 + +Spring MVC 服务定义范例: +```java +@RestController +@RequestMapping("/demo") +public interface DemoService { + @GetMapping(value = "/hello") + String sayHello(); +} +``` + +JAX-RS 服务定义范例: +```java +@Path("/demo") +public interface DemoService { + @GET + @Path("/hello") + String sayHello(); +} +``` + +如果你记得 triple 协议原生支持 cURL 访问,即类似 `org.apache.dubbo.springboot.demo.idl.Greeter/greet` 的访问模式。通过增加以上注解后,即可为 triple 服务额外增加 REST 风格访问支持。 + +关于 rest 协议的具体使用示例请参见【使用教程 - 通信协议】中的 [rest 协议示例](../rest/) + +## 多协议发布 +### 多端口多协议 +多协议发布是指为同一个服务同时提供多种协议访问方式,多协议可以是任意两个或多个协议的组合,比如下面的配置将同时发布了 dubbo、triple 协议: + +```yaml +dubbo: + protocols: + - name: tri + port: 50051 + - name: dubbo + port: 20880 +``` + +基于以上配置,如果应用中有服务 DemoService,则既可以通过 dubbo 协议访问 DemoService,也可以通过 triple 协议访问 DemoService,其工作原理图如下: + +多协议 + +1. 提供者实例同时监听两个端口 20880 和 50051 +2. 同一个实例,会在注册中心注册两条地址 url +3. 不同的消费端可以选择以不同协议调用同一个提供者发布的服务 + +对于消费端而言,如果用户没有明确配置,默认情况下框架会自动选择 `dubbo` 协议调用。Dubbo 框架支持配置通过哪个协议访问服务,如 `@DubboReference(protocol="tri")`,或者在 application.yml 配置文件中指定全局默认值: + +```yaml +dubbo: + consumer: + protocol: tri +``` + +### 单端口多协议 + +除了以上发布多个端口、注册多条 url 到注册中心的方式。对于 dubbo、triple 这两个内置协议,框架提供了在单个端口上同时发布 dubbo 和 triple 协议的能力。这对于老用户来说是一个非常重要的能力,因为它可以做到不增加任何负担的情况下,让使用 dubbo 协议的用户可以额外发布 triple 协议,这样当所有的应用都实现多协议发布之后,我们就可以设置消费端去通过 triple 协议发起调用了。 + +单端口多协议 + +单端口多协议的基本配置如下: + + ```yaml + dubbo: + protocol: + name: dubbo + ext-protocol: tri + ``` diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/rest.md b/content/en/overview/mannual/java-sdk/tasks/protocols/rest.md new file mode 100644 index 000000000000..985fee6fb06f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/rest.md @@ -0,0 +1,188 @@ +--- +aliases: + - /zh/overview/tasks/protocols/ + - /zh-cn/overview/tasks/protocols/ +description: "演示了如何以标准 `rest` 请求访问 triple、dubbo 协议发布的服务。" +hide: true +linkTitle: rest协议 +title: 发布 REST 风格的服务 +type: docs +weight: 3 +--- + +{{% alert %}} +本文要讲的 "rest 协议" 实际上并不是一个真正的协议实现,而是关于如何使得 triple 协议支持以 rest 风格的 http 请求直接访问。 +我们将演示如何使用 rest 请求访问标准 triple 协议的 Dubbo 服务。 +{{% /alert %}} + +{{% alert title="注意" color="warning" %}} +从 Dubbo 3.3 版本开始,rest 协议已移至 extensions 库,由 triple 协议来对 Rest 提供更全面的支持,新版本的内置协议实现只剩下 triple 和 dubbo。 +
因此,当我们提到 rest 时,都是指 triple 协议的 rest 访问支持能力,具体参见 [Triple Rest用户手册](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual/) +{{% /alert %}} + +在讲解 [triple 协议示例](../triple/interface/#curl) 时,我们曾提到 triple 协议支持以 `application/json` 格式直接访问: + +```shell +curl \ + --header "Content-Type: application/json" \ + --data '["Dubbo"]' \ + http://localhost:50052/org.apache.dubbo.samples.api.GreetingsService/sayHi/ +``` + +如果你认为以上 +`http://localhost:50052/org.apache.dubbo.samples.api.GreetingsService/sayHi` 格式的 path 请求不够友好,还可以通过注解自定义 http 请求的路径和方法等参数, +目前已支持 内置,Spring Web和JAX-RS 三种注解格式。以下示例的完整代码请参见 [dubbo-samples-triple-rest](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-rest)。 + +### 下载并运行示例 + +```bash +# 获取示例代码 +git clone --depth=1 https://github.com/apache/dubbo-samples.git +cd dubbo-samples/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-basic +# 直接运行 +mvn spring-boot:run +# 或打包后运行 +mvn clean package -DskipTests +java -jar target/dubbo-samples-triple-rest-basic-1.0.0-SNAPSHOT.jar +``` + +当然,也可以直接用IDE导入工程后直接执行 +`org.apache.dubbo.rest.demo.BasicRestApplication#main` 来运行,并通过下断点 debug 的方式来深入理解原理。 + + +### 示例代码 + +```java +// 服务接口 +package org.apache.dubbo.rest.demo; + +import org.apache.dubbo.remoting.http12.rest.Mapping; +import org.apache.dubbo.remoting.http12.rest.Param; + +public interface DemoService { + String hello(String name); + + @Mapping(path = "/hi", method = HttpMethods.POST) + String hello(User user, @Param(value = "c", type = ParamType.Header) int count); +} + +// 服务实现 +@DubboService +public class DemoServiceImpl implements DemoService { + @Override + public String hello(String name) { + return "Hello " + name; + } + + @Override + public String hello(User user, int count) { + return "Hello " + user.getTitle() + ". " + user.getName() + ", " + count; + } +} + +// 模型 +@Data +public class User { + private String title; + private String name; +} +``` + + + +### 测试基本服务 + +```bash +curl -v "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hello?name=world" +# 输出如下 +#> GET /org.apache.dubbo.rest.demo.DemoService/hello?name=world HTTP/1.1 +#> Host: 127.0.0.1:8081 +#> User-Agent: curl/8.7.1 +#> Accept: */* +#> +#* Request completely sent off +#< HTTP/1.1 200 OK +#< content-type: application/json +#< alt-svc: h2=":8081" +#< content-length: 13 +#< +#"Hello world" +``` + +代码讲解:
可以看到输出了 "Hello world" ,有双引号是因为默认输出 content-type 为 application/json
通过这个例子可以了解 Triple 默认将服务导出到 +`/{serviceInterface}/{methodName}`路径,并支持通过url方式传递参数 + + +### 测试高级服务 + +```bash +curl -v -H "c: 3" -d 'name=Yang' "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr" +# 输出如下 +#> POST /org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr HTTP/1.1 +#> Host: 127.0.0.1:8081 +#> User-Agent: curl/8.7.1 +#> Accept: */* +#> c: 3 +#> Content-Length: 9 +#> Content-Type: application/x-www-form-urlencoded +#> +#* upload completely sent off: 9 bytes +#< HTTP/1.1 200 OK +#< content-type: text/plain +#< alt-svc: h2=":8081" +#< content-length: 17 +#< +#Hello Mr. Yang, 3 +``` + +代码讲解:
可以看到输出 Hello Mr. Yang, 3 ,没有双引号是因为通过指定后缀 txt 的方式要求用 `text/plain` 输出
通过这个例子可以了解如何通过 Mapping 注解来定制路径,通过 Param 注解来定制参数来源,并支持通过 post body 或 url方式传递参数,详细说明参见: [Basic使用指南](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual/#GdlnC) + + +### 观察日志 + +可以通过打开 debug 日志的方式来了解rest的启动和响应请求过程 + +```yaml +logging: + level: + "org.apache.dubbo.rpc.protocol.tri": debug + "org.apache.dubbo.remoting": debug +``` + +打开后可以观察到 Rest 映射注册和请求响应过程 + +``` +# 注册mapping +DEBUG o.a.d.r.p.t.TripleProtocol : [DUBBO] Register triple grpc mapping: 'org.apache.dubbo.rest.demo.DemoService' -> invoker[tri://192.168.2.216:8081/org.apache.dubbo.rest.demo.DemoService] + INFO .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] BasicRequestMappingResolver resolving rest mappings for ServiceMeta{interface=org.apache.dubbo.rest.demo.DemoService, service=DemoServiceImpl@2a8f6e6} at url [tri://192.168.2.216:8081/org.apache.dubbo.rest.demo.DemoService] +DEBUG .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Register rest mapping: '/org.apache.dubbo.rest.demo.DemoService/hi' -> mapping=RequestMapping{name='DemoServiceImpl#hello', path=PathCondition{paths=[org.apache.dubbo.rest.demo.DemoService/hi]}, methods=MethodsCondition{methods=[POST]}}, method=MethodMeta{method=org.apache.dubbo.rest.demo.DemoService.hello(User, int), service=DemoServiceImpl@2a8f6e6} +DEBUG .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Register rest mapping: '/org.apache.dubbo.rest.demo.DemoService/hello' -> mapping=RequestMapping{name='DemoServiceImpl#hello~S', path=PathCondition{paths=[org.apache.dubbo.rest.demo.DemoService/hello]}}, method=MethodMeta{method=org.apache.dubbo.rest.demo.DemoService.hello(String), service=DemoServiceImpl@2a8f6e6} + INFO .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Registered 2 REST mappings for service [DemoServiceImpl@44627686] at url [tri://192.168.2.216:8081/org.apache.dubbo.rest.demo.DemoService] in 11ms + +# 请求响应 +DEBUG .a.d.r.p.t.r.m.RestRequestHandlerMapping : [DUBBO] Received http request: DefaultHttpRequest{method='POST', uri='/org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr', contentType='application/x-www-form-urlencoded'} +DEBUG .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Matched rest mapping=RequestMapping{name='DemoServiceImpl#hello', path=PathCondition{paths=[/org.apache.dubbo.rest.demo.DemoService/hi]}, methods=MethodsCondition{methods=[POST]}}, method=MethodMeta{method=org.apache.dubbo.rest.demo.DemoService.hello(User, int), service=DemoServiceImpl@2a8f6e6} +DEBUG .a.d.r.p.t.r.m.RestRequestHandlerMapping : [DUBBO] Content-type negotiate result: request='application/x-www-form-urlencoded', response='text/plain' +DEBUG .d.r.h.AbstractServerHttpChannelObserver : [DUBBO] Http response body is: '"Hello Mr. Yang, 3"' +DEBUG .d.r.h.AbstractServerHttpChannelObserver : [DUBBO] Http response headers sent: {:status=[200], content-type=[text/plain], alt-svc=[h2=":8081"], content-length=[17]} +``` + +## 实际应用场景 + +接下来,我们看一下在 triple 协议支持 rest 格式访问后,能被应用于哪些场景中解决实际问题。 + +### Spring Cloud 互调 + +首先,第一个场景就是实现 Dubbo 体系与 http 微服务体系互通。 + +设想你是一条业务线负责人,你们有一套基于 Dubbo 开发的微服务集群,集群内服务间都是基于 triple 二进制协议通信;公司内还有一个重要业务,是跑在基于 Spring Cloud 开发的微服务集群上,而 Spring Cloud 集群内的服务间都是 http+json 协议通信。现在要实现这两个业务的互通,服务之间如何实现互调那?triple 协议支持 rest 格式访问可以解决这个问题,对于 Dubbo 微服务集群而言,相当于是对内使用 triple 二进制协议通信,对外交互使用 triple 提供的 rest 请求格式。 + +关于这部分的具体使用示例,请参考博客 [微服务最佳实践零改造实现 Spring Cloud、Apache Dubbo 互通](/zh-cn/blog/2023/10/07/微服务最佳实践零改造实现-spring-cloud-apache-dubbo-互通/)。 + +### 网关流量接入 + +支持 rest 格式访问的另外一个非常有价值的场景就是方便网关流量接入。二进制格式的 rpc 协议接入一直是个难题,之前 dubbo 还特意提供了 +`泛化调用` 来解决这个问题,网关可以基于泛化调用实现 `http -> dubbo` 协议转换来接入后端微服务集群。 + +现在,有了 rest 格式支持,无需任何网关做协议转换,即可实现去中心化接入。具体请参见 [HTTP 网关流量接入](../../gateway/) + diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/triple/_index.md b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/_index.md new file mode 100755 index 000000000000..7fc9974eac39 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/overview/tasks/protocols/ + - /zh-cn/overview/tasks/protocols/ +description: "演示了如何开发基于 `triple` 协议通信的服务。" +hide: true +linkTitle: triple协议 +title: "基于 HTTP1/2 的 RPC 通信协议 - triple" +type: docs +weight: 2 +--- + diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/triple/grpc.md b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/grpc.md new file mode 100644 index 000000000000..0841c9457e27 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/grpc.md @@ -0,0 +1,67 @@ +--- +aliases: + - /zh/overview/tasks/protocols/grpc/ +description: "演示了如何使用 triple 协议实现 Dubbo 服务与标准 gRPC 服务的互相调用。" +linkTitle: 发布/调用标准gRPC服务 +title: 使用 Dubbo 开发 gRPC 服务 +type: docs +weight: 5 +--- + +这个示例演示了如何使用 triple 协议实现 Dubbo 服务与标准 gRPC 服务的互相调用,可在此查看 [示例完整源码](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-grpc) + +![triple-grpc.png](/imgs/v3/tasks/protocol/triple-grpc.png) + +就像在 [Triple协议规范](https://dubbo.apache.org/zh-cn/overview/reference/protocols/triple/) 中所描述的,triple 协议与 gRPC 协议保持 100% 兼容,同时在易用性方面有了非常大的提升(比如支持 cURL、浏览器直接访问等),可以说 triple 是一个更好用的 gRPC 设计与实现。 + +## 运行示例 + +首先,可通过以下命令下载示例源码 +```shell +git clone --depth=1 https://github.com/apache/dubbo-samples.git +``` + +进入示例源码目录: +```shell +cd dubbo-samples/2-advanced/dubbo-samples-triple-grpc +``` + +接下来,我们分别从 dubbo 调用 grpc、grpc 调用 dubbo 两个不同的方向,看一下如何基于 triple 协议实现互调。 + +### 作为标准的 gRPC Server +在这一部分,我们会发布一个 Dubbo Triple Server,然后启动一个标准的 gRPC 消费端(示例采用谷歌官方发布的 grpc-java 编码)来调用 Triple 服务。 + +#### 启动 Dubbo server +确保你在 `dubbo-samples-triple-grpc` 目录,运行以下命令: + +```shell +$ mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.tri.grpc.interop.server.TriOpServer" +``` + +#### 使用标准 gRPC client 调用 Triple 服务 +打开一个新的终端,在 `dubbo-samples-triple-grpc` 目录运行以下命令: + +```shell +$ mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.tri.grpc.interop.server.GrpcClient" +``` + +### 作为标准的 gRPC Client +以下部分我们演示如何使用 triple 协议访问谷歌官方的 gRPC 服务(示例采用谷歌官方发布的 grpc-java 编写). + +#### 启动标准 gRPC server +```shell +$ mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.tri.grpc.interop.client.GrpcServer" +``` + +#### 使用 Dubbo client 调用标准 gRPC 服务 +```shell +$ mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.tri.grpc.interop.client.TriOpClient" +``` + +## 更多内容 + +本示例主要演示 triple 可以 100% 兼容谷歌发布的 gRPC 框架,而在 triple 相关部分具体代码与配置上,本示例与之前介绍的 [基于 protobuf 的 triple 示例完全一致](../idl/),因此我们不再重复讲解源代码与开发步骤。 + +本示例演示的是 unary 模式的通信兼容性,对于 streaming 模式同样适用。 + + diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/triple/idl.md b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/idl.md new file mode 100644 index 000000000000..a19bfe3e9f46 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/idl.md @@ -0,0 +1,290 @@ +--- +description: "Triple 协议支持使用 Protocol Buffers (Protobuf) 定义服务,对于因为多语言、gRPC、安全性等场景选型protobuf 的用户更友好。" +linkTitle: Protobuf(IDL)方式 +title: 使用 Protobuf(IDL) 开发 triple 通信服务 +type: docs +weight: 2 +--- + +本示例演示如何使用 Protocol Buffers 定义服务,并将其发布为对外可调用的 triple 协议服务。如果你有多语言业务互调、gRPC互通,或者熟悉并喜欢 Protobuf 的开发方式,则可以使用这种模式,否则可以考虑上一篇基于Java接口的 triple 开发模式。 + +可在此查看 [本示例的完整代码](https://github.com/apache/dubbo-samples/tree/master/1-basic/dubbo-samples-api-idl)。 + +{{% alert title="注意" color="info" %}} +本文使用的示例是基于原生 API 编码的,这里还有一个 [Spring Boot 版本的示例](https://github.com/apache/dubbo-samples/tree/master/1-basic/dubbo-samples-spring-boot-idl) 供参考,同样是 `protobuf+triple` 的模式,但额外加入了服务发现配置。 +{{% /alert %}} + +## 运行示例 + +首先,可通过以下命令下载示例源码: +```shell +git clone --depth=1 https://github.com/apache/dubbo-samples.git +``` + +进入示例源码目录: +```shell +cd dubbo-samples/1-basic/dubbo-samples-api-idl +``` + +编译项目,由 IDL 生成代码,这会调用 dubbo 提供的 protoc 插件生成对应的服务定义代码: +```shell +mvn clean compile +``` + +生成代码如下 + +```text +├── build +│   └── generated +│   └── source +│   └── proto +│   └── main +│   └── java +│   └── org +│   └── apache +│   └── dubbo +│   └── samples +│   └── tri +│   └── unary +│   ├── DubboGreeterTriple.java +│   ├── Greeter.java +│   ├── GreeterOuterClass.java +│   ├── GreeterReply.java +│   ├── GreeterReplyOrBuilder.java +│   ├── GreeterRequest.java +│   └── GreeterRequestOrBuilder.java +``` + +### 启动Server +运行以下命令启动 server。 +```shell +mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.tri.unary.TriUnaryServer" +``` + +### 访问服务 +有两种方式可以访问 Triple 服务: +* 以标准 HTTP 工具访问 +* 以 Dubbo client sdk 访问 + +#### cURL 访问 + +```shell +curl \ + --header "Content-Type: application/json" \ + --data '{"name":"Dubbo"}' \ + http://localhost:50052/org.apache.dubbo.samples.tri.unary.Greeter/greet/ +``` + +#### Dubbo client 访问 +运行以下命令,启动 Dubbo client 并完成服务调用 +```shell +mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.tri.unary.TriUnaryClient" +``` + +## 源码讲解 + +### 项目依赖 +由于使用 IDL 开发模式,因此要添加 dubbo、protobuf-java 等依赖,同时还要配置 protobuf-maven-plugin 等插件,用于生成桩代码。 + +```xml + + org.apache.dubbo + dubbo + ${dubbo.version} + + + com.google.protobuf + protobuf-java + 3.19.6 + + + com.google.protobuf + protobuf-java-util + 3.19.6 + +``` + +```xml + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.6.1 + + com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} + build/generated/source/proto/main/java + + + dubbo + org.apache.dubbo + dubbo-compiler + ${dubbo.version} + org.apache.dubbo.gen.tri.Dubbo3TripleGenerator + + + + + + + compile + + + + +``` + +{{% alert title="protoc 插件版本说明" color="warning" %}} + +{{% /alert %}} + +### 服务定义 +使用 Protocol Buffers 定义 Greeter 服务 + +```protobuf +syntax = "proto3"; +option java_multiple_files = true; +package org.apache.dubbo.samples.tri.unary; + +message GreeterRequest { + string name = 1; +} +message GreeterReply { + string message = 1; +} + +service Greeter{ + rpc greet(GreeterRequest) returns (GreeterReply); +} +``` + +请注意以上 package 定义 `package org.apache.dubbo.samples.tri.unary;`,在此示例中 package 定义的路径将同时作为 java 包名和服务名前缀。这意味着 rpc 服务的完整定义是:`org.apache.dubbo.samples.tri.unary.Greeter`,与生成代码的路径完全一致。 + +但保持一致并不是必须的,你也可以将 java 包名与服务名前缀定义分开定义,对于一些跨语言调用的场景比较有用处。如以下 IDL 定义中: +* 完整服务名是 `greet.Greeter`,rpc 调用及服务发现过程中会使用这个值 +* java 包名则是 java_package 定义的 `org.apache.dubbo.samples.tri.unary`,生成的 java 代码会放在这个目录。 + +```protobuf +package greet; +option java_package = "org.apache.dubbo.samples.tri.unary;" +option go_package = "github.com/apache/dubbo-go-samples/helloworld/proto;greet"; +``` + +### 服务实现 +在运行 `mvn clean compile` 后可生成 Dubbo 桩代码。接下来继承生成的基础类 `DubboGreeterTriple.GreeterImplBase`,添加具体的业务逻辑实现: + +```java +public class GreeterImpl extends DubboGreeterTriple.GreeterImplBase { + @Override + public GreeterReply greet(GreeterRequest request) { + LOGGER.info("Server {} received greet request {}", serverName, request); + return GreeterReply.newBuilder() + .setMessage("hello," + request.getName()) + .build(); + } +} +``` + +注册服务到 server,其中 protocol 设置为 tri 代表开启 triple 协议。 + +```java +public class TriUnaryServer { + public static void main(String[] args) throws IOException { + ServiceConfig service = new ServiceConfig<>(); + service.setInterface(Greeter.class); + service.setRef(new GreeterImpl()); + + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50052)) + .service(service) + .start().await(); + } +} +``` + +### 编写 client 逻辑 +```java +public class TriUnaryClient { + public static void main(String[] args) throws IOException { + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + ReferenceConfig ref = new ReferenceConfig<>(); + ref.setInterface(Greeter.class); + ref.setUrl("tri://localhost:50052"); + + bootstrap.reference(ref).start(); + Greeter greeter = ref.get(); + final GreeterReply reply = greeter.greet(GreeterRequest.newBuilder().setName("name").build()); + } +} +``` + +## 常见问题 + +### protobuf 类找不到 + +由于 Triple 协议底层需要依赖 protobuf 协议进行传输,即使定义的服务接口不使用 protobuf 也需要在环境中引入 protobuf 的依赖。 + +```xml + + com.google.protobuf + protobuf-java + 3.19.4 + +``` + +同时,为了支持 `application/json` 格式请求直接访问,还需要增加如下依赖。 +```xml + + com.google.protobuf + protobuf-java-util + 3.19.4 + +``` + +### 生成的代码无法编译 +在使用 Protobuf 时,请尽量保持 dubbo 核心库版本与 protoc 插件版本一致,并运行 `mvn clean compile` 重新生成代码。 + +**1. 3.3.0 版本之后** + +3.3.0+ 版本开始使用 `dubbo-maven-plugin` 配置 protoc 插件,`dubbo-maven-plugin` 的版本必须保持和使用的内核 dubbo 版本一致: + +```xml + + org.apache.dubbo + dubbo-maven-plugin + ${dubbo.version} + + + + +``` + +**2. 3.3.0 版本之前** + +3.3.0 之前的版本使用 `protobuf-maven-plugin` 配置 protoc 插件,其中 `dubbo-compiler` 必须保持和使用的内核 dubbo 版本一致: + +```xml + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.6.1 + + com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} + build/generated/source/proto/main/java + + + dubbo + org.apache.dubbo + dubbo-compiler + ${dubbo.version} + org.apache.dubbo.gen.tri.Dubbo3TripleGenerator + + + + + + + compile + + + + +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/triple/interface.md b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/interface.md new file mode 100644 index 000000000000..367b1138fb75 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/interface.md @@ -0,0 +1,148 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/pojo/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/pojo/ +description: "Triple 协议完全兼容 gRPC,但易用性更好不绑定 Protobuf,你可以继续使用 `Java 接口` 直接定义服务。" +linkTitle: Java接口方式 +title: 使用 Java 接口方式开发 triple 通信服务 +type: docs +weight: 1 +--- + +**不同于谷歌官方 gRPC 实现,Dubbo 实现的 triple 协议易用性更好(不绑定 Protobuf),你可以继续使用 `Java 接口` 直接定义服务。对于期望平滑升级、没有多语言业务或者不熟悉 Protobuf 的用户而言,`Java 接口`方式是最简单的使用 triple 的方式。** + +以下是一个使用`Java 接口`开发 Dubbo 服务的基本示例,示例使用 triple 协议通信,可在此查看 [本示例的完整代码](https://github.com/apache/dubbo-samples/tree/master/1-basic/dubbo-samples-api)。 + +{{% alert title="注意" color="info" %}} +本文使用的示例是基于原生 API 编码的,这里还有一个 [Spring Boot 版本的示例](https://github.com/apache/dubbo-samples/tree/master/1-basic/dubbo-samples-spring-boot) 供参考,同样是 `Java接口+triple` 的模式,此示例还额外加入了服务发现配置。 +{{% /alert %}} + +## 运行示例 +首先,可通过以下命令下载示例源码 +```shell +git clone --depth=1 https://github.com/apache/dubbo-samples.git +``` + +进入示例源码目录: +```shell +cd dubbo-samples/1-basic/dubbo-samples-api +``` + +### 启动Server +运行以下命令启动 server + +```bash +mvn -Dexec.mainClass=org.apache.dubbo.samples.provider.Application exec:java +``` + +### 启动Client + +有两种方式可以调用 server 发布的服务 +* 使用标准的 http 工具,如 cURL +* 使用 Dubbo SDK 开发一个 client + +#### cURL +```shell +curl \ + --header "Content-Type: application/json" \ + --data '["Dubbo"]' \ + http://localhost:50052/org.apache.dubbo.samples.api.GreetingsService/sayHi/ +``` + +#### SDK Client + +```bash +mvn -Dexec.mainClass=org.apache.dubbo.samples.client.Application exec:java +``` + +## 源码讲解 +如果您是 Dubbo 老用户,你会发现以下内容与之前 Dubbo2 的开发模式基本一样,只是协议名称从 `dubbo` 换成了 `tri`。 + +### 定义服务 +首先是服务定义,使用 Java 接口定义 Dubbo 服务。 +```java +public interface GreetingsService { + String sayHi(String name); +} +``` + +### 服务提供者 +其次,对于提供者一侧而言,需要提供服务的具体实现: +```java +public class GreetingsServiceImpl implements GreetingsService { + @Override + public String sayHi(String name) { + return "hi, " + name; + } +} +``` + +最后,是将服务发布出去: +```java +public static void main(String[] args) { + DubboBootstrap.getInstance() + .protocol(ProtocolBuilder.newBuilder().name("tri").port(50052).build()) + .service(ServiceBuilder.newBuilder().interfaceClass(GreetingsService.class).ref(new GreetingsServiceImpl()).build()) + .start() + .await(); +} +``` + +### 服务消费者 + +接下来,就可以发起对远程服务的 RPC 调用了: +```java +public static void main(String[] args) throws IOException { + ReferenceConfig reference = + ReferenceBuilder.newBuilder() + .interfaceClass(GreetingsService.class) + .url("tri://localhost:50052") + .build(); + DubboBootstrap.getInstance().reference(reference).start(); + GreetingsService service = reference.get(); + + String message = service.sayHi("dubbo"); +} +``` + +## 注意事项 + +### 序列化编码 + +Dubbo 是如何做到同时支持普通 Java 对象、Protobuf 对象的那?Dubbo 实现中有一个对象类型判断,首先判断参数类型是否为 protobuf 对象,如果不是。用一个 protobuf 对象将 request 和 response 进行包装(wrapper),将普通的 Java 对象传输在底层统一为 protobuf 对象传输。在 wrapper 对象内部声明序列化类型,来支持序列化的扩展。 + +wrapper 的 IDL 如下: +```proto +syntax = "proto3"; + +package org.apache.dubbo.triple; + +message TripleRequestWrapper { + // hessian4 + // json + string serializeType = 1; + repeated bytes args = 2; + repeated string argTypes = 3; +} + +message TripleResponseWrapper { + string serializeType = 1; + bytes data = 2; + string type = 3; +} +``` + +对于请求,使用`TripleRequestWrapper`进行包装,对于响应使用`TripleResponseWrapper`进行包装。 + +> 对于请求参数,可以看到 args 被`repeated`修饰,这是因为需要支持 java 方法的多个参数。当然,序列化只能是一种。序列化的实现沿用 Dubbo2 实现的 spi + +### 性能表现 +由于链路上传输的数据额外经过了一层序列化编码(如 hessian2),同时,server 端的方法调用基于反射,因此相比于 `protobuf+triple` 的编码模式,Java 接口方式在性能上会存在一定的下降。 + +Protobuf 模式固然有一定的性能优势,但易用性与使用成本也会陡然增加,我们建议还是优先考虑业务场景,如果没有多语言业务、dubbo2老用户,则继续保持 Java 接口模式是一个比较好、低成本的选择。 + +### gRPC兼容性 +由于 gRPC 仅支持 protobuf 模式,因此本文介绍的 `接口+triple` 的模式无法与谷歌官方原生的 gRPC 协议互调。 + +### 前端流量接入 +对于来自前端的 HTTP 流量(比如浏览器或 web 应用),要想通过网关接入 triple,就要走 triple 内置的 `application/json` 模式发起调用,具体请参见[【使用教程-HTTP网关接入】](/zh-cn/overview/mannual/java-sdk/tasks/gateway/triple/)。 \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/triple/streaming.md b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/streaming.md new file mode 100644 index 000000000000..19ac9a12db5e --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/streaming.md @@ -0,0 +1,325 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/streaming/ + - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/streaming/ +description: "演示了服务端流、双向流等 Streaming 流式通信的基本使用方法。" +linkTitle: Streaming流式通信 +title: Streaming 通信 +type: docs +weight: 4 +--- +在 [选择 RPC 通信协议](../../protocol/) 一节提到,Streaming 是 Dubbo3 新提供的一种 RPC 数据传输模式,适用于以下场景: + +- 接口需要发送大量数据,这些数据无法被放在一个 RPC 的请求或响应中,需要分批发送,但应用层如果按照传统的多次 RPC 方式无法解决顺序和性能的问题,如果需要保证有序,则只能串行发送 +- 流式场景,数据需要按照发送顺序处理, 数据本身是没有确定边界的 +- 推送类场景,多个消息在同一个调用的上下文中被发送和处理 + +Streaming 分为以下三种: +- SERVER_STREAM(服务端流) +- CLIENT_STREAM(客户端流) +- BIDIRECTIONAL_STREAM(双向流) + +以下示例演示 triple streaming 流式通信的基本使用方法,涵盖了客户端流、服务端流、双向流等三种模式,示例使用 Protocol Buffers 的服务开发模式,对于 Java 接口模式的开发者可以在本文最后查看相应说明。可在此查看 [本示例完整代码](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-streaming)。 + +## 运行示例 + +首先,可通过以下命令下载示例源码: +```shell +git clone --depth=1 https://github.com/apache/dubbo-samples.git +``` + +进入示例源码目录: +```shell +cd dubbo-samples/2-advanced/dubbo-samples-triple-streaming +``` + +编译项目,由 IDL 生成代码,这会调用 dubbo 提供的 protoc 插件生成对应的服务定义代码: +```shell +mvn clean compile +``` + +### 启动server + +运行以下命令,启动 server: +```shell +$ mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.tri.streaming.TriStreamServer" +``` + +#### 启动client +运行以下命令,启动 client: + +```shell +$ mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.tri.streaming.TriStreamClient" +``` + +## 源码解读 +与 [使用 Protobuf(IDL) 开发 triple 协议服务](../idl/) 一节中提到的一样,这个示例使用 protobuf 定义服务,因此示例需要的依赖、配置等基本是一致的,请参考那一节了解完整详情。接下来,我们将重点讲解流式通信部分的内容。 + +### protobuf服务定义 + +```protobuf +syntax = "proto3"; +option java_multiple_files = true; +package org.apache.dubbo.samples.tri.streaming; + +message GreeterRequest { + string name = 1; +} +message GreeterReply { + string message = 1; +} + +service Greeter{ + rpc biStream(stream GreeterRequest) returns (stream GreeterReply); + rpc serverStream(GreeterRequest) returns (stream GreeterReply); +} +``` + +在上面的 proto 文件中,我们定义了两个方法: +* `biStream(stream GreeterRequest) returns (stream GreeterReply)` 双向流 +* `serverStream(GreeterRequest) returns (stream GreeterReply)` 服务端流 + +### 生成代码 +接下来,我们需要从 .proto 服务定义生成 Dubbo 客户端和服务器接口。protoc dubbo 插件可以帮助我们生成需要的代码,在使用 Gradle 或 Maven 时,protoc 构建插件可以生成必要的代码作为构建的一部分。具体 maven 配置及代码生成步骤我们在 [上一节](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/) 中有具体的描述。 + +target/generated-sources/protobuf/java/org/apache/dubbo/samples/tri/streaming/ 目录中可以发现如下生成代码,其中我们将重点讲解 `DubboGreeterTriple.java`: + +``` +├── DubboGreeterTriple.java +├── Greeter.java +├── GreeterOuterClass.java +├── GreeterReply.java +├── GreeterReplyOrBuilder.java +├── GreeterRequest.java +└── GreeterRequestOrBuilder.java +``` + +### Server +首先,让我们看一下如何定义服务实现并启动提供者: +1. 实现 IDL 代码生成过程中定义的服务基类,提供自定义的业务逻辑。 +2. 运行 Dubbo 服务以侦听来自客户端的请求并返回服务响应。 + +#### 提供服务实现 GreeterImplBase +定义类 `GreeterImpl` 实现 `DubboGreeterTriple.GreeterImplBase`。 + +```java +public class GreeterImpl extends DubboGreeterTriple.GreeterImplBase { + // ... +} +``` +##### 服务端流 + +`GreeterImpl` 实现了所有 rpc 定义中的方法。接下里,我们看一下 server-side streaming 的具体定义。 + +不同于普通的方法定义,`serverStream` 方法有两个参数,第一个参数 `request` 是入参,第二个参数 `responseObserver` 为响应值,其参数类型是 `StreamObserver`。在方法实现中,我们不停的调用 `responseObserver.onNext(...)` 将结果发送回消费方,并在最后调用 `onCompleted()` 表示流式响应结束。 + +```java +@Override +public void serverStream(GreeterRequest request, StreamObserver responseObserver) { + LOGGER.info("receive request: {}", request.getName()); + for (int i = 0; i < 10; i++) { + GreeterReply reply = GreeterReply.newBuilder().setMessage("reply from serverStream. " + i).build(); + responseObserver.onNext(reply); + } + responseObserver.onCompleted(); +} +``` + +##### 双向流 +双向流方法 `biStream` 的参数和返回值都是 `StreamObserver<...>` 类型。但需要注意的是,它与我们传统方法定义中参数是请求值、返回值是响应的理解是反过来的,在这里,参数 `StreamObserver responseObserver` 是响应,我们通过 responseObserver 不停的写回响应。 + +请注意这里`请求流`与`响应流`是独立的,我们在写回响应流数据的过程中,随时可能有请求流到达,对于每个流而言,值都是有序的。 + +```java +@Override +public StreamObserver biStream(StreamObserver responseObserver) { + return new StreamObserver() { + @Override + public void onNext(GreeterRequest data) { + GreeterReply resp = GreeterReply.newBuilder().setMessage("reply from biStream " + data.getName()).build(); + responseObserver.onNext(resp); + } + + @Override + public void onError(Throwable throwable) { + + } + + @Override + public void onCompleted() { + + } + }; +} +``` + +#### 启动 server +启动 Dubbo 服务的过程与普通应用完全一致: + +```java +public static void main(String[] args) throws IOException { + ServiceConfig service = new ServiceConfig<>(); + service.setInterface(Greeter.class); + service.setRef(new GreeterImpl("tri-stub")); + + ApplicationConfig applicationConfig = new ApplicationConfig("tri-stub-server"); + applicationConfig.setQosEnable(false); + + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application(applicationConfig) + .registry(new RegistryConfig(TriSampleConstants.ZK_ADDRESS)) + .protocol(new ProtocolConfig(CommonConstants.TRIPLE, TriSampleConstants.SERVER_PORT)) + .service(service) + .start(); +} +``` + +### Client +和普通的 Dubbo 服务调用一样,我们首先需要声明 rpc 服务引用: + +```java +public static void main(String[] args) throws IOException { + ReferenceConfig ref = new ReferenceConfig<>(); + ref.setInterface(Greeter.class); + ref.setProtocol(CommonConstants.TRIPLE); + + DubboBootstrap.getInstance().reference(ref).start(); + Greeter greeter = ref.get(); +} +``` + +接下来,我们就可以利用 `greeter` 像调用本地方法一样发起调用了。 + +#### 服务端流 +调用 `serverStream()` 传入能够处理流式响应的 `SampleStreamObserver` 对象,调用发起后即快速返回,之后流式响应会不停的发送到 `SampleStreamObserver`。 + +```java +GreeterRequest request = GreeterRequest.newBuilder().setName("server stream request.").build(); +greeter.serverStream(request, new SampleStreamObserver()); +``` + +以下是 `SampleStreamObserver` 类的具体定义,包含其收到响应后的具体处理逻辑。 + +```java +private static class SampleStreamObserver implements StreamObserver { + @Override + public void onNext(GreeterReply data) { + LOGGER.info("stream <- reply:{}", data); + } + + // ...... +} +``` + +#### 双向流 +调用 `greeter.biStream()` 方法会立即返回一个 `requestStreamObserver`,同时,需要为方法传入一个能处理响应的 observer 对象 `new SampleStreamObserver()`。 + +接下来,我们就可以用才刚才返回值中得到的 `requestStreamObserver` 持续发送请求 `requestStreamObserver.onNext(request)`;此时,如果有响应返回,则会由 `SampleStreamObserver` 接收处理,其定义请参考上文。 + +```java +StreamObserver requestStreamObserver = greeter.biStream(new SampleStreamObserver()); +for (int i = 0; i < 10; i++) { + GreeterRequest request = GreeterRequest.newBuilder().setName("name-" + i).build(); + requestStreamObserver.onNext(request); +} +requestStreamObserver.onCompleted(); +``` + +## 其他 +### Java接口模式下的流式通信 +对于不使用 Protobuf 的用户而言,你可以直接在接口中定义 streaming 格式的方法,这样你就能使用流式通信了。 + +#### 接口定义 +```java +public interface WrapperGreeter { + // 双向流 + StreamObserver sayHelloStream(StreamObserver response); + // 服务端流 + void sayHelloServerStream(String request, StreamObserver response); +} +``` + +其中,`org.apache.dubbo.common.stream.StreamObserver` 是 Dubbo 框架提供的流式通信参数类型,请务必按照以上示例所示的方式定义 + +> Stream 方法的方法入参和返回值是严格约定的,为防止写错而导致问题,Dubbo3 框架侧做了对参数的检查, 如果出错则会抛出异常。 +> 对于 `双向流(BIDIRECTIONAL_STREAM)`, 需要注意参数中的 `StreamObserver` 是响应流,返回参数中的 `StreamObserver` 为请求流。 + +#### 实现类 +```java +public class WrapGreeterImpl implements WrapGreeter { + + //... + + @Override + public StreamObserver sayHelloStream(StreamObserver response) { + return new StreamObserver() { + @Override + public void onNext(String data) { + System.out.println(data); + response.onNext("hello,"+data); + } + + @Override + public void onError(Throwable throwable) { + throwable.printStackTrace(); + } + + @Override + public void onCompleted() { + System.out.println("onCompleted"); + response.onCompleted(); + } + }; + } + + @Override + public void sayHelloServerStream(String request, StreamObserver response) { + for (int i = 0; i < 10; i++) { + response.onNext("hello," + request); + } + response.onCompleted(); + } +} +``` + +#### 调用方式 +```java +delegate.sayHelloServerStream("server stream", new StreamObserver() { + @Override + public void onNext(String data) { + System.out.println(data); + } + + @Override + public void onError(Throwable throwable) { + throwable.printStackTrace(); + } + + @Override + public void onCompleted() { + System.out.println("onCompleted"); + } +}); + + +StreamObserver request = delegate.sayHelloStream(new StreamObserver() { + @Override + public void onNext(String data) { + System.out.println(data); + } + + @Override + public void onError(Throwable throwable) { + throwable.printStackTrace(); + } + + @Override + public void onCompleted() { + System.out.println("onCompleted"); + } +}); +for (int i = 0; i < n; i++) { + request.onNext("stream request" + i); +} +request.onCompleted(); +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/rate-limit/_index.md b/content/en/overview/mannual/java-sdk/tasks/rate-limit/_index.md new file mode 100755 index 000000000000..dc231b35c7aa --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/rate-limit/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/overview/tasks/rate-limit/ + - /zh-cn/overview/tasks/rate-limit/ +description: 演示 Dubbo 熔断、限流、降级等场景工作方式 +hide: true +linkTitle: 限流降级 +title: 限流降级 +type: docs +weight: 8 +--- diff --git a/content/en/overview/mannual/java-sdk/tasks/rate-limit/adaptive-concurrency-control.md b/content/en/overview/mannual/java-sdk/tasks/rate-limit/adaptive-concurrency-control.md new file mode 100644 index 000000000000..ebb60201fd1a --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/rate-limit/adaptive-concurrency-control.md @@ -0,0 +1,48 @@ +--- +description: "自适应限流,区别于普通限流策略,其具备自动调整限流策略是否生效、限流阈值的能力,heuristic flow control。" +linkTitle: 自适应限流 +title: 自适应限流 +type: docs +weight: 3 +--- + +自适应限流的设计与实现思路请参考 [Dubbo 自适应限流功能](/zh-cn/overview/reference/proposals/heuristic-flow-control/#自适应限流)。自适应限流能够确保分布式系统稳定性和可靠性,例如在服务提供商资源有限且多变的场景下。 + +## 使用场景 +- 服务降级预防:当服务提供者因资源耗尽而性能下降时,使用自适应限流暂时减少其接受的请求数直至恢复正常。 +- 峰值流量处理:当服务流量突然激增时,自适应流量限制可以通过动态减少接受的请求数量来帮助防止服务过载。 +- 不可预测流量处理:服务提供商可能会遇到不可预测的流量,第三方应用程序使用服务时可能会偶尔产生流量,自适应流量限制可以根据当前系统负载调整允许的最大并发请求数并防止过载。 + +## 使用方式 + +设置方法与静态的最大并发值设置类似,只需在服务端设置 flowcontrol 参数即可,可选值有以下两种: +* heuristicSmoothingFlowControl。当服务端收到一个请求时,首先判断CPU的使用率是否超过50%。如果没有超过50%,则接受这个请求进行处理。如果超过50%,说明当前的负载较高,便从 HeuristicSmoothingFlowControl 算法中获得当前的 maxConcurrency 值。如果当前正在处理的请求数量超过了 maxConcurrency,则拒绝该请求。 +* autoConcurrencyLimiter。与 HeuristicSmoothingFlowControl 的最大区别是,AutoConcurrencyLimiter 是基于窗口的,每当窗口内积累了一定量的采样数据时,才利用窗口内的数据来更新得到 maxConcurrency,其次,利用exploreRatio来对剩余的容量进行探索。 + +> 在确保服务端存在多个节点,并且消费端开启重试策略的前提下,限流功能才能更好的发挥作用。 + +### 示例一:使用 heuristicSmoothingFlowControl 自适应限流算法 + +```properties +dubbo.provider.flowcontrol=heuristicSmoothingFlowControl +``` + +```xml + +``` + +### 示例二:使用 autoConcurrencyLimiter 自适应限流算法 +```properties +dubbo.provider.flowcontrol=autoConcurrencyLimiter +``` + +```xml + +``` + +### 示例三:设置服务粒度的 heuristicSmoothingFlowControl 自适应限流 + +```xml + +``` + diff --git a/content/en/overview/mannual/java-sdk/tasks/rate-limit/concurrency-control.md b/content/en/overview/mannual/java-sdk/tasks/rate-limit/concurrency-control.md new file mode 100644 index 000000000000..46b9c13a30be --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/rate-limit/concurrency-control.md @@ -0,0 +1,101 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control/ +description: "Dubbo 框架内置的并发控制或者限流策略,通过限制从同一客户端到同一服务的并发请求数,防止恶意请求使服务器过载,确保服务的稳定性,并防止使用过多资源。" +linkTitle: 框架内置限流 +title: Dubbo 框架内置的并发控制策略 +type: docs +weight: 2 +--- + +Dubbo 通过 Filter 拦截器机制,内置了并发控制策略实现。限制从同一客户端到同一服务的并发请求数,防止恶意请求使服务器过载,确保服务的稳定性,并防止使用过多资源。 + +* 控制某些服务的最大并发请求数,确保其他服务的资源可用性。系统过载和确保系统稳定性。 +* 允许在需求增加时更平滑地扩展服务。 +* 确保服务在高峰使用时间保持可靠和稳定。 + +{{% alert title="注意" color="warning" %}} +这种方式要求用户准确的预先评估系统能处理的并发数,而准确的评估系统处理能力并不是一件容易的事情,因此 Dubbo 还提供了自适应限流模式,根据系统负载自动识别系统健康程度并进行限流保护,可以在此查看 [自适应限流模式使用文档](../adaptive-concurrency-control)。 +{{% /alert %}} + +## 限流策略配置 +### 限制服务器端并发执行数(服务粒度) + +限制 `com.foo.BarService` 的每个方法,服务器端并发执行(或占用线程池线程数)不能超过 10 个 + +XML 方式: +```xml + +``` + +注解方式: +```java +@DubboService(executes=10) +private DemoServiceImpl implements DemoService{} +``` + +### 限制服务器端并发执行数(方法粒度) + +限制 `com.foo.BarService` 的 `sayHello` 方法,服务器端并发执行(或占用线程池线程数)不能超过 10 个 + +XML 方式: +```xml + + + +``` + +注解方式: +```java +@DubboService(executes=10, methods = {@Method(name="sayHello",executes=10)}) +private DemoServiceImpl implements DemoService{} +``` + +### 限制消费端并发调用数(服务粒度) + +限制 `com.foo.BarService` 的每个方法,每客户端并发执行(或占用连接的请求数)不能超过 10 个 + +XML 方式: +```xml + +``` + +注解方式: +```java +@DubboReference(actives=10) +private DemoService demoService; +``` + +### 限制消费端并发调用数(方法粒度) + +限制 `com.foo.BarService` 的 `sayHello` 方法,每客户端并发执行(或占用连接的请求数)不能超过 10 个 + +XML 方式: +```xml + + + +``` + +注解方式: +```java +@DubboReference(actives=10, methods = {@Method(name="sayHello",executes=10)}) +private DemoService demoService; +``` + +> 如果提供端 `@DubboService` 和消费端 `@DubboReference` 都配了 actives,则消费端配置值优先级更高,参见:[配置的覆盖策略](https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/config/principle/)。 + +## 最小并发数负载均衡 + +配置服务的客户端的 `loadbalance` 属性为 `leastactive`,此 Loadbalance 会调用并发数最小的 Provider(Consumer端并发数)。 + +```xml + +``` + +**或** + +```xml + +``` \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/tasks/rate-limit/sentinel.md b/content/en/overview/mannual/java-sdk/tasks/rate-limit/sentinel.md new file mode 100644 index 000000000000..c375214ec0aa --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/rate-limit/sentinel.md @@ -0,0 +1,228 @@ +--- +aliases: + - /zh-cn/overview/tasks/ecosystem/rate-limit/ + - /zh-cn/overview/what/ecosystem/rate-limit/ + - /zh-cn/overview/what/ecosystem/rate-limit/sentinel/ + - /zh/overview/tasks/rate-limit/sentinel/ + - /zh-cn/overview/tasks/rate-limit/sentinel/ +description: "使用 Sentinel 保护您的 Dubbo 应用,防止应用因个别服务的突发流量过载而出现稳定性问题。" +linkTitle: Sentinel限流 +title: 使用 Sentinel 应对突发流量,保护您的应用 +type: docs +weight: 1 +--- + +在复杂的生产环境下可能部署着成千上万的 Dubbo 服务实例,流量持续不断地进入,服务之间进行相互调用。但是分布式系统中可能会因流量激增、系统负载过高、网络延迟等一系列问题,导致某些服务不可用,如果不进行相应的控制可能导致级联故障,影响服务的可用性,因此如何对流量进行合理的控制,成为保障服务稳定性的关键。 + +[Sentinel](https://github.com/alibaba/Sentinel) 是阿里中间件团队开源的,面向分布式服务架构的轻量级流量控制产品,主要以流量为切入点,从**流量控制**、**熔断降级**、**系统负载保护**等多个维度来帮助用户保护服务的稳定性。 + +本文提供 Dubbo 整合 Sentinel 限流降级的最佳实践。 + +## 快速接入 Sentinel + +Sentinel 通过对服务提供方和服务消费方的限流提升服务在极端场景下的可用性,接下来我们看看 Sentinel 对服务提供方和服务消费方限流的技术实现方式。 + +使用时我们只需引入以下模块(以 Maven 为例): + +```xml + + com.alibaba.csp + sentinel-apache-dubbo3-adapter + 1.8.6 + + + + com.alibaba.csp + sentinel-transport-simple-http + 1.8.6 + +``` + +引入此依赖后,Dubbo 的服务接口和方法(包括调用端和服务端)就会成为 Sentinel 中的资源,在配置了规则后就可以自动享受到 Sentinel 的防护能力。 + +> `sentinel-apache-dubbo3-adapter` 中包含 Sentinel Filter 实现,加入依赖之后会自动开启。如若不希望开启 Sentinel Dubbo Adapter 中的某个 Filter,可通过配置关闭,如 `dubbo.provider.filter="-sentinel.dubbo.consumer.filter"`。 + + +## 示例详解 + +可在此查看以下 [示例的完整源码](https://github.com/apache/dubbo-samples/tree/master/4-governance/dubbo-samples-sentinel)。 + + +### Provider 端限流 + +对服务提供方的流量控制可分为 **服务提供方的自我保护能力** 和 **服务提供方对服务消费方的请求分配能力** 两个维度。 + + +#### 基于 QPS 设定限流 +为了保护 Provider 不被激增的流量拖垮影响稳定性,可以给 Provider 配置 **QPS 模式** 的限流,这样当每秒的请求量超过设定的阈值时会自动拒绝多出来的请求。 + +以下是示例中配置的 **服务级别** 的 QPS 限流配置,最大 QPS 设定为 10: + +```java +// Limit DemoService to 10 QPS +FlowRule flowRule = new FlowRule(); +// Note: the resource name here is the interface name. +flowRule.setResource(DemoService.class.getName()); +flowRule.setCount(10); +flowRule.setLimitApp("default"); +flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); +FlowRuleManager.loadRules(Collections.singletonList(flowRule)); +``` + +以下是示例中配置的 **方法级别** 的 QPS 限流配置,最大 QPS 设定为 5: + +```java +// Limit sayHelloAgain method to 10 QPS +FlowRule flowRule = new FlowRule(); +// Note: the resource name here includes the method signature. +flowRule.setResource(DemoService.class.getName() + ":sayHelloAgain(java.lang.String)"); +flowRule.setCount(5); +flowRule.setLimitApp("default"); +flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); +FlowRuleManager.loadRules(Collections.singletonList(flowRule)); +``` + +启动消费端进程并持续发起调用,以下是限流生效后 provider 端打印的日志: + +``` +2018-07-24 17:13:43|1|com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String),FlowException,default,|5,0 +``` + +在 Provider 对应的 metrics 日志中也有记录: + +``` +1532423623000|2018-07-24 17:13:43|com.alibaba.csp.sentinel.demo.dubbo.FooService|15|0|15|0|3 +1532423623000|2018-07-24 17:13:43|com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String)|10|5|10|0|0 +``` + +#### 基于 QPS 限流(针对特定消费者) + +上一节中的 QPS 限流值是针对所有消费端流量的,你也可以对来自特定消费端(以 dubbo 应用名识别)的 QPS 进行限流,通过设置 `flowRule.setLimitApp("sentinel-consumer");` 即可,其中 `sentinel-consumer` 为发起调用的消费端应用名: + +```java +//...... +// Note: this will take effect only for the specific consumer whose app name is "sentinel-consumer". +flowRule.setLimitApp("sentinel-consumer"); +flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); +FlowRuleManager.loadRules(Collections.singletonList(flowRule)); +``` + +在限流日志中会也会记录调用方的名称,如下面的日志中的 `sentinel-consumer` 即为调用方名称: + +``` +2018-07-25 16:26:48|1|com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String),FlowException,default,demo-consumer|5,0 +``` + +> 注意:为了使 `limitApp` 生效,开发者需要调用调用 `RpcContext.getContext.setAttachment("dubboApplication", "sentinel-consumer")` 标识自己的身份,如果消费端引入了 `sentinel-apache-dubbo3-adapter` 则不需要额外调用以上方法了。 + +#### 设置限流发生后执行的方法 + +调用 `DubboAdapterGlobalConfig.setProviderFallback()` 可以设置限流发生后的方法回调,这样就能在限流后做更多的定制动作。 + +```java +DubboAdapterGlobalConfig.setProviderFallback((invoker, invocation, ex) -> { + System.out.println("Blocked by Sentinel: " + ex.getClass().getSimpleName() + ", " + invocation); + return AsyncRpcResult.newDefaultAsyncResult(ex.toRuntimeException(), invocation); +}); +``` + +### Consumer 端限流 + +对服务消费方的流量控制可分为 **控制并发线程数** 和 **服务降级** 两个维度。 + +#### 并发线程数限流 + +推荐给 Consumer 配置**线程数模式**限流,来保证自身不被不稳定服务所影响。采用基于线程数的限流模式后,我们不需要再显式地去进行线程池隔离,Sentinel 会控制资源的线程数,超出的请求直接拒绝,直到堆积的线程处理完成,可以达到**信号量隔离**的效果。 + + +以下方法设置消费端的最大并发线程数,方法 `sayHelloConsumerFlowControl` 的并发调用在超过 3 个线程时就会发生限流: + +```java +FlowRule flowRule = new FlowRule(); +flowRule.setResource("org.apache.dubbo.samples.sentinel.DemoService:sayHelloConsumerFlowControl(java.lang.String)"); +flowRule.setCount(3); +flowRule.setGrade(RuleConstant.FLOW_GRADE_THREAD); +FlowRuleManager.loadRules(Collections.singletonList(flowRule)); +``` + +通过调用以下方法,可以设置限流发生时的回调方法(可选): + +```java +DubboAdapterGlobalConfig.setConsumerFallback((invoker, invocation, ex) -> { + System.out.println("Blocked by Sentinel: " + ex.getClass().getSimpleName() + ", " + invocation); + return AsyncRpcResult.newDefaultAsyncResult(ex.toRuntimeException(), invocation); +}); +``` + +#### 服务熔断降级 + +当服务依赖于多个下游服务,而某个下游服务调用非常慢时,会严重影响当前服务的调用。这里我们可以利用 Sentinel 熔断降级的功能,为调用端配置基于平均 RT 的[降级规则](https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7)。这样当调用链路中某个服务调用的平均 RT 升高,在一定的次数内超过配置的 RT 阈值,Sentinel 就会对此调用资源进行降级操作,接下来的调用都会立刻拒绝,直到过了一段设定的时间后才恢复,从而保护服务不被调用端短板所影响。同时可以配合 fallback 功能使用,在被降级的时候提供相应的处理逻辑。 + +以下方法设置 `sayHelloConsumerDowngrade` 的降级策略,当接口调用失败率达到 70% 时,方法调用自动降级: + +```java +@Component +static class SentinelDowngradeConfig implements CommandLineRunner { + @Override + public void run(String... args) { + List rules = new ArrayList<>(); + DegradeRule rule = new DegradeRule(); + rule.setResource("org.apache.dubbo.samples.sentinel.DemoService:sayHelloConsumerDowngrade(java.lang.String)"); + rule.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType()); + rule.setCount(0.7); // Threshold is 70% error ratio + rule.setMinRequestAmount(100); + rule.setStatIntervalMs(30000); // 30s + rule.setTimeWindow(10); + rules.add(rule); + DegradeRuleManager.loadRules(rules); + } +} +``` + +## Sentinel控制台 + +Sentinel 的控制台可以作为流量控制、熔断降级规则统一配置和管理的入口,同时它为用户提供了多个维度的监控功能。在 Sentinel 控制台上: +* 动态下发配置规则并实时查看流量控制效果 +* 查看机器列表以及健康情况 + + +### 应用如何接入控制台 +接入 Sentinel 控制台的步骤如下(**缺一不可**): + +1. 按照 [Sentinel 控制台文档](https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0) 启动控制台 +2. 应用引入 `sentinel-transport-simple-http` 依赖,以便控制台可以拉取对应应用的相关信息 +3. 给应用添加相关的启动参数,启动应用。需要配置的参数有: + - `-Dcsp.sentinel.api.port`:客户端的 port,用于上报相关信息(默认为 8719) + - `-Dcsp.sentinel.dashboard.server`:控制台的地址 + - `-Dproject.name`:应用名称,会在控制台中显示 + + +这样在启动应用后就能在控制台找到对应的应用了。 + +### 控制台功能简介 + +- **单台设备监控**:当在机器列表中看到您的机器,就代表着已经成功接入控制台,可以查看单台设备的设备名称、IP地址、端口号、健康状态和心跳时间等信息。 + +![sentinel-dashboard](/imgs/v3/tasks/sentinel/dashboard-1.png) + +- **链路监控**:簇点链路实时的去拉取指定客户端资源的运行情况,它提供了两种展示模式,一种用书状结构展示资源的调用链路;另外一种则不区分调用链路展示资源的运行情况。通过链路监控,可以查看到每个资源的流控和降级的历史状态。 + +树状链路 + +![sentinel-dashboard](/imgs/v3/tasks/sentinel/dashboard-2.png) + +平铺链路 + +![sentinel-dashboard](/imgs/v3/tasks/sentinel/dashboard-3.png) + +- **聚合监控**:同一个服务下的所有机器的簇点信息会被汇总,实现实时监控,精确度达秒级。 + +![sentinel-dashboard](/imgs/v3/tasks/sentinel/dashboard-4.png) + +- **规则配置**:可以查看已有的限流、降级和系统保护规则,并实时地进行配置。 + +![sentinel-dashboard](/imgs/v3/tasks/sentinel/dashboard-5.png) + +## 参考链接 + +关于 Sentinel 的更多使用方式可以参考 [Sentinel 官网](https://sentinelguard.io/zh-cn/index.html) diff --git a/content/en/overview/mannual/java-sdk/tasks/security/_index.md b/content/en/overview/mannual/java-sdk/tasks/security/_index.md new file mode 100755 index 000000000000..8a213e0f2de8 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/security/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/ +description: 演示 Dubbo 配置安全策略的方式 +hide: true +linkTitle: 安全策略 +title: 安全策略 +type: docs +weight: 12 +--- diff --git a/content/en/overview/mannual/java-sdk/tasks/security/auth.md b/content/en/overview/mannual/java-sdk/tasks/security/auth.md new file mode 100644 index 000000000000..aa3fe59d48b8 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/security/auth.md @@ -0,0 +1,51 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/security/auth/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/security/auth/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/auth/ +description: 了解 Dubbo 服务鉴权 +linkTitle: 服务鉴权 +title: 服务鉴权 +type: docs +weight: 23 +--- + + + + + + +## 特性说明 + +类似支付之类的对安全性敏感的业务可能会有限制匿名调用的需求。在加固安全性方面,2.7.5 引入了基于 AK/SK 机制的认证鉴权机制,并且引入了鉴权服务中心,主要原理是消费端在请求需要鉴权的服务时,会通过 SK、请求元数据、时间戳、参数等信息来生成对应的请求签名,通过 Dubbo 的 Attahcment 机制携带到对端进行验签,验签通过才进行业务逻辑处理。如下图所示: + +![img](/imgs/docsv2.7/user/examples/auth/auth.png) + + +## 使用场景 +部署新服务时,使用身份验证来确保只部署正确的服务,如果部署了未经授权的服务,则使用身份验证来拒绝访问并防止使用未经授权服务。 + +## 使用方式 + +### 接入方式 + +1. 使用者需要在微服务站点上填写自己的应用信息,并为该应用生成唯一的证书凭证。 + +2. 之后在管理站点上提交工单,申请某个敏感业务服务的使用权限,并由对应业务管理者进行审批,审批通过之后,会生成对应的 AK/SK 到鉴权服务中心。 + +3. 导入该证书到对应的应用下,并且进行配置。配置方式也十分简单,以注解方式为例: + + ### 服务提供端 + 只需要设置 `service.auth` 为 true,表示该服务的调用需要鉴权认证通过。`param.sign` 为 `true` 表示需要对参数也进行校验。 + + ```java + @Service(parameters = {"service.auth","true","param.sign","true"}) + public class AuthDemoServiceImpl implements AuthService { + } + + ``` + + ### 服务消费端 + 只需要配置好对应的证书等信息即可,之后会自动地在对这些需要认证的接口发起调用前进行签名操作,通过与鉴权服务的交互,用户无需在代码中配置 AK/SK 这些敏感信息,并且在不重启应用的情况下刷新 AK/SK,达到权限动态下发的目的。 + +> 该方案目前已经提交给 Dubbo 开源社区,并且完成了基本框架的合并,除了 AK/SK 的鉴权方式之外,通过 SPI 机制支持用户可定制化的鉴权认证以及适配公司内部基础设施的密钥存储。 diff --git a/content/en/overview/mannual/java-sdk/tasks/security/class-check.md b/content/en/overview/mannual/java-sdk/tasks/security/class-check.md new file mode 100644 index 000000000000..56b12c0153fd --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/security/class-check.md @@ -0,0 +1,223 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/security/class-check/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/security/class-check/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/ +description: 了解 Dubbo 类检查机制 +linkTitle: 类检查机制 +title: 类检查机制 +type: docs +weight: 1 +--- +## 特性说明 +该机制保证服务提供方和服务消费方类之间的兼容性和安全。 + +## 使用场景 +防止由于类版本不匹配、方法签名不兼容或缺少类而可能发生的潜在问题。 + +## 使用方式 + +支持版本 +Dubbo >= 3.1.6 + +适用范围 +目前序列化检查支持 Hessian2、Fastjson2 序列化以及泛化调用。其他的序列化方式暂不支持。 + +### 检查模式 +检查模式分为三个级别:`STRICT` 严格检查,`WARN` 告警,`DISABLE` 禁用。 +`STRICT` 严格检查:禁止反序列化所有不在允许序列化列表(白名单)中的类。 +`WARN` 告警:仅禁止序列化所有在不允许序列化列表中(黑名单)的类,同时在反序列化不在允许序列化列表(白名单)中类的时候通过日志进行告警。 +`DISABLE` 禁用:不进行任何检查。 + +3.1 版本中默认为 `WARN` 告警级别,3.2 版本中默认为 `STRICT` 严格检查级别。 + +通过 ApplicationConfig 配置: +```java +ApplicationConfig applicationConfig = new ApplicationConfig(); +applicationConfig.setSerializeCheckStatus("STRICT"); +``` + +通过 Spring XML 配置: +```xml + +``` + +通过 Spring Properties / dubbo.properties 配置: +```properties +dubbo.application.serialize-check-status=STRICT +``` + +通过 System Property 配置: +```properties +-Ddubbo.application.serialize-check-status=STRICT +``` + +配置成功后可以在日志中看到如下的提示: +``` +INFO utils.SerializeSecurityManager: [DUBBO] Serialize check level: STRICT +``` + +注:在同一个进程(Dubbo Framework Model)下的多个应用如果同时配置不同的检查模式,最终会生效“最宽松”的级别。如两个 Spring Context 同时启动,一个配置为 `STRICT`,另外一个配置为 `WARN`,则最终生效 `WARN` 级别的配置。 + +### Serializable 接口检查 + +Serializable 接口检查模式分为两个级别:`true` 开启,`false` 关闭。开启检查后会拒绝反序列化所有未实现 `Serializable` 的类。 + +Dubbo 中默认配置为 `true` 开启检查。 + +通过 ApplicationConfig 配置: +```java +ApplicationConfig applicationConfig = new ApplicationConfig(); +applicationConfig.setCheckSerializable(true); +``` + +通过 Spring XML 配置: +```xml + +``` + +通过 Spring Properties / dubbo.properties 配置: +```properties +dubbo.application.check-serializable=true +``` + +通过 System Property 配置: +```properties +-Ddubbo.application.check-serializable=true +``` + +配置成功后可以在日志中看到如下的提示: +``` +INFO utils.SerializeSecurityManager: [DUBBO] Serialize check serializable: true +``` + +注 1:在同一个进程(Dubbo Framework Model)下的多个应用如果同时配置不同的 Serializable 接口检查模式,最终会生效“最宽松”的级别。如两个 Spring Context 同时启动,一个配置为 `true`,另外一个配置为 `false`,则最终生效 `false` 级别的配置。 +注 2:目前暂未打通 Hessian2、Fastjson2 内置的 `Serializable` 检查配置。对于泛化调用,仅需要配置 `dubbo.application.check-serializable` 即可修改检查配置;对于 Hessian2 序列化,需要同时修改 `dubbo.application.check-serializable` 和 `dubbo.hessian.allowNonSerializable` 两个配置;对于 Fastjson2 序列化,目前暂不支持修改。 + +### 自动扫描相关配置 + +Dubbo 类自动扫描机制共有两个配置项:`AutoTrustSerializeClass` 是否启用自动扫描和 `TrustSerializeClassLevel` 类信任层级。 + +简单来说,在开启类自动扫描之后,Dubbo 会通过 `ReferenceConfig` 和 `ServiceConfig` 自动扫描接口所有可能会用到的相关类,并且递归信任其所在的 package。 `TrustSerializeClassLevel` 类信任层级可以用来限制最终信任的 package 层级。如 `io.dubbo.test.pojo.User` 在 `TrustSerializeClassLevel` 配置为 `3` 的时候,最终会信任 `io.dubbo.test` 这个 package 下所有的类。 + +Dubbo 中默认配置 `AutoTrustSerializeClass` 为 `true` 启用扫描, `TrustSerializeClassLevel` 为 `3`。 + +通过 ApplicationConfig 配置: +```java +ApplicationConfig applicationConfig = new ApplicationConfig(); +applicationConfig.setAutoTrustSerializeClass(true); +applicationConfig.setTrustSerializeClassLevel(3); +``` + +通过 Spring XML 配置: +```xml + +``` + +通过 Spring Properties / dubbo.properties 配置: +```properties +dubbo.application.auto-trust-serialize-class=true +dubbo.application.trust-serialize-class-level=3 +``` + +通过 System Property 配置: +```properties +-Ddubbo.application.auto-trust-serialize-class=true +-Ddubbo.application.trust-serialize-class-level=3 +``` + +配置成功后可以通过 QoS 命令检查当前已经加载的可信类结果是否符合预期。 + +注:开启检查之后在启动的过程中会有一定的性能损耗。 + +### 可信/不可信类自定义配置 + +除了 Dubbo 自动扫描类之外,也支持通过资源文件的方式配置可信/不可信类列表。 + +配置方式:在资源目录(resource)下定义以下文件。 + +```properties +# security/serialize.allowlist +io.dubbo.test +``` + +```properties +# security/serialize.blockedlist +io.dubbo.block +``` + +配置成功以后可以在日志看到以下提示: +```properties +INFO utils.SerializeSecurityConfigurator: [DUBBO] Read serialize allow list from file:/Users/albumen/code/dubbo-samples/99-integration/dubbo-samples-serialize-check/target/classes/security/serialize.allowlist +INFO utils.SerializeSecurityConfigurator: [DUBBO] Read serialize blocked list from file:/Users/albumen/code/dubbo-samples/99-integration/dubbo-samples-serialize-check/target/classes/security/serialize.blockedlist +``` + +配置优先级为:用户自定义可信类 = 框架内置可信类 > 用户自定义不可信类 = 框架内置不可信类 > 自动类扫描可信类。 + +### 审计方式 + +Dubbo 支持通过 QoS 命令实时查看当前的配置信息以及可信/不可信类列表。目前共支持两个命令:`serializeCheckStatus` 查看当前配置信息,`serializeWarnedClasses` 查看实时的告警列表。 + +1. `serializeCheckStatus` 查看当前配置信息 + +通过控制台直接访问: +```bash +> telnet 127.0.0.1 22222 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>serializeCheckStatus +CheckStatus: WARN + +CheckSerializable: true + +AllowedPrefix: +... + +DisAllowedPrefix: +... + + +dubbo> +``` + +通过 http 请求 json 格式结果: +```bash +> curl http://127.0.0.1:22222/serializeCheckStatus +{"checkStatus":"WARN","allowedPrefix":[...],"checkSerializable":true,"disAllowedPrefix":[...]} +``` + +2. `serializeWarnedClasses` 查看实时的告警列表 + +通过控制台直接访问: +```bash +> telnet 127.0.0.1 22222 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>serializeWarnedClasses +WarnedClasses: +io.dubbo.test.NotSerializable +io.dubbo.test2.NotSerializable +io.dubbo.test2.OthersSerializable +org.apache.dubbo.samples.NotSerializable + + +dubbo> +``` + +通过 http 请求 json 格式结果: +```bash +> curl http://127.0.0.1:22222/serializeWarnedClasses +{"warnedClasses":["io.dubbo.test2.NotSerializable","org.apache.dubbo.samples.NotSerializable","io.dubbo.test.NotSerializable","io.dubbo.test2.OthersSerializable"]} +``` + +> 建议及时关注 `serializeWarnedClasses` 的结果,通过返回结果是否非空来判断是否受到攻击。 diff --git a/content/en/overview/mannual/java-sdk/tasks/security/tls.md b/content/en/overview/mannual/java-sdk/tasks/security/tls.md new file mode 100644 index 000000000000..06ae0537e3c8 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/security/tls.md @@ -0,0 +1,64 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/security/tls/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/security/tls/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/tls/ + - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tls/ +description: ' 了解在 Dubbo 的 TLS 保证传输安全' +linkTitle: TLS支持 +title: TLS支持 +type: docs +weight: 10 +--- + + + + + +## 特性说明 + +内置的 Dubbo Netty Server 和新引入的 gRPC 协议都提供了基于 TLS 的安全链路传输机制。 + +TLS 的配置都有统一的入口。 + +## 使用场景 + +对全链路有加密需求的用户可以使用 TLS。 + +> 参考用例 +[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-ssl](https://github.com/apache/dubbo-samples/tree/master/4-governance/dubbo-samples-ssl) + +## 使用方式 + +### Provider 端 +```java +SslConfig sslConfig = new SslConfig(); +sslConfig.setServerKeyCertChainPath("path to cert"); +sslConfig.setServerPrivateKeyPath(args[1]); +// 如果开启双向 cert 认证 +if (mutualTls) { + sslConfig.setServerTrustCertCollectionPath(args[2]); +} + +ProtocolConfig protocolConfig = new ProtocolConfig("dubbo/grpc"); +protocolConfig.setSslEnabled(true); +``` +如果要使用的是 gRPC 协议,在开启 TLS 时会使用到协议协商机制,因此必须使用支持 ALPN 机制的 Provider,推荐使用的是 netty-tcnative,具体可参见 gRPC Java 社区的 [总结]( https://github.com/grpc/grpc-java/blob/master/SECURITY.md) + + +### Consumer 端 + +```java +if (!mutualTls) {} + sslConfig.setClientTrustCertCollectionPath(args[0]); +} else { + sslConfig.setClientTrustCertCollectionPath(args[0]); + sslConfig.setClientKeyCertChainPath(args[1]); + sslConfig.setClientPrivateKeyPath(args[2]); +} +``` + +为尽可能保证应用启动的灵活性,TLS Cert 的指定还能通过 -D 参数或环境变量等方式来在启动阶段根据部署环境动态指定,参考 Dubbo [配置读取规则](/zh-cn/docs/advanced/config-rule) + + +> 在服务调用的安全性上,Dubbo 在后续的版本中会持续投入,其中服务发现/调用的鉴权机制预计在接下来的版本中就会和大家见面。 diff --git a/content/en/overview/mannual/java-sdk/tasks/security/token-authorization.md b/content/en/overview/mannual/java-sdk/tasks/security/token-authorization.md new file mode 100644 index 000000000000..24b380af2887 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/security/token-authorization.md @@ -0,0 +1,59 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/security/token-authorization/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/security/token-authorization/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/token-authorization/ +description: 了解 Dubbo 权限控制的配置和使用 +linkTitle: 权限控制 +title: 权限控制 +type: docs +weight: 2 +--- + + + + + + +## 特性说明 + +通过令牌验证在注册中心控制权限,以决定要不要下发令牌给消费者, +可以防止消费者绕过注册中心访问提供者, +另外通过注册中心可灵活改变授权方式,而不需修改或升级提供者。 + +![/user-guide/images/dubbo-token.jpg](/imgs/user/dubbo-token.jpg) + +## 使用场景 + +在一定程度上实现客户端和服务端的可信鉴权,避免任意客户端都可以访问,降低出现安全问题的风险。 + +## 使用方式 + +### 全局设置 + +开启令牌验证 + +```xml + + +``` + +或 + +```xml + + +``` +### 服务级别设置 + +```xml + + +``` + +或 + +```xml + + +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/service-discovery/_index.md b/content/en/overview/mannual/java-sdk/tasks/service-discovery/_index.md new file mode 100755 index 000000000000..26f412b27334 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/service-discovery/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/others/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/others/ +description: 注册中心与服务发现 +linkTitle: 服务发现 +title: 注册中心、服务发现与负载均衡 +type: docs +weight: 4 +--- diff --git a/content/en/overview/mannual/java-sdk/tasks/service-discovery/kubernetes.md b/content/en/overview/mannual/java-sdk/tasks/service-discovery/kubernetes.md new file mode 100644 index 000000000000..69278d23c6c3 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/service-discovery/kubernetes.md @@ -0,0 +1,25 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ +description: "通过示例演示基于 Kubernetes Service 的服务发现模式。" +linkTitle: 使用Kubernetes注册中心 +title: 基于 Kubernetes Service 的服务发现 +type: docs +weight: 5 +--- + +上面两节我们分别讲解了 Nacos、Zookeeper 两种注册中心模式,它们更像是传统的注册中心解决方案。在 Kubernetes 部署环境下,Dubbo 支持基于 Kubernetes Service 的服务发现模式,其基本工作原理如下图所示: + + + +在这种模式下,服务发现与用户的部署运维操作形成统一,用户定义标准的 Kubernetes Service、Deployment,并将其部署到 Kubernetes,之后 Control Plane 通过监控 APISERVER 资源并与 SDK 进程联动,形成一整套的服务发现体系。 + +关于使用 Kubernetes 作为注册中心的具体实践案例,请参考 [Kubernetes Service 部署]() 一节了解更多细节。 + + + + + diff --git a/content/en/overview/mannual/java-sdk/tasks/service-discovery/loadbalance.md b/content/en/overview/mannual/java-sdk/tasks/service-discovery/loadbalance.md new file mode 100644 index 000000000000..a373e96ae62d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/service-discovery/loadbalance.md @@ -0,0 +1,120 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance/ +description: "Dubbo 支持的消费端负载均衡策略及其使用方法" +linkTitle: 负载均衡 +title: 负载均衡策略与配置细节 +type: docs +weight: 1 +--- + +Dubbo 内置了 client-based 负载均衡机制,如下是当前支持的负载均衡算法,结合上文提到的自动服务发现机制,消费端会自动使用 `Weighted Random LoadBalance 加权随机负载均衡策略` 选址调用。 + +如果要调整负载均衡算法,以下是 Dubbo 框架内置的负载均衡策略: + +| 算法 | 特性 | 备注 | 配置值 | +| :-------------------------- | :---------------------- | :---------------------------------------------- | :---------------------------------------------- | +| Weighted Random LoadBalance | 加权随机 | 默认算法,默认权重相同 | random (默认) | +| RoundRobin LoadBalance | 加权轮询 | 借鉴于 Nginx 的平滑加权轮询算法,默认权重相同 | roundrobin | +| LeastActive LoadBalance | 最少活跃优先 + 加权随机 | 背后是能者多劳的思想 | leastactive | +| Shortest-Response LoadBalance | 最短响应优先 + 加权随机 | 更加关注响应速度 | shortestresponse | +| ConsistentHash LoadBalance | 一致性哈希 | 确定的入参,确定的提供者,适用于有状态请求 | consistenthash | +| P2C LoadBalance | Power of Two Choice | 随机选择两个节点后,继续选择“连接数”较小的那个节点。 | p2c | +| Adaptive LoadBalance | 自适应负载均衡 | 在 P2C 算法基础上,选择二者中 load 最小的那个节点 | adaptive | + +## 全局配置 +Dubbo 框架的默认策略是 `random` 加权随机负载均衡。如果要调整策略,只需要设置 `loadbalance` 相应取值即可,每种负载均衡策略取值请参见文档最上方表格。 + +为所有服务调用指定全局配置: +```yaml +dubbo: + consumer: + loadbalance: roundrobin +``` + +## 接口级配置 +可以为每个服务指定不同的负载均衡策略。 + +在 provider 端设置,作为 consumer 侧默认值 +```java +@DubboService(loadbalance = "roundrobin") +public class DemoServiceImpl implements DemoService {} +``` + +在 consumer 端设置,具备更高优先级 +```java +@DubboReference(loadbalance = "roundrobin") +private DemoService demoService; +``` + +## 方法级配置 +也可以指定方法(method)级别的负载均衡策略。 + +在 Spring Boot 开发模式下,配置 method 级别参数有以下几种方式: + +**JavaConfig** +```java +@Configuration +public class DubboConfiguration { + @Bean + public ServiceBean demoService() { + MethodConfig method = new MethodConfig(); + method.setName("sayHello"); + method.setLoadbalance("roundrobin"); + + ServiceBean service = new ServiceBean(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + service.addMethod(method) + return service; + } +} +``` + +```java +@Autowire +private DemoService demoService; + +@Configuration +public class DubboConfiguration { + @Bean + public ReferenceBean demoService() { + MethodConfig method = new MethodConfig(); + method.setName("sayHello"); + method.setLoadbalance("roundrobin"); + + ReferenceBean reference = new ReferenceBean<>(); + reference.setInterface(DemoService.class); + reference.addMethod(method); + return reference; + } +} +``` + +**dubbo.properties** +```properties +dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.loadbalance=roundrobin +``` + +## 一致性哈希配置 + +默认采用第一个参数作为哈希 key,如果需要切换参数,可以指定 `hash.arguments` 属性 + +```java +ReferenceConfig referenceConfig = new ReferenceConfig(); +// ... init +Map parameters = new HashMap(); +parameters.put("hash.arguments", "1"); +parameters.put("sayHello.hash.arguments", "0,1"); +referenceConfig.setParameters(parameters); +referenceConfig.setLoadBalance("consistenthash"); +referenceConfig.get(); +``` + +## 自适应负载均衡配置 + +只需要在 consumer 或 provider 端将 `loadbalance` 设置为 `p2c` 或者 `adaptive` 即可,可在此查看 [工作原理](/zh-cn/overview/reference/proposals/heuristic-flow-control) diff --git a/content/en/overview/mannual/java-sdk/tasks/service-discovery/nacos.md b/content/en/overview/mannual/java-sdk/tasks/service-discovery/nacos.md new file mode 100644 index 000000000000..871130d721c7 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/service-discovery/nacos.md @@ -0,0 +1,219 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ +description: "通过示例演示如何使用 Nacos 作为注册中心实现自动服务发现。" +linkTitle: 使用Nacos注册中心 +title: 使用 Nacos 作为注册中心实现自动服务发现 +type: docs +weight: 4 +--- + +本示例演示 Nacos 作为注册中心实现自动服务发现,示例基于 Spring Boot 应用展开,可在此查看 [完整示例代码](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-nacos) + +## 1 基本配置 + +### 1.1 增加依赖 +增加 dubbo、nacos-client 依赖: +```xml + + + org.apache.dubbo + dubbo + 3.3.0 + + + com.alibaba.nacos + nacos-client + 2.1.0 + + +``` + +对于 Spring Boot 应用,可以使用如下 spring-boot-starter: +```xml + + org.apache.dubbo + dubbo-spring-boot-starter + 3.3.0 + + + org.apache.dubbo + dubbo-nacos-spring-boot-starter + 3.3.0 + +``` + +### 1.2 Nacos 版本 +Nacos 版本映射关系: +| Dubbo | 推荐 Nacos 版本 | Nacos 兼容范围 | +| --- | --- | --- | +| 3.3.0 | 2.2.3 | 2.x | +| 3.2.21 | 2.1.0 | 2.x | +| 3.1.11 | 2.0.9 | 2.x | +| 3.0.10 | 2.0.9 | 2.x | +| 2.7.21 | 1.x | 1.x | +| 2.6.0 | 1.x | 1.x | + +### 1.3 配置并启用 Nacos + +```yaml +# application.yml (Spring Boot) +dubbo + registry + address: nacos://localhost:8848 + register-mode: instance # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all,默认值为 all,未来版本将切换默认值为 instance +``` +或 +```properties +# dubbo.properties +dubbo.registry.address=nacos://localhost:8848 +dubbo.registry.register-mode=instance +``` +或 +```xml + +``` + +## 2 高级配置 + +### 2.1 认证 + +```yaml +# application.yml (Spring Boot) +dubbo + registry + address: nacos://localhost:8848?username=nacos&password=nacos + register-mode: instance +``` + +或 + +```properties +# dubbo.properties +dubbo.registry.address: nacos://nacos:nacos@localhost:8848 +# 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all,默认值为 all,未来版本将切换默认值为 instance +dubbo.registry.register-mode=instance +``` + +### 2.2 自定义命名空间 + +```yaml +# application.yml (Spring Boot) +dubbo: + registry: + address: nacos://localhost:8848?namespace=5cbb70a5-xxx-xxx-xxx-d43479ae0932 + register-mode: instance # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all +``` + +或者 + +```yaml +# application.yml (Spring Boot) +dubbo: + registry: + address: nacos://localhost:8848 + register-mode: instance # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all + parameters.namespace: 5cbb70a5-xxx-xxx-xxx-d43479ae0932 +``` + +### 2.3 自定义分组 + +```yaml +# application.yml +dubbo: + registry: + address: nacos://localhost:8848 + register-mode: instance # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all + group: dubbo +``` + +> 如果不配置的话,group 是由 Nacos 默认指定。group 和 namespace 在 Nacos 中代表不同的隔离层次,通常来说 namespace 用来隔离不同的用户或环境,group 用来对同一环境内的数据做进一步归组。 + +### 2.4 注册接口级消费者 +Dubbo 3.0.0 版本以后,增加了是否注册消费者的参数,如果需要将消费者注册到 nacos 注册中心上,需要将参数(register-consumer-url)设置为true,默认是false。 +```yaml +# application.yml +dubbo: + registry: + register-mode: instance # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all + address: nacos://localhost:8848?register-consumer-url=true +``` +或者 +```yaml +# application.yml +dubbo: + registry: + address: nacos://localhost:8848 + register-mode: instance # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all + parameters.register-consumer-url: true +``` + +### 2.5 更多配置 + +参数名 | 中文描述| 默认值 +---|---|--- +username|连接Nacos Server的用户名|nacos +paasword|连接Nacos Server的密码|nacos +backup|备用地址|空 +namespace|命名空间的ID|public +group|分组名称|DEFAULT_GROUP +register-consumer-url|是否注册消费端|false +com.alibaba.nacos.naming.log.filename|初始化日志文件名|naming.log +endpoint|连接Nacos Server指定的连接点,可参考[文档](https://nacos.io/zh-cn/blog/address-server.html)|空 +endpointPort|连接Nacos Server指定的连接点端口,可以参考[文档](https://nacos.io/zh-cn/blog/address-server.html)|空 +endpointQueryParams|endpoint查参数询|空 +isUseCloudNamespaceParsing|是否解析云环境中的namespace参数|true +isUseEndpointParsingRule|是否开启endpoint 参数规则解析|true +namingLoadCacheAtStart|启动时是否优先读取本地缓存|true +namingCacheRegistryDir|指定缓存子目录,位置为 .../nacos/{SUB_DIR}/naming|空 +namingClientBeatThreadCount|客户端心跳的线程池大小|机器的CPU数的一半 +namingPollingThreadCount|客户端定时轮询数据更新的线程池大小|机器的CPU数的一半 +namingRequestDomainMaxRetryCount|client通过HTTP向Nacos Server请求的重试次数|3 +namingPushEmptyProtection|在服务没有有效(健康)实例时,是否开启保护,开启后则会使用旧的服务实例|false +push.receiver.udp.port|客户端UDP的端口|空 + +在nacos-server@`1.0.0`版本后,支持客户端通过上报一些包含特定的元数据的实例到服务端来控制实例的一些行为。 + +参数名 | 中文描述| 默认值 +---|---|--- +preserved.heart.beat.timeout|该实例在不发送心跳后,从健康到不健康的时间(毫秒)|15000 +preserved.ip.delete.timeout|该实例在不发送心跳后,被服务端下掉该实例的时间(毫秒)|30000 +preserved.heart.beat.interval|该实例在客户端上报心跳的间隔时间(毫秒)|5000 +preserved.instance.id.generator|该实例的id生成策略,值为`snowflake`时,从0开始增加|simple +preserved.register.source|注册实例注册时服务框架类型(例如Dubbo,Spring Cloud等)|空 + + 这些参数都可以类似 `namespace` 的方式通过通过参数扩展配置到 Nacos,如 + + ```properties + dubbo.registry.parameters.preserved.heart.beat.timeout=5000 + ``` + +## 3 工作原理 + +在前面的一节中,我们讲解了应用级服务发现与接口级服务发现的区别,以下是两种模式在 Nacos 实现中的具体存储结构。 + +### 3.1 Dubbo2 注册数据 + +随后,重启您的 Dubbo 应用,Dubbo 的服务提供和消费信息在 Nacos 控制台中可以显示: + +![dubbo-registry-nacos-1.png](/imgs/blog/dubbo-registry-nacos-1.png) + +如图所示,服务名前缀为 `providers:` 的信息为服务提供者的元信息,`consumers:` 则代表服务消费者的元信息。点击“**详情**”可查看服务状态详情: + +![image-dubbo-registry-nacos-2.png](/imgs/blog/dubbo-registry-nacos-2.png) + +### 3.2 Dubbo3 注册数据 +应用级服务发现的 "服务名" 为应用名 + +> Dubbo3 默认采用 "应用级服务发现 + 接口级服务发现" 的双注册模式,因此会发现应用级服务(应用名)和接口级服务(接口名)同时出现在 Nacos 控制台,可以通过配置 `dubbo.registry.register-mode=instance/interface/all` 来改变注册行为。 + +### 3.3 客户端缓存 + +### 3.4 心跳检测 + +### 3.5 + + diff --git a/content/en/overview/mannual/java-sdk/tasks/service-discovery/registry.md b/content/en/overview/mannual/java-sdk/tasks/service-discovery/registry.md new file mode 100644 index 000000000000..667c3cb0d22f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/service-discovery/registry.md @@ -0,0 +1,273 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ +description: "Dubbo 服务发现的工作方式、基本使用方法与配置细节,涵盖延迟注册、优雅上下线、启动时检查、断网恢复、推空保护等。" +linkTitle: 服务发现 +title: 服务发现的工作方式、基本使用方法与配置细节 +type: docs +weight: 1 +--- +Dubbo 支持基于注册中心的自动实例发现机制,即 Dubbo 提供者注册实例地址到注册中心,Dubbo 消费者通过订阅注册中心变更事件自动获取最新实例变化,从而确保流量始终转发到正确的节点之上。Dubbo 目前支持 Nacos、Zookeeper、Kubernetes Service 等多种注册中心接入。 + +## 注册中心 +以下是 Dubbo 服务发现接入的一些主流注册中心实现,更多扩展实现与工作原理请查看 [注册中心参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/overview/): + +| 注册中心 | 配置值 | 服务发现模型 | 是否支持鉴权 | spring-boot-starter | +| --- | --- | --- | --- | --- | +| Nacos | nacos | 应用级、接口级 | 是 | dubbo-nacos-spring-boot-starter | +| Zookeeper | zookeeper | 应用级、接口级 | 是 | - dubbo-zookeeper-spring-boot-starter
- dubbo-zookeeper-curator5-spring-boot-starter | +| Kubernetes Service | 参考独立使用文档 | 应用级 | 是 | 无 | + +## 延迟注册 +如果你的服务需要预热时间,比如初始化缓存、等待相关资源就位等,可以使用 `delay` 参数进行延迟注册。如果是在 Spring 应用中,则 `delay = n(n > 0)` 延迟的时间是 Spring 上下文初始化完成后开始算起。 + +```java +@DubboService(delay = 5000) +public class DemoServiceImpl implements DemoService { +} +``` + +以上配置后,应用将延迟 5 秒暴露此服务(应用启动 5s 后发布该服务到注册中心)。或者可以配置全局默认值,让所有服务都延迟 5s 后注册: + +```yaml +dubbo: + provider: + delay: 5000 +``` + +{{% alert title="手动注册" color="warning" %}} +通过配置 `delay = -1`,可以禁止框架自动发布服务到注册中心,直到用户通过调用 [online](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/qos-list/) 等命令手动完成发布,可以用这个特性配合部署系统实现服务的优雅上线,让用户对上线时机有更好的控制。具体配置如下: + +```yaml +dubbo: + provider: + delay: -1 + application: + manual-register: true +``` +{{% /alert %}} + +## 优雅上下线 +通过控制服务实例发布到注册中心、从注册中心摘除的时机,可以让每个实例平滑的处理所有运行中的请求,做到部署期间的流量无损。以下是推荐的上下线操作顺序: + +### 优雅上线 +1. 配置实例地址延迟(或手动)注册,具体请参考上一节的延迟注册配置方式。 +2. 消费端收到新注册的地址实例后,会对新实例进行预热,即以一定的比例分配少部分流量到新实例,逐步增加比例直到与其他实例对等。 + + 预热的计算主要有两个因素,第一个是实例启动时间 timestamp,第二个是预热的总时长 warmup,预热总时长可通过 `` 参数设置。计算公式类似: + + + +### 优雅下线 +优雅下线的推荐步骤如下: +1. 在尝试停止 Dubbo 进程之前,先调用 [offline](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/qos-list/) 从注册中心摘除实例地址(建议操作完成后额外等待几秒钟,以确保注册中心地址下线事件生效)。 +2. 通过 `kill pid` 尝试停止 Dubbo 进程,此时框架会依次检查以下环节: + * 2.1 框架向所有消费方(通过遍历其持有的 channel 链接)发送 readonly 事件,收到事件的消费方将会停止往该实例发送新的请求。此动作默认开启。 + * 2.2 框架会等待一定的时间,等待线程池中所有运行中的请求处理完成,默认是 `10000` 毫秒,可通过 `-Ddubbo.service.shutdown.wait=20000` 调整等待时间。 +3. 以上步骤执行完成后,Dubbo 进程自动停止。 + +{{% alert title="注意" color="info" %}} +有些场景下,需要在代码中控制地址注册、摘除的时机,可以通过调用以下代码实现: + +```java + +``` + +```java + +``` +{{% /alert %}} + +## 多注册中心 +Dubbo 支持在同一应用内配置多个注册中心,一个或一组服务可同时注册到多个注册中心,一个或一组服务可同时订阅多个中心的地址,对于订阅方而言,还可以设置如何调用来自多个注册中心的地址(优先调用某一个注册中心或者其他策略)。 + +指定全局默认的一个或多个注册中心,所有的服务默认都注册到或订阅配置的注册中心: +```yaml +dubbo + registries + beijingRegistry + register-mode: instance #新用户建议使用,老用户如继续使用老服务发现模型则删除此配置 + address: zookeeper://localhost:2181 + shanghaiRegistry + register-mode: instance #新用户建议使用,老用户如继续使用老服务发现模型则删除此配置 + address: zookeeper://localhost:2182 +``` + +指定某个服务注册到多个注册中心: + +```java +@DubboService(registry = {"beijingRegistry"}) +public class DemoServiceImpl implements DemoService {} +``` + +指定某个服务订阅来自多个注册中心的地址: + +```java +@DubboReference(registry = {"beijingRegistry"}) +private DemoService demoService +``` + +关于多注册中心的更多配置、使用场景说明请参见[【参考手册 - 注册中心 - 多注册中心】](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/multiple-registry/) + +## 应用级vs接口级 +Dubbo3 在兼容 Dubbo2 `接口级服务发现`的同时,定义了新的`应用级服务发现`模型,关于它们的含义与工作原理请参考 [应用级服务发现](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/service-discovery-application-vs-interface/)。Dubbo3 具备自动协商服务发现模型的能力,因此老版本 Dubbo2 用户可以无缝升级 Dubbo3。 + +{{% alert title="注意" color="warning" %}} +如果你是 Dubbo 新用户,强烈建议增加以下配置项目,以明确指示框架使用应用级服务发现: +```yml +dubbo: + registry: + address: "nacos://127.0.0.1:8848" + register-mode: instance # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all +``` + +老用户均建议参考 [应用级服务发现迁移指南](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery/) 完成平滑迁移。 +{{% /alert %}} + +## 只注册 +如果有两个镜像环境,两个注册中心,有一个服务只在其中一个注册中心有部署,另一个注册中心还没来得及部署,而两个注册中心的其它应用都需要依赖此服务。这个时候,可以让服务提供者方只注册服务到另一注册中心,而不从另一注册中心订阅服务。该机制通常用于提供程序相对静态且不太可能更改的场景或者提供程序和使用者互不依赖的场景。 + +```yaml +dubbo: + registry: + subscribe: false +``` + +## 只订阅 + +为方便开发测试,经常会在线下共用一个所有服务可用的注册中心,这时,如果一个正在开发中的服务提供者注册,可能会影响消费者不能正常运行。可以让服务提供者开发方,只订阅服务(开发的服务可能依赖其它服务),而不注册正在开发的服务,通过直连测试正在开发的服务。 + +![/user-guide/images/subscribe-only.jpg](/imgs/user/subscribe-only.jpg) + +```yaml +dubbo: + registry: + register: false +``` + +## 权限控制 +通过令牌验证在注册中心控制权限,以决定要不要下发令牌给消费者,可以防止消费者绕过注册中心访问提供者。另外通过注册中心可灵活改变授权方式,而不需修改或升级提供者。 + +![/user-guide/images/dubbo-token.jpg](/imgs/user/dubbo-token.jpg) + +增加以下配置: +```yaml +dubbo: + provider: + token: true #UUID +``` +或者 +```yaml +dubbo: + provider: + token: 123456 +``` + +## 指定注册地址 +当服务提供者启动时,Dubbo 框架会自动扫描本机可用的网络设备地址,并将其中一个有效ip地址注册到注册中心。扫描遵循以下原则或顺序: + +1. 未联网时,返回 127.0.0.1 +2. 在阿里云服务器中,返回私有地址,如: 172.18.46.234 +3. 在本机测试时,返回公有地址,如: 30.5.10.11 + +对于有多个网络设备的情况,Dubbo 会随机选择其中一个,此时如果注册的 ip 地址不符合预期,可以通过以下方式指定地址。 + +* -D 参数指定框架读取的网卡地址,如 `-Ddubbo.network.interface.preferred=eth0`。 +* 系统环境变量指定上报到注册中心的 ip,如 `DUBBO_IP_TO_REGISTRY=30.5.10.11` + + +最后,还可以通过在 protocol 中指定 tcp 监听地址,因为监听地址会默认用作发送到注册中心的地址 +```yaml +dubbo: + protocol: + name: dubbo + port: 20880 + host: 30.5.10.11 # 也可以是域名,如 dubbo.apache.org +``` + +{{% alert title="注意" color="primary" %}} +Dubbo 框架会默认监听 `0.0.0.0:20880`,如果指定了 host,则框架会转而监听 `30.5.10.11:20880`。 +{{% /alert %}} + +## 启动时检查 + +### 消费端地址列表检查 +Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时(这里指地址列表为空)会抛出异常,阻止应用初始化完成,以便上线时能及早发现问题,默认 `check="true"`。 + +可以通过 `check="false"` 关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。注意如果 `check="false"` 且启动时无地址可用,此时总是会正常返回 rpc 引用,但如果此时发起调用就会出现 “无地址可用异常”,当服务地址列表恢复时,rpc 应用会自动可用。 + +**1. 使用场景** +- 单向依赖:有依赖关系(建议默认设置)和无依赖关系(可以设置 check=false) +- 相互依赖:即循环依赖,(不建议设置 check=false) +- 延迟加载处理 + +> check 只用来启动时检查,运行时没有相应的依赖仍然会报错。 + +**2. 配置方式** +```java +@DubboReference(check = false) +private DemoService demoService; +``` + +```yaml +dubbo: + consumer: + check: false +``` +### 注册中心连通性检查 +除了检查消费者端地址列表之外,Dubbo 还支持与注册中心的连通性检查。默认情况下,不论是提供者、消费者,如果启动阶段连接不上注册中心都会导致进程启动失败。 + +可以关闭注册中心启动时检查,即使注册中心连接失败进程也会继续正常启动。框架会记录所有失败的注册、订阅动作,并在注册中心链接恢复后尝试重新注册、订阅,直到所有失败事件都重试成功。 + +```yaml +dubbo: + registry: + check: false +``` + +## 注册中心缓存 + +当某个服务尝试向注册中心订阅地址时,此时注册中心应该同步返回获当前可用的地址列表,如果此时因网络故障等原因导致读取可用地址列表失败,框架会查询本地缓存的注册中心地址并返回(如不想使用使用缓存地址,可通过设置 `check=true` 快速失败抛出异常)。失败的订阅动作会被放入一个重试队列,定期重试直到成功,以确保故障恢复后可及时读到最新地址列表。 + +注册中心缓存文件的默认存放路径是:`${HOME}/.dubbo/dubbo-registry-{application-name}-{address}.cache`,以一定的间隔定期刷新。 + +如果不需要注册中心本地文件缓存,可通过以下配置关闭: +```yml +dubbo: + registry: + file-cache: false +``` + +## 断网恢复 + +### 注册中心断网恢复 + +当 dubbo 进程与注册中心之间的链接中断后,dubbo 框架会自动尝试恢复,并确保链接恢复后所有的已注册或订阅的服务都正常恢复。 + +### 消费端地址断网恢复 + +Dubbo 消费端进程可以通过 tcp 链接自动跟踪提供端实例的可用性,当发现实例不可用时,消费端会自动将不可用的实例转移到不可用地址池,以确保正常的服务调用不受影响。Dubbo 会自动探测被拉黑的不可用地址池,当发现 tcp 链接恢复后,自动从不可用地址池移除。 + +## 推空保护 +推空保护是对消费端而言的,当推空保护开启后,消费端进程会忽略注册中心推送过来的空地址事件(会继续保留当前内存已有地址列表)。这是避免在一些异常场景下误将注册中心地址列表清空,导致服务调用不可用。 + +推空保护默认关闭,可通过以下方式开启 +```yaml +dubbo: + registry: + enableEmptyProtection: true +``` + +## 直连提供者 +如果你的项目开启了服务发现,但在测试中想调用某个特定的 ip,可通过设置对端 ip 地址的 [直连模式](/zh-cn/overview/mannual/java-sdk/tasks/framework/more/explicit-target/) 绕过服务发现机制进行调用。 + +## 问题排查 +相比于 client 到 server 的 RPC 直连调用,开启服务发现后,常常会遇到各种个样奇怪的调用失败问题,以下是一些常见的问题与排查方法。 + +1. **消费方找不到可用地址 (No Provider available)**,这里有详细的 [具体原因排查步骤](/zh-cn/overview/mannual/java-sdk/tasks/troubleshoot/no-provider/)。 +2. **忘记配置注册中心**,从 3.3.0 开始,不配置注册中心地址的情况下,应用也是能够正常启动的,只是应用的任何服务都不会注册到注册中心,或者从注册中心订阅地址列表。 +3. **注册中心连不上**,如果配置了 `check=false`,虽然进程启动成功,可能服务注册、订阅并没有成功。 +4. **消费方因没有有效的地址而启动报错**,可以通过配置ReferenceConfig跳过可用地址列表检查,注解示例为 `@DubboRerefence(check=false)`。 diff --git a/content/en/overview/mannual/java-sdk/tasks/service-discovery/zookeeper.md b/content/en/overview/mannual/java-sdk/tasks/service-discovery/zookeeper.md new file mode 100644 index 000000000000..faf88af98de8 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/service-discovery/zookeeper.md @@ -0,0 +1,218 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ +description: "通过示例演示如何使用 Zookeeper 作为注册中心实现自动服务发现。" +linkTitle: 使用Zookeeper注册中心 +title: 使用 Zookeeper 作为注册中心实现自动服务发现 +type: docs +weight: 3 +--- + +本示例演示 Zookeeper 作为注册中心实现自动服务发现,示例基于 Spring Boot 应用展开,可在此查看 [完整示例代码](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-zookeeper) + +## 1 基本配置 +### 1.1 增加 Maven 依赖 +添加 dubbo、zookeeper 等依赖。`dubbo-spring-boot-starter` 将自动为应用增加 Zookeeper 相关客户端的依赖,减少用户使用 Zookeeper 成本,如使用中遇到版本兼容问题,用户也可以选择自行添加 Curator、Zookeeper Client 等依赖。 + +对于 Spring Boot 应用而言,可使用如下依赖: +```xml + + org.apache.dubbo + dubbo-spring-boot-starter + 3.3.0 + + + + org.apache.dubbo + dubbo-zookeeper-spring-boot-starter + 3.3.0 + + +``` + +其中,dubbo-zookeeper-spring-boot-starter 或 `dubbo-zookeeper-curator5-spring-boot-starter` 负责管理 zookeeper 相关依赖。 + + +{{% alert title="注意" color="info" %}} +如果您不使用 Spring Boot,也可以使用以下方式管理依赖 + +```xml + + + org.apache.dubbo + dubbo + 3.3.0 + + + + + org.apache.dubbo + dubbo-dependencies-zookeeper + 3.3.0 + pom + + + +``` +{{% /alert %}} + +### 1.2 选择 Zookeeper 版本 + +由于 Dubbo 使用 Curator 作为与 Zookeeper Server 交互的编程客户端,因此,要特别注意 Zookeeper Server 与 Dubbo 版本依赖的兼容性。 + +Dubbo 提供了 Zookeeper 依赖的辅助管理组件,开发者可根据当前使用的 Zookeeper Server 版本选择依赖版本: + +**1. 如果您是 Dubbo3 3.3 版本及以上用户,请根据如下表格选择组件:** + +| **Zookeeper Server 版本** | **Dubbo 依赖** | **Dubbo Starter 依赖(SpringBoot用户)** | +| --- | --- | --- | +| 3.4.x 及以下 | dubbo-dependencies-zookeeper | dubbo-zookeeper-spring-boot-starter | +| 3.5.x 及以上 | dubbo-dependencies-zookeeper-curator5 | dubbo-zookeeper-curator5-spring-boot-starter | + +**2. 如果您是 Dubbo3 3.2 及以下、Dubbo2 2.7.x 用户:** + +| **Zookeeper Server 版本** | **Dubbo 依赖** | **Dubbo Starter 依赖(SpringBoot用户)** | +| --- | --- | --- | +| 3.4.x 及以下 | dubbo-dependencies-zookeeper | 不支持(自行管理) | +| 3.5.x 及以上 | 不支持(自行管理) | 不支持(自行管理) | + +{{% alert title="注意" color="info" %}} +* Dubbo 3.3.0 版本开始正式支持 JDK 17,如果您使用 JDK 17,则必须选用 dubbo-dependencies-zookeeper-curator5 或 dubbo-zookeeper-curator5-spring-boot-starter 依赖,对应的 Zookeeper Server 推荐是 3.8.0 版本及以上。 +{{% /alert %}} + + +### 1.3 配置并启用 Zookeeper +```yaml +# application.yml +dubbo + registry + address: zookeeper://localhost:2181 + register-mode: instance # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all,默认值为 all,未来版本将切换默认值为 instance +``` +或 +```properties +# dubbo.properties +dubbo.registry.address=zookeeper://localhost:2181 +# 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all,默认值为 all,未来版本将切换默认值为 instance +dubbo.registry.register-mode=instance +``` +或 +```xml + +``` + +`address` 是启用 zookeeper 注册中心唯一必须指定的属性,而在生产环境下,`address` 通常被指定为集群地址,如 + +`address=zookeeper://10.20.153.10:2181?backup=10.20.153.11:2181,10.20.153.12:2181` + +protocol 与 address 分开配置的模式也可以,如 + +`` + +## 2 高级配置 +### 2.1 认证与鉴权 + +如果 Zookeeper 开启认证,Dubbo 支持指定 username、password 的方式传入身份标识。 + +```yaml +# application.yml +dubbo + registry + address: zookeeper://localhost:2181 + register-mode: instance # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all + username: hello + password: 1234 +``` + +也可以直接将参数扩展在 address 上 `address=zookeeper://hello:1234@localhost:2181` + +### 2.2 分组隔离 +通过指定 `group` 属性,可以在同一个 Zookeeper 集群内实现微服务地址的逻辑隔离。比如可以在一套集群内隔离出多套开发环境,在地址发现层面实现隔离。 + +```yaml +# application.yml +dubbo + registry + address: zookeeper://localhost:2181 + register-mode: instance # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all + group: daily1 +``` + +### 2.3 其他扩展配置 +配置连接、会话过期时间 +```yaml +# application.yml +dubbo + registry + address: zookeeper://localhost:2181 + register-mode: instance # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all + timeout: 30 * 1000* # 连接超时时间,默认 30s + session: 60 * 1000* # 会话超时时间,默认 60s +``` + +Zookeeper 注册中心还支持其他一些控制参数,具体可参见[Registry 配置项手册](../../config/properties#registry) + +## 3 工作原理 +在前面的一节中,我们讲解了应用级服务发现与接口级服务发现的区别,在 Zookeeper 实现中,它们的存储结构也存在较大差异。总体来说,Zookeeper 注册中心实现支持以下高可用能力: + +* 当提供者出现断电等异常停机时,注册中心能自动删除提供者信息 +* 当注册中心重启时,能自动恢复注册数据,以及订阅请求 +* 当会话过期时,能自动恢复注册数据,以及订阅请求 +* 当设置 `registry.check=false` 时,记录失败注册和订阅请求,后台定时重试 + +### 3.1 接口级节点结构 + +![/user-guide/images/zookeeper.jpg](/imgs/user/zookeeper.jpg) + +流程: +* 服务提供者启动时: 向 `/dubbo/com.foo.BarService/providers` 目录下写入自己的 URL 地址。 +* 服务消费者启动时: 订阅 `/dubbo/com.foo.BarService/providers` 目录下的提供者 URL 地址。并向 `/dubbo/com.foo.BarService/consumers` 目录下写入自己的 URL 地址 +* 监控中心启动时: 订阅 `/dubbo/com.foo.BarService` 目录下的所有提供者和消费者 URL 地址。 + +可通过 `registry.group` 设置 zookeeper 的根节点,不配置将使用默认的 `/dubbo` 根节点。 + +### 3.2 应用级节点结构 + +#### 3.2.1 地址列表 + + +应用级服务发现的地址结构比接口级更精简,它以应用名为粒度分发地址列表。服务提供者启动时,向 `/services/app` 目录下写入自己的 URL 地址,相比于接口级别的 URL,应用级别的 URL 更简单,只包含一些实例级别的参数,如 `tri://ip:port?region=hangzhou`。 + +可通过 `registry.group` 设置 zookeeper 的根节点,如设置 `registry.group=dubbo` 后,地址根节点变为 `/dubbo`。不配置将使用默认的 `/services` 根节点。在与 Spring Cloud Gateway 共用情况下,使用 `/services` 根节点会导致 dubbo 地址被 gateway 消费,此时可考虑设置独立 group。 + +{{% alert title="注意" color="info" %}} +在应用级服务发现模型中,接口级别的配置信息由消费者与提供者之间自行协商同步,不再由注册中心负责同步,从而大大减少了注册中心地址同步压力。 +{{% /alert %}} + +#### 3.2.2 接口应用映射 +在应用级服务发现中,zookeeper 注册中心还会存储一份额外的元数据,用于解决 `接口名到应用名` 之间的映射关系,其存储结构如下: + + + +service1 节点的 value 值是应用列表,可通过 `get /dubbo/mapping/service1` 查看:app1,app2 + +#### 3.2.3 元数据 +如果您用的是应用级服务发现的集中式元数据模式(默认是点对点的元数据模式,可通过 `dubbo.registry.metadata-type=remote` 开启)。在开启集中式元数据模式后,zookeeper 中还会发现以下节点内容: + + + +每个 revision 下是该应用的部署元数据信息,包含完整的接口服务列表及其配置信息。 + + + diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/_index.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/_index.md new file mode 100755 index 000000000000..6811d4244be4 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/_index.md @@ -0,0 +1,118 @@ +--- +aliases: [/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/traffic/] +description: 演示 Dubbo 流量治理特性的使用方式。 +linkTitle: 流量管控 +no_list: true +title: 流量管控 +type: docs +weight: 5 +--- + +我们通过一个使用 Dubbo 开发的商城微服务项目,演示 Dubbo 流量管控规则的基本使用方法,包括如下场景: + +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ 调整超时时间 +

+

通过在运行期动态的调整服务超时时间,可以有效的应对超时设置不合理、系统突发情况等导致的服务频繁超时、服务阻塞等问题,提升系统稳定性。

+
+
+
+
+
+
+

+ 增加重试次数 +

+

在服务初次调用失败后,通过重试能有效的提升总体调用成功率。

+
+
+
+
+
+
+

+ 访问日志 +

+

访问日志可以很好的记录某台机器在某段时间内处理的所有服务请求信息,运行态动态的开启访问日志对于排查问题非常有帮助。 +

+
+
+
+
+
+
+

+ 同机房/区域优先 +

+

同机房/区域优先是指应用调用服务时,优先调用同机房/区域的服务提供者,避免了跨区域带来的网络延时,从而减少了调用的响应时间。 +

+
+
+
+
+
+
+

+ 环境隔离 +

+

通过为集群中的某一个或多个应用划分逻辑隔离环境,可用于灰度环境或多套测试环境搭建。 +

+
+
+
+
+
+
+

+ 参数路由 +

+

如基于用户 ID 路由流量,将一小部分用户请求转发到最新发布的产品版本,以验证新版本的稳定性、获取用户的产品体验反馈等。 +

+
+
+
+
+
+
+

+ 权重比例 +

+

通过规则动态调整单个或一组机器的权重,可以在运行态改变请求流量的分布,实现动态的按比例的流量路由。 +

+
+
+
+
+
+
+

+ 服务降级 +

+

服务降级的核心目标就是针对这些弱依赖项,在弱依赖不可用或调用失败时,通过返回降级结果尽可能的维持功能完整。 +

+
+
+
+
+
+
+

+ 固定机器导流 +

+

通过将请求固定的转发某一台提供者机器,帮助快速复现开发或线上问题。 +

+
+
+
+
+
+
+ +{{< /blocks/section >}} diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/accesslog.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/accesslog.md new file mode 100644 index 000000000000..71a04e45436d --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/accesslog.md @@ -0,0 +1,87 @@ +--- +aliases: + - /zh/overview/tasks/traffic-management/accesslog/ + - /zh-cn/overview/tasks/traffic-management/accesslog/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/accesslog/ +description: "" +linkTitle: 访问日志 +title: 通过动态开启访问日志跟踪服务调用情况 +type: docs +weight: 3 +--- + + + +访问日志可以很好的记录某台机器在某段时间内处理的所有服务请求信息,包括请求接收时间、远端 IP、请求参数、响应结果等,运行态动态的开启访问日志对于排查问题非常有帮助。 + +## 开始之前 +* [部署 Shop 商城项目](../#部署商场系统) +* 部署并打开 [Dubbo Admin](../.././../reference/admin/architecture/) + +## 任务详情 + +商城的所有用户服务都由 `User` 应用的 UserService 提供,通过这个任务,我们为 `User` 应用的某一台或几台机器开启访问日志,以便观察用户服务的整体访问情况。 + +### 动态开启访问日志 + +Dubbo 通过 `accesslog` 标记识别访问日志的开启状态,我们可以指定日志文件的输出位置,也可以单独打开某台机器的访问日志。 + +![accesslog.png](/imgs/v3/tasks/accesslog/accesslog1.png) + +#### 操作步骤 +1. 打开 Dubbo Admin 控制台 +2. 在左侧导航栏选择【服务治理】>【动态配置】 +3. 点击 "创建",输入应用名 `shop-user` 并勾选 "开启访问日志"(此时访问日志将和普通日志打印在一起)。 + +![Admin 访问日志设置截图](/imgs/v3/tasks/accesslog/accesslog_admin.png) + +再次访问登录页面,登录到 `User` 应用的任意一台机器,可以看到如下格式的访问日志。 + +```text +[2022-12-30 12:36:31.15900] -> [2022-12-30 12:36:31.16000] 192.168.0.103:60943 -> 192.168.0.103:20884 - org.apache.dubbo.samples.UserService login(java.lang.String,java.lang.String) ["test",""], dubbo version: 3.2.0-beta.4-SNAPSHOT, current host: 192.168.0.103 +[2022-12-30 12:36:33.95900] -> [2022-12-30 12:36:33.95900] 192.168.0.103:60943 -> 192.168.0.103:20884 - org.apache.dubbo.samples.UserService getInfo(java.lang.String) ["test"], dubbo version: 3.2.0-beta.4-SNAPSHOT, current host: 192.168.0.103 +[2022-12-30 12:36:31.93500] -> [2022-12-30 12:36:34.93600] 192.168.0.103:60943 -> 192.168.0.103:20884 - org.apache.dubbo.samples.UserService getInfo(java.lang.String) ["test"], dubbo version: 3.2.0-beta.4-SNAPSHOT, current host: 192.168.0.103 +``` + +#### 规则详解 + +**规则 key :** shop-user + +**规则体** + +```yaml +configVersion: v3.0 +enabled: true +configs: + - side: provider + parameters: + accesslog: true +``` + +以下是开启访问日志的关键配置 + +```yaml +parameters: + accesslog: true +``` + +accesslog 的有效值如下: +* `true` 或 `default` 时,访问日志将随业务 logger 一同输出,此时可以在应用内提前配置 `dubbo.accesslog` appender 调整日志的输出位置和格式 +* 具体的文件路径如 `/home/admin/demo/dubbo-access.log`,这样访问日志将打印到指定的文件内 + +在 Admin 界面,还可以单独指定开启某一台机器的访问日志,以方便精准排查问题,对应的后台规则如下: + +```yaml +configVersion: v3.0 +enabled: true +configs: + - match + address: + oneof: + - wildcard: "{ip}:*" + side: provider + parameters: + accesslog: true +``` + +其中,`{ip}` 替换为具体的机器地址即可。 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/architecture.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/architecture.md new file mode 100755 index 000000000000..b52f3ba13c42 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/architecture.md @@ -0,0 +1,201 @@ +--- +aliases: + - /zh/overview/tasks/traffic-management/ + - /zh-cn/overview/tasks/traffic-management/ +description: 演示 Dubbo 流量治理特性的使用方式。 +linkTitle: 示例应用架构 +title: 示例应用架构 +type: docs +weight: 1 +--- + +此任务基于一个简单的线上商城微服务系统演示了 Dubbo 的流量管控能力。 + +{{% alert title="注意" color="warning" %}} +本示例展示的所有能力均基于 [Dubbo 路由规则](/zh-cn/overview/what/core-features/traffic/introduction/) 实现,如想了解具体工作原理可查看详情。 +{{% /alert %}} + + +线上商城的架构图如下: + +![shop-arc](/imgs/v3/traffic/shop-arc.png) + +系统由 5 个微服务应用组成: +* `Frontend 商城主页`,作为与用户交互的 web 界面,通过调用 `User`、`Detail`、`Order` 等提供用户登录、商品展示和订单管理等服务。 +* `User 用户服务`,负责用户数据管理、身份校验等。 +* `Order 订单服务`,提供订订单创建、订单查询等服务,依赖 `Detail` 服务校验商品库存等信息。 +* `Detail 商品详情服务`,展示商品详情信息,调用 `Comment` 服务展示用户对商品的评论记录。 +* `Comment 评论服务`,管理用户对商品的评论数据。 + +## 部署商场系统 + +为方便起见,我们将整个系统部署在 Kubernetes 集群,执行以下命令即可完成商城项目部署,项目源码示例在 [dubbo-samples/task](https://github.com/apache/dubbo-samples/tree/master/10-task/dubbo-samples-shop)。 + +```sh +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/10-task/dubbo-samples-shop/deploy/All.yml +``` + +完整的部署架构图如下: + +![shop-arc](/imgs/v3/traffic/shop-arc-deploy2.png) + +`Order 订单服务`有两个版本 `v1` 和 `v2`,`v2` 是订单服务优化后发布的新版本。 +* 版本 v1 只是简单的创建订单,不展示订单详情 +* 版本 v2 在订单创建成功后会展示订单的收货地址详情 + +`Detail` 和 `Comment` 服务也分别有两个版本 `v1` 和 `v2`,我们通过多个版本来演示流量导流后的效果。 +* 版本 `v1` 默认为所有请求提供服务 +* 版本 `v2` 模拟被部署在特定的区域的服务,因此 `v2` 实例会带有特定的标签 + +执行以下命令,确定所有服务、Pod都已正常运行: +```sh +$ kubectl get services -n dubbo-demo + +``` + +```sh +$ kubectl get pods -n dubbo-demo + +``` + +为了保障系统完整性,除了商城相关的几个微服务应用,示例还在后台拉起了 Nacos 注册配置中心、Dubbo Admin 控制台 和 Skywalking 全链路追踪系统。 + +```sh +$ kubectl get services -n dubbo-system + +``` + +```sh +$ kubectl get pods -n dubbo-system + +``` + +## 获得访问地址 +执行以下命令,将集群端口映射到本地端口: + +```sh +kubectl port-forward -n dubbo-demo deployment/shop-frontend 8080:8080 +``` + +```sh +kubectl port-forward -n dubbo-system service/dubbo-admin 38080:38080 +``` + +```sh +kubectl port-forward -n dubbo-system service/skywalking-oap-dashboard 8082:8082 +``` + +此时,打开浏览器,即可通过以下地址访问: +* 商城首页 `http://localhost:8080` +* Dubbo Admin 控制台 `http://localhost:38080` +* Skywalking 控制台 `http://localhost:8082` + +## 任务项 +接下来,试着通过如下任务项给商城增加一些流量管控规则吧。 + +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ 调整超时时间 +

+

通过在运行期动态的调整服务超时时间,可以有效的应对超时设置不合理、系统突发情况等导致的服务频繁超时、服务阻塞等问题,提升系统稳定性。

+
+
+
+
+
+
+

+ 增加重试次数 +

+

在服务初次调用失败后,通过重试能有效的提升总体调用成功率。

+
+
+
+
+
+
+

+ 访问日志 +

+

访问日志可以很好的记录某台机器在某段时间内处理的所有服务请求信息,运行态动态的开启访问日志对于排查问题非常有帮助。 +

+
+
+
+
+
+
+

+ 同机房/区域优先 +

+

同机房/区域优先是指应用调用服务时,优先调用同机房/区域的服务提供者,避免了跨区域带来的网络延时,从而减少了调用的响应时间。 +

+
+
+
+
+
+
+

+ 环境隔离 +

+

通过为集群中的某一个或多个应用划分逻辑隔离环境,可用于灰度环境或多套测试环境搭建。 +

+
+
+
+
+
+
+

+ 参数路由 +

+

如基于用户 ID 路由流量,将一小部分用户请求转发到最新发布的产品版本,以验证新版本的稳定性、获取用户的产品体验反馈等。 +

+
+
+
+
+
+
+

+ 权重比例 +

+

通过规则动态调整单个或一组机器的权重,可以在运行态改变请求流量的分布,实现动态的按比例的流量路由。 +

+
+
+
+
+
+
+

+ 服务降级 +

+

服务降级的核心目标就是针对这些弱依赖项,在弱依赖不可用或调用失败时,通过返回降级结果尽可能的维持功能完整。 +

+
+
+
+
+
+
+

+ 固定机器导流 +

+

通过将请求固定的转发某一台提供者机器,帮助快速复现开发或线上问题。 +

+
+
+
+
+
+
+ +{{< /blocks/section >}} diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/arguments.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/arguments.md new file mode 100644 index 000000000000..91eaca43d7da --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/arguments.md @@ -0,0 +1,88 @@ +--- +aliases: + - /zh/overview/tasks/traffic-management/arguments/ + - /zh-cn/overview/tasks/traffic-management/arguments/ +description: "" +linkTitle: 参数路由 +title: 根据请求参数引导流量分布 +type: docs +weight: 6 +--- + + + +根据请求参数值转发流量,是一种非常灵活且实用的流量管控策略。比如微服务实践中,根据参数(如用户 ID)路由流量,将一小部分用户请求转发到最新发布的产品版本,以验证新版本的稳定性、获取用户的产品体验反馈等,是生产实践中常用的一种有效的灰度机制。 + +或者,有些产品提供差异化的付费服务,需要根据请求参数中的用户 ID 将请求路由到具有不同服务等级保障的集群,就像接下来我们在示例任务中所做的那样。 + +## 开始之前 + +* [部署 Shop 商城项目](../#部署商场系统) +* 部署并打开 [Dubbo Admin](../.././../reference/admin/architecture/) + +## 任务详情 + +为了增加用户粘性,我们为商城示例系统新增了 VIP 用户服务,现在商城有两类用户:普通用户和 VIP 用户,其中 VIP 用户可以看到比普通用户更低的商品价格。 + +回到商城登录页面,我们以 VIP 用户 `dubbo` 登录系统,是否看到如下图所示的 VIP 专属商品价格,多刷新几次商品页面那? + +![arguments1](/imgs/v3/tasks/arguments/arguments1.png) + +哦,是不是价格忽高忽低?!这是因为在当前部署的示例系统中,只有 detail v2 版本才能识别 VIP 用户并提供特价服务,因此,我们要确保 `dubbo` 用户始终访问 detail v2 实例,以便享受稳定的 VIP 服务。 + +![arguments2](/imgs/v3/tasks/arguments/arguments2.png) + +### 为 VIP 用户提供稳定的特价商品服务 + +Detail v2 版本能够识别 VIP 用户并在商品详情中展示特价。商品详情服务由 Detail 应用中的 `org.apache.dubbo.samples.DetailService` 服务提供,`DetailService` 显示商品详情的 `getItem` 方法定义如下,第二个参数为用户名。 + +```java +public interface DetailService { + Item getItem(long sku, String username); +} +``` + +因此,接下来我们就为 `DetailService` 服务的 `getItem` 方法增加参数路由规则,如果用户参数是 `dubbo` 就转发到 v2 版本的服务。 + +#### 操作步骤 +1. 打开 Dubbo Admin 控制台 +2. 在左侧导航栏选择【服务治理】 > 【参数路由】 +3. 点击 "创建" 按钮,输入。 + +![Admin 参数路由设置截图](/imgs/v3/tasks/arguments/arguments_admin.png) + +方法参数的索引从 `0` 开始,我们上面填入 `1` 表示根据第二个参数进行流量转发。 + +#### 规则详解 + +**规则 key** :`org.apache.dubbo.samples.DetailService` + +**规则体** +```yaml +configVersion: v3.0 +key: org.apache.dubbo.samples.DetailService +scope: service +force: false +enabled: true +priority: 1 +conditions: + - method=getItem & arguments[1]=dubbo => detailVersion=v2 +``` + +* `method=getItem & arguments[1]=dubbo` 表示流量规则匹配 `getItem` 方法调用的第二个参数,当参数值为 `dubbo` 时做进一步的地址子集筛选。 +* `detailVersion=v2` 将过滤出所有带有 `detailVersion=v2` 标识的 URL 地址子集(在示例部署中,我们所有 detail v2 的实例都已经打上了 `detailVersion=v2` 标签)。 + +```yaml +conditions: + - method=getItem & arguments[1]=dubbo => detailVersion=v2 +``` + +`force: false` 表示如果没有 `detailVersion=v2` 的地址,则随机访问所有可用地址。 + +## 其他事项 +本示例只是 Dubbo 条件路由的一种使用场景,除了根据方法名、参数匹配进行流量转发,条件路由还可以根据附加参数 Attachments、URL 中的数据等进行流量转发,同时匹配条件也支持范围、通配符等,比如: +* attachments[key]=hello* +* arguments[0]=1~100 +* url_key=value + +更为灵活的是,条件路由的匹配条件支持扩展,用户可以自定义匹配条件的来源和格式,具体可参见 [条件路由规则说明](/zh-cn/overview/core-features/traffic/condition-rule/)。 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/host.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/host.md new file mode 100644 index 000000000000..59529b3a6ae0 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/host.md @@ -0,0 +1,69 @@ +--- +aliases: + - /zh/overview/tasks/traffic-management/host/ + - /zh-cn/overview/tasks/traffic-management/host/ +description: "" +linkTitle: 固定机器导流 +title: 将流量点对点引导到一台机器 (如排查问题) +type: docs +weight: 9 +--- + + + +自动的地址发现和负载均衡机制有很多优势,它让我们构建可伸缩的分布式微服务系统成为可能,但这种动态的流量分配也带来很多复杂性。一个典型问题是我们无法再预测一次请求具体会落到那一台提供者机器上,但有时能预期或控制请求固定的发往某一台提供者机器在一些场景下会非常有用处,比如当开发者在测试甚至线上环境排查一些复杂问题时,如果能在某一台指定的机器上稳定复现问题现象,对于最终的问题排查肯定会带来很大帮助。 + +## 开始之前 + +* [部署 Shop 商城项目](../#部署商场系统) +* 部署并打开 [Dubbo Admin](../.././../reference/admin/architecture/) + +## 任务详情 + +本任务我们将以 User 服务作为示例,将商城中 Frontend 应用对用户详情方法的调用 `UserService#getInfo` 全部导流到一台固定实例上去。 + +![host1.png](/imgs/v3/tasks/host/host1.png) + +### 将用户详情服务调用导流到一台固定机器 + +首先,确定部署 User 应用的实际机器列表 + +```sh +$ kubectl get pods -n dubbo-demo +# list result here +``` + +为 `org.apache.dubbo.samples.UserService` 服务的 `getInfo` 方法调用设置条件路由规则,所有这个方法的调用全部转发到一台指定机器。 + +#### 操作步骤 +1. 打开 Dubbo Admin 控制台 +2. 在左侧导航栏选择【服务治理】>【条件路由】 +3. 点击 "创建",输入服务 `org.apache.dubbo.samples.UserService` 。 + +![Admin 指定机器导流配置截图](/imgs/v3/tasks/host/host_admin.png) + +打开机器日志,刷新页面多触发机器用户详情服务调用,可以看到只有规则中指定的实例中在持续刷新以下日志: +```text +Received getInfo request...... +``` + +#### 规则详解 + +**规则 key** :`org.apache.dubbo.samples.UserService` + +**规则体** +```yaml +configVersion: v3.0 +enabled: true +force: false +conditions: + - 'method=getInfo => host = {your ip address}' +``` + +替换 `{your ip address}` 为 User 实际的部署地址。 + +## 清理 +为了不影响其他任务效果,通过 Admin 删除或者禁用刚刚配置的条件路由规则。 + +## 其他事项 +在生产环境中引导流量到固定机器要做好安全性评估,避免单机负载过高影响系统稳定性,另外,云原生背景下的 IP 地址的变化更加频繁,IP 地址可能随时会失效,要注意及时清理绑定特定 IP 的路由规则。 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/isolation.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/isolation.md new file mode 100644 index 000000000000..b9cc840a0cee --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/isolation.md @@ -0,0 +1,138 @@ +--- +aliases: + - /zh/overview/tasks/traffic-management/isolation/ + - /zh-cn/overview/tasks/traffic-management/isolation/ +description: "" +linkTitle: 环境隔离 +title: 通过标签实现流量隔离环境(灰度、多套开发环境等) +type: docs +weight: 5 +--- + + + +无论是在日常开发测试环境,还是在预发生产环境,我们经常都会遇到流量隔离环境的需求。 +* 在日常开发中,为了避免开发测试过程中互相干扰,我们有搭建多套独立测试环境的需求,但通过搭建物理集群的方式成本非常高且不够灵活 +* 在生产发布过程中,为了保障新版本得到充分的验证,我们需要搭建一套完全隔离的线上灰度环境用来部署新版本服务,线上灰度环境能完全模拟生产运行情况,但只有固定的带有特定标记的线上流量会被导流到灰度环境,充分验证新版本的同时将线上变更风险降到最低。 + +利用 Dubbo 提供的标签路由能力,可以非常灵活的实现流量隔离能力。可以单独为集群中的某一个或多个应用划分隔离环境,也可以为整个微服务集群划分隔离环境;可以在部署态静态的标记隔离环境,也可以在运行态通过规则动态的隔离出一部分机器环境。 + +> 注意:标签路由是一套严格隔离的流量体系,对于同一个应用而言,一旦打了标签则这部分地址子集就被隔离出来,只有带有对应标签的请求流量可以访问这个地址子集,这部分地址不再接收没有标签或者具有不同标签的流量。举个例子,如果我们将一个应用进行打标,打标后划分为 tag-a、tag-b、无 tag 三个地址子集,则访问这个应用的流量,要么路由到 tag-a (当请求上下文 dubbo.tag=tag-a),要么路由到 tag-b (dubbo.tag=tag-b),或者路由到无 tag 的地址子集 (dubbo.tag 未设置),不会出现混调的情况。 + +## 开始之前 + +* [部署 Shop 商城项目](../#部署商场系统) +* 部署并打开 [Dubbo Admin](../.././../reference/admin/architecture/) + +## 任务详情 + +我们决定为商城系统建立一套完整的线上灰度验证环境,灰度环境和线上环境共享一套物理集群,需要我们通过 Dubbo 标签路由从逻辑上完全隔离出一套环境,做到灰度流量和线上流量互不干扰。 + +![gray1](/imgs/v3/tasks/gray/gray1.png) + +### 为商城搭建一套完全隔离的灰度环境 +首先,为 User、Detail、Comment、Order 几个应用都部署灰度环境实例,我们为这部分实例都带有 `env=gray` 的环境标。部署可以通过以下命令快速完成 + +```sh +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/10-task/dubbo-samples-shop/deploy/Gray.yml +``` + +{{% alert title="如何为机器或实例打标?" color="info" %}} + +**方法一:通过 `dubbo.labels` 或 `DUBBO_LABELS` 指定需要增加到 URL 中的键值对。** + +```properties +# JVM 参数 +-Ddubbo.labels = "tag1=value1; tag2=value2" + +# 环境变量 +DUBBO_LABELS = "tag1=value1; tag2=value2" +``` + +最终生成的 URL 会包含 tag1、tag2 两个 key: `dubbo://xxx?tag1=value1&tag2=value2` + +**方法二:通过 `dubbo.env.keys` 或 `DUBBO_ENV_KEYS` 指定要加载的环境变量,Dubbo 会尝试从环境变量加载每个 key。** + +```properties +# JVM 参数 +-Ddubbo.env.keys = "DUBBO_TAG1, DUBBO_TAG2" + +# 环境变量 +DUBBO_ENV_KEYS = "DUBBO_TAG1, DUBBO_TAG2" +``` + +最终生成的 URL 会包含 DUBBO_TAG1、DUBBO_TAG2 两个 key: `dubbo://xxx?DUBBO_TAG1=value1&DUBBO_TAG2=value2` +{{% /alert %}} + + +接下来,我们开始为几个应用分别增加标签规则,将刚刚部署的实例从普通流量实例隔离出来。 + +#### 操作步骤 + +1. 打开 Dubbo Admin 控制台 +2. 在左侧导航栏选择【服务治理】>【标签路由】 +3. 点击 "创建",输入 `shop-detail` 和流量隔离条件保存即可;重复为 `shop-comment`、`shop-order` 创建相同的隔离规则。 + +![Admin 灰度隔离环境设置截图](/imgs/v3/tasks/gray/gray_admin.png) + +以上规则为每个应用隔离出了一套独立的灰度环境,所有带有 `env=gray` 的标签都属于灰度环境。等待一小会确保规则下发完成,接下来就可以验证灰度流量在隔离环境中运行。 + +为了模拟灰度流量,我们为商城示例首页设置了一个 `Login To Gray` 的入口来模拟从灰度环境进入商城的流量,在真实环境中这可以通过在入口网关根据某些规则识别流量并自动打标实现。 + +![gray2](/imgs/v3/tasks/gray/gray2.png) + +通过 `Login To Gray` 登录后,之后所有请求 Detail、Comment、Order、User 服务的流量都会自动带有 `dubbo.tag=gray` 的标识,Dubbo 标签路由组件会识别这个标识,并将流量路由到刚才圈定的灰度环境(即所有 `env=gray` 的实例)。系统运行效果如下: + +![Admin 灰度隔离环境设置截图](/imgs/v3/tasks/gray/gray3.png) + +#### 规则详解 + +我们需要通过 Admin 为 `shop-detail`、`shop-comment`、`shop-order`、`shop-user` 四个应用分别设置标签归组规则,以 `shop-detail` 为例: + +**规则 key** :`shop-detail` + +**规则体** + +```yaml +configVersion: v3.0 +force: true +enabled: true +key: shop-detail +tags: + - name: gray + match: + - key: env + value: + exact: gray +``` + +其中,`name` 为灰度环境的流量匹配条件,只有请求上下文中带有 `dubbo.tag=gray` 的流量才会被转发到隔离环境地址子集。请求上下文可通过 `RpcContext.getClientAttachment().setAttachment("dubbo.tag", "gray")` 传递。 + +```yaml +name: gray +``` + +`match` 指定了地址子集筛选条件,示例中我们匹配了所有地址 URL 中带有 `env=gray` 标签的地址列表(商城示例中 v2 版本部署的实例都带已经被打上这个标签)。 + +```yaml +match: + - key: env + value: + exact: gray +``` + +`force` 指定了是否允许流量跳出灰度隔离环境,这决定了某个服务发现灰度隔离环境没有可用地址时的行为,默认值为 `false` 表示会 fallback 到不属于任何隔离环境 (不带标签) 的普通地址集(不会 fallback 到任何已经归属其他隔离环境的 ip 地址)。示例中设置 `froce: true` 表示当灰度环境地址子集为空时,服务调用失败(No provider exception)。 + +```yaml +force: true +``` + +## 清理 + +为了不影响其他任务效果,通过 Admin 删除或者禁用刚刚配置的流量隔离规则。 + +## 其他事项 + +除了示例中演示的动态环境划分,也可以在部署态指定实例所属流量标签(通过一个特殊的 key `dubbo.provider.tag` 实现),这样当实例启动成功后就已经被自动圈定在某个流量环境,具体配置方式可参见 [标签路由](/zh-cn/overview/core-features/traffic/tag-rule/) 说明。 + +通常,`dubbo.tag` 流量标的传递需要依赖全链路追踪工具的帮助,Dubbo 只会负责 A-B 的点对点标签传递,示例中也是通过在每次点对点 RPC 调用前重复设置达成的传递效果,在实践中,全链路灰度往往从 tag 设置进全链路上下文后自动启动,我们只需要扩展 Dubbo Filter 将全链路工具上下文中的 tag 标签读取并设置进 Dubbo 上下文即可实现全链路在 Dubbo 中的自动传递,具体可参见 [Dubbo 链路追踪集成示例](../../observability)。另外,除了 RPC 调用,在微服务体系的其他基础产品中也需要依赖全链路上下文保证灰度标识的传递,以保证完整的流量隔离环境。 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/mock.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/mock.md new file mode 100644 index 000000000000..f788b9ec8eda --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/mock.md @@ -0,0 +1,72 @@ +--- +aliases: + - /zh/overview/tasks/traffic-management/mock/ + - /zh-cn/overview/tasks/traffic-management/mock/ +description: "" +linkTitle: 服务降级 +title: 在大促之前对弱依赖调用进行服务降级 +type: docs +weight: 8 +--- + + + +由于微服务系统的分布式特性,一个服务往往需要依赖非常多的外部服务来实现某一项功能,因此,一个服务的稳定性不但取决于其自身,同时还取决于所有外部依赖的稳定性。我们可以根据这些依赖的重要程度将它们划分为强依赖和弱依赖:强依赖是指那些无论如何都要保证稳定性的服务,如果它们不可用则当前服务也就不可用;弱依赖项指当它们不可用之后当前服务仍能正常工作的依赖项,弱依赖不可用只是影响功能的部分完整性。 + +服务降级的核心目标就是针对这些弱依赖项。在弱依赖不可用或调用失败时,通过返回降级结果尽可能的维持功能完整性;另外,我们有时也会主动的屏蔽一些非关键弱依赖项的调用,比如在大促流量洪峰之前,通过预先设置一些有效的降级策略来短路部分依赖调用,来有效的提升流量高峰时期系统的整体效率和稳定性。 + +## 开始之前 + +* [部署 Shop 商城项目](../#部署商场系统) +* 部署并打开 [Dubbo Admin](../.././../reference/admin/architecture/) + +## 任务详情 + +正常情况下,商品详情页会展示来自顾客的商品评论信息。 + +![mock1.png](/imgs/v3/tasks/mock/mock1.png) + +评论信息的缺失在很多时候并不会影响用户浏览和购买商品,因此,我们定义评论信息属于商品详情页面的弱依赖。接下来,我们就模拟在大促前夕常用的一个策略,通过服务降级提前关闭商品详情页对于评论服务的调用(返回一些本地预先准备好的历史评论数据),来降低集群整体负载水位并提高响应速度。 + +![mock0.png](/imgs/v3/tasks/mock/mock0.png) + +### 通过降级规则短路 Comment 评论服务调用 + +评论数据由 Comment 应用的 `org.apache.dubbo.samples.CommentService` 服务提供,接下来我们就为 `CommentService` 配置降级规则。 + +#### 操作步骤 +1. 打开 Dubbo Admin 控制台 +2. 在左侧导航栏选择【流量管控】>【服务降级】 +3. 点击 "创建",输入服务 `org.apache.dubbo.samples.CommentService` 和降级规则。 + +![Admin 服务降级规则配置截图](/imgs/v3/tasks/mock/mock_admin.png) + +等待降级规则推送完成之后,刷新商品详情页面,发现商品评论信息已经变为我们预先设置的 "Mock Comment",因为商品详情页的 Comment 服务调用已经在本地短路,并没有真正的发送到后端服务提供者机器上。 + +![mock2.png](/imgs/v3/tasks/mock/mock2.png) + +再次刷新页面 + +#### 规则详解 + +**规则 key** :`org.apache.dubbo.samples.CommentService` + +**规则体** + +```yaml +configVersion: v3.0 +enabled: true +configs: + - side: consumer + parameters: + mock: force:return Mock Comment +``` + +## 清理 +为了不影响其他任务效果,通过 Admin 删除或者禁用刚刚配置的降级规则。 + +## 其他事项 + +服务降级功能也可以用于开发测试环境,由于微服务分布式的特点,不同的服务或应用之间都有相互依赖关系,因此,一个服务或应用很难不依赖其他服务而独立部署工作。但测试环境下并不是所有服务都是随时就绪的状态,这对于微服务强调的服务独立演进是一个很大的障碍,通过服务降级这个功能,我们可以模拟或短路应用对其他服务的依赖,从而可以让应用按照自己预期的行为 Mock 外部服务调用的返回结果。具体可参见 [Dubbo Admin 服务 Mock](../.././../reference/admin/mock/) 特性的使用方式。 + +Dubbo 的降级规则用来设置发生降级时的行为和返回值,而对于何时应该执行限流降级动作,即限流降级时机的判断并没有过多涉猎,这一点 Dubbo 通过集成更专业的限流降级产品如 Sentinel 进行了补全,可以配合 Dubbo 降级规则一起使用,具体可参见 [限流降级](/zh-cn/overview/core-features/traffic/circuit-breaking/) 文档。 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/region.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/region.md new file mode 100644 index 000000000000..b6939326d490 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/region.md @@ -0,0 +1,85 @@ +--- +aliases: + - /zh/overview/tasks/traffic-management/region/ + - /zh-cn/overview/tasks/traffic-management/region/ +description: 在 Dubbo-Admin 动态配置同机房/区域优先 +linkTitle: 同区域优先 +title: 同机房/区域优先 +type: docs +weight: 4 +--- + + + +为了保证服务的整体高可用,我们经常会采用把服务部署在多个可用区(机房)的策略,通过这样的冗余/容灾部署模式,当一个区域出现故障的时候,我们仍可以保证服务整体的可用性。 + +当应用部署在多个不同机房/区域的时候,应用之间相互调用就会出现跨区域的情况,而跨区域调用会增加响应时间,影响用户体验。同机房/区域优先是指应用调用服务时,优先调用同机房/区域的服务提供者,避免了跨区域带来的网络延时,从而减少了调用的响应时间。 + +## 开始之前 + +* [部署 Shop 商城项目](../#部署商场系统) +* 部署并打开 [Dubbo Admin](../.././../reference/admin/architecture/) + +## 任务详情 + +Detail 应用和 Comment 应用都有双区域部署,其中 Detail v1 与 Comment v1 部署在区域 Beijing,Detail v2 与 Comment v2 部署在区域 Hangzhou 区域。为了保证服务调用的响应速度,我们需要增加同区域优先的调用规则,确保 Beijing 区域内的 Detail v1 始终默认调用 Comment v1,Hangzhou 区域内的 Detail v2 始终调用 Comment v2。 + +![region1](/imgs/v3/tasks/region/region1.png) + +当同区域内的服务出现故障或不可用时,则允许跨区域调用。 + +![region2](/imgs/v3/tasks/region/region2.png) + + +### 配置 `Detail` 访问同区域部署的 `Comment` 服务 + +正常登录商城系统后,首页默认展示商品详情信息,多次刷新页面,发现商品详情 (description) 与评论 (comment) 选项会出现多个不同版本的组合,结合上面 Detail 和 Comment 的部署结构,这说明服务调用并没有遵循同区域优先的原则。 + +![region3](/imgs/v3/tasks/region/region3.png) + +因此,接下来我们需要添加同区域优先规则,保证: +* `hangzhou` 区域的 Detail 服务调用同区域的 Comment 服务,即 description v1 与 comment v1 始终组合展示 +* `beijing` 区域的 Detail 服务调用同区域的 Comment 服务,即 description v2 与 comment v2 始终组合展示 + +#### 操作步骤 +1. 登录 Dubbo Admin 控制台 +2. 在左侧导航栏选择【服务治理】 > 【条件路由】。 +3. 点击 "创建" 按钮,填入要启用同区域优先的服务如 `org.apache.dubbo.samples.CommentService` 与 `区域标识` 如 `region` 即可。 + +![Admin 同区域优先设置截图](/imgs/v3/tasks/region/region_admin.png) + +同区域优先开启后,此时再尝试刷新商品详情页面,可以看到 description 与 comment 始终保持 v1 或 v2 的同步。 + +![region4](/imgs/v3/tasks/region/region4.png) + +如果你将 `hangzhou` 区域部署的 Comment v2 版本全部下线,则 Detail v2 会自动的跨区域访问到 `beijing` 区域的 Comment v1。 + +#### 规则详解 + +**规则 key** :`org.apache.dubbo.samples.CommentService` + +**规则体** +```yaml +configVersion: v3.0 +enabled: true +force: false +key: org.apache.dubbo.samples.CommentService +conditions: + - '=> region = $region' +``` + +这里使用的是条件路由,`region` 为我们示例中的区域标识,会自动的识别当前发起调用的一方所在的区域值,当请求到达 `hangzhou` 区域部署的 Detail 后,从 Detail 发出的请求自动筛选 URL 地址中带有 `region=hangzhou` 标识的 Comment 地址,如果发现有可用的地址子集则将请求发出,如果没有匹配条件的地址,则随机发往任意可用区地址。 + +```yaml +conditions: + - '=> region = $region' +``` + +`force: false` 也是关键,这允许在同区域无有效地址时,可以跨区域调用服务。 + +## 清理 +为了不影响其他任务效果,通过 Admin 删除或者禁用刚刚配置的同区域流量规则。 + +## 其他事项 + +我们上面的示例并未纳入多区域之间注册中心的复杂性,如果每个区域部署有独立的注册中心,则多区域间的地址同步就是一个需要考虑的问题。对于这种场景,Dubbo 通过多注册&多订阅机制也提供了同区域优先的支持,具体可以参见[多注册&多订阅](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-registry/)相关文档。 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/retry.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/retry.md new file mode 100644 index 000000000000..263f481a6004 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/retry.md @@ -0,0 +1,75 @@ +--- +aliases: + - /zh/overview/tasks/traffic-management/retry/ + - /zh-cn/overview/tasks/traffic-management/retry/ +description: "" +linkTitle: 服务重试 +title: 通过重试提高服务调用成功率 +type: docs +weight: 2 +--- + + + +在服务初次调用失败后,通过重试能有效的提升总体调用成功率。但也要注意重试可能带来的响应时间增长,系统负载升高等,另外,重试一般适用于只读服务,或者具有幂等性保证的写服务。 + +## 开始之前 +* [部署 Shop 商城项目](../#部署商场系统) +* 部署并打开 [Dubbo Admin](../.././../reference/admin/architecture/) + +## 任务详情 + +成功登录商城项目后,商城会默认在首页展示当前登录用户的详细信息。 + +![retry1.png](/imgs/v3/tasks/retry/retry1.png) + +但有些时候,提供用户详情的 Dubbo 服务也会由于网络不稳定等各种原因变的不稳定,比如我们提供用户详情的 User 服务就很大概率会调用失败,导致用户无法看到账户的详细信息。 + +![retry2.png](/imgs/v3/tasks/retry/retry2.png) + +用户账户详情查询失败后的系统界面如下: + +![retry2.png](/imgs/v3/tasks/retry/retry4.png) + +商城为了获得带来更好的使用体验,用户信息的加载过程是异步的,因此用户信息加载失败并不会影响对整个商城页面的正常访问,但如果能始终展示完整的用户信息总能给使用者留下更好的印象。 +### 增加重试提高成功率 + +考虑到访问用户详情的过程是异步的(隐藏在页面加载背后),只要最终数据能加载出来,适当的增加等待时间并不是大的问题。因此,我们可以考虑通过对每次用户访问增加重试次数的方式,提高服务详情服务的整体访问成功率。 + +![retry3.png](/imgs/v3/tasks/retry/retry3.png) + +#### 操作步骤 +1. 打开 Dubbo Admin 控制台 +2. 在左侧导航栏选择【服务治理】>【动态配置】 +3. 点击 "创建",输入服务 `org.apache.dubbo.samples.UserService` 和失败重试次数如 `4` 即可。 + +![Admin 重试次数设置截图](/imgs/v3/tasks/retry/retry_admin.png) + +保存后,尝试多次刷新页面,发现用户详情数据总是能正常显示,虽然有时由于重试的缘故加载时间会明显变长。 + +#### 规则详解 + +**规则 key** :`org.apache.dubbo.samples.UserService` + +**规则体** + +```yaml +configVersion: v3.0 +enabled: true +configs: + - side: consumer + parameters: + retries: 5 +``` + +从 `UserService` 服务消费者视角(即 Frontend 应用)增加了调用失败后的重试次数。 + +```yaml +parameters: + retries: 5 +``` + +`side: consumer` 配置会将规则发送到服务消费方实例,所有 `UserService` 服务实例会基于新的 timeout 值进行重新发布,并通过注册中心通知给所有消费方。 + +## 清理 +为了不影响其他任务效果,通过 Admin 删除或者禁用刚刚配置的重试规则。 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/route.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/route.md new file mode 100644 index 000000000000..6f9074cad131 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/route.md @@ -0,0 +1,56 @@ +--- +description: Spring Boot +linkTitle: 基于条件的流量路由 +title: 基于条件的流量路由 +type: docs +weight: 5 +--- + +路由是 Dubbo 中的核心流量管控机制, 我们可以基于它实现金丝雀发布、按比例流量转发、同区域优先、全链路灰度等流量策略。Dubbo 中路由(Router)机制的设计与基本原理,内置的几种路由规则 + + +## 常用流量管控场景 +Dubbo 内置的流量策略非常的灵活,但同时也有一定的理解与使用成本,因此,我们根据总结了一些常用的使用场景,并给出了配置方法: + +| **场景** | **效果** | **作用对象** | **说明** | +| --- | --- | --- | --- | +| 超时时间 | | | | +| 访问日志 | | | | +| 调用重试 | | | | +| + | | | | +| | | | | +| | | | | +| | | | | + + +接下来,我们就以一个条件路由为例,来看一下如何使用 Dubbo 流量管控机制。 +## 一个条件路由示例 +需求非常的直观明了。 + +- 匹配这个条件的流量,转发到这一批机器 +- 匹配另一个条件的流量,转发到另一批机器 + +![画一张流量匹配和转发的图]() + +这在 Dubbo 中就是用 条件路由 来实现的,关于其详细工作原理我们在介绍中有详细讲解。 +在以上示例中,xxx 代表;yyy 代表 + +我们需要把规则下发到运行中的dubbo sdk,在 dubbo 体系中这是如下如下工作的。 + +![路由规则的分发与生效原理图]() + +一个 zk/nacos、下发一条规则,dubbo实例接收到规则推送,rpc调用过程中应用规则筛选,选出地址子集调用 + +{{% alert title="注意" color="info" %}} +传统 Nacos/Zookeeper 的微服务部署方案中,Dubbo 的路由规则配置中心存储并转发到 Dubbo SDK,而在 Kubernetes Service 或服务网格场景下,路由规则的存储与推送机制会有一些变化,具体请参考 [Kubernetes 最佳实践]()。 +{{% /alert %}} + +这时,如果我们对 xxx 服务发送一个请求, + +有一点非常 + +## 更多内容 +- 配置了路由规则不生效?[Dubbo 路由规则排查方法]() +- 当前的路由规则不够灵活,无法达到效果?来看看 [脚本路由]() 吧 +- 您还可以通过 [扩展 Dubbo 的路由实现]() 定制自己的流量策略 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/timeout.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/timeout.md new file mode 100644 index 000000000000..eb11f1c5428f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/timeout.md @@ -0,0 +1,72 @@ +--- +aliases: + - /zh/overview/tasks/traffic-management/timeout/ + - /zh-cn/overview/tasks/traffic-management/timeout/ +description: 在 Dubbo-Admin 动态调整服务超时时间 +linkTitle: 调整超时时间 +title: 动态调整服务超时时间 +type: docs +weight: 2 +--- + +Dubbo 提供动态调整服务超时时间的能力,在无需重启应用的情况下调整服务的超时时间,这对于临时解决一些服务上下游依赖不稳定而导致的调用失败问题非常有效。 + +## 开始之前 +* [部署 Shop 商城项目](../#部署商场系统) +* 部署并打开 [Dubbo Admin](../.././../reference/admin/architecture/) + +## 任务详情 + +商城项目通过 `org.apache.dubbo.samples.UserService` 提供用户信息管理服务,访问 `http://localhost:8080/` 打开商城并输入任意账号密码,点击 `Login` 即可以正常登录到系统。 + +![timeout1.png](/imgs/v3/tasks/timeout/timeout1.png) + +有些场景下,User 服务的运行速度会变慢,比如存储用户数据的数据库负载过高导致查询变慢,这时就会出现 `UserService` 访问超时的情况,导致登录失败。 + +![timeout2.png](/imgs/v3/tasks/timeout/timeout2.png) + +在示例系统中,可通过下图 `Timeout Login` 模拟突发的 `UserService` 访问超时异常 + +![timeout4.png](/imgs/v3/tasks/timeout/timeout4.png) + +### 通过规则动态调整超时时间 + +为了解决突发的登录超时问题,我们只需要适当增加 `UserService` 服务调用的等待时间即可。 + +![timeout3.png](/imgs/v3/tasks/timeout/timeout3.png) + +#### 操作步骤 +1. 打开 Dubbo Admin 控制台 +2. 在左侧导航栏选择【服务治理】>【动态配置】 +3. 点击 "创建",输入服务 `org.apache.dubbo.samples.UserService` 和新的超时时间如 `2000` 即可。 + +![Admin 超时时间设置截图](/imgs/v3/tasks/timeout/timeout_admin.png) + +保存后,再次点击 `Timeout Login`,此时在经过短暂的等待后系统可以正常登录。 + +#### 规则详解 + +**规则 key** :`org.apache.dubbo.samples.UserService` + +**规则体** + +```yaml +configVersion: v3.0 +enabled: true +configs: + - side: provider + parameters: + timeout: 2000 +``` + +从 `UserService` 服务提供者视角,将超时时间总体调整为 2s。 + +```yaml +parameters: + timeout: 2000 +``` + +`side: provider` 配置会将规则发送到服务提供方实例,所有 `UserService` 服务实例会基于新的 timeout 值进行重新发布,并通过注册中心通知给所有消费方。 + +## 清理 +为了不影响其他任务效果,通过 Admin 删除或者禁用刚刚配置的超时规则。 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/weight.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/weight.md new file mode 100644 index 000000000000..095fb25d7852 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/weight.md @@ -0,0 +1,94 @@ +--- +aliases: + - /zh/overview/tasks/traffic-management/weight/ + - /zh-cn/overview/tasks/traffic-management/weight/ +description: "" +linkTitle: 权重比例 +title: 基于权重值的比例流量转发 +type: docs +weight: 7 +--- + + + +Dubbo 提供了基于权重的负载均衡算法,可以实现按比例的流量分布:权重高的提供者机器收到更多的请求流量,而权重低的机器收到相对更少的流量。 + +以基于权重的流量调度算法为基础,通过规则动态调整单个或一组机器的权重,可以在运行态改变请求流量的分布,实现动态的按比例的流量路由,这对于一些典型场景非常有用。 +* 当某一组机器负载过高,通过动态调低权重可有效减少新请求流入,改善整体成功率的同时给高负载机器提供喘息之机。 +* 刚刚发布的新版本服务,先通过赋予新版本低权重控制少量比例的流量进入,待验证运行稳定后恢复正常权重,并完全替换老版本。 +* 服务多区域部署或非对等部署时,通过高、低权重的设置,控制不同部署区域的流量比例。 + +## 开始之前 + +* [部署 Shop 商城项目](../#部署商场系统) +* 部署并打开 [Dubbo Admin](../.././../reference/admin/architecture/) + +## 任务详情 + +示例项目中,我们发布了 Order 服务 v2 版本,并在 v2 版本中优化了下单体验:用户订单创建完成后,显示订单收货地址信息。 + +![weight2.png](/imgs/v3/tasks/weight/weight2.png) + +现在如果你体验疯狂下单 (不停的点击 "Buy Now"),会发现 v1 与 v2 总体上是 50% 概率出现,说明两者目前具有相同的默认权重。但我们为了保证商城系统整体稳定性,接下来会先控制引导 20% 流量到 v2 版本,80% 流量依然访问 v1 版本。 + +![weight1.png](/imgs/v3/tasks/weight/weight1.png) + +### 实现 Order 服务 80% v1 、20% v2 的流量分布 +在调整权重前,首先我们要知道 Dubbo 实例的权重 (weight) 都是绝对值,每个实例的默认权重 (weight) 是 100。举个例子,如果一个服务部署有两个实例:实例 A 权重值为 100,实例 B 权重值为 200,则 A 和 B 收到的流量分布为 1:2。 + +接下来,我们就开始调整订单服务访问 v1 和 v2 的流量比例,订单创建服务由 `org.apache.dubbo.samples.OrderService` 接口提供,接下来通过动态规则调整新版本 `OrderService` 实例的权重值。 + +#### 操作步骤 +1. 打开 Dubbo Admin 控制台 +2. 在左侧导航栏选择【服务治理】>【动态配置】 +3. 点击 "创建",输入要调整的 `org.apache.dubbo.samples.OrderService` 、目标实例匹配条件和权重值。 + +![Admin 权重比例设置截图](/imgs/v3/tasks/weight/weight_admin.png) + +再次疯狂点击 "Buy Now" 尝试多次创建订单,现在大概只有 20% 的机会看到 v2 版本的订单详情信息 + +在确定 v2 版本的 Order 服务稳定运行后,进一步的增加 v2 权重,直到所有老版本服务都被新版本替换掉,这样就完成了一次稳定的服务版本升级。 + +#### 规则详解 + +**规则 key** :`org.apache.dubbo.samples.UserService` + +**规则体** + +```yaml +configVersion: v3.0 +scope: service +key: org.apache.dubbo.samples.OrderService +configs: + - side: provider + match: + param: + - key: orderVersion + value: + exact: v2 + parameters: + weight: 25 +``` + +以下匹配条件表示权重规则对所有带有 `orderVersion=v2` 标签的实例生效(Order 服务的所有 v2 版本都已经带有这个标签)。 + +```yaml +match: + param: + - key: orderVersion + value: + exact: v2 +``` + +`weight: 25` 是因为 v1 版本的默认权重是 `100`,这样 v2 和 v1 版本接收到的流量就变成了 25:100 即 1:4 的比例。 + +```yaml +parameters: + weight: 25 +``` + +## 清理 +为了不影响其他任务效果,通过 Admin 删除或者禁用刚刚配置的权重规则。 + +## 其他事项 +`weight=0` diff --git a/content/en/overview/mannual/java-sdk/tasks/trasaction/_index.md b/content/en/overview/mannual/java-sdk/tasks/trasaction/_index.md new file mode 100755 index 000000000000..1a2f320d9e6c --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/trasaction/_index.md @@ -0,0 +1,9 @@ +--- +description: 分布式事务 +hide: true +linkTitle: 分布式事务 +no_list: true +title: 分布式事务 +type: docs +weight: 7 +--- diff --git a/content/en/overview/mannual/java-sdk/tasks/trasaction/distributed-transaction.md b/content/en/overview/mannual/java-sdk/tasks/trasaction/distributed-transaction.md new file mode 100644 index 000000000000..33dd863f54ba --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/trasaction/distributed-transaction.md @@ -0,0 +1,159 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction/ + - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/distributed-transaction/ +description: "使用 Seata 解决 Dubbo 服务数据一致性问题,支持分布式事务。" +linkTitle: 使用Seata让Dubbo支持分布式事务 +title: 使用 Seata 支持分布式事务 +type: docs +weight: 42 +--- +本示例演示如何使用 Apache Seata 实现 Dubbo 分布式事务功能,保证数据一致性。 + +Apache Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。 +在Dubbo中集成Seata实现分布式事务非常方便,只需简单几步即可完成,本文将通过一个示例带你快速体验,示例总体架构图如下: + +![seata-flow](/imgs/docs3-v2/java-sdk/seata/flow.png) + +开始前,请先完成以下内容: + +1. 下载示例源码 + ```shell + git clone --depth=1 https://github.com/apache/dubbo-samples.git + ``` + + 进入示例源码目录: + ```shell + cd dubbo-samples/2-advanced/dubbo-samples-seata + ``` + +2. 下载最新版的[seata-server二进制包](https://seata.apache.org/zh-cn/unversioned/download/seata-server)至本地。 + +## 步骤 1:建立数据库并初始化相关测试数据 +- 本文将使用MySQL 5.7 (更多支持的数据库可在文末查看附录)。 +进入dubbo-samples-seata的script目录,找到dubbo_biz.sql和undo_log.sql两个数据库脚本文件,内容如下: + +undo_log.sql是Seata AT 模式需要 `UNDO_LOG` 表 +```sql +-- for AT mode you must to init this sql for you business database. the seata server not need it. +CREATE TABLE IF NOT EXISTS `undo_log` +( + `branch_id` BIGINT NOT NULL COMMENT 'branch transaction id', + `xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id', + `context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization', + `rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info', + `log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status', + `log_created` DATETIME(6) NOT NULL COMMENT 'create datetime', + `log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime', + UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`) + ) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='AT transaction mode undo table'; +ALTER TABLE `undo_log` ADD INDEX `ix_log_created` (`log_created`); + +``` +dubbo_biz.sql是示例业务表以及初始化数据 + +```sql +DROP TABLE IF EXISTS `stock_tbl`; +CREATE TABLE `stock_tbl` +( + `id` int(11) NOT NULL AUTO_INCREMENT, + `commodity_code` varchar(255) DEFAULT NULL, + `count` int(11) DEFAULT 0, + PRIMARY KEY (`id`), + UNIQUE KEY (`commodity_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +DROP TABLE IF EXISTS `order_tbl`; +CREATE TABLE `order_tbl` +( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` varchar(255) DEFAULT NULL, + `commodity_code` varchar(255) DEFAULT NULL, + `count` int(11) DEFAULT 0, + `money` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +DROP TABLE IF EXISTS `account_tbl`; +CREATE TABLE `account_tbl` +( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` varchar(255) DEFAULT NULL, + `money` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +---INITIALIZE THE ACCOUNT TABLE +INSERT INTO account_tbl(`user_id`,`money`) VALUES('ACC_001','1000'); +---INITIALIZE THE STOCK TABLE +INSERT INTO stock_tbl(`commodity_code`,`count`) VALUES('STOCK_001','100'); + +``` +### 请依次执行以下操作: +* 1.1 创建seata数据库(实际业务场景中会使用不同的数据库,本文为了方便演示仅创建一个数据库,所有的表都在该数据库中创建) +* 1.2 执行undo_log.sql表中的脚本完成AT模式所需的undo_log表创建 +* 1.3 执行dubbo_biz.sql表中的脚本完成示例业务表创建以及测试数据的初始化 + +## 步骤 2:更新spring-boot应用配置中的数据库连接信息 + +请将以下3个子模块的数据库连接信息更新为你的信息,其他配置无需更改,至此,客户端的配置已经完毕。 + +* dubbo-samples-seata-account +* dubbo-samples-seata-order +* dubbo-samples-seata-stock +```yaml +url: jdbc:mysql://127.0.0.1:3306/seata?serverTimezone=Asia/Shanghai&useSSL=false&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useOldAliasMetadataBehavior=true +username: root +password: 123456 +``` + +## 步骤 3:启动Seata-Server +- 本文使用的是Seata-Server V2.0.0版本。 + +请将下载的Seata-Server二进制包解压,并进入bin目录,然后执行以下命令即可启动Seata-Server。 + +如果你是Mac OS 或者Linux操作系统,请执行: +``` +./seata-server.sh +``` +或者你是Windows操作系统,请执行: +``` +./seata-server.bat +``` + +## 步骤 4:启动示例 + +一切准备就绪,开始启动示例 + +### 请依次启动以下子项目: +* 4.1 Account Service +* 4.2 Order Service +* 4.3 Stock Service +* 4.4 Business Service + +## 步骤 5:查看分布式事务执行结果 +通过访问以下链接,可以测试分布式事务成功提交流程: + +http://127.0.0.1:9999/test/commit?userId=ACC_001&commodityCode=STOCK_001&orderCount=1 + +**分布式事务成功提交时,业务表的数据将正常更新,请注意观察数据库表中的数据。** + +通过访问以下链接,可以测试分布式事务失败回滚流程: + +http://127.0.0.1:9999/test/rollback?userId=ACC_001&commodityCode=STOCK_001&orderCount=1 + +**分布式事务失败回滚时,业务表的数据将没有任何改变,请注意观察数据库表中的数据。** + +## 附录 +* 支持的事务模式:Seata目前支持AT、TCC、SAGA、XA等模式,详情请访问[Seata官网](https://seata.apache.org/zh-cn/docs/user/mode/at)进行了解 +* 支持的配置中心:Seata支持丰富的配置中心,如zookeeper、nacos、consul、apollo、etcd、file(本文使用此配置中心,无需第三方依赖,方便快速演示),详情请访问[Seata配置中心](https://seata.apache.org/zh-cn/docs/user/configuration/)进行了解 +* 支持的注册中心:Seata支持丰富的注册中心,如eureka、sofa、redis、zookeeper、nacos、consul、etcd、file(本文使用此注册中心,无需第三方依赖,方便快速演示),详情请访问[Seata注册中心](https://seata.apache.org/zh-cn/docs/user/registry/)进行了解 +* 支持的部署方式:直接部署、Docker、K8S、Helm等部署方式,详情请访问[Seata部署方式](https://seata.apache.org/zh-cn/docs/ops/deploy-guide-beginner)进行了解 +* 支持的API:Seata的API分为两大类:High-Level API 和 Low-Level API,详情请访问[Seata API](https://seata.apache.org/zh-cn/docs/user/api)进行了解 +* 支持的数据库:Seata支持MySQL、Oracle、PostgreSQL、TiDB、MariaDB等数据库,不同的事务模式会有差别,详情请访问[Seata支持的数据库](https://seata.apache.org/zh-cn/docs/user/datasource)进行了解 +* 支持ORM框架:Seata 虽然是保证数据一致性的组件,但对于 ORM 框架并没有特殊的要求,像主流的Mybatis,Mybatis-Plus,Spring Data JPA, Hibernate等都支持。这是因为ORM框架位于JDBC结构的上层,而 Seata 的 AT,XA 事务模式是对 JDBC 标准接口操作的拦截和增强。详情请访问[Seata支持的ORM框架](https://seata.apache.org/zh-cn/docs/user/ormframework)进行了解 +* 支持的微服务框架:Seata目前支持Dubbo、gRPC、hsf、http、motan、sofa等框架,同时seata提供了丰富的拓展机制,理论上可以支持任何微服务框架。详情请访问[Seata支持的微服务框架](https://seata.apache.org/zh-cn/docs/user/microservice)进行了解 +* SQL限制:Seata 事务目前支持 INSERT、UPDATE、DELETE 三类 DML 语法的部分功能,这些类型都是已经经过Seata开源社区的验证。SQL 的支持范围还在不断扩大,建议在本文限制的范围内使用。详情请访问[Seata SQL限制](https://seata.apache.org/zh-cn/docs/user/sqlreference/sql-restrictions)进行了解 diff --git a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/_index.md b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/_index.md new file mode 100755 index 000000000000..96c7baa73055 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/overview/tasks/troubleshoot/ + - /zh-cn/overview/tasks/troubleshoot/ +description: 对常见的 Dubbo 异常场景进行排查的思路 +linkTitle: 故障排查 +title: 故障排查 +type: docs +weight: 100 +--- diff --git a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/no-provider.md b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/no-provider.md new file mode 100644 index 000000000000..50b70e0da9d7 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/no-provider.md @@ -0,0 +1,601 @@ +--- +aliases: + - /zh/overview/tasks/troubleshoot/no-provider/ + - /zh-cn/overview/tasks/troubleshoot/no-provider/ +description: 在 Dubbo 抛出地址找不到异常的时候的排查思路 +linkTitle: 地址找不到异常 +title: 地址找不到异常 +type: docs +weight: 2 +--- + + + +在开发与生产部署过程中,由于 Dubbo 是一个需要基于服务发现功能进行调用的框架,很容易由于各种客观原因出现 `No Provder` 的异常,本文旨在通过体系化的排查思路,让您能够在异常的时候快速定位原因并解决。 + +``` +java.lang.IllegalStateException: Failed to check the status of the service org.apache.dubbo.samples.api.GreetingsService. No provider available for the service org.apache.dubbo.samples.api.GreetingsService from the url consumer://*** to the consumer 30.221.146.226 use dubbo version 3.2.0-beta.4 +``` + +``` +Exception in thread "main" org.apache.dubbo.rpc.RpcException: No provider available from registry 127.0.0.1:2181 for service org.apache.dubbo.samples.api.GreetingsService on consumer 30.221.146.226 use dubbo version 3.2.0-beta.4, please check status of providers(disabled, not registered or in blacklist). +``` + +## 一句话总结 +服务找不到时先自查服务是否已经开发完部署了,然后在注册中心中确认是否已经注册,如果注册检查服务端发布情况、如果未注册检查消费端订阅情况,中间任何一步出问题都会导致异常。 + +## 排查思路全览 + +![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676536783437-2e3853cf-68bd-43b1-bc66-81dfc1c4585b.jpeg) + +## 详细教程 +### 1 识别异常的服务以及订阅模式 +为了后续正确定位排查的方向,第一步需要先确认有报错的服务名。 + +![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676616010488-a31451e7-e34e-44b8-ba16-bf6e3f162e33.png) +![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676615807014-5413111b-109e-4976-a25b-d15fe75b314d.png) +![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676616273793-f0bd82b5-bbc6-483f-b945-abe707556b37.png) +![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676616314724-042f1157-cdee-4aaa-b1ac-355c6f1b53e4.png) + +如上图所示,常见的地址找不到异常报错中会包括对应的服务名,格式有以下两种。 + +``` +No provider available for the service ${serviceName} + +No provider available from registry ${registryAddress} for service ${serviceName} +``` + +在这个报错日志中可以提取出报错对应的服务名。此处需要注意关注对应的分组与版本号,通常格式如下: + +``` +${group}/${interfaceName}:${version} +``` + +除了获取报错对应的服务名外,还需要获取该服务的订阅模式。(默认通常为 `APPLICATION_FIRST` 也即是双订阅模式) + +如一下日志所示,可以在 Dubbo 的日志中搜索 `[DUBBO] Succeed Migrated to` 关键字,获取对应的订阅模式。 + +``` +[26/02/23 03:27:07:007 CST] main INFO migration.MigrationRuleHandler: [DUBBO] Succeed Migrated to APPLICATION_FIRST mode. Service Name: org.apache.dubbo.samples.api.GreetingsService, dubbo version: 3.2.0-beta.6-SNAPSHOT, current host: 192.168.31.5 +``` + +当前 Dubbo 共有三种订阅模式: + +- FORCE_INTERFACE:仅订阅接口级服务发现模型的数据,这种数据为 2.7.x 及之前的 Dubbo 版本发布的数据模型。 +- FORCE_APPLICATION:仅应用级服务发现模型的数据,这种数据为 3.x 版本开始 Dubbo 为云原生大规模部署的应用所设计的数据模型。 +- APPLICATION_FIRST:同时订阅接口级服务发现模型和应用级服务发现模型的数据,任何一种模型下有数据都可以调用,默认优先使用应用级服务发现模型的数据。 + +如果该有问题的服务的订阅模式为 FORCE_INTERFACE,则后续排查中需要检查接口级的地址是否正常发布;如果为 FORCE_APPLICATION 则需要检查应用级地址是否正常发布;如果为 APPLICATION_FIRST 则任意一种地址模型发布都可以。 + +### 2 查询注册中心是否存在服务 +#### 2.1 通过 Dubbo Admin 查询(推荐) +如果您的集群中部署了 Dubbo Admin,可以直接 Dubbo Admin 的控制台中的“服务查询”模块查询该服务的注册情况。 +![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676619545350-62c71bca-44c2-4d28-8660-969e2a24dccb.png) +![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676620038647-54bcbafb-1ee1-470f-8e48-8017dd7321dc.png) + +如上图所示,请结合前述第 1 步中服务发现模型确认是否能查询到预期的服务端。 +如果能查到,请跳转到第 x 步继续排查,如果不能查到请跳转到第 3 步进行排查。 + +#### 2.2 通过注册中心查询 +如果您没有部署 Dubbo Admin,则可以通过注册中心直接查询原始数据。 + +#### 2.2.1 Nacos 注册中心 +1)接口级服务发现 +在接口级服务发现模型下,可以直接通过 Nacos 控制台查询服务信息,入口为 "服务管理" - "服务列表",输入服务名在服务名称一栏搜索即可查询。 + +注:Nacos 注册中心下,Dubbo 服务名与 Nacos 服务名映射关系为 `providers:${interfaceName}:${version}:${group}`,如 `dev/com.example.DemoService:1.0.0` 映射为 `providers:com.example.DemoService:1.0.0:dev`。 + +![img](/imgs/docs3-v2/java-sdk/troubleshoot/1677399028899-c36dbb0e-a6a9-42f1-85f8-a746410588ec.png) + +如上图所示,请结合前述第 1 步中服务发现模型确认是否能查询到预期的服务端。 +如果能查到,请跳转到第 x 步继续排查,如果不能查到请跳转到第 3 步进行排查。 + +2)应用级服务发现 +在应用级服务发现模型下,需要先查询服务映射的信息,入口为 "配置管理" - "配置列表",Data ID 为接口名,Group 为 `mapping`。 + +注:查询服务映射时 Data ID 为接口名,不需要填写分组、版本号。 + +![img](/imgs/docs3-v2/java-sdk/troubleshoot/1677399521159-399758bd-09c9-4365-a2e3-960fadbf93a8.png) + +![img](/imgs/docs3-v2/java-sdk/troubleshoot/1677399582939-a92dbc6a-e197-418d-899e-a13cbd958ec2.png) + +如上图所示,查询该配置的配置内容中是否存在预期的应用名。 +如果能查到,请以该应用名为服务名称继续排查,如果不能查到请跳转到第 3 步进行排查。 + +在查询到应用名以后,需要进一步查询服务信息,入口为 "服务管理" - "服务列表",输入服务名在服务名称一栏搜索即可查询。 + +注:此处的服务名称为上一步查询出的应用名,非接口名。 + +![img](/imgs/docs3-v2/java-sdk/troubleshoot/1677399702538-0d198aa5-dd40-49ec-a5ad-b3615c4e9d6a.png) + +如上图所示,请结合前述第 1 步中服务发现模型确认是否能查询到预期的服务端。 +如果能查到,请跳转到第 x 步继续排查,如果不能查到请跳转到第 3 步进行排查。 + +#### 2.2.2 通过 Zookeeper 注册中心查询 + +1)接口级服务发现 +在接口级服务发现模型下,可以直接通过 Zookeeper 命令行查询服务信息,路径为 `/dubbo/${interfaceName}/providers`。 + +注:Zookeeper 注册中心中路径上为接口名,分组和版本号在地址参数上,如果您指定了服务的分组或版本号,需要检查每个地址的参数。 + +```bash +[zk: localhost:2181(CONNECTED) 1] ls /dubbo/org.apache.dubbo.samples.api.GreetingsService/providers +[dubbo%3A%2F%2F30.221.144.195%3A20880%2Forg.apache.dubbo.samples.api.GreetingsService%3Fanyhost%3Dtrue%26application%3Dfirst-dubbo-provider%26background%3Dfalse%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26environment%3Dproduct%26executor-management-mode%3Ddefault%26file-cache%3Dtrue%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.samples.api.GreetingsService%26methods%3DsayHi%26pid%3D37828%26prefer.serialization%3Dfastjson2%2Chessian2%26release%3D3.2.0-beta.6-SNAPSHOT%26service-name-mapping%3Dtrue%26side%3Dprovider%26timestamp%3D1677463548624] +``` + +如上所示,请结合前述第 1 步中服务发现模型确认是否能查询到预期的服务端。 +如果能查到,请跳转到第 x 步继续排查,如果不能查到请跳转到第 3 步进行排查。 + +2)应用级服务发现 +在应用级服务发现模型下,需要先查询服务映射的信息,可以通过 Zookeeper 的命令行工具查询,路径为 `/dubbo/mapping/${interfaceName}` + +注:查询服务映射时 interfaceName 为接口名,不需要填写分组、版本号。 + +```bash +[zk: localhost:2181(CONNECTED) 6] get /dubbo/mapping/org.apache.dubbo.samples.api.GreetingsService +first-dubbo-provider +``` + +如上所示,查询该配置的配置内容中是否存在预期的应用名。 +如果能查到,请以该应用名为服务名称继续排查,如果不能查到请跳转到第 3 步进行排查。 + +在查询到应用名以后,需要进一步查询服务信息,可以直接通过 Zookeeper 命令行查询服务信息,路径为 `/services/${interfaceName}`。 + +注:此处的服务名称为上一步查询出的应用名,非接口名。 + +```bash +[zk: localhost:2181(CONNECTED) 7] ls /services/first-dubbo-provider +[30.221.144.195:20880] +``` + +如上图所示,请结合前述第 1 步中服务发现模型确认是否能查询到预期的服务端。 +如果能查到,请跳转到第 x 步继续排查,如果不能查到请跳转到第 3 步进行排查。 + +注:如果采用了应用级服务发现模型后检查消费端地址仍找不到则可能是该服务端没有发布对应的服务,请从第 3 步开始排查。 + +### 3 检查服务端是否已经发布服务 +#### 3.1 通过 Dubbo QoS 查询(推荐) +在 Dubbo 应用启动的时候,默认会在本地的 22222 端口发布一个 QoS 服务,可以用于运行时查询节点的状态。通常,如果没有独立配置 `dubbo.application.qos-enable` 或者 `dubbo.application.qos-port` 都可以基于本方法查询服务的信息。 + +找到预期发布该服务的机器,登陆到其控制台,执行 `telnet 127.0.0.1 22222` 和 `ls`: +```bash +➜ telnet 127.0.0.1 22222 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>ls +As Provider side: ++------------------------------------------------------------------------------------+---------------------+ +| Provider Service Name | PUB | ++------------------------------------------------------------------------------------+---------------------+ +| org.apache.dubbo.samples.api.GreetingsService |nacos-A(Y)/nacos-I(Y)| ++------------------------------------------------------------------------------------+---------------------+ +|DubboInternal - first-dubbo-provider/org.apache.dubbo.metadata.MetadataService:1.0.0| | ++------------------------------------------------------------------------------------+---------------------+ +As Consumer side: ++---------------------+---+ +|Consumer Service Name|NUM| ++---------------------+---+ + +dubbo> + +``` + +如果机器上没有 `telnet` 也可以通过 `cURL` 发起调用,请求地址为 `http://127.0.0.1:22222/ls`: +```bash +➜ curl http://127.0.0.1:22222/ls +As Provider side: ++------------------------------------------------------------------------------------+---------------------+ +| Provider Service Name | PUB | ++------------------------------------------------------------------------------------+---------------------+ +| org.apache.dubbo.samples.api.GreetingsService |nacos-A(Y)/nacos-I(Y)| ++------------------------------------------------------------------------------------+---------------------+ +|DubboInternal - first-dubbo-provider/org.apache.dubbo.metadata.MetadataService:1.0.0| | ++------------------------------------------------------------------------------------+---------------------+ +As Consumer side: ++---------------------+---+ +|Consumer Service Name|NUM| ++---------------------+---+ +``` + +注:默认情况下 `ls` 命令仅允许本机调用,如果您无法登陆对应的机器,请参考 3.2 通过日志进行检查。 + +如上结果所示,请检查在 `As Provider side` 一栏中是否存在您所发布的服务名,如果存在则代表该服务已经发布。 +第二列 `PUB` 中的信息为该服务的注册情况,格式为 `${registryName}-${registerType}(${status})`。`registerType` 有两种情况,分别是 `A` 和 `I` 代表着应用级服务发现模型和接口级服务发现模型。可以通过该信息判断服务发布的情况。 + +如果您无法找到您所发布的服务,请检查以下清单: + +1. 该服务是否已经添加到该机器所对应的运行代码中 +2. 该服务是否已经正确配置到 Dubbo 环境中,请检查如 `@EnableDubbo`、`@DubboService` 或者 XML 等配置是否正确 + +如果您找到了您所发布的服务,但是服务状态是 `N`,请检查以下清单: + +1. 该服务配置了 `register=false` +2. 是否有外部的命令调用了 `offline` +3. 应用是否启动成功(包括但不限于如 Tomcat、Spring 的启动状态) + +如果您找到了您所发布的服务,但是对应的服务发现模型错误,请检查以下清单: + +1. 注册中心地址是否配置了 `registry-type=service` +2. 是否配置了应用级的注册模式,如 `dubbo.application.register-type` + +如果您找到了您所发布的服务,且对应的服务发现模型下服务状态是 `Y`,请跳转到第 4 步进行排查。 + +#### 3.2 通过日志检查 +如果您由于各种原因无法使用 Dubbo QoS,可以在对应机器的日志上搜索 `[DUBBO] Export dubbo service ${serviceName}` 来检查服务是否已经发布。 + +```bash +[26/02/23 04:34:41:041 CST] main INFO config.ServiceConfig: [DUBBO] Export dubbo service org.apache.dubbo.samples.api.GreetingsService to local registry url : injvm://***, dubbo version: 3.1.7, current host: 192.168.31.5 +``` + +如上所示,则代表着该服务已经发布,如果您无法找到您所发布的服务,请检查以下清单: + +1. 该服务是否已经添加到该机器所对应的运行代码中 +2. 该服务是否已经正确配置到 Dubbo 环境中,请检查如 `@EnableDubbo`、`@DubboService` 或者 XML 等配置是否正确 + +在确定了服务已经发布了以后,可以在对应机器的日志上搜索 `[DUBBO] Register dubbo service ${serviceName} to registry ${registryAddress}` 来检查服务是否已经注册。 + +```bash +[26/02/23 04:34:41:041 CST] main INFO config.ServiceConfig: [DUBBO] Register dubbo service org.apache.dubbo.samples.api.GreetingsService url dubbo://*** to registry 127.0.0.1:8848, dubbo version: 3.1.7, current host: 192.168.31.5 +``` + +如上所示,则代表着该服务已经注册,如果您无法找到相关日志,请检查以下清单: + +1. 该服务配置了 `register=false` +2. 是否有外部的命令调用了 `offline` +3. 应用是否启动成功(包括但不限于如 Tomcat、Spring 的启动状态) + +如果您找到了您所注册的服务,请跳转到第 4 步进行排查。 + +### 4 检查服务端注册中心配置 +#### 4.1 通过 Dubbo Admin 查询(推荐) +注:Dubbo 3.2.0 及以上版本支持 + +在 Dubbo 应用启动的时候,默认会在本地的 22222 端口发布一个 QoS 服务,可以用于运行时查询节点的状态。通常,如果没有独立配置 `dubbo.application.qos-enable` 或者 `dubbo.application.qos-port` 都可以基于本方法查询服务的信息。 + +找到预期发布该服务的机器,登陆到其控制台,执行 `telnet 127.0.0.1 22222` 和 `getConfig RegistryConfig`: +```bash +➜ telnet 127.0.0.1 22222 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>getConfig RegistryConfig +ApplicationModel: Dubbo Application[1.1](first-dubbo-provider) +RegistryConfig: null + + +``` + +如上述结果所示,请检查对应的注册中心配置是否符合预期,如果不符合请修改对应的配置。 +如果第 3 步和第 4 步检查均符合预期,则该服务应该可以在第 2 步的注册中心中查询到,如果查询不到请检查注册中心是否工作正常。 + +注:`getConfig` 命令仅允许本机调用,如果您无法登陆对应的机器,请参考 4.2 通过日志进行检查。 + +#### 4.2 通过日志检查 +如果您由于各种原因无法使用 Dubbo QoS,可以在对应机器的日志上搜索 `[DUBBO] , dubbo version: 3.2.0-beta.6-SNAPSHOT, current host: 30.221.144.195 +``` + +如上述结果所示,请检查对应的注册中心配置是否符合预期,如果不符合请修改对应的配置。 +如果第 3 步和第 4 步检查均符合预期,则该服务应该可以在第 2 步的注册中心中查询到,如果查询不到请检查注册中心是否工作正常。 + +### 5 检查服务端网络配置 + +在服务端发布了服务以后,请检查网络防火墙(iptables、ACL 等)是否允许 Dubbo 端口进行通信,默认 Dubbo 协议端口号为 20880、Triple 协议端口号为 50051。具体端口号可以从第 2 步注册中心中的信息获取。 + +测试方式:在消费端机器直接 telnet 远程的端口。 + +### 6 检查消费端是否订阅服务 +#### 6.1 通过 Dubbo QoS 查询(推荐) +在 Dubbo 应用启动的时候,默认会在本地的 22222 端口发布一个 QoS 服务,可以用于运行时查询节点的状态。通常,如果没有独立配置 `dubbo.application.qos-enable` 或者 `dubbo.application.qos-port` 都可以基于本方法查询服务的信息。 + +找到预期发布该服务的机器,登陆到其控制台,执行 `telnet 127.0.0.1 22222` 和 `ls`: +```bash +➜ telnet 127.0.0.1 22222 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>ls +As Provider side: ++------------------------------------------------------------------------------------+---+ +| Provider Service Name |PUB| ++------------------------------------------------------------------------------------+---+ +|DubboInternal - first-dubbo-consumer/org.apache.dubbo.metadata.MetadataService:1.0.0| | ++------------------------------------------------------------------------------------+---+ +As Consumer side: ++---------------------------------------------+---------------------+ +| Consumer Service Name | NUM | ++---------------------------------------------+---------------------+ +|org.apache.dubbo.samples.api.GreetingsService|zookeeper-AF(I-1,A-1)| ++---------------------------------------------+---------------------+ + +dubbo> + +``` + +如果机器上没有 `telnet` 也可以通过 `cURL` 发起调用,请求地址为 `http://127.0.0.1:22222/ls`: +```bash +➜ curl http://127.0.0.1:22222/ls +As Provider side: ++------------------------------------------------------------------------------------+---+ +| Provider Service Name |PUB| ++------------------------------------------------------------------------------------+---+ +|DubboInternal - first-dubbo-consumer/org.apache.dubbo.metadata.MetadataService:1.0.0| | ++------------------------------------------------------------------------------------+---+ +As Consumer side: ++---------------------------------------------+---------------------+ +| Consumer Service Name | NUM | ++---------------------------------------------+---------------------+ +|org.apache.dubbo.samples.api.GreetingsService|zookeeper-AF(I-1,A-1)| ++---------------------------------------------+---------------------+ +``` + +注:默认情况下 `ls` 命令仅允许本机调用,如果您无法登陆对应的机器,请参考 3.2 通过日志进行检查。 + +如上结果所示,请检查在 `As Consumer side` 一栏中是否存在您所发布的服务名,如果存在则代表该服务已经发布。 +第二列 `NUM` 中的信息为该服务的注册情况,格式为 `${registryName}-${migrationType}(${level}-${count})`。 + +1. `migrationType` 有三种情况,分别是 `AF`、`FA` 和 `FI` 代表着订阅的模式。`AF` 会优先使用应用级模型下的地址,如果应用级地址找不到会自动使用接口级模型的地址。`FA` 和 `FI` 则会只使用应用级模型的地址和接口级模型的地址。 +2. `level` 有两种情况,分别是 `I` 和 `A`,代表着接口级模型下的地址和应用级模型下的地址。 + +如果您无法找到您所发布的服务,请检查以下清单: + +1. 该服务是否已经添加到该机器所对应的运行代码中 +2. 该服务是否已经正确配置到 Dubbo 环境中,请检查如 `@EnableDubbo`、`@DubboReference` 或者 XML 等配置是否正确 + +如果您找到了您所发布的服务,但是服务的地址数是 `0`,请检查以下清单: + +1. 注册中心的工作状态 +2. 从第 2 步重新排查 + +如果您找到了您所发布的服务,但是对应的服务发现模型错误,请检查以下清单: + +1. 是否配置的订阅迁移规则,如 `dubbo-migration.yaml` 或动态配置,请参考 [应用级服务发现地址迁移规则说明](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) + +如果您找到了您所发布的服务,且对应的服务发现模型下地址数非 `0`,请跳转到第 7 步进行排查。 + +#### 6.2 通过日志检查 +如果您由于各种原因无法使用 Dubbo QoS,可以在对应机器的日志上搜索 `[DUBBO] Subscribe: ` 来检查服务是否已经订阅。 + +```bash +[27/02/23 11:02:05:005 CST] main INFO zookeeper.ZookeeperRegistry: [DUBBO] Subscribe: consumer://***/org.apache.dubbo.samples.api.GreetingsService?***, dubbo version: 3.2.0-beta.6, current host: 30.221.144.195 +``` + +如上所示,则代表着该服务已经发布,如果您无法找到您所发布的服务,请检查以下清单: + +1. 该服务是否已经添加到该机器所对应的运行代码中 +2. 该服务是否已经正确配置到 Dubbo 环境中,请检查如 `@EnableDubbo`、`@DubboReference` 或者 XML 等配置是否正确 + +在确定了服务已经订阅了以后,可以在对应机器的日志上搜索 `[DUBBO] Received invokers changed event from registry. ` 来检查服务是否已经推送。 + +```bash +[27/02/23 11:02:05:005 CST] main INFO integration.RegistryDirectory: [DUBBO] Received invokers changed event from registry. Registry type: interface. Service Key: org.apache.dubbo.samples.api.GreetingsService. Urls Size : 1. Invokers Size : 1. Available Size: 1. Available Invokers : 30.221.144.195:20880, dubbo version: 3.2.0-beta.6, current host: 30.221.144.195 +``` + +如上所示,则代表着该服务已经推送,如果您无法找到相关日志,请检查以下清单: + +1. 注册中心的工作状态 +2. 从第 2 步重新排查 + +如果您找到了您所注册的服务,请跳转到第 7 步进行排查。 + +注:推送日志仅 3.2.0 及以上版本支持 + +### 7 检查消费端注册中心配置 +注:本小节排查思路与第 4 步检查服务端注册中心配置类似。 +#### 7.1 通过 Dubbo Admin 查询(推荐) +注:Dubbo 3.2.0 及以上版本支持 + +在 Dubbo 应用启动的时候,默认会在本地的 22222 端口发布一个 QoS 服务,可以用于运行时查询节点的状态。通常,如果没有独立配置 `dubbo.application.qos-enable` 或者 `dubbo.application.qos-port` 都可以基于本方法查询服务的信息。 + +找到预期发布该服务的机器,登陆到其控制台,执行 `telnet 127.0.0.1 22222` 和 `getConfig RegistryConfig`: +```bash +➜ telnet 127.0.0.1 22222 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>getConfig RegistryConfig +ApplicationModel: Dubbo Application[1.1](first-dubbo-provider) +RegistryConfig: null + + +``` + +如上述结果所示,请检查对应的注册中心配置是否符合预期,如果不符合请修改对应的配置。 +如果第 6 步和第 7 步检查均符合预期,则该服务应该可以在第 2 步的注册中心中查询到,如果查询不到请检查注册中心是否工作正常。 + +注:`getConfig` 命令仅允许本机调用,如果您无法登陆对应的机器,请参考 4.2 通过日志进行检查。 + +#### 7.2 通过日志检查 +如果您由于各种原因无法使用 Dubbo QoS,可以在对应机器的日志上搜索 `[DUBBO] , dubbo version: 3.2.0-beta.6-SNAPSHOT, current host: 30.221.144.195 +``` + +如上述结果所示,请检查对应的注册中心配置是否符合预期,如果不符合请修改对应的配置。 +如果第 3 步和第 4 步检查均符合预期,则该服务应该可以在第 2 步的注册中心中查询到,如果查询不到请检查注册中心是否工作正常。 + +### 8 检查注册中心推送的地址信息 +注:本小节中使用的查询命令 Dubbo 3.2.0 及以上版本支持 + +在 Dubbo 应用启动的时候,默认会在本地的 22222 端口发布一个 QoS 服务,可以用于运行时查询节点的状态。通常,如果没有独立配置 `dubbo.application.qos-enable` 或者 `dubbo.application.qos-port` 都可以基于本方法查询服务的信息。 + +找到预期发布该服务的机器,登陆到其控制台,执行 `telnet 127.0.0.1 22222` 和 `getAddress ${serviceName}`: + +```bash +➜ telnet 127.0.0.1 22222 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ___ __ __ ___ ___ ____ + / _ \ / / / // _ ) / _ ) / __ \ + / // // /_/ // _ |/ _ |/ /_/ / +/____/ \____//____//____/ \____/ +dubbo>getAddress org.apache.dubbo.samples.api.GreetingsService +ConsumerModel: org.apache.dubbo.samples.api.GreetingsService@38b2d161 + +Registry: zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=first-dubbo-consumer&dubbo=2.0.2&environment=product&executor-management-mode=default&file-cache=true&interface=org.apache.dubbo.registry.RegistryService&pid=44482&release=3.2.0-beta.6-SNAPSHOT +MigrationStep: APPLICATION_FIRST +Interface-Level: +All Invokers: +dubbo://30.221.144.195:20880/org.apache.dubbo.samples.api.GreetingsService?anyhost=true&application=first-dubbo-provider&background=false&check=false&deprecated=false&dubbo=2.0.2&dynamic=true&executor-management-mode=default&file-cache=true&generic=false&interface=org.apache.dubbo.samples.api.GreetingsService&methods=sayHi&prefer.serialization=fastjson2,hessian2&release=3.2.0-beta.6-SNAPSHOT&service-name-mapping=true&side=provider + +Valid Invokers: +dubbo://30.221.144.195:20880/org.apache.dubbo.samples.api.GreetingsService?anyhost=true&application=first-dubbo-provider&background=false&check=false&deprecated=false&dubbo=2.0.2&dynamic=true&executor-management-mode=default&file-cache=true&generic=false&interface=org.apache.dubbo.samples.api.GreetingsService&methods=sayHi&prefer.serialization=fastjson2,hessian2&release=3.2.0-beta.6-SNAPSHOT&service-name-mapping=true&side=provider + +Disabled Invokers: + +Application-Level: +All Invokers: +dubbo://30.221.144.195:20880/org.apache.dubbo.samples.api.GreetingsService?anyhost=true&application=first-dubbo-consumer&background=false&deprecated=false&dubbo=2.0.2&dubbo.endpoints=[{"port":20880,"protocol":"dubbo"}]&dubbo.metadata-service.url-params={"prefer.serialization":"fastjson2,hessian2","version":"1.0.0","dubbo":"2.0.2","release":"3.2.0-beta.6-SNAPSHOT","side":"provider","port":"20880","protocol":"dubbo"}&dubbo.metadata.revision=e37fc5748b33c325056556550d33dde7&dubbo.metadata.storage-type=local&dynamic=true&environment=product&executor-management-mode=default&file-cache=true&generic=false&interface=org.apache.dubbo.samples.api.GreetingsService&methods=sayHi&pid=44482&prefer.serialization=fastjson2,hessian2®ister.ip=30.221.144.195&release=3.2.0-beta.6-SNAPSHOT&service-name-mapping=true&side=consumer&sticky=false×tamp=1677466879396&unloadClusterRelated=false + +Valid Invokers: +dubbo://30.221.144.195:20880/org.apache.dubbo.samples.api.GreetingsService?anyhost=true&application=first-dubbo-consumer&background=false&deprecated=false&dubbo=2.0.2&dubbo.endpoints=[{"port":20880,"protocol":"dubbo"}]&dubbo.metadata-service.url-params={"prefer.serialization":"fastjson2,hessian2","version":"1.0.0","dubbo":"2.0.2","release":"3.2.0-beta.6-SNAPSHOT","side":"provider","port":"20880","protocol":"dubbo"}&dubbo.metadata.revision=e37fc5748b33c325056556550d33dde7&dubbo.metadata.storage-type=local&dynamic=true&environment=product&executor-management-mode=default&file-cache=true&generic=false&interface=org.apache.dubbo.samples.api.GreetingsService&methods=sayHi&pid=44482&prefer.serialization=fastjson2,hessian2®ister.ip=30.221.144.195&release=3.2.0-beta.6-SNAPSHOT&service-name-mapping=true&side=consumer&sticky=false×tamp=1677466879396&unloadClusterRelated=false + +Disabled Invokers: + + +dubbo> +``` + +如上述结果所示,格式如下: + +```bash +ConsumerModel: 订阅的信息 + +Registry: 注册中心地址 +MigrationStep: 迁移模型(FORCE_APPLICATION, APPLCATION_FIRST, FORCE_INTERFACE) + +Interface-Level: 接口级服务发现模型下地址 +All Invokers: +从注册中心推送的所有地址 + +Valid Invokers: +所有可用地址 + +Disabled Invokers: +所有被拉黑的地址(通常是主动下线) + +Application-Level: 应用级服务发现模型下地址 +All Invokers: +从注册中心推送的所有地址 + +Valid Invokers: +所有可用地址 + +Disabled Invokers: +所有被拉黑的地址(通常是主动下线) + +``` + +请检查对应迁移模型是否符合预期,默认为 `APPLCATION_FIRST`,如果对应的服务发现模型错误,请检查以下清单: + +1. 是否配置的订阅迁移规则,如 `dubbo-migration.yaml` 或动态配置,请参考 [应用级服务发现地址迁移规则说明](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) + +如果迁移模型正确,请检查对应模型下的**所有**地址是否符合预期,如果不符合预期,请检查以下清单: + +1. 注册中心的工作状态 +2. 从第 2 步重新排查 + +如果注册中心推送的地址符合预期,请检查**可用**地址是否符合预期,如果不符合预期,一般为连接异常导致的自动拉黑,通常在四层网络不通或者机房断网等情况下出现,请跳转到第 9 步进行排查。 + +如果**可用**地址符合预期,请跳转到第 10 步进行检查。 + +注:`getAddress` 命令仅允许本机调用。 + +### 9 检查消费端与服务端网络连通性 + +在服务端发布了服务以后,请检查网络防火墙(iptables、ACL 等)是否允许 Dubbo 端口进行通信,默认 Dubbo 协议端口号为 20880、Triple 协议端口号为 50051。具体端口号可以从第 2 步注册中心中的信息获取。 + +测试方式:在消费端机器直接 telnet 远程的端口。 + +常见异常场景: + +1. 服务端消费端多集群部署,但是底层网络未打通 +2. 生产与测试共用注册中心,但是测试环境无法调用生产服务(**Dubbo 极其不推荐测试与生产环境混用**) +3. 单机调试,但是网络与大测试网不通 +4. 机房断网导致的节点断连 +5. 四层网络 ACL 规则未开放 Dubbo 端口访问 +6. 网络质量低、服务端负载过高等导致的网络连接质量差 + +### 10 检查路由信息 +注:Dubbo 3.1.0 及以上版本支持 +#### 10.1 报错时检查日志 + +在 Dubbo 出现调用异常的时候,可以在对应机器的日志上搜索 `[DUBBO] No provider available after route for the service` 来检查路由的状态。 + +```bash +[27/02/23 11:33:16:016 CST] main WARN cluster.SingleRouterChain: [DUBBO] No provider available after route for the service org.apache.dubbo.samples.api.GreetingsService from registry 30.221.144.195 on the consumer 30.221.144.195 using the dubbo version 3.2.0-beta.6-SNAPSHOT. Router snapshot is below: +[ Parent (Input: 1) (Current Node Output: 1) (Chain Node Output: 0) ] Input: 30.221.144.195:20880 -> Chain Node Output: Empty + [ MockInvokersSelector (Input: 1) (Current Node Output: 1) (Chain Node Output: 0) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 30.221.144.195:20880 + [ StandardMeshRuleRouter (Input: 1) (Current Node Output: 1) (Chain Node Output: 0) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 30.221.144.195:20880 + [ TagStateRouter (Input: 1) (Current Node Output: 0) (Chain Node Output: 0) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: Empty, dubbo version: 3.2.0-beta.6-SNAPSHOT, current host: 30.221.144.195, error code: 2-2. This may be caused by No provider available after route for the service, go to https://dubbo.apache.org/faq/2/2 to find instructions +``` + +请检查对应的 `Current Node Output: 0` 所在的日志行,通常为该级路由导致的地址为空。 + +#### 10.2 通过 Dubbo Admin 采样查询 + +对于线上运行的机器,Dubbo 提供了路由结果动态采样的能力,可以通过 Dubbo QoS 开启。 + +开启采样的方式: +```bash +dubbo>enableRouterSnapshot com.dubbo.* +OK. Found service count: 1. This will cause performance degradation, please be careful! + +dubbo> +``` + +获取采样结果: +```bash +dubbo>getRecentRouterSnapshot +1658224330156 - Router snapshot service com.dubbo.dubbointegration.BackendService from registry 172.18.111.184 on the consumer 172.18.111.184 using the dubbo version 3.0.9 is below: +[ Parent (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) ] Input: 172.18.111.187:20880,172.18.111.183:20880 -> Chain Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ MockInvokersSelector (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ StandardMeshRuleRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ TagStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ ServiceStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ AppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + +1658224330156 - Router snapshot service com.dubbo.dubbointegration.BackendService from registry 172.18.111.184 on the consumer 172.18.111.184 using the dubbo version 3.0.9 is below: +[ Parent (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) ] Input: 172.18.111.187:20880,172.18.111.183:20880 -> Chain Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ MockInvokersSelector (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ StandardMeshRuleRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ TagStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ ServiceStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + [ AppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880,172.18.111.183:20880 + +··· + +dubbo> +``` + +关闭采样的方式: +```bash +dubbo>disableRouterSnapshot com.dubbo.* +OK. Found service count: 1 + +dubbo> +``` + +注:采集路由信息会消耗一定的性能,排查完毕后请及时关闭。 +参考文档:[路由状态命令](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/router-snapshot/) diff --git a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/profiler.md b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/profiler.md new file mode 100644 index 000000000000..0c4c0a213e2f --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/profiler.md @@ -0,0 +1,190 @@ +--- +aliases: + - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/profiler/ + - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/profiler/ +description: Dubbo 请求耗时采样 +linkTitle: 请求耗时采样 +title: 请求耗时采样 +type: docs +weight: 1 +--- + + +性能采样功能可以对 Dubbo 处理链路上的各处耗时进行检测,在出现超时的时候 `( usageTime / timeout > profilerWarnPercent * 100 )` 通过日志记录调用的耗时。 + +此功能分为 `simple profiler` 和 `detail profiler` 两个模式,其中 `simple profiler` 模式默认开启,`detail profiler` 模式默认关闭。 +`detail profiler` 相较 `simple profiler` 模式多采集了每个 filter 的处理耗时、协议上的具体耗时等。 +在 `simple profiler` 模式下如果发现 Dubbo 框架内部存在耗时长的情况,可以开启 `detail profiler` 模式,以便更好地排查问题。 + +## 使用场景 + +需要对 Dubbo 请求的精确耗时进行采集分析的场景,如服务不明原因的超时等 + +## 使用方式 + +`simple profiler` 默认自动开启,对于请求处理时间超过超时时间 3/4 的,都会通过日志打印出慢调用信息。如果需要开启 `detail profiler` 模式或者修改超时告警比例,可以参考[性能采样命令](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/profiler/)文档。 + +### 日志说明 + +日志中各字段的含义如下: + +``` +[Dubbo-Consumer] execute service 接口#方法 cost 实际耗时, this invocation almost (maybe already) timeout. Timeout: 超时时间 +invocation context: +请求上下文 +thread info: +Start time: 开始请求时间(nano 时间) ++-[ Offset: 当前节点开始时间; Usage: 当前节点使用总耗时, 当前节点耗时比例 ] 当前节点描述 + +-[ Offset: 当前节点开始时间; Usage: 当前节点使用总耗时, 当前节点耗时比例 ] 当前节点描述 +``` + +对于请求耗时这里以两个例子进行介绍: + +``` +methodA() { + do something (1) + methodB (2) + do something (3) +} + +methodB() { + do something (4) + methodC (5) + do something (6) +} + +methodC() { + do something (7) +} + ++-[ Offset: 0 ms; Usage: (1) + (2) + (3) ms] execute methodA + +-[ Offset: (1) ms; Usage: (4) + (5) + (6) = (2) ms ] execute methodB + +-[ Offset: (1) + (4) ms; Usage: (7) = (5) ms ] execute methodC + +(1) (2) (3) ... 均为时间占位符 +``` + +``` +methodA() { + do something (1) + methodB (2) + methodE (3) + do something (4) +} + +methodB() { + do something (5) + methodC (6) + methodD (7) + do something (8) +} + +methodC() { + do something (9) +} + +methodD() { + do something (10) +} + +methodE() { + do something (11) +} + ++-[ Offset: 0 ms; Usage: (1) + (2) + (3) + (4) ms] execute methodA + +-[ Offset: (1) ms; Usage: (5) + (6) + (7) + (8) = (2) ms ] execute methodB + +-[ Offset: (1) + (5) ms; Usage: (9) = (6) ms ] execute methodC + +-[ Offset: (1) + (5) + (6) ms; Usage: (10) = (7) ms ] execute methodD + +-[ Offset: (1) + (2) ms; Usage: (11) = (3) ms ] execute methodE + +(1) (2) (3) ... 均为时间占位符 +``` + +### simple profiler + +Consumer 侧: +``` +[19/07/22 07:08:35:035 CST] main WARN proxy.InvokerInvocationHandler: [DUBBO] [Dubbo-Consumer] execute service org.apache.dubbo.samples.api.GreetingsService#sayHi cost 1003.015746 ms, this invocation almost (maybe already) timeout. Timeout: 1000ms +invocation context: +path=org.apache.dubbo.samples.api.GreetingsService; +remote.application=first-dubbo-consumer; +interface=org.apache.dubbo.samples.api.GreetingsService; +version=0.0.0; +timeout=1000; +thread info: +Start time: 285821581299853 ++-[ Offset: 0.000000ms; Usage: 1003.015746ms, 100% ] Receive request. Client invoke begin. ServiceKey: org.apache.dubbo.samples.api.GreetingsService MethodName:sayHi + +-[ Offset: 7.987015ms; Usage: 994.207928ms, 99% ] Invoker invoke. Target Address: xx.xx.xx.xx:20880, dubbo version: 3.0.10-SNAPSHOT, current host: xx.xx.xx.xx +``` + +Provider 侧: +``` +[19/07/22 07:08:35:035 CST] DubboServerHandler-30.227.64.173:20880-thread-2 WARN filter.ProfilerServerFilter: [DUBBO] [Dubbo-Provider] execute service org.apache.dubbo.samples.api.GreetingsService:0.0.0#sayHi cost 808.494672 ms, this invocation almost (maybe already) timeout. Timeout: 1000ms +client: xx.xx.xx.xx:51604 +invocation context: +input=281; +path=org.apache.dubbo.samples.api.GreetingsService; +remote.application=first-dubbo-consumer; +dubbo=2.0.2; +interface=org.apache.dubbo.samples.api.GreetingsService; +version=0.0.0; +timeout=1000; +thread info: +Start time: 285821754461125 ++-[ Offset: 0.000000ms; Usage: 808.494672ms, 100% ] Receive request. Server invoke begin. + +-[ Offset: 1.030912ms; Usage: 804.236342ms, 99% ] Receive request. Server biz impl invoke begin., dubbo version: 3.0.10-SNAPSHOT, current host: xx.xx.xx.xx +``` + +### detail profiler + +Consumer 侧: +``` +[19/07/22 07:10:59:059 CST] main WARN proxy.InvokerInvocationHandler: [DUBBO] [Dubbo-Consumer] execute service org.apache.dubbo.samples.api.GreetingsService#sayHi cost 990.828336 ms, this invocation almost (maybe already) timeout. Timeout: 1000ms +invocation context: +path=org.apache.dubbo.samples.api.GreetingsService; +remote.application=first-dubbo-consumer; +interface=org.apache.dubbo.samples.api.GreetingsService; +version=0.0.0; +timeout=1000; +thread info: +Start time: 285965458479241 ++-[ Offset: 0.000000ms; Usage: 990.828336ms, 100% ] Receive request. Client invoke begin. ServiceKey: org.apache.dubbo.samples.api.GreetingsService MethodName:sayHi + +-[ Offset: 0.852044ms; Usage: 989.899439ms, 99% ] Filter org.apache.dubbo.rpc.cluster.filter.support.ConsumerContextFilter invoke. + +-[ Offset: 1.814858ms; Usage: 988.924876ms, 99% ] Filter org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter invoke. + +-[ Offset: 1.853211ms; Usage: 988.877928ms, 99% ] Filter org.apache.dubbo.monitor.support.MonitorClusterFilter invoke. + +-[ Offset: 1.873243ms; Usage: 988.661708ms, 99% ] Filter org.apache.dubbo.rpc.cluster.router.RouterSnapshotFilter invoke. + +-[ Offset: 2.159140ms; Usage: 0.504939ms, 0% ] Router route. + +-[ Offset: 8.125823ms; Usage: 981.748366ms, 99% ] Cluster org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker invoke. + +-[ Offset: 8.258359ms; Usage: 981.612033ms, 99% ] Invoker invoke. Target Address: xx.xx.xx.xx:20880, dubbo version: 3.0.10-SNAPSHOT, current host: xx.xx.xx.xx +``` + +Provider 侧: +``` +[19/07/22 07:10:59:059 CST] DubboServerHandler-30.227.64.173:20880-thread-2 WARN filter.ProfilerServerFilter: [DUBBO] [Dubbo-Provider] execute service org.apache.dubbo.samples.api.GreetingsService:0.0.0#sayHi cost 811.017347 ms, this invocation almost (maybe already) timeout. Timeout: 1000ms +client: xx.xx.xx.xx:52019 +invocation context: +input=281; +path=org.apache.dubbo.samples.api.GreetingsService; +remote.application=first-dubbo-consumer; +dubbo=2.0.2; +interface=org.apache.dubbo.samples.api.GreetingsService; +version=0.0.0; +timeout=1000; +thread info: +Start time: 285965612316294 ++-[ Offset: 0.000000ms; Usage: 811.017347ms, 100% ] Receive request. Server invoke begin. + +-[ Offset: 1.096880ms; Usage: 809.916668ms, 99% ] Filter org.apache.dubbo.rpc.filter.EchoFilter invoke. + +-[ Offset: 1.133478ms; Usage: 809.866204ms, 99% ] Filter org.apache.dubbo.rpc.filter.ClassLoaderFilter invoke. + +-[ Offset: 1.157563ms; Usage: 809.838572ms, 99% ] Filter org.apache.dubbo.rpc.filter.GenericFilter invoke. + +-[ Offset: 1.202075ms; Usage: 809.736843ms, 99% ] Filter org.apache.dubbo.rpc.filter.ContextFilter invoke. + +-[ Offset: 1.433193ms; Usage: 809.504401ms, 99% ] Filter org.apache.dubbo.auth.filter.ProviderAuthFilter invoke. + +-[ Offset: 1.470760ms; Usage: 809.464291ms, 99% ] Filter org.apache.dubbo.rpc.filter.ExceptionFilter invoke. + +-[ Offset: 1.489103ms; Usage: 809.440183ms, 99% ] Filter org.apache.dubbo.monitor.support.MonitorFilter invoke. + +-[ Offset: 1.515757ms; Usage: 809.381893ms, 99% ] Filter org.apache.dubbo.rpc.filter.TimeoutFilter invoke. + +-[ Offset: 1.526632ms; Usage: 809.366553ms, 99% ] Filter org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter invoke. + +-[ Offset: 1.536964ms; Usage: 809.335907ms, 99% ] Filter org.apache.dubbo.rpc.filter.ClassLoaderCallbackFilter invoke. + +-[ Offset: 1.558545ms; Usage: 804.276436ms, 99% ] Receive request. Server biz impl invoke begin., dubbo version: 3.0.10-SNAPSHOT, current host: xx.xx.xx.xx +``` +{{% alert title="注意" color="warning" %}} +由于日志框架不匹配导致的日志为空可以参考[日志框架适配及运行时管理](../../others/logger-management/)动态修改日志输出框架。 +{{% /alert %}} diff --git a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/request-failed.md b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/request-failed.md new file mode 100644 index 000000000000..f5d3322f0514 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/request-failed.md @@ -0,0 +1,166 @@ +--- +aliases: + - /zh/overview/tasks/troubleshoot/request-failed/ + - /zh-cn/overview/tasks/troubleshoot/request-failed/ +description: 在 Dubbo 请求成功率低时的排查思路 +linkTitle: 请求成功率低 +title: 请求成功率低 +type: docs +weight: 3 +--- + + + +在生产环境中,请求成功率与延时是最关键的指标,本文将介绍在请求成功率下降时候的排查思路。 + +## 一句话总结 +全链路指标(消费端、网络、服务端、外部依赖等)分析瓶颈 + +![img](/imgs/docs3-v2/java-sdk/troubleshoot/1677487652373-fdc41dbd-0fe0-461f-b827-fa8db68ba2a2.jpeg) + +## 排查思路 +### 1 消费端是否正常构造请求 +#### 1.1 检查类对象是否都是可以序列化的 +在使用 Dubbo 进行 RPC 进行远程调用的时候,由于是跨进程的调用,为了防止非预期的数据在网络中请求,Dubbo 遵循 Java 的序列化最佳实践会检查所有数据对象是否实现了 `Serializable` 接口。 + +以下是检查到序列化异常时的日志样例: +``` +io.netty.handler.codec.EncoderException: java.lang.IllegalArgumentException: [Serialization Security] Serialized class org.apache.dubbo.samples.api.GreetingsService$Data has not implement Serializable interface. Current mode is strict check, will disallow to deserialize it by default. + at io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:125) + at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:881) + at io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:863) + at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:968) + at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:856) + at io.netty.handler.timeout.IdleStateHandler.write(IdleStateHandler.java:304) + at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:879) + at io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:863) + at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:968) + at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:856) + at io.netty.channel.ChannelDuplexHandler.write(ChannelDuplexHandler.java:115) + at org.apache.dubbo.remoting.transport.netty4.NettyClientHandler.write(NettyClientHandler.java:88) + at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:879) + at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:940) + at io.netty.channel.AbstractChannelHandlerContext$WriteTask.run(AbstractChannelHandlerContext.java:1247) + at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174) + at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167) + at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470) + at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569) + at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) + at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) + at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) + at java.lang.Thread.run(Thread.java:748) +Caused by: java.lang.IllegalArgumentException: [Serialization Security] Serialized class org.apache.dubbo.samples.api.GreetingsService$Data has not implement Serializable interface. Current mode is strict check, will disallow to deserialize it by default. + at org.apache.dubbo.common.utils.DefaultSerializeClassChecker.loadClass(DefaultSerializeClassChecker.java:112) + at org.apache.dubbo.common.serialize.hessian2.Hessian2SerializerFactory.getDefaultSerializer(Hessian2SerializerFactory.java:49) + at com.alibaba.com.caucho.hessian.io.SerializerFactory.getSerializer(SerializerFactory.java:393) + at com.alibaba.com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:411) + at org.apache.dubbo.common.serialize.hessian2.Hessian2ObjectOutput.writeObject(Hessian2ObjectOutput.java:99) + at org.apache.dubbo.rpc.protocol.dubbo.DubboCodec.encodeRequestData(DubboCodec.java:208) + at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encodeRequest(ExchangeCodec.java:261) + at org.apache.dubbo.remoting.exchange.codec.ExchangeCodec.encode(ExchangeCodec.java:75) + at org.apache.dubbo.rpc.protocol.dubbo.DubboCountCodec.encode(DubboCountCodec.java:47) + at org.apache.dubbo.remoting.transport.netty4.NettyCodecAdapter$InternalEncoder.encode(NettyCodecAdapter.java:69) + at io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:107) + ... 22 more +``` + +典型的日志关键字为 `has not implement Serializable interface`。 + +如果存在报错的类信息,请添加实现 `Serializable` 接口后重新部署。 + +#### 1.2 检查自定义扩展的逻辑是否正常 +如果您基于 Dubbo 的 SPI 机制扩展了如 Filter、Cluster、Router 等,请检查对应的实现是否有报错,任何一个组件报错都将影响业务的正常请求。 + +### 2 消费端是否正常写入请求 +#### 2.1 检查机器性能指标 +在消费端发起网络请求的时候,需要关注机器的 CPU 状态,如使用率、上下文切换次数等。如果机器负载过高,也将影响 Dubbo 请求处理的效率。 + +#### 2.2 检查 JVM 指标 +除了机器性能之外,JVM 虚拟机的性能也将直接影响 Dubbo,请关注 JVM 进程的以下指标: + +1. GC 次数(特别是 Full GC) +2. Young / Old Gen 大小 +3. C1 / C2 编译情况 + +为了更好地观测 JVM 虚拟机,可以通过 Java Flight Recorder 工具进行采样分析,参考。 + +### 3 网络传输是否正常 +#### 3.1 检查网络可达性 +对于绝大多数多机房部署的应用,机器之间的互通经过至少 1 个交换机,请检查: + +1. 转发(路由)规则是否正常 +2. ACL 是否对 Dubbo 开放 + +#### 3.2 检查网络延迟与重传率 +除了可达性之外,Dubbo 作为同步调用的 RPC,对时延和重传是非常敏感的,请检查: + +1. 节点之间的 RT +2. 网络的丢包率 +3. 网络的重传率(包括 TCP 重传) + +对于丢包率和重传率,可以通过 tcpdump 进行流量采样,然后通过 wireshark 进行分析。Dubbo 默认采用长连接复用模式,如果存在网络抖动将严重影响当下的所有在途请求。如果您希望您的请求成功率尽可能接近 100% 需要保证网络的 RT 是平稳的,丢包率和重传率接近于 0。 + +#### 3.3 检查网络吞吐量 +对于存在跨机房调用的用户来说,请密切关注网络的带宽指标,一旦达到运营商所限制的最大值将导致严重的请求丢包等情况,这对于 Dubbo 来说的影响是巨大的。 + +### 4 服务端是否正常接收请求 +#### 4.1 检查机器性能指标 +在服务端处理网络请求的时候,需要关注机器的 CPU 状态,如使用率、上下文切换次数等。如果机器负载过高,也将影响 Dubbo 请求处理的效率。 + +#### 4.2 检查 JVM 指标 +除了机器性能之外,JVM 虚拟机的性能也将直接影响 Dubbo,请关注 JVM 进程的以下指标: + +1. GC 次数(特别是 Full GC) +2. Young / Old Gen 大小 +3. C1 / C2 编译情况 + +为了更好地观测 JVM 虚拟机,可以通过 Java Flight Recorder 工具进行采样分析,参考。 + +### 5 服务端是否正常处理请求 +#### 5.1 检查是否服务端线程池满 +Dubbo 默认为服务端配置了 200(可修改)并发值的限制,如果某一时刻下超过了该限制将拒绝所有的新请求1⃣以保护服务端。 + +以下为线程池满时的日志样例: +``` +[27/02/23 05:37:40:040 CST] NettyServerWorker-5-2 WARN support.AbortPolicyWithReport: [DUBBO] Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-30.221.144.195:20880, Pool Size: 20 (active: 20, core: 20, max: 20, largest: 20), Task: 27 (completed: 7), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://30.221.144.195:20880!, dubbo version: 3.1.7, current host: 30.221.144.195, error code: 0-1. This may be caused by too much client requesting provider, go to https://dubbo.apache.org/faq/0/1 to find instructions. +``` + +典型的日志关键字为 `Thread pool is EXHAUSTED` + +Dubbo 默认会在 `user.home` 目录下打印异常时的 `jstack` 信息,您也可以自行执行 `jstack` 进行排查。 + +#### 5.2 检查是否被限流了 +如果您开启了 Dubbo 的 TPS 限流或者是引入了如 Sentinel、Hystrix 等限流组件,请检查是否触发限流值。 + +#### 5.3 检查自定义扩展的逻辑是否正常 +如果您基于 Dubbo 的 SPI 机制扩展了如 Filter 等,请检查对应的实现是否有报错,任何一个组件报错都将影响业务的正常请求。 + +#### 5.4 检查服务端处理时长 +如果服务端处理的时长接近或者是超过客户端配置的超时时间,则客户端会直接快速抛出异常。 + +关于服务端处理的时长可以参考以下日志: + +``` +[27/02/23 05:30:04:004 CST] DubboServerHandler-30.221.144.195:20880-thread-5 WARN filter.ProfilerServerFilter: [DUBBO] [Dubbo-Provider] execute service org.apache.dubbo.samples.api.GreetingsService:0.0.0#sayHi cost 3001.533827 ms, this invocation almost (maybe already) timeout. Timeout: 1000ms +client: fd00:1:5:5200:a0a1:52b:e079:8582:58731 +invocation context: +input=284; +path=org.apache.dubbo.samples.api.GreetingsService; +remote.application=first-dubbo-consumer; +dubbo=2.0.2; +interface=org.apache.dubbo.samples.api.GreetingsService; +version=0.0.0; +timeout=1000; +thread info: +Start time: 4237588012688 ++-[ Offset: 0.000000ms; Usage: 3001.533827ms, 100% ] Receive request. Server invoke begin. + +-[ Offset: 0.045578ms; Usage: 3001.436721ms, 99% ] Receive request. Server biz impl invoke begin., dubbo version: 3.1.7, current host: 30.221.144.195, error code: 3-7. This may be caused by , go to https://dubbo.apache.org/faq/3/7 to find instructions. +``` + +可以搜索 `execute service *** cost *** ms, this invocation almost (maybe already) timeout`相关日志。 + +通常在出现此日志的时候,您的服务实现中可能存在以下情况: + +1. 长时间的锁等待 +2. 外部依赖(RPC、MQ、Cache、DB 等)处理时长过长,可以接入全链路追踪平台诊断 +3. 机器的负载过高 diff --git a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/start-failed.md b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/start-failed.md new file mode 100644 index 000000000000..b89baf6503da --- /dev/null +++ b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/start-failed.md @@ -0,0 +1,253 @@ +--- +aliases: + - /zh/overview/tasks/troubleshoot/start-failed/ + - /zh-cn/overview/tasks/troubleshoot/start-failed/ +description: 在 Dubbo 应用启动失败时的排查思路 +linkTitle: 应用启动失败 +title: 应用启动失败 +type: docs +weight: 1 +--- + + + +在开发与生产部署过程中,由于各种非预期的变更,可能会出现应用无法启动的情况。对于 Dubbo 来说,通常启动失败时都会有类似以下的报错信息。 + +```bash +Caused by: java.lang.IllegalStateException: Dubbo Module[1.1.1] is stopping or stopped, can not start again +``` + +```bash +[DUBBO] Dubbo Application[1.1](first-dubbo-consumer) start failure +``` + +## 一句话总结 +正确配置日志输出,往前翻到第一个报错的位置并进行处理。 + +## 排查方式 +### 1 配置日志输出 +目前 Dubbo 支持多种日志框架,如果环境中存在多种日志框架的支持(如 log4j 和 logback),Dubbo 会按照 (log4j > slf4j > log4j2 > jcl)的顺序输出日志框架。 + +如果与预期的日志框架不同时,会出现日志无法输出的问题。此时可以通过以下的配置进行调整: + +```properties +dubbo.application.logger=slf4j +``` + +注:3.2.0 及以上的版本中将自动分析日志框架是否存在配置,优选日志框架输出。 + +### 2 找到真正的报错信息 +在正确配置日志输出之后,可以在日志中搜索 `[DUBBO] Model start failed` 或者 `start failure` 关键字,查看真正导致 Dubbo 启动失败的原因。 + +如下所示,启动失败的原因为有服务订阅找不到提供者。 +``` +[27/02/23 12:49:18:018 CST] main ERROR deploy.DefaultModuleDeployer: [DUBBO] Model start failed: Dubbo Module[1.1.1] start failed: java.lang.IllegalStateException: Failed to check the status of the service org.apache.dubbo.samples.api.GreetingsService. No provider available for the service org.apache.dubbo.samples.api.GreetingsService from the url consumer://30.221.144.195/org.apache.dubbo.samples.api.GreetingsService?application=first-dubbo-consumer&background=false&dubbo=2.0.2&environment=product&executor-management-mode=default&file-cache=true&interface=org.apache.dubbo.samples.api.GreetingsService&methods=sayHi&pid=54580®ister.ip=30.221.144.195&release=3.2.0-beta.6-SNAPSHOT&side=consumer&sticky=false×tamp=1677473358611&unloadClusterRelated=false to the consumer 30.221.144.195 use dubbo version 3.2.0-beta.6-SNAPSHOT, dubbo version: 3.2.0-beta.6-SNAPSHOT, current host: 30.221.144.195, error code: 5-14. This may be caused by , go to https://dubbo.apache.org/faq/5/14 to find instructions. +java.lang.IllegalStateException: Failed to check the status of the service org.apache.dubbo.samples.api.GreetingsService. No provider available for the service org.apache.dubbo.samples.api.GreetingsService from the url consumer://30.221.144.195/org.apache.dubbo.samples.api.GreetingsService?application=first-dubbo-consumer&background=false&dubbo=2.0.2&environment=product&executor-management-mode=default&file-cache=true&interface=org.apache.dubbo.samples.api.GreetingsService&methods=sayHi&pid=54580®ister.ip=30.221.144.195&release=3.2.0-beta.6-SNAPSHOT&side=consumer&sticky=false×tamp=1677473358611&unloadClusterRelated=false to the consumer 30.221.144.195 use dubbo version 3.2.0-beta.6-SNAPSHOT +``` + +## 常见的原因 +本章将介绍 Dubbo 中常见的启动失败原因。 +### 1 消费端地址找不到 +消费端地址找不到的日志特征如下: + +``` +Failed to check the status of the service ***. No provider available for the service *** from the url +``` + +解决方案:服务找不到时先自查服务是否已经开发完部署了,然后在注册中心中确认是否已经注册,如果注册检查服务端发布情况、如果未注册检查消费端订阅情况,中间任何一步出问题都会导致异常。 + +更多关于地址找不到的排查思路可以参考[地址找不到异常](../no-provider)一文。 + +### 2 配置异常 +#### 2.1 应用名未配置 +应用名未配置的日志特征如下: + +``` +[27/02/23 02:23:14:014 CST] main ERROR deploy.DefaultApplicationDeployer: [DUBBO] Dubbo Application[1.1](unknown) start failure, dubbo version: 3.2.0-beta.6-SNAPSHOT, current host: 30.221.144.195, error code: 5-14. This may be caused by , go to https://dubbo.apache.org/faq/5/14 to find instructions. +java.lang.IllegalStateException: There's no ApplicationConfig specified. + at org.apache.dubbo.config.context.ConfigManager.lambda$getApplicationOrElseThrow$0(ConfigManager.java:85) +``` + +典型的日志内容为 `There's no ApplicationConfig specified`。 + +解决方案: + +1. Spring Boot 项目配置 `dubbo.application.name` 应用名并重新启动 +2. Spring 项目配置 `` 属性并重新启动 +3. 直接使用 Dubbo API 的项目需要注入 `ApplicationConfig applicationConfig = new ApplicationConfig("xxx");` 属性并重新启动 + +#### 2.2 重复配置覆盖 +重复配置覆盖的日志特征如下: +``` +Exception in thread "main" java.lang.IllegalStateException: Duplicate Configs found for ApplicationConfig, only one unique ApplicationConfig is allowed for one application. previous: , later: . According to config mode [STRICT], please remove redundant configs and keep only one. +``` + +典型的日志内容为 `Duplicate Configs found for`。 + +解决方案: + +1. Spring 项目中通常为注入了多个 Config 导致的,请按照日志提示删除到仅剩下一个并重新启动 +2. Spring XML 项目中通常引入了多个互斥的属性导致的,请按照日志提示删除到仅剩下一个并重新启动 +3. 直接使用 Dubbo API 的项目通常是注入了多个相同维度的配置导致的,请按照日志提示删除到仅剩下一个并重新启动 +4. 对于无法修改重复属性的用户,可以在启动参数中指定 `dubbo.config.mode` 为 `OVERRIDE` 或 `IGNORE` 分别代表着覆盖原配置或忽略新配置。 + +注:此异常为 3.x 中新检查行为,2.7.x 及以前版本中存在任意覆盖的问题。 + +### 3 类找不到 +类找不到的日志特征如下: +``` +[27/02/23 02:44:50:050 CST] main ERROR deploy.DefaultApplicationDeployer: [DUBBO] Dubbo Application[1.1](first-dubbo-consumer) start failure, dubbo version: 3.2.0-beta.6-SNAPSHOT, current host: 30.221.144.195, error code: 5-14. This may be caused by , go to https://dubbo.apache.org/faq/5/14 to find instructions. +java.lang.IllegalStateException: org.apache.dubbo.samples.api.Greetings + at org.apache.dubbo.config.ReferenceConfig.checkAndUpdateSubConfigs(ReferenceConfig.java:706) + at org.apache.dubbo.config.ReferenceConfig.postProcessRefresh(ReferenceConfig.java:721) + at org.apache.dubbo.config.AbstractConfig.refresh(AbstractConfig.java:693) + at java.util.concurrent.ConcurrentHashMap$ValuesView.forEach(ConcurrentHashMap.java:4707) + at org.apache.dubbo.config.context.ModuleConfigManager.refreshAll(ModuleConfigManager.java:180) + at org.apache.dubbo.config.deploy.DefaultModuleDeployer.loadConfigs(DefaultModuleDeployer.java:317) + at org.apache.dubbo.config.deploy.DefaultModuleDeployer.initialize(DefaultModuleDeployer.java:113) + at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.initModuleDeployers(DefaultApplicationDeployer.java:238) + at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.initialize(DefaultApplicationDeployer.java:211) + at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.start(DefaultApplicationDeployer.java:616) + at org.apache.dubbo.config.bootstrap.DubboBootstrap.start(DubboBootstrap.java:226) + at org.apache.dubbo.config.bootstrap.DubboBootstrap.start(DubboBootstrap.java:215) + at org.apache.dubbo.samples.client.Application.main(Application.java:50) +Caused by: java.lang.ClassNotFoundException: org.apache.dubbo.samples.api.Greetings + at java.net.URLClassLoader.findClass(URLClassLoader.java:382) + at java.lang.ClassLoader.loadClass(ClassLoader.java:418) + at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355) + at java.lang.ClassLoader.loadClass(ClassLoader.java:351) + at java.lang.Class.forName0(Native Method) + at java.lang.Class.forName(Class.java:348) + at org.apache.dubbo.config.ReferenceConfig.checkAndUpdateSubConfigs(ReferenceConfig.java:702) + ... 12 more + +``` + +典型的日志内容为 `java.lang.ClassNotFoundException`。 + +解决方案: + +1. 检查是否正确打包,是否存在依赖包丢失的情况。(可以结合 arthas 进行诊断) +2. 对于确实不需要使用类对象的(如网关场景),可以配置 `generic` 属性开启泛化调用,会自动忽略类检查 + +### 4 方法找不到 +方法找不到的日志特征如下: +``` +[27/02/23 02:49:31:031 CST] main ERROR deploy.DefaultApplicationDeployer: [DUBBO] Dubbo Application[1.1](first-dubbo-consumer) start failure, dubbo version: 3.2.0-beta.6-SNAPSHOT, current host: 30.221.144.195, error code: 5-14. This may be caused by , go to https://dubbo.apache.org/faq/5/14 to find instructions. +java.lang.IllegalStateException: Failed to override field value of config bean: + at org.apache.dubbo.config.AbstractConfig.refresh(AbstractConfig.java:690) + at java.util.concurrent.ConcurrentHashMap$ValuesView.forEach(ConcurrentHashMap.java:4707) + at org.apache.dubbo.config.context.ModuleConfigManager.refreshAll(ModuleConfigManager.java:180) + at org.apache.dubbo.config.deploy.DefaultModuleDeployer.loadConfigs(DefaultModuleDeployer.java:317) + at org.apache.dubbo.config.deploy.DefaultModuleDeployer.initialize(DefaultModuleDeployer.java:113) + at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.initModuleDeployers(DefaultApplicationDeployer.java:238) + at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.initialize(DefaultApplicationDeployer.java:211) + at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.start(DefaultApplicationDeployer.java:616) + at org.apache.dubbo.config.bootstrap.DubboBootstrap.start(DubboBootstrap.java:226) + at org.apache.dubbo.config.bootstrap.DubboBootstrap.start(DubboBootstrap.java:215) + at org.apache.dubbo.samples.client.Application.main(Application.java:56) +Caused by: java.lang.IllegalStateException: Found invalid method config, the interface org.apache.dubbo.samples.api.GreetingsService not found method "sayHi123" : [] + at org.apache.dubbo.config.AbstractInterfaceConfig.verifyMethodConfig(AbstractInterfaceConfig.java:399) + at org.apache.dubbo.config.AbstractInterfaceConfig.lambda$processExtraRefresh$2(AbstractInterfaceConfig.java:369) + at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:174) + at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384) + at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) + at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472) + at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) + at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) + at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) + at org.apache.dubbo.config.AbstractInterfaceConfig.processExtraRefresh(AbstractInterfaceConfig.java:370) + at org.apache.dubbo.config.AbstractConfig.refreshWithPrefixes(AbstractConfig.java:735) + at org.apache.dubbo.config.ReferenceConfigBase.preProcessRefresh(ReferenceConfigBase.java:140) + at org.apache.dubbo.config.AbstractConfig.refresh(AbstractConfig.java:686) + +``` + +典型的日志内容为 `Found invalid method config`。 + +解决方案: + +1. 检查是否正确打包,是否存在依赖包丢失的情况。(可以结合 arthas 进行诊断) +2. 如果确定该方法已经删除,请删除对应的 `MethodConfig` 并重新启动 +3. 对于确实不需要使用类对象的(如网关场景),可以配置 `generic` 属性开启泛化调用,会自动忽略类检查 + +### 5 端口冲突 +端口冲突的日志特征如下: +``` +[27/02/23 02:52:00:000 CST] main ERROR deploy.DefaultApplicationDeployer: [DUBBO] Dubbo Application[1.1](first-dubbo-provider) start failure, dubbo version: 3.2.0-beta.6-SNAPSHOT, current host: 30.221.144.195, error code: 5-14. This may be caused by , go to https://dubbo.apache.org/faq/5/14 to find instructions. +org.apache.dubbo.rpc.RpcException: Fail to start server(url: dubbo://30.221.144.195:20880/org.apache.dubbo.samples.api.GreetingsService?anyhost=true&application=first-dubbo-provider&background=false&bind.ip=30.221.144.195&bind.port=20880&channel.readonly.sent=true&codec=dubbo&deprecated=false&dubbo=2.0.2&dubbo.tag=dev&dynamic=true&executor-management-mode=default&file-cache=true&generic=false&heartbeat=60000&interface=org.apache.dubbo.samples.api.GreetingsService&methods=sayHi&pid=63841&prefer.serialization=fastjson2,hessian2&qos.port=22223&release=3.2.0-beta.6-SNAPSHOT&service-name-mapping=true&side=provider×tamp=1677480719543) Failed to bind NettyServer on /0.0.0.0:20880, cause: Address already in use +at org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol.createServer(DubboProtocol.java:385) +at org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol.openServer(DubboProtocol.java:350) +at org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol.export(DubboProtocol.java:331) +at org.apache.dubbo.qos.protocol.QosProtocolWrapper.export(QosProtocolWrapper.java:79) +at org.apache.dubbo.rpc.protocol.ProtocolSecurityWrapper.export(ProtocolSecurityWrapper.java:80) +at org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper.export(ProtocolListenerWrapper.java:66) +at org.apache.dubbo.rpc.cluster.filter.ProtocolFilterWrapper.export(ProtocolFilterWrapper.java:61) +at org.apache.dubbo.rpc.protocol.ProtocolSerializationWrapper.export(ProtocolSerializationWrapper.java:47) +at org.apache.dubbo.rpc.Protocol$Adaptive.export(Protocol$Adaptive.java) +at org.apache.dubbo.registry.integration.RegistryProtocol.lambda$doLocalExport$3(RegistryProtocol.java:305) +at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) +at org.apache.dubbo.registry.integration.RegistryProtocol.doLocalExport(RegistryProtocol.java:303) +at org.apache.dubbo.registry.integration.RegistryProtocol.export(RegistryProtocol.java:249) +at org.apache.dubbo.qos.protocol.QosProtocolWrapper.export(QosProtocolWrapper.java:79) +at org.apache.dubbo.rpc.protocol.ProtocolSecurityWrapper.export(ProtocolSecurityWrapper.java:80) +at org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper.export(ProtocolListenerWrapper.java:64) +at org.apache.dubbo.rpc.cluster.filter.ProtocolFilterWrapper.export(ProtocolFilterWrapper.java:58) +at org.apache.dubbo.rpc.protocol.ProtocolSerializationWrapper.export(ProtocolSerializationWrapper.java:47) +at org.apache.dubbo.rpc.Protocol$Adaptive.export(Protocol$Adaptive.java) +at org.apache.dubbo.config.ServiceConfig.doExportUrl(ServiceConfig.java:739) +at org.apache.dubbo.config.ServiceConfig.exportRemote(ServiceConfig.java:717) +at org.apache.dubbo.config.ServiceConfig.exportUrl(ServiceConfig.java:658) +at org.apache.dubbo.config.ServiceConfig.doExportUrlsFor1Protocol(ServiceConfig.java:451) +at org.apache.dubbo.config.ServiceConfig.doExportUrls(ServiceConfig.java:433) +at org.apache.dubbo.config.ServiceConfig.doExport(ServiceConfig.java:395) +at org.apache.dubbo.config.ServiceConfig.export(ServiceConfig.java:247) +at org.apache.dubbo.config.deploy.DefaultModuleDeployer.exportServiceInternal(DefaultModuleDeployer.java:350) +at org.apache.dubbo.config.deploy.DefaultModuleDeployer.exportServices(DefaultModuleDeployer.java:322) +at org.apache.dubbo.config.deploy.DefaultModuleDeployer.startSync(DefaultModuleDeployer.java:158) +at org.apache.dubbo.config.deploy.DefaultModuleDeployer.start(DefaultModuleDeployer.java:139) +at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.startModules(DefaultApplicationDeployer.java:681) +at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.doStart(DefaultApplicationDeployer.java:645) +at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.start(DefaultApplicationDeployer.java:618) +at org.apache.dubbo.config.bootstrap.DubboBootstrap.start(DubboBootstrap.java:226) +at org.apache.dubbo.config.bootstrap.DubboBootstrap.start(DubboBootstrap.java:215) +at org.apache.dubbo.samples.provider.Application.main(Application.java:52) +Caused by: org.apache.dubbo.remoting.RemotingException: Failed to bind NettyServer on /0.0.0.0:20880, cause: Address already in use +at org.apache.dubbo.remoting.transport.AbstractServer.(AbstractServer.java:75) +at org.apache.dubbo.remoting.transport.netty4.NettyServer.(NettyServer.java:85) +at org.apache.dubbo.remoting.transport.netty4.NettyTransporter.bind(NettyTransporter.java:35) +at org.apache.dubbo.remoting.Transporter$Adaptive.bind(Transporter$Adaptive.java) +at org.apache.dubbo.remoting.Transporters.bind(Transporters.java:55) +at org.apache.dubbo.remoting.exchange.support.header.HeaderExchanger.bind(HeaderExchanger.java:52) +at org.apache.dubbo.remoting.exchange.Exchangers.bind(Exchangers.java:69) +at org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol.createServer(DubboProtocol.java:383) +... 35 more +Caused by: java.net.BindException: Address already in use +at sun.nio.ch.Net.bind0(Native Method) +at sun.nio.ch.Net.bind(Net.java:444) +at sun.nio.ch.Net.bind(Net.java:436) +at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:225) +at io.netty.channel.socket.nio.NioServerSocketChannel.doBind(NioServerSocketChannel.java:141) +at io.netty.channel.AbstractChannel$AbstractUnsafe.bind(AbstractChannel.java:562) +at io.netty.channel.DefaultChannelPipeline$HeadContext.bind(DefaultChannelPipeline.java:1334) +at io.netty.channel.AbstractChannelHandlerContext.invokeBind(AbstractChannelHandlerContext.java:600) +at io.netty.channel.AbstractChannelHandlerContext.bind(AbstractChannelHandlerContext.java:579) +at io.netty.channel.DefaultChannelPipeline.bind(DefaultChannelPipeline.java:973) +at io.netty.channel.AbstractChannel.bind(AbstractChannel.java:260) +at io.netty.bootstrap.AbstractBootstrap$2.run(AbstractBootstrap.java:356) +at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174) +at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167) +at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470) +at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569) +at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) +at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) +at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) +at java.lang.Thread.run(Thread.java:748) +``` + +典型的日志内容为 `Address already in use`。 + +解决方案: + +1. 检查本地是否有其他进程已经占用了端口(可以基于 `lsof -i:20880` 、`netstat -ano | grep 20880` 等命令排查) +2. 如果本地启动多个 Dubbo 进程,请给不同的进程指定不同的 `dubbo.protocol.port` 。或者指定为 `-1`,Dubbo 将自动寻找一个可以使用的端口进行绑定。 diff --git a/content/en/overview/mannual/java-sdk/versions.md b/content/en/overview/mannual/java-sdk/versions.md new file mode 100644 index 000000000000..e20d7459cba5 --- /dev/null +++ b/content/en/overview/mannual/java-sdk/versions.md @@ -0,0 +1,23 @@ +--- +aliases: + - /zh/docs3-v2/golang-sdk/refer/compatible_version/ + - /zh-cn/docs3-v2/golang-sdk/refer/compatible_version/ + - /zh-cn/overview/mannual/golang-sdk/preface/refer/compatible_version/ +description: 依赖适配版本号 +title: 版本信息 +type: docs +weight: 1 +--- +我们提供了不同版本的 Dubbo Java 实现文档,您可以在下方版本列表中选择不同的版本文档,查看每个版本的维护情况、组件版本、升级注意事项等。 + +## 版本说明 + +| Dubbo 分支 | 最新版本 | JDK | Spring Boot | 组件版本 | 详细说明 | +| --- | --- | --- | --- | --- | --- | --- | --- | +| 3.3.x (当前文档) | 3.3.0 | 8, 17, 21 | [2.x、3.x](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://github.com/apache/dubbo/blob/dubbo-3.3.0/dubbo-dependencies-bom/pom.xml#L91) | - [版本变更记录](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.2-to-3.3-compatibility-guide/)

- **生产可用(推荐,长期维护)!** 最新Triple协议升级,内置Metrics、Tracing、GraalVM支持等 | +| [3.2.x](https://dubbo-202409.staged.apache.org/zh-cn/overview/mannual/java-sdk/) | 3.2.10 | 8, 17 | [2.x、3.x](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://github.com/apache/dubbo/blob/dubbo-3.2.10/dubbo-dependencies-bom/pom.xml#L91) | - [版本变更记录](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.1-to-3.2-compatibility-guide/)

- 生产可用(长期维护)! | +| [3.1.x](https://dubbo-202409.staged.apache.org/zh-cn/overview/mannual/java-sdk/) | 3.1.11 | 8, 17 | [2.x、3.x](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://github.com/apache/dubbo/blob/dubbo-3.1.11/dubbo-dependencies-bom/pom.xml#L91) | - [版本变更记录](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.0-to-3.1-compatibility-guide/)

- 仅修复安全漏洞! | +| [3.0.x](https://dubbo-202409.staged.apache.org/zh-cn/docs/) | 3.0.15 | 8 | [2.x](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://github.com/apache/dubbo/blob/dubbo-3.0.15/dubbo-dependencies-bom/pom.xml#L91) | - [版本变更记录](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/2.x-to-3.x-compatibility-guide/)

- 停止维护! | +| [2.7.x](https://dubbo-202409.staged.apache.org/zh-cn/docsv2.7/) | 2.7.23 | 8 | [2.x](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://raw.githubusercontent.com/apache/dubbo/dubbo-2.7.23/dubbo-dependencies-bom/pom.xml) | - [了解如何升级到Dubbo3](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/)

- 停止维护! | +| 2.6.x | 2.6.20 | 6, 7 | - | _ | - [了解如何升级到Dubbo3](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/)

- 停止维护! | +| 2.5.x | 2.5.10 | 6, 7 | - | - | - [了解如何升级到Dubbo3](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/)

- 停止维护! | diff --git a/content/en/overview/mannual/nodejs-sdk/_index.md b/content/en/overview/mannual/nodejs-sdk/_index.md new file mode 100755 index 000000000000..294410b450f9 --- /dev/null +++ b/content/en/overview/mannual/nodejs-sdk/_index.md @@ -0,0 +1,7 @@ +--- +description: Node.js SDK 使用手册 +linkTitle: Node.js SDK +title: Node.js SDK 手册 +type: docs +weight: 3 +--- diff --git a/content/en/overview/mannual/nodejs-sdk/quick-start.md b/content/en/overview/mannual/nodejs-sdk/quick-start.md new file mode 100644 index 000000000000..d27fefb32237 --- /dev/null +++ b/content/en/overview/mannual/nodejs-sdk/quick-start.md @@ -0,0 +1,186 @@ +--- +aliases: + - /zh/overview/quickstart/nodejs/ + - /zh-cn/overview/quickstart/nodejs/ +description: 使用 Node.js 开发后端微服务 +linkTitle: 快速开始 +title: 快速开始 +type: docs +weight: 1 +--- + +基于 Dubbo 定义的 Triple 协议,你可以轻松编写浏览器、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。Dubbo Node.js SDK 支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 API 来发布或调用这些服务。 + +本示例演示了基于 Triple 协议的 RPC 通信模式,示例使用 Protocol Buffer 定义 RPC 服务,并演示了代码生成、服务发布和服务访问等过程。 + +## 前置条件 + +因为使用 Protocol Buffer 的原因,我们首先需要安装相关的代码生成工具,这包括 `@bufbuild/protoc-gen-es`、`@bufbuild/protobuf`、`@apachedubbo/protoc-gen-apache-dubbo-es`、`@apachedubbo/dubbo`。 + +```Shell +npm install @bufbuild/protoc-gen-es @bufbuild/protobuf @apachedubbo/protoc-gen-apache-dubbo-es @apachedubbo/dubbo +``` + +## 定义服务 + +现在,使用 Protocol Buffer (IDL) 来定义一个 Dubbo 服务。 + +创建目录,并生成文件 + +```Shell +mkdir -p proto && touch proto/example.proto +``` + +写入内容 + +```Protobuf +syntax = "proto3"; + +package apache.dubbo.demo.example.v1; + +message SayRequest { + string sentence = 1; +} + +message SayResponse { + string sentence = 1; +} + +service ExampleService { + rpc Say(SayRequest) returns (SayResponse) {} +} +``` + +这个文件声明了一个叫做 `ExampleService` 的服务,为这个服务定义了 `Say` 方法以及它的请求参数 `SayRequest` 和返回值 `SayResponse`。 + +## 生成代码 + +创建 gen 目录,做为生成文件放置的目标目录 + +``` +mkdir -p gen +``` + +运行以下命令,在 gen 目录下生成代码文件 + +```Shell +PATH=$PATH:$(pwd)/node_modules/.bin \ + protoc -I proto \ + --es_out gen \ + --es_opt target=ts \ + --apache-dubbo-es_out gen \ + --apache-dubbo-es_opt target=ts \ + example.proto +``` + +运行命令后,应该可以在目标目录中看到以下生成的文件: + +```Plain Text +├── gen +│ ├── example_dubbo.ts +│ └── example_pb.ts +├── proto +│ └── example.proto +``` + +## 实现服务 + +接下来我们就需要添加业务逻辑了,实现 ExampleService ,并将其注册到 DubboRouter 中。 + +创建 dubbo.ts 文件 + +```typescript +import { DubboRouter } from "@apachedubbo/dubbo"; +import { ExampleService } from "./gen/example_dubbo"; + +export default (router: DubboRouter) => + // registers apache.dubbo.demo.example.v1 + router.service(ExampleService, { + // implements rpc Say + async say(req) { + return { + sentence: `You said: ${req.sentence}`, + }; + }, + }, { serviceGroup: 'dubbo', serviceVersion: '1.0.0' }); +``` + +## 启动 Server + +Dubbo 服务可以嵌入到普通的 Node.js 服务器、Next.js、Express 或 Fastify 中。 +在这里我们将使用 Fastify,所以让我们安装 Fastify 以及我们为 Fastify 准备的插件。 + +```Shell +npm install fastify @apachedubbo/dubbo-fastify +``` + +创建 server.ts 文件,新建一个 Server,把上一步中实现的 `ExampleService` 注册给它。 +接下来就可以直接初始化和启动 Server 了,它将在指定的端口接收请求。 + +```typescript +import { fastify } from "fastify"; +import { fastifyDubboPlugin } from "@apachedubbo/dubbo-fastify"; +import routes from "./dubbo"; + +async function main() { + const server = fastify(); + await server.register(fastifyDubboPlugin, { + routes, + }); + server.get("/", (_, reply) => { + reply.type("text/plain"); + reply.send("Hello World!"); + }); + await server.listen({ host: "localhost", port: 8080 }); + console.log("server is listening at", server.addresses()); +} + +void main(); +``` + +最后,运行代码启动服务 + +```Shell +npx tsx server.ts +``` + +## 访问服务 + +最简单方式是使用 HTTP/1.1 POST 请求访问服务,参数则作以标准 JSON 格式作为 HTTP 负载传递。如下是使用 cURL 命令的访问示例: + +```Shell +curl \ + --header 'Content-Type: application/json' \ + --header 'TRI-Service-Version: 1.0.0' \ + --header 'TRI-Service-group: dubbo' \ + --data '{"sentence": "Hello World"}' \ + http://localhost:8080/apache.dubbo.demo.example.v1.ExampleService/Say +``` + +也可以使用标准的 Dubbo client 请求服务,我们首先需要从生成代码即 dubbo-node 包中获取服务代理,为它指定 server 地址并初始化,之后就可以发起起 RPC 调用了。 + +创建 client.ts 文件。 + +```typescript +import { createPromiseClient } from "@apachedubbo/dubbo"; +import { ExampleService } from "./gen/example_dubbo"; +import { createDubboTransport } from "@apachedubbo/dubbo-node"; + +const transport = createDubboTransport({ + baseUrl: "http://localhost:8080", + httpVersion: "1.1", +}); + +async function main() { + const client = createPromiseClient(ExampleService, transport, { serviceVersion: '1.0.0', serviceGroup: 'dubbo' }); + const res = await client.say({ sentence: "Hello World" }); + console.log(res); +} +void main(); +``` + +运行客户端 + +```Shell +npx tsx client.ts +``` diff --git a/content/en/overview/mannual/rust-sdk/_index.md b/content/en/overview/mannual/rust-sdk/_index.md new file mode 100755 index 000000000000..cc146fb0aa73 --- /dev/null +++ b/content/en/overview/mannual/rust-sdk/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/docs3-v2/rust-sdk/ + - /zh-cn/docs3-v2/rust-sdk/ +description: Rust SDK 使用手册 +linkTitle: Rust SDK +title: Rust SDK 手册 +type: docs +weight: 5 +--- diff --git a/content/en/overview/mannual/rust-sdk/java-interoperability.md b/content/en/overview/mannual/rust-sdk/java-interoperability.md new file mode 100644 index 000000000000..dcf8a74f8361 --- /dev/null +++ b/content/en/overview/mannual/rust-sdk/java-interoperability.md @@ -0,0 +1,78 @@ +--- +aliases: + - /zh/docs3-v2/rust-sdk/java-interoperability/ + - /zh-cn/docs3-v2/rust-sdk/java-interoperability/ +description: 使用 Rust 调用 Java 开发的 Dubbo 服务。 +linkTitle: Rust和Java互相调用 +title: Rust和Java互相调用 +type: docs +weight: 2 +--- + + + + + + +## 1 前置条件 +- 安装 [Rust](https://rustup.rs/) 开发环境 +- 安装 [protoc](https://grpc.io/docs/protoc-installation/) 工具 +- 安装 Java 开发环境 + +## 2 运行示例 Java 版本的 Dubbo provider + +Java 版本的 Dubbo provider 示例源码见。 + +Clone 源代码、编译构建,并运行 provider: + +```sh +$ # clone 源代码 +$ git clone https://github.com/apache/dubbo-samples.git +$ cd dubbo-samples/dubbo-samples-triple/ + +$ # 构建 +$ mvn clean compile package -DskipTests + +$ # 运行 provider +$ java -Dprovider.port=8888 -jar ./target/dubbo-samples-triple-1.0-SNAPSHOT.jar +# ……省略部分日志 +Dubbo triple stub server started, port=8888 +``` + +[Java 侧的接口定义](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/proto/greeter.proto) + +## 3 运行 Rust 版本的 Dubbo consumer + +Rust 版本的 Dubbo consumer 示例源码见。 + +Clone 源代码、编译构建,并运行 consumer: + +```sh +$ # clone 源代码 +$ git clone https://github.com/apache/dubbo-rust.git +$ cd dubbo-rust/examples/greeter/ + +$ # 构建 +$ cargo build + +$ # 运行 consumer,调用provider +$ ../../target/debug/greeter-client +# unary call +Response: GreeterReply { message: "hello, dubbo-rust" } +# client stream +client streaming, Response: GreeterReply { message: "hello client streaming" } +# bi stream +parts: Metadata { inner: {"content-type": "application/grpc", "date": "Wed, 28 Sep 2022 23:54:56 GMT"} } +reply: GreeterReply { message: "server reply: \"msg1 from client\"" } +reply: GreeterReply { message: "server reply: \"msg2 from client\"" } +reply: GreeterReply { message: "server reply: \"msg3 from client\"" } +trailer: Some(Metadata { inner: {"grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity", "content-type": "application/grpc", "grpc-status": "0"} }) +# server stream +parts: Metadata { inner: {"content-type": "application/grpc", "date": "Wed, 28 Sep 2022 23:54:56 GMT"} } +reply: GreeterReply { message: "msg1 from server" } +reply: GreeterReply { message: "msg2 from server" } +reply: GreeterReply { message: "msg3 from server" } +trailer: Some(Metadata { inner: {"content-type": "application/grpc", "grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity", "grpc-status": "0"} }) +``` + +[Rust侧的接口定义](https://github.com/apache/dubbo-rust/blob/main/examples/greeter/proto/greeter.proto) \ No newline at end of file diff --git a/content/en/overview/mannual/rust-sdk/quick-start.md b/content/en/overview/mannual/rust-sdk/quick-start.md new file mode 100644 index 000000000000..9fa9f61dd4a6 --- /dev/null +++ b/content/en/overview/mannual/rust-sdk/quick-start.md @@ -0,0 +1,256 @@ +--- +aliases: + - /zh/docs3-v2/rust-sdk/quick-start/ + - /zh-cn/docs3-v2/rust-sdk/quick-start/ + - /zh/overview/quickstart/rust/ + - /zh-cn/overview/quickstart/rust/ +description: 使用 Rust 快速开发 Dubbo 服务。 +linkTitle: 快速开始 +title: 快速开始 +type: docs +weight: 1 +--- + + + + + + +请在此查看完整 [示例](https://github.com/apache/dubbo-rust/tree/main/examples/greeter)。 + +## 1 前置条件 +- 安装 [Rust](https://rustup.rs/) 开发环境 +- 安装 [protoc](https://grpc.io/docs/protoc-installation/) 工具 + +## 2 使用 IDL 定义 Dubbo 服务 + +Greeter 服务定义如下,包含一个 Unary(request-response) 模型的 Dubbo 服务。 + +```protobuf +// ./proto/greeter.proto +syntax = "proto3"; + +option java_multiple_files = true; + +package org.apache.dubbo.sample.tri; + + +// The request message containing the user's name. +message GreeterRequest { + string name = 1; +} + +// The response message containing the greetings +message GreeterReply { + string message = 1; +} + +service Greeter{ + // unary + rpc greet(GreeterRequest) returns (GreeterReply); +} +``` + +## 3 添加 Dubbo-rust 及相关依赖到项目 +```toml +# ./Cargo.toml +[package] +name = "example-greeter" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "greeter-server" +path = "src/greeter/server.rs" + +[[bin]] +name = "greeter-client" +path = "src/greeter/client.rs" + +[dependencies] +http = "0.2" +http-body = "0.4.4" +futures-util = {version = "0.3", default-features = false} +tokio = { version = "1.0", features = [ "rt-multi-thread", "time", "fs", "macros", "net", "signal"] } +prost-derive = {version = "0.10", optional = true} +prost = "0.10.4" +async-trait = "0.1.56" +tokio-stream = "0.1" + +dubbo = "0.1.0" +dubbo-config = "0.1.0" + +[build-dependencies] +dubbo-build = "0.1.0" +``` + +## 4 配置 dubbo-build 编译 IDL + +在项目根目录创建 (not /src),创建 `build.rs` 文件并添加以下内容: + +```rust +// ./build.rs +fn main() { + dubbo_build::prost::configure() + .compile(&["proto/greeter.proto"], &["proto/"]) + .unwrap(); +} +``` +这样配置之后,编译项目就可以生成 Dubbo Stub 相关代码,路径一般在`./target/debug/build/example-greeter-/out/org.apache.dubbo.sample.tri.rs`。 + +## 5 编写 Dubbo 业务代码 + +### 5.1 编写 Dubbo Server + +```rust +// ./src/greeter/server.rs +use ... + +#[tokio::main] +async fn main() { + register_server(GreeterServerImpl { + name: "greeter".to_string(), + }); + + // Dubbo::new().start().await; + Dubbo::new() + .with_config({ + let r = RootConfig::new(); + match r.load() { + Ok(config) => config, + Err(_err) => panic!("err: {:?}", _err), // response was droped + } + }) + .start() + .await; +} + +#[allow(dead_code)] +#[derive(Default, Clone)] +struct GreeterServerImpl { + name: String, +} + +// #[async_trait] +#[async_trait] +impl Greeter for GreeterServerImpl { + async fn greet( + &self, + request: Request, + ) -> Result, dubbo::status::Status> { + println!("GreeterServer::greet {:?}", request.metadata); + + Ok(Response::new(GreeterReply { + message: "hello, dubbo-rust".to_string(), + })) + } +} +``` + +### 5.2 配置dubbo.yaml + +dubbo.yaml指示server端的配置,包括暴露的服务列表、协议配置、监听配置等。 + +```yaml +# ./dubbo.yaml +name: dubbo +service: + org.apache.dubbo.sample.tri.Greeter: + version: 1.0.0 + group: test + protocol: triple + registry: '' + serializer: json + protocol_configs: + triple: + ip: 0.0.0.0 + port: '8888' + name: triple +protocols: + triple: + ip: 0.0.0.0 + port: '8888' + name: triple +``` + +### 5.3 编写 Dubbo Client + +```rust +// ./src/greeter/client.rs +use ... + +#[tokio::main] +async fn main() { + let mut cli = GreeterClient::new().with_uri("http://127.0.0.1:8888".to_string()); + + println!("# unary call"); + let resp = cli + .greet(Request::new(GreeterRequest { + name: "message from client".to_string(), + })) + .await; + let resp = match resp { + Ok(resp) => resp, + Err(err) => return println!("{:?}", err), + }; + let (_parts, body) = resp.into_parts(); + println!("Response: {:?}", body); +} +``` + +## 6 运行并总结 + +1. 编译 + +执行`cargo build`来编译server和client。 + +2. 运行server + +执行`./target/debug/greeter-server`来运行server,如上文dubbo.yaml所配置,server会监听8888端口,并以triple协议提供RPC服务: + +```sh +$ ./target/debug/greeter-server +2022-09-28T23:33:28.104577Z INFO dubbo::framework: url: Some(Url { uri: "triple://0.0.0.0:8888/org.apache.dubbo.sample.tri.Greeter", protocol: "triple", location: "0.0.0.0:8888", ip: "0.0.0.0", port: "8888", service_key: ["org.apache.dubbo.sample.tri.Greeter"], params: {} }) +``` + +3. 运行client,验证调用是否成功 + +执行`./target/debug/greeter-client`来运行client,调用`triple://127.0.0.1:8888/org.apache.dubbo.sample.tri.Greeter`下的各种方法: + + +```sh +$ ./target/debug/greeter-client +Response: GreeterReply { message: "hello, dubbo-rust" } +``` + +## 7 更多示例 + +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ Streaming 通信模式 +

+

使用 Dubbo Rust 实现 Streaming 通信模型。

+
+
+
+
+
+
+

+ 与 Dubbo Java 互通 +

+

实现与其他 Dubbo 多语言服务的互通

+
+
+
+
+
+
+ +{{< /blocks/section >}} diff --git a/content/en/overview/mannual/rust-sdk/router-module.md b/content/en/overview/mannual/rust-sdk/router-module.md new file mode 100644 index 000000000000..6b78285c9c48 --- /dev/null +++ b/content/en/overview/mannual/rust-sdk/router-module.md @@ -0,0 +1,153 @@ +--- +aliases: + - /zh/docs3-v2/rust-sdk/router-module/ + - /zh-cn/docs3-v2/rust-sdk/router-module/ +description: "服务路由" +linkTitle: 服务路由 +title: 服务路由规则 +type: docs +weight: 2 +--- + +## 条件路由 +使用模式与 [条件路由文档](/zh/overview/core-features/traffic/condition-rule/) 中的模式类似,但配置格式略有不同,以下是条件路由规则示例。 + +基于以下示例规则,所有 `org.apache.dubbo.sample.tri.Greeter` 服务 `greet` +方法的调用都将被转发到有 `port=8888` 标记的地址子集 + +```yaml +configVersion: v1.0 +scope: "service" +force: false +enabled: true +key: "org.apache.dubbo.sample.tri.Greeter" +conditions: + - method=greet => port=8888 +``` +注:
+dubbo rust目前还没有实现对于**应用粒度**的区分,无法区分服务来自哪个应用
+因此对于标签路由和条件路由,都仅能配置一条应用级别的配置
+对于应用级别的配置,默认key指定为application,此配置将对全部服务生效
+例如: +```yaml +configVersion: v1.0 +scope: "application" +force: false +enabled: true +key: application +conditions: + - ip=127.0.0.1 => port=8000~8888 +``` + +#### 匹配/过滤条件 + +**参数支持** + +* 服务调用上下文,如:service_name, method等 +* URL 本身的字段,如:location, ip, port等 +* URL params中存储的字段信息 + +**条件支持** + +* 等号 = 表示 "匹配",如:method = getComment +* 不等号 != 表示 "不匹配",如:method != getComment + +**值支持** + +* 以逗号 , 分隔多个值,如:ip != 10.20.153.10,10.20.153.11 +* 以星号 * 结尾,表示通配,如:ip != 10.20.* +* 整数值范围,如:port = 80~8080 + + +## 标签路由 +使用模式与 [标签路由文档](/zh/overview/core-features/traffic/tag-rule/)中的模式类似,但配置格式略有不同,以下是标签路由规则示例 +```yaml +configVersion: v1.0 +force: false +enabled: true +key: application +tags: + - name: local + match: + - key: ip + value: 127.0.0.1 +``` +在此配置中,所有ip=127.0.0.1的服务提供者/消费者均会被打上local的标签 + +## 动态配置 +### 动态下发配置 简介 +动态下发配置使用 Nacos 作为配置中心实现,需要在项目的 application.yaml 配置文件中对 Nacos 进行配置,若不进行配置则使用本地路由配置。 +### 使用方式: +```yaml +nacos: + addr: "127.0.0.1:8848" + namespace: "namespace-name" + app: "app-name" + enable_auth: + auth_username: username + auth_password: password +``` +app:路由配置项在Nacos中所处的app +namespace:配置信息在Nacos所处的namespace +addr:Nacos服务地址 +enable_auth:可选配置项,若启用了Nacos的认证功能,则需要配置此项,auth_username对应帐号,auth_password对应密钥 + + +#### 配置条件路由 + +在nacos中创建条件路由配置项时, +app和namespace为配置nacos时所填写的信息; +group:固定为condition; +name:需要和 服务名称 保持一致; + + +#### 配置标签路由 +在nacos中创建标签路由配置项时, + +app:配置nacos时所填写的app; +namespace:配置nacos时所填写的namespace; +group:固定为tag; +name:固定为application; + +#### 注意事项 +dubbo rust目前还没有实现对于**应用**的区分,无法区分服务来自哪个应用; +故对于应用级别的配置项,默认对所有服务生效 +因此对于标签路由和条件路由,都仅能配置一条应用级别的配置,配置名称(name)指定为application + +#### 例: +![nacos-example.png](/imgs/rust/router-example/nacos-example.png) +#### 对应的配置项: + +*服务级别的条件路由配置:* +```yaml +configVersion: v1.0 +scope: "service" +force: false +enabled: true +key: "org.apache.dubbo.sample.tri.Greeter" +conditions: + - method=greet => ip=127.* +``` +*标签路由配置:* +```yaml +configVersion: v1.0 +force: true +enabled: true +key: shop-detail +tags: + - name: local + match: + - key: ip + value: 127.0.0.1 +``` + +*应用级别的条件路由配置:* +```yaml +configVersion: v1.0 +scope: "application" +force: false +enabled: true +key: application +conditions: + - ip=127.0.0.1 => port=8000~8888 +``` \ No newline at end of file diff --git a/content/en/overview/mannual/rust-sdk/service-discovery.md b/content/en/overview/mannual/rust-sdk/service-discovery.md new file mode 100644 index 000000000000..d22c33572b27 --- /dev/null +++ b/content/en/overview/mannual/rust-sdk/service-discovery.md @@ -0,0 +1,100 @@ +--- +aliases: + - /zh/docs3-v2/rust-sdk/service-discovery/ + - /zh-cn/docs3-v2/rust-sdk/service-discovery/ +description: 服务发现 +linkTitle: 服务发现 +title: 服务发现 +type: docs +weight: 2 +--- + +## Dubbo Rust服务发现简介 +Dubbo Rust提供的是一种 Client-Based 的服务发现机制,依赖第三方注册中心组件来协调服务发现过程,支持的注册中心: Nacos、Zookeeper + +以下是 Dubbo Rust服务发现机制的基本工作原理图: + +![service-discovery](/imgs/rust/dubbo-rust-service-discovery.png) + +服务发现包含提供者、消费者和注册中心三个参与角色,其中,Dubbo 提供者实例注册 URL 地址到注册中心,注册中心负责对数据进行聚合,Dubbo 消费者从注册中心读取地址列表并订阅变更,每当地址列表发生变化,注册中心将最新的列表通知到所有订阅的消费者实例。 + +* Dubbo Rust注册中心以服务粒度聚合实例数据,消费者按消费需求精准订阅。 + +Dubbo Rust服务发现的一个示例:[example](https://github.com/apache/dubbo-rust/tree/feat/cluster/examples/greeter) + +## 高效地址推送实现 + +从注册中心视角来看,它负责以服务名 (例如:org.apache.dubbo.sample.tri.Greeter) 对整个集群的实例地址进行聚合,每个对外提供服务的实例将自身的实例ip:port 地址信息 (例如:127.0.0.1:8848) 注册到注册中心。 + +## 配置方式 +Dubbo Rust服务发现支持两种注册中心组件,既Nacos、Zookeeper,可以通过以下方式创建不同的注册中心,并将其绑定到Dubbo Rust框架。 + +配置方式: +假设有服务:Greeter,对应的服务实现为GreeterServerImpl + +服务端: +``` + //注册服务 + register_server(GreeterServerImpl { + name: "greeter".to_string(), + }); + + //创建注册中心 + let zkr = ZookeeperRegistry::default(); + + let r = RootConfig::new(); + let r = match r.load() { + Ok(config) => config, + Err(_err) => panic!("err: {:?}", _err), // response was droped + }; + + //启动Dubbo框架 + let mut f = Dubbo::new() + .with_config(r) + //将创建出的注册中心绑定Dubbo框架 + .add_registry("zookeeper", Box::new(zkr)); + f.start().await; +``` +对于上述过程,可以通过修改创建注册中心的步骤来更改所使用的注册中心 + +客户端: +``` + let mut builder = ClientBuilder::new(); + + //通过env获取注册中心地址 + if let Ok(zk_servers) = env::var("ZOOKEEPER_SERVERS") { + //创建注册中心 + let zkr = ZookeeperRegistry::new(&zk_servers); + //绑定注册中心 + let directory = RegistryDirectory::new(Box::new(zkr)); + builder = builder.with_directory(Box::new(directory)); + } else if let Ok(nacos_url_str) = env::var("NACOS_URL") { + // NACOS_URL=nacos://mse-96efa264-p.nacos-ans.mse.aliyuncs.com + //创建注册中心 + let nacos_url = Url::from_url(&nacos_url_str).unwrap(); + let registry = NacosRegistry::new(nacos_url); + //绑定注册中心 + let directory = RegistryDirectory::new(Box::new(registry)); + builder = builder.with_directory(Box::new(directory)); + } else { + builder = builder.with_host("http://127.0.0.1:8888"); + } + + let mut cli = GreeterClient::new(builder); +``` + +创建Nacos注册中心: +``` +//通过Url创建注册中心实例 +let nacos_url = Url::from_url("127.0.0.1:1221").unwrap(); +let registry = NacosRegistry::new(nacos_url); +``` +创建Zookeeper注册中心: +``` +//直接创建Zookeeper注册中心 +let zkr = ZookeeperRegistry::new("127.0.0.1:1221"); +``` +``` +//使用default方法创建Zookeeper注册中心会默认使用环境变量中的值ZOOKEEPER_SERVERS +let zkr = ZookeeperRegistry::default(); +``` diff --git a/content/en/overview/mannual/rust-sdk/streaming.md b/content/en/overview/mannual/rust-sdk/streaming.md new file mode 100644 index 000000000000..2352eefc65a2 --- /dev/null +++ b/content/en/overview/mannual/rust-sdk/streaming.md @@ -0,0 +1,389 @@ +--- +aliases: + - /zh/docs3-v2/rust-sdk/streaming/ + - /zh-cn/docs3-v2/rust-sdk/streaming/ +description: 介绍使用 Dubbo Rust 快速开发 Client streaming、Server streaming、Bidirectional streaming 模型的服务。 +linkTitle: Streaming通信模型 +title: Streaming 通信模型 +type: docs +weight: 3 +--- + + + + + + +本文重点讲解 Dubbo Rust Streaming 通信模式,请先查看 [Quick Start](../quick-start) 了解 Dubbo Rust 基本使用,在此查看本文的[完整示例](https://github.com/apache/dubbo-rust/tree/main/examples/greeter)。 + +## 1 IDL 中增加 Streaming 模型定义 + +完整 Greeter 服务定义如下,包含一个 Unary、Client stream、Server stream、Bidirectional stream 模型的 Dubbo 服务。 + +```protobuf +// ./proto/greeter.proto +syntax = "proto3"; + +option java_multiple_files = true; + +package org.apache.dubbo.sample.tri; + + +// The request message containing the user's name. +message GreeterRequest { + string name = 1; +} + +// The response message containing the greetings +message GreeterReply { + string message = 1; +} + +service Greeter{ + + // unary + rpc greet(GreeterRequest) returns (GreeterReply); + + // clientStream + rpc greetClientStream(stream GreeterRequest) returns (GreeterReply); + + // serverStream + rpc greetServerStream(GreeterRequest) returns (stream GreeterReply); + + // bi streaming + rpc greetStream(stream GreeterRequest) returns (stream GreeterReply); + +} +``` + +## 2 使用 Streaming 模型定义编写逻辑 + +### 2.1 编写 Streaming Server + +```rust +// ./src/greeter/server.rs +pub mod protos { + include!(concat!(env!("OUT_DIR"), "/org.apache.dubbo.sample.tri.rs")); +} + +use futures_util::StreamExt; +use protos::{ + greeter_server::{register_server, Greeter}, + GreeterReply, GreeterRequest, +}; + +use std::{io::ErrorKind, pin::Pin}; + +use async_trait::async_trait; +use futures_util::Stream; +use tokio::sync::mpsc; +use tokio_stream::wrappers::ReceiverStream; + +use dubbo_config::RootConfig; +use dubbo::{codegen::*, Dubbo}; + +type ResponseStream = + Pin> + Send>>; + +#[tokio::main] +async fn main() { + register_server(GreeterServerImpl { + name: "greeter".to_string(), + }); + + // Dubbo::new().start().await; + Dubbo::new() + .with_config({ + let r = RootConfig::new(); + match r.load() { + Ok(config) => config, + Err(_err) => panic!("err: {:?}", _err), // response was droped + } + }) + .start() + .await; +} + +#[allow(dead_code)] +#[derive(Default, Clone)] +struct GreeterServerImpl { + name: String, +} + +// #[async_trait] +#[async_trait] +impl Greeter for GreeterServerImpl { + async fn greet( + &self, + request: Request, + ) -> Result, dubbo::status::Status> { + println!("GreeterServer::greet {:?}", request.metadata); + + Ok(Response::new(GreeterReply { + message: "hello, dubbo-rust".to_string(), + })) + } + + async fn greet_client_stream( + &self, + request: Request>, + ) -> Result, dubbo::status::Status> { + let mut s = request.into_inner(); + loop { + let result = s.next().await; + match result { + Some(Ok(val)) => println!("result: {:?}", val), + Some(Err(val)) => println!("err: {:?}", val), + None => break, + } + } + Ok(Response::new(GreeterReply { + message: "hello client streaming".to_string(), + })) + } + + type greetServerStreamStream = ResponseStream; + async fn greet_server_stream( + &self, + request: Request, + ) -> Result, dubbo::status::Status> { + println!("greet_server_stream: {:?}", request.into_inner()); + + let data = vec![ + Result::<_, dubbo::status::Status>::Ok(GreeterReply { + message: "msg1 from server".to_string(), + }), + Result::<_, dubbo::status::Status>::Ok(GreeterReply { + message: "msg2 from server".to_string(), + }), + Result::<_, dubbo::status::Status>::Ok(GreeterReply { + message: "msg3 from server".to_string(), + }), + ]; + let resp = futures_util::stream::iter(data); + + Ok(Response::new(Box::pin(resp))) + } + + type greetStreamStream = ResponseStream; + async fn greet_stream( + &self, + request: Request>, + ) -> Result, dubbo::status::Status> { + println!( + "GreeterServer::greet_stream, grpc header: {:?}", + request.metadata + ); + + let mut in_stream = request.into_inner(); + let (tx, rx) = mpsc::channel(128); + + // this spawn here is required if you want to handle connection error. + // If we just map `in_stream` and write it back as `out_stream` the `out_stream` + // will be drooped when connection error occurs and error will never be propagated + // to mapped version of `in_stream`. + tokio::spawn(async move { + while let Some(result) = in_stream.next().await { + match result { + Ok(v) => { + // if v.name.starts_with("msg2") { + // tx.send(Err(dubbo::status::Status::internal(format!("err: args is invalid, {:?}", v.name)) + // )).await.expect("working rx"); + // continue; + // } + tx.send(Ok(GreeterReply { + message: format!("server reply: {:?}", v.name), + })) + .await + .expect("working rx") + } + Err(err) => { + if let Some(io_err) = match_for_io_error(&err) { + if io_err.kind() == ErrorKind::BrokenPipe { + // here you can handle special case when client + // disconnected in unexpected way + eprintln!("\tclient disconnected: broken pipe"); + break; + } + } + + match tx.send(Err(err)).await { + Ok(_) => (), + Err(_err) => break, // response was droped + } + } + } + } + println!("\tstream ended"); + }); + + // echo just write the same data that was received + let out_stream = ReceiverStream::new(rx); + + Ok(Response::new( + Box::pin(out_stream) as Self::greetStreamStream + )) + } +} + +fn match_for_io_error(err_status: &dubbo::status::Status) -> Option<&std::io::Error> { + let mut err: &(dyn std::error::Error + 'static) = err_status; + + loop { + if let Some(io_err) = err.downcast_ref::() { + return Some(io_err); + } + + err = match err.source() { + Some(err) => err, + None => return None, + }; + } +} +``` + +### 2.2 编写 Streaming Client + +```rust +// ./src/greeter/client.rs +pub mod protos { + include!(concat!(env!("OUT_DIR"), "/org.apache.dubbo.sample.tri.rs")); +} + +use dubbo::codegen::*; +use futures_util::StreamExt; +use protos::{greeter_client::GreeterClient, GreeterRequest}; + +#[tokio::main] +async fn main() { + let mut cli = GreeterClient::new().with_uri("http://127.0.0.1:8888".to_string()); + + println!("# unary call"); + let resp = cli + .greet(Request::new(GreeterRequest { + name: "message from client".to_string(), + })) + .await; + let resp = match resp { + Ok(resp) => resp, + Err(err) => return println!("{:?}", err), + }; + let (_parts, body) = resp.into_parts(); + println!("Response: {:?}", body); + + println!("# client stream"); + let data = vec![ + GreeterRequest { + name: "msg1 from client streaming".to_string(), + }, + GreeterRequest { + name: "msg2 from client streaming".to_string(), + }, + GreeterRequest { + name: "msg3 from client streaming".to_string(), + }, + ]; + let req = futures_util::stream::iter(data); + let resp = cli.greet_client_stream(req).await; + let client_streaming_resp = match resp { + Ok(resp) => resp, + Err(err) => return println!("{:?}", err), + }; + let (_parts, resp_body) = client_streaming_resp.into_parts(); + println!("client streaming, Response: {:?}", resp_body); + + println!("# bi stream"); + let data = vec![ + GreeterRequest { + name: "msg1 from client".to_string(), + }, + GreeterRequest { + name: "msg2 from client".to_string(), + }, + GreeterRequest { + name: "msg3 from client".to_string(), + }, + ]; + let req = futures_util::stream::iter(data); + + let bidi_resp = cli.greet_stream(req).await.unwrap(); + + let (parts, mut body) = bidi_resp.into_parts(); + println!("parts: {:?}", parts); + while let Some(item) = body.next().await { + match item { + Ok(v) => { + println!("reply: {:?}", v); + } + Err(err) => { + println!("err: {:?}", err); + } + } + } + let trailer = body.trailer().await.unwrap(); + println!("trailer: {:?}", trailer); + + println!("# server stream"); + let resp = cli + .greet_server_stream(Request::new(GreeterRequest { + name: "server streaming req".to_string(), + })) + .await + .unwrap(); + + let (parts, mut body) = resp.into_parts(); + println!("parts: {:?}", parts); + while let Some(item) = body.next().await { + match item { + Ok(v) => { + println!("reply: {:?}", v); + } + Err(err) => { + println!("err: {:?}", err); + } + } + } + let trailer = body.trailer().await.unwrap(); + println!("trailer: {:?}", trailer); +} +``` + +## 3 运行示例 + +1. 编译 + +执行`cargo build`来编译server和client。 + +2. 运行server + +执行`./target/debug/greeter-server`来运行server,如上文dubbo.yaml所配置,server会监听8888端口,并以triple协议提供RPC服务: + +```sh +$ ./target/debug/greeter-server +2022-09-28T23:33:28.104577Z INFO dubbo::framework: url: Some(Url { uri: "triple://0.0.0.0:8888/org.apache.dubbo.sample.tri.Greeter", protocol: "triple", location: "0.0.0.0:8888", ip: "0.0.0.0", port: "8888", service_key: ["org.apache.dubbo.sample.tri.Greeter"], params: {} }) +``` + +3. 运行client,可以看到 Streaming 通信效果 + +执行`./target/debug/greeter-client`来运行client,调用`triple://127.0.0.1:8888/org.apache.dubbo.sample.tri.Greeter`下的各种方法: + + +```sh +$ ./target/debug/greeter-client +# unary call +Response: GreeterReply { message: "hello, dubbo-rust" } +# client stream +client streaming, Response: GreeterReply { message: "hello client streaming" } +# bi stream +parts: Metadata { inner: {"content-type": "application/grpc", "date": "Wed, 28 Sep 2022 23:34:20 GMT"} } +reply: GreeterReply { message: "server reply: \"msg1 from client\"" } +reply: GreeterReply { message: "server reply: \"msg2 from client\"" } +reply: GreeterReply { message: "server reply: \"msg3 from client\"" } +trailer: Some(Metadata { inner: {"content-type": "application/grpc", "grpc-status": "0", "grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity"} }) +# server stream +parts: Metadata { inner: {"content-type": "application/grpc", "date": "Wed, 28 Sep 2022 23:34:20 GMT"} } +reply: GreeterReply { message: "msg1 from server" } +reply: GreeterReply { message: "msg2 from server" } +reply: GreeterReply { message: "msg3 from server" } +trailer: Some(Metadata { inner: {"content-type": "application/grpc", "grpc-status": "0", "grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity"} }) +``` \ No newline at end of file diff --git a/content/en/overview/mannual/rust-sdk/unix-transport.md b/content/en/overview/mannual/rust-sdk/unix-transport.md new file mode 100644 index 000000000000..48c0a4191c7f --- /dev/null +++ b/content/en/overview/mannual/rust-sdk/unix-transport.md @@ -0,0 +1,84 @@ +--- +aliases: + - /zh/docs3-v2/rust-sdk/unix-transport/ + - /zh-cn/docs3-v2/rust-sdk/unix-transport/ +description: 介绍使用 Dubbo Rust Triple 协议使用 Unix 套接字连接器实现通信。 +linkTitle: 使用Unix套接字连接器通信 +title: 使用Unix套接字连接器通信 +type: docs +weight: 3 +--- + + + + + + +本文重点讲解 Dubbo Rust Triple 协议使用Unix 套接,请先查看 [Quick Start](../quick-start) 了解 Dubbo Rust 基本使用,在此查看本文的[完整示例](https://github.com/apache/dubbo-rust/tree/main/examples/greeter)。 + +## 1 使用 Unix 套接字连接器 说明 +> #[cfg(any(target_os = "macos", target_os="unix"))] 当操作系统符合cfg配置时,unix 模块会被编译使用,否则无法使用 + +## 2 使用 client/connection 使用 Unix 套接字连接器编写逻辑 + +### 2.1 编写 Client 端 + +```rust +// examples/echo/src/echo/client.rs +// 使用 ClientBuilder 初始化 Client +let builder = ClientBuilder::new().with_connector("unix").with_host("unix://127.0.0.1:8888"); +let mut cli = EchoClient::build(builder); +``` + +### 2.2 编写 Server 端 + +```rust +// examples/echo/src/echo/server.rs +// 通过 serverbuilder 来初始化 Server +let builder = ServerBuilder::new() + .with_listener("unix".to_string()) + .with_service_names(vec!["grpc.examples.echo.Echo".to_string()]) + .with_addr("127.0.0.1:8888"); +builder.build().serve().await.unwrap(); + +``` + +## 3 运行示例 + +1. 编译 + +执行`cargo build`来编译server和client。 + +2. 运行server + +执行`cargo run --bin echo-server`来运行server,如上文dubbo.yaml所配置,server会监听8888端口,并以triple协议提供RPC服务: + +```sh +$ cargo run --bin echo-server +2023-01-19T08:36:25.663138Z INFO dubbo::triple::server::builder: server starting. addr: Some(127.0.0.1:8888) +``` + +3. 运行client,可以看到 Unix 通信效果 + +执行`cargo run --bin echo-client`来运行client,调用`triple://127.0.0.1:8888/org.apache.dubbo.sample.tri.Greeter`下的各种方法: + + +```sh +$ cargo run --bin echo-client +2023-01-19T08:38:52.516792Z INFO dubbo::triple::transport::connector::unix_connector: host is ip address: "127.0.0.1" +Response: EchoResponse { message: "hello, dubbo-rust" } +2023-01-19T08:38:52.526697Z INFO dubbo::triple::transport::connector::unix_connector: host is ip address: "127.0.0.1" +client streaming, Response: EchoResponse { message: "hello client streaming" } +2023-01-19T08:38:52.539439Z INFO dubbo::triple::transport::connector::unix_connector: host is ip address: "127.0.0.1" +parts: Metadata { inner: {"content-type": "application/grpc", "date": "Thu, 19 Jan 2023 08:38:52 GMT"} } +reply: EchoResponse { message: "server reply: \"msg1 from client\"" } +reply: EchoResponse { message: "server reply: \"msg2 from client\"" } +reply: EchoResponse { message: "server reply: \"msg3 from client\"" } +trailer: Some(Metadata { inner: {"grpc-accept-encoding": "gzip,identity", "grpc-status": "0", "grpc-message": "poll trailer successfully.", "content-type": "application/grpc"} }) +2023-01-19T08:38:52.645035Z INFO dubbo::triple::transport::connector::unix_connector: host is ip address: "127.0.0.1" +parts: Metadata { inner: {"content-type": "application/grpc", "date": "Thu, 19 Jan 2023 08:38:52 GMT"} } +reply: EchoResponse { message: "msg1 from server" } +reply: EchoResponse { message: "msg2 from server" } +reply: EchoResponse { message: "msg3 from server" } +trailer: Some(Metadata { inner: {"grpc-status": "0", "content-type": "application/grpc", "grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity"} }) +``` \ No newline at end of file diff --git a/content/en/overview/mannual/web-sdk/_index.md b/content/en/overview/mannual/web-sdk/_index.md new file mode 100755 index 000000000000..0c16b02ac2d5 --- /dev/null +++ b/content/en/overview/mannual/web-sdk/_index.md @@ -0,0 +1,7 @@ +--- +description: Web SDK 使用手册 +linkTitle: Web SDK +title: Web SDK 手册 +type: docs +weight: 4 +--- diff --git a/content/en/overview/mannual/web-sdk/quick-start.md b/content/en/overview/mannual/web-sdk/quick-start.md new file mode 100644 index 000000000000..b3690167fabb --- /dev/null +++ b/content/en/overview/mannual/web-sdk/quick-start.md @@ -0,0 +1,267 @@ +--- +aliases: + - /zh/docs3-v2/rust-sdk/quick-start/ + - /zh-cn/docs3-v2/rust-sdk/quick-start/ +description: 使用 dubbo-js 开发运行在浏览器页面的微服务。 +linkTitle: Web浏览器访问Dubbo服务 +title: Web 浏览器访问 Dubbo 服务 +type: docs +weight: 1 +--- + +基于 Dubbo3 定义的 Triple 协议,你可以轻松编写浏览器、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。[Dubbo TypeScript SDK](https://github.com/apache/dubbo-js/) 支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 API 来发布或调用这些服务。 + +Dubbo-js 已于 9 月份发布支持 Dubbo3 协议的首个 alpha 版本,它的发布将有机会彻底改变微服务前后端的架构与通信模式,让你能直接在浏览器页面或web服务器中访问后端 Dubbo RPC 服务。 + +![dubbo-web.png](/imgs/v3/web/web-1.png) + +# 浏览器 Web 应用示例 + +本示例演示了如何使用 dubbo-js 开发运行在浏览器上的 web 应用程序,web 页面将调用 dubbo node.js 开发的后端服务并生成页面内容。本示例演示基于 IDL 和非 IDL 两种编码模式。 + +![dubbo-web.png](/imgs/v3/web/web-2.png) + +## IDL 模式 + +### 前置条件 + +首先,我们将使用 Vite 来生成我们的前端项目模板,它内置了我们稍后需要的所有功能支持。 + +```shell +npm create vite@latest -- dubbo-web-example --template react-ts +cd dubbo-web-example +npm install +``` + +因为使用 Protocol Buffer 的原因,我们首先需要安装相关的代码生成工具,这包括 `@bufbuild/protoc-gen-es`、`@bufbuild/protobuf`、`@apachedubbo/protoc-gen-apache-dubbo-es`、`@apachedubbo/dubbo`。 + +```shell +npm install @bufbuild/protoc-gen-es @bufbuild/protobuf @apachedubbo/protoc-gen-apache-dubbo-es @apachedubbo/dubbo +``` + +### 使用 Proto 定义服务 + +现在,使用 Protocol Buffer (IDL) 来定义一个 Dubbo 服务。 + +src 下创建 util/proto 目录,并生成文件 + +```shell +mkdir -p src/util/proto && touch src/util/proto/example.proto +``` + +写入内容 + +```protobuf +syntax = "proto3"; + +package apache.dubbo.demo.example.v1; + +message SayRequest { + string sentence = 1; +} + +message SayResponse { + string sentence = 1; +} + +service ExampleService { + rpc Say(SayRequest) returns (SayResponse) {} +} +``` + +这个文件声明了一个叫做 `ExampleService` 的服务,为这个服务定义了 `Say` 方法以及它的请求参数 `SayRequest` 和返回值 `SayResponse`。 + +### 生成代码 + +创建 gen 目录,作为生成文件放置的目标目录 + +```shell +mkdir -p src/util/gen +``` + +运行以下命令,利用 `protoc-gen-es`、`protoc-gen-apache-dubbo-es` 等插件在 gen 目录下生成代码文件 + +```shell +PATH=$PATH:$(pwd)/node_modules/.bin \ + protoc -I src/util/proto \ + --es_out src/util/gen \ + --es_opt target=ts \ + --apache-dubbo-es_out src/util/gen \ + --apache-dubbo-es_opt target=ts \ + example.proto +``` + +运行命令后,应该可以在目标目录中看到以下生成的文件: + +``` +├── src +│ ├── util +│ │ ├── gen +│ │ │ ├── example_dubbo.ts +│ │ │ └── example_pb.ts +│ │ └── proto +│ │ └── example.proto +``` + +### 创建 App + +需要先下载 `@apachedubbo/dubbo-web` + +```shell +npm install @apachedubbo/dubbo-web +``` + +现在我们可以从包中导入服务并设置一个客户端。在 App.tsx 中添加以下内容: + +```typescript +import { useState } from "react"; +import "./App.css"; + +import { createPromiseClient } from "@apachedubbo/dubbo"; +import { createDubboTransport } from "@apachedubbo/dubbo-web"; + +// Import service definition that you want to connect to. +import { ExampleService } from "./util/gen/example_dubbo"; + +// The transport defines what type of endpoint we're hitting. +// In our example we'll be communicating with a Dubbo endpoint. +const transport = createDubboTransport({ + baseUrl: "http://localhost:8080", +}); + +// Here we make the client itself, combining the service +// definition with the transport. +const client = createPromiseClient(ExampleService, transport, { serviceGroup: 'dubbo', serviceVersion: '1.0.0' }); + +function App() { + const [inputValue, setInputValue] = useState(""); + const [messages, setMessages] = useState< + { + fromMe: boolean; + message: string; + }[] + >([]); + return ( + <> +
    + {messages.map((msg, index) => ( +
  1. {`${msg.fromMe ? "ME:" : "Dubbo Server:"} ${msg.message}`}
  2. + ))} +
+
{ + e.preventDefault(); + // Clear inputValue since the user has submitted. + setInputValue(""); + // Store the inputValue in the chain of messages and + // mark this message as coming from "me" + setMessages((prev) => [ + ...prev, + { + fromMe: true, + message: inputValue, + }, + ]); + const response = await client.say({ + sentence: inputValue, + }); + setMessages((prev) => [ + ...prev, + { + fromMe: false, + message: response.sentence, + }, + ]); + }} + > + setInputValue(e.target.value)} /> + +
+ + ); +} + +export default App; +``` + +执行以下命令,即可得到样例页面 + +```shell +npm run dev +``` + +### 启动 Server + +接下来我们需要启动 Server,可以使用 Java、Go、Node.js 等 Dubbo 支持的任一语言开发 Server。这里我们采用 Dubbo 服务嵌入的 Node.js 服务器,具体可参考 [Node.js 开发 Dubbo 后端服务](https://github.com/apache/dubbo-js/tree/dubbo3/example/dubbo-node-example) 中的操作步骤。 + +不过需要注意,我们额外需要修改 Node.js 示例:引入 @fastify/cors 来解决前端请求的跨域问题 + +```shell +npm install @fastify/cors +``` + +需要在 server.ts 文件下修改 + +```typescript +... +import cors from "@fastify/cors"; + +... +async function main() { + const server = fastify(); + ... + await server.register(cors, { + origin: true, + }); + ... + await server.listen({ host: "localhost", port: 8080 }); + ... +} + +void main(); +``` + +最后,运行代码启动服务 + +```shell +npx tsx server.ts +``` + +## 无 IDL 模式 + +在接下来的版本中,我们将继续提供无 IDL 模式的通信支持,这样就可以更方便的访问无 IDL 的后端服务。在这里,我们先快速的看一下无 IDL 模式的使用方式。 + +同样需要先安装 `@apachedubbo/dubbo`、`@apachedubbo/dubbo-web` + +```shell +npm install @apachedubbo/dubbo @apachedubbo/dubbo-web +``` + +现在就可以一个启动一个客户端,并发起调用了。App.tsx 中的代码与 IDL 模式基本一致,区别点在于以下内容: + +```typescript +// ... +// set backend server to connect +const transport = createDubboTransport({ + baseUrl: "http://localhost:8080", +}); +// init client +const client = createPromiseClient(transport); + +function App() { + // ... + // call remote Dubbo service + const response = await client.call( + "apache.dubbo.demo.example.v1.ExampleService", + "say", + { + sentence: inputValue, + }); +} +``` + +执行以下命令,即可得到样例页面 + +```shell +npm run dev +``` diff --git a/content/en/overview/notices/_index.md b/content/en/overview/notices/_index.md index 9a44e14bc7a7..647a8a0dcd9d 100755 --- a/content/en/overview/notices/_index.md +++ b/content/en/overview/notices/_index.md @@ -1,24 +1,23 @@ --- -title: "Security Notice" -linkTitle: "Security Notice" -description: "Dubbo Security Notice" +title: "安全公告" +linkTitle: "安全公告" +description: "Dubbo 安全公告" aliases: - /en/docs/notices/security + - /zh-cn/blog/notices/ weight: 50 type: docs --- -## Reporting security issues +## 报告安全问题 -The Apache Software Foundation takes a very active stance in eliminating security problems and denial of service attacks against its products. +Apache 软件基金会在消除针对其产品的安全问题和拒绝服务攻击方面采取了非常积极的立场。 -We strongly encourage folks to report such problems to our private security mailing list first, before disclosing them in a public forum. +我们强烈鼓励人们首先向我们的安全问题上报邮件列表报告此类问题,然后再在公共论坛上披露这些问题。 -Please note that the security mailing list should only be used for reporting undisclosed security vulnerabilities and managing the process of fixing such vulnerabilities. We cannot accept regular bug reports or other queries at this address. All mail sent to this address that does not relate to an undisclosed security problem in our source code will be ignored. +请注意,安全邮件列表仅应用于报告未公开的安全漏洞和管理修复此类漏洞的过程。我们无法在此地址接受定期错误报告或其他查询。发送到此地址的所有与我们源代码中未公开的安全问题无关的邮件都将被忽略。 -If you need to report a bug that isn't an undisclosed security vulnerability, please use the bug reporting page. +如果您需要报告非未公开安全漏洞的错误,请使用错误报告页面。 -The private security mailing address is: security@dubbo.apache.org - -For more information about how the ASF deals with security potential problems see https://www.apache.org/security/ +安全问题上报邮件地址:security@dubbo.apache.org +有关 ASF 如何处理安全潜在问题的更多信息,请参阅 https://www.apache.org/security/ diff --git a/content/en/overview/notices/admin.md b/content/en/overview/notices/admin.md index fa166d26e2ae..306ed30f1a22 100644 --- a/content/en/overview/notices/admin.md +++ b/content/en/overview/notices/admin.md @@ -1,30 +1,30 @@ --- -title: "Dubbo Admin Security" -linkTitle: "Dubbo Admin Security" +title: "Dubbo Admin 安全" +linkTitle: "Dubbo Admin 安全" weight: 4 type: docs -description: "Use Dubbo Admin more securely" +description: "更安全地使用 Dubbo Admin" --- -In order to facilitate the use of Dubbo, Dubbo officially provides the Dubbo Admin console to facilitate the management of Dubbo applications. +为了便于使用 Dubbo,Dubbo 官方提供了 Dubbo Admin 控制台,以便于管理 Dubbo 应用。 -## Risk +## 风险 -Dubbo Admin has query and call permissions for the entire cluster by default, so it needs to be used with more caution in the online environment. -In addition, in order to reduce the risk of arbitrary access to Dubbo Admin, Dubbo Admin also provides a simple authentication mechanism. -To make Dubbo Admin more secure, please refer to the documentation below. +Dubbo Admin 默认拥有整个集群的查询、调用权限,因此对于线上环境,需要更加谨慎地使用。 +此外,为了减低任意访问 Dubbo Admin 的风险,Dubbo Admin 还提供了简易的鉴权机制。 +为了使 Dubbo Admin 更安全,请参考下面的文档。 -## Authentication scheme +## 鉴权方案 -Dubbo Admin provides a login mechanism based on username and password by default, and authenticates based on JWT Token during the request process. -From the perspective of convenience for beginners, Dubbo Admin includes a default username, password, and JWT Secret Token. +Dubbo Admin 默认提供基于用户名密码的登陆机制,在请求过程中基于 JWT Token 进行鉴权。 +从便于初学者的角度出发,Dubbo Admin 包含了一个默认的用户名密码、JWT Secret Token。 -> **Since Dubbo Admin is publicly released, the default username, password, and JWT Secret Token are all public. -In your production environment, be sure to change the default username, password, and JWT Secret Token.** +> **由于 Dubbo Admin 是公开发行的,因此默认的用户名密码、JWT Secret Token 都是公开的。 +在您的生产环境中,请务必更换默认的用户名密码、JWT Secret Token。** -## How to change the default username, password, and JWT Secret Token +## 如何更换默认的用户名密码、JWT Secret Token -For users who package and deploy directly based on Java code, they can directly modify the following configuration in `dubbo-admin-server/src/main/resources/application.properties`: +对于直接基于 Java 代码打包部署的用户,可以直接修改 `dubbo-admin-server/src/main/resources/application.properties` 中以下配置: ```properties admin.root.user.name=root @@ -32,7 +32,7 @@ admin.root.user.password=root admin.check.signSecret=86295dd0c4ef69a1036b0b0c15158d77 ``` -For users deployed through Docker, you can modify the following configuration in `/dubbo/dubbo-admin/properties`: +对于通过 Docker 部署的用户,可以修改 `/dubbo/dubbo-admin/properties` 中以下配置: ```properties admin.root.user.name=root @@ -40,7 +40,7 @@ admin.root.user.password=root admin.check.signSecret=86295dd0c4ef69a1036b0b0c15158d77 ``` -For users deployed via Kubernetes, the following configurations in ConfigMap can be modified: +对于通过 Kubernetes 部署的用户,可以修改 ConfigMap 中以下配置: ```properties admin.root.user.name=root @@ -48,7 +48,7 @@ admin.root.user.password=root admin.check.signSecret=86295dd0c4ef69a1036b0b0c15158d77 ``` -For users deploying via Helm, you can specify the following configuration: +对于通过 Helm 部署的用户,可以指定以下配置: ```yaml properties: @@ -57,7 +57,7 @@ properties: admin.check.signSecret: 86295dd0c4ef69a1036b0b0c15158d77 ``` -## Best Practices +## 最佳实践 -1. Please update the default username, password, and JWT Secret Token during privatized deployment. It is recommended to modify the authentication logic of Dubbo Admin and connect it to your organization's personnel management system. -2. Do not directly expose the Dubbo Admin port to the Internet. +1. 请在私有化部署时更新默认的用户名密码、JWT Secret Token。建议修改 Dubbo Admin 的鉴权逻辑接入您所在组织的人员管理系统。 +2. 请勿直接把 Dubbo Admin 的端口暴露到互联网上。 diff --git a/content/en/overview/notices/log4j.md b/content/en/overview/notices/log4j.md index df732bf63e24..a2e670a1cc76 100755 --- a/content/en/overview/notices/log4j.md +++ b/content/en/overview/notices/log4j.md @@ -1,53 +1,53 @@ + --- -title: "Log4j vulnerability impact" -linkTitle: "Log4j vulnerability impact" -description: "Log4j CVE-2021-44228 vulnerability impact" +title: "Log4j 漏洞影响" +linkTitle: "Log4j 漏洞影响" +description: "Log4j CVE-2021-44228 漏洞影响" aliases: -- /zh-cn/blog/1/01/01/Security Vulnerability/ +- /zh-cn/blog/1/01/01/安全漏洞/ weight: 90 type: docs --- -Recently, the mainstream logging component [log4j2](https://logging.apache.org/log4j/2.x/) broke out [security vulnerability CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228). - -The following is a summary of the impact of vulnerability CVE-2021-44228 on the Apache Dubbo framework and user response guidelines. +最近,主流日志组件 [log4j2](https://logging.apache.org/log4j/2.x/) 爆出[安全漏洞 CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228)。 -## Dubbo scope of influence +以下是漏洞 CVE-2021-44228 对 Apache Dubbo 框架的影响总结及用户应对指南。 -**This vulnerability has no impact on the security of Dubbo framework. ** +## Dubbo 影响范围 +**该漏洞对 Dubbo 框架使用安全并无影响。** -Dubbo itself does not rely heavily on the log4j2 framework, nor does it bring log4j2 to business projects through dependency transfer. Therefore, users who are using Dubbo 2.7.x, 3.0.x and other versions do not need to be forced to upgrade the Dubbo version. +Dubbo 本身不强依赖 log4j2 框架,也不会通过依赖传递将 log4j2 带到业务工程中去,因此,正在使用 Dubbo 2.7.x、3.0.x 等版本的用户均无需强制升级 Dubbo 版本。 -The following is an analysis of the dependence of Dubbo components on log4j2, involving `dubbo-common`, `dubbo-spring-boot-starter`, and `dubbo-spring-boot-actuator`: +以下是 Dubbo 各组件对 log4j2 的依赖分析,涉及 `dubbo-common`、`dubbo-spring-boot-starter`、`dubbo-spring-boot-actuator`: -* dubbo-common includes an optional dependency on `log4j-core`. Please check whether the log4j dependency is enabled in the project itself. If so, upgrade accordingly. +* dubbo-common 包含对 `log4j-core` 的可选依赖,请检查项目自身是否启用了 log4j 依赖,如启用则对应升级即可。 ```xml -[INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @dubbo-common --- +[INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ dubbo-common --- [INFO] org.apache.dubbo:dubbo-common:jar:2.7.14-SNAPSHOT [INFO] +- org.apache.logging.log4j:log4j-api:jar:2.11.1:provided [INFO] \- org.apache.logging.log4j:log4j-core:jar:2.11.1:provided ``` -* dubbo-spring-boot-starter passes the log4j-api dependency through the spring-boot component. Log4j-api itself has no security issues. When upgrading the log4j-core component, pay attention to compatibility with log4j-api. +* dubbo-spring-boot-starter 通过 spring-boot 组件传递了 log4j-api 依赖,log4j-api 本身并无安全问题,升级 log4j-core 组件时注意与 log4j-api 的兼容性 ```xml -[INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @dubbo-spring-boot-starter --- +[INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ dubbo-spring-boot-starter --- [INFO] org.apache.dubbo:dubbo-spring-boot-starter:jar:2.7.14-SNAPSHOT -[INFO] \- org.springframework.boot:spring-boot-starter:jar:2.3.1.RELEASE:compile (optional) -[INFO] \- org.springframework.boot:spring-boot-starter-logging:jar:2.3.1.RELEASE:compile (optional) -[INFO] \- org.apache.logging.log4j:log4j-to-slf4j:jar:2.13.3:compile (optional) -[INFO] \- org.apache.logging.log4j:log4j-api:jar:2.13.3:compile (optional) +[INFO] \- org.springframework.boot:spring-boot-starter:jar:2.3.1.RELEASE:compile (optional) +[INFO] \- org.springframework.boot:spring-boot-starter-logging:jar:2.3.1.RELEASE:compile (optional) +[INFO] \- org.apache.logging.log4j:log4j-to-slf4j:jar:2.13.3:compile (optional) +[INFO] \- org.apache.logging.log4j:log4j-api:jar:2.13.3:compile (optional) ``` -* dubbo-spring-boot-actuator passes the log4j-api dependency through the spring-boot component. Log4j-api itself has no security issues. When upgrading the log4j-core component, attention should be paid to compatibility with log4j-api +* dubbo-spring-boot-actuator 通过 spring-boot 组件传递了 log4j-api 依赖,log4j-api 本身并无安全问题,升级 log4j-core 组件时应注意与 log4j-api 的兼容性 ```xml [INFO] org.apache.dubbo:dubbo-spring-boot-actuator:jar:2.7.14-SNAPSHOT -[INFO] \- org.springframework.boot:spring-boot-starter-web:jar:2.3.1.RELEASE:compile (optional) -[INFO] \- org.springframework.boot:spring-boot-starter:jar:2.3.1.RELEASE:compile -[INFO] \- org.springframework.boot:spring-boot-starter-logging:jar:2.3.1.RELEASE:compile -[INFO] \- org.apache.logging.log4j:log4j-to-slf4j:jar:2.13.3:compile -[INFO] \- org.apache.logging.log4j:log4j-api:jar:2.13.3:compile +[INFO] \- org.springframework.boot:spring-boot-starter-web:jar:2.3.1.RELEASE:compile (optional) +[INFO] \- org.springframework.boot:spring-boot-starter:jar:2.3.1.RELEASE:compile +[INFO] \- org.springframework.boot:spring-boot-starter-logging:jar:2.3.1.RELEASE:compile +[INFO] \- org.apache.logging.log4j:log4j-to-slf4j:jar:2.13.3:compile +[INFO] \- org.apache.logging.log4j:log4j-api:jar:2.13.3:compile ``` diff --git a/content/en/overview/notices/protocol.md b/content/en/overview/notices/protocol.md index 277ac9ab78f8..30c7eb620275 100644 --- a/content/en/overview/notices/protocol.md +++ b/content/en/overview/notices/protocol.md @@ -1,39 +1,37 @@ --- -title: "RPC Protocol Security" -linkTitle: "RPC protocol security" +title: "RPC 协议安全" +linkTitle: "RPC 协议安全" weight: 2 -description: "Use RPC protocol more securely in Dubbo" type: docs +description: "在 Dubbo 中更安全的使用 RPC 协议" --- -Dubbo supports the extension of the RPC protocol. In theory, users can enable any RPC protocol based on this extension mechanism. This brings great flexibility, but at the same time, users must be aware of the hidden security risks. +Dubbo 支持 RPC 协议的扩展,理论上用户可以基于该扩展机制启用任意的 RPC 协议,这带来了极大的灵活的,但同时也要意识到其中潜藏的安全性风险。 -The serialization protocols provided by the official version of Dubbo 2.7 are as follows: +Dubbo 2.7 官方版本提供的序列化协议有如下几种: * Dubbo * RMI * Hessian -* Http/Rest +* Http / Rest * Webservice * Thrift * gRPC -* … +* …… -Starting from Dubbo 3.0, only the following serialization protocol support is provided by default: +从 Dubbo 3.0 开始默认仅提供以下序列化协议支持: * Dubbo -* Triple/gRPC -* Http/Rest +* Triple / gRPC +* Http / Rest -The Triple, gRPC, Http, and Rest protocols are all built based on the HTTP protocol. The format of the request can be strictly distinguished. For example, the header is plain text to avoid risks such as RCE when reading the Token. -For the Dubbo protocol, since it is designed based on TCP binary directly, except for a few specific fields, it is written using the serialization protocol. Therefore, if a risky serialization protocol is turned on, there will still be risks such as RCE. -For the RMI protocol, since it is based on the Java serialization mechanism, there are risks such as RCE. -For the Hessian protocol, because it is based on the Hessian serialization mechanism, and the default Hessian protocol (non-Dubbo Shade's Hessian-Lite protocol) cannot configure a black and white list and has no default black list, there are risks such as RCE. +对于 Triple、gRPC、Http、Rest 协议都是基于 HTTP 协议构建的,可以严格区分请求的格式,如 Header 为纯文本,避免在读取 Token 时带来的 RCE 等风险。 +对于 Dubbo 协议,由于其基于 TCP 二进制直接设计,除了特定几个字段外均使用序列化协议写入,因此如果开启了有风险的序列化协议,仍然会存在 RCE 等风险。 +对于 RMI 协议,由于其基于 Java 序列化机制,存在 RCE 等风险。 +对于 Hessian 协议,由于其基于 Hessian 序列化机制,且默认 Hessian 协议(非 Dubbo Shade 的 Hessian-Lite 协议)无法配置黑白名单且无默认黑名单,存在 RCE 等风险。 -1. If the user wants to use the Token authentication mechanism to prevent unauthenticated and untrusted request sources from threatening the security of the Provider, they should use protocols based on HTTP standard extensions such as Triple to avoid security risks when reading token parameters. +(1)如果用户希望使用 Token 鉴权机制,防止未鉴权的不可信请求来源威胁 Provider 的安全性,应使用 Triple 等基于 Http 标准扩展的协议,避免 token 参数读取时的安全风险。 -2. In particular, the Dubbo community **strongly does not recommend** exposing the Dubbo protocol, RMI protocol, Hessian protocol and other protocols that are not based on HTTP standard extensions to the public network environment, because the original intention of the Dubbo protocol is to be used on the intranet Provide high-performance RPC services in the environment, rather than in the public network environment. - -3. If your application needs to expose public network access, the Dubbo community recommends that you use the Triple protocol and avoid using non-Protobuf mode or services based on Dubbo 3.3 and above that only expose standard application/json format services. - -4. Please be advised that all networked servers are susceptible to Denial of Service (DoS) attacks. We are unable to provide **magic** solutions for common issues, such as clients transmitting large amounts of data to your server or repeatedly requesting the same URL. Generally, Apache Dubbo aims to defend against attacks that could cause server resource consumption to become disproportionate to the size or structure of the input data. Therefore, to safeguard your server, ensure you have a Web Application Firewall (WAF) or other security devices in place before exposing your Dubbo services to the public internet, in order to prevent such attacks. +(2)特别的,Dubbo 社区**非常不推荐**将 Dubbo 协议、RMI 协议、Hessian 协议等非基于 Http 标准扩展的协议暴露在公网环境下,因为 Dubbo 协议的设计初衷是为了在内网环境下提供高性能的 RPC 服务,而非公网环境下的服务。 +(3)如果您的应用有暴露公网访问的需求,Dubbo 社区建议您使用 Triple 协议,并且避免使用非 Protobuf 模式或者是基于 Dubbo 3.3 及以上的版本仅暴露标准 application/json 格式的服务。 +(4)请注意,所有联网服务器都可能遭受拒绝服务(DoS)攻击,我们无法对通用问题(例如客户端向您的服务器传输大量数据或重复请求相同的URL)提供**特殊**的解决方法。Apache Dubbo 的目标是避免任何会导致服务器资源消耗与输入数据大小或结构不成线性关系的攻击。因此,为了保护您的服务器,在您将 Dubbo 服务暴露到公网之前,请确保您的服务前置有网页应用程序防火墙(WAF)或其他安全设备,以防止这些攻击。 diff --git a/content/en/overview/notices/registry.md b/content/en/overview/notices/registry.md index f3f21daa771e..405ef404b9ac 100644 --- a/content/en/overview/notices/registry.md +++ b/content/en/overview/notices/registry.md @@ -1,26 +1,26 @@ --- -title: "Registration Center Security" -linkTitle: "Registration Center Security" +title: "注册中心安全" +linkTitle: "注册中心安全" weight: 3 -description: "Use the registration center more safely in Dubbo" type: docs +description: "在 Dubbo 中更安全的使用注册中心" --- -Dubbo supports the extension of the registration center. In theory, users can enable any registration center based on this extension mechanism. This brings great flexibility, but at the same time, users must be aware of the hidden security risks. +Dubbo 支持注册中心的扩展,理论上用户可以基于该扩展机制启用任意的注册中心,这带来了极大的灵活的,但同时也要意识到其中潜藏的安全性风险。 -The official version of Dubbo 2.7 provides the following registration centers: +Dubbo 2.7 官方版本提供的注册中心有如下几种: * Zookeeper * Redis * Nacos * Etcd * Consul -* ... +* …… -Starting from Dubbo 3.0, only the following registration centers are supported by default: +从 Dubbo 3.0 开始默认仅提供以下注册中心支持: * Zookeeper * Nacos -For the registration center, Dubbo can only fully trust the data pushed by it. Therefore, if there is a security vulnerability in the registration center, the Dubbo service may be maliciously registered or data may be maliciously pushed, resulting in the service being attacked. -Therefore, in order to ensure the security of the registration center, Dubbo officially recommends that you: -* Enable the authentication mechanism of the registration center, such as Zookeeper's ACL mechanism, Nacos' username and password mechanism, etc. -* Avoid exposing the registration center to the public network environment, and try to deploy the registration center in a trusted intranet environment +对于注册中心,Dubbo 只能完全信任其推送的数据,因此如果注册中心存在安全漏洞,可能会导致 Dubbo 服务被恶意注册或者是被恶意推送数据,从而导致服务被攻击。 +因此为了保证注册中心的安全性,Dubbo 官方建议您: +* 开启注册中心的鉴权机制,如 Zookeeper 的 ACL 机制、Nacos 的用户名密码机制等 +* 避免将注册中心暴露在公网环境下,尽量将注册中心部署在可信内网环境下 diff --git a/content/en/overview/notices/serialization.md b/content/en/overview/notices/serialization.md index cd6cc2500938..77fd0baeea97 100644 --- a/content/en/overview/notices/serialization.md +++ b/content/en/overview/notices/serialization.md @@ -1,21 +1,21 @@ --- -title: "Serialization Security" -linkTitle: "Serialization Security" +title: "序列化安全" +linkTitle: "序列化安全" weight: 1 -aliases: - - /zh-cn/blog/1/01/01/Serialization Protocol Security/ -description: "Use serialization protocol more safely in Dubbo" type: docs +aliases: + - /zh-cn/blog/1/01/01/序列化协议安全/ +description: "在 Dubbo 中更安全的使用序列化协议" --- -# Overview +# 概述 -Dubbo supports the extension of serialization protocols. In theory, users can enable any serialization protocol based on this extension mechanism. This brings great flexibility, but at the same time, users must be aware of the hidden security risks. -Data deserialization is the link most easily exploited by attackers, who use it to perform RCE attacks to steal or destroy server-side data. -Before switching serialization protocols or implementations, users should fully investigate the security guarantees of the target serialization protocol and its framework implementation, and set up corresponding security measures in advance (such as setting up a black/white list). -The Dubbo framework itself cannot directly guarantee the security of the target serialization mechanism. +Dubbo 支持序列化协议的扩展,理论上用户可以基于该扩展机制启用任意的序列化协议,这带来了极大的灵活的,但同时也要意识到其中潜藏的安全性风险。 +数据反序列化是最容易被被攻击者利用的一个环节,攻击者利用它执行 RCE 攻击等窃取或破坏服务端数据。 +用户在切换序列化协议或实现前, 应充分调研目标序列化协议及其框架实现的安全性保障,并提前设置相应的安全措施(如设置黑/白名单)。 +Dubbo 框架自身并不能直接保证目标序列化机制的安全性。 -The serialization protocols provided by the official version of Dubbo 2.7 are as follows: +Dubbo 2.7 官方版本提供的序列化协议有如下几种: * Hessian2 * Fastjson * Kryo @@ -26,35 +26,35 @@ The serialization protocols provided by the official version of Dubbo 2.7 are as * Avro * Gson -Starting from Dubbo 3.0, only the following serialization protocol support is provided by default: +从 Dubbo 3.0 开始默认仅提供以下序列化协议支持: * Hessian2 * JDK * Protocol Buffers -Starting from Dubbo 3.2, the following serialization protocol support is provided by default: +从 Dubbo 3.2 开始默认提供以下序列化协议支持: * Hessian2 * Fastjson2 * JDK * Protocol Buffers -For security reasons, starting from Dubbo 3.3, only the following serialization protocols will be supported by default: +处于安全性考虑,从 Dubbo 3.3 开始将默认仅提供以下序列化协议支持: * Hessian2 * Fastjson2 * Protocol Buffers -For the above serialization extensions, after discovering or receiving relevant vulnerability reports, Dubbo officials will follow up and upgrade dependencies to the latest security version, but the final vulnerability fix depends on the serialization framework implementation. +针对以上序列化扩展,在发现或收到相关的漏洞报告之后,Dubbo 官方会跟进并升级依赖到最新的安全版本,但最终的漏洞修复方案取决于序列化的框架实现。 -> For users using the [dubbo hessian2](https://github.com/apache/dubbo-hessian-lite/releases) version, Dubbo officials will ensure the security of the hessian2 serialization mechanism and fix reported security vulnerabilities as much as possible +> 针对使用 [dubbo hessian2](https://github.com/apache/dubbo-hessian-lite/releases) 版本的用户,Dubbo 官方会保证hessian2序列化机制的安全性并尽可能的修复上报的安全漏洞 -In addition, starting from Dubbo version 3.2, the whitelist mechanism is adopted by default for Hessian2 and Fastjson2. If you find that some data processing has been removed, you can refer to [Document](/zh-cn/overview/mannual/java-sdk/advanced-features- and-usage/security/class-check/) to configure. +此外,从 Dubbo 3.2 版本开始,对于 Hessian2 和 Fastjson2 默认采用白名单机制,如果您发现部分数据处理移除,可以参考[文档](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/)进行配置。 -# Full reinforcement +# 全面加固 -In order to improve the security of application serialization as much as possible, Dubbo 3.0 has upgraded and strengthened the security of the serialization protocol. It is recommended to use the non-Wrapper mode of the Tripe protocol. -This protocol is secure by default, but requires developers to write IDL files. +为了尽可能提高应用序列化的安全性,Dubbo3.0在序列化协议安全方面进行了升级加固,推荐使用 Tripe 协议的非 Wrapper 模式。 +该协议默认安全,但需要开发人员编写IDL文件。 -Triple protocol Wrapper mode allows compatibility with other serialized data, providing good compatibility. However, other protocols may have deserialization security flaws. For the Hessian2 protocol, users with high security attributes should follow the sample code instructions to turn on the whitelist mode. The framework will turn on the blacklist mode by default to intercept malicious calls. +Triple 协议 Wrapper 模式下,允许兼容其它序列化数据,提供了良好的兼容性。但其它协议可能存在反序列化安全缺陷,对于 Hessian2 协议,高安全属性用户应当按照 samples 代码指示,开启白名单模式,框架默认会开启黑名单模式,拦截恶意调用。 -If other serialization protocols must be used, a certain degree of security is expected. The Token authentication mechanism should be enabled to prevent unauthenticated and untrusted request sources from threatening Provider security. When turning on the Token authentication mechanism, the authentication function of the registration center should be turned on simultaneously. +若必须使用其它序列化协议,同时希望具备一定安全性。应当开启Token鉴权机制,防止未鉴权的不可信请求来源威胁 Provider 的安全性。开启 Token 鉴权机制时,应当同步开启注册中心的鉴权功能。 -[Reinforcement reference](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/) +[加固参考](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/) diff --git a/content/en/overview/quickstart/_index.md b/content/en/overview/quickstart/_index.md deleted file mode 100755 index f21fc3e7d81c..000000000000 --- a/content/en/overview/quickstart/_index.md +++ /dev/null @@ -1,38 +0,0 @@ - ---- -type: docs -title: "Quick Start" -linkTitle: "Quick Start" -weight: 2 ---- - -{{< blocks/section color="white" height="auto">}} -
-
-
-
-
-

- Java SDK -

-

Dubbo Java SDK Quick start

-
-
-
-
-
-
-

-Golang SDK -

-

Dubbo Golang SDK Quick start

-
-
-
- -
-
-
- -{{< /blocks/section >}} \ No newline at end of file diff --git a/content/en/overview/quickstart/go.md b/content/en/overview/quickstart/go.md deleted file mode 100644 index 13f9a1563632..000000000000 --- a/content/en/overview/quickstart/go.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "Quick Start With Golang" -linkTitle: "Quick Start" -weight: 2 ---- \ No newline at end of file diff --git a/content/en/overview/quickstart/rust.md b/content/en/overview/quickstart/rust.md deleted file mode 100644 index 180288629400..000000000000 --- a/content/en/overview/quickstart/rust.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "Quick Start With Rust" -linkTitle: "Quick Start" -weight: 2 ---- \ No newline at end of file diff --git a/content/en/overview/reference/Metrics/_index.md b/content/en/overview/reference/Metrics/_index.md new file mode 100644 index 000000000000..20eaeea4f5f5 --- /dev/null +++ b/content/en/overview/reference/Metrics/_index.md @@ -0,0 +1,7 @@ +--- +description: "" +linkTitle: Metrics +title: Metrics +type: docs +weight: 2 +--- diff --git a/content/en/overview/reference/Metrics/standard_metrics.md b/content/en/overview/reference/Metrics/standard_metrics.md new file mode 100644 index 000000000000..4b93d3a4ab0e --- /dev/null +++ b/content/en/overview/reference/Metrics/standard_metrics.md @@ -0,0 +1,194 @@ +--- +aliases: + - /zh-cn/overview/reference/Metrics/standard_metrics/ +linkTitle: 标准监控指标 +title: Dubbo 框架标准监控指标 +type: docs +weight: 1 +description: | + 描述了 Dubbo 中统计的一些标准监控指标。 +--- + +### Dubbo 指标含义 + +#### Provider Metrics + +| Metrics Name | Description | 说明 | +|---------------------------------------------------------|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| +| dubbo_provider_qps_total | The number of requests received by the provider per second | 提供者每秒接收的请求数 | +| dubbo_provider_requests_total | The total number of received requests by the provider | 提供者总的接收请求数 | +| dubbo_provider_requests_total_aggregate | The total number of received requests by the provider under the sliding window | 滑动窗口下的提供者总的接收请求数 | +| dubbo_provider_requests_processing | The number of received requests being processed by the provider | 提供者正在处理的接收的请求数 | +| dubbo_provider_requests_succeed_total | The number of requests successfully received by the provider | 提供者请求成功接收的请求数 | +| dubbo_provider_requests_succeed_aggregate | The number of successful requests received by the provider under the sliding window | 滑动窗口下的提供者成功的接收请求数 | +| dubbo_provider_rt_milliseconds_min | The minimum response time among all requests processed by the provider | 提供者所有处理请求中最小的响应时间 | +| dubbo_provider_rt_min_milliseconds_aggregate | The minimum response time of the provider under the sliding window | 滑动窗口下的提供者最小响应时间 | +| dubbo_provider_rt_milliseconds_avg | The average response time of all requests processed by the provider | 提供者所有处理请求的平均响应时间 | +| dubbo_provider_rt_avg_milliseconds_aggregate | The average response time of the provider under the sliding window | 滑动窗口下的提供者平均响应时间 | +| dubbo_provider_rt_milliseconds_sum | The total time taken by the provider to process all requests | 提供者所有处理请求的时间总和 | +| dubbo_provider_rt_milliseconds_max | The maximum response time among all requests from the provider | 提供者所有请求中最大的响应时间 | +| dubbo_provider_rt_max_milliseconds_aggregate | The maximum response time of the provider under the sliding window | 滑动窗口下的提供者最大响应时间 | +| dubbo_provider_rt_milliseconds_last | The current response time in the provider's processing of requests | 提供者处理请求中当前的响应时间 | +| dubbo_provider_rt_milliseconds_p50 | The total response time spent by providers processing 50% of requests | 提供者处理请求中50%的请求耗费的总响应时间 | +| dubbo_provider_rt_milliseconds_p90 | The total response time spent by providers processing 90% of requests | 提供者处理请求中90%的请求耗费的总响应时间 | +| dubbo_provider_rt_milliseconds_p95 | The total response time spent by providers processing 95% of requests | 提供者处理请求中95%的请求耗费的总响应时间 | +| dubbo_provider_rt_milliseconds_p99 | The total response time spent by providers processing 99% of requests | 提供者处理请求中99%的请求耗费的总响应时间 | +| dubbo_provider_requests_processing_total | The number of received requests being processed by the provider | 提供者正在处理的接收的请求数 | +| dubbo_provider_rt_milliseconds_histogram_seconds_bucket | The histogram of response time of the provider under the sliding window | 滑动窗口下的提供者响应时间直方图 | +| dubbo_provider_rt_milliseconds_histogram_seconds_count | The count of histogram of response time of the provider under the sliding window | 滑动窗口下的提供者响应时间直方图总数 | +| dubbo_provider_rt_milliseconds_histogram_seconds_max | The max of histogram of response time of the provider under the sliding window | 滑动窗口下的提供者响应时间直方图最大值 | +| dubbo_provider_rt_milliseconds_histogram_seconds_sum | The sum of histogram of response time of the provider under the sliding window | 滑动窗口下的提供者响应时间直方图总和 | +| dubbo_provider_requests_business_failed_total | Total Failed Business Requests | 当RPC请求异常状态码为 RpcException.BIZ_EXCEPTION | +| dubbo_provider_requests_timeout_total | Total Timeout Failed Requests | 当RPC请求异常为超时异常状态码为 RpcException.TIMEOUT_EXCEPTION | +| dubbo_provider_requests_limit_total | Total Limit Failed Requests | RPC请求中一般为并发数超过了限制 max concurrent invoke 或者是超过了系统的上限出现了异常状态码为RpcException.LIMIT_EXCEEDED_EXCEPTION或者异常类型为LimitExceededException LimitExceededException | +| dubbo_provider_requests_unknown_failed_total | Total Unknown Failed Requests | 暂为归类的其他类型的异常具体分析根据日志来看 | +| dubbo_provider_requests_failed_total | Total Failed Requests | 总的异常次数 | +| dubbo_provider_requests_failed_total_aggregate | Total Failed Aggregate Requests | 聚合请求失败次数,当聚合请求中有一个请求失败时候会触发此异常 | +| dubbo_provider_requests_failed_network_total | Total network Failed Requests | 一般发生在网络连接失败或者网络通信时候发生的异常,对应Java异常为RemotingException | +| dubbo_provider_requests_failed_service_unavailable_total | Total Service Unavailable Failed Requests | 当不存在提供者或者调用了被禁止访问提的提供者时候会出现此异常 ,对应异常码FORBIDDEN_EXCEPTION | +| dubbo_provider_requests_failed_codec_total | Total codec failed | 序列化相关的异常,异常码SERIALIZATION_EXCEPTION | +| dubbo_provider_requests_failed_aggregate | Total Failed Aggregate Requests | 聚合请求失败次数,当聚合请求中有一个请求失败时候会触发此异常 | +| dubbo_provider_requests_timeout_total | Total Timeout Failed Requests | 当RPC请求异常为超时异常状态码为 RpcException.TIMEOUT_EXCEPTION | +| dubbo_provider_requests_limit_total | Total Limit Failed Requests | RPC请求中一般为并发数超过了限制 max concurrent invoke 或者是超过了系统的上限出现了异常状态码为RpcException_LIMIT_EXCEEDED_EXCEPTION或者异常类型为LimitExceededException LimitExceededException | +| dubbo_provider_requests_unknown_failed_total | Total Unknown Failed Requests | 暂为归类的其他类型的异常具体分析根据日志来看 | +| dubbo_provider_requests_failed_total | Total Failed Requests | 总的异常次数 | +| dubbo_provider_requests_failed_network_total | Total network Failed Requests | 一般发生在网络连接失败或者网络通信时候发生的异常,对应Java异常为RemotingException | +| dubbo_provider_requests_failed_service_unavailable_total | Total Service Unavailable Failed Requests | 当不存在提供者或者调用了被禁止访问提的提供者时候会出现此异常 ,对应异常码FORBIDDEN_EXCEPTION | +| dubbo_provider_requests_failed_codec_total | Total codec failed | 序列化相关的异常,异常码SERIALIZATION_EXCEPTION | + +#### Consumer Metrics + +| Metrics Name | Description | 说明 | +|---------------------------------------------------------|------------------------------------------------------------------------------|------------------------| +| dubbo_consumer_qps_total | The number of requests sent by consumers per second | 消费者每秒发送的请求数 | +| dubbo_consumer_requests_total | Total number of sent requests by consumers | 消费者总的发送请求数 | +| dubbo_consumer_requests_total_aggregate | The total number of requests sent by consumers under the sliding window | 滑动窗口下的消费者总的发送请求数 | +| dubbo_consumer_requests_processing | The number of sent requests that consumers are currently processing | 消费者正在处理的发送的请求数 | +| dubbo_consumer_requests_succeed_total | The number of successful requests sent by consumers | 消费者请求成功发送的请求数 | +| dubbo_consumer_requests_succeed_aggregate | The number of successful requests sent by consumers under the sliding window | 滑动窗口下的消费者成功的发送请求数 | +| dubbo_consumer_rt_milliseconds_min | Minimum response time among all consumer requests | 消费者所有请求中最小的响应时间 | +| dubbo_consumer_rt_min_milliseconds_aggregate | The minimum response time of the consumer under the sliding window | 滑动窗口下的消费者最小响应时间 | +| dubbo_consumer_rt_milliseconds_avg | Average response time of all requests from consumers | 消费者所有请求的平均响应时间 | +| dubbo_consumer_rt_avg_milliseconds_aggregate | The average response time of the consumer under the sliding window | 滑动窗口下的消费者平均响应时间 | +| dubbo_consumer_rt_milliseconds_sum | The total time of all consumer requests | 消费者所有请求的时间总和 | +| dubbo_consumer_rt_milliseconds_max | Maximum response time among all requests from consumers | 消费者所有请求中最大的响应时间 | +| dubbo_consumer_rt_max_milliseconds_aggregate | The maximum response time of the consumer under the sliding window | 滑动窗口下的消费者最大响应时间 | +| dubbo_consumer_rt_milliseconds_last | The current response time in consumer processing requests | 消费者处理请求中当前的响应时间 | +| dubbo_consumer_rt_milliseconds_p50 | The total response time spent by consumers processing 50% of requests | 消费者处理请求中50%的请求耗费的总响应时间 | +| dubbo_consumer_rt_milliseconds_p90 | The total response time spent by consumers processing 90% of requests | 消费者处理请求中90%的请求耗费的总响应时间 | +| dubbo_consumer_rt_milliseconds_p95 | The total response time spent by consumers processing 95% of requests | 消费者处理请求中95%的请求耗费的总响应时间 | +| dubbo_consumer_rt_milliseconds_p99 | The total response time spent by consumers processing 99% of requests | 消费者处理请求中99%的请求耗费的总响应时间 | +| dubbo_consumer_rt_milliseconds_histogram_seconds_bucket | Histogram of response time of all requests from consumers | 消费者所有请求的响应时间直方图 | +| dubbo_consumer_rt_milliseconds_histogram_seconds_count | count of Histogram of all requests from consumers | 消费者所有请求的响应时间直方图总数量 | +| dubbo_consumer_rt_milliseconds_histogram_seconds_sum | sum of Histogram of all requests from consumers | 消费者所有请求的响应时间直方图总和 | +| dubbo_consumer_rt_milliseconds_histogram_seconds_max | max of Histogram of all requests from consumers | 消费者所有请求的响应时间直方图最大值 | +| dubbo_consumer_requests_business_failed_total | Total Failed Business Requests | 当RPC请求异常状态码为RpcException.BIZ_EXCEPTION | +| dubbo_consumer_requests_timeout_total | Total Timeout Failed Requests | 当RPC请求异常为超时异常状态码为RpcException.TIMEOUT_EXCEPTION | +| dubbo_consumer_requests_timeout_failed_aggregate | Total Timeout Failed Requests | 滑动窗口内的聚合指标 当RPC请求异常为超时异常状态码为RpcException.TIMEOUT_EXCEPTION | +| dubbo_consumer_requests_limit_total | Total Limit Failed Requests | RPC请求状态码为RpcException.LIMIT_EXCEEDED_EXCEPTION或者异常类型为LimitExceededException 一般为并发数超过了限制 max concurrent invoke 或者是超过了系统的上限出现了异常LimitExceededException | +| dubbo_consumer_requests_unknown_failed_total | Total Unknown Failed Requests | 暂为归类的其他类型的异常具体分析根据日志来看 | +| dubbo_consumer_requests_failed_total | Total Failed Requests | 总的异常次数 | +| dubbo_consumer_requests_failed_total_aggregate | Total Failed Requests | 滑动窗口内的聚合指标 总的异常次数 | +| dubbo_consumer_requests_failed_network_total | Total network Failed Requests | 一般发生在网络连接失败或者网络通信时候发生的异常,对应Java异常为RemotingException | +| dubbo_consumer_requests_failed_network_total_aggregate | Total network Failed Requests | 滑动窗口内的聚合指标 一般发生在网络连接失败或者网络通信时候发生的异常,对应Java异常为RemotingException | +| dubbo_consumer_requests_failed_service_unavailable_total | Total Service Unavailable Failed Requests | 当不存在提供者或者调用了被禁止访问提的提供者时候会出现此异常 ,对应异常码FORBIDDEN_EXCEPTION | +| dubbo_consumer_requests_failed_codec_total | Total codec failed | 序列化相关的异常,异常码SERIALIZATION_EXCEPTION | + +#### ThreadPool Metrics + +| Metrics Name | Description | 说明 | +|--------------------------------|--------------------------|-------------| +| dubbo_thread_pool_max_size | Thread Pool Max Size | 线程池最大大小 | +| dubbo_thread_pool_largest_size | Thread Pool Largest Size | 线程池最大大小 | +| dubbo_thread_pool_thread_count | Thread Pool Thread Count | 线程池线程计数 | +| dubbo_thread_pool_queue_size | Thread Pool Queue Size | 线程池队列大小 | +| dubbo_thread_pool_active_size | Thread Pool Active Size | 线程池活动大小 | +| dubbo_thread_pool_core_size | Thread Pool Core Size | 线程池核心大小 | +| dubbo_thread_pool_reject_thread_count | Thread Pool Reject Count | 线程池拒绝执行任务数量 | + +#### Registration Center Metrics + +| Metrics Name | Description | 说明 | +|----------------------------------------------------|-----------------------------------------|------------------------| +| dubbo_register_service_rt_milliseconds_avg | Average Service Register Time | **接口级** 服务接口注册平均时间 | +| dubbo_register_service_rt_milliseconds_last | Last Service Register Time | **接口级** 服务接口注册最新响应时间 | +| dubbo_register_service_rt_milliseconds_max | Max Service Register Time | **接口级** 服务接口注册总的最大时间 | +| dubbo_register_service_rt_milliseconds_min | Min Service Register Time | **接口级** 服务接口注册总的最小时间 | +| dubbo_register_service_rt_milliseconds_sum | Sum Service Register Time | **接口级** 服务接口注册总的注册时间 | +| dubbo_registry_directory_num_all | Total Directory Num | **接口级** 服务接口目录总数 | +| dubbo_registry_directory_num_disable_total | Total Disable Directory Num | **接口级** 服务接口目录禁用总数 | +| dubbo_registry_directory_num_to_reconnect_total | Total Directory Num To Reconnect | **接口级** 服务接口目录重连总数 | +| dubbo_registry_directory_num_valid_total | Total Valid Directory Num | **接口级** 服务接口目录有效总数 | +| dubbo_registry_notify_num_last | Last Notify Num | **接口级** 服务接口通知最新响应时间 | +| dubbo_registry_notify_requests_total | Total Notify Requests | **接口级** 服务接口通知总次数 | +| dubbo_register_rt_milliseconds_max | Max Response Time | **应用级** 实例注册总的最大时间 | +| dubbo_register_rt_milliseconds_avg | Average Response Time | **应用级** 实例注册总的平均时间 | +| dubbo_register_rt_milliseconds_sum | Sum Response Time | **应用级** 实例注册总的注册时间 | +| dubbo_register_rt_milliseconds_min | Min Response Time | **应用级** 实例注册总的最小时间 | +| dubbo_registry_register_requests_succeed_total | Succeed Register Requests | **应用级** 实例注册成功的次数 | +| dubbo_registry_register_requests_total | Total Register Requests | **应用级** 实例注册总次数包含成功与失败 | +| dubbo_registry_register_requests_failed_total | Failed Register Requests | **应用级** 实例注册失败次数 | +| dubbo_register_rt_milliseconds_last | Last Response Time | **应用级** 实例注册最新响应时间 | +| dubbo_registry_register_service_total | Total Service-Level Register Requests | **接口级** 服务接口注册总数 | +| dubbo_registry_register_service_succeed_total | Succeed Service-Level Register Requests | **接口级** 服务接口注册成功总数 | +| dubbo_registry_register_service_failed_total | Failed Service-Level Register Requests | **接口级** 服务接口注册失败总数 | +| dubbo_registry_subscribe_num_failed_total | Failed Subscribe Num | **应用级** 实例订阅失败总数 | +| dubbo_registry_subscribe_num_succeed_total | Succeed Subscribe Num | **应用级** 实例订阅成功总数 | +| dubbo_registry_subscribe_num_total | Total Subscribe Num | **应用级** 实例订阅总数 | +| dubbo_registry_subscribe_service_num_total | Total Service-Level Subscribe Num | **接口级** 服务接口订阅总数 | +| dubbo_registry_subscribe_service_num_succeed_total | Succeed Service-Level Num | **接口级** 服务接口订阅成功总数 | +| dubbo_registry_subscribe_service_num_failed_total | Failed Service-Level Num | **接口级** 服务接口订阅失败总数 | +| dubbo_notify_rt_milliseconds_avg | Average Notify Time | **接口级** 服务接口通知总的平均时间 | +| dubbo_notify_rt_milliseconds_last | Last Notify Time | **接口级** 服务接口通知最新响应时间 | +| dubbo_notify_rt_milliseconds_max | Max Notify Time | **接口级** 服务接口通知总的最大时间 | +| dubbo_notify_rt_milliseconds_min | Min Notify Time | **接口级** 服务接口通知总的最小时间 | +| dubbo_notify_rt_milliseconds_sum | Sum Notify Time | **接口级** 服务接口通知总的通知时间 | + +#### Metadata Center Metrics + +部分元数据指标生效范围:当元数据为集中式配置时(report-metadata为true或者metadataType为remote) + +| Metrics Name | Description | 说明 | +|-----------------------------------------------------|---------------------------------------|-------------------------------------------------| +| dubbo_metadata_push_num_total | Total Num | **提供者** 推送元数据到元数据中心的成功次数,当提供者元数据发生了变更时触发 | +| dubbo_metadata_push_num_succeed_total | Succeed Push Num | **提供者** 推送元数据到元数据中心的成功次数,当提供者元数据发生了变更时触发 | +| dubbo_metadata_push_num_failed_total | Failed Push Num | **提供者** 推送元数据到元数据中心的失败次数,当提供者元数据发生了变更时并且出现异常触发 | +| dubbo_metadata_subscribe_num_total | Total Metadata Subscribe Num | **消费者** 获取元数据的总次数,当消费者启动时本地磁盘缓存无元数据获取元数据的次数 | +| dubbo_metadata_subscribe_num_succeed_total | Succeed Metadata Subscribe Num | **消费者** 获取元数据的总次数,当消费者启动时本地磁盘缓存无元数据并且成功获取元数据的次数 | +| dubbo_metadata_subscribe_num_failed_total | Failed Metadata Subscribe Num | **消费者** 获取元数据的总次数,当消费者启动时本地磁盘缓存无元数据并且获取元数据失败的次数 | +| dubbo_push_rt_milliseconds_sum | Sum Response Time | **提供者** 推送元数据到元数据中心的总时间 | +| dubbo_push_rt_milliseconds_last | Last Response Time | **提供者** 推送元数据到元数据中心的最新耗时 | +| dubbo_push_rt_milliseconds_min | Min Response Time | **提供者** 推送元数据到元数据中心的最小时间 | +| dubbo_push_rt_milliseconds_max | Max Response Time | **提供者** 推送元数据到元数据中心的最大时间 | +| dubbo_push_rt_milliseconds_avg | Average Response Time | **提供者** 推送元数据到元数据中心的平均时间 | +| dubbo_subscribe_rt_milliseconds_sum | Sum Response Time | **消费者** 获取元数据从元数据中心的总时间 | +| dubbo_subscribe_rt_milliseconds_last | Last Response Time | **消费者** 推送元数据到元数据中心的最新耗时 | +| dubbo_subscribe_rt_milliseconds_min | Min Response Time | **消费者** 推送元数据到元数据中心的最小时间 | +| dubbo_subscribe_rt_milliseconds_max | Max Response Time | **消费者** 推送元数据到元数据中心的最大时间 | +| dubbo_subscribe_rt_milliseconds_avg | Average Response Time | **消费者** 推送元数据到元数据中心的平均时间 | +| dubbo_metadata_store_provider_failed_total | Total Failed Provider Metadata Store | **提供者** 元数据中心存储提供者元数据失败次数 | +| dubbo_metadata_store_provider_succeed_total | Total Succeed Provider Metadata Store | **提供者** 元数据中心存储提供者元数据成功次数 | +| dubbo_metadata_store_provider_total | Total Provider Metadata Store | **提供者** 元数据中心存储提供者元数据总次数 | +| dubbo_store_provider_interface_rt_milliseconds_avg | Average Store Provider Interface Time | **接口级** 服务接口存储提供者平均时间 | +| dubbo_store_provider_interface_rt_milliseconds_last | Last Store Provider Interface Time | **接口级** 服务接口存储提供者最新响应时间 | +| dubbo_store_provider_interface_rt_milliseconds_max | Max Store Provider Interface Time | **接口级** 服务接口存储提供者最大时间 | +| dubbo_store_provider_interface_rt_milliseconds_min | Min Store Provider Interface Time | **接口级** 服务接口存储提供者最小时间 | +| dubbo_store_provider_interface_rt_milliseconds_sum | Sum Store Provider Interface Time | **接口级** 服务接口存储提供者总的存储时间 | +| dubbo_subscribe_service_rt_milliseconds_last | Last Subscribe Service Time | **接口级** 服务接口订阅元数据最新响应时间 | +| dubbo_subscribe_service_rt_milliseconds_max | Max Subscribe Service Time | **接口级** 服务接口订阅元数据最大时间 | +| dubbo_subscribe_service_rt_milliseconds_min | Min Subscribe Service Time | **接口级** 服务接口订阅元数据最小时间 | +| dubbo_subscribe_service_rt_milliseconds_sum | Sum Subscribe Service Time | **接口级** 服务接口订阅元数据总的存储时间 | +| dubbo_subscribe_service_rt_milliseconds_avg | Average Subscribe Service Time | **接口级** 服务接口订阅元数据平均时间 | + +#### Configcenter + +| Metrics Name | Description | 说明 | +|--------------------------|----------------------|------------| +| dubbo_configcenter_total | Config Changed Total | 配置中心推送配置次数 | + +#### ApplicationInfo + +| Metrics Name | Description | 说明 | +|------------------------------|------------------------|----------------| +| dubbo_application_info_total | Total Application Info | 应用信息包含应用名、版本号等 | + diff --git a/content/en/overview/reference/_index.md b/content/en/overview/reference/_index.md new file mode 100755 index 000000000000..d2c7cc2af825 --- /dev/null +++ b/content/en/overview/reference/_index.md @@ -0,0 +1,51 @@ +--- +aliases: + - /zh/overview/reference/ +description: "" +linkTitle: 其他 +no_list: true +title: 其他 +type: docs +weight: 7 +--- + +{{< blocks/section color="white" height="auto">}} +
+
+
+
+
+

+ Dubbo Metrics +

+

Dubbo Metrics 监控指标

+
+
+
+
+
+
+

+ Dubbo Integrations +

+

Dubbo Integrations 使用指南

+
+
+
+
+
+
+

+ Dubbo Proposals +

+

Dubbo 提案

+
+
+
+ +
+
+
+ +{{< /blocks/section >}} diff --git a/content/en/overview/reference/erlang-sdk/_index.md b/content/en/overview/reference/erlang-sdk/_index.md new file mode 100755 index 000000000000..bbe745d36e1d --- /dev/null +++ b/content/en/overview/reference/erlang-sdk/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/erlang-sdk/ + - /zh-cn/docs3-v2/erlang-sdk/ + - /zh-cn/overview/reference/erlang-sdk/ + - /zh-cn/overview/mannual/erlang-sdk/ +description: Erlang 支持 +linkTitle: Erlang SDK +title: Erlang SDK 手册 +type: docs +weight: 8 +--- diff --git a/content/en/overview/reference/erlang-sdk/quick-start.md b/content/en/overview/reference/erlang-sdk/quick-start.md new file mode 100644 index 000000000000..4ad051a37f0e --- /dev/null +++ b/content/en/overview/reference/erlang-sdk/quick-start.md @@ -0,0 +1,71 @@ +--- +aliases: + - /zh/docs3-v2/erlang-sdk/quick-start/ + - /zh-cn/docs3-v2/erlang-sdk/quick-start/ + - /zh-cn/overview/mannual/erlang-sdk/quick-start/ + - /zh-cn/overview/reference/erlang-sdk/quick-start/ +description: Erlang 快速开始 +linkTitle: 快速开始 +title: 快速开始 +type: docs +weight: 1 +--- + +建议先使用 java 定义接口 jar,并使用 [erlanalysis](https://github.com/apache/dubbo-erlang/tree/master/tools/erlanalysis) 工具解析java接口至Erlang lib + +## 导入依赖库 + +### 使用 Rebar 编译工具。 +Add dubblerl to rebar.config with your project +```erlang +{deps, [ + {dubboerl, {git, "https://github.com/apache/dubbo-erlang.git", {branch, "master"}}} +]}. +``` + +### 使用 erlang.mk 编译工具 +`待补充` + +## 导入接口库 +Suppose the interface lib you exported is called dubbo_service. +* If you didn't upload your lib to your git repository, It is recommended that you copy the `dubbo_service` lib +into the project's `apps` directory. +* If it is upload to your git repository, you can import like this: +```erlang +{deps, [ + {dubboerl, {git, "https://github.com/apache/dubbo-erlang.git", {branch, "master"}}}, + {dubbo_service,{git,"${INTERFACE_LIB_URL}",{branch,"master"}}} %% replace ${INTERFACE_LIB_URL} with your lib git repos url +]}. +``` + +## 消费者配置 +Please reference [Reference Config](../reference/) + +## Init dubbolib in your project +It is need you +```erlang +dubboerl:init(). +``` + +## 如何调用? + +### 同步调用 +```erlang +Request = #userInfoRequest{requestId = 123, username = "testname"}, +{ok,RequestRef,Response,RpcContent} = userOperator:queryUserInfo(Request,#{sync=> true}). +``` +If it occur error, is reponse `{error,Reason}`. + +### 异步调用 + +Default is Async call. +```erlang +Request = #userInfoRequest{requestId = 123, username = "testname"}, +{ok,RequestRef} = userOperator:queryUserInfo(Request). + +%% you can receive the message after. +handle_cast({msg_back,RequestRef,Response,RpcContent},State). +``` + +## 示例 +参考项目 [dubboerl_demo](https://github.com/apache/dubbo-erlang/tree/master/samples) diff --git a/content/en/overview/reference/erlang-sdk/reference.md b/content/en/overview/reference/erlang-sdk/reference.md new file mode 100644 index 000000000000..230601811fcb --- /dev/null +++ b/content/en/overview/reference/erlang-sdk/reference.md @@ -0,0 +1,34 @@ +--- +aliases: + - /zh/docs3-v2/erlang-sdk/reference/ + - /zh-cn/docs3-v2/erlang-sdk/reference/ + - /zh-cn/overview/mannual/erlang-sdk/reference/ + - /zh-cn/overview/reference/erlang-sdk/reference/ +description: 在 erlang 中配置消费者 +linkTitle: 消费者配置 +title: 消费者配置 +type: docs +weight: 2 +--- + + + + + + +## 基础配置 + +消费者配置项需要添加到 `sys.config` 文件 `dubboerl` 应用配置项里。 + +```erlang +{dubboerl,[ + %% other config ... + {consumer,[ + {<<"interface fullname">>,[Option]}, + %% eg: + {<<"org.apache.dubbo.erlang.sample.service.facade.UserOperator">>,[]}, + ]} +]} +``` + +Option 配置项待添加中。 diff --git a/content/en/overview/reference/erlang-sdk/serialization.md b/content/en/overview/reference/erlang-sdk/serialization.md new file mode 100644 index 000000000000..20fe7f4b4e41 --- /dev/null +++ b/content/en/overview/reference/erlang-sdk/serialization.md @@ -0,0 +1,36 @@ +--- +aliases: + - /zh/docs3-v2/erlang-sdk/serialization/ + - /zh-cn/docs3-v2/erlang-sdk/serialization/ + - /zh-cn/overview/mannual/erlang-sdk/serialization/ + - /zh-cn/overview/reference/erlang-sdk/serialization/ +description: 在 erlang 中配置序列化方式 +linkTitle: 序列化配置项 +title: 序列化配置项 +type: docs +weight: 4 +--- + + + + + + +当前该库只实现了 `dubbo://` 通讯协议。 + +序列化方式实现了 `hessian` 和 `json` 两种方式。 + +## 配置样例 + +序列化配置需要添加到 `sys.config` 文件 `dubboerl` 应用配置项里。 + +```erlang +{dubboerl,[ + %% other config ... + {protocol,hessian} +]} +``` + +| ConfigName | Type | DefaultValue | Remarks | +| --- | --- | --- | --- | +| protocol | atom() | hessian | hessian,json | diff --git a/content/en/overview/reference/erlang-sdk/service.md b/content/en/overview/reference/erlang-sdk/service.md new file mode 100644 index 000000000000..d0529ed2da3d --- /dev/null +++ b/content/en/overview/reference/erlang-sdk/service.md @@ -0,0 +1,40 @@ +--- +aliases: + - /zh/docs3-v2/erlang-sdk/service/ + - /zh-cn/docs3-v2/erlang-sdk/service/ + - /zh-cn/overview/mannual/erlang-sdk/service/ + - /zh-cn/overview/reference/erlang-sdk/service/ +description: 在 erlang 中配置服务提供者 +linkTitle: 提供者配置 +title: 提供者配置 +type: docs +weight: 3 +--- + + + + + + +## 基本配置 + +提供者配置项需要添加到 `sys.config` 文件 `dubboerl` 应用配置项里。 + +```erlang +{dubboerl,[ + %% other config ... + {provider,[ + {module_implements,interface_module,interface_fullname,[Options]}, + %% eg: + {userOperator_impl,userOperator,<<"org.apache.dubbo.erlang.sample.service.facade.UserOperator">>,[Option]} + ]} +]} +``` + +| ConfigName | Type | DefaultValue | Remarks | +| --- | --- | --- | --- | +| module_implements | atom() | - | The service implements module name| +| interface_module | atom() | - | Interface module name is transfer form java jar | +| interface_fullname | binary() | - | Interface full name is the java class name | + +Option is to be added. diff --git a/content/en/overview/reference/integrations/_index.md b/content/en/overview/reference/integrations/_index.md new file mode 100644 index 000000000000..9bb0b0c0c610 --- /dev/null +++ b/content/en/overview/reference/integrations/_index.md @@ -0,0 +1,9 @@ +--- +aliases: + - /zh/overview/reference/integrations/ +description: "" +linkTitle: 集成适配 +title: 集成适配 +type: docs +weight: 3 +--- diff --git a/content/en/overview/reference/integrations/grafana.md b/content/en/overview/reference/integrations/grafana.md new file mode 100644 index 000000000000..1a4f406c038c --- /dev/null +++ b/content/en/overview/reference/integrations/grafana.md @@ -0,0 +1,72 @@ +--- +aliases: + - /zh/overview/reference/integrations/grafana/ +description: 配置 Grafana 与 Dubbo 一起工作 +linkTitle: Grafana +title: Grafana +type: docs +weight: 2 +--- + +Grafana 是一种开源的监控解决方案,可用于为 Dubbo 配置可视化仪表板,您可以使用 Grafana 来监控 Dubbo 集群的运行状况。 + +## 配置可视化控制面板 + +以下是 Dubbo 社区提供的默认指标面板,您配置好数据源并直接导入使用即可。如果默认面板不能满足要求,您还可以自定义 Grafana 面板。 + +* [**Apache Dubbo Observability Dashboard:**](https://grafana.com/grafana/dashboards/18469) +* [**JVM (Micrometer) Dashboard:**](https://grafana.com/grafana/dashboards/4701) + +您可以通过以下几种方式快速的导入 Grafana 监控面板。 + +### 方式一:Kubernetes 安装 + +你可以使用 Dubbo 社区提供的示例配置快速安装 Grafana,安装后的 Grafana 提供了社区默认指标面板视图。 + +```bash +kubectl create -f https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/deploy/kubernetes/grafana.yaml +``` + +你可能需要端口映射获得访问地址 `$ kubectl port-forward service/grafana 3000:3000`,打开浏览器访问页面 `http://localhost:3000`。 + +> 获取登录信息 +> ```bash +> kubectl get secrets grafana -o jsonpath="{.data.admin-user}" | base64 --decode ; echo && kubectl get secrets grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo +> ``` + +### 方式二:向已经安装好的集群导入 dashboard + +如果你已经有安装好的 Grafana 服务了,则还可以通过 [Grafana 控制台的导入菜单](https://grafana.com/docs/grafana/v8.4/dashboards/export-import/#importing-a-dashboard) 导入 dashboard。根据 Grafana 的要求,导入 dashboard 的过程中需要同时指定 Prometheus 数据源地址。 + +你也可以选择使用以下脚本快速导入。 + +```sh +$ # Address of Grafana +$ GRAFANA_HOST="http://localhost:3000" +$ # Login credentials, if authentication is used +$ GRAFANA_CRED="USER:PASSWORD" +$ # The name of the Prometheus data source to use +$ GRAFANA_DATASOURCE="Prometheus" +$ # The version of Dubbo to deploy +$ VERSION=3.2.0 +$ # Import all Dubbo dashboards +$ for DASHBOARD in 18469 4701; do +$ #REVISION="$(curl -s https://grafana.com/api/dashboards/${DASHBOARD}/revisions -s | jq ".items[] | select(.description | contains(\"${VERSION}\")) | .revision")" +$ REVISION=1 +$ curl -s https://grafana.com/api/dashboards/${DASHBOARD}/revisions/${REVISION}/download > /tmp/dashboard.json +$ echo "Importing $(cat /tmp/dashboard.json | jq -r '.title') (revision ${REVISION}, id ${DASHBOARD})..." +$ curl -s -k -u "$GRAFANA_CRED" -XPOST \ +$ -H "Accept: application/json" \ +$ -H "Content-Type: application/json" \ +$ -d "{\"dashboard\":$(cat /tmp/dashboard.json),\"overwrite\":true, \ +$ \"inputs\":[{\"name\":\"DS_PROMETHEUS\",\"type\":\"datasource\", \ +$ \"pluginId\":\"prometheus\",\"value\":\"$GRAFANA_DATASOURCE\"}]}" \ +$ $GRAFANA_HOST/api/dashboards/import +$ echo -e "\nDone\n" +$ done +``` + +### 方式三:自定义 +Grafana 可以通过其他方法进行安装和配置,可以参阅有关安装方法的文档了解如何制作和导入 Dubbo 检测面板 +* [Grafana provisioning 官方文档](https://grafana.com/docs/grafana/latest/administration/provisioning/#dashboards) +* [为 `stable/grafana` Helm chart 导入面板](https://github.com/helm/charts/tree/master/stable/grafana#import-dashboards) diff --git a/content/en/overview/reference/integrations/higress.md b/content/en/overview/reference/integrations/higress.md new file mode 100644 index 000000000000..6704c9eac49e --- /dev/null +++ b/content/en/overview/reference/integrations/higress.md @@ -0,0 +1,48 @@ +--- +aliases: +- /zh/overview/reference/integrations/skywalking/ +description: "如何安装与配置 Higress,涵盖本地、docker、kubernetes 等环境。" +linkTitle: Higress +title: Higress +type: docs +weight: 6 +--- + +本文档讲解如何安装与配置 Higress,涵盖本地、docker、kubernetes 等环境。以下仅为快速示例安装指南,如想搭建生产可用集群请参考 Higress 官方文档。 + +## docker +使用 docker 启动 Higress,请首先确保您已经在本地机器正确 下载页面 安装 docker。 + +使用以下命令安装 Higress: + +```shell +curl -fsSL https://higress.io/standalone/get-higress.sh | bash -s -- -a -c nacos://192.168.0.1:8848 --nacos-username=nacos --nacos-password=nacos +``` + +请将 `192.168.0.1` 替换为 Nacos 服务器的 IP(如果 Nacos 部署在本机,请不要使用如 `localhost` 或 `127.0.0.1` 的 Loopback 地址)。按需调整 --nacos-username 和 --nacos-password 的取值,如果 Nacos 服务未开启认证功能,则可以移除这两个参数。 + +{{% alert title="注意" color="info" %}} +* 如果您还没有安装 nacos,请 [参考文档完成安装](../nacos/)。 +* 如果您使用 Zookeeper 做服务发现,请修改对应的集群地址为 zookeeper 集群地址。 +{{% /alert %}} + +在浏览器中输入 `http://127.0.0.1:8080` 进入 Higress 控制台。 + +## kubernetes + +通过以下命令安装 Higress: + +```shell +helm repo add higress.io https://higress.io/helm-charts +helm install higress -n higress-system higress.io/higress --create-namespace --render-subchart-notes --set global.local=true --set higress-console.o11y.enabled=false +``` + +通过以下端口映射命令,对本机访问开放端口: + +```shell +kubectl port-forward service/higress-gateway -n higress-system 80:80 443:443 8080:8080 +``` + +在浏览器中输入 `http://127.0.0.1:8080` 进入 Higress 控制台。 + + diff --git a/content/en/overview/reference/integrations/nacos.md b/content/en/overview/reference/integrations/nacos.md new file mode 100644 index 000000000000..2c8012f3c9e9 --- /dev/null +++ b/content/en/overview/reference/integrations/nacos.md @@ -0,0 +1,50 @@ +--- +aliases: +- /zh/overview/reference/integrations/skywalking/ +description: "如何安装与配置 Nacos,涵盖本地、docker、kubernetes等环境。" +linkTitle: Nacos +title: Nacos +type: docs +weight: 5 +--- + +本文档讲解如何安装与配置 Nacos,涵盖本地、docker、kubernetes 等环境。以下仅为快速示例安装指南,如想搭建生产可用集群请参考 Nacos 官方文档。 + +## 本地下载 + +Nacos 依赖 Java 环境 来运行,目前支持 Linux、MacOS、Windows 等环境。 + +您可以 下载最新稳定版本 Nacos,解压缩二进制包: + +```shell +unzip nacos-server-$version.zip +cd nacos/bin +#tar -xvf nacos-server-$version.tar.gz +``` + +#### 启动命令 +```shell +# Linux/Unix/Mac +sh startup.sh -m standalone + +# Ubuntu +bash startup.sh -m standalone + +# Windows +startup.cmd -m standalone +``` + +#### 验证 nacos 正常启动 + +通过浏览器访问以下链接打开控制台:http://127.0.0.1:8848/nacos/ + +## docker +使用 docker 启动 nacos,请首先确保您已经在本地机器正确 下载页面 安装 docker。 + +```shell +docker run --name nacos-quick -e MODE=standalone -p 8849:8848 -d nacos/nacos-server:2.3.1 +``` + +## kubernetes + +请参考 nacos-operator 了解如何部署 Nacos 到 Kubernetes 集群。 diff --git a/content/en/overview/reference/integrations/prometheus.md b/content/en/overview/reference/integrations/prometheus.md new file mode 100644 index 000000000000..89839a4de16d --- /dev/null +++ b/content/en/overview/reference/integrations/prometheus.md @@ -0,0 +1,52 @@ +--- +aliases: + - /zh/overview/reference/integrations/prometheus/ +description: 配置 Prometheus 与 Dubbo 一起工作 +linkTitle: Prometheus +title: Prometheus +type: docs +weight: 1 +--- + +## 安装 + +你可以使用 Dubbo 社区提供的示例配置快速安装 Prometheus。 + +```bash +kubectl create -f https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/deploy/kubernetes/prometheus.yaml +``` +> 本安装仅适用于测试或体验使用,生产级别的安装请参考 Prometheus 官方安装文档。 + +执行端口映射 `kubectl -n dubbo-system port-forward svc/prometheus-server 9090:9090`,访问页面 `http://localhost:9090`,切换到 graph 视图。 + +![Prometheus](/imgs/v3/reference/integrations/prometheus.jpg) + +## Scrape 配置 + +Dubbo 的每个实例都会暴露一个 http 端口用于 Metrics 采集,Prometheus 通过 scraping 每个实例的 http 接口来采集统计数据。具体的 scraping 路径可以通过 Prometheus 配置文件进行调整,该文件控制 scraping 实例的端口、路径、TLS 设置等。 + +### Kubernetes 注解约定 + +在 Kubernetes 部署模式下,使用官方社区维护的 [Helm Charts 安装 Prometheus](https://github.com/prometheus-community/helm-charts),Prometheus 服务可以自动识别包含 `prometheus.io` 注解的 Dubbo Pod 实例,并将它们列入 Scraping 实例列表。 + +Dubbo 官网给出的示例即是基于 `prometheus.io` 注解实现了 scraping target 地址的自动发现,具体注解配置可参见示例中的 [Deployment 资源定义](https://github.com/apache/dubbo-samples/blob/master/4-governance/dubbo-samples-metrics-spring-boot/Deployment.yml)。 + +```yaml +annotations: + prometheus.io/scrape: "true" + prometheus.io/path: /management/prometheus + prometheus.io/port: "22222" +``` + +在此模式下,Dubbo 实例默认提供的 Prometheus Metrics 采集路径是:`/management/prometheus`。 + +### 自定义配置 + +对于已经安装好的 Prometheus 服务,可以通过 Dubbo Admin 提供的 Prometheus http_sd 服务发现接口来配置 Dubbo Metrics 采集的目标实例。可以参考 Admin 安装相关文档,安装完成后 Prometheus 侧需要调整的配置如下: + +```yaml +- job_name: 'dubbo' + http_sd_configs: + - url: http://{admin-address}/api/dev/metrics/prometheus +``` + diff --git a/content/en/overview/reference/integrations/skywalking.md b/content/en/overview/reference/integrations/skywalking.md new file mode 100644 index 000000000000..55bb598b9853 --- /dev/null +++ b/content/en/overview/reference/integrations/skywalking.md @@ -0,0 +1,18 @@ +--- +aliases: +- /zh/overview/reference/integrations/skywalking/ +description: 配置 Skywalking 与 Dubbo 一起工作 +linkTitle: Skywalking +title: Skywalking +type: docs +weight: 3 +--- + +## 安装 + +你可以使用 Dubbo 社区提供的示例配置快速安装 Skywalking。 + +```bash +kubectl create -f https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/deploy/kubernetes/skywalking.yaml +``` +> 本安装仅适用于测试或体验使用,生产级别的安装请参考 Skywalking 官方安装文档。 diff --git a/content/en/overview/reference/integrations/zipkin.md b/content/en/overview/reference/integrations/zipkin.md new file mode 100644 index 000000000000..27ee8fc17373 --- /dev/null +++ b/content/en/overview/reference/integrations/zipkin.md @@ -0,0 +1,18 @@ +--- +aliases: +- /zh/overview/reference/integrations/zipkin/ +description: 配置 Zipkin 与 Dubbo 一起工作 +linkTitle: Zipkin +title: Zipkin +type: docs +weight: 4 +--- + +## 安装 + +你可以使用 Dubbo 社区提供的示例配置快速安装 Zipkin。 + +```bash +kubectl create -f https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/deploy/kubernetes/zipkin.yaml +``` +> 本安装仅适用于测试或体验使用,生产级别的安装请参考 Zipkin 官方安装文档。 diff --git a/content/en/overview/reference/integrations/zookeeper.md b/content/en/overview/reference/integrations/zookeeper.md new file mode 100644 index 000000000000..dce003589532 --- /dev/null +++ b/content/en/overview/reference/integrations/zookeeper.md @@ -0,0 +1,92 @@ +--- +aliases: +- /zh/overview/reference/integrations/skywalking/ +description: "如何安装与配置 Zookeeper,涵盖本地、docker、kubernetes等环境。" +linkTitle: Zookeeper +title: Zookeeper +type: docs +weight: 6 +--- + +这篇文章讲解如何安装与配置 Zookeeper,涵盖本地、docker、kubernetes 等环境。以下仅为快速示例安装指南,如想搭建生产可用集群请参考 Zookeeper 官方文档。 + +## 本地下载 + +#### 下载Zookeeper +请到 Apache Zookeeper 下载页面 下载最新版本的 zookeeper 发行包。 + +解压下载的 zookeeper 包: + +```shell +tar -zxvf apache-zookeeper-3.8.3.tar.gz +cd apache-zookeeper-3.8.3 +``` + +#### 启动 Zookeeper + +在启动 zookeeper 之前,首先需要在根目录以下位置创建文件 `conf/zoo.cfg`: + +``` +tickTime=2000 +clientPort=2181 +admin.enableServer=false +``` + +以下是一些参数的详细解释: +* tickTime : Zookeeper 用到的基本时间设置,tickTime 为心跳检测间隔, 2*tickTime 是最大 session 超时时间等(单位是毫秒 ms)。 +* clientPort : 监听端口,客户端可通过这个端口方案 zookeeper server +* admin.enableServer:运维端口,默认为 8080,建议关闭防止和 Spring Web 应用程序冲突 + +接下来,可以以 standalone 模式启动 Zookeeper 了: + +```shell +bin/zkServer.sh start +``` + +#### 测试连接到 ZooKeeper + +运行以下命令,连接到刚刚启动的 zookeeper server: + +```shell +$ bin/zkCli.sh -server 127.0.0.1:2181 +``` + +连接成功后,可看到以下输出: + +```shell +Connecting to localhost:2181 +... +Welcome to ZooKeeper! +JLine support is enabled +[zkshell: 0] +``` + +执行以下命令查看根节点内容: + +```shell +[zkshell: 8] ls / +[zookeeper] +``` + +## docker + +使用 docker 启动 zookeeper,请首先确保您已经在本地机器正确 下载页面 安装 docker。 + +运行以下命令启动 zookeeper server: + +```shell +docker run --name some-zookeeper -p 2181:2181 -e JVMFLAGS="-Dzookeeper.admin.enableServer=false" --restart always -d zookeeper:3.8.3 +``` + +如果你要指定 `/conf` 配置文件,可通过 mount 本地文件到 docker 容器: +```shell +$ docker run --name some-zookeeper --restart always -e JVMFLAGS="-Dzookeeper.admin.enableServer=false" -d -v $(pwd)/zoo.cfg:/conf/zoo.cfg +``` + +## kubernetes + +您可以使用 Dubbo 社区提供的示例配置快速安装 Zookeeper 到 Kubernetes 集群。 + +```shell +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/deploy/kubernetes/zookeeper.yaml +``` \ No newline at end of file diff --git a/content/en/overview/reference/pixiu/_index.md b/content/en/overview/reference/pixiu/_index.md new file mode 100755 index 000000000000..b7c369e7720e --- /dev/null +++ b/content/en/overview/reference/pixiu/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/ + - /zh-cn/overview/reference/pixiu/ +description: Dubbo Go Pixiu 简介 +linkTitle: Pixiu gateway +title: Dubbo Go Pixiu 简介 +type: docs +weight: 15 +--- diff --git a/content/en/overview/reference/pixiu/dev/_index.md b/content/en/overview/reference/pixiu/dev/_index.md new file mode 100755 index 000000000000..df862b67ff1b --- /dev/null +++ b/content/en/overview/reference/pixiu/dev/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh-cn/overview/mannual/dubbo-go-pixiu/dev/ + - /zh-cn/overview/reference/pixiu/dev/ +description: 开发者指南 +linkTitle: 开发者指南 +title: 开发者指南 +type: docs +weight: 30 +--- diff --git a/content/en/overview/reference/pixiu/dev/dubbo-pilot.md b/content/en/overview/reference/pixiu/dev/dubbo-pilot.md new file mode 100644 index 000000000000..8ad56b648b83 --- /dev/null +++ b/content/en/overview/reference/pixiu/dev/dubbo-pilot.md @@ -0,0 +1,203 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/dev/dubbo-pilot/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/dev/dubbo-pilot/ + - /zh-cn/overview/reference/pixiu/dev/dubbo-pilot/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/dev/dubbo-pilot/ +description: dubbo-pilot Control Plane 部署 +linkTitle: dubbo-pilot Control Plane 部署 +title: dubbo-pilot Control Plane 部署 +type: docs +weight: 2 +--- + + + + + + +* [1.总体目标](#target) +* [2.基本流程](#basic) +* [3.详细步骤](#detail) + + [3.1 环境要求](#env) + + [3.2 istio 本地部署](#native_deploy) + - [3.2.1 编译](#nbuild) + - [3.2.2 部署 & debug](#ndeploy) + + [3.3 istio 容器部署](#docker_deploy) + - [3.3.1 编译](#dbuild) + - [3.3.2 部署 & debug](#ddeploy) +

1 总体目标

+ +* 控制面编译和镜像构建 +* 使用 istioctl 在 kubernetes 环境部署 +* 如何对控制面程序 debug + + + +

2 基本流程

+这个例子将演示如何在编译 dubbo-pilot 控制平面并在 kubernetes 环境下如何使用 istioctl 进行部署 + +1. 本地启动控制平面,对 dubbo-pilot 进行启动和 debug +2. 使用 istioctl 在 k8s 环境启动和 debug + + +

3 详细步骤

+

3.1 环境要求

+ +* Golang +* Docker +* Minikube/Kind +* Kubectl +* Dlv + + +

3.2 本地部署

+

3.2.1 编译

+ +1. 编译 docker-builder +``` +cd dubbo-go-pixiu/tools/docker-builder && go install + +docker-builder -h: + +Builds Istio docker images + +Usage: + [flags] + +Flags: + --architecures strings architectures to build (default [linux/amd64]) + --base-version string base version to use (default "latest") + --builder string type of builder to use. options are crane or docker (default "docker") + -h, --help help for this command + --hub strings docker hub(s) (default [localhost:5000]) + --istio-version string istio version to use (default "1.14-dev") + --kind-load kind cluster to load into + --no-cache disable caching + --no-clobber do not allow pushing images that already exist + --proxy-version string proxy version to use (default "7ae8e27f274b33dc2f4d83100aea5971ed6698d3") + --push push targets to registry + --save save targets to tar.gz + --tag strings docker tag(s) (default [latest]) + --targets strings targets to build (default [app,app_sidecar_centos_7,app_sidecar_debian_11,app_sidecar_ubuntu_jammy,app_sidecar_ubuntu_xenial,ext-authz,install-cni,istioctl,operator,pilot,proxyv2]) + --variants strings variants to build (default [default]) + --version show build version +``` + +2. 使用 docker-builder 自动编译 && 构建镜像 + +编译 istioctl +``` +docker-builder --targets istioctl + +编译完成: + +ls out/linux_amd64/ +istioctl logs pilot-agent pilot-discovery +``` + +编译 dubbo-pilot 并推送到私有镜像仓库 +``` +tools/docker-builder/docker-builder --targets pilot --hub docker.io/bobtthp --push +``` + + +

3.2.2 本地部署

+ +本地启动方式: +``` +./out/linux_amd64/pilot-discovery + +启动日志: +2022-09-24T15:31:56.751245Z info FLAG: --caCertFile="" +2022-09-24T15:31:56.751277Z info FLAG: --clusterAliases="[]" +2022-09-24T15:31:56.751280Z info FLAG: --clusterID="Kubernetes" +2022-09-24T15:31:56.751282Z info FLAG: --clusterRegistriesNamespace="istio-system" +2022-09-24T15:31:56.751284Z info FLAG: --configDir="" +2022-09-24T15:31:56.751286Z info FLAG: --ctrlz_address="localhost" +2022-09-24T15:31:56.751289Z info FLAG: --ctrlz_port="9876" +2022-09-24T15:31:56.751291Z info FLAG: --domain="cluster.local" +... +2022-09-24T15:31:56.753814Z info initializing mesh configuration ./etc/istio/config/mesh +``` + +

3.3 容器部署

+ +

3.3.1 镜像构建

+ +构建远程 debug 镜像 + +1. 下载 dlv +``` +git clone https://github.com/go-delve/delve.git +make install + +which dlv +/root/go/bin/dlv +``` + +2. Dockerfile 增加dlv dubbo-go-pixiu/pilot/docker/Dockerfile.pilot: +``` +COPY ${TARGETARCH:-amd64}/dlv /usr/local/bin/dlv +``` + +3. 拷贝 dlv 至镜像挂载目录中: +``` +cp /root/go/bin/dlv out/linux_amd64/dockerx_build/build.docker.pilot/amd64/ +``` + +4. debug 镜像构建并推送: +``` +docker-builder --targets pilot --hub docker.io/bobtthp --push --tag debug +``` + +5. 本地也可以查看镜像构建情况: + +``` +[root~master-1] /tmp/dubbo-go-pixiu/tools/docker-builder> docker images +REPOSITORY TAG IMAGE ID CREATED SIZE +bobtthp/pilot latest 7b1aadd55120 13 minutes ago 262MB +``` + + + +

3.3.2 部署

+ +1. 使用刚构建的镜像部署: +``` +out/linux_amd64/istioctl --set .values.pilot.image=bobtthp/pilot:debug install +``` + +2. 查看部署情况: +``` +[root~master] /tmp/dubbo-go-pixiu/tools/docker-builder> kubectl get po -n istio-system +NAME READY STATUS RESTARTS AGE +istiod-fd5d9f77-2ncjq 1/1 Running 0 18m +``` + + +3. 进入容器远程 debug: +``` +[root~master-1] /tmp/dubbo-go-pixiu> kubectl exec -it -n istio-system istiod-fd5d9f77-2ncjq bash +kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. +``` + +4. 启动 dlv: +``` +istio-proxy@istiod-fd5d9f77-2ncjq:/$ dlv --listen=:8015 --headless=true --api-version=2 --log attach `ps -ef |grep pilot-discovery| awk '{print $2}'` +2022-11-04T15:43:14Z error layer=debugger could not create config directory: mkdir /home/istio-proxy/.config: read-only file system +API server listening at: [::]:8015 +2022-11-04T15:43:14Z warning layer=rpc Listening for remote connections (connections are not authenticated nor encrypted) +2022-11-04T15:43:14Z info layer=debugger attaching to pid 1 +``` + + +5. 对外暴露端口: + +``` +[root~master-1] /tmp> kubectl port-forward -n istio-system istiod-fd5d9f77-2ncjq 8015:8015 +Forwarding from 127.0.0.1:8015 -> 8015 +Forwarding from [::1]:8015 -> 8015 +``` + +6. 可以进行远程调试 diff --git a/content/en/overview/reference/pixiu/dev/filter-extension.md b/content/en/overview/reference/pixiu/dev/filter-extension.md new file mode 100644 index 000000000000..a7c4066c632f --- /dev/null +++ b/content/en/overview/reference/pixiu/dev/filter-extension.md @@ -0,0 +1,143 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/dev/filter-extension/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/dev/filter-extension/ + - /zh-cn/overview/reference/pixiu/dev/filter-extension/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/dev/filter-extension/ +description: Pixiu Filter体系介绍 +linkTitle: Pixiu Filter体系介绍 +title: Pixiu Filter体系介绍 +type: docs +weight: 1 +--- + + + + + + +## **怎样编写一个Filter** +`更详细的信息,请移步Blog《谈谈Pixiu的Filter》` + +我们来尝试写一个简单的Filter,这个Filter将会有简单的配置,在Decode阶段把请求的Body Log出来,并翻转后作为Mock的返回值。最后在Encode阶段根据配置把返回值Log出来。 + +1.首先创建一个Filter + +```go +type DemoFilter struct { + logPrefix string +} + +// Decode阶段,发生在调用Upstream之前 +func (f *DemoFilter) Decode(ctx *contexthttp.HttpContext) filter.FilterStatus { + body, _ := ioutil.ReadAll(ctx.Request.Body) + logger.Infof("request body: %s", body) + + //reverse res str + runes := []rune(string(body)) + for i := 0; i < len(runes)/2; i += 1 { + runes[i], runes[len(runes)-1-i] = runes[len(runes)-1-i], runes[i] + } + reverse := string(runes) + + //mock response + ctx.SendLocalReply(200, []byte(reverse)) + return filter.Stop +} + +// Encode阶段,此时可以获取到Upstream的Response +func (f *DemoFilter) Encode(ctx *contexthttp.HttpContext) filter.FilterStatus { + res := ctx.SourceResp.(string) + logger.Infof("%s: %s", f.logPrefix, res) + return filter.Continue +} +``` + +2.创建Filter Factory + +```go +type ( + DemoFilterFactory struct { + conf *Config + } + // Config describe the config of Filter + Config struct { + LogPrefix string `yaml:"logPrefix,omitempty"` + } +) + +func (f *DemoFilterFactory) PrepareFilterChain(ctx *contexthttp.HttpContext, chain filter.FilterChain) error { + demo := &DemoFilter{logPrefix: f.conf.LogPrefix} + + chain.AppendDecodeFilters(demo) + chain.AppendEncodeFilters(demo) + return nil +} + +func (f *DemoFilterFactory) Config() interface{} { + return f.conf +} + +func (f *DemoFilterFactory) Apply() error { + return nil +} +``` + +3.创建Filter Plugin,并注册自己 + +```go +//important +func init() { + filter.RegisterHttpFilter(&Plugin{}) +} + +type Plugin struct { +} + +func (p *Plugin) Kind() string { + return "dgp.filters.demo" +} + +func (p *Plugin) CreateFilterFactory() (filter.HttpFilterFactory, error) { + return &DemoFilterFactory{conf: &Config{}}, nil +} +``` + +4.配置文件中配置此Filter,并启动Pixiu + +```yaml +static_resources: + listeners: + - name: "net/http" + protocol_type: "HTTP" + address: + socket_address: + address: "0.0.0.0" + port: 8888 + filter_chains: + filters: + - name: dgp.filter.httpconnectionmanager + config: + route_config: + routes: + - match: + prefix: "/" + http_filters: + - name: dgp.filters.demo + config: +``` + +5.访问并查看日志与结果 + +```shell +curl localhost:8888/demo -d "eiv al tse’c" + +c’est la vie% +``` + +日志 + +``` +2022-02-19T20:20:11.900+0800 INFO demo/demo.go:62 request body: eiv al tse’c +2022-02-19T20:20:11.900+0800 INFO demo/demo.go:71 : eiv al tse’c +``` diff --git a/content/en/overview/reference/pixiu/dev/trie.md b/content/en/overview/reference/pixiu/dev/trie.md new file mode 100644 index 000000000000..3c9293505144 --- /dev/null +++ b/content/en/overview/reference/pixiu/dev/trie.md @@ -0,0 +1,147 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/dev/trie/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/dev/trie/ + - /zh-cn/overview/reference/pixiu/dev/trie/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/dev/trie/ +description: Trie 前缀树介绍 +linkTitle: Trie 前缀树介绍 +title: Trie 前缀树介绍 +type: docs +weight: 2 +--- + + + + + +# 简介 + +![image.png](/imgs/pixiu/trie-1.png)
网关的核心之一是路由逻辑,决定一个请求需要经过怎样的加工,被转发到哪个下行服务。
其中 80% 的路由需求表达都以 URL 为基础。需要描述清楚具有某个特征的 URL 或者 URL 集合对应怎样的一系列下游处理策略。 + +例如,'/test/**' 开头的 URL 路由到测试环境集群,'/release/user/**' 开头的 URL 会被路由到正式环境的 user 服务集群。 + + +同时网关作为所有请求的入口,每一毫秒的延时都会做用在全量的业务下,在 mesh 场景下,延时还会随着调用链路的加深,被倍数放大。按照生产环境业务相应 <=7 毫秒的标准来看,规则匹配的性能要求也是十分苛刻的。一定不能随着规则数目的增加而性能退化。 + +# 使用介绍 + +仅从使用方的角度阐述 pixiu 的配置文件如何描述 URL 相关的路由规则。(下面,我们介绍一下如何配置 URL 路由规则)
如下是一份 pixiu 的 api 配置文件,这份配置文件会被解析后生成一份对应的内存模型,作为 pixiu 路由相关配置的初始状态。之后由 RDS 协议修改解析后得到的内存模型,实现路由逻辑动态生效的效果。RDS 协议(RDS:xDS 协议下描述路由规则的部分)相关内容是后话不详细阐述。我们把注意力聚焦到resource部分。
resource 下 path 部分就是上文阐述的,URL 相关的路由描述。意思是满足 path 描述特征的 URL 会被成功匹配。 + +```json +name: server +description: server sample +resources: + - path: '/api/v1/test-dubbo/user/name/:name' + type: restful + description: user + methods: + - httpVerb: GET + enable: true + timeout: 1000ms + inboundRequest: + requestType: http + uri: + - name: name + required: true + integrationRequest: + requestType: dubbo + mappingParams: + - name: uri.name + mapTo: 0 + mapType: "string" + applicationName: "UserProvider" + interface: "com.dubbogo.server.UserService" + method: "GetUserByName" + group: "test" + version: 1.0.0 + clusterName: "test_dubbo" + + +``` + +被匹配后的请求会被转化成 dubbo 协议转发到 test_dubbo 集群调用 com.dubbogo.server.UserService 下的 GetUserByName 服务。
我们继续聚焦到如下范围: +```json +path: '/api/v1/test-dubbo/user/name/:name' +``` +为了描述清楚一个 URL 或者一组 URL,路由引擎需要拥有以下能力: + +1. URL 可以包含变量,'/api/v1/test-dubbo/user/name/:name' 代表 URL 用“/”分割后,第六个部分的值作为变量 name 的值,向下游 filter 传递供filter使用。 +1. 需要有通配符 + 1. * 代表一个层级任意字符的通配 '/api/*/test-dubbo/user/name/:name' 这样的一个 path 描述代表了可能并不关心具体的版本,不论什么版本下的 URL 只要匹配都使用相同的逻辑加工数据并转发。 + 1. ** 代表多个层级的通配,从这个层级以后,子层级也可以是任意字符,**只可能存在于 URL 的末尾,不然会有二义性。'/api/v1/**' 这样的 path 表达了所有 V1 版本下的 URL 都采用相同的逻辑。 + +为了正确的使用 pixiu 您可能还需要了解如下内容。 + +## 优先级 + +并非是独创的,类似 java 下的 spring 以及其他框架统一具有的优先级逻辑: + +1. 通配的优先级低于特指 。 '/api/v1/**' 低于 '/api/v1/test-dubbo/user/name/:name' 的优先级,假设有两个 resource 分别采用了如上两个path 配置,request 为 '/api/v1/test-dubbo/user/name/yqxu' 的请求到达pixiu 后应该生效哪个 resource?按照通配低于特指的原则,'/api/v1/test-dubbo/user/name/:name' 这条规则会生效。 +1. 深度更深的,优先级更高 。 '/api/v1/**' 对比 /api/v1/test-dubbo/**' ,如果请求同时满足如上两个描述, '/api/v1/test-dubbo/**' 深度更深,会生效。 +1. 通配符之间 '/*' 优先级高于 '/**' +1. 变量等同于通配。 + +## 冲突处理 + +优先级规则只是冲突解决策略的一种,才同时匹配多个url描述时,优先级更高的那一种将会生效,然而优先级策略并不能涵盖所有的情况。
如果强行配置两条 resource path 完全相同,但是转发到不同的下游服务,这时候就会冲突。pixiu 下应对冲突的方案是 failfast,在 pixiu 初始化阶段,发现配置文件中有冲突的两项规则,则启动失败,让开发者今早发现问题并处理。 + +# 原理介绍 + +技术选型之初,以及确定使用pixiu后为了处理一些突发情况,以及应付一些pixiu自身可能存在的bug,开发者需要对pixiu 的路由原理有更深刻的了解。
下面,我们将详细介绍路由引擎的相关原理和实现,供感兴趣的同学了解。
相信阅读这部分内容的同学一定会有人下意识联想到字典树这个结构。使用字典树这个结构能实现存量规则数无关的匹配性能优化。 + +一个存放字符串作为node的字典树,具有表达url 的能力。
![img](/imgs/pixiu/trie-2.png)
如上图描述等价于URL集合 '/api/v1' ,'/api/v2' ,'/web' + +维护一个标准字典树有几个关键的操作 + +1. 字典树指定节点的查找(find): 从root 开始遍历字典书,'/api/v2' 称之为路径,在当前层级寻找指定路径,如果存在就继续在子树下完成剩下的路径匹配。'/api/v2' 先从 logic root 找到 '/api' ,并在 '/api' 的子树下继续查找剩下的路径 '/v2' 。 +1. 字典树节点的添加(add): 尝试查找指定节点,如果指定节点不存在则新建一个节点。假设一个空树状态下添加 '/api/v1' ,因为是空树那么logic root 下查找 '/api' 一定不存在,则在 root 下创建 '/api' ,继续在创建的 '/api' 节点下查找 '/v1' 因为 '/api' 是新建的 v1 一定也不存在,则继续创建v1 +1. 字典树url匹配(match):在这个最简单的版本下,匹配逻辑与指定节点的查找逻辑没有区别。 + +还有一些不涉及递归或者复用上面逻辑递归操作的简单操作 + +4. 修改字典树节点(modify):通过 find 逻辑找到指定节点,调用 set 方法或者直接赋值的方式修改节点内容。 +4. 删除字典树节点(delete): 通过 modify 逻辑修改 isdeleted 标为 true,并把节点内容 modify 为空。节点本身的内存不释放。 +4. 重建字典树(rebuild):遍历所有节点,添加到新树,如果 isdeleted为 true 则不添加到新树,通过rebuild 操作创建副本。 + +由上可知,标准字典树结构距离通用的路由引擎底层数据结构能力还有一定差距,缺乏统配描述能力,缺乏变量表达的能力,下面我们来看一下如何进行改进。 + +添加 描述统配逻辑的子树,作为子树中默认存在的一部分
![img](/imgs/pixiu/trie-3.png)
现在我们的变种字典树多了变量表达能力
'/web/:appname/test/*' 这样的url 在图中应该怎么表达?
没错就是这个路径
+ +![img](/imgs/pixiu/trie-4.png) + + +继续分析字典树几个关键的操作是否需要做变化? + +1. 字典树指定节点的查找 : + 1. 如果不改动使用前一版本逻辑在 '/*' 节点处理之前都不会有问题: 从root 开始遍历字典书,'/api/v2/*' 称之为路径,在当前层级寻找指定路径,如果存在就继续在子树下完成剩下的路径匹配。 /api/v2 先从 logic root 找到 '/api' ,并在 '/api' 的子树下继续查找剩下的路径 '/v2' 。 + 1. 这版本我们加上对 '/*' 节点的处理:'/v2' 后是 '/*' ,'/*' 对应单级通配节点,继续递归查找 '/v2' 节点下一级通配节点是否为空。如果 path 是 '/api/v2/*/test2' 这样的路径则继续在统配子树下完成递归过程。 +2. 字典树节点的添加 : + 1. 在添加 '/*' 节点之前,所有逻辑上一版本就足够处理:尝试查找指定节点,如果指定节点不存在则新建一个节点。假设一个空树状态下添加 '/api/v1/*' ,因为是空树那么 logic root 下查找 '/api' 一定不存在,则在 root 下创建 '/api' ,继续在创建的 '/api' 节点下查找 '/v1' 因为 '/api' 是新建的 v1 一定也不存在,则继续创建 v1。 + 1. 这版本加上 '/*' 的特殊处理 :'/v1' 新建后,查看通配子树,通配子树不存在,则为V1 节点添加内容为空的单级通配子树并在子树中继续递归。 +3. 字典树url匹配:在这个版本下,对比查找逻辑需要增加回朔逻辑。 + 1. 在遇到通配节点前逻辑与find 依旧相同 : 从root 开始遍历字典书,'/api/v2/*' 称之为路径,在当前层级寻找指定路径,如果存在就继续在子树下完成剩下的路径匹配。 '/api/v2' 先从 logic root 找到 '/api' ,并在 '/api' 的子树下继续查找剩下的路径 '/v2' 。 + 1. 在处理统配节点的时候会与 find 逻辑有所不同:'/v2' 下普通子树无匹配节点,回朔到通配子树,查看是否能匹配,这个例子中 '/v2' 下无通配子树,查询不到节点 。值得注意的是回朔逻辑的先后顺序,是先找普通子树再回朔到通配子树还是先查找通配子树再回朔到普通子树是取决于优先级规则的,按照需求必须是先查找普通子树。 + +但是我们目前还是缺乏 '/**' 这种通配的表达能力代表了多级通配,可以分析需求得到结论,这种通配符,一定不存在子树,是一种特殊的叶子结点,仅用于 match 逻辑回朔时做特殊判断。继续加点特殊 node 后演化为:
![img](/imgs/pixiu/trie-5.png)
好了至此,需求都能满足了。
'/api/**' 等价路径为:
![img](/imgs/docs3-v2/dubbo-go-pixiu/dev/trie/1642993180981-51a0df19-bb03-49c8-9128-a6e95dbabfcd.png)
其他逻辑大同小异,match 逻辑回朔再多一级判断,如果一级通配子树也匹配不到结果,则再看一下多级通配子树是否为空(其实留一个标位就可以,为了统一模型好理解,还是用一个子树去描述) + +到目前这个版本所有上文提到的能力已经都能有效支撑,回头分析一下时间复杂读。
url 被 '/' 分割出一个一个的段,容易理解在匹配一个url 过程中复杂度是 O(n) n= url 段数。与树中存有的规则数量无关。再分析 n 的范围,n 其实不是一个可以无限大的数字,一部分浏览器甚至约束 url 长度必须小于 2000,按照一个单词长度为 5 来计算,可以大概估计段数最多会在 400 左右,n 如果可以被视为一个常数,那么复杂读可以看作是 O(1)。 + +稍微解释一下find 和 match 有什么不同,为什么需要两种查找节点的方法。看下这个例子 :假设树中已经add 了 '/api/v1/:name/add' 这个 path,那么
find("/api/v1/:name/add"),find("/api/v1/*/add")两个调用应该能够拿到结果,在add 的过程中用于冲突判断。
假设有请求进来url 为 '/api/v1/:name/add' 那么match("/api/v1/:name/list")也应该能 match 到结果且变量name 为 :name。
再假设有请求进来 url 为 '/api/v1/yq/add' 那么match("/api/v1/yq/list")也应该能 match 到结果且变量name 为 yq 。find("/api/v1/yq/add" ) 则不会匹配到结果。 +# 后续改进 + +目前实现在读树和写树之前,竞争一把全局锁,竞争失败后自旋直到竞争成功,然后完成读写。
解释一下为什么读都需要上锁,因为代码中大量运用了go 的 map 结构。这个结构只要并发读写直接会报如下错误:concurrent map read and map write
目前实现如下
![img](/imgs/pixiu/trie-6.png)
引入 command 队列,所有对 trie 的用户写操作先入列,同时做读写分离,分为读树和写树,维护一个线程负责追 log 把 command 写入到写树,读树因为只读,没有写入线程操作读树所以可以不加锁。写树因为只有一条线程向树内写入,没有竞争问题,也可以不加锁。(写入操作并不会很频繁单线程完全能负荷)
定义一个配置延迟生效的时间,比如3s
每3秒,读树和写树角色切换,每个 trie 分别维护一个 command 队列的游标,游标代表当前这个 trie,追 log 追到了哪条记录,写入线程每3s 切换写游标引用。
+ +![img](/imgs/pixiu/trie-7.png) + +如上图,最上面部分是一个先进先出的 command 队列,追 log 线程从这个队列中读取用户写操作,这个队列维护了两个游标 index1,index2,index1 代表了trie1 追 log 追到了 index1 的位置,index2 代表了 trie2 追 log 追到了 index2 的位置。追 log 线程同一时间内只会使用一个引用进行写操作,每次写完树对应的 index 游标下移一格,另一个 trie 引用将被用于读操作,一切读请求将从读引用对应的树中读取。因为追的是同一份 log ,最终一致性是能保证的。 + +切换逻辑: + +1. 先使追 log 线程空转(不挂起,避免上下文切换,因为马上要恢复) +1. 保证两个树都没有写入线程操作 +1. 切换读引用到另一个树 +1. 切换写引用到另一个树 +1. 恢复追 log 线程 + +pr:
[https://github.com/apache/dubbo-go-pixiu/pull/262](https://github.com/apache/dubbo-go-pixiu/pull/262)
pkg/common/router/trie/trie.go:26 diff --git a/content/en/overview/reference/pixiu/overview/_index.md b/content/en/overview/reference/pixiu/overview/_index.md new file mode 100755 index 000000000000..6815f4c36b9e --- /dev/null +++ b/content/en/overview/reference/pixiu/overview/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/overview/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/overview/ + - /zh-cn/overview/reference/pixiu/overview/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/overview/ +description: 入门概述 +linkTitle: 入门概述 +title: 入门概述 +type: docs +weight: 10 +--- diff --git a/content/en/overview/reference/pixiu/overview/faq.md b/content/en/overview/reference/pixiu/overview/faq.md new file mode 100755 index 000000000000..22da713f34a0 --- /dev/null +++ b/content/en/overview/reference/pixiu/overview/faq.md @@ -0,0 +1,30 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/overview/faq/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/overview/faq/ + - /zh-cn/overview/reference/pixiu/overview/faq/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/overview/faq/ +description: Pixiu 常见问题 +linkTitle: Pixiu 常见问题 +title: Pixiu 常见问题 +type: docs +weight: 3 +--- + + + + + + + +### 常见问题 Q1 +**Pixiu 目前可以用于生产环境吗?** + +**A:** + 0.4.0版本之后就可以上生产环境,欢迎已经在使用的企业参与此 issue: [who's using Pixiu](https://github.com/apache/dubbo-go-pixiu/issues/64) + +### 常见问题 Q2 +**Pixiu 目前支持高可用吗?** + +**A:** + 目前 Pixiu 仅支持单实例部署,可以和 Nginx 组成无状态多实例集群。 diff --git a/content/en/overview/reference/pixiu/overview/terminology.md b/content/en/overview/reference/pixiu/overview/terminology.md new file mode 100755 index 000000000000..ca4fdbbf3bfd --- /dev/null +++ b/content/en/overview/reference/pixiu/overview/terminology.md @@ -0,0 +1,44 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/overview/terminology/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/overview/terminology/ + - /zh-cn/overview/reference/pixiu/overview/terminology/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/overview/terminology/ +description: Pixiu 术语 +linkTitle: Pixiu 术语 +title: Pixiu 术语 +type: docs +weight: 2 +--- + + + + + + + +![img](/imgs/pixiu/overview/terminology.png) + +### Listener 监听器 + +Lisnter 代表网络端口监听的能力,可以配置监听的协议类型,地址,端口。目前支持 TCP、HTTP、HTTP2 和 TRIPLE 协议。 + +### Network Filter 网络过滤器 + +NetworkFilter 直接和 Listener 进行对接,代表对基础网络请求的处理,包括原始协议解析,路由解析等功能。 + +### Http Filter & Dubbo Filter HTTP & Dubbo 过滤器 + +Http Filter 和 Dubbo Filter 可以看做二级 Filter,提供诸如协议转换,限流,身份认证等通用功能。 + +### Route 路由 + +Route 代表请求的路由规则 + +### Cluster 集群 + +Cluter 代表相同服务的集群,Endpoint 则代表服务集群中的单一服务实例。 + +### Adapter 适配器 + +Adapter 则代表 Pixiu 和外界进行元数据获取的能力。能够根据服务中的服务元数据,进行路由和集群信息的动态获取。目前 Pixiu 支持两宽 Adapter,分别是从 Dubbo 集群和 Springcloud 集群获取信息。 diff --git a/content/en/overview/reference/pixiu/overview/what-is-pixiu.md b/content/en/overview/reference/pixiu/overview/what-is-pixiu.md new file mode 100755 index 000000000000..2cb6d8e13fbd --- /dev/null +++ b/content/en/overview/reference/pixiu/overview/what-is-pixiu.md @@ -0,0 +1,48 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/overview/what-is-pixiu/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/overview/what-is-pixiu/ + - /zh-cn/overview/reference/pixiu/overview/what-is-pixiu/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/overview/what-is-pixiu/ +description: Pixiu 是一款开源的 Dubbo 生态的 API 网关和 接入 dubbo 集群的语言解决方案。作为 API 网关形态。 +linkTitle: Pixiu 是什么 +title: Pixiu 是什么 +type: docs +weight: 1 +--- + + + + + + +### Pixiu 说明 + + +Pixiu 是一款开源的 Dubbo 生态的 API 网关和 接入 dubbo 集群的语言解决方案。作为 API 网关形态, Pixiu 能接收外界的网络请求,将其转换为 dubbo 等协议请求,转发给背后集群;作为 Sidecar,Pixiu 期望可以代替代理服务注册到 Dubbo 集群,让多语言服务接入 Dubbo 集群提供更快捷的解决方案。 + + +![image](/imgs/pixiu/overview/pixiu-overview.png) + + + + +### API 网关 + +作为一款网关产品,Pixiu 帮助用户轻松创建、发布、维护、监控和保护任意规模的 API ,接受和处理成千上万个并发 API 调用,包括流量管理、 CORS 支持、授权和访问控制、限制、监控,以及 API 版本管理。除此以外,作为 Dubbo 的衍生产品,Pixiu 可以帮助 Dubbo 用户进行协议转换,实现跨系统、跨协议的服务能力互通。 +Pixiu 的整体设计遵守以下原则: +- High performance: 高吞吐量以及毫秒级的延时。 +- 可扩展: 通过 go-plugin,用户可以根据自己的需求延展 Pixiu 的功能。 +- 简单可用: 用户通过少量配置,即可上线。 + + +### Sidecar 模式 + +目前最为主流的接入 dubbo 集群的方式当然是集成语言对应的 sdk,但是如图的左侧部分。但是对于dubbo来讲,它的多语言支持能力不足,目前较为成熟的只有 java 版本和 go 版本,当然 js 版本 和 python 版本也在努力追赶中.其次,就是使用sdk的通用问题,比如代码耦合度高,版本升级困难,服务发现,服务路由和负载均衡策略不易整体调控等。 + +所以 mesh 话或者 sidecar 的方案,也就是 service mesh 在16年时被提出。将服务发现,服务路由和负载均衡等逻辑放在 sidecar,服务使用轻量级 sdk 与之进行交互。 + +![img](/imgs/pixiu/overview/pixiu-sidecar.png) + +对于接入 dubbo 的多语言解决方案。首推的当然是 pixiu 作为 sidecar 和 服务进行同时部署。pixiu提供 服务发现,流量治理,路由能力,协议转换能力和通讯能力。如图的左侧部分,使用sidecar的服务可以和原生使用 dubbo 框架的服务组成集群,无感的进行相互调用。 +另外一种方案是 pixiu 只单单作为代理,将服务注册到dubbo集群中,如图右侧部分,这种方案部署和运维较为简单,比如适合中小规模的集群。 diff --git a/content/en/overview/reference/pixiu/user/_index.md b/content/en/overview/reference/pixiu/user/_index.md new file mode 100755 index 000000000000..1b21e015232c --- /dev/null +++ b/content/en/overview/reference/pixiu/user/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/ + - /zh-cn/overview/reference/pixiu/user/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/ +description: 用户文档 +linkTitle: 用户文档 +title: 用户文档 +type: docs +weight: 20 +--- diff --git a/content/en/overview/reference/pixiu/user/adapter/_index.md b/content/en/overview/reference/pixiu/user/adapter/_index.md new file mode 100755 index 000000000000..c66262d179c9 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/adapter/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/adapter/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/adapter/ + - /zh-cn/overview/reference/pixiu/user/adapter/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/adapter/ +description: Adapter 介绍 +linkTitle: Adapter 介绍 +title: Adapter 介绍 +type: docs +weight: 60 +--- diff --git a/content/en/overview/reference/pixiu/user/adapter/dubbo.md b/content/en/overview/reference/pixiu/user/adapter/dubbo.md new file mode 100644 index 000000000000..56d634d99ea1 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/adapter/dubbo.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/adapter/dubbo/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/adapter/dubbo/ + - /zh-cn/overview/reference/pixiu/user/adapter/dubbo/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/adapter/dubbo/ +description: Dubbo 集群中心 Adapter +linkTitle: Dubbo 集群中心 Adapter +title: Dubbo 集群中心 Adapter +type: docs +weight: 10 +--- diff --git a/content/en/overview/reference/pixiu/user/adapter/springcloud.md b/content/en/overview/reference/pixiu/user/adapter/springcloud.md new file mode 100644 index 000000000000..01339a53be88 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/adapter/springcloud.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/adapter/springcloud/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/adapter/springcloud/ + - /zh-cn/overview/reference/pixiu/user/adapter/springcloud/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/adapter/springcloud/ +description: Spring Cloud 集群中心 Adapter +linkTitle: Spring Cloud 集群中心 Adapter +title: Spring Cloud 集群中心 Adapter +type: docs +weight: 20 +--- diff --git a/content/en/overview/reference/pixiu/user/appendix/_index.md b/content/en/overview/reference/pixiu/user/appendix/_index.md new file mode 100755 index 000000000000..879e2baf0d11 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/appendix/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/appendix/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/appendix/ + - /zh-cn/overview/reference/pixiu/user/appendix/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/appendix/ +description: 附录 +linkTitle: 附录 +title: 附录 +type: docs +weight: 90 +--- diff --git a/content/en/overview/reference/pixiu/user/appendix/http-to-dubbo-default-stragety.md b/content/en/overview/reference/pixiu/user/appendix/http-to-dubbo-default-stragety.md new file mode 100644 index 000000000000..e5c287f9f4df --- /dev/null +++ b/content/en/overview/reference/pixiu/user/appendix/http-to-dubbo-default-stragety.md @@ -0,0 +1,327 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/appendix/http-to-dubbo-default-stragety/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/appendix/http-to-dubbo-default-stragety/ + - /zh-cn/overview/reference/pixiu/user/appendix/http-to-dubbo-default-stragety/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/appendix/http-to-dubbo-default-stragety/ +description: HTTP to Dubbo 默认转换协议 +linkTitle: HTTP to Dubbo 默认转换协议 +title: HTTP to Dubbo 默认转换协议 +type: docs +weight: 10 +--- + + + + + + +# 背景 + + +​ 通过 Http 提供一个统一的服务提供者视图,用户不用在乎后端Dubbo服务的版本差异,协议差异,通过简单地在Http请求中传递rpc调用的参数,完成一次Rpc调用,通过实现http调用后端dubbo服务,进一步简化后端服务设计的复杂性。 + +# 目的 + +​ 统一Http调用后端dubbo服务的形式,方便网关产品实现 Http 调用转 dubbo 调用的实现,Dubbo能和网关更好的融合。 + +# Conception + +## Dubbo RPC 调用的基本形式 + + + +![img](/imgs/pixiu/user/appendix/img1.png) + + + +希望通过提供Http调用Dubbo的方式简化 Consumer 的Rpc调用流程 + + + +![img](/imgs/pixiu/user/appendix/img2.png) + + + +网关会在整个服务调用的过程中承担更多的原本客户端的功能,比如负载均衡,服务治理,安全等能力,外部用户调用服务的时候将更多的关注与调用本身。 + + + +## Http request 和 Http response 的格式 + +request的URL和Header中包含RPC调用的元信息,包含服务名,方法名,服务分组,服务版本,request 的 body 中包含请求的参数,参数是 **json list** 的格式, 如果没有参数则为 ***null*** + +http response 中包含请求的处理状态,返回结果或者调用的错误类型以及错误具体信息,返回的body中只包含一个 ***json object***,这个object中包含 ***code***,***result***,***error*** + +通过 code 表示返回的具体状态,result 和 error 在返回中只会返回其中一个,分别是调用的返回结果,调用返回的错误信息。 + + + +### Http request + +#### Http 请求的方法 + +只能为 **POST** 方法 + + + +#### Http 请求的 URL + +格式:`[http://host/ {service} / {method](http://host/service/method)}` or `[https://host/ {service} / {method](https://host/service/method)}` + + + +- service 是调用的服务名,对应于Dubbo message body中的 service Name +- method 是调用的方法名,对应于Dubbo message body中的 method Name + +服务名和方法名都应该和后端服务的声明一致 + + + +如果URL中无法获取到service和method,应该直接返回 + +| http code | code | detail | +| --------- | ---- | ------------------------------ | +| 400 | 3 | service or method not provided | + + + +#### Http 请求的Header + + + +Header中必须包含以下条目: + +- x-dubbo-service-protocol + +表明这个Http 请求是一个Http转dubbo的请求,目前支持Dubbo 协议和 triple 协议,可配置的选项为: + +- - x-dubbo-service-protocol: triple + - x-dubbo-service-protocol: dubbo + +​ 前者表示这是转化为triple协议,后者表示转化为dubbo协议 + + + +可选参数: + +- x-dubbo-service-version 如果提供了应该填充到Dubbo message 的Serviceversion字段中. +- x-dubbo-service-group 如果提供了应该在attachment 添加 group 字段并把对应的值进行填充。 + + + +#### Http 请求的Body + + + +body中包含请求的参数,body中只包含一个 ***Json object*** 对象 + +这个对象目前包含两个字段: + +- param + +param 的值类型为 list,标识调用方法的参数,顺序和方法签名中的参数顺序一致 + +这里使用object组装请求参数是为了协议能够向后兼容,body中的对象可能会增加新的字段。 + + + +##### 基本类型在 Json Java Go 中的映射关系 + +| Json Type | Java Type | Golang Type | +| --------- | ----------------- | ----------- | +| Integer | java.lang.Long | int64 | +| Double | java.lang.Double | float64 | +| String | java.lang.String | string | +| Null | null | nil | +| Bool | java.lang.Boolean | bool | +| List | java.lang.List | silice | +| Object | java.lang.Map | map | + +通过对基本类型映射关系的定义简化网关配置,对于只使用基本配置的转化,网关应该可以在不使用额外配置的情况下完成转化的 + + + +##### Body 处理异常时的处理策略 + +1. 调用方提供的请求参数 Json 解析错误,返回状态码 400 +2. 调用的时候,无法确定参数的具体类型,例如,用户使用的自定义类型,但是没有在网关配置具体的类型名,应该返回状态码 400 + +| http code | code | detail | +| --------- | ---- | ---------------------------- | +| 400 | 3 | argument parse error | +| 400 | 3 | argument type info not found | + +在以上条件都符合时,一个Http 调用可以被转化成为 Dubbo 协议的调用,只要网关能够成功进行请求的转化,则网关回复调用方的时候,Http 状态码都应该是 200 OK,至于调用方调用后端服务出现错误的信息,应该放在 body 中的 code 以及 error 字段中。 + + + +### http response + +在请求经过后端返回之后,需要将一下信息传递给调用方: + +| name | description | +| -------- | -------------------------------------------------------- | +| status | 返回的状态,在dubbo response 的header的status 中 | +| 返回值 | 调用成功返回的结果,如果没有返回值,则result 的值为 null | +| 返回异常 | 调用失败,产生异常,返回异常的具体message | + +返回值和返回异常只能出现一项 + +code 和 grpc 中的 status code 一致 详细的 code 及其含义见 https://grpc.github.io/grpc/core/md_doc_statuscodes.html + + + +#### 返回异常的处理: + +dubbo 中的异常以hessian2 的 class 类型返回,返沪的error中只需要对应的message 字段即可 + + + + + +## Dubbo 协议的具体转化 + +### Dubbo 协议的具体介绍 可以见文章 + +https://dubbo.apache.org/en/blog/2018/10/05/introduction-to-the-dubbo-protocol/ + + + +### Dubbo 协议的 message 格式 + +![img](/imgs/dev/dubbo_protocol_header.png) + + + +#### Dubbo Header的封装要求 + +| bits | Name | description | +| -------- | -------------- | ----------------------------------------------------- | +| 0 - 15 | Magic Number | 必须为 0xdabb | +| 16 | message 的类型 | 必须为 1 (request) | +| 17 | 2-way | 必须为 1 (需要服务端返回值) | +| 18 | Event | 必须为 0 不支持事件类型 | +| 19 - 23 | 序列化类型 | 可以扩展实现Hessian,Json等序列化类型,类型编号如下表 | +| 24 - 31 | Status | 表示 response 的状态,见Status 处理要求 | +| 32 - 95 | Request Id | 客户端的请求ID,可以根据需要自行定义 | +| 96 - 127 | Data length | 请求体的长度,请求体的大小 | + + + +序列化类型编号: + +| Serialization Type | Code | +| ------------------ | ---- | +| Hessian2 | 2 | +| Java | 3 | +| Compact Java | 4 | +| Fast Json | 6 | +| Native Java | 7 | + + + +请求Header中的字段应该以大端的形式封装,发送到服务端 + + + +#### Dubbo Body + + + +请求的body应该包含以下内容: + +| name | description | +| ---------------------- | ------------------------------------------------------------ | +| Dubbo Version | 根据网关的配置,或者Http请求获取 | +| Service Name | 服务名 | +| Method Name | 调用方法名,采用泛化调用的方式,此项目固定为“$invoke” | +| Method parameter types | 参数类型,泛化调用有固定值 "Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/Object;" | +| Method arguments | 使用配置的序列化方式将对应的参数序列化,按照用户传入的参数的顺序放入参数 | + +以上的各个项目在使用了指定的序列化形式之后,按照上表指定的顺序进行序列化。 + +attachment 目前不转化 + + + +***注意***: + + + +使用文本类型的序列化(Json) 在每一个序列化对象后边要加上行分割符( ***"\n"*** or ***"\r\n"*** ) + +Java 中在使用FastJson 编解码的时候使用了BufferedReader,每次取buffer中的对象的时候,会先调用BufferReader的readLine方法,此方法分割行依靠 ‘/n’ , ’/r/n‘ + +以下给出了Dubbo 协议中返回header中的status对应于GRPC status的对应列表 + + + +##### Status 的处理 + +Dubbo resposne status 中,OK延续使用grpc的 OK code,其余的 status Number编号紧接着 grpc 的16个 code进行编号 + +对应的error详情是 response 中异常的 message。 + +| Dubbo State | Number | +| ---------------------------------------------- | ------ | +| ResponseStatus::Ok | 0 | +| ResponseStatus::ClientTimeout | 130 | +| ResponseStatus::ServerTimeout | 131 | +| ResponseStatus::ServiceNotFound | 12 | +| ResponseStatus::ServerThreadpoolExhaustedError | 13 | +| ResponseStatus::ClientError | \ | +| ResponseStatus::ServerError | 13 | +| ResponseStatus::ServiceError | 13 | +| ResponseStatus::BadResponse | 13 | +| ResponseStatus::BadRequest | 3 | + +## Triple 协议的具体转化 + +Triple 是基于GRPC的,定义在Http2 协议之上 + +### Triple中RPC调用的元信息 + + + +#### Triple 通过 URL 传递调用的服务名和方法名 + +格式: `[http://host/ {service} / {method](http://host/service/method)}` + +我们的规范兼容 Triple 通过http2传递参数的形式,尽量做到dubbo 和 triple 的统一。 + + + +#### Header Frame + +header 中应该包含以下条目 + +- Content-Type:***application/grpc-proto*** + +标识这是一个 triple 协议的rpc调用 + +- x-dubbo-service-group + +指明调用的服务的分组 + +- x-dubbo-service-version + +指明调用的服务的版本 + + + +#### Data frame + +Triple协议将请求参数放在Body中,在triple中,如果服务中的方法定义能够使用pb序列化,则只有一层序列化,如果需要用到其他的序列化,则需要使用TripleRequestWrapper + +对参数进行包装。 + + + +我们推广使用 ***Triple + pb*** 的序列化形式,服务的提供方需要给出服务的 proto 定义,对于triple协议网关对于***triple + pb*** 的转化是比较容易实现的,如果用户没有提供proto定义,需要返回信息: + +| http code | code | detail | +| --------- | ---- | ---------------------------- | +| 400 | 3 | argument type info not found | + +### diff --git a/content/en/overview/reference/pixiu/user/configurations.md b/content/en/overview/reference/pixiu/user/configurations.md new file mode 100755 index 000000000000..3511e79939ca --- /dev/null +++ b/content/en/overview/reference/pixiu/user/configurations.md @@ -0,0 +1,160 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/configurations/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/configurations/ + - /zh-cn/overview/reference/pixiu/user/configurations/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/configurations/ +description: 启动和配置 +linkTitle: 启动和配置 +title: 启动和配置 +type: docs +weight: 20 +--- + + + + + + +### Pixiu 启动命令 + +Pixiu 分为两个形态 Gateway 和 Sidecar,目前 Pixiu 可执行程序的命令如下所示,其中 pixiu 是可执行文件名称。注意,-c 后是本地配置文件的绝对路径。 + +``` +pixiu gateway start -c /config/conf.yaml +``` + +### 配置详解 + +Pixiu 接受 yaml 格式的文件作为其主配置文件,其中对 Pixiu 的各类组件进行配置。我们以快速开始中的配置文件为例,详细讲解其中的组成部分,并且列出可能的扩展。 + +``` +static_resources: + listeners: + - name: "net/http" + protocol_type: "HTTP" + address: + socket_address: + address: "0.0.0.0" + port: 8883 + filter_chains: + filters: + - name: dgp.filter.httpconnectionmanager + config: + route_config: + routes: + - match: + prefix: "*" + http_filters: + - name: dgp.filter.http.dubboproxy + config: + dubboProxyConfig: + auto_resolve: true + registries: + "zookeeper": + protocol: "zookeeper" + timeout: "3s" + address: "127.0.0.1:2181" + username: "" + password: "" +``` + +首先,类似 `envoy`的配置,`static_resources` 表示如下都是静态配置。在静态配置中包括 Listener,NetworkFilter,Route,HttpFilter等组件,它们之间并不是完全独立的。 + +#### Listener + +比如说上述配置就声明了一个监听本地 8883 端口的 HTTP 类型的 Listener,更多 Listener 的配置可以查看 [Listener](../listener/http/)。 + +``` + listeners: + - name: "net/http" + protocol_type: "HTTP" + address: + socket_address: + address: "0.0.0.0" + port: 8883 + filter_chains: +``` +listeners 的配置有 `protocol_type` 表示是 HTTP 类型的 Listener,`address` 则配置了监听的地址和端口,`filter_chains` 则指定了该 Listener 接收到请求要交由哪些 NetworkFilter 处理。 + +#### NetworkFilter + +NetworkFilter 是 Pixiu 的关键组件之一,它可以有 Route 和 HttpFilter 一起组成,负责接收 Listener 传递而来的请求并进行处理。 + +``` +filters: + - name: dgp.filter.httpconnectionmanager + config: + route_config: + http_filters: +``` + +上述配置指明了使用 `dgp.filter.httpconnectionmanager` 这款 NetworkFilter,它能够接收 Http 请求的 `Request` 和 `Response` 进行处理,并且可以配置 Route 路由信息和使用 HttpFilter 对请求进行链式处理。更多的 NetworkFilter 可以查看 [NetworkfFilter文档](../networkfilter/http/) + + + +#### Route 路由 和 Cluster 集群 + +route 可以用于对请求进行路由分发,以下面配置为例。具体配置文件可以查看 `/samples/http/simple` 案例的配置文件 + +``` + - name: dgp.filter.httpconnectionmanager + config: + route_config: + routes: + - match: + prefix: "/user" + route: + cluster: "user" +``` + +上述配置指定了对于 Path 的前缀为 `/user` 的 HTTP 请求,转发给名称为 user 的 cluster 服务集群中。 + +而具体 cluster 集群的定义如下所示: + +``` + clusters: + - name: "user" + lb_policy: "RoundRobin" + endpoints: + - id: 1 + socket_address: + address: 127.0.0.1 + port: 1314 +``` + +上述配置定义了名为 user 的 cluster 集群信息,它的负载均衡策略是 RoundRobin,然后它包含一个 endpoint 实例,其地址是 127.0.0.1。 + +目前,在转发 HTTP 请求或者 Grpc 请求的场景下需要使用 Route 和 Cluster,而涉及到转发 Dubbo 相关请求的场景下暂时不需要二者。 + +#### HttpFilter + +当 NetworkFilter 接收到 Listener 传来的请求后,需要对其进行系列操作,例如限流、鉴权等,最后还需要将这个请求转发给具体上游服务。这些工作都交给 NetworkFilter 所持有的 HttpFilter 链进行处理。 + +``` + - name: dgp.filter.httpconnectionmanager + config: + http_filters: + - name: dgp.filter.http.dubboproxy + config: + dubboProxyConfig: + auto_resolve: true + registries: + "zookeeper": + protocol: "zookeeper" + timeout: "3s" + address: "127.0.0.1:2181" + username: "" + password: "" +``` + +如上配置所示,`httpconnectionmanager` 这个 NetworkFilter 下有一个 HttpFilter chain。其中包括 `dgp.filter.http.dubboproxy` 这一款 HttpFilter。 +它负责将 HTTP 请求转换为 Dubbo 请求,并转发出去。它需要配置一个 Dubbo 集群注册中心的地址信息,指定其为 zookeeper 中间件。其中 `auto_resolve` 则指定使用 HTTP to Dubbo 默认转换协议来进行相关数据转换,具体可以参考[《默认转换协议》](../appendix/http-to-dubbo-default-stragety/)。 + +更多的 HttpFilter 可以查看 [HttpFilter文档](../httpfilter/dubbo/)。 + +#### Adapter + +Adapter 代表 Pixiu 和外界元数据中心交互的能力。目前有两款,分别是 `dgp.adapter.dubboregistrycenter` 和 `dgp.adapter.springcloud`,分别代表从 Dubbo 集群注册中心和 Spring Cloud 集群注册中心获取服务实例信息,构建 Pixiu 转发 Http 请求路由规则的。 + +更多的 Adapter 可以查看 [Adapter文档](../adapter/dubbo/)。 diff --git a/content/en/overview/reference/pixiu/user/deployment.md b/content/en/overview/reference/pixiu/user/deployment.md new file mode 100644 index 000000000000..63bd461fa135 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/deployment.md @@ -0,0 +1,90 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/deployment/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/deployment/ + - /zh-cn/overview/reference/pixiu/user/deployment/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/deployment/ +description: 部署操作 +linkTitle: 部署操作 +title: 部署操作 +type: docs +weight: 30 +--- + + + + + + +## 一、Docker镜像部署 + +注:首先确认本机已经安装好docker并且启动 + +### 1、从docker hub 拉取 pixiu 镜像 + +`docker pull phial3/dubbo-go-pixiu:latest` + +### 2、按照需求准备pixiu配置 +#### [pixiu配置参数详解](../configurations/) + +准备 `log.yml` 和 `conf.yaml` 配置文件,将这两个配置文件在pixiu启动的时候挂在到本地 + +### 3、启动 pixiu + +**前台启动**:,可方便查看服务信息运行是否正常 +```shell +docker run --name dubbo-go-pixiu -p 8883:8883 \ + -v /yourpath/conf.yaml:/etc/pixiu/conf.yaml \ + -v /yourpath/log.yml:/etc/pixiu/log.yml \ + apache/dubbo-go-pixiu:latest +``` +**后台启动**: +```shell +docker run -itd --name dubbo-go-pixiu -p 8883:8883 \ + -v /yourpath/conf.yaml:/etc/pixiu/conf.yaml \ + -v /yourpath/log.yml:/etc/pixiu/log.yml \ + apache/dubbo-go-pixiu:latest +``` + +> 注: +> +> (1) `--name`命令后面的dubbo-go-pixiu为你的pixiu实例的名称,可自行修改 +> +> (2)命令中的`/yourpath/**`路径为你本地存放pixiu配置文件的绝对路径 + +### 4、查看 pixiu 实例 + +`docker ps | grep dubbo-go-pixiu` 正在运行的pixiu实例 + +`docker exec -it dubbo-go-pixiu /bin/bash` 进入pixiu + +### 5、停止pixiu + +`docker stop dubbo-go-pixiu` 停止pixiu + +`docker restart dubbo-go-pixiu` 重启pixiu + + +## 二、源码构建部署 + +注:首先确认本机已经安装好 golang 1.15+ 开发环境,启用`go mod` + +### 1、下载 pixiu 源码到本地 +`git clone git@github.com:apache/dubbo-go-pixiu.git` + +### 2、配置pixiu + +#### [pixiu配置参数详解](../configurations/) + +进入到pixiu的源码目录`cd dubbo-go-pixiu/`,在`dubbo-go-pixiu/configs/`目录下 +修改配置文件`conf.yaml`和`log.yml` + +### 3、编译构建 +在pixiu的源码目录`dubbo-go-pixiu/`下执行`make build` +: 构建完成会在当前目录下生成名为`dubbo-go-pixiu`的可执行文件 + +### 4、启动服务与运行示例 + +在当前目录下`make run` 可根据你当前的配置直接启动pixiu服务 + +[运行示例参考](../quickstart/) diff --git a/content/en/overview/reference/pixiu/user/httpfilter/_index.md b/content/en/overview/reference/pixiu/user/httpfilter/_index.md new file mode 100755 index 000000000000..78dbdb9e5dc5 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/httpfilter/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/httpfilter/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/httpfilter/ + - /zh-cn/overview/reference/pixiu/user/httpfilter/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/httpfilter/ +description: Http Filter 介绍 +linkTitle: Http Filter 介绍 +title: Http Filter 介绍 +type: docs +weight: 60 +--- diff --git a/content/en/overview/reference/pixiu/user/httpfilter/dubbo.md b/content/en/overview/reference/pixiu/user/httpfilter/dubbo.md new file mode 100644 index 000000000000..31b8a66cbc0d --- /dev/null +++ b/content/en/overview/reference/pixiu/user/httpfilter/dubbo.md @@ -0,0 +1,113 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/httpfilter/dubbo/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/httpfilter/dubbo/ +description: Dubbo HttpFilter 介绍 +linkTitle: Dubbo HttpFilter 介绍 +title: Dubbo HttpFilter 介绍 +type: docs +weight: 10 +--- + +# 使用 HTTP 调用 Dubbo + +## 定义Pixiu配置文件 + +```yaml +static_resources: + listeners: + - name: "http-listener" + protocol_type: "HTTP" + address: + socket_address: + address: "0.0.0.0" + port: 8888 + filter_chains: + filters: + - name: dgp.filter.httpconnectionmanager + config: + route_config: + routes: + - match: + prefix: "*" + http_filters: + - name: dgp.filter.http.dubboproxy + config: + dubboProxyConfig: + auto_resolve: true + registries: + "zookeeper": + protocol: "zookeeper" + timeout: "3s" + address: "127.0.0.1:2181" + username: "" + password: "" + timeout_config: + connect_timeout: 5s + request_timeout: 5s + clusters: + - name: "dubbo-server" + lb_policy: "lb" + endpoints: + - id: 1 + socket_address: + address: 127.0.0.1 + port: 20000 + shutdown_config: + timeout: "60s" + step_timeout: "10s" + reject_policy: "immediacy" +``` + +## 准备Dubbo服务 + +### 启动zookeeper,需要提前准备好docker和compose,如果本地有的话可以忽略 + +[docker-compose.yml](https://github.com/apache/dubbo-go-pixiu-samples/tree/main/dubbohttpproxy/server/dubbo/app) + +```shell +docker-compose -f {CURRENT_PATH}/dubbo-go-pixiu-samples/dubbohttpproxy/docker/docker-compose.yml && docker-compose up -d +``` + +### 启动 Dubbo Server + +[Run](https://github.com/apache/dubbo-go-pixiu-samples/tree/main/dubbohttpproxy/server/dubbo/app) + +```shell +export DUBBO_GO_CONFIG_PATH={CURRENT_PATH}/dubbo-go-pixiu-samples/dubbohttpproxy/server/dubbo/profiles/dev/server.yml +go run . +``` + +## 启动 Pixiu + +```shell +./dubbo-go-pixiu gateway start --config {CURRENT_PATH}pixiu/conf.yaml +``` + +## 使用 curl 来做查询和更新 + +使用以下命令运行命令 curl: + +> 查询 + +```shell +curl http://localhost:8888/UserService/com.dubbogo.pixiu.UserService/GetUserByName -X POST \ + -H 'Content-Type: application/json' \ + -H 'x-dubbo-http1.1-dubbo-version: 1.0.0' \ + -H 'x-dubbo-service-protocol: dubbo' \ + -H 'x-dubbo-service-version: 1.0.0' \ + -H 'x-dubbo-service-group: test' \ + -d '{"types":"string","values":"tc"}' +``` + +> 更新 + +```shell +curl http://localhost:8888/UserService/com.dubbogo.pixiu.UserService/UpdateUserByName -X POST \ + -H 'Content-Type: application/json' \ + -H 'x-dubbo-http1.1-dubbo-version: 1.0.0' \ + -H 'x-dubbo-service-protocol: dubbo' \ + -H 'x-dubbo-service-version: 1.0.0' \ + -H 'x-dubbo-service-group: test' \ + -d '{"types":"string,object","values":["tc",{"id":"0001","code":1,"name":"tc","age":15}]}' +``` \ No newline at end of file diff --git a/content/en/overview/reference/pixiu/user/httpfilter/hystrix.md b/content/en/overview/reference/pixiu/user/httpfilter/hystrix.md new file mode 100644 index 000000000000..d848ed81f9c4 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/httpfilter/hystrix.md @@ -0,0 +1,19 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/httpfilter/hystrix/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/httpfilter/hystrix/ + - /zh-cn/overview/reference/pixiu/user/httpfilter/hystrix/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/httpfilter/hystrix/ +description: 断路器介绍 +linkTitle: 断路器介绍 +title: 断路器介绍 +type: docs +weight: 30 +--- + + + + + + +欢迎认领补充此文档。 diff --git a/content/en/overview/reference/pixiu/user/httpfilter/ratelimit.md b/content/en/overview/reference/pixiu/user/httpfilter/ratelimit.md new file mode 100644 index 000000000000..892c72457141 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/httpfilter/ratelimit.md @@ -0,0 +1,19 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/httpfilter/ratelimit/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/httpfilter/ratelimit/ + - /zh-cn/overview/reference/pixiu/user/httpfilter/ratelimit/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/httpfilter/ratelimit/ +description: RateLimiter 介绍 +linkTitle: RateLimiter 介绍 +title: RateLimiter 介绍 +type: docs +weight: 20 +--- + + + + + + +欢迎认领补充此文档。 diff --git a/content/en/overview/reference/pixiu/user/listener/_index.md b/content/en/overview/reference/pixiu/user/listener/_index.md new file mode 100755 index 000000000000..43ebd115e266 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/listener/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/listener/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/listener/ + - /zh-cn/overview/reference/pixiu/user/listener/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/listener/ +description: Listener 介绍 +linkTitle: Listener 介绍 +title: Listener 介绍 +type: docs +weight: 40 +--- diff --git a/content/en/overview/reference/pixiu/user/listener/http.md b/content/en/overview/reference/pixiu/user/listener/http.md new file mode 100644 index 000000000000..8b4b6c1f9dec --- /dev/null +++ b/content/en/overview/reference/pixiu/user/listener/http.md @@ -0,0 +1,53 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/listener/http/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/listener/http/ + - /zh-cn/overview/reference/pixiu/user/listener/http/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/listener/http/ +description: Http Listener 介绍 +linkTitle: Http Listener 介绍 +title: Http Listener 介绍 +type: docs +weight: 10 +--- + + + + + + +Http Listener 是专门负载接收 HTTP 请求的 Listener,它可以设置 HTTP 监听的地址和端口。它可以通过如下配置进行引入。 + +``` +static_resources: + listeners: + - name: "net/http" + protocol_type: "HTTP" # 表明是引入 HTTP Listener + address: + socket_address: + address: "0.0.0.0" # 地址 + port: 8883 # 端口 +``` + +Http Listener 的具体实现可以参考 `pkg/listener/http`。 + +有关 HTTP Listener 的案例,可以参考: +- HTTP to Dubbo 请求的转换,[案例](/zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/http_to_dubbo/) +- HTTP 请求代理,[案例](/zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/http_proxy/) + +目前也支持 HTTPS 协议。可以将 `protocol_type` 修改为 `HTTPS`。并且添加 `domains` 和 `certs_dir` 来指定域名和 cert 文件目录。 + +``` + listeners: + - name: "net/http" + protocol_type: "HTTPS" + address: + socket_address: + domains: + - "sample.domain.com" + - "sample.domain-1.com" + - "sample.domain-2.com" + certs_dir: $PROJECT_DIR/cert +``` + +具体案例可以查看 [案例](/zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/https/) diff --git a/content/en/overview/reference/pixiu/user/listener/http2.md b/content/en/overview/reference/pixiu/user/listener/http2.md new file mode 100644 index 000000000000..24ed858fbbde --- /dev/null +++ b/content/en/overview/reference/pixiu/user/listener/http2.md @@ -0,0 +1,19 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/listener/http2/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/listener/http2/ + - /zh-cn/overview/reference/pixiu/user/listener/http2/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/listener/http2/ +description: Http2 Listener 介绍 +linkTitle: Http2 Listener 介绍 +title: Http2 Listener 介绍 +type: docs +weight: 20 +--- + + + + + + +欢迎认领补充此文档。 diff --git a/content/en/overview/reference/pixiu/user/listener/tcp.md b/content/en/overview/reference/pixiu/user/listener/tcp.md new file mode 100644 index 000000000000..fafe5f2d607b --- /dev/null +++ b/content/en/overview/reference/pixiu/user/listener/tcp.md @@ -0,0 +1,19 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/listener/tcp/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/listener/tcp/ + - /zh-cn/overview/reference/pixiu/user/listener/tcp/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/listener/tcp/ +description: TCP Listener 介绍 +linkTitle: TCP Listener 介绍 +title: TCP Listener 介绍 +type: docs +weight: 30 +--- + + + + + + +欢迎认领补充此文档。 diff --git a/content/en/overview/reference/pixiu/user/listener/triple.md b/content/en/overview/reference/pixiu/user/listener/triple.md new file mode 100644 index 000000000000..5d50b9d5dacb --- /dev/null +++ b/content/en/overview/reference/pixiu/user/listener/triple.md @@ -0,0 +1,19 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/listener/triple/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/listener/triple/ + - /zh-cn/overview/reference/pixiu/user/listener/triple/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/listener/triple/ +description: Triple Listener 介绍 +linkTitle: Triple Listener 介绍 +title: Triple Listener 介绍 +type: docs +weight: 40 +--- + + + + + + +欢迎认领补充此文档。 diff --git a/content/en/overview/reference/pixiu/user/networkfilter/_index.md b/content/en/overview/reference/pixiu/user/networkfilter/_index.md new file mode 100755 index 000000000000..76d329902d2b --- /dev/null +++ b/content/en/overview/reference/pixiu/user/networkfilter/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/networkfilter/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/networkfilter/ + - /zh-cn/overview/reference/pixiu/user/networkfilter/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/networkfilter/ +description: Network Filter 介绍 +linkTitle: Network Filter 介绍 +title: Network Filter 介绍 +type: docs +weight: 50 +--- diff --git a/content/en/overview/reference/pixiu/user/networkfilter/dubbo.md b/content/en/overview/reference/pixiu/user/networkfilter/dubbo.md new file mode 100644 index 000000000000..74f000bdf9c4 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/networkfilter/dubbo.md @@ -0,0 +1,19 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/networkfilter/dubbo/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/networkfilter/dubbo/ + - /zh-cn/overview/reference/pixiu/user/networkfilter/dubbo/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/networkfilter/dubbo/ +description: Dubbo NetWorkFilter 介绍 +linkTitle: Dubbo NetWorkFilter 介绍 +title: Dubbo NetWorkFilter 介绍 +type: docs +weight: 30 +--- + + + + + + +欢迎认领补充此文档。 diff --git a/content/en/overview/reference/pixiu/user/networkfilter/grpc.md b/content/en/overview/reference/pixiu/user/networkfilter/grpc.md new file mode 100644 index 000000000000..c9fa07536837 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/networkfilter/grpc.md @@ -0,0 +1,105 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/networkfilter/grpc/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/networkfilter/grpc/ +description: Grpc NetWorkFilter 介绍 +linkTitle: Grpc NetWorkFilter 介绍 +title: Grpc NetWorkFilter 介绍 +type: docs +weight: 20 +--- + +# 使用 grpc 调用服务提供程序 + +> [下面的文档符合代码](https://github.com/apache/dubbo-go-pixiu-samples/blob/main/http/grpc/pixiu/conf.yaml) + +## 定义Pixiu配置文件 + +```yaml +static_resources: + listeners: + - name: "net/http" + protocol_type: "HTTP" + address: + socket_address: + address: "0.0.0.0" + port: 8881 + filter_chains: + filters: + - name: dgp.filter.httpconnectionmanager + config: + route_config: + routes: + - match: + prefix: "/api/v1" + route: + cluster: "test-grpc" + cluster_not_found_response_code: 505 + http_filters: + - name: dgp.filter.http.grpcproxy + config: + path: /mnt/d/WorkSpace/GoLandProjects/dubbo-go-pixiu/samples/http/grpc/proto + - name: dgp.filter.http.response + config: + server_name: "test-http-grpc" + generate_request_id: false + config: + idle_timeout: 5s + read_timeout: 5s + write_timeout: 5s + clusters: + - name: "test-grpc" + lb_policy: "RoundRobin" + endpoints: + - socket_address: + address: 127.0.0.1 + port: 50001 + protocol_type: "GRPC" + timeout_config: + connect_timeout: "5s" + request_timeout: "10s" + shutdown_config: + timeout: "60s" + step_timeout: "10s" + reject_policy: "immediacy" +``` + +> Grpc 服务器在“集群”中定义 + +> 目前 http 请求仅支持 json body 解析参数 + +## 准备服务器 + +[generate pb files under with command:](https://github.com/apache/dubbo-go-pixiu-samples/tree/main/http/grpc/proto) + +``` +protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative hello_grpc.proto +``` + +## 启动 Server + +[Run](https://github.com/apache/dubbo-go-pixiu-samples/blob/main/http/grpc/server/app/server.go) + +```shell +go run server.go +``` + +## 启动 Pixiu + +```shell +./dubbo-go-pixiu gateway start --config {CURRENT_PATH}/samples/http/grpc/pixiu/conf.yaml +``` + +## 使用 curl 进行测试 + +使用以下命令运行命令 curl: + +```shell +curl http://127.0.0.1:8881/api/v1/provider.UserProvider/GetUser +``` + +```shell +curl http://127.0.0.1:8881/api/v1/provider.UserProvider/GetUser -X POST -d '{"userId":1}' +``` + +> 如果响应正文是 json,则`Content-Type`的标头将设置为`application/json`。如果它只是一个纯文本,则`Content-Type`的标题是`text/plain`。 diff --git a/content/en/overview/reference/pixiu/user/networkfilter/http.md b/content/en/overview/reference/pixiu/user/networkfilter/http.md new file mode 100644 index 000000000000..5a03965f9a71 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/networkfilter/http.md @@ -0,0 +1,19 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/networkfilter/http/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/networkfilter/http/ + - /zh-cn/overview/reference/pixiu/user/networkfilter/http/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/networkfilter/http/ +description: Http NetWorkFilter 介绍 +linkTitle: Http NetWorkFilter 介绍 +title: Http NetWorkFilter 介绍 +type: docs +weight: 10 +--- + + + + + + +Http NetWorkFilter 用来处理 HTTP 请求,它能接收来自 HTTP Listener 传递的 HTTP 请求,然后将其交给自身维护的 HTTP Filter 链进行处理,最后将响应返回给调用方。 diff --git a/content/en/overview/reference/pixiu/user/quality/_index.md b/content/en/overview/reference/pixiu/user/quality/_index.md new file mode 100755 index 000000000000..b296bad52f99 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/quality/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/quality/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/quality/ + - /zh-cn/overview/reference/pixiu/user/quality/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/quality/ +description: 质量指标 +linkTitle: 质量指标 +title: 质量指标 +type: docs +weight: 80 +--- diff --git a/content/en/overview/reference/pixiu/user/quality/performance.md b/content/en/overview/reference/pixiu/user/quality/performance.md new file mode 100755 index 000000000000..13633e789fb1 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/quality/performance.md @@ -0,0 +1,19 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/quality/performance/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/quality/performance/ + - /zh-cn/overview/reference/pixiu/user/quality/stability/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/quality/stability/ +description: 性能 +linkTitle: 性能 +title: 性能 +type: docs +weight: 10 +--- + + + + + + +欢迎认领补充此文档。 diff --git a/content/en/overview/reference/pixiu/user/quality/stability.md b/content/en/overview/reference/pixiu/user/quality/stability.md new file mode 100644 index 000000000000..0da92f432ee0 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/quality/stability.md @@ -0,0 +1,19 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/quality/stability/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/quality/stability/ + - /zh-cn/overview/reference/pixiu/user/quality/stability/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/quality/stability/ +description: 稳定性 +linkTitle: 稳定性 +title: 稳定性 +type: docs +weight: 10 +--- + + + + + + +欢迎认领补充此文档。 diff --git a/content/en/overview/reference/pixiu/user/quickstart.md b/content/en/overview/reference/pixiu/user/quickstart.md new file mode 100755 index 000000000000..8f89a64b01a6 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/quickstart.md @@ -0,0 +1,171 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/quickstart/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/quickstart/ + - /zh-cn/overview/reference/pixiu/user/quickstart/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/quickstart/ +description: 快速开始 +linkTitle: 快速开始 +title: 快速开始 +type: docs +weight: 10 +--- + + +让我们从将 HTTP 请求转换为 Dubbo2 请求的案例来快速展示 Pixiu 的能力。 + +## 用例 + +Pixiu 将 Client 的 HTTP 请求转换为 Dubbo2 请求,然后转发给背后的 Dubbo Server,然后将 Dubbo Server 的响应转换为 HTTP +响应,最后返回给 Client。 + +### 架构图 + +![Architecture](/imgs/pixiu/user/quick_start_architecture.png) + +### 案例 + +案例路径请查看 `/samples/dubbogo/simple/resolve` + +#### Dubbo Server 实现和启动 + +Dubbo Server 提供用户增删改查的相关接口,其具体的代码实现见案例路径下的 `server` + +Dubbo Server 的配置如下所示,注册了 Dubbo2 协议的 interface `com.dubbogo.pixiu.UserService`。 + +```yaml +dubbo: + registries: + zk: + protocol: zookeeper + timeout: 3s + address: 127.0.0.1:2181 + protocols: + dubbo: + name: dubbo + port: 20000 + provider: + registry-ids: zk + services: + UserProvider: + group: test + version: 1.0.0 + cluster: test_dubbo + serialization: hessian2 + interface: com.dubbogo.pixiu.UserService +``` + +#### Pixiu 配置和启动 + +为了用例的场景,Pixiu 需要启动对应的 HTTP Listener 进行 HTTP 请求的监听,所以就会使用到 `httpconnectionmanager`。 +然后因为要将 HTTP 请求转换为 Dubbo请求,所以需要使用 `dgp.filter.http.dubboproxy`,这里我们将其`auto_resolve` 设置为true,表示开启 +HTTP to Dubbo 默认转换协议(具体定义请看[附录](../appendix/http-to-dubbo-default-stragety))。 + +Pixiu 的具体配置如下所示 + +``` +static_resources: + listeners: + - name: "net/http" + protocol_type: "HTTP" + address: + socket_address: + address: "0.0.0.0" + port: 8883 + filter_chains: + filters: + - name: dgp.filter.httpconnectionmanager + config: + route_config: + routes: + - match: + prefix: "*" + http_filters: + - name: dgp.filter.http.dubboproxy + config: + dubboProxyConfig: + auto_resolve: true + registries: + "zookeeper": + protocol: "zookeeper" + timeout: "3s" + address: "127.0.0.1:2181" + username: "" + password: "" +``` + +#### Client 实现 + +Client 就是简单的 HTTP Client 实现,但是需要按照前文提及的 HTTP to Dubbo 默认转换协议在 HTTP 请求的 Path 和 Header +中填入对应的数据,具体如下所示。 + +``` + url := "http://localhost:8883/UserService/com.dubbogo.pixiu.UserService/GetUserByName" + data := "{\"types\":\"string\",\"values\":\"tc\"}" + client := &http.Client{Timeout: 5 * time.Second} + req, err := http.NewRequest("POST", url, strings.NewReader(data)) + req.Header.Set("x-dubbo-http1.1-dubbo-version", "1.0.0") + req.Header.Set("x-dubbo-service-protocol", "dubbo") + req.Header.Set("x-dubbo-service-version", "1.0.0") + req.Header.Set("x-dubbo-service-group", "test") + + assert.NoError(t, err) + req.Header.Add("Content-Type", "application/json") + resp, err := client.Do(req) +``` + +#### 案例启动 + +项目提供了快速启动脚本,需要本地先安装有 Go 语言开发环境。 + +``` +# cd 到案例总目录 +cd samples/dubbogo/simple/ + +# 进行环境准备,启动 zk 和准备对应配置文件 +./start.sh prepare resolve + +# 启动 dubbo server +./start.sh startServer resolve + +# 启动 pixiu + +./start.sh startPixiu resolve + +# 启动 Client 测试用例 + +./start.sh startTest resolve + +# 或者使用 curl + +curl -X POST 'http://localhost:8883/UserService/com.dubbogo.pixiu.UserService/GetUserByName' -d '{"types":"string","values":"tc"}' -H 'Content-Type: application/json' -H 'x-dubbo-http1.1-dubbo-version: 1.0.0' -H 'x-dubbo-service-protocol: dubbo' -H 'x-dubbo-service-version: 1.0.0' -H 'x-dubbo-service-group: test' + +# 返回值 {"age":15,"code":1,"iD":"0001","name":"tc","time":"2021-08-01T18:08:41+08:00"} + +``` + +#### docker示例 + +```shell +docker pull phial3/dubbo-go-pixiu:latest + +docker run --name pixiuname -p 8883:8883 \ + -v /yourpath/conf.yaml:/etc/pixiu/conf.yaml \ + -v /yourpath/log.yml:/etc/pixiu/log.yml \ + apache/dubbo-go-pixiu:latest + +# http请求调用dubbo服务转换,首先启动provider,这里使用zookeeper作为注册中心 +cd samples/dubbogo/simple/resolve/server + +# 添加需要的环境变量,指定provider的配置文件位置 +export DUBBO_GO_CONFIG_PATH="../profiles/dev/server.yml" +export APP_LOG_CONF_FILE="../profiles/dev/log.yml" + +# 启动provider +go run server.go user.go + +# 进入到test目录下,启动test示例 +cd samples/dubbogo/simple/resolve/test + +go test pixiu_test.go +``` \ No newline at end of file diff --git a/content/en/overview/reference/pixiu/user/samples/_index.md b/content/en/overview/reference/pixiu/user/samples/_index.md new file mode 100755 index 000000000000..29f0f01d1015 --- /dev/null +++ b/content/en/overview/reference/pixiu/user/samples/_index.md @@ -0,0 +1,12 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/samples/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/samples/ + - /zh-cn/overview/reference/pixiu/user/samples/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/ +description: 案例介绍 +linkTitle: 案例介绍 +title: 案例介绍 +type: docs +weight: 70 +--- diff --git a/content/en/overview/reference/pixiu/user/samples/http_proxy.md b/content/en/overview/reference/pixiu/user/samples/http_proxy.md new file mode 100644 index 000000000000..312762bb7dfe --- /dev/null +++ b/content/en/overview/reference/pixiu/user/samples/http_proxy.md @@ -0,0 +1,75 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/samples/http_proxy/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/samples/http_proxy/ + - /zh-cn/overview/reference/pixiu/user/samples/http_proxy/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/http_proxy/ +description: Http Proxy 案例介绍 +linkTitle: Http Proxy 案例介绍 +title: Http Proxy 案例介绍 +type: docs +weight: 10 +--- + + + + + + +### HTTP 代理 + +HTTP 代理案例展示了 Pixiu 接收外界 HTTP 请求然后转发给背后的 HTTP Server 的功能。 + +![img](/imgs/pixiu/user/samples/http_proxy.png) + +案例代码具体查看 `/samples/http/simple`。案例中的目录结构和作用如下所示: + +``` +- pixiu # pixiu 配置文件 +- server # http server +- test # client or unit test +``` + + +我们来具体看一下有关 pixiu 的具体配置文件。 + +``` +static_resources: + listeners: + - name: "net/http" + protocol_type: "HTTP" # 使用 HTTP Listener + address: + socket_address: + address: "0.0.0.0" # 监听地址设置为 0.0.0.0 + port: 8888 # 端口设置为 8888 + filter_chains: + filters: + - name: dgp.filter.httpconnectionmanager # NetworkFilter 设置为 httpconnectionmanager + config: + route_config: + routes: + - match: + prefix: "/user" # 设置路由规则,将 /user 前缀的请求转发给名称为 user 的 cluster 集群 + route: + cluster: "user" + cluster_not_found_response_code: 505 + http_filters: + - name: dgp.filter.http.httpproxy # 使用 dgp.filter.http.httpproxy 这个 HttpFilter 来进行转发 + config: + + clusters: + - name: "user" # 配置一个名称为 user 的 集群,其中有一个实例,地址是 127.0.0.1:1314 + lb_policy: "random" + endpoints: + - id: 1 + socket_address: + address: 127.0.0.1 + port: 1314 +``` + + +可以先启动 `Server` 文件夹下的 Http Server,然后再使用如下命令启动 `Pixiu`,最后执行 test 文件夹下的单元测试。注意,-c 后是本地配置文件的绝对路径。 + +``` +pixiu gateway start -c /pixiu/conf.yaml +``` diff --git a/content/en/overview/reference/pixiu/user/samples/http_to_dubbo.md b/content/en/overview/reference/pixiu/user/samples/http_to_dubbo.md new file mode 100644 index 000000000000..bf3ba20048ca --- /dev/null +++ b/content/en/overview/reference/pixiu/user/samples/http_to_dubbo.md @@ -0,0 +1,19 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/samples/http_to_dubbo/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/samples/http_to_dubbo/ + - /zh-cn/overview/reference/pixiu/user/samples/http_to_dubbo/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/http_to_dubbo/ +description: Http to Dubbo 案例介绍 +linkTitle: Http to Dubbo 案例介绍 +title: Http to Dubbo 案例介绍 +type: docs +weight: 20 +--- + + + + + + +欢迎认领补充此文档。 diff --git a/content/en/overview/reference/pixiu/user/samples/https.md b/content/en/overview/reference/pixiu/user/samples/https.md new file mode 100644 index 000000000000..2caa4212b7ea --- /dev/null +++ b/content/en/overview/reference/pixiu/user/samples/https.md @@ -0,0 +1,19 @@ +--- +aliases: + - /zh/docs3-v2/dubbo-go-pixiu/user/samples/https/ + - /zh-cn/docs3-v2/dubbo-go-pixiu/user/samples/https/ + - /zh-cn/overview/reference/pixiu/user/samples/https/ + - /zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/https/ +description: Https 案例介绍 +linkTitle: Https 案例介绍 +title: Https 案例介绍 +type: docs +weight: 30 +--- + + + + + + +欢迎认领补充此文档。 diff --git a/content/en/overview/reference/proposals/_index.md b/content/en/overview/reference/proposals/_index.md new file mode 100644 index 000000000000..a2cd48189f50 --- /dev/null +++ b/content/en/overview/reference/proposals/_index.md @@ -0,0 +1,9 @@ +--- +aliases: + - /zh/overview/reference/proposals/ +description: "Dubbo 框架核心功能设计方案" +linkTitle: 提案 +title: 提案 +type: docs +weight: 4 +--- diff --git a/content/en/overview/reference/proposals/admin.md b/content/en/overview/reference/proposals/admin.md new file mode 100644 index 000000000000..ec327d76e31f --- /dev/null +++ b/content/en/overview/reference/proposals/admin.md @@ -0,0 +1,110 @@ +--- +aliases: + - /zh/overview/reference/proposals/admin/ +author: Jun Liu +date: 2023-02-28T00:00:00Z +description: | + 本文描述了 Dubbo Admin 作为控制面的总体架构设计与抽象。 +linkTitle: Admin 架构设计 +title: Dubbo Admin 控制面总体架构设计 +type: docs +weight: 3 +working_in_progress: true +--- + + +## 1 Dubbo 整体架构 +![DubboAdmin架构图.png](/imgs/v3/reference/admin/architecture.png) + +架构上分为:**服务治理抽象控制面** 和 **Dubbo 数据面** 。 + +- **服务治理控制面**。控制面包含注册中心、流量管控策略、Admin 控制台、Istio、OpenSergo 等组件。 +- **Dubbo 数据面**。数据面代表集群部署的所有 Dubbo 进程,进程之间通过 RPC 协议实现数据交换,并与控制面进行治理策略交互。 + +**进一步解释:**https://cn.dubbo.apache.org/zh-cn/overview/what/overview/ + +## Dubbo Admin 的整体定位与解释 + +**Dubbo Admin 是对微服务治理体系的统一定义与抽象,通过自定义核心组件与一系列配套工具,为不同部署架构和基础设施环境下部署的微服务集群带来统一的开发与运维差异。** + +## 2 面向用户的开发步骤 +### 第一步:安装 Dubbo Stack/Admin +> 核心思路是,屏蔽架构差异,通过统一入口将治理组件的安装和配置纳入成为 Dubbo 体系中的前置步骤 + +```shell +dubboctl install dubbo-stack +``` + +安装请参见: [Dubbo Admin 安装指南](../../setup/install/) + +### 第二步:服务框架开发 + +- [Java](https://cn.dubbo.apache.org/zh-cn/overview/quickstart/java/) +- [Go](https://cn.dubbo.apache.org/zh-cn/overview/quickstart/go/) +- [Node.js](https://github.com/apache/dubbo-js) +- [Rust](https://cn.dubbo.apache.org/zh-cn/overview/quickstart/rust/) + +## 3 控制面方案 +![Dubbo架构草图.jpeg](/imgs/v3/reference/admin/architecture-draft.png) +### 3.1 确定 Dubbo 微服务治理体系的核心能力 + +- 服务发现 +- 配置管理 +- 流量治理规则 +- 安全基础设施 +- 可视化控制台 + +### 3.2 统一服务治理层接入方式 + +![address-discovery.png](/imgs/v3/reference/admin/address-discovery.png) + +**对于任何微服务部署模式,Dubbo 数据面统一面向 **`**dubbo://hopst:ip**`**抽象服务治理控制面编程。** + +具体工作流程: + +1. 数据面通过配置先与 admin 组件进行交互,admin 返回当前部署架构下的实际注册中心、配置中心等组件地址,如图中的 `nacos://host:port`。 +2. 数据面组件接收到新的组件地址后,直接与 Nacos 建立通信,此后依赖 Nacos 完成服务发现等功能。 + +### 3.3 在不同场景下如何兑现这些核心能力? +#### 场景一:传统微服务体系 (VM & Kubernetes) + +- 控制面治理体系一键安装 (Admin & Nacos) +- 传统 Nacos 服务发现与治理模式 +- 控制面可按需拉起更多的的组件,如 prometheus 等 + +![traditional.png](/imgs/v3/reference/admin/traditional.png) + +#### 场景二:Kubernetes Service + +1. **Istio 模式** + +![kubernetes-service.png](/imgs/v3/reference/admin/kubernetes-service.png) + +2. **其他对等模式 Nacos/OpenSergo** +#### 场景三:Migration or Multi-cluster +集群处于隔离的子网络空间 + +- 1 +- 2 + + +![multi-cluster-ingress.png](/imgs/v3/reference/admin/multi-cluster-ingress.png) + +集群处于同一网络空间 + +![multi-cluster.png](/imgs/v3/reference/admin/multi-cluster.png) + +### 3.4 Admin 控制面 + +![admin-core-components +.png](/imgs/v3/reference/admin/admin-core-components.png) + +### 3.5 其他配套基础设施与工具 + +#### 用户控制台 Console + +交互地址:[https://qedzyx.axshare.com/#id=2pqh0k&p=admin__&g=1](https://qedzyx.axshare.com/#id=2pqh0k&p=admin__&g=1) + +![console-ui.png](/imgs/v3/reference/admin/console-ui.png) + +#### Dubboctl & Helm diff --git a/content/en/overview/reference/proposals/heuristic-flow-control.md b/content/en/overview/reference/proposals/heuristic-flow-control.md new file mode 100644 index 000000000000..ef26db667bf2 --- /dev/null +++ b/content/en/overview/reference/proposals/heuristic-flow-control.md @@ -0,0 +1,234 @@ +--- +aliases: + - /zh/overview/reference/proposals/heuristic-flow-control/ +author: Quanlu Liu +date: 2023-01-30T00:00:00Z +description: 本文所说的柔性服务主要是指**consumer端的负载均衡**和**provider端的限流**两个功能。在之前的dubbo版本中,负载均衡部分更多的考虑的是公平性原则,即consumer端尽可能平等的从provider中作出选择,在某些情况下表现并不够理想。而限流部分只提供了静态的限流方案,需要用户对provider端设置静态的最大并发值,然而该值的合理选取对用户来讲并不容易。我们针对这些存在的问题进行了改进。 +linkTitle: 服务柔性 +title: 自适应负载均衡与限流 +type: docs +weight: 5 +working_in_progress: true +--- + + +# 整体介绍 +本文所说的柔性服务主要是指**consumer端的负载均衡**和**provider端的限流**两个功能。在之前的dubbo版本中, +* 负载均衡部分更多的考虑的是公平性原则,即consumer端尽可能平等的从provider中作出选择,在某些情况下表现并不够理想。 +* 限流部分只提供了静态的限流方案,需要用户对provider端设置静态的最大并发值,然而该值的合理选取对用户来讲并不容易。 + +我们针对这些存在的问题进行了改进。 + +## 负载均衡 +### 使用介绍 +在原本的dubbo版本中,有五种负载均衡的方案供选择,他们分别是 `Random`、`ShortestResponse`、`RoundRobin`、`LeastActive` 和 `ConsistentHash`。其中除 `ShortestResponse` 和 `LeastActive` 外,其他的几种方案主要是考虑选择时的公平性和稳定性。 + +对于 `ShortestResponse` 来说,其设计目的是从所有备选的 provider 中选择 response 时间最短的以提高系统整体的吞吐量。然而存在两个问题: +1. 在大多数的场景下,不同provider的response时长没有非常明显的区别,此时该算法会退化为随机选择。 +2. response的时间长短有时也并不能代表机器的吞吐能力。对于 `LeastActive` 来说,其认为应该将流量尽可能分配到当前并发处理任务较少的机器上。但是其同样存在和 `ShortestResponse` 类似的问题,即这并不能单独代表机器的吞吐能力。 + +基于以上分析,我们提出了两种新的负载均衡算法。一种是同样基于公平性考虑的单纯 `P2C` 算法,另一种是基于自适应的方法 `adaptive`,其试图自适应的衡量 provider 端机器的吞吐能力,然后将流量尽可能分配到吞吐能力高的机器上,以提高系统整体的性能。 + +#### 总体效果 +对于负载均衡部分的有效性实验在两个不同的情况下进行的,分别是提供端机器配置比较均衡和提供端机器配置差距较大的情况。 + +![image.png](/imgs/overview/reference/proposals/heuristic-flow-control/1675265258687-c3df68a8-80e0-4311-816c-63480494850c.png) + +![image.png](/imgs/overview/reference/proposals/heuristic-flow-control/1675265271198-5b045ced-8524-42a2-8b34-d7edbbd1f232.png) + +#### 使用方法 +[Dubbo Java 实现的使用方法](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance) 与原本的负载均衡方法相同。只需要在consumer端将"loadbalance"设置为"p2c"或者"adaptive"即可。 + +#### 代码结构 +负载均衡部分的算法实现只需要在原本负载均衡框架内继承 LoadBalance接口即可。 + +### 原理介绍 + +#### P2C算法 + +Power of Two Choice 算法简单但是经典,主要思路如下: + +1. 对于每次调用,从可用的provider列表中做两次随机选择,选出两个节点providerA和providerB。 +2. 比较providerA和providerB两个节点,选择其“当前正在处理的连接数”较小的那个节点。 + +#### adaptive算法 + +[代码的github地址](https://github.com/apache/dubbo/pull/10745) + +##### 相关指标 +1. cpuLoad +![img](/imgs/overview/reference/proposals/heuristic-flow-control/26808016bc7f1ee83ab425e308074f17.svg)。该指标在provider端机器获得,并通过invocation的attachment传递给consumer端。 + +2. rt +rt为一次rpc调用所用的时间,单位为毫秒。 + +3. timeout +timeout为本次rpc调用超时剩余的时间,单位为毫秒。 + +4. weight +weight是设置的服务权重。 + +5. currentProviderTime +provider端在计算cpuLoad时的时间,单位是毫秒 + +6. currentTime +currentTime为最后一次计算load时的时间,初始化为currentProviderTime,单位是毫秒。 +7. multiple +![img](/imgs/overview/reference/proposals/heuristic-flow-control/b60f036bd026b92129df8a6476922cc8.svg) + +8. lastLatency +![img](/imgs/overview/reference/proposals/heuristic-flow-control/f2abbc771049cf4f3e492e93a258d699.svg)![img](/imgs/overview/reference/proposals/heuristic-flow-control/8fb1af970b995232ebed2764a5706aab.svg) + +9. beta +平滑参数,默认为0.5 + +10. ewma +lastLatency的平滑值![img](/imgs/overview/reference/proposals/heuristic-flow-control/c26fdbae56f3a06c46434ae91185a3d6.svg) + +11. inflight +inflight为consumer端还未返回的请求的数量。 +![img](/imgs/overview/reference/proposals/heuristic-flow-control/f429c4726dec484e70ee73e6a37c88dd.svg) + +12. load +对于备选后端机器x来说,若距离上次被调用的时间大于2*timeout,则其load值为0。 +否则, + +![img](/imgs/overview/reference/proposals/heuristic-flow-control/0f56746b3643dc3ed0e019c24ad5f377.svg) + +##### 算法实现 +依然是基于P2C算法。 + +1. 从备选列表中做两次随机选择,得到providerA和providerB +2. 比较providerA和providerB的load值,选择较小的那个。 + +## 自适应限流 + +与负载均衡运行在consumer端不同的是,限流功能运行在provider端。其作用是限制provider端处理并发任务时的最大数量。从理论上讲,服务端机器的处理能力是存在上限的,对于一台服务端机器,当短时间内出现大量的请求调用时,会导致处理不及时的请求积压,使机器过载。在这种情况下可能导致两个问题: + +1. 由于请求积压,最终所有的请求都必须等待较长时间才能被处理,从而使整个服务瘫痪。 +2. 服务端机器长时间的过载可能有宕机的风险。 + +因此,在可能存在过载风险时,拒绝掉一部分请求反而是更好的选择。在之前的 Dubbo 版本中,限流是通过在 provider 端设置静态的最大并发值实现的。但是在服务数量多,拓扑复杂且处理能力会动态变化的局面下,该值难以通过计算静态设置。 + +基于以上原因,我们需要一种自适应的算法,其可以动态调整服务端机器的最大并发值,使其可以在保证机器不过载的前提下,尽可能多的处理接收到的请求。因此,我们参考相关理论与算法实践基础上,在 Dubbo 框架内实现了两种自适应限流算法,分别是基于启发式平滑的`HeuristicSmoothingFlowControl` 和基于窗口的 `AutoConcurrencyLimier`。 + +[代码的github地址](https://github.com/apache/dubbo/pull/10642) + +### 使用介绍 +#### 总体效果 + +自适应限流部分的有效性实验我们在提供端机器配置尽可能大的情况下进行,并且为了凸显效果,在实验中我们将单次请求的复杂度提高,将超时时间尽可能设置的大,并且开启消费端的重试功能。 +![image.png](/imgs/overview/reference/proposals/heuristic-flow-control/1675267798831-3da99681-577f-4e5a-b122-b87c8aba7299.png) + +#### 使用方法 +要确保服务端存在多个节点,并且消费端开启重试策略的前提下,限流功能才能更好的发挥作用。 + +[Dubbo Java 实现的自适应限流开启方法](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance) 与静态的最大并发值设置类似,只需在provider端将"flowcontrol"设置为"autoConcurrencyLimier"或者"heuristicSmoothingFlowControl"即可。 + +#### 代码结构 +1. FlowControlFilter:在provider端的filter负责根据限流算法的结果来对provider端进行限流功能。 +2. FlowControl:根据dubbo的spi实现的限流算法的接口。限流的具体实现算法需要继承自该接口并可以通过dubbo的spi方式使用。 +3. CpuUsage:周期性获取cpu的相关指标 +4. HardwareMetricsCollector:获取硬件指标的相关方法 +5. ServerMetricsCollector:基于滑动窗口的获取限流需要的指标的相关方法。比如qps等。 +6. AutoConcurrencyLimier:自适应限流的具体实现算法。 +7. HeuristicSmoothingFlowControl:自适应限流的具体实现方法。 + +### 原理介绍 +#### HeuristicSmoothingFlowControl +##### 相关指标 +1. alpha +alpha为可接受的延时的上升幅度,默认为0.3 + +2. minLatency +在一个时间窗口内的最小的Latency值。 + +3. noLoadLatency +noLoadLatency是单纯处理任务的延时,不包括排队时间。这是服务端机器的固有属性,但是并不是一成不变的。在HeuristicSmoothingFlowControl算法中,我们根据机器CPU的使用率来确定机器当前的noLoadLatency。当机器的CPU使用率较低时,我们认为minLatency便是noLoadLatency。当CPU使用率适中时,我们平滑的用minLatency来更新noLoadLatency的值。当CPU使用率较高时,noLoadLatency的值不再改变。 + +4. maxQPS +一个时间窗口周期内的QPS的最大值。 + +5. avgLatency +一个时间窗口周期内的Latency的平均值,单位为毫秒。 + +6. maxConcurrency +计算得到的当前服务提供端的最大并发值。 +![img](/imgs/overview/reference/proposals/heuristic-flow-control/f40e48ebdb49648cf942714609808c52.svg) + +##### 算法实现 +当服务端收到一个请求时,首先判断CPU的使用率是否超过50%。如果没有超过50%,则接受这个请求进行处理。如果超过50%,说明当前的负载较高,便从HeuristicSmoothingFlowControl算法中获得当前的maxConcurrency值。如果当前正在处理的请求数量超过了maxConcurrency,则拒绝该请求。 + +#### AutoConcurrencyLimier +##### 相关指标 +1. MaxExploreRatio +默认设置为0.3 +2. MinExploreRatio +默认设置为0.06 +3. SampleWindowSizeMs +采样窗口的时长。默认为1000毫秒。 +4. MinSampleCount +采样窗口的最小请求数量。默认为40。 +5. MaxSampleCount +采样窗口的最大请求数量。默认为500。 +6. emaFactor +平滑处理参数。默认为0.1。 +7. exploreRatio +探索率。初始设置为MaxExploreRatio。 +若avgLatency<=noLoadLatency*(1.0 + MinExploreRatio)或者qps>=maxQPS*(1.0 + MinExploreRatio) +则exploreRatio=min(MaxExploreRatio,exploreRatio+0.02) +否则 +exploreRatio=max(MinExploreRatio,exploreRatio-0.02) + +8. maxQPS +窗口周期内QPS的最大值。 +![img](/imgs/overview/reference/proposals/heuristic-flow-control/d5cf045bc17267befc176f3d76273267.svg) +9. noLoadLatency +![img](/imgs/overview/reference/proposals/heuristic-flow-control/8c700211f5c7a13403e3088df9cd9f43.svg) +10. halfSampleIntervalMs +半采样区间。默认为25000毫秒。 +11. resetLatencyUs +下一次重置所有值的时间戳,这里的重置包括窗口内值和noLoadLatency。单位是微秒。初始为0. +![img](/imgs/overview/reference/proposals/heuristic-flow-control/1af4a6134ede96985302ee8a27f93df7.svg) +12. remeasureStartUs +下一次重置窗口的开始时间。 +![img](/imgs/overview/reference/proposals/heuristic-flow-control/c7da904b9a4c890456499b09d01938d3.svg) +13. startSampleTimeUs +开始采样的时间。单位为微秒。 +14. sampleCount +当前采样窗口内请求的数量。 +15. totalSampleUs +采样窗口内所有请求的latency的和。单位为微秒。 +16. totalReqCount +采样窗口时间内所有请求的数量和。注意区别sampleCount。 +17. samplingTimeUs +采样当前请求的时间戳。单位为微秒。 +18. latency +当前请求的latency。 +19. qps +在该时间窗口内的qps值。 +![img](/imgs/overview/reference/proposals/heuristic-flow-control/c0e8b30fc1ecf9438bc2d574fb3da8b6.svg) +20. avgLatency +窗口内的平均latency。 +![img](/imgs/overview/reference/proposals/heuristic-flow-control/3a3acfdb05be7d3985835d43e492d3b9.svg) +21. maxConcurrency +上一个窗口计算得到当前周期的最大并发值。 +22. nextMaxConcurrency +当前窗口计算出的下一个周期的最大并发值。 +![img](/imgs/overview/reference/proposals/heuristic-flow-control/09852cc0ef125b43a37719796cb8baae.svg) + +##### Little's Law +* 当服务处于稳定状态时:concurrency=latency*qps。这是自适应限流理论的基础。 +* 当请求没有导致机器超载时,latency基本稳定,qps和concurrency处于线性关系。 +* 当短时间内请求数量过多,导致服务超载的时候,concurrency会和latency一起上升,qps则会趋于稳定。 + +##### 算法实现 +AutoConcurrencyLimier的算法使用过程和HeuristicSmoothingFlowControl类似。与HeuristicSmoothingFlowControl的最大区别是: + +AutoConcurrencyLimier是基于窗口的。每当窗口内积累了一定量的采样数据时,才利用窗口内的数据来更新得到maxConcurrency。 +其次,利用exploreRatio来对剩余的容量进行探索。 + +另外,每隔一段时间都会自动缩小max_concurrency并持续一段时间,以处理noLoadLatency上涨的情况。因为估计noLoadLatency时必须先让服务处于低负载的状态,因此对maxConcurrency的缩小是难以避免的。 + +由于 max_concurrency < concurrency 时,服务会拒绝掉所有的请求,限流算法将 "排空所有的经历过排队的等待请求的时间" 设置为 2*latency,以确保 minLatency 的样本绝大部分时没有经过排队等待的。 + diff --git a/content/en/overview/reference/proposals/metrics.md b/content/en/overview/reference/proposals/metrics.md new file mode 100644 index 000000000000..4724d9723575 --- /dev/null +++ b/content/en/overview/reference/proposals/metrics.md @@ -0,0 +1,529 @@ +--- +aliases: + - /zh/overview/reference/proposals/metrics/ +author: Song Xiaosheng +date: 2023-02-20T00:00:00Z +description: 指标埋点 +linkTitle: 指标埋点 +title: 指标埋点 +type: docs +weight: 4 +--- + + + +# 概述 + +## 1. 指标接入说明 + +## 2. 指标体系设计 + +Dubbo的指标体系,总共涉及三块,指标收集、本地聚合、指标推送 +* 指标收集:将Dubbo内部需要监控的指标推送至统一的Collector中进行存储 +* 本地聚合:指标收集获取的均为基础指标,而一些分位数指标则需通过本地聚合计算得出 +* 指标推送:收集和聚合后的指标通过一定的方式推送至第三方服务器,目前只涉及Prometheus + +## 3. 结构设计 +- 移除原来与 Metrics 相关的类 +- 创建新模块 dubbo-metrics/dubbo-metrics-api、dubbo-metrics/dubbo-metrics-prometheus,MetricsConfig 作为该模块的配置类 +- 使用micrometer,在Collector中使用基本类型代表指标,如Long、Double等,并在dubbo-metrics-api中引入micrometer,由micrometer对内部指标进行转换 +## 4. 数据流转 + ![img.png](/imgs/docs3-v2/java-sdk/observability/dataflow.png) + + +## 5. 目标 + 指标接口将提供一个 MetricsService,该 Service 不仅提供柔性服务所的接口级数据,也提供所有指标的查询方式,其中方法级指标的查询的接口可按如下方式声明 + +```java +public interface MetricsService { + + /** + * Default {@link MetricsService} extension name. + */ + String DEFAULT_EXTENSION_NAME = "default"; + + /** + * The contract version of {@link MetricsService}, the future update must make sure compatible. + */ + String VERSION = "1.0.0"; + + /** + * Get metrics by prefixes + * + * @param categories categories + * @return metrics - key=MetricCategory value=MetricsEntityList + */ + Map> getMetricsByCategories(List categories); + + /** + * Get metrics by interface and prefixes + * + * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) + * @param categories categories + * @return metrics - key=MetricCategory value=MetricsEntityList + */ + Map> getMetricsByCategories(String serviceUniqueName, List categories); + + /** + * Get metrics by interface、method and prefixes + * + * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) + * @param methodName methodName + * @param parameterTypes method parameter types + * @param categories categories + * @return metrics - key=MetricCategory value=MetricsEntityList + */ + Map> getMetricsByCategories(String serviceUniqueName, String methodName, Class[] parameterTypes, List categories); +} +``` + +其中 MetricsCategory 设计如下: +```java +public enum MetricsCategory { + RT, + QPS, + REQUESTS, +} +``` + +MetricsEntity 设计如下 +```java +public class MetricsEntity { + private String name; + private Map tags; + private MetricsCategory category; + private Object value; +} +``` + +# 指标收集 +## 1. 嵌入位置 + Dubbo 架构图如下 + ![img.png](/imgs/docs3-v2/java-sdk/observability/dubbo.png) + +在 provider 中添加一层 MetricsFilter 重写 invoke 方法嵌入调用链路用于收集指标,用 try-catch-finally 处理,核心代码如下 + +```java +@Activate(group = PROVIDER, order = -1) +public class MetricsFilter implements Filter, ScopeModelAware { + @Override + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + collector.increaseTotalRequests(interfaceName, methodName, group, version); + collector.increaseProcessingRequests(interfaceName, methodName, group, version); + Long startTime = System.currentTimeMillis(); + try { + Result invoke = invoker.invoke(invocation); + collector.increaseSucceedRequests(interfaceName, methodName, group, version); + return invoke; + } catch (RpcException e) { + collector.increaseFailedRequests(interfaceName, methodName, group, version); + throw e; + } finally { + Long endTime = System.currentTimeMillis(); + Long rt = endTime - startTime; + collector.addRT(interfaceName, methodName, group, version, rt); + collector.decreaseProcessingRequests(interfaceName, methodName, group, version); + } + } +} + +``` + + +## 2. 指标标识 + 用以下五个属性作为隔离级别区分标识不同方法,也是各个 ConcurrentHashMap 的 key +```java +public class MethodMetric { + private String applicationName; + private String interfaceName; + private String methodName; + private String group; + private String version; +} +``` + +## 3. 基础指标 + 指标通过 common 模块下的 MetricsCollector 存储所有指标数据 + +```java +public class DefaultMetricsCollector implements MetricsCollector { + private Boolean collectEnabled = false; + private final List listeners = new ArrayList<>(); + private final ApplicationModel applicationModel; + private final String applicationName; + + private final Map totalRequests = new ConcurrentHashMap<>(); + private final Map succeedRequests = new ConcurrentHashMap<>(); + private final Map failedRequests = new ConcurrentHashMap<>(); + private final Map processingRequests = new ConcurrentHashMap<>(); + + private final Map lastRT = new ConcurrentHashMap<>(); + private final Map minRT = new ConcurrentHashMap<>(); + private final Map maxRT = new ConcurrentHashMap<>(); + private final Map avgRT = new ConcurrentHashMap<>(); + private final Map totalRT = new ConcurrentHashMap<>(); + private final Map rtCount = new ConcurrentHashMap<>(); + } +``` + +# 本地聚合 +本地聚合指将一些简单的指标通过计算获取各分位数指标的过程 +## 1. 参数设计 + 收集指标时,默认只收集基础指标,而一些单机聚合指标则需要开启服务柔性或者本地聚合后另起线程计算。此处若开启服务柔性,则本地聚合默认开启 + +### 1.1 本地聚合开启方式 +```xml + + + +``` + +### 1.2 指标聚合参数 +```xml + + + +``` + +## 2. 具体指标 + +Dubbo的指标模块帮助用户从外部观察正在运行的系统的内部服务状况 ,Dubbo参考 ["四大黄金信号"](https://sre.google/sre-book/monitoring-distributed-systems/)、*RED方法*、*USE方法*等理论并结合实际企业应用场景从不同维度统计了丰富的关键指标,关注这些核心指标对于提供可用性的服务是至关重要的。 + +Dubbo的关键指标包含:**延迟(Latency)**、**流量(Traffic)**、 **错误(Errors)** 和 **饱和度(Saturation)** 等内容 。同时,为了更好的监测服务运行状态,Dubbo 还提供了对核心组件状态的监控,如Dubbo应用信息、线程池信息、三大中心交互的指标数据等。 + +在Dubbo中主要包含如下监控指标: + +| | 基础设施 | 业务监控 | +| :------- | :----------------------------------------------------------- |:-----------------------------| +| 延迟类 | IO 等待; 网络延迟; | 接口、服务的平均耗时、TP90、TP99、TP999 等 | +| 流量类 | 网络和磁盘 IO; | 服务层面的 QPS、 | +| 错误类 | 宕机; 磁盘(坏盘或文件系统错误); 进程或端口挂掉; 网络丢包; | 错误日志;业务状态码、错误码走势; | +| 饱和度类 | 系统资源利用率: CPU、内存、磁盘、网络等; 饱和度:等待线程数,队列积压长度; | 这里主要包含JVM、线程池等| + +- qps: 基于滑动窗口获取动态qps +- rt: 基于滑动窗口获取动态rt +- 失败请求数: 基于滑动窗口获取最近时间内的失败请求数 +- 成功请求数: 基于滑动窗口获取最近时间内的成功请求数 +- 处理中请求数: 前后增加Filter简单统计 +- 具体指标依赖滑动窗口,额外使用 AggregateMetricsCollector 收集 + +输出到普罗米修斯的相关指标可以参考的内容如下: +``` +# HELP jvm_gc_live_data_size_bytes Size of long-lived heap memory pool after reclamation +# TYPE jvm_gc_live_data_size_bytes gauge +jvm_gc_live_data_size_bytes 1.6086528E7 +# HELP requests_succeed_aggregate Aggregated Succeed Requests +# TYPE requests_succeed_aggregate gauge +requests_succeed_aggregate{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 39.0 +# HELP jvm_buffer_memory_used_bytes An estimate of the memory that the Java virtual machine is using for this buffer pool +# TYPE jvm_buffer_memory_used_bytes gauge +jvm_buffer_memory_used_bytes{id="direct",} 1.679975E7 +jvm_buffer_memory_used_bytes{id="mapped",} 0.0 +# HELP jvm_gc_memory_allocated_bytes_total Incremented for an increase in the size of the (young) heap memory pool after one GC to before the next +# TYPE jvm_gc_memory_allocated_bytes_total counter +jvm_gc_memory_allocated_bytes_total 2.9884416E9 +# HELP requests_total_aggregate Aggregated Total Requests +# TYPE requests_total_aggregate gauge +requests_total_aggregate{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 39.0 +# HELP system_load_average_1m The sum of the number of runnable entities queued to available processors and the number of runnable entities running on the available processors averaged over a period of time +# TYPE system_load_average_1m gauge +system_load_average_1m 0.0 +# HELP system_cpu_usage The "recent cpu usage" for the whole system +# TYPE system_cpu_usage gauge +system_cpu_usage 0.015802269043760128 +# HELP jvm_threads_peak_threads The peak live thread count since the Java virtual machine started or peak was reset +# TYPE jvm_threads_peak_threads gauge +jvm_threads_peak_threads 40.0 +# HELP requests_processing Processing Requests +# TYPE requests_processing gauge +requests_processing{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 +# HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management +# TYPE jvm_memory_max_bytes gauge +jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'profiled nmethods'",} 1.22912768E8 +jvm_memory_max_bytes{area="heap",id="G1 Survivor Space",} -1.0 +jvm_memory_max_bytes{area="heap",id="G1 Old Gen",} 9.52107008E8 +jvm_memory_max_bytes{area="nonheap",id="Metaspace",} -1.0 +jvm_memory_max_bytes{area="heap",id="G1 Eden Space",} -1.0 +jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 5828608.0 +jvm_memory_max_bytes{area="nonheap",id="Compressed Class Space",} 1.073741824E9 +jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 1.22916864E8 +# HELP jvm_threads_states_threads The current number of threads having BLOCKED state +# TYPE jvm_threads_states_threads gauge +jvm_threads_states_threads{state="blocked",} 0.0 +jvm_threads_states_threads{state="runnable",} 10.0 +jvm_threads_states_threads{state="waiting",} 16.0 +jvm_threads_states_threads{state="timed-waiting",} 13.0 +jvm_threads_states_threads{state="new",} 0.0 +jvm_threads_states_threads{state="terminated",} 0.0 +# HELP jvm_buffer_total_capacity_bytes An estimate of the total capacity of the buffers in this pool +# TYPE jvm_buffer_total_capacity_bytes gauge +jvm_buffer_total_capacity_bytes{id="direct",} 1.6799749E7 +jvm_buffer_total_capacity_bytes{id="mapped",} 0.0 +# HELP rt_p99 Response Time P99 +# TYPE rt_p99 gauge +rt_p99{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 1.0 +# HELP jvm_memory_used_bytes The amount of used memory +# TYPE jvm_memory_used_bytes gauge +jvm_memory_used_bytes{area="heap",id="G1 Survivor Space",} 1048576.0 +jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'profiled nmethods'",} 1.462464E7 +jvm_memory_used_bytes{area="heap",id="G1 Old Gen",} 1.6098728E7 +jvm_memory_used_bytes{area="nonheap",id="Metaspace",} 4.0126952E7 +jvm_memory_used_bytes{area="heap",id="G1 Eden Space",} 8.2837504E7 +jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 1372032.0 +jvm_memory_used_bytes{area="nonheap",id="Compressed Class Space",} 4519248.0 +jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 5697408.0 +# HELP qps Query Per Seconds +# TYPE qps gauge +qps{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.3333333333333333 +# HELP rt_min Min Response Time +# TYPE rt_min gauge +rt_min{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 +# HELP jvm_buffer_count_buffers An estimate of the number of buffers in the pool +# TYPE jvm_buffer_count_buffers gauge +jvm_buffer_count_buffers{id="mapped",} 0.0 +jvm_buffer_count_buffers{id="direct",} 10.0 +# HELP system_cpu_count The number of processors available to the Java virtual machine +# TYPE system_cpu_count gauge +system_cpu_count 2.0 +# HELP jvm_classes_loaded_classes The number of classes that are currently loaded in the Java virtual machine +# TYPE jvm_classes_loaded_classes gauge +jvm_classes_loaded_classes 7325.0 +# HELP rt_total Total Response Time +# TYPE rt_total gauge +rt_total{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 2783.0 +# HELP rt_last Last Response Time +# TYPE rt_last gauge +rt_last{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 +# HELP jvm_gc_memory_promoted_bytes_total Count of positive increases in the size of the old generation memory pool before GC to after GC +# TYPE jvm_gc_memory_promoted_bytes_total counter +jvm_gc_memory_promoted_bytes_total 1.4450952E7 +# HELP jvm_gc_pause_seconds Time spent in GC pause +# TYPE jvm_gc_pause_seconds summary +jvm_gc_pause_seconds_count{action="end of minor GC",cause="Metadata GC Threshold",} 2.0 +jvm_gc_pause_seconds_sum{action="end of minor GC",cause="Metadata GC Threshold",} 0.026 +jvm_gc_pause_seconds_count{action="end of minor GC",cause="G1 Evacuation Pause",} 37.0 +jvm_gc_pause_seconds_sum{action="end of minor GC",cause="G1 Evacuation Pause",} 0.156 +# HELP jvm_gc_pause_seconds_max Time spent in GC pause +# TYPE jvm_gc_pause_seconds_max gauge +jvm_gc_pause_seconds_max{action="end of minor GC",cause="Metadata GC Threshold",} 0.0 +jvm_gc_pause_seconds_max{action="end of minor GC",cause="G1 Evacuation Pause",} 0.0 +# HELP rt_p95 Response Time P95 +# TYPE rt_p95 gauge +rt_p95{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 +# HELP requests_total Total Requests +# TYPE requests_total gauge +requests_total{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 27738.0 +# HELP process_cpu_usage The "recent cpu usage" for the Java Virtual Machine process +# TYPE process_cpu_usage gauge +process_cpu_usage 8.103727714748784E-4 +# HELP rt_max Max Response Time +# TYPE rt_max gauge +rt_max{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 4.0 +# HELP jvm_gc_max_data_size_bytes Max size of long-lived heap memory pool +# TYPE jvm_gc_max_data_size_bytes gauge +jvm_gc_max_data_size_bytes 9.52107008E8 +# HELP jvm_threads_live_threads The current number of live threads including both daemon and non-daemon threads +# TYPE jvm_threads_live_threads gauge +jvm_threads_live_threads 39.0 +# HELP jvm_threads_daemon_threads The current number of live daemon threads +# TYPE jvm_threads_daemon_threads gauge +jvm_threads_daemon_threads 36.0 +# HELP jvm_classes_unloaded_classes_total The total number of classes unloaded since the Java virtual machine has started execution +# TYPE jvm_classes_unloaded_classes_total counter +jvm_classes_unloaded_classes_total 0.0 +# HELP jvm_memory_committed_bytes The amount of memory in bytes that is committed for the Java virtual machine to use +# TYPE jvm_memory_committed_bytes gauge +jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'profiled nmethods'",} 1.4680064E7 +jvm_memory_committed_bytes{area="heap",id="G1 Survivor Space",} 1048576.0 +jvm_memory_committed_bytes{area="heap",id="G1 Old Gen",} 5.24288E7 +jvm_memory_committed_bytes{area="nonheap",id="Metaspace",} 4.1623552E7 +jvm_memory_committed_bytes{area="heap",id="G1 Eden Space",} 9.0177536E7 +jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 2555904.0 +jvm_memory_committed_bytes{area="nonheap",id="Compressed Class Space",} 5111808.0 +jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 5701632.0 +# HELP requests_succeed Succeed Requests +# TYPE requests_succeed gauge +requests_succeed{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 27738.0 +# HELP rt_avg Average Response Time +# TYPE rt_avg gauge +rt_avg{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 +``` + +## 聚合收集器 +```java +public class AggregateMetricsCollector implements MetricsCollector, MetricsListener { + private int bucketNum; + private int timeWindowSeconds; + + private final Map totalRequests = new ConcurrentHashMap<>(); + private final Map succeedRequests = new ConcurrentHashMap<>(); + private final Map failedRequests = new ConcurrentHashMap<>(); + private final Map qps = new ConcurrentHashMap<>(); + private final Map rt = new ConcurrentHashMap<>(); + + private final ApplicationModel applicationModel; + + private static final Integer DEFAULT_COMPRESSION = 100; + private static final Integer DEFAULT_BUCKET_NUM = 10; + private static final Integer DEFAULT_TIME_WINDOW_SECONDS = 120; + +//在构造函数中解析配置信息 + + public AggregateMetricsCollector(ApplicationModel applicationModel) { + this.applicationModel = applicationModel; + ConfigManager configManager = applicationModel.getApplicationConfigManager(); + MetricsConfig config = configManager.getMetrics().orElse(null); + if (config != null && config.getAggregation() != null && Boolean.TRUE.equals(config.getAggregation().getEnabled())) { + // only registered when aggregation is enabled. + registerListener(); + + AggregationConfig aggregation = config.getAggregation(); + this.bucketNum = aggregation.getBucketNum() == null ? DEFAULT_BUCKET_NUM : aggregation.getBucketNum(); + this.timeWindowSeconds = aggregation.getTimeWindowSeconds() == null ? DEFAULT_TIME_WINDOW_SECONDS : aggregation.getTimeWindowSeconds(); + } + } +} +``` + +如果开启了本地聚合,则通过 spring 的 BeanFactory 添加监听,将 AggregateMetricsCollector 与 DefaultMetricsCollector 绑定,实现一种生存者消费者的模式,DefaultMetricsCollector 中使用监听器列表,方便扩展 + +```java +private void registerListener() { + applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).addListener(this); +} +``` + +## 3. 指标聚合 +滑动窗口 +假设我们初始有6个bucket,每个窗口时间设置为2分钟 +每次写入指标数据时,会将数据分别写入6个bucket内,每隔两分钟移动一个bucket并且清除原来bucket内的数据 +读取指标时,读取当前current指向的bucket,以达到滑动窗口的效果 +具体如下图所示,实现了当前 bucket 内存储了配置中设置的 bucket 生命周期内的数据,即近期数据 +![img_1.png](/imgs/docs3-v2/java-sdk/observability/aggre.png) + +在每个bucket内,使用**TDigest 算法**计算分位数指标 + +> **TDigest 算法**(极端分位精确度高,如p1 p99,中间分位精确度低,如p50),相关资料如下 +> +> - https://op8867555.github.io/posts/2018-04-09-tdigest.html +> - https://blog.csdn.net/csdnnews/article/details/116246540 +> - 开源实现:https://github.com/tdunning/t-digest + +代码实现如下,除了 TimeWindowQuantile 用来计算分位数指标外,另外提供了 TimeWindowCounter 来收集时间区间内的指标数量 +```java +public class TimeWindowQuantile { + private final double compression; + private final TDigest[] ringBuffer; + private int currentBucket; + private long lastRotateTimestampMillis; + private final long durationBetweenRotatesMillis; + + public TimeWindowQuantile(double compression, int bucketNum, int timeWindowSeconds) { + this.compression = compression; + this.ringBuffer = new TDigest[bucketNum]; + for (int i = 0; i < bucketNum; i++) { + this.ringBuffer[i] = TDigest.createDigest(compression); + } + + this.currentBucket = 0; + this.lastRotateTimestampMillis = System.currentTimeMillis(); + this.durationBetweenRotatesMillis = TimeUnit.SECONDS.toMillis(timeWindowSeconds) / bucketNum; + } + + public synchronized double quantile(double q) { + TDigest currentBucket = rotate(); + return currentBucket.quantile(q); + } + + public synchronized void add(double value) { + rotate(); + for (TDigest bucket : ringBuffer) { + bucket.add(value); + } + } + + private TDigest rotate() { + long timeSinceLastRotateMillis = System.currentTimeMillis() - lastRotateTimestampMillis; + while (timeSinceLastRotateMillis > durationBetweenRotatesMillis) { + ringBuffer[currentBucket] = TDigest.createDigest(compression); + if (++currentBucket >= ringBuffer.length) { + currentBucket = 0; + } + timeSinceLastRotateMillis -= durationBetweenRotatesMillis; + lastRotateTimestampMillis += durationBetweenRotatesMillis; + } + return ringBuffer[currentBucket]; + } +} +``` + +# 指标推送 +指标推送只有用户在设置了配置且配置protocol参数后才开启,若只开启指标聚合,则默认不推送指标。 +## 1. Promehteus Pull ServiceDiscovery + 使用dubbo-admin等类似的中间层,启动时根据配置将本机 IP、Port、MetricsURL 推送地址信息至dubbo-admin(或任意中间层)的方式,暴露HTTP ServiceDiscovery供prometheus读取,配置方式如,其中在pull模式下address为可选参数,若不填则需用户手动在Prometheus配置文件中配置地址 + +```java +private void exportHttpServer() { + boolean exporterEnabled = url.getParameter(PROMETHEUS_EXPORTER_ENABLED_KEY, false); + if (exporterEnabled) { + int port = url.getParameter(PROMETHEUS_EXPORTER_METRICS_PORT_KEY, PROMETHEUS_DEFAULT_METRICS_PORT); + String path = url.getParameter(PROMETHEUS_EXPORTER_METRICS_PATH_KEY, PROMETHEUS_DEFAULT_METRICS_PATH); + if (!path.startsWith("/")) { + path = "/" + path; + } + + try { + prometheusExporterHttpServer = HttpServer.create(new InetSocketAddress(port), 0); + prometheusExporterHttpServer.createContext(path, httpExchange -> { + String response = prometheusRegistry.scrape(); + httpExchange.sendResponseHeaders(200, response.getBytes().length); + try (OutputStream os = httpExchange.getResponseBody()) { + os.write(response.getBytes()); + } + }); + + httpServerThread = new Thread(prometheusExporterHttpServer::start); + httpServerThread.start(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} +``` + +## 2. Prometheus Push Pushgateway +用户直接在Dubbo配置文件中配置Prometheus Pushgateway的地址即可,如,其中interval代表推送间隔 + +```java + +private void schedulePushJob() { + boolean pushEnabled = url.getParameter(PROMETHEUS_PUSHGATEWAY_ENABLED_KEY, false); + if (pushEnabled) { + String baseUrl = url.getParameter(PROMETHEUS_PUSHGATEWAY_BASE_URL_KEY); + String job = url.getParameter(PROMETHEUS_PUSHGATEWAY_JOB_KEY, PROMETHEUS_DEFAULT_JOB_NAME); + int pushInterval = url.getParameter(PROMETHEUS_PUSHGATEWAY_PUSH_INTERVAL_KEY, PROMETHEUS_DEFAULT_PUSH_INTERVAL); + String username = url.getParameter(PROMETHEUS_PUSHGATEWAY_USERNAME_KEY); + String password = url.getParameter(PROMETHEUS_PUSHGATEWAY_PASSWORD_KEY); + + NamedThreadFactory threadFactory = new NamedThreadFactory("prometheus-push-job", true); + pushJobExecutor = Executors.newScheduledThreadPool(1, threadFactory); + PushGateway pushGateway = new PushGateway(baseUrl); + if (!StringUtils.isBlank(username)) { + pushGateway.setConnectionFactory(new BasicAuthHttpConnectionFactory(username, password)); + } + + pushJobExecutor.scheduleWithFixedDelay(() -> push(pushGateway, job), pushInterval, pushInterval, TimeUnit.SECONDS); + } +} + +protected void push(PushGateway pushGateway, String job) { + try { + pushGateway.pushAdd(prometheusRegistry.getPrometheusRegistry(), job); + } catch (IOException e) { + logger.error("Error occurred when pushing metrics to prometheus: ", e); + } +} +``` + +## 可视化展示 +目前推荐使用 Prometheus 来进行服务监控,Grafana 来展示指标数据。可以通过案例来快速入门 [Dubbo 可视化监控](../../../tasks/observability/grafana/)。 diff --git a/content/en/overview/reference/proposals/protocol-http.md b/content/en/overview/reference/proposals/protocol-http.md new file mode 100644 index 000000000000..63e39209fa1c --- /dev/null +++ b/content/en/overview/reference/proposals/protocol-http.md @@ -0,0 +1,658 @@ +--- +aliases: + - /zh/overview/reference/proposals/protocol-http/ +description: 本文将介绍 Dubbo 的 REST/HTTP 协议设计。 +linkTitle: Rest 协议 +title: Rest 协议 +type: docs +weight: 1 +--- +本文将介绍 Dubbo 的 REST/HTTP 协议设计。 + +## RestProtocol 设计 + +### 原版本dubbo rest + +**consumer** + +restClient支持 依赖resteasy 不支持spring mvc  + +**provider(较重)** + +依赖web container   (tomcat,jetty,)servlet 模式,jaxrs netty server + +### 新版本dubbo rest  + +更加轻量,具有dubbo风格的rest,微服务体系互通(Springcloud Alibaba) + +**1.注解解析** + +**2.报文编解码** + +**3.restClient** + +**4.restServer(netty)** + +支持程度: + +content-type   text json xml form(后续会扩展) + +注解 + +param,header,body,pathvaribale (spring mvc & resteasy) + +## Http 协议报文 + + POST /test/path? HTTP/1.1 + Host: localhost:8080 + Connection: keep-alive + Content-type: application/json + + + {"name":"dubbo","age":10,"address":"hangzhou"} + + + +### dubbo http(header) + + // service key header + path: com.demo.TestInterface + group: demo + port: 80 + version: 1.0.0 + + // 保证长连接 + Keep-Alive,Connection: keep-alive + Keep-alive: 60 + + // RPCContext Attachment + userId: 123456 + + +## 支持粒度 + +| 数据位置 | content-type | spring注解 | resteasy注解 | +| --- | --- | --- | --- | +| body | 无要求 | ReuqestBody |  无注解即为body | +| querystring(?test=demo) | 无要求 | RequestParam | QueryParam | +| header | 无要求 | RequestHeader | PathParam | +| form | application/x-www-form-urlencoded | RequestParam ReuqestBody | FormParam | +| path | 无要求 | PathVariable | PathParam | +| method | 无要求 | PostMapping GetMapping | GET POST | +| url | | PostMapping GetMapping path属性 | Path | +| content-type | | PostMapping GetMapping consumers属性 | Consumers | +| Accept | | PostMapping GetMapping produces属性 | Produces | + +## rest注解解析 +ServiceRestMetadataResolver + + JAXRSServiceRestMetadataResolver + + SpringMvcServiceRestMetadataResolver + +ServiceRestMetadata + + public class ServiceRestMetadata implements Serializable { + + private String serviceInterface; // com.demo.TestInterface + + private String version;// 1.0.0 + + private String group;// demo + + private Set meta;// method 元信息 + + private int port;// 端口 for provider service key + + private boolean consumer;// consumer 标志 + + /** + * make a distinction between mvc & resteasy + */ + private Class codeStyle;// + + /** + * for provider + */ + private Map pathToServiceMap; + + /** + * for consumer + */ + private Map> methodToServiceMa + +RestMethodMetadata + + public class RestMethodMetadata implements Serializable { + + private MethodDefinition method; // method 定义信息(name ,pramType,returnType) + + private RequestMetadata request;// 请求元信息 + + private Integer urlIndex; + + private Integer bodyIndex; + + private Integer headerMapIndex; + + private String bodyType; + + private Map> indexToName; + + private List formParams; + + private Map indexToEncoded; + + private ServiceRestMetadata serviceRestMetadata; + + private List argInfos; + + private Method reflectMethod; + + /** + * make a distinction between mvc & resteasy + */ + private Class codeStyle; + + +ArgInfo + + public class ArgInfo { + /** + * method arg index 0,1,2,3 + */ + private int index; + /** + * method annotation name or name + */ + private String annotationNameAttribute; + + /** + * param annotation type + */ + private Class paramAnnotationType; + + /** + * param Type + */ + private Class paramType; + + /** + * param name + */ + private String paramName; + + /** + * url split("/") String[n] index + */ + private int urlSplitIndex; + + private Object defaultValue; + + private boolean formContentType; + +RequestMeatadata + + public class RequestMetadata implements Serializable { + + private static final long serialVersionUID = -240099840085329958L; + + private String method;// 请求method + + private String path;// 请求url + + + private Map> params // param参数?拼接 + + private Map> headers// header; + + private Set consumes // content-type; + + private Set produces // Accept; + +### Consumer 代码 + +refer + + @Override + protected Invoker protocolBindingRefer(final Class type, final URL url) throws RpcException { + + // restClient spi创建 + ReferenceCountedClient refClient = + clients.computeIfAbsent(url.getAddress(), key -> createReferenceCountedClient(url, clients)); + + refClient.retain(); + + // resolve metadata + Map> metadataMap = MetadataResolver.resolveConsumerServiceMetadata(type, url); + + ReferenceCountedClient finalRefClient = refClient; + Invoker invoker = new AbstractInvoker(type, url, new String[]{INTERFACE_KEY, GROUP_KEY, TOKEN_KEY}) { + @Override + protected Result doInvoke(Invocation invocation) { + try { + // 获取 method的元信息 + RestMethodMetadata restMethodMetadata = metadataMap.get(invocation.getMethodName()).get(ParameterTypesComparator.getInstance(invocation.getParameterTypes())); + + RequestTemplate requestTemplate = new RequestTemplate(invocation, restMethodMetadata.getRequest().getMethod(), url.getAddress(), getContextPath(url)); + + HttpConnectionCreateContext httpConnectionCreateContext = new HttpConnectionCreateContext(); + // TODO dynamic load config + httpConnectionCreateContext.setConnectionConfig(new HttpConnectionConfig()); + httpConnectionCreateContext.setRequestTemplate(requestTemplate); + httpConnectionCreateContext.setRestMethodMetadata(restMethodMetadata); + httpConnectionCreateContext.setInvocation(invocation); + httpConnectionCreateContext.setUrl(url); + + // http 信息构建拦截器 + for (HttpConnectionPreBuildIntercept intercept : httpConnectionPreBuildIntercepts) { + intercept.intercept(httpConnectionCreateContext); + } + + + CompletableFuture future = finalRefClient.getClient().send(requestTemplate); + CompletableFuture responseFuture = new CompletableFuture<>(); + AsyncRpcResult asyncRpcResult = new AsyncRpcResult(responseFuture, invocation); + // response 处理 + future.whenComplete((r, t) -> { + if (t != null) { + responseFuture.completeExceptionally(t); + } else { + AppResponse appResponse = new AppResponse(); + try { + int responseCode = r.getResponseCode(); + MediaType mediaType = MediaType.TEXT_PLAIN; + + if (400 < responseCode && responseCode < 500) { + throw new HttpClientException(r.getMessage()); + } else if (responseCode >= 500) { + throw new RemoteServerInternalException(r.getMessage()); + } else if (responseCode < 400) { + mediaType = MediaTypeUtil.convertMediaType(r.getContentType()); + } + + + Object value = HttpMessageCodecManager.httpMessageDecode(r.getBody(), + restMethodMetadata.getReflectMethod().getReturnType(), mediaType); + appResponse.setValue(value); + Map headers = r.headers() + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0))); + appResponse.setAttachments(headers); + responseFuture.complete(appResponse); + } catch (Exception e) { + responseFuture.completeExceptionally(e); + } + } + }); + return asyncRpcResult; + } catch (RpcException e) { + if (e.getCode() == RpcException.UNKNOWN_EXCEPTION) { + e.setCode(getErrorCode(e.getCause())); + } + throw e; + } + } + + @Override + public void destroy() { + super.destroy(); + invokers.remove(this); + destroyInternal(url); + } + }; + invokers.add(invoker); + return invoker; + +### provider 代码 + +export + + public Exporter export(final Invoker invoker) throws RpcException { + URL url = invoker.getUrl(); + final String uri = serviceKey(url); + Exporter exporter = (Exporter) exporterMap.get(uri); + if (exporter != null) { + // When modifying the configuration through override, you need to re-expose the newly modified service. + if (Objects.equals(exporter.getInvoker().getUrl(), invoker.getUrl())) { + return exporter; + } + } + + + // TODO addAll metadataMap to RPCInvocationBuilder metadataMap + Map metadataMap = MetadataResolver.resolveProviderServiceMetadata(url.getServiceModel().getProxyObject().getClass(),url); + + PathAndInvokerMapper.addPathAndInvoker(metadataMap, invoker); + + + final Runnable runnable = doExport(proxyFactory.getProxy(invoker, true), invoker.getInterface(), invoker.getUrl()); + exporter = new AbstractExporter(invoker) { + @Override + public void afterUnExport() { + exporterMap.remove(uri); + if (runnable != null) { + try { + runnable.run(); + } catch (Throwable t) { + logger.warn(PROTOCOL_UNSUPPORTED, "", "", t.getMessage(), t); + } + } + } + }; + exporterMap.put(uri, exporter); + return exporter; + } + +RestHandler + + private class RestHandler implements HttpHandler { + + @Override + public void handle(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException, ServletException { + // 有servlet reuqest 和nettyRequest + RequestFacade request = RequestFacadeFactory.createRequestFacade(servletRequest); + RpcContext.getServiceContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort()); + // dispatcher.service(request, servletResponse); + + Pair build = null; + try { + // 根据请求信息创建 RPCInvocation + build = RPCInvocationBuilder.build(request, servletRequest, servletResponse); + } catch (PathNoFoundException e) { + servletResponse.setStatus(404); + } + + Invoker invoker = build.getSecond(); + + Result invoke = invoker.invoke(build.getFirst()); + + // TODO handling exceptions + if (invoke.hasException()) { + servletResponse.setStatus(500); + } else { + + try { + Object value = invoke.getValue(); + String accept = request.getHeader(RestConstant.ACCEPT); + MediaType mediaType = MediaTypeUtil.convertMediaType(accept); + // TODO write response + HttpMessageCodecManager.httpMessageEncode(servletResponse.getOutputStream(), value, invoker.getUrl(), mediaType); + servletResponse.setStatus(200); + } catch (Exception e) { + servletResponse.setStatus(500); + } + + + } + + // TODO add Attachment header + + + } + } + +RPCInvocationBuilder + + { + + + private static final ParamParserManager paramParser = new ParamParserManager(); + + + public static Pair build(RequestFacade request, Object servletRequest, Object servletResponse) { + + // 获取invoker + Pair invokerRestMethodMetadataPair = getRestMethodMetadata(request); + + RpcInvocation rpcInvocation = createBaseRpcInvocation(request, invokerRestMethodMetadataPair.getSecond()); + + ProviderParseContext parseContext = createParseContext(request, servletRequest, servletResponse, invokerRestMethodMetadataPair.getSecond()); + // 参数构建 + Object[] args = paramParser.providerParamParse(parseContext); + + rpcInvocation.setArguments(args); + + return Pair.make(rpcInvocation, invokerRestMethodMetadataPair.getFirst()); + + } + + private static ProviderParseContext createParseContext(RequestFacade request, Object servletRequest, Object servletResponse, RestMethodMetadata restMethodMetadata) { + ProviderParseContext parseContext = new ProviderParseContext(request); + parseContext.setResponse(servletResponse); + parseContext.setRequest(servletRequest); + + Object[] objects = new Object[restMethodMetadata.getArgInfos().size()]; + parseContext.setArgs(Arrays.asList(objects)); + parseContext.setArgInfos(restMethodMetadata.getArgInfos()); + + + return parseContext; + } + + private static RpcInvocation createBaseRpcInvocation(RequestFacade request, RestMethodMetadata restMethodMetadata) { + RpcInvocation rpcInvocation = new RpcInvocation(); + + + int localPort = request.getLocalPort(); + String localAddr = request.getLocalAddr(); + int remotePort = request.getRemotePort(); + String remoteAddr = request.getRemoteAddr(); + + String HOST = request.getHeader(RestConstant.HOST); + String GROUP = request.getHeader(RestConstant.GROUP); + + String PATH = request.getHeader(RestConstant.PATH); + String VERSION = request.getHeader(RestConstant.VERSION); + + String METHOD = restMethodMetadata.getMethod().getName(); + String[] PARAMETER_TYPES_DESC = restMethodMetadata.getMethod().getParameterTypes(); + + rpcInvocation.setParameterTypes(restMethodMetadata.getReflectMethod().getParameterTypes()); + + + rpcInvocation.setMethodName(METHOD); + rpcInvocation.setAttachment(RestConstant.GROUP, GROUP); + rpcInvocation.setAttachment(RestConstant.METHOD, METHOD); + rpcInvocation.setAttachment(RestConstant.PARAMETER_TYPES_DESC, PARAMETER_TYPES_DESC); + rpcInvocation.setAttachment(RestConstant.PATH, PATH); + rpcInvocation.setAttachment(RestConstant.VERSION, VERSION); + rpcInvocation.setAttachment(RestConstant.HOST, HOST); + rpcInvocation.setAttachment(RestConstant.REMOTE_ADDR, remoteAddr); + rpcInvocation.setAttachment(RestConstant.LOCAL_ADDR, localAddr); + rpcInvocation.setAttachment(RestConstant.REMOTE_PORT, remotePort); + rpcInvocation.setAttachment(RestConstant.LOCAL_PORT, localPort); + + Enumeration attachments = request.getHeaders(RestConstant.DUBBO_ATTACHMENT_HEADER); + + while (attachments != null && attachments.hasMoreElements()) { + String s = attachments.nextElement(); + + String[] split = s.split("="); + + rpcInvocation.setAttachment(split[0], split[1]); + } + + + // TODO set path,version,group and so on + return rpcInvocation; + } + + + private static Pair getRestMethodMetadata(RequestFacade request) { + String path = request.getRequestURI(); + String version = request.getHeader(RestConstant.VERSION); + String group = request.getHeader(RestConstant.GROUP); + int port = request.getIntHeader(RestConstant.REST_PORT); + + return PathAndInvokerMapper.getRestMethodMetadata(path, version, group, port); + } + + + } + +## 编码示例 + +**API** + +mvc + + @RestController() + @RequestMapping("/demoService") + public interface DemoService { + @RequestMapping(value = "/hello", method = RequestMethod.GET) + Integer hello(@RequestParam Integer a, @RequestParam Integer b); + + @RequestMapping(value = "/error", method = RequestMethod.GET) + String error(); + + @RequestMapping(value = "/say", method = RequestMethod.POST, consumes = MediaType.TEXT_PLAIN_VALUE) + String sayHello(@RequestBody String name); + } + +resteasy: + + @Path("/demoService") + public interface RestDemoService { + @GET + @Path("/hello") + Integer hello(@QueryParam("a")Integer a,@QueryParam("b") Integer b); + + @GET + @Path("/error") + String error(); + + @POST + @Path("/say") + @Consumes({MediaType.TEXT_PLAIN}) + String sayHello(String name); + + boolean isCalled(); + } + +impl(service) + + @DubboService() + public class RestDemoServiceImpl implements RestDemoService { + private static Map context; + private boolean called; + + + @Override + public String sayHello(String name) { + called = true; + return "Hello, " + name; + } + + + public boolean isCalled() { + return called; + } + + @Override + public Integer hello(Integer a, Integer b) { + context = RpcContext.getServerAttachment().getObjectAttachments(); + return a + b; + } + + + @Override + public String error() { + throw new RuntimeException(); + } + + public static Map getAttachments() { + return context; + } + } + +## 流程图 + +**Consumer**   + +![image](https://static.dingtalk.com/media/lQLPJxLOtqTxs9TNA5rNBQCwci8F2QYiGAYD5sSyd4BVAA_1280_922.png) + +**Provider(RestServer)** + +![image](https://static.dingtalk.com/media/lQLPJxZcNUm4M9TNA1_NBMuwZUu6IC3FeYAD5sSydYADAA_1227_863.png) + +## 场景  + +### 1.体系互通 + +**非dubbo体系互通(Springcloud alibaba  互通)** + +互通条件: + +| | 协议 | Dubbo | SpringCloud Alibaba | 互通 | +| --- | --- | --- | --- | --- | +| 通信协议 | rest | spring web/resteasy  编码风格 | 集成feignclient,ribbon (spring web 编码风格) | 是 | +| | triple | | | | +| | dubbo | | | | +| | grpc | | | | +| | hessian | | | | +| 注册中心 | zookeeper | | | | +| | nacos | 支持 | 支持 | 应用级别注册 | + +### 2.dubbo 双注册  + + 完成应用级别注册,(dubo2-dubbo3 过度),dubbo版本升级 + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/0ceca951-f467-4ab3-9b71-8e7d52e5e7d1.png) + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/6bcc7aed-1d22-470f-b185-efbab32df1e5.png) + +### 3.多协议发布 + +配置: + + + +### 4.跨语言 + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/1bdf8f91-9666-4c20-9aea-8396c745f554.png) + +### 5.多协议交互 + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/af72e3df-05d5-42a2-a333-618be7ec6cb8.png) + +### 6.协议迁移 + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/36d30183-8d5f-494c-8ebb-b57403c88661.png) + +rest编码风格 + +Http协议更通用跨语言调用 + +dubbo rest 对其他http服务 进行调用 + +其他httpclient 对dubbo rest进行调用 + +dubbo restServer 可以与其他web服务,浏览器等客户端直接进行http交互 + +## consumer TODOLIST +> 功能已经初步实现,可以调通解析response + +1. org/apache/dubbo/rpc/protocol/rest/RestProtocol.java:157  dynamic load config + +2.org/apache/dubbo/remoting/http/factory/AbstractHttpClientFactory.java:50 load config  HttpClientConfig + +3.org/apache/dubbo/rpc/protocol/rest/annotation/metadata/MetadataResolver.java:52  support Dubbo style service + +4.org/apache/dubbo/remoting/http/restclient/HttpClientRestClient.java:120  TODO config + +5.org/apache/dubbo/remoting/http/restclient/HttpClientRestClient.java:140 TODO close judge + +6.org/apache/dubbo/rpc/protocol/rest/message/decode/MultiValueCodec.java:35  TODO java bean  get set convert + +## provider TODOLIST +> 待实现 + +基于netty实现支持http协议的NettyServer + +无注解协议定义 + +官网场景补充 + +## Rest使用说明文档及demo diff --git a/content/en/overview/reference/proposals/registry-config-meta.md b/content/en/overview/reference/proposals/registry-config-meta.md new file mode 100644 index 000000000000..11c0f4c5f239 --- /dev/null +++ b/content/en/overview/reference/proposals/registry-config-meta.md @@ -0,0 +1,93 @@ +--- +aliases: + - /zh/overview/reference/proposals/registry-config-meta/ +description: 本文介绍三中心架构设计 +linkTitle: 注册&配置&元数据中心 +title: 注册中心、配置中心和元数据中心 +type: docs +weight: 2 +--- + + +## 三中心逻辑架构 +> 本节侧重描述传统模式下的 Dubbo 部署架构,在云原生背景下的部署架构会有些变化,主要体现在基础设施(Kubernetes、Service Mesh等)会承担更多的职责, +> 中心化组件如注册中心、元数据中心、配置中心等的职责被集成、运维变得更加简单,但通过强调这些中心化的组件能让我们更容易理解 Dubbo 的工作原理。 + +作为一个微服务框架,Dubbo sdk 跟随着微服务组件被部署在分布式集群各个位置,为了在分布式环境下实现各个微服务组件间的协作, +Dubbo 定义了一些中心化组件,这包括: +* 注册中心。协调 Consumer 与 Provider 之间的地址注册与发现 +* 配置中心。 + * 存储 Dubbo 启动阶段的全局配置,保证配置的跨环境共享与全局一致性 + * 负责服务治理规则(路由规则、动态配置等)的存储与推送。 +* 元数据中心。 + * 接收 Provider 上报的服务接口元数据,为 Admin 等控制台提供运维能力(如服务测试、接口文档等) + * 作为服务发现机制的补充,提供额外的接口/方法级别配置信息的同步能力,相当于注册中心的额外扩展 + +![threecenters](/imgs/v3/concepts/threecenters.png) + +上图完整的描述了 Dubbo 微服务组件与各个中心的交互过程。 + +以上三个中心并不是运行 Dubbo 的必要条件,用户完全可以根据自身业务情况决定只启用其中一个或多个,以达到简化部署的目的。通常情况下,所有用户都会以独立的注册中心 +以开始 Dubbo 服务开发,而配置中心、元数据中心则会在微服务演进的过程中逐步的按需被引入进来。 + +### 注册中心 + +注册中心扮演着非常重要的角色,它承载着服务注册和服务发现的职责。目前Dubbo支持以下两种粒度的服务发现和服务注册,分别是接口级别和应用级别,注册中心可以按需进行部署: + +- 在传统的Dubbo SDK使用姿势中,如果仅仅提供直连模式的RPC服务,不需要部署注册中心。 +- 无论是接口级别还是应用级别,如果需要Dubbo SDK自身来做服务注册和服务发现,则可以选择部署注册中心,在Dubbo中集成对应的注册中心。 + +- 在Dubbo + Mesh 的场景下,随着 Dubbo 服务注册能力的弱化,Dubbo内的注册中心也不再是必选项,其职责开始被控制面取代,如果采用了Dubbo + Mesh的部署方式,无论是ThinSDK的mesh方式还是Proxyless的mesh方式,都不再需要独立部署注册中心。 + +而注册中心并不依赖于配置中心和元数据中心,如下图所示: + +![centers-registry](/imgs/v3/concepts/centers-registry.png) + +该图中没有部署配置中心和元数据中心,在Dubbo中会默认将注册中心的实例同时作为配置中心和元数据中心,这是Dubbo的默认行为,如果确实不需要配置中心或者元数据中心的能力,可在配置中关闭,在注册中心的配置中有两个配置分别为use-as-config-center和use-as-metadata-center,将配置置为false即可。 + +### 元数据中心 + +元数据中心在2.7.x版本开始支持,随着应用级别的服务注册和服务发现在Dubbo中落地,元数据中心也变的越来越重要。在以下几种情况下会需要部署元数据中心: + +1. 对于一个原先采用老版本Dubbo搭建的应用服务,在迁移到Dubbo 3时,Dubbo 3 会需要一个元数据中心来维护RPC服务与应用的映射关系(即接口与应用的映射关系),因为如果采用了应用级别的服务发现和服务注册,在注册中心中将采用“应用 —— 实例列表”结构的数据组织形式,不再是以往的“接口 —— 实例列表”结构的数据组织形式,而以往用接口级别的服务注册和服务发现的应用服务在迁移到应用级别时,得不到接口与应用之间的对应关系,从而无法从注册中心得到实例列表信息,所以Dubbo为了兼容这种场景,在Provider端启动时,会往元数据中心存储接口与应用的映射关系。 +2. 为了让注册中心更加聚焦于地址的发现和推送能力,减轻注册中心的负担,元数据中心承载了所有的服务元数据、大量接口/方法级别配置信息等,无论是接口粒度还是应用粒度的服务发现和注册,元数据中心都起到了重要的作用。 + +如果有以上两种需求,都可以选择部署元数据中心,并通过Dubbo的配置来集成该元数据中心。 + +元数据中心并不依赖于注册中心和配置中心,用户可以自由选择是否集成和部署元数据中心,如下图所示: + +![centers-metadata](/imgs/v3/concepts/centers-metadata.png) + +该图中不配备配置中心,意味着可以不需要全局管理配置的能力。该图中不配备注册中心,意味着可能采用了Dubbo mesh的方案,也可能不需要进行服务注册,仅仅接收直连模式的服务调用。 + +### 配置中心 + +配置中心与其他两大中心不同,它无关于接口级还是应用级,它与接口并没有对应关系,它仅仅与配置数据有关,即使没有部署注册中心和元数据中心,配置中心也能直接被接入到Dubbo应用服务中。在整个部署架构中,整个集群内的实例(无论是Provider还是Consumer)都将会共享该配置中心集群中的配置,如下图所示: +![centers-config](/imgs/v3/concepts/centers-config.png) + +该图中不配备注册中心,意味着可能采用了Dubbo mesh的方案,也可能不需要进行服务注册,仅仅接收直连模式的服务调用。 + +该图中不配备元数据中心,意味着Consumer可以从Provider暴露的MetadataService获取服务元数据,从而实现RPC调用 + +### 保证三大中心高可用的部署架构 + +虽然三大中心已不再是Dubbo应用服务所必须的,但是在真实的生产环境中,一旦已经集成并且部署了该三大中心,三大中心还是会面临可用性问题,Dubbo需要支持三大中心的高可用方案。在Dubbo中就支持多注册中心、多元数据中心、多配置中心,来满足同城多活、两地三中心、异地多活等部署架构模式的需求。 + +Dubbo SDK对三大中心都支持了Multiple模式。 + +- 多注册中心:Dubbo 支持多注册中心,即一个接口或者一个应用可以被注册到多个注册中心中,比如可以注册到ZK集群和Nacos集群中,Consumer也能够从多个注册中心中进行订阅相关服务的地址信息,从而进行服务发现。通过支持多注册中心的方式来保证其中一个注册中心集群出现不可用时能够切换到另一个注册中心集群,保证能够正常提供服务以及发起服务调用。这也能够满足注册中心在部署上适应各类高可用的部署架构模式。 +- 多配置中心:Dubbo支持多配置中心,来保证其中一个配置中心集群出现不可用时能够切换到另一个配置中心集群,保证能够正常从配置中心获取全局的配置、路由规则等信息。这也能够满足配置中心在部署上适应各类高可用的部署架构模式。 + +- 多元数据中心:Dubbo 支持多元数据中心:用于应对容灾等情况导致某个元数据中心集群不可用,此时可以切换到另一个元数据中心集群,保证元数据中心能够正常提供有关服务元数据的管理能力。 + +拿注册中心举例,下面是一个多活场景的部署架构示意图: + +![multiple-registry-deployment-architecture](/imgs/v3/concepts/multiple-registry-deployment-architecture.png) + +## 三中心物理部署架构 + +![同一集群,承担三个中心职责](#) + +## 不同场景下的推荐使用方式 +* 只配置 registry,默认作为 metadata、config-center +* registry、metadata、config-center 使用不同的集群甚至是不同的扩展实现,此时需要独立配置 metadata 或 config-center diff --git a/content/en/overview/reference/proposals/service-discovery.md b/content/en/overview/reference/proposals/service-discovery.md new file mode 100644 index 000000000000..295ee58efc68 --- /dev/null +++ b/content/en/overview/reference/proposals/service-discovery.md @@ -0,0 +1,90 @@ +--- +aliases: + - /zh/overview/reference/proposals/service-discovery/ +author: Jun Liu +date: 2023-01-30T00:00:00Z +description: 应用级服务发现设计 +linkTitle: 应用级服务发现 +title: Dubbo3 应用级服务发现设计 +type: docs +weight: 6 +--- + + + +## Objective +* 显著降低服务发现过程的资源消耗,包括提升注册中心容量上限、降低消费端地址解析资源占用等,使得 Dubbo3 框架能够支持更大规模集群的服务治理,实现无限水平扩容。 +* 适配底层基础设施服务发现模型,如 Kubernetes、Service Mesh 等。 + +## Background +![interface-arc](/imgs/blog/proposals/discovery/arc.png) + +我们从 Dubbo 最经典的工作原理图说起,Dubbo 从设计之初就内置了服务地址发现的能力,Provider 注册地址到注册中心,Consumer 通过订阅实时获取注册中心的地址更新,在收到地址列表后,consumer 基于特定的负载均衡策略发起对 provider 的 RPC 调用。 + +在这个过程中: +* 每个 Provider 通过特定的 key 向注册中心注册本机可访问地址; +* 注册中心通过这个 key 对 provider 实例地址进行聚合; +* Consumer 通过同样的 key 从注册中心订阅,以便及时收到聚合后的地址列表; + +![interface-data1](/imgs/blog/proposals/discovery/interface-data1.png) + +这里,我们对接口级地址发现的内部数据结构进行详细分析。 + +首先,看右下角 provider 实例内部的数据与行为。Provider 部署的应用中通常会有多个 Service,也就是 Dubbo2 中的服务,每个 service 都可能会有其独有的配置,我们所讲的 service 服务发布的过程,其实就是基于这个服务配置生成地址 URL 的过程,生成的地址数据如图所示;同样的,其他服务也都会生成地址。 + +然后,看一下注册中心的地址数据存储结构,注册中心以 service 服务名为数据划分依据,将一个服务下的所有地址数据都作为子节点进行聚合,子节点的内容就是实际可访问的ip地址,也就是我们 Dubbo 中 URL,格式就是刚才 provider 实例生成的。 + +![interface-data2](/imgs/blog/proposals/discovery/interface-data2.png) + +这里把 URL 地址数据划分成了几份: +* 首先是实例可访问地址,主要信息包含 ip port,是消费端将基于这条数据生成 tcp 网络链接,作为后续 RPC 数据的传输载体 +* 其次是 RPC 元数据,元数据用于定义和描述一次 RPC 请求,一方面表明这条地址数据是与某条具体的 RPC 服务有关的,它的版本号、分组以及方法相关信息,另一方面表明 +* 下一部分是 RPC 配置数据,部分配置用于控制 RPC 调用的行为,还有一部分配置用于同步 Provider 进程实例的状态,典型的如超时时间、数据编码的序列化方式等。 +* 最后一部分是自定义的元数据,这部分内容区别于以上框架预定义的各项配置,给了用户更大的灵活性,用户可任意扩展并添加自定义元数据,以进一步丰富实例状态。 + +结合以上两页对于 Dubbo2 接口级地址模型的分析,以及最开始的 Dubbo 基本原理图,我们可以得出这么几条结论: +* 第一,地址发现聚合的 key 就是 RPC 粒度的服务 +* 第二,注册中心同步的数据不止包含地址,还包含了各种元数据以及配置 +* 得益于 1 与 2,Dubbo 实现了支持应用、RPC 服务、方法粒度的服务治理能力 + +这就是一直以来 Dubbo2 在易用性、服务治理功能性、可扩展性上强于很多服务框架的真正原因。 + +![interface-defect](/imgs/blog/proposals/discovery/interface-defect.png) + +一个事物总是有其两面性,Dubbo2 地址模型带来易用性和强大功能的同时,也给整个架构的水平可扩展性带来了一些限制。这个问题在普通规模的微服务集群下是完全感知不到的,而随着集群规模的增长,当整个集群内应用、机器达到一定数量时,整个集群内的各个组件才开始遇到规模瓶颈。在总结包括阿里巴巴、工商银行等多个典型的用户在生产环境特点后,我们总结出以下两点突出问题(如图中红色所示): +* 首先,注册中心集群容量达到上限阈值。由于所有的 URL 地址数据都被发送到注册中心,注册中心的存储容量达到上限,推送效率也随之下降。 +* 而在消费端这一侧,Dubbo2 框架常驻内存已超 40%,每次地址推送带来的 cpu 等资源消耗率也非常高,影响正常的业务调用。 + +为什么会出现这个问题?我们以一个具体 provider 示例进行展开,来尝试说明为何应用在接口级地址模型下容易遇到容量问题。 +青蓝色部分,假设这里有一个普通的 Dubbo Provider 应用,该应用内部定义有 10 个 RPC Service,应用被部署在 100 个机器实例上。这个应用在集群中产生的数据量将会是 “Service 数 * 机器实例数”,也就是 10 * 100 = 1000 条。数据被从两个维度放大: +* 从地址角度。100 条唯一的实例地址,被放大 10 倍 +* 从服务角度。10 条唯一的服务元数据,被放大 100 倍 + +## Proposal + +![app-principle](/imgs/blog/proposals/discovery/app-principle.png) + +面对这个问题,在 Dubbo3 架构下,我们不得不重新思考两个问题: +* 如何在保留易用性、功能性的同时,重新组织 URL 地址数据,避免冗余数据的出现,让 Dubbo3 能支撑更大规模集群水平扩容? +* 如何在地址发现层面与其他的微服务体系如 Kubernetes、Spring Cloud 打通? + +![app-data1](/imgs/blog/proposals/discovery/app-data1.png) + +Dubbo3 的应用级服务发现方案设计本质上就是围绕以上两个问题展开。其基本思路是:地址发现链路上的聚合元素也就是我们之前提到的 Key 由服务调整为应用,这也是其名称叫做应用级服务发现的由来;另外,通过注册中心同步的数据内容上做了大幅精简,只保留最核心的 ip、port 地址数据。 + +![app-data2](/imgs/blog/proposals/discovery/app-data2.png) + +这是升级之后应用级地址发现的内部数据结构进行详细分析。 +对比之前接口级的地址发现模型,我们主要关注橙色部分的变化。首先,在 provider 实例这一侧,相比于之前每个 RPC Service 注册一条地址数据,一个 provider 实例只会注册一条地址到注册中心;而在注册中心这一侧,地址以应用名为粒度做聚合,应用名节点下是精简过后的 provider 实例地址; + +![app-metadataservice](/imgs/blog/proposals/discovery/app-metadataservice.png) + +应用级服务发现的上述调整,同时实现了地址单条数据大小和总数量的下降,但同时也带来了新的挑战:我们之前 Dubbo2 强调的易用性和功能性的基础损失了,因为元数据的传输被精简掉了,如何精细的控制单个服务的行为变得无法实现。 + +针对这个问题,Dubbo3 的解法是引入一个内置的 MetadataService 元数据服务,由中心化推送转为 Consumer 到 Provider 的点对点拉取,在这个模式下,元数据传输的数据量将不在是一个问题,因此可以在元数据中扩展出更多的参数、暴露更多的治理数据。 + +![app-metadataservice](/imgs/blog/proposals/discovery/app-workflow.png) + +这里我们个重点看消费端 Consumer 的地址订阅行为,消费端从分两步读取地址数据,首先是从注册中心收到精简后的地址,随后通过调用 MetadataService 元数据服务,读取对端的元数据信息。在收到这两部分数据之后,消费端会完成地址数据的聚合,最终在运行态还原出类似 Dubbo2 的 URL 地址格式。因此从最终结果而言,应用级地址模型同时兼顾了地址传输层面的性能与运行层面的功能性。 + +以上就是的应用级服务发现背景、工作原理部分的所有内容,接下来我们看一下饿了么升级到 Dubbo3 尤其是应用级服务发现的过程。 diff --git a/content/en/overview/reference/proposals/support-more-content-types.md b/content/en/overview/reference/proposals/support-more-content-types.md new file mode 100644 index 000000000000..35a4050dbb41 --- /dev/null +++ b/content/en/overview/reference/proposals/support-more-content-types.md @@ -0,0 +1,172 @@ +--- +aliases: + - /zh/overview/reference/proposals/support-more-content-type/ +author: 武钰皓 +description: | + 本文主要介绍Triple对更多Http标准Content-Type的支持方式,以及服务该如何接收这些请求。 +title: Triple协议Http标准能力增强-多Content-Type支持 +type: docs +working_in_progress: true +--- + +### **Triple协议Http标准能力增强-多Content-Type支持** +> 本文主要介绍Triple对更多HTTP标准Content-Type的支持方式,以及服务该如何接收这些请求。 +#### **概述** + +Triple目前支持两种序列化方式:Json和protobuf,对应的ContentType: + +* application/json +* application/grpc+proto + +这在消费者和提供者都是后端服务时没有问题。但对于浏览器客户端,其可能发送更多类型的ContentType,需要服务端支持解码,如: + +* multipart/formdata +* text/plain +* application/x-www-form-urlencoded +* application/xml + +Rest已基本实现上述解码能力,使Triple实现这些能力是让Triple服务端与浏览器客户端完全互通的重要一步。 + + + +#### **用法** + +##### **multipart/formdata** + +```http +POST /org.apache.dubbo.samples.tri.noidl.api.PojoGreeter/greetPojo HTTP/1.1 +Host: 192.168.202.1:50052 +Content-Type: multipart/form-data; boundary=example-part-boundary +Accept: application/json + +--example-part-boundary +Content-Disposition: form-data; name="username" +Content-Type: text/plain + +LuYue +--example-part-boundary +Content-Disposition: form-data; name="userdetail" +Content-Type: application/json + +{ + "location":"beijing", + "username":"LuYue" +} +--example-part-boundary +Content-Disposition: form-data; name="userimg";filename="user.jpeg" +Content-Type: image/jpeg + +--example-part-boundary-- +``` + +接收: + +```java + @Override + public ServerResponse greetPojo(String username, User user, byte[] attachment) { + //LuYue + System.out.println(username); + //user.name=Luyue;user.location=beijing + System.out.println(user); + // + System.out.println(new String(attachment, StandardCharsets.UTF_8)); + return new ServerResponse("Server Received:"+username); + } +``` + +* 每一个 part 根据其 Content-Type 解码 +* 若方法参数是 byte[] 或 Byte[],对应字段不会解码 +* 响应使用 application/json 编码 + + + +##### application/x-www-form-urlencoded + +```http +POST /org.apache.dubbo.samples.tri.noidl.api.PojoGreeter/greetUrlForm HTTP/1.1 +Host: 192.168.202.1:50052 +Content-Type: application/x-www-form-urlencoded +Content-Length: 33 +Accept: application/json +Hello=World&Apache=Dubbo&id=10086 +``` + +两种接收方式: + +```java + public ServerResponse greetUrlForm(String hello,String apache,long id){ + System.out.println("Hello:"+hello); + System.out.println("Apache:"+apache); + System.out.println("Id:"+id); + return new ServerResponse("Server Received url form"); + } +``` + +```java + public ServerResponse greetUrlForm(Map params){ + System.out.println("Hello:"+params.get("Hello")); + System.out.println("Apache"+params.get("Apache")); + System.out.println("Id"+params.get("Id")); + return new ServerResponse("Server Received url form"); + } +``` + +* 若参数为Map,则解码为Map传入 +* 若参数均为String或数值类型,按照参数列表逐个解码传入 +* 响应使用 application/json 编码 + + + +##### text/plain + +```http +POST /org.apache.dubbo.samples.tri.noidl.api.PojoGreeter/greetString HTTP/1.1 +Host: 192.168.202.1:50052 +Content-Type: text/plain; charset=UTF-8 +Content-Length: 6 +Accept: application/json +World! +``` + +接收: + +```java + public ServerResponse greetUrlForm(String world){ + System.out.println("Hello:"+ world); + return new ServerResponse("Server Received url form."); + } +``` + +* charset支持ASCII、UTF-8、UTF-16等,默认UTF-8 +* 响应使用 application/json 编码 + + + +##### application/xml + +```http +POST /org.apache.dubbo.samples.tri.noidl.api.PojoGreeter/greetXml HTTP/1.1 +Host: 192.168.202.1:50052 +Content-Type: application/xml +Content-Length: 86 +Accept: application/xml + + + JohnDoe + New York + +``` + +接收: + +```java + @Override + public ServerResponse greetXml(User user) { + System.out.println(user.getUsername()); + System.out.println(user.getLocation()); + return new ServerResponse("Server Received xml."); + } +``` + +* 该实现与Rest的XMLCodec相同 +* 响应使用 application/xml 编码 \ No newline at end of file diff --git a/content/en/overview/reference/protoc-installation.md b/content/en/overview/reference/protoc-installation.md new file mode 100644 index 000000000000..c06bd064ef81 --- /dev/null +++ b/content/en/overview/reference/protoc-installation.md @@ -0,0 +1,73 @@ +--- +title: 如何安装 Protocol Buffer Compiler +linkTitle: Protoc安装 +description: 如何安装 protocol buffer 编译器。 +protoc-version: 3.15.8 +toc_hide: true +type: docs +--- + +虽然不是强制性的,但 Apache Dubbo 支持使用 [Protocol Buffers (proto3版本)](https://protobuf.dev/programming-guides/proto3) 作为服务定义和序列化协议。 + +在 Protocol buffer 体系下,我们使用 `.proto` 文件定义服务和消息体格式,使用 `protoc` 编译器编译 `.proto` 文件,你可以使用以下几种方式安装 `protoc`。 + +### 使用包管理器安装 + +在 Linux 或 macOS 环境下,你可以使用包管理器安装 `protoc`。 + +{{% alert title="Warning" color="warning" %}} +**一定要注意检查所安装 `protoc` 的版本!** 检查方法如下文说述,因为有时一些包管理器安装的 `protoc` 版本是严重过时的。 + +下一节所展示的 [使用预先编译好的二进制文件安装](#binary-install) 可以确保你安装正确的 `protoc` 版本。 +{{% /alert %}} + +- Linux,使用 `apt` 或者 `apt-get`,比如: + + ```sh + $ apt install -y protobuf-compiler + $ protoc --version # Ensure compiler version is 3+ + ``` + +- MacOS,使用 [Homebrew](https://brew.sh): + + ```sh + $ brew install protobuf + $ protoc --version # Ensure compiler version is 3+ + ``` + + + +### 使用预先编译好的二进制文件安装(适用任何操作系统) + +参考以下步骤安装 [最新版本](https://protobuf.dev/downloads#release-packages) 的 protoc 二进制包: + + 1. 根据你的操作系统类型,手动下载 [github.com/google/protobuf/releases](https://github.com/google/protobuf/releases) 二进制文件 + (`protoc---.zip`),你也可以使用以下命令直接下载: + + ```sh + $ PB_REL="https://github.com/protocolbuffers/protobuf/releases" + $ curl -LO $PB_REL/download/v{{< param protoc-version >}}/protoc-{{< param protoc-version >}}-linux-x86_64.zip + ``` + + 2. 将文件解压到`$HOME/.local` 目录,或者任意你想要的目录也可以。比如: + + ```sh + $ unzip protoc-{{< param protoc-version >}}-linux-x86_64.zip -d $HOME/.local + ``` + + 3. 修改系统 `PATH` 路径,将 `protoc` 加入可执行文件路径。比如: + + ```sh + $ export PATH="$PATH:$HOME/.local/bin" + ``` + +### 其他安装方法 + +如果你想要自行编译源码安装,或者想要安装老版本的二进制包。请参考 [下载 Protocol Buffers](https://protobuf.dev/downloads) + +[download]: https://protobuf.dev/downloads +[github.com/google/protobuf/releases]: https://github.com/google/protobuf/releases +[Homebrew]: https://brew.sh +[latest release]: https://protobuf.dev/downloads#release-packages +[pb]: https://developers.google.com/protocol-buffers +[proto3]: https://protobuf.dev/programming-guides/proto3 diff --git a/content/en/overview/reference/protocols/_index.md b/content/en/overview/reference/protocols/_index.md new file mode 100644 index 000000000000..f0eb66eff061 --- /dev/null +++ b/content/en/overview/reference/protocols/_index.md @@ -0,0 +1,7 @@ +--- +description: "Dubbo 内置协议设计思路与协议规范" +linkTitle: 协议规范 +title: 协议规范 +type: docs +weight: 4 +--- diff --git a/content/en/overview/reference/protocols/http.md b/content/en/overview/reference/protocols/http.md new file mode 100644 index 000000000000..2c1c5b24b78d --- /dev/null +++ b/content/en/overview/reference/protocols/http.md @@ -0,0 +1,625 @@ +--- +description: "HTTP Json 协议规范" +linkTitle: HTTP 协议规范 +title: HTTP 协议规范 +type: docs +weight: 3 +working_in_progress: true +--- + +{{% alert title="注意" color="warning" %}} +从 Dubbo 3.3 版本开始,Rest 协议已移至 Extensions 库,由 Triple 协议来对 Rest 提供更全面的支持,具体参见 [Triple Rest用户手册](../../../mannual/java-sdk/reference-manual/protocol/tripe-rest-manual/), +如需继续使用原 Rest 协议,可引入对应 [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) 库依赖 +{{% /alert %}} + +## 什么是 Dubbo Http +基于 spring web 和 resteasy 注解编码风格,通过http协议进行服务间调用互通,dubbo protocol扩展实现的协议 + +## 为什么选择Dubbo Http +- dubbo http 可以实现微服务与dubbo之间的互通 +- 多协议发布服务,可以实现服务协议的平滑迁移 +- http的通用性,解决跨语言互通 +- 最新版本的http 无需添加其他组件,更轻量 +- resteasy以及spring web的编码风格,上手更快 + +## 协议规范 +- Request + +相对于原生的http协议dubbo http 请求增加version和group两个header用于确定服务的唯一, +如果provider一端没有声明group和version,http请求时就不需要传递这连个header,反之必须要传递目标 +服务的group和version, 如果使用dubbo http的RestClient这两个header将会默认通过attachment传递 +为区别于其他的header,attachment将会增加rest-service-前缀,因此通过其他形式的http client调用 +dubbo http服务需要传递 rest-service-version 和 rest-service-group 两个header +```` +POST /test/path HTTP/1.1 +Host: localhost:8080 +Content-type: application/json +Accept: text/html +rest-service-version: 1.0.0 +rest-service-group: dubbo + +{"name":"dubbo","age":10,"address":"hangzhou"} + + +```` +- Response +```` +HTTP/1.1 200 +Content-Type: text/html +Content-Length: 4 +Date: Fri, 28 Apr 2023 14:16:42 GMT + +"success" +```` +- content-type支持 + - application/json + - application/x-www-form-urlencoded + - text/plain + - text/xml + +目前支持以上media,后面还会对type进行扩展 + +## 快速入门 +详细的依赖以及spring配置,可以参见dubbo 项目的dubbo-demo-xml模块 +https://github.com/apache/dubbo/tree/3.2/dubbo-demo/dubbo-demo-xml + +- spring web 编码 +在使用dubbo http的spring web编码时,类注解我们要求必须出现@RequestMapping或者@Controller,以此来判断用户使用的编码风格,决定使用对应的SpringMvcServiceRestMetadataResolver +注解解析器进行元注解解析,Provider一侧我们允许用户使用实现类作为Dubbo Service(相比之前dubbo service export时service必须是接口的要求) + +API +````java +@RequestMapping("/spring/demo/service") +public interface SpringRestDemoService { + + @RequestMapping(method = RequestMethod.GET, value = "/hello") + Integer hello(@RequestParam("a") Integer a, @RequestParam("b") Integer b); + + @RequestMapping(method = RequestMethod.GET, value = "/error") + String error(); + + @RequestMapping(method = RequestMethod.POST, value = "/say") + String sayHello(@RequestBody String name); + + @RequestMapping(method = RequestMethod.POST, value = "/testFormBody", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + Long testFormBody(@RequestBody Long number); + + @RequestMapping(method = RequestMethod.POST, value = "/testJavaBeanBody", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + User testJavaBeanBody(@RequestBody User user); + + + @RequestMapping(method = RequestMethod.GET, value = "/primitive") + int primitiveInt(@RequestParam("a") int a, @RequestParam("b") int b); + + @RequestMapping(method = RequestMethod.GET, value = "/primitiveLong") + long primitiveLong(@RequestParam("a") long a, @RequestParam("b") Long b); + + @RequestMapping(method = RequestMethod.GET, value = "/primitiveByte") + long primitiveByte(@RequestParam("a") byte a, @RequestParam("b") Long b); + + + @RequestMapping(method = RequestMethod.POST, value = "/primitiveShort") + long primitiveShort(@RequestParam("a") short a, @RequestParam("b") Long b, @RequestBody int c); + + + @RequestMapping(method = RequestMethod.GET, value = "/testMapParam") + String testMapParam(@RequestParam Map params); + + @RequestMapping(method = RequestMethod.GET, value = "/testMapHeader") + String testMapHeader(@RequestHeader Map headers); + + @RequestMapping(method = RequestMethod.POST, value = "/testMapForm", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + List testMapForm(MultiValueMap params); + + + @RequestMapping(method = RequestMethod.GET, value = "/headerInt") + int headerInt(@RequestHeader("header") int header); + + +} +```` + +Provider + +````java + @DubboService(interfaceClass = SpringRestDemoService.class ,protocol = "rest") +public class SpringRestDemoServiceImpl implements SpringRestDemoService { + + @Override + public String sayHello(String name) { + return "Hello, " + name; + } + + @Override + public Long testFormBody(Long number) { + return number; + } + + @Override + public User testJavaBeanBody(User user) { + return user; + } + + + @Override + public int primitiveInt(int a, int b) { + return a + b; + } + + @Override + public long primitiveLong(long a, Long b) { + return a + b; + } + + @Override + public long primitiveByte(byte a, Long b) { + return a + b; + } + + @Override + public long primitiveShort(short a, Long b, int c) { + return a + b; + } + + + @Override + public String testMapParam(Map params) { + return params.get("param"); + } + + @Override + public String testMapHeader(Map headers) { + return headers.get("header"); + } + + @Override + public List testMapForm(MultiValueMap params) { + return params.get("form"); + } + + + @Override + public int headerInt(int header) { + return header; + } + + + @Override + public Integer hello(Integer a, Integer b) { + return a + b; + } + + + @Override + public String error() { + throw new RuntimeException("test error"); + } + +} +```` +Consumer +````java +@Component +public class SpringRestDemoServiceConsumer { + @DubboReference(interfaceClass = SpringRestDemoService.class ) + SpringRestDemoService springRestDemoService; + + public void invoke(){ + String hello = springRestDemoService.sayHello("hello"); + assertEquals("Hello, hello", hello); + Integer result = springRestDemoService.primitiveInt(1, 2); + Long resultLong = springRestDemoService.primitiveLong(1, 2l); + long resultByte = springRestDemoService.primitiveByte((byte) 1, 2l); + long resultShort = springRestDemoService.primitiveShort((short) 1, 2l, 1); + + assertEquals(result, 3); + assertEquals(resultShort, 3l); + assertEquals(resultLong, 3l); + assertEquals(resultByte, 3l); + + assertEquals(Long.valueOf(1l), springRestDemoService.testFormBody(1l)); + + MultiValueMap forms = new LinkedMultiValueMap<>(); + forms.put("form", Arrays.asList("F1")); + + assertEquals(Arrays.asList("F1"), springRestDemoService.testMapForm(forms)); + assertEquals(User.getInstance(), springRestDemoService.testJavaBeanBody(User.getInstance())); + } + + private void assertEquals(Object returnStr, Object exception) { + boolean equal = returnStr != null && returnStr.equals(exception); + + if (equal) { + return; + } else { + throw new RuntimeException(); + } + } + + +} + +```` + +- JaxRs 编码 + JaxRs注解使用的时候我们要求service 类上必须使用@Path注解,来确定使用JAXRSServiceRestMetadataResolver + 注解解析器来解析注解元信息 + +API +````java +@Path("/jaxrs/demo/service") +public interface JaxRsRestDemoService { + @GET + @Path("/hello") + Integer hello(@QueryParam("a") Integer a, @QueryParam("b") Integer b); + + @GET + @Path("/error") + String error(); + + @POST + @Path("/say") + String sayHello(String name); + + + + + + @POST + @Path("/testFormBody") + Long testFormBody(@FormParam("number") Long number); + + @POST + @Path("/testJavaBeanBody") + @Consumes({MediaType.APPLICATION_JSON}) + User testJavaBeanBody(User user); + + + + @GET + @Path("/primitive") + int primitiveInt(@QueryParam("a") int a, @QueryParam("b") int b); + + @GET + @Path("/primitiveLong") + long primitiveLong(@QueryParam("a") long a, @QueryParam("b") Long b); + + @GET + @Path("/primitiveByte") + long primitiveByte(@QueryParam("a") byte a, @QueryParam("b") Long b); + + @POST + @Path("/primitiveShort") + long primitiveShort(@QueryParam("a") short a, @QueryParam("b") Long b, int c); + + @GET + @Path("testMapParam") + @Produces({MediaType.TEXT_PLAIN}) + @Consumes({MediaType.TEXT_PLAIN}) + String testMapParam(@QueryParam("test") Map params); + + @GET + @Path("testMapHeader") + @Produces({MediaType.TEXT_PLAIN}) + @Consumes({MediaType.TEXT_PLAIN}) + String testMapHeader(@HeaderParam("test") Map headers); + + @POST + @Path("testMapForm") + @Produces({MediaType.APPLICATION_JSON}) + @Consumes({MediaType.APPLICATION_FORM_URLENCODED}) + List testMapForm(MultivaluedMap params); + + @POST + @Path("/header") + @Consumes({MediaType.TEXT_PLAIN}) + String header(@HeaderParam("header") String header); + + @POST + @Path("/headerInt") + @Consumes({MediaType.TEXT_PLAIN}) + int headerInt(@HeaderParam("header") int header); + + +} +```` + +Provider +````java +@DubboService(interfaceClass =JaxRsRestDemoService.class ,protocol = "rest",version = "1.0.0",group = "test") +public class JaxRsRestDemoServiceImpl implements JaxRsRestDemoService { + + @Override + public String sayHello(String name) { + return "Hello, " + name; + } + + @Override + public Long testFormBody(Long number) { + return number; + } + + @Override + public User testJavaBeanBody(User user) { + return user; + } + + + @Override + public int primitiveInt(int a, int b) { + return a + b; + } + + @Override + public long primitiveLong(long a, Long b) { + return a + b; + } + + @Override + public long primitiveByte(byte a, Long b) { + return a + b; + } + + @Override + public long primitiveShort(short a, Long b, int c) { + return a + b; + } + + + + @Override + public String testMapParam(Map params) { + return params.get("param"); + } + + @Override + public String testMapHeader(Map headers) { + return headers.get("header"); + } + + @Override + public List testMapForm(MultivaluedMap params) { + return params.get("form"); + } + + @Override + public String header(String header) { + return header; + } + + @Override + public int headerInt(int header) { + return header; + } + + + @Override + public Integer hello(Integer a, Integer b) { + return a + b; + } + + + @Override + public String error() { + throw new RuntimeException("test error"); + } + +} +```` +Consumer +````java +@Component +public class JaxRsRestDemoService { + @DubboReference(interfaceClass = JaxRsRestDemoService.class) + JaxRsRestDemoService jaxRsRestDemoService; + + public void jaxRsRestDemoServiceTest(ClassPathXmlApplicationContext context) { + JaxRsRestDemoService jaxRsRestDemoService = context.getBean("jaxRsRestDemoService", JaxRsRestDemoService.class); + String hello = jaxRsRestDemoService.sayHello("hello"); + assertEquals("Hello, hello", hello); + Integer result = jaxRsRestDemoService.primitiveInt(1, 2); + Long resultLong = jaxRsRestDemoService.primitiveLong(1, 2l); + long resultByte = jaxRsRestDemoService.primitiveByte((byte) 1, 2l); + long resultShort = jaxRsRestDemoService.primitiveShort((short) 1, 2l, 1); + + assertEquals(result, 3); + assertEquals(resultShort, 3l); + assertEquals(resultLong, 3l); + assertEquals(resultByte, 3l); + + assertEquals(Long.valueOf(1l), jaxRsRestDemoService.testFormBody(1l)); + + MultivaluedMapImpl forms = new MultivaluedMapImpl<>(); + forms.put("form", Arrays.asList("F1")); + + assertEquals(Arrays.asList("F1"), jaxRsRestDemoService.testMapForm(forms)); + assertEquals(User.getInstance(), jaxRsRestDemoService.testJavaBeanBody(User.getInstance())); + } + +} +```` + + +## 使用场景 + + 因为dubbo http consumer一端实现http 调用的RestClient 实现有三种形式:httpclient,okhttp,URLConnection(jdk内置) + 默认请情况下采用okhttp,因此在使用dubbo http 去调用其他http服务时,需要添加引入的依赖有 + +````xml + + org.apache.dubbo + dubbo-rpc-rest + ${dubbo-rpc-rest_version} + + + + com.squareup.okhttp3 + mockwebserver + ${okhttp_version} + + 或 + + org.apache.httpcomponents + httpclient + ${httpclient_version} + +```` + +- 微服务服务调用dubbo http + +````java + +/** + * URL rest://localhost:8888/services + * rest: protocol + * localhost:8888: server address + * services: context path + */ +@DubboReference(interfaceClass = HttpService.class ,url = "rest://localhost:8888/services",version = "1.0.0",group = "test") + HttpService httpService; + + public void invokeHttpService() { + String http = httpService.http("Others Java Architecture Invoke Dubbo Rest"); + System.out.println(http); + } +```` + +- 跨语言调用 + + python + ```` + import requests + url = 'http://localhost:8888/services/curl' + headers = { + 'rest-service-group': 'test', + 'rest-service-version': '1.0.0' + } + response = requests.get(url, headers=headers) + ```` + + go + ```` + import ( + "fmt" + "net/http" + ) + + func main() { + url := "http://localhost:8888/services/curl" + req, err := http.NewRequest("GET", url, nil) + if err != nil { + fmt.Println("Error creating request:", err) + return + } + + req.Header.Set("rest-service-group", "test") + req.Header.Set("rest-service-version", "1.0.0") + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + fmt.Println("Error sending request:", err) + return + } + + defer resp.Body.Close() + + +- 多协议发布 + - dubbo 协议的代码使用http 进行数据请求测试 + - 服务协议迁移 + +````java +@DubboService(interfaceClass = HttpService.class, protocol = "rest,dubbo", version = "1.0.0", group = "test") +public class HttpServiceImpl implements HttpService { + + + @Override + public String http(String invokeType) { + return "Rest http request test success! by invokeType: " + invokeType; + } +} +```` + + - http client组件调用dubbo http(可以不引入 service api) + +````java +public class HttpClientInvoke { + + + private final String versionHeader = RestHeaderEnum.VERSION.getHeader(); + private final String groupHeader = RestHeaderEnum.GROUP.getHeader(); + /** + * contextPath services + */ + private final String url = "http://localhost:8888/services/http"; + + + public void httpServiceHttpClientInvoke() throws IOException { + CloseableHttpClient httpClient = createHttpClient(); + HttpRequestBase httpUriRequest = new HttpGet(url); + httpUriRequest.addHeader(versionHeader, "1.0.0"); + httpUriRequest.addHeader(RestConstant.ACCEPT, "text/plain"); + httpUriRequest.addHeader(groupHeader, "test"); + httpUriRequest.addHeader("type", "Http Client Invoke Dubbo Rest Service"); + CloseableHttpResponse response = httpClient.execute(httpUriRequest); + + RestResult restResult = parseResponse(response); + + System.out.println(new String(restResult.getBody())); + } + + private RestResult parseResponse(CloseableHttpResponse response) { + return new RestResult() { + @Override + public String getContentType() { + return response.getFirstHeader("Content-Type").getValue(); + } + + @Override + public byte[] getBody() throws IOException { + if (response.getEntity() == null) { + return new byte[0]; + } + return IOUtils.toByteArray(response.getEntity().getContent()); + } + + @Override + public Map> headers() { + return Arrays.stream(response.getAllHeaders()).collect(Collectors.toMap(Header::getName, h -> Collections.singletonList(h.getValue()))); + } + + @Override + public byte[] getErrorResponse() throws IOException { + return getBody(); + } + + @Override + public int getResponseCode() { + return response.getStatusLine().getStatusCode(); + } + + @Override + public String getMessage() throws IOException { + return appendErrorMessage(response.getStatusLine().getReasonPhrase(), + new String(getErrorResponse())); + } + }; + } + + + private CloseableHttpClient createHttpClient() { + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); + return HttpClients.custom().setConnectionManager(connectionManager).build(); + } +} +```` + +## 3.2 与 3.0 HTTP 实现对比 + +因为 Dubbo Java 3.2 内部移除了原本 Resteasy 的实现,因此在对 Resteasy 内置的 Response,extend,ExceptionMapper 支持上将会有所变化 +ExceptionMapper 转换成了org.apache.dubbo.rpc.protocol.rest.exception.mapper.ExceptionHandler,Response后面也会做适配处理 + +| 版本 | JaxRs| j2ee | web容器(tomcat/jetty)|spring web| http client\(okhttp/httpclient/jdk URLConnnection ) +| ---- | ---- |--- |--- |--- |---| +| 3.0 | 依赖与resteasy的client和server |遵循j2ee规范|依赖常见web容器|不依赖|不依赖 +| 3.2 | 不依赖(仅需要JaxRs注解包) |不遵循|netty实现的http服务器|仅依赖spring web注解|内部实现RestClient依赖http client(默认为okhttp) diff --git a/content/en/overview/reference/protocols/tcp.md b/content/en/overview/reference/protocols/tcp.md new file mode 100644 index 000000000000..8a19320ac51f --- /dev/null +++ b/content/en/overview/reference/protocols/tcp.md @@ -0,0 +1,100 @@ +--- +description: "TCP (Dubbo2) 协议规范" +linkTitle: Dubbo2 协议规范 +title: Dubbo2 协议规范 +type: docs +weight: 2 +--- + +![/dev-guide/images/dubbo_protocol_header.jpg](/imgs/dev/dubbo_protocol_header.png) + +## 协议规范 Specification + +- Magic - Magic High & Magic Low (16 bits) + + 标识协议版本号,Dubbo 协议:0xdabb + +- Req/Res (1 bit) + + 标识是请求或响应。请求: 1; 响应: 0。 + +- 2 Way (1 bit) + + 仅在 Req/Res 为1(请求)时才有用,标记是否期望从服务器返回值。如果需要来自服务器的返回值,则设置为1。 + +- Event (1 bit) + + 标识是否是事件消息,例如,心跳事件。如果这是一个事件,则设置为1。 + +- Serialization ID (5 bit) + + 标识序列化类型:比如 fastjson 的值为6。 + +- Status (8 bits) + + 仅在 Req/Res 为0(响应)时有用,用于标识响应的状态。 + + - 20 - OK + - 30 - CLIENT_TIMEOUT + - 31 - SERVER_TIMEOUT + - 40 - BAD_REQUEST + - 50 - BAD_RESPONSE + - 60 - SERVICE_NOT_FOUND + - 70 - SERVICE_ERROR + - 80 - SERVER_ERROR + - 90 - CLIENT_ERROR + - 100 - SERVER_THREADPOOL_EXHAUSTED_ERROR + +- Request ID (64 bits) + + 标识唯一请求。类型为long。 + +- Data Length (32 bits) + + 序列化后的内容长度(可变部分),按字节计数。int类型。 + +- Variable Part + + 被特定的序列化类型(由序列化 ID 标识)序列化后,每个部分都是一个 byte [] 或者 byte + + - 如果是请求包 ( Req/Res = 1),则每个部分依次为: + - Dubbo version + - Service name + - Service version + - Method name + - Method parameter types + - Method arguments + - Attachments + - 如果是响应包(Req/Res = 0),则每个部分依次为: + - 返回值类型(byte),标识从服务器端返回的值类型: + - 返回空值:RESPONSE_NULL_VALUE 2 + - 正常响应值: RESPONSE_VALUE 1 + - 异常:RESPONSE_WITH_EXCEPTION 0 + - 返回值:从服务端返回的响应bytes + +**注意:** 对于(Variable Part)变长部分,当前版本的Dubbo 框架使用json序列化时,在每部分内容间额外增加了换行符作为分隔,请在Variable Part的每个part后额外增加换行符, 如: + +``` +Dubbo version bytes (换行符) +Service name bytes (换行符) +... +``` + +## 协议特点分析 + +### 优点 + +- 协议设计上很紧凑,能用 1 个 bit 表示的,不会用一个 byte 来表示,比如 boolean 类型的标识。 +- 请求、响应的 header 一致,通过序列化器对 content 组装特定的内容,代码实现起来简单。 + +### 可以改进的点 + +- 对于网关代理类组件不友好。http 请求而言,通过 header 就可以确定要访问的资源,而 Dubbo 需要涉及到用特定序列化协议才可以将服务名、方法、方法签名解析出来,并且这些资源定位符是 string 类型或者 string 数组,很容易转成 bytes,因此可以组装到 header 中。类似于 http2 的 header 压缩,对于 rpc 调用的资源也可以协商出来一个int来标识,从而提升性能,如果在`header`上组装资源定位符的话,该功能则更易实现。 + +- 通过 req/res 是否是请求后,可以精细定制协议,去掉一些不需要的标识和添加一些特定的标识。比如`status`,`twoWay`标识可以严格定制,去掉冗余标识。还有超时时间是作为 Dubbo 的 `attachment` 进行传输的,理论上应该放到请求协议的header中,因为超时是网络请求中必不可少的。提到 `attachment` ,通过实现可以看到 `attachment` 中有一些是跟协议 `content`中已有的字段是重复的,比如 `path`和`version`等字段,这些会增大协议尺寸。 + +- Dubbo 会将服务名`com.alibaba.middleware.hsf.guide.api.param.ModifyOrderPriceParam`,转换为`Lcom/alibaba/middleware/hsf/guide/api/param/ModifyOrderPriceParam;`,理论上是不必要的,最后追加一个`;`即可。 + +- Dubbo 协议没有预留扩展字段,没法新增标识,扩展性不太好,比如新增`响应上下文`的功能,只有改协议版本号的方式,但是这样要求客户端和服务端的版本都进行升级,对于分布式场景很不友好。 + + diff --git a/content/en/overview/reference/protocols/triple-spec.md b/content/en/overview/reference/protocols/triple-spec.md new file mode 100644 index 000000000000..3ce482305022 --- /dev/null +++ b/content/en/overview/reference/protocols/triple-spec.md @@ -0,0 +1,329 @@ +--- +description: "Triple 协议规范" +linkTitle: Triple 协议规范 +title: Triple 协议设计理念与规范 +type: docs +weight: 1 +working_in_progress: true +--- + +## 1 协议设计理念 +Triple 协议的设计参考了 gRPC、gRPC-Web、通用 HTTP 等多种协议模式,吸取每个协议各自的特性和优点,最终设计成为一个易于浏览器访问、完全兼容 gRPC 且支持 Streaming 通信的协议,Triple 支持同时运行在 HTTP/1、HTTP/2 协议之上。 + +Triple 协议的设计目标如下: +* Triple 设计为对人类、开发调试友好的一款基于 HTTP 的协议,尤其是对 unary 类型的 RPC 请求。 +* 完全兼容基于 HTTP/2 的 gRPC 协议,因此 Dubbo Triple 协议实现可以 100% 与 gRPC 体系互调互通。 +* 仅依赖标准的、被广泛使用的 HTTP 特性,以便在实现层面可以直接依赖官方的标准 HTTP 网络库。 + +当与 Protocol Buffers 一起使用时(即使用 IDL 定义服务),Triple 协议可支持 unary、client-streaming、server-streaming 和 bi-streaming RPC 通信模式,支持二进制 Protobuf、JSON 两种数据格式 payload。 Triple 实现并不绑定 Protocol Buffers,比如你可以使用 Java 接口定义服务,Triple 协议有对这种模式的扩展 Content-type 支持。 + +## 2 示例 +### 2.1 Unary 请求 + +以 HTTP/1 请求为例,目前 HTTP/1 协议仅支持 Unary RPC,支持使用 application/proto 和 application/json 编码类型,使用方式与 REST 风格请求保持一致,同时响应也包含常规的 HTTP 响应编码(如 200 OK)。 + +```text +> POST /org.apache.dubbo.demo.GreetService/Greet HTTP/1.1 +> Host: 127.0.0.1:30551 +> Content-Type: application/json +> +> ["Dubbo"] + +< HTTP/1.1 200 OK +< Content-Type: application/json +< +< {"greeting": "Hello, Dubbo!"} +``` + +一个包含指定超时时间的调用请求。 + +```text +> POST /org.apache.dubbo.demo.GreetService/Greet HTTP/1.1 +> Host: 127.0.0.1:30551 +> Content-Type: application/json +> Rest-service-timeout: 5000 +> +> ["Dubbo"] + +< HTTP/1.1 200 OK +< Content-Type: application/json +< +< {"greeting": "Hello, Buf!"} +``` + +> 目前仅支持 POST 请求类型,我们将考虑在未来支持 GET 请求类型,GET 请求可能适用于具有幂等属性的一些服务调用。 + +### 2.2 Streaming 调用请求 + +Triple 仅支持在 HTTP/2 上支持 Streaming RPC。并且为了与 gRPC 协议保持兼容,Triple 在 HTTP/2 协议实现上(包含 Streaming RPC)保持与标准 gRPC 协议完全一致。 + +Request + +```text +HEADERS (flags = END_HEADERS) +:method = POST +:scheme = http +:path = /google.pubsub.v2.PublisherService/CreateTopic +:authority = pubsub.googleapis.com +grpc-timeout = 1S +content-type = application/grpc+proto +grpc-encoding = gzip +authorization = Bearer y235.wef315yfh138vh31hv93hv8h3v + +DATA (flags = END_STREAM) + +``` + +Response + +```text +HEADERS (flags = END_HEADERS) +:status = 200 +grpc-encoding = gzip +content-type = application/grpc+proto + +DATA + + +HEADERS (flags = END_STREAM, END_HEADERS) +grpc-status = 0 # OK +trace-proto-bin = jher831yy13JHy3hc +``` + +## 3 规范详情 + +Triple 协议支持同时运行在 HTTP/1 和 HTTP/2 协议之上,其包含以下两部分内容: +1. 一套自定义的精简 HTTP RPC 子协议,支持 HTTP/1 和 HTTP/2 作为传输层实现,仅支持 Request-Response 类型的 Unary RPC。 +2. 一套基于 gRPC 协议的扩展子协议(仍保持和 gRPC 的 100% 兼容),仅支持 HTTP/2 实现,支持 Unary RPC 和 Streaming RPC。 + +### 3.1 Triple 之 HTTP RPC 协议 + +大部分的 RPC 调用都是 unary (request-response) 模式的,Triple HTTP RPC 协议 unary 模式能很好的满足后端服务间的数据传输需求。同时解决了gRPC协议的痛点,让浏览器、cURL 以及其他一些 HTTP 工具更容易的访问后端服务,即不需要借助代理和gRPC-web,使用标准的 HTTP 协议直接发起调用。 + +Triple HTTP RPC 同时支持 HTTP/1、HTTP/2 作为底层传输层协议,在实现上对应支持的 content-type 类型为 application/json、application/proto + +#### 3.1.1 请求 Request + +- Request → Request-Headers Bare-Message +- Request-Headers → Call-Specification *Leading-Metadata +- Call-Specification → +Schema Http-Method Path Http-Host Content-Type TRI-Protocol-Version TRI-Service-Timeout TRI-Service-Version TRI-Service-Group +Content-Encoding Accept-Encoding Accept Content-Length +- Scheme → "http" / "https" +- Http-Method → POST +- Path → /Service-Name/Method-Name; case-sensitive +- Service-Name → service interface full classname +- Method-Name → service interface declared method`s name +- Http-Host → Target-IP:Target-Port +- Target-IP → target server ip or domain +- Target-Port → target server process port +- Content-Type → “Content-Type: ” “application/” Message-Codec +- Message-Codec → (“json” / {custom}) +- TRI-Protocol-Version → "tri-protocol-version" "1" +- TRI-Service-Timeout → “tri-service-timeout: ” Timeout-Milliseconds +- Timeout-Milliseconds → positive integer +- TRI-Service-Version → “tri-service-version: ” Version +- Version → dubbo service version +- TRI-Service-Group → "tri-service-group: " Group +- Group → dubbo service group +- Content-Encoding → “content-encoding” Content-Coding +- Content-Coding → “identity” / “gzip” / “br” / “zstd” / {custom} +- Accept-Encoding → “accept-encoding” Content-Coding *("," [" “] Content-Coding) ; subset of HTTP quality value syntax +- Content-Length → length of the encoded payload +- Leading-Metadata → Custom-Metadata +- Custom-Metadata → ASCII-Metadata / Binary-Metadata +- ASCII-Metadata → Header-Name ASCII-Value +- Binary-Metadata → {Header-Name "-bin"} {base64-encoded value} +- Header-Name → 1*( %x30-39 / %x61-7A / "_" / "-" / ".") ; 0-9 a-z _ - . +- ASCII-Value → 1*( %x20-%x7E ) ; space & printable ASCII +- Bare-Message → data that encoded by json or custom and Content-Encoding + +Triple 协议请求的仅支持 POST 请求,请求 path 为 interfaceName/methodName,为了实现调用超时机制,需要添加 tri-service-timeout (单位 ms), + +Dubbo 框架支持基于 **分组(group)** 和 **版本(version)** 的服务隔离机制,因此 Triple 协议中引入了 tri-service-group、tri-service-version 支持。 + +**Request-Headers** 以标准的 HTTP header 的形式发送,如果收到的 headers 数量过多,server 可返回相应错误信息。 + +**TRI-Protocol-Version** 头用来区分具有相同 Content-Type 的 triple 协议请求和其他协议请求,因为 application/json 格式的 Content-Type 非常普遍。所有的 Dubbo 原生客户端实现都应该在请求中携带 TRI-Protocol-Version,Dubbo 服务端或代理可以选择拒绝没有 TRI-Protocol-Version 的请求并返回 Http-Status 400 错误。 + +如果 Server 不支持 **Message-Codec** 指定的编码格式,则必须返回标准 HTTP 415 编码表明 Unsupported Media Type 异常。 + +**Bare-Message** 即请求 payload 的编码格式取决于 Message-Codec 设置: +* Message-Codec: json 的场景下,payload 采用有序的数组编码形式,即将 rpc 方法的参数按顺序组装进 Array 后进行 json 序列化,方法参数的位置与数组下标保持一致,当 Triple server 接收到请求体时,根据每个参数的类型进行反序列化成对应的参数数组。对于使用 Protocol Buffer 的情形,payload 则是只有一个 json 对象的数组。 +* Message-Codec: proto 的场景下,Protobuf 生成的 Request 类包含了编码格式,因此将直接使用 Request 对象中的内置编码方式。 +* Message-Codec 支持更多自定义扩展值,请确保框架实现遵循相应的编码与解码约定。 + +如果 Content-Encoding 指定了相应值,则 payload 是被压缩过的,应该首先进行解压缩后再解析编码数据,Bare-Message 将作为 HTTP Body 在链路上传输。 + +##### Request 报文示例 + +- 请求行 + - POST /org.apache.dubbo.demo.GreetService/greeting HTTP/1.1 +- 请求头 + - Host: 127.0.0.1:30551 + - Content-Type: application/json + - Accept: application/json + - Content-Length: 11 + - Accept-Encoding: compress, gzip + - tri-protocol-version: 1.0.0 + - tri-service-version: 1.0.0 + - tri-service-group: dubbo + - tri-service-timeout: 3000 +- 请求体 + - [{"world"}] + +```latex +POST /org.apache.dubbo.demo.GreetService/Greet HTTP/1.1 +Host: 127.0.0.1:30551 +Content-Type: application/json +Accept: application/json +Content-Length: 11 +Accept-Encoding: compress, gzip +tri-protocol-version: 1.0.0 +tri-service-version: 1.0.0 +tri-service-group: dubbo +tri-service-timeout: 3000 + +[{"world"}] +``` + + +#### 3.1.2 响应 Response + +- Response → Response-Headers *Bare-Message +- Response-Headers → HTTP-Status Content-Type [Content-Encoding] [Accept-Encoding] *Leading-Metadata *Prefixed-Trailing-Metadata +- HTTP-Status → 200 /{error code translated to HTTP} +- Bare-Message → data that encoded by Content-Type and Content-Encoding + +对于成功 Response 响应 **HTTP-Status** 是 200,在这种场景下,响应体的 Content-Type 将保持和请求体的 Content-Type 保持一致。**Bare-Message** 就是 RPC 响应的 Payload,以 Content-Type 指定的方式进行编码并且以 Content-Encoding 来压缩(如果指定了 Content-Encoding 的话)。Bare-Message 作为 HTTP response body 发送。 + +异常 Response 响应的 HTTP-Status 是 non-200,并且都是标准的 HTTP status code,在这个场景下,**Content-Type** 必须是 "application/json"。**Bare-Message** 可以是空的,如果 Bare-Message 有值的话则是一个标准 JSON 格式数据,如果 **Content-Encoding** 有指定的话则是一个压缩过的数据,Bare-Message 作为标准的 HTTP response body 发送回调用方。客户端可以根据以下表格,查询 HTTP-Status 与 RPC status 之间的映射关系,以了解具体的 RPC 错误情况。 + +##### Response 报文格式 +** 成功响应 ** + +```latex +HTTP/1.1 200 OK +Content-Type: application/json +Content-Length: 11 + +hello world +``` + +** 失败响应 ** + +```latex +HTTP/1.1 400 Bad Request +Content-Type: application/json +Content-Length: 46 +{"status":20,"message":"request format error"} +``` + +#### 3.1.3 Error Codes + +Dubbo 的错误码参考 + +``` + status http-status message + 20 200 ok + 25 400 serialization error + 30 408 client side timeout + 31 408 server side timeout + 35 500 channel inactive, directly return the unfinished requests + 40 400 request format error + 50 500 response format error + 60 404 service not found. + 70 500 service error + 80 500 internal server error + 90 500 internal client error +``` + +> Connect 的 HTTP to Error Code 参考 +> +> | HTTP Status | Inferred Code | +> | --- | --- | +> | 400 Bad Request | invalid_argument | +> | 401 Unauthorized | unauthenticated | +> | 403 Forbidden | permission_denied | +> | 404 Not Found | unimplemented | +> | 408 Request Timeout | deadline_exceeded | +> | 409 Conflict | aborted | +> | 412 Precondition Failed | failed_precondition | +> | 413 Payload Too Large | resource_exhausted | +> | 415 Unsupported Media Type | internal | +> | 429 Too Many Requests | unavailable | +> | 431 Request Header Fields Too Large | resource_exhausted | +> | 502 Bad Gateway | unavailable | +> | 503 Service Unavailable | unavailable | +> | 504 Gateway Timeout | unavailable | +> | _all others_ | unknown | + + +### 3.2 Triple 之扩展版 gRPC 协议 + +Triple 协议的 Streaming 请求处理完全遵循 gRPC 协议规范,且仅支持 HTTP/2 作为传输层协议。并且后端服务间的 Unary 请求默认采用扩展版 gPRC 协议。 + +Triple 支持的 content-type 类型为标准的 gRPC 类型,包括 application/grpc、application/grpc+proto、application/grpc+json,除此之外,Triple 在实现上还扩展了 application/triple+wrapper 编码格式。 + +#### 3.2.1 Outline + +The following is the general sequence of message atoms in a GRPC request & response message stream + +* Request → Request-Headers \*Length-Prefixed-Message EOS +* Response → (Response-Headers \*Length-Prefixed-Message Trailers) / Trailers-Only + + +#### 3.2.2 Requests + +* Request → Request-Headers \*Length-Prefixed-Message EOS + +Request-Headers are delivered as HTTP2 headers in HEADERS + CONTINUATION frames. + +* **Request-Headers** → Call-Definition \*Custom-Metadata +* **Call-Definition** → Method Scheme Path TE [Authority] [Timeout] Content-Type [Message-Type] [Message-Encoding] [Message-Accept-Encoding] [User-Agent] Service-Version Service-Group Tracing-ID Tracing-Span-ID Cluster-Info +* **Method** → ":method POST" +* **Scheme** → ":scheme " ("http" / "https") +* **Path** → ":path" "/" Service-Name "/" {_method name_} # But see note below. +* **Service-Name** → {_IDL-specific service name_} +* **Authority** → ":authority" {_virtual host name of authority_} +* **TE** → "te" "trailers" # Used to detect incompatible proxies +* **Timeout** → "grpc-timeout" TimeoutValue TimeoutUnit +* **TimeoutValue** → {_positive integer as ASCII string of at most 8 digits_} +* **TimeoutUnit** → Hour / Minute / Second / Millisecond / Microsecond / Nanosecond + * **Hour** → "H" + * **Minute** → "M" + * **Second** → "S" + * **Millisecond** → "m" + * **Microsecond** → "u" + * **Nanosecond** → "n" +* **Content-Type** → "content-type" "application/grpc" [("+proto" / "+json" / {_custom_})] +* **Content-Coding** → "identity" / "gzip" / "deflate" / "snappy" / {_custom_} +* **Message-Encoding** → "grpc-encoding" Content-Coding +* **Message-Accept-Encoding** → "grpc-accept-encoding" Content-Coding \*("," Content-Coding) +* **User-Agent** → "user-agent" {_structured user-agent string_} +* **Message-Type** → "grpc-message-type" {_type name for message schema_} +* **Custom-Metadata** → Binary-Header / ASCII-Header +* **Binary-Header** → {Header-Name "-bin" } {_base64 encoded value_} +* **ASCII-Header** → Header-Name ASCII-Value +* **Header-Name** → 1\*( %x30-39 / %x61-7A / "\_" / "-" / ".") ; 0-9 a-z \_ - . +* **ASCII-Value** → 1\*( %x20-%x7E ) ; space and printable ASCII +* Service-Version → "tri-service-version" {Dubbo service version} +* Service-Group → "tri-service-group" {Dubbo service group} +* Tracing-ID → "tri-trace-traceid" {tracing id} +* Tracing-RPC-ID → "tri-trace-rpcid" {_span id _} +* Cluster-Info → "tri-unit-info" {cluster infomation} + +#### 3.2.3 Responses + +* **Response** → (Response-Headers \*Length-Prefixed-Message Trailers) / Trailers-Only +* **Response-Headers** → HTTP-Status [Message-Encoding] [Message-Accept-Encoding] Content-Type \*Custom-Metadata +* **Trailers-Only** → HTTP-Status Content-Type Trailers +* **Trailers** → Status [Status-Message] \*Custom-Metadata +* **HTTP-Status** → ":status 200" +* **Status** → "grpc-status" 1\*DIGIT ; 0-9 +* **Status-Message** → "grpc-message" Percent-Encoded +* **Percent-Encoded** → 1\*(Percent-Byte-Unencoded / Percent-Byte-Encoded) +* **Percent-Byte-Unencoded** → 1\*( %x20-%x24 / %x26-%x7E ) ; space and VCHAR, except % +* **Percent-Byte-Encoded** → "%" 2HEXDIGIT ; 0-9 A-F + +以上即为 Triple 扩展版本的 gRPC 协议,更多详细规范说明请参照 gRPC 协议规范。 diff --git a/content/en/overview/reference/protocols/triple.md b/content/en/overview/reference/protocols/triple.md new file mode 100644 index 000000000000..41177421832d --- /dev/null +++ b/content/en/overview/reference/protocols/triple.md @@ -0,0 +1,86 @@ +--- +description: "Triple 协议优势与目标:Triple 协议是 Dubbo3 设计的基于 HTTP 的 RPC 通信协议规范,它完全兼容 gRPC 协议并可同时运行在 HTTP/1 和 HTTP/2 之上。" +linkTitle: Triple 协议优势与目标 +title: Triple 协议优势与目标 +type: docs +weight: 1 +working_in_progress: true +--- + +## 简介 +Triple 协议是 Dubbo3 设计的基于 HTTP 的 RPC 通信协议规范,它完全兼容 gRPC 协议,支持 Request-Response、Streaming 流式等通信模型,可同时运行在 HTTP/1 和 HTTP/2 之上。 + +Dubbo 框架提供了 Triple 协议的多种语言实现,它们可以帮助你构建浏览器、gRPC 兼容的 HTTP API 接口:你只需要定义一个标准的 Protocol Buffer 格式的服务并实现业务逻辑,Dubbo 负责帮助生成语言相关的 Server Stub、Client Stub,并将整个调用流程无缝接入如路由、服务发现等 Dubbo 体系。Go、Java 等语言的 Triple 协议实现原生支持 HTTP/1 传输层通信,相比于 gRPC 官方实现,Dubbo 框架提供的协议实现更简单、更稳定,帮助你更容易的开发和治理微服务应用。 + +针对某些语言版本,Dubbo 框架还提供了更贴合语言特性的编程模式,即不绑定 IDL 的服务定义与开发模式,比如在 Dubbo Java 中,你可以选择使用 Java Interface 和 Pojo 类定义 Dubbo 服务,并将其发布为基于 Triple 协议通信的微服务。 + +## 协议规范(Specification) +基于 Triple 协议,你可以实现以下目标: + +### 当 Dubbo 作为 Client 时 +Dubbo Client 可以访问 Dubbo 服务端 (Server) 发布的 Triple 协议服务,同时还可以访问标准的 gRPC 服务端。 +* 调用标准 gRPC 服务端,发送 Content-type 为标准 gRPC 类型的请求:application/grpc, application/grpc+proto, and application/grpc+json +* 调用 Dubbo 服务端,发送 Content-type 为 Triple 类型的请求:application/json, application/proto, application/triple+wrapper + +### 当 Dubbo 作为 Server 时 +Dubbo Server 默认将同时发布对 Triple、gRPC 协议的支持,并且 Triple 协议可以同时工作在 HTTP/1、HTTP/2 之上。因此,Dubbo Server 可以处理 Dubbo 客户端发过来的 Triple 协议请求,可以处理标准的 gRPC 协议请求,还能处理 cURL、浏览器发送过来的 HTTP 请求。以 Content-type 区分就是: +* 处理 gRPC 客户端发送的 Content-type 为标准 gRPC 类型的请求:application/grpc、application/grpc+proto、application/grpc+json +* 处理 Dubbo 客户端发送的 Content-type 为 Triple 类型的请求:application/json、application/proto、application/grpc+wrapper +* 处理 cURL、浏览器等发送的 Content-type 为 Triple 类型的请求:application/json、application/proto、application/grpc+wrapper + +详细在此查看详细的 [Triple Specification](../triple-spec)。 + +## 与 gRPC 协议的关系 +上面提到 Triple 完全兼容 gRPC 协议,那既然 gRPC 官方已经提供了多语言的框架实现,为什么 Dubbo 还要通过 Triple 重新实现一遍呢?核心目标主要有以下两点: + +* 首先,在协议设计上,Dubbo 参考 gRPC 与 gRPC-Web 两个协议设计了自定义的 Triple 协议:Triple 是一个基于 HTTP 传输层协议的 RPC 协议,它完全兼容 gRPC 的同时可运行在 HTTP/1、HTTP/2 之上。 +* 其次,Dubbo 框架在每个语言的实现过程中遵循了符合框架自身定位的设计理念,相比于 grpc-java、grpc-go 等框架库,Dubbo 协议实现更简单、更纯粹,尝试在实现上规避 gRPC 官方库中存在的一系列问题。 + +gRPC 本身作为 RPC 协议规范非常优秀,但我们发现原生的 gRPC 库实现在实际使用存在一系列问题,包括实现复杂、绑定 IDL、难以调试等,Dubbo 在协议设计与实现上从实践出发,很好的规避了这些问题: + +* 原生的 gRPC 实现受限于 HTTP/2 交互规范,无法为浏览器、HTTP API 提供交互方式,你需要额外的代理组件如 grpc-web、grpc-gateway 等才能实现。在 Dubbo 中,你可以直接用 curl、浏览器访问 Dubbo HTTP/2 服务. +* gRPC 官方库强制绑定 Proto Buffer,唯一的开发选择就是使用 IDL 定义和管理服务,这对于一些多语言诉求不强的用户是一个非常大的使用负担。Dubbo 则在支持 IDL 的同时,为 Java、Go 等提供了语言特有的服务定义与开发方式。 +* 在开发阶段,以 gRPC 协议发布的服务非常难以调试,你只能使用 gRPC 特定的工具来进行,很多工具都比较简陋 & 不成熟。而从 Dubbo3 开始,你可以直接使用 curl | jq 或者 Chrome 开发者工具来调试你的服务,直接传入 JSON 结构体就能调用服务。 +* 首先,gRPC 协议库有超过 10 万行代码的规模,但 Dubbo (Go、Java、Rust、Node.js 等) 关于协议实现部分仅有几千行代码,这让代码维护和问题排查变得更简单。 +* 谷歌提供的 gRPC 实现库没有使用主流的第三方或语言官方协议库,而是选择自己维护了一套实现,让整个维护与生态扩展变得更加复杂。比如 grpc-go 自己维护了一套 HTTP/2 库而不是使用的 go 官方库。Dubbo 使用了官方库的同时,相比 gRPC 自行维护的 http 协议库维持了同一性能水准。 +* gRPC 库仅仅提供了 RPC 协议实现,需要你做很多额外工作为其引入服务治理能力。而 Dubbo 本身是不绑定协议的微服务开发框架,内置 HTTP/2 协议实现可以与 Dubbo 服务治理能力更好的衔接在一起。 + +### 实现简单 +Dubbo 框架实现专注在 Triple 协议自身,而对于底层的网络通信、HTTP/2 协议解析等选择依赖那些经过长期检验的网络库。比如 Dubbo Java 基于 Netty 构建,而 Dubbo Go 则是直接使用的 Go 官方 HTTP 库。 + +Dubbo 提供的 Triple 协议实现非常简单,对应 Dubbo 中的 Protocol 组件实现,你可以仅仅花一下午时间就搞清楚 Dubbo 协议的代码实现。 + +### 大规模生产环境检验 +自 Dubbo3 发布以来,Triple 协议已被广泛应用于阿里巴巴以及众多社区标杆企业,尤其是一些代理、网关互通场景。一方面 Triple 通过大规模生产实践被证实可靠稳定,另一方面 Triple 的简单、易于调试、不绑定 IDL 的设计也是其得到广泛应用的重要因素。 + +### 原生多协议支持 +当以 Dubbo 框架为服务端对外发布服务时,可以做到在同一端口原生支持 Triple、gRPC 和 HTTP/1 协议,这意味着你可以用多种形式访问 Dubbo 服务端发布的服务,所有请求形式最终都会被转发到相同的业务逻辑实现,这给你提供了更大的灵活性。 + +Dubbo 完全兼容 gRPC 协议及相关特性包括 streaming、trailers、error details 等,你选择直接在 Dubbo 框架中使用 Triple 协议(另外,你也可以选择使用原生的 gRPC 协议),然后你就可以直接使用 Dubbo 客户端、curl、浏览器等访问你发布的服务。在与 gRPC 生态互操作性方面,任何标准的 gRPC 客户端,都可以正常访问 Dubbo 服务;Dubbo 客户端也可以调用任何标准的 gRPC 服务,这里有提供的 [互操作性示例](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/interop) + +以下是使用 cURL 客户端访问 Dubbo 服务端 Triple 协议服务的示例: + +```sh +curl \ + --header "Content-Type: application/json" \ + --data '{"sentence": "Hello Dubbo."}' \ + https://host:port/org.apache.dubbo.sample.GreetService/sayHello +``` + +### 一站式服务治理接入 +我们都知道 Dubbo 有丰富的微服务治理能力,比如服务发现、负载均衡、流量管控等,这也是我们使用 Dubbo 框架开发应用的优势所在。要想在 Dubbo 体系下使用 gRPC 协议通信,有两种方式可以实现,一种是直接在 Dubbo 框架中引入 gRPC 官方发布的二进制包,另一种是在 Dubbo 内原生提供 gRPC 协议兼容的源码实现。 + +相比于第一种引入二进制依赖的方式,Dubbo 框架通过内置 Triple 协议实现的方式,原生支持了 gRPC 协议,这种方式的优势在于源码完全由自己掌控,因此协议的实现与 Dubbo 框架结合更为紧密,能够更灵活的接入 Dubbo 的服务治理体系。 + +### Java 语言 +在 Dubbo Java 库实现中,除了 IDL 方式外,你可以使用 Java Interface 方式定义服务,这对于众多熟悉 Dubbo 体系的 Java 用户来说,可以大大降低使用 gRPC 协议的成本。 + +另外,Java 版本的协议实现在性能上与 grpc-java 库基本持平,甚至某些场景下比 grpc-java 性能表现还要出色。而这一切还是建立在 Dubbo 版本协议的实现复杂度远小于 gRPC 版本的情况下,因为 grpc-java 维护了一套定制版本的 netty 协议实现。 + +### Go 语言实现 +Dubbo Go 推荐 IDL 开发模式,通过 Dubbo 配套的 protoc 插件生成 stub 代码,你只需要提供对应的业务逻辑实现即可,你可以通过 curl、浏览器访问 Dubbo Go 发布的 gRPC 服务。 + +## 后续规划 +当前我们已经提供了 Triple 协议的 Java、Go 语言版本,接下来我们计划陆续提供 Rust、Python、Node.js 等语言的对应实现。 + + diff --git a/content/en/overview/reference/setup/_index.md b/content/en/overview/reference/setup/_index.md new file mode 100755 index 000000000000..fdcb7aa4bbf2 --- /dev/null +++ b/content/en/overview/reference/setup/_index.md @@ -0,0 +1,11 @@ +--- +aliases: + - /zh/overview/reference/setup/ +description: 指导如何安装 Dubbo 控制面及依赖的相关服务治理组件。 +linkTitle: 安装 +no_list: true +title: 安装 +toc_hide: true +type: docs +weight: 50 +--- diff --git a/content/en/overview/reference/setup/install.md b/content/en/overview/reference/setup/install.md new file mode 100644 index 000000000000..2e9bd4d654b7 --- /dev/null +++ b/content/en/overview/reference/setup/install.md @@ -0,0 +1,209 @@ +--- +aliases: + - /zh/overview/reference/setup/install/ +description: Dubbo 控制面是微服务治理的核心依赖,本文档描述了如何快速安装 Dubbo Admin 控制面、控制台以及服务发现、监控等组件。 +linkTitle: 安装 Dubbo +title: 安装 Dubbo Admin 及服务治理组件 +toc_hide: true +type: docs +weight: 50 +--- + + +## Dubboctl 安装 +### Download +下载 Dubbo Admin 发行版本 +```shell +curl -L https://dubbo.apache.org/installer.sh | VERSION=0.1.0 sh - +# Admin 要组织好发行版本 +``` + +将 dubboctl 放入可执行路径 +```shell +ln -s dubbo-admin-0.1.0/bin/dubboctl /usr/local/bin/dubboctl +``` +### Install +安装过程会依次: + +1. 安装 Admin 自定义的一些资源 +2. 拉起 Admin、Nacos、Zookeeper 等不同的组件服务 +```shell +dubboctl install # 使用默认 manifests 安装 + +# or + +dubboctl manifests| kubectl apply -f - +``` + +```shell +dubboctl install --set profile=minimal # 指定不同的 profile,即安装组件的组合 +``` + +```shell +dubboctl install --set admin.nacos.enabled=true, admin.nacos.namespace=test +# 指定不同的覆盖参数 +``` + +检查安装效果 +```shell +kubectl get pod -n dubbo-system +``` + +### 打开 Admin 控制台 +```shell +kubectl port-forward svc/dubbo-admin -n dubbo-system 38080:38080 +``` + +打开浏览器,访问: `http://127.0.0.1:38080/` +## Helm 安装 +### 前置条件 + +- [Install the Helm client](https://helm.sh/docs/intro/install/), version 3.6 or above. +- Kubernetes 集群 +- 配置 helm repository +```shell +$ helm repo add dubbo https://dubbo.apache.org/charts +$ helm repo update +``` +### 安装步骤 +#### 安装方式一 +```shell +helm install dubbo-admin dubbo/dubbo-stack -n dubbo-system + +helm install dubbo-admin-nacos dubbo/dubbo-stack -n dubbo-system + +helm install dubbo-admin-zookeeper dubbo/dubbo-stack -n dubbo-system +``` + +```shell +helm install dubbo-admin-grafana dubbo/dubbo-stack -n dubbo-system + +helm install dubbo-admin-prometheus dubbo/dubbo-stack -n dubbo-system +``` +#### 安装方式二 +```shell +helm install dubbo-admin-all dubbo/dubbo-stack -n dubbo-system +``` + +> 引发的问题。需要明确哪些组件是保证生产可用的,哪些是仅作展示的,比如 nacos/zookeeper/admin 保障生产可用,prometheus/grafana 是仅作展示 +> 如果基于以上结论,则大部分情况下,dubbo-admin-all 是不推荐保生产安装的;更推荐使用类似 dubbo-admin-nacos 生产保障包,然后自己用 prometheus 社区的生产安装包 + + +检查安装状态 +```shell +helm ls -n dubbo-system + +kubectl get deployments -n dubbo-system --output wide +``` + +## VM 安装 +### Download +下载 Dubbo Admin 发行版本 +```shell +curl -L https://dubbo.apache.org/installer.sh | VERSION=0.1.0 sh - +# Admin 要组织好发行版本 +``` + +将 dubboctl 放入可执行路径 +```shell +ln -s dubbo-admin-0.1.0/bin/dubbo-admin /usr/local/bin/dubbo-admin +``` +### Run +```shell +dubbo-admin run -f override-configuration.yml +``` +### Configuration +配置用于控制 dubbo-admin 的行为 + + +```yaml +# Environment type. Available values are: "kubernetes" or "universal" +environment: universal # ENV: DUBBO_ENVIRONMENT +# Mode in which Dubbo CP is running. Available values are: "standalone", "global", "zone" +mode: standalone # ENV: DUBBO_MODE + +# Resource Store configuration +store: + # Type of Store used in the Control Plane. Available values are: "kubernetes", "postgres" or "memory" + type: memory # ENV: DUBBO_STORE_TYPE + + # Kubernetes Store configuration (used when store.type=kubernetes) + kubernetes: + # Namespace where Control Plane is installed to. + systemNamespace: dubbo-system # ENV: DUBBO_STORE_KUBERNETES_SYSTEM_NAMESPACE + + # Postgres Store configuration (used when store.type=postgres) + mysql: + # Host of the Postgres DB + host: 127.0.0.1 # ENV: DUBBO_STORE_POSTGRES_HOST + # Port of the Postgres DB + port: 15432 # ENV: DUBBO_STORE_POSTGRES_PORT + # User of the Postgres DB + user: dubbo # ENV: DUBBO_STORE_POSTGRES_USER + # Password of the Postgres DB + password: dubbo # ENV: DUBBO_STORE_POSTGRES_PASSWORD + # Database name of the Postgres DB + dbName: dubbo # ENV: DUBBO_STORE_POSTGRES_DB_NAME + # Connection Timeout to the DB in seconds + connectionTimeout: 5 # ENV: DUBBO_STORE_POSTGRES_CONNECTION_TIMEOUT + # Maximum number of open connections to the database + # `0` value means number of open connections is unlimited + maxOpenConnections: 50 # ENV: DUBBO_STORE_POSTGRES_MAX_OPEN_CONNECTIONS + # Maximum number of connections in the idle connection pool + # <0 value means no idle connections and 0 means default max idle connections + maxIdleConnections: 50 # ENV: DUBBO_STORE_POSTGRES_MAX_IDLE_CONNECTIONS + # TLS settings + tls: + # Mode of TLS connection. Available values are: "disable", "verifyNone", "verifyCa", "verifyFull" + mode: disable # ENV: DUBBO_STORE_POSTGRES_TLS_MODE + # Path to TLS Certificate of the client. Used in verifyCa and verifyFull modes + certPath: # ENV: DUBBO_STORE_POSTGRES_TLS_CERT_PATH + # Path to TLS Key of the client. Used in verifyCa and verifyFull modes + keyPath: # ENV: DUBBO_STORE_POSTGRES_TLS_KEY_PATH + # Path to the root certificate. Used in verifyCa and verifyFull modes. + caPath: # ENV: DUBBO_STORE_POSTGRES_TLS_ROOT_CERT_PATH + # MinReconnectInterval controls the duration to wait before trying to + # re-establish the database connection after connection loss. After each + # consecutive failure this interval is doubled, until MaxReconnectInterval + # is reached. Successfully completing the connection establishment procedure + # resets the interval back to MinReconnectInterval. + minReconnectInterval: "10s" # ENV: DUBBO_STORE_POSTGRES_MIN_RECONNECT_INTERVAL + # MaxReconnectInterval controls the maximum possible duration to wait before trying + # to re-establish the database connection after connection loss. + maxReconnectInterval: "60s" # ENV: DUBBO_STORE_POSTGRES_MAX_RECONNECT_INTERVAL +server: + port: 38080 +registry: + address: xxx +metadata-center: + address: xxx +config-center: + address: xxx +external-services: + prometheus: + # Prometheus service name is "metrics" and is in the "telemetry" namespace + # http://prometheus.:9090 + url: "http://metrics.telemetry:9090/" + tracing: + # Enabled by default. Kiali will anyway fallback to disabled if + # Jaeger is unreachable. + enabled: true + # Jaeger service name is "tracing" and is in the "telemetry" namespace. + # Make sure the URL you provide corresponds to the non-GRPC enabled endpoint + # if you set "use_grpc" to false. + in_cluster_url: 'http://tracing.telemetry:16685/jaeger' + use_grpc: true + # Public facing URL of Jaeger + url: 'http://my-jaeger-host/jaeger' + grafana: + enabled: true + # Grafana service name is "grafana" and is in the "telemetry" namespace. + in_cluster_url: 'http://grafana.telemetry:3000/' + # Public facing URL of Grafana + url: 'http://my-ingress-host/grafana' + +# 更多配置 +``` +### 打开 Admin 控制台 + +打开浏览器,访问: `http://127.0.0.1:38080/` \ No newline at end of file diff --git a/content/en/overview/tasks/_index.md b/content/en/overview/tasks/_index.md deleted file mode 100755 index 796599cf1dbc..000000000000 --- a/content/en/overview/tasks/_index.md +++ /dev/null @@ -1,11 +0,0 @@ - ---- -type: docs -title: "Tasks" -linkTitle: "Tasks" -description: "" -weight: 4 ---- - - - diff --git a/content/en/overview/tasks/ecosystem/_index.md b/content/en/overview/tasks/ecosystem/_index.md deleted file mode 100755 index b85bb1111cfd..000000000000 --- a/content/en/overview/tasks/ecosystem/_index.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -type: docs -title: "Microservice Governance" -linkTitle: "Microservice Governance" -description: "Demonstrate how to solve Dubbo microservice governance problems, such as transactions, full link tracking, current limiting and degradation, etc." -weight: 6 -no_list: true ---- - -{{< blocks/section color="white" height="auto">}} -
-
-
-
-
-

- Transaction Management -

-

This example demonstrates how to implement transaction management of distributed Dubbo services through Seata to ensure data consistency.

-
-
-
-
-
-
-

- rate limit downgrade -

-

Use Sentinel to protect your application from stability issues caused by sudden traffic overload of individual services.

-
-
-
-
-
-
-

-

http gateway access (document construction)

-

-

By converting the gateway http to dubbo protocol, the front-end traffic can be connected to the back-end dubbo service.

-
-
-
-
-
-
-

-

Spring Cloud system interoperability (document construction)

-

-

Demonstrates how to communicate with Spring Cloud's rest protocol through the Dubbo3 application-level service discovery mechanism.

-
-
-
-
-
-
- -{{< /blocks/section >}} \ No newline at end of file diff --git a/content/en/overview/tasks/ecosystem/rate-limit.md b/content/en/overview/tasks/ecosystem/rate-limit.md deleted file mode 100644 index dbf13d152120..000000000000 --- a/content/en/overview/tasks/ecosystem/rate-limit.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -type: docs -title: "Current Limit Downgrade" -linkTitle: "Current limit downgrade" -weight: 2 -description: "Use Sentinel to protect your application from stability issues caused by sudden traffic overload of individual services." ---- - -## What is Sentinel - -With the popularity of microservices, the stability between services and services has become more and more important. Sentinel is a traffic management component for distributed, multilingual and heterogeneous service architectures. It mainly uses traffic as the entry point, from traffic routing, traffic control, traffic shaping, fuse downgrade, system adaptive overload protection, hotspot traffic protection, etc. dimensions to help developers ensure the stability of microservices. - -## 1. Example architecture description - -Interface definition: - -```java -public interface FooService { - - String sayHello(String name); -} -``` - -Interface implementation: - -```java -@DubboService(timeout = 3000) -public class FooServiceImpl implements FooService { - - @Override - public String sayHello(String name) { - return String. format("Hello, %s at %s", name, LocalDateTime. now()); - } -} -``` - -Current limiting configuration: - -```java -FlowRule flowRule = new FlowRule(FooService. class. getName()) - .setCount(10) - .setGrade(RuleConstant.FLOW_GRADE_QPS); -FlowRuleManager. loadRules(Collections. singletonList(flowRule)); -``` - -## 2. Quick start example - -### Step 1: Download the source code - -```shell script -git clone -b master https://github.com/apache/dubbo-samples.git -cd ./dubbo-samples-sentinel/ -``` - -### Step 2: Build use cases - -Execute the maven command to package the demo project - -```bash -mvn clean package -``` - -### Step 3: Start Provider - -```java -java -classpath ./target/dubbo-samples-sentinel-1.0-SNAPSHOT.jar org.apache.samples.sentinel.FooProviderBootstrap -``` - -### Step 4: Start OrderService - -```java -java -classpath ./target/dubbo-samples-sentinel-1.0-SNAPSHOT.jar org.apache.samples.sentinel.FooConsumerBootstrap -``` - -You can see that in the console output, `Blocked` means that blocking has started. - -``` -Success: Hello, dubbo at 2022-08-08T15:42:40.809 -Success: Hello, dubbo at 2022-08-08T15:42:40.812 -Success: Hello, dubbo at 2022-08-08T15:42:40.815 -Success: Hello, dubbo at 2022-08-08T15:42:40.818 -Success: Hello, dubbo at 2022-08-08T15:42:40.821 -Success: Hello, dubbo at 2022-08-08T15:42:40.823 -Success: Hello, dubbo at 2022-08-08T15:42:40.826 -Success: Hello, dubbo at 2022-08-08T15:42:40.828 -Success: Hello, dubbo at 2022-08-08T15:42:40.830 -Success: Hello, dubbo at 2022-08-08T15:42:40.834 -Blocked -Blocked -Blocked -Blocked -Blocked -``` - -> For more usage methods of Sentinel, please refer to: [Sentinel escorts Dubbo services](/zh-cn/blog/2018/07/27/sentinel-为-dubbo-服务保驾护航/), [Sentinel official website](https://sentinelguard.io/zh-cn/index.html) \ No newline at end of file diff --git a/content/en/overview/tasks/ecosystem/transaction.md b/content/en/overview/tasks/ecosystem/transaction.md deleted file mode 100644 index 103fae9eb246..000000000000 --- a/content/en/overview/tasks/ecosystem/transaction.md +++ /dev/null @@ -1,307 +0,0 @@ ---- -type: docs -title: "Transaction Management" -linkTitle: "Transaction Management" -weight: 1 -description: "This example demonstrates how to implement transaction management of distributed Dubbo services through Seata to ensure data consistency." ---- - -## What is Seata -Seata is an open source distributed transaction solution dedicated to providing high-performance and easy-to-use distributed transaction services. Seata will provide users with AT, TCC, SAGA and XA transaction modes to create a one-stop distributed solution for users. - -## 1. Example architecture description -The user purchases commodity business, and the whole business includes 3 microservices: - -- Inventory service: deduction of the inventory quantity of a given item. -- Order service: Generate orders based on purchase requests. -- Account Services: deduction of the user account amount. - -![image.png](/imgs/docs3-v2/java-sdk/seata/transaction-1.png) - -### StorageService - -```java -public interface StorageService { - - /** - * Deducted storage quantity - */ - void deduct(String commodityCode, int count); -} -``` - -### OrderService - -```java -public interface OrderService { - - /** - * Create Order - */ - Order create(String userId, String commodityCode, int orderCount); -} -``` - -### AccountService - -```java -public interface AccountService { - - /** - * Borrow from user account - */ - void debit(String userId, int money); -} -``` - -## Two, the main business logic - -### BusinessService - -```java -public class BusinessServiceImpl implements BusinessService { - - private StorageService storageService; - - private OrderService orderService; - - /** - * Purchasing - */ - public void purchase(String userId, String commodityCode, int orderCount) { - // Deduct storage amount - storageService.deduct(commodityCode, orderCount); - // Create Order - orderService.create(userId, commodityCode, orderCount); - } -} -``` - -### StorageService - -```java -public class StorageServiceImpl implements StorageService { - - private JdbcTemplate jdbcTemplate; - - @Override - public void deduct(String commodityCode, int count) { - // Modify the database: deduct the amount of storage - jdbcTemplate.update("update storage_tbl set count = count - ? where commodity_code = ?", - new Object[]{count, commodityCode}); - } -} -``` - -### OrderService - -```java -public class OrderServiceImpl implements OrderService { - - private AccountService accountService; - - private JdbcTemplate jdbcTemplate; - - public Order create(String userId, String commodityCode, int orderCount) { - // calculate the amount - int orderMoney = calculate(commodityCode, orderCount); - - // The amount deducted from the user account - accountService.debit(userId, orderMoney); - - // Modify the database: create a new order - final Order order = new Order(); - order.userId = userId; - order.commodityCode = commodityCode; - order.count = orderCount; - order.money = orderMoney; - KeyHolder keyHolder = new GeneratedKeyHolder(); - jdbcTemplate. update(con -> { - PreparedStatement pst = con. prepareStatement( - "insert into order_tbl (user_id, commodity_code, count, money) values (?, ?, ?, ?)", - PreparedStatement. RETURN_GENERATED_KEYS); - pst.setObject(1, order.userId); - pst.setObject(2, order.commodityCode); - pst.setObject(3, order.count); - pst.setObject(4, order.money); - return pst; - }, keyHolder); - order.id = keyHolder.getKey().longValue(); - return order; - } -} -``` - -### AccountService - - -```java -public class AccountServiceImpl implements AccountService { - - private JdbcTemplate jdbcTemplate; - - @Override - public void debit(String userId, int money) { - // Modify the database: deduct the amount from the user account - jdbcTemplate.update("update account_tbl set money = money - ? where user_id = ?", new Object[]{money, userId}); - } -} -``` - -## 3. Quick start example - -### Step 1: Download the source code - -```shell script -git clone -b master https://github.com/apache/dubbo-samples.git -cd ./dubbo-samples-transaction/ -``` - -### Step 2: Start Seata-Server and MySQL through docker-compose - -In this example, we use docker-compose to quickly pull up services like seata-server and mysql. - -```bash -cd src/main/resources/docker -docker-compose up -``` - -### Step 3: Build use cases - -Execute the maven command to package the demo project - -```bash -mvn clean package -``` - -### Step 4: Start AccountService - -```java -java -classpath ./target/dubbo-samples-transaction-1.0-SNAPSHOT.jar org.apache.dubbo.samples.starter.DubboAccountServiceStarter -``` - -### Step 5: Start OrderService - -```java -java -classpath ./target/dubbo-samples-transaction-1.0-SNAPSHOT.jar org.apache.dubbo.samples.starter.DubboOrderServiceStarter -``` -### Step 6: Start StorageService - -```java -java -classpath ./target/dubbo-samples-transaction-1.0-SNAPSHOT.jar org.apache.dubbo.samples.starter.DubboStorageServiceStarter -``` - -### Step 7: Start BusinessService -```java -java -classpath ./target/dubbo-samples-transaction-1.0-SNAPSHOT.jar org.apache.dubbo.samples.starter.DubboBusinessTester -``` - -## 4. Example core process - -![image.png](/imgs/docs3-v2/java-sdk/seata/transaction-2.png) - -### Step 1: Modify the business code -Here only one line of annotation `@GlobalTransactional` is required to be written on the method of the business initiator: - -```java - @GlobalTransactional - public void purchase(String userId, String commodityCode, int orderCount) { -  … - } -``` - -### Step 2: Install the database - -- Requirements: MySQL (InnoDB storage engine). - -**Tips:** In fact, the 3 microservices in the example require 3 independent databases, but for convenience we use the same physical database and configure 3 logical connection strings. - -Change the database url, username and password in the following xml files - -dubbo-account-service.xml -dubbo-order-service.xml -dubbo-storage-service.xml - -```xml - - - -``` - -### Step 3: Create undo_log table for Seata - -`UNDO_LOG` This table is used in Seata's AT mode. - -```sql --- Note that when the Seata version is upgraded to 0.3.0+, the normal index will be changed to a unique index. -CREATE TABLE `undo_log` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT, - `branch_id` bigint(20) NOT NULL, - `xid` varchar(100) NOT NULL, - `context` varchar(128) NOT NULL, - `rollback_info` longblob NOT NULL, - `log_status` int(11) NOT NULL, - `log_created` datetime NOT NULL, - `log_modified` datetime NOT NULL, - `ext` varchar(100) DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; -``` - -### Step 4: Create related business tables - -```sql - -DROP TABLE IF EXISTS `storage_tbl`; -CREATE TABLE `storage_tbl` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `commodity_code` varchar(255) DEFAULT NULL, - `count` int(11) DEFAULT 0, - PRIMARY KEY (`id`), - UNIQUE KEY (`commodity_code`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `order_tbl`; -CREATE TABLE `order_tbl` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `user_id` varchar(255) DEFAULT NULL, - `commodity_code` varchar(255) DEFAULT NULL, - `count` int(11) DEFAULT 0, - `money` int(11) DEFAULT 0, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `account_tbl`; -CREATE TABLE `account_tbl` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `user_id` varchar(255) DEFAULT NULL, - `money` int(11) DEFAULT 0, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; -``` - -### Step 5: Start the Seata-Server service - -- Download the [server package](https://github.com/seata/seata/releases), unzip it. - -```shell -Usage: sh seata-server.sh(for linux and mac) or cmd seata-server.bat(for windows) [options] - Options: - --host, -h - The host to bind. - Default: 0.0.0.0 - --port, -p - The port to listen. - Default: 8091 - --storeMode, -m - log store mode: file, db - Default: file - --help - -e.g. - -sh seata-server.sh -p 8091 -h 127.0.0.1 -m file -``` \ No newline at end of file diff --git a/content/en/overview/tasks/extensibility/_index.md b/content/en/overview/tasks/extensibility/_index.md deleted file mode 100644 index 90ff6e9200ef..000000000000 --- a/content/en/overview/tasks/extensibility/_index.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -aliases: - - /en/overview/tasks/extensibility/ -description: Demonstrates how to use Dubbo's extensibility features. -linkTitle: Custom Extensions -no_list: true -title: Custom Extensions -type: docs -weight: 7 ---- - -## Dubbo's Extensibility Design Philosophy - -* Equality towards third-party implementations: In Dubbo, all internal and external implementations are treated equally. Users can replace Dubbo's native implementations based on their business requirements. -* Each extension point encapsulates only one variable factor for maximum reuse: The implementer of each extension point is often only concerned with one thing. If users need to extend functionality, they only need to extend the relevant extension points, significantly reducing the workload. - -## Java SPI-based Extensibility Design - -Dubbo's extensibility comes from an enhanced version of the JDK standard SPI (Service Provider Interface). It improves upon the following issues with the JDK's standard SPI: - -* The standard SPI instantiates all extension points at once, wasting resources if some are not used. -* If extension point loading fails, even the name of the extension point cannot be retrieved. - -Dubbo's extensibility features: - -* On-demand loading: Dubbo doesn't instantiate all implementations at once, reducing resource waste. -* IOC (Inversion of Control) capabilities: Dubbo not only discovers extension service implementation classes but also automatically injects dependent objects into the extension class. -* AOP (Aspect-Oriented Programming) capabilities: Dubbo automatically discovers wrapper classes for extensions, constructing them to enhance extension functionality. -* Dynamic extension selection: Dubbo dynamically chooses the corresponding extension class based on parameters at runtime. -* Extension implementation sorting: Users can specify the execution order of extension implementations. -* Adaptive extension points: Extensions can be made effective on either the consumer or provider side. - -### Extension Loading Process - -Dubbo's extension loading process is as follows: - -![//imgs/v3/concepts/extension-load.png](/imgs/v3/concepts/extension-load.png) - -The main steps are: - -* Read and parse the configuration file -* Cache all extension implementations -* Instantiate the corresponding extension implementation based on the user-executed extension name -* Perform IOC injection for extension instance attributes and instantiate extension wrapper classes for AOP features - -## Task Items - -Next, let's introduce Dubbo's extensibility features through the following task items. - -{{< blocks/section color="white" height="auto">}} -
-
-
-
-
-

- Custom Filters -

-

Dynamically load custom filters through the SPI mechanism to uniformly handle, validate returned results, and minimize developer interruptions.

-
-
-
-
-
-
-

- Custom Routing -

-

Customize routing strategies during service invocation based on actual use-cases to effectively improve service throughput and latency.

-
-
-
-
-
-
-

- Custom Protocols -

-

Use custom transport protocols for different heterogeneous systems to eliminate the differences between protocols and facilitate system integration.

-
-
-
-
-
-
-

- Custom Registry Centers -

-

Include services from different registry centers into the Dubbo ecosystem. Customizing registry centers is a key to bridging different service ecosystems.

-
-
-
-
-
-
- -{{< /blocks/section >}} - -Dubbo's extensibility design aims to provide users with a highly flexible extension mechanism, offering features like dynamic extension selection, IOC, and AOP. This makes it easier to adapt Dubbo to various scenarios and integrate it into different technology stacks. \ No newline at end of file diff --git a/content/en/overview/tasks/extensibility/filter.md b/content/en/overview/tasks/extensibility/filter.md deleted file mode 100644 index 540a3c498548..000000000000 --- a/content/en/overview/tasks/extensibility/filter.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -aliases: - - /en/overview/tasks/extensibility/ -description: Demonstrates how to use Dubbo extensibility features. -linkTitle: Custom extension -no_list: true -title: Custom extension -type: docs -weight: 7 ---- - diff --git a/content/en/overview/tasks/extensibility/protocol.md b/content/en/overview/tasks/extensibility/protocol.md deleted file mode 100644 index 34f73012b42d..000000000000 --- a/content/en/overview/tasks/extensibility/protocol.md +++ /dev/null @@ -1,278 +0,0 @@ ---- -aliases: - - /en/overview/tasks/extensibility/protocol/ -description: Custom Protocols -linkTitle: Protocol -no_list: true -title: Protocol -type: docs -weight: 2 ---- - -Dubbo has implemented a lot of built-in functionalities through protocol extensions and also supports many commonly used protocols. You can see all custom protocols in the `org.apache.dubbo.rpc.Protocol` file. For example, in Dubbo 3, we have: - -```properties -# Built-in functionalities implemented by Dubbo through protocol extension -filter=org.apache.dubbo.rpc.cluster.filter.ProtocolFilterWrapper -qos=org.apache.dubbo.qos.protocol.QosProtocolWrapper -registry=org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol -service-discovery-registry=org.apache.dubbo.registry.integration.RegistryProtocol -listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper -mock=org.apache.dubbo.rpc.support.MockProtocol -serializationwrapper=org.apache.dubbo.rpc.protocol.ProtocolSerializationWrapper -securitywrapper=org.apache.dubbo.rpc.protocol.ProtocolSecurityWrapper - -# Commonly used protocols supported by Dubbo -dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol -injvm=org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol -rest=org.apache.dubbo.rpc.protocol.rest.RestProtocol -grpc=org.apache.dubbo.rpc.protocol.grpc.GrpcProtocol -tri=org.apache.dubbo.rpc.protocol.tri.TripleProtocol -``` - -As you can see, Dubbo has implemented a series of functionalities like filtering, monitoring, service discovery, listeners, mock, serialization, and security through protocol extensions. It also supports `dubbo`, `injvm`, `rest`, `grpc`, and `tri` protocols for external use. - -There are two ways to customize a private protocol. The first is to wrap an existing protocol and add some specific business logic. The other is to fully customize a new protocol. The former is simpler and has extensive usage in Dubbo, like `ProtocolFilterWrapper`, `QosProtocolWrapper`, `ProtocolListenerWrapper`, etc. The latter is more complex, but Dubbo has implemented most of the commonly used protocols which are well-tested in production environments. - -This article will demonstrate how to implement a custom protocol based on an existing protocol. - -## Prerequisites - -Two deployment and running methods, choose one -### Based on Kubernetes -* Install [Kubernetes](https://kubernetes.io/docs/tasks/tools/) environment -* Modify the configuration file in [Provider](https://github.com/apache/dubbo-samples/blob/master/10-task/dubbo-samples-extensibility/dubbo-samples-extensibility-protocol-provider/src/main/resources/application.properties) to enable the address of nacos deployed in Kubernetes - ```properties - # Specify the application name of Dubbo - dubbo.application.name=extensibility-protocol-provider - - # Enable token verification for each invocation - dubbo.provider.token=true - - # Specify the registry address - # dubbo.registry.address=nacos://localhost:8848?username=nacos&password=nacos - dubbo.registry.address=nacos://${nacos.address:localhost}:8848?username=nacos&password=nacos - - # Custom protocol edubbo - dubbo.provider.protocol=edubbo - ``` - -* Modify the configuration file in [Consumer](https://github.com/apache/dubbo-samples/blob/master/10-task/dubbo-samples-extensibility/dubbo-samples-extensibility-protocol-consumer/src/main/resources/application.properties) to enable the address of nacos deployed in Kubernetes - ```properties - # Specify the application name of Dubbo - dubbo.application.name=extensibility-protocol-consumer - - # Enable token verification for each invocation - dubbo.provider.token=true - - # Specify the registry address - # dubbo.registry.address=nacos://localhost:8848?username=nacos&password=nacos - dubbo.registry.address=nacos://${nacos.address:localhost}:8848?username=nacos&password=nacos - - # Custom protocol edubbo - dubbo.consumer.protocol=edubbo - ``` -* Deploy `[Extensibility Protocol Task](https://github.com/apache/dubbo-samples/blob/master/10-task/dubbo-samples-extensibility/deploy/All.yml)` - -### Using Local IDE -* Deploy [Nacos](https://nacos.io/en-us/) version 2.2.0 -* Modify the configuration file in [Provider](https://github.com/apache/dubbo-samples/blob/master/10-task/dubbo-samples-extensibility/dubbo-samples-extensibility-protocol-provider/src/main/resources/application.properties) to enable the local nacos address - ```properties - # Specify the application name of Dubbo - dubbo.application.name=extensibility-protocol-provider - - # Enable token verification for each invocation - dubbo.provider.token=true - - # Specify the registry address - # Enable local nacos address - dubbo.registry.address=nacos://localhost:8848?username=nacos&password=nacos - - # Custom protocol edubbo - dubbo.provider.protocol=edubbo - ``` -* Modify the configuration file in [Consumer](https://github.com/apache/dubbo-samples/blob/master/10-task/dubbo-samples-extensibility/dubbo-samples-extensibility-protocol-consumer/src/main/resources/application.properties) to enable the local nacos address - ```properties - # Specify the application name of Dubbo - dubbo.application.name=extensibility-protocol-consumer - - # Enable token verification for each invocation - dubbo.provider.token=true - - # Specify the registry address - # Enable local nacos address - dubbo.registry.address=nacos://localhost:8848?username=nacos&password=nacos - - # Custom protocol edubbo - dubbo.consumer.protocol=edubbo - ``` - -## Task Details - -Implement a custom protocol `edubbo` based on the existing `dubbo` protocol. - -## Implementation Method - -Wrap the existing `dubbo` protocol to implement the `edubbo` protocol. - -#### Code Structure - -##### Common - -```properties -src - |-main - |-java - |-org - |-apache - |-dubbo - |-samples - |-extensibility - |-protocol - |-common - |-EnhancedProtocol.java (Implement Protocol interface) -``` - -##### Provider -```properties -src - |-main - |-java - |-org - |-apache - |-dubbo - |-samples - |-extensibility - |-protocol - |-provider - |-ExtensibilityProtocolProviderApplication.java - |-ExtensibilityProtocolServiceImpl.java - |-resources - |-META-INF - |-application.properties (Dubbo Provider configuration file) - |-dubbo - |-org.apache.dubbo.rpc.Protocol (Plain text file) -``` - -##### Consumer -```properties -src - |-main - |-java - |-org - |-apache - |-dubbo - |-samples - |-extensibility - |-protocol - |-consumer - |-ExtensibilityProtocolConsumerApplication.java - |-ExtensibilityProtocolConsumerTask.java - |-resources - |-META-INF - |-application.properties (Dubbo Consumer configuration file) - |-dubbo - |-org.apache.dubbo.rpc.Protocol ( - -Plain text file) -``` - -#### Code Details -```java -package org.apache.dubbo.samples.extensibility.protocol.common; - -import org.apache.dubbo.common.URL; -import org.apache.dubbo.rpc.Protocol; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.Exporter; -import org.apache.dubbo.rpc.ProtocolServer; -import org.apache.dubbo.rpc.RpcException; -import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol; - -import java.util.List; - -public class EnhancedProtocol implements Protocol { - - public EnhancedProtocol(FrameworkModel frameworkModel) { - this.protocol = new DubboProtocol(frameworkModel); - } - - private final Protocol protocol; - - @Override - public int getDefaultPort() { - return this.protocol.getDefaultPort(); - } - - @Override - public Exporter export(Invoker invoker) throws RpcException { - // do something - return this.protocol.export(invoker); - } - - @Override - public Invoker refer(Class type, URL url) throws RpcException { - // do something - return this.protocol.refer(type, url); - } - - @Override - public void destroy() { - this.protocol.destroy(); - } - - @Override - public List getServers() { - return protocol.getServers(); - } -} -``` - -#### SPI Configuration - -##### Provider - -Add the following configuration to the `resources/META-INF/dubbo/org.apache.dubbo.rpc.Protocol` file: -```properties -edubbo=org.apache.dubbo.samples.extensibility.protocol.common.EnhancedProtocol -``` - -##### Consumer - -Add the following configuration to the `resources/META-INF/dubbo/org.apache.dubbo.rpc.Protocol` file: -```properties -edubbo=org.apache.dubbo.samples.extensibility.protocol.common.EnhancedProtocol -``` - -#### Configuration File - -##### Provider - -Add the following configuration to the `resources/application.properties` file: -```properties -# Custom protocol -dubbo.provider.protocol=edubbo -``` - -##### Consumer - -Add the following configuration to the `resources/application.properties` file: -```properties -# Custom protocol -dubbo.consumer.protocol=edubbo -``` - -## Execution Results - -Run the task using the **Using Local IDE** method, and the results are as follows: - -#### Register Protocol - -![dubbo-samples-extensibility-protocol-output2.jpg](/imgs/v3/tasks/extensibility/dubbo-samples-extensibility-protocol-output2.jpg) - -#### Output Result - -![dubbo-samples-extensibility-protocol-output1.png](/imgs/v3/tasks/extensibility/dubbo-samples-extensibility-protocol-output1.png) - -In summary, Dubbo provides a powerful and flexible protocol extension mechanism. This tutorial demonstrates how to create a custom protocol `edubbo` based on the existing `dubbo` protocol, which allows users to add custom logic without changing the underlying architecture. \ No newline at end of file diff --git a/content/en/overview/tasks/extensibility/registry.md b/content/en/overview/tasks/extensibility/registry.md deleted file mode 100644 index bfc28d5fd74c..000000000000 --- a/content/en/overview/tasks/extensibility/registry.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -aliases: - - /en/overview/tasks/extensibility/registry/ -description: Customized registry -linkTitle: Registry -no_list: true -title: Registry -type: docs -weight: 3 ---- diff --git a/content/en/overview/tasks/kubernetes/_index.md b/content/en/overview/tasks/kubernetes/_index.md deleted file mode 100755 index ac88a582e0c9..000000000000 --- a/content/en/overview/tasks/kubernetes/_index.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -type: docs -title: "Kubernetes Deployment Solution" -linkTitle: "Kubernetes Deployment Solution" -description: "Demonstrate how to deploy Dubbo to Kubernetes and reuse Kubernetes Native Service." -weight: 2 -no_list: true ---- - -{{< blocks/section color="white" height="auto">}} -
-
-
-
-
-

- API-SERVER -

-

Use API-SERVER as the registration center, deploy Dubbo application to Kubernetes and reuse Kubernetes Native Service example

-
-
-
-
-
-
-

- Dubbo Mesh -

-

Through the Dubbo Control Plane, the details of service governance are shielded, while retaining the native ability to adapt to kubernetes, the decoupling of the data plane and kubernetes is realized from the architecture, and various problems caused by direct communication between the data plane and kubernetes are avoided.

For details, please refer to the Mesh solution section

-
-
-
-
-
-
- -{{< /blocks/section >}} \ No newline at end of file diff --git a/content/en/overview/tasks/mesh/_index.md b/content/en/overview/tasks/mesh/_index.md deleted file mode 100755 index 9f50664f02b3..000000000000 --- a/content/en/overview/tasks/mesh/_index.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -type: docs -title: "Mesh Deployment Solution" -linkTitle: "Mesh Deployment Solution" -description: "Demonstrates Dubbo Mesh solutions in various deployment forms, and how Dubbo Mesh helps users achieve smooth migration of architecture." -weight: 2 -no_list: true ---- - -{{< blocks/section color="white" height="auto">}} -
-
-
-
-
-

- Istio + Sidecar + Thin SDK -

-

Demonstration of Dubbo3's Sidecar Mesh form, which can fully access Istio's service governance capabilities. This solution limits Dubbo3 application-level service discovery.

-
-
-
-
-
-
-

- Istio + Proxyless -

-

The Dubbo3 Proxyless Mesh form without Sidecar can fully access the service management capability of Istio. This solution limits Dubbo3 application-level service discovery.

-
-
-
-
-
-
-

- -

Dubbo Control Plane + Thin SDK (document construction)

-

-

-
-
-
-
-
-
-

- -

Dubbo Control Plane + Proxyless (document construction)

-

-

-
-
-
- -
-
-
- -{{< /blocks/section >}} \ No newline at end of file diff --git a/content/en/overview/tasks/mesh/dubbo-mesh.md b/content/en/overview/tasks/mesh/dubbo-mesh.md deleted file mode 100644 index 271ff4894d91..000000000000 --- a/content/en/overview/tasks/mesh/dubbo-mesh.md +++ /dev/null @@ -1,301 +0,0 @@ ---- -type: docs -title: "Dubbo proxy mesh using Envoy & Istio" -linkTitle: "Sidecar mode" -weight: 1 -description: "This example demonstrates how to use Istio+Envoy's Service Mesh deployment mode to develop a Dubbo3 service. The Dubbo3 service uses Triple as the communication protocol. The communication process is intercepted by the Envoy data plane, and Dubbo is managed using the standard Istio traffic management capability." ---- - -By following the steps below, you can easily learn how to develop a Dubbo service that conforms to the Service Mesh architecture, deploy it to Kubernetes, and access Istio's traffic management system. Check here [Complete sample source code](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-mesh-k8s) - -## 1 Overall Objective - -* Deploy Dubbo application to Kubernetes -* Istio automatically injects Envoy and implements traffic interception -* Traffic governance based on Istio rules - -## 2 Basic process and working principle - -This example demonstrates how to deploy an application developed by Dubbo under the Istio system to realize Envoy's automatic proxying of Dubbo services. The overall architecture of the example is shown in the figure below. - -![thinsdk](/imgs/v3/mesh/thinsdk-envoy.png) - -The steps you will need to complete the example are as follows: - -1. Create a Dubbo application ( [dubbo-samples-mesh-k8s](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-mesh-k8s) ) -2. Build the container image and push it to the mirror warehouse ([the official image of this example](https://hub.docker.com/r/apache/dubbo-demo) ) -3. Deploy Dubbo Provider and Dubbo Consumer to Kubernetes respectively and verify that Envoy proxy injection is successful -4. Verify Envoy discovers the service address, normally intercepts RPC traffic and implements load balancing -5. Proportional traffic forwarding based on Istio VirtualService - -## 3 detailed steps - -### 3.1 Environmental requirements - -Please ensure that the following environment is installed locally to provide container runtime, Kubernetes cluster and access tools - -* [Docker](https://www.docker.com/get-started/) -* [Minikube](https://minikube.sigs.k8s.io/docs/start/) -* [Kubectl](https://kubernetes.io/docs/tasks/tools/) -* [Istio](https://istio.io/latest/docs/setup/getting-started/) -* [Kubens(optional)](https://github.com/ahmetb/kubectx) - -Start the local Kubernetes cluster with the following command - -```shell -minikube start -``` - -Check that the cluster is up and running with kubectl, and that kubectl is bound to the default local cluster - -```shell -kubectl cluster-info -``` - -### 3.2 Create an independent namespace and enable automatic injection - -Use the following command to create an independent Namespace `dubbo-demo` for the sample project, and enable sidecar automatic injection at the same time. - -```shell -# Initialize the namespace -kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/Namespace.yml - -# switch namespace -kubens dubbo-demo - -# dubbo-demo enable automatic injection -kubectl label namespace dubbo-demo istio-injection=enabled - -``` - -### 3.3 Deploy to Kubernetes - -#### 3.3.1 Deploy Provider - -```shell -# Deploy the Service -kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/provider/Service.yml - -# Deploy Deployment -kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/provider/Deployment.yml -``` - -The above command creates a Service named `dubbo-samples-mesh-provider`, note that the service name here is the same as the dubbo application name in the project. - -Then the Deployment deploys a 2-copy pod instance, and the Provider is started. - -You can check the startup log with the following command. - -```shell -# View pod list -kubectl get pods -l app=dubbo-samples-mesh-provider - -# View pod deployment logs -kubectl logs your-pod-id -``` - -At this time, there should be a dubbo provider container instance and an Envoy Sidecar container instance in the pod. - -#### 3.3.2 Deploy Consumer - -```shell -# Deploy the Service -kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/consumer/Service.yml - -# Deploy Deployment -kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/consumer/Deployment.yml -``` - -Deploying consumer and provider is the same, here also keep K8S Service and Dubbo consumer application name (in [dubbo.properties](https://github.com/apache/dubbo-samples/blob/master/3-extensions/registry //dubbo-samples-mesh-k8s/dubbo-samples-mesh-consumer/src/main/resources/spring/dubbo-consumer.properties) consistent: `dubbo.application.name=dubbo-samples-mesh- consumer`. - -> The provider service (application) name of consumption is also specified in the Dubbo Consumer service statement `@DubboReference(version = "1.0.0", providedBy = "dubbo-samples-mesh-provider", lazy = true)` - -### 3.4 Check the normal communication between Provider and Consumer - -After performing step 3.3, check the startup log to see that the consumer has completed consumption of the provider service. - -```shell -# View pod list -kubectl get pods -l app=dubbo-samples-mesh-consumer - -# View pod deployment logs -kubectl logs your-pod-id - -# View pod isitio-proxy logs -kubectl logs your-pod-id -c istio-proxy -``` - -You can see that the consumer pod log output is as follows (the Triple protocol is load balanced by the Envoy proxy): - -```bash -===================== dubbo invoke 0 end ====================== -[10/08/22 07:07:36:036 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello, service mesh, response from provider-v1: 172.18.96.22:50052, client: 172.18. 96.22, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" - -===================== dubbo invoke 1 end ====================== -[10/08/22 07:07:42:042 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello, service mesh, response from provider-v1: 172.18.96.18:50052, client: 172.18. 96.18, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" - -``` - -The consumer istio-proxy log output is as follows: - -```shell -[2022-07-15T05:35:14.418Z] "POST /org.apache.dubbo.samples.Greeter/greet HTTP/2" 200 -- via_upstream - "-" 19 160 2 1 "-" "-" "6b8a5a03-5783-98bf-9bee-f93ea6e3d68e" -"dubbo-samples-mesh-provider:50052" "172.17.0.4:50052" -outbound|50052||dubbo-samples-mesh-provider.dubbo-demo.svc.cluster.local 172.17.0.7:52768 10.101.172.129:50052 172.17.0.7:38488 - default -``` - -You can see the provider pod log output as follows: - -```shell -[10/08/22 07:08:47:047 UTC] tri-protocol-50052-thread-8 INFO impl.GreeterImpl: Server test dubbo tri mesh received greet request name: "service mesh" - -[10/08/22 07:08:57:057 UTC] tri-protocol-50052-thread-9 INFO impl.GreeterImpl: Server test dubbo tri mesh received greet request name: "service mesh" -``` - -The log output of provider istio-proxy is as follows: - -```shell -[2022-07-15T05:25:34.061Z] "POST /org.apache.dubbo.samples.Greeter/greet HTTP/2" 200 -- via_upstream - "-" 19 162 1 1 "-" "-" "201e6976-da10-96e1-8da7-ad032e58db47" -"dubbo-samples-mesh-provider:50052" "172.17.0.10:50052" - inbound|50052|| 127.0.0.6:47013 172.17.0.10:50052 172.17.0.7:60244 - outbound_.50052_._.dubbo-samples-mesh-provider.dubbo-demo.svc.cluster.local default -``` - -### 3.5 Traffic Governance - VirtualService implements proportional traffic forwarding - -Deploy the v2 version of the demo provider -```shell -kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/provider/Deployment-v2.yml -``` - -Set VirtualService and DestinationRule, and observe that traffic is directed to provider v1 and provider v2 respectively in a ratio of 4:1. -```shell -kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/3-extensions/registry/dubbo-samples-mesh-k8s/deploy/traffic/virtual-service.yml -``` - -From the log output of the consumer side, observe the traffic distribution effect as shown in the figure below: - -```java -===================== dubbo invoke 100 end ====================== -[10/08/22 07:15:58:058 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello, service mesh, response from provider-v1: 172.18.96.18:50052, client: 172.18. 96.18, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" - -===================== dubbo invoke 101 end ====================== -[10/08/22 07:16:03:003 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello, service mesh, response from provider-v1: 172.18.96.22:50052, client: 172.18. 96.22, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" - -===================== dubbo invoke 102 end ====================== -[10/08/22 07:16:08:008 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello, service mesh, response from provider-v1: 172.18.96.18:50052, client: 172.18. 96.18, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" - -===================== dubbo invoke 103 end ====================== -[10/08/22 07:16:13:013 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello, service mesh, response from provider-v2: 172.18.96.6:50052, client: 172.18. 96.6, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" - -===================== dubbo invoke 104 end ====================== -[10/08/22 07:16:18:018 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello, service mesh, response from provider-v1: 172.18.96.22:50052, client: 172.18. 96.22, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" - -===================== dubbo invoke 105 end ====================== -[10/08/22 07:16:24:024 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello, service mesh, response from provider-v1: 172.18.96.18:50052, client: 172.18. 96.18, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" - -===================== dubbo invoke 106 end ====================== -[10/08/22 07:16:29:029 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello, service mesh, response from provider-v1: 172.18.96.22:50052, client: 172.18. 96.22, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" - -===================== dubbo invoke 107 end ====================== -[10/08/22 07:16:34:034 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello, service mesh, response from provider-v1: 172.18.96.18:50052, client: 172.18. 96.18, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" - -===================== dubbo invoke 108 end ====================== -[10/08/22 07:16:39:039 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello, service mesh, response from provider-v1: 172.18.96.22:50052, client: 172.18. 96.22, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" - -===================== dubbo invoke 109 end ====================== -[10/08/22 07:16:44:044 UTC] main INFO action.GreetingServiceConsumer: consumer Unary reply <-message: "hello, service mesh, response from provider-v1: 172.18.96.18:50052, client: 172.18. 96.18, local: dubbo-samples-mesh-provider, remote: null, isProviderSide: true" - - -``` - -### 3.6 View dashboard - -See [How to start the dashboard](https://istio.io/latest/docs/setup/getting-started/#dashboard) on the Istio official website. - -## 4 Modified Example - -> 1. Modifying the example is not a necessary step, this section is for readers who want to adjust the code and see the deployment effect. -> 2. Note that the project source code storage path must be in English, otherwise protobuf compilation will fail. - -Modify Dubbo Provider configuration `dubbo-provider.properties` - -```properties -# provider -dubbo.application.name=dubbo-samples-mesh-provider -dubbo.application.metadataServicePort=20885 -dubbo.registry.address=N/A -dubbo.protocol.name=tri -dubbo.protocol.port=50052 -dubbo.application.qosEnable=true -# In order for the Kubernetes cluster to access the probe normally, it is necessary to enable QOS to allow remote access, which may bring security Risk, please carefully evaluate before opening -dubbo.application.qosAcceptForeignIp=true -``` - -Modify Dubbo Consumer configuration `dubbo-consumer.properties` - -```properties -# consumer -dubbo.application.name=dubbo-samples-mesh-consumer -dubbo.application.metadataServicePort=20885 -dubbo.registry.address=N/A -dubbo.protocol.name=tri -dubbo.protocol.port=20880 -dubbo.consumer.timeout=30000 -dubbo.application.qosEnable=true -# In order for the Kubernetes cluster to access the probe normally, it is necessary to enable QOS to allow remote access. This operation may bring security risks. Please evaluate it carefully before opening it -dubbo.application.qosAcceptForeignIp=true -# Flag to enable mesh sidecar proxy mode -dubbo.consumer.meshEnable=true -``` - -After completing the code modification, package the image through the Dockerfile provided by the project - -```shell -# Package and push the image -mvn compile jib:build -``` - -> The Jib plugin will automatically package and publish the image. Note that for local development, you need to change the docker registry organization apache/dubbo-demo in the jib plug-in configuration to an organization with your own authority (including dubboteam in other kubernetes manifests to ensure that kubernetes deploys your own customized image) , if you encounter jib plug-in authentication problems, please refer to [corresponding link](https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md#what-should-i-do-when-the- registry-responds-with-unauthorized) to configure docker registry authentication information. -> You can specify `mvn compile jib:build -Djib.to.auth.username=x -Djib.to.auth.password=x -Djib.from.auth.username=x -Djib.from.auth directly on the command line .username=x`, or use docker-credential-helper. - -## 5 Common commands - -```shell -# dump current Envoy configs -kubectl exec -it ${your pod id} -c istio-proxy curl http://127.0.0.1:15000/config_dump > config_dump - -# Enter the istio-proxy container -kubectl exec -it ${your pod id} -c istio-proxy -- /bin/bash - -# View container logs -kubectl logs ${your pod id} -n ${your namespace} - -kubectl logs ${your pod id} -n ${your namespace} -c istio-proxy - -# Enable automatic sidecar injection -kubectl label namespace ${your namespace} istio-injection=enabled --overwrite - -# Turn off automatic sidecar injection -kubectl label namespace ${your namespace} istio-injection=disabled --overwrite -``` - -## 6 Notes - -1. In the example, both the producer and the consumer belong to the same namespace; if you need to call a provider of a different namespace, you need to configure it as follows (**dubbo version>=3.1.2**): - -Annotation method: -```java - @DubboReference(providedBy = "istio-demo-dubbo-producer", providerPort = 20885, providerNamespace = "istio-demo") - -``` -xml way -```xml - -``` \ No newline at end of file diff --git a/content/en/overview/tasks/mesh/proxyless.md b/content/en/overview/tasks/mesh/proxyless.md deleted file mode 100644 index 8f1e71bf2359..000000000000 --- a/content/en/overview/tasks/mesh/proxyless.md +++ /dev/null @@ -1,270 +0,0 @@ ---- -type: docs -title: "Istio + Proxyless" -linkTitle: "Proxyless mode" -weight: 2 -description: "" ---- - -Proxyless mode means that Dubbo communicates directly with Istiod, and implements service discovery and service governance capabilities through the xDS protocol. -In this example, a simple example will be used to demonstrate how to use the Proxyless mode. - -[Sample Address](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-xds) - -## code structure - -This section mainly introduces the code structure of the example used in this article. By imitating the relevant configuration in this example and modifying the existing project code, the existing project can quickly run in Proxyless Mesh mode. - -### 1. Interface definition - -In order to make the example simple enough, a simple interface definition is used here, and only the parameters are spliced ​​to be returned. - -```java -public interface GreetingService { - String sayHello(String name); -} -``` - -### 2. Interface implementation - -```java -@DubboService(version = "1.0.0") -public class AnnotatedGreetingService implements GreetingService { - @Override - public String sayHello(String name) { - System.out.println("greeting service received: " + name); - return "hello, " + name + "! from host: " + NetUtils. getLocalHost(); - } -} -``` - -### 3. Client subscription method - -**Because the native xDS protocol cannot support the mapping from interface to application name, it is necessary to configure the `providedBy` parameter to mark which application this service comes from. ** - -In the future, we will realize automatic [service mapping](/en/docs3-v2/java-sdk/concepts-and-architecture/service-discovery/) relationship acquisition based on the control plane of Dubbo Mesh, and there will be no need for independent configuration parameters at that time. Dubbo can be run under the Mesh system, so stay tuned. - -```java -@Component("annotated Consumer") -public class GreetingServiceConsumer { - @DubboReference(version = "1.0.0", providedBy = "dubbo-samples-xds-provider") - private GreetingService greetingService; - public String doSayHello(String name) { - return greetingService.sayHello(name); - } -} -``` - -### 4. Server configuration - -The server configuration registration center is the address of istio, and the protocol is xds. - -We recommend configuring `protocol` to be the tri protocol (fully compatible with the grpc protocol) for a better experience in the istio system. - -In order to make Kubernetes aware of the state of the application, it is necessary to configure `qosAcceptForeignIp` parameter so that Kubernetes can obtain the correct application state, [alignment lifecycle](/en/docs3-v2/java-sdk/advanced-features-and-usage/ others/dubbo-kubernetes-probe/). - -```properties -dubbo.application.name=dubbo-samples-xds-provider -dubbo.application.metadataServicePort=20885 -dubbo.registry.address=xds://istiod.istio-system.svc:15012 -dubbo.protocol.name=tri -dubbo.protocol.port=50052 -dubbo.application.qosAcceptForeignIp=true -``` - -### 5. Client Configuration - -The client configuration registration center is the address of istio, and the protocol is xds. - -```properties -dubbo.application.name=dubbo-samples-xds-consumer -dubbo.application.metadataServicePort=20885 -dubbo.registry.address=xds://istiod.istio-system.svc:15012 -dubbo.application.qosAcceptForeignIp=true -``` - -## Quick start - -### Step 1: Build the Kubernetes environment - -Currently Dubbo only supports Mesh deployment in the Kubernetes environment, so you need to build the Kubernetes environment before running and starting this example. - -Build reference documents: - -> [minikube(https://kubernetes.io/zh-cn/docs/tutorials/hello-minikube/)](https://kubernetes.io/zh-cn/docs/tutorials/hello-minikube/) -> -> [kubeadm(https://kubernetes.io/zh-cn/docs/setup/production-environment/tools/)](https://kubernetes.io/zh-cn/docs/setup/production-environment/tools /) -> -> [k3s(https://k3s.io/)](https://k3s.io/) - -### Step 2: Build the Istio environment - -Build the Istio environment reference document: - -[Istio Installation Documentation (https://istio.io/latest/docs/setup/getting-started/)](https://istio.io/latest/docs/setup/getting-started/) - -Note: When installing Istio, you need to enable [first-party-jwt support](https://istio.io/latest/docs/ops/best-practices/security/#configure-third-party-service-account-tokens) (add the parameter `--set values.global.jwtPolicy=first-party-jwt` when using the `istioctl` tool to install)**, otherwise it will cause the problem of client authentication failure. - -Attached installation command reference: - -```bash -curl -L https://istio.io/downloadIstio | sh - -cd istio-1.xx.x -export PATH=$PWD/bin:$PATH -istioctl install --set profile=demo --set values.global.jwtPolicy=first-party-jwt -y -``` - -### Step 3: Pull the code and build - -```bash -git clone https://github.com/apache/dubbo-samples.git -cd dubbo-samples/dubbo-samples-xds -mvn clean package -DskipTests -``` - -### Step 4: Build the image - -Since Kubernetes adopts containerized deployment, the code needs to be packaged in a mirror before deployment. - -```bash -cd ./dubbo-samples-xds-provider/ -# dubbo-samples-xds/dubbo-samples-xds-provider/Dockerfile -docker build -t apache/dubbo-demo:dubbo-samples-xds-provider_0.0.1 . -cd ../dubbo-samples-xds-consumer/ -# dubbo-samples-xds/dubbo-samples-xds-consumer/Dockerfile -docker build -t apache/dubbo-demo:dubbo-samples-xds-consumer_0.0.1 . -cd ../ -``` - -### Step 5: Create namespace - -```bash -# Initialize the namespace -kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-xds/deploy/Namespace.yml - -# switch namespace -kubens dubbo-demo -``` - -### Step 6: Deploy the container - -```bash -cd ./dubbo-samples-xds-provider/src/main/resources/k8s -# dubbo-samples-xds/dubbo-samples-xds-provider/src/main/resources/k8s/Deployment.yml -# dubbo-samples-xds/dubbo-samples-xds-provider/src/main/resources/k8s/Service.yml -kubectl apply -f Deployment.yml -kubectl apply -f Service.yml -cd ../../../../../dubbo-samples-xds-consumer/src/main/resources/k8s -# dubbo-samples-xds/dubbo-samples-xds-consumer/src/main/resources/k8s/Deployment.yml -kubectl apply -f Deployment.yml -cd ../../../../../ -``` - -Looking at the log of the consumer, you can observe the following log: -``` -result: hello, xDS Consumer! from host: 172.17.0.5 -result: hello, xDS Consumer! from host: 172.17.0.5 -result: hello, xDS Consumer! from host: 172.17.0.6 -result: hello, xDS Consumer! from host: 172.17.0.6 -``` - -## common problem - -1. Configure a separate Istio cluster `clusterId` - -Usually the `clusterId` of Istio under the Kubernetes system is `Kubernetes`, if you are using a self-built istio production cluster or a cluster provided by a cloud vendor, you may need to configure `clusterId`. - -Configuration method: Specify the `ISTIO_META_CLUSTER_ID` environment variable as the desired `clusterId`. - -Reference configuration: -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: dubbo-samples-xds-consumer -spec: - selector: - matchLabels: - demo: consumer - replicas: 2 - template: - metadata: - labels: - demo: consumer - spec: - containers: - - env: - - name: ISTIO_META_CLUSTER_ID - value: Kubernetes - name: dubbo-samples-xds-provider - image: xxx -``` - -How to get `clusterId`: -> kubectl describe pod -n istio-system istiod-58b4f65df9-fq2ks -> Read the value of `CLUSTER_ID` in the environment variable - -2. Istio authentication failed - -Since the current Dubbo version does not support istio's `third-party-jwt` authentication, it is necessary to configure `jwtPolicy` to `first-party-jwt`. - -3. providedBy - -Since the current Dubbo version is limited by the communication model of istio and cannot obtain the application name corresponding to the interface, it is necessary to configure the `providedBy` parameter to mark which application the service comes from. -In the future, we will realize automatic [service mapping](/en/docs3-v2/java-sdk/concepts-and-architecture/service-discovery/) relationship acquisition based on the control plane of Dubbo Mesh, and there will be no need for independent configuration parameters at that time. Dubbo can be run under the Mesh system, so stay tuned. - -4. protocol name - -In Proxyless mode, application-level service discovery uses `Kubernetes Native Service` for application service discovery, but due to the limitation of istio, it currently only supports traffic interception and forwarding of `http` protocol and `grpc` protocol, so `Kubernetes Service` is configured in When you need to specify the `spec.ports.name` property to start with `http` or `grpc`. -Therefore we recommend using the triple protocol (fully compatible with the grpc protocol). Here, even if `name` is configured to start with `grpc`, it is actually a `dubbo` protocol that can also perform normal service discovery, but it affects the function of traffic routing. - -Reference configuration: -```yaml -apiVersion: v1 -kind: Service -metadata: - name: dubbo-samples-xds-provider -spec: - clusterIP: None - selector: - demo: provider - ports: - - name: grpc-tri - protocol: TCP - port: 50052 - targetPort: 50052 -``` - -5. metadataServicePort - -Since the metadata discovered by Dubbo 3 application-level services cannot be obtained from istio, it is necessary to use the service introspection mode. This requires that the port of `Dubbo MetadataService` is unified in the whole cluster. - -Reference configuration: -```properties -dubbo.application.metadataServicePort=20885 -``` - -In the future, we will realize automatic acquisition of [service metadata](/en/docs3-v2/java-sdk/concepts-and-architecture/service-discovery/) based on the control plane of Dubbo Mesh, and no independent configuration parameters will be required at that time. Dubbo can be run under the Mesh system, so stay tuned. - -6. qosAcceptForeignIp - -Due to the limitations of the working principle of the Kubernetes probe detection mechanism, the originator of the detection request is not `localhost`, so you need to configure the `qosAcceptForeignIp` parameter to enable global access. - -```properties -dubbo.application.qosAcceptForeignIp=true -``` - -Note: There are dangerous commands on the qos port, please evaluate the security of the network first. Even if the qos is not open, it only affects the inability of Kubernetes to obtain the life cycle status of Dubbo. - -7. Do not need to enable injection - -In Proxyless mode, the pod does not need to enable envoy injection. Please make sure that there is no `istio-injection=enabled` label in the namespace. - -8. Plain text connection istiod - -In Proxyless mode, connect to istiod through ssl by default, and also support connecting to istiod through clear text. - -Plain text connection reference configuration: -```properties -dubbo.registry.secure=plaintext -``` diff --git a/content/en/overview/tasks/migration/2to3.md b/content/en/overview/tasks/migration/2to3.md deleted file mode 100644 index 25d758212b5d..000000000000 --- a/content/en/overview/tasks/migration/2to3.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -type: docs -title: "Upgrade to Dubbo3" -linkTitle: "Upgrade to Dubbo3" -weight: 1 -description: "Quickly understand the upgrade steps and compatibility of Dubbo 3" ---- - -** Upgrade directly to Dubbo 3.0 without changing any code. ** - -At the beginning of the design and development of version 3.0, we set the goal of being compatible with older versions of Dubbo users (2.5, 2.6, 2.7). Therefore, the upgrade process to version 3.0 will be completely transparent, users do not need to do any business transformation, and the behavior of the framework after upgrading to version 3.x will remain completely consistent with version 2.x. - -```xml - - org.apache.dubbo - dubbo - 3.0.10 - -``` - - -But also note that the transparent upgrade is only the first step towards 3.0, because "consistent framework behavior" means that users will not be able to experience the new features of 3.0. **If you want to enable the new features brought by 3.0, users need to make some modifications. We call this process migration, which is an on-demand process. ** - - - -Therefore, for legacy users, there are two different migration paths: - -* **In two steps, first promote business upgrade to version 3.0 in compatibility mode (no modification required), and then enable new features on demand at certain times (modification on demand);** -* **The upgrade and migration are completed synchronously. When the business is upgraded to version 3.0, the transformation is completed and new features are enabled;** - - - -The new features provided by Dubbo 3.0 include: - -* ** New address discovery model (application-level service discovery). ** - * See [Application-Level Service Discovery Migration Samples](/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/). - * See [Migration steps for application-level service discovery](/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery/) - * See [Description of application-level service discovery address migration rules](/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) -* **The next generation of the HTTP/2-based Triple protocol. ** - * See [Triple Protocol Migration Steps](/en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/) - * See [Triple protocol usage](/en/docs3-v2/java-sdk/reference-manual/protocol/triple/guide/) - * See [Triple Protocol Design and Implementation](/en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/). -* **Unified routing rules. ** - * See [Design and Implementation of Unified Routing Rules](/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/) \ No newline at end of file diff --git a/content/en/overview/tasks/migration/_index.md b/content/en/overview/tasks/migration/_index.md deleted file mode 100755 index e418c7082649..000000000000 --- a/content/en/overview/tasks/migration/_index.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -type: docs -title: "How to smoothly migrate to the new functions of Dubbo3" -linkTitle: "Migrate to Dubbo3" -description: "Demonstrate how to migrate to Dubbo3 with minimal cost and enable various new features." -weight: 5 -no_list: true ---- - -{{< blocks/section color="white" height="auto">}} -
-
-
-
-
-

- Smooth upgrade to Dubbo3 -

-

Smoothly upgrade to Dubbo3 version.

-
-
-
-
-
-
-

- Migrate to Dubbo3 application-level service discovery -

-

Migrate to Dubbo3 application-level service discovery.

-
-
-
-
-
-
-

- Migrate to Triple Protocol -

-

Migrate to Dubbo3 Triple protocol

-
-
-
-
-
-
- -{{< /blocks/section >}} \ No newline at end of file diff --git a/content/en/overview/tasks/migration/migration-triple.md b/content/en/overview/tasks/migration/migration-triple.md deleted file mode 100644 index d3474234d2e2..000000000000 --- a/content/en/overview/tasks/migration/migration-triple.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -type: docs -linkTitle: "Triple Protocol" -title: "Guide to Migrating Dubbo Protocol to Triple Protocol" -weight: 2 -description: "Triple Protocol Migration Guide" ---- - -## Triple Introduction - -For the format and principle of the `Triple` protocol, please refer to [RPC Communication Protocol](/en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/) - -According to the goals of Triple design, the `Triple` protocol has the following advantages: - -- Capable of cross-language interaction. Both the traditional multi-language and multi-SDK mode and the Mesh cross-language mode require a more general and scalable data transmission protocol. -- Provide a more complete request model. In addition to supporting the traditional Request/Response model (Unary one-way communication), it also supports Stream (streaming communication) and Bidirectional (two-way communication). -- Easy to expand, high penetration, including but not limited to Tracing / Monitoring and other support, should also be recognized by devices at all levels, gateway facilities, etc. can identify data packets, friendly to Service Mesh deployment, and reduce the difficulty of understanding for users. -- Fully compatible with grpc, the client/server can communicate with the native grpc client. -- Components in the existing grpc ecosystem can be reused to meet cross-language, cross-environment, and cross-platform intercommunication requirements in cloud-native scenarios. - -For Dubbo users currently using other protocols, the framework provides migration capabilities compatible with existing serialization methods. Without affecting existing online businesses, the cost of migrating protocols is almost zero. - -Dubbo users who need to add new connection to Grpc service can directly use the Triple protocol to achieve the connection, and do not need to introduce the grpc client separately to complete it. Not only can the existing Dubbo ease of use be retained, but also the complexity of the program and the development and maintenance can be reduced. Cost, it can be connected to the existing ecology without additional adaptation and development. - -For Dubbo users who need gateway access, the Triple protocol provides a more native way to make gateway development or use open source grpc gateway components easier. The gateway can choose not to parse the payload, which greatly improves the performance. When using the Dubbo protocol, the language-related serialization method is a big pain point for the gateway, and the traditional HTTP-to-Dubbo method is almost powerless for cross-language serialization. At the same time, since Triple's protocol metadata is stored in the request header, the gateway can easily implement customized requirements, such as routing and current limiting. - - -## Dubbo2 protocol migration process - -Dubbo2 users use dubbo protocol + custom serialization, such as hessian2 to complete remote calls. - -By default, Grpc only supports Protobuf serialization, and it cannot support multi-parameter and method overloading in the Java language. - -At the beginning of Dubbo3, one goal was to be perfectly compatible with Dubbo2. Therefore, in order to ensure the smooth upgrade of Dubbo2, the Dubbo framework has done a lot of work to ensure that the upgrade is seamless. Currently, the default serialization is consistent with Dubbo2 as `hessian2`. - -**So, if you decide to upgrade to Dubbo3's `Triple` protocol, you only need to modify the protocol name in the configuration to `tri` (note: not triple). ** - -For more instructions on using the `Triple` protocol, please refer to [Triple Protocol Migration Guide](/en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/). \ No newline at end of file diff --git a/content/en/overview/tasks/migration/service-discovery-samples.md b/content/en/overview/tasks/migration/service-discovery-samples.md deleted file mode 100644 index 66e0e2baebca..000000000000 --- a/content/en/overview/tasks/migration/service-discovery-samples.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -type: docs -title: "Dubbo3 application-level service discovery" -linkTitle: "Application-Level Service Discovery" -weight: 5 -description: "This article specifically explains how users can quickly enable new features of application-level service discovery after upgrading to Dubbo 3.0." ---- - -Application-level service discovery is a protocol for service discovery between applications. Therefore, to use application-level service discovery, both the consumer and the server must be upgraded to Dubbo 3.0 and new features enabled (enabled by default) to use application-level service discovery in the link. Take advantage of application-level service discovery. -## Open method -## Server -After the application is upgraded to Dubbo 3.0, the server will automatically enable the interface-level + application-level dual registration function, and the developer does not need to modify any configuration by default - -### Consumer side -After the application is upgraded to Dubbo 3.0, the consumer side automatically starts the interface-level + application-level dual subscription function, and the developer does not need to modify any configuration by default. It is recommended that after the server is upgraded to Dubbo 3.0 and the application-level registration is enabled, configure the consumer end to close the interface-level subscription through rules to release the corresponding memory space. - -## Detailed description -### Server configuration - -1. Global switch - -Application configuration (can be specified by configuration file or -D) `dubbo.application.register-mode` enables the global registration switch for instance (only register application level) and all (both interface level and application level registration). After configuring this switch , by default, application-level addresses will be registered with all registries for service discovery on the consumer side. -> Example: [https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-cloud-native/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-provider2/src/main/resources/ dubbo.properties](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-provider2/src /main/resources/dubbo.properties) - -``` -# double registration -dubbo.application.register-mode=all -``` -``` -# Application-level registration only -dubbo.application.register-mode=instance -``` - -2. Registration center address parameter configuration - -Registry-type=service can be configured on the address of the registry to display the registry that specifies the registry as application-level service discovery, and the registry with this configuration will only perform application-level service discovery. -> Example: [https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-cloud-native/dubbo-demo-servicediscovery-xml/servicediscovery-provider/src/main/resources/spring/ dubbo-provider.xml](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-demo-servicediscovery-xml/servicediscovery-provider/src /main/resources/spring/dubbo-provider.xml) - -```xml - -``` -### Consumer Subscription Mode - -FORCE_INTERFACE: only interface-level subscription, the behavior is consistent with Dubbo 2.7 and previous versions. -APPLICATION_FIRST: interface level + application level multi-subscription, if the application level can subscribe to the address, use the application level subscription, if the address cannot be subscribed, use the interface level subscription, so as to ensure the greatest compatibility during the migration process. (Note: Due to the simultaneous subscription behavior, the memory usage in this mode will increase to a certain extent, so after all servers are upgraded to Dubbo 3.0, it is recommended to migrate to FORCE_APPLICATION mode to reduce memory usage) -FORCE_APPLICATION: Only application-level subscriptions will only use the new service discovery model. - -### Consumer configuration - -1. Default configuration (no configuration required) - -After upgrading to Dubbo 3.0, the default behavior is interface-level + application-level multi-subscription. If the address can be subscribed at the application level, the application-level subscription will be used. If the address cannot be subscribed, the interface-level subscription will be used to ensure maximum compatibility. - -2. Subscription parameter configuration - -Application configuration (can be specified by configuration file or -D) `dubbo.application.service-discovery.migration` is `APPLICATION_FIRST` to enable multi-subscription mode, and configuration to `FORCE_APPLICATION` can force application-level subscription mode only. -The specific interface subscription can be configured in `parameters` in `ReferenceConfig`, and the Key is `migration.step`, and the Value is `APPLICATION_FIRST` or `FORCE_APPLICATION` key-value pair to configure a single subscription. -> Example: [https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-cloud-native/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-consumer/src/test/java/ org/apache/dubbo/demo/consumer/DemoServiceConfigIT.java](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration /dubbo-servicediscovery-migration-consumer/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConfigIT.java) - -```java -System.setProperty("dubbo.application.service-discovery.migration", "APPLICATION_FIRST"); -``` -```java -ReferenceConfig referenceConfig = new ReferenceConfig<>(applicationModel. newModule()); -referenceConfig.setInterface(DemoService.class); -referenceConfig.setParameters(new HashMap<>()); -referenceConfig.getParameters().put("migration.step", mode); -return referenceConfig.get(); -``` - -3. Dynamic configuration (highest priority, configuration can be modified at runtime) - -This configuration needs to be pushed based on the configuration center, the Key is the application name + `.migration` (such as `demo-application.migraion`), and the Group is `DUBBO_SERVICEDISCOVERY_MIGRATION`. For details on rule body configuration, see [Guidelines for migrating from interface-level service discovery to application-level service discovery](/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/). -> Example: [https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-cloud-native/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-consumer/src/main/java/ org/apache/dubbo/demo/consumer/UpgradeUtil.java](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration /dubbo-servicediscovery-migration-consumer/src/main/java/org/apache/dubbo/demo/consumer/UpgradeUtil.java) - -```java -step: FORCE_INTERFACE -``` diff --git a/content/en/overview/tasks/traffic-management/_index.md b/content/en/overview/tasks/traffic-management/_index.md deleted file mode 100755 index fae717134ab3..000000000000 --- a/content/en/overview/tasks/traffic-management/_index.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -type: docs -title: "Traffic Management" -linkTitle: "Traffic Governance" -description: "Demonstrates how to use Dubbo's traffic management feature." -weight: 1 -no_list: true ---- - -{{< blocks/section color="white" height="auto">}} -
-
-
-
-
-

- Dynamically adjust request timeout -

-

Setting a timeout period for Dubbo requests can effectively improve system stability and prevent individual services from being blocked and occupying too many resources.

By dynamically adjusting the service timeout period during the running period, it can effectively deal with problems such as frequent service timeouts and service blocking caused by unreasonable timeout settings and system emergencies, and improve system stability.

-
-
-
-
-
-
-

- Adjust traffic distribution by weight -

-

Adjust traffic distribution by weight

-
-
-
-
-
-
-

- Temporarily kick the service instance -

-

Temporarily kick the service instance

-
-
-
-
-
-
-

- traffic grayscale -

-

According to the tags in the request context, the traffic is restricted and the grayscale release

-
-
-
-
-
-
-

- Routing according to request conditions -

-

Routing according to the request initiator and method condition

-
-
-
-
-
-
-

- Traffic isolation -

-

Isolate service traffic in different environments to ensure that services are not affected by each other

-
-
-
-
-
-
-

- Same computer room/zone priority -

-

When an application invokes a service, it preferentially invokes the service provider in the same computer room/area.

-
-
-
-
-
-
- -{{< /blocks/section >}} \ No newline at end of file diff --git a/content/en/overview/tasks/traffic-management/isolation.md b/content/en/overview/tasks/traffic-management/isolation.md deleted file mode 100644 index c5e9a7943307..000000000000 --- a/content/en/overview/tasks/traffic-management/isolation.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -type: docs -title: "Temporarily kick out the problem service instance" -linkTitle: "Temporarily kick out the problem service instance" -weight: 5 -description: "Temporarily kick out problematic service instances in Dubbo-Admin" ---- - - -Dubbo provides the service management capability of temporarily removing problematic service instances, which can temporarily remove problematic service instances without restarting the application. - -Dubbo can temporarily remove problem service instances through XML configuration, annotation configuration, and dynamic configuration. Here we mainly introduce the dynamic configuration method. For other configuration methods, please refer to the old document [Configuration](/zh-cn/docsv2.7/user/configuration/) - - -## before the start - -Please make sure to run Dubbo-Admin successfully - -## Background Information - -When the service is running online, it is inevitable that some nodes have problems. In order not to affect the normal operation of the overall service, the service instance with the problem needs to be temporarily offline. Dubbo-Admin provides the ability to temporarily remove problematic service instances, which can help you temporarily offline problematic service instances without affecting the operation of the overall service. - - - -## Steps - -### Dynamic configuration - -1. Log in to the Dubbo-Admin console -2. In the left navigation pane, select Service Governance > Dynamic Configuration. -3. Click the Create button, fill in the rule content in the create dynamic configuration panel, and click Save. - - - -#### Detailed Rules - -##### Configuration template - -```yaml ---- -configVersion: v2.7 -scope: application/service -key: app-name/group+service+version -enabled: true -configs: -- addresses: ["0.0.0.0"] - providerAddresses: ["1.1.1.1:20880", "2.2.2.2:20881"] - side: consumer - applications/services: [] - parameters: - timeout: 1000 - loadbalance: random -- addresses: ["0.0.0.0:20880"] - side: provider - applications/services: [] - parameters: - threadpool: fixed - threads: 200 - iothreads: 4 - dispatcher: all - weight: 200 -... -``` - -**For the scenario of temporarily kicking out problematic service instances, you only need to clarify the following issues to know how to write the configuration:** - -1. Whether you want to modify the configuration of the entire application or a service. - - Application: `scope: application, key: app-name` (you can also use `services` to specify certain services). - - Service: `scope: service, key:group+service+version`. -2. The modification is applied to the provider side. - - Provider: `side: provider`. -3. Whether the configuration takes effect only for certain specific instances. - - All instances: `addresses: ["0.0.0.0"]` or `addresses: ["0.0.0.0:*"]` depends on the side value. - - Specified instances: `addersses[list of instance addresses]`. -4. The disabled parameter to be modified. - -## Result validation -Select the application related to the temporary removal of the problematic service instance configuration to trigger the call verification. \ No newline at end of file diff --git a/content/en/overview/tasks/traffic-management/timeout.md b/content/en/overview/tasks/traffic-management/timeout.md deleted file mode 100644 index bb28ae46159b..000000000000 --- a/content/en/overview/tasks/traffic-management/timeout.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -type: docs -title: "Dynamic adjustment of service timeout" -linkTitle: "Dynamic adjustment of service timeout" -weight: 5 -description: "Dynamic adjustment of service timeout in Dubbo-Admin" ---- - - - -Dubbo provides the service governance capability of dynamically adjusting the timeout period, which can dynamically adjust the service timeout period without restarting the application. - -Dubbo can dynamically adjust the timeout time through XML configuration, annotation configuration, and dynamic configuration. Here we mainly introduce the dynamic configuration method. For other configuration methods, please refer to the old document [Configuration](/zh-cn/docsv2.7/user/configuration/) - -## before the start - -Please make sure to run Dubbo-Admin successfully - -## Background Information - -Various timeout configurations are encountered in daily work. After the business logic is changed, the existing call relationship may need to be adjusted continuously with the development of the business, and the change of the response time of the corresponding service interface may not be determined until it goes online. Dubbo-Admin provides a dynamic timeout configuration capability, which can help you quickly and dynamically adjust the interface timeout time to improve service availability. - - - -## Steps - -### Dynamic configuration - -1. Log in to the Dubbo-Admin console -2. In the left navigation pane, select Service Governance > Dynamic Configuration. -3. Click the Create button, fill in the rule content in the create dynamic configuration panel, and click Save. - - - -#### Detailed Rules - -##### Configuration template - -```yaml ---- -configVersion: v2.7 -scope: application/service -key: app-name/group+service+version -enabled: true -configs: -- addresses: ["0.0.0.0"] - providerAddresses: ["1.1.1.1:20880", "2.2.2.2:20881"] - side: consumer - applications/services: [] - parameters: - timeout: 1000 - loadbalance: random -- addresses: ["0.0.0.0:20880"] - side: provider - applications/services: [] - parameters: - threadpool: fixed - threads: 200 - iothreads: 4 - dispatcher: all - weight: 200 -... -``` - -**For the scenario of dynamically adjusting the timeout time, you only need to clarify the following issues to know how to write the configuration:** - -1. Whether you want to modify the configuration of the entire application or a service. - - Application: `scope: application, key: app-name` (you can also use `services` to specify certain services). - - Service: `scope: service, key:group+service+version`. -2. Whether the modification is applied to the consumer or the provider. - - Consumer: `side: consumer`, when acting on the consumer side, you can further use `providerAddress`, `applications` to select a specific provider example or application, if you configure the consumer and provider at the same time, the consumer will override provider. - - Provider: `side: provider`. -3. Whether the configuration takes effect only for certain specific instances. - - All instances: `addresses: ["0.0.0.0"]` or `addresses: ["0.0.0.0:*"]` depends on the side value. - - Specified instances: `addersses[list of instance addresses]`. -4. The timeout period to be modified. - -## Result validation -Select the application related to the timeout configuration to trigger the call verification. \ No newline at end of file diff --git a/content/en/overview/tasks/traffic-management/traffic-condition.md b/content/en/overview/tasks/traffic-management/traffic-condition.md deleted file mode 100644 index 28d067fa75c0..000000000000 --- a/content/en/overview/tasks/traffic-management/traffic-condition.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -type: docs -title: "Traffic Isolation" -linkTitle: "Traffic Isolation" -weight: 5 -description: "Dynamic traffic isolation in Dubbo-Admin" ---- - -Dubbo provides the service management capability of dynamic traffic isolation, which can dynamically isolate traffic without restarting the application. - -Dubbo can implement traffic isolation through XML configuration, annotation configuration, and dynamic configuration. Here we mainly introduce the dynamic configuration method. For other configuration methods, please refer to the old document [Configuration](/zh-cn/docsv2.7/user/configuration/) - -## before the start - -Please make sure to run Dubbo-Admin successfully - -## Background Information - -If multiple versions of an application run simultaneously online and are deployed in different environments, such as daily environments and special environments, you can use label routing to isolate the traffic of different versions in different environments, and the order traffic of flash sales or orders from different channels Routing to special environments, routing normal traffic to everyday environments. Even if the special environment is abnormal, the traffic that should have entered the special environment will not enter the daily environment, and will not affect the use of the daily environment. - - -## Steps - -### Label Routing - -1. Log in to the Dubbo-Admin console -2. In the left navigation pane, select Service Governance > Label Routing. -3. Click the Create button, and in the Create New Tag Rule pane, fill in the rule content, and then click Save. - -#### Detailed Rules - -##### Configuration template - -```yaml ---- - force: false - runtime: true - enabled: true - key: governance-tagrouter-provider - tags: - - name: tag1 - addresses: ["127.0.0.1:20880"] - - name: tag2 - addresses: ["127.0.0.1:20881"] - ... -``` - -**For the traffic isolation scenario, you only need to clarify the following issues to know how to write the configuration:** - -1. To modify the configuration of the provider application to which the service belongs. - - Application: `scope: application, key: app-name` (you can also use `services` to specify certain services). -2. When the routing result is empty, whether to force return. - - force=false: When the routing result is empty, downgrade the provider whose tag is empty. - - force=true: When the routing result is empty, an exception will be returned directly. -3. Priority of routing rules - - priority=1: The priority of routing rules, used for sorting, the higher the priority, the higher the execution, it can be left blank, the default is 0. -4. Whether the configuration takes effect only for certain specific instances. - - All instances: `addresses: ["0.0.0.0"]` or `addresses: ["0.0.0.0:*"]` depends on the side value. - - Specified instances: `addersses[list of instance addresses]`. -5. The tag name to modify. - -## Result validation -Select the application related to the traffic isolation configuration to trigger the call verification. \ No newline at end of file diff --git a/content/en/overview/tasks/traffic-management/traffic-gray.md b/content/en/overview/tasks/traffic-management/traffic-gray.md deleted file mode 100644 index b9d26543e236..000000000000 --- a/content/en/overview/tasks/traffic-management/traffic-gray.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -type: docs -title: "Traffic Grayscale" -linkTitle: "Traffic Grayscale" -weight: 5 -description: "Configure label routing rules in Dubbo-Admin to achieve gray scale release" ---- - -Dubbo provides traffic grayscale service management capabilities, and can configure label routing rules and conditional routing to achieve grayscale publishing without restarting the application. - -Dubbo can achieve traffic grayscale through XML configuration, annotation configuration, and dynamic configuration. Here we mainly introduce the dynamic configuration method. For other configuration methods, please refer to the old document [Configuration](/zh-cn/docsv2.7/user/configuration/) - -## before the start - -Please make sure to run Dubbo-Admin successfully - -## Background Information - -Scenarios of demand changes and version iterations will be encountered during product development. In order to take into account both demand changes and system stability, the release should be as smooth as possible, and the number of affected people should be small to large, and roll back immediately if there is a problem. Dubbo-Admin provides dynamic traffic grayscale capabilities, which can help you bid for new services, release services smoothly, and improve service stability and availability. - -## Steps - -### Conditional Routing - -1. Log in to the Dubbo-Admin console -2. In the left navigation pane, select Service Governance > Conditional Routing. -3. Click the Create button, in the Create New Routing Rule panel, fill in the rule content, and then click Save. - - -#### Detailed Rules - -##### Configuration template - -```yaml ---- -scope: application/service -force: true -runtime: true -enabled: true -key: app-name/group+service+version -conditions: - - application=app1 => address=*:20880 - - method=sayHello => address=*:20880 -``` - -**For traffic grayscale scenarios, you only need to clarify the following issues to know how to write the configuration:** - -1. To modify the configuration of the consumer application or the configuration of a service. - - Application: `scope: application, key: app-name` (you can also use `services` to specify certain services). - - Service: `scope: service, key:group+service+version`. -2. When the routing result is empty, whether to force return. - - force=false: When the routing result is empty, downgrade the provider whose tag is empty. - - force=true: When the routing result is empty, an exception will be returned directly. -3. Priority of routing rules - - priority=1: The priority of routing rules, used for sorting, the higher the priority, the higher the execution, it can be left blank, the default is 0. -4. Whether the configuration takes effect only for certain specific instances. - - All instances: `addresses: ["0.0.0.0"]` or `addresses: ["0.0.0.0:*"]` depends on the side value. - - Specified instances: `addersses[list of instance addresses]`. -5. The condition rule to modify. - - => The previous one is the consumer matching condition. All parameters are compared with the consumer’s URL. When the consumer meets the matching condition, the subsequent filtering rules are executed for the consumer. - - => After that, it is the filter condition of the provider's address list. All parameters are compared with the provider's URL, and consumers only get the filtered address list in the end. - - If the matching condition is empty, it means to apply to all consumers, such as: => host != 10.20.153.11 - - If the filter condition is empty, access is prohibited, such as: host = 10.20.153.10 => - -### Label Routing - -1. Log in to the Dubbo-Admin console -2. In the left navigation pane, select Service Governance > Label Routing. -3. Click the Create button, and in the Create New Tag Rule pane, fill in the rule content, and then click Save. - -#### Detailed Rules - -##### Configuration template - -```yaml ---- - force: false - runtime: true - enabled: true - key: governance-tagrouter-provider - tags: - - name: tag1 - addresses: ["127.0.0.1:20880"] - - name: tag2 - addresses: ["127.0.0.1:20881"] - ... -``` - -**For traffic grayscale scenarios, you only need to clarify the following issues to know how to write the configuration:** - -1. To modify the configuration of the provider application to which the service belongs. - - Application: `scope: application, key: app-name` (you can also use `services` to specify certain services). -2. When the routing result is empty, whether to force return. - - force=false: When the routing result is empty, downgrade the provider whose tag is empty. - - force=true: When the routing result is empty, an exception will be returned directly. -3. Priority of routing rules - - priority=1: The priority of routing rules, used for sorting, the higher the priority, the higher the execution, it can be left blank, the default is 0. -4. Whether the configuration takes effect only for certain specific instances. - - All instances: `addresses: ["0.0.0.0"]` or `addresses: ["0.0.0.0:*"]` depends on the side value. - - Specified instances: `addersses[list of instance addresses]`. -5. The tag name to modify. - -## Result validation -Select the application related to traffic grayscale configuration to trigger the call verification. \ No newline at end of file diff --git a/content/en/overview/tasks/traffic-management/traffic-routing.md b/content/en/overview/tasks/traffic-management/traffic-routing.md deleted file mode 100644 index fafce1758ce2..000000000000 --- a/content/en/overview/tasks/traffic-management/traffic-routing.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -type: docs -title: "Request Routing" -linkTitle: "Request Routing" -weight: 5 -description: "Routing according to request conditions in Dubbo-Admin" ---- - -Dubbo provides the service governance capability of dynamically creating conditional routing, which can route according to the request initiator and method without restarting the application. - -Dubbo can implement dynamic routing according to request conditions through XML configuration, annotation configuration, and dynamic configuration. Here we mainly introduce the dynamic configuration method. For other configuration methods, please refer to the old document [Configuration](/zh-cn/docsv2.7/user/configuration/) - -## before the start - -Please make sure to run Dubbo-Admin successfully - -## Background Information - -In business scenarios such as black and white lists, excluding pre-release machines, exposing only some machines, and isolation by environment, routing rules are required to filter the target server address before initiating an RPC call, and the filtered address is used as the candidate address for the final RPC call. Dubbo-Admin provides conditional routing capabilities, which can help you configure routing rules to meet business scenarios. - -## Steps - -### Conditional Routing - -1. Log in to the Dubbo-Admin console -2. In the left navigation pane, select Service Governance > Conditional Routing. -3. Click the Create button, in the Create New Routing Rule panel, fill in the rule content, and then click Save. - - -#### Detailed Rules - -##### Configuration template - -```yaml ---- -scope: application/service -force: true -runtime: true -enabled: true -key: app-name/group+service+version -conditions: - - application=app1 => address=*:20880 - - method=sayHello => address=*:20880 -``` - -**For conditional routing scenarios, you only need to clarify the following questions to know how to write the configuration:** - -1. To modify the configuration of the consumer application or the configuration of a service. - - Application: `scope: application, key: app-name` (you can also use `services` to specify certain services). - - Service: `scope: service, key:group+service+version`. -2. When the routing result is empty, whether to force return. - - force=false: When the routing result is empty, downgrade the provider whose tag is empty. - - force=true: When the routing result is empty, an exception will be returned directly. -3. Priority of routing rules - - priority=1: The priority of routing rules, used for sorting, the higher the priority, the higher the execution, it can be left blank, the default is 0. -4. Whether the configuration takes effect only for certain specific instances. - - All instances: `addresses: ["0.0.0.0"]` or `addresses: ["0.0.0.0:*"]` depends on the side value. - - Specified instances: `addersses[list of instance addresses]`. -5. The condition rule to modify. - - => The previous one is the consumer matching condition. All parameters are compared with the consumer’s URL. When the consumer meets the matching condition, the subsequent filtering rules are executed for the consumer. - - => After that, it is the filter condition of the provider's address list. All parameters are compared with the provider's URL, and consumers only get the filtered address list in the end. - - If the matching condition is empty, it means to apply to all consumers, such as: => host != 10.20.153.11 - - If the filter condition is empty, access is prohibited, such as: host = 10.20.153.10 => - -## Result validation -Select the application related to the conditional routing configuration to trigger the call verification. \ No newline at end of file diff --git a/content/en/overview/tasks/traffic-management/weight.md b/content/en/overview/tasks/traffic-management/weight.md deleted file mode 100644 index 5877716100fd..000000000000 --- a/content/en/overview/tasks/traffic-management/weight.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -type: docs -title: "Adjust traffic distribution by weight" -linkTitle: "Adjust traffic distribution by weight" -weight: 5 -description: "Adjust traffic distribution by weight in Dubbo-Admin" ---- - - - -Dubbo provides the service governance capability of adjusting traffic distribution by weight, and can dynamically adjust traffic distribution by weight without restarting the application. - -Dubbo can adjust traffic distribution by weight through XML configuration, annotation configuration, and dynamic configuration. Here we mainly introduce the dynamic configuration method. For other configuration methods, please refer to the old document [Configuration](/zh-cn/docsv2.7/user/configuration/) - -## before the start - -Please make sure to run Dubbo-Admin successfully - - -## Background Information - -In the case of different machine performance, the load of different machines needs to be evaluated systematically, and some machines need to be downgraded. By adjusting the traffic ratio of the machine by weight, the performance of the machine can be reasonably evaluated. -Certain services will face traffic shocks. In order to ensure the availability of core services, some services need to be downgraded. Adjust traffic distribution by weight to avoid faults caused by traffic impact. - - -## Steps - -### Weight Adjustment - -1. Log in to the Dubbo-Admin console -2. In the left navigation bar, select Service Governance > Weight Adjustment. -3. Click the Create button, and in the New Weight Rule panel, fill in the rule content, and then click Save. - - -#### Detailed Rules - - -**For the scenario of dynamically adjusting traffic distribution through weight, you only need to clarify the following issues to know how to write the configuration:** - -1. Whether you want to modify the configuration of the entire application or a service. - - Application: `scope: application, key: app-name` (you can also use `services` to specify certain services). - - Service: `scope: service, key:group+service+version`. -2. Whether the address list configuration takes effect only for some specific instances. - - All instances: `addresses: ["0.0.0.0"]` or `addresses: ["0.0.0.0:*"]` depends on the side value. - - Specified instances: `addersses[list of instance addresses]`. -3. The weight to modify. - -## Result validation -Select the application related to the weight configuration to trigger the call verification. \ No newline at end of file diff --git a/content/en/overview/tasks/traffic-management/zone.md b/content/en/overview/tasks/traffic-management/zone.md deleted file mode 100644 index 515b2cc70c43..000000000000 --- a/content/en/overview/tasks/traffic-management/zone.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -type: docs -title: "Same computer room/area priority" -linkTitle: "Same computer room/area priority" -weight: 5 -description: "Dynamic configuration in Dubbo-Admin The priority of the same computer room/area" ---- - -Dubbo provides the service management capability of dynamically configuring the priority of the same computer room/region, and can dynamically configure the priority of the same computer room/region without restarting the application. - -Dubbo can be configured through XML, annotation configuration, and dynamic configuration in the same computer room/area first. Here we mainly introduce the dynamic configuration method. For other configuration methods, please refer to the old document [Configuration](/zh-cn/docsv2.7/user/configuration/) - -## before the start - -Please make sure to run Dubbo-Admin successfully - -## Background Information - -When applications are deployed in multiple different computer rooms/regions, cross-region calls will occur between applications, and cross-region calls will increase the response time. Priority in the same computer room/area means that when an application invokes a service, the service provider in the same computer room/area is called first. Dubbo-Admin provides a dynamic same-computer room/region priority capability, which can help you quickly and dynamically configure the same-computer room/region priority, avoiding network delays caused by cross-regions, thereby reducing call response time. - - -## Steps - -### Label Routing - -1. Log in to the Dubbo-Admin console -2. In the left navigation pane, select Service Governance > Label Routing. -3. Click the Create button, and in the Create New Tag Rule pane, fill in the rule content, and then click Save. - -#### Detailed Rules - -##### Configuration template - -```yaml ---- - force: false - runtime: true - enabled: true - key: governance-tagrouter-provider - tags: - - name: tag1 - addresses: ["127.0.0.1:20880"] - - name: tag2 - addresses: ["127.0.0.1:20881"] - ... -``` - -**For the same computer room/area priority scenario, you only need to clarify the following questions to know how to write the configuration:** - -1. To modify the configuration of the provider application to which the service belongs. - - Application: `scope: application, key: app-name` (you can also use `services` to specify certain services). -2. When the routing result is empty, whether to force return. - - force=false: When the routing result is empty, downgrade the provider whose tag is empty. - - force=true: When the routing result is empty, an exception will be returned directly. -3. Priority of routing rules - - priority=1: The priority of routing rules, used for sorting, the higher the priority, the higher the execution, it can be left blank, the default is 0. -4. Whether the configuration takes effect only for certain specific instances. - - All instances: `addresses: ["0.0.0.0"]` or `addresses: ["0.0.0.0:*"]` depends on the side value. - - Specified instances: `addersses[list of instance addresses]`. -5. The tag name to modify. - -## Result validation -Select the application related to the priority configuration of the same computer room/area to trigger the call verification. \ No newline at end of file diff --git a/content/en/overview/tasks/triple/_index.md b/content/en/overview/tasks/triple/_index.md deleted file mode 100755 index 9ce330875dac..000000000000 --- a/content/en/overview/tasks/triple/_index.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -type: docs -title: "Triple Usage Example" -linkTitle: "Triple Usage Example" -description: "Demonstrates Triple's cross-language communication, Streaming and other capabilities" -weight: 2 -no_list: true ---- - -{{< blocks/section color="white" height="auto">}} -
-
-
-
-
-

- Define a service using IDL -

-

Using IDL to define cross-language services

-
-
-
-
-
-
-

- Pojo serialization compatibility mode -

-

Pojo serialization compatibility mode

-
-
-
-
-
-
-

- Streaming communication -

-

Stream communication mode

-
-
-
-
-
-
- -{{< /blocks/section >}} \ No newline at end of file diff --git a/content/en/overview/tasks/triple/idl.md b/content/en/overview/tasks/triple/idl.md deleted file mode 100644 index 1a9ec1734b9c..000000000000 --- a/content/en/overview/tasks/triple/idl.md +++ /dev/null @@ -1,237 +0,0 @@ ---- -type: docs -title: "Using IDL + Protobuf to define services across languages" -linkTitle: "Using IDL + Protobuf to define services across languages" -weight: 1 -description: "" ---- - -Service is the core concept in Dubbo. A service represents a set of RPC methods. Service is the basic unit of user-oriented programming and service discovery mechanism. The basic process of Dubbo development is: user-defined RPC service, through agreed configuration -Declare RPC as a Dubbo service, and then program based on the service API. For the service provider, it provides a specific implementation of the RPC service, while for the service consumer, it uses specific data to initiate a service call. - -The following describes how to quickly develop Dubbo services from three aspects: defining services, compiling services, configuring and loading services. - -For specific use cases, please refer to: [dubbo-samples-triple/stub](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java /org/apache/dubbo/sample/tri/stub); - -## Define the service -Dubbo3 recommends using IDL to define cross-language services. If you are more accustomed to using language-specific service definition methods, please move to [Multi-language SDK](/en/docs3-v2/) to view. - -```text -syntax = "proto3"; - -option java_multiple_files = true; -option java_package = "org.apache.dubbo.demo"; -option java_outer_classname = "DemoServiceProto"; -option objc_class_prefix = "DEMOSRV"; - -package demoservice; - -// The demo service definition. -service DemoService { - rpc SayHello (HelloRequest) returns (HelloReply) {} -} - -// The request message containing the user's name. -message HelloRequest { - string name = 1; -} - -// The response message containing the greetings -message HelloReply { - string message = 1; -} - -``` - -The above is a simple example of using IDL to define a service. We can name it `DemoService.proto`. The RPC service name `DemoService` and method signature are defined in the proto file -`SayHello (HelloRequest) returns (HelloReply) {}`, and also defines the method input parameter structure, output parameter structure `HelloRequest` and `HelloReply`. -The service in IDL format relies on the Protobuf compiler to generate client and server programming APIs that can be called by users. Dubbo provides unique plug-ins for multiple languages based on the native Protobuf Compiler to adapt to the Dubbo framework Proprietary API and programming model. - -> The service defined using Dubbo3 IDL only allows one input and output parameter. This form of service signature has two advantages. One is that it is more friendly to multi-language implementation, and the other is that it can guarantee the backward compatibility of the service, relying on the Protobuf sequence With optimized compatibility, we can easily adjust the transmitted data structure, such as adding and deleting fields, without worrying about interface compatibility at all. - -## Compile service -According to the language currently used, configure the corresponding Protobuf plug-in, and after compilation, the language-related service definition stub will be produced. - -### Java - -Java compiler configuration reference: -```xml - - org.xolstice.maven.plugins - protobuf-maven-plugin - 0.6.1 - - com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} - - grpc-java - io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} - - - - dubbo - org.apache.dubbo - dubbo-compiler - 3.0.10 - org.apache.dubbo.gen.tri.Dubbo3TripleGenerator - - - - - - - compile - test-compile - compile-custom - test-compile-custom - - - - -``` - -The stub generated by the Java language is as follows, the core is an interface definition -```java -@javax.annotation.Generated( -value = "by Dubbo generator", -comments = "Source: DemoService.proto") -public interface DemoService { - static final String JAVA_SERVICE_NAME = "org.apache.dubbo.demo.DemoService"; - static final String SERVICE_NAME = "demoservice. DemoService"; - - org.apache.dubbo.demo.HelloReply sayHello(org.apache.dubbo.demo.HelloRequest request); - - CompletableFuture sayHelloAsync(org.apache.dubbo.demo.HelloRequest request); -} -``` - -### Golang - -The stub generated by the Go language is as follows. This stub stores user-defined interfaces and data types. - -```go -func _DUBBO_Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { -in := new(HelloRequest) -if err := dec(in); err != nil { -return nil, err -} -base := srv.(dgrpc.Dubbo3GrpcService) -args := []interface{}{} -args = append(args, in) -invo := invocation. NewRPCInvocation("SayHello", args, nil) -if interceptor == nil { -result := base.GetProxyImpl().Invoke(ctx, invo) -return result.Result(), result.Error() -} -info := &grpc. UnaryServerInfo{ -Server: srv, -FullMethod: "/main. Greeter/SayHello", -} -handler := func(ctx context.Context, req interface{}) (interface{}, error) { -result := base.GetProxyImpl().Invoke(context.Background(), invo) -return result.Result(), result.Error() -} -return interceptor(ctx, in, info, handler) -} -``` - - -## Configure and load the service -The provider is responsible for providing specific Dubbo service implementations, that is, following the format constrained by the RPC signature to implement specific business logic codes. After implementing the service, register the service implementation as a standard Dubbo service, -Afterwards, the Dubbo framework can forward the received request to the service implementation, execute the method, and return the result. - -The configuration on the consumer side will be simpler. You only need to declare that the service defined by IDL is a standard Dubbo service, and the framework can help developers generate corresponding proxies. Developers will be completely oriented to proxy programming. -Basically, the implementation of all languages in Dubbo ensures that the proxy exposes standardized interfaces according to the IDL service definition. - -### Java -Provider, implement service -```java -public class DemoServiceImpl implements DemoService { - private static final Logger logger = LoggerFactory. getLogger(DemoServiceImpl. class); - - @Override - public HelloReply sayHello(HelloRequest request) { - logger.info("Hello " + request.getName() + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); - return HelloReply. newBuilder() - .setMessage("Hello " + request.getName() + ", response from provider: " - + RpcContext.getContext().getLocalAddress()) - .build(); - } - - @Override - public CompletableFuture sayHelloAsync(HelloRequest request) { - return CompletableFuture.completedFuture(sayHello(request)); - } -} -``` -Provider, registration service (take Spring XML as an example) -```xml - - -``` - -Consumer side, reference service -```xml - -``` - -On the consumer side, use the service proxy -```java -public void callService() throws Exception { - ... - DemoService demoService = context. getBean("demoService", DemoService. class); - HelloRequest request = HelloRequest.newBuilder().setName("Hello").build(); - HelloReply reply = demoService.sayHello(request); - System.out.println("result: " + reply.getMessage()); -} -``` - -### Golang - -Provider, implement service - -```go -type User struct { -ID string -name string -Age int32 -Time time. Time -} - -type UserProvider struct { -} - -func (u *UserProvider) GetUser(ctx context.Context, req []interface{}) (*User, error) { -gxlog.CInfo("req:%#v", req) -rsp := User{"A001", "Alex Stocks", 18, time. Now()} -gxlog.CInfo("rsp:%#v", rsp) -return &rsp, nil -} - -func (u *UserProvider) Reference() string { -return "UserProvider" -} - -func (u User) JavaClassName() string { -return "org.apache.dubbo.User" -} - -func main() { - hessian.RegisterPOJO(&User{}) -config. SetProviderService(new(UserProvider)) -} -``` - -On the consumer side, use the service proxy - -```go -func main() { -config. Load() -user := &pkg. User{} -err := userProvider.GetUser(context.TODO(), []interface{}{"A001"}, user) -if err != nil { -os. Exit(1) -return -} -gxlog.CInfo("response result: %v\n", user) -} -``` \ No newline at end of file diff --git a/content/en/overview/tasks/triple/streaming.md b/content/en/overview/tasks/triple/streaming.md deleted file mode 100644 index bb3abc752455..000000000000 --- a/content/en/overview/tasks/triple/streaming.md +++ /dev/null @@ -1,296 +0,0 @@ ---- -type: docs -title: "Streaming communication mode" -linkTitle: "Streaming communication mode" -weight: 3 -description: "" ---- - -For specific use cases, please refer to: [dubbo-samples-triple/pojo](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java /org/apache/dubbo/sample/tri/pojo); - -## Open the new feature of Triple - Stream (stream) -Stream is a new call type provided by Dubbo3. It is recommended to use stream in the following scenarios: - -- The interface needs to send a large amount of data. These data cannot be placed in an RPC request or response, and need to be sent in batches. However, if the application layer cannot solve the order and performance problems in the traditional multiple RPC method, if the order needs to be guaranteed , it can only be sent serially -- In streaming scenarios, data needs to be processed in the order they are sent, and the data itself has no definite boundary -- In push scenarios, multiple messages are sent and processed in the context of the same call - -Stream is divided into the following three types: -- SERVER_STREAM (server stream) - ![SERVER_STREAM](/imgs/v3/migration/tri/migrate-server-stream.png) -- CLIENT_STREAM (client stream) - ![CLIENT_STREAM](/imgs/v3/migration/tri/migrate-client-stream.png) -- BIDIRECTIONAL_STREAM (bidirectional stream) - ![BIDIRECTIONAL_STREAM](/imgs/v3/migration/tri/migrate-bi-stream.png) - -> Due to the limitations of the `java` language, the implementation of BIDIRECTIONAL_STREAM and CLIENT_STREAM is the same. - -In Dubbo3, the stream interface is declared and used as `SteamObserver`, and users can use and implement this interface to send and handle stream data, exceptions, and end. - -> For Dubbo2 users, they may be unfamiliar with StreamObserver, which is a stream type defined by Dubbo3. There is no Stream type in Dubbo2, so it has no impact on migration scenarios. - -Stream Semantic Guarantees -- Provide message boundaries, which can easily process messages separately -- Strictly ordered, the order of the sender is consistent with the order of the receiver -- Full duplex, no need to wait for sending -- Support cancellation and timeout - -### Non-PB serialized stream -1. api -```java -public interface IWrapperGreeter { - - StreamObserver sayHelloStream(StreamObserver response); - - void sayHelloServerStream(String request, StreamObserver response); -} -``` - -> The method input parameters and return values of the Stream method are strictly agreed. In order to prevent problems caused by writing errors, the Dubbo3 framework side checks the parameters, and throws an exception if there is an error. -> For `BIDIRECTIONAL_STREAM`, it should be noted that `StreamObserver` in the parameter is the response stream, and `StreamObserver` in the return parameter is the request stream. - -2. Implementation class -```java -public class WrapGreeterImpl implements WrapGreeter { - - //... - - @Override - public StreamObserver sayHelloStream(StreamObserver response) { - return new StreamObserver() { - @Override - public void onNext(String data) { - System.out.println(data); - response.onNext("hello,"+data); - } - - @Override - public void onError(Throwable throwable) { - throwable. printStackTrace(); - } - - @Override - public void onCompleted() { - System.out.println("onCompleted"); - response.onCompleted(); - } - }; - } - - @Override - public void sayHelloServerStream(String request, StreamObserver response) { - for (int i = 0; i < 10; i++) { - response.onNext("hello," + request); - } - response.onCompleted(); - } -} -``` - -3. Call method -```java -delegate.sayHelloServerStream("server stream", new StreamObserver() { - @Override - public void onNext(String data) { - System.out.println(data); - } - - @Override - public void onError(Throwable throwable) { - throwable. printStackTrace(); - } - - @Override - public void onCompleted() { - System.out.println("onCompleted"); - } -}); - - -StreamObserver request = delegate.sayHelloStream(new StreamObserver() { - @Override - public void onNext(String data) { - System.out.println(data); - } - - @Override - public void onError(Throwable throwable) { - throwable. printStackTrace(); - } - - @Override - public void onCompleted() { - System.out.println("onCompleted"); - } -}); -for (int i = 0; i < n; i++) { - request.onNext("stream request" + i); -} -request.onCompleted(); -``` - -## Serialized stream using Protobuf - -For the `Protobuf` serialization method, it is recommended to write `IDL` and use the `compiler` plugin to compile and generate. The generated code is roughly as follows: -```java -public interface PbGreeter { - - static final String JAVA_SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; - static final String SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; - - static final boolean inited = PbGreeterDubbo.init(); - - //... - - void greetServerStream(org.apache.dubbo.sample.tri.GreeterRequest request, org.apache.dubbo.common.stream.StreamObserver responseObserver); - - org.apache.dubbo.common.stream.StreamObserver greetStream(org.apache.dubbo.common.stream.StreamObserver responseObserver); -} -``` - -### Complete use case - -1. Writing the Java interface - ```java - import org.apache.dubbo.common.stream.StreamObserver; - import org.apache.dubbo.hello.HelloReply; - import org.apache.dubbo.hello.HelloRequest; - - public interface IGreeter { - /** - *
-          * Sends greeting by stream
-          * 
- */ - StreamObserver sayHello(StreamObserver replyObserver); - - } - ``` - -2. Write the implementation class - ```java - public class IStreamGreeterImpl implements IStreamGreeter { - - @Override - public StreamObserver sayHello(StreamObserver replyObserver) { - - return new StreamObserver() { - private List replyList = new ArrayList<>(); - - @Override - public void onNext(HelloRequest helloRequest) { - System.out.println("onNext receive request name:" + helloRequest.getName()); - replyList.add(HelloReply.newBuilder() - .setMessage("receive name:" + helloRequest.getName()) - .build()); - } - - @Override - public void onError(Throwable cause) { - System.out.println("onError"); - replyObserver.onError(cause); - } - - @Override - public void onCompleted() { - System.out.println("onComplete receive request size:" + replyList.size()); - for (HelloReply reply : replyList) { - replyObserver.onNext(reply); - } - replyObserver.onCompleted(); - } - }; - } - } - ``` -3. Create a Provider - - ```java - public class StreamProvider { - public static void main(String[] args) throws InterruptedException { - ServiceConfig service = new ServiceConfig<>(); - service.setInterface(IStreamGreeter.class); - service.setRef(new IStreamGreeterImpl()); - service.setProtocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051)); - service.setApplication(new ApplicationConfig("stream-provider")); - service.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181")); - service. export(); - System.out.println("dubbo service started"); - new CountDownLatch(1). await(); - } - } - ``` - -4. Create Consumer - - ```java - public class StreamConsumer { - public static void main(String[] args) throws InterruptedException, IOException { - ReferenceConfig ref = new ReferenceConfig<>(); - ref. setInterface(IStreamGreeter. class); - ref. setCheck(false); - ref.setProtocol(CommonConstants.TRIPLE); - ref. setLazy(true); - ref. setTimeout(100000); - ref. setApplication(new ApplicationConfig("stream-consumer")); - ref.setRegistry(new RegistryConfig("zookeeper://mse-6e9fda00-p.zk.mse.aliyuncs.com:2181")); - final IStreamGreeter iStreamGreeter = ref. get(); - - System.out.println("dubbo ref started"); - try { - - StreamObserver streamObserver = iStreamGreeter.sayHello(new StreamObserver() { - @Override - public void onNext(HelloReply reply) { - System.out.println("onNext"); - System.out.println(reply.getMessage()); - } - - @Override - public void onError(Throwable throwable) { - System.out.println("onError:" + throwable.getMessage()); - } - - @Override - public void onCompleted() { - System.out.println("onCompleted"); - } - }); - - streamObserver.onNext(HelloRequest.newBuilder() - .setName("tony") - .build()); - - streamObserver.onNext(HelloRequest.newBuilder() - .setName("nick") - .build()); - - streamObserver.onCompleted(); - } catch (Throwable t) { - t. printStackTrace(); - } - System.in.read(); - } - } - ``` - -5. Run Provider and Consumer, you can see that the request returns normally - > onNext\ - > receive name:tony\ - > onNext\ - > receive name:nick\ - > onCompleted - -### common problem - -1. protobuf class not found - -Since the bottom layer of the Triple protocol needs to rely on the protobuf protocol for transmission, even if the defined service interface does not use protobuf, it is necessary to introduce protobuf dependencies into the environment. - -```xml - - com.google.protobuf - protobuf-java - 3.19.4 - -``` \ No newline at end of file diff --git a/content/en/overview/tasks/triple/wrap.md b/content/en/overview/tasks/triple/wrap.md deleted file mode 100644 index 6ff2eb21c58b..000000000000 --- a/content/en/overview/tasks/triple/wrap.md +++ /dev/null @@ -1,171 +0,0 @@ ---- -type: docs -title: "Pojo Serialization Compatibility Mode" -linkTitle: "Pojo serialization compatibility mode" -weight: 2 -description: "" ---- - -This tutorial will build a simple project from scratch to demonstrate how to use Dubbo Triple based on POJO, and upgrade to the Triple protocol while the application does not change the existing interface definition. **In this mode, Triple is used in the same way as Dubbo protocol. ** - -For specific use cases, please refer to: [dubbo-samples-triple/pojo](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java /org/apache/dubbo/sample/tri/pojo); - -### precondition -- [JDK](https://jdk.java.net/) version >= 8 -- Installed [Maven](https://maven.apache.org/) -- Installed and started [Zookeeper](https://zookeeper.apache.org/) - -### Create project -1. First create an empty maven project - ``` - $ mvn archetype:generate \ - -DgroupId=org.apache.dubbo \ - -DartifactId=tri-pojo-demo\ - -DarchetypeArtifactId=maven-archetype-quickstart\ - -DarchetypeVersion=1.4 \ - -DarchetypeGroupId=org.apache.maven.archetypes \ - -Dversion=1.0-SNAPSHOT - ``` -2. Switch to the project directory - ``` - $ cd tri-pojo-demo - ``` -3. Set JDK version in `pom.xml`, add Dubbo dependencies and plugins - ```xml - - UTF-8 - 1.8 - 1.8 - - - - - junit - junit - 4.13 - test - - - org.apache.dubbo - dubbo - 3.0.8 - - - org.apache.dubbo - dubbo-dependencies-zookeeper-curator5 - pom - 3.0.8 - - - com.google.protobuf - protobuf-java - 3.19.4 - - - ``` -4. Add interface definition `src/main/java/org/apache/dubbo/Greeter.java` - ```java - package org.apache.dubbo; - - public interface Greeter { - String sayHello(String name); - } - ``` -5. Add server-side interface implementation `src/main/java/org/apache/dubbo/GreeterImpl.java` - ```java - package org.apache.dubbo; - - public class GreeterImpl implements Greeter { - @Override - public String sayHello(String name) { - return "Hello," + name + "!"; - } - } - ``` -6. Add server startup class `src/main/java/org/apache/dubbo/MyDubboServer.java` - ```java - package org.apache.dubbo; - - import org.apache.dubbo.common.constants.CommonConstants; - import org.apache.dubbo.config.ApplicationConfig; - import org.apache.dubbo.config.ProtocolConfig; - import org.apache.dubbo.config.RegistryConfig; - import org.apache.dubbo.config.ServiceConfig; - import org.apache.dubbo.config.bootstrap.DubboBootstrap; - - import java.io.IOException; - - public class MyDubboServer { - - public static void main(String[] args) throws IOException { - ServiceConfig service = new ServiceConfig<>(); - service.setInterface(Greeter.class); - service.setRef(new GreeterImpl()); - - DubboBootstrap bootstrap = DubboBootstrap. getInstance(); - bootstrap. application(new ApplicationConfig("tri-pojo-server")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051)) - .service(service) - .start(); - System.out.println("Dubbo triple pojo server started"); - System.in.read(); - } - } - ``` - -7. Add the client startup class `src/main/java/org/apache/dubbo/MyDubboClient.java` - ```java - package org.apache.dubbo; - - import org.apache.dubbo.common.constants.CommonConstants; - import org.apache.dubbo.config.ApplicationConfig; - import org.apache.dubbo.config.ReferenceConfig; - import org.apache.dubbo.config.RegistryConfig; - import org.apache.dubbo.config.bootstrap.DubboBootstrap; - - public class MyDubboClient { - public static void main(String[] args) { - DubboBootstrap bootstrap = DubboBootstrap. getInstance(); - ReferenceConfig ref = new ReferenceConfig<>(); - ref. setInterface(Greeter. class); - ref.setProtocol(CommonConstants.TRIPLE); - ref. setTimeout(3000); - bootstrap. application(new ApplicationConfig("tri-pojo-client")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .reference(ref) - .start(); - - Greeter greeter = ref. get(); - String reply = greeter. sayHello("pojo"); - System.out.println("Received reply:" + reply); - } - } - ``` -8. Compile the code - ``` - $ mvn clean install - ``` -9. Start the server - ``` - $ mvn org.codehaus.mojo:exec-maven-plugin:3.0.0:java -Dexec.mainClass="org.apache.dubbo.MyDubboServer" - Dubbo triple pojo server started - ``` -10. Open a new terminal and start the client - ``` - $ mvn org.codehaus.mojo:exec-maven-plugin:3.0.0:java -Dexec.mainClass="org.apache.dubbo.MyDubboClient" - Received reply: message: "Hello, Demo!" - ``` -### common problem - -1. protobuf class not found - -Since the bottom layer of the Triple protocol needs to rely on the protobuf protocol for transmission, even if the defined service interface does not use protobuf, it is necessary to introduce protobuf dependencies into the environment. - -```xml - - com.google.protobuf - protobuf-java - 3.19.4 - -``` \ No newline at end of file diff --git a/content/en/overview/what/_index.md b/content/en/overview/what/_index.md index e4a4be6e8ef5..fe233661ecf8 100644 --- a/content/en/overview/what/_index.md +++ b/content/en/overview/what/_index.md @@ -1,16 +1,72 @@ --- -type: docs -title: "What is Dubbo" -linkTitle: "What is Dubbo" -weight: 1 +aliases: + - /zh/overview/what/ description: "" +hide_summary: true +linkTitle: 介绍 +no_list: true +title: Dubbo 介绍 +type: docs +weight: 2 --- -Apache Dubbo is an RPC microservice framework that provides SDK implementations in multiple languages including Java and Golang. -* If it is your first time to contact Dubbo, please continue to read this chapter to understand the rich functions and core concepts provided by Dubbo; -* If you want to experience Dubbo quickly, please refer to [Quick Start](../quickstart) -* Dubbo3 Advanced Usage Reference [Multilanguage SDK Documentation](../mannual) -* Dubbo3 design and migration - * [3.0 Design Concept and Core Functions](./dubbo3/) - * [How to migrate to Dubbo3](/en/docs3-v2/java-sdk/upgrades-and-compatibility) +[5 分钟快速掌握 Apache Dubbo]({{< relref "../../blog/news/dubbo-introduction" >}}) + +Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, +利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。 + +在云原生时代,Dubbo 相继衍生出了 Dubbo3、Proxyless Mesh 等架构与解决方案,在易用性、超大规模微服务实践、云原生基础设施适配、安全性等几大方向上进行了全面升级。 + +## Dubbo 的开源故事 + +Apache Dubbo 最初是为了解决阿里巴巴内部的微服务架构问题而设计并开发的,在十多年的时间里,它在阿里巴巴公司内部的很多业务系统得到了非常广泛的应用。最早在 2008 年,阿里巴巴就将 Dubbo 捐献到开源社区,它很快成为了国内开源服务框架选型的事实标准框架,得到了业界更广泛的应用。在 2017 年,Dubbo 被正式捐献 Apache 软件基金会并成为 Apache 顶级项目,开始了一段新的征程。 + +Dubbo 被证实能很好的满足企业的大规模微服务实践,并且能有效降低微服务建设的开发与管理成本,不论是阿里巴巴还是工商银行、中国平安、携程、海尔等社区用户,它们都通过多年的大规模生产环境流量对 Dubbo 的稳定性与性能进行了充分验证。后来 Dubbo 在很多大企业内部衍生出了独立版本。自云原生概念推广以来,各大厂商都开始拥抱开源标准实现,阿里巴巴将其内部 HSF 系统与开源社区 Dubbo 相融合,与社区一同推出了云原生时代的 Dubbo3 架构,截止 2022 年双十一结束,**Dubbo3 已经在阿里巴巴内部广泛落地,实现了老版本 HSF2 框架升级,包括电商核心、阿里云等核心系统已经全面运行在 Dubbo3 之上**。 + +## 为什么需要 Dubbo,它能做什么? +按照微服务架构的定义,采用它的组织能够很好的提高业务迭代效率与系统稳定性,但前提是要先能保证微服务按照期望的方式运行,要做到这一点需要解决服务拆分与定义、数据通信、地址发现、流量管理、数据一致性、系统容错能力等一系列问题。 + +Dubbo 可以帮助解决如下微服务实践问题: + +* **微服务编程范式和工具** + +Dubbo 支持基于 IDL 或语言特定方式的服务定义,提供多种形式的服务调用形式(如同步、异步、流式等) + +* **高性能的 RPC 通信** + +Dubbo 帮助解决微服务组件之间的通信问题,提供了基于 HTTP、HTTP/2、TCP 等的多种高性能通信协议实现,并支持序列化协议扩展,在实现上解决网络连接管理、数据传输等基础问题。 + +* **微服务监控与治理** + +Dubbo 官方提供的服务发现、动态配置、负载均衡、流量路由等基础组件可以很好的帮助解决微服务基础实践的问题。除此之外,您还可以用 Admin 控制台监控微服务状态,通过周边生态完成限流降级、数据一致性、链路追踪等能力。 + +* **部署在多种环境** + +Dubbo 服务可以直接部署在容器、Kubernetes、Service Mesh等多种架构下。 + +* **活跃的社区** + +Dubbo 项目托管在 Apache 社区,有来自国际、国内的活跃贡献者维护着超 10 个生态项目,贡献者包括来自海外、阿里巴巴、工商银行、携程、蚂蚁、腾讯等知名企业技术专家,确保 Dubbo 及时解决项目缺陷、需求及安全漏洞,跟进业界最新技术发展趋势。 + +* **庞大的用户群体** + +Dubbo3 已在阿里巴巴成功落地,实现了对老版本 HSF2 框架全面升级,成为阿里集团面向云原生时代的统一服务框架底座,庞大的用户群体是 Dubbo 保持稳定性、需求来源、先进性的基础。 + +## Dubbo 不是什么? + +* **不是应用开发框架的替代者** + +Dubbo 设计为让开发者以主流的应用开发框架的开发模式工作,它不是各个语言应用开发框架的替代者,如它不是 Spring/Spring Boot 的竞争者,当你使用 Spring 时,Dubbo 可以无缝的与 Spring & Spring Boot 集成在一起。 + +* **不仅仅只是一款 RPC 框架** + +Dubbo 提供了内置 RPC 通信协议实现,但它不仅仅是一款 RPC 框架。首先,它不绑定某一个具体的 RPC 协议,开发者可以在基于 Dubbo 开发的微服务体系中使用多种通信协议;其次,除了 RPC 通信之外,Dubbo 提供了丰富的服务治理能力与生态。 + +* **不是 gRPC 协议的替代品** + +Dubbo 支持基于 gRPC 作为底层通信协议,在 Dubbo 模式下使用 gRPC 可以带来更好的开发体验,享有统一的编程模型和更低的服务治理接入成本 + +* **不只有 Java 语言实现** + +自 Dubbo3 开始,Dubbo 提供了 Java、Golang、Rust、Node.js 等多语言实现,未来会有更多的语言实现。 diff --git a/content/en/overview/what/advantages/_index.md b/content/en/overview/what/advantages/_index.md new file mode 100644 index 000000000000..60ad035cb5bd --- /dev/null +++ b/content/en/overview/what/advantages/_index.md @@ -0,0 +1,9 @@ +--- +aliases: + - /zh/overview/what/advantages/ +description: "" +linkTitle: 核心优势 +title: 核心优势 +type: docs +weight: 4 +--- diff --git a/content/en/overview/what/advantages/governance.md b/content/en/overview/what/advantages/governance.md new file mode 100644 index 000000000000..7f7a2d6d17bc --- /dev/null +++ b/content/en/overview/what/advantages/governance.md @@ -0,0 +1,61 @@ +--- +aliases: + - /zh/overview/what/advantages/governance/ +description: 服务治理 +linkTitle: 服务治理 +title: 服务治理 +type: docs +weight: 3 +--- + + + + +## 流量管控 + +在地址发现和负载均衡机制之外,Dubbo 丰富的流量管控规则可以控制服务间的流量走向和 API 调用,基于这些规则可以实现在运行期动态的调整服务行为如超时时间、重试次数、限流参数等,通过控制流量分布可以实现 A/B 测试、金丝雀发布、多版本按比例流量分配、条件匹配路由、黑白名单等,提高系统稳定性。 + +#### Dubbo 流量管控能解决哪些问题 +场景一:搭建多套独立的逻辑测试环境。 + +场景二:搭建一套完全隔离的线上灰度环境用来部署新版本服务。 + +![gray1](/imgs/v3/tasks/gray/gray1.png) + +场景三:金丝雀发布 + +![weight1.png](/imgs/v3/tasks/weight/weight1.png) + +场景四:同区域优先。当应用部署在多个不同机房/区域的时候,优先调用同机房/区域的服务提供者,避免了跨区域带来的网络延时,从而减少了调用的响应时间。 + +![region1](/imgs/v3/tasks/region/region1.png) + +除了以上几个典型场景,我们还可以基于 Dubbo 支持的流量管控规则实现微服务场景中更丰富的流量管控,如: + +* 动态调整超时时间 +* 服务重试 +* 访问日志 +* 同区域优先 +* 灰度环境隔离 +* 参数路由 +* 按权重比例分流 +* 金丝雀发布 +* 服务降级 +* 实例临时拉黑 +* 指定机器导流 + +可以在 [流量管理任务](../../../tasks/traffic-management/) 中了解以上实践场景细节。背后的规则定义与工作原理请参见 [Dubbo 流量管控规则设计与定义](../../../core-features/traffic/)。。 + +## 微服务生态 +围绕 Dubbo 我们构建了完善的微服务治理生态,对于绝大多数服务治理需求,通过简单几行配置即可开启。对于官方尚未适配的组件或者用户内部系统,也可以通过 Dubbo 扩展机制轻松适配。 + +![governance](/imgs/v3/what/governance.png) + +## 可视化控制台 +Dubbo Admin 是 Dubbo 官方提供的可视化 Web 交互控制台,基于 Admin 你可以实时监测集群流量、服务部署状态、排查诊断问题。 + +## 安全体系 +Dubbo 支持基于 TLS 的 HTTP、HTTP/2、TCP 数据传输通道,并且提供认证、鉴权策略,让开发者实现更细粒度的资源访问控制。 + +## 服务网格 +基于 Dubbo 开发的服务可以透明的接入 Istio 等服务网格体系,Dubbo 支持基于 Envoy 的流量拦截方式,也支持更加轻量的 Proxyless Mesh 部署模式。 diff --git a/content/en/overview/what/advantages/performance.md b/content/en/overview/what/advantages/performance.md new file mode 100644 index 000000000000..0066495d2edd --- /dev/null +++ b/content/en/overview/what/advantages/performance.md @@ -0,0 +1,67 @@ +--- +aliases: + - /zh/overview/what/advantages/performance/ +description: 超高性能 +linkTitle: 超高性能 +title: 超高性能 +type: docs +weight: 2 +--- + + +Dubbo 被设计用于解决阿里巴巴超大规模的电商微服务集群实践,并在各个行业头部企业经过多年的十万、百万规模的微服务实践检验,因此,Dubbo 在通信性能、稳定性方面具有无可比拟的优势,非常适合构建近乎无限水平伸缩的微服务集群,这也是 Dubbo 从实践层面优于业界很多同类的产品的巨大优势。 + +## 高性能数据传输 +Dubbo 内置支持 Dubbo2、Triple 两款高性能通信协议。其中 +* Dubbo2 是基于 TCP 传输协议之上构建的二进制私有 RPC 通信协议,是一款非常简单、紧凑、高效的通信协议。 +* Triple 是基于 HTTP/2 的新一代 RPC 通信协议,在网关穿透性、通用性以及 Streaming 通信上具备优势,Triple 完全兼容 gRPC 协议。 + +以下是基于 Dubbo 3.2 版本得出的压测指标数据,您也可以通过 [dubbo-benchmark](https://github.com/apache/dubbo-benchmark) 项目自行压测。 + +### TCP protocol benchmark + +对比 Dubbo 2.x 及早期 3.x 版本 +* 较小报文场景 createUser、getUser 下,提升率约 180%。 +* 极小报文 existUser(仅一个boolean值)下提升率约 24% +* 较大报文 listUser 提升率最高,达到了 1000%! + +![dubbo-rpc-protocol-benchmark](/imgs/v3/performance/rpc-dubbo.png) + +### Triple protocol benchmark + +* 较小报文场景 createUser、existUser、getUser 下,较 3.1 版本性能提升约 40-45%,提升后的性能与 gRPC 同场景的性能基本持平。 +* 较大报文场景 listUser 下较 3.1 版本提升了约 17%,相较于同场景下的 gRPC 低 11%。 + +![dubbo-http2-protobuf-benchmark](/imgs/v3/performance/rpc-triple.png) + +了解更多 +* [通信协议](../../../core-features/protocols) +* [Benchmark 指标 (不定期更新)](https://github.com/apache/dubbo/issues/10558#issuecomment-1473015636) + +## 构建可伸缩的微服务集群 +业务增长带来了集群规模的快速增长,而集群规模的增长会对服务治理架构带来挑战: +* 注册中心的存储容量瓶颈 +* 节点动态变化带来的地址推送与解析效率下降 +* 消费端存储大量网络地址的资源开销 +* 复杂的网络链接管理 +* 高峰期的流量无损上下线 +* 异常节点的自动节点管理 + +以上内容直接关系到微服务集群的稳定性,因此很容易成为影响集群和业务增长的瓶颈,集群规模越大,问题带来的影响面也就被进一步放大。很多开发者可能会想只有几个应用而已,当前不需要并不关心集群规模,但作为技术架构选型的关键因素之一,我们还是要充分考虑微服务集群未来的可伸缩性。并且基于对业界大量微服务架构和框架实现的调研,一些产品的性能瓶颈点可能很快就会到来(部分产品所能高效支持的瓶颈节点规模阈值都是比较低的,比如几十个应用、数百个节点)。 + +Dubbo 的优势在于近乎无限水平扩容的集群规模,在阿里巴巴双十一场景万亿次调用的实践检验,通过以下内容了解 Dubbo 构建生产可用的、可伸缩的大规模微服务集群背后的原理: +* [Dubbo3 服务发现](../../../core-features/service-discovery/) +* [流量管控](../../../core-features/traffic/) + +## 智能化流量调度 +Dubbo3 内置了具备自适应感知集群负载状态、智能调节流量分布的限流与调度算法实现,从消费者、提供者两个不同视角智能调整流量分布,最大限度确保将流量调度到具有最佳处理能力的实例上,从而提升整个集群的吞吐量与稳定性。 + +### 自适应负载均衡 +自适应负载均衡是从消费者视角考虑如何将请求分配到当前具有最优处理能力的机器实例。Dubbo3 新引入了两种负载均衡算法 +* 一种是基于公平性考虑的单纯 `P2C` 算法 +* 另一种是基于自适应的方法 `adaptive`,其试图自适应的衡量 provider 端机器的吞吐能力,然后将流量尽可能分配到吞吐能力高的机器上,以提高系统整体的性能。 + +### 自适应限流 +与负载均衡运行在消费者端不同的是,限流功能运行在提供者端。其作用是限制提供端实例处理并发任务时的最大数量。从理论上讲,服务端机器的处理能力是存在上限的,因此当并发请求量达到或接近上限时,拒绝掉一部分请求反而是更好的选择。相比于人为提前设置静态最大并发值,自适应限流算法可以动态调整服务端机器的最大并发值,使其可以在保证机器不过载的前提下,尽可能多的处理接收到的请求。 + +关于这部分请参考 [Dubbo3 服务柔性设计文档](../../../reference/proposals/heuristic-flow-control) \ No newline at end of file diff --git a/content/en/overview/what/advantages/production-ready.md b/content/en/overview/what/advantages/production-ready.md new file mode 100644 index 000000000000..4cbd3bb6f0c7 --- /dev/null +++ b/content/en/overview/what/advantages/production-ready.md @@ -0,0 +1,34 @@ +--- +aliases: + - /zh/overview/what/advantages/production-ready/ +description: 生产环境验证 +linkTitle: 生产环境验证 +title: 生产环境验证 +type: docs +weight: 4 +--- + + + +Apache Dubbo 是一款有着数以万计企业用户的国际化开源项目,经过了多年大规模集群生产环境的检验,影响了数百万开发者,带动了大量微服务开源生态发展。Dubbo 从企业实践中孵化并走向开源,又迅速在开源社区获得了成功,大量的生产实践用户是 Dubbo 长期保持先进性、稳定性和活跃度的核心驱动力。 + +## Dubbo 在阿里巴巴的应用 +Dubbo 设计用于解决阿里巴巴内部复杂的电商微服务集群的开发和治理问题,在 2020 年,阿里巴巴与 Apache Dubbo 社区共同合作,基于 Dubbo2 & HSF2 发布了面向云原生架构的下一代服务框架 - Dubbo3,目前,Dubbo3 已经完全升级 HSF2、Dubbo2 成为阿里巴巴内部统一的服务框架,成功的跑在了数十万应用、数百万节点的双十一集群之上。 + +Dubbo3 吸取了 HSF2 框架所有大规模微服务集群的治理经验,解决了 Dubbo2 架构设计上长期积累的一些缺陷,同时增加了一系列面向云原生架构的新特性。 + +![production-ready](/imgs/v3/advantages/production-ready.png) + +* 阿里巴巴结合 HSF 框架的大规模集群实践经验,基于 Apache Dubbo、开源社区需求等推出了面向云原生架构的全新服务框架 - Dubbo3,Dubbo3 在完全兼容之前 API 模式的情况下,完成了彻底的云原生架构升级。 +* Dubbo 的高度可扩展能力是其广泛适用的重要前提,阿里巴巴基于 Dubbo3 内核维护了一套内部特有的适配插件体系以实现平滑升级,这包括注册中心扩展、路由组件扩展、监控组件扩展等。 +* 几乎所有主流云厂商、主流微服务开源社区都提供了 Dubbo 适配或托管服务。 + +关于阿里巴巴 Dubbo3 应用的更多细节,请参见 [博客文章](/zh-cn/blog/) + +## 更多案例 +据 [Wanted, Who's Using Dubbo](https://github.com/apache/dubbo/issues/1012) 统计,Dubbo 已知部分典型用户包括: + +网联清算、银联商务、中国人寿、中国平安、中国银行、人民银行、工商银行、招商证券、平安保险、中国人寿、阿里巴巴、滴滴出行、携程网、小米、斗鱼直播、瓜子二手车、金蝶、亚信科技、中国电信、文思海辉、中科软、科大讯飞、恒生电子、红星凯美龙、海尔、新东方、软通动力、中远海运、昆明航空、中通快递、顺丰科技、普华永道等。 + + +{{< about/testimonials >}} diff --git a/content/en/overview/what/advantages/usability.md b/content/en/overview/what/advantages/usability.md new file mode 100644 index 000000000000..822400230ad5 --- /dev/null +++ b/content/en/overview/what/advantages/usability.md @@ -0,0 +1,44 @@ +--- +aliases: + - /zh/overview/what/advantages/usability/ +description: 快速易用 +linkTitle: 快速易用 +title: 快速易用 +type: docs +weight: 1 +--- + + + +无论你是计划采用微服务架构开发一套全新的业务系统,还是准备将已有业务从单体架构迁移到微服务架构,Dubbo 框架都可以帮助到你。Dubbo 让微服务开发变得非常容易,它允许你选择多种编程语言、使用任意通信协议,并且它还提供了一系列针对微服务场景的开发、测试工具帮助提升研发效率。 + +## 多语言 SDK +Dubbo 提供几乎所有主流语言的 SDK 实现,定义了一套统一的微服务开发范式。Dubbo 与每种语言体系的主流应用开发框架做了适配,总体编程方式、配置符合大多数开发者已有编程习惯。 + +比如在 Java 语言体系下,你可以使用 `dubbo-spring-boot-starter` 来开发符合 Spring、Spring Boot 模式的微服务应用,开发 Dubbo +应用只是为 Spring Bean 添加几个注解、完善 application.properties 配置文件。 + +![sdk](/imgs/v3/what/sdk.png) + +## 任意通信协议 +Dubbo 微服务间远程通信实现细节,支持 HTTP、HTTP/2、gRPC、TCP 等所有主流通信协议。与普通 RPC 框架不同,Dubbo 不是某个单一 RPC 协议的实现,它通过上层的 RPC 抽象可以将任意 RPC 协议接入 Dubbo 的开发、治理体系。 + +多协议支持让用户选型,多协议迁移、互通等变得更灵活。 + +![protocols](/imgs/v3/what/protocol.png) + +## 加速微服务开发 + +### 项目脚手架 +项目脚手架 让 Dubbo 项目创建、依赖管理更容易。 + +比如通过如下可视化界面,勾选 Dubbo 版本、Zookeeper 注册中心以及必要的微服务生态选项后,一个完整的 Dubbo 项目模板就可以自动生成,接下来基于脚手架项目添加业务逻辑就可以了。更多脚手架使用方式的讲解,请参见任务模块的 [通过模板生成项目脚手架](../../../tasks/develop/template/) + +![脚手架示例图](/imgs/v3/advantages/initializer.png) + +### 开发测试 +相比于单体应用,微服务分布式的特性会让不同组织之间的研发协同变得困难,这时我们需要有效的配套工具,用来提升整体的微服务研发效率。 + +Dubbo 从内核设计和实现阶段就考虑了如何解决开发、测试与运维问题,比如 Dubbo RPC 协议均支持 curl 访问,让开发协作更简单;配合官方提供的生态工具,可以实现服务测试、服务 Mock、文档管理、单机运维等能力,并通过 Dubbo Admin 控制台将所有操作都可视化的展现出来。 + +![admin](/imgs/v3/what/admin.png) diff --git a/content/en/overview/what/architecture.md b/content/en/overview/what/architecture.md deleted file mode 100644 index 97ad586e05b6..000000000000 --- a/content/en/overview/what/architecture.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -type: docs -title: "Architecture" -linkTitle: "Architecture" -weight: 3 ---- - -## RPC communication -Dubbo3's Triple protocol is built on the HTTP/2 protocol, so it has better penetration and versatility. The Triple protocol is compatible with gRPC and provides communication models such as Request Response, Request Streaming, Response Streaming, and Bi-directional Streaming; from Triple Starting from the agreement, Dubbo also supports IDL-based service definition. - -In addition, Dubbo also integrates most of the industry's mainstream protocols, allowing users to use these communication protocols within the Dubbo framework, providing users with a unified programming model and service governance model, these protocols include rest, hessian2, jsonrpc, thrift, etc. , note that there will be some differences in the range supported by different language SDK implementations. - -Details can be viewed -* [Triple Quick Facts](/en/docs3-v2/java-sdk/concepts-and-architecture/triple/) -* [Specification](https://github.com/apache/dubbo-awesome/blob/master/proposals/D0-triple.md) - -## Service Discovery -Service discovery, that is, the ability of the consumer to automatically discover the list of service addresses, is a key capability that the microservice framework needs to have. With the help of automated service discovery, microservices can be implemented without knowing the deployment location and IP address of the peer. communication. - -There are many ways to realize service discovery. Dubbo provides a Client-Based service discovery mechanism. Usually, additional third-party registry components need to be deployed to coordinate the service discovery process, such as the commonly used [Nacos](https:/ /nacos.io/), Consul, Zookeeper, etc. Dubbo itself also provides the connection to various registry components, and users can choose flexibly. - -Dubbo is based on the automatic service discovery capability of the consumer, and its basic working principle is as follows: - -![architecture](/imgs/architecture.png) - -Under the traditional deployment architecture, service discovery involves three participating roles: provider, consumer, and registration center. Among them, the provider registers the URL address to the registration center, the registration center is responsible for aggregating data, and the consumer subscribes to the URL address from the registration center. renew. -In the context of cloud native, for example, when the application is deployed on a platform such as Kubernetes, since the platform itself maintains the mapping relationship between the application/service and the instance, the registration center and the registration action are sinked to the infrastructure layer to a certain extent, so the framework Own registration action is sometimes not necessary. - -Dubbo3 provides a new application-level service discovery model, which is different from Dubbo2's interface-level service discovery model in terms of design and implementation. It can be viewed here: -* [Application-level service discovery](/en/docs3-v2/java-sdk/concepts-and-architecture/service-discovery/#Introduction to application-level service discovery) - -## Traffic management -Since Dubbo2, Dubbo has provided rich service governance rules, including routing rules, dynamic configuration, etc. - -On the one hand, Dubbo3 is connecting to the governance rules represented by VirtualService and DestinationRule used in popular Mesh products such as Istio by docking xDS; on the other hand, Dubbo is seeking to design a set of its own rules to achieve Traffic governance, and flexible governance capabilities. - -* [Dubbo2 Service Governance Rules](../../tasks/traffic-management) -* Dubbo3 service governance rules - -## Dubbo Mesh -The goal of Dubbo Mesh is to provide a complete Mesh solution adapted to the Dubbo system, including customized control plane (Control Plane) and customized data plane solutions. The Dubbo control plane is based on the industry's mainstream Istio extension, and supports richer traffic governance rules, Dubbo application-level service discovery models, etc. The Dubbo data plane can use Envoy Sidecar, which implements the deployment solution of Dubbo SDK + Envoy, or Dubbo Proxyless mode. Directly realize the communication between Dubbo and the control plane. Dubbo Mesh is undergoing rapid evolution, we will try our best to keep the content of the document updated. - -![mix-mesh](/imgs/v3/mesh/mix-mesh.png) - -View Dubbo Mesh design details here -* [Dubbo Proxy Mesh](https://github.com/apache/dubbo-awesome/blob/master/proposals/D3.1-thinsdk-sidecar-mesh.md) -* [Dubbo Proxyless Mesh](https://github.com/apache/dubbo-awesome/blob/master/proposals/D3.2-proxyless-mesh.md) -* [Dubbo Control Plane](https://github.com/apache/dubbo-awesome/blob/master/proposals/D3.2-proxyless-mesh.md) - -## Deployment Architecture -> This section focuses on describing the Dubbo deployment architecture in the traditional mode. The deployment architecture in the cloud-native background will change, mainly reflected in the fact that the infrastructure (Kubernetes, Service Mesh, etc.) will take on more responsibilities. -> The responsibilities of centralized components such as registration center, metadata center, configuration center, etc. are integrated, and operation and maintenance become simpler, but by emphasizing these centralized components, it is easier for us to understand the working principle of Dubbo. - -As a micro-service framework, Dubbo sdk is deployed in each location of the distributed cluster along with the micro-service components. In order to realize the cooperation between various micro-service components in a distributed environment, -Dubbo defines some centralized components, including: -* Registry. Coordinate address registration and discovery between Consumer and Provider -* Configuration center. - * Store the global configuration of the Dubbo startup phase to ensure cross-environment sharing and global consistency of the configuration - * Responsible for the storage and push of service governance rules (routing rules, dynamic configuration, etc.). -* Metadata Center. - * Receive the service interface metadata reported by the Provider, and provide operation and maintenance capabilities for Admin and other consoles (such as service testing, interface documents, etc.) - * As a supplement to the service discovery mechanism, it provides the synchronization capability of additional interface/method level configuration information, which is equivalent to the additional extension of the registration center - -![threecenters](/imgs/v3/concepts/threecenters.png) - -The above figure completely describes the interaction process between Dubbo microservice components and each center. - -The above three centers are not a necessary condition for running Dubbo. Users can decide to enable only one or more of them according to their own business conditions to simplify deployment. Typically, all users will be registered with an independent -Start Dubbo service development, and the configuration center and metadata center will be gradually introduced on demand during the evolution of microservices. - -### Registry - -The registration center plays a very important role, and it carries the responsibilities of service registration and service discovery. Currently Dubbo supports service discovery and service registration at the following two granularities, namely interface level and application level, and the registration center can be deployed on demand: - -- In the traditional Dubbo SDK usage posture, if you only provide RPC services in direct connection mode, you do not need to deploy a registration center. -- Regardless of the interface level or the application level, if Dubbo SDK itself is required for service registration and service discovery, you can choose to deploy a registration center and integrate the corresponding registration center in Dubbo. - -- In the Dubbo + Mesh scenario, with the weakening of Dubbo service registration capabilities, the registration center in Dubbo is no longer a must, and its responsibilities are beginning to be replaced by the control plane. If the Dubbo + Mesh deployment method is adopted, whether it is The mesh method of ThinSDK or the mesh method of Proxyless no longer requires independent deployment of the registration center. - -The registration center does not depend on the configuration center and metadata center, as shown in the following figure: - -![centers-registry](/imgs/v3/concepts/centers-registry.png) - -The configuration center and metadata center are not deployed in the figure. In Dubbo, the instance of the registration center will be used as the configuration center and metadata center at the same time by default. This is the default behavior of Dubbo. If you really do not need the capabilities of the configuration center or metadata center , which can be turned off in the configuration. There are two configurations in the configuration of the registration center, namely use-as-config-center and use-as-metadata-center. Just set the configuration to false. - -### Metadata Center - -The metadata center is supported in version 2.7.x. As application-level service registration and service discovery are implemented in Dubbo, the metadata center becomes more and more important. The metadata center will need to be deployed in the following situations: - -1. For an application service originally built with the old version of Dubbo, when migrating to Dubbo 3, Dubbo 3 will need a metadata center to maintain the mapping relationship between RPC services and applications (that is, the mapping relationship between interfaces and applications), because if Application-level service discovery and service registration are adopted, and the data organization form of the "application-instance list" structure will be adopted in the registration center, which is no longer the data organization form of the previous "interface-instance list" structure. When the application services that use interface-level service registration and service discovery are migrated to the application level, the corresponding relationship between the interface and the application cannot be obtained, so that the instance list information cannot be obtained from the registration center. Therefore, in order to be compatible with this scenario, Dubbo is in When the Provider side starts, it will store the mapping relationship between the interface and the application in the metadata center. -2. In order to allow the registration center to focus more on address discovery and push capabilities and reduce the burden on the registration center, the metadata center carries all service metadata, a large number of interface/method level configuration information, etc., regardless of interface granularity or application granularity Service discovery and registration, and the metadata center all play an important role. - -If you have the above two requirements, you can choose to deploy the metadata center and integrate the metadata center through Dubbo configuration. - -The metadata center does not depend on the registration center and configuration center, and users can freely choose whether to integrate and deploy the metadata center, as shown in the following figure: - -![centers-metadata](/imgs/v3/concepts/centers-metadata.png) - -There is no configuration center in this figure, which means that the ability to manage configuration globally may not be required. There is no registration center in the figure, which means that the Dubbo mesh solution may be adopted, or service registration may not be required, and only receive service calls in direct connection mode. - -### Configuration Center - -The configuration center is different from the other two centers. It has nothing to do with the interface level or the application level. It has no corresponding relationship with the interface. It is only related to the configuration data. Even if the registration center and metadata center are not deployed, the configuration center can be directly accessed. into the Dubbo application service. In the entire deployment architecture, instances in the entire cluster (whether they are Providers or Consumers) will share the configuration in the configuration center cluster, as shown in the following figure: - -![centers-config](/imgs/v3/concepts/centers-config.png) - -There is no registration center in the figure, which means that the Dubbo mesh solution may be adopted, or service registration may not be required, and only receive service calls in direct connection mode. - -There is no metadata center in this figure, which means that Consumer can obtain service metadata from the MetadataService exposed by Provider, so as to realize RPC call - -### Guarantee the high-availability deployment architecture of the three centers - -Although the three major centers are no longer necessary for Dubbo application services, in a real production environment, once the three major centers have been integrated and deployed, the three major centers will still face availability issues. Dubbo needs to support the three major centers High availability solution. Dubbo supports multiple registration centers, multiple data centers, and multiple configuration centers to meet the needs of deployment architecture models such as multi-active in the same city, three centers in two places, and multi-active in different places. - -Dubbo SDK supports Multiple mode for all three centers. - -- Multiple registries: Dubbo supports multiple registries, that is, an interface or an application can be registered in multiple registries, such as ZK clusters and Nacos clusters, and consumers can also subscribe from multiple registries Service address information for service discovery. By supporting multiple registration centers, it is ensured that one of the registration center clusters can be switched to another registration center cluster when it is unavailable, so that services can be provided normally and service calls can be initiated. This can also satisfy the registration center to adapt to various high-availability deployment architecture modes in deployment. -- Multiple configuration centers: Dubbo supports multiple configuration centers to ensure that when a configuration center cluster becomes unavailable, it can switch to another configuration center cluster to ensure that the global configuration, routing rules, and other information can be obtained from the configuration center normally. This can also satisfy the configuration center to adapt to various high-availability deployment architecture modes in deployment. - -- Multiple data centers: Dubbo supports multiple data centers: it is used to deal with disaster recovery and other situations where a metadata center cluster is unavailable. At this time, you can switch to another metadata center cluster to ensure that the metadata center can normally provide relevant service elements. Data management capabilities. - -Taking the registration center as an example, the following is a schematic diagram of the deployment architecture of a multi-active scenario: - -![multiple-registry-deployment-architecture](/imgs/v3/concepts/multiple-registry-deployment-architecture.png) \ No newline at end of file diff --git a/content/en/overview/what/core-features/_index.md b/content/en/overview/what/core-features/_index.md new file mode 100755 index 000000000000..39fca832de3b --- /dev/null +++ b/content/en/overview/what/core-features/_index.md @@ -0,0 +1,10 @@ +--- +aliases: + - /zh/overview/core-features/ + - /zh-cn/overview/core-features/ +description: Dubbo 核心特性 +linkTitle: 功能 +title: Dubbo 核心特性 +type: docs +weight: 4 +--- diff --git a/content/en/overview/what/core-features/ecosystem.md b/content/en/overview/what/core-features/ecosystem.md new file mode 100644 index 000000000000..dec12eb049c9 --- /dev/null +++ b/content/en/overview/what/core-features/ecosystem.md @@ -0,0 +1,46 @@ +--- +aliases: + - /zh-cn/overview/what/ecosystem/ + - /zh-cn/overview/core-features/ecosystem/ +description: 微服务生态 +feature: + description: | + 一站式微服务生态适配:注册中心、网关、限流降级、负载均衡、一致性事务、异步消息、Tracing 等。 + title: 丰富生态 +linkTitle: 微服务生态 +title: 微服务生态 +type: docs +weight: 10 +--- + +Dubbo 社区和众多优秀的开源项目一起围绕 Dubbo 建立了丰富的微服务生态支持,这让开发者从选型 Dubbo 作为开发框架的第一天,就无需担心后续的服务治理诉求,Dubbo 对每一个常见问题均提供了生产级的解决方案。 + +以下表格为基于最新 Dubbo Java 3.2.x 版本统计的生态组件支持情况,后续将根据开发进展持续更新。同时每个语言支持的组件完善度会有一定差异,具体请参见各个 [语言参考手册](../../mannual/) 内的详细说明 + +| 功能 | 组件列表 | 组件列表 | 组件列表 | 组件列表 | 组件列表 | +| --- | --- | --- | --- | --- | --- | +| 服务发现 | [Zookeeper](../../mannual/java-sdk/reference-manual/registry/zookeeper) | [Nacos](../../mannual/java-sdk/reference-manual/registry/nacos) | [Kubernetes Service](/) | DNS【开发中】 | 更多 | +| 动态配置 | [Zookeeper](../../mannual/java-sdk/reference-manual/config-center/zookeeper) | [Nacos](../../mannual/java-sdk/reference-manual/config-center/nacos) | [Apollo](../../mannual/java-sdk/reference-manual/config-center/apollo) | Kubernetes【开发中】| 更多 | +| 元数据管理 | [Zookeeper](../../mannual/java-sdk/reference-manual/metadata-center/zookeeper) | [Nacos](../../mannual/java-sdk/reference-manual/metadata-center/nacos) | [Redis](../../mannual/java-sdk/reference-manual/metadata-center/redis) | Kubernetes【开发中】 | 更多 | +| RPC 协议 | [HTTP/2 (Triple)](../../reference/protocols/triple) | [TCP](../../reference/protocols/tcp) | [HTTP/REST【Alpha】](../../reference/protocols/http) | [gRPC](../../reference/protocols/triple) | [更多](../../reference/protocols/) | +| 可视化观测平台 | [Admin](../../tasks/observability/admin/) | [Grafana](../../tasks/observability/grafana/) | [Prometheus](../../tasks/observability/prometheus/) | - | - | +| 全链路追踪 | [Zipkin](../../tasks/observability/tracing/zipkin/) | [Skywalking](../../tasks/observability/tracing/skywalking/) | OpenTelemetry | - | - | +| 限流降级 | [Sentinel](../../tasks/rate-limit/sentinel) | [Resilience4j](../../tasks/rate-limit/resilience4j) | [Hystrix](../../tasks/rate-limit/hystrix) | - | - | +| 分布式事务 | [Seata](../../tasks/ecosystem/transaction/) | - | - | - | - | +| 网关 | [Higress]({{< relref "../../../../blog/integration/how-to-proxy-dubbo-in-higress" >}}) | [APISIX](../../tasks/ecosystem/gateway/) | [Shenyu]({{< relref "../../../../blog/integration/how-to-proxy-dubbo-in-apache-shenyu" >}}) | [Envoy](https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/network_filters/dubbo_proxy_filter) | - | +| 服务网格 | Istio【开发中】 | Aeraka | OpenSergo【开发中】 | Proxyless【Alpha】 | 更多 | + + +## 微服务生态示例架构 + +{{< mse >}} + +{{< blocks/section color="white" height="auto" >}} +
+
+
+
+
+{{< /blocks/section >}} + + diff --git a/content/en/overview/what/core-features/extensibility.md b/content/en/overview/what/core-features/extensibility.md new file mode 100644 index 000000000000..38c1b3b9a5aa --- /dev/null +++ b/content/en/overview/what/core-features/extensibility.md @@ -0,0 +1,123 @@ +--- +aliases: + - /zh/overview/core-features/extensibility/ + - /zh-cn/overview/core-features/extensibility/ +description: 扩展适配 +feature: + description: | + 一切皆可扩展,通过扩展 (Filter、Router、Service Discovery、Configuration 等) 自定义调用、管控行为,适配开源微服务生态。 + title: 可扩展性 +linkTitle: 扩展适配 +title: 扩展适配 +type: docs +weight: 6 +--- + + + +Dubbo 从设计上是高度可扩展的,通过这些扩展点你可以做到: +* 拦截流量并控制流量行为 +* 按需调优 Dubbo 的一些默认策略与实现 +* 将 Dubbo 服务适配到公司内部微服务集群或其他主流的开源组件 + +## 一切皆可扩展 + +Dubbo 扩展能力使得 Dubbo 项目很方便的切分成一个一个的子模块,实现热插拔特性。用户完全可以基于自身需求,替换 Dubbo 原生实现,来满足自身业务需求。 + +![Admin 效果图](/imgs/v3/advantages/extensibility.png) + +* **协议与编码扩展**。通信协议、序列化编码协议等 +* **流量管控扩展**。集群容错策略、路由规则、负载均衡、限流降级、熔断策略等 +* **服务治理扩展**。注册中心、配置中心、元数据中心、分布式事务、全链路追踪、监控系统等 +* **诊断与调优扩展**。流量统计、线程池策略、日志、QoS 运维命令、健康检查、配置加载等 + + +## 基于扩展点的微服务生态 +众多的扩展点与抽象,是 Dubbo 与众多微服务生态组件对接、实现微服务治理能力的基础。 + +* [全链路追踪](../../tasks/observability/tracing/) +* [数据一致性](../../tasks/ecosystem/transaction/) +* [限流降级](../../core-features/traffic/circuit-breaking/) + +Dubbo 的各语言 sdk 实现都是采用的 "微内核+插件" 的设计模式,几乎所有流程中的核心节点都被定义为扩展点,官方发布的组件也是以扩展点的实现形式发布,因此 Dubbo 可以平等的对待所有官方与第三方组件扩展。 +* 扩展适配能力是实现 Dubbo 微服务生态的关键,Dubbo 生态组件如全链路追踪、注册中心实现等的适配都是基于 Filter、Registry、DynamicConfiguration 等扩展点实现。 +* 扩展适配给用户带来最大的灵活性,开发者可以随时接入公司内部组件、按需定制核心能力等。 + +![extensibility-echosystem.png](/imgs/v3/feature/extensibility/arc.png) + +以上是按架构层次划分的 Dubbo 内的一些核心扩展点定义及实现,从三个层次来展开: +* 协议通信层 +* 流量管控层 +* 服务治理层 + +## 协议通信层 +在通信协议一节我们强调过,Dubbo 不绑定任何协议,用户可以选择 Triple、gRPC、Dubbo2、REST、自定义协议等任一 RPC 远程通信协议,除此之外,RPC 协议之上的数据编码格式 (即序列化协议) 也是通过扩展点定义,用户可以灵活选择 RPC 与序列化的通信协议组合。 + +![协议与编码原理图](/imgs/v3/feature/extensibility/protocol.png) + +### Protocol +Protocol 扩展点定义对应的是 RPC 协议,利用这个扩展点可以让 Dubbo 作为统一的微服务开发和治理框架,而在下层通信协议上实现灵活切换。官方发布了对大多数主流 RPC 通信协议的适配,你可以通过几条简单的配置直接使用,如果你想使用公司自定义的 RPC 通信协议,请通过 Protocol 提供自定义扩展实现。 + +### Serialization +Serialization 扩展点定义了序列化协议扩展,Dubbo 官方提供了 Fastjson、Protobuf、Hessian2、Kryo、FST 等序列化协议适配。 + +## 流量管控层 +Dubbo 在服务调用链路上预置了大量扩展点,通过这些扩展点用户可以控制运行态的流量走向、改变运行时调用行为等,包括 Dubbo 内置的一些负载均衡策略、流量路由策略、超时等很多流量管控能力都是通过这类扩展点实现的。 + +![协议与编码原理图](/imgs/v3/feature/extensibility/traffic.png) + +### Filter +Filter 流量拦截器是 Dubbo 服务调用之上的 AOP 设计模式,Filter 用来对每次服务调用做一些预处理、后处理动作,使用 Filter 可以完成访问日志、加解密、流量统计、参数验证等任务,Dubbo 中的很多生态适配如限流降级 Sentinel、全链路追踪 Tracing 等都是通过 Fitler 扩展实现的。一次请求过程中可以植入多个 Filter,Filter 之间相互独立没有依赖。 +* 从消费端视角,它在请求发起前基于请求参数等做一些预处理工作,在接收到响应后,对响应结果做一些后置处理; +* 从提供者视角则,在接收到访问请求后,在返回响应结果前做一些预处理, + +### Router +Router 路由器是 Dubbo 中流量管控的关键组件,它将符合一定条件的流量转发到特定分组的地址子集,是 Dubbo 流量管控中一些关键能力如按比例流量转发、流量隔离等的基础。每次服务调用请求都会流经一组路由器 (路由链),每个路由器根据预先设定好的规则、全量地址列表以及当前请求上下文计算出一个地址子集,再传给下一个路由器,重复这一过程直到最后得出一个有效的地址子集。 + +Dubbo 官方发布版本预置了丰富的流量管控规则与 router 实现,如 [流量管控](../traffic/) 一文中阐述的,用户通过下发规则即可实现各种模式的流量管控。如果有其他流量管控诉求,可以通过提供自定义的 router 扩展实现。 + +### Load Balance +在 Dubbo 中,Load Balance 负载均衡工作在 router 之后,对于每次服务调用,负载均衡负责在 router 链输出的地址子集中选择一台机器实例进行访问,保证一段时间内的调用都均匀的分布在地址子集的所有机器上。 + +Dubbo 官方提供了加权随机、加权轮询、一致性哈希、最小活跃度优先、最短响应时间优先等负载均衡策略,还提供了根据集群负载自适应调度的负载均衡算法。 + +## 服务治理层 +以下是 Dubbo 部署的经典架构图,由注册中心 (服务发现)、配置中心和元数据中心构成了整个服务治理的核心。 + +![服务治理架构图](/imgs/v3/concepts/threecenters.png) + +这里我们主要从架构、实现的视角来分析了 Dubbo 服务治理,Dubbo 很多服务治理的核心能力都是通过上图描述的几个关键组件实现的,用户通过控制面或者 Admin 下发的各种规则与配置、各类微服务集群状态的展示等都是直接与注册中心、配置中心和元数据中心交互。 + +在具体实现或者部署上,注册中心、配置中心和元数据中心可以是同一组件,比如 Zookeeper 可同时作为注册、配置和元数据中心,Nacos 也是如此。因此,三个中心只是从架构职责上的划分,你甚至可以用同一个 Zookeeper 集群来承担所有三个职责,只需要在应用里将他们设置为同一个集群地址就可以了。 + +> 在云原生部署架构下,随着 Kubernetes、Service Mesh 架构的流行,微服务基础设施呈现下沉趋势,注册、配置和元数据中心的职责正被 Kubernetes、Istio 等组件取代,具体可参见 [服务网格](../service-mesh/) 一节的描述。 + +### Registry +注册中心是 Dubbo 实现服务发现能力的基础,Dubbo 官方支持 Zookeeper、Nacos、Etcd、Consul、Eureka 等注册中心。 + +通过对 Consul、Eureka 的支持,Dubbo 也实现了与 Spring Cloud 体系在地址和通信层面的互通,让用户同时部署 Dubbo 与 Spring Cloud,或者从 Spring Cloud 迁移到 Dubbo 变得更容易。 + +### Config Center +配置中心是用户实现动态控制 Dubbo 行为的关键组件,我们在 [流量管控](../../tasks/traffic-management) 任务中下发的所有规则,都是先下发到配置中心保存起来,进而 Dubbo 实例通过监听配置中心的变化,收到路由规则并达到控制流量的行为。 + +Dubbo 官方支持 Zookeeper、Nacos、Etcd、Redis、Apollo 等配置中心实现。 + +### Metadata Center +与配置中心相反,从用户视角来看元数据中心是只读的,元数据中心唯一的写入方是 Dubbo 进程实例,Dubbo 实例会在启动之后将一些内部状态(如服务列表、服务配置、服务定义格式等)上报到元数据中心,供一些治理能力作为数据来源,如服务测试、文档管理、服务状态展示等。 + +Dubbo 官方支持 Zookeeper、Nacos、Etcd、Redis 等元数据中心实现。 + +## 自定义扩展示例 + +以下示例演示了如何扩展 Dubbo 来解决实际问题,可以跟随示例学习。 + +* [自定义 RPC 协议](../../tasks/extensibility/protocol/) +* [自定义流量路由规则](../../tasks/extensibility/router/) +* [自定义注册中心](../../tasks/extensibility/registry/) +* [自定义拦截器](../../tasks/extensibility/filter/) + +## 更多扩展点 +本文列出了 Dubbo 常用的一些扩展点,但还有大量的扩展点可供灵活定制,并且不同语言 sdk 的扩展定义和配置方式上也存在差异,以下是 Dubbo SDK 的扩展点手册。 + +* [Java 扩展点手册](../../mannual/java-sdk/reference-manual/spi/description/) +* [Go 扩展点手册](../../mannual/golang-sdk/preface/design/aop_and_extension/) diff --git a/content/en/overview/what/core-features/load-balance.md b/content/en/overview/what/core-features/load-balance.md new file mode 100644 index 000000000000..fb888d68931c --- /dev/null +++ b/content/en/overview/what/core-features/load-balance.md @@ -0,0 +1,105 @@ +--- +aliases: + - /zh/overview/core-features/load-balance/ + - /zh-cn/overview/core-features/load-balance/ +description: 负载均衡 +linkTitle: 负载均衡 +title: 负载均衡 +type: docs +weight: 3 +--- + + + +在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 `weighted random` 基于权重的随机负载均衡策略。 + +具体实现上,Dubbo 提供的是客户端负载均衡,即由 Consumer 通过负载均衡算法得出需要将请求提交到哪个 Provider 实例。 + +## 负载均衡策略 +目前 Dubbo 内置了如下负载均衡算法,可通过调整配置项启用。 + +| 算法 | 特性 | 备注 | +| :-------------------------- | :---------------------- | :---------------------------------------------- | +| Weighted Random LoadBalance | 加权随机 | 默认算法,默认权重相同 | +| RoundRobin LoadBalance | 加权轮询 | 借鉴于 Nginx 的平滑加权轮询算法,默认权重相同, | +| LeastActive LoadBalance | 最少活跃优先 + 加权随机 | 背后是能者多劳的思想 | +| Shortest-Response LoadBalance | 最短响应优先 + 加权随机 | 更加关注响应速度 | +| ConsistentHash LoadBalance | 一致性哈希 | 确定的入参,确定的提供者,适用于有状态请求 | +| P2C LoadBalance | Power of Two Choice | 随机选择两个节点后,继续选择“连接数”较小的那个节点。 | +| Adaptive LoadBalance | 自适应负载均衡 | 在 P2C 算法基础上,选择二者中 load 最小的那个节点 | + +### Weighted Random + +* **加权随机**,按权重设置随机概率。 +* 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。 +* 缺点:存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。 + +### RoundRobin +* **加权轮询**,按公约后的权重设置轮询比率,循环调用节点 +* 缺点:同样存在慢的提供者累积请求的问题。 + +加权轮询过程中,如果某节点权重过大,会存在某段时间内调用过于集中的问题。 +例如 ABC 三节点有如下权重:`{A: 3, B: 2, C: 1}` +那么按照最原始的轮询算法,调用过程将变成:`A A A B B C` + +对此,Dubbo 借鉴 Nginx 的平滑加权轮询算法,对此做了优化,调用过程可抽象成下表: + +| 轮前加和权重 | 本轮胜者 | 合计权重 | 轮后权重(胜者减去合计权重) | +| :------------------ | :------- | :------- | :--------------------------- | +| 起始轮 | \ | \ | `A(0), B(0), C(0)` | +| `A(3), B(2), C(1)` | A | 6 | `A(-3), B(2), C(1)` | +| `A(0), B(4), C(2)` | B | 6 | `A(0), B(-2), C(2)` | +| `A(3), B(0), C(3)` | A | 6 | `A(-3), B(0), C(3)` | +| `A(0), B(2), C(4)` | C | 6 | `A(0), B(2), C(-2)` | +| `A(3), B(4), C(-1)` | B | 6 | `A(3), B(-2), C(-1)` | +| `A(6), B(0), C(0)` | A | 6 | `A(0), B(0), C(0)` | + +我们发现经过合计权重(3+2+1)轮次后,循环又回到了起点,整个过程中节点流量是平滑的,且哪怕在很短的时间周期内,概率都是按期望分布的。 + +如果用户有加权轮询的需求,可放心使用该算法。 + +### LeastActive +* **加权最少活跃调用优先**,活跃数越低,越优先调用,相同活跃数的进行加权随机。活跃数指调用前后计数差(针对特定提供者:请求发送数 - 响应返回数),表示特定提供者的任务堆积量,活跃数越低,代表该提供者处理能力越强。 +* 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大;相对的,处理能力越强的节点,处理更多的请求。 + +### ShortestResponse +* **加权最短响应优先**,在最近一个滑动窗口中,响应时间越短,越优先调用。相同响应时间的进行加权随机。 +* 使得响应时间越快的提供者,处理更多的请求。 +* 缺点:可能会造成流量过于集中于高性能节点的问题。 + +这里的响应时间 = 某个提供者在窗口时间内的平均响应时间,窗口时间默认是 30s。 + + +### ConsistentHash +* **一致性 Hash**,相同参数的请求总是发到同一提供者。 +* 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。 +* 算法参见:[Consistent Hashing | WIKIPEDIA](http://en.wikipedia.org/wiki/Consistent_hashing) +* 缺省只对第一个参数 Hash,如果要修改,请配置 `` +* 缺省用 160 份虚拟节点,如果要修改,请配置 `` + +### P2C Load Balance +Power of Two Choice 算法简单但是经典,主要思路如下: + +1. 对于每次调用,从可用的provider列表中做两次随机选择,选出两个节点providerA和providerB。 +2. 比较providerA和providerB两个节点,选择其“当前正在处理的连接数”较小的那个节点。 + +以下是 [Dubbo P2C 算法实现提案](../../reference/proposals/heuristic-flow-control/#p2c算法) + +### Adaptive Load Balance +Adaptive 即自适应负载均衡,是一种能根据后端实例负载自动调整流量分布的算法实现,它总是尝试将请求转发到负载最小的节点。 + +以下是 [Dubbo Adaptive 算法实现提案](../../reference/proposals/heuristic-flow-control/#adaptive算法) + +## 配置方式 +Dubbo 支持在服务提供者一侧配置默认的负载均衡策略,这样所有的消费者都将默认使用提供者指定的负载均衡策略,消费者可以自己配置要使用的负载均衡策略,如果都没有任何配置, +则默认使用随机负载均衡策略。 + +同一个应用内支持配置不同的服务使用不同的负载均衡策略,支持为同一服务的不同方法配置不同的负载均衡策略。 + +具体配置方式参加以下多语言实现 + +* [Java](../../mannual/java-sdk/advanced-features-and-usage/performance/loadbalance/#使用方式) +* [Golang](../../mannual/golang-sdk/) + +## 自定义扩展 +负载均衡策略支持自定义扩展实现,具体请参见 [Dubbo 可扩展性](../extensibility) diff --git a/content/en/overview/what/core-features/more.md b/content/en/overview/what/core-features/more.md new file mode 100644 index 000000000000..17f44509b4e3 --- /dev/null +++ b/content/en/overview/what/core-features/more.md @@ -0,0 +1,72 @@ +--- +aliases: + - /zh/overview/core-features/more/ + - /zh-cn/overview/core-features/more/ +description: 高级功能指南 +linkTitle: 更多高级功能 +title: 更多高级功能 +type: docs +weight: 11 +--- + + +作为一款与应用开发紧密相关的微服务框架,同时旨在为微服务集群提供企业级服务治理能力,Dubbo 还提供了很多高级功能,涵盖服务调用行为控制、服务诊断与调优、服务治理等。 + +多种语言 sdk 在功能实现、配置方式上会略有差异,具体功能列表和使用方式可参考如下文档: +* [Java](../../mannual/java-sdk/advanced-features-and-usage/) +* [Golang](../../mannual/golang-sdk/tutorial/) + +## 控制服务调用行为 +* 服务版本 +* 服务分组 +* 分组聚合 +* 异步调用 +* 异步执行 +* 流式通信 +* 响应式编程 +* 泛化调用 +* 泛化实现 +* 调用链路传递隐式参数 +* RPC调用上下文 +* 调用触发事件通知 +* 服务端对客户端进行回调 +* 只订阅 +* 只注册 +* 运行时动态指定 IP 调用 +* 直连提供者 +* 启动时检查 +* 本地调用 +* 参数校验 +* 本地伪装 +* 本地存根 +* 回声测试 +* 调用信息记录 +* 延迟暴露 +* 集群容错 +* 服务降级 + +## 诊断与调优 +* 端口协议复用 +* 线程池隔离 +* 多协议 +* 多注册中心 +* 请求耗时采样 +* 线程模型 +* 服务引用配置对象缓存 +* 路由状态采集 +* 负载均衡 +* 注册信息简化 +* 调用结果缓存 +* 并发控制 +* 连接控制 +* 延迟连接 +* 粘滞连接 +* 支持 Graal VM +* 导出线程堆栈 +* Kryo 和 FST 序列化 +* 自定义服务容器 +* 优雅停机 +* 主机地址自定义暴露 +* 一致性哈希选址 +* 日志框架适配及运行时管理 +* Kubernetes 生命周期探针 diff --git a/content/en/overview/what/core-features/observability.md b/content/en/overview/what/core-features/observability.md new file mode 100644 index 000000000000..230bae6d754e --- /dev/null +++ b/content/en/overview/what/core-features/observability.md @@ -0,0 +1,60 @@ +--- +aliases: + - /zh/overview/core-features/observability/ + - /zh-cn/overview/core-features/observability/ +description: 观测服务 +feature: + description: | + 多维度的可观测指标(Metrics、Tracing、Accesslog)帮助了解服务运行状态,Admin 控制台、Grafana 等帮助实现数据指标可视化展示。 + title: 可观测性 +linkTitle: 观测服务 +title: 观测服务 +type: docs +weight: 7 +--- + + + +Dubbo 内部维护了多个纬度的可观测指标,并且支持多种方式的可视化监测。可观测性指标从总体上来说分为三个度量纬度: + +* **Admin** Admin 控制台可视化展示了集群中的应用、服务、实例及依赖关系,支持流量治理规则下发,同时还提供如服务测试、mock、文档管理等提升研发测试效率的工具。 + +* **Metrics** Dubbo 统计了一系列的流量指标如 QPS、RT、成功请求数、失败请求数等,还包括一系列的内部组件状态如线程池数、服务健康状态等。 + +* **Tracing** Dubbo 与业界主流的链路追踪工作做了适配,包括 Skywalking、Zipkin、Jaeger 都支持 Dubbo 服务的链路追踪。 + +* **Logging** Dubbo 支持多种日志框架适配。以 Java 体系为例,支持包括 Slf4j、Log4j2、Log4j、Logback、Jcl 等,用户可以基于业务需要选择合适的框架;同时 Dubbo 还支持 Access Log 记录请求踪迹。 + +## Admin +Admin 控制台可视化展示了集群中的应用、服务、实例及依赖关系,支持流量治理规则下发,同时还提供如服务测试、mock、文档管理等提升研发测试效率的工具 + +![Admin 效果图](/imgs/v3/feature/observability/admin.jpg) + +* [Admin 部署与效果演示](../../tasks/observability/admin/) + +## Metrics +Dubbo 运行时统计了包括 qps、rt、调用总数、成功数、失败数,失败原因统计等在内的核心服务指标,同时,为了更好的监测服务运行状态,Dubbo 还提供了对核心组件状态的监控,如线程池数量、服务健康状态等。 + +可以通过 Grafana 可视化的查看 Metrics 指标 + +![Grafana 效果图](/imgs/v3/feature/observability/provider-stat.png) + +* [使用 Grafana 可视化展示 Metrics 指标](../../tasks/observability/grafana/) +* [如何从 Prometheus 查询特定 Metrics 指标](../../tasks/observability/prometheus/) + +## Tracing +全链路追踪对于监测分布式系统运行状态具有非常重要的价值,Dubbo 通过 Filter 拦截器实现了请求运行时的埋点跟踪,通过将跟踪数据导出到一些主流实现如 Zipkin、Skywalking、Jaeger 等,可以实现全链路跟踪数据的分析与可视化展示。 + +![Tracing 效果图](/imgs/v3/feature/observability/tracing.png) + +> 未来我们计划支持通过 Dubbo Admin 等治理平台动态调整 Dubbo 的链路追踪采样率。 + +* [基于 Skywalking 实现全链路追踪](../../tasks/observability/tracing/skywalking/) +* [基于 Zipkin 实现全链路追踪](../../tasks/observability/tracing/zipkin/) +* [通过链路追踪关联日志系统](../../mannual/java-sdk/advanced-features-and-usage/observability/tracing#关联日志) + +## Logging +访问日志可以帮助分析系统的流量情况,在有些场景下,开启访问日志对于排查问题也非常有帮助。 + +* [开启 Access Log](../../mannual/java-sdk/advanced-features-and-usage/service/accesslog/) +* [你还在运行态开启 Access Log](../../tasks/traffic-management/accesslog/) diff --git a/content/en/overview/what/core-features/protocols.md b/content/en/overview/what/core-features/protocols.md new file mode 100644 index 000000000000..befc5b87b2c1 --- /dev/null +++ b/content/en/overview/what/core-features/protocols.md @@ -0,0 +1,89 @@ +--- +aliases: + - /zh/overview/core-features/protocols/ + - /zh-cn/overview/core-features/protocols/ +description: 通信协议 +feature: + description: | + 支持 HTTP/2、gRPC、TCP、REST 等任意通信协议,切换协议只需要修改一行配置,支持单个端口上的多协议发布。 + title: 通信协议 +linkTitle: 通信协议 +title: 通信协议 +type: docs +weight: 5 +--- + +Dubbo 框架提供了自定义的高性能 RPC 通信协议:基于 HTTP/2 的 Triple 协议 和 基于 TCP 的 Dubbo2 协议。除此之外,Dubbo 框架支持任意第三方通信协议,如官方支持的 gRPC、Thrift、REST、JsonRPC、Hessian2 等,更多协议可以通过自定义扩展实现。这对于微服务实践中经常要处理的多协议通信场景非常有用。 + +**Dubbo 框架不绑定任何通信协议,在实现上 Dubbo 对多协议的支持也非常灵活,它可以让你在一个应用内发布多个使用不同协议的服务,并且支持用同一个 port 端口对外发布所有协议。** + +![protocols](/imgs/v3/feature/protocols/protocol1.png) + +通过 Dubbo 框架的多协议支持,你可以做到: +* 将任意通信协议无缝地接入 Dubbo 服务治理体系。Dubbo 体系下的所有通信协议,都可以享受到 Dubbo 的编程模型、服务发现、流量管控等优势。比如 gRPC over Dubbo 的模式,服务治理、编程 API 都能够零成本接入 Dubbo 体系。 +* 兼容不同技术栈,业务系统混合使用不同的服务框架、RPC 框架。比如有些服务使用 gRPC 或者 Spring Cloud 开发,有些服务使用 Dubbo 框架开发,通过 Dubbo 的多协议支持可以很好的实现互通。 +* 让协议迁移变的更简单。通过多协议、注册中心的协调,可以快速满足公司内协议迁移的需求。比如如从自研协议升级到 Dubbo 协议,Dubbo 协议自身升级,从 Dubbo 协议迁移到 gRPC,从 HTTP 迁移到 Dubbo 协议等。 + +## HTTP/2 (Triple) +Triple 协议是 Dubbo3 发布的面向云原生时代的通信协议,它基于 HTTP/2 并且完全兼容 gRPC 协议,原生支持 Streaming 通信语义,Triple 可同时运行在 HTTP/1 和 HTTP/2 传输协议之上,让你可以直接使用 curl、浏览器访问后端 Dubbo 服务。 + +自 Triple 协议开始,Dubbo 还支持基于 Protocol Buffers 的服务定义与数据传输,但 Triple 实现并不绑定 IDL,比如你可以直接使用 Java Interface 定义和发布 Triple 服务。Triple 具备更好的网关、代理穿透性,因此非常适合于跨网关、代理通信的部署架构,如服务网格等。 + +Triple 协议的核心特性如下: +* 支持 TLS 加密、Plaintext 明文数据传输 +* 支持反压与限流 +* 支持 Streaming 流式通信 +* 同时支持 HTTP/1 和 HTTP/2 传输协议 + +在编程与通信模型上,Triple 协议支持如下模式: +* 消费端异步请求(Client Side Asynchronous Request-Response) +* 提供端异步执行(Server Side Asynchronous Request-Response) +* 消费端请求流(Request Streaming) +* 提供端响应流(Response Streaming) +* 双向流式通信(Bidirectional Streaming) + +开发实践 +* Triple 协议使用请参见 [Triple 协议开发任务](../../tasks/protocols/triple/) 或 [java sdk 示例文档](../../mannual/java-sdk/reference-manual/protocol/triple/) +* [Triple 设计思路与协议规范](../../reference/protocols/triple/) + +## Dubbo2 +Dubbo2 协议是基于 TCP 传输层协议之上构建的一套 RPC 通信协议,由于其紧凑、灵活、高性能的特点,在 Dubbo2 时代取得了非常广泛的应用,是企业构建高性能、大规模微服务集群的关键通信方案。在云原生时代,我们更推荐使用通用性、穿透性更好的 Triple 协议。 + +Dubbo2 协议也内置 HTTP 支持,因此你可以使用 curl 在开发阶段快速验证或调试服务。 + +* [Dubbo2 协议开发任务](../../tasks/protocols/dubbo/) +* [Dubbo2 设计思路与协议规范](../../reference/protocols/tcp/) + +## gRPC +你可以用 Dubbo 开发和治理微服务,然后设置使用 gRPC 协议进行底层通信。但为什么要这么做呢,与直接使用 gRPC 框架对比有什么优势?简单的答案是,这是使用 gRPC 进行微服务开发的常用模式,具体请往下看。 + +gRPC 是谷歌开源的基于 HTTP/2 的通信协议,如同我们在 [产品对比](../../what/xyz-difference) 文档中提到的,gRPC 的定位是通信协议与实现,是一款纯粹的 RPC 框架,而 Dubbo 定位是一款微服务框架,为微服务实践提供解决方案。因此,相比于 Dubbo,gRPC 相对欠缺了微服务编程模型、服务治理等能力的抽象。 + +在 Dubbo 体系下使用 gRPC 协议 (gRPC over Dubbo Framework) 是一个非常高效和轻量的选择,它让你既能使用原生的 gRPC 协议通信,又避免了基于 gRPC 进行二次定制与开发的复杂度 (二次开发与定制 gRPC,是很多企业规模化实践后证实不可避免的环节,Dubbo 框架替开发者完成了这一步,让开发者可以直接以最简单的方式使用 gRPC)。 + +[gRPC over Dubbo 示例](../../tasks/protocols/grpc/) + +## REST +微服务领域常用的一种通信模式是 HTTP + JSON,包括 Spring Cloud、Microprofile 等一些主流的微服务框架都默认使用的这种通信模式,Dubbo 同样提供了对基于 HTTP 的编程、通信模式的支持。 + +* [HTTP over Dubbo 示例](../../tasks/protocols/web/) +* [Dubbo 与 Spring Cloud 体系互通](../../tasks/protocols/springcloud/) + +## 其他通信协议 +除了以上介绍的几种协议之外,你还可以将以下协议运行在 Dubbo 之上。对 Dubbo 而言,只需要修改一行简单的配置,就可以切换底层服务的通信协议,其他外围 API 和治理能力不受影响。 +* Hessian2 +* Thrift +* JsonRPC + +## 异构微服务体系互通 +关于协议迁移、多协议技术栈共存的实践方案,请参考本篇[博客文章](/zh-cn/blog/2023/01/05/dubbo-连接异构微服务体系-多协议多注册中心/)。 + +## 配置方式 +以上协议的配置和使用方式,包括如何配置 `单端口多协议` 支持等,请参照以下 sdk 示例文档: + +* [Java](../../mannual/java-sdk/reference-manual/protocol/) +* [Golang](../../mannual/golang-sdk/tutorial/develop/protocol/) +* [Rust](../../mannual/rust-sdk/) + +## 自定义扩展 +除了以上官方版本支持的通信协议,Dubbo 支持扩展新协议支持,具体请参见 [【任务】-【可扩展性】-【protocol】](../../tasks/extensibility/protocol/) diff --git a/content/en/overview/what/core-features/security.md b/content/en/overview/what/core-features/security.md new file mode 100644 index 000000000000..cc133bf260de --- /dev/null +++ b/content/en/overview/what/core-features/security.md @@ -0,0 +1,109 @@ +--- +aliases: + - /zh/overview/core-features/security/ + - /zh-cn/overview/core-features/security/ +description: 认证鉴权 +feature: + description: | + 支持基于 TLS 的传输链路认证与加密通信以及基于请求身份的权限校验,帮助构建零信任分布式微服务体系。 + title: 认证鉴权 +linkTitle: 认证鉴权 +title: 认证鉴权 +type: docs +weight: 8 +--- + +Dubbo 提供了构建安全微服务通信体系 (零信任体系) 的完善机制,这包括: +* 避免通信过程中的中间人攻击,Dubbo 提供了身份认证 (Authentication) 和基于 TLS 的通信链路加密能力 +* 控制服务间的访问鉴权 (Authorization),Dubbo 提供了 mTLS 和权限检查机制 + +通过这篇文档,你将了解如果使用 Dubbo 的安全机制构建微服务零信任体系,实现身份认证、透明链路加密、鉴权、审计等能力。由于构建零信任是一套系统的工作,而 Dubbo 只是其中数据通信层的一环,因此你可能需要一系列基础设施的配合,包括证书生成、分发、安全策略管控等。 + +> **证书的生成和分发不在本文讨论范围,我们假设您已经有完善的基础设施解决了证书管理问题,因此,我们将更专注在讲解 Dubbo 体系的认证和鉴权机制与流程。** 如果您并没有这些证书管理设施,我们推荐您使用服务网格架构 (具体请参见 [Dubbo Mesh 服务网格](../service-mesh/) 文档说明),借助 [Istio](https://istio.io/latest/docs/concepts/security/) 等服务网格控制面的证书管理机制和安全策略,您可以很容易将 Dubbo 集群的认证和鉴权能力实施起来。 + +> 另外,以下默认讲的都是 Dubbo Proxyless Mesh 模式下的 Dubbo 数据面行为,对于部署 Envoy 的场景,由于 Dubbo 只是作为通信和编程 sdk,因此 Envoy 场景下认证鉴权能力请完全参考标准 Istio 文档即可。 + +## 架构 + +一套完整的零信任体系包含多个组成部分: + +* 一个根证书机构 (CA) 来负责管理 key 和 certificate +* 一个安全策略的管理和分发中心,来负责将安全策略实时下发给数据面组件: + * 认证策略 + * 鉴权策略 + * 安全命名信息 (Secure Naming Information) +* 数据面组件 (Dubbo) 负责识别和执行身份认证、加密、策略解析等动作 +* 一系列的工具和生态,配合完成安全审计、数据链路监控等工作 + +在服务网格 (Istio) 部署模式下,控制面通常负责安全策略、证书等的管理,控制面负责与基础设施如 Kubernetes API Server 等交互,将配置数据下发给 Dubbo 或者 Envoy 等数据面组件。但如我们前面提到的,我们假设控制面产品已经就绪,因此不会涉及控制面如何签发证书、定义认证鉴权策略的讨论,我们将专注在 Dubbo 作为数据面的职责及与控制面的交互流程上。 + +以下是完整的 Dubbo 零信任架构图 + +![Authentication](/imgs/v3/feature/security/arch.png) + +## Authentication 认证 + +Dubbo 提供了两种认证模式: + +* **传输通道认证 (Channel Authentication)**:Dubbo 支持基于 TLS 的 HTTP/2 和 TCP 通信,通过 Channel Authentication API 或者控制面认证策略可以开启 TLS,实现 Server 身份端认证以及数据链路加密。另外,还可以开启 mTLS 实现 Client、Server 双向认证。Channel Authentication 是 service-to-service 模式的认证,代表的是服务或实例的身份认证。 +* **请求认证 (Request Authentication)**:Dubbo 提供了 API 用来在用户请求上下文中放入代表用户身份的 credential (如 JSON Web Token),Dubbo 框架将自动识别请求中的身份信息并进行权限校验。另外,你也可以定制请求上下文中的身份,如放入 Access Token 的如 OAuth2 tokens。Request Authentication 是 end-user 模式的认证,代表登录系统的用户身份的认证。 + +### 架构图 + +你可以使用 Istio 控制面管理证书、认证策略等,不同的认证策略会影响 Dubbo 数据面的认证行为,如是否开启 mTLS、是否允许迁移阶段的 Plaintext 请求等。 + +在 Istio 模式下,Dubbo 认证机制通过 xDS 实现了和 Istio 控制面的自动对接,即 Istio 控制面生成的证书、认证策略配置会自动的下发到 Dubbo 数据面,Dubbo 数据面通过 Authentication API 接收配置并将它们应用到后续的所有数据通信环节,如启用新的证书、执行新的认证策略等。 + +如果认证策略开启了 Request Authentication,则 Dubbo 数据面要负责 JWT token 的读取与填充,即 token 要在请求发起前附加到请求上下文中。Request Authentication 使用的前提一定是开启了 Channel Authentication,否则 Request Authentication 无法生效。 + +![Authentication](/imgs/v3/feature/security/auth-1.png) + +#### Dubbo mTLS 流程 + +在 Istio 部署架构下,可以通过控制面认证策略开启或关闭 Channel Authentication 的双向认证,双向认证的工作流程如下: + +1. 通过 Istio 下发认证策略,开启双向认证 +2. Dubbo 客户端同服务端开启双向 TLS 握手,在此期间,Dubbo 客户端会做 secure naming check 以检查服务端的身份(它被证实是有运行这个服务的合法身份)。 +3. 客户端和服务端之间建立一条双向的 mTLS 链接,随后发起正常的加密通信。 +4. Dubbo 服务端收到请求后,识别客户端身份并检查其是否有权限访问响应的资源。 + +### 认证策略 +具体请查看 Istio 官方支持的认证规则,Dubbo 完全支持 Istio 定义的认证策略。 + +https://istio.io/latest/docs/concepts/security/#authentication-policies + +## Authorization 鉴权 + +Dubbo 抽象了一套鉴权的扩展机制,但当前在具体实现上只支持 Istio 体系,因此其鉴权能力与 Istio 官方描述对等。具体可参见 +[Istio 鉴权文档](https://istio.io/latest/docs/concepts/security/#authorization) + +### 架构图 + +Dubbo 通过 xDS 与 Istio 控制面的数据通道,接收用户配置的鉴权策略,当一个请求到达 Dubbo 实例时,Dubbo SDK 使用内置的鉴权策略引擎将请求参数和用户身份与鉴权策略进行匹配,如果匹配成功则允许访问,否则拒绝访问。 + +![Authorization](/imgs/v3/feature/security/authz-1.png) + +Dubbo 完整的鉴权工作流程如下: + +![Authorization](/imgs/v3/feature/security/authz-2.png) + +### 鉴权策略 +具体请查看 Istio 官方支持的鉴权规则,Dubbo 完全支持 Istio 定义的鉴权策略。 + +https://istio.io/latest/docs/concepts/security/#authorization-policies + + +## Dubbo 认证 API +Dubbo 定义了一套认证 API,对于常规使用的场景,开发者可以通过这套 API 启用 TLS/mTLS 通信;但对于 Istio 控制面部署的场景,Dubbo 会自动识别 Istio 控制面下发的证书和认证策略,因此只需要与 Istio 控制面交互即可,不需要 Dubbo 侧的特别配置。 + +不论是否使用 Istio 控制面,对于 Request Authentication,JWT token 仍需要在 Dubbo 侧编程指定。 + +每种语言实现的认证 API 定义略有差异,具体定义请参考各 SDK 文档: +* [Java](/) +* [Go](/) +* [Rust](/) +* [Node.js](/) + +## 示例任务 + +访问如下 [Dubbo 任务示例](/) 进行安全策略动手实践。 diff --git a/content/en/overview/what/core-features/service-definition.md b/content/en/overview/what/core-features/service-definition.md new file mode 100644 index 000000000000..907564b35f0e --- /dev/null +++ b/content/en/overview/what/core-features/service-definition.md @@ -0,0 +1,129 @@ +--- +aliases: + - /zh/overview/core-features/service-definition/ + - /zh-cn/overview/core-features/service-definition/ +description: 微服务开发 +linkTitle: 微服务开发 +title: 微服务开发 +type: docs +weight: 1 +--- + + +Dubbo 解决企业微服务从开发、部署到治理运维的一系列挑战,Dubbo 为开发者提供从项目创建、开发测试,到部署、可视化监测、流量治理,再到生态集成的全套服务。 +* **开发层面**,Dubbo 提供了 Java、Go、Rust、Node.js 等语言实现并定义了一套微服务开发范式,配套脚手架可用于快速创建微服务项目骨架 +* **部署层面**,Dubbo 应用支持虚拟机、Docker 容器、Kubernetes、服务网格架构部署 +* **服务治理层面**,Dubbo 提供了地址发现、负载均衡、流量管控等治理能力,官方还提供 Admin 可视化控制台、丰富的微服务生态集成 + +## 开发 + +接下来以 Java 体系 Spring Boot 项目为例讲解 Dubbo 应用开发的基本步骤,整个过程非常直观简单,其他语言开发过程类似。 + +### 创建项目 +Dubbo 微服务项目脚手架(支持浏览器页面、命令行和 IDE)可用于快速创建微服务项目,只需要告诉脚手架期望包含的功能或组件,脚手架最终可以帮助开发者生成具有必要依赖的微服务工程。更多脚手架使用方式的讲解,请参见任务模块的 [通过模板生成项目脚手架](../../tasks/develop/template/) + +![脚手架示例图](/imgs/v3/advantages/initializer.png) + +### 开发服务 + +**1. 定义服务** + +```java +public interface DemoService { + String hello(String arg); +} +``` + +**2. 提供业务逻辑实现** + +```java +@DubboService +public class DemoServiceImpl implements DemoService { + public String hello(String arg) { + // put your microservice logic here + } +} +``` + +### 发布服务 +**1. 发布服务定义** + +为使消费方顺利调用服务,服务提供者首先要将服务定义以 Jar 包形式发布到 Maven 中央仓库。 + +**2. 对外暴露服务** + +补充 Dubbo 配置并启动 Dubbo Server + +```yaml +dubbo: + application: + name: dubbo-demo + protocol: + name: dubbo + port: -1 + registry: + address: zookeeper://127.0.0.1:2181 +``` + +### 调用服务 + +首先,消费方通过 Maven/Gradle 引入 `DemoService` 服务定义依赖。 + +```xml + + org.apache.dubbo + dubbo-demo-interface + 3.2.0 + +``` + +编程注入远程 Dubbo 服务实例 + +```java +@Bean +public class Consumer { + @DubboReference + private DemoService demoService; +} +``` + +以上是 Dubbo 微服务开发的流程性说明,实际开发的详细指导步骤请参见: +* [Java 微服务开发入门](../../quickstart/java) +* [Go 微服务开发入门](../../quickstart/go) +* [Rust 微服务开发入门](../../quickstart/rust) +* [Node.js 微服务开发入门](https://github.com/apache/dubbo-js) + +## 部署 +Dubbo 原生服务可打包部署到 Docker 容器、Kubernetes、服务网格 等云原生基础设施和微服务架构。 + +关于不同环境的部署示例,可参考: +* [部署 Dubbo 服务到 Docker 容器](../../tasks/deploy/deploy-on-docker) +* [部署 Dubbo 服务到 Kubernetes](../../tasks/deploy/deploy-on-k8s-docker) + +## 治理 +对于服务治理,绝大多数应用只需要增加以下配置即可,Dubbo 应用将具备地址发现和负载均衡能力。 + +```yaml +dubbo: + registry: + address: zookeeper://127.0.0.1:2181 +``` + +部署并打开 [Dubbo Admin 控制台](../../tasks/deploy),可以看到集群的服务部署和调用数据 + +![Admin](/imgs/v3/what/admin.png) + +除此之外,Dubbo Amin 还可以通过以下能力提升研发测试效率 +* 文档管理,提供普通服务、IDL 文档管理 +* 服务测试 & 服务 Mock +* 服务状态查询 + +对于更复杂的微服务实践场景,Dubbo 还提供了更多高级服务治理特性,具体请参见文档了解更多。包括: +* 流量治理 +* 动态配置 +* 限流降级 +* 数据一致性 +* 可观测性 +* 多协议 +* 多注册中心 +* 服务网格 diff --git a/content/en/overview/what/core-features/service-definition.md.bak b/content/en/overview/what/core-features/service-definition.md.bak new file mode 100644 index 000000000000..27fd038a8e5d --- /dev/null +++ b/content/en/overview/what/core-features/service-definition.md.bak @@ -0,0 +1,497 @@ +--- +type: docs +title: "Dubbo 一站式微服务开发" +linkTitle: "微服务开发" +weight: 1 +description: "" +feature: + title: 定义服务 + description: > + 定义服务 +--- + +本文可帮助开发者了解 Dubbo 微服务项目构建、开发、部署、观测、治理的全生命周期基本流程,这篇文档更多的是展示 Dubbo 的开发流程与开发模式。 + +如果您需要可实际动手实践的示例,期望能跟随示例讲解一步步的完成开发,请参考以下每个语言的快速开始: +* [Java 快速开始]() +* [Go 快速开始]() +* [Rust 快速开始]() + +## 第一步,准备微服务环境 +在开发微服务之前,您需要安装相关的微服务基础设施如注册中心、服务治理控制台等。 + +以下文档可以引导您快速的安装 Nacos、Zookeeper、Dubbo Admin 等注册中心与控制台组件。 +* [Kubernetes 环境安装]() +* [传统虚拟机环境安装]() + +安装注册中心、服务治理中心等组件 + +## 第一步,初始化项目 +如果您正在使用 Java 或 Go 开发微服务,则可以使用 Dubbo 提供的脚手架快速创建项目骨架,骨架项目包含开发 Dubbo 必须的依赖和配置,同时还包含一些对应的微服务开发的常用模式: +* Java 项目脚手架 +* Go 项目脚手架 + +以下是一个脚手架示例项目结构: + +![骨架项目截图]() + +可以直接导入 IDE 开始微服务业务开发。对于除 Java 和 Go 之外的其他语言,您也可以基于 Dubbo 提供的指引快速的创建项目。 + +## 第二步,定义服务 +服务是 Dubbo 开发、通信和治理的基本单位,通常我们讲的 Dubbo 服务是一个类似编程语言接口的概念,它是一系列可以被调用的方法的集合。通常来说,服务提供者 (Server) 负责提供服务定义的实现,而服务消费者 (Client) 基于服务定义对服务提供者发起 RPC 调用。 + +Dubbo 提供多种语言实现,开发者既可以选择以语言特有的方式定义服务,也可以选择使用语言中立的 IDL (Proto Buffers) 定义服务。 + +{{< tabpane langEqualsHeader=true >}} +{{< tab header="Java" >}} +public interface DemoService { + String sayHello(String name); +} +{{< /tab >}} +{{< tab header="Go" >}} +type DemoService struct { + SayHello func(req []string) (string, error) +} +{{< /tab >}} +{{< tab header="IDL" >}} +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.dubbo.demo.hello"; +option java_outer_classname = "HelloWorldProto"; +option objc_class_prefix = "HLW"; + +package helloworld; + +service Greeter{ + // unary + rpc greet(HelloRequest) returns (HelloReply); +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} +{{< /tab >}} +{{< /tabpane >}} + +## 第三步,开发服务提供者 +服务提供者(Server)需要完成两件事情: +1. 基于上一步的服务定义给出业务逻辑实现 +2. 启动一个 Dubbo Server 监听来自客户端的请求并返回服务响应 +

+ +首先,开发者遵循服务定义规范编写业务逻辑实现,如业务类需要实现特定接口或者抽象某个抽象类等。 +

+ +{{< tabpane langEqualsHeader=true >}} +{{< tab header="Java" >}} +public class DemoServiceImpl implements DemoService { + @Override + public String sayHello(String name) { + return "Hello " + name + ", response from provider: " + RpcContext.getServiceContext().getLocalAddress(); + } +} +{{< /tab >}} +{{< tab header="Go" >}} +type DemoServiceImpl struct { +} + +func (u *DemoServiceImpl) SayHello(msg string) (string, error) { + return "Response message!", nil +} +{{< /tab >}} +{{< tab header="IDL Java" lang="Java" >}} +// Code generated by Dubbo plugin of protoc compiler +// Greeter.java +public interface Greeter { + String JAVA_SERVICE_NAME = "org.apache.dubbo.demo.hello.Greeter"; + String SERVICE_NAME = "helloworld.Greeter"; + + org.apache.dubbo.demo.hello.HelloReply greet(org.apache.dubbo.demo.hello.HelloRequest request); + + default CompletableFuture greetAsync(org.apache.dubbo.demo.hello.HelloRequest request){ + return CompletableFuture.completedFuture(greet(request)); + } + // ...... +} + +// Code generated by Dubbo plugin of protoc compiler +// DubboGreeterTriple.java +public static abstract class GreeterImplBase implements Greeter, ServerService { + @Override + public org.apache.dubbo.demo.hello.HelloReply greet(org.apache.dubbo.demo.hello.HelloRequest request){ + throw unimplementedMethodException(greetMethod); + } + // ...... +} + +// The actual business logic that is written and provided by Dubbo user +public class GreeterServiceImpl extends DubboGreeterTriple.GreeterImplBase { + @Override + public HelloReply greet(HelloRequest request) { + return HelloReply.newBuilder() + .setMessage("Hello " + request.getName()) + .build(); + } +} +{{< /tab >}} +{{< tab header="IDL Go" lang="Go" >}} +// Paste the protoc generated and user provided code snippet here. +{{< /tab >}} +{{< tab header="IDL Rust" lang="Rust" >}} +use ... + +#[allow(dead_code)] +#[derive(Default, Clone)] +struct GreeterServerImpl { + name: String, +} + +// #[async_trait] +#[async_trait] +impl Greeter for GreeterServerImpl { + async fn greet( + &self, + request: Request, + ) -> Result, dubbo::status::Status> { + println!("GreeterServer::greet {:?}", request.metadata); + + Ok(Response::new(GreeterReply { + message: "hello, dubbo-rust".to_string(), + })) + } +} +{{< /tab >}} +{{< tab header="IDL Node.js" >}} +// Paste the protoc generated and user provided code snippet here. +{{< /tab >}} +{{< /tabpane >}} + +
+配置并注册以上服务实现类,同时,还可以指定服务参数、注册中心地址、协议与端口等配置,以下是支持几种配置格式示例: +

+ +{{< tabpane langEqualsHeader=true >}} +{{< tab header="YAML" lang="yaml" >}} +dubbo: + application: + name: demo-provider + protocol: + name: dubbo + port: -1 + registry: + address: zookeeper://127.0.0.1:2181 +{{< /tab >}} +{{< tab header="API" lang="java" >}} +public static void main(String[] args) throws Exception { + ServiceConfig service = new ServiceConfig<>(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider")) + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) + .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) + .service(service) + .start() + .await(); +} +{{< /tab >}} +{{< tab header="Spring XML" >}} + + + + + + + + + + + + + + + +{{< /tab >}} +{{< tab header="Java Annotation" lang="Java" >}} +@DubboService +public class DemoServiceImpl implements DemoService { + // business implementation +} + +public class DemoServiceComponent implements DemoService { + @DubboReference + private DemoService demoService; +} +{{< /tab >}} +{{< tab header="dubbo.properties" lang="properties" >}} +dubbo.application.name=dubbo-demo-annotation-provider +dubbo.protocol.name=dubbo +dubbo.protocol.port=-1 +dubbo.registry.address=zookeeper://127.0.0.1:2181 +{{< /tab >}} +{{< /tabpane >}} + +
+启动 Server 监听服务 +

+ +{{< tabpane langEqualsHeader=true >}} +{{< tab header="Java" >}} +public static void main(String[] args) throws Exception { + ServiceConfig service = new ServiceConfig<>(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider")) + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) + .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) + .service(service) + .start() + .await(); +} +{{< /tab >}} +{{< tab header="Go" >}} +func main() { + config.SetProviderService(&DemoServiceImpl{}) + if err := config.Load(); err != nil { + panic(err) + } + select {} +} +{{< /tab >}} +{{< tab header="Rust" >}} +#[tokio::main] +async fn main() { + register_server(GreeterServerImpl { + name: "greeter".to_string(), + }); + + // Dubbo::new().start().await; + Dubbo::new() + .with_config({ + let r = RootConfig::new(); + match r.load() { + Ok(config) => config, + Err(_err) => panic!("err: {:?}", _err), // response was droped + } + }) + .start() + .await; +} +{{< /tab >}} +{{< tab header="Node.js" >}} +// Put node.js server bootstrapping snippet here +{{< /tab >}} +{{< /tabpane >}} + +
+至此,能监听请求并提供特定服务的 Dubbo Server 就开发和启动完成了。 + +## 第四步,开发服务消费者 + +接下来就是开发一个调用服务的 Client 了 + +> 在 Client 调用服务的前提是需要有服务定义的依赖,这可以通过语言特定的依赖分发系统或 IDL 管理系统实现。 + +通过配置/API声明服务调用,告诉 Dubbo 要生成 Proxy 的服务,同时可以指定服务发现的注册中心等配置: + +{{< tabpane langEqualsHeader=true >}} +{{< tab header="YAML" lang="yaml" >}} +dubbo: + application: + name: demo-consumer + registry: + address: zookeeper://127.0.0.1:2181 +{{< /tab >}} +{{< tab header="API" lang="java" >}} +private static void main(String[] args) { + ReferenceConfig reference = new ReferenceConfig<>(); + reference.setInterface(DemoService.class); + reference.setGeneric("true"); + + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application(new ApplicationConfig("demo-consumer")) + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) + .reference(reference) + .start(); +} +{{< /tab >}} +{{< tab header="Spring XML" >}} + + + + + + + + +{{< /tab >}} +{{< tab header="Java Annotation" lang="Java" >}} +public class SpringApplication { + @DubboReference + private DemoService demoService; +} +{{< /tab >}} +{{< tab header="dubbo.properties" lang="properties" >}} +dubbo.application.name=dubbo-demo-annotation-provider +dubbo.registry.address=zookeeper://127.0.0.1:2181 +{{< /tab >}} +{{< /tabpane >}} + +
+启动 Client +

+ +{{< tabpane langEqualsHeader=true >}} +{{< tab header="Java" >}} +public static void main(String[] args) throws Exception { + // ... + DemoService demoService = bootstrap.getCache().get(reference); + String message = demoService.sayHello("dubbo"); + System.out.println("Result: " + message); +} +{{< /tab >}} +{{< tab header="Go" >}} +func main() { + config.SetProviderService(&DemoServiceImpl{}) + if err := config.Load(); err != nil { + panic(err) + } + select {} +} +{{< /tab >}} +{{< tab header="Rust" >}} +#[tokio::main] +async fn main() { + let mut cli = GreeterClient::new().with_uri("http://127.0.0.1:8888".to_string()); + + println!("# unary call"); + let resp = cli + .greet(Request::new(GreeterRequest { + name: "message from client".to_string(), + })) + .await; + let resp = match resp { + Ok(resp) => resp, + Err(err) => return println!("{:?}", err), + }; + let (_parts, body) = resp.into_parts(); + println!("Response: {:?}", body); +} +{{< /tab >}} +{{< tab header="Node.js" >}} +// Put node.js client snippet here +{{< /tab >}} +{{< /tabpane >}} + +服务调用 + +## 第五步,打包部署 + +#### 语言特定形式分发包 + +您可以选择以语言特定方式打包 Dubbo 开发的服务 (如 Java Jar、Go Module 等),并以语言提供的发机制将二进制包分发出去。一般来讲,要注意一以下几点: +* 服务定义最好作为单独的二进制包由 Server 端定义并打包分发,以便所有 Client 都能依赖并基于服务定义编码; +* Dubbo Server 和 Dubbo Client 的打包与分发与普通应用完全一样,如 Java 应用就可以用 Maven 或 Gradle 直接打包分发; +* 如果您是以 IDL 方式定义服务,还需要考虑 IDL 的分发与管理方式; + +#### Docker 镜像 + +在当今容器时代,打包为 Docker 镜像已变为更通用的分发形式 + +```sh +docker build -t ${your-organization}/${project-name}:${tag-or-version} . +``` + +> 通常,在脚手架生成的根目录下 `/deploy` 有预先生成的镜像打包 Dockerfile 模版,可以按需修改后直接用来打包。 + + +## 第六步,部署 +Dubbo 微服务支持多种部署架构,与云原生基础设施做了很好的适配: +* 传统的自建服务治理体系模式,需自行维护微服务需要的注册中心集群、配置中心集群等 +* 基于 Kubernetes Native Service 微服务体系,此时 Kubernetes 集群承担服务抽象、注册中心、配置中心等角色 +* 服务网格架构,服务治理角色由控制面承担,Dubbo 作为数据面组件与 Sidecar 部署在一起,或者采用无 Sidecar 的 Proxyless 架构 + +#### 传统自建注册、配置中心模式 + +Dubbo 微服务需要依赖一些中心化集群协调状态,以下是一个抽象的 Dubbo 部署架构图: + +![三中心部署架构图]() + +图:部署在虚拟机或 Kubernetes 集群的传统 Dubbo 微服务架构 + +* 注册中心。协调 Consumer 与 Provider 之间的地址注册与发现 +* 配置中心 (可选) + * 存储 Dubbo 启动阶段的全局配置,保证配置的跨环境共享与全局一致性 + * 负责服务治理规则(路由规则、动态配置等)的存储与推送。 +* 元数据中心 (可选) + * 接收 Provider 上报的服务接口元数据,为 Admin 等控制台提供运维能力(如服务测试、接口文档等) + * 作为服务发现机制的补充,提供额外的接口/方法级别配置信息的同步能力,相当于注册中心的额外扩展 + +以上三个中心集群并不是运行 Dubbo 的必要条件,用户完全可以根据自身业务情况决定只启用其中一个或多个,以达到简化部署的目的。通常情况下,所有用户都会从独立的注册中心开始 Dubbo 服务开发,而配置中心、元数据中心则会在微服务演进的过程中逐步的按需被引入进来。注册中心、配置中心和元数据中心都是逻辑概念,它们完全可以是同一个物理集群,如部署一个 Zookeeper 集群同时作为注册中心、配置中心和元数据中心。 + +如您是在 Kubernetes 搭建 Dubbo 微服务集群,请参考 [如何在 Kubernetes 集群部署 Dubbo 服务]() 了解更多。 + +#### Kubernetes 原生服务 + +![参考下 Spring Kubernetes 等的架构图]() + +在这种模式下,Dubbo 服务将与 Kubernetes 原生服务实现概念对齐,同时,开发者也不再需要部署独立的注册、配置中心集群,这部分职责由 Kubernetes 及相应组件如 Service、ConfigMap、Deployment 等承担。具体是原理上,是由 Dubbo 节点直接与 Kubernete api-server 或 DNS 通信实现。 + +请参考 [Dubbo Kubernetes 原生服务任务]() 了解更多 + +#### 服务网格 + +Dubbo 服务可以无缝接入 Istio 体系,并且,Dubbo 支持更灵活的数据面部署形式 +* Sidecar 模式,Dubbo 可以与 Envoy 等代理部署在一起,实现流量拦截和治理 +* Proxyless 模式,Dubbo 通过直接与 Istio 等控制面通信,实现与 Sidecar 模式对等能力的同时,减少了部署成本和性能损耗。 + +![服务网格部署架构图](/imgs/v3/mesh/thinsdk-envoy.png) + +具体可参见 [Dubbo 服务网格]() 部分说明。 + +## 第七步,观测服务状态 + +可以通过 Dubbo 官方提供的 Admin 控制台非常方便的观测服务运行状态。 + +![Admin 截图]() + +请参考 [如何部署 Admin]() 了解如何将 Admin 部署您的开发或生产环境。 + +> 注意:部署过程中必须要配置 Admin 连接到您正在使用的注册中心或配置中心集群,保证 Admin 和 Dubbo 微服务集群共享相同数据源。 + +如果您将 Dubbo 部署在服务网格架构,则还可以使用对应控制面产品支持的控制台来观测 Dubbo 服务状态,如 Istio、Kiali。更多可观测能力如 Accessing Log、Tracing 等,请参考[可观测性]()文档。 + +## 第八步,服务治理 +为了使 Dubbo 服务稳定、可控的运行,我们需要在运行态对 Dubbo 服务进行治理。 + +首先,可以通过 Dubbo Admin 完成绝大多数的治理需求,如查看服务状态、下发流量规则等 + +![Dubbo Admin 治理效果图]() + +对于更高阶的治理诉求,可通过以下内容了解: + +* [网关流量接入](),通过网关实现前端 HTTP 流量接入 Dubbo 服务 +* [限流降级](),通过 Sentinel 等突发流量,就要用到限流降级能力, +* [数据一致性](),了解 Dubbo 服务的分布式事物解决方案 +* [全链路追踪](),了解 Dubbo 服务如何接入 Zipkin、Skywalking、OpenTracing 等全链路监控组件 +* [服务发现](),了解 Dubbo 的服务发现机制和扩展实现 +* [流量管控](),了解 Dubbo 丰富的流量管控规则定义及使用方式 + diff --git a/content/en/overview/what/core-features/service-discovery.md b/content/en/overview/what/core-features/service-discovery.md new file mode 100644 index 000000000000..c077de55e061 --- /dev/null +++ b/content/en/overview/what/core-features/service-discovery.md @@ -0,0 +1,73 @@ +--- +aliases: + - /zh/overview/core-features/service-discovery/ + - /zh-cn/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/ + - /zh-cn/overview/core-features/service-discovery/ +description: 服务发现 +feature: + description: | + Dubbo 提供了高性能、可伸缩的服务发现机制,面向百万集群实例规模设计,默认提供 Nacos、Zookeeper 等注册中心适配并支持自定义扩展。 + title: 服务发现 +linkTitle: 服务发现 +title: 服务发现 +type: docs +weight: 2 +--- + + +Dubbo 提供的是一种 Client-Based 的服务发现机制,依赖第三方注册中心组件来协调服务发现过程,支持常用的注册中心如 Nacos、Consul、Zookeeper 等。 + +以下是 Dubbo 服务发现机制的基本工作原理图: + +![service-discovery](/imgs/v3/feature/service-discovery/arc.png) + +服务发现包含提供者、消费者和注册中心三个参与角色,其中,Dubbo 提供者实例注册 URL 地址到注册中心,注册中心负责对数据进行聚合,Dubbo 消费者从注册中心读取地址列表并订阅变更,每当地址列表发生变化,注册中心将最新的列表通知到所有订阅的消费者实例。 + +## 面向百万实例集群的服务发现机制 +区别于其他很多微服务框架的是,**Dubbo3 的服务发现机制诞生于阿里巴巴超大规模微服务电商集群实践场景,因此,其在性能、可伸缩性、易用性等方面的表现大幅领先于业界大多数主流开源产品**。是企业面向未来构建可伸缩的微服务集群的最佳选择。 + +![service-discovery](/imgs/v3/feature/service-discovery/arc2.png) + +* 首先,Dubbo 注册中心以应用粒度聚合实例数据,消费者按消费需求精准订阅,避免了大多数开源框架如 Istio、Spring Cloud 等全量订阅带来的性能瓶颈。 +* 其次,Dubbo SDK 在实现上对消费端地址列表处理过程做了大量优化,地址通知增加了异步、缓存、bitmap 等多种解析优化,避免了地址更新常出现的消费端进程资源波动。 +* 最后,在功能丰富度和易用性上,服务发现除了同步 ip、port 等端点基本信息到消费者外,Dubbo 还将服务端的 RPC/HTTP 服务及其配置的元数据信息同步到消费端,这让消费者、提供者两端的更细粒度的协作成为可能,Dubbo 基于此机制提供了很多差异化的治理能力。 + +### 高效地址推送实现 + +从注册中心视角来看,它负责以应用名 (dubbo.application.name) 对整个集群的实例地址进行聚合,每个对外提供服务的实例将自身的应用名、实例ip:port 地址信息 (通常还包含少量的实例元数据,如机器所在区域、环境等) 注册到注册中心。 + +> Dubbo2 版本注册中心以服务粒度聚合实例地址,比应用粒度更细,也就意味着传输的数据量更大,因此在大规模集群下也遇到一些性能问题。 +> 针对 Dubbo2 与 Dubbo3 跨版本数据模型不统一的问题,Dubbo3 给出了[平滑迁移方案](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery/),可做到模型变更对用户无感。 + +![service-discovery](/imgs/v3/feature/service-discovery/registry-data.png) + +
+每个消费服务的实例从注册中心订阅实例地址列表,相比于一些产品直接将注册中心的全量数据 (应用 + 实例地址) 加载到本地进程,Dubbo 实现了按需精准订阅地址信息。比如一个消费者应用依赖 app1、app2,则只会订阅 app1、app2 的地址列表更新,大幅减轻了冗余数据推送和解析的负担。 + +

+
+ +![service-discovery](/imgs/v3/feature/service-discovery/subscription2.png) + +### 丰富元数据配置 +除了与注册中心的交互,Dubbo3 的完整地址发现过程还有一条额外的元数据通路,我们称之为元数据服务 (MetadataService),实例地址与元数据共同组成了消费者端有效的地址列表。 + +![service-discovery](/imgs/v3/feature/service-discovery/metadata.png) + +完整工作流程如上图所示,首先,消费者从注册中心接收到地址 (ip:port) 信息,然后与提供者建立连接并通过元数据服务读取到对端的元数据配置信息,两部分信息共同组装成 Dubbo 消费端有效的面向服务的地址列表。以上两个步骤都是在实际的 RPC 服务调用发生之前。 + +> 关于 MetadataService 的定义及完整服务发现流程分析,请查看 [应用级服务发现详解]({{< relref "../../../blog/proposals/service-discovery/" >}})。 + +> 对于微服务间服务发现模型的数据同步,REST 定义了一套非常有意思的成熟度模型,感兴趣的朋友可以参考这里的链接 https://www.martinfowler.com/articles/richardsonMaturityModel.html, 按照文章中的 4 级成熟度定义,Dubbo 当前基于接口粒度的模型可以对应到最高的 L4 级别。 + +## 配置方式 +Dubbo 服务发现扩展了多种注册中心组件支持,如 Nacos、Zookeeper、Consul、Redis、kubernetes 等,可以通过配置切换不同实现,同时还支持鉴权、命名空间隔离等配置。具体配置方式请查看 SDK 文档 + +* [Java](../../mannual/java-sdk/reference-manual/registry) +* [Golang](../../mannual/golang-sdk/tutorial/develop/registry) +* [Rust](../../mannual/rust-sdk/) + +Dubbo 还支持一个应用内配置多注册中心的情形如双注册、双订阅等,这对于实现不同集群地址数据互通、集群迁移等场景非常有用处,我们将在未来文档中添加 `最佳实践` 对这部分内容进行示例说明。 + +## 自定义扩展 +注册中心适配支持自定义扩展实现,具体请参见 [Dubbo 可扩展性](../extensibility) diff --git a/content/en/overview/what/core-features/service-mesh.md b/content/en/overview/what/core-features/service-mesh.md new file mode 100644 index 000000000000..a122d05b81ee --- /dev/null +++ b/content/en/overview/what/core-features/service-mesh.md @@ -0,0 +1,90 @@ +--- +aliases: + - /zh/overview/core-features/service-mesh/ + - /zh-cn/overview/mannual/java-sdk/concepts-and-architecture/mesh/ + - /zh-cn/overview/core-features/service-mesh/ +description: 服务网格 +feature: + description: | + 灵活的数据面 (Proxy & Proxyless) 部署形态支持,无缝接入 Istio 控制面治理体系。 + title: 服务网格(Service Mesh) +linkTitle: 服务网格 +title: 服务网格 +type: docs +weight: 9 +working-in-progress: true +--- + + + +Dubbo Mesh 是 Dubbo 在云原生背景的微服务整体解决方案,它帮助开发者实现 Dubbo 服务与标准的 Kubernetes Native Service 体系的打通,让 Dubbo 应用能够无缝接入 Istio 等业界主流服务网格产品。 + +以下是 Dubbo Mesh 的部署架构图 + +![Dubbo-Mesh](/imgs/v3/mesh/mix-mesh.png) + +* 控制面。Istio 作为统一控制面,为集群提供 Kubernetes 适配、服务发现、证书管理、可观测性、流量治理等能力。 +* 数据面。Dubbo 应用实例作为数据面组件,支持两种部署模式 + * Proxy 模式。Dubbo 进程与 Envoy 部署在同一 pod,进出 Dubbo 的流量都经 Envoy 代理拦截,由 Envoy 执行流量管控。 + * Proxyless 模式。Dubbo 进程独立部署,进程间直接通信,通过 xDS 协议与控制面直接交互。 + +关于服务网格架构以及为何要接入 Istio 控制面,请参考 [Istio 官网](https://istio.io/),本文不包含这部分通用内容的讲解,而是会侧重在 Dubbo Mesh 解决方案本身。 + +## Dubbo Mesh + +### Proxy Mesh +在 proxy 模式下,Dubbo 与 Envoy 等边车 (Proxy or Sidecar) 部署在一起 + +![dubbo-sidecar](/imgs/v3/mesh/dubbo-proxy.png) + +以上是 Dubbo Proxy Mesh 部署架构图 +* Dubbo 与 Envoy 部署在同一个 Pod 中,Istio 实现对流量和治理的统一管控。 +* Dubbo 只提供面向业务应用的编程 API、RPC 通信能力,其余流量管控能力如地址发现、负载均衡、路由寻址等都下沉到 Envoy,Envoy 拦截所有进出流量并完成路由寻址等服务治理工作。 +* 控制面与 Envoy 之间通过图中虚线所示的 xDS 协议进行配置分发。 + +在 Proxy 模式下,Dubbo3 通信层选用 Triple、gRPC、REST 等基于 HTTP 的通信协议可以获得更好的网关穿透性与性能体验。 + +### Proxyless Mesh +在 Proxyless 模式下,没有 Envoy 等代理组件,Dubbo 进程保持独立部署并直接通信,Istio 控制面通过 xDS 与 Dubbo 进程进行治理能力交互。 + +![dubbo-proxyless](/imgs/v3/mesh/dubbo-proxyless.png) + +Proxyless 模式下 Dubbo 部署与服务网格之前基本一致,通过不同语言版本的 Dubbo3 SDK 直接实现 xDS 协议解析 + +#### 为什么需要 Proxyless Mesh + +Proxy 模式很好的实现了治理能力与有很多优势,如平滑升级、多语言、业务侵入小等,但也带来了一些额外的问题,比如: +* Sidecar 通信带来了额外的性能损耗,这在复杂拓扑的网络调用中将变得尤其明显。 +* Sidecar 的存在让应用的声明周期管理变得更加复杂。 +* 部署环境受限,并不是所有的环境都能满足 Sidecar 部署与请求拦截要求。 + +在 Proxyless 模式下,Dubbo 进程之间继续保持直连通信模式: +* 没有额外的 Proxy 中转损耗,因此更适用于性能敏感应用 +* 更有利于遗留系统的平滑迁移 +* 架构简单,容易运维部署 +* 适用于几乎所有的部署环境 + +## 示例任务 +了解了足够多的原理知识,我们推荐你访问如下 [示例](../../tasks/mesh) 进行动手实践。 + +## 可视化 +推荐使用 [Dubbo Admin](../../tasks/deploy) 作为您 Dubbo 集群的可视化控制台,它兼容所有 Kubernetes、Mesh 和非 Mesh 架构的部署。 + +除此之外,你也可以使用 [Istio 官方推荐的可视化工具](https://istio.io/latest/docs/tasks/observability/kiali/) 来管理您的 Dubbo Mesh 集群。 + +## 接入非 Istio 控制面 +Dubbo Mesh 本身并不绑定任何控制面产品实现,你可以使用 Istio、Linkerd、Kuma 或者任一支持 xDS 协议的控制面产品,对于 Sidecar 亦是如此。 + +如果你已经完整的体验了 [基于 Istio 的 Dubbo Mesh](/) 示例任务,并且发现 Istio 很好的满足了你的 Dubbo Mesh 治理诉求,那么采用 Istio 作为你的控制面是首选的解决方案。 + +如果你发现 Istio 模式下 Dubbo 部分能力受限,而这部分能力正好是你需要的,那么你需要考虑接入 Dubbo 控制面,用 Dubbo 控制面来替代 Istio,以获得更多 Dubbo 体系原生能力支持、更好的性能体验。具体请参见 [基于 Dubbo 定制控制面的 Dubbo Mesh 示例任务](/)。 + +> 简单来讲,这是 Dubbo 社区发布的一款基于 Istio 的定制版本控制面,Dubbo 控制面安装与能力差异请参见上面的示例任务链接。 + +## 老系统迁移方案 +### 如何解决注册中心数据同步的问题? +Address Synchronization + +### 如何解决 Dubbo2 协议通信的问题? + +Aeraki Mesh diff --git a/content/en/overview/what/core-features/traffic/_index.md b/content/en/overview/what/core-features/traffic/_index.md new file mode 100755 index 000000000000..a0c241b679ce --- /dev/null +++ b/content/en/overview/what/core-features/traffic/_index.md @@ -0,0 +1,275 @@ +--- +aliases: + - /zh/overview/core-features/traffic/ + - /zh-cn/overview/core-features/traffic/ +description: 流量管控 +feature: + description: | + Dubbo 提供的基于路由规则的流量管控策略,可以帮助实现全链路灰度、金丝雀发布、按比例流量转发、动态调整调试时间、设置重试次数等服务治理能力。 + title: 流量管控 +linkTitle: 流量管控 +no_list: true +title: 流量管控 +type: docs +weight: 4 +--- + + + +Dubbo 提供了丰富的流量管控策略 +* **地址发现与负载均衡**,地址发现支持服务实例动态上下线,负载均衡确保流量均匀的分布到每个实例上。 +* **基于路由规则的流量管控**,路由规则对每次请求进行条件匹配,并将符合条件的请求路由到特定的地址子集。 + +服务发现保证调用方看到最新的提供方实例地址,服务发现机制依赖注册中心 (Zookeeper、Nacos、Istio 等) 实现。在消费端,Dubbo 提供了多种负载均衡策略,如随机负载均衡策略、一致性哈希负载、基于权重的轮询、最小活跃度优先、P2C 等。 + +Dubbo 的流量管控规则可以基于应用、服务、方法、参数等粒度精准的控制流量走向,根据请求的目标服务、方法以及请求体中的其他附加参数进行匹配,符合匹配条件的流量会进一步的按照特定规则转发到一个地址子集。流量管控规则有以下几种: +* 条件路由规则 +* 标签路由规则 +* 脚本路由规则 +* 动态配置规则 + +如果底层用的是基于 HTTP 的 RPC 协议 (如 REST、gRPC、Triple 等),则服务和方法等就统一映射为 HTTP 路径 (path),此时 Dubbo 路由规则相当于是基于 HTTP path 和 headers 的流量分发机制。 + +> Dubbo 中有应用、服务和方法的概念,一个应用可以发布多个服务,一个服务包含多个可被调用的方法,从抽象的视角来看,一次 Dubbo 调用就是某个消费方应用发起了对某个提供方应用内的某个服务特定方法的调用,Dubbo 的流量管控规则可以基于应用、服务、方法、参数等粒度精准的控制流量走向。 + +## 工作原理 + +以下是 Dubbo 单个路由器的工作过程,路由器接收一个服务的实例地址集合作为输入,基于请求上下文 (Request Context) 和 (Router Rule) 实际的路由规则定义对输入地址进行匹配,所有匹配成功的实例组成一个地址子集,最终地址子集作为输出结果继续交给下一个路由器或者负载均衡组件处理。 + +![Router](/imgs/v3/feature/traffic/router1.png) + +通常,在 Dubbo 中,多个路由器组成一条路由链共同协作,前一个路由器的输出作为另一个路由器的输入,经过层层路由规则筛选后,最终生成有效的地址集合。 +* Dubbo 中的每个服务都有一条完全独立的路由链,每个服务的路由链组成可能不同,处理的规则各异,各个服务间互不影响。 +* 对单条路由链而言,即使每次输入的地址集合相同,根据每次请求上下文的不同,生成的地址子集结果也可能不同。 + +![Router](/imgs/v3/feature/traffic/router2.png) + +## 路由规则分类 +### 标签路由规则 + +标签路由通过将某一个服务的实例划分到不同的分组,约束具有特定标签的流量只能在指定分组中流转,不同分组为不同的流量场景服务,从而实现流量隔离的目的。标签路由可以作为蓝绿发布、灰度发布等场景能力的基础。 + +标签路由规则是一个非此即彼的流量隔离方案,也就是匹配`标签`的请求会 100% 转发到有相同`标签`的实例,没有匹配`标签`的请求会 100% 转发到其余未匹配的实例。如果您需要按比例的流量调度方案,请参考示例 [基于权重的按比例流量路由](../../tasks/traffic-management/weight/)。 + +`标签`主要是指对 Provider 端应用实例的分组,目前有两种方式可以完成实例分组,分别是`动态规则打标`和`静态规则打标`。`动态规则打标` 可以在运行时动态的圈住一组机器实例,而 `静态规则打标` 则需要实例重启后才能生效,其中,动态规则相较于静态规则优先级更高,而当两种规则同时存在且出现冲突时,将以动态规则为准。 + +#### 标签规则示例 - 静态打标 + +静态打标需要在服务提供者实例启动前确定,并且必须通过特定的参数 `tag` 指定。 + +##### Provider + +在 Dubbo 实例启动前,指定当前实例的标签,如部署在杭州区域的实例,指定 `tag=gray`。 + +```xml + +``` + +or + +```xml + +``` + +or + +```properties +java -jar xxx-provider.jar -Ddubbo.provider.tag=gray +``` + +##### Consumer + +发起调用的一方,在每次请求前通过 `tag` 设置流量标签,确保流量被调度到带有同样标签的服务提供方。 + +```java +RpcContext.getContext().setAttachment(Constants.TAG_KEY, "gray"); +``` + +#### 标签规则示例 - 动态打标 + +相比于静态打标只能通过 `tag` 属性设置,且在启动阶段就已经固定下来,动态标签可以匹配任意多个属性,根据指定的匹配条件将 Provider 实例动态的划分到不同的流量分组中。 + +##### Provider + +以下规则对 `shop-detail` 应用进行了动态归组,匹配 `env: gray` 的实例被划分到 `gray` 分组,其余不匹配 `env: gray` 继续留在默认分组 (无 tag)。 + +```yaml +configVersion: v3.0 +force: true +enabled: true +key: shop-detail +tags: + - name: gray + match: + - key: env + value: + exact: gray +``` + +> 这里牵涉到如何给您的实例打各种原始 label 的问题,即上面示例中的 `env`,一种方式是直接写在配置文件中,如上面静态规则实例 provider 部分的配置所示,另一种方式是通过预设环境变量指定,关于这点请参考下文的 [如何给实例打标](#如何给实例打标) 一节。 + +##### Consumer + +服务发起方的设置方式和之前静态打标规则保持一致,只需要在每次请求前通过 `tag` 设置流量标签,确保流量被调度到带有同样标签的服务提供方。 + +```java +RpcContext.getContext().setAttachment(Constants.TAG_KEY, "Hangzhou"); +``` + +设置了以上标签的流量,将全部导流到 `hangzhou-region` 划分的实例上。 + +> 请求标签的作用域仅为一次点对点的 RPC 请求。比如,在一个 A -> B -> C 调用链路上,如果 A -> B 调用通过 `setAttachment` 设置了 `tag` 参数,则该参数不会在 B -> C 的调用中生效,同样的,在完成了 A -> B -> C 的整个调用同时 A 收到调用结果后,如果想要相同的 `tag` 参数,则在发起其他调用前仍需要单独设置 `setAttachment`。可以参考 [示例任务 - 环境隔离](../../tasks/traffic-management/isolation/) 了解更多 `tag` 全链路传递解决方案。 + +### 条件路由规则 + +条件路由与标签路由的工作模式非常相似,也是首先对请求中的参数进行匹配,符合匹配条件的请求将被转发到包含特定实例地址列表的子集。相比于标签路由,条件路由的匹配方式更灵活: + +* 在标签路由中,一旦给某一台或几台机器实例打了标签,则这部分实例就会被立马从通用流量集合中移除,不同标签之间不会再有交集。有点类似下图,地址集合在输入阶段就已经划分明确。 + +![tag-condition-compare](/imgs/v3/feature/traffic/tag-condition-compare1.png) + +* 而从条件路由的视角,所有的实例都是一致的,路由过程中不存在分组隔离的问题,每次路由过滤都是基于全量地址中执行 + +![tag-condition-compare](/imgs/v3/feature/traffic/tag-condition-compare2.png) + +条件路由规则的主体 `conditions` 主要包含两部分内容: + +* => 之前的为请求参数匹配条件,指定的 `匹配条件指定的参数` 将与 `消费者的请求上下文 (URL)、甚至方法参数` 进行对比,当消费者满足匹配条件时,对该消费者执行后面的地址子集过滤规则。 +* => 之后的为地址子集过滤条件,指定的 `过滤条件指定的参数` 将与 `提供者实例地址 (URL)` 进行对比,消费者最终只能拿到符合过滤条件的实例列表,从而确保流量只会发送到符合条件的地址子集。 + * 如果匹配条件为空,表示对所有请求生效,如:`=> status != staging` + * 如果过滤条件为空,表示禁止来自相应请求的访问,如:`application = product =>` + + +#### 条件路由规则示例 + +基于以下示例规则,所有 `org.apache.dubbo.demo.CommentService` 服务调用都将被转发到与当前消费端机器具有相同 `region` 标记的地址子集。`$region` 是特殊引用符号,执行过程中将读取消费端机器的实际的 `region` 值替代。 + +```yaml +configVersion: v3.0 +enabled: true +force: false +key: org.apache.dubbo.samples.CommentService +conditions: + - '=> region = $region' +``` + +> 针对条件路由,我们通常推荐配置 `scope: service` 的规则,因为它可以跨消费端应用对所有消费特定服务 (service) 的应用生效。关于 Dubbo 规则中的 `scope` 以及 `service`、`application` 的说明请阅读 [条件路由规则手册](./condition-rule)。 + +条件路由规则还支持设置具体的机器地址如 ip 或 port,这种情况下使用条件路由可以处理一些开发或线上机器的临时状况,实现**黑名单、白名单、实例临时摘除**等运维效果,如以下规则可以将机器 `172.22.3.91` 从服务的可用列表中排除。 + +```yaml +=> host != 172.22.3.91 +``` + +条件路由还支持基于请求参数的匹配,示例如下: + +```yaml +conditions: + - method=getDetail&arguments[0]=dubbo => port=20880 +``` + +### 动态配置规则 +通过 Dubbo 提供的动态配置规则,您可以动态的修改 Dubbo 服务进程的运行时行为,整个过程不需要重启,配置参数实时生效。基于这个强大的功能,基本上所有运行期参数都可以动态调整,比如超时时间、临时开启 Access Log、修改 Tracing 采样率、调整限流降级参数、负载均衡、线程池配置、日志等级、给机器实例动态打标签等。与上文讲到的流量管控规则类似,动态配置规则支持应用、服务两个粒度,也就是说您一次可以选择只调整应用中的某一个或几个服务的参数配置。 + +当然,出于系统稳定性、安全性的考量,有些特定的参数是不允许动态修改的,但除此之外,基本上所有参数都允许动态修改,很多强大的运行态能力都可以通过这个规则实现,您可以找个示例应用去尝试一下。通常 URL 地址中的参数均可以修改,这在每个语言实现的参考手册里也记录了一些更详细的说明。 + +#### 动态配置规则示例 - 修改超时时间 + +以下示例将 `org.apache.dubbo.samples.UserService` 服务的超时参数调整为 2000ms + +```yaml +configVersion: v3.0 +scope: service +key: org.apache.dubbo.samples.UserService +enabled: true +configs: + - side: provider + parameters: + timeout: 2000 +``` + +以下部分指定这个配置是服务粒度,具体变更的服务名为 `org.apache.dubbo.samples.UserService`。`scope` 支持 `service`、`application` 两个可选值,如果 `scope: service`,则 `key` 应该配置为 `version/service:group` 格式。 + +```yaml +scope: service +key: org.apache.dubbo.samples.UserService +``` + +> 关于 Dubbo 规则中的 `scope` 以及 `service`、`application` 的说明请参考 [动态配置参考手册](./configuration-rule/) 或 [动态配置示例](../../tasks/traffic-management/timeout/)。 + +`parameters` 参数指定了新的修改值,这里将通过 `timeout: 2000` 将超时时间设置为 2000ms。 + +```yaml +parameters: + timeout: 2000 +``` + +### 脚本路由规则 +脚本路由是最直观的路由方式,同时它也是当前最灵活的路由规则,因为你可以在脚本中定义任意的地址筛选规则。如果我们为某个服务定义一条脚本规则,则后续所有请求都会先执行一遍这个脚本,脚本过滤出来的地址即为请求允许发送到的、有效的地址集合。 + +```yaml +configVersion: v3.0 +key: demo-provider +type: javascript +enabled: true +script: | + (function route(invokers,invocation,context) { + var result = new java.util.ArrayList(invokers.size()); + for (i = 0; i < invokers.size(); i ++) { + if ("10.20.3.3".equals(invokers.get(i).getUrl().getHost())) { + result.add(invokers.get(i)); + } + } + return result; + } (invokers, invocation, context)); // 表示立即执行方法 +``` + +## 如何给实例打标 + +当前,有两种方式可以在启动阶段为 Dubbo 实例指定标签,一种是之前提到的应用内配置的方式,如在 xml 文件中设置 ``,应用打包部署后即自动被打标。 + +还有一种更灵活的方式,那就是通过读取所部署机器上的环境信息给应用打标,这样应用的标签就可以跟随实例动态的自动填充,避免每次更换部署环境就重新打包应用镜像的问题。当前 Dubbo 能自动读取以下环境变量配置: + +```yaml +spec: + containers: + - name: detail + image: apache/demo-detail:latest + env: + - name: DUBBO_LABELS + value: "region=hangzhou; env=gray" +``` + +```yaml +spec: + containers: + - name: detail + image: apache/demo-detail:latest + env: + - name: DUBBO_ENV_KEYS + value: "REGION, ENV" + - name: REGION + value: "hangzhou" + - name: ENV + value: "gray" +``` + +如果您有不同的实例环境保存机制,可以通过扩展 `InfraAdapter 扩展点` 来自定义自己的标签加载方式。如果您的应用是部署在 Kubernetes 环境下,并且已经接入了服务网格体系,则也可以使用标准 deployment 标签的方式打标,具体请跟随 [服务网格任务示例](../../tasks/mesh/) 学习。 + +## 如何配置流量规则 +Dubbo 提供了控制台 Dubbo Admin,帮助您可视化的下发流量管控规则,并实时监控规则生效情况。 + +![Admin](/imgs/v3/what/admin.png) + +Dubbo 还提供了 `dubboctl` 命令行工具,需要有 Dubbo Admin 提前部署就绪,因为 dubboctl 是通过与 Admin 进行 http 通信完成规则下发的。 + +如果您使用的是如 Istio 的服务网格架构,还可以使用 Istioctl、kubectl 等下发 Istio 标准规则。 + +## 接入服务网格 + +以上介绍的都是 Dubbo 体系内的流量治理规则,如果您对服务网格架构感兴趣,则可以将 Dubbo 服务接入服务网格体系,这样,您就可以使用服务网格提供的流量治理能力,如 Istio 体系的 VirtualService 等。 + +具体请参见 [Dubbo 中的服务网格架构](../service-mesh)。 + +## 跟随示例学习 +我们搭建了一个 [线上商城系统](../../tasks/traffic-management/) 供您学习流量规则的具体使用。 diff --git a/content/en/overview/what/core-features/traffic/circuit-breaking.md b/content/en/overview/what/core-features/traffic/circuit-breaking.md new file mode 100644 index 000000000000..24d0af733f62 --- /dev/null +++ b/content/en/overview/what/core-features/traffic/circuit-breaking.md @@ -0,0 +1,43 @@ +--- +aliases: + - /zh-cn/overview/core-features/traffic/circuit-breaking/ +description: "" +linkTitle: 限流 & 熔断 +title: 限流 & 熔断 +type: docs +weight: 5 +--- + +由于微服务分布式的特点,如何构建稳定的微服务集群是一个很大的挑战,其中有两项非常关键的点值得关注 +* 流量控制 (Rate Limiting) +* 熔断降级 (Circuit Breaking) + +## 流量控制 +**流量控制更多的是站在 Dubbo 服务提供者视角来保证服务稳定性**,通过明确的为 Dubbo 服务设置请求上限阈值,确保服务所处理的请求数始终在一个合理范围之内,从而确保系统整体的稳定性。 + +![provider-rate-limit](/imgs/v3/feature/circuit-breaking/provider-rate-limit.png) + +根据服务的具体部署情况,服务所能处理的流量上限是一定的,当对服务的请求数量保持在合理的范围时,系统运行正常;而当请求数量严重超过服务处理能力时,如大促期间的流量洪峰等场景,就可能造成服务提供者端的资源过度消耗、负载过高,进而出现响应延迟、请求无应答、系统假死等情况。 + +流量控制解决的问题和工作方式比较容易理解,而其使用的难点就是如何确定服务所能处理的流量最大值? +* 一种模式是由用户预先设定一个固定的限流值,如 Dubbo 通过集成 Sentinel 等产品实现的限流能力即是这种模式 + * [Dubbo Sentinel 流量控制](../../../tasks/rate-limit/sentinel/) +* 另一种方式是 Dubbo 框架自动根据系统或集群负载情况执行限流,相比用户预先设置限流值更加灵活方便,Dubbo 目前内置了自适应限流模式,具体可参见: + * [Java 自适应限流使用方式](../../../mannual/java-sdk/advanced-features-and-usage/performance/adaptive-concurrency-control/) + * [Go 自适应限流使用方式](../../../reference/proposals/heuristic-flow-control/) + * [自适应限流设计原理](../../../reference/proposals/heuristic-flow-control/) + +## 熔断降级 +**熔断降级则是更多的从 Dubbo 服务消费者视角来保障系统稳定性的重要手段**。一个服务往往需要调用更多的下游 Dubbo 服务来完成业务逻辑,这时下游服务的稳定性就会影响当前服务甚至整个系统的稳定性,熔断(Circuit Breaking)即是面向不稳定服务场景设计的,它能最大限度避免下游服务不稳定对上游服务带来的影响。 + +而相比于熔断后直接返回调用失败信息,配合服务降级能力,我们可以继续调用预先设置好的服务降级逻辑,以降级逻辑的结果作为最终调用结果,以更优雅的返回给服务调用方。 + +![consumer-circuit-breaking](/imgs/v3/feature/circuit-breaking/consumer-circuit-breaking.png) + +如上图所示,Dubbo Consumer 依赖的下游的三个 Dubbo 服务,当 Service 3 出现不稳定的情况时(如响应时间变长、错误率增加等),从而 Consumer 调用 Service 3 的线程等资源就会产生堆积,如果此时我们不在 Consumer 侧做任何限制,则 Service 1 与 Service 2 的调用都会受到稳定性影响。通过熔断 Service 3 我们就能保证整个 Dubbo Consumer 服务的稳定性,不拖垮整个 Consumer 服务,熔断 Service 3 的方式可以有很多种实现,包括线程数、信号量、错误率等。 + +Dubbo 通过集成业界主流的框架实现了服务熔断降级能力 + +* [Sentinel](../../../tasks/rate-limit/sentinel/) +* [Hystrix](../../../tasks/rate-limit/hystrix/) +* [Resilience4J](../../../tasks/rate-limit/resilience4j/) diff --git a/content/en/overview/what/core-features/traffic/condition-rule.md b/content/en/overview/what/core-features/traffic/condition-rule.md new file mode 100644 index 000000000000..5c9898444a6e --- /dev/null +++ b/content/en/overview/what/core-features/traffic/condition-rule.md @@ -0,0 +1,79 @@ +--- +aliases: + - /zh/overview/core-features/traffic/condition-rule/ + - /zh-cn/overview/core-features/traffic/condition-rule/ +description: "" +linkTitle: 条件路由 +title: 条件路由规则 +type: docs +weight: 1 + +--- + + + +条件路由规则将符合特定条件的请求转发到特定的地址实例子集上。规则首先对发起流量的请求参数进行匹配,符合匹配条件的请求将被转发到包含特定实例地址列表的子集。 + +以下是一个条件路由规则示例。 + +基于以下示例规则,所有 `org.apache.dubbo.samples.CommentService` 服务 `getComment` 方法的调用都将被转发到有 `region=Hangzhou` 标记的地址子集。 + + ```yaml + configVersion: v3.0 + scope: service + force: true + runtime: true + enabled: true + key: org.apache.dubbo.samples.CommentService + conditions: + - method=getComment => region=Hangzhou + ``` + +可以看具体的例子代码: [条件路由](https://github.com/apache/dubbo-samples/tree/master/4-governance/dubbo-samples-configconditionrouter/src/main/java/org/apache/dubbo/samples/governance) + +## ConditionRule + +条件路由规则主体。定义路由规则生效的目标服务或应用、流量过滤条件以及一些特定场景下的行为。 + +| 字段名 | 类型 | **描述** | 必填 | +| --- | --- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ---- | +| configVersion | string | 条件路由的版本,当前版本为 `v3.0` | 是 | +| scope | string | 支持 `service` 和 `application` 两种规则 | 是 | +| key | string | 应用到的目标服务或应用程序的标识符

- 当 `scope:service` 时, `key`应该是该规则生效的服务名比如 org.apache.dubbo.samples.CommentService
- 当 `scope:application` 时, then `key`应该是该规则应该生效的应用名称,比如说my-dubbo-service. | 是 | +| enabled | bool | 规则是否生效 当 `enabled:false` 时,规则不生效 | 是 | +| conditions | string[] | 配置中定义的条件规则,详情可以看[条件规则](https://cn.dubbo.apache.org/zh-cn/overview/core-features/traffic/condition-rule/#condition) | 是 | +| force | bool | T路由后实例子集为空时的行为。 `true` 则抛出一个No Provider Exception。 `false` 则忽略规则,直接去请求其他的实例。默认值是false | 否 | +| runtime | bool | 是否为每个 rpc 调用运行路由规则或使用路由缓存(如果可用)。默认值是false(false则走缓存,true不走缓存) | 否 | + +## Condition + +`Condition` 为条件路由规则的主体,类型为一个复合结构的 string 字符串,如 `method=getComment => region=Hangzhou`。其中, + +* => 之前的为请求参数匹配条件,指定的 `匹配条件指定的参数` 将与 `消费者的请求上下文 (URL)、甚至方法参数` 进行对比,当消费者满足匹配条件时,对该消费者执行后面的地址子集过滤规则。 +* => 之后的为地址子集过滤条件,指定的 `过滤条件指定的参数` 将与 `提供者实例地址 (URL)` 进行对比,消费者最终只能拿到符合过滤条件的实例列表,从而确保流量只会发送到符合条件的地址子集。 + * 如果匹配条件为空,表示对所有请求生效,如:`=> status != staging` + * 如果过滤条件为空,表示禁止来自相应请求的访问,如:`application = product =>` + +### 匹配/过滤条件 + +**参数支持** + +* 服务调用上下文,如:interface, method, group, version 等 +* 请求上下文,如 attachments[key] = value +* 方法参数,如 arguments[0] = tom +* URL 本身的字段,如:protocol, host, port 等 +* URL 上任务扩展参数,如:application, organization 等 +* 支持开发者自定义扩展 + +**条件支持** + +* 等号 = 表示 "匹配",如:method = getComment +* 不等号 != 表示 "不匹配",如:method != getComment + +**值支持** + +* 以逗号 , 分隔多个值,如:host != 10.20.153.10,10.20.153.11 +* 以星号 * 结尾,表示通配,如:host != 10.20.* +* 以美元符 $ 开头,表示引用消费者参数,如:region = $region +* 整数值范围,如:userId = 1~100、userId = 101~ +* 支持开发者自定义扩展 diff --git a/content/en/overview/what/core-features/traffic/configuration-rule.md b/content/en/overview/what/core-features/traffic/configuration-rule.md new file mode 100644 index 000000000000..0eec2d23e523 --- /dev/null +++ b/content/en/overview/what/core-features/traffic/configuration-rule.md @@ -0,0 +1,95 @@ +--- +aliases: + - /zh/overview/core-features/traffic/configuration-rule/ + - /zh-cn/overview/core-features/traffic/configuration-rule/ +description: "" +linkTitle: 动态配置 +title: 动态配置规则 +type: docs +weight: 4 +--- + + +动态配置规则 (ConfigurationRule) 是 Dubbo 设计的在无需重启应用的情况下,动态调整 RPC 调用行为的一种能力,也称为动态覆盖规则,因为它是通过在运行态覆盖 Dubbo 实例或者 Dubbo 实例中 URL 地址的各种参数值,实现改变 RPC 调用行为的能力。 + +使用动态配置规则,有以下几条关键信息值得注意: +* **设置规则生效过滤条件。** 配置规则支持一系列的过滤条件,用来限定规则只对符合特定条件的服务、应用或实例才生效。 +* **设置规则生效范围。** 一个 rpc 服务有服务发起方(消费者)和服务处理方(提供者)两个角色,对某一个服务定义的规则,可以具体到限制是对消费者还是提供者生效。 +* **选择规则管理粒度。** Dubbo 支持从服务和应用两个粒度来管理和下发规则。 + +以下一个应用级别的配置示例,配置生效后,`shop-detail` 应用下提供的所有服务都将启用 accesslog,对 `shop-detail` 部署的所有实例生效。 + +```yaml +configVersion: v3.0 +scope: application +key: shop-detail +configs: + - side: provider + parameters: + accesslog: 'true' +``` + +以下是一个服务级别的配置示例,`key: org.apache.dubbo.samples.UserService` 和 `side: consumer` 说明这条配置对所有正在消费 UserService 的 Dubbo 实例生效,在调用失败后都执行 4 次重试。`match` 条件进一步限制了消费端的范围,限定为只对应用名为 `shop-frontend` 的这个消费端应用生效。 + +```yaml +configVersion: v3.0 +scope: service +key: org.apache.dubbo.samples.UserService +configs: + - match: + application: + oneof: + - exact: shop-frontend + side: consumer + parameters: + retries: '4' +``` +## ConfigurationRule +配置规则主体,定义要设置的目标服务或应用、具体的规则配置。具体配置规则 (configs) 可以设置多条。 + +| Field | Type | Description | Required | +| --- | --- | --- | --- | +| configVersion | string | The version of the configuration rule definition, currently available version is `v3.0` | Yes | +| scope | string | Supports `service` and `application` scope configurations. | Yes | +| key | string | The identifier of the target service or application that this rule is about to apply to.

- If `scope:service`is set, then `key`should be specified as the Dubbo service key that this rule targets to control.
- If `scope:application` is set, then `key`should be specified as the name of the application that this rule targets to control.| Yes | +| enabled | bool | Whether enable this rule or not, set `enabled:false` to disable this rule. | Yes | +| configs | Config[] | The `match condition` and `configuration` of this rule. | Yes | + +## Config +具体的规则配置定义,包含生效端 (consumer 或 provider) 和过滤条件。 + +| Field | Type | Description | Required | +| --- | --- | --- | --- | +| side | string | Especially useful when `scope:service`is set.

- `side: provider`means this Config will only take effect on the provider instances of the service key.
- `side:consumer`means this Config will only take effect on the consumer instances of the service key| Yes | +| parameters | map | The keys and values this rule aims to change. | Yes | +| match | MatchCondition | A set of criterion to be met in order for the rule/config to be applied to the Dubbo instance. | No | +| enabled | bool | Whether enable this Config or not, will use the value in ConfigurationRule if not set | No | +| ~~addresses~~ | ~~string[]~~ | ~~replaced with address in MatchCondition~~ | ~~No~~ | +| ~~providerAddresses~~ | ~~string[]~~ | ~~not supported anymore~~ | ~~No~~ | +| ~~services~~ | ~~string[]~~ | ~~replaced with service in MatchCondition~~ | ~~No~~ | +| ~~applications~~ | ~~string[]~~ | ~~replaced with application in MatchCondition~~ | ~~No~~ | + +## MatchCondition +过滤条件,用来设置规则对哪个服务 (service)、应用 (application)、实例 (address),或者包含哪些参数 (param) 的实例生效。 + +| Field | Type | Description | Required | +| --- | --- | --- | --- | +| address | StringMatch | The instance address matching condition for this config rule to take effect.

- xact: "value" for exact string match
- prefix: "value" for prefix-based match
- regex: "value" for RE2 style regex-based match ([https://github.com/google/re2/wiki/Syntax)](https://github.com/google/re2/wiki/Syntax)).| No | +| service | StringMatch (oneof) | The service matching condition for this config rule to take effect. Effective when `scope: application` is set.

- exact: "value" for exact string match
- prefix: "value" for prefix-based match
- regex: "value" for RE2 style regex-based match ([https://github.com/google/re2/wiki/Syntax)](https://github.com/google/re2/wiki/Syntax)).| No | +| application | StringMatch (oneof) | The application matching condition for this config rule to take effect. Effective when `scope: service` is set.

- exact: "value" for exact string match
- prefix: "value" for prefix-based match
- regex: "value" for RE2 style regex-based match ([https://github.com/google/re2/wiki/Syntax)](https://github.com/google/re2/wiki/Syntax)).| No | +| param | ParamCondition[] | The Dubbo url keys and values matching condition for this config rule to take effect. | No | + +## ParamCondition +定义实例参数 (param) 过滤条件,对应到 Dubbo URL 地址参数。 + +| Field | Type | Description | Required | +| --- | --- | --- | --- | +| key | string | The name of the key in the Dubbo url address. | Yes | +| value | StringMatch (oneof) | The matching condition for the value in the Dubbo url address. | Yes | + +## StringMatch +| Field | Type | Description | Required | +| --- | --- | --- | --- | +| exact | string (oneof) | exact string match | No | +| prefix | string (oneof) | prefix-based match | No | +| regex | string (oneof) | RE2 style regex-based match ([https://github.com/google/re2/wiki/Syntax)](https://github.com/google/re2/wiki/Syntax)). | No | diff --git a/content/en/overview/what/core-features/traffic/introduction.md b/content/en/overview/what/core-features/traffic/introduction.md new file mode 100644 index 000000000000..dd1ed1108222 --- /dev/null +++ b/content/en/overview/what/core-features/traffic/introduction.md @@ -0,0 +1,268 @@ +--- +aliases: + - /zh/overview/core-features/traffic/ + - /zh-cn/overview/core-features/traffic/ +description: "Dubbo 的流量管控规则可以基于应用、服务、方法、参数等粒度精准的控制流量走向,根据请求的目标服务、方法以及请求体中的其他附加参数进行匹配,符合匹配条件的流量会进一步的按照特定规则转发到一个地址子集" +linkTitle: 路由机制介绍 +title: Dubbo 路由(router)机制及其如何实现流量管控介绍 +type: docs +weight: 1 +--- + +Dubbo 提供了丰富的流量管控策略 +* **地址发现与负载均衡**,地址发现支持服务实例动态上下线,负载均衡确保流量均匀的分布到每个实例上。 +* **基于路由规则的流量管控**,路由规则对每次请求进行条件匹配,并将符合条件的请求路由到特定的地址子集。 + +服务发现保证调用方看到最新的提供方实例地址,服务发现机制依赖注册中心 (Zookeeper、Nacos、Istio 等) 实现。在消费端,Dubbo 提供了多种负载均衡策略,如随机负载均衡策略、一致性哈希负载、基于权重的轮询、最小活跃度优先、P2C 等。 + +Dubbo 的流量管控规则可以基于应用、服务、方法、参数等粒度精准的控制流量走向,根据请求的目标服务、方法以及请求体中的其他附加参数进行匹配,符合匹配条件的流量会进一步的按照特定规则转发到一个地址子集。流量管控规则有以下几种: +* 条件路由规则 +* 标签路由规则 +* 脚本路由规则 +* 动态配置规则 + +如果底层用的是基于 HTTP 的 RPC 协议 (如 REST、gRPC、Triple 等),则服务和方法等就统一映射为 HTTP 路径 (path),此时 Dubbo 路由规则相当于是基于 HTTP path 和 headers 的流量分发机制。 + +> Dubbo 中有应用、服务和方法的概念,一个应用可以发布多个服务,一个服务包含多个可被调用的方法,从抽象的视角来看,一次 Dubbo 调用就是某个消费方应用发起了对某个提供方应用内的某个服务特定方法的调用,Dubbo 的流量管控规则可以基于应用、服务、方法、参数等粒度精准的控制流量走向。 + +## Router工作原理 + +以下是 Dubbo 单个路由器的工作过程,路由器接收一个服务的实例地址集合作为输入,基于请求上下文 (Request Context) 和 (Router Rule) 实际的路由规则定义对输入地址进行匹配,所有匹配成功的实例组成一个地址子集,最终地址子集作为输出结果继续交给下一个路由器或者负载均衡组件处理。 + +![Router](/imgs/v3/feature/traffic/router1.png) + +通常,在 Dubbo 中,多个路由器组成一条路由链共同协作,前一个路由器的输出作为另一个路由器的输入,经过层层路由规则筛选后,最终生成有效的地址集合。 +* Dubbo 中的每个服务都有一条完全独立的路由链,每个服务的路由链组成可能不通,处理的规则各异,各个服务间互不影响。 +* 对单条路由链而言,即使每次输入的地址集合相同,根据每次请求上下文的不同,生成的地址子集结果也可能不同。 + +![Router](/imgs/v3/feature/traffic/router2.png) + +## 路由规则分类 +### 标签路由规则 + +标签路由通过将某一个服务的实例划分到不同的分组,约束具有特定标签的流量只能在指定分组中流转,不同分组为不同的流量场景服务,从而实现流量隔离的目的。标签路由可以作为蓝绿发布、灰度发布等场景能力的基础。 + +标签路由规则是一个非此即彼的流量隔离方案,也就是匹配`标签`的请求会 100% 转发到有相同`标签`的实例,没有匹配`标签`的请求会 100% 转发到其余未匹配的实例。如果您需要按比例的流量调度方案,请参考示例 [基于权重的按比例流量路由](../../tasks/traffic-management/weight/)。 + +`标签`主要是指对 Provider 端应用实例的分组,目前有两种方式可以完成实例分组,分别是`动态规则打标`和`静态规则打标`。`动态规则打标` 可以在运行时动态的圈住一组机器实例,而 `静态规则打标` 则需要实例重启后才能生效,其中,动态规则相较于静态规则优先级更高,而当两种规则同时存在且出现冲突时,将以动态规则为准。 + +#### 标签规则示例 - 静态打标 + +静态打标需要在服务提供者实例启动前确定,并且必须通过特定的参数 `tag` 指定。 + +##### Provider + +在 Dubbo 实例启动前,指定当前实例的标签,如部署在杭州区域的实例,指定 `tag=gray`。 + +```xml + +``` + +or + +```xml + +``` + +or + +```properties +java -jar xxx-provider.jar -Ddubbo.provider.tag=gray +``` + +##### Consumer + +发起调用的一方,在每次请求前通过 `tag` 设置流量标签,确保流量被调度到带有同样标签的服务提供方。 + +```java +RpcContext.getContext().setAttachment(Constants.TAG_KEY, "gray"); +``` + +#### 标签规则示例 - 动态打标 + +相比于静态打标只能通过 `tag` 属性设置,且在启动阶段就已经固定下来,动态标签可以匹配任意多个属性,根据指定的匹配条件将 Provider 实例动态的划分到不同的流量分组中。 + +##### Provider + +以下规则对 `shop-detail` 应用进行了动态归组,匹配 `env: gray` 的实例被划分到 `gray` 分组,其余不匹配 `env: gray` 继续留在默认分组 (无 tag)。 + +```yaml +configVersion: v3.0 +force: true +enabled: true +key: shop-detail +tags: + - name: gray + match: + - key: env + value: + exact: gray +``` + +> 这里牵涉到如何给您的实例打各种原始 label 的问题,即上面示例中的 `env`,一种方式是直接写在配置文件中,如上面静态规则实例 provider 部分的配置所示,另一种方式是通过预设环境变量指定,关于这点请参考下文的 [如何给实例打标](#如何给实例打标) 一节。 + +##### Consumer + +服务发起方的设置方式和之前静态打标规则保持一致,只需要在每次请求前通过 `tag` 设置流量标签,确保流量被调度到带有同样标签的服务提供方。 + +```java +RpcContext.getContext().setAttachment(Constants.TAG_KEY, "Hangzhou"); +``` + +设置了以上标签的流量,将全部导流到 `hangzhou-region` 划分的实例上。 + +> 请求标签的作用域仅为一次点对点的 RPC 请求。比如,在一个 A -> B -> C 调用链路上,如果 A -> B 调用通过 `setAttachment` 设置了 `tag` 参数,则该参数不会在 B -> C 的调用中生效,同样的,在完成了 A -> B -> C 的整个调用同时 A 收到调用结果后,如果想要相同的 `tag` 参数,则在发起其他调用前仍需要单独设置 `setAttachment`。可以参考 [示例任务 - 环境隔离](../../tasks/traffic-management/isolation/) 了解更多 `tag` 全链路传递解决方案。 + +### 条件路由规则 + +条件路由与标签路由的工作模式非常相似,也是首先对请求中的参数进行匹配,符合匹配条件的请求将被转发到包含特定实例地址列表的子集。相比于标签路由,条件路由的匹配方式更灵活: + +* 在标签路由中,一旦给某一台或几台机器实例打了标签,则这部分实例就会被立马从通用流量集合中移除,不同标签之间不会再有交集。有点类似下图,地址集合在输入阶段就已经划分明确。 + +![tag-condition-compare](/imgs/v3/feature/traffic/tag-condition-compare1.png) + +* 而从条件路由的视角,所有的实例都是一致的,路由过程中不存在分组隔离的问题,每次路由过滤都是基于全量地址中执行 + +![tag-condition-compare](/imgs/v3/feature/traffic/tag-condition-compare2.png) + +条件路由规则的主体 `conditions` 主要包含两部分内容: + +* => 之前的为请求参数匹配条件,指定的 `匹配条件指定的参数` 将与 `消费者的请求上下文 (URL)、甚至方法参数` 进行对比,当消费者满足匹配条件时,对该消费者执行后面的地址子集过滤规则。 +* => 之后的为地址子集过滤条件,指定的 `过滤条件指定的参数` 将与 `提供者实例地址 (URL)` 进行对比,消费者最终只能拿到符合过滤条件的实例列表,从而确保流量只会发送到符合条件的地址子集。 + * 如果匹配条件为空,表示对所有请求生效,如:`=> status != staging` + * 如果过滤条件为空,表示禁止来自相应请求的访问,如:`application = product =>` + + +#### 条件路由规则示例 + +基于以下示例规则,所有 `org.apache.dubbo.demo.CommentService` 服务调用都将被转发到与当前消费端机器具有相同 `region` 标记的地址子集。`$region` 是特殊引用符号,执行过程中将读取消费端机器的实际的 `region` 值替代。 + +```yaml +configVersion: v3.0 +enabled: true +force: false +key: org.apache.dubbo.samples.CommentService +conditions: + - '=> region = $region' +``` + +> 针对条件路由,我们通常推荐配置 `scope: service` 的规则,因为它可以跨消费端应用对所有消费特定服务 (service) 的应用生效。关于 Dubbo 规则中的 `scope` 以及 `service`、`application` 的说明请阅读 [条件路由规则手册](./condition-rule)。 + +条件路由规则还支持设置具体的机器地址如 ip 或 port,这种情况下使用条件路由可以处理一些开发或线上机器的临时状况,实现**黑名单、白名单、实例临时摘除**等运维效果,如以下规则可以将机器 `172.22.3.91` 从服务的可用列表中排除。 + +```yaml +=> host != 172.22.3.91 +``` + +条件路由还支持基于请求参数的匹配,示例如下: + +```yaml +conditions: + - method=getDetail&arguments[0]=dubbo => port=20880 +``` + +### 动态配置规则 +通过 Dubbo 提供的动态配置规则,您可以动态的修改 Dubbo 服务进程的运行时行为,整个过程不需要重启,配置参数实时生效。基于这个强大的功能,基本上所有运行期参数都可以动态调整,比如超时时间、临时开启 Access Log、修改 Tracing 采样率、调整限流降级参数、负载均衡、线程池配置、日志等级、给机器实例动态打标签等。与上文讲到的流量管控规则类似,动态配置规则支持应用、服务两个粒度,也就是说您一次可以选择只调整应用中的某一个或几个服务的参数配置。 + +当然,出于系统稳定性、安全性的考量,有些特定的参数是不允许动态修改的,但除此之外,基本上所有参数都允许动态修改,很多强大的运行态能力都可以通过这个规则实现,您可以找个示例应用去尝试一下。通常 URL 地址中的参数均可以修改,这在每个语言实现的参考手册里也记录了一些更详细的说明。 + +#### 动态配置规则示例 - 修改超时时间 + +以下示例将 `org.apache.dubbo.samples.UserService` 服务的超时参数调整为 2000ms + +```yaml +configVersion: v3.0 +scope: service +key: org.apache.dubbo.samples.UserService +enabled: true +configs: + - side: provider + parameters: + timeout: 2000 +``` + +以下部分指定这个配置是服务粒度,具体变更的服务名为 `org.apache.dubbo.samples.UserService`。`scope` 支持 `service`、`application` 两个可选值,如果 `scope: service`,则 `key` 应该配置为 `version/service:group` 格式。 + +```yaml +scope: service +key: org.apache.dubbo.samples.UserService +``` + +> 关于 Dubbo 规则中的 `scope` 以及 `service`、`application` 的说明请参考 [动态配置参考手册](./configuration-rule/) 或 [动态配置示例](../../tasks/traffic-management/timeout/)。 + +`parameters` 参数指定了新的修改值,这里将通过 `timeout: 2000` 将超时时间设置为 2000ms。 + +```yaml +parameters: + timeout: 2000 +``` + +### 脚本路由规则 +脚本路由是最直观的路由方式,同时它也是当前最灵活的路由规则,因为你可以在脚本中定义任意的地址筛选规则。如果我们为某个服务定义一条脚本规则,则后续所有请求都会先执行一遍这个脚本,脚本过滤出来的地址即为请求允许发送到的、有效的地址集合。 + +```yaml +configVersion: v3.0 +key: demo-provider +type: javascript +enabled: true +script: | + (function route(invokers,invocation,context) { + var result = new java.util.ArrayList(invokers.size()); + for (i = 0; i < invokers.size(); i ++) { + if ("10.20.3.3".equals(invokers.get(i).getUrl().getHost())) { + result.add(invokers.get(i)); + } + } + return result; + } (invokers, invocation, context)); // 表示立即执行方法 +``` + +## 如何给实例打标 + +当前,有两种方式可以在启动阶段为 Dubbo 实例指定标签,一种是之前提到的应用内配置的方式,如在 xml 文件中设置 ``,应用打包部署后即自动被打标。 + +还有一种更灵活的方式,那就是通过读取所部署机器上的环境信息给应用打标,这样应用的标签就可以跟随实例动态的自动填充,避免每次更换部署环境就重新打包应用镜像的问题。当前 Dubbo 能自动读取以下环境变量配置: + +```yaml +spec: + containers: + - name: detail + image: apache/demo-detail:latest + env: + - name: DUBBO_LABELS + value: "region=hangzhou; env=gray" +``` + +```yaml +spec: + containers: + - name: detail + image: apache/demo-detail:latest + env: + - name: DUBBO_ENV_KEYS + value: "REGION, ENV" + - name: REGION + value: "hangzhou" + - name: ENV + value: "gray" +``` + +如果您有不同的实例环境保存机制,可以通过扩展 `InfraAdapter 扩展点` 来自定义自己的标签加载方式。如果您的应用是部署在 Kubernetes 环境下,并且已经接入了服务网格体系,则也可以使用标准 deployment 标签的方式打标,具体请跟随 [服务网格任务示例](../../tasks/mesh/) 学习。 + +## 如何配置流量规则 +Dubbo 提供了控制台 Dubbo Admin,帮助您可视化的下发流量管控规则,并实时监控规则生效情况。 + +![Admin](/imgs/v3/what/admin.png) + +Dubbo 还提供了 `dubboctl` 命令行工具,需要有 Dubbo Admin 提前部署就绪,因为 dubboctl 是通过与 Admin 进行 http 通信完成规则下发的。 + +如果您使用的是如 Istio 的服务网格架构,还可以使用 Istioctl、kubectl 等下发 Istio 标准规则。 + +## 接入服务网格 + +以上介绍的都是 Dubbo 体系内的流量治理规则,如果您对服务网格架构感兴趣,则可以将 Dubbo 服务接入服务网格体系,这样,您就可以使用服务网格提供的流量治理能力,如 Istio 体系的 VirtualService 等。 + +具体请参见 [Dubbo 中的服务网格架构](../service-mesh)。 + +## 跟随示例学习 +我们搭建了一个 [线上商城系统](../../tasks/traffic-management/) 供您学习流量规则的具体使用。 diff --git a/content/en/overview/core-features/traffic/mesh-rule.md.bak b/content/en/overview/what/core-features/traffic/mesh-rule.md similarity index 98% rename from content/en/overview/core-features/traffic/mesh-rule.md.bak rename to content/en/overview/what/core-features/traffic/mesh-rule.md index 7c4fad9c586e..924167bcae09 100644 --- a/content/en/overview/core-features/traffic/mesh-rule.md.bak +++ b/content/en/overview/what/core-features/traffic/mesh-rule.md @@ -8,7 +8,8 @@ description: "" Dubbo Mesh 路由规则是基于 Istio 的 VirtualService、DestinationRule 改造而来,总体思路和格式可以参考 Istio 流量管控规则参考手册:[Istio VirtualService](https://istio.io/latest/docs/reference/config/networking/virtual-service/) 和 [Istio DestinationRule](https://istio.io/latest/docs/reference/config/networking/destination-rule/) -本文描述了 Dubbo Mesh 路由规则的设计原理,和 Istio 规则的差异等。 +本文描述了 Dubbo Mesh 路由规则的设计原理,以及它和 Istio 规则的差异等。参考链接:https://www.yuque.com/docs/share/c132d5db-0dcb-487f-8833-7c7732964bd4?#。 + ### 基本思想 基于路由链,采用Pipeline的处理方式,如下图所示: diff --git a/content/en/overview/what/core-features/traffic/script-rule.md b/content/en/overview/what/core-features/traffic/script-rule.md new file mode 100644 index 000000000000..96cf57f40340 --- /dev/null +++ b/content/en/overview/what/core-features/traffic/script-rule.md @@ -0,0 +1,64 @@ +--- +aliases: + - /zh/overview/core-features/traffic/script-rule/ + - /zh-cn/overview/core-features/traffic/script-rule/ +description: "" +linkTitle: 脚本路由 +title: 脚本路由规则 +type: docs +weight: 3 +--- + + + +脚本路由为流量管理提供了最大的灵活性,所有流量在执行负载均衡选址之前,都会动态的执行一遍规则脚本,根据脚本执行的结果确定可用的地址子集。 + +脚本路由只对消费者生效且只支持应用粒度管理,因此, `key` 必须设置为消费者应用名;脚本语法支持多种,以 Dubbo Java SDK 为例,脚本语法支持 Javascript、Groovy、Kotlin 等,具体可参见每个语言实现的限制。 + +> 脚本路由由于可以动态加载远端代码执行,因此存在潜在的安全隐患,在启用脚本路由前,一定要确保脚本规则在安全沙箱内运行。 + +```yaml +configVersion: v3.0 +key: demo-provider +type: javascript +enabled: true +script: | + (function route(invokers,invocation,context) { + var result = new java.util.ArrayList(invokers.size()); + for (i = 0; i < invokers.size(); i ++) { + if ("10.20.3.3".equals(invokers.get(i).getUrl().getHost())) { + result.add(invokers.get(i)); + } + } + return result; + } (invokers, invocation, context)); // 表示立即执行方法 +``` + +## ScriptRule +脚本路由规则主体。定义脚本规则生效的目标消费者应用、流量过滤脚本以及一些特定场景下的行为。 + +| Field | Type | Description | Required | +| --- | --- | --- | --- | +| configVersion | string | The version of the script rule definition, currently available version is `v3.0` | Yes | +| key | string | The identifier of the target application that this rule is about to apply to.| Yes | +| type | string | The script language used to define `script`. | Yes | +| enabled | bool | Whether enable this rule or not, set `enabled:false` to disable this rule. | Yes | +| script | string | The script definition used to filter dubbo provider instances. | Yes | +| force | bool | The behaviour when the instance subset is empty after after routing. `true` means return no provider exception while `false` means ignore this rule. | No | + +## Script +`script` 为脚本路由规则的主体,类型为一个具有符合结构的 string 字符串,具体取决于 `type` 指定的脚本语言。 + +以下是 `type: javascript` 的一个脚本规则示例: + +```javascript +(function route(invokers,invocation,context) { + var result = new java.util.ArrayList(invokers.size()); + for (i = 0; i < invokers.size(); i ++) { + if ("10.20.3.3".equals(invokers.get(i).getUrl().getHost())) { + result.add(invokers.get(i)); + } + } + return result; + } (invokers, invocation, context)); // 表示立即执行方法 +``` diff --git a/content/en/overview/what/core-features/traffic/tag-rule.md b/content/en/overview/what/core-features/traffic/tag-rule.md new file mode 100644 index 000000000000..6e382f401106 --- /dev/null +++ b/content/en/overview/what/core-features/traffic/tag-rule.md @@ -0,0 +1,62 @@ +--- +aliases: + - /zh/overview/core-features/traffic/tag-rule/ + - /zh-cn/overview/core-features/traffic/tag-rule/ +description: "" +linkTitle: 标签路由 +title: 标签路由规则 +type: docs +weight: 2 +--- + + + +标签路由通过将某一个服务的实例划分到不同的分组,约束具有特定标签的流量只能在指定分组中流转,不同分组为不同的流量场景服务,从而达到实现流量隔离的目的,可以作为蓝绿发布、灰度发布等场景能力的基础。目前有两种方式可以对实例打标,分别是`动态规则打标`和`静态规则打标`。`动态规则打标` 可以在运行时动态的圈住一组机器实例,而 `静态规则打标` 则需要实例重启后才能生效,其中,动态规则相较于静态规则优先级更高,而当两种规则同时存在且出现冲突时,将以动态规则为准。 + +本文要讲的就是标签路由规则就是 `动态规则打标`。 + +标签路由是一套严格隔离的流量体系,对于同一个应用而言,一旦打了标签则这部分地址子集就被隔离出来,只有带有对应标签的请求流量可以访问这个地址子集,这部分地址不再接收没有标签或者具有不同标签的流量。 + +举个例子,如果我们将一个应用进行打标,打标后划分为 tag-a、tag-b、无 tag 三个地址子集,则访问这个应用的流量,要么路由到 tag-a (当请求上下文 dubbo.tag=tag-a),要么路由到 tag-b (dubbo.tag=tag-b),或者路由到无 tag 的地址子集 (dubbo.tag 未设置),不会出现混调的情况。 + +标签路由的作用域是提供者应用,消费者应用无需配置标签路由规则。一个提供者应用内的所有服务只能有一条分组规则,不会有服务 A 使用一条路由规则、服务 B 使用另一条路由规则的情况出现。以下条件路由示例,在 `shop-detail` 应用中圈出了一个隔离环境 `gray`,`gray` 环境包含所有带有 `env=gray` 标识的机器实例。 + +```yaml +configVersion: v3.0 +force: true +enabled: true +key: shop-detail +tags: + - name: gray + match: + - key: env + value: + exact: gray +``` +## TagRule +标签路由规则主体。定义路由规则生效的目标应用、标签分类规则以及一些特定场景下的行为。 + +| Field | Type | Description | Required | +| --- | --- | --- | --- | +| configVersion | string | The version of the tag rule definition, currently available version is `v3.0` | Yes | +| key | string | The identifier of the target application that this rule is about to control| Yes | +| enabled | bool | Whether enable this rule or not, set `enabled:false` to disable this rule. | Yes | +| tags | Tag[] | The tag definition of this rule. | Yes | +| force | bool | The behaviour when the instance subset is empty after routing. `true` means return no provider exception while `false` means fallback to subset without any tags. | No | +| runtime | bool | Whether run routing rule for every rpc invocation or use routing cache if available. | No | + +## Tag +标签定义,根据 `match` 条件筛选出一部分地址子集。 + +| Field | Type | Description | Required | +| --- | --- | --- | --- | +| name | string | The name of the tag used to match the `dubbo.tag` value in the request context. | Yes | +| match | MatchCondition | A set of criterion to be met for instances to be classified as member of this tag. | No | + +## MatchCondition +定义实例过滤条件,根据 Dubbo URL 地址中的特定参数进行过滤。 + +| Field | Type | Description | Required | +| --- | --- | --- | --- | +| key | string | The name of the key in the Dubbo url address. | Yes | +| value | StringMatch (oneof) | The matching condition for the value in the Dubbo url address. | Yes | diff --git a/content/en/overview/what/dubbo3.md b/content/en/overview/what/dubbo3.md deleted file mode 100644 index 7033e33cb45a..000000000000 --- a/content/en/overview/what/dubbo3.md +++ /dev/null @@ -1,94 +0,0 @@ - ---- -type: docs -title: "Dubbo 3 Quick Facts" -linkTitle: "Dubbo 3 Quick Facts" -weight: 2 ---- - -This article will take you to quickly understand the design background, overall architecture and core features of Dubbo3, and its relationship with typical users such as Alibaba HSF2, etc. You can also learn more in the following sections: -* **New users, take a quick look at the core features of Dubbo3:** - * [Next Generation Communication Protocol - Triple](/en/docs3-v2/java-sdk/concepts-and-architecture/triple/) - * [Secrets of a million-instance cluster - application-level service discovery](/en/docs3-v2/java-sdk/concepts-and-architecture/service-discovery/) - * [Dubbo Mesh](/en/docs3-v2/java-sdk/concepts-and-architecture/mesh/) -* **Dubbo3 compatibility and migration cost?** - * [Java - Migration Guide](/en/docs3-v2/java-sdk/upgrades-and-compatibility) - * [Golang - Migration Guide](/en/docs3-v2/golang-sdk/) -* **Dubbo3 related resources:** - * For more information, such as performance indicators, advanced feature descriptions, etc., please refer to [Multilingual SDK Implementation](/en/overview/mannual/) - * Speeches and offline activities - -### background - -The design and development of Dubbo3 has two major backgrounds. - -**First, how to better meet the demands of corporate practice. ** Since Dubbo was donated by Alibaba in 2011, it has been the preferred open source service framework for many large-scale enterprise microservice practices. During this period, the enterprise architecture has undergone changes from the SOA architecture to the microservice architecture, and the Dubbo community itself is constantly updating and iterating to better meet the demands of the enterprise. However, the limitations of Dubbo2 architecture are gradually highlighted in practice: -- **Protocol**, the Dubbo2 protocol is famous for its performance and simplicity, but it encounters more and more problems of versatility and penetration in the cloud-native era; -- **Scalability**, Dubbo2 is still far superior to many other frameworks in terms of scalability, but as microservices bring more applications and instances, we have to think about how to deal with the actual combat of larger-scale clusters; -- **Service Governance Ease of Use**, such as richer traffic governance, observability, intelligent load balancing, etc. - -**Secondly, adapt to the development of cloud native technology stack. ** While microservices make the evolution of business development more flexible and fast, it also brings some unique features and requirements: such as the number of components after microservices is increasing, how to solve the stability of each component, how to quickly Horizontal expansion, etc., cloud-native infrastructure represented by Docker, Kubernetes, and Service Mesh has brought some new options to solve these problems. As more microservice components and capabilities are sinking to the infrastructure layer represented by Kubernetes, the traditional microservice development framework should eliminate some redundant mechanisms and actively adapt to the infrastructure layer to achieve capability reuse. Capabilities such as the life cycle and service governance of the microservice framework should be better integrated with the Kubernetes service orchestration mechanism; the microservice architecture represented by Service Mesh brings new options to microservice development, and Sidecar brings multilingual, transparent upgrades, and traffic control However, it also brings disadvantages such as operation and maintenance complexity and performance loss. Therefore, the traditional microservice system based on the service framework will still be the mainstream, and will still occupy half of the country in the long run, and will maintain mixed deployment for a long time state. - -### Overall objective - -Dubbo3 still maintains the classic architecture of 2.x. Its main responsibility is to solve the communication between microservice processes, and to better manage and control microservice clusters through rich service governance (such as address discovery, traffic management, etc.); The upgrade of the framework is comprehensive, reflected in almost every aspect of the core Dubbo features, through the upgrade to achieve a comprehensive improvement in stability, performance, scalability, and ease of use. - -![architecture-1](/imgs/v3/concepts/architecture-1.png) - -- **Common communication protocol.** The new RPC protocol should abandon the private protocol stack, use the more general HTTP/2 protocol as the transport layer carrier, and use the standardized features of the HTTP protocol to solve the problems of traffic versatility and penetration, so that the protocol can better respond Scenarios such as front-end and back-end docking, gateway proxy, etc.; supports the Stream communication mode, which meets the demands of different business communication models and brings greater throughput to the cluster. -- **For millions of cluster instances, the cluster is highly scalable.** With the promotion of micro-service practices, the scale of micro-service cluster instances is also constantly expanding, which benefits from the characteristics of light-weight micro-services and easy horizontal expansion, but also brings a burden to the entire cluster capacity, especially It is some centralized service governance components; Dubbo3 needs to solve various resource bottlenecks caused by the expansion of instance scale, and realize truly unlimited horizontal expansion. -- **Richer programming model, less business intrusion.** In the development state, the business application is programmed for Dubbo SDK. In the running state, the SDK and the business application run in the same process. The ease of use, stability and resource consumption of the SDK will greatly affect the business application; therefore, 3.0 should have More abstract API, more friendly configuration mode, less encroachment on business application resources, and higher availability. -- **Easier to use and richer service governance capabilities.** The dynamic nature of microservices has brought high complexity to the governance work, and Dubbo has been doing a good job in this regard. It is the earliest batch of governance capability definers and practitioners; 3.0 needs to be oriented to richer scenarios. Provides capabilities such as observability, security, grayscale release, error injection, external configuration, and unified governance rules. -- **Fully embrace cloud native.** - -### Facing the pain points of enterprise production practice - -Dubbo2 is still the preferred open source service framework in China. It is widely used in almost all digital transformation enterprises such as the Internet, financial insurance, software companies, and traditional enterprises, and has been tested in a large-scale production environment. Take Alibaba, a contributor and typical user of Dubbo2, as an example. The HSF2 framework maintained internally by Alibaba based on Dubbo2 has experienced previous double-eleven peak tests. Billions of RPC calls are made every day, and more than ten million service instances are managed. In the long-term optimization and practical accumulation, Alibaba has a vision and plan for the next-generation service framework, and began to evolve rapidly internally, and was quickly contributed to the Apache community. Just like Alibaba, the practical demands of other users are related to Pain points are also rapidly accumulating in the open source community, forming a consistent direction and technical solutions. It can be said that the birth of Dubbo3 comes from the accumulation of a large base of enterprise users, in order to better meet their practical demands. - -![dubbo3-hsf](/imgs/v3/concepts/dubbo-hsf.png) - -Dubbo3 integrates a large amount of service management experience of Alibaba HSF2 and other community enterprises. Currently, Dubbo3 has been fully applied to the production practice environment. Banks, Fenghuodi, Ping An Health, etc. The virtuous circle formed by the cooperation between the community and users has greatly promoted the development of Dubbo3. Alibaba has completely replaced the internally maintained HSF2 framework with the community version of Dubbo3. Their practical experience has promoted the stability of Dubbo3 on the one hand, and is positively It is enough to continuously export the practical experience of service governance to the open source community. - -### For millions of cluster instances, horizontal scalability - -With the accumulation of practical experience in microservices, microservices are split into finer grains and deployed to more and more machine instances to support the growing business scale. Among many Dubbo2 enterprise users, especially large-scale enterprises represented by finance, insurance and the Internet, they began to encounter cluster capacity bottlenecks (for typical cases, please refer to Industrial and Commercial Bank of China Practice Cases: -* **Service discovery process** - * The data storage scale of the registration center reaches the capacity bottleneck - * Data registration & push efficiency is seriously reduced -* **Dubbo Process** - * Occupy more machine resources, resulting in lower utilization of business resources - * Frequent GC affects business stability - -Dubbo3 solves these problems very well in design. The service governance (service discovery) model implemented through the new design can realize the data transmission and data storage on the service discovery link to reduce by about 90% on average; at the same time, Dubbo3 itself is in the business In the process, it becomes lighter and more stable, achieving a 50% increase in resource utilization. - -A greater advantage of Dubbo3 lies in its improvement of the stability of the overall architecture. The new service discovery architecture makes it easier and more accurate to evaluate the capacity and scalability of the entire cluster. - -![capacity](/imgs/v3/concepts/capacity.png) - -If application development is roughly divided into two levels: business development and operation and maintenance deployment, factors that change frequently include services (interfaces), applications, and machine instances. In the 2.x era, the growth of all these three factors will affect the overall capacity of the microservice cluster, especially the fluctuation caused by the increase or decrease of interfaces, which is very opaque to the overall capacity assessment. In 3.0, the change of cluster capacity is only related to the two factors of application name and machine instance, and the objects of capacity evaluation are often applications and instances, so the entire cluster becomes more stable and transparent. - -### Cloud Native - -In the cloud-native era, changes in the underlying infrastructure are profoundly affecting application deployment, operation and maintenance, and even the development process. It also affects the selection and deployment mode of Dubbo3 microservice technology solutions. - -#### Next Generation RPC Protocol - -The new-generation Triple protocol is based on HTTP/2 as the transport layer, has better gateway and proxy penetration, natively supports Stream communication semantics, and is compatible with the gRPC protocol. - -#### Multilingual Friendly - -Dubbo3 has taken multilingual friendliness as a key consideration in terms of service definition, RPC protocol, serialization, and service governance. Currently, it provides stable multilingual versions of Java and Golang, and 3.0 implementations of more language versions such as Rust , Javascript, C/C++, C#, etc. are under development and construction. - -#### Kubernetes - -Applications developed by Dubbo3 can be natively deployed on the Kubernetes platform. Dubbo3 has been designed to be aligned with container scheduling platforms such as Kubernetes in terms of address and life cycle; for users who want to further reuse the underlying infrastructure capabilities of Kubernetes, Dubbo3 has also been connected to the native The Kubernetes Service system. - -#### Service Mesh - -Service Mesh emphasizes the role of the control plane in microservice governance, which to a certain extent promotes the expansion and standardization of the control plane communication protocol and scope of responsibility; the Sidecar model under the traditional Mesh architecture emphasizes the unified control of traffic by bypass agents to achieve Features such as transparent upgrade, multilingual non-sense, and no business intrusion. - -Dubbo3 provides a Dubbo Mesh solution based on its own thinking, emphasizing the unified management and control of microservice clusters. In terms of deployment architecture, it supports both sicecar and proxyless deployment architecture without sidecar. Users who use Dubbo Mesh are based on their own business Features will have more options for deployment architectures. - -#### Heterogeneous System Interoperability - -We are seeing more and more requests for interoperability of heterogeneous microservice systems, such as Dubbo, Spring Cloud, gRPC, etc. Some are due to the migration of the technology stack, and some are due to the need to achieve business intermodulation after the merger of the organization. With the help of the new service discovery model and the flexible and scalable RPC protocol, Dubbo3 can become the future development goal of Dubbo3. diff --git a/content/en/overview/what/ecosystem.md b/content/en/overview/what/ecosystem.md deleted file mode 100644 index 0fb7d3629efa..000000000000 --- a/content/en/overview/what/ecosystem.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -type: docs -title: "Ecosystem" -linkTitle: "Ecosystem" -weight: 5 ---- -### Dashboard - -* [Dubbo-admin](https://github.com/apache/dubbo-admin) - -### Supported Components and Deployment Architectures - -Dubbo implementations generally support the following products or deployment architectures, and specific multilingual SDK implementations may vary. - -* Registry - * Zookeeper - * [Nacos](https://nacos.io/zh-cn/docs/use-nacos-with-dubbo.html) - * Kubernetes -* Metadata center - * Zookeeper - * [Nacos](https://nacos.io/zh-cn/docs/use-nacos-with-dubbo.html) - * Redis -* Configuration center - * Zookeeper - * [Nacos](https://nacos.io/zh-cn/docs/use-nacos-with-dubbo.html) - * Redis - * Apollo -* Mesh - * Data plane Envoy - * Control plane Istio - -### Protocols and Interoperability -* Interoperability with the gRPC system can be realized based on the Triple protocol -* Based on the REST protocol and application-level service discovery, the interoperability of the Spring Cloud system at the protocol and address discovery levels can be realized - -### SPI Integration -There are many Dubbo extension implementations here, including protocols, serialization, registration centers, etc. -* [dubbo-spi-extensions] - -### Gateway component -* [Apache Shenyu] -* [Apache APISIX] -* [Apache Dubbo-pixiu] -* [Tengine] - -### Link Tracking -* [Zipkin] -* [Apache Skywalking] - -### Other microservice components -* Current Limiting [Sentinel] -* Affairs [Seata] - -### Multilingual implementation -* Golang -* Java -* Rust -* Node -* Python -* PHP \ No newline at end of file diff --git a/content/en/overview/what/extensibility.md b/content/en/overview/what/extensibility.md deleted file mode 100644 index a66dcfdd7500..000000000000 --- a/content/en/overview/what/extensibility.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -type: docs -title: "Extensibility" -linkTitle: "Extensibility" -weight: 4 ---- - -## Extended Design Ideas - -Scalability is what any system pursues, and it is equally applicable to Dubbo. - -### What is scalability - -Scalability is a design concept that represents our vision for the future. We hope that based on the existing architecture or design, when some aspects change in the future, we can adapt to this with minimal changes. kind of change. - -### Advantages of Scalability - -The advantage of scalability is mainly manifested in the decoupling between modules, which conforms to the principle of opening and closing, which is open to expansion and closed to modification. When a new function is added to the system, there is no need to modify the structure and code of the existing system, just add an extension. - -### Extended implementation - -Generally speaking, the system will use Factory, IoC, OSGI, etc. to manage the extension (plug-in) life cycle. Considering the applicability of Dubbo, I don't want to strongly rely on IoC containers such as Spring. -And building a small IoC container by myself feels a bit over-designed, so choose the simplest Factory way to manage extensions (plug-ins). In Dubbo, all internal and third-party implementations are equal. - -### Scalability in Dubbo - -* Treat third-party implementations equally. In Dubbo, all internal implementations and third-party implementations are equal, and users can replace the native implementations provided by Dubbo based on their own business needs. -* Each extension point only encapsulates one change factor to maximize reuse. The implementers of each extension point often only care about one thing. If users need to expand, they only need to expand the extension points they care about, which greatly reduces the workload of users. - -## Features of Dubbo extension - -The extension capability in Dubbo is enhanced from the JDK standard SPI extension point discovery mechanism, which improves the following problems of the JDK standard SPI: - -* The JDK standard SPI will instantiate all the implementations of the extension point at one time. If there is an extension implementation, it will take time to initialize, but if it is not used, it will be loaded, which will waste resources. -* If the extension point fails to load, even the name of the extension point cannot be obtained. For example: JDK standard ScriptEngine, get the name of the script type through getName(), but if RubyScriptEngine fails to load the RubyScriptEngine class because the jruby. When the user executes the ruby script, it will report that ruby is not supported, not the real reason for the failure. - -Based on the expansion capabilities provided by Dubbo, users can easily expand other protocols, filters, routes, etc. based on their own needs. The following introduces the characteristics of Dubbo's extension capabilities. - -* Load on demand. Dubbo's extension capability does not instantiate all implementations at once, but instantiates which extension class is used to reduce resource waste. -* Increase the IOC capability of the extended class. Dubbo's extension capability is not just to discover the extension service implementation class, but to go further on this basis. If the attributes of the extension class depend on other objects, Dubbo will automatically complete the injection function of the dependent object. -* Increase the AOP capability of extended classes. Dubbo's extension capability will automatically discover the wrapper class of the extension class, complete the construction of the wrapper class, and enhance the function of the extension class. -* Possess the ability to dynamically select the extension implementation. The Dubbo extension will dynamically select the corresponding extension class at runtime based on parameters, which improves Dubbo's scalability. -* The extension implementation can be sorted. The execution order of the extension implementation can be specified based on user requirements. -* Provides the Adaptive capability of the extension point. This capability enables some extension classes to take effect on the consumer side, and some extension classes to take effect on the provider side. - -From the design goal of Dubbo extension, it can be seen that some features implemented by Dubbo, such as dynamic selection of extension implementation, IOC, AOP, etc., can provide users with very flexible expansion capabilities. - -## Dubbo extension loading process - -The whole process of Dubbo loading extension is as follows: - -![//imgs/v3/concepts/extension-load.png](/imgs/v3/concepts/extension-load.png) - -There are 4 main steps: -* Read and parse configuration files -* Cache all extension implementations -* Based on the extension name executed by the user, instantiate the corresponding extension implementation -* Perform IOC injection of extended instance attributes and instantiate extended wrapper classes to realize AOP features - -## How to use Dubbo's extension capability to expand - -The following takes the extension protocol as an example to illustrate how to use the extension capabilities provided by Dubbo to extend the Triple protocol. - -(1) Place a text file in the protocol implementation jar package: META-INF/dubbo/org.apache.dubbo.remoting.api.WireProtocol -```text -tri=org.apache.dubbo.rpc.protocol.tri.TripleHttp2Protocol -``` - -(2) Implementation class content -```java -@Activate -public class TripleHttp2Protocol extends Http2WireProtocol { - //... -} -``` - -Instructions: Http2WireProtocol implements the WireProtocol interface - -(3) In the Dubbo configuration module, each extension point has a corresponding configuration attribute or label, and the configuration specifies which extension to use. for example: -```text - -``` - -As can be seen from the above expansion steps, the user basically completes the expansion under the black box. - -## Dubbo extended application - -Dubbo's expansion capability is very flexible, and it is ubiquitous in the realization of its own functions. - -![//imgs/v3/concepts/extension-use.png](/imgs/v3/concepts/extension-use.png) - -Dubbo's extensibility makes it easy to divide the Dubbo project into sub-modules one by one to realize the hot-swappable feature. Users can completely replace Dubbo's native implementation based on their own needs to meet their own business needs. - -## scenes to be used - -* If you need to customize the load balancing strategy, you can use Dubbo's scalability. -* If you need to implement a custom registry, you can use Dubbo's extension capabilities. -* If you need to implement custom filters, you can use Dubbo's extension capabilities. - -Dubbo extensions treat internal implementations and third-party implementations equally. For more usage scenarios, see [SPI extension implementation](/en/docs3-v2/java-sdk/reference-manual/spi/description/) \ No newline at end of file diff --git a/content/en/overview/what/overview.md b/content/en/overview/what/overview.md index 0b7171316430..15f5ace8782d 100644 --- a/content/en/overview/what/overview.md +++ b/content/en/overview/what/overview.md @@ -1,105 +1,116 @@ --- +aliases: + - /zh/overview/what/overview/ + - /zh/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture/ + - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture/ + - /zh-cn/overview/mannual/java-sdk/concepts-and-architecture/overall-architecture/ +description: "" +linkTitle: 概念与架构 +title: 了解 Dubbo 核心概念和架构 type: docs -title: "Introduction to Dubbo" -linkTitle: "Introduction" weight: 1 -description: "" --- -Apache Dubbo is an RPC service development framework, which is used to solve service governance and communication problems under the microservice architecture. It officially provides multi-language SDK implementations such as Java and Golang. Microservices developed using Dubbo are natively capable of remote address discovery and communication with each other. -Using the rich service governance features provided by Dubbo, service governance demands such as service discovery, load balancing, and traffic scheduling can be realized. Dubbo is designed to be highly scalable, and users can easily implement various custom logics for traffic interception and location selection. -Dubbo3 is defined as a cloud-native-oriented next-generation RPC service framework. 3.0 has evolved based on Dubbo 2.x. While maintaining the original core features, Dubbo3 has improved in ease of use, ultra-large-scale microservice practice, cloud-native infrastructure adaptation, and security. Comprehensive upgrades have been made in several major directions, including ease of use, hyperscale microservice practices, cloud-native infrastructure adaptation, and security. -### What is Dubbo +![architecture](/imgs/v3/concepts/architecture-2.png) + +以上是 Dubbo 的工作原理图,从抽象架构上分为两层:**服务治理抽象控制面** 和 **Dubbo 数据面** 。 +* **服务治理控制面**。服务治理控制面不是特指如注册中心类的单个具体组件,而是对 Dubbo 治理体系的抽象表达。控制面包含协调服务发现的注册中心、流量管控策略、Dubbo Admin 控制台等,如果采用了 Service Mesh 架构则还包含 Istio 等服务网格控制面。 +* **Dubbo 数据面**。数据面代表集群部署的所有 Dubbo 进程,进程之间通过 RPC 协议实现数据交换,Dubbo 定义了微服务应用开发与调用规范并负责完成数据传输的编解码工作。 + * 服务消费者 (Dubbo Consumer),发起业务调用或 RPC 通信的 Dubbo 进程 + * 服务提供者 (Dubbo Provider),接收业务调用或 RPC 通信的 Dubbo 进程 + +## Dubbo 数据面 +从数据面视角,Dubbo 帮助解决了微服务实践中的以下问题: +* Dubbo 作为 **服务开发框架** 约束了微服务定义、开发与调用的规范,定义了服务治理流程及适配模式 +* Dubbo 作为 **RPC 通信协议实现** 解决服务间数据传输的编解码问题 + +![framework](/imgs/v3/what/framework1.png) + +### 服务开发框架 +微服务的目标是构建足够小的、自包含的、独立演进的、可以随时部署运行的分布式应用程序,几乎每个语言都有类似的应用开发框架来帮助开发者快速构建此类微服务应用,比如 Java 微服务体系的 Spring Boot,它帮 Java 微服务开发者以最少的配置、最轻量的方式快速开发、打包、部署与运行应用。 + +微服务的分布式特性,使得应用间的依赖、网络交互、数据传输变得更频繁,因此不同的**应用需要定义、暴露或调用 RPC 服务,那么这些 RPC 服务如何定义、如何与应用开发框架结合、服务调用行为如何控制?这就是 Dubbo 服务开发框架的含义,Dubbo 在微服务应用开发框架之上抽象了一套 RPC 服务定义、暴露、调用与治理的编程范式**,比如 Dubbo Java 作为服务开发框架,当运行在 Spring 体系时就是构建在 Spring Boot 应用开发框架之上的微服务开发框架,并在此之上抽象了一套 RPC 服务定义、暴露、调用与治理的编程范式。 + +![framework](/imgs/v3/what/framework2.png) + +Dubbo 作为服务开发框架包含的具体内容如下: +* **RPC 服务定义、开发范式**。比如 Dubbo 支持通过 IDL 定义服务,也支持编程语言特有的服务开发定义方式,如通过 Java Interface 定义服务。 +* **RPC 服务发布与调用 API**。Dubbo 支持同步、异步、Reactive Streaming 等服务调用编程模式,还支持请求上下文 API、设置超时时间等。 +* **服务治理策略、流程与适配方式等**。作为服务框架数据面,Dubbo 定义了服务地址发现、负载均衡策略、基于规则的流量路由、Metrics 指标采集等服务治理抽象,并适配到特定的产品实现。 + +想了解如何使用 Dubbo 微服务框架进行业务编码?从以下 SDK 开始微服务项目开发之旅吧: +* [Java](/zh-cn/overview/quickstart/java/) +* [Golang](/zh-cn/overview/quickstart/go/) +* [Rust](/zh-cn/overview/quickstart/rust/) +* [Node](https://github.com/apache/dubbo-js) + +### 通信协议 +**Dubbo 从设计上不绑定任何一款特定通信协议,HTTP/2、REST、gRPC、JsonRPC、Thrift、Hessian2 等几乎所有主流的通信协议,Dubbo 框架都可以提供支持。** 这样的 Protocol 设计模式给构建微服务带来了最大的灵活性,开发者可以根据需要如性能、通用型等选择不同的通信协议,不再需要任何的代理来实现协议转换,甚至你还可以通过 Dubbo 实现不同协议间的迁移。 -Apache Dubbo was originally donated by Alibaba as an open source in 2008, and soon became the de facto standard framework for the selection of open source service frameworks in China, and has been widely used in various industries. In 2017, Dubbo officially donated to the Apache Software Foundation and became a top-level project of Apache. Currently, Dubbo3 is already a one-stop microservice solution providing: -* HTTP/2-based [Triple protocol](/en/docs3-v2/java-sdk/concepts-and-architecture/triple/) and programming experience for proxy API. -* Powerful [traffic management capability] (../../tasks/traffic-management), such as address discovery, load balancing, routing address selection, dynamic configuration, etc. -* [Multi-language SDK implementation](../../mannual/), covering Java, Golang, Javascript, etc. More language implementations will be released in succession. -* Flexible adaptation and expansion capabilities, which can be easily adapted to other components of the microservice system such as Tracing and Transaction. -* [Dubbo Mesh Solution](/en/docs3-v2/java-sdk/concepts-and-architecture/mesh/), while supporting flexible Mesh deployment solutions such as Sidecar and Proxyless. +![protocols](/imgs/v3/what/protocol.png) -The overall architecture of Apache Dubbo can well meet the large-scale microservice practice of enterprises, because it is designed to solve the practical problems of ultra-large-scale microservice clusters from the beginning, whether it is Alibaba, ICBC, China Ping An, Ctrip and other community users, They have fully verified the stability and performance of Dubbo through years of large-scale production environment traffic. Therefore, Dubbo has unparalleled advantages in solving business landing and large-scale practice: -* out of the box - * High ease of use, such as the interface-oriented proxy feature of the Java version can realize local transparent calls - * Rich in functions, most of the microservice governance capabilities can be realized based on native libraries or lightweight extensions -* Designed for ultra-large-scale microservice clusters - * Extreme performance, high-performance RPC communication protocol design and implementation - * Horizontally scalable, easily supporting address discovery and traffic management of millions of cluster instances -* [highly extensible](../extensibility) - * Interception and extension of traffic and protocols during calling, such as Filter, Router, LB, etc. - * Extension of microservice governance components, such as Registry, Config Center, Metadata Center, etc. -* Enterprise-level microservice governance capabilities - * The de facto standard service framework supported by domestic public cloud vendors - * Years of enterprise practical experience test +Dubbo Protocol 被设计支持扩展,您可以将内部私有协议适配到 Dubbo 框架上,进而将私有协议接入 Dubbo 体系,以享用 Dubbo 的开发体验与服务治理能力。比如 Dubbo3 的典型用户阿里巴巴,就是通过扩展支持 HSF 协议实现了内部 HSF 框架到 Dubbo3 框架的整体迁移。 -### Dubbo basic workflow +Dubbo 还支持多协议暴露,您可以在单个端口上暴露多个协议,Dubbo Server 能够自动识别并确保请求被正确处理,也可以将同一个 RPC 服务发布在不同的端口(协议),为不同技术栈的调用方服务。 -![dubbo-rpc](/imgs/v3/concepts/rpc.png) +Dubbo 提供了两款内置高性能 Dubbo2、Triple (兼容 gRPC) 协议实现,以满足部分微服务用户对高性能通信的诉求,两者最开始都设计和诞生于阿里巴巴内部的高性能通信业务场景。 +* Dubbo2 协议是在 TCP 传输层协议之上设计的二进制通信协议 +* Triple 则是基于 HTTP/2 之上构建的支持流式模式的通信协议,并且 Triple 完全兼容 gRPC 但实现上做了更多的符合 Dubbo 框架特点的优化。 -First of all, Dubbo is an RPC framework, which defines its own RPC communication protocol and programming method. As shown in the figure above, when using Dubbo, users first need to define the Dubbo service; secondly, after deploying the Dubbo service online, rely on Dubbo's application layer communication protocol to realize data exchange, and the data transmitted by Dubbo must be serialized. And here the serialization protocol is fully extensible. -The first step in using Dubbo is to define Dubbo services. The definition of services in Dubbo is a set of methods to complete business functions. You can choose to define them in a way that is bound to a certain language. For example, in Java, Dubbo services have a set of interface of the method can also use the language-neutral Protobuf Buffers [IDL definition service](../../tasks/triple/idl/). After the service is defined, the server (Provider) needs to provide a specific implementation of the service and declare it as a Dubbo service. From the perspective of the service consumer (Consumer), a service proxy can be obtained by calling the API provided by the Dubbo framework ( stub) object, and then you can call the service method like a local service. -After the consumer initiates a call to the service method, the Dubbo framework is responsible for sending the request to the service provider deployed on the remote machine. After receiving the request, the provider will call the implementation class of the service, and then return the processing result to the consumer. This completes a complete service call. The data flow of Request and Response in the figure is shown. -> It should be noted that in Dubbo, when we refer to services, we usually refer to RPC-grained interfaces or methods that provide the function of adding, deleting, and modifying a specific business, which is not the same as the services generally referred to in some microservice concept books concept. +总的来说,Dubbo 对通信协议的支持具有以下特点: +* 不绑定通信协议 +* 提供高性能通信协议实现 +* 支持流式通信模型 +* 不绑定序列化协议 +* 支持单个服务的多协议暴露 +* 支持单端口多协议发布 +* 支持一个应用内多个服务使用不同通信协议 -In a distributed system, especially with the development of the microservice architecture, the deployment, release, and scaling of applications become extremely frequent. As an RPC consumer, how to dynamically discover the address of the service provider becomes a precondition for RPC communication . Dubbo provides an automatic address discovery mechanism to deal with the dynamic migration of machine instances in distributed scenarios. As shown in the figure below, the address of the provider and the consumer is coordinated by introducing the registration center. After the provider starts, it registers its own address with the registration center, and the consumer dynamically perceives the address list of the provider by pulling or subscribing to a specific node in the registration center. Variety. +## Dubbo 服务治理 +服务开发框架解决了开发与通信的问题,但在微服务集群环境下,我们仍需要解决无状态服务节点动态变化、外部化配置、日志跟踪、可观测性、流量管理、高可用性、数据一致性等一系列问题,我们将这些问题统称为服务治理。 -![arch-service-discovery](/imgs/architecture.png) +Dubbo 抽象了一套微服务治理模式并发布了对应的官方实现,服务治理可帮助简化微服务开发与运维,让开发者更专注在微服务业务本身。 -### Dubbo core features +### 服务治理抽象 -#### High performance RPC communication protocol -Service communication across processes or hosts is a basic capability of Dubbo. Dubbo RPC sends the request data (Request) to the backend service in a predefined protocol encoding method, and receives the calculation result (Response) returned by the server. RPC communication is completely transparent to the user, and the user does not need to care about how and where the request is sent, and only needs to get the correct call result for each call. In addition to the Request-Response communication model in synchronous mode, Dubbo3 also provides a richer selection of communication models: -* Consumer side asynchronous request (Client Side Asynchronous Request-Response) -* Provider side asynchronous execution (Server Side Asynchronous Request-Response) -* Consumer request stream (Request Streaming) -* Provider response stream (Response Streaming) -* Bidirectional Streaming +以下展示了 Dubbo 核心的服务治理功能定义 -For details, please refer to the list of optional protocols implemented by each language SDK or [Triple Protocol](/en/docs3-v2/java-sdk/concepts-and-architecture/triple/) +![governance](/imgs/v3/what/governance.png) -#### Automatic service (address) discovery -Dubbo's service discovery mechanism allows microservice components to evolve independently and be deployed arbitrarily, and the consumer can complete communication without knowing the deployment location and IP address of the peer. Dubbo provides a Client-Based service discovery mechanism, and users can enable service discovery in various ways: -* Use independent registry components, such as [Nacos](https://nacos.io/), Zookeeper, Consul, Etcd, etc. -* Leave the organization and registration of services to the underlying container platform, such as Kubernetes, which is understood to be a more cloud-native usage +* **地址发现** -#### Run state traffic control -Transparent address discovery allows Dubbo requests to be sent to any IP instance, and traffic is randomly allocated during this process. When richer and finer-grained control of traffic is required, Dubbo's traffic control strategy can be used. Dubbo provides strategies including load balancing, traffic routing, request timeout, traffic degradation, retry, etc., based on these basic capabilities You can easily implement more scenario-based routing solutions, including canary release, A/B testing, weight routing, same-region priority, etc. What's even cooler is that Dubbo supports traffic control policies to take effect dynamically in the running state without redeployment . For details, please refer to: -* [Traffic management example](../../tasks/traffic-management) +Dubbo 服务发现具备高性能、支持大规模集群、服务级元数据配置等优势,默认提供 Nacos、Zookeeper、Consul 等多种注册中心适配,与 Spring Cloud、Kubernetes Service 模型打通,支持自定义扩展。 -#### Rich extension components and ecology -Dubbo's powerful service governance capabilities are not only reflected in the core framework, but also include its excellent expansion capabilities and the support of surrounding supporting facilities. Through the definition of extension points that exist in almost every key process, such as Filter, Router, and Protocol, we can enrich Dubbo's functions or realize the connection with other microservice supporting systems, including Transaction and Tracing. Currently, there are implementations that extend through SPI For details, please refer to the details of Dubbo extensibility, and you can also find more extension implementations in the [apache/dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions) project. For details, please refer to: -* [Dubbo Ecosystem](../../what/ecosystem) -* [Dubbo Extensibility Design](../../what/extensibility) +* **负载均衡** -#### Cloud Native Design +Dubbo 默认提供加权随机、加权轮询、最少活跃请求数优先、最短响应时间优先、一致性哈希和自适应负载等策略 -Dubbo is designed to fully follow the development concept of cloud-native microservices, which is reflected in many aspects. First, it supports cloud-native infrastructure and deployment architecture, including containers, Kubernetes, etc. The overall solution of Dubbo Mesh is also in version 3.1 Official release; on the other hand, many core components of Dubbo have been upgraded for cloud native, including Triple protocol, unified routing rules, and support for multiple languages. +* **流量路由** -It is worth mentioning that how to use Dubbo to support elastic scaling services such as Serverless is also planned in the future, including using Native Image to improve Dubbo's startup speed and resource consumption. +Dubbo 支持通过一系列流量规则控制服务调用的流量分布与行为,基于这些规则可以实现基于权重的比例流量分发、灰度验证、金丝雀发布、按请求参数的路由、同区域优先、超时配置、重试、限流降级等能力。 -Combined with the current version, this section mainly expands Dubbo's cloud-native features from the following two points -* [Container Scheduling Platform (Kubernetes)](../../tasks/kubernetes/deploy-on-k8s) -* [Dubbo Mesh](/en/docs3-v2/java-sdk/concepts-and-architecture/mesh/) +* **链路追踪** -##### Kubernetes -For Dubbo microservices to support Kubernetes platform scheduling, the most basic thing is to realize the alignment of the dubbo service life cycle and the container life cycle, which includes life cycle events such as Dubbo startup, destruction, and service registration. Compared with the past where Dubbo defined life cycle events by itself and required developers to abide by the agreement during operation and maintenance practice, the underlying infrastructure of Kubernetes defines strict component life cycle events (probes), and instead requires Dubbo to adapt according to the agreement. +Dubbo 官方通过适配 OpenTelemetry 提供了对 Tracing 全链路追踪支持,用户可以接入支持 OpenTelemetry 标准的产品如 Skywalking、Zipkin 等。另外,很多社区如 Skywalking、Zipkin 等在官方也提供了对 Dubbo 的适配。 -Kubernetes Service is another level of adaptation, which reflects the trend of service definition and registration sinking to the cloud-native underlying infrastructure. In this mode, users no longer need to build additional registry components, Dubbo consumer end nodes can automatically connect to Kubernetes (API-Server or DNS), and query the instance list (Kubernetes endpoints) according to the service name (Kubernetes Service Name) . At this point, the service is defined through the standard Kubernetes Service API and dispatched to each node. +* **可观测性** -##### Dubbo Mesh +Dubbo 实例通过 Prometheus 等上报 QPS、RT、请求次数、成功率、异常次数等多维度的可观测指标帮助了解服务运行状态,通过接入 Grafana、Admin 控制台帮助实现数据指标可视化展示。 -Service Mesh has been widely disseminated and recognized in the industry, and is considered to be the next-generation microservice architecture, mainly because it solves many difficult problems, including transparent upgrades, multilingualism, dependency conflicts, and traffic management. The typical architecture of Service Mesh is to intercept all egress and ingress traffic by deploying independent Sidecar components, and integrate rich traffic management strategies such as load balancing and routing in Sidecar. In addition, Service Mesh also requires a control plane (Control Panel) to realize the control of Sidecar traffic, that is, to issue various policies. We call this architecture here Classic Mesh. +Dubbo 服务治理生态还提供了对 **API 网关**、**限流降级**、**数据一致性**、**认证鉴权**等场景的适配支持。 -However, no technical architecture is perfect, and classic Mesh also faces the problem of high cost at the implementation level -1. Operation and maintenance control panel (Control Panel) is required -2. Need to operate and maintain Sidecar -3. Need to consider how to migrate from the original SDK to Sidecar -4. It is necessary to consider the performance loss of the entire link after introducing Sidecar +### Dubbo Admin +Admin 控制台提供了 Dubbo 集群的可视化视图,通过 Admin 你可以完成集群的几乎所有管控工作。 +* 查询服务、应用或机器状态 +* 创建项目、服务测试、文档管理等 +* 查看集群实时流量、定位异常问题等 +* 流量比例分发、参数路由等流量管控规则下发 -In order to solve the related cost problems introduced by Sidecar, Dubbo introduced and implemented a new Proxyless Mesh architecture. As the name suggests, Proxyless Mesh refers to the deployment without Sidecar, and the Dubbo SDK directly interacts with the control plane. The architecture diagram is as follows +![Admin](/imgs/v3/what/admin.png) -![dubbo-proxyless](/imgs/v3/mesh/dubbo-proxyless.png) +### 服务网格 +将 Dubbo 接入 Istio 等服务网格治理体系。 -It can be imagined that in different organizations and different development stages, microservices built with Dubbo will allow three deployment architectures in the future: traditional SDK, Sidecar-based Service Mesh, and Proxyless Mesh without Sidecar. Based on Sidecar's Service Mesh, that is, the classic Mesh architecture, the independent sidecar runtime takes over all the traffic, separate from the Sidecar's Proxyless Mesh, and the secondary SDK directly communicates with the control plane through xDS. Dubbo microservices allow deployment on physical machines, containers, and Kubernetes platforms, and can use Admin as the control plane and manage them with unified traffic governance rules. +![Dubbo-Mesh](/imgs/v3/mesh/mix-mesh.png) diff --git a/content/en/overview/what/xyz-difference.md b/content/en/overview/what/xyz-difference.md new file mode 100644 index 000000000000..1e12b8f08439 --- /dev/null +++ b/content/en/overview/what/xyz-difference.md @@ -0,0 +1,84 @@ +--- +aliases: + - /zh/overview/what/xyz-difference/ +description: "" +linkTitle: 与 gRPC、Spring Cloud、Istio 关系 +title: 与 gRPC、Spring Cloud、Istio 的关系 +type: docs +weight: 2 +--- + + + +很多开发者经常会问到 Apache Dubbo 与 Spring Cloud、gRPC 以及一些 Service Mesh 项目如 Istio 的关系,要解释清楚它们的关系并不困难,你只需要跟随这篇文章和 Dubbo 文档做一些更深入的了解,但总的来说,它们之间有些能力是重合的,但在一些场景你可以把它们放在一起使用。 + +虽然这是一篇 Dubbo 维护者写的文档,我们仍会尽力将 Dubbo 与其他组件之间的联系与差异客观、透明的展现出来,但考虑到每个人对不同产品的熟悉程度不一,这里的个别表述可能并不完全准确,希望能给开发者带来帮助。 + +## Dubbo 与 Spring Cloud + +![dubbo-springcloud](/imgs/v3/difference/dubbo-springcloud.png) + +从上图我们可以看出,Dubbo 和 Spring Cloud 有很多相似之处,它们都在整个架构图的相同位置并提供一些相似的功能。 + +* **Dubbo 和 Spring Cloud 都侧重在对分布式系统中常见问题模式的抽象(如服务发现、负载均衡、动态配置等)**,同时对每一个问题都提供了配套组件实现,形成了一套微服务整体解决方案,让使用 Dubbo 及 Spring Cloud 的用户在开发微服务应用时可以专注在业务逻辑开发上。 +* **Dubbo 和 Spring Cloud 都完全兼容 Spring 体系的应用开发模式**,Dubbo 对 Spring 应用开发框架、Spring Boot 微服务框架都做了很好的适配,由于 Spring Cloud 出自 Spring 体系,在这一点上自然更不必多说。 + +虽然两者有很多相似之处,但由于它们在诞生背景与架构设计上的巨大差异,**两者在性能、适用的微服务集群规模、生产稳定性保障、服务治理等方面都有很大差异**。 + +Spring Cloud 的优势在于: +* 同样都支持 Spring 开发体系的情况下,Spring Cloud 得到更多的原生支持 +* 对一些常用的微服务模式做了抽象如服务发现、动态配置、异步消息等,同时包括一些批处理任务、定时任务、持久化数据访问等领域也有涉猎。 +* 基于 HTTP 的通信模式,加上相对比较完善的入门文档和演示 demo 和 starters,让开发者在第一感觉上更易于上手 + +Spring Cloud 的问题有: +* 只提供抽象模式的定义不提供官方稳定实现,开发者只能寻求类似 Netflix、Alibaba、Azure 等不同厂商的实现套件,而每个厂商支持的完善度、稳定性、活跃度各异 +* 有微服务全家桶却不是能拿来就用的全家桶,demo 上手容易,但落地推广与长期使用的成本非常高 +* 欠缺服务治理能力,尤其是流量管控方面如负载均衡、流量路由方面能力都比较弱 +* 编程模型与通信协议绑定 HTTP,在性能、与其他 RPC 体系互通上存在障碍 +* 总体架构与实现只适用于小规模微服务集群实践,当集群规模增长后就会遇到地址推送效率、内存占用等各种瓶颈的问题,但此时迁移到其他体系却很难实现 +* 很多微服务实践场景的问题需要用户独自解决,比如优雅停机、启动预热、服务测试,再比如双注册、双订阅、延迟注册、服务按分组隔离、集群容错等 + +而以上这些点,都是 **Dubbo 的优势**所在: +* 完全支持 Spring & Spring Boot 开发模式,同时在服务发现、动态配置等基础模式上提供与 Spring Cloud 对等的能力。 +* 是企业级微服务实践方案的整体输出,Dubbo 考虑到了企业微服务实践中会遇到的各种问题如优雅上下线、多注册中心、流量管理等,因此其在生产环境的长期维护成本更低 +* 在通信协议和编码上选择更灵活,包括 rpc 通信层协议如 HTTP、HTTP/2(Triple、gRPC)、TCP 二进制协议、rest等,序列化编码协议Protobuf、JSON、Hessian2 等,支持单端口多协议。 +* Dubbo 从设计上突出服务服务治理能力,如权重动态调整、标签路由、条件路由等,支持 Proxyless 等多种模式接入 Service Mesh 体系 +* 高性能的 RPC 协议编码与实现, +* Dubbo 是在超大规模微服务集群实践场景下开发的框架,可以做到百万实例规模的集群水平扩容,应对集群增长带来的各种问题 +* Dubbo 提供 Java 外的多语言实现,使得构建多语言异构的微服务体系成为可能 + +如果您的目标是构建企业级应用,并期待在未来的持久维护中能够更省心、更稳定,我们建议你能更深入的了解 Dubbo 的使用和其提供的能力。 +> Dubbo 在入门资料上的欠缺是对比 Spring Cloud 的一个劣势,这体现在依赖配置管理、文档、demo 示例完善度上,当前整个社区在重点投入这一部分的建设,期望能降低用户在第一天体验和学习 Dubbo 时的门槛,不让开发者因为缺乏文档而错失 Dubbo 这样一款优秀的产品。 + +## Dubbo 与 gRPC +Dubbo 与 gRPC 最大的差异在于两者的定位上: +* **gRPC 定位为一款 RPC 框架**,Google 推出它的核心目标是定义云原生时代的 rpc 通信规范与标准实现; +* **Dubbo 定位是一款微服务开发框架**,它侧重解决微服务实践从服务定义、开发、通信到治理的问题,因此 Dubbo 同时提供了 RPC 通信、与应用开发框架的适配、服务治理等能力。 + +Dubbo 不绑定特定的通信协议,即 Dubbo 服务间可通过多种 RPC 协议通信并支持灵活切换。因此,你可以在 Dubbo 开发的微服务中选用 gRPC 通信,**Dubbo 完全兼容 gRPC,并将 gRPC 设计为内置原生支持的协议之一**。 + +![dubbo-grpc](/imgs/v3/difference/dubbo-grpc.png) + +如果您看中基于 HTTP/2 的通信协议、基于 Protobuf 的服务定义,并基于此决定选型 gRPC 作为微服务开发框架,那很有可能您会在未来的微服务业务开发中遇到障碍,这主要源于 gRPC 没有为开发者提供以下能力: +* 缺乏与业务应用框架集成的开发模式,用户需要基于 gRPC 底层的 RPC API 定义、发布或调用微服务,中间可能还有与业务应用开发框架整合的问题 +* 缺乏微服务周边生态扩展与适配,如服务发现、限流降级、链路追踪等没有多少可供选择的官方实现,且扩展起来非常困难 +* 缺乏服务治理能力,作为一款 rpc 框架,缺乏对服务治理能力的抽象 + +因此,gRPC 更适合作为底层的通信协议规范或编解码包,而 Dubbo 则可用作微服务整体解决方案。**对于 gRPC 协议,我们推荐的使用模式 Dubbo + gRPC 的组合**,这个时候,gRPC 只是隐藏在底层的一个通信协议,不被微服务开发者感知,开发者基于 Dubbo 提供的 API 和配置开发服务,并基于 dubbo 的服务治理能力治理服务,在未来,开发者还能使用 Dubbo 生态和开源的 IDL 配套工具管理服务定义与发布。 + +如果我们忽略 gRPC 在应用开发框架侧的空白,只考虑如何给 gRPC 带来服务治理能力,则另一种可以采用的模式就是在 Service Mesh 架构下使用 gRPC,这就引出了我们下一小节要讨论的内容:Dubbo 与 Service Mesh 架构的关系。 + +## Dubbo 与 Istio +Service Mesh 是近年来在云原生背景下诞生的一种微服务架构,在 Kubernetes 体系下,让微服务开发中的更多能力如流量拦截、服务治理等下沉并成为基础设施,让微服务开发、升级更轻量。Istio 是 Service Mesh 的开源代表实现,它从部署架构上分为数据面与控制面,从这一点上与 [Dubbo 总体架构](../overview) 是基本一致的,Istio 带来的主要变化在于: +* 数据面,Istio 通过引入 Sidecar 实现了对服务流量的透明拦截,Sidecar 通常是与 Dubbo 等开发的传统微服务组件部署在一起 +* 控制面,将之前抽象的服务治理中心聚合为一个具有统一实现的具体组件,并实现了与底层基础设施如 Kubernetes 无缝适配 + +**Dubbo 已经实现了对 Istio 体系的全面接入,可以用 Istio 控制面治理 Dubbo 服务,而在数据面部署架构上,针对 Sidecar 引入的复杂性与性能问题,Dubbo 还支持无代理的 Proxyless 模式。** 除此之外,Dubbo Mesh 体系还解决了 Istio 架构落地过程中的很多问题,包括提供更灵活的数据面部署架构、更低的迁移成本等。 + +![Dubbo-Mesh](/imgs/v3/mesh/mix-mesh.png) + +从**数据面**的视角,Dubbo 支持如下两种开发和部署模式,可以通过 Istio、Consul、Linkerd 等控制面组件实现对数据面服务的治理。 +* Proxy 模式,Dubbo 与 Envoy 一起部署,Dubbo 作为编程框架 & 协议通信组件存在,流量管控由 Envoy 与 Istio 控制面交互实现。 +* Proxyless 模式,Dubbo 进程保持独立部署,Dubbo 通过标准 xDS 协议直接接入 Istio 等控制面组件。 + +从**控制面**视角,Dubbo 可接入原生 Istio 标准控制面和规则体系,而对于一些 Dubbo 老版本用户,Dubbo Mesh 提供了平滑迁移方案,具体请查看 [Dubbo Mesh 服务网格](../../tasks/mesh/)。 From aaa3d67237220848a67175adf5a7353c8e6aa516 Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Mon, 30 Sep 2024 11:53:51 +0800 Subject: [PATCH 02/23] Replace addr --- content/en/overview/_index.md | 2 +- content/en/overview/demo/_index.md | 5 +- content/en/overview/home/_index.md | 81 ++--- content/en/overview/mannual/_index.md | 6 +- .../overview/mannual/control-plane/_index.md | 4 +- .../mannual/control-plane/architecture.md | 4 +- .../mannual/control-plane/documentation.md | 4 +- .../en/overview/mannual/control-plane/mock.md | 6 +- .../overview/mannual/control-plane/search.md | 4 +- .../en/overview/mannual/control-plane/test.md | 4 +- .../en/overview/mannual/golang-sdk/_index.md | 4 +- .../mannual/golang-sdk/introduction.md | 18 +- .../mannual/golang-sdk/quickstart/_index.md | 8 +- .../golang-sdk/quickstart/microservices.md | 6 +- .../mannual/golang-sdk/quickstart/rpc.md | 6 +- .../mannual/golang-sdk/refer/_index.md | 8 +- .../mannual/golang-sdk/refer/ecology.md | 6 +- .../mannual/golang-sdk/refer/generic.md | 6 +- .../mannual/golang-sdk/refer/nacos.md | 6 +- .../refer/sourcecode/3.0_feature.md | 8 +- .../golang-sdk/refer/sourcecode/_index.md | 6 +- .../refer/sourcecode/aop_and_extension.md | 8 +- .../refer/sourcecode/app_and_interface.md | 6 +- .../refer/sourcecode/architecture.md | 8 +- .../golang-sdk/refer/sourcecode/generic-2.md | 10 +- .../golang-sdk/refer/sourcecode/generic.md | 6 +- .../golang-sdk/refer/sourcecode/protocol.md | 6 +- .../golang-sdk/refer/sourcecode/registry.md | 6 +- .../golang-sdk/refer/use_dubbogo_cli.md | 6 +- .../mannual/golang-sdk/tutorial/_index.md | 6 +- .../tutorial/configuration/_index.md | 8 +- .../tutorial/configuration/remote.md | 4 +- .../golang-sdk/tutorial/deploy2/_index.md | 4 +- .../golang-sdk/tutorial/deploy2/deploy.md | 8 +- .../tutorial/deploy2/graceful_shutdown.md | 6 +- .../golang-sdk/tutorial/deploy2/istio.md | 6 +- .../deploy2/proxyless_service_mesh.md | 8 +- .../tutorial/deploy2/traffic_management.md | 6 +- .../tutorial/gateway/http_triple.md | 6 +- .../tutorial/gateway/pixiu-nacos-triple.md | 6 +- .../tutorial/interop-dubbo/_index.md | 6 +- .../call_java_protocol_dubbo_non_protobuf.md | 4 +- .../call_java_protocol_triple_protobuf.md | 4 +- .../tutorial/interop-grpc/_index.md | 6 +- .../tutorial/interop-grpc/call_grpc.md | 4 +- .../tutorial/observability/_index.md | 6 +- .../tutorial/observability/logger.md | 2 +- .../tutorial/observability/rpc_metrics.md | 4 +- .../mannual/golang-sdk/tutorial/rpc/_index.md | 4 +- .../mannual/golang-sdk/tutorial/rpc/error.md | 2 +- .../mannual/golang-sdk/tutorial/rpc/filter.md | 2 +- .../golang-sdk/tutorial/rpc/protocol.md | 6 +- .../golang-sdk/tutorial/rpc/start-check.md | 6 +- .../tutorial/service-discovery/_index.md | 8 +- .../service-discovery/multi_registry.md | 6 +- .../tutorial/service-discovery/nacos.md | 8 +- .../tutorial/service-discovery/zookeeper.md | 4 +- .../golang-sdk/tutorial/traffic/_index.md | 4 +- .../golang-sdk/tutorial/traffic/router.md | 6 +- .../golang-sdk/tutorial/traffic/sentinel.md | 4 +- .../overview/mannual/golang-sdk/versions.md | 6 +- .../en/overview/mannual/java-sdk/_index.md | 6 +- .../mannual/java-sdk/quick-start/_index.md | 12 +- .../mannual/java-sdk/quick-start/starter.md | 6 +- .../java-sdk/reference-manual/_index.md | 6 +- .../reference-manual/architecture/_index.md | 6 +- .../architecture/code-architecture.md | 8 +- .../architecture/dubbo-spi.md | 4 +- .../reference-manual/architecture/mesh.md.bak | 4 +- .../architecture/multi-protocol.md | 4 +- .../architecture/overall-architecture.md.bak | 6 +- .../architecture/service-discovery.md.bak | 6 +- .../architecture/service-invocation.md | 14 +- .../reference-manual/config-center/_index.md | 6 +- .../reference-manual/config-center/apollo.md | 6 +- .../config-center/introduction.md | 10 +- .../reference-manual/config-center/nacos.md | 18 +- .../config-center/zookeeper.md | 14 +- .../reference-manual/config/_index.md | 6 +- .../reference-manual/config/api/_index.md | 4 +- .../reference-manual/config/api/api.md | 8 +- .../reference-manual/config/principle.md | 6 +- .../reference-manual/config/properties.md | 22 +- .../config/properties3.md.bak | 10 +- .../reference-manual/config/spring/_index.md | 4 +- .../config/spring/spring-boot.md | 10 +- .../reference-manual/config/spring/xml.md | 6 +- .../java-sdk/reference-manual/faq/0/1.md | 6 +- .../java-sdk/reference-manual/faq/0/10.md | 6 +- .../java-sdk/reference-manual/faq/0/11.md | 6 +- .../java-sdk/reference-manual/faq/0/12.md | 6 +- .../java-sdk/reference-manual/faq/0/13.md | 8 +- .../java-sdk/reference-manual/faq/0/14.md | 6 +- .../java-sdk/reference-manual/faq/0/15.md | 6 +- .../java-sdk/reference-manual/faq/0/16.md | 6 +- .../java-sdk/reference-manual/faq/0/17.md | 6 +- .../java-sdk/reference-manual/faq/0/18.md | 6 +- .../java-sdk/reference-manual/faq/0/19.md | 6 +- .../java-sdk/reference-manual/faq/0/2.md | 8 +- .../java-sdk/reference-manual/faq/0/20.md | 6 +- .../java-sdk/reference-manual/faq/0/21.md | 6 +- .../java-sdk/reference-manual/faq/0/22.md | 6 +- .../java-sdk/reference-manual/faq/0/23.md | 6 +- .../java-sdk/reference-manual/faq/0/24.md | 6 +- .../java-sdk/reference-manual/faq/0/25.md | 6 +- .../java-sdk/reference-manual/faq/0/26.md | 6 +- .../java-sdk/reference-manual/faq/0/27.md | 6 +- .../java-sdk/reference-manual/faq/0/28.md | 6 +- .../java-sdk/reference-manual/faq/0/29.md | 6 +- .../java-sdk/reference-manual/faq/0/3.md | 6 +- .../java-sdk/reference-manual/faq/0/4.md | 6 +- .../java-sdk/reference-manual/faq/0/5.md | 6 +- .../java-sdk/reference-manual/faq/0/6.md | 6 +- .../java-sdk/reference-manual/faq/0/7.md | 6 +- .../java-sdk/reference-manual/faq/0/8.md | 6 +- .../java-sdk/reference-manual/faq/0/9.md | 6 +- .../java-sdk/reference-manual/faq/0/99.md | 6 +- .../java-sdk/reference-manual/faq/0/_index.md | 6 +- .../java-sdk/reference-manual/faq/1/1.md | 6 +- .../java-sdk/reference-manual/faq/1/10.md | 8 +- .../java-sdk/reference-manual/faq/1/11.md | 6 +- .../java-sdk/reference-manual/faq/1/12.md | 8 +- .../java-sdk/reference-manual/faq/1/13.md | 6 +- .../java-sdk/reference-manual/faq/1/14.md | 8 +- .../java-sdk/reference-manual/faq/1/15.md | 6 +- .../java-sdk/reference-manual/faq/1/16.md | 6 +- .../java-sdk/reference-manual/faq/1/17.md | 8 +- .../java-sdk/reference-manual/faq/1/18.md | 8 +- .../java-sdk/reference-manual/faq/1/19.md | 6 +- .../java-sdk/reference-manual/faq/1/20.md | 6 +- .../java-sdk/reference-manual/faq/1/21.md | 6 +- .../java-sdk/reference-manual/faq/1/22.md | 6 +- .../java-sdk/reference-manual/faq/1/26.md | 6 +- .../java-sdk/reference-manual/faq/1/27.md | 6 +- .../java-sdk/reference-manual/faq/1/28.md | 6 +- .../java-sdk/reference-manual/faq/1/29.md | 6 +- .../java-sdk/reference-manual/faq/1/3.md | 8 +- .../java-sdk/reference-manual/faq/1/30.md | 6 +- .../java-sdk/reference-manual/faq/1/31.md | 6 +- .../java-sdk/reference-manual/faq/1/32.md | 6 +- .../java-sdk/reference-manual/faq/1/33.md | 6 +- .../java-sdk/reference-manual/faq/1/34.md | 6 +- .../java-sdk/reference-manual/faq/1/35.md | 6 +- .../java-sdk/reference-manual/faq/1/36.md | 8 +- .../java-sdk/reference-manual/faq/1/37.md | 6 +- .../java-sdk/reference-manual/faq/1/38.md | 6 +- .../java-sdk/reference-manual/faq/1/39.md | 6 +- .../java-sdk/reference-manual/faq/1/4.md | 8 +- .../java-sdk/reference-manual/faq/1/40.md | 6 +- .../java-sdk/reference-manual/faq/1/41.md | 6 +- .../java-sdk/reference-manual/faq/1/42.md | 6 +- .../java-sdk/reference-manual/faq/1/5.md | 6 +- .../java-sdk/reference-manual/faq/1/6.md | 6 +- .../java-sdk/reference-manual/faq/1/7.md | 8 +- .../java-sdk/reference-manual/faq/1/8.md | 8 +- .../java-sdk/reference-manual/faq/1/9.md | 8 +- .../java-sdk/reference-manual/faq/1/_index.md | 6 +- .../java-sdk/reference-manual/faq/2/1.md | 6 +- .../java-sdk/reference-manual/faq/2/10.md | 6 +- .../java-sdk/reference-manual/faq/2/11.md | 6 +- .../java-sdk/reference-manual/faq/2/12.md | 6 +- .../java-sdk/reference-manual/faq/2/13.md | 8 +- .../java-sdk/reference-manual/faq/2/14.md | 6 +- .../java-sdk/reference-manual/faq/2/15.md | 6 +- .../java-sdk/reference-manual/faq/2/16.md | 6 +- .../java-sdk/reference-manual/faq/2/17.md | 6 +- .../java-sdk/reference-manual/faq/2/18.md | 6 +- .../java-sdk/reference-manual/faq/2/19.md | 6 +- .../java-sdk/reference-manual/faq/2/2.md | 6 +- .../java-sdk/reference-manual/faq/2/20.md | 6 +- .../java-sdk/reference-manual/faq/2/3.md | 8 +- .../java-sdk/reference-manual/faq/2/4.md | 8 +- .../java-sdk/reference-manual/faq/2/5.md | 6 +- .../java-sdk/reference-manual/faq/2/6.md | 6 +- .../java-sdk/reference-manual/faq/2/7.md | 6 +- .../java-sdk/reference-manual/faq/2/8.md | 6 +- .../java-sdk/reference-manual/faq/2/9.md | 6 +- .../java-sdk/reference-manual/faq/2/_index.md | 6 +- .../java-sdk/reference-manual/faq/3/1.md | 6 +- .../java-sdk/reference-manual/faq/3/2.md | 6 +- .../java-sdk/reference-manual/faq/3/3.md | 8 +- .../java-sdk/reference-manual/faq/3/4.md | 6 +- .../java-sdk/reference-manual/faq/3/5.md | 6 +- .../java-sdk/reference-manual/faq/3/6.md | 6 +- .../java-sdk/reference-manual/faq/3/7.md | 6 +- .../java-sdk/reference-manual/faq/3/8.md | 6 +- .../java-sdk/reference-manual/faq/3/_index.md | 6 +- .../java-sdk/reference-manual/faq/4/1.md | 10 +- .../java-sdk/reference-manual/faq/4/10.md | 6 +- .../java-sdk/reference-manual/faq/4/11.md | 6 +- .../java-sdk/reference-manual/faq/4/12.md | 6 +- .../java-sdk/reference-manual/faq/4/13.md | 6 +- .../java-sdk/reference-manual/faq/4/14.md | 6 +- .../java-sdk/reference-manual/faq/4/15.md | 6 +- .../java-sdk/reference-manual/faq/4/16.md | 6 +- .../java-sdk/reference-manual/faq/4/17.md | 6 +- .../java-sdk/reference-manual/faq/4/18.md | 6 +- .../java-sdk/reference-manual/faq/4/19.md | 8 +- .../java-sdk/reference-manual/faq/4/2.md | 8 +- .../java-sdk/reference-manual/faq/4/20.md | 6 +- .../java-sdk/reference-manual/faq/4/21.md | 8 +- .../java-sdk/reference-manual/faq/4/3.md | 6 +- .../java-sdk/reference-manual/faq/4/4.md | 6 +- .../java-sdk/reference-manual/faq/4/5.md | 6 +- .../java-sdk/reference-manual/faq/4/6.md | 6 +- .../java-sdk/reference-manual/faq/4/7.md | 6 +- .../java-sdk/reference-manual/faq/4/8.md | 6 +- .../java-sdk/reference-manual/faq/4/9.md | 6 +- .../java-sdk/reference-manual/faq/4/_index.md | 6 +- .../java-sdk/reference-manual/faq/5/1.md | 6 +- .../java-sdk/reference-manual/faq/5/10.md | 6 +- .../java-sdk/reference-manual/faq/5/11.md | 6 +- .../java-sdk/reference-manual/faq/5/12.md | 6 +- .../java-sdk/reference-manual/faq/5/13.md | 6 +- .../java-sdk/reference-manual/faq/5/14.md | 6 +- .../java-sdk/reference-manual/faq/5/15.md | 6 +- .../java-sdk/reference-manual/faq/5/16.md | 8 +- .../java-sdk/reference-manual/faq/5/17.md | 6 +- .../java-sdk/reference-manual/faq/5/18.md | 6 +- .../java-sdk/reference-manual/faq/5/2.md | 6 +- .../java-sdk/reference-manual/faq/5/20.md | 6 +- .../java-sdk/reference-manual/faq/5/21.md | 6 +- .../java-sdk/reference-manual/faq/5/22.md | 6 +- .../java-sdk/reference-manual/faq/5/23.md | 6 +- .../java-sdk/reference-manual/faq/5/24.md | 6 +- .../java-sdk/reference-manual/faq/5/25.md | 6 +- .../java-sdk/reference-manual/faq/5/26.md | 6 +- .../java-sdk/reference-manual/faq/5/27.md | 6 +- .../java-sdk/reference-manual/faq/5/28.md | 6 +- .../java-sdk/reference-manual/faq/5/29.md | 6 +- .../java-sdk/reference-manual/faq/5/3.md | 6 +- .../java-sdk/reference-manual/faq/5/30.md | 6 +- .../java-sdk/reference-manual/faq/5/31.md | 6 +- .../java-sdk/reference-manual/faq/5/32.md | 6 +- .../java-sdk/reference-manual/faq/5/33.md | 6 +- .../java-sdk/reference-manual/faq/5/34.md | 6 +- .../java-sdk/reference-manual/faq/5/35.md | 6 +- .../java-sdk/reference-manual/faq/5/36.md | 6 +- .../java-sdk/reference-manual/faq/5/37.md | 6 +- .../java-sdk/reference-manual/faq/5/38.md | 6 +- .../java-sdk/reference-manual/faq/5/39.md | 6 +- .../java-sdk/reference-manual/faq/5/4.md | 6 +- .../java-sdk/reference-manual/faq/5/40.md | 6 +- .../java-sdk/reference-manual/faq/5/41.md | 6 +- .../java-sdk/reference-manual/faq/5/42.md | 6 +- .../java-sdk/reference-manual/faq/5/43.md | 6 +- .../java-sdk/reference-manual/faq/5/5.md | 6 +- .../java-sdk/reference-manual/faq/5/6.md | 6 +- .../java-sdk/reference-manual/faq/5/7.md | 6 +- .../java-sdk/reference-manual/faq/5/8.md | 6 +- .../java-sdk/reference-manual/faq/5/9.md | 6 +- .../java-sdk/reference-manual/faq/5/_index.md | 6 +- .../java-sdk/reference-manual/faq/6/1.md | 6 +- .../java-sdk/reference-manual/faq/6/10.md | 8 +- .../java-sdk/reference-manual/faq/6/11.md | 6 +- .../java-sdk/reference-manual/faq/6/12.md | 6 +- .../java-sdk/reference-manual/faq/6/13.md | 6 +- .../java-sdk/reference-manual/faq/6/14.md | 6 +- .../java-sdk/reference-manual/faq/6/15.md | 6 +- .../java-sdk/reference-manual/faq/6/16.md | 6 +- .../java-sdk/reference-manual/faq/6/2.md | 6 +- .../java-sdk/reference-manual/faq/6/3.md | 6 +- .../java-sdk/reference-manual/faq/6/4.md | 8 +- .../java-sdk/reference-manual/faq/6/5.md | 6 +- .../java-sdk/reference-manual/faq/6/6.md | 8 +- .../java-sdk/reference-manual/faq/6/7.md | 6 +- .../java-sdk/reference-manual/faq/6/8.md | 6 +- .../java-sdk/reference-manual/faq/6/9.md | 6 +- .../java-sdk/reference-manual/faq/6/_index.md | 6 +- .../java-sdk/reference-manual/faq/7/1.md | 8 +- .../java-sdk/reference-manual/faq/7/2.md | 8 +- .../java-sdk/reference-manual/faq/7/3.md | 8 +- .../java-sdk/reference-manual/faq/7/4.md | 8 +- .../java-sdk/reference-manual/faq/7/5.md | 8 +- .../java-sdk/reference-manual/faq/7/6.md | 6 +- .../java-sdk/reference-manual/faq/7/7.md | 8 +- .../java-sdk/reference-manual/faq/7/_index.md | 6 +- .../java-sdk/reference-manual/faq/81/1.md | 6 +- .../java-sdk/reference-manual/faq/81/2.md | 6 +- .../java-sdk/reference-manual/faq/81/3.md | 6 +- .../java-sdk/reference-manual/faq/81/4.md | 6 +- .../reference-manual/faq/81/_index.md | 6 +- .../java-sdk/reference-manual/faq/99/0.md | 8 +- .../java-sdk/reference-manual/faq/99/1.md | 6 +- .../reference-manual/faq/99/_index.md | 6 +- .../java-sdk/reference-manual/faq/_index.md | 6 +- .../java-sdk/reference-manual/faq/intro.md | 8 +- .../reference-manual/graalvm/_index.md | 6 +- .../graalvm/support-graalvm.md | 6 +- .../reference-manual/merics/_index.md | 4 +- .../java-sdk/reference-manual/merics/meter.md | 12 +- .../java-sdk/reference-manual/mesh/_index.md | 4 +- .../java-sdk/reference-manual/mesh/mesh.md | 6 +- .../metadata-center/_index.md | 6 +- .../reference-manual/metadata-center/nacos.md | 14 +- .../metadata-center/others.md | 8 +- .../metadata-center/overview.md | 6 +- .../metadata-center/zookeeper.md | 16 +- .../reference-manual/performance/_index.md | 4 +- .../performance/benchmarking.md | 6 +- .../performance/rpc-benchmarking.md | 6 +- .../reference-manual/protocol/_index.md | 6 +- .../reference-manual/protocol/dubbo.md | 6 +- .../protocol/multi-protocols.md | 8 +- .../protocol/others/_index.md | 6 +- .../protocol/others/hessian.md | 8 +- .../protocol/others/http.md.bak | 4 +- .../protocol/others/memcached.md | 2 +- .../reference-manual/protocol/others/redis.md | 2 +- .../reference-manual/protocol/others/rmi.md | 10 +- .../protocol/others/thrift.md | 2 +- .../others/v3.2_rest_protocol_design.md | 4 +- .../protocol/others/webservice.md | 8 +- .../reference-manual/protocol/overview.md | 8 +- .../reference-manual/protocol/rest.md.bak | 70 ++--- .../protocol/tripe-rest-manual.md | 8 +- .../reference-manual/protocol/triple-3.3.md | 4 +- .../reference-manual/protocol/triple.md | 20 +- .../reference-manual/protocol/triple.md.bak | 4 +- .../java-sdk/reference-manual/qos/_index.md | 4 +- .../qos/introduction/command.md | 4 +- .../qos/introduction/default_metrics.md | 4 +- .../qos/introduction/logger-management.md | 6 +- .../qos/introduction/probe.md | 4 +- .../qos/introduction/profiler.md | 6 +- .../qos/introduction/router-snapshot.md | 6 +- .../qos/introduction/security.md | 6 +- .../qos/introduction/service-management.md | 4 +- .../java-sdk/reference-manual/qos/overview.md | 4 +- .../java-sdk/reference-manual/qos/qos-list.md | 2 +- .../reference-manual/registry/_index.md | 4 +- .../registry/multiple-registry.md | 6 +- .../reference-manual/registry/nacos.md | 8 +- .../registry/others/_index.md | 4 +- .../registry/others/consul.md | 6 +- .../reference-manual/registry/others/etcd.md | 6 +- .../registry/others/multicast.md | 6 +- .../reference-manual/registry/others/redis.md | 12 +- .../reference-manual/registry/overview.md | 8 +- ...vice-discovery-application-vs-interface.md | 4 +- .../reference-manual/registry/zookeeper.md | 8 +- .../reference-manual/serialization/_index.md | 4 +- .../serialization/dubbo/_index.md | 2 +- .../serialization/dubbo/avro.md | 4 +- .../serialization/dubbo/fastjson.md | 4 +- .../serialization/dubbo/fastjson2.md | 4 +- .../serialization/dubbo/fst.md | 4 +- .../serialization/dubbo/gson.md | 4 +- .../serialization/dubbo/hessian.md | 4 +- .../serialization/dubbo/kryo.md | 4 +- .../serialization/dubbo/msgpack.md | 4 +- .../serialization/serialization-upgrade.md | 6 +- .../serialization/serialization.md | 6 +- .../serialization/triple/_index.md | 2 +- .../serialization/triple/protobuf.md | 6 +- .../serialization/triple/wrapper.md | 8 +- .../java-sdk/reference-manual/spi/_index.md | 4 +- .../spi/description/_index.md | 4 +- .../reference-manual/spi/description/cache.md | 6 +- .../spi/description/cluster.md | 6 +- .../spi/description/compiler.md | 6 +- .../spi/description/config-center.md | 6 +- .../spi/description/container.md | 6 +- .../spi/description/dispatcher.md | 6 +- .../spi/description/exchanger.md | 6 +- .../spi/description/exporter-listener.md | 6 +- .../spi/description/extension-factory.md | 6 +- .../spi/description/filter.md | 6 +- .../spi/description/invoker-listener.md | 6 +- .../spi/description/liveness.md | 6 +- .../spi/description/load-balance.md | 6 +- .../spi/description/logger-adapter.md | 6 +- .../spi/description/merger.md | 6 +- .../spi/description/metadata-report.md | 6 +- .../spi/description/monitor.md | 6 +- .../spi/description/networker.md | 6 +- .../reference-manual/spi/description/page.md | 6 +- .../spi/description/protocol.md | 4 +- .../spi/description/proxy-factory.md | 6 +- .../spi/description/qos-permission.md | 6 +- .../spi/description/readiness.md | 6 +- .../spi/description/registry.md | 6 +- .../spi/description/remoting.md | 6 +- .../spi/description/router.md | 6 +- .../spi/description/serialize.md | 6 +- .../spi/description/startup.md | 6 +- .../spi/description/status-checker.md | 6 +- .../spi/description/telnet-handler.md | 4 +- .../spi/description/threadpool.md | 6 +- .../spi/description/validation.md | 6 +- .../java-sdk/reference-manual/spi/overview.md | 16 +- .../upgrades-and-compatibility/_index.md | 6 +- .../migration-service-discovery.md | 12 +- .../migration-triple.md | 8 +- .../migration-triple.md.bak | 10 +- .../upgrades-and-compatibility/migration.md | 6 +- .../migration.md.bak | 8 +- .../version/2.x-to-3.x-compatibility-guide.md | 20 +- .../version/3.0-to-3.1-compatibility-guide.md | 6 +- .../version/3.1-to-3.2-compatibility-guide.md | 8 +- .../version/3.2-to-3.3-compatibility-guide.md | 10 +- .../version/_index.md | 6 +- .../overview/mannual/java-sdk/tasks/_index.md | 4 +- .../mannual/java-sdk/tasks/deploy/_index.md | 4 +- .../deploy/deploy-on-kubernetes-service.md | 12 +- .../tasks/deploy/deploy-on-kubernetes.md | 4 +- .../java-sdk/tasks/deploy/deploy-on-vm.md | 6 +- .../mannual/java-sdk/tasks/develop/_index.md | 4 +- .../mannual/java-sdk/tasks/develop/api.md | 12 +- .../java-sdk/tasks/develop/springboot.md | 12 +- .../java-sdk/tasks/extensibility/_index.md | 4 +- .../java-sdk/tasks/extensibility/filter.md | 4 +- .../java-sdk/tasks/extensibility/protocol.md | 6 +- .../java-sdk/tasks/extensibility/registry.md | 6 +- .../java-sdk/tasks/extensibility/router.md | 4 +- .../java-sdk/tasks/extensibility/spi.md | 2 +- .../mannual/java-sdk/tasks/framework/async.md | 10 +- .../java-sdk/tasks/framework/attachment.md | 10 +- .../framework/fault-tolerent-strategy.md | 4 +- .../java-sdk/tasks/framework/filter.md | 10 +- .../java-sdk/tasks/framework/generic.md | 16 +- .../tasks/framework/lightweight-rpc.md | 4 +- .../framework/more/callback-parameter.md | 6 +- .../framework/more/concurrency-control.md | 8 +- .../framework/more/config-connections.md | 18 +- .../tasks/framework/more/echo-service.md | 6 +- .../tasks/framework/more/events-notify.md | 6 +- .../tasks/framework/more/explicit-target.md | 6 +- .../tasks/framework/more/generic-impl.md | 8 +- .../tasks/framework/more/local-call.md | 6 +- .../tasks/framework/more/local-mock.md | 12 +- .../tasks/framework/more/local-stub.md | 6 +- .../framework/more/parameter-validation.md | 8 +- .../java-sdk/tasks/framework/more/reactive.md | 8 +- .../framework/more/reference-config-cache.md | 6 +- .../tasks/framework/more/result-cache.md | 8 +- .../tasks/framework/more/router-snapshot.md | 8 +- .../java-sdk/tasks/framework/more/set-host.md | 2 +- .../tasks/framework/more/specify-ip.md | 6 +- .../tasks/framework/threading-model.md | 8 +- .../java-sdk/tasks/framework/timeout.md | 10 +- .../java-sdk/tasks/framework/version_group.md | 20 +- .../mannual/java-sdk/tasks/gateway/dubbo.md | 10 +- .../mannual/java-sdk/tasks/gateway/triple.md | 14 +- .../mannual/java-sdk/tasks/mesh/_index.md | 4 +- .../tasks/mesh/bookinfo-proxyless/_index.md | 4 +- .../bookinfo-proxyless/security/_index.md | 4 +- .../security/request-routing.md | 4 +- .../mesh/bookinfo-proxyless/traffic/_index.md | 4 +- .../traffic/request-routing.md | 4 +- .../tasks/mesh/bookinfo-sidecar/_index.md | 4 +- .../mesh/bookinfo-sidecar/security/_index.md | 4 +- .../security/request-routing.md | 4 +- .../mesh/bookinfo-sidecar/traffic/_index.md | 4 +- .../traffic/request-routing.md | 4 +- .../java-sdk/tasks/mesh/migration/_index.md | 4 +- .../tasks/mesh/migration/deploy-on-k8s.md | 4 +- .../tasks/mesh/migration/dubbo-mesh.md | 4 +- .../tasks/mesh/migration/proxyless.md | 12 +- .../java-sdk/tasks/observability/_index.md | 4 +- .../java-sdk/tasks/observability/console.md | 4 +- .../java-sdk/tasks/observability/grafana.md | 8 +- .../java-sdk/tasks/observability/logging.md | 6 +- .../tasks/observability/prometheus.md | 8 +- .../tasks/observability/tracing/_index.md | 4 +- .../tasks/observability/tracing/otlp.md | 4 +- .../tasks/observability/tracing/skywalking.md | 4 +- .../tasks/observability/tracing/tracing.md | 8 +- .../tasks/observability/tracing/zipkin.md | 4 +- .../java-sdk/tasks/protocols/_index.md | 6 +- .../mannual/java-sdk/tasks/protocols/dubbo.md | 6 +- .../java-sdk/tasks/protocols/protocol.md | 12 +- .../mannual/java-sdk/tasks/protocols/rest.md | 10 +- .../java-sdk/tasks/protocols/triple/_index.md | 4 +- .../java-sdk/tasks/protocols/triple/grpc.md | 2 +- .../tasks/protocols/triple/interface.md | 6 +- .../tasks/protocols/triple/streaming.md | 6 +- .../java-sdk/tasks/rate-limit/_index.md | 4 +- .../adaptive-concurrency-control.md | 2 +- .../tasks/rate-limit/concurrency-control.md | 6 +- .../java-sdk/tasks/rate-limit/sentinel.md | 10 +- .../mannual/java-sdk/tasks/security/_index.md | 2 +- .../mannual/java-sdk/tasks/security/auth.md | 6 +- .../java-sdk/tasks/security/class-check.md | 6 +- .../mannual/java-sdk/tasks/security/tls.md | 10 +- .../tasks/security/token-authorization.md | 6 +- .../tasks/service-discovery/_index.md | 4 +- .../tasks/service-discovery/kubernetes.md | 8 +- .../tasks/service-discovery/loadbalance.md | 12 +- .../java-sdk/tasks/service-discovery/nacos.md | 8 +- .../tasks/service-discovery/registry.md | 24 +- .../tasks/service-discovery/zookeeper.md | 8 +- .../tasks/traffic-management/accesslog.md | 6 +- .../tasks/traffic-management/architecture.md | 6 +- .../tasks/traffic-management/arguments.md | 6 +- .../java-sdk/tasks/traffic-management/host.md | 4 +- .../tasks/traffic-management/isolation.md | 6 +- .../java-sdk/tasks/traffic-management/mock.md | 6 +- .../tasks/traffic-management/region.md | 6 +- .../tasks/traffic-management/retry.md | 4 +- .../tasks/traffic-management/timeout.md | 4 +- .../tasks/traffic-management/weight.md | 4 +- .../trasaction/distributed-transaction.md | 6 +- .../java-sdk/tasks/troubleshoot/_index.md | 4 +- .../tasks/troubleshoot/no-provider.md | 10 +- .../java-sdk/tasks/troubleshoot/profiler.md | 6 +- .../tasks/troubleshoot/request-failed.md | 4 +- .../tasks/troubleshoot/start-failed.md | 4 +- .../en/overview/mannual/java-sdk/versions.md | 20 +- .../mannual/nodejs-sdk/quick-start.md | 4 +- .../en/overview/mannual/rust-sdk/_index.md | 4 +- .../mannual/rust-sdk/java-interoperability.md | 6 +- .../overview/mannual/rust-sdk/quick-start.md | 8 +- .../mannual/rust-sdk/router-module.md | 10 +- .../mannual/rust-sdk/service-discovery.md | 4 +- .../en/overview/mannual/rust-sdk/streaming.md | 6 +- .../mannual/rust-sdk/unix-transport.md | 6 +- .../overview/mannual/web-sdk/quick-start.md | 4 +- content/en/overview/notices/_index.md | 23 +- content/en/overview/notices/admin.md | 40 ++- content/en/overview/notices/log4j.md | 27 +- content/en/overview/notices/protocol.md | 29 +- content/en/overview/notices/registry.md | 21 +- content/en/overview/notices/serialization.md | 41 ++- .../reference/Metrics/standard_metrics.md | 266 ++++++----------- content/en/overview/reference/_index.md | 2 +- .../overview/reference/erlang-sdk/_index.md | 14 +- .../reference/erlang-sdk/quick-start.md | 57 ++-- .../reference/erlang-sdk/reference.md | 21 +- .../reference/erlang-sdk/serialization.md | 28 +- .../overview/reference/erlang-sdk/service.md | 30 +- .../overview/reference/integrations/_index.md | 2 +- .../reference/integrations/grafana.md | 2 +- .../reference/integrations/higress.md | 2 +- .../overview/reference/integrations/nacos.md | 2 +- .../reference/integrations/prometheus.md | 2 +- .../reference/integrations/skywalking.md | 2 +- .../overview/reference/integrations/zipkin.md | 2 +- .../reference/integrations/zookeeper.md | 4 +- content/en/overview/reference/pixiu/_index.md | 8 +- .../en/overview/reference/pixiu/dev/_index.md | 4 +- .../reference/pixiu/dev/dubbo-pilot.md | 8 +- .../reference/pixiu/dev/filter-extension.md | 8 +- .../en/overview/reference/pixiu/dev/trie.md | 8 +- .../reference/pixiu/overview/_index.md | 8 +- .../overview/reference/pixiu/overview/faq.md | 8 +- .../reference/pixiu/overview/terminology.md | 8 +- .../reference/pixiu/overview/what-is-pixiu.md | 8 +- .../overview/reference/pixiu/user/_index.md | 8 +- .../reference/pixiu/user/adapter/_index.md | 8 +- .../reference/pixiu/user/adapter/dubbo.md | 8 +- .../pixiu/user/adapter/springcloud.md | 8 +- .../reference/pixiu/user/appendix/_index.md | 16 +- .../http-to-dubbo-default-stragety.md | 279 +++--------------- .../reference/pixiu/user/configurations.md | 8 +- .../reference/pixiu/user/deployment.md | 8 +- .../reference/pixiu/user/httpfilter/_index.md | 16 +- .../reference/pixiu/user/httpfilter/dubbo.md | 32 +- .../pixiu/user/httpfilter/hystrix.md | 20 +- .../pixiu/user/httpfilter/ratelimit.md | 16 +- .../reference/pixiu/user/listener/_index.md | 15 +- .../reference/pixiu/user/listener/http.md | 40 ++- .../reference/pixiu/user/listener/http2.md | 20 +- .../reference/pixiu/user/listener/tcp.md | 17 +- .../reference/pixiu/user/listener/triple.md | 17 +- .../pixiu/user/networkfilter/_index.md | 8 +- .../pixiu/user/networkfilter/dubbo.md | 8 +- .../pixiu/user/networkfilter/grpc.md | 4 +- .../pixiu/user/networkfilter/http.md | 8 +- .../reference/pixiu/user/quality/_index.md | 8 +- .../pixiu/user/quality/performance.md | 20 +- .../reference/pixiu/user/quality/stability.md | 20 +- .../reference/pixiu/user/quickstart.md | 10 +- .../reference/pixiu/user/samples/_index.md | 8 +- .../pixiu/user/samples/http_proxy.md | 8 +- .../pixiu/user/samples/http_to_dubbo.md | 8 +- .../reference/pixiu/user/samples/https.md | 8 +- .../en/overview/reference/proposals/_index.md | 2 +- .../en/overview/reference/proposals/admin.md | 2 +- .../proposals/heuristic-flow-control.md | 6 +- .../overview/reference/proposals/metrics.md | 2 +- .../reference/proposals/protocol-http.md | 2 +- .../proposals/registry-config-meta.md | 2 +- .../reference/proposals/service-discovery.md | 2 +- .../proposals/support-more-content-types.md | 4 +- .../overview/reference/protoc-installation.md | 39 +-- content/en/overview/reference/setup/_index.md | 11 +- .../en/overview/reference/setup/install.md | 159 +++------- content/en/overview/what/_index.md | 68 ++--- content/en/overview/what/advantages/_index.md | 6 +- .../en/overview/what/advantages/governance.md | 64 ++-- .../overview/what/advantages/performance.md | 80 ++--- .../what/advantages/production-ready.md | 30 +- .../en/overview/what/advantages/usability.md | 39 ++- .../en/overview/what/core-features/_index.md | 10 +- .../overview/what/core-features/ecosystem.md | 47 ++- .../what/core-features/extensibility.md | 136 ++++----- .../what/core-features/load-balance.md | 108 ++++--- .../en/overview/what/core-features/more.md | 121 ++++---- .../what/core-features/observability.md | 58 ++-- .../overview/what/core-features/protocols.md | 96 +++--- .../overview/what/core-features/security.md | 109 ++++--- .../what/core-features/service-definition.md | 104 +++---- .../what/core-features/service-discovery.md | 62 ++-- .../what/core-features/service-mesh.md | 93 +++--- .../what/core-features/traffic/_index.md | 153 +++++----- .../core-features/traffic/circuit-breaking.md | 43 +-- .../core-features/traffic/condition-rule.md | 80 +++-- .../traffic/configuration-rule.md | 40 +-- .../core-features/traffic/introduction.md | 150 +++++----- .../what/core-features/traffic/mesh-rule.md | 81 +++-- .../what/core-features/traffic/script-rule.md | 24 +- .../what/core-features/traffic/tag-rule.md | 36 +-- content/en/overview/what/overview.md | 128 ++++---- content/en/overview/what/xyz-difference.md | 104 +++---- 615 files changed, 3341 insertions(+), 3767 deletions(-) diff --git a/content/en/overview/_index.md b/content/en/overview/_index.md index 36de6153402f..65294327bc4a 100755 --- a/content/en/overview/_index.md +++ b/content/en/overview/_index.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/ + - /en/overview/ description: Dubbo 文档 linkTitle: 文档 title: Dubbo 文档 diff --git a/content/en/overview/demo/_index.md b/content/en/overview/demo/_index.md index 52a64b0f67b1..9d3d40fd3100 100644 --- a/content/en/overview/demo/_index.md +++ b/content/en/overview/demo/_index.md @@ -1,6 +1,7 @@ --- title: "Demo" -layout: "shortcodes/blocks/demo-zh" +layout: "shortcodes/blocks/demo-en" toc_hide: true --- - {{< blocks/demo-zh >}} + {{< blocks/demo-en >}} + diff --git a/content/en/overview/home/_index.md b/content/en/overview/home/_index.md index faa0410eae51..cde46c541070 100644 --- a/content/en/overview/home/_index.md +++ b/content/en/overview/home/_index.md @@ -1,72 +1,73 @@ --- aliases: - - /zh/overview/home/ + - /en/overview/home/ content: - - 快速开始: + - Quick Start: - description: "" links: - - '[为什么需要 Dubbo](../what/)' - - '[概念与架构](../what/overview/)' - - '[对比 gRPC、Spring Cloud、Istio](../what/xyz-difference/)' - - '[核心特性](../what/advantages/)' - name: 了解 Dubbo + - '[Why Dubbo](../what/)' + - '[Concepts and Architecture](../what/overview/)' + - '[Comparison with gRPC, Spring Cloud, Istio](../what/xyz-difference/)' + - '[Core Features](../what/advantages/)' + name: Learn about Dubbo - description: "" links: - - '[Java 微服务开发](../quickstart/java/)' - - '[Go 微服务开发](../quickstart/go/)' - - '[Rust 微服务开发](../quickstart/rust/)' - - '[Node.js 微服务开发](https://github.com/apache/dubbo-js)' - name: 尝试使用 Dubbo 开发微服务 - - name: "跟随示例学习 Dubbo" + - '[Java Microservice Development](../quickstart/java/)' + - '[Go Microservice Development](../quickstart/go/)' + - '[Rust Microservice Development](../quickstart/rust/)' + - '[Node.js Microservice Development](https://github.com/apache/dubbo-js)' + name: Try developing microservices with Dubbo + - name: "Learn Dubbo through examples" description: "" links: - - "[开发服务](../tasks/develop/)" - - "[部署服务](../tasks/deploy/)" - - "[流量管控](../tasks/traffic-management/)" - - "[观测服务](../tasks/observability/)" - - "[通信协议](../tasks/protocols/)" - - "[常见问题诊断](../tasks/troubleshoot/)" - - name: "生产环境的 Dubbo 微服务生态" + - "[Develop Services](../tasks/develop/)" + - "[Deploy Services](../tasks/deploy/)" + - "[Traffic Control](../tasks/traffic-management/)" + - "[Observe Services](../tasks/observability/)" + - "[Communication Protocols](../tasks/protocols/)" + - "[Common Issues Troubleshooting](../tasks/troubleshoot/)" + - name: "Production-grade Dubbo Microservices Ecosystem" description: "" links: - - "[服务发现&配置&元数据中心](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/)" - - "[HTTP 网关](../tasks/ecosystem/gateway/)" - - "[保证数据一致性](../tasks/ecosystem/transaction/)" - - "[Tracing 全链路追踪](../tasks/observability/tracing/)" - - "[自定义扩展](../tasks/extensibility/)" - - name: "SDK 参考手册" + - "[Service Discovery & Configuration & Metadata Center](/overview/mannual/java-sdk/reference-manual/registry/)" + - "[HTTP Gateway](../tasks/ecosystem/gateway/)" + - "[Ensuring Data Consistency](../tasks/ecosystem/transaction/)" + - "[Full-link Tracing](../tasks/observability/tracing/)" + - "[Custom Extensions](../tasks/extensibility/)" + - name: "SDK Reference Manual" description: "" links: - - "[Java 参考手册](../mannual/java-sdk/)" - - "[Golang 参考手册](../mannual/golang-sdk/)" - - "[Rust 参考手册](../mannual/rust-sdk//)" - - "[Node 参考手册](https://github.com/apache/dubbo-js)" - - name: "关心 Dubbo3" + - "[Java Reference Manual](../mannual/java-sdk/)" + - "[Golang Reference Manual](../mannual/golang-sdk/)" + - "[Rust Reference Manual](../mannual/rust-sdk/)" + - "[Node.js Reference Manual](https://github.com/apache/dubbo-js)" + - name: "Dubbo3 Focus" description: "" links: - - "[Dubbo3 概述](../what/overview/)" - - "[gRPC & HTTP/2 通信协议](../reference/protocols/triple/)" - - "[应用级服务发现](../core-features/service-discovery/)" - - "[平滑迁移](../../docs3-v2/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide)" -description: "Apache Dubbo 是一款支持多语言的、易用的 web 和 rpc 框架,同时为构建企业级微服务提供服务发现、流量治理、可观测、认证鉴权等能力、工具与最佳实践。" + - "[Dubbo3 Overview](../what/overview/)" + - "[gRPC & HTTP/2 Communication Protocols](../reference/protocols/triple/)" + - "[Application-level Service Discovery](../core-features/service-discovery/)" + - "[Smooth Migration](../../docs3-v2/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide)" +description: "Apache Dubbo is a multilingual, easy-to-use web and RPC framework that provides tools and best practices for building enterprise-level microservices with service discovery, traffic governance, observability, authentication, and authorization capabilities." hide_feedback: true hide_summary: true -linkTitle: 主页 +linkTitle: Home main_menu: true toc_hide: true menu: main: - name: 文档 + name: Documentation weight: 1 no_list: true noedit: true -title: Dubbo 文档 +title: Dubbo Documentation type: docs weight: 1 --- -请跟随以下内容,快速了解 Apache Dubbo 的功能、特点与最佳实践吧! +Follow the content below to quickly understand the features, advantages, and best practices of Apache Dubbo!

{{% docs/document_box %}} + diff --git a/content/en/overview/mannual/_index.md b/content/en/overview/mannual/_index.md index b2af438234a2..caf922698dcc 100755 --- a/content/en/overview/mannual/_index.md +++ b/content/en/overview/mannual/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/overview/mannual/ - - /zh/docs3-v2/ - - /zh-cn/docs3-v2/ + - /en/overview/mannual/ + - /en/docs3-v2/ + - /en/docs3-v2/ always_unfold: true description: Dubbo SDK 用户手册 feature: diff --git a/content/en/overview/mannual/control-plane/_index.md b/content/en/overview/mannual/control-plane/_index.md index 8421fd1f3f8d..6093af9b0178 100644 --- a/content/en/overview/mannual/control-plane/_index.md +++ b/content/en/overview/mannual/control-plane/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/reference/admin/ - - /zh-cn/overview/reference/admin/ + - /en/overview/reference/admin/ + - /en/overview/reference/admin/ description: "" linkTitle: 控制面 title: Admin 控制台操作手册 diff --git a/content/en/overview/mannual/control-plane/architecture.md b/content/en/overview/mannual/control-plane/architecture.md index d6b1eb5565b0..2a326211ec9f 100644 --- a/content/en/overview/mannual/control-plane/architecture.md +++ b/content/en/overview/mannual/control-plane/architecture.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/reference/admin/architecture/ - - /zh-cn/overview/reference/admin/architecture/ + - /en/overview/reference/admin/architecture/ + - /en/overview/reference/admin/architecture/ description: "" linkTitle: 架构与安装 no_list: true diff --git a/content/en/overview/mannual/control-plane/documentation.md b/content/en/overview/mannual/control-plane/documentation.md index e05ebf8b72fb..7685636f6eef 100644 --- a/content/en/overview/mannual/control-plane/documentation.md +++ b/content/en/overview/mannual/control-plane/documentation.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/reference/admin/documentation/ - - /zh-cn/overview/reference/admin/documentation/ + - /en/overview/reference/admin/documentation/ + - /en/overview/reference/admin/documentation/ description: "" linkTitle: 文档管理 no_list: true diff --git a/content/en/overview/mannual/control-plane/mock.md b/content/en/overview/mannual/control-plane/mock.md index 582960435e70..abe0f3034ef1 100644 --- a/content/en/overview/mannual/control-plane/mock.md +++ b/content/en/overview/mannual/control-plane/mock.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/reference/admin/mock/ - - /zh-cn/overview/reference/admin/mock/ + - /en/overview/reference/admin/mock/ + - /en/overview/reference/admin/mock/ description: "" linkTitle: 服务Mock no_list: true @@ -62,7 +62,7 @@ Dubbo Admin 服务 mock 是一种更为轻量和便捷实现方式,主要用 ``` - > 查看 [dubbo-mock-admin 的可用版本](/zh-cn/download/spi-extensions/) + > 查看 [dubbo-mock-admin 的可用版本](/en/download/spi-extensions/) 2. 配置 `-Denable.dubbo.admin.mock=true` 参数开启 Mock 并重启进程 3. 打开 Admin 配置 Mock 规则 diff --git a/content/en/overview/mannual/control-plane/search.md b/content/en/overview/mannual/control-plane/search.md index 031f5289c8b9..c8e411164c54 100644 --- a/content/en/overview/mannual/control-plane/search.md +++ b/content/en/overview/mannual/control-plane/search.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/reference/admin/search/ - - /zh-cn/overview/reference/admin/search/ + - /en/overview/reference/admin/search/ + - /en/overview/reference/admin/search/ description: "" linkTitle: 文档查询 title: Admin 服务查询 diff --git a/content/en/overview/mannual/control-plane/test.md b/content/en/overview/mannual/control-plane/test.md index ce4a83b3356c..bddd6849a8b0 100644 --- a/content/en/overview/mannual/control-plane/test.md +++ b/content/en/overview/mannual/control-plane/test.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/reference/admin/test/ - - /zh-cn/overview/reference/admin/test/ + - /en/overview/reference/admin/test/ + - /en/overview/reference/admin/test/ description: "" linkTitle: 服务测试 no_list: true diff --git a/content/en/overview/mannual/golang-sdk/_index.md b/content/en/overview/mannual/golang-sdk/_index.md index cfece42de572..c19f720bc605 100755 --- a/content/en/overview/mannual/golang-sdk/_index.md +++ b/content/en/overview/mannual/golang-sdk/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/ - - /zh-cn/docs3-v2/golang-sdk/ + - /en/docs3-v2/golang-sdk/ + - /en/docs3-v2/golang-sdk/ description: Golang SDK 手册 linkTitle: Golang SDK title: Golang SDK diff --git a/content/en/overview/mannual/golang-sdk/introduction.md b/content/en/overview/mannual/golang-sdk/introduction.md index 61191e64c539..a9c1836fd035 100644 --- a/content/en/overview/mannual/golang-sdk/introduction.md +++ b/content/en/overview/mannual/golang-sdk/introduction.md @@ -1,10 +1,10 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/preface/ - - /zh-cn/docs3-v2/golang-sdk/preface/ - - /zh-cn/overview/mannual/golang-sdk/preface/ - - /zh-cn/overview/mannual/golang-sdk/preface/concept/ - - /zh-cn/overview/mannual/golang-sdk/preface/concept/protocol/ + - /en/docs3-v2/golang-sdk/preface/ + - /en/docs3-v2/golang-sdk/preface/ + - /en/overview/mannual/golang-sdk/preface/ + - /en/overview/mannual/golang-sdk/preface/concept/ + - /en/overview/mannual/golang-sdk/preface/concept/protocol/ description: Dubbo-go 框架 linkTitle: 框架介绍 title: 框架介绍 @@ -47,7 +47,7 @@ dubbo-go 总体上遵循 `框架内核+插件` 的的设计理念,左侧的 ` ### RPC #### Triple -基于 Dubbo 定义的 [triple 协议](/zh-cn/overview/reference/protocols/triple/),你可以轻松编写浏览器、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。作为 Apache Dubbo 多语言 RPC体系的一环,dubbo-go 提供了 triple 协议的完整实现,支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 API 来发布或调用这些服务。triple 协议让 dubbo-go 可以: +基于 Dubbo 定义的 [triple 协议](/en/overview/reference/protocols/triple/),你可以轻松编写浏览器、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。作为 Apache Dubbo 多语言 RPC体系的一环,dubbo-go 提供了 triple 协议的完整实现,支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 API 来发布或调用这些服务。triple 协议让 dubbo-go 可以: * **作为后端服务与 Dubbo 其他语言实现互通** * **接收浏览器等标准 http 工具发起的请求** * **与标准的 gRPC 体系互通** @@ -102,7 +102,7 @@ Dubbo-go 支持的注册中心类型如下,具体配置方式请参考使用 | Polaris | polaris | #### 可观测 -dubbo-go 的可视化指标采集遵循 Apache Dubbo 定义的 [metrics 指标规范](/zh-cn/overview/reference/Metrics/standard_metrics/)。在实现 metrics 指标采集后,接下来就是如何可视化展示的问题,当前最常用的式导出到 Prometheus 并通过 Grafana 实现数据可视化展示。 +dubbo-go 的可视化指标采集遵循 Apache Dubbo 定义的 [metrics 指标规范](/en/overview/reference/Metrics/standard_metrics/)。在实现 metrics 指标采集后,接下来就是如何可视化展示的问题,当前最常用的式导出到 Prometheus 并通过 Grafana 实现数据可视化展示。 具体启用方式请参考使用手册中的 [可视化观测](../tutorial/observability/)。 @@ -113,8 +113,8 @@ dubbo-go 支持通过 Open Telemetry 接入 Zipkin、Jaeger、Skywalking 等全 #### 流量管控 dubbo-go 实现的流量治理规则完全遵循 Dubbo 框架设计的流量治理能力,可以通过以下链接了解更多详情: -* [Dubbo 流量治理规则设计](/zh-cn/overview/core-features/traffic/) -* [Dubbo 流量治理示例任务](/zh-cn/overview/tasks/traffic-management/) +* [Dubbo 流量治理规则设计](/en/overview/core-features/traffic/) +* [Dubbo 流量治理示例任务](/en/overview/tasks/traffic-management/) diff --git a/content/en/overview/mannual/golang-sdk/quickstart/_index.md b/content/en/overview/mannual/golang-sdk/quickstart/_index.md index 7e5d6fad4738..4c5b49570227 100755 --- a/content/en/overview/mannual/golang-sdk/quickstart/_index.md +++ b/content/en/overview/mannual/golang-sdk/quickstart/_index.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/quickstart/ - - /zh-cn/docs3-v2/golang-sdk/quickstart/ - - /zh/overview/quickstart/go/ - - /zh-cn/overview/quickstart/go/ + - /en/docs3-v2/golang-sdk/quickstart/ + - /en/docs3-v2/golang-sdk/quickstart/ + - /en/overview/quickstart/go/ + - /en/overview/quickstart/go/ description: Dubbo-go 快速开始 linkTitle: 快速开始 title: 快速开始 diff --git a/content/en/overview/mannual/golang-sdk/quickstart/microservices.md b/content/en/overview/mannual/golang-sdk/quickstart/microservices.md index 8af303b021b5..f165404db3a3 100644 --- a/content/en/overview/mannual/golang-sdk/quickstart/microservices.md +++ b/content/en/overview/mannual/golang-sdk/quickstart/microservices.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/quickstart/ - - /zh-cn/docs3-v2/golang-sdk/quickstart/ + - /en/docs3-v2/golang-sdk/quickstart/ + - /en/docs3-v2/golang-sdk/quickstart/ description: Dubbo-go 快速开始 linkTitle: 开发微服务应用 title: 开发微服务 @@ -32,7 +32,7 @@ $ cd dubbo-go-samples/registry/nacos ### 启动 Nacos -由于示例应用中启用了服务发现能力且使用 Nacos 作为注册中心,在运行示例之前需要先启动注册中心。请参考 [Nacos 本地安装](/zh-cn/overview/reference/integrations/nacos/) 了解如何快速安装和启动 Nacos。 +由于示例应用中启用了服务发现能力且使用 Nacos 作为注册中心,在运行示例之前需要先启动注册中心。请参考 [Nacos 本地安装](/en/overview/reference/integrations/nacos/) 了解如何快速安装和启动 Nacos。 ### 运行 server 在 `go-server/cmd` 示例目录: diff --git a/content/en/overview/mannual/golang-sdk/quickstart/rpc.md b/content/en/overview/mannual/golang-sdk/quickstart/rpc.md index 82d695fa4b09..30d375c8c530 100644 --- a/content/en/overview/mannual/golang-sdk/quickstart/rpc.md +++ b/content/en/overview/mannual/golang-sdk/quickstart/rpc.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/quickstart/ - - /zh-cn/docs3-v2/golang-sdk/quickstart/ - - /zh-cn/overview/mannual/golang-sdk/quickstart/quickstart_triple/ + - /en/docs3-v2/golang-sdk/quickstart/ + - /en/docs3-v2/golang-sdk/quickstart/ + - /en/overview/mannual/golang-sdk/quickstart/quickstart_triple/ description: Dubbo-go 快速开始 linkTitle: 开发RPC服务 title: 开发 RPC Server & RPC Client diff --git a/content/en/overview/mannual/golang-sdk/refer/_index.md b/content/en/overview/mannual/golang-sdk/refer/_index.md index c881a44468f8..2fc5c5b0ff5f 100644 --- a/content/en/overview/mannual/golang-sdk/refer/_index.md +++ b/content/en/overview/mannual/golang-sdk/refer/_index.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/refer/ - - /zh-cn/docs3-v2/golang-sdk/refer/ - - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/config-center/ - - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/features/ + - /en/docs3-v2/golang-sdk/refer/ + - /en/docs3-v2/golang-sdk/refer/ + - /en/overview/mannual/golang-sdk/tutorial/develop/config-center/ + - /en/overview/mannual/golang-sdk/tutorial/develop/features/ description: Dubbo-go 更多参考资料 title: 参考手册 type: docs diff --git a/content/en/overview/mannual/golang-sdk/refer/ecology.md b/content/en/overview/mannual/golang-sdk/refer/ecology.md index eeaa2d13b06a..068873544cf5 100644 --- a/content/en/overview/mannual/golang-sdk/refer/ecology.md +++ b/content/en/overview/mannual/golang-sdk/refer/ecology.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/refer/ecology/ - - /zh-cn/docs3-v2/golang-sdk/refer/ecology/ + - /en/docs3-v2/golang-sdk/refer/ecology/ + - /en/docs3-v2/golang-sdk/refer/ecology/ description: Dubbo-go 生态组件 title: 生态组件 type: docs @@ -61,4 +61,4 @@ Dubbo-go-hessian2 是一个Go语言 hessian2 序列化协议库 - dubbo-cli 工具(废弃) - imports-formatter Go语言 imports 块格式化工具 - protoc-gen-triple PB编译插件 -- protoc-gen-dubbo3grpc PB编译插件 \ No newline at end of file +- protoc-gen-dubbo3grpc PB编译插件 diff --git a/content/en/overview/mannual/golang-sdk/refer/generic.md b/content/en/overview/mannual/golang-sdk/refer/generic.md index 7a1217db900b..9bf54dd6d82d 100644 --- a/content/en/overview/mannual/golang-sdk/refer/generic.md +++ b/content/en/overview/mannual/golang-sdk/refer/generic.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/preface/concept/generic/ - - /zh-cn/docs3-v2/golang-sdk/preface/concept/generic/ - - /zh-cn/overview/mannual/golang-sdk/preface/concept/generic/ + - /en/docs3-v2/golang-sdk/preface/concept/generic/ + - /en/docs3-v2/golang-sdk/preface/concept/generic/ + - /en/overview/mannual/golang-sdk/preface/concept/generic/ description: 泛化调用 keywords: 泛化调用 title: 泛化调用 diff --git a/content/en/overview/mannual/golang-sdk/refer/nacos.md b/content/en/overview/mannual/golang-sdk/refer/nacos.md index c343fb0871a8..b455fff6cfd0 100644 --- a/content/en/overview/mannual/golang-sdk/refer/nacos.md +++ b/content/en/overview/mannual/golang-sdk/refer/nacos.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/develop/registry/nacos/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/registry/nacos/ + - /en/docs3-v2/golang-sdk/tutorial/develop/registry/nacos/ + - /en/docs3-v2/golang-sdk/tutorial/develop/registry/nacos/ description: 使用 Nacos 作为注册中心 title: 使用 Nacos 作为注册中心 type: docs @@ -144,4 +144,4 @@ server端打印结果 req:&main.CallUserStruct{ID:"A000", Male:true, SubInfo:main.SubInfo{SubID:"A001", SubMale:false, SubAge:18}} ======================= ``` -可见接收到了来自cli的数据 \ No newline at end of file +可见接收到了来自cli的数据 diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/3.0_feature.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/3.0_feature.md index 1fde5e38933b..2af58dc6138d 100644 --- a/content/en/overview/mannual/golang-sdk/refer/sourcecode/3.0_feature.md +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/3.0_feature.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/preface/3.0_feature/ - - /zh-cn/docs3-v2/golang-sdk/preface/3.0_feature/ - - /zh-cn/overview/mannual/golang-sdk/preface/3.0_feature/ + - /en/docs3-v2/golang-sdk/preface/3.0_feature/ + - /en/docs3-v2/golang-sdk/preface/3.0_feature/ + - /en/overview/mannual/golang-sdk/preface/3.0_feature/ description: Dubbo-go 3.0 新特性 keywords: 新特性 title: 新特性 @@ -77,4 +77,4 @@ virtual_service.yaml ## 4. 相关文章 -阿里云官方介绍文章:[《Dubbo 3.0 - 开启下一代云原生微服务》](https://developer.aliyun.com/article/770964?utm_content=g_1000175535) \ No newline at end of file +阿里云官方介绍文章:[《Dubbo 3.0 - 开启下一代云原生微服务》](https://developer.aliyun.com/article/770964?utm_content=g_1000175535) diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/_index.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/_index.md index 2e93b505de11..106da6d444bc 100644 --- a/content/en/overview/mannual/golang-sdk/refer/sourcecode/_index.md +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/sourcecode/ - - /zh-cn/docs3-v2/golang-sdk/sourcecode/ - - /zh-cn/overview/mannual/golang-sdk/sourcecode/ + - /en/docs3-v2/golang-sdk/sourcecode/ + - /en/docs3-v2/golang-sdk/sourcecode/ + - /en/overview/mannual/golang-sdk/sourcecode/ description: Dubbo-go 源码解读 title: 源码解读 type: docs diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/aop_and_extension.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/aop_and_extension.md index d7bb5af3a3de..50c77caec311 100644 --- a/content/en/overview/mannual/golang-sdk/refer/sourcecode/aop_and_extension.md +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/aop_and_extension.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/preface/design/aop_and_extension/ - - /zh-cn/docs3-v2/golang-sdk/preface/design/aop_and_extension/ - - /zh-cn/overview/mannual/golang-sdk/preface/design/aop_and_extension/ + - /en/docs3-v2/golang-sdk/preface/design/aop_and_extension/ + - /en/docs3-v2/golang-sdk/preface/design/aop_and_extension/ + - /en/overview/mannual/golang-sdk/preface/design/aop_and_extension/ description: AOP 与可扩展机制 keywords: AOP 与可扩展机制 title: AOP 与可扩展机制 @@ -108,4 +108,4 @@ import ( 这些接口的多种实现往往组成一组调用链,单个实现类只处理自己所关注的逻辑。 -相关阅读:[【AOP wikipedia】](https://en.wikipedia.org/wiki/Aspect-oriented_programming) \ No newline at end of file +相关阅读:[【AOP wikipedia】](https://en.wikipedia.org/wiki/Aspect-oriented_programming) diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/app_and_interface.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/app_and_interface.md index 80561c645b19..39f2469d405d 100644 --- a/content/en/overview/mannual/golang-sdk/refer/sourcecode/app_and_interface.md +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/app_and_interface.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/preface/design/app_and_interface/ - - /zh-cn/docs3-v2/golang-sdk/preface/design/app_and_interface/ - - /zh-cn/overview/mannual/golang-sdk/preface/design/app_and_interface/ + - /en/docs3-v2/golang-sdk/preface/design/app_and_interface/ + - /en/docs3-v2/golang-sdk/preface/design/app_and_interface/ + - /en/overview/mannual/golang-sdk/preface/design/app_and_interface/ description: Dubbo的应用和接口 keywords: 基本概念 title: Dubbo的应用和接口 diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/architecture.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/architecture.md index 261badbc9213..a6f9146d0d09 100644 --- a/content/en/overview/mannual/golang-sdk/refer/sourcecode/architecture.md +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/architecture.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/preface/design/architecture/ - - /zh-cn/docs3-v2/golang-sdk/preface/design/architecture/ - - /zh-cn/overview/mannual/golang-sdk/preface/design/architecture/ + - /en/docs3-v2/golang-sdk/preface/design/architecture/ + - /en/docs3-v2/golang-sdk/preface/design/architecture/ + - /en/overview/mannual/golang-sdk/preface/design/architecture/ description: 架构 keywords: 架构 title: 架构 @@ -28,4 +28,4 @@ type: docs * `0. register` : 当服务提供方在启动的时候,会自动将自己的服务注册到注册中心 * `1. subscribe` : 服务消费方会在启动的时候,向注册中心订阅自己所需要的服务 * `2. notify` : 注册中心返回服务注册的信息给到服务消费方,当订阅的服务发生变更,会推送变更的数据给到消费方 -* `3. invoke` : 服务消费者根据从注册中心获得的服务地址,经过负载均衡算法选出一个合适的服务地址发起请求 \ No newline at end of file +* `3. invoke` : 服务消费者根据从注册中心获得的服务地址,经过负载均衡算法选出一个合适的服务地址发起请求 diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic-2.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic-2.md index babff85cb72c..e97938bc49e5 100644 --- a/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic-2.md +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic-2.md @@ -1,10 +1,10 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/develop/features/generic/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/features/generic/ - - /zh/docs3-v2/golang-sdk/tutorial/develop/features/generic-2/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/features/generic-2/ - - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/features/generic/ + - /en/docs3-v2/golang-sdk/tutorial/develop/features/generic/ + - /en/docs3-v2/golang-sdk/tutorial/develop/features/generic/ + - /en/docs3-v2/golang-sdk/tutorial/develop/features/generic-2/ + - /en/docs3-v2/golang-sdk/tutorial/develop/features/generic-2/ + - /en/overview/mannual/golang-sdk/tutorial/develop/features/generic/ description: 泛化调用 title: 泛化调用 type: docs diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic.md index 0b73538e8d5c..92a06cb31b11 100644 --- a/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic.md +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/generic.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/develop/features/generic/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/features/generic/ + - /en/docs3-v2/golang-sdk/tutorial/develop/features/generic/ + - /en/docs3-v2/golang-sdk/tutorial/develop/features/generic/ description: 泛化调用 title: 泛化调用 type: docs @@ -104,4 +104,4 @@ GenericService 的 Invoke 方法包括三个参数:context.Context, []string, ``` INFO cmd/client.go:89 GetUser1(userId string) res: map[age:48 class:org.apache.dubbo.User id:A003 name:Joe sex:MAN time:2021-10-04 14:03:03.37 +0800 CST] -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/protocol.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/protocol.md index 0b16486364ad..c632f36cf035 100644 --- a/content/en/overview/mannual/golang-sdk/refer/sourcecode/protocol.md +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/protocol.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/sourcecode/protocol/ - - /zh-cn/docs3-v2/golang-sdk/sourcecode/protocol/ + - /en/docs3-v2/golang-sdk/sourcecode/protocol/ + - /en/docs3-v2/golang-sdk/sourcecode/protocol/ description: 网络协议源码解读 title: 网络协议 type: docs @@ -30,4 +30,4 @@ type Protocol interface { Refer 方法负责服务的引用过程,其入参 url 为 dubbo 框架通用的结构,可以描述一个希望引用的服务,url 参数中包含了多个希望引用服务的参数,例如对应服务的接口名(interface),版本号(version),使用协议(protocol) 等等。在具体网络协议(例如Triple)实现的 Refer 方法中,会将特定的网络协议封装到 Invoker 可调用实例的方法中,用户层发起的 RPC 调用即可直接通过返回的 Invoker 对象,发起特定协议的网络请求。 -Destroy 方法作用为销毁当前暴露的服务,用于服务下线场景。Dubbogo 框架有优雅下线机制,可以在服务进程终止前以监听信号的形式,下线所有已启动的服务。 \ No newline at end of file +Destroy 方法作用为销毁当前暴露的服务,用于服务下线场景。Dubbogo 框架有优雅下线机制,可以在服务进程终止前以监听信号的形式,下线所有已启动的服务。 diff --git a/content/en/overview/mannual/golang-sdk/refer/sourcecode/registry.md b/content/en/overview/mannual/golang-sdk/refer/sourcecode/registry.md index 1017aad4ea03..685ec5a7ced3 100644 --- a/content/en/overview/mannual/golang-sdk/refer/sourcecode/registry.md +++ b/content/en/overview/mannual/golang-sdk/refer/sourcecode/registry.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/sourcecode/registry/ - - /zh-cn/docs3-v2/golang-sdk/sourcecode/registry/ + - /en/docs3-v2/golang-sdk/sourcecode/registry/ + - /en/docs3-v2/golang-sdk/sourcecode/registry/ description: 注册中心源码解读 title: 注册中心 type: docs @@ -58,4 +58,4 @@ type Registry interface { 该接口主要包含四个方法,分别是注册、反注册、订阅、取消订阅。顾名思义,概括了客户端和服务端与注册中心交互的动作。针对普通接口级服务注册发现场景,在Provider 服务启动时,会将自身服务接口信息抽象为一个 url,该 url 包含了客户端发起调用所需的所有信息(ip、端口、协议等),服务端的注册中心组件会将该 url 写入注册中心(例如zk)。客户端启动后,在服务引用 Refer 步骤会通过注册中心组件订阅(Subscribe)需要的服务信息,获取到的服务信息以异步事件更新的形式写入客户端缓存,从而在服务发现成功后,可以根据拿到的服务 url 参数,向对应服务提供者发起调用。 -## \ No newline at end of file +## diff --git a/content/en/overview/mannual/golang-sdk/refer/use_dubbogo_cli.md b/content/en/overview/mannual/golang-sdk/refer/use_dubbogo_cli.md index 1524b3def6a0..3aa57c563c08 100644 --- a/content/en/overview/mannual/golang-sdk/refer/use_dubbogo_cli.md +++ b/content/en/overview/mannual/golang-sdk/refer/use_dubbogo_cli.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/refer/use_dubbogo_cli/ - - /zh-cn/docs3-v2/golang-sdk/refer/use_dubbogo_cli/ + - /en/docs3-v2/golang-sdk/refer/use_dubbogo_cli/ + - /en/docs3-v2/golang-sdk/refer/use_dubbogo_cli/ description: 使用 dubbogo-cli 工具 title: 使用 dubbogo-cli 工具 type: docs @@ -433,4 +433,4 @@ req:&main.CallUserStruct{ID:"A000", Male:true, SubInfo:main.SubInfo{SubID:"A001" ======================= ``` -可见接收到了来自cli的数据 \ No newline at end of file +可见接收到了来自cli的数据 diff --git a/content/en/overview/mannual/golang-sdk/tutorial/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/_index.md index 6e598676b958..aa096ec655a4 100755 --- a/content/en/overview/mannual/golang-sdk/tutorial/_index.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/ - - /zh-cn/overview/mannual/golang-sdk/preface/samples/ + - /en/docs3-v2/golang-sdk/tutorial/ + - /en/docs3-v2/golang-sdk/tutorial/ + - /en/overview/mannual/golang-sdk/preface/samples/ description: Dubbo-go 使用教程 linkTitle: 使用教程 title: 使用教程 diff --git a/content/en/overview/mannual/golang-sdk/tutorial/configuration/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/configuration/_index.md index 046fe925805a..6ea4d28f4aa7 100755 --- a/content/en/overview/mannual/golang-sdk/tutorial/configuration/_index.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/configuration/_index.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/debugging/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ - - /zh-cn/overview/mannual/golang-sdk/refer/basic_concept/ - - /zh-cn/overview/mannual/golang-sdk/refer/config/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/overview/mannual/golang-sdk/refer/basic_concept/ + - /en/overview/mannual/golang-sdk/refer/config/ description: "使用 dubbogo.yml 配置文件形式开发微服务应用。" title: 配置文件 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/configuration/remote.md b/content/en/overview/mannual/golang-sdk/tutorial/configuration/remote.md index c68340283afa..d80b114708aa 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/configuration/remote.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/configuration/remote.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/develop/config-center/remote_config/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/config-center/remote_config/ + - /en/docs3-v2/golang-sdk/tutorial/develop/config-center/remote_config/ + - /en/docs3-v2/golang-sdk/tutorial/develop/config-center/remote_config/ description: 远程加载 dubbogo.yaml 配置文件 title: 远程配置文件 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/_index.md index dfcdc5c34e96..044203fbe575 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/_index.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/ description: "学习在 Kubernetes、Service Mesh(Kubernetes Service)、虚拟机(Zookeeper、Nacos)等场景部署 dubbo-go 应用。" title: 部署应用 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/deploy.md b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/deploy.md index 2e61d43a2c79..507eae71544d 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/deploy.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/deploy.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/deploy/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/deploy/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/deploy/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/deploy/ description: Istio 环境部署 Dubbo-go 应用 title: Istio 环境部署 Dubbo-go 应用 type: docs @@ -241,7 +241,7 @@ Forwarding from 127.0.0.1:20000 -> 20000 Forwarding from [::1]:20000 -> 20000 ``` -使用 grpc_cli 调试集群内的应用,参考任务[【使用 grpc_cli 调试 Dubbo-go 应用】](/zh-cn/overview/mannual/golang-sdk/tutorial/debugging/grpc_cli/) +使用 grpc_cli 调试集群内的应用,参考任务[【使用 grpc_cli 调试 Dubbo-go 应用】](/en/overview/mannual/golang-sdk/tutorial/debugging/grpc_cli/) ```bash $ grpc_cli ls localhost:20000 -l @@ -427,4 +427,4 @@ $ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs dubbogo-cli 提供的应用模板可以方便地支持开发者进行镜像的构建、推送、部署。 -在 Istio 环境中,server 应用将自身服务信息注册在 Isito 上,由客户端监听 xds 资源,查询 istio debug 端口进行接口级别的服务发现。开发人员无需关心 service名、主机名、集群名等概念,只需要引入接口,发起调用即可。 \ No newline at end of file +在 Istio 环境中,server 应用将自身服务信息注册在 Isito 上,由客户端监听 xds 资源,查询 istio debug 端口进行接口级别的服务发现。开发人员无需关心 service名、主机名、集群名等概念,只需要引入接口,发起调用即可。 diff --git a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/graceful_shutdown.md b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/graceful_shutdown.md index 40fca749bbf2..235bb31e0231 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/graceful_shutdown.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/graceful_shutdown.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/governance/traffic/graceful_shutdown/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/traffic/graceful_shutdown/ + - /en/docs3-v2/golang-sdk/tutorial/governance/traffic/graceful_shutdown/ + - /en/docs3-v2/golang-sdk/tutorial/governance/traffic/graceful_shutdown/ description: 本文主要介绍优雅下线的基本步骤和使用说明 keywords: 优雅下线 title: 优雅下线 @@ -63,4 +63,4 @@ extension.AddCustomShutdownCallback(func() { ## 参考资料 -[【Dubbo-go 优雅上下线的设计与实践】](https://developer.aliyun.com/article/860775) \ No newline at end of file +[【Dubbo-go 优雅上下线的设计与实践】](https://developer.aliyun.com/article/860775) diff --git a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/istio.md b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/istio.md index 5e7782f83edc..c9a2eab68e21 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/istio.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/istio.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/istio/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/istio/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/istio/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/istio/ description: 部署 Istio 环境 title: 部署 Istio 环境 type: docs @@ -37,4 +37,4 @@ $ helm install istiod istio/istiod --namespace istio-system $ kubectl delete hpa istiod -n istio-system ``` -安装完成后,可以在 istio-system 命名空间下看到一个 istiod pod 在正常运行。 \ No newline at end of file +安装完成后,可以在 istio-system 命名空间下看到一个 istiod pod 在正常运行。 diff --git a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/proxyless_service_mesh.md b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/proxyless_service_mesh.md index 9ee8ff7bf1d2..ec7fc24c2138 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/proxyless_service_mesh.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/proxyless_service_mesh.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/proxyless_service_mesh/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/proxyless_service_mesh/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/proxyless_service_mesh/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/proxyless_service_mesh/ description: 无代理服务网格 keywords: 无代理服务网格 title: 无代理服务网格 @@ -84,7 +84,7 @@ Dubbo-go 拥有路由能力,通过 xds 协议客户端从 istiod 订阅路由 dubbogo-cli 是 Apache/dubbo-go 生态的子项目,为开发者提供便利的应用模板创建、工具安装、接口调试等功能,以提高用户的研发效率。 -详情可以参阅 [【dubbogo-cli 工具】](/zh-cn/overview/mannual/golang-sdk/refer/use_dubbogo_cli/) +详情可以参阅 [【dubbogo-cli 工具】](/en/overview/mannual/golang-sdk/refer/use_dubbogo_cli/) ## 3. Dubbo-go-Mesh 的优势 @@ -113,4 +113,4 @@ Dubbo-go 是一个横跨多个生态的服务框架。 - 多语言优势,可以实现 go-java 应用互通。 - 兼容 pixiu 网关,方便地进行服务的暴露和协议转换。 - - 使用 Dubbo-go 生态组件。 \ No newline at end of file + - 使用 Dubbo-go 生态组件。 diff --git a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/traffic_management.md b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/traffic_management.md index 2340b4f02c72..caddd947e159 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/deploy2/traffic_management.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/deploy2/traffic_management.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/traffic_management/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/traffic_management/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/traffic_management/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/traffic_management/ description: 流量管理 title: 流量管理 type: docs @@ -422,4 +422,4 @@ $ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs 2022-04-07T05:56:01.050Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" 2022-04-07T05:56:02.053Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" 2022-04-07T05:56:03.055Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/golang-sdk/tutorial/gateway/http_triple.md b/content/en/overview/mannual/golang-sdk/tutorial/gateway/http_triple.md index ad53a36cbb06..7bb27374c409 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/gateway/http_triple.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/gateway/http_triple.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/http_triple/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/http_triple/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/http_triple/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/http_triple/ description: 接入 Ingress 流量 title: 接入 Ingress 流量 type: docs @@ -85,4 +85,4 @@ pixiu LoadBalancer 192.168.156.175 30.XXX.XXX.XX 8881:30173/TCP ```bash $ curl -X POST -d '{"name":"laurence"}' http://30.XXX.XXX.XX:8881/dubbogoDemoServer/org.apache.dubbo.laurence.samples.UserProvider/SayHello {"name":"Hello laurence","id":"12345","age":21} -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/golang-sdk/tutorial/gateway/pixiu-nacos-triple.md b/content/en/overview/mannual/golang-sdk/tutorial/gateway/pixiu-nacos-triple.md index 779cd6e8abf8..c6a98572eab4 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/gateway/pixiu-nacos-triple.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/gateway/pixiu-nacos-triple.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/pixiu-nacos-triple/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/pixiu-nacos-triple/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/pixiu-nacos-triple/ + - /en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/pixiu-nacos-triple/ description: 使用 Pixiu 暴露 Dubbo-go 服务 title: 使用 Pixiu 暴露 Dubbo-go 服务 type: docs @@ -76,4 +76,4 @@ pixiu LoadBalancer 192.168.156.175 30.XXX.XXX.XX 8881:30173/TCP ```bash $ curl -X POST -d '{"name":"laurence"}' http://30.XXX.XXX.XX:8881/dubbogoDemoServer/org.apache.dubbo.laurence.samples.UserProvider/SayHello {"name":"Hello laurence","id":"12345","age":21} -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/_index.md index cb383816a580..fa6b690ae1f0 100755 --- a/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/_index.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/debugging/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ - - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/interflow/call_java/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/overview/mannual/golang-sdk/tutorial/develop/interflow/call_java/ description: "实现 dubbo go 和 dubbo java 应用互通,包括服务发现、协议通信等。" title: 与dubbo-java互通 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_dubbo_non_protobuf.md b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_dubbo_non_protobuf.md index d181013f460d..df49507cbea5 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_dubbo_non_protobuf.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_dubbo_non_protobuf.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java/ + - /en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java/ + - /en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java/ description: "如果您是 dubbo java 的老用户,可能您的 dubbo java 应用并没有使用 protobuf(直接使用 java interface 定义服务),这个时候您需要使用以下方式开发 dubbo go-client,来调用老版本的 dubbo 服务。" title: 非protoubf模式协议互通(适用于老版本 dubbo java 应用) linkTitle: 非protoubf模式协议互通 diff --git a/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_triple_protobuf.md b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_triple_protobuf.md index f3d7e1fa350e..235ea5b0e2df 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_triple_protobuf.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/interop-dubbo/call_java_protocol_triple_protobuf.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java/ + - /en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java/ + - /en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java/ description: “基于 protobuf 实现 dubbo-java 与 dubbo-go 的 triple 协议互通。” title: 基于 protobuf 实现 triple 协议互通(适用于两边都用 protobuf 开发的场景) linkTitle: protobuf+triple 协议互通 diff --git a/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/_index.md index e60338535880..85d8285a97fa 100755 --- a/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/_index.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/debugging/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ - - /zh-cn/overview/mannual/golang-sdk/tutorial/debugging/grpc_cli/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/overview/mannual/golang-sdk/tutorial/debugging/grpc_cli/ description: "实现 dubbo go 与谷歌官方版本 grpc 框架互通。" title: 与grpc互通 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/call_grpc.md b/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/call_grpc.md index 1fcee98563f6..830ccfa810df 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/call_grpc.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/interop-grpc/call_grpc.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/develop/interflow/call_grpc/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/interflow/call_grpc/ + - /en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_grpc/ + - /en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_grpc/ description: 与 gRPC 应用互通 title: 与 gRPC 应用互通 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/observability/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/observability/_index.md index 3ebc15411dc7..cd3b10588e99 100755 --- a/content/en/overview/mannual/golang-sdk/tutorial/observability/_index.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/observability/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/debugging/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ - - /zh-cn/overview/mannual/golang-sdk/tutorial/governance/monitor/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/overview/mannual/golang-sdk/tutorial/governance/monitor/ description: "可视化查看应用内部状态,包括日志、metrics指标监控、全链路追踪等" title: 可视化观测 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/observability/logger.md b/content/en/overview/mannual/golang-sdk/tutorial/observability/logger.md index 3d5fd32cd1ab..c9d8e22dc6b3 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/observability/logger.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/observability/logger.md @@ -1,6 +1,6 @@ --- aliases: - - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/features/custom-logger/ + - /en/overview/mannual/golang-sdk/tutorial/develop/features/custom-logger/ description: logger title: 配置和管理框架日志 linkTitle: 框架日志 diff --git a/content/en/overview/mannual/golang-sdk/tutorial/observability/rpc_metrics.md b/content/en/overview/mannual/golang-sdk/tutorial/observability/rpc_metrics.md index 79f58b00ddb2..de6ca73bfd4f 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/observability/rpc_metrics.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/observability/rpc_metrics.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/governance/monitor/rpc_metrics/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/monitor/rpc_metrics/ + - /en/docs3-v2/golang-sdk/tutorial/governance/monitor/rpc_metrics/ + - /en/docs3-v2/golang-sdk/tutorial/governance/monitor/rpc_metrics/ description: "采集运行态 Metrics 指标并接入 Prometheus、Grafana 系统" title: metrics监控 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/_index.md index 2ad00452f7bb..1e47424ec90e 100755 --- a/content/en/overview/mannual/golang-sdk/tutorial/rpc/_index.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/debugging/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ description: "rpc 框架通信常用的一些功能与配置方式,包括流式通信、超时时间、Filter拦截器、附加参数、健康检查等。" title: RPC框架 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/error.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/error.md index 33f590772cfb..b358c1572134 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/rpc/error.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/error.md @@ -1,6 +1,6 @@ --- aliases: - - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/protocol/exception_response/ + - /en/overview/mannual/golang-sdk/tutorial/develop/protocol/exception_response/ description: "当服务端请求处理失败时,dubbo 会支持返回 error 类型值,本示例演示如何处理异常类型返回值。" title: 异常类型返回值 linkTitle: 异常类型返回值 diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/filter.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/filter.md index 999f21a90d12..d48b2bfe97d8 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/rpc/filter.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/filter.md @@ -1,6 +1,6 @@ --- aliases: - - /zh-cn/overview/mannual/golang-sdk/tutorial/governance/features/custom-filter/ + - /en/overview/mannual/golang-sdk/tutorial/governance/features/custom-filter/ description: filter拦截器 title: filter拦截器 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/protocol.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/protocol.md index d45d451e844b..e30e67d0ff4c 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/rpc/protocol.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/protocol.md @@ -11,12 +11,12 @@ Dubbo-go 框架内置提供了两款协议:triple、dubbo,除此之外,框 * dubbo,基于 TCP 的高性能私有通信协议,缺点是通用性较差,更适合在 Dubbo SDK 间使用; * 任意协议扩展,通过扩展 protocol 可以之前任意 RPC 协议,官方生态库提供 JsonRPC、thrift 等支持。 -本篇文档中,我们将介绍关于 triple 协议的使用方式、如何实现与已有 dubbo2 系统的互相调用、扩展更多协议支持等。更多原理性介绍请参考 [协议规范](/zh-cn/overview/reference/protocols/triple-spec/) 或者 [dubbo java 中相关描述文档](/zh-cn/overview/mannual/java-sdk/tasks/protocols/protocol/)。 +本篇文档中,我们将介绍关于 triple 协议的使用方式、如何实现与已有 dubbo2 系统的互相调用、扩展更多协议支持等。更多原理性介绍请参考 [协议规范](/en/overview/reference/protocols/triple-spec/) 或者 [dubbo java 中相关描述文档](/en/overview/mannual/java-sdk/tasks/protocols/protocol/)。 ## triple 协议 triple 协议支持使用 protobuf 和 non-protobuf 两种开发模式,我们 **推荐使用 protobuf 模式开发服务**。 -目前我们大部分示例都是使用这个模式开发,可查看 [快速开始](/zh-cn/overview/mannual/golang-sdk/quickstart/rpc/) 学习完整开发示例,以下是基本步骤: +目前我们大部分示例都是使用这个模式开发,可查看 [快速开始](/en/overview/mannual/golang-sdk/quickstart/rpc/) 学习完整开发示例,以下是基本步骤: 1. 先使用 protobuf 定义服务 @@ -38,7 +38,7 @@ service GreetService { } ``` -2. [安装 protoc 插件](/zh-cn/overview/mannual/golang-sdk/quickstart/rpc/#前置条件),编译生成代码: +2. [安装 protoc 插件](/en/overview/mannual/golang-sdk/quickstart/rpc/#前置条件),编译生成代码: ```shell protoc --go_out=. --go_opt=paths=source_relative \ --go-triple_out=. --go-triple_opt=paths=source_relative \ diff --git a/content/en/overview/mannual/golang-sdk/tutorial/rpc/start-check.md b/content/en/overview/mannual/golang-sdk/tutorial/rpc/start-check.md index 3925a17a2b63..4fbc7b54d3ca 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/rpc/start-check.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/rpc/start-check.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/governance/health/start-check/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/health/start-check/ - - /zh-cn/overview/mannual/golang-sdk/tutorial/governance/health/start-check/ + - /en/docs3-v2/golang-sdk/tutorial/governance/health/start-check/ + - /en/docs3-v2/golang-sdk/tutorial/governance/health/start-check/ + - /en/overview/mannual/golang-sdk/tutorial/governance/health/start-check/ description: "缺省会在启动时检查依赖的服务是否可用(注册中心是否有可用地址),不可用时会抛出异常,阻止应用初始化完成。" keywords: 启动时检查 title: 启动时检查 diff --git a/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/_index.md index ebd30961f991..c52a9cb6aa74 100755 --- a/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/_index.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/_index.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/debugging/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ - - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/registry/ - - /zh-cn/overview/mannual/golang-sdk/tutorial/develop/registry/service-discovery/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/overview/mannual/golang-sdk/tutorial/develop/registry/ + - /en/overview/mannual/golang-sdk/tutorial/develop/registry/service-discovery/ description: "使用 Nacos、Zookeeper 等作为注册中心,实现地址变更的自动发现。" title: 地址发现 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/multi_registry.md b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/multi_registry.md index 33e7090a585c..3449a4e53193 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/multi_registry.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/multi_registry.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/develop/registry/multi_registry/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/registry/multi_registry/ + - /en/docs3-v2/golang-sdk/tutorial/develop/registry/multi_registry/ + - /en/docs3-v2/golang-sdk/tutorial/develop/registry/multi_registry/ description: 多注册中心 title: 多注册中心 type: docs @@ -83,4 +83,4 @@ dubbo: token: ${北极星资源鉴权 token} # 如果北极星服务端开启了针对客户端的鉴权,则需要配置该参数 ``` -对于 Kubernetes 注册中心的使用方式,请参考 [控制面](/zh-cn/overview/mannual/control-plane/) 文档。 \ No newline at end of file +对于 Kubernetes 注册中心的使用方式,请参考 [控制面](/en/overview/mannual/control-plane/) 文档。 diff --git a/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/nacos.md b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/nacos.md index f5369961011d..982b3a0bda0e 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/nacos.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/nacos.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/develop/registry/nacos-2/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/registry/nacos-2/ + - /en/docs3-v2/golang-sdk/tutorial/develop/registry/nacos-2/ + - /en/docs3-v2/golang-sdk/tutorial/develop/registry/nacos-2/ description: 使用 Nacos 作为注册中心 title: 使用 Nacos 作为注册中心 type: docs @@ -34,7 +34,7 @@ srv, err := ins.NewServer() ## How to run ### Start Nacos server -Follow this instruction to [install and start Nacos server](/zh-cn/overview/reference/integrations/nacos/). +Follow this instruction to [install and start Nacos server](/en/overview/reference/integrations/nacos/). ### Run server ```shell @@ -55,4 +55,4 @@ Open `https://localhost:8848/nacos/` with browser, check url address successfull ```shell $ go run ./go-client/cmd/client.go hello world -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/zookeeper.md b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/zookeeper.md index 257c969da340..e3f3880e29ed 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/zookeeper.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/service-discovery/zookeeper.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/develop/registry/zookeeper/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/develop/registry/zookeeper/ + - /en/docs3-v2/golang-sdk/tutorial/develop/registry/zookeeper/ + - /en/docs3-v2/golang-sdk/tutorial/develop/registry/zookeeper/ description: 使用 Zookeeper 作为注册中心 title: 使用 Zookeeper 作为注册中心 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/traffic/_index.md b/content/en/overview/mannual/golang-sdk/tutorial/traffic/_index.md index 7556e4519c4d..c5440976a1ab 100755 --- a/content/en/overview/mannual/golang-sdk/tutorial/traffic/_index.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/traffic/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/debugging/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ + - /en/docs3-v2/golang-sdk/tutorial/debugging/ description: "通过下发路由规则实现流量管控,包括按比例流量转发、参数路由、灰度发布、动态调整超时时间等。" title: 流量管控 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/traffic/router.md b/content/en/overview/mannual/golang-sdk/tutorial/traffic/router.md index 31b2e5b3190f..8bdd2d73f014 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/traffic/router.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/traffic/router.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/tutorial/governance/traffic/mesh_router/ - - /zh-cn/docs3-v2/golang-sdk/tutorial/governance/traffic/mesh_router/ - - /zh-cn/overview/mannual/golang-sdk/tutorial/governance/traffic/mesh_router/ + - /en/docs3-v2/golang-sdk/tutorial/governance/traffic/mesh_router/ + - /en/docs3-v2/golang-sdk/tutorial/governance/traffic/mesh_router/ + - /en/overview/mannual/golang-sdk/tutorial/governance/traffic/mesh_router/ description: 路由规则 title: 路由规则 type: docs diff --git a/content/en/overview/mannual/golang-sdk/tutorial/traffic/sentinel.md b/content/en/overview/mannual/golang-sdk/tutorial/traffic/sentinel.md index 852b183f0ef5..866017850bea 100644 --- a/content/en/overview/mannual/golang-sdk/tutorial/traffic/sentinel.md +++ b/content/en/overview/mannual/golang-sdk/tutorial/traffic/sentinel.md @@ -18,7 +18,7 @@ server.WithTpsLimiterXxx() // 设置限流相关阈值,请根据具体方法 Dubbo-go 内置限流策略相对简单,对于一些更复杂的场景,我们建议通过使用 Sentinel 等专业的第三方框架可以实现更丰富、更灵活的限流策略。 -可在此查看 [本示例完整源码](https://github.com/apache/dubbo-go-samples/tree/main/filter/sentinel),也可以参考 [Dubbo+Sentinel 的 Java 示例](/zh-cn/overview/mannual/java-sdk/tasks/rate-limit/sentinel/) 获得更多灵感。 +可在此查看 [本示例完整源码](https://github.com/apache/dubbo-go-samples/tree/main/filter/sentinel),也可以参考 [Dubbo+Sentinel 的 Java 示例](/en/overview/mannual/java-sdk/tasks/rate-limit/sentinel/) 获得更多灵感。 ## Provider 限流 @@ -32,4 +32,4 @@ Dubbo-go 内置限流策略相对简单,对于一些更复杂的场景,我 -### 基于并发请求数限流(未收到响应的请求数) \ No newline at end of file +### 基于并发请求数限流(未收到响应的请求数) diff --git a/content/en/overview/mannual/golang-sdk/versions.md b/content/en/overview/mannual/golang-sdk/versions.md index e5e5c394f6bd..9df3ac93df0b 100644 --- a/content/en/overview/mannual/golang-sdk/versions.md +++ b/content/en/overview/mannual/golang-sdk/versions.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/refer/compatible_version/ - - /zh-cn/docs3-v2/golang-sdk/refer/compatible_version/ - - /zh-cn/overview/mannual/golang-sdk/preface/refer/compatible_version/ + - /en/docs3-v2/golang-sdk/refer/compatible_version/ + - /en/docs3-v2/golang-sdk/refer/compatible_version/ + - /en/overview/mannual/golang-sdk/preface/refer/compatible_version/ description: 依赖适配版本号 title: 版本信息 type: docs diff --git a/content/en/overview/mannual/java-sdk/_index.md b/content/en/overview/mannual/java-sdk/_index.md index a2b522b0789d..9186dcf987f6 100755 --- a/content/en/overview/mannual/java-sdk/_index.md +++ b/content/en/overview/mannual/java-sdk/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/ - - /zh-cn/docs3-v2/java-sdk/ + - /en/docs3-v2/java-sdk/ + - /en/docs3-v2/java-sdk/ content: - 快速开始: - description: 快速体验 Dubbo Java 微服务开发 @@ -19,7 +19,7 @@ content: name: '[版本迁移指南](reference-manual/upgrades-and-compatibility/)' - 历史版本文档: - description: 历史版本文档 - name: '[2.x 及早期版本文档](/zh-cn/docsv2.7/)' + name: '[2.x 及早期版本文档](/en/docsv2.7/)' description: Java SDK 手册 hide_feedback: true hide_summary: true diff --git a/content/en/overview/mannual/java-sdk/quick-start/_index.md b/content/en/overview/mannual/java-sdk/quick-start/_index.md index cea661e66260..09215900ff58 100755 --- a/content/en/overview/mannual/java-sdk/quick-start/_index.md +++ b/content/en/overview/mannual/java-sdk/quick-start/_index.md @@ -1,11 +1,11 @@ --- aliases: - - /zh/docs3-v2/java-sdk/quick-start/ - - /zh-cn/docs3-v2/java-sdk/quick-start/ - - /zh/overview/quickstart/java/ - - /zh-cn/overview/quickstart/java/ - - /zh/overview/quickstart/ - - /zh-cn/overview/quickstart/ + - /en/docs3-v2/java-sdk/quick-start/ + - /en/docs3-v2/java-sdk/quick-start/ + - /en/overview/quickstart/java/ + - /en/overview/quickstart/java/ + - /en/overview/quickstart/ + - /en/overview/quickstart/ description: "" linkTitle: 快速入门 title: 快速入门 diff --git a/content/en/overview/mannual/java-sdk/quick-start/starter.md b/content/en/overview/mannual/java-sdk/quick-start/starter.md index 214c15a55c31..cd44f306ea24 100644 --- a/content/en/overview/mannual/java-sdk/quick-start/starter.md +++ b/content/en/overview/mannual/java-sdk/quick-start/starter.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config/overview/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config/overview/ - - /zh-cn/overview/mannual/java-sdk/quick-start/spring-boot/ + - /en/docs3-v2/java-sdk/reference-manual/config/overview/ + - /en/docs3-v2/java-sdk/reference-manual/config/overview/ + - /en/overview/mannual/java-sdk/quick-start/spring-boot/ description: 创建基于Spring Boot的Dubbo应用。 linkTitle: 创建基于Spring Boot的Dubbo应用 title: 创建基于Spring Boot的微服务应用 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/_index.md index 8d05c7706e1e..1c97c2079aa1 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/ + - /en/docs3-v2/java-sdk/reference-manual/ + - /en/docs3-v2/java-sdk/reference-manual/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/ description: 参考手册 linkTitle: 参考手册 title: 参考手册 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/_index.md index 920b0022d463..295c268e3ae9 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/concepts-and-architecture/ - - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/ - - /zh-cn/overview/mannual/java-sdk/concepts-and-architecture/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/ + - /en/overview/mannual/java-sdk/concepts-and-architecture/ description: 概念和架构 linkTitle: 源码架构 title: 源码架构 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/code-architecture.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/code-architecture.md index 42935d0889db..73d7923f74c5 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/code-architecture.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/code-architecture.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/concepts-and-architecture/code-architecture/ - - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/code-architecture/ - - /zh-cn/overview/mannual/java-sdk/concepts-and-architecture/code-architecture/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/code-architecture/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/code-architecture/ + - /en/overview/mannual/java-sdk/concepts-and-architecture/code-architecture/ description: 本文将介绍 Dubbo 代码架构。 linkTitle: 代码架构 title: 代码架构 @@ -110,4 +110,4 @@ weight: 2 ## 基本设计原则 * 采用 Microkernel + Plugin 模式,Microkernel 只负责组装 Plugin,Dubbo 自身的功能也是通过扩展点实现的,也就是 Dubbo 的所有功能点都可被用户自定义扩展所替换。 -* 采用 URL 作为配置信息的统一格式,所有扩展点都通过传递 URL 携带配置信息。 \ No newline at end of file +* 采用 URL 作为配置信息的统一格式,所有扩展点都通过传递 URL 携带配置信息。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi.md index 0d0487980895..ef0f341b68ff 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/dubbo-spi/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/dubbo-spi/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/dubbo-spi/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/dubbo-spi/ description: 本文介绍了 Dubbo SPI 的原理和实现细节 linkTitle: 扩展点开发指南 title: 扩展点开发指南 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/mesh.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/architecture/mesh.md.bak index 3a6b24400b7b..4eedd9ef08c5 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/mesh.md.bak +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/mesh.md.bak @@ -1,6 +1,6 @@ --- aliases: - - /zh/docs3-v2/java-sdk/concepts-and-architecture/mesh/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/mesh/ - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/mesh/ description: 本文将介绍 Dubbo Mesh 架构设计。 linkTitle: Dubbo Mesh @@ -77,4 +77,4 @@ ThinSDK + Sidecar 模式的 Mesh 架构有很多优势,如平滑升级、多 ### Dubbo 控制面治理规则 TBD -Dubbo SDK 提供了非常灵活的配置来控制服务治理行为,如接口粒度的服务地址发现能力、接口粒度的配置同步等,这些能力让应用的开发和部署更加灵活。而在通用的 Mesh 部署方案或产品下一些高级功能可能受限,从总体上影响了易用性与灵活性。为此 Dubbo 计划提供自研控制面产品,以最大化的在 Mesh 体系发挥 Dubbo3 能力。 \ No newline at end of file +Dubbo SDK 提供了非常灵活的配置来控制服务治理行为,如接口粒度的服务地址发现能力、接口粒度的配置同步等,这些能力让应用的开发和部署更加灵活。而在通用的 Mesh 部署方案或产品下一些高级功能可能受限,从总体上影响了易用性与灵活性。为此 Dubbo 计划提供自研控制面产品,以最大化的在 Mesh 体系发挥 Dubbo3 能力。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol.md index 06f9050534e9..0ec10862d2e6 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol.md @@ -33,7 +33,7 @@ Dubbo协议支持,以及Qos协议支持。这些协议的识别都是由一个 ## 使用方式 在同一主机上部署多个服务或需要通过负载均衡器访问多个服务。 -> 关于Dubbo支持的配置方式 [配置说明](/zh-cn/overview/mannual/java-sdk/reference-manual/config/) +> 关于Dubbo支持的配置方式 [配置说明](/en/overview/mannual/java-sdk/reference-manual/config/) ### 服务多协议导出 @@ -88,7 +88,7 @@ dubbo.protocol.port=20880 ``` -完成Qos模块的导入之后,相关的配置项可参考[Qos操作手册](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/overview/)进行配置。 +完成Qos模块的导入之后,相关的配置项可参考[Qos操作手册](/en/overview/mannual/java-sdk/reference-manual/qos/overview/)进行配置。 默认情况下,基于端口复用的Qos服务在模块导入后是启动的。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/overall-architecture.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/architecture/overall-architecture.md.bak index 04457022e848..1eb9df7a06bb 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/overall-architecture.md.bak +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/overall-architecture.md.bak @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture/ - - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture/ description: 本文将介绍 Dubbo 总体架构。 linkTitle: 总体架构 title: 总体架构 @@ -72,4 +72,4 @@ Dubbo 架构具有以下几个特点,分别是连通性、健壮性、伸缩 | `Scheduler` | 调度中心基于访问压力自动增减服务提供者 | | `Admin` | 统一管理控制台 | | `Registry` | 服务注册与发现的注册中心 | -| `Monitor` | 统计服务的调用次数和调用时间的监控中心 | \ No newline at end of file +| `Monitor` | 统计服务的调用次数和调用时间的监控中心 | diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-discovery.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-discovery.md.bak index 1e5b20b7a831..c59f2318d542 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-discovery.md.bak +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-discovery.md.bak @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/concepts-and-architecture/service-discovery/ - - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/service-discovery/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/service-discovery/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/service-discovery/ description: 本文将介绍 Dubbo 服务发现。 linkTitle: 服务发现 title: 服务发现 @@ -65,4 +65,4 @@ Dubbo3 服务发现模型更适合构建可伸缩的服务体系,这点要如 对于 Dubbo3 来说,新的注册发现模型只需要 1 个服务(只和应用有关和接口无关), 只注册和机器实例数相等的 1 * 100 = 100 个虚拟节点到注册中心。 在这个简单的示例中,Dubbo 所注册的地址数量下降到了原来的 1 / 100,对于注册中心、订阅方的存储压力都是一个极大的释放。更重要的是, 地址发现容量彻底与业务 RPC 定义解耦开来,整个集群的容量评估对运维来说将变得更加透明:部署多少台机器就会有多大负载,不会像 Dubbo2 一样, -因为业务 RPC 重构就会影响到整个集群服务发现的稳定性。 \ No newline at end of file +因为业务 RPC 重构就会影响到整个集群服务发现的稳定性。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-invocation.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-invocation.md index 6b5a3f3317cf..4aae3cbc2739 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-invocation.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-invocation.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/concepts-and-architecture/service-invocation/ - - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/service-invocation/ - - /zh-cn/overview/mannual/java-sdk/concepts-and-architecture/service-invocation/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/service-invocation/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/service-invocation/ + - /en/overview/mannual/java-sdk/concepts-and-architecture/service-invocation/ description: 本文将介绍如何在 Dubbo Java 实现中自定义调用链路上核心的扩展点以满足您的需求。 linkTitle: 服务调用 title: 服务调用扩展点 @@ -86,7 +86,7 @@ public interface ClusterFilter extends BaseFilter { @Activate(group = CommonConstants.PROVIDER) ``` -> [调用拦截扩展方式](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/filter/) +> [调用拦截扩展方式](/en/overview/mannual/java-sdk/reference-manual/spi/description/filter/) ## Router(路由选址) @@ -125,7 +125,7 @@ public interface Router extends Comparable { } ``` -> [路由选址扩展方式](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/router/) +> [路由选址扩展方式](/en/overview/mannual/java-sdk/reference-manual/spi/description/router/) ## Cluster(集群规则) @@ -142,7 +142,7 @@ public abstract class AbstractClusterInvoker implements ClusterInvoker { ``` -> [集群规则扩展方式](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/cluster/) +> [集群规则扩展方式](/en/overview/mannual/java-sdk/reference-manual/spi/description/cluster/) ## LoadBalance(负载均衡) @@ -156,4 +156,4 @@ public interface LoadBalance { Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException; } ``` -> [调用拦截扩展方式](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/filter/) +> [调用拦截扩展方式](/en/overview/mannual/java-sdk/reference-manual/spi/description/filter/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/_index.md index 2fa6d5b61c8e..a8a5df8bcddf 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config-center/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config-center/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config-center/ - - /zh-cn/overview/what/ecosystem/config-center/ + - /en/docs3-v2/java-sdk/reference-manual/config-center/ + - /en/docs3-v2/java-sdk/reference-manual/config-center/ + - /en/overview/what/ecosystem/config-center/ description: Dubbo 配置中心的基本使用和工作原理 linkTitle: 配置中心 title: 配置中心 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/apollo.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/apollo.md index c715537c2b80..16c7141913a0 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config-center/apollo.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/apollo.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config-center/apollo/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config-center/apollo/ - - /zh-cn/overview/what/ecosystem/config-center/apollo/ + - /en/docs3-v2/java-sdk/reference-manual/config-center/apollo/ + - /en/docs3-v2/java-sdk/reference-manual/config-center/apollo/ + - /en/overview/what/ecosystem/config-center/apollo/ description: Apollo 配置中心的基本使用和工作原理。 linkTitle: Apollo title: Apollo diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/introduction.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/introduction.md index cd3edada6a13..261d53a32a0f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config-center/introduction.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/introduction.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config-center/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config-center/ - - /zh-cn/overview/what/ecosystem/config-center/ + - /en/docs3-v2/java-sdk/reference-manual/config-center/ + - /en/docs3-v2/java-sdk/reference-manual/config-center/ + - /en/overview/what/ecosystem/config-center/ description: Dubbo 配置中心的基本使用和工作原理 linkTitle: 配置中心概述 title: 配置中心 @@ -13,7 +13,7 @@ weight: 1 配置中心 (config-center) 在 Dubbo 中可承担两类职责: -1. [外部化配置](/zh-cn/overview/mannual/java-sdk/reference-manual/config/principle/#33-外部化配置):启动配置的集中式存储 (简单理解为 dubbo.properties 的外部化存储)。 +1. [外部化配置](/en/overview/mannual/java-sdk/reference-manual/config/principle/#33-外部化配置):启动配置的集中式存储 (简单理解为 dubbo.properties 的外部化存储)。 2. 流量治理规则存储 请参考具体扩展实现了解如何启用配置中心。 @@ -22,7 +22,7 @@ weight: 1 * namespace - 配置命名空间,默认值 `dubbo`。命名空间通常用于多租户隔离,即对不同用户、不同环境或完全不关联的一系列配置进行逻辑隔离,区别于物理隔离的点是不同的命名空间使用的还是同一物理集群。 * group - 配置分组,默认值 `dubbo`。`group` 通常用于归类一组相同类型/目的的配置项,是对 `namespace` 下配置项的进一步隔离。 -参考 [配置说明 - 配置项手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#dubboconfig-center) 了解 namespace 和 group 之外 config-center 开放的更多配置项。 +参考 [配置说明 - 配置项手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/#dubboconfig-center) 了解 namespace 和 group 之外 config-center 开放的更多配置项。 {{% alert title="使用注册中心作为默认配置中心" color="info" %}} 在使用 Zookeeper、Nacos 作为注册中心且没有显式配置配置中心的情况下,Dubbo 框架会默认将此 Zookeeper、Nacos 用作配置中心,用作服务治理用途。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/nacos.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/nacos.md index 3bf51acfc078..79f78267aa50 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config-center/nacos.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/nacos.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config-center/nacos/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config-center/nacos/ - - /zh-cn/overview/what/ecosystem/config-center/nacos/ + - /en/docs3-v2/java-sdk/reference-manual/config-center/nacos/ + - /en/docs3-v2/java-sdk/reference-manual/config-center/nacos/ + - /en/overview/what/ecosystem/config-center/nacos/ description: Nacos 配置中心的基本使用和工作原理。 linkTitle: Nacos title: Nacos @@ -11,17 +11,17 @@ weight: 3 --- ## 1 前置条件 -* 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/starter/) -* 安装并启动 [Nacos](/zh-cn/overview/reference/integrations/nacos/) +* 了解 [Dubbo 基本开发步骤](/en/overview/mannual/java-sdk/quick-start/starter/) +* 安装并启动 [Nacos](/en/overview/reference/integrations/nacos/) -> 当Dubbo使用`3.0.0`及以上版本时,需要使用Nacos `2.0.0`及以上版本。请参考 [nacos 注册中心](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/nacos/#12-nacos-版本) 了解 nacos 版本适配情况。 +> 当Dubbo使用`3.0.0`及以上版本时,需要使用Nacos `2.0.0`及以上版本。请参考 [nacos 注册中心](/en/overview/mannual/java-sdk/reference-manual/registry/nacos/#12-nacos-版本) 了解 nacos 版本适配情况。 ## 2 使用说明 ### 2.1 增加 Maven 依赖 如果项目已经启用 Nacos 作为注册中心,则无需增加任何额外配置。 -如果未启用 Nacos 注册中心,则请参考 [为注册中心增加 Nacos 依赖](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/nacos/#11-增加依赖)。 +如果未启用 Nacos 注册中心,则请参考 [为注册中心增加 Nacos 依赖](/en/overview/mannual/java-sdk/reference-manual/registry/nacos/#11-增加依赖)。 ### 2.2 启用 Nacos 配置中心 ```xml @@ -112,5 +112,5 @@ dubbo 流量治理规则有多种类型,不同类型的规则 dataId 的后缀是不同的: -- configurators [覆盖规则](/zh-cn/overview/core-features/traffic/configuration-rule/) -- tag-router [标签路由](/zh-cn/overview/core-features/traffic/tag-rule/) 与 condition-router [条件路由](/zh-cn/overview/core-features/traffic/condition-rule/) \ No newline at end of file +- configurators [覆盖规则](/en/overview/core-features/traffic/configuration-rule/) +- tag-router [标签路由](/en/overview/core-features/traffic/tag-rule/) 与 condition-router [条件路由](/en/overview/core-features/traffic/condition-rule/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/zookeeper.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/zookeeper.md index a315d774cd12..ce04706a0fca 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config-center/zookeeper.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/zookeeper.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config-center/zookeeper/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config-center/zookeeper/ - - /zh-cn/overview/what/ecosystem/config-center/zookeeper/ + - /en/docs3-v2/java-sdk/reference-manual/config-center/zookeeper/ + - /en/docs3-v2/java-sdk/reference-manual/config-center/zookeeper/ + - /en/overview/what/ecosystem/config-center/zookeeper/ description: Zookeeper 配置中心的基本使用和工作原理。 linkTitle: Zookeeper title: Zookeeper @@ -12,8 +12,8 @@ weight: 2 ## 1 前置条件 -* 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/starter/) -* 安装并启动 [Zookeeper](/zh-cn/overview/reference/integrations/zookeeper/) +* 了解 [Dubbo 基本开发步骤](/en/overview/mannual/java-sdk/quick-start/starter/) +* 安装并启动 [Zookeeper](/en/overview/reference/integrations/zookeeper/) ## 2 使用说明 在此查看[完整示例代码](https://github.com/apache/dubbo-samples/tree/master/3-extensions/configcenter/dubbo-samples-configcenter-annotation) @@ -21,7 +21,7 @@ weight: 2 ### 2.1 增加 Maven 依赖 如果项目已经启用 Zookeeper 作为注册中心,则无需增加任何额外配置。 -如果未使用 Zookeeper 注册中心,则请参考 [为注册中心增加 Zookeeper 相关依赖](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/zookeeper/#11-增加-maven-依赖)。 +如果未使用 Zookeeper 注册中心,则请参考 [为注册中心增加 Zookeeper 相关依赖](/en/overview/mannual/java-sdk/reference-manual/registry/zookeeper/#11-增加-maven-依赖)。 ### 2.2 启用 Zookeeper 配置中心 ```xml @@ -96,4 +96,4 @@ dubbo - namespace,用于不同配置的环境隔离。 - config,Dubbo 约定的固定节点,不可更改,所有配置和流量治理规则都存储在此节点下。 - dubbo,所有服务治理规则都是全局性的,dubbo 为默认节点 -- configurators/tag-router/condition-router/migration,不同的服务治理规则类型,node value 存储具体规则内容 \ No newline at end of file +- configurators/tag-router/condition-router/migration,不同的服务治理规则类型,node value 存储具体规则内容 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/config/_index.md index dd5549e51b71..3a5e73862f4d 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/config/overview/ + - /en/docs3-v2/java-sdk/reference-manual/config/ + - /en/docs3-v2/java-sdk/reference-manual/config/ + - /en/overview/mannual/java-sdk/reference-manual/config/overview/ description: Dubbo 配置指南 linkTitle: 配置说明 title: 配置手册 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/api/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/config/api/_index.md index d6ab16f56a08..4556ee3f3583 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/api/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/api/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config/ + - /en/docs3-v2/java-sdk/reference-manual/config/ + - /en/docs3-v2/java-sdk/reference-manual/config/ description: Dubbo 配置指南 linkTitle: 原生API title: 配置手册 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/api/api.md b/content/en/overview/mannual/java-sdk/reference-manual/config/api/api.md index 1f14a143ebc5..749227266fe4 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/api/api.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/api/api.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config/api/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config/api/ + - /en/docs3-v2/java-sdk/reference-manual/config/api/ + - /en/docs3-v2/java-sdk/reference-manual/config/api/ description: 以 API 的方式来配置你的 Dubbo 应用 linkTitle: API 配置 title: API 配置 @@ -9,7 +9,7 @@ type: docs weight: 2 --- -作为一款 RPC 框架,Dubbo 定义了一套完善的 API 接口,我们可以基于原生 API 开发 Dubbo 应用,关于如何使用原生API开发轻量RPC、微服务应用等的具体示例可查看 [使用教程 - API开发模式](/zh-cn/overview/mannual/java-sdk/tasks/develop/api/) 中的示例。它的适用场景包括以下两类: +作为一款 RPC 框架,Dubbo 定义了一套完善的 API 接口,我们可以基于原生 API 开发 Dubbo 应用,关于如何使用原生API开发轻量RPC、微服务应用等的具体示例可查看 [使用教程 - API开发模式](/en/overview/mannual/java-sdk/tasks/develop/api/) 中的示例。它的适用场景包括以下两类: * **轻量 RPC Server & Client**,通常用于一些应用内、基础组件、中间件等内的简单远程调用场景 * **微服务应用**,不依赖 Spring、Spring Boot 的情况下,直接用 API 开发微服务;同时,直接使用 API 对于一些网关或测试平台集成场景也可能比较有用。 @@ -326,7 +326,7 @@ public class DemoConsumer { 3. Module 与 Module 之间可以由用户自定义进行进行隔离,可以是热部署周期的一个状态、也可以是 Spring Context 的一个 Context。通过 Module,用户可以对 Dubbo 的生命周期粒度进行最小的管理。 为了实现 Dubbo 多实例化,Dubbo 框架内做的最多的变化是修改掉大部分的从静态变量中获取的参数的逻辑,最明显的逻辑是 Dubbo 内部用于参数传递的 URL 对象带上了 ScopeModel 状态,这个 ScopeModel 对应的就是上面提到的三层模型的具体数据承载对象。 -关于多示例的更多实现原理、设计细节等,请参考 [源码架构 - 多实例设计与实现](/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/)。 +关于多示例的更多实现原理、设计细节等,请参考 [源码架构 - 多实例设计与实现](/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/)。 ```java diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/principle.md b/content/en/overview/mannual/java-sdk/reference-manual/config/principle.md index cb1c396c7777..d2e8004f6ebf 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/principle.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/principle.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config/principle/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config/principle/ + - /en/docs3-v2/java-sdk/reference-manual/config/principle/ + - /en/docs3-v2/java-sdk/reference-manual/config/principle/ description: Dubbo 配置方式和工作原理的深度解读,包括配置格式、设计思路、来源、加载流程等。 linkTitle: 配置加载流程 title: 配置工作原理 @@ -36,7 +36,7 @@ method | 指定方法级的配置 | service 和 reference 的子配置 | 可选 argument | 某个方法的参数配置 | method的子配置 | 可选 -> 从实现原理层面,最终 Dubbo 所有的配置项都会被组装到 URL 中,以 URL 为载体在后续的启动、RPC 调用过程中传递,进而控制框架行为。如想了解更多,请参照 Dubbo 源码解析系列文档或 [Blog](/zh-cn/blog/2019/10/17/dubbo-中的-url-统一模型/#rpc调用)。 +> 从实现原理层面,最终 Dubbo 所有的配置项都会被组装到 URL 中,以 URL 为载体在后续的启动、RPC 调用过程中传递,进而控制框架行为。如想了解更多,请参照 Dubbo 源码解析系列文档或 [Blog](/en/blog/2019/10/17/dubbo-中的-url-统一模型/#rpc调用)。 > 各组件支持的具体配置项及含义请参考 [配置项手册](../properties) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/properties.md b/content/en/overview/mannual/java-sdk/reference-manual/config/properties.md index 0dbbdf5f9c8d..5c95fceeab1a 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/properties.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/properties.md @@ -1,16 +1,16 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config/properties/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config/properties/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/dump/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/lazy-connect/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/simplify-registry-data/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/stickiness/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/delay-publish/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/preflight-check/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/registry-only/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/service-downgrade/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/subscribe-only/ + - /en/docs3-v2/java-sdk/reference-manual/config/properties/ + - /en/docs3-v2/java-sdk/reference-manual/config/properties/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/performance/dump/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/performance/lazy-connect/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/performance/simplify-registry-data/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/performance/stickiness/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/delay-publish/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/preflight-check/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/registry-only/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/service-downgrade/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/subscribe-only/ description: 包含 Dubbo 支持的所有配置组件及每个配置组件支持的所有配置项 linkTitle: 配置项手册 title: 配置项参考手册 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/properties3.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/config/properties3.md.bak index dffc97376eb1..3827efbbb1a6 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/properties3.md.bak +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/properties3.md.bak @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config/properties/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config/properties/ + - /en/docs3-v2/java-sdk/reference-manual/config/properties/ + - /en/docs3-v2/java-sdk/reference-manual/config/properties/ description: 包含 Dubbo 支持的所有配置组件及每个配置组件支持的所有配置项 linkTitle: 配置项手册 title: 配置项参考手册 @@ -84,7 +84,7 @@ weight: 6 | owner | owner | string | 可选 | | 服务治理 | 服务负责人,用于服务治理,请填写负责人公司邮箱前缀 | 2.0.5以上版本 | | document | document | string | 可选 | | 服务治理 | 服务文档URL | 2.0.5以上版本 | | weight | weight | int | 可选 | | 性能调优 | 服务权重 | 2.0.5以上版本 | -| executes | executes | int | 可选 | 0 | 性能调优 | 服务提供者每服务每方法最大可并行执行请求数 | 2.0.5以上版本 | +| executes | executes | int | 可选 | 0 | 性能调优 | 服务提供者每服务每方法最大可并行执行请求数 | 2.0.5以上版本 | | actives | actives | int | 可选 | 0 | 性能调优 | 每服务消费者每服务每方法最大并发调用数 | 2.0.5以上版本 | | proxy | proxy | string | 可选 | javassist | 性能调优 | 生成动态代理方式,可选:jdk/javassist | 2.0.5以上版本 | | cluster | cluster | string | 可选 | failover | 性能调优 | 集群方式,可选:failover/failfast/failsafe/failback/forking/available/mergeable(2.1.0以上版本)/broadcast(2.1.0以上版本)/zone-aware(2.7.5以上版本) | 2.0.5以上版本 | @@ -216,7 +216,7 @@ weight: 6 | password | password | string | 可选 | | 元数据中心需要做校验,密码
Apollo暂未启用 | 2.7.0以上版本 | | timeout | timeout | int | 可选 | | 获取元数据超时时间(ms) | 2.7.0以上版本 | | group | group | string | 可选 | dubbo | 元数据分组,适用于环境隔离。与注册中心group意义相同 | 2.7.0以上版本 | -| retryTimes | retry-times| int | 可选 | 100 | 重试次数 | 2.7.0以上版本 | +| retryTimes | retry-times| int | 可选 | 100 | 重试次数 | 2.7.0以上版本 | | retryPeriod | retry-period | int | 可选 | 3000ms | 重试间隔时间(ms) | 2.7.0以上版本 | | cycleReport | cycle-report | boolean| 可选 | true | 是否每天更新完整元数据 | 2.7.0以上版本 | | syncReport | sync-report | boolean| 可选 | false | 是否同步更新元数据,默认为异步 | 2.7.0以上版本 | @@ -378,7 +378,7 @@ weight: 6 | 属性 | 类型 | 是否必填 | 缺省值 | 描述 | | --- | --- | ---- | --- | --- | -| exporter.enabled | boolean | 可选 | | 是否启用prometheus exporter | +| exporter.enabled | boolean | 可选 | | 是否启用prometheus exporter | | exporter.enableHttpServiceDiscovery | boolean | 可选 | | 是否启用http服务发现 | | exporter.httpServiceDiscoveryUrl | string | 可选 | | http服务发现地址 | | exporter.metricsPort | int | 可选 | | 当使用pull方法时,暴露的端口号 | diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/_index.md index 03dc67168db4..bc3f4a4a5b37 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config/ + - /en/docs3-v2/java-sdk/reference-manual/config/ + - /en/docs3-v2/java-sdk/reference-manual/config/ description: Dubbo 配置指南 linkTitle: Spring title: 配置手册 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot.md b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot.md index 9558dde72565..7208da3fba8c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config/annotation/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config/annotation/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/config/annotation/ + - /en/docs3-v2/java-sdk/reference-manual/config/annotation/ + - /en/docs3-v2/java-sdk/reference-manual/config/annotation/ + - /en/overview/mannual/java-sdk/reference-manual/config/annotation/ description: 以 Annotation、Spring Boot 开发 Dubbo 应用 linkTitle: Spring Boot title: Spring Boot @@ -10,7 +10,7 @@ type: docs weight: 3 --- -关于 Spring Boot 的注解、基本使用方法等请参考 [使用教程 - Spring Boot](/zh-cn/overview/mannual/java-sdk/tasks/develop/springboot/)。以下是 spring boot 支持的配置详情与 starter 列表。 +关于 Spring Boot 的注解、基本使用方法等请参考 [使用教程 - Spring Boot](/en/overview/mannual/java-sdk/tasks/develop/springboot/)。以下是 spring boot 支持的配置详情与 starter 列表。 ## application.yaml @@ -88,6 +88,6 @@ dubbo: * `dubbo-tracing-otel-zipkin-spring-boot-starter`,管理 brave/zipkin、micrometer 等相关相关依赖,使用 OpenTelemetry 作为 Tracer,将 Trace 信息 export 到 Zipkin。 {{% alert title="注意" color="info" %}} -* 关于每个 starter 适配的第三方组件版本,请查看 [组件版本映射表](/zh-cn/overview/mannual/java-sdk/versions/#版本说明)。 +* 关于每个 starter 适配的第三方组件版本,请查看 [组件版本映射表](/en/overview/mannual/java-sdk/versions/#版本说明)。 * 每个 starter 都有对应的 application.yml 配置项,请跟随上文 [配置项列表](./#配置示例) 了解使用细节。 {{% /alert %}} diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/xml.md b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/xml.md index 1296a303ccae..5a9e3e24183f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/xml.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/xml.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/config/xml/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/config/xml/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/config/xml/ + - /en/docs3-v2/java-sdk/reference-manual/config/xml/ + - /en/docs3-v2/java-sdk/reference-manual/config/xml/ + - /en/overview/mannual/java-sdk/reference-manual/config/xml/ description: 以 Spring XML 开发 Dubbo 应用 linkTitle: XML 配置 title: XML 配置 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/1.md index b071c05bcc50..dd51c90f6be0 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/1.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/1.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/1/ -- /zh-cn/docs3-v2/java-sdk/faq/0/1/ -- /zh-cn/overview/mannual/java-sdk/faq/0/1/ +- /en/docs3-v2/java-sdk/faq/0/1/ +- /en/docs3-v2/java-sdk/faq/0/1/ +- /en/overview/mannual/java-sdk/faq/0/1/ description: 0-1 - 线程池资源枯竭 linkTitle: 0-1 - 线程池资源枯竭 title: 0-1 - 线程池资源枯竭 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/10.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/10.md index fa3c0a1e2f19..9f8e3789b8fd 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/10.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/10.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/10/ -- /zh-cn/docs3-v2/java-sdk/faq/0/10/ -- /zh-cn/overview/mannual/java-sdk/faq/0/10/ +- /en/docs3-v2/java-sdk/faq/0/10/ +- /en/docs3-v2/java-sdk/faq/0/10/ +- /en/overview/mannual/java-sdk/faq/0/10/ description: 0-10 - 当前调用不在支持 linkTitle: 0-10 - 当前调用不在支持 title: 0-10 - 当前调用不在支持 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/11.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/11.md index 2f34f5bb4c8c..272de626bc50 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/11.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/11.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/11/ -- /zh-cn/docs3-v2/java-sdk/faq/0/11/ -- /zh-cn/overview/mannual/java-sdk/faq/0/11/ +- /en/docs3-v2/java-sdk/faq/0/11/ +- /en/docs3-v2/java-sdk/faq/0/11/ +- /en/overview/mannual/java-sdk/faq/0/11/ description: 0-11 - 服务停止失败 linkTitle: 0-11 - 服务停止失败 title: 0-11 - 服务停止失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/12.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/12.md index d698476b0604..a589cdf8a3ba 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/12.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/12.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/12/ -- /zh-cn/docs3-v2/java-sdk/faq/0/12/ -- /zh-cn/overview/mannual/java-sdk/faq/0/12/ +- /en/docs3-v2/java-sdk/faq/0/12/ +- /en/docs3-v2/java-sdk/faq/0/12/ +- /en/overview/mannual/java-sdk/faq/0/12/ description: 0-12 - 未知异常 linkTitle: 0-12 - 未知异常 title: 0-12 - 未知异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/13.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/13.md index 2fee987fd875..ef70771e6779 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/13.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/13.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/13/ -- /zh-cn/docs3-v2/java-sdk/faq/0/13/ -- /zh-cn/overview/mannual/java-sdk/faq/0/13/ +- /en/docs3-v2/java-sdk/faq/0/13/ +- /en/docs3-v2/java-sdk/faq/0/13/ +- /en/overview/mannual/java-sdk/faq/0/13/ description: 0-13 - 指标收集器发生异常 linkTitle: 0-13 - 指标收集器发生异常 title: 0-13 - 指标收集器发生异常 @@ -22,4 +22,4 @@ weight: 13 ### 排查和解决步骤 -请参考配置项参考手册[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/)。 +请参考配置项参考手册[配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/14.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/14.md index c673e002ce44..05ef19696b8d 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/14.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/14.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/14/ -- /zh-cn/docs3-v2/java-sdk/faq/0/14/ -- /zh-cn/overview/mannual/java-sdk/faq/0/14/ +- /en/docs3-v2/java-sdk/faq/0/14/ +- /en/docs3-v2/java-sdk/faq/0/14/ +- /en/overview/mannual/java-sdk/faq/0/14/ description: 0-14 - 监控异常 linkTitle: 0-14 - 监控异常 title: 0-14 - 监控异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/15.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/15.md index 17c75ddd70d6..f660665af79e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/15.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/15.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/15/ -- /zh-cn/docs3-v2/java-sdk/faq/0/15/ -- /zh-cn/overview/mannual/java-sdk/faq/0/15/ +- /en/docs3-v2/java-sdk/faq/0/15/ +- /en/docs3-v2/java-sdk/faq/0/15/ +- /en/overview/mannual/java-sdk/faq/0/15/ description: 0-15 - 加载扩展类时发生异常 linkTitle: 0-15 - 加载扩展类时发生异常 title: 0-15 - 加载扩展类时发生异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/16.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/16.md index 3ac1e2167b59..61edaebd6614 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/16.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/16.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/16/ -- /zh-cn/docs3-v2/java-sdk/faq/0/16/ -- /zh-cn/overview/mannual/java-sdk/faq/0/16/ +- /en/docs3-v2/java-sdk/faq/0/16/ +- /en/docs3-v2/java-sdk/faq/0/16/ +- /en/overview/mannual/java-sdk/faq/0/16/ description: 0-16 - 没有可用的执行器 linkTitle: 0-16 - 没有可用的执行器 title: 0-16 - 没有可用的执行器 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/17.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/17.md index 8d4887f156e4..70ffd70e0f2c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/17.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/17.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/17/ -- /zh-cn/docs3-v2/java-sdk/faq/0/17/ -- /zh-cn/overview/mannual/java-sdk/faq/0/17/ +- /en/docs3-v2/java-sdk/faq/0/17/ +- /en/docs3-v2/java-sdk/faq/0/17/ +- /en/overview/mannual/java-sdk/faq/0/17/ description: 0-17 - 执行器在关闭时发生未知异常 linkTitle: 0-17 - 执行器在关闭时发生未知异常 title: 0-17 - 执行器在关闭时发生未知异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/18.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/18.md index 846e60e60923..663371be4f49 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/18.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/18.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/18/ -- /zh-cn/docs3-v2/java-sdk/faq/0/18/ -- /zh-cn/overview/mannual/java-sdk/faq/0/18/ +- /en/docs3-v2/java-sdk/faq/0/18/ +- /en/docs3-v2/java-sdk/faq/0/18/ +- /en/overview/mannual/java-sdk/faq/0/18/ description: 0-18 - 线程池执行器被错误使用 linkTitle: 0-18 - 线程池执行器被错误使用 title: 0-18 - 线程池执行器被错误使用 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/19.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/19.md index aa8fe7ef0b1f..20a210d89a89 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/19.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/19.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/19/ -- /zh-cn/docs3-v2/java-sdk/faq/0/19/ -- /zh-cn/overview/mannual/java-sdk/faq/0/19/ +- /en/docs3-v2/java-sdk/faq/0/19/ +- /en/docs3-v2/java-sdk/faq/0/19/ +- /en/overview/mannual/java-sdk/faq/0/19/ description: 0-19 - 处理任务时发生异常 linkTitle: 0-19 - 处理任务时发生异常 title: 0-19 - 处理任务时发生异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/2.md index f3ce40d87e52..66488af7ac38 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/2.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/2.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/2/ -- /zh-cn/docs3-v2/java-sdk/faq/0/2/ -- /zh-cn/overview/mannual/java-sdk/faq/0/2/ +- /en/docs3-v2/java-sdk/faq/0/2/ +- /en/docs3-v2/java-sdk/faq/0/2/ +- /en/overview/mannual/java-sdk/faq/0/2/ description: 0-2 - 非法属性值 linkTitle: 0-2 - 非法属性值 title: 0-2 - 非法属性值 @@ -15,4 +15,4 @@ weight: 2 这个提示是指用户配置的值与属性本身所需的数据类型并不匹配。比如 `dubbo.comsumer.threads` 属性只能接受数值属性,但是用户所输入的值混入了字母。 ### 排查和解决步骤 -根据[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/),查找出错的配置项,检查该项指定的类型,检查是否出现类型不一致的情况。 +根据[配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/),查找出错的配置项,检查该项指定的类型,检查是否出现类型不一致的情况。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/20.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/20.md index e9c985b73a82..900b134d9fdd 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/20.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/20.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/20/ -- /zh-cn/docs3-v2/java-sdk/faq/0/20/ -- /zh-cn/overview/mannual/java-sdk/faq/0/20/ +- /en/docs3-v2/java-sdk/faq/0/20/ +- /en/docs3-v2/java-sdk/faq/0/20/ +- /en/overview/mannual/java-sdk/faq/0/20/ description: 0-20 - 存储堆栈信息时发生异常 linkTitle: 0-20 - 存储堆栈信息时发生异常 title: 0-20 - 存储堆栈信息时发生异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/21.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/21.md index 918053167e85..97e6a6941ee8 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/21.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/21.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/21/ -- /zh-cn/docs3-v2/java-sdk/faq/0/21/ -- /zh-cn/overview/mannual/java-sdk/faq/0/21/ +- /en/docs3-v2/java-sdk/faq/0/21/ +- /en/docs3-v2/java-sdk/faq/0/21/ +- /en/overview/mannual/java-sdk/faq/0/21/ description: 0-21 - 构建的实例过多 linkTitle: 0-21 - 构建的实例过多 title: 0-21 - 构建的实例过多 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/22.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/22.md index 5067b58c45b5..b1f19436e128 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/22.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/22.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/22/ -- /zh-cn/docs3-v2/java-sdk/faq/0/22/ -- /zh-cn/overview/mannual/java-sdk/faq/0/22/ +- /en/docs3-v2/java-sdk/faq/0/22/ +- /en/docs3-v2/java-sdk/faq/0/22/ +- /en/overview/mannual/java-sdk/faq/0/22/ description: 0-22 - 输入输出流异常 linkTitle: 0-22 - 输入输出流异常 title: 0-22 - 输入输出流异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/23.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/23.md index 1f3ed674cbb5..07053e2934bd 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/23.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/23.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/23/ -- /zh-cn/docs3-v2/java-sdk/faq/0/23/ -- /zh-cn/overview/mannual/java-sdk/faq/0/23/ +- /en/docs3-v2/java-sdk/faq/0/23/ +- /en/docs3-v2/java-sdk/faq/0/23/ +- /en/overview/mannual/java-sdk/faq/0/23/ description: 0-23 - 序列化数据转换异常 linkTitle: 0-23 - 序列化数据转换异常 title: 0-23 - 序列化数据转换异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/24.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/24.md index 95cbc29440cf..5e4076f70056 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/24.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/24.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/24/ -- /zh-cn/docs3-v2/java-sdk/faq/0/24/ -- /zh-cn/overview/mannual/java-sdk/faq/0/24/ +- /en/docs3-v2/java-sdk/faq/0/24/ +- /en/docs3-v2/java-sdk/faq/0/24/ +- /en/overview/mannual/java-sdk/faq/0/24/ description: 0-24 - 覆盖字段值异常 linkTitle: 0-24 - 覆盖字段值异常 title: 0-24 - 覆盖字段值异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/25.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/25.md index 6c7fb5aa52da..778c5197de9a 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/25.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/25.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/25/ -- /zh-cn/docs3-v2/java-sdk/faq/0/25/ -- /zh-cn/overview/mannual/java-sdk/faq/0/25/ +- /en/docs3-v2/java-sdk/faq/0/25/ +- /en/docs3-v2/java-sdk/faq/0/25/ +- /en/overview/mannual/java-sdk/faq/0/25/ description: 0-25 - 加载映射错误 linkTitle: 0-25 - 加载映射错误 title: 0-25 - 加载映射错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/26.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/26.md index 55d6d86991cd..9b15c8da723e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/26.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/26.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/26/ -- /zh-cn/docs3-v2/java-sdk/faq/0/26/ -- /zh-cn/overview/mannual/java-sdk/faq/0/26/ +- /en/docs3-v2/java-sdk/faq/0/26/ +- /en/docs3-v2/java-sdk/faq/0/26/ +- /en/overview/mannual/java-sdk/faq/0/26/ description: 0-26 - 元数据发布服务时的警告信息 linkTitle: 0-26 - 元数据发布服务时的警告信息 title: 0-26 - 元数据发布服务时的警告信息 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/27.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/27.md index 35e39155f99e..a04b06da7151 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/27.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/27.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/27/ -- /zh-cn/docs3-v2/java-sdk/faq/0/27/ -- /zh-cn/overview/mannual/java-sdk/faq/0/27/ +- /en/docs3-v2/java-sdk/faq/0/27/ +- /en/docs3-v2/java-sdk/faq/0/27/ +- /en/overview/mannual/java-sdk/faq/0/27/ description: 0-27 - 线程池隔离配置异常 linkTitle: 0-27 - 线程池隔离配置异常 title: 0-27 - 线程池隔离配置异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/28.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/28.md index 1755794dd97e..e33159430380 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/28.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/28.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/28/ -- /zh-cn/docs3-v2/java-sdk/faq/0/28/ -- /zh-cn/overview/mannual/java-sdk/faq/0/28/ +- /en/docs3-v2/java-sdk/faq/0/28/ +- /en/docs3-v2/java-sdk/faq/0/28/ +- /en/overview/mannual/java-sdk/faq/0/28/ description: 0-28 - 操作了可能会引起危险的行为 linkTitle: 0-28 - 危险的行为 title: 0-28 - 操作了可能会引起危险的行为 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/29.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/29.md index 8ccd185b72a0..732ffcb46245 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/29.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/29.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/29/ -- /zh-cn/docs3-v2/java-sdk/faq/0/29/ -- /zh-cn/overview/mannual/java-sdk/faq/0/29/ +- /en/docs3-v2/java-sdk/faq/0/29/ +- /en/docs3-v2/java-sdk/faq/0/29/ +- /en/overview/mannual/java-sdk/faq/0/29/ description: 0-29 - 未找到Tracer依赖 linkTitle: 0-29 - 未找到Tracer依赖 title: 0-29 - 未找到Tracer依赖 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/3.md index 9ef6a66efdec..7a6f674d5279 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/3.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/3.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/3/ -- /zh-cn/docs3-v2/java-sdk/faq/0/3/ -- /zh-cn/overview/mannual/java-sdk/faq/0/3/ +- /en/docs3-v2/java-sdk/faq/0/3/ +- /en/docs3-v2/java-sdk/faq/0/3/ +- /en/overview/mannual/java-sdk/faq/0/3/ description: 0-3 - 无法访问缓存路径 linkTitle: 0-3 - 无法访问缓存路径 title: 0-3 - 无法访问缓存路径 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/4.md index 81d308067bb2..a89c49e24d48 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/4.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/4.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/4/ -- /zh-cn/docs3-v2/java-sdk/faq/0/4/ -- /zh-cn/overview/mannual/java-sdk/faq/0/4/ +- /en/docs3-v2/java-sdk/faq/0/4/ +- /en/docs3-v2/java-sdk/faq/0/4/ +- /en/overview/mannual/java-sdk/faq/0/4/ description: 0-4 - 缓存条目超限 linkTitle: 0-4 - 缓存条目超限 title: 0-4 - 缓存条目超限 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/5.md index 61e8bf0472bd..5de70e0de16e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/5.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/5.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/5/ -- /zh-cn/docs3-v2/java-sdk/faq/0/5/ -- /zh-cn/overview/mannual/java-sdk/faq/0/5/ +- /en/docs3-v2/java-sdk/faq/0/5/ +- /en/docs3-v2/java-sdk/faq/0/5/ +- /en/overview/mannual/java-sdk/faq/0/5/ description: 0-5 - 缓存文件大小超限 linkTitle: 0-5 - 缓存文件大小超限 title: 0-5 - 缓存文件大小超限 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/6.md index a96fca69ec2c..65c109d68a0c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/6.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/6.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/6/ -- /zh-cn/docs3-v2/java-sdk/faq/0/6/ -- /zh-cn/overview/mannual/java-sdk/faq/0/6/ +- /en/docs3-v2/java-sdk/faq/0/6/ +- /en/docs3-v2/java-sdk/faq/0/6/ +- /en/overview/mannual/java-sdk/faq/0/6/ description: 0-6 - 线程中断异常 linkTitle: 0-6 - 线程中断异常 title: 0-6 - 线程中断异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/7.md index 22fa36806e0a..126bab4475f0 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/7.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/7.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/7/ -- /zh-cn/docs3-v2/java-sdk/faq/0/7/ -- /zh-cn/overview/mannual/java-sdk/faq/0/7/ +- /en/docs3-v2/java-sdk/faq/0/7/ +- /en/docs3-v2/java-sdk/faq/0/7/ +- /en/overview/mannual/java-sdk/faq/0/7/ description: 0-7 - 未找到反射类 linkTitle: 0-7 - 未找到反射类 title: 0-7 - 未找到反射类 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/8.md index 0d2d78d8056e..f40bcd14a24a 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/8.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/8.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/8/ -- /zh-cn/docs3-v2/java-sdk/faq/0/8/ -- /zh-cn/overview/mannual/java-sdk/faq/0/8/ +- /en/docs3-v2/java-sdk/faq/0/8/ +- /en/docs3-v2/java-sdk/faq/0/8/ +- /en/overview/mannual/java-sdk/faq/0/8/ description: 0-8 - 反射失败 linkTitle: 0-8 - 反射失败 title: 0-8 - 反射失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/9.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/9.md index 9746c1eb4a44..7430e8218491 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/9.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/9.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/9/ -- /zh-cn/docs3-v2/java-sdk/faq/0/9/ -- /zh-cn/overview/mannual/java-sdk/faq/0/9/ +- /en/docs3-v2/java-sdk/faq/0/9/ +- /en/docs3-v2/java-sdk/faq/0/9/ +- /en/overview/mannual/java-sdk/faq/0/9/ description: 0-9 - 通知事件失败 linkTitle: 0-9 - 通知事件失败 title: 0-9 - 通知事件失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/99.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/99.md index 6c97fb8ef714..0a1fbba1c679 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/99.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/99.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/99/ -- /zh-cn/docs3-v2/java-sdk/faq/0/99/ -- /zh-cn/overview/mannual/java-sdk/faq/0/99/ +- /en/docs3-v2/java-sdk/faq/0/99/ +- /en/docs3-v2/java-sdk/faq/0/99/ +- /en/overview/mannual/java-sdk/faq/0/99/ description: 0-99 - 调用了过时 (Deprecated) 的方法 linkTitle: 0-99 - 调用了过时 (Deprecated) 的方法 title: 0-99 - 调用了过时 (Deprecated) 的方法 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/_index.md index 47f4da13de72..15063bc6b3a5 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/_index.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/0/ -- /zh-cn/docs3-v2/java-sdk/faq/0/ -- /zh-cn/overview/mannual/java-sdk/faq/0/_index/ +- /en/docs3-v2/java-sdk/faq/0/ +- /en/docs3-v2/java-sdk/faq/0/ +- /en/overview/mannual/java-sdk/faq/0/_index/ description: 0 - Common 层 linkTitle: 0 - Common 层 title: 0 - Common 层 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/1.md index 1008ca725924..408db1a94c97 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/1.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/1.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/1/ -- /zh-cn/docs3-v2/java-sdk/faq/1/1/ -- /zh-cn/overview/mannual/java-sdk/faq/1/1/ +- /en/docs3-v2/java-sdk/faq/1/1/ +- /en/docs3-v2/java-sdk/faq/1/1/ +- /en/overview/mannual/java-sdk/faq/1/1/ description: 1-1 - 地址非法 linkTitle: 1-1 - 地址非法 title: 1-1 - 地址非法 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/10.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/10.md index 569d0035c0b6..d304bb939bce 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/10.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/10.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/10/ -- /zh-cn/docs3-v2/java-sdk/faq/1/10/ -- /zh-cn/overview/mannual/java-sdk/faq/1/10/ +- /en/docs3-v2/java-sdk/faq/1/10/ +- /en/docs3-v2/java-sdk/faq/1/10/ +- /en/overview/mannual/java-sdk/faq/1/10/ description: 1-10 - 读写注册中心服务缓存失败 linkTitle: 1-10 - 读写注册中心服务缓存失败 title: 1-10 - 读写注册中心服务缓存失败 @@ -23,4 +23,4 @@ weight: 10 该错误常与 1-9 错误共同出现。检查是否有多个 Dubbo 进程使用了同一个缓存文件或者是否指定多个注册中心使用同一缓存文件。 > 另请参阅 -[注册中心的配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#registry) +[注册中心的配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/#registry) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/11.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/11.md index 27ac6ef07c89..d0fdbeede669 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/11.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/11.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/11/ -- /zh-cn/docs3-v2/java-sdk/faq/1/11/ -- /zh-cn/overview/mannual/java-sdk/faq/1/11/ +- /en/docs3-v2/java-sdk/faq/1/11/ +- /en/docs3-v2/java-sdk/faq/1/11/ +- /en/overview/mannual/java-sdk/faq/1/11/ description: 1-11 - 注册服务实例创建失败 linkTitle: 1-11 - 注册服务实例创建失败 title: 1-11 - 注册服务实例创建失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/12.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/12.md index 7063e0382144..e4ecc191977a 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/12.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/12.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/12/ -- /zh-cn/docs3-v2/java-sdk/faq/1/12/ -- /zh-cn/overview/mannual/java-sdk/faq/1/12/ +- /en/docs3-v2/java-sdk/faq/1/12/ +- /en/docs3-v2/java-sdk/faq/1/12/ +- /en/overview/mannual/java-sdk/faq/1/12/ description: 1-12 - “注册服务” 的实例均已销毁 linkTitle: 1-12 - “注册服务” 的实例均已销毁 title: 1-12 - “注册服务” 的实例均已销毁 @@ -22,4 +22,4 @@ weight: 12 ### 排查和解决步骤 > 另请参阅 -[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) +[配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/13.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/13.md index 40a20e7f6206..75685d4f0c64 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/13.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/13.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/13/ -- /zh-cn/docs3-v2/java-sdk/faq/1/13/ -- /zh-cn/overview/mannual/java-sdk/faq/1/13/ +- /en/docs3-v2/java-sdk/faq/1/13/ +- /en/docs3-v2/java-sdk/faq/1/13/ +- /en/overview/mannual/java-sdk/faq/1/13/ description: 1-13 - 执行重试任务失败 linkTitle: 1-13 - 执行重试任务失败 title: 1-13 - 执行重试任务失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/14.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/14.md index 44c9cdeba35f..6117ccfa1bfa 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/14.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/14.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/14/ -- /zh-cn/docs3-v2/java-sdk/faq/1/14/ -- /zh-cn/overview/mannual/java-sdk/faq/1/14/ +- /en/docs3-v2/java-sdk/faq/1/14/ +- /en/docs3-v2/java-sdk/faq/1/14/ +- /en/overview/mannual/java-sdk/faq/1/14/ description: 1-14 - 动态配置识别失败 linkTitle: 1-14 - 动态配置识别失败 title: 1-14 - 动态配置识别失败 @@ -22,4 +22,4 @@ weight: 14 ### 另请参阅 -> [配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) +> [配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/15.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/15.md index fd7cb427f5e5..bfd50bfef261 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/15.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/15.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/15/ -- /zh-cn/docs3-v2/java-sdk/faq/1/15/ -- /zh-cn/overview/mannual/java-sdk/faq/1/15/ +- /en/docs3-v2/java-sdk/faq/1/15/ +- /en/docs3-v2/java-sdk/faq/1/15/ +- /en/overview/mannual/java-sdk/faq/1/15/ description: 1-15 - 销毁服务失败 linkTitle: 1-15 - 销毁服务失败 title: 1-15 - 销毁服务失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/16.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/16.md index de182f9073f5..93c710edf259 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/16.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/16.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/16/ -- /zh-cn/docs3-v2/java-sdk/faq/1/16/ -- /zh-cn/overview/mannual/java-sdk/faq/1/16/ +- /en/docs3-v2/java-sdk/faq/1/16/ +- /en/docs3-v2/java-sdk/faq/1/16/ +- /en/overview/mannual/java-sdk/faq/1/16/ description: 1-16 - 存在不支持的类别 linkTitle: 1-16 - 存在不支持的类别 title: 1-16 - 存在不支持的类别 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/17.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/17.md index 5b11decd5c40..d6c650347671 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/17.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/17.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/17/ -- /zh-cn/docs3-v2/java-sdk/faq/1/17/ -- /zh-cn/overview/mannual/java-sdk/faq/1/17/ +- /en/docs3-v2/java-sdk/faq/1/17/ +- /en/docs3-v2/java-sdk/faq/1/17/ +- /en/overview/mannual/java-sdk/faq/1/17/ description: 1-17 - metadata Server 失效 linkTitle: 1-17 - metadata Server 失效 title: 1-17 - metadata Server 失效 @@ -23,4 +23,4 @@ weight: 17 2. 排查 `metadataServicePort` 端口号是否存在冲突问题。Provider 和 Consumer 所配置端口同时存在冲突,会产生 metadata Server 失效。 > 另请参阅 -[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) +[配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/18.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/18.md index 74223b62c157..e5dd435ea88e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/18.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/18.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/18/ -- /zh-cn/docs3-v2/java-sdk/faq/1/18/ -- /zh-cn/overview/mannual/java-sdk/faq/1/18/ +- /en/docs3-v2/java-sdk/faq/1/18/ +- /en/docs3-v2/java-sdk/faq/1/18/ +- /en/overview/mannual/java-sdk/faq/1/18/ description: 1-18 - 未提供 metadata service 端口 linkTitle: 1-18 - 未提供 metadata service 端口 title: 1-18 - 未提供 metadata service 端口 @@ -23,4 +23,4 @@ weight: 18 2.检查 Provider 侧的 `metadataServicePort` 配置是否正确,特别注意是否和其他应用端口存在冲突。 > 另请参阅 -[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) +[配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/19.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/19.md index 0fc37b8b4270..86a12ea67ce4 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/19.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/19.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/19/ -- /zh-cn/docs3-v2/java-sdk/faq/1/19/ -- /zh-cn/overview/mannual/java-sdk/faq/1/19/ +- /en/docs3-v2/java-sdk/faq/1/19/ +- /en/docs3-v2/java-sdk/faq/1/19/ +- /en/overview/mannual/java-sdk/faq/1/19/ description: 1-19 - K8S监听异常 linkTitle: 1-19 - K8S监听异常 title: 1-19 - K8S监听异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/20.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/20.md index e7ceded9d8ef..139c35acc0ea 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/20.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/20.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/20/ -- /zh-cn/docs3-v2/java-sdk/faq/1/20/ -- /zh-cn/overview/mannual/java-sdk/faq/1/20/ +- /en/docs3-v2/java-sdk/faq/1/20/ +- /en/docs3-v2/java-sdk/faq/1/20/ +- /en/overview/mannual/java-sdk/faq/1/20/ description: 1-20 - K8S Pod不存在 linkTitle: 1-20 - K8S Pod不存在 title: 1-20 - K8S Pod不存在 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/21.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/21.md index db786def449a..d28595c11dec 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/21.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/21.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/21/ -- /zh-cn/docs3-v2/java-sdk/faq/1/21/ -- /zh-cn/overview/mannual/java-sdk/faq/1/21/ +- /en/docs3-v2/java-sdk/faq/1/21/ +- /en/docs3-v2/java-sdk/faq/1/21/ +- /en/overview/mannual/java-sdk/faq/1/21/ description: 1-21 - K8S 无可用服务 linkTitle: 1-21 - K8S 无可用服务 title: 1-21 - K8S 无可用服务 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/22.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/22.md index a40dcae5873a..d5af3c4dd502 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/22.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/22.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/22/ -- /zh-cn/docs3-v2/java-sdk/faq/1/22/ -- /zh-cn/overview/mannual/java-sdk/faq/1/22/ +- /en/docs3-v2/java-sdk/faq/1/22/ +- /en/docs3-v2/java-sdk/faq/1/22/ +- /en/overview/mannual/java-sdk/faq/1/22/ description: 1-22 - K8S 配置地址错误 linkTitle: 1-22 - K8S 配置地址错误 title: 1-22 - K8S 配置地址错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/26.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/26.md index b1d6cfcdd05c..a2d01bbec535 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/26.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/26.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/26/ -- /zh-cn/docs3-v2/java-sdk/faq/1/26/ -- /zh-cn/overview/mannual/java-sdk/faq/1/26/ +- /en/docs3-v2/java-sdk/faq/1/26/ +- /en/docs3-v2/java-sdk/faq/1/26/ +- /en/overview/mannual/java-sdk/faq/1/26/ description: 1-26 - xDS 证书生成失败 linkTitle: 1-26 - xDS 证书生成失败 title: 1-26 - xDS 证书生成失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/27.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/27.md index 55f37967e2c2..3221ffe7596c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/27.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/27.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/27/ -- /zh-cn/docs3-v2/java-sdk/faq/1/27/ -- /zh-cn/overview/mannual/java-sdk/faq/1/27/ +- /en/docs3-v2/java-sdk/faq/1/27/ +- /en/docs3-v2/java-sdk/faq/1/27/ +- /en/overview/mannual/java-sdk/faq/1/27/ description: 1-27 - K8S监听异常 linkTitle: 1-27 - K8S监听异常 title: 1-27 - K8S监听异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/28.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/28.md index a3eeaf89dd2e..538ad95ad768 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/28.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/28.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/28/ -- /zh-cn/docs3-v2/java-sdk/faq/1/28/ -- /zh-cn/overview/mannual/java-sdk/faq/1/28/ +- /en/docs3-v2/java-sdk/faq/1/28/ +- /en/docs3-v2/java-sdk/faq/1/28/ +- /en/overview/mannual/java-sdk/faq/1/28/ description: 1-28 - xDS 存根错误 linkTitle: 1-28 - xDS 存根错误 title: 1-28 - xDS 存根错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/29.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/29.md index 802658d09e25..7d4c9577cd32 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/29.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/29.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/29/ -- /zh-cn/docs3-v2/java-sdk/faq/1/29/ -- /zh-cn/overview/mannual/java-sdk/faq/1/29/ +- /en/docs3-v2/java-sdk/faq/1/29/ +- /en/docs3-v2/java-sdk/faq/1/29/ +- /en/overview/mannual/java-sdk/faq/1/29/ description: 1-29 - xDS 读取文件失败 linkTitle: 1-29 - xDS 读取文件失败 title: 1-29 - xDS 读取文件失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/3.md index 05d05db1d85b..fc5e81417ddd 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/3.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/3.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/3/ -- /zh-cn/docs3-v2/java-sdk/faq/1/3/ -- /zh-cn/overview/mannual/java-sdk/faq/1/3/ +- /en/docs3-v2/java-sdk/faq/1/3/ +- /en/docs3-v2/java-sdk/faq/1/3/ +- /en/overview/mannual/java-sdk/faq/1/3/ description: 1-3 - URL 销毁失败 linkTitle: 1-3 - URL 销毁失败 title: 1-3 - URL 销毁失败 @@ -20,4 +20,4 @@ weight: 3 ### 排查和解决步骤 -> 另请参阅 [配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) +> 另请参阅 [配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/30.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/30.md index c2e83cc52d07..8ec25afb264a 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/30.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/30.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/30/ -- /zh-cn/docs3-v2/java-sdk/faq/1/30/ -- /zh-cn/overview/mannual/java-sdk/faq/1/30/ +- /en/docs3-v2/java-sdk/faq/1/30/ +- /en/docs3-v2/java-sdk/faq/1/30/ +- /en/overview/mannual/java-sdk/faq/1/30/ description: 1-30 - xDS 请求失败 linkTitle: 1-30 - xDS 请求失败 title: 1-30 - xDS 请求失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/31.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/31.md index 59cd265f6ae2..32098733c6aa 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/31.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/31.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/31/ -- /zh-cn/docs3-v2/java-sdk/faq/1/31/ -- /zh-cn/overview/mannual/java-sdk/faq/1/31/ +- /en/docs3-v2/java-sdk/faq/1/31/ +- /en/docs3-v2/java-sdk/faq/1/31/ +- /en/overview/mannual/java-sdk/faq/1/31/ description: 1-31 - xDS 响应失败 linkTitle: 1-31 - xDS 响应失败 title: 1-31 - xDS 响应失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/32.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/32.md index 0c2ab9d7cb20..60319c1f549f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/32.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/32.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/32/ -- /zh-cn/docs3-v2/java-sdk/faq/1/32/ -- /zh-cn/overview/mannual/java-sdk/faq/1/32/ +- /en/docs3-v2/java-sdk/faq/1/32/ +- /en/docs3-v2/java-sdk/faq/1/32/ +- /en/overview/mannual/java-sdk/faq/1/32/ description: 1-32 - xDS Channel 初始化失败 linkTitle: 1-32 - xDS Channel 初始化失败 title: 1-32 - xDS Channel 初始化失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/33.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/33.md index 06ee64f207fc..6d649f5a931a 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/33.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/33.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/33/ -- /zh-cn/docs3-v2/java-sdk/faq/1/33/ -- /zh-cn/overview/mannual/java-sdk/faq/1/33/ +- /en/docs3-v2/java-sdk/faq/1/33/ +- /en/docs3-v2/java-sdk/faq/1/33/ +- /en/overview/mannual/java-sdk/faq/1/33/ description: 1-33 - xDS 服务发现初始化失败 linkTitle: 1-33 - xDS 服务发现初始化失败 title: 1-33 - xDS 服务发现初始化失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/34.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/34.md index 12a92898a06a..825c11193061 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/34.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/34.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/34/ -- /zh-cn/docs3-v2/java-sdk/faq/1/34/ -- /zh-cn/overview/mannual/java-sdk/faq/1/34/ +- /en/docs3-v2/java-sdk/faq/1/34/ +- /en/docs3-v2/java-sdk/faq/1/34/ +- /en/overview/mannual/java-sdk/faq/1/34/ description: 1-34 - xDS 解析发生错误 linkTitle: 1-34 - xDS 解析发生错误 title: 1-34 - xDS 解析发生错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/35.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/35.md index b44713ebfc1d..c7cd054d6841 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/35.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/35.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/35/ -- /zh-cn/docs3-v2/java-sdk/faq/1/35/ -- /zh-cn/overview/mannual/java-sdk/faq/1/35/ +- /en/docs3-v2/java-sdk/faq/1/35/ +- /en/docs3-v2/java-sdk/faq/1/35/ +- /en/overview/mannual/java-sdk/faq/1/35/ description: 1-35 - ZK 异常 linkTitle: 1-35 - ZK 异常 title: 1-35 - ZK 异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/36.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/36.md index e6c865194246..c22cd5779dfa 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/36.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/36.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/36/ -- /zh-cn/docs3-v2/java-sdk/faq/1/36/ -- /zh-cn/overview/mannual/java-sdk/faq/1/36/ +- /en/docs3-v2/java-sdk/faq/1/36/ +- /en/docs3-v2/java-sdk/faq/1/36/ +- /en/overview/mannual/java-sdk/faq/1/36/ description: 1-36 - 未知异常 linkTitle: 1-36 - 未知异常 title: 1-36 - 未知异常 @@ -16,7 +16,7 @@ weight: 36 ### 可能的原因 -该错误码的意义已经调整。对于 Dubbo 3.1.4、3.2.0-beta.3 及其之前的版本的该错误码的出错,请参考错误码 [99-0](/zh-cn/overview/mannual/java-sdk/faq/99/0/)。 +该错误码的意义已经调整。对于 Dubbo 3.1.4、3.2.0-beta.3 及其之前的版本的该错误码的出错,请参考错误码 [99-0](/en/overview/mannual/java-sdk/faq/99/0/)。 ### 排查和解决步骤 (该错误码目前空缺) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/37.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/37.md index 7251ac02312e..c63975ba952b 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/37.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/37.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/37/ -- /zh-cn/docs3-v2/java-sdk/faq/1/37/ -- /zh-cn/overview/mannual/java-sdk/faq/1/37/ +- /en/docs3-v2/java-sdk/faq/1/37/ +- /en/docs3-v2/java-sdk/faq/1/37/ +- /en/overview/mannual/java-sdk/faq/1/37/ description: 1-37 - Nacos 异常 linkTitle: 1-37 - Nacos 异常 title: 1-37 - Nacos 异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/38.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/38.md index 39140dc17469..449747f83625 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/38.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/38.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/38/ -- /zh-cn/docs3-v2/java-sdk/faq/1/38/ -- /zh-cn/overview/mannual/java-sdk/faq/1/38/ +- /en/docs3-v2/java-sdk/faq/1/38/ +- /en/docs3-v2/java-sdk/faq/1/38/ +- /en/overview/mannual/java-sdk/faq/1/38/ description: 1-38 - Socket 连接异常 linkTitle: 1-38 - Socket 连接异常 title: 1-38 - Socket 连接异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/39.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/39.md index ec4c03a808e4..139af6a10ecf 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/39.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/39.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/39/ -- /zh-cn/docs3-v2/java-sdk/faq/1/39/ -- /zh-cn/overview/mannual/java-sdk/faq/1/39/ +- /en/docs3-v2/java-sdk/faq/1/39/ +- /en/docs3-v2/java-sdk/faq/1/39/ +- /en/overview/mannual/java-sdk/faq/1/39/ description: 1-39 - 获取元数据失败 linkTitle: 1-39 - 获取元数据失败 title: 1-39 - 获取元数据失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/4.md index 7ff6c3c87f59..a05013d6910c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/4.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/4.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/4/ -- /zh-cn/docs3-v2/java-sdk/faq/1/4/ -- /zh-cn/overview/mannual/java-sdk/faq/1/4/ +- /en/docs3-v2/java-sdk/faq/1/4/ +- /en/docs3-v2/java-sdk/faq/1/4/ +- /en/overview/mannual/java-sdk/faq/1/4/ description: 1-4 - 空地址 linkTitle: 1-4 - 空地址 title: 1-4 - 空地址 @@ -25,4 +25,4 @@ weight: 4 3. 检查注册中心的`enable-empty-protection`是否为true(默认为true)。 > 另请参阅 -[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) +[配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/40.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/40.md index 8616825fdfc4..13ac16b92926 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/40.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/40.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/40/ -- /zh-cn/docs3-v2/java-sdk/faq/1/40/ -- /zh-cn/overview/mannual/java-sdk/faq/1/40/ +- /en/docs3-v2/java-sdk/faq/1/40/ +- /en/docs3-v2/java-sdk/faq/1/40/ +- /en/overview/mannual/java-sdk/faq/1/40/ description: 1-40 - 路由等待时间过长 linkTitle: 1-40 - 路由等待时间过长 title: 1-40 - 路由等待时间过长 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/41.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/41.md index 70ed5ce565e5..f71319279d34 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/41.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/41.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/41/ -- /zh-cn/docs3-v2/java-sdk/faq/1/41/ -- /zh-cn/overview/mannual/java-sdk/faq/1/41/ +- /en/docs3-v2/java-sdk/faq/1/41/ +- /en/docs3-v2/java-sdk/faq/1/41/ +- /en/overview/mannual/java-sdk/faq/1/41/ description: 1-41 - Istio 异常 linkTitle: 1-41 - Istio 异常 title: 1-41 - Istio 异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/42.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/42.md index 0ae6ae4e1c65..1369af61bf2d 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/42.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/42.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/42/ -- /zh-cn/docs3-v2/java-sdk/faq/1/42/ -- /zh-cn/overview/mannual/java-sdk/faq/1/42/ +- /en/docs3-v2/java-sdk/faq/1/42/ +- /en/docs3-v2/java-sdk/faq/1/42/ +- /en/overview/mannual/java-sdk/faq/1/42/ description: 1-42 - Nacos 存在低版本服务 linkTitle: 1-42 - Nacos 存在低版本服务 title: 1-42 - Nacos 存在低版本服务 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/5.md index 0856e38ede3e..d810f99b5c2f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/5.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/5.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/5/ -- /zh-cn/docs3-v2/java-sdk/faq/1/5/ -- /zh-cn/overview/mannual/java-sdk/faq/1/5/ +- /en/docs3-v2/java-sdk/faq/1/5/ +- /en/docs3-v2/java-sdk/faq/1/5/ +- /en/overview/mannual/java-sdk/faq/1/5/ description: 1-5 - 接收到没有任何参数的 URL linkTitle: 1-5 - 接收到没有任何参数的 URL title: 1-5 - 接收到没有任何参数的 URL diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/6.md index c958f75f0418..2e80552b4b98 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/6.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/6.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/6/ -- /zh-cn/docs3-v2/java-sdk/faq/1/6/ -- /zh-cn/overview/mannual/java-sdk/faq/1/6/ +- /en/docs3-v2/java-sdk/faq/1/6/ +- /en/docs3-v2/java-sdk/faq/1/6/ +- /en/overview/mannual/java-sdk/faq/1/6/ description: 1-6 - 清空URL缓存出错 linkTitle: 1-6 - 清空URL缓存出错 title: 1-6 - 清空URL缓存出错 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/7.md index 03355ae06d72..0544bc7b4083 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/7.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/7.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/7/ -- /zh-cn/docs3-v2/java-sdk/faq/1/7/ -- /zh-cn/overview/mannual/java-sdk/faq/1/7/ +- /en/docs3-v2/java-sdk/faq/1/7/ +- /en/docs3-v2/java-sdk/faq/1/7/ +- /en/overview/mannual/java-sdk/faq/1/7/ description: 1-7 - 通知注册事件失败 linkTitle: 1-7 - 读写注册中心服务缓存失败 title: 1-7 - 通知注册事件失败 @@ -22,4 +22,4 @@ weight: 7 ### 排查和解决步骤 > 另请参阅 -[注册中心-配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#registry) +[注册中心-配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/#registry) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/8.md index cfc916611eab..bd38bae0dc13 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/8.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/8.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/8/ -- /zh-cn/docs3-v2/java-sdk/faq/1/8/ -- /zh-cn/overview/mannual/java-sdk/faq/1/8/ +- /en/docs3-v2/java-sdk/faq/1/8/ +- /en/docs3-v2/java-sdk/faq/1/8/ +- /en/overview/mannual/java-sdk/faq/1/8/ description: 1-8 - 销毁时注销(取消订阅)地址失败 linkTitle: 1-8 - 销毁时注销(取消订阅)地址失败 title: 1-8 - 销毁时注销(取消订阅)地址失败 @@ -25,4 +25,4 @@ weight: 8 3. 排查 provider 的注册中心相关参数比如 `registry` `config-center` `metadata-report`是否配置正确。 > 另请参阅 -[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) +[配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/9.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/9.md index 8fbeab0ac0e0..1e1bd881bd1d 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/9.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/9.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/9/ -- /zh-cn/docs3-v2/java-sdk/faq/1/9/ -- /zh-cn/overview/mannual/java-sdk/faq/1/9/ +- /en/docs3-v2/java-sdk/faq/1/9/ +- /en/docs3-v2/java-sdk/faq/1/9/ +- /en/overview/mannual/java-sdk/faq/1/9/ description: 1-9 - 读写注册中心服务缓存失败 linkTitle: 1-9 - 读写注册中心服务缓存失败 title: 1-9 - 读写注册中心服务缓存失败 @@ -32,4 +32,4 @@ weight: 9 4. 排查是否出现了“两个注册中心使用了同一文件存储” 这一情况,如果出现则调整。 > 另请参阅 -[注册中心的配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#registry) +[注册中心的配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/#registry) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/_index.md index 9dd655306eb2..418a12e8f135 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/1/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/1/_index.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/1/ -- /zh-cn/docs3-v2/java-sdk/faq/1/ -- /zh-cn/overview/mannual/java-sdk/faq/1/_index/ +- /en/docs3-v2/java-sdk/faq/1/ +- /en/docs3-v2/java-sdk/faq/1/ +- /en/overview/mannual/java-sdk/faq/1/_index/ description: 1 - 注册中心层 linkTitle: 1 - 注册中心层 title: 1 - 注册中心层 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/1.md index 1b9d9fcdaa66..5c4d5b4b32da 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/1.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/1.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/1/ -- /zh-cn/docs3-v2/java-sdk/faq/2/1/ -- /zh-cn/overview/mannual/java-sdk/faq/2/1/ +- /en/docs3-v2/java-sdk/faq/2/1/ +- /en/docs3-v2/java-sdk/faq/2/1/ +- /en/overview/mannual/java-sdk/faq/2/1/ description: 2-1 - 路由选址执行失败 linkTitle: 2-1 - 路由选址执行失败 title: 2-1 - 路由选址执行失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/10.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/10.md index 3c62a2dee2d0..f12f5dd104a9 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/10.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/10.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/10/ -- /zh-cn/docs3-v2/java-sdk/faq/2/10/ -- /zh-cn/overview/mannual/java-sdk/faq/2/10/ +- /en/docs3-v2/java-sdk/faq/2/10/ +- /en/docs3-v2/java-sdk/faq/2/10/ +- /en/overview/mannual/java-sdk/faq/2/10/ description: 2-10 - 调用服务提供方失败 linkTitle: 2-10 - 调用服务提供方失败 title: 2-10 - 调用服务提供方失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/11.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/11.md index 251d5ea348b0..f2123e3574b9 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/11.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/11.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/11/ -- /zh-cn/docs3-v2/java-sdk/faq/2/11/ -- /zh-cn/overview/mannual/java-sdk/faq/2/11/ +- /en/docs3-v2/java-sdk/faq/2/11/ +- /en/docs3-v2/java-sdk/faq/2/11/ +- /en/overview/mannual/java-sdk/faq/2/11/ description: 2-11 - 标签路由规则不合法 linkTitle: 2-11 - 标签路由规则不合法 title: 2-11 - 标签路由规则不合法 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/12.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/12.md index 094d23481627..9735c5b2d47f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/12.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/12.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/12/ -- /zh-cn/docs3-v2/java-sdk/faq/2/12/ -- /zh-cn/overview/mannual/java-sdk/faq/2/12/ +- /en/docs3-v2/java-sdk/faq/2/12/ +- /en/docs3-v2/java-sdk/faq/2/12/ +- /en/overview/mannual/java-sdk/faq/2/12/ description: 2-12 - 标签路由获取提供方应用名为空 linkTitle: 2-12 - 标签路由获取提供方应用名为空 title: 2-12 - 标签路由获取提供方应用名为空 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/13.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/13.md index 874df2431a5c..df6488fe6af0 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/13.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/13.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/13/ -- /zh-cn/docs3-v2/java-sdk/faq/2/13/ -- /zh-cn/overview/mannual/java-sdk/faq/2/13/ +- /en/docs3-v2/java-sdk/faq/2/13/ +- /en/docs3-v2/java-sdk/faq/2/13/ +- /en/overview/mannual/java-sdk/faq/2/13/ description: 2-13 - 接收加载mesh的路由规则失败 linkTitle: 2-13 - 接收加载mesh的路由规则失败 title: 2-13 - 接收加载mesh的路由规则失败 @@ -20,4 +20,4 @@ weight: 13 * mesh 路由配置的规则不合法,加载异常。 ### 排查和解决步骤 -> 检查 mesh 路由规则配置。[mesh示例](/zh-cn/overview/tasks/mesh/)。 +> 检查 mesh 路由规则配置。[mesh示例](/en/overview/tasks/mesh/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/14.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/14.md index 8f248c5424cf..1797992b2c00 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/14.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/14.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/14/ -- /zh-cn/docs3-v2/java-sdk/faq/2/14/ -- /zh-cn/overview/mannual/java-sdk/faq/2/14/ +- /en/docs3-v2/java-sdk/faq/2/14/ +- /en/docs3-v2/java-sdk/faq/2/14/ +- /en/overview/mannual/java-sdk/faq/2/14/ description: 2-14 - 脚本路由执行失败 linkTitle: 2-14 - 脚本路由执行失败 title: 2-14 - 脚本路由执行失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/15.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/15.md index 1c23e9f5bbc4..9b84dc2e3bcb 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/15.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/15.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/15/ -- /zh-cn/docs3-v2/java-sdk/faq/2/15/ -- /zh-cn/overview/mannual/java-sdk/faq/2/15/ +- /en/docs3-v2/java-sdk/faq/2/15/ +- /en/docs3-v2/java-sdk/faq/2/15/ +- /en/overview/mannual/java-sdk/faq/2/15/ description: 2-15 - 路由规则解析失败 linkTitle: 2-15 - 路由规则解析失败 title: 2-15 - 路由规则解析失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/16.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/16.md index 803c1281e95b..d4c04158b65f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/16.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/16.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/16/ -- /zh-cn/docs3-v2/java-sdk/faq/2/16/ -- /zh-cn/overview/mannual/java-sdk/faq/2/16/ +- /en/docs3-v2/java-sdk/faq/2/16/ +- /en/docs3-v2/java-sdk/faq/2/16/ +- /en/overview/mannual/java-sdk/faq/2/16/ description: 2-16 - 请求重试多次失败 linkTitle: 2-16 - 请求重试多次失败 title: 2-16 - 请求重试多次失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/17.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/17.md index 70117de72fdc..aa6cca834047 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/17.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/17.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/17/ -- /zh-cn/docs3-v2/java-sdk/faq/2/17/ -- /zh-cn/overview/mannual/java-sdk/faq/2/17/ +- /en/docs3-v2/java-sdk/faq/2/17/ +- /en/docs3-v2/java-sdk/faq/2/17/ +- /en/overview/mannual/java-sdk/faq/2/17/ description: 2-17 - mock请求失败 linkTitle: 2-17 - mock请求失败 title: 2-17 - mock请求失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/18.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/18.md index 9a308e1d626b..e4bb3ff14729 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/18.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/18.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/18/ -- /zh-cn/docs3-v2/java-sdk/faq/2/18/ -- /zh-cn/overview/mannual/java-sdk/faq/2/18/ +- /en/docs3-v2/java-sdk/faq/2/18/ +- /en/docs3-v2/java-sdk/faq/2/18/ +- /en/overview/mannual/java-sdk/faq/2/18/ description: 2-18 - mesh路由规则未被监听 linkTitle: 2-18 - mesh路由规则未被监听 title: 2-18 - mesh路由规则未被监听 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/19.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/19.md index 0e87796e5f84..c21941ea9e7a 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/19.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/19.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/19/ -- /zh-cn/docs3-v2/java-sdk/faq/2/19/ -- /zh-cn/overview/mannual/java-sdk/faq/2/19/ +- /en/docs3-v2/java-sdk/faq/2/19/ +- /en/docs3-v2/java-sdk/faq/2/19/ +- /en/overview/mannual/java-sdk/faq/2/19/ description: 2-19 - 异步请求失败 linkTitle: 2-19 - 异步请求失败 title: 2-19 - 异步请求失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/2.md index 5f105ca07c43..8d5e527f0822 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/2.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/2.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/2/ -- /zh-cn/docs3-v2/java-sdk/faq/2/2/ -- /zh-cn/overview/mannual/java-sdk/faq/2/2/ +- /en/docs3-v2/java-sdk/faq/2/2/ +- /en/docs3-v2/java-sdk/faq/2/2/ +- /en/overview/mannual/java-sdk/faq/2/2/ description: 2-2 - 没有可用的 Provider(地址找不到) linkTitle: 2-2 - 没有可用的 Provider(地址找不到) title: 2-2 - 没有可用的 Provider(地址找不到) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/20.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/20.md index 473387bdb455..af24b64836b1 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/20.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/20.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/20/ -- /zh-cn/docs3-v2/java-sdk/faq/2/20/ -- /zh-cn/overview/mannual/java-sdk/faq/2/20/ +- /en/docs3-v2/java-sdk/faq/2/20/ +- /en/docs3-v2/java-sdk/faq/2/20/ +- /en/overview/mannual/java-sdk/faq/2/20/ description: 2-20 - 获取分组结果合并时失败 linkTitle: 2-20 - 获取分组结果合并时失败 title: 2-20 - 获取分组结果合并时失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/3.md index a4c092c54a1c..1a9ab4a27253 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/3.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/3.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/3/ -- /zh-cn/docs3-v2/java-sdk/faq/2/3/ -- /zh-cn/overview/mannual/java-sdk/faq/2/3/ +- /en/docs3-v2/java-sdk/faq/2/3/ +- /en/docs3-v2/java-sdk/faq/2/3/ +- /en/overview/mannual/java-sdk/faq/2/3/ description: 2-3 - 路由关闭失败 linkTitle: 2-3 - 路由关闭失败 title: 2-3 - 路由关闭失败 @@ -20,4 +20,4 @@ weight: 3 * 用户自定义路由未按规范编写。 ### 排查和解决步骤 -> 参照社区SPI扩展使用手册,检查用户自定义路由 [《SPI 扩展使用手册》](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/)。 +> 参照社区SPI扩展使用手册,检查用户自定义路由 [《SPI 扩展使用手册》](/en/overview/mannual/java-sdk/reference-manual/spi/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/4.md index 06678cdfa875..784f6d578ad0 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/4.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/4.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/4/ -- /zh-cn/docs3-v2/java-sdk/faq/2/4/ -- /zh-cn/overview/mannual/java-sdk/faq/2/4/ +- /en/docs3-v2/java-sdk/faq/2/4/ +- /en/docs3-v2/java-sdk/faq/2/4/ +- /en/overview/mannual/java-sdk/faq/2/4/ description: 2-4 - Merger接口加载失败 linkTitle: 2-4 - Merger接口加载失败 title: 2-4 - Merger接口加载失败 @@ -20,4 +20,4 @@ weight: 4 * Dubbo 提供了聚合下游所有提供方响应的 SPI 扩展 Merger 接口,Dubbo 在加载用户在自定义扩展 Merger 接口时,加载配置失败。 ### 排查和解决步骤 -> 参照社区 SPI 扩展使用手册,检查用户自定义扩展 Merger 接口实现 [《SPI 扩展使用手册》](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/)。 +> 参照社区 SPI 扩展使用手册,检查用户自定义扩展 Merger 接口实现 [《SPI 扩展使用手册》](/en/overview/mannual/java-sdk/reference-manual/spi/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/5.md index c26e667df976..b7ee22af4c8f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/5.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/5.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/5/ -- /zh-cn/docs3-v2/java-sdk/faq/2/5/ -- /zh-cn/overview/mannual/java-sdk/faq/2/5/ +- /en/docs3-v2/java-sdk/faq/2/5/ +- /en/docs3-v2/java-sdk/faq/2/5/ +- /en/overview/mannual/java-sdk/faq/2/5/ description: 2-5 - 筛选提供方失败 linkTitle: 2-5 - 筛选提供方失败 title: 2-5 - 筛选提供方失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/6.md index f48e4b4122c9..733482d68f62 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/6.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/6.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/6/ -- /zh-cn/docs3-v2/java-sdk/faq/2/6/ -- /zh-cn/overview/mannual/java-sdk/faq/2/6/ +- /en/docs3-v2/java-sdk/faq/2/6/ +- /en/docs3-v2/java-sdk/faq/2/6/ +- /en/overview/mannual/java-sdk/faq/2/6/ description: 2-6 - 条件路由筛选提供方列表为空 linkTitle: 2-6 - 条件路由筛选提供方列表为空 title: 2-6 - 条件路由筛选提供方列表为空 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/7.md index 84d576f3e2e8..c99855ce1209 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/7.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/7.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/7/ -- /zh-cn/docs3-v2/java-sdk/faq/2/7/ -- /zh-cn/overview/mannual/java-sdk/faq/2/7/ +- /en/docs3-v2/java-sdk/faq/2/7/ +- /en/docs3-v2/java-sdk/faq/2/7/ +- /en/overview/mannual/java-sdk/faq/2/7/ description: 2-7 - 条件路由执行异常 linkTitle: 2-7 - 条件路由执行异常 title: 2-7 - 条件路由执行异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/8.md index 1d3b1bb140a9..3591f8c6f781 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/8.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/8.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/8/ -- /zh-cn/docs3-v2/java-sdk/faq/2/8/ -- /zh-cn/overview/mannual/java-sdk/faq/2/8/ +- /en/docs3-v2/java-sdk/faq/2/8/ +- /en/docs3-v2/java-sdk/faq/2/8/ +- /en/overview/mannual/java-sdk/faq/2/8/ description: 2-8 - 提供方返回异常响应 linkTitle: 2-8 - 提供方返回异常响应 title: 2-8 - 提供方返回异常响应 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/9.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/9.md index 91b910b44f39..2a2fe89afcbe 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/9.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/9.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/9/ -- /zh-cn/docs3-v2/java-sdk/faq/2/9/ -- /zh-cn/overview/mannual/java-sdk/faq/2/9/ +- /en/docs3-v2/java-sdk/faq/2/9/ +- /en/docs3-v2/java-sdk/faq/2/9/ +- /en/overview/mannual/java-sdk/faq/2/9/ description: 2-9 - 增加超时检查任务失败 linkTitle: 2-9 - 增加超时检查任务失败 title: 2-9 - 增加超时检查任务失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/_index.md index a5266b171a98..138cd89c8819 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/2/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/2/_index.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/2/ -- /zh-cn/docs3-v2/java-sdk/faq/2/ -- /zh-cn/overview/mannual/java-sdk/faq/2/_index/ +- /en/docs3-v2/java-sdk/faq/2/ +- /en/docs3-v2/java-sdk/faq/2/ +- /en/overview/mannual/java-sdk/faq/2/_index/ description: 2 - 路由层 linkTitle: 2 - 路由层 title: 2 - 路由层 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/1.md index f9b7a9e56537..e6204c8e19ac 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/1.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/1.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/3/1/ -- /zh-cn/docs3-v2/java-sdk/faq/3/1/ -- /zh-cn/overview/mannual/java-sdk/faq/3/1/ +- /en/docs3-v2/java-sdk/faq/3/1/ +- /en/docs3-v2/java-sdk/faq/3/1/ +- /en/overview/mannual/java-sdk/faq/3/1/ description: 3-1 - 将地址转换成 Invoker 失败 linkTitle: 3-1 - 将地址转换成 Invoker 失败 title: 3-1 - 将地址转换成 Invoker 失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/2.md index dfff87e88304..f6b52b9608b0 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/2.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/2.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/3/2/ -- /zh-cn/docs3-v2/java-sdk/faq/3/2/ -- /zh-cn/overview/mannual/java-sdk/faq/3/2/ +- /en/docs3-v2/java-sdk/faq/3/2/ +- /en/docs3-v2/java-sdk/faq/3/2/ +- /en/overview/mannual/java-sdk/faq/3/2/ description: 3-2 - 发布或推送服务失败 linkTitle: 3-2 - 发布或推送服务失败 title: 3-2 - 发布或推送服务失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/3.md index 37d9e7ed482b..f05cfc5121b7 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/3.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/3.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/3/3/ -- /zh-cn/docs3-v2/java-sdk/faq/3/3/ -- /zh-cn/overview/mannual/java-sdk/faq/3/3/ +- /en/docs3-v2/java-sdk/faq/3/3/ +- /en/docs3-v2/java-sdk/faq/3/3/ +- /en/overview/mannual/java-sdk/faq/3/3/ description: 3-3 - 通过Javassist生成字节码失败 linkTitle: 3-3 - 通过Javassist生成字节码失败 title: 3-3 - 通过Javassist生成字节码失败 @@ -16,7 +16,7 @@ weight: 3 ### 可能的原因 -该错误码的意义已经调整。对于 Dubbo 3.1.4、3.2.0-beta.3 及其之前的版本的该错误码的出错,请参考错误码 [3-8](/zh-cn/overview/mannual/java-sdk/faq/3/8/)。 +该错误码的意义已经调整。对于 Dubbo 3.1.4、3.2.0-beta.3 及其之前的版本的该错误码的出错,请参考错误码 [3-8](/en/overview/mannual/java-sdk/faq/3/8/)。 ### 排查和解决步骤 (该错误码目前空缺) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/4.md index 2f21d8c4ad12..b7239873450d 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/4.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/4.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/3/4/ -- /zh-cn/docs3-v2/java-sdk/faq/3/4/ -- /zh-cn/overview/mannual/java-sdk/faq/3/4/ +- /en/docs3-v2/java-sdk/faq/3/4/ +- /en/docs3-v2/java-sdk/faq/3/4/ +- /en/overview/mannual/java-sdk/faq/3/4/ description: 3-4 - 客户端发送请求超时 linkTitle: 3-4 - 客户端发送请求超时 title: 3-4 - 客户端发送请求超时 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/5.md index 52a566957684..ef788a89aac4 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/5.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/5.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/3/5/ -- /zh-cn/docs3-v2/java-sdk/faq/3/5/ -- /zh-cn/overview/mannual/java-sdk/faq/3/5/ +- /en/docs3-v2/java-sdk/faq/3/5/ +- /en/docs3-v2/java-sdk/faq/3/5/ +- /en/overview/mannual/java-sdk/faq/3/5/ description: 3-5 - 异步响应出现异常 linkTitle: 3-5 - 异步响应出现异常 title: 3-5 - 异步响应出现异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/6.md index d1f8acf060b1..b599f40bc4eb 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/6.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/6.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/3/6/ -- /zh-cn/docs3-v2/java-sdk/faq/3/6/ -- /zh-cn/overview/mannual/java-sdk/faq/3/6/ +- /en/docs3-v2/java-sdk/faq/3/6/ +- /en/docs3-v2/java-sdk/faq/3/6/ +- /en/overview/mannual/java-sdk/faq/3/6/ description: 3-6 - 代理执行服务发生异常 linkTitle: 3-6 - 代理执行服务发生异常 title: 3-6 - 代理执行服务发生异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/7.md index 92a96644c68e..8acbc0e51a3c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/7.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/7.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/3/7/ -- /zh-cn/docs3-v2/java-sdk/faq/3/7/ -- /zh-cn/overview/mannual/java-sdk/faq/3/7/ +- /en/docs3-v2/java-sdk/faq/3/7/ +- /en/docs3-v2/java-sdk/faq/3/7/ +- /en/overview/mannual/java-sdk/faq/3/7/ description: 3-7 - 服务端响应结果超时 linkTitle: 3-7 - 服务端响应结果超时 title: 3-7 - 服务端响应结果超时 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/8.md index 7a6a6980fc8b..493a4c810a91 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/8.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/8.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/3/8/ -- /zh-cn/docs3-v2/java-sdk/faq/3/8/ -- /zh-cn/overview/mannual/java-sdk/faq/3/8/ +- /en/docs3-v2/java-sdk/faq/3/8/ +- /en/docs3-v2/java-sdk/faq/3/8/ +- /en/overview/mannual/java-sdk/faq/3/8/ description: 3-8 - 代理失败 linkTitle: 3-8 - 代理失败 title: 3-8 - 代理失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/_index.md index 80fec2c10bf4..1eb304d73d97 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/3/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/3/_index.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/3/ -- /zh-cn/docs3-v2/java-sdk/faq/3/ -- /zh-cn/overview/mannual/java-sdk/faq/3/_index/ +- /en/docs3-v2/java-sdk/faq/3/ +- /en/docs3-v2/java-sdk/faq/3/ +- /en/overview/mannual/java-sdk/faq/3/_index/ description: 3 - 动态代理层 linkTitle: 3 - 动态代理层 title: 3 - 动态代理层 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/1.md index 98f5bdcc6d75..a1dd8700d29c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/1.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/1.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/1/ -- /zh-cn/docs3-v2/java-sdk/faq/4/1/ -- /zh-cn/overview/mannual/java-sdk/faq/4/1/ +- /en/docs3-v2/java-sdk/faq/4/1/ +- /en/docs3-v2/java-sdk/faq/4/1/ +- /en/overview/mannual/java-sdk/faq/4/1/ description: 4-1 - 不支持的协议 linkTitle: 4-1 - 不支持的协议 title: 4-1 - 不支持的协议 @@ -24,5 +24,5 @@ weight: 1 2. 确定 Protocol 的依赖包的 SPI 配置文件的名字没有写错。 > 另请参阅 -[Dubbo SPI 概述](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/overview/) -[协议扩展说明](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/protocol/) +[Dubbo SPI 概述](/en/overview/mannual/java-sdk/reference-manual/spi/overview/) +[协议扩展说明](/en/overview/mannual/java-sdk/reference-manual/spi/description/protocol/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/10.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/10.md index dc740749ab94..2f0356f652be 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/10.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/10.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/10/ -- /zh-cn/docs3-v2/java-sdk/faq/4/10/ -- /zh-cn/overview/mannual/java-sdk/faq/4/10/ +- /en/docs3-v2/java-sdk/faq/4/10/ +- /en/docs3-v2/java-sdk/faq/4/10/ +- /en/overview/mannual/java-sdk/faq/4/10/ description: 4-10 - Triple 序列化结果失败 linkTitle: 4-10 - Triple 序列化结果失败 title: 4-10 - Triple 序列化结果失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/11.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/11.md index 37704d641f78..ce64e779f3e1 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/11.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/11.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/11/ -- /zh-cn/docs3-v2/java-sdk/faq/4/11/ -- /zh-cn/overview/mannual/java-sdk/faq/4/11/ +- /en/docs3-v2/java-sdk/faq/4/11/ +- /en/docs3-v2/java-sdk/faq/4/11/ +- /en/overview/mannual/java-sdk/faq/4/11/ description: 4-11 - 发起请求失败 linkTitle: 4-11 - 发起请求失败 title: 4-11 - 发起请求失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/12.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/12.md index 5eff33dc1d4c..14836f095370 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/12.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/12.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/12/ -- /zh-cn/docs3-v2/java-sdk/faq/4/12/ -- /zh-cn/overview/mannual/java-sdk/faq/4/12/ +- /en/docs3-v2/java-sdk/faq/4/12/ +- /en/docs3-v2/java-sdk/faq/4/12/ +- /en/overview/mannual/java-sdk/faq/4/12/ description: 4-12 - 创建Triple流失败 linkTitle: 4-12 - 创建Triple流失败 title: 4-12 - 创建Triple流失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/13.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/13.md index 864b916ed2dc..6cde85bda93b 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/13.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/13.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/13/ -- /zh-cn/docs3-v2/java-sdk/faq/4/13/ -- /zh-cn/overview/mannual/java-sdk/faq/4/13/ +- /en/docs3-v2/java-sdk/faq/4/13/ +- /en/docs3-v2/java-sdk/faq/4/13/ +- /en/overview/mannual/java-sdk/faq/4/13/ description: 4-13 - 服务端超时 linkTitle: 4-13 - 服务端超时 title: 4-13 - 服务端超时 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/14.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/14.md index cccf9cb31405..af7df4470063 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/14.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/14.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/14/ -- /zh-cn/docs3-v2/java-sdk/faq/4/14/ -- /zh-cn/overview/mannual/java-sdk/faq/4/14/ +- /en/docs3-v2/java-sdk/faq/4/14/ +- /en/docs3-v2/java-sdk/faq/4/14/ +- /en/overview/mannual/java-sdk/faq/4/14/ description: 4-14 - 响应结果失败 linkTitle: 4-14 - 响应结果失败 title: 4-14 - 响应结果失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/15.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/15.md index c41c4bc44f63..7812eb4aab0f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/15.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/15.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/15/ -- /zh-cn/docs3-v2/java-sdk/faq/4/15/ -- /zh-cn/overview/mannual/java-sdk/faq/4/15/ +- /en/docs3-v2/java-sdk/faq/4/15/ +- /en/docs3-v2/java-sdk/faq/4/15/ +- /en/overview/mannual/java-sdk/faq/4/15/ description: 4-15 - 客户端流监听器 linkTitle: 4-15 - 客户端流监听器 title: 4-15 - 客户端流监听器 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/16.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/16.md index 54cffeeac61f..0a7dec630c80 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/16.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/16.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/16/ -- /zh-cn/docs3-v2/java-sdk/faq/4/16/ -- /zh-cn/overview/mannual/java-sdk/faq/4/16/ +- /en/docs3-v2/java-sdk/faq/4/16/ +- /en/docs3-v2/java-sdk/faq/4/16/ +- /en/overview/mannual/java-sdk/faq/4/16/ description: 4-16 - 服务已关闭 linkTitle: 4-16 - 服务已关闭 title: 4-16 - 服务已关闭 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/17.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/17.md index f0add9767594..a2d08c55ba11 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/17.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/17.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/17/ -- /zh-cn/docs3-v2/java-sdk/faq/4/17/ -- /zh-cn/overview/mannual/java-sdk/faq/4/17/ +- /en/docs3-v2/java-sdk/faq/4/17/ +- /en/docs3-v2/java-sdk/faq/4/17/ +- /en/overview/mannual/java-sdk/faq/4/17/ description: 4-17 - 关闭所有调用程序时发生错误 linkTitle: 4-17 - 关闭所有调用程序时发生错误 title: 4-17 - 关闭所有调用程序时发生错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/18.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/18.md index b29fd3250bba..0f9b2a470fc7 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/18.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/18.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/18/ -- /zh-cn/docs3-v2/java-sdk/faq/4/18/ -- /zh-cn/overview/mannual/java-sdk/faq/4/18/ +- /en/docs3-v2/java-sdk/faq/4/18/ +- /en/docs3-v2/java-sdk/faq/4/18/ +- /en/overview/mannual/java-sdk/faq/4/18/ description: 4-18 - 无法从调用中获取服务模型 linkTitle: 4-18 - 无法从调用中获取服务模型 title: 4-18 - 无法从调用中获取服务模型 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/19.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/19.md index a474cc14ab7f..7ac043aebf0d 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/19.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/19.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/19/ -- /zh-cn/docs3-v2/java-sdk/faq/4/19/ -- /zh-cn/overview/mannual/java-sdk/faq/4/19/ +- /en/docs3-v2/java-sdk/faq/4/19/ +- /en/docs3-v2/java-sdk/faq/4/19/ +- /en/overview/mannual/java-sdk/faq/4/19/ description: 4-19 - 参数值有出错的可能 linkTitle: 4-19 - 参数值有出错的可能 title: 4-19 - 参数值有出错的可能 @@ -23,4 +23,4 @@ weight: 19 ### 排查和解决步骤 调整协议和端口的监听关系。 -> 该错误码的意义已经调整。对于 Dubbo 3.1.4、3.2.0-beta.3 及其之前的版本的该错误码的出错,请参考错误码 [0-2](/zh-cn/overview/mannual/java-sdk/faq/0/2/)。 +> 该错误码的意义已经调整。对于 Dubbo 3.1.4、3.2.0-beta.3 及其之前的版本的该错误码的出错,请参考错误码 [0-2](/en/overview/mannual/java-sdk/faq/0/2/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/2.md index 97c6fdf4fbb2..0f14a6a2a0c8 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/2.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/2.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/2/ -- /zh-cn/docs3-v2/java-sdk/faq/4/2/ -- /zh-cn/overview/mannual/java-sdk/faq/4/2/ +- /en/docs3-v2/java-sdk/faq/4/2/ +- /en/docs3-v2/java-sdk/faq/4/2/ +- /en/overview/mannual/java-sdk/faq/4/2/ description: 4-2 - 序列化优化器初始发生错误 linkTitle: 4-2 - 序列化优化器初始发生错误 title: 4-2 - 序列化优化器初始发生错误 @@ -21,4 +21,4 @@ weight: 2 ### 排查和解决步骤 -[Kryo 和 FST 序列化](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/serialization/) +[Kryo 和 FST 序列化](/en/overview/mannual/java-sdk/advanced-features-and-usage/performance/serialization/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/20.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/20.md index b51fad776fa7..7398b44b10db 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/20.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/20.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/20/ -- /zh-cn/docs3-v2/java-sdk/faq/4/20/ -- /zh-cn/overview/mannual/java-sdk/faq/4/20/ +- /en/docs3-v2/java-sdk/faq/4/20/ +- /en/docs3-v2/java-sdk/faq/4/20/ +- /en/overview/mannual/java-sdk/faq/4/20/ description: 4-20 - 数据解码失败 linkTitle: 4-20 - 数据解码失败 title: 4-20 - 数据解码失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/21.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/21.md index d765a4654adf..739290f9cb48 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/21.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/21.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/21/ -- /zh-cn/docs3-v2/java-sdk/faq/4/21/ -- /zh-cn/overview/mannual/java-sdk/faq/4/21/ +- /en/docs3-v2/java-sdk/faq/4/21/ +- /en/docs3-v2/java-sdk/faq/4/21/ +- /en/overview/mannual/java-sdk/faq/4/21/ description: 4-21 - 检测到不安全的序列化数据 linkTitle: 4-21 - 检测到不安全的序列化数据 title: 4-21 - 检测到不安全的序列化数据 @@ -22,7 +22,7 @@ weight: 21 ### 排查和解决步骤 1. 如果请求源是攻击源,请及时进行安全加固。 -2. 如果请求源是预期的,请在 `security/serialize.allowlist` 资源文件中声明您所使用的类名,Dubbo 将自动将其加载到安全列表中。请参考 [类检查机制](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/) 一文。 +2. 如果请求源是预期的,请在 `security/serialize.allowlist` 资源文件中声明您所使用的类名,Dubbo 将自动将其加载到安全列表中。请参考 [类检查机制](/en/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/) 一文。 > 当前 Dubbo 可以工作在监控模式和限制模式下。监控模式只打印日志,不进行拦截;限制模型将进行拦截。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/3.md index 6836b47ad2fd..d0f2ec4001f8 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/3.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/3.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/3/ -- /zh-cn/docs3-v2/java-sdk/faq/4/3/ -- /zh-cn/overview/mannual/java-sdk/faq/4/3/ +- /en/docs3-v2/java-sdk/faq/4/3/ +- /en/docs3-v2/java-sdk/faq/4/3/ +- /en/overview/mannual/java-sdk/faq/4/3/ description: 4-3 - 接口引用调用失败 linkTitle: 4-3 - 接口引用调用失败 title: 4-3 - 接口引用调用失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/4.md index 4342b3057e04..78cf045185ee 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/4.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/4.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/4/ -- /zh-cn/docs3-v2/java-sdk/faq/4/4/ -- /zh-cn/overview/mannual/java-sdk/faq/4/4/ +- /en/docs3-v2/java-sdk/faq/4/4/ +- /en/docs3-v2/java-sdk/faq/4/4/ +- /en/overview/mannual/java-sdk/faq/4/4/ description: 4-4 - 非安全序列化方式 linkTitle: 4-4 - 非安全序列化方式 title: 4-4 - 非安全序列化方式 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/5.md index ccf8ef49de8c..5b34cc5951b2 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/5.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/5.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/5/ -- /zh-cn/docs3-v2/java-sdk/faq/4/5/ -- /zh-cn/overview/mannual/java-sdk/faq/4/5/ +- /en/docs3-v2/java-sdk/faq/4/5/ +- /en/docs3-v2/java-sdk/faq/4/5/ +- /en/overview/mannual/java-sdk/faq/4/5/ description: 4-5 - 流关闭异常 linkTitle: 4-5 - 流关闭异常 title: 4-5 - 流关闭异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/6.md index 423246a3566c..d397b04b2df5 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/6.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/6.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/6/ -- /zh-cn/docs3-v2/java-sdk/faq/4/6/ -- /zh-cn/overview/mannual/java-sdk/faq/4/6/ +- /en/docs3-v2/java-sdk/faq/4/6/ +- /en/docs3-v2/java-sdk/faq/4/6/ +- /en/overview/mannual/java-sdk/faq/4/6/ description: 4-6 - 反序列化失败 linkTitle: 4-6 - 反序列化失败 title: 4-6 - 反序列化失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/7.md index a0ce8627b22e..8f5e00cc37f2 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/7.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/7.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/7/ -- /zh-cn/docs3-v2/java-sdk/faq/4/7/ -- /zh-cn/overview/mannual/java-sdk/faq/4/7/ +- /en/docs3-v2/java-sdk/faq/4/7/ +- /en/docs3-v2/java-sdk/faq/4/7/ +- /en/overview/mannual/java-sdk/faq/4/7/ description: 4-7 - 关闭客户端时发生错误 linkTitle: 4-7 - 关闭客户端时发生错误 title: 4-7 - 关闭客户端时发生错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/8.md index 70aa8aafeb22..dde132f35cfb 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/8.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/8.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/8/ -- /zh-cn/docs3-v2/java-sdk/faq/4/8/ -- /zh-cn/overview/mannual/java-sdk/faq/4/8/ +- /en/docs3-v2/java-sdk/faq/4/8/ +- /en/docs3-v2/java-sdk/faq/4/8/ +- /en/overview/mannual/java-sdk/faq/4/8/ description: 4-8 - 关闭服务端时发生错误 linkTitle: 4-8 - 关闭服务端时发生错误 title: 4-8 - 关闭服务端时发生错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/9.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/9.md index 83c0a2a92fa6..d3bbed4c6e8c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/9.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/9.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/9/ -- /zh-cn/docs3-v2/java-sdk/faq/4/9/ -- /zh-cn/overview/mannual/java-sdk/faq/4/9/ +- /en/docs3-v2/java-sdk/faq/4/9/ +- /en/docs3-v2/java-sdk/faq/4/9/ +- /en/overview/mannual/java-sdk/faq/4/9/ description: 4-9 - 解析失败 linkTitle: 4-9 - 解析失败 title: 4-9 - 解析失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/_index.md index c4a3bc2cbb77..5eeec815e8f7 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/4/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/4/_index.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/4/ -- /zh-cn/docs3-v2/java-sdk/faq/4/ -- /zh-cn/overview/mannual/java-sdk/faq/4/_index/ +- /en/docs3-v2/java-sdk/faq/4/ +- /en/docs3-v2/java-sdk/faq/4/ +- /en/overview/mannual/java-sdk/faq/4/_index/ description: 4 - 协议层 linkTitle: 4 - 协议层 title: 4 - 协议层 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/1.md index df344c117184..31dc767793a6 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/1.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/1.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/1/ -- /zh-cn/docs3-v2/java-sdk/faq/5/1/ -- /zh-cn/overview/mannual/java-sdk/faq/5/1/ +- /en/docs3-v2/java-sdk/faq/5/1/ +- /en/docs3-v2/java-sdk/faq/5/1/ +- /en/overview/mannual/java-sdk/faq/5/1/ description: 5-1 - 配置中心连接失败 linkTitle: 5-1 - 配置中心连接失败 title: 5-1 - 配置中心连接失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/10.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/10.md index 786a46ca1b80..bfe6c2116d9f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/10.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/10.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/10/ -- /zh-cn/docs3-v2/java-sdk/faq/5/10/ -- /zh-cn/overview/mannual/java-sdk/faq/5/10/ +- /en/docs3-v2/java-sdk/faq/5/10/ +- /en/docs3-v2/java-sdk/faq/5/10/ +- /en/overview/mannual/java-sdk/faq/5/10/ description: 5-10 - 服务的注册接口应用程序映射失败 linkTitle: 5-10 - 服务的注册接口应用程序映射失败 title: 5-10 - 服务的注册接口应用程序映射失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/11.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/11.md index a197e837788d..dbc38f47b697 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/11.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/11.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/11/ -- /zh-cn/docs3-v2/java-sdk/faq/5/11/ -- /zh-cn/overview/mannual/java-sdk/faq/5/11/ +- /en/docs3-v2/java-sdk/faq/5/11/ +- /en/docs3-v2/java-sdk/faq/5/11/ +- /en/overview/mannual/java-sdk/faq/5/11/ description: 5-11 - 注册实例错误 linkTitle: 5-11 - 注册实例错误 title: 5-11 - 注册实例错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/12.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/12.md index 6bf125d511f7..2a86a210a43b 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/12.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/12.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/12/ -- /zh-cn/docs3-v2/java-sdk/faq/5/12/ -- /zh-cn/overview/mannual/java-sdk/faq/5/12/ +- /en/docs3-v2/java-sdk/faq/5/12/ +- /en/docs3-v2/java-sdk/faq/5/12/ +- /en/overview/mannual/java-sdk/faq/5/12/ description: 5-12 - 刷新实例和元数据错误 linkTitle: 5-12 - 刷新实例和元数据错误 title: 5-12 - 刷新实例和元数据错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/13.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/13.md index 89a8208887ee..0635a7561321 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/13.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/13.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/13/ -- /zh-cn/docs3-v2/java-sdk/faq/5/13/ -- /zh-cn/overview/mannual/java-sdk/faq/5/13/ +- /en/docs3-v2/java-sdk/faq/5/13/ +- /en/docs3-v2/java-sdk/faq/5/13/ +- /en/overview/mannual/java-sdk/faq/5/13/ description: 5-13 - 无法销毁模型 linkTitle: 5-13 - 无法销毁模型 title: 5-13 - 无法销毁模型 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/14.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/14.md index 7047387317aa..ae6fea01bc84 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/14.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/14.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/14/ -- /zh-cn/docs3-v2/java-sdk/faq/5/14/ -- /zh-cn/overview/mannual/java-sdk/faq/5/14/ +- /en/docs3-v2/java-sdk/faq/5/14/ +- /en/docs3-v2/java-sdk/faq/5/14/ +- /en/overview/mannual/java-sdk/faq/5/14/ description: 5-14 - 模型启动错误 linkTitle: 5-14 - 模型启动错误 title: 5-14 - 模型启动错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/15.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/15.md index 07c8d6271341..ba37d778c613 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/15.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/15.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/15/ -- /zh-cn/docs3-v2/java-sdk/faq/5/15/ -- /zh-cn/overview/mannual/java-sdk/faq/5/15/ +- /en/docs3-v2/java-sdk/faq/5/15/ +- /en/docs3-v2/java-sdk/faq/5/15/ +- /en/overview/mannual/java-sdk/faq/5/15/ description: 5-15 - 模型引用错误 linkTitle: 5-15 - 模型引用错误 title: 5-15 - 模型引用错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/16.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/16.md index cdc9a8359d58..3c2ba9ac2986 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/16.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/16.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/16/ -- /zh-cn/docs3-v2/java-sdk/faq/5/16/ -- /zh-cn/overview/mannual/java-sdk/faq/5/16/ +- /en/docs3-v2/java-sdk/faq/5/16/ +- /en/docs3-v2/java-sdk/faq/5/16/ +- /en/overview/mannual/java-sdk/faq/5/16/ description: 5-16 - 无法找到任何有效的协议 linkTitle: 5-16 - 无法找到任何有效的协议 title: 5-16 - 无法找到任何有效的协议 @@ -24,4 +24,4 @@ weight: 16 目前支持的协议有 dubbo、rmi、hessian、http、webservice、thrift、redis 等。 > 另请参阅 -[配置项参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/) +[配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/17.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/17.md index d1ede8cecc09..049c01f7a0db 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/17.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/17.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/17/ -- /zh-cn/docs3-v2/java-sdk/faq/5/17/ -- /zh-cn/overview/mannual/java-sdk/faq/5/17/ +- /en/docs3-v2/java-sdk/faq/5/17/ +- /en/docs3-v2/java-sdk/faq/5/17/ +- /en/overview/mannual/java-sdk/faq/5/17/ description: 5-17 - 参数值格式错误 linkTitle: 5-17 - 参数值格式错误 title: 5-17 - 参数值格式错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/18.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/18.md index c137314a55d6..9a502aea54ed 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/18.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/18.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/18/ -- /zh-cn/docs3-v2/java-sdk/faq/5/18/ -- /zh-cn/overview/mannual/java-sdk/faq/5/18/ +- /en/docs3-v2/java-sdk/faq/5/18/ +- /en/docs3-v2/java-sdk/faq/5/18/ +- /en/overview/mannual/java-sdk/faq/5/18/ description: 5-18 - 通知注册事件失败 linkTitle: 5-18 - 通知注册事件失败 title: 5-18 - 通知注册事件失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/2.md index 385495293313..41da7f627570 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/2.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/2.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/2/ -- /zh-cn/docs3-v2/java-sdk/faq/5/2/ -- /zh-cn/overview/mannual/java-sdk/faq/5/2/ +- /en/docs3-v2/java-sdk/faq/5/2/ +- /en/docs3-v2/java-sdk/faq/5/2/ +- /en/overview/mannual/java-sdk/faq/5/2/ description: 5-2 - 注册/注销关闭钩子方法失败 linkTitle: 5-2 - 注册/注销关闭钩子方法失败 title: 5-2 - 注册/注销关闭钩子方法失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/20.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/20.md index 0b82a0959863..cdeb15a83c1e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/20.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/20.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/20/ -- /zh-cn/docs3-v2/java-sdk/faq/5/20/ -- /zh-cn/overview/mannual/java-sdk/faq/5/20/ +- /en/docs3-v2/java-sdk/faq/5/20/ +- /en/docs3-v2/java-sdk/faq/5/20/ +- /en/overview/mannual/java-sdk/faq/5/20/ description: 5-20 - 停止 dubbo 模块时发生错误 linkTitle: 5-20 - 停止 dubbo 模块时发生错误 title: 5-20 - 停止 dubbo 模块时发生错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/21.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/21.md index b6f968603615..6984b7a55263 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/21.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/21.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/21/ -- /zh-cn/docs3-v2/java-sdk/faq/5/21/ -- /zh-cn/overview/mannual/java-sdk/faq/5/21/ +- /en/docs3-v2/java-sdk/faq/5/21/ +- /en/docs3-v2/java-sdk/faq/5/21/ +- /en/overview/mannual/java-sdk/faq/5/21/ description: 5-21 - 服务销毁时发生异常错误 linkTitle: 5-21 - 服务销毁时发生异常错误 title: 5-21 - 服务销毁时发生异常错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/22.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/22.md index bd25b3026531..3d14ebd4e077 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/22.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/22.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/22/ -- /zh-cn/docs3-v2/java-sdk/faq/5/22/ -- /zh-cn/overview/mannual/java-sdk/faq/5/22/ +- /en/docs3-v2/java-sdk/faq/5/22/ +- /en/docs3-v2/java-sdk/faq/5/22/ +- /en/overview/mannual/java-sdk/faq/5/22/ description: 5-22 - 注册中心在初始化时发生错误 linkTitle: 5-22 - 注册中心在初始化时发生错误 title: 5-22 - 注册中心在初始化时发生错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/23.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/23.md index 33c9226637c3..579bd33af945 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/23.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/23.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/23/ -- /zh-cn/docs3-v2/java-sdk/faq/5/23/ -- /zh-cn/overview/mannual/java-sdk/faq/5/23/ +- /en/docs3-v2/java-sdk/faq/5/23/ +- /en/docs3-v2/java-sdk/faq/5/23/ +- /en/overview/mannual/java-sdk/faq/5/23/ description: 5-23 - 等待导出/引用服务发生异常 linkTitle: 5-23 - 等待导出/引用服务发生异常 title: 5-23 - 等待导出/引用服务发生异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/24.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/24.md index 433294bf3f79..56ad96050767 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/24.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/24.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/24/ -- /zh-cn/docs3-v2/java-sdk/faq/5/24/ -- /zh-cn/overview/mannual/java-sdk/faq/5/24/ +- /en/docs3-v2/java-sdk/faq/5/24/ +- /en/docs3-v2/java-sdk/faq/5/24/ +- /en/overview/mannual/java-sdk/faq/5/24/ description: 5-24 - 异步等待引用服务发生异常 linkTitle: 5-24 - 异步等待引用服务发生异常 title: 5-24 - 异步等待引用服务发生异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/25.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/25.md index e4b50ef41959..2283b177e938 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/25.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/25.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/25/ -- /zh-cn/docs3-v2/java-sdk/faq/5/25/ -- /zh-cn/overview/mannual/java-sdk/faq/5/25/ +- /en/docs3-v2/java-sdk/faq/5/25/ +- /en/docs3-v2/java-sdk/faq/5/25/ +- /en/overview/mannual/java-sdk/faq/5/25/ description: 5-25 - 自定义实现发生未定义异常 linkTitle: 5-25 - 自定义实现发生未定义异常 title: 5-25 - 自定义实现发生未定义异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/26.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/26.md index 102de19e7eea..6c61a61c2e91 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/26.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/26.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/26/ -- /zh-cn/docs3-v2/java-sdk/faq/5/26/ -- /zh-cn/overview/mannual/java-sdk/faq/5/26/ +- /en/docs3-v2/java-sdk/faq/5/26/ +- /en/docs3-v2/java-sdk/faq/5/26/ +- /en/overview/mannual/java-sdk/faq/5/26/ description: 5-26 - 元数据已导出 linkTitle: 5-26 - 元数据已导出 title: 5-26 - 元数据已导出 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/27.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/27.md index 7bd71b15855b..c6e624f180d3 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/27.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/27.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/27/ -- /zh-cn/docs3-v2/java-sdk/faq/5/27/ -- /zh-cn/overview/mannual/java-sdk/faq/5/27/ +- /en/docs3-v2/java-sdk/faq/5/27/ +- /en/docs3-v2/java-sdk/faq/5/27/ +- /en/overview/mannual/java-sdk/faq/5/27/ description: 5-27 - 内部类API被错误使用 linkTitle: 5-27 - 内部类API被错误使用 title: 5-27 - 内部类API被错误使用 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/28.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/28.md index eca8853e7dc4..1919df65b221 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/28.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/28.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/28/ -- /zh-cn/docs3-v2/java-sdk/faq/5/28/ -- /zh-cn/overview/mannual/java-sdk/faq/5/28/ +- /en/docs3-v2/java-sdk/faq/5/28/ +- /en/docs3-v2/java-sdk/faq/5/28/ +- /en/overview/mannual/java-sdk/faq/5/28/ description: 5-28 - 未发现可用注解 linkTitle: 5-28 - 未发现可用注解 title: 5-28 - 未发现可用注解 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/29.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/29.md index f38389bab21c..4bde4261e2e8 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/29.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/29.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/29/ -- /zh-cn/docs3-v2/java-sdk/faq/5/29/ -- /zh-cn/overview/mannual/java-sdk/faq/5/29/ +- /en/docs3-v2/java-sdk/faq/5/29/ +- /en/docs3-v2/java-sdk/faq/5/29/ +- /en/overview/mannual/java-sdk/faq/5/29/ description: 5-29 - 扫描包未配置 linkTitle: 5-29 - 扫描包未配置 title: 5-29 - 扫描包未配置 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/3.md index c3184a57622c..acf263cb0240 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/3.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/3.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/3/ -- /zh-cn/docs3-v2/java-sdk/faq/5/3/ -- /zh-cn/overview/mannual/java-sdk/faq/5/3/ +- /en/docs3-v2/java-sdk/faq/5/3/ +- /en/docs3-v2/java-sdk/faq/5/3/ +- /en/overview/mannual/java-sdk/faq/5/3/ description: 5-3 - 销毁方法调用时发生意外错误 linkTitle: 5-3 - 销毁方法调用时发生意外错误 title: 5-3 - 销毁方法调用时发生意外错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/30.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/30.md index febece4c989a..fef1781f633e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/30.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/30.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/30/ -- /zh-cn/docs3-v2/java-sdk/faq/5/30/ -- /zh-cn/overview/mannual/java-sdk/faq/5/30/ +- /en/docs3-v2/java-sdk/faq/5/30/ +- /en/docs3-v2/java-sdk/faq/5/30/ +- /en/overview/mannual/java-sdk/faq/5/30/ description: 5-30 - 声明bean定义重复 linkTitle: 5-30 - 声明bean定义重复 title: 5-30 - 声明bean定义重复 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/31.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/31.md index 06d67461fa83..7828b014b8ca 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/31.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/31.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/31/ -- /zh-cn/docs3-v2/java-sdk/faq/5/31/ -- /zh-cn/overview/mannual/java-sdk/faq/5/31/ +- /en/docs3-v2/java-sdk/faq/5/31/ +- /en/docs3-v2/java-sdk/faq/5/31/ +- /en/overview/mannual/java-sdk/faq/5/31/ description: 5-31 - 状态检查错误 linkTitle: 5-31 - 状态检查错误 title: 5-31 - 状态检查错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/32.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/32.md index 03eed30c2f1f..9725ad2c85a1 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/32.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/32.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/32/ -- /zh-cn/docs3-v2/java-sdk/faq/5/32/ -- /zh-cn/overview/mannual/java-sdk/faq/5/32/ +- /en/docs3-v2/java-sdk/faq/5/32/ +- /en/docs3-v2/java-sdk/faq/5/32/ +- /en/overview/mannual/java-sdk/faq/5/32/ description: 5-32 - Apollo 断开连接时发生错误 linkTitle: 5-32 - Apollo 断开连接时发生错误 title: 5-32 - Apollo 断开连接时发生错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/33.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/33.md index c6cd6f5465eb..2c8e9b8eda6b 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/33.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/33.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/33/ -- /zh-cn/docs3-v2/java-sdk/faq/5/33/ -- /zh-cn/overview/mannual/java-sdk/faq/5/33/ +- /en/docs3-v2/java-sdk/faq/5/33/ +- /en/docs3-v2/java-sdk/faq/5/33/ +- /en/overview/mannual/java-sdk/faq/5/33/ description: 5-33 - Apollo 配置更新事件发生异常 linkTitle: 5-33 - Apollo 配置更新事件发生异常 title: 5-33 - Apollo 配置更新事件发生异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/34.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/34.md index 1dc2c83c3403..cd3104e15662 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/34.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/34.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/34/ -- /zh-cn/docs3-v2/java-sdk/faq/5/34/ -- /zh-cn/overview/mannual/java-sdk/faq/5/34/ +- /en/docs3-v2/java-sdk/faq/5/34/ +- /en/docs3-v2/java-sdk/faq/5/34/ +- /en/overview/mannual/java-sdk/faq/5/34/ description: 5-34 - NACOS 发生错误 linkTitle: 5-34 - NACOS 发生错误 title: 5-34 - NACOS 发生错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/35.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/35.md index 6afe4a7879f2..7895d046ccb9 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/35.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/35.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/35/ -- /zh-cn/docs3-v2/java-sdk/faq/5/35/ -- /zh-cn/overview/mannual/java-sdk/faq/5/35/ +- /en/docs3-v2/java-sdk/faq/5/35/ +- /en/docs3-v2/java-sdk/faq/5/35/ +- /en/overview/mannual/java-sdk/faq/5/35/ description: 5-35 - 容器初始化失败 linkTitle: 5-35 - 容器初始化失败 title: 5-35 - 容器初始化失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/36.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/36.md index 6b337d196bf0..1ce1d0c0fdb5 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/36.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/36.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/36/ -- /zh-cn/docs3-v2/java-sdk/faq/5/36/ -- /zh-cn/overview/mannual/java-sdk/faq/5/36/ +- /en/docs3-v2/java-sdk/faq/5/36/ +- /en/docs3-v2/java-sdk/faq/5/36/ +- /en/overview/mannual/java-sdk/faq/5/36/ description: 5-36 - 过滤器校验时发生错误 linkTitle: 5-36 - 过滤器校验时发生错误 title: 5-36 - 过滤器校验时发生错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/37.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/37.md index e216f007259b..1b8fa0a79deb 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/37.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/37.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/37/ -- /zh-cn/docs3-v2/java-sdk/faq/5/37/ -- /zh-cn/overview/mannual/java-sdk/faq/5/37/ +- /en/docs3-v2/java-sdk/faq/5/37/ +- /en/docs3-v2/java-sdk/faq/5/37/ +- /en/overview/mannual/java-sdk/faq/5/37/ description: 5-37 - 动态配置监听处理发生错误 linkTitle: 5-37 - 动态配置监听处理发生错误 title: 5-37 - 动态配置监听处理发生错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/38.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/38.md index e1a911575d5c..7d91d9f291db 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/38.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/38.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/38/ -- /zh-cn/docs3-v2/java-sdk/faq/5/38/ -- /zh-cn/overview/mannual/java-sdk/faq/5/38/ +- /en/docs3-v2/java-sdk/faq/5/38/ +- /en/docs3-v2/java-sdk/faq/5/38/ +- /en/overview/mannual/java-sdk/faq/5/38/ description: 5-38 - 配置参数未定义 linkTitle: 5-38 - 配置参数未定义 title: 5-38 - 配置参数未定义 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/39.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/39.md index 9ed6c90f3236..22be52688bb1 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/39.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/39.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/39/ -- /zh-cn/docs3-v2/java-sdk/faq/5/39/ -- /zh-cn/overview/mannual/java-sdk/faq/5/39/ +- /en/docs3-v2/java-sdk/faq/5/39/ +- /en/docs3-v2/java-sdk/faq/5/39/ +- /en/overview/mannual/java-sdk/faq/5/39/ description: 5-39 - Dubbo配置bean初始化器发生错误 linkTitle: 5-39 - Dubbo配置bean初始化器发生错误 title: 5-39 - Dubbo配置bean初始化器发生错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/4.md index f557175c9c96..b5d3e2d346d7 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/4.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/4.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/4/ -- /zh-cn/docs3-v2/java-sdk/faq/5/4/ -- /zh-cn/overview/mannual/java-sdk/faq/5/4/ +- /en/docs3-v2/java-sdk/faq/5/4/ +- /en/docs3-v2/java-sdk/faq/5/4/ +- /en/overview/mannual/java-sdk/faq/5/4/ description: 5-4 - 服务接口中找不到方法 linkTitle: 5-4 - 服务接口中找不到方法 title: 5-4 - 服务接口中找不到方法 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/40.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/40.md index ca79402f4e1d..566972e0b32e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/40.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/40.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/40/ -- /zh-cn/docs3-v2/java-sdk/faq/5/40/ -- /zh-cn/overview/mannual/java-sdk/faq/5/40/ +- /en/docs3-v2/java-sdk/faq/5/40/ +- /en/docs3-v2/java-sdk/faq/5/40/ +- /en/overview/mannual/java-sdk/faq/5/40/ description: 5-40 - Dubbo配置bean未找到 linkTitle: 5-40 - Dubbo配置bean未找到 title: 5-40 - Dubbo配置bean未找到 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/41.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/41.md index 5167fc20cfed..2d565b4310ae 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/41.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/41.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/41/ -- /zh-cn/docs3-v2/java-sdk/faq/5/41/ -- /zh-cn/overview/mannual/java-sdk/faq/5/41/ +- /en/docs3-v2/java-sdk/faq/5/41/ +- /en/docs3-v2/java-sdk/faq/5/41/ +- /en/overview/mannual/java-sdk/faq/5/41/ description: 5-41 - SSL证书读取失败 linkTitle: 5-41 - SSL证书读取失败 title: 5-41 - SSL证书读取失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/42.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/42.md index e32b4a65ef2b..45e218b4d383 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/42.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/42.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/42/ -- /zh-cn/docs3-v2/java-sdk/faq/5/42/ -- /zh-cn/overview/mannual/java-sdk/faq/5/42/ +- /en/docs3-v2/java-sdk/faq/5/42/ +- /en/docs3-v2/java-sdk/faq/5/42/ +- /en/overview/mannual/java-sdk/faq/5/42/ description: 5-42 - Dubbo 证书签发失败 linkTitle: 5-42 - Dubbo 证书签发失败 title: 5-42 - Dubbo 证书签发失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/43.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/43.md index 4ac65c40416f..f8a16d2bc16f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/43.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/43.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/43/ -- /zh-cn/docs3-v2/java-sdk/faq/5/43/ -- /zh-cn/overview/mannual/java-sdk/faq/5/43/ +- /en/docs3-v2/java-sdk/faq/5/43/ +- /en/docs3-v2/java-sdk/faq/5/43/ +- /en/overview/mannual/java-sdk/faq/5/43/ description: 5-43 - Dubbo 证书签发连接不安全 linkTitle: 5-43 - Dubbo 证书签发连接不安全 title: 5-43 - Dubbo 证书签发连接不安全 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/5.md index b1fc2889a647..8dd049553aad 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/5.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/5.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/5/ -- /zh-cn/docs3-v2/java-sdk/faq/5/5/ -- /zh-cn/overview/mannual/java-sdk/faq/5/5/ +- /en/docs3-v2/java-sdk/faq/5/5/ +- /en/docs3-v2/java-sdk/faq/5/5/ +- /en/overview/mannual/java-sdk/faq/5/5/ description: 5-5 - 无法获得env变量 linkTitle: 5-5 - 无法获得env变量 title: 5-5 - 无法获得env变量 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/6.md index 45dd63782dfe..f60e3cb5b346 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/6.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/6.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/6/ -- /zh-cn/docs3-v2/java-sdk/faq/5/6/ -- /zh-cn/overview/mannual/java-sdk/faq/5/6/ +- /en/docs3-v2/java-sdk/faq/5/6/ +- /en/docs3-v2/java-sdk/faq/5/6/ +- /en/overview/mannual/java-sdk/faq/5/6/ description: 5-6 - 接口类型的属性冲突 linkTitle: 5-6 - 接口类型的属性冲突 title: 5-6 - 接口类型的属性冲突 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/7.md index 5041addb585f..4381c156a730 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/7.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/7.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/7/ -- /zh-cn/docs3-v2/java-sdk/faq/5/7/ -- /zh-cn/overview/mannual/java-sdk/faq/5/7/ +- /en/docs3-v2/java-sdk/faq/5/7/ +- /en/docs3-v2/java-sdk/faq/5/7/ +- /en/overview/mannual/java-sdk/faq/5/7/ description: 5-7 - 取消导出时发生意外错误 linkTitle: 5-7 - 取消导出时发生意外错误 title: 5-7 - 取消导出时发生意外错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/8.md index c0966beb4828..384ace2b0f54 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/8.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/8.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/8/ -- /zh-cn/docs3-v2/java-sdk/faq/5/8/ -- /zh-cn/overview/mannual/java-sdk/faq/5/8/ +- /en/docs3-v2/java-sdk/faq/5/8/ +- /en/docs3-v2/java-sdk/faq/5/8/ +- /en/overview/mannual/java-sdk/faq/5/8/ description: 5-8 - 协议将使用随机可用端口 linkTitle: 5-8 - 协议将使用随机可用端口 title: 5-8 - 协议将使用随机可用端口 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/9.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/9.md index 57a333eb4a18..beb98b256930 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/9.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/9.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/9/ -- /zh-cn/docs3-v2/java-sdk/faq/5/9/ -- /zh-cn/overview/mannual/java-sdk/faq/5/9/ +- /en/docs3-v2/java-sdk/faq/5/9/ +- /en/docs3-v2/java-sdk/faq/5/9/ +- /en/overview/mannual/java-sdk/faq/5/9/ description: 5-9 - 服务配置导出失败 linkTitle: 5-9 - 服务配置导出失败 title: 5-9 - 服务配置导出失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/_index.md index 26a7bcd20484..ba47f197f230 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/5/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/5/_index.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/5/ -- /zh-cn/docs3-v2/java-sdk/faq/5/ -- /zh-cn/overview/mannual/java-sdk/faq/5/_index/ +- /en/docs3-v2/java-sdk/faq/5/ +- /en/docs3-v2/java-sdk/faq/5/ +- /en/overview/mannual/java-sdk/faq/5/_index/ description: 5 - 配置(中心)层 linkTitle: 5 - 配置(中心)层 title: 5 - 配置(中心)层 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/1.md index 96c7734da080..932886994b78 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/1.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/1.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/1/ -- /zh-cn/docs3-v2/java-sdk/faq/6/1/ -- /zh-cn/overview/mannual/java-sdk/faq/6/1/ +- /en/docs3-v2/java-sdk/faq/6/1/ +- /en/docs3-v2/java-sdk/faq/6/1/ +- /en/overview/mannual/java-sdk/faq/6/1/ description: 6-1 - 服务端连接失败 linkTitle: 6-1 - 服务端连接失败 title: 6-1 - 服务端连接失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/10.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/10.md index ac18c5ea06d4..1bcae7841a83 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/10.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/10.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/10/ -- /zh-cn/docs3-v2/java-sdk/faq/6/10/ -- /zh-cn/overview/mannual/java-sdk/faq/6/10/ +- /en/docs3-v2/java-sdk/faq/6/10/ +- /en/docs3-v2/java-sdk/faq/6/10/ +- /en/overview/mannual/java-sdk/faq/6/10/ description: 6-10 - 超过有效载荷限制异常 linkTitle: 6-10 - 超过有效载荷限制异常 title: 6-10 - 超过有效载荷限制异常 @@ -21,4 +21,4 @@ weight: 10 ### 排查和解决步骤 -各组件支持的具体配置项及含义请参考 [配置项手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) +各组件支持的具体配置项及含义请参考 [配置项手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/11.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/11.md index e8a385ec43eb..7a1842f76f89 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/11.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/11.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/11/ -- /zh-cn/docs3-v2/java-sdk/faq/6/11/ -- /zh-cn/overview/mannual/java-sdk/faq/6/11/ +- /en/docs3-v2/java-sdk/faq/6/11/ +- /en/docs3-v2/java-sdk/faq/6/11/ +- /en/overview/mannual/java-sdk/faq/6/11/ description: 6-11 - 字符集不被支持 linkTitle: 6-11 - 字符集不被支持 title: 6-11 - 字符集不被支持 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/12.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/12.md index 58b4d27d0b98..a519f8ae89a2 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/12.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/12.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/12/ -- /zh-cn/docs3-v2/java-sdk/faq/6/12/ -- /zh-cn/overview/mannual/java-sdk/faq/6/12/ +- /en/docs3-v2/java-sdk/faq/6/12/ +- /en/docs3-v2/java-sdk/faq/6/12/ +- /en/overview/mannual/java-sdk/faq/6/12/ description: 6-12 - ZK客户端销毁时发生错误 linkTitle: 6-12 - ZK客户端销毁时发生错误 title: 6-12 - ZK客户端销毁时发生错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/13.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/13.md index 76c1392b058f..7e4f90ddd9ee 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/13.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/13.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/13/ -- /zh-cn/docs3-v2/java-sdk/faq/6/13/ -- /zh-cn/overview/mannual/java-sdk/faq/6/13/ +- /en/docs3-v2/java-sdk/faq/6/13/ +- /en/docs3-v2/java-sdk/faq/6/13/ +- /en/overview/mannual/java-sdk/faq/6/13/ description: 6-13 - 流关闭异常 linkTitle: 6-13 - 流关闭异常 title: 6-13 - 流关闭异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/14.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/14.md index 07bd31411399..d96ef9d6ea1b 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/14.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/14.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/14/ -- /zh-cn/docs3-v2/java-sdk/faq/6/14/ -- /zh-cn/overview/mannual/java-sdk/faq/6/14/ +- /en/docs3-v2/java-sdk/faq/6/14/ +- /en/docs3-v2/java-sdk/faq/6/14/ +- /en/overview/mannual/java-sdk/faq/6/14/ description: 6-14 - 服务端响应失败 linkTitle: 6-14 - 服务端响应失败 title: 6-14 - 服务端响应失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/15.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/15.md index 565f47239166..1aefc20d8381 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/15.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/15.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/15/ -- /zh-cn/docs3-v2/java-sdk/faq/6/15/ -- /zh-cn/overview/mannual/java-sdk/faq/6/15/ +- /en/docs3-v2/java-sdk/faq/6/15/ +- /en/docs3-v2/java-sdk/faq/6/15/ +- /en/overview/mannual/java-sdk/faq/6/15/ description: 6-15 - 跳过未读完的流数据 linkTitle: 6-15 - 跳过未读完的流数据 title: 6-15 - 跳过未读完的流数据 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/16.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/16.md index 4ed6d440761d..917d7acb492b 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/16.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/16.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/16/ -- /zh-cn/docs3-v2/java-sdk/faq/6/16/ -- /zh-cn/overview/mannual/java-sdk/faq/6/16/ +- /en/docs3-v2/java-sdk/faq/6/16/ +- /en/docs3-v2/java-sdk/faq/6/16/ +- /en/overview/mannual/java-sdk/faq/6/16/ description: 6-16 - 重连时发生异常 linkTitle: 6-16 - 重连时发生异常 title: 6-16 - 重连时发生异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/2.md index 425161657877..d43625605410 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/2.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/2.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/2/ -- /zh-cn/docs3-v2/java-sdk/faq/6/2/ -- /zh-cn/overview/mannual/java-sdk/faq/6/2/ +- /en/docs3-v2/java-sdk/faq/6/2/ +- /en/docs3-v2/java-sdk/faq/6/2/ +- /en/overview/mannual/java-sdk/faq/6/2/ description: 6-2 - 客户端超时 linkTitle: 6-2 - 客户端超时 title: 6-2 - 客户端超时 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/3.md index cc612f74e92d..dc6095a486a5 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/3.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/3.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/3/ -- /zh-cn/docs3-v2/java-sdk/faq/6/3/ -- /zh-cn/overview/mannual/java-sdk/faq/6/3/ +- /en/docs3-v2/java-sdk/faq/6/3/ +- /en/docs3-v2/java-sdk/faq/6/3/ +- /en/overview/mannual/java-sdk/faq/6/3/ description: 6-3 - 网络连接关闭失败 linkTitle: 6-3 - 网络连接关闭失败 title: 6-3 - 网络连接关闭失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/4.md index 40a49072c93a..a9dc335553e2 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/4.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/4.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/4/ -- /zh-cn/docs3-v2/java-sdk/faq/6/4/ -- /zh-cn/overview/mannual/java-sdk/faq/6/4/ +- /en/docs3-v2/java-sdk/faq/6/4/ +- /en/docs3-v2/java-sdk/faq/6/4/ +- /en/overview/mannual/java-sdk/faq/6/4/ description: 6-4 - 网络通讯层未知异常 linkTitle: 6-4 - 网络通讯层未知异常 title: 6-4 - 网络通讯层未知异常 @@ -16,7 +16,7 @@ weight: 4 ### 可能的原因 -> 该错误码的意义已经调整。对于 Dubbo 3.1.4、3.2.0-beta.3 及其之前的版本的该错误码的出错,请参考错误码 [99-0](/zh-cn/overview/mannual/java-sdk/faq/99/0/)。 +> 该错误码的意义已经调整。对于 Dubbo 3.1.4、3.2.0-beta.3 及其之前的版本的该错误码的出错,请参考错误码 [99-0](/en/overview/mannual/java-sdk/faq/99/0/)。 ### 排查和解决步骤 (该错误码目前空缺) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/5.md index 8cf5c6c41ed1..2ccd88a813f5 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/5.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/5.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/5/ -- /zh-cn/docs3-v2/java-sdk/faq/6/5/ -- /zh-cn/overview/mannual/java-sdk/faq/6/5/ +- /en/docs3-v2/java-sdk/faq/6/5/ +- /en/docs3-v2/java-sdk/faq/6/5/ +- /en/overview/mannual/java-sdk/faq/6/5/ description: 6-5 - 网络连接断开失败 linkTitle: 6-5 - 网络连接断开失败 title: 6-5 - 网络连接断开失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/6.md index 07f50c01f853..0ae40c0e998e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/6.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/6.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/6/ -- /zh-cn/docs3-v2/java-sdk/faq/6/6/ -- /zh-cn/overview/mannual/java-sdk/faq/6/6/ +- /en/docs3-v2/java-sdk/faq/6/6/ +- /en/docs3-v2/java-sdk/faq/6/6/ +- /en/overview/mannual/java-sdk/faq/6/6/ description: 6-6 - 不支持的消息 linkTitle: 6-6 - 不支持的消息 title: 6-6 - 不支持的消息 @@ -24,4 +24,4 @@ weight: 6 可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 -各组件支持的具体配置项及含义请参考 [配置项手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) +各组件支持的具体配置项及含义请参考 [配置项手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/7.md index 137a8002f48c..ff698540b677 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/7.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/7.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/7/ -- /zh-cn/docs3-v2/java-sdk/faq/6/7/ -- /zh-cn/overview/mannual/java-sdk/faq/6/7/ +- /en/docs3-v2/java-sdk/faq/6/7/ +- /en/docs3-v2/java-sdk/faq/6/7/ +- /en/overview/mannual/java-sdk/faq/6/7/ description: 6-7 - 线程连接数超限警告 linkTitle: 6-7 - 服务端连接失败 title: 6-7 - 线程连接数超限警告 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/8.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/8.md index cce08265ad13..ffd7db8deb16 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/8.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/8.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/8/ -- /zh-cn/docs3-v2/java-sdk/faq/6/8/ -- /zh-cn/overview/mannual/java-sdk/faq/6/8/ +- /en/docs3-v2/java-sdk/faq/6/8/ +- /en/docs3-v2/java-sdk/faq/6/8/ +- /en/overview/mannual/java-sdk/faq/6/8/ description: 6-8 - 返回数据解码失败 linkTitle: 6-8 - 返回数据解码失败 title: 6-8 - 返回数据解码失败 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/9.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/9.md index 9ad290c6237d..64ba7aa055ad 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/9.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/9.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/9/ -- /zh-cn/docs3-v2/java-sdk/faq/6/9/ -- /zh-cn/overview/mannual/java-sdk/faq/6/9/ +- /en/docs3-v2/java-sdk/faq/6/9/ +- /en/docs3-v2/java-sdk/faq/6/9/ +- /en/overview/mannual/java-sdk/faq/6/9/ description: 6-9 - 序列号ID存在重复 linkTitle: 6-9 - 服务端连接失败 title: 6-9 - 序列号ID存在重复 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/_index.md index c998a9712a62..0b12d70042eb 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/6/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/6/_index.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/6/ -- /zh-cn/docs3-v2/java-sdk/faq/6/ -- /zh-cn/overview/mannual/java-sdk/faq/6/_index/ +- /en/docs3-v2/java-sdk/faq/6/ +- /en/docs3-v2/java-sdk/faq/6/ +- /en/overview/mannual/java-sdk/faq/6/_index/ description: 6 - 网络传输层 linkTitle: 6 - 网络传输层 title: 6 - 网络传输层 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/1.md index 2757de9f90cb..ca51ec9b84ae 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/1.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/1.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/7/1/ -- /zh-cn/docs3-v2/java-sdk/faq/7/1/ -- /zh-cn/overview/mannual/java-sdk/faq/7/1/ +- /en/docs3-v2/java-sdk/faq/7/1/ +- /en/docs3-v2/java-sdk/faq/7/1/ +- /en/overview/mannual/java-sdk/faq/7/1/ description: 7-1 - QOS 已关闭 linkTitle: 7-1 - QOS 已关闭 title: 7-1 - QOS 已关闭 @@ -22,4 +22,4 @@ QOS 已关闭 ### 排查和解决步骤 -> 请参考[QOS 操作手册](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/)。 +> 请参考[QOS 操作手册](/en/overview/mannual/java-sdk/reference-manual/qos/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/2.md index 06dfa2b102ff..3e59ff722450 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/2.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/2.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/7/2/ -- /zh-cn/docs3-v2/java-sdk/faq/7/2/ -- /zh-cn/overview/mannual/java-sdk/faq/7/2/ +- /en/docs3-v2/java-sdk/faq/7/2/ +- /en/docs3-v2/java-sdk/faq/7/2/ +- /en/overview/mannual/java-sdk/faq/7/2/ description: 7-2 - QOS 已开启 linkTitle: 7-2 - QOS 已开启 title: 7-2 - QOS 已开启 @@ -22,4 +22,4 @@ QOS 已开启,默认为开启状态。 ### 排查和解决步骤 -> 请参考[QOS 操作手册](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/)。 +> 请参考[QOS 操作手册](/en/overview/mannual/java-sdk/reference-manual/qos/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/3.md index f9175cf1a4db..3a52161ecbfe 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/3.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/3.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/7/3/ -- /zh-cn/docs3-v2/java-sdk/faq/7/3/ -- /zh-cn/overview/mannual/java-sdk/faq/7/3/ +- /en/docs3-v2/java-sdk/faq/7/3/ +- /en/docs3-v2/java-sdk/faq/7/3/ +- /en/overview/mannual/java-sdk/faq/7/3/ description: 7-3 - 设置超时时间的警告百分比值 linkTitle: 7-3 - 设置超时时间的警告百分比值 title: 7-3 - 设置超时时间的警告百分比值 @@ -22,5 +22,5 @@ QOS 设置超时时间的警告百分比值, 默认为0.75。修改后,控制 ## 排查和解决步骤 -请参考 QOS 操作手册[性能采样命令](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/profiler/)。 +请参考 QOS 操作手册[性能采样命令](/en/overview/mannual/java-sdk/reference-manual/qos/profiler/)。

diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/4.md index fd8fc540bee9..10170d905dbd 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/4.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/4.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/7/4/ -- /zh-cn/docs3-v2/java-sdk/faq/7/4/ -- /zh-cn/overview/mannual/java-sdk/faq/7/4/ +- /en/docs3-v2/java-sdk/faq/7/4/ +- /en/docs3-v2/java-sdk/faq/7/4/ +- /en/overview/mannual/java-sdk/faq/7/4/ description: 7-4 - QOS 服务启动失败 linkTitle: 7-4 - QOS 服务启动失败 title: 7-4 - QOS 服务启动失败 @@ -22,4 +22,4 @@ QOS 参数值未正确设置。主要参数有 `qos.host` 和 `qos.port` ### 排查和解决步骤 -> 请参考QOS 操作手册[QOS 概述](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/overview/)。 +> 请参考QOS 操作手册[QOS 概述](/en/overview/mannual/java-sdk/reference-manual/qos/overview/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/5.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/5.md index b9726dd07e8d..a1459794e6da 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/5.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/5.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/7/5/ -- /zh-cn/docs3-v2/java-sdk/faq/7/5/ -- /zh-cn/overview/mannual/java-sdk/faq/7/5/ +- /en/docs3-v2/java-sdk/faq/7/5/ +- /en/docs3-v2/java-sdk/faq/7/5/ +- /en/overview/mannual/java-sdk/faq/7/5/ description: 7-5 - QOS 命令未找到 linkTitle: 7-5 - QOS 命令未找到 title: 7-5 - QOS 命令未找到 @@ -23,4 +23,4 @@ QOS 命令拼写错误。 QOS 命令不存在。 -> 请参考 QOS 操作手册[基础命令手册](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/command/)。 +> 请参考 QOS 操作手册[基础命令手册](/en/overview/mannual/java-sdk/reference-manual/qos/command/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/6.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/6.md index 83c49e4df379..e568005bdd4a 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/6.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/6.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/7/6/ -- /zh-cn/docs3-v2/java-sdk/faq/7/6/ -- /zh-cn/overview/mannual/java-sdk/faq/7/6/ +- /en/docs3-v2/java-sdk/faq/7/6/ +- /en/docs3-v2/java-sdk/faq/7/6/ +- /en/overview/mannual/java-sdk/faq/7/6/ description: 7-6 - QOS 发生未知异常 linkTitle: 7-6 - QOS 发生未知异常 title: 7-6 - QOS 发生未知异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/7.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/7.md index 5ac45a2ee3bb..68390dbeb63b 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/7.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/7.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/7/7/ -- /zh-cn/docs3-v2/java-sdk/faq/7/7/ -- /zh-cn/overview/mannual/java-sdk/faq/7/7/ +- /en/docs3-v2/java-sdk/faq/7/7/ +- /en/docs3-v2/java-sdk/faq/7/7/ +- /en/overview/mannual/java-sdk/faq/7/7/ description: 7-7 - QOS 无权限访问 linkTitle: 7-7 - QOS 无权限访问 title: 7-7 - QOS 无权限访问 @@ -22,4 +22,4 @@ weight: 7 ### 排查和解决步骤 检查请求是否是预期发生的,如果非预期请检查是否有恶意攻击源。 -> 如果是预期的,请参考 [QoS 安全](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/overview/#%E5%AE%89%E5%85%A8) 一文配置对应的权限信息。 +> 如果是预期的,请参考 [QoS 安全](/en/overview/mannual/java-sdk/reference-manual/qos/overview/#%E5%AE%89%E5%85%A8) 一文配置对应的权限信息。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/_index.md index 6b3aef9e5110..2cce3ec2098f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/7/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/7/_index.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/7/ -- /zh-cn/docs3-v2/java-sdk/faq/7/ -- /zh-cn/overview/mannual/java-sdk/faq/7/_index/ +- /en/docs3-v2/java-sdk/faq/7/ +- /en/docs3-v2/java-sdk/faq/7/ +- /en/overview/mannual/java-sdk/faq/7/_index/ description: 7 - QoS 插件模块 linkTitle: 7 - QoS 插件模块 title: 7 - QoS 插件模块 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/1.md index c57fa729d91b..01cbfa944290 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/1.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/1.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/81/1/ -- /zh-cn/docs3-v2/java-sdk/faq/81/1/ -- /zh-cn/overview/mannual/java-sdk/faq/81/1/ +- /en/docs3-v2/java-sdk/faq/81/1/ +- /en/docs3-v2/java-sdk/faq/81/1/ +- /en/overview/mannual/java-sdk/faq/81/1/ description: 81-1 - ZK 启动异常 linkTitle: 81-1 - ZK 启动异常 title: 81-1 - ZK 启动异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/2.md index d6b530687d25..63fb4ed60eb8 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/2.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/2.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/81/2/ -- /zh-cn/docs3-v2/java-sdk/faq/81/2/ -- /zh-cn/overview/mannual/java-sdk/faq/81/2/ +- /en/docs3-v2/java-sdk/faq/81/2/ +- /en/docs3-v2/java-sdk/faq/81/2/ +- /en/overview/mannual/java-sdk/faq/81/2/ description: 81-2 - ZK 销毁异常 linkTitle: 81-2 - ZK 销毁异常 title: 81-2 - ZK 销毁异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/3.md index 56acd1c8048a..50104c83bbe5 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/3.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/3.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/81/3/ -- /zh-cn/docs3-v2/java-sdk/faq/81/3/ -- /zh-cn/overview/mannual/java-sdk/faq/81/3/ +- /en/docs3-v2/java-sdk/faq/81/3/ +- /en/docs3-v2/java-sdk/faq/81/3/ +- /en/overview/mannual/java-sdk/faq/81/3/ description: 81-3 - 通过url无法下载文件 linkTitle: 81-3 - 通过url无法下载文件 title: 81-3 - 通过url无法下载文件 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/4.md index 1fb0738db147..ffba7b4dc65d 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/4.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/4.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/81/4/ -- /zh-cn/docs3-v2/java-sdk/faq/81/4/ -- /zh-cn/overview/mannual/java-sdk/faq/81/4/ +- /en/docs3-v2/java-sdk/faq/81/4/ +- /en/docs3-v2/java-sdk/faq/81/4/ +- /en/overview/mannual/java-sdk/faq/81/4/ description: 81-4 - 嵌入式ZooKeeper运行异常 linkTitle: 81-4 - 嵌入式ZooKeeper运行异常 title: 81-4 - 嵌入式ZooKeeper运行异常 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/_index.md index 3afa03d52492..ad7894836b82 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/81/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/81/_index.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/81/ -- /zh-cn/docs3-v2/java-sdk/faq/81/ -- /zh-cn/overview/mannual/java-sdk/faq/81/_index/ +- /en/docs3-v2/java-sdk/faq/81/ +- /en/docs3-v2/java-sdk/faq/81/ +- /en/overview/mannual/java-sdk/faq/81/_index/ description: 81 - 单元测试辅助模块(注册中心) linkTitle: 81 - 单元测试辅助模块(注册中心) title: 81 - 单元测试辅助模块(注册中心) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/99/0.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/99/0.md index fa86ec7a4f07..87f096173e63 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/99/0.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/99/0.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/99/0/ -- /zh-cn/docs3-v2/java-sdk/faq/99/0/ -- /zh-cn/overview/mannual/java-sdk/faq/99/0/ +- /en/docs3-v2/java-sdk/faq/99/0/ +- /en/docs3-v2/java-sdk/faq/99/0/ +- /en/overview/mannual/java-sdk/faq/99/0/ description: 99-0 - 内部未知错误 linkTitle: 99-0 - 内部未知错误 title: 99-0 - 内部未知错误 @@ -27,4 +27,4 @@ Dubbo 内部的未知错误。 5. 如果都没解决,请尽可能做出一个复现该问题的最小 Demo,之后到 [GitHub Issue Tracker](https://github.com/apache/dubbo/issues) 下发 Issue。 > 另请参阅 -[配置项手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) +[配置项手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/99/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/99/1.md index 56fb31b83cea..9f98b4842c97 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/99/1.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/99/1.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/99/1/ -- /zh-cn/docs3-v2/java-sdk/faq/99/1/ -- /zh-cn/overview/mannual/java-sdk/faq/99/1/ +- /en/docs3-v2/java-sdk/faq/99/1/ +- /en/docs3-v2/java-sdk/faq/99/1/ +- /en/overview/mannual/java-sdk/faq/99/1/ description: 99-1 - 程序被打断 linkTitle: 99-1 - 程序被打断 title: 99-1 - 程序被打断 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/99/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/99/_index.md index 54769f408c6f..9d632de968ae 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/99/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/99/_index.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/99/ -- /zh-cn/docs3-v2/java-sdk/faq/99/ -- /zh-cn/overview/mannual/java-sdk/faq/99/_index/ +- /en/docs3-v2/java-sdk/faq/99/ +- /en/docs3-v2/java-sdk/faq/99/ +- /en/overview/mannual/java-sdk/faq/99/_index/ description: 99 - 其它未知错误 linkTitle: 99 - 其它未知错误 title: 99 - 其它未知错误 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/_index.md index d1a247a7db2b..d8eb1cb0cf99 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/_index.md @@ -1,8 +1,8 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/ -- /zh-cn/docs3-v2/java-sdk/faq/ -- /zh-cn/overview/mannual/java-sdk/faq/_index/ +- /en/docs3-v2/java-sdk/faq/ +- /en/docs3-v2/java-sdk/faq/ +- /en/overview/mannual/java-sdk/faq/_index/ description: 错误码 FAQ linkTitle: 错误码 FAQ title: 错误码 FAQ diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/intro.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/intro.md index b6603302232c..279feb74ead1 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/intro.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/intro.md @@ -1,9 +1,9 @@ --- aliases: -- /zh/docs3-v2/java-sdk/faq/intro/ -- /zh-cn/docs3-v2/java-sdk/faq/intro/ -- /zh-cn/overview/mannual/java-sdk/faq/intro/ -- /zh-cn/overview/java-sdk/reference-manual/faq/intro/ +- /en/docs3-v2/java-sdk/faq/intro/ +- /en/docs3-v2/java-sdk/faq/intro/ +- /en/overview/mannual/java-sdk/faq/intro/ +- /en/overview/java-sdk/reference-manual/faq/intro/ description: 错误码机制的介绍 linkTitle: 错误码机制的介绍 title: 错误码机制的介绍 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/graalvm/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/graalvm/_index.md index 035bda8d933b..f0a74f67df27 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/graalvm/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/graalvm/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/graalvm/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/graalvm/ + - /en/docs3-v2/java-sdk/reference-manual/graalvm/ + - /en/docs3-v2/java-sdk/reference-manual/graalvm/ description: "" hide_summary: true linkTitle: GraalVM @@ -220,4 +220,4 @@ consumer端同样执行编译,在consumer的target下也会生成二进制文 -**完成以上几步后就可以进行项目的编译了。** \ No newline at end of file +**完成以上几步后就可以进行项目的编译了。** diff --git a/content/en/overview/mannual/java-sdk/reference-manual/graalvm/support-graalvm.md b/content/en/overview/mannual/java-sdk/reference-manual/graalvm/support-graalvm.md index 947998df91a5..370f21791d13 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/graalvm/support-graalvm.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/graalvm/support-graalvm.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/support-graalvm/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/support-graalvm/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/support-graalvm/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/support-graalvm/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/support-graalvm/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/performance/support-graalvm/ description: "Dubbo AOT 技术详解,如何使用 GraalVM Native Image 实现 Dubbo 应用静态化。" linkTitle: 支持 GraalVM Native Image title: "Dubbo AOT -- 如何使用 GraalVM Native Image 实现 Dubbo 应用静态化" diff --git a/content/en/overview/mannual/java-sdk/reference-manual/merics/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/merics/_index.md index 40b7c93713bc..b95c38c655aa 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/merics/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/merics/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/mesh/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/mesh/ + - /en/docs3-v2/java-sdk/reference-manual/mesh/ + - /en/docs3-v2/java-sdk/reference-manual/mesh/ description: Dubbo Mesh 使用指南 linkTitle: Mesh手册 title: Mesh手册 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/merics/meter.md b/content/en/overview/mannual/java-sdk/reference-manual/merics/meter.md index efe8534aa980..db9e2598bca6 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/merics/meter.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/merics/meter.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/observability/meter/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/observability/meter/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/observability/meter/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/observability/meter/ description: "开启 Metrics 指标埋点" hide_summary: true linkTitle: Metrics @@ -14,7 +14,7 @@ weight: 1 ## 概述 -Dubbo Metrics 的总体设计请参考 [可观测性 Metrics Proposal](/zh-cn/overview/reference/proposals/metrics/)。 +Dubbo Metrics 的总体设计请参考 [可观测性 Metrics Proposal](/en/overview/reference/proposals/metrics/)。 以下是 Dubbo Java 相关的具体实现与使用方式讲解。 @@ -31,7 +31,7 @@ Dubbo Metrics 的总体设计请参考 [可观测性 Metrics Proposal](/zh-cn/ov ``` * 完整示例请参见 dubbo-samples-metrics-spring-boot -* 完整配置参数请参见 [Metrics 配置项手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties//) +* 完整配置参数请参见 [Metrics 配置项手册](/en/overview/mannual/java-sdk/reference-manual/config/properties//) ## 实现原理解析 @@ -47,7 +47,7 @@ Dubbo Metrics 的总体设计请参考 [可观测性 Metrics Proposal](/zh-cn/ov ### 指标上报接口 根据上图架构,指标接口是 Dubbo 对外暴露指标数据的出口,以下是指标接口的具体定义: -> 另外,该 Service 还作为一些 [智能自适应流量调度算法](/zh-cn/overview/reference/proposals/heuristic-flow-control/) 的数据来源 +> 另外,该 Service 还作为一些 [智能自适应流量调度算法](/en/overview/reference/proposals/heuristic-flow-control/) 的数据来源 ```java public interface MetricsService { @@ -204,7 +204,7 @@ dubbo.metrics.aggregation.time-window-seconds=10 ``` #### 具体指标 -[具体指标](/zh-cn/overview/reference/metrics/standard_metrics/) 请参考 Dubbo Metrics 总体设计文档。 +[具体指标](/en/overview/reference/metrics/standard_metrics/) 请参考 Dubbo Metrics 总体设计文档。 #### 聚合收集器实现 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/mesh/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/mesh/_index.md index 40b7c93713bc..b95c38c655aa 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/mesh/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/mesh/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/mesh/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/mesh/ + - /en/docs3-v2/java-sdk/reference-manual/mesh/ + - /en/docs3-v2/java-sdk/reference-manual/mesh/ description: Dubbo Mesh 使用指南 linkTitle: Mesh手册 title: Mesh手册 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/mesh/mesh.md b/content/en/overview/mannual/java-sdk/reference-manual/mesh/mesh.md index 99075a8ca4ae..91c382893d94 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/mesh/mesh.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/mesh/mesh.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/mesh/mesh/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/mesh/mesh/ + - /en/docs3-v2/java-sdk/reference-manual/mesh/mesh/ + - /en/docs3-v2/java-sdk/reference-manual/mesh/mesh/ description: 描述如何对Dubbo mesh proxyless模式进行debug。 linkTitle: Debug参考文档 title: Debug参考文档 @@ -162,4 +162,4 @@ kubectl port-forward dubbo-samples-xds-consumer-64c6c6f444-kk2vr 31000:31000 可以看到断点已经成功进来了: ![xds-debug-success.png](/imgs/user/xds-debug-success.png) 此时查看k8s_server_dubbo-samples-xds-consumer-XXX的日志可以看到已经成功在运行: -![xds-consumer-debug-success-log.png](/imgs/user/xds-consumer-debug-success-log.png) \ No newline at end of file +![xds-consumer-debug-success-log.png](/imgs/user/xds-consumer-debug-success-log.png) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/_index.md index 81b2a134a551..453101830ec3 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/metadata-center/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/metadata-center/ - - /zh-cn/overview/what/ecosystem/metadata-center/ + - /en/docs3-v2/java-sdk/reference-manual/metadata-center/ + - /en/docs3-v2/java-sdk/reference-manual/metadata-center/ + - /en/overview/what/ecosystem/metadata-center/ description: Dubbo 元数据中心基本使用与工作原理 linkTitle: 元数据中心 title: 元数据中心 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/nacos.md b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/nacos.md index 04a6817adb63..7cb977d54362 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/nacos.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/nacos.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/metadata-center/nacos/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/metadata-center/nacos/ - - /zh-cn/overview/what/ecosystem/metadata-center/nacos/ + - /en/docs3-v2/java-sdk/reference-manual/metadata-center/nacos/ + - /en/docs3-v2/java-sdk/reference-manual/metadata-center/nacos/ + - /en/overview/what/ecosystem/metadata-center/nacos/ description: Nacos 元数据中心基本使用与工作原理 linkTitle: Nacos title: Nacos @@ -11,8 +11,8 @@ weight: 2 --- ## 1 预备工作 -- 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/spring-boot/) -- 参考 [Nacos](/zh-cn/overview/reference/integrations/nacos/) 启动 Nacos server +- 了解 [Dubbo 基本开发步骤](/en/overview/mannual/java-sdk/quick-start/spring-boot/) +- 参考 [Nacos](/en/overview/reference/integrations/nacos/) 启动 Nacos server > 当Dubbo使用`3.0.0`及以上版本时,需要使用Nacos `2.0.0`及以上版本 @@ -23,7 +23,7 @@ Dubbo 融合 Nacos 成为元数据中心的操作步骤非常简单,大致分 ### 2.1 增加 Maven 依赖 如果项目已经启用 Nacos 作为注册中心,则无需增加任何额外配置。 -如果未启用 Nacos 注册中心,则请参考 [为注册中心增加 Nacos 依赖](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/nacos/#12-nacos-版本)。 +如果未启用 Nacos 注册中心,则请参考 [为注册中心增加 Nacos 依赖](/en/overview/mannual/java-sdk/reference-manual/registry/nacos/#12-nacos-版本)。 ### 2.2 启用 Nacos 配置中心 ```xml @@ -115,4 +115,4 @@ dubbo.metadata-report.report-metadata=true Nacos server 中的元数据信息详情如下: -![image-dubbo-metadata-nacos-2.png](/imgs/blog/dubbo-metadata-nacos-2.png) \ No newline at end of file +![image-dubbo-metadata-nacos-2.png](/imgs/blog/dubbo-metadata-nacos-2.png) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/others.md b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/others.md index b3fe43c42530..c03796e7cd91 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/others.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/others.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/metadata-center/redis/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/metadata-center/redis/ - - /zh-cn/overview/what/ecosystem/metadata-center/redis/ + - /en/docs3-v2/java-sdk/reference-manual/metadata-center/redis/ + - /en/docs3-v2/java-sdk/reference-manual/metadata-center/redis/ + - /en/overview/what/ecosystem/metadata-center/redis/ description: "更多元数据中心扩展实现,包括 redis、etcd、consul 等" linkTitle: 扩展实现 title: 更多元数据中心扩展实现 @@ -81,4 +81,4 @@ Consul 元数据中心由社区生态库维护,具体可参见 [](https://gith dubbo metadata-report address: consul://127.0.0.1:1111 -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/overview.md b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/overview.md index daf98308059c..159a58e39265 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/overview.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/overview.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/metadata-center/overview/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/metadata-center/overview/ + - /en/docs3-v2/java-sdk/reference-manual/metadata-center/overview/ + - /en/docs3-v2/java-sdk/reference-manual/metadata-center/overview/ description: 元数据中心概述 linkTitle: 元数据中心概述 title: 元数据中心概述 @@ -15,7 +15,7 @@ weight: 1 - 2 服务运维元数据,用于外围运维系统如可视化控制台进行服务查询、测试等。 ## 1 地址发现元数据 -Dubbo3 中引入了 [应用级服务发现机制](/zh-cn/overview/core-features/service-discovery/#面向百万实例集群的服务发现机制) 用来解决异构微服务体系互通与大规模集群实践的性能问题,应用级服务发现将全面取代 2.x 时代的接口级服务发现。 +Dubbo3 中引入了 [应用级服务发现机制](/en/overview/core-features/service-discovery/#面向百万实例集群的服务发现机制) 用来解决异构微服务体系互通与大规模集群实践的性能问题,应用级服务发现将全面取代 2.x 时代的接口级服务发现。 同时为了保持 Dubbo 面向服务/接口的易用性、服务治理的灵活性,Dubbo 围绕应用级服务发现构建了一套元数据机制,即 `接口 - 应用映射关系` 与 `接口配置元数据`。 ### 1.1 接口 - 应用映射关系 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/zookeeper.md b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/zookeeper.md index d169b3e15840..8c7f98beab11 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/zookeeper.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/metadata-center/zookeeper.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/metadata-center/zookeeper/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/metadata-center/zookeeper/ - - /zh-cn/overview/what/ecosystem/metadata-center/zookeeper/ + - /en/docs3-v2/java-sdk/reference-manual/metadata-center/zookeeper/ + - /en/docs3-v2/java-sdk/reference-manual/metadata-center/zookeeper/ + - /en/overview/what/ecosystem/metadata-center/zookeeper/ description: Zookeeper 元数据中心基本使用与工作原理 linkTitle: Zookeeper title: Zookeeper @@ -12,15 +12,15 @@ weight: 3 ## 1 预备工作 -- 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/spring-boot/) -- 安装并启动 [Zookeeper](/zh-cn/overview/reference/integrations/zookeeper/) +- 了解 [Dubbo 基本开发步骤](/en/overview/mannual/java-sdk/quick-start/spring-boot/) +- 安装并启动 [Zookeeper](/en/overview/reference/integrations/zookeeper/) ## 2 使用说明 ### 2.1 增加 Maven 依赖 如果项目已经启用 Zookeeper 作为注册中心,则无需增加任何额外配置。 -如果未使用 Zookeeper 注册中心,则请参考 [为注册中心增加 Zookeeper 相关依赖](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/zookeeper/#11-增加-maven-依赖)。 +如果未使用 Zookeeper 注册中心,则请参考 [为注册中心增加 Zookeeper 相关依赖](/en/overview/mannual/java-sdk/reference-manual/registry/zookeeper/#11-增加-maven-依赖)。 ### 2.2 启用 Zookeeper 配置中心 ```xml @@ -52,7 +52,7 @@ metadataConfig.setAddress("zookeeper://127.0.0.1:2181"); ## 3 高级配置 -完整配置参数请参考 [metadata-report-config](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#dubbometadata-report)。 +完整配置参数请参考 [metadata-report-config](/en/overview/mannual/java-sdk/reference-manual/config/properties/#dubbometadata-report)。 ## 4 工作原理 @@ -175,4 +175,4 @@ aclVersion = 0 ephemeralOwner = 0x0 dataLength = 1286 numChildren = 0 -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/performance/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/performance/_index.md index 3796c3466da1..f0c7a0284ad7 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/performance/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/performance/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/performance/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/performance/ + - /en/docs3-v2/java-sdk/reference-manual/performance/ + - /en/docs3-v2/java-sdk/reference-manual/performance/ description: Dubbo 基准测试性能参考指南 linkTitle: 性能Benchmark title: 性能参考手册 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/performance/benchmarking.md b/content/en/overview/mannual/java-sdk/reference-manual/performance/benchmarking.md index 1c2e5a6a23b9..034b32aa210b 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/performance/benchmarking.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/performance/benchmarking.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/performance/benchmarking/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/performance/benchmarking/ + - /en/docs3-v2/java-sdk/reference-manual/performance/benchmarking/ + - /en/docs3-v2/java-sdk/reference-manual/performance/benchmarking/ description: "" linkTitle: 应用级服务发现基准 title: 应用级服务发现基准测试 @@ -47,4 +47,4 @@ weight: 1
图二 服务发现模型 GC 变化

- Dubbo3 接口级服务发现模型,YGC 次数 2.x 版本大幅下降,从数百次下降到十几次 -- Dubbo3 应用级服务发现模型,FGC 次数 2.x 版本大幅下降,从数百次下降到零次 \ No newline at end of file +- Dubbo3 应用级服务发现模型,FGC 次数 2.x 版本大幅下降,从数百次下降到零次 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/performance/rpc-benchmarking.md b/content/en/overview/mannual/java-sdk/reference-manual/performance/rpc-benchmarking.md index 9caad23222f1..2a553e914d01 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/performance/rpc-benchmarking.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/performance/rpc-benchmarking.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/performance/rpc-benchmarking/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/performance/rpc-benchmarking/ + - /en/docs3-v2/java-sdk/reference-manual/performance/rpc-benchmarking/ + - /en/docs3-v2/java-sdk/reference-manual/performance/rpc-benchmarking/ description: "" linkTitle: RPC 基准 title: RPC 协议 Triple&Dubbo 基准测试 @@ -60,4 +60,4 @@ TBD

### 1.2.4 模拟 Stream 通信场景的吞吐量提升 -TBD \ No newline at end of file +TBD diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/_index.md index 9289bb67279a..abd4daa5207f 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/ - - /zh/overview/what/ecosystem/protocol/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/ + - /en/overview/what/ecosystem/protocol/ description: Dubbo RPC 协议指南 linkTitle: RPC协议 title: RPC 协议 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/dubbo.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/dubbo.md index 5d67a7415400..24e2c213a4bc 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/dubbo.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/dubbo.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/dubbo/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/dubbo/ - - /zh/overview/what/ecosystem/protocol/dubbo/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/dubbo/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/dubbo/ + - /en/overview/what/ecosystem/protocol/dubbo/ description: "本文描述 Dubbo 协议 java 实现的特点与具体实现细节" linkTitle: dubbo title: Dubbo协议 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols.md index 123c5265cbb1..6f2a82517dc7 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-protocols/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-protocols/ - - /zh-cn/overview/tasks/protocols/multi-protocols/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-protocols + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-protocols/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-protocols/ + - /en/overview/tasks/protocols/multi-protocols/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-protocols description: 在 Dubbo 中配置多协议 linkTitle: 多协议 title: 多协议 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/_index.md index ae16b6a99d5a..f9d00d6ca9d4 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/ - - /zh/overview/what/ecosystem/protocol/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/ + - /en/overview/what/ecosystem/protocol/ description: Dubbo RPC 协议指南 linkTitle: 扩展实现 title: Dubbo 提供的更多 RPC 扩展协议实现 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/hessian.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/hessian.md index e22981e1813b..d97a25de1f5e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/hessian.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/hessian.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/hessian/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/hessian/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/hessian/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/hessian/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/hessian/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/hessian/ description: Hessian协议 linkTitle: Hessian协议 title: Hessian协议 @@ -43,7 +43,7 @@ hessian是一个轻量级的RPC服务,是基于Binary-RPC协议实现的,序 ### 依赖 -从 Dubbo 3 开始,Hessian 协议已经不再内嵌在 Dubbo 中,需要单独引入独立的[模块](/zh-cn/download/spi-extensions/#dubbo-rpc)。 +从 Dubbo 3 开始,Hessian 协议已经不再内嵌在 Dubbo 中,需要单独引入独立的[模块](/en/download/spi-extensions/#dubbo-rpc)。 ```xml org.apache.dubbo.extensions diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/http.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/http.md.bak index b06415fe1389..6ab195ea14cb 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/http.md.bak +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/http.md.bak @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/http/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/http/ - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/http/ - - /zh/overview/what/ecosystem/protocol/http/ + - /en/overview/what/ecosystem/protocol/http/ description: HTTP协议 linkTitle: HTTP协议 title: HTTP协议 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/memcached.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/memcached.md index 6e861e7ec71a..20ec7103b559 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/memcached.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/memcached.md @@ -1,6 +1,6 @@ --- aliases: - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/memcached/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/memcached/ description: Memcached 协议 linkTitle: Memcached 协议 title: Memcached 协议 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/redis.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/redis.md index 677e3dc8735e..9d844af6bc71 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/redis.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/redis.md @@ -1,6 +1,6 @@ --- aliases: - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/redis/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/redis/ description: Redis 协议 linkTitle: Redis 协议 title: Redis 协议 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/rmi.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/rmi.md index 191f6463e2d0..040216270107 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/rmi.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/rmi.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/rmi/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/rmi/ - - /zh/overview/what/ecosystem/protocol/rmi/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/rmi/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/rmi/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/rmi/ + - /en/overview/what/ecosystem/protocol/rmi/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/rmi/ description: Rmi协议 linkTitle: Rmi协议 title: Rmi协议 @@ -41,7 +41,7 @@ RMI 协议采用 JDK 标准的 `java.rmi.*` 实现,采用阻塞式短连接和 ### 引入依赖 -从 Dubbo 3 开始,RMI 协议已经不再内嵌在 Dubbo 中,需要单独引入独立的[模块](/zh-cn/download/spi-extensions/#dubbo-rpc)。 +从 Dubbo 3 开始,RMI 协议已经不再内嵌在 Dubbo 中,需要单独引入独立的[模块](/en/download/spi-extensions/#dubbo-rpc)。 ```xml org.apache.dubbo.extensions diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/thrift.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/thrift.md index 028ddbf24c5a..027feeb59cd7 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/thrift.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/thrift.md @@ -1,6 +1,6 @@ --- aliases: - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/thrift/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/thrift/ description: Thrift 协议 linkTitle: Thrift 协议 title: Thrift 协议 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/v3.2_rest_protocol_design.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/v3.2_rest_protocol_design.md index 025ecc665590..36b8f3d7c54d 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/v3.2_rest_protocol_design.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/v3.2_rest_protocol_design.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ - - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ - zh-cn/overview/mannual/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ description: 本文将介绍 Dubbo 的 Rest 协议。 linkTitle: Rest 协议 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/webservice.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/webservice.md index 6da21d39eedc..5d5910ad6ee6 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/webservice.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/others/webservice.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/webservice/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/webservice/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/webservice/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/webservice/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/webservice/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/webservice/ description: Webservice协议 linkTitle: Webservice协议 title: Webservice协议 @@ -34,7 +34,7 @@ CXF 是 Apache 开源的一个 RPC 框架,由 Xfire 和 Celtix 合并而来。 ## 使用方式 ### 依赖 -从 Dubbo 3 开始,Webservice 协议已经不再内嵌在 Dubbo 中,需要单独引入独立的[模块](/zh-cn/download/spi-extensions/#dubbo-rpc)。 +从 Dubbo 3 开始,Webservice 协议已经不再内嵌在 Dubbo 中,需要单独引入独立的[模块](/en/download/spi-extensions/#dubbo-rpc)。 ```xml org.apache.dubbo.extensions diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/overview.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/overview.md index c9c60b3e953b..ffe55ef0d57b 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/overview.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/overview.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/overview/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/overview/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/overview/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/overview/ description: 协议概述 linkTitle: 协议概述 title: 协议概述 @@ -31,11 +31,11 @@ Dubbo 作为一款 RPC 框架内置了高效的 RPC 通信协议,帮助解决 {{% alert title="注意" color="warning" %}} * 自 3.3 版本开始,triple 协议支持以 rest 风格发布标准的 http 服务,因此框架中实际已不存在独立的 rest protocol 扩展实现, - * 考虑到对过往版本的兼容性,当前 Dubbo 各个发行版本均默认使用 `dubbo` 通信协议。**对于新用户而言,我们强烈建议在一开始就明确配置使用 `triple` 协议**,老用户也尽快参考文档 [实现协议的平滑迁移](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/migration)。 + * 考虑到对过往版本的兼容性,当前 Dubbo 各个发行版本均默认使用 `dubbo` 通信协议。**对于新用户而言,我们强烈建议在一开始就明确配置使用 `triple` 协议**,老用户也尽快参考文档 [实现协议的平滑迁移](/en/overview/mannual/java-sdk/reference-manual/protocol/triple/migration)。 {{% /alert %}} ## 多协议扩展 -以下是当前 Dubbo 官方生态库提供的拓展协议实现。如果要扩展更多自定义协议,请参考 [SPI 扩展手册](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/) 或 [使用教程 - 协议扩展](/zh-cn/overview/mannual/java-sdk/tasks/extensibility/protocol/)。 +以下是当前 Dubbo 官方生态库提供的拓展协议实现。如果要扩展更多自定义协议,请参考 [SPI 扩展手册](/en/overview/mannual/java-sdk/reference-manual/spi/) 或 [使用教程 - 协议扩展](/en/overview/mannual/java-sdk/tasks/extensibility/protocol/)。 | 协议 | 配置值 | 说明 | | --- | --- | --- | diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/rest.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/protocol/rest.md.bak index e53ad674b3a8..949364ff499d 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/rest.md.bak +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/rest.md.bak @@ -1,6 +1,6 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/rest/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/rest/ - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/rest/ description: Rest协议 linkTitle: rest @@ -93,7 +93,7 @@ http://localhost:8080/users/register 首先,开发服务的接口 ```java -public class UserService { +public class UserService { void registerUser(User user); } ``` @@ -103,7 +103,7 @@ public class UserService { ```java @Path("users") public class UserServiceImpl implements UserService { - + @POST @Path("register") @Consumes({MediaType.APPLICATION_JSON}) @@ -127,13 +127,13 @@ public class UserServiceImpl implements UserService { ```xml - + - + -``` +``` ### REST 服务提供端 @@ -183,7 +183,7 @@ public User getUser(@PathParam("id") Long id) { ```java @Path("users") public interface UserService { - + @GET @Path("{id : \\d+}") @Produces({MediaType.APPLICATION_JSON}) @@ -261,7 +261,7 @@ User getUser(@PathParam("id") Long id); public class User implements Serializable { // ... } -``` +``` 此外,如果service方法中的返回值是Java的 primitive类型(如int,long,float,double等),最好为它们添加一层wrapper对象,因为JAXB不能直接序列化primitive类型。 @@ -276,20 +276,20 @@ long registerUser(User user); ```java @XmlRootElement public class RegistrationResult implements Serializable { - + private Long id; - + public RegistrationResult() { } - + public RegistrationResult(Long id) { this.id = id; } - + public Long getId() { return id; } - + public void setId(Long id) { this.id = id; } @@ -311,7 +311,7 @@ RegistrationResult registerUser(User user); 如果不加 wrapper,JSON 返回值将直接是 ``` -1001 +1001 ``` 而在 XML 中,加 wrapper 后返回值将是: @@ -336,9 +336,9 @@ Dubbo 中的 REST 实现是用 JAXB 做 XML 序列化,用 Jackson 做 JSON 序 @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class User implements Serializable { - - @XmlElement(name="username") - private String name; + + @XmlElement(name="username") + private String name; } ``` @@ -346,7 +346,7 @@ public class User implements Serializable { ```java public class User implements Serializable { - + @JsonProperty("username") private String name; } @@ -398,21 +398,21 @@ public class User implements Serializable { contextConfigLocation /WEB-INF/classes/META-INF/spring/dubbo-demo-provider.xml - + org.apache.dubbo.remoting.http.servlet.BootstrapListener - + org.springframework.web.context.ContextLoaderListener - + dispatcher org.apache.dubbo.remoting.http.servlet.DispatcherServlet 1 - + dispatcher /* @@ -437,7 +437,7 @@ public class User implements Serializable { ```java public User getUser(@PathParam("id") Long id, @Context HttpServletRequest request) { System.out.println("Client address is " + request.getRemoteAddr()); -} +} ``` 用 Context 修饰 getUser() 的一个方法参数后,就可以将当前的 HttpServletRequest 注入进来,然后直接调用 servlet api 获取 IP。 @@ -449,7 +449,7 @@ public User getUser(@PathParam("id") Long id, @Context HttpServletRequest reques ```java public User getUser(@PathParam("id") Long id) { System.out.println("Client address is " + RpcContext.getContext().getRemoteAddressString()); -} +} ``` > 注意:这种方式只能在设置 server="jetty" 或者 server="tomcat" 或者 server="servlet" 或者 server="tjws" 的时候才能工作。另外,目前 dubbo 的 RpcContext 是一种比较有侵入性的用法,未来我们很可能会做出重构。 @@ -507,13 +507,13 @@ dubbo 中的 rest 协议默认将采用80端口,如果想修改端口,直接 ```java @Path("users") public class UserServiceImpl implements UserService { - + @POST @Path("register") @Consumes({MediaType.APPLICATION_JSON}) public void registerUser(User user) { // save the user... - } + } } ``` @@ -604,14 +604,14 @@ public class UserServiceImpl implements UserService { @Autowired private UserRepository userRepository; - + @POST @Path("register") @Consumes({MediaType.APPLICATION_JSON}) public void registerUser(User user) { // save the user userRepository.save(user); - } + } } ``` @@ -640,7 +640,7 @@ Interceptor 主要用于访问和修改输入与输出字节流,例如,手 ```java public class GZIPWriterInterceptor implements WriterInterceptor { - + @Override public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { @@ -667,7 +667,7 @@ public class GZIPWriterInterceptor implements WriterInterceptor { ```java public class LoggingFilter implements ClientResponseFilter { - + public void filter(ClientRequestContext reqCtx, ClientResponseContext resCtx) throws IOException { System.out.println("status: " + resCtx.getStatus()); System.out.println("date: " + resCtx.getDate()); @@ -682,7 +682,7 @@ public class LoggingFilter implements ClientResponseFilter { System.out.print("\n"); } System.out.println("media-type: " + resCtx.getMediaType().getType()); - } + } } ``` @@ -693,7 +693,7 @@ Dubbo 的 REST 也支持 JAX-RS 标准的 ExceptionMapper,可以用来定制 ```java public class CustomExceptionMapper implements ExceptionMapper { - public Response toResponse(NotFoundException e) { + public Response toResponse(NotFoundException e) { return Response.status(Response.Status.NOT_FOUND).entity("Oops! the requested resource is not found!").type("text/plain").build(); } } @@ -736,7 +736,7 @@ Dubbo rest 支持输出所有 HTTP 请求/响应中的 header 字段和 body 消 然后在日志中会有类似如下的内容输出 ``` -The HTTP headers are: +The HTTP headers are: accept: application/json;charset=UTF-8 accept-encoding: gzip, deflate connection: Keep-Alive @@ -747,7 +747,7 @@ user-agent: Apache-HttpClient/4.2.1 (java 1.5) ``` ``` -The contents of request body is: +The contents of request body is: {"id":1,"name":"dang"} ``` @@ -761,7 +761,7 @@ dubbo 的 rest 支持采用 Java 标准的 bean validation annotation(JSR 303) ```java public interface UserService { - + User getUser(@Min(value=1L, message="User ID must be greater than 1") Long id); } diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual.md index db1bca0760a2..0f2f3f5205fd 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/rest/manual/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/rest/manual/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/rest/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/http/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/rest/manual/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/rest/manual/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/rest/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/http/ description: "本文是Triple Rest的用户使用手册" linkTitle: triple-rest用户手册 title: Triple Rest 用户手册 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple-3.3.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple-3.3.md index ff73d7ec5d9e..e4a7ac1a8a73 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple-3.3.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple-3.3.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/3.3/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/3.3/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/3.3/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/3.3/ description: "本文介绍 triple 协议在 3.3 版本中的新特性" linkTitle: tripe-3.3新特性 title: Tripe 3.3 新特性 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md b/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md index 5fccb7b7b3a8..9879ab6dab2c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md @@ -1,13 +1,13 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/grpc/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/guide/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/migration - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/overview/ - - /zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/protobufinterface/ - - /zh-cn/overview/mannual/java-sdk/tasks/gateway/triple/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/grpc/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/triple/guide/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/triple/migration + - /en/overview/mannual/java-sdk/reference-manual/protocol/triple/overview/ + - /en/overview/mannual/java-sdk/upgrades-and-compatibility/protobufinterface/ + - /en/overview/mannual/java-sdk/tasks/gateway/triple/ description: "本文 triple 在 dubbo java 实现中的一些具体细节,配置方式、性能指标等" linkTitle: triple title: 协议概述 @@ -15,7 +15,7 @@ type: docs weight: 2 --- -请参考文档其他部分了解 [triple 协议规范规范](/zh-cn/overview/reference/protocols/triple-spec/) 和 [基本使用方式](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/)。本文只展开 triple 协议 Java 实现中的一些具体细节内容。 +请参考文档其他部分了解 [triple 协议规范规范](/en/overview/reference/protocols/triple-spec/) 和 [基本使用方式](/en/overview/mannual/java-sdk/tasks/protocols/triple/)。本文只展开 triple 协议 Java 实现中的一些具体细节内容。 ## 编程模式 使用 triple 协议时,开发者可以使用 `Java Interface`、`Protobuf(IDL)` 两种方式定义 RPC 服务,两种服务定义方式的协议能力是对等的,仅影响开发者的编程体验、序列化方式,具体选用那种开发模式,取决于使用者的业务背景。 @@ -55,7 +55,7 @@ service Greeter{ } ``` -通过 [Dubbo 提供的 protoc 编译插件](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/#生成的代码无法编译),将以上 IDL 服务定义预编译为相关 stub 代码,其中就包含 Dubbo 需要的 Interface 接口定义,因此在后续编码上区别并不大,只不过相比于前面的用户自定义 Java Interface 模式,这里由插件自动帮我们生成 Interface 定义。 +通过 [Dubbo 提供的 protoc 编译插件](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/#生成的代码无法编译),将以上 IDL 服务定义预编译为相关 stub 代码,其中就包含 Dubbo 需要的 Interface 接口定义,因此在后续编码上区别并不大,只不过相比于前面的用户自定义 Java Interface 模式,这里由插件自动帮我们生成 Interface 定义。 ```java // Generated by dubbo protoc plugin diff --git a/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md.bak index 40727de64178..be85752e2e97 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md.bak +++ b/content/en/overview/mannual/java-sdk/reference-manual/protocol/triple.md.bak @@ -1,6 +1,6 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/ - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/ description: 协议概述 linkTitle: triple @@ -24,7 +24,7 @@ weight: 2 当前使用其他协议的 Dubbo 用户,框架提供了兼容现有序列化方式的迁移能力,在不影响线上已有业务的前提下,迁移协议的成本几乎为零。 -### GRPC +### GRPC 需要新增对接 grpc 服务的 Dubbo 用户,可以直接使用 Triple 协议来实现打通,不需要单独引入 grpc client 来完成,不仅能保留已有的 Dubbo 易用性,也能降低程序的复杂度和开发运维成本,不需要额外进行适配和开发即可接入现有生态。 ### 网关接入 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/_index.md index f2ed9eafcb95..bca6f3646116 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/qos/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/qos/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/ + - /en/docs3-v2/java-sdk/reference-manual/qos/ + - /en/docs3-v2/java-sdk/reference-manual/qos/ description: Dubbo QOS 操作指南 linkTitle: 单机运维命令(QOS) title: QOS 操作手册 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/command.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/command.md index 53abb18c3e3b..55c4b70edb9d 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/command.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/command.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/qos/command/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/command/ + - /en/docs3-v2/java-sdk/reference-manual/qos/command/ + - /en/docs3-v2/java-sdk/reference-manual/qos/command/ description: 基础命令手册 linkTitle: 基础命令手册 title: 基础命令手册 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/default_metrics.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/default_metrics.md index 1ce36706f368..51b4c93c20e1 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/default_metrics.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/default_metrics.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/qos/logger-management/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/logger-management/ + - /en/docs3-v2/java-sdk/reference-manual/qos/logger-management/ + - /en/docs3-v2/java-sdk/reference-manual/qos/logger-management/ description: 当用户未接入 prometheus 时可以使用默认的监控指标命令 linkTitle: 默认监控指标命令 title: 默认监控指标命令 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/logger-management.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/logger-management.md index 3f1f155c1fb4..f3b453b1db15 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/logger-management.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/logger-management.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/qos/logger-management/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/logger-management/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/logger-management/ + - /en/docs3-v2/java-sdk/reference-manual/qos/logger-management/ + - /en/docs3-v2/java-sdk/reference-manual/qos/logger-management/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/others/logger-management/ description: 在 Dubbo 中运行时动态切换使用的日志框架 linkTitle: 日志框架运行时管理 title: 日志框架运行时管理 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/probe.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/probe.md index dbb0cd0301d9..7f5be25b4805 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/probe.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/probe.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/qos/probe/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/probe/ + - /en/docs3-v2/java-sdk/reference-manual/qos/probe/ + - /en/docs3-v2/java-sdk/reference-manual/qos/probe/ description: 框架状态命令 linkTitle: 框架状态命令 title: 框架状态命令 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/profiler.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/profiler.md index b92ad9bab81d..aa779fbb82dd 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/profiler.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/profiler.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/qos/profiler/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/profiler/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/qos/profiler/ + - /en/docs3-v2/java-sdk/reference-manual/qos/profiler/ + - /en/docs3-v2/java-sdk/reference-manual/qos/profiler/ + - /en/overview/mannual/java-sdk/reference-manual/qos/profiler/ description: 性能采样命令 linkTitle: 性能采样命令 title: 性能采样命令 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/router-snapshot.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/router-snapshot.md index 4c5c3e165189..cd9aef30c106 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/router-snapshot.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/router-snapshot.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/qos/router-snapshot/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/router-snapshot/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/qos/router-snapshot/ + - /en/docs3-v2/java-sdk/reference-manual/qos/router-snapshot/ + - /en/docs3-v2/java-sdk/reference-manual/qos/router-snapshot/ + - /en/overview/mannual/java-sdk/reference-manual/qos/router-snapshot/ description: 路由状态命令 linkTitle: 路由状态命令 title: 路由状态命令 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/security.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/security.md index 85197b145afb..f0ee6f54030f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/security.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/security.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/qos/security/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/security/ + - /en/docs3-v2/java-sdk/reference-manual/qos/security/ + - /en/docs3-v2/java-sdk/reference-manual/qos/security/ description: 序列化安全审计 linkTitle: 序列化安全审计 title: 序列化安全审计 @@ -80,5 +80,5 @@ dubbo> {{% alert title="注意" color="primary" %}} 建议及时关注 `serializeWarnedClasses` 的结果,通过返回结果是否非空来判断是否受到攻击。 -[Dubbo 类检查机制](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/)。 +[Dubbo 类检查机制](/en/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/)。 {{% /alert %}} diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/service-management.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/service-management.md index afbe235871cd..3f4cd4a14de3 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/service-management.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/introduction/service-management.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/qos/service-management/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/service-management/ + - /en/docs3-v2/java-sdk/reference-manual/qos/service-management/ + - /en/docs3-v2/java-sdk/reference-manual/qos/service-management/ description: 服务管理命令 linkTitle: 服务管理命令 title: 服务管理命令 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/overview.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/overview.md index 2bdc5d25367a..28a0bbba355b 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/qos/overview.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/overview.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/qos/overview/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/qos/overview/ + - /en/docs3-v2/java-sdk/reference-manual/qos/overview/ + - /en/docs3-v2/java-sdk/reference-manual/qos/overview/ description: "QoS 命令的设计目的、使用方法说明,包括如何开启、关闭 qos 命令等,支持 HTTP/Telnet 访问方式," linkTitle: QOS 概述 title: QOS 概述 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/qos/qos-list.md b/content/en/overview/mannual/java-sdk/reference-manual/qos/qos-list.md index 7be8be1602f8..682be5037794 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/qos/qos-list.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/qos/qos-list.md @@ -1,6 +1,6 @@ --- aliases: - - /zh-cn/overview/mannual/java-sdk/reference-manual/qos/command/ + - /en/overview/mannual/java-sdk/reference-manual/qos/command/ description: "QoS 命令列表、命令大全。" linkTitle: 命令列表 title: QoS 命令列表,命令大全 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/_index.md index 7d24bc99fd54..961f0d4b0c6c 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/registry/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/others/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/others/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/others/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/others/ description: 注册中心 linkTitle: 注册中心与服务发现 title: 注册中心、服务发现与负载均衡 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/multiple-registry.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/multiple-registry.md index 9c0a9e842745..eb056d372722 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/registry/multiple-registry.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/multiple-registry.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/registry/multiple-registry/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/registry/multiple-registry/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-registry/ + - /en/docs3-v2/java-sdk/reference-manual/registry/multiple-registry/ + - /en/docs3-v2/java-sdk/reference-manual/registry/multiple-registry/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-registry/ description: 本文介绍了 Dubbo 的多注册中心支持及使用场景,如何通过多注册/多订阅实现跨区域服务部署、服务迁移等,也描述了同机房有限等跨机房流量调度的实现方式。 linkTitle: 多注册中心 title: 多注册中心 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/nacos.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/nacos.md index 98edcb84973d..c58db836c7f8 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/registry/nacos.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/nacos.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ description: "通过示例演示如何使用 Nacos 作为注册中心实现自动服务发现。" linkTitle: nacos title: 使用 Nacos 作为注册中心实现自动服务发现 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/_index.md index 11c5e2e0865b..d126beba96a9 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/others/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/others/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/others/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/others/ description: 注册中心 linkTitle: 扩展实现 title: 注册中心、服务发现与负载均衡 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/consul.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/consul.md index 406b76ed516a..736a6e365176 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/consul.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/consul.md @@ -8,14 +8,14 @@ weight: 5 ## 前置条件 -* 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/starter/) +* 了解 [Dubbo 基本开发步骤](/en/overview/mannual/java-sdk/quick-start/starter/) * 安装并启动 [Consul](http://consul.io) 服务 ## 使用说明 ### 添加依赖 -从 Dubbo3 开始,consul 注册中国适配已经不再内嵌在 Dubbo 中,使用前需要单独引入独立的[模块](/zh-cn/download/spi-extensions/#dubbo-registry)。 +从 Dubbo3 开始,consul 注册中国适配已经不再内嵌在 Dubbo 中,使用前需要单独引入独立的[模块](/en/download/spi-extensions/#dubbo-registry)。 ```xml @@ -50,4 +50,4 @@ weight: 5 ## 使用场景 -使用 Consul 作为共享注册中心实现,可用于 [Dubbo 与 Spring Cloud 体系的互通或迁移](/zh-cn/blog/2023/10/07/微服务最佳实践零改造实现-spring-cloud-apache-dubbo-互通/) +使用 Consul 作为共享注册中心实现,可用于 [Dubbo 与 Spring Cloud 体系的互通或迁移](/en/blog/2023/10/07/微服务最佳实践零改造实现-spring-cloud-apache-dubbo-互通/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/etcd.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/etcd.md index aa8475231df5..3ac637a2be12 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/etcd.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/etcd.md @@ -9,14 +9,14 @@ weight: 5 ## 前置条件 -* 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/starter/) +* 了解 [Dubbo 基本开发步骤](/en/overview/mannual/java-sdk/quick-start/starter/) * 安装并启动 Etcd 服务 ## 使用说明 ### 添加依赖 -从 Dubbo3 开始,etcd 注册中心适配已经不再内嵌在 Dubbo 中,使用前需要单独引入独立的[模块](/zh-cn/download/spi-extensions/#dubbo-registry)。 +从 Dubbo3 开始,etcd 注册中心适配已经不再内嵌在 Dubbo 中,使用前需要单独引入独立的[模块](/en/download/spi-extensions/#dubbo-registry)。 ```xml @@ -47,4 +47,4 @@ weight: 5 ```xml -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/multicast.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/multicast.md index 6abd7d91df08..8967d5ecc3dc 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/multicast.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/multicast.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/registry/multicast/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/registry/multicast/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/registry/multicast/ + - /en/docs3-v2/java-sdk/reference-manual/registry/multicast/ + - /en/docs3-v2/java-sdk/reference-manual/registry/multicast/ + - /en/overview/mannual/java-sdk/reference-manual/registry/multicast/ description: Multicast 广播注册中心(限开发阶段使用)。 linkTitle: Multicast title: Multicast diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/redis.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/redis.md index 8a05e862de48..e4d34b02150c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/registry/others/redis.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/others/redis.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/registry/redis/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/registry/redis/ - - /zh-cn/overview/what/ecosystem/registry/redis/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/registry/redis/ + - /en/docs3-v2/java-sdk/reference-manual/registry/redis/ + - /en/docs3-v2/java-sdk/reference-manual/registry/redis/ + - /en/overview/what/ecosystem/registry/redis/ + - /en/overview/mannual/java-sdk/reference-manual/registry/redis/ description: Redis 注册中心的基本使用和工作原理。 linkTitle: Redis title: Redis @@ -14,14 +14,14 @@ weight: 5 ## 前置条件 -* 了解 [Dubbo 基本开发步骤](/zh-cn/overview/mannual/java-sdk/quick-start/starter/) +* 了解 [Dubbo 基本开发步骤](/en/overview/mannual/java-sdk/quick-start/starter/) * 安装并启动 [Redis](http://redis.io) 服务 ## 使用说明 ### 添加依赖 -从 Dubbo3 开始,redis 注册中心适配已经不再内嵌在 Dubbo 中,使用前需要单独引入独立的[模块](/zh-cn/download/spi-extensions/#dubbo-registry)。 +从 Dubbo3 开始,redis 注册中心适配已经不再内嵌在 Dubbo 中,使用前需要单独引入独立的[模块](/en/download/spi-extensions/#dubbo-registry)。 ```xml diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/overview.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/overview.md index 2fe82a1643fa..185af2201404 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/registry/overview.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/overview.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/registry/overview/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/registry/overview/ + - /en/docs3-v2/java-sdk/reference-manual/registry/overview/ + - /en/docs3-v2/java-sdk/reference-manual/registry/overview/ description: "" linkTitle: 注册中心概述 title: 注册中心概述 @@ -10,7 +10,7 @@ weight: 1 --- -注册中心是 Dubbo 服务治理的核心组件,Dubbo 依赖注册中心的协调实现服务(地址)发现,自动化的服务发现是微服务实现动态扩缩容、负载均衡、、流量治理的基础。Dubbo 的服务发现机制经历了 Dubbo2 时代的接口级服务发现、Dubbo3 时代的应用级服务发现,具体可参见 [服务发现机制](/zh-cn/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/) 解析了解具体演进过程。 +注册中心是 Dubbo 服务治理的核心组件,Dubbo 依赖注册中心的协调实现服务(地址)发现,自动化的服务发现是微服务实现动态扩缩容、负载均衡、、流量治理的基础。Dubbo 的服务发现机制经历了 Dubbo2 时代的接口级服务发现、Dubbo3 时代的应用级服务发现,具体可参见 [服务发现机制](/en/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/) 解析了解具体演进过程。 ![service-discovery](/imgs/v3/feature/service-discovery/arc.png) @@ -36,7 +36,7 @@ dubbo 3.3.0 及之后的版本可不配置注册中心。而在 3.3.0 版本之前的 Dubbo 应用必须指定注册中心配置,即使不启用注册中心也要配置(可通过设置地址为空 address='N/A' )。 {{% /alert %}} -每个注册中心组件有自己特有的配置,可以用来控制命名空间、分组、鉴权等,具体可以参考 [registry 配置参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#registry)或通过 parameters 参数进行扩展。 +每个注册中心组件有自己特有的配置,可以用来控制命名空间、分组、鉴权等,具体可以参考 [registry 配置参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/#registry)或通过 parameters 参数进行扩展。 ## 配置中心与元数据中心 配置中心、元数据中心是实现 Dubbo 高阶服务治理能力会依赖的组件,如流量管控规则等,相比于注册中心通常这两个组件的配置是可选的。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/service-discovery-application-vs-interface.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/service-discovery-application-vs-interface.md index 577d06b2cd9e..99786e2c6574 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/registry/service-discovery-application-vs-interface.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/service-discovery-application-vs-interface.md @@ -101,9 +101,9 @@ Dubbo3 的应用级服务发现方案设计本质上就是围绕以上两个问 1. 期望简化进入注册中心的 provider 和 consumer 配置数量。 2. 期望将部分配置项以其他形式存储。这些配置项需要满足:不在服务调用链路上,同时这些配置项不在注册中心的核心链路上(服务查询,服务列表)。 -Dubbo provider 中的服务配置项有接近 [30 个配置项](/zh-cn/docs/references/xml/dubbo-parameter)。 排除注册中心服务治理需要之外,很大一部分配置项是 provider 自己使用,不需要透传给消费者。这部分数据不需要进入注册中心,而只需要以 key-value 形式持久化存储。 +Dubbo provider 中的服务配置项有接近 [30 个配置项](/en/docs/references/xml/dubbo-parameter)。 排除注册中心服务治理需要之外,很大一部分配置项是 provider 自己使用,不需要透传给消费者。这部分数据不需要进入注册中心,而只需要以 key-value 形式持久化存储。 -Dubbo consumer 中的配置项也有 [20+个配置项](/zh-cn/docs/references/xml/dubbo-consumer)。在注册中心之中,服务消费者列表中只需要关注 application,version,group,ip,dubbo 版本等少量配置,其他配置也可以以 key-value 形式持久化存储。 +Dubbo consumer 中的配置项也有 [20+个配置项](/en/docs/references/xml/dubbo-consumer)。在注册中心之中,服务消费者列表中只需要关注 application,version,group,ip,dubbo 版本等少量配置,其他配置也可以以 key-value 形式持久化存储。 这些数据是以服务为维度注册进入注册中心,导致了数据量的膨胀,进而引发注册中心 (如 zookeeper) 的网络开销增大,性能降低。 {{% alert title="注意" color="warning" %}} diff --git a/content/en/overview/mannual/java-sdk/reference-manual/registry/zookeeper.md b/content/en/overview/mannual/java-sdk/reference-manual/registry/zookeeper.md index 7e779fb8a3b5..63e9a4cde729 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/registry/zookeeper.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/registry/zookeeper.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ description: "通过示例演示如何使用 Zookeepoer 作为注册中心实现自动服务发现。" linkTitle: zookeeper title: 使用 Zookeeper 作为注册中心实现自动服务发现 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/_index.md index f084c4cd4e2a..8958a6a8e95c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/what/ecosystem/serialization/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/serialization/ + - /en/overview/what/ecosystem/serialization/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/performance/serialization/ description: "Dubbo 序列化使用指南" linkTitle: 序列化协议 title: 序列化 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/_index.md index b0a1217260b0..d84af82cfa40 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/_index.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/what/ecosystem/serialization/ + - /en/overview/what/ecosystem/serialization/ description: "dubbo 协议支持的序列化协议" linkTitle: dubbo title: dubbo 协议支持的序列化 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/avro.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/avro.md index 685c34c98160..743859582000 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/avro.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/avro.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/what/ecosystem/serialization/avro/ - - /zh-cn/overview/what/ecosystem/serialization/avro/ + - /en/overview/what/ecosystem/serialization/avro/ + - /en/overview/what/ecosystem/serialization/avro/ description: "本文介绍 Avro 序列化" linkTitle: Avro title: Avro diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson.md index 344d72ce39c4..1361a23cf78e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/what/ecosystem/serialization/fastjson/ - - /zh-cn/overview/what/ecosystem/serialization/fastjson/ + - /en/overview/what/ecosystem/serialization/fastjson/ + - /en/overview/what/ecosystem/serialization/fastjson/ description: "本文介绍 Fastjson 序列化" linkTitle: Fastjson title: Fastjson diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson2.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson2.md index 1ab5961dad38..3dc5917b8a4c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson2.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fastjson2.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/what/ecosystem/serialization/fastjson2/ - - /zh-cn/overview/what/ecosystem/serialization/fastjson2/ + - /en/overview/what/ecosystem/serialization/fastjson2/ + - /en/overview/what/ecosystem/serialization/fastjson2/ description: "本文介绍 Fastjson2 序列化" linkTitle: Fastjson2 title: Fastjson2 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fst.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fst.md index 3a3096fb2f0b..b4eee9489ce9 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fst.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/fst.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/what/ecosystem/serialization/fst/ - - /zh-cn/overview/what/ecosystem/serialization/fst/ + - /en/overview/what/ecosystem/serialization/fst/ + - /en/overview/what/ecosystem/serialization/fst/ description: "本文介绍 FST 序列化" linkTitle: FST title: FST diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/gson.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/gson.md index cbadc5f3e9a2..b61c5e20de75 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/gson.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/gson.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/what/ecosystem/serialization/gson/ - - /zh-cn/overview/what/ecosystem/serialization/gson/ + - /en/overview/what/ecosystem/serialization/gson/ + - /en/overview/what/ecosystem/serialization/gson/ description: "本文介绍 Gson 序列化" linkTitle: Gson title: Gson diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/hessian.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/hessian.md index 2a98ff40eca4..b02f182e93d9 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/hessian.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/hessian.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/what/ecosystem/serialization/hessian/ - - /zh-cn/overview/what/ecosystem/serialization/hessian/ + - /en/overview/what/ecosystem/serialization/hessian/ + - /en/overview/what/ecosystem/serialization/hessian/ description: "本文介绍 Hessian 序列化" linkTitle: Hessian title: Hessian diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/kryo.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/kryo.md index b9fb5fd37de0..09b4fc49522f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/kryo.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/kryo.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/what/ecosystem/serialization/kryo/ - - /zh-cn/overview/what/ecosystem/serialization/kryo/ + - /en/overview/what/ecosystem/serialization/kryo/ + - /en/overview/what/ecosystem/serialization/kryo/ description: "本文介绍 Kryo 序列化" linkTitle: Kryo title: Kryo diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/msgpack.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/msgpack.md index 89c23d009dcc..7988a7111cea 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/msgpack.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/dubbo/msgpack.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/what/ecosystem/serialization/msgpack/ - - /zh-cn/overview/what/ecosystem/serialization/msgpack/ + - /en/overview/what/ecosystem/serialization/msgpack/ + - /en/overview/what/ecosystem/serialization/msgpack/ description: "本文介绍 MessagePack 序列化" linkTitle: MessagePack title: MessagePack diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization-upgrade.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization-upgrade.md index bfdb578304fa..f83266197d32 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization-upgrade.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization-upgrade.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/serialization-upgrade/ - - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/serialization-upgrade/ - - /zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/serialization-upgrade/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/serialization-upgrade/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/serialization-upgrade/ + - /en/overview/mannual/java-sdk/upgrades-and-compatibility/serialization-upgrade/ description: 无损升级序列化协议指南 linkTitle: 序列化协议升级 title: 序列化协议升级 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization.md index ef2199fed071..1ec3d11fe4d8 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/serialization.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/serialization/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/serialization/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/serialization/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/serialization/ description: 在 Dubbo 中使用高效的 Java 序列化(Kryo 和 FST) linkTitle: 序列化概述 title: Dubbo 序列化机制介绍 @@ -29,7 +29,7 @@ weight: 1 序列化对于远程调用的响应速度、吞吐量、网络带宽消耗等起着至关重要的作用,是我们提升分布式系统性能的最关键因素之一。 -具体请查看 [参考手册 - 性能基准报告](/zh-cn/overview/mannual/java-sdk/reference-manual/performance/)。 +具体请查看 [参考手册 - 性能基准报告](/en/overview/mannual/java-sdk/reference-manual/performance/)。 ## 切换序列化协议 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/_index.md index d01699b5915b..549ed7a4f8a6 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/_index.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/what/ecosystem/serialization/ + - /en/overview/what/ecosystem/serialization/ description: "triple 协议支持的序列化协议" linkTitle: triple title: triple 协议支持的序列化 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/protobuf.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/protobuf.md index 0a5f298a1e9c..4e39285de532 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/protobuf.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/protobuf.md @@ -1,6 +1,6 @@ --- aliases: - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/idl/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/triple/idl/ description: "本文介绍 protobuf 序列化,如何在 triple 协议场景下使用 protobuf、json 序列化。" linkTitle: Protobuf title: 如何在 triple 协议场景下使用 protobuf、json 序列化 @@ -13,7 +13,7 @@ weight: 1 Protobuf(Protocol Buffers) 是由 Google 开发的一种轻量级、高效的数据交换格式,它被用于结构化数据的序列化、反序列化和传输。 相比于XML 和JSON 等文本格式,Protobuf 具有更小的数据体积、更快的解析速度和更强的可扩展性。 ## 2 使用方式 -**在使用 [Protobuf(IDL) 开发 triple 通信服务](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/) 的时候,dubbo server 将自动启用 protobuf、protobuf-json 序列化模式支持。** +**在使用 [Protobuf(IDL) 开发 triple 通信服务](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/) 的时候,dubbo server 将自动启用 protobuf、protobuf-json 序列化模式支持。** ### 2.1 添加依赖 使用 triple + protobuf 模式,必须添加以下依赖: @@ -35,7 +35,7 @@ weight: 1 ``` ### 2.2 配置启用 -只要是基于 [Protobuf(IDL) 开发模式进行 triple 协议通信](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/) ,就会使用 protobuf 序列化,只要定义 protobuf 文件并启用 triple 协议即可。 +只要是基于 [Protobuf(IDL) 开发模式进行 triple 协议通信](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/) ,就会使用 protobuf 序列化,只要定义 protobuf 文件并启用 triple 协议即可。 当使用 cURL 访问 triple 服务时,是会启用 protobuf-json 序列化模式 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/wrapper.md b/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/wrapper.md index fbf99f95373d..81124b095d25 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/wrapper.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/serialization/triple/wrapper.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/what/ecosystem/serialization/fastjson/ - - /zh-cn/overview/what/ecosystem/serialization/fastjson/ + - /en/overview/what/ecosystem/serialization/fastjson/ + - /en/overview/what/ecosystem/serialization/fastjson/ description: "本文介绍基于 Java 接口模式开发 triple 服务时,底层的序列化机制实现。" linkTitle: Protobuf Wrapper title: 基于 Java 接口模式开发 triple 服务时,底层的序列化机制实现 @@ -18,7 +18,7 @@ Dubbo 实现的 triple 协议易用性更好(不绑定 Protobuf),开发者 ## 2 使用方式 -**在使用 [Java 接口方式开发 triple 通信服务](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/) 的时候,dubbo server 将自动启用 protobuf、protobuf-json 序列化模式支持。** +**在使用 [Java 接口方式开发 triple 通信服务](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/) 的时候,dubbo server 将自动启用 protobuf、protobuf-json 序列化模式支持。** ### 2.1 添加依赖 @@ -41,7 +41,7 @@ Dubbo 实现的 triple 协议易用性更好(不绑定 Protobuf),开发者 ``` ### 2.2 配置启用 -只要是基于 [Java 接口方式模式使用 triple 协议](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/) ,就会使用 protobuf wrapper 序列化,只要定义 Java 接口并启用 triple 协议即可: +只要是基于 [Java 接口方式模式使用 triple 协议](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/) ,就会使用 protobuf wrapper 序列化,只要定义 Java 接口并启用 triple 协议即可: 通过 Java 接口定义 Dubbo 服务: ```java diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/_index.md index fb4874fe8a70..d55708bf2be0 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/ + - /en/docs3-v2/java-sdk/reference-manual/spi/ + - /en/docs3-v2/java-sdk/reference-manual/spi/ description: Dubbo SPI 扩展使用指南 linkTitle: SPI插件扩展点 title: SPI 插件扩展点使用手册 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/_index.md index d2046ecac384..edae9b9c8705 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/ description: "Dubbo SPI 插件定义及使用详细介绍。" linkTitle: 部分重点SPI使用说明 title: Dubbo SPI 插件定义及使用详细介绍 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cache.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cache.md index 353a84f2c543..7074065d3147 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cache.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cache.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/cache/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/cache/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/cache/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/cache/ description: 缓存扩展 linkTitle: 缓存扩展 title: 缓存扩展 @@ -94,4 +94,4 @@ META-INF/dubbo/org.apache.dubbo.cache.CacheFactory: ```properties xxx=com.xxx.XxxCacheFactory -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cluster.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cluster.md index 548c26cd652a..cfdca0bd7210 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cluster.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/cluster.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/cluster/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/cluster/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/cluster/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/cluster/ description: 集群扩展 linkTitle: 集群扩展 title: 集群扩展 @@ -89,4 +89,4 @@ META-INF/dubbo/org.apache.dubbo.rpc.cluster.Cluster: ```properties xxx=com.xxx.XxxCluster -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/compiler.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/compiler.md index de8fd9f8b625..085e37ba1c9c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/compiler.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/compiler.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/compiler/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/compiler/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/compiler/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/compiler/ description: 编译器扩展 linkTitle: 编译器扩展 title: 编译器扩展 @@ -66,4 +66,4 @@ META-INF/dubbo/org.apache.dubbo.common.compiler.Compiler: ```properties xxx=com.xxx.XxxCompiler -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/config-center.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/config-center.md index 549365c263d4..fe03c51a8a9e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/config-center.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/config-center.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/config-center/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/config-center/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/config-center/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/config-center/ description: 配置中心扩展 linkTitle: 配置中心扩展 title: 配置中心扩展 @@ -108,4 +108,4 @@ Nacos 作为一个专业的第三方配置中心,拥有专门为配置中心 ### Apollo -Apollo 与 Nacos 类似,请参考动态配置中心使用文档中关于 Apollo 部分的描述。 \ No newline at end of file +Apollo 与 Nacos 类似,请参考动态配置中心使用文档中关于 Apollo 部分的描述。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/container.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/container.md index f39a47b3aa05..a3a0495e55b2 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/container.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/container.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/container/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/container/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/container/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/container/ description: 容器扩展 linkTitle: 容器扩展 title: 容器扩展 @@ -73,4 +73,4 @@ META-INF/dubbo/org.apache.dubbo.container.Container: ```properties xxx=com.xxx.XxxContainer -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/dispatcher.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/dispatcher.md index bf983cdf5da4..3d7b7be66b86 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/dispatcher.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/dispatcher.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/dispatcher/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/dispatcher/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/dispatcher/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/dispatcher/ description: 消息派发扩展 linkTitle: 消息派发扩展 title: 消息派发扩展 @@ -73,4 +73,4 @@ META-INF/dubbo/org.apache.dubbo.remoting.Dispatcher: ```properties xxx=com.xxx.XxxDispatcher -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exchanger.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exchanger.md index 9d082b744132..b4c7313cbee9 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exchanger.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exchanger.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/exchanger/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/exchanger/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/exchanger/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/exchanger/ description: 信息交换扩展 linkTitle: 信息交换扩展 title: 信息交换扩展 @@ -102,4 +102,4 @@ META-INF/dubbo/org.apache.dubbo.remoting.exchange.Exchanger: ```properties xxx=com.xxx.XxxExchanger -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exporter-listener.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exporter-listener.md index c8850e39d00e..ba669035deac 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exporter-listener.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/exporter-listener.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/exporter-listener/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/exporter-listener/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/exporter-listener/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/exporter-listener/ description: 暴露监听扩展 linkTitle: 暴露监听扩展 title: 暴露监听扩展 @@ -76,4 +76,4 @@ META-INF/dubbo/org.apache.dubbo.rpc.ExporterListener: ```properties xxx=com.xxx.XxxExporterListener -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/extension-factory.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/extension-factory.md index 1c78b29bcf9d..67ffcf24ac9f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/extension-factory.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/extension-factory.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/extension-factory/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/extension-factory/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/extension-factory/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/extension-factory/ description: 扩展点加载扩展 linkTitle: 扩展点加载扩展 title: 扩展点加载扩展 @@ -68,4 +68,4 @@ META-INF/dubbo/org.apache.dubbo.common.extension.ExtensionFactory: ```properties xxx=com.xxx.XxxExtensionFactory -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/filter.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/filter.md index 003cab1ae9f0..86df14e4890d 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/filter.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/filter.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/filter/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/filter/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/filter/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/filter/ description: 调用拦截扩展 linkTitle: 调用拦截扩展 title: 调用拦截扩展 @@ -100,4 +100,4 @@ META-INF/dubbo/org.apache.dubbo.rpc.Filter: ```properties xxx=com.xxx.XxxFilter -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/invoker-listener.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/invoker-listener.md index 7b45af6d0285..4bef99eaf868 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/invoker-listener.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/invoker-listener.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/invoker-listener/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/invoker-listener/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/invoker-listener/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/invoker-listener/ description: 引用监听扩展 linkTitle: 引用监听扩展 title: 引用监听扩展 @@ -75,4 +75,4 @@ META-INF/dubbo/org.apache.dubbo.rpc.InvokerListener: ```properties xxx=com.xxx.XxxInvokerListener -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/liveness.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/liveness.md index 1ffebef09fb8..7cb5bad1637b 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/liveness.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/liveness.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/liveness/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/liveness/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/liveness/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/liveness/ description: Liveness 存活探针 linkTitle: 存活探针 title: Liveness 存活探针 @@ -78,4 +78,4 @@ META-INF/dubbo/org.apache.dubbo.qos.probe.LivenessProbe: ``` xxx=com.xxx.XxxLivenessProbe -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/load-balance.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/load-balance.md index 787dbb191688..0ac54aa2339e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/load-balance.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/load-balance.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/load-balance/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/load-balance/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/load-balance/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/load-balance/ description: 负载均衡扩展 linkTitle: 负载均衡扩展 title: 负载均衡扩展 @@ -76,4 +76,4 @@ META-INF/dubbo/org.apache.dubbo.rpc.cluster.LoadBalance: ```properties xxx=com.xxx.XxxLoadBalance -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/logger-adapter.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/logger-adapter.md index 3af5b930e55a..c2672a5792a2 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/logger-adapter.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/logger-adapter.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/logger-adapter/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/logger-adapter/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/logger-adapter/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/logger-adapter/ description: 日志适配扩展 linkTitle: 日志适配扩展 title: 日志适配扩展 @@ -95,4 +95,4 @@ META-INF/dubbo/org.apache.dubbo.common.logger.LoggerAdapter: ```properties xxx=com.xxx.XxxLoggerAdapter -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/merger.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/merger.md index d93cea80c243..f26556ba6744 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/merger.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/merger.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/merger/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/merger/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/merger/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/merger/ description: 合并结果扩展 linkTitle: 合并结果扩展 title: 合并结果扩展 @@ -78,4 +78,4 @@ META-INF/dubbo/org.apache.dubbo.rpc.cluster.Merger: ```properties xxx=com.xxx.XxxMerger -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/metadata-report.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/metadata-report.md index 0671d93ee4ea..3595b95aa1a8 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/metadata-report.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/metadata-report.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/metadata-report/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/metadata-report/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/metadata-report/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/metadata-report/ description: 元数据中心扩展 linkTitle: 元数据中心扩展 title: 元数据中心扩展 @@ -97,4 +97,4 @@ redis=org.apache.dubbo.metadata.store.redis.RedisMetadataReportFactory 只要将上面的修改和project打包成jar包,然后配置元数据中心的url:redis://10.20.153.10:6379。 -至此,一个自定义的元数据存储就可以运行了。 \ No newline at end of file +至此,一个自定义的元数据存储就可以运行了。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/monitor.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/monitor.md index 7cc50bc1ca35..c9fa18577307 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/monitor.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/monitor.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/monitor/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/monitor/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/monitor/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/monitor/ description: 监控中心扩展 linkTitle: 监控中心扩展 title: 监控中心扩展 @@ -86,4 +86,4 @@ META-INF/dubbo/org.apache.dubbo.monitor.MonitorFactory: ```properties xxx=com.xxx.XxxMonitorFactory -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/networker.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/networker.md index 082bb1476b12..fc2becb319cc 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/networker.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/networker.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/networker/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/networker/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/networker/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/networker/ description: 组网扩展 linkTitle: 组网扩展 title: 组网扩展 @@ -70,4 +70,4 @@ META-INF/dubbo/org.apache.dubbo.remoting.p2p.Networker: ```properties xxx=com.xxx.XxxNetworker -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/page.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/page.md index 10e6b03a8991..26960b561bbc 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/page.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/page.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/page/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/page/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/page/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/page/ description: 对等网络节点组网器扩展 linkTitle: 对等网络节点组网器扩展 title: 对等网络节点组网器扩展 @@ -74,4 +74,4 @@ META-INF/dubbo/org.apache.dubbo.container.page.PageHandler: ```properties xxx=com.xxx.XxxPageHandler -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/protocol.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/protocol.md index 54a209b69fb7..91ce119a9359 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/protocol.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/protocol.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/protocol/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/protocol/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/protocol/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/protocol/ description: 协议扩展 linkTitle: 协议扩展 title: 协议扩展 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/proxy-factory.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/proxy-factory.md index 2e09cd55bcd0..3bd4e6c541cf 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/proxy-factory.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/proxy-factory.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/proxy-factory/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/proxy-factory/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/proxy-factory/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/proxy-factory/ description: 动态代理扩展 linkTitle: 动态代理扩展 title: 动态代理扩展 @@ -76,4 +76,4 @@ META-INF/dubbo/org.apache.dubbo.rpc.ProxyFactory: ```properties xxx=com.xxx.XxxProxyFactory -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/qos-permission.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/qos-permission.md index 3a51baff1a1f..17f79f035d5e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/qos-permission.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/qos-permission.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/qos-permission/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/qos-permission/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/qos-permission/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/qos-permission/ description: QoS匿名访问权限验证扩展 linkTitle: QoS匿名访问权限验证扩展 title: QoS匿名访问权限验证扩展 @@ -68,4 +68,4 @@ META-INF/dubbo/org.apache.dubbo.qos.permission.PermissionChecker: ```properties qosPermissionChecker=com.xxx.XxxPermissionChecker -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/readiness.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/readiness.md index 5b4b7efd3701..30cc34f04c9a 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/readiness.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/readiness.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/readiness/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/readiness/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/readiness/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/readiness/ description: Readiness 就绪探针 linkTitle: 就绪探针 title: Readiness 就绪探针 @@ -80,4 +80,4 @@ META-INF/dubbo/org.apache.dubbo.qos.probe.ReadinessProbe: ``` xxx=com.xxx.XxxReadinessProbe -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/registry.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/registry.md index 78204216d265..4e51209949a2 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/registry.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/registry.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/registry/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/registry/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/registry/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/registry/ description: 注册中心扩展 linkTitle: 注册中心扩展 title: 注册中心扩展 @@ -216,4 +216,4 @@ META-INF/dubbo/org.apache.dubbo.registry.RegistryFactory: ```properties xxx=com.xxx.XxxRegistryFactory -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/remoting.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/remoting.md index 9184f8516b3b..a93589663d34 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/remoting.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/remoting.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/remoting/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/remoting/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/remoting/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/remoting/ description: 网络传输扩展 linkTitle: 网络传输扩展 title: 网络传输扩展 @@ -133,4 +133,4 @@ META-INF/dubbo/org.apache.dubbo.remoting.Transporter: ```properties xxx=com.xxx.XxxTransporter -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/router.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/router.md index c1facf97912a..d477439fa1a8 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/router.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/router.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/router/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/router/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/router/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/router/ description: 路由扩展 linkTitle: 路由扩展 title: 路由扩展 @@ -73,4 +73,4 @@ META-INF/dubbo/org.apache.dubbo.rpc.cluster.RouterFactory: ```properties xxx=com.xxx.XxxRouterFactory -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/serialize.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/serialize.md index 4c8a8f2d477a..6e14226d5d16 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/serialize.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/serialize.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/serialize/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/serialize/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/serialize/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/serialize/ description: 序列化扩展 linkTitle: 序列化扩展 title: 序列化扩展 @@ -83,4 +83,4 @@ META-INF/dubbo/org.apache.dubbo.common.serialize.Serialization: ```properties xxx=com.xxx.XxxSerialization -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/startup.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/startup.md index 14e90e26d9b5..5857f601100b 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/startup.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/startup.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/startup/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/startup/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/startup/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/startup/ description: Startup 启动探针 linkTitle: 启动探针 title: Startup 启动探针 @@ -79,4 +79,4 @@ META-INF/dubbo/org.apache.dubbo.qos.probe.StartupProbe: ``` xxx=com.xxx.XxxStartupProbe -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/status-checker.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/status-checker.md index 19a4fabf7fbd..e09de2d42665 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/status-checker.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/status-checker.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/status-checker/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/status-checker/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/status-checker/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/status-checker/ description: 状态检查扩展 linkTitle: 状态检查扩展 title: 状态检查扩展 @@ -75,4 +75,4 @@ META-INF/dubbo/org.apache.dubbo.common.status.StatusChecker: ```properties xxx=com.xxx.XxxStatusChecker -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/telnet-handler.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/telnet-handler.md index 262c98fd3082..97e09484ab77 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/telnet-handler.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/telnet-handler.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/telnet-handler/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/telnet-handler/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/telnet-handler/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/telnet-handler/ description: Telnet 命令扩展 linkTitle: Telnet 命令扩展 title: Telnet 命令扩展 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/threadpool.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/threadpool.md index d73ecf0a0907..d5413585c347 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/threadpool.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/threadpool.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/threadpool/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/threadpool/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/threadpool/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/threadpool/ description: 线程池扩展 linkTitle: 线程池扩展 title: 线程池扩展 @@ -71,4 +71,4 @@ META-INF/dubbo/org.apache.dubbo.common.threadpool.ThreadPool: ```properties xxx=com.xxx.XxxThreadPool -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/validation.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/validation.md index 39804cf4f2cf..0d3d0099a4ca 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/description/validation.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/description/validation.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/description/validation/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/description/validation/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/validation/ + - /en/docs3-v2/java-sdk/reference-manual/spi/description/validation/ description: 验证扩展 linkTitle: 验证扩展 title: 验证扩展 @@ -86,4 +86,4 @@ META-INF/dubbo/org.apache.dubbo.validation.Validation: ```properties xxx=com.xxx.XxxValidation -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/spi/overview.md b/content/en/overview/mannual/java-sdk/reference-manual/spi/overview.md index 9ebf6e85627a..667605f6f11a 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/spi/overview.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/spi/overview.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/spi/overview/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/spi/overview/ + - /en/docs3-v2/java-sdk/reference-manual/spi/overview/ + - /en/docs3-v2/java-sdk/reference-manual/spi/overview/ description: Dubbo 通过 SPI 机制提供了非常灵活的可扩展性 linkTitle: SPI 概述 title: Dubbo SPI 概述 @@ -12,14 +12,14 @@ weight: 1 使用 IoC 容器帮助管理组件的生命周期、依赖关系注入等是很多开发框架的常用设计,Dubbo 中内置了一个轻量版本的 IoC 容器,用来管理框架内部的插件,实现包括插件实例化、生命周期、依赖关系自动注入等能力。 感兴趣的读者可以了解: -* [Dubbo SPI 扩展体系的工作原理](/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/) -* [Dubbo SPI 扩展使用示例](/zh-cn/overview/mannual/java-sdk/tasks/extensibility/spi/) +* [Dubbo SPI 扩展体系的工作原理](/en/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/) +* [Dubbo SPI 扩展使用示例](/en/overview/mannual/java-sdk/tasks/extensibility/spi/) Dubbo 插件体系与 IoC 容器具有以下特点: * **[核心组件均被定义为插件](../spi-list/),用户或二次开发者扩展非常简单。** 在无需改造框架内核的情况下,用户可以基于自身需求扩展如负载均衡、注册中心、通信协议、路由等策略。 * **平等对待第三方扩展实现。** Dubbo 中所有内部实现和第三方实现都是平等的,用户可以基于自身业务需求替换 Dubbo 提供的原生实现。 -* **[插件依赖支持自动注入(IoC)](/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#23-ioc-机制)。** 如果插件实现依赖其他插件属性,则 Dubbo 框架会完成该依赖对象的自动注入,支持属性、构造函数等方式。 -* **[插件扩展实现支持 AOP 能力](/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#24-aop-机制)。** 框架可以自动发现扩展类的包装类,通过包装器模式对插件进行 AOP 增强。 -* **[支持插件自动激活](/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#25-activate激活条件)。** 通过为插件实现指定激活条件(通过注解参数等),框架可在运行时自动根据当前上下文决策是否激活该插件实现。 -* **[支持插件扩展排序](/zh-cn/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#26-扩展点排序)。** +* **[插件依赖支持自动注入(IoC)](/en/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#23-ioc-机制)。** 如果插件实现依赖其他插件属性,则 Dubbo 框架会完成该依赖对象的自动注入,支持属性、构造函数等方式。 +* **[插件扩展实现支持 AOP 能力](/en/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#24-aop-机制)。** 框架可以自动发现扩展类的包装类,通过包装器模式对插件进行 AOP 增强。 +* **[支持插件自动激活](/en/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#25-activate激活条件)。** 通过为插件实现指定激活条件(通过注解参数等),框架可在运行时自动根据当前上下文决策是否激活该插件实现。 +* **[支持插件扩展排序](/en/overview/mannual/java-sdk/reference-manual/architecture/dubbo-spi/#26-扩展点排序)。** diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/_index.md index 16e43cb651e0..494a4c1cd119 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/ - - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/ - - /zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/ + - /en/overview/mannual/java-sdk/upgrades-and-compatibility/ description: 升级和兼容性 linkTitle: 升级和兼容性 title: 升级和兼容性 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery.md index 21fad0da0910..3fcdfdddb5de 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/ - - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/ - - /zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/ + - /en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/ description: 本文具体说明了用户在升级到 Dubbo3 之后,如何快速开启应用级服务发现新特性,从接口级服务发现平滑迁移到应用级服务发现。 linkTitle: 升级到应用级服务发现 title: 升级到应用级服务发现 @@ -11,8 +11,8 @@ weight: 3 --- {{% alert title="请注意" color="warning" %}} -* 本文档内容并不是升级 Dubbo3 必须的,您完全可以只升级框架并使用 [框架的服务发现默认行为](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery/#启用应用级服务发现)。 -* 本文档更适用于 Dubbo2 老用户,用于了解在升级到 Dubbo3 版本后,框架中的服务发现模型切换过程与工作原理。新用户请直接 [配置启用应用级服务发现](/zh-cn/overview/mannual/java-sdk/tasks/service-discovery/nacos/#13-配置并启用-nacos)。 +* 本文档内容并不是升级 Dubbo3 必须的,您完全可以只升级框架并使用 [框架的服务发现默认行为](/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery/#启用应用级服务发现)。 +* 本文档更适用于 Dubbo2 老用户,用于了解在升级到 Dubbo3 版本后,框架中的服务发现模型切换过程与工作原理。新用户请直接 [配置启用应用级服务发现](/en/overview/mannual/java-sdk/tasks/service-discovery/nacos/#13-配置并启用-nacos)。 {{% /alert %}} 对于 Dubbo2 老用户而言,在升级 Dubbo3 时有以下两个选择,而决策的考虑因素仅有一个:性能。 @@ -73,5 +73,5 @@ dubbo: ### 状态收敛 -关于以上双注册、双订阅行为的更多详细解释,以及如何尽快完成服务发现模型的收敛,请参考博客文章 [Dubbo3 服务发现平滑迁移步骤与原理](/zh-cn/blog/2024/05/13/如果从接口级服务发现平滑迁移到应用级服务发现/)。 +关于以上双注册、双订阅行为的更多详细解释,以及如何尽快完成服务发现模型的收敛,请参考博客文章 [Dubbo3 服务发现平滑迁移步骤与原理](/en/blog/2024/05/13/如果从接口级服务发现平滑迁移到应用级服务发现/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md index de08662063f0..1caaaf0551b2 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/ - - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/ - - /zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/migration-triple/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/ + - /en/overview/mannual/java-sdk/upgrades-and-compatibility/migration-triple/ description: "如何平滑的从 dubbo 协议升级到 triple 协议。" linkTitle: 升级到triple协议 title: 升级到triple协议 @@ -12,7 +12,7 @@ weight: 2 {{% alert title="请注意" color="warning" %}} * 本文档内容并不是升级 Dubbo3 必须的,您完全可以只升级框架并继续使用 dubbo 通信协议。 -* 如果您是 Dubbo 新用户,强烈建议直接 [使用 triple 协议](/zh-cn/overview/mannual/java-sdk/tasks/protocol/) 即可。 +* 如果您是 Dubbo 新用户,强烈建议直接 [使用 triple 协议](/en/overview/mannual/java-sdk/tasks/protocol/) 即可。 {{% /alert %}} 本文档适合服务已经运行在 dubbo 协议之上的老用户,请先参考上一篇文档 [如何从 Dubbo2 升级到 Dubbo3](../migration/) 完成框架版本升级,然后遵循以下步骤以最小改动平滑迁移到 triple 协议。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md.bak index 910d130944ea..d38c92a3c438 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md.bak +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-triple.md.bak @@ -1,6 +1,6 @@ --- aliases: - - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/ - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/ description: Triple 协议迁移指南 linkTitle: Dubbo 协议迁移至 Triple 协议 @@ -50,8 +50,8 @@ Dubbo3的之初就有一条目标是完美兼容 Dubbo2,所以为了 Dubbo2 ```java public interface IWrapperGreeter { - //... - + //... + /** * 这是一个普通接口,没有使用 pb 序列化 */ @@ -301,7 +301,7 @@ public interface PbGreeter { static final String SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; static final boolean inited = PbGreeterDubbo.init(); - + //... void greetServerStream(org.apache.dubbo.sample.tri.GreeterRequest request, org.apache.dubbo.common.stream.StreamObserver responseObserver); @@ -330,7 +330,7 @@ public interface PbGreeter { 通过对于协议的介绍,我们知道 `Triple` 协议是基于 `HTTP2` 并兼容 `GRPC`。为了保证和验证与`GRPC`互通能力,Dubbo3 也编写了各种从场景下的测试。详细的可以通过[这里](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/README.MD) 了解更多。 -{{% alert title="未来: Everything on Stub" color="primary" %}} +{{% alert title="未来: Everything on Stub" color="primary" %}} 用过 `Grpc` 的同学应该对 `Stub` 都不陌生。 Grpc 使用 `compiler` 将编写的 `proto` 文件编译为相关的 protobuf 对象和相关 rpc 接口。默认的会同时生成几种不同的 `stub` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md index 3cee46083f52..186ec3f9c35c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/migration/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/migration/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/migration/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/migration/ + - /en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/ description: "从 dubbo2 升级到 dubbo3:涵盖 2.6.x、2.5.x、2.7.x 等版本升级。" linkTitle: 升级到Dubbo3 title: 从 dubbo2 升级到 dubbo3(涵盖 2.5.x、2.6.x、2.7.x 等版本) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md.bak b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md.bak index 36d71387bb14..c3f375341d07 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md.bak +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration.md.bak @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/migration/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/migration/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/migration/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/migration/ description: Dubbo2 协议迁移 linkTitle: Dubbo2 协议迁移 title: Dubbo2 协议迁移 @@ -31,8 +31,8 @@ Dubbo3 的之初就有一条目标是完美兼容 Dubbo2,所以为了 Dubbo2 ```java public interface IWrapperGreeter { - //... - + //... + /** * 这是一个普通接口,没有使用 pb 序列化 */ diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/2.x-to-3.x-compatibility-guide.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/2.x-to-3.x-compatibility-guide.md index 10e9f39b5422..ed5d932577b0 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/2.x-to-3.x-compatibility-guide.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/2.x-to-3.x-compatibility-guide.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide/ - - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide/ - - /zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide/ + - /en/overview/mannual/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide/ description: Dubbo 3 升级与兼容性指南 linkTitle: 2.x 升级至 3.x title: 2.x 升级至 3.x @@ -24,15 +24,15 @@ Dubbo3 依旧保持了 2.x 的经典架构,以解决微服务进程间通信 Dubbo 3.0 提供的新特性包括: * **新的地址发现模型(应用级服务发现)。** - * 查看[应用级服务发现迁移示例](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/)。 - * 查看[应用级服务发现的迁移步骤](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery/) - * 查看[应用级服务发现地址迁移规则说明](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) + * 查看[应用级服务发现迁移示例](/en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/)。 + * 查看[应用级服务发现的迁移步骤](/en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery/) + * 查看[应用级服务发现地址迁移规则说明](/en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) * **下一代基于 HTTP/2 的 Triple 协议。** - * 查看[Triple 协议迁移步骤](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/migration-triple/) - * 查看 [Triple 协议使用方式](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/guide/) - * 查看 [Triple 协议设计与实现](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/overview/)。 + * 查看[Triple 协议迁移步骤](/en/overview/mannual/java-sdk/upgrades-and-compatibility/migration-triple/) + * 查看 [Triple 协议使用方式](/en/overview/mannual/java-sdk/reference-manual/protocol/triple/guide/) + * 查看 [Triple 协议设计与实现](/en/overview/mannual/java-sdk/reference-manual/protocol/triple/overview/)。 * **统一的路由规则。** - * 查看[统一路由规则设计与实现](/zh-cn/overview/tasks/traffic-management/) + * 查看[统一路由规则设计与实现](/en/overview/tasks/traffic-management/) ## 升级前的兼容性检查 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.0-to-3.1-compatibility-guide.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.0-to-3.1-compatibility-guide.md index 19838ce8ad34..c1a82f6219f2 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.0-to-3.1-compatibility-guide.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.0-to-3.1-compatibility-guide.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/3.0-to-3.1-compatibility-guide/ - - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/3.0-to-3.1-compatibility-guide/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/3.0-to-3.1-compatibility-guide/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/3.0-to-3.1-compatibility-guide/ description: Dubbo 3.1 升级与兼容性指南 linkTitle: 3.0 升级至 3.1 title: 3.0 升级至 3.1 @@ -27,4 +27,4 @@ weight: 2 注意事项: 1. 请检查注册中心 URL 上是否已经配置了 group 属性,如果是的话需要检查服务端和消费端的 group 是否都一致,如果不一致请修改为一致 -2. 如果不希望 group 重新对齐到 Nacos 注册中心中的 group 分组,可以配置 `dubbo.nacos-service-discovery.use-default-group=false` 全局属性值忽略该功能 \ No newline at end of file +2. 如果不希望 group 重新对齐到 Nacos 注册中心中的 group 分组,可以配置 `dubbo.nacos-service-discovery.use-default-group=false` 全局属性值忽略该功能 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.1-to-3.2-compatibility-guide.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.1-to-3.2-compatibility-guide.md index 87ffcbbf8ba0..06a0cd835847 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.1-to-3.2-compatibility-guide.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.1-to-3.2-compatibility-guide.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/3.1-to-3.2-compatibility-guide/ - - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/3.1-to-3.2-compatibility-guide/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/3.1-to-3.2-compatibility-guide/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/3.1-to-3.2-compatibility-guide/ description: Dubbo 3.2 升级与兼容性指南 linkTitle: 3.1 升级至 3.2 title: 3.1 升级至 3.2 @@ -37,7 +37,7 @@ weight: 3 对于一些使用了泛型等可能存在扫描不全或者是**服务规模较大**的用户,我们建议您添加 `-Ddubbo.application.serialize-check-status=WARN` 配置。 观察一段时间后(通过日志、QoS 命令),如果没有触发安全告警,则可以配置强校验模式。 -关于自定义白名单的配置,可以参考官网的 [文档 / SDK 手册 / Java SDK / 高级特性和用法 / 提升安全性 / 类检查机制](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/) 一文进行配置。 +关于自定义白名单的配置,可以参考官网的 [文档 / SDK 手册 / Java SDK / 高级特性和用法 / 提升安全性 / 类检查机制](/en/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/) 一文进行配置。 #### Q1:为什么要开启序列化白名单的强校验? @@ -55,7 +55,7 @@ Dubbo 3.2.0 版本开始默认序列化方式从 `hessian2` 切换为 `fastjson2 #### Q1:会不会影响和低版本的 Dubbo 互通? -不会。与低版本互通仍使用 `hessian-lite`。原理可参考[序列化协议升级指南](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/serialization-upgrade/)一文。 +不会。与低版本互通仍使用 `hessian-lite`。原理可参考[序列化协议升级指南](/en/overview/mannual/java-sdk/upgrades-and-compatibility/serialization-upgrade/)一文。 #### Q2:为什么要切换默认序列化方式? diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.2-to-3.3-compatibility-guide.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.2-to-3.3-compatibility-guide.md index 889828aa2c87..e8496fd2874b 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.2-to-3.3-compatibility-guide.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.2-to-3.3-compatibility-guide.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/upgrades-and-compatibility/3.2-to-3.3-compatibility-guide/ - - /zh-cn/docs3-v2/java-sdk/upgrades-and-compatibility/3.2-to-3.3-compatibility-guide/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/3.2-to-3.3-compatibility-guide/ + - /en/docs3-v2/java-sdk/upgrades-and-compatibility/3.2-to-3.3-compatibility-guide/ description: Dubbo 3.3 升级与兼容性指南 linkTitle: 3.2 升级至 3.3 title: 3.2 升级至 3.3 @@ -55,7 +55,7 @@ Dubbo 3.3.0 版本开始默认序列化方式从 `fastjson2` 切换为 `hessian2 3. Dubbo 3.2.x Consumer 与 Dubbo 3.3.x Provider 互通时默认使用 Dubbo 3.3.x 中 `hessian2` 优先的策略,此时由于 Dubbo 3.2.x Consumer 中携带的 `hessian2` 为低版本的,在 JDK >= 17 的场景下可能会出现兼容性问题,建议按照 Q3 中的最佳实践进行升级。 4. Dubbo 3.1.x 及以下版本 Consumer 与 Dubbo 3.3.x Provider 互通时默认使用 Dubbo 3.3.x 中 `hessian2` 优先的策略,此时由于 Dubbo 3.1.x 及以下版本 Consumer 中携带的 `hessian2` 为低版本的,在 JDK >= 17 的场景下可能会出现兼容性问题,建议按照 Q3 中的最佳实践进行升级。 -原理可参考[序列化协议升级指南](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/serialization-upgrade/)一文。 +原理可参考[序列化协议升级指南](/en/overview/mannual/java-sdk/upgrades-and-compatibility/serialization-upgrade/)一文。 ### Q3:升级序列化最佳实践是什么? @@ -153,7 +153,7 @@ Dubbo 3.3.0 版本开始默认序列化方式从 `fastjson2` 切换为 `hessian2 在 3.3 版本中,Dubbo 移除了 dubbo-native-plugin,同时 dubbo-native-plugin 相关的功能都将迁移至 dubbo-maven-plugin。此外,在 dubbo-maven-plugin 中也新增了对 dubbo-compiler 的支持。 -更多过于 dubbo-maven-plugin 的说明请参考[配置详情](/zh-cn/overview/mannual/java-sdk/reference-manual/config/maven-plugin/)。 +更多过于 dubbo-maven-plugin 的说明请参考[配置详情](/en/overview/mannual/java-sdk/reference-manual/config/maven-plugin/)。 ### Q1:为什么要做这个迁移和调整? @@ -276,7 +276,7 @@ Dubbo 3.3.0 版本开始默认序列化方式从 `fastjson2` 切换为 `hessian2 在 Dubbo 3.3.x 中,Triple 协议支持了 Provider 侧原生 REST 协议的所有特性,同时移除了原 REST 协议实现的支持。 -1. 如果仅使用 REST 协议作为服务提供者,请修改协议名字为 `tri`,使用方式无需改变,详见 [Triple 3.3新特性](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple-3.3/) 和 [Triple REST 用户手册](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual/) +1. 如果仅使用 REST 协议作为服务提供者,请修改协议名字为 `tri`,使用方式无需改变,详见 [Triple 3.3新特性](/en/overview/mannual/java-sdk/reference-manual/protocol/triple-3.3/) 和 [Triple REST 用户手册](/en/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual/) 2. 如果需要使用 REST 协议作为服务消费者,可以添加以下依赖提供能力兼容 ```xml diff --git a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/_index.md index 7ce0943a83b5..83f989fac8d8 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/version/ - - /zh-cn/docs3-v2/java-sdk/version/ - - /zh-cn/overview/mannual/java-sdk/version/ + - /en/docs3-v2/java-sdk/version/ + - /en/docs3-v2/java-sdk/version/ + - /en/overview/mannual/java-sdk/version/ description: "Dubbo 各个版本变更记录(release note),跨版本升级兼容性说明。" linkTitle: 版本变更记录 title: 版本变更记录 diff --git a/content/en/overview/mannual/java-sdk/tasks/_index.md b/content/en/overview/mannual/java-sdk/tasks/_index.md index 39d273ea7063..e93c3bc403d7 100755 --- a/content/en/overview/mannual/java-sdk/tasks/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/ - - /zh-cn/overview/tasks/ + - /en/overview/tasks/ + - /en/overview/tasks/ description: "" linkTitle: 使用教程 title: 跟随示例任务学习 Dubbo diff --git a/content/en/overview/mannual/java-sdk/tasks/deploy/_index.md b/content/en/overview/mannual/java-sdk/tasks/deploy/_index.md index cb40bbb75b1d..2e93bd8c5132 100644 --- a/content/en/overview/mannual/java-sdk/tasks/deploy/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/deploy/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/deploy/ - - /zh-cn/overview/tasks/deploy/ + - /en/overview/tasks/deploy/ + - /en/overview/tasks/deploy/ description: "学习在 Kubernetes、Service Mesh(Kubernetes Service)、虚拟机(Zookeeper、Nacos)等场景部署 Dubbo 应用。" feature: description: | diff --git a/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes-service.md b/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes-service.md index 3423f24dcc7b..229adf1a17ff 100644 --- a/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes-service.md +++ b/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes-service.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/deploy/deploy-on-vm/ - - /zh-cn/overview/tasks/deploy/deploy-on-vm/ + - /en/overview/tasks/deploy/deploy-on-vm/ + - /en/overview/tasks/deploy/deploy-on-vm/ description: "部署 Dubbo 应用到服务网格(Service Mesh),基于 Kubernetes Service 与控制面。" linkTitle: 服务网格 title: 部署 Dubbo 应用到虚拟机环境 @@ -62,7 +62,7 @@ kind: deployment 接口将自动获取当前应用所有 SPI 的实现,对应接口的 SPI 实现均成功就绪则接口返回成功。 -Dubbo3 SPI 更多扩展的介绍见 [Dubbo SPI扩展](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/) +Dubbo3 SPI 更多扩展的介绍见 [Dubbo SPI扩展](/en/overview/mannual/java-sdk/reference-manual/spi/description/) ## 使用场景 `liveness probe` 来确定你的应用程序是否正在运行,查看是否存活。 @@ -77,18 +77,18 @@ Dubbo3 SPI 更多扩展的介绍见 [Dubbo SPI扩展](/zh-cn/overview/mannual/ja 对于 livenessProbe 存活检测,由于 Dubbo3 框架本身无法获取到应用的存活状态,因此本接口无默认实现,且默认返回成功。开发者可以根据 SPI 定义对此 SPI 接口进行拓展,从应用层次对是否存活进行判断。 -关于 [liveness 存活探针](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/liveness/) 扩展示例 +关于 [liveness 存活探针](/en/overview/mannual/java-sdk/reference-manual/spi/description/liveness/) 扩展示例 ### 就绪检测 对于 readinessProbe 就绪检测,目前 Dubbo3 默认提供了两个检测维度,一是对 Dubbo3 服务自身是否启停做判断,另外是对所有服务是否存在已注册接口,如果所有服务均已从注册中心下线(可以通过 QOS 运维进行操作)将返回未就绪的状态。 -关于 [readiness 就绪探针](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/readiness/) 扩展示例 +关于 [readiness 就绪探针](/en/overview/mannual/java-sdk/reference-manual/spi/description/readiness/) 扩展示例 ### 启动检测 对于 startupProbe 启动检测,目前 Dubbo3 默认提供了一个检测维度,即是在所有启动流程(接口暴露、注册中心写入等)均结束后返回已就绪状态。 -关于 [startup 启动探针](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/startup/) 扩展示例 +关于 [startup 启动探针](/en/overview/mannual/java-sdk/reference-manual/spi/description/startup/) 扩展示例 ### 参考示例 ```yaml diff --git a/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes.md b/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes.md index 56fe5149adf5..3c61426a1d7b 100644 --- a/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes.md +++ b/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-kubernetes.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/deploy/deploy-on-vm/ - - /zh-cn/overview/tasks/deploy/deploy-on-vm/ + - /en/overview/tasks/deploy/deploy-on-vm/ + - /en/overview/tasks/deploy/deploy-on-vm/ description: "部署 Dubbo 应用到 Kubernetes 环境,使用 Nacos 或者 Zookeeper 等作为注册中心。" linkTitle: Kubernetes title: 部署 Dubbo 应用到 Kubernetes 环境 diff --git a/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-vm.md b/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-vm.md index 695f09958df5..02bb195e7dbd 100644 --- a/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-vm.md +++ b/content/en/overview/mannual/java-sdk/tasks/deploy/deploy-on-vm.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/deploy/deploy-on-vm/ - - /zh-cn/overview/tasks/deploy/deploy-on-vm/ + - /en/overview/tasks/deploy/deploy-on-vm/ + - /en/overview/tasks/deploy/deploy-on-vm/ description: "传统基于 Zookeeper、Nacos 的注册中心部署架构,部署 Dubbo 应用到虚拟机环境" linkTitle: 传统注册中心 title: 传统基于 Zookeeper、Nacos 的注册中心部署架构,部署 Dubbo 应用到虚拟机环境 @@ -117,4 +117,4 @@ PORT_TO_REGISTRY 或 IP_TO_REGISTRY 不会用作默认 PORT_TO_BIND 或 IP_TO_BI $ curl http://offline $ sleep 10 $ kill dubbo-pid -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/develop/_index.md b/content/en/overview/mannual/java-sdk/tasks/develop/_index.md index 9520e800ed8a..fc5f2a405f0a 100755 --- a/content/en/overview/mannual/java-sdk/tasks/develop/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/develop/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/develop/ - - /zh-cn/overview/tasks/develop/ + - /en/overview/tasks/develop/ + - /en/overview/tasks/develop/ description: 演示 Dubbo 框架提供的微服务开发 API 与编程模式 linkTitle: 快速创建应用 title: 快速创建应用 diff --git a/content/en/overview/mannual/java-sdk/tasks/develop/api.md b/content/en/overview/mannual/java-sdk/tasks/develop/api.md index a927377b58a3..0f3512d98c67 100644 --- a/content/en/overview/mannual/java-sdk/tasks/develop/api.md +++ b/content/en/overview/mannual/java-sdk/tasks/develop/api.md @@ -27,7 +27,7 @@ public class Application { 官方推荐使用 `DubboBootstrap.start()` 作为应用的集中启动入口,但为了方便在进程启动后,在运行态单独发布一些服务,Dubbo 框架也允许直接调用 `ServiceConfig.export()` 或 `ReferenceConfig.refer()` 方法发布单个服务,这时 Service/Reference 会注册到默认的 DubboBootstrap 实例中,效果同调用 `DubboBootstrap.service(...).start()` 类似。 -以下是开发中会常用到的一些组件,完整组件定义及详细参数说明请参见 [参考手册 - 配置项手册](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#配置项手册): +以下是开发中会常用到的一些组件,完整组件定义及详细参数说明请参见 [参考手册 - 配置项手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/#配置项手册): | API 组件 | 全局唯一 | 核心方法或属性 | 说明 | | --- | --- | --- | --- | @@ -63,7 +63,7 @@ public class Application { ### 定义服务 -定义一个名为 `DemoService`的标准 Java 接口作为 Dubbo 服务(Dubbo 还支持[基于 IDL 的服务定义模式](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/))。 +定义一个名为 `DemoService`的标准 Java 接口作为 Dubbo 服务(Dubbo 还支持[基于 IDL 的服务定义模式](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/))。 ```java public interface DemoService { @@ -189,7 +189,7 @@ private DemoService referService() { } ``` -由于 ReferenceConfig.get() 创建的代理对象持有连接、地址等大量资源,因此建议缓存复用,Dubbo 官方提供了 SimpleReferenceCache 实现参考实现。关于 SimpleReferenceCache 更多内容,请参考 [RPC 框架](/zh-cn/overview/mannual/java-sdk/tasks/framework/more/reference-config-cache/)。 +由于 ReferenceConfig.get() 创建的代理对象持有连接、地址等大量资源,因此建议缓存复用,Dubbo 官方提供了 SimpleReferenceCache 实现参考实现。关于 SimpleReferenceCache 更多内容,请参考 [RPC 框架](/en/overview/mannual/java-sdk/tasks/framework/more/reference-config-cache/)。 #### 获得引用代理 使用 DubboBootstrap 作为启动入口,订阅服务并获得代理对象。 @@ -294,6 +294,6 @@ private DemoService referService() { ## 更多内容 -- Triple 协议完全兼容 gRPC,您可以参考这里了解如何 [使用 IDL 编写 gRPC 兼容的服务](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/),或者 [使用其他通信协议](/zh-cn/overview/mannual/java-sdk/tasks/protocols/) -- 作为 RPC 框架,Dubbo 支持异步调用、连接管理、context上下文等,请参考 [RPC 框架核心功能](/zh-cn/overview/mannual/java-sdk/tasks/framework/) -- 使用 [Dubbo Spring Boot 开发微服务应用](/zh-cn/overview/mannual/java-sdk/tasks/develop/springboot/) +- Triple 协议完全兼容 gRPC,您可以参考这里了解如何 [使用 IDL 编写 gRPC 兼容的服务](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/),或者 [使用其他通信协议](/en/overview/mannual/java-sdk/tasks/protocols/) +- 作为 RPC 框架,Dubbo 支持异步调用、连接管理、context上下文等,请参考 [RPC 框架核心功能](/en/overview/mannual/java-sdk/tasks/framework/) +- 使用 [Dubbo Spring Boot 开发微服务应用](/en/overview/mannual/java-sdk/tasks/develop/springboot/) diff --git a/content/en/overview/mannual/java-sdk/tasks/develop/springboot.md b/content/en/overview/mannual/java-sdk/tasks/develop/springboot.md index 555ad30b27d3..fe924f55dd4f 100644 --- a/content/en/overview/mannual/java-sdk/tasks/develop/springboot.md +++ b/content/en/overview/mannual/java-sdk/tasks/develop/springboot.md @@ -11,10 +11,10 @@ Dubbo 提供了对 Spring 框架的完整支持,我们推荐使用官方提供 ## 创建项目 创建 Dubbo 应用最快捷的方式就是使用官方项目脚手架工具 - start.dubbo.apache.org 在线服务。它可以帮助开发者创建 Spring Boot 结构应用,自动管理 `dubbo-spring-boot-starter` 等依赖和必要配置。 -另外,Jetbrain 官方也提供了 Apache Dubbo 项目插件,可用于快速创建 Dubbo Spring Boot 项目,能力与 start.dubbo.apache.org 对等,具体安装使用请查看 [博客文章](/zh-cn/blog/2023/10/23/intellij-idea%EF%B8%8Fapache-dubboidea官方插件正式发布/) +另外,Jetbrain 官方也提供了 Apache Dubbo 项目插件,可用于快速创建 Dubbo Spring Boot 项目,能力与 start.dubbo.apache.org 对等,具体安装使用请查看 [博客文章](/en/blog/2023/10/23/intellij-idea%EF%B8%8Fapache-dubboidea官方插件正式发布/) ## dubbo-spring-boot-starter -在 [快速开始](/zh-cn/overview/mannual/java-sdk/quick-start/) 中,我们已经详细介绍了典型的 Dubbo Spring Boot 工程源码及其项目结构,不熟悉的开发者可以前往查看。 +在 [快速开始](/en/overview/mannual/java-sdk/quick-start/) 中,我们已经详细介绍了典型的 Dubbo Spring Boot 工程源码及其项目结构,不熟悉的开发者可以前往查看。 `dubbo-spring-boot-starter` 可为项目引入 dubbo 核心依赖,自动扫描 dubbo 相关配置与注解。 @@ -67,7 +67,7 @@ dubbo: address: zookeeper://127.0.0.1:2181 ``` -除 service、reference 之外的组件都可以在 application.yml 文件中设置,具体可参考 [配置列表](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#applicationyaml)。 +除 service、reference 之外的组件都可以在 application.yml 文件中设置,具体可参考 [配置列表](/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#applicationyaml)。 service、reference 组件也可以通过 `id` 与 application 中的全局组件做关联,以下面配置为例。如果要扩展 service 或 reference 的注解配置,则需要增加 `dubbo.properties` 配置文件或使用其他非注解如 Java Config 方式,具体请看下文 [扩展注解的配置](#扩展注解配置)。 @@ -196,12 +196,12 @@ dubbo.reference.org.apache.dubbo.springboot.demo.DemoService.timeout=6000 ## 更多微服务开发模式 * [纯 API 开发模式](../api/) * 其他 Spring 开发模式 - * [Spring XML](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/xml/) + * [Spring XML](/en/overview/mannual/java-sdk/reference-manual/config/spring/xml/) ## Dubbo 与 Spring Cloud 的关系 -Dubbo 与 Spring Cloud 是两套平行的微服务开发与解决方案,两者都提供了微服务定义、发布、治理的相关能力,对于微服务开发者来说,我们建议在开发之初就确定好 Apache Dubbo 与 Spring Cloud 之间的选型,尽量避免两个不同体系在同一集群中出现,以降低集群维护复杂度。而对于一些确需两套体系共存的场景,为了解决相互之间的通信问题,我们提供了 [Dubbo 与 Spring Cloud 异构微服务体系互通最佳实践](/zh-cn/blog/2023/10/07/微服务最佳实践零改造实现-spring-cloud-apache-dubbo-互通/) 解决方案。 +Dubbo 与 Spring Cloud 是两套平行的微服务开发与解决方案,两者都提供了微服务定义、发布、治理的相关能力,对于微服务开发者来说,我们建议在开发之初就确定好 Apache Dubbo 与 Spring Cloud 之间的选型,尽量避免两个不同体系在同一集群中出现,以降低集群维护复杂度。而对于一些确需两套体系共存的场景,为了解决相互之间的通信问题,我们提供了 [Dubbo 与 Spring Cloud 异构微服务体系互通最佳实践](/en/blog/2023/10/07/微服务最佳实践零改造实现-spring-cloud-apache-dubbo-互通/) 解决方案。 - Dubbo 与 Spring Boot 是互补的关系,Dubbo 在 Spring Boot 体系之上提供了完整的微服务开发、治理能力,关于这一点我们在另一篇文章中有更详尽的说明:[Dubbo、Spring Cloud 与 Istio](/zh-cn/overview/what/xyz-difference/)。 + Dubbo 与 Spring Boot 是互补的关系,Dubbo 在 Spring Boot 体系之上提供了完整的微服务开发、治理能力,关于这一点我们在另一篇文章中有更详尽的说明:[Dubbo、Spring Cloud 与 Istio](/en/overview/what/xyz-difference/)。 diff --git a/content/en/overview/mannual/java-sdk/tasks/extensibility/_index.md b/content/en/overview/mannual/java-sdk/tasks/extensibility/_index.md index 2778fcca2b18..b6957d1539ba 100755 --- a/content/en/overview/mannual/java-sdk/tasks/extensibility/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/extensibility/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/extensibility/ - - /zh-cn/overview/tasks/extensibility/ + - /en/overview/tasks/extensibility/ + - /en/overview/tasks/extensibility/ description: 演示 Dubbo 扩展能力特性的使用方式。 linkTitle: 自定义扩展 no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/extensibility/filter.md b/content/en/overview/mannual/java-sdk/tasks/extensibility/filter.md index 14f20f0d1397..d0c966486013 100644 --- a/content/en/overview/mannual/java-sdk/tasks/extensibility/filter.md +++ b/content/en/overview/mannual/java-sdk/tasks/extensibility/filter.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/extensibility/filter/ - - /zh-cn/overview/tasks/extensibility/filter/ + - /en/overview/tasks/extensibility/filter/ + - /en/overview/tasks/extensibility/filter/ description: 在本文中,我们来了解如何扩展自定义的过滤器实现:一个可以对返回的结果进行统一的处理、验证等统一 Filter 处理器,减少对开发人员的打扰。 linkTitle: Filter no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/extensibility/protocol.md b/content/en/overview/mannual/java-sdk/tasks/extensibility/protocol.md index 0679b645872e..9e107ab8c9ec 100644 --- a/content/en/overview/mannual/java-sdk/tasks/extensibility/protocol.md +++ b/content/en/overview/mannual/java-sdk/tasks/extensibility/protocol.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/extensibility/protocol/ - - /zh-cn/overview/tasks/extensibility/protocol/ + - /en/overview/tasks/extensibility/protocol/ + - /en/overview/tasks/extensibility/protocol/ description: 本文讲解如何通过扩展 `org.apache.dubbo.rpc.Protocol` SPI,提供自定义的 RPC 协议实现。 linkTitle: Protocol no_list: true @@ -10,7 +10,7 @@ type: docs weight: 2 --- -在 [通信协议](/zh-cn/overview/mannual/java-sdk/tasks/protocols/) 一章中,我们了解了 Dubbo 内置的几个核心 RPC 协议 `dubbo`、`rest`、和`tri` 以及它们的使用方式。本文讲解如何通过扩展 `org.apache.dubbo.rpc.Protocol` SPI,提供自定义的 RPC 协议实现。 +在 [通信协议](/en/overview/mannual/java-sdk/tasks/protocols/) 一章中,我们了解了 Dubbo 内置的几个核心 RPC 协议 `dubbo`、`rest`、和`tri` 以及它们的使用方式。本文讲解如何通过扩展 `org.apache.dubbo.rpc.Protocol` SPI,提供自定义的 RPC 协议实现。 自定义一套私有协议有两种方式,第一种是对原有的协议进行包装,添加一些特定的业务逻辑。另外一种是完全自定义一套协议。前者实现简单,在`dubbo`中也是有广泛的使用,比如:`ProtocolFilterWrapper`, `QosProtocolWrapper`, `ProtocolListenerWrapper`等。后者实现相对复杂,但却具有最大的灵活性,比如 Dubbo 框架内置的协议 `dubbo`、`triple` 协议都可以算作这种实现方式。 diff --git a/content/en/overview/mannual/java-sdk/tasks/extensibility/registry.md b/content/en/overview/mannual/java-sdk/tasks/extensibility/registry.md index 8bef424e5038..a98cd873d2d1 100644 --- a/content/en/overview/mannual/java-sdk/tasks/extensibility/registry.md +++ b/content/en/overview/mannual/java-sdk/tasks/extensibility/registry.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/extensibility/registry/ - - /zh-cn/overview/tasks/extensibility/registry/ + - /en/overview/tasks/extensibility/registry/ + - /en/overview/tasks/extensibility/registry/ description: 本文讲解如何通过扩展 `org.apache.dubbo.registry.client.ServiceDiscovery` SPI,提供自定义的注册中心实现。 linkTitle: Registry no_list: true @@ -10,7 +10,7 @@ type: docs weight: 3 --- -在 [服务发现](/zh-cn/overview/mannual/java-sdk/tasks/protocols/) 一章中,我们了解了 Dubbo 内置的几个核心注册中心实现 `Nacos`、`Zookeeper` 的使用方式与工作原理。本文讲解如何通过扩展 `org.apache.dubbo.registry.client.ServiceDiscovery` 和 `org.apache.dubbo.registry.nacos.NacosServiceDiscoveryFactory` SPI,提供自定义的注册中心实现。 +在 [服务发现](/en/overview/mannual/java-sdk/tasks/protocols/) 一章中,我们了解了 Dubbo 内置的几个核心注册中心实现 `Nacos`、`Zookeeper` 的使用方式与工作原理。本文讲解如何通过扩展 `org.apache.dubbo.registry.client.ServiceDiscovery` 和 `org.apache.dubbo.registry.nacos.NacosServiceDiscoveryFactory` SPI,提供自定义的注册中心实现。 本示例的完整源码请参见 [dubbo-registry-etcd](https://github.com/apache/dubbo-spi-extensions/tree/3.2.0/dubbo-registry-extensions/dubbo-registry-etcd3)。除了本示例之外,Dubbo 核心仓库 apache/dubbo 以及扩展库 apache/dubbo-spi-extensions 中的众多注册中心扩展实现,都可以作为扩展参考实现: diff --git a/content/en/overview/mannual/java-sdk/tasks/extensibility/router.md b/content/en/overview/mannual/java-sdk/tasks/extensibility/router.md index 816303ec22ba..70d7a88bc178 100644 --- a/content/en/overview/mannual/java-sdk/tasks/extensibility/router.md +++ b/content/en/overview/mannual/java-sdk/tasks/extensibility/router.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/extensibility/router/ - - /zh-cn/overview/tasks/extensibility/router/ + - /en/overview/tasks/extensibility/router/ + - /en/overview/tasks/extensibility/router/ description: 本文讲解如何通过扩展 Router 实现自定义路由策略,可以根据业务场景的特点来实现特定的路由方式。 linkTitle: Router no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/extensibility/spi.md b/content/en/overview/mannual/java-sdk/tasks/extensibility/spi.md index 724fe31266c5..bb3957f19747 100644 --- a/content/en/overview/mannual/java-sdk/tasks/extensibility/spi.md +++ b/content/en/overview/mannual/java-sdk/tasks/extensibility/spi.md @@ -6,7 +6,7 @@ type: docs weight: 1 --- -下面以 `RPC 协议插件` 为例,说明如何利用 Dubbo 提供的 SPI 插件提供一个自定义的 RPC 协议实现。如果想了解 SPI 机制的工作原理以及框架内置的 SPI 扩展点列表,请查看 [参考手册 - SPI扩展](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/overview)。 +下面以 `RPC 协议插件` 为例,说明如何利用 Dubbo 提供的 SPI 插件提供一个自定义的 RPC 协议实现。如果想了解 SPI 机制的工作原理以及框架内置的 SPI 扩展点列表,请查看 [参考手册 - SPI扩展](/en/overview/mannual/java-sdk/reference-manual/spi/overview)。 ## 1. 提供 SPI 插件实现类 提供一个 Java 类实现 `org.apache.dubbo.rpc.Protocol` 接口。 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/async.md b/content/en/overview/mannual/java-sdk/tasks/framework/async.md index 4bc64491a2f5..846a533b55bd 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/async.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/async.md @@ -1,10 +1,10 @@ --- aliases: - - /zh/overview/tasks/develop/async/ - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/async-call/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-call/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-execute-on-provider/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async/ + - /en/overview/tasks/develop/async/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/async-call/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/async-call/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/async-execute-on-provider/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/async/ description: 某些情况下希望dubbo接口异步调用,避免不必要的等待。 linkTitle: 异步调用 title: 异步调用 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/attachment.md b/content/en/overview/mannual/java-sdk/tasks/framework/attachment.md index 56e11f64a8c0..9a0564874b59 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/attachment.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/attachment.md @@ -1,10 +1,10 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/attachment/ - - /zh/overview/tasks/develop/context/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/attachment/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/context/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/attachment/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/attachment/ + - /en/overview/tasks/develop/context/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/attachment/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/context/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/attachment/ description: 通过 Dubbo 中的 Attachment 在服务消费方和提供方之间隐式传递参数 linkTitle: 传递附加参数 title: 调用链路传递隐式参数 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/fault-tolerent-strategy.md b/content/en/overview/mannual/java-sdk/tasks/framework/fault-tolerent-strategy.md index 52b96762d6c4..3e336eec70fa 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/fault-tolerent-strategy.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/fault-tolerent-strategy.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docsv2.7/user/examples/fault-tolerent-strategy/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/fault-tolerent-strategy/ + - /en/docsv2.7/user/examples/fault-tolerent-strategy/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/fault-tolerent-strategy/ description: 集群调用失败时,Dubbo 提供的容错方案 linkTitle: 集群容错(重试) title: 集群容错 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/filter.md b/content/en/overview/mannual/java-sdk/tasks/framework/filter.md index 9578e81a9e75..ca787cc0deaf 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/filter.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/filter.md @@ -1,10 +1,10 @@ --- aliases: - - /zh/overview/tasks/develop/async/ - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/async-call/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-call/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-execute-on-provider/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async/ + - /en/overview/tasks/develop/async/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/async-call/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/async-call/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/async-execute-on-provider/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/async/ description: 使用 Filter 过滤器动态拦截请求(request)或响应(response)以转换或使用请求或响应中包含的信息。 linkTitle: Filter拦截器 title: 使用 Filter 过滤器动态拦截请求(request)或响应(response) diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/generic.md b/content/en/overview/mannual/java-sdk/tasks/framework/generic.md index 125f609039fe..57d1ccdce300 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/generic.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/generic.md @@ -1,12 +1,12 @@ --- aliases: - - /zh/overview/tasks/develop/generic/ - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-reference/ - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-service/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-service/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-reference/ - - /zh-cn/overview/mannual/java-sdk/tasks/framework/more/generic/ + - /en/overview/tasks/develop/generic/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-reference/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-service/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/generic/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-service/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-reference/ + - /en/overview/mannual/java-sdk/tasks/framework/more/generic/ description: 泛化调用,用于在调用方没有服务方提供的 API(SDK)的情况下,对服务方进行调用 linkTitle: 泛化调用 title: 泛化调用 @@ -15,7 +15,7 @@ weight: 9 --- {{% alert title="注意" color="warning" %}} - 泛化调用适用于老版本 dubbo 通信协议,如果您使用的是 3.3 及之后版本的 triple 协议,请直接使用 triple 自带的 http application/json 能力直接发起服务调用,相关示例可参考 [网关接入说明](/zh-cn/overview/mannual/java-sdk/tasks/gateway/triple/)。 + 泛化调用适用于老版本 dubbo 通信协议,如果您使用的是 3.3 及之后版本的 triple 协议,请直接使用 triple 自带的 http application/json 能力直接发起服务调用,相关示例可参考 [网关接入说明](/en/overview/mannual/java-sdk/tasks/gateway/triple/)。 {{% /alert %}} 泛化调用(客户端泛化调用)是指在调用方没有服务提供方 API(SDK)的情况下,对服务方进行调用,并且可以正常拿到调用结果。调用方没有接口及模型类元,知道服务的接口的全限定类名和方法名的情况下,可以通过泛化调用调用对应接口。 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/lightweight-rpc.md b/content/en/overview/mannual/java-sdk/tasks/framework/lightweight-rpc.md index 56956e7b0809..c53bb6446091 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/lightweight-rpc.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/lightweight-rpc.md @@ -31,7 +31,7 @@ weight: 1 ## 定义服务 -定义一个名为 `DemoService`的标准 Java 接口作为 Dubbo 服务(Dubbo 还支持[基于 IDL 的服务定义模式](/zh-cn/overview/mannual/java-sdk/quick-start/))。 +定义一个名为 `DemoService`的标准 Java 接口作为 Dubbo 服务(Dubbo 还支持[基于 IDL 的服务定义模式](/en/overview/mannual/java-sdk/quick-start/))。 ```java public interface DemoService { @@ -104,6 +104,6 @@ public class Application { ## 更多内容 -- Triple 协议完全兼容 gRPC,您可以参考这里了解如何 [使用 IDL 编写 gRPC 兼容的服务](/zh-cn/overview/mannual/java-sdk/quick-start/),或者 [使用其他通信协议]() +- Triple 协议完全兼容 gRPC,您可以参考这里了解如何 [使用 IDL 编写 gRPC 兼容的服务](/en/overview/mannual/java-sdk/quick-start/),或者 [使用其他通信协议]() - 作为 RPC 框架,Dubbo 支持异步调用、连接管理、context上下文等,请参考 [RPC 框架核心功能]() - 您可以继续 [使用 API 为应用添加更多微服务治理能力](),但我们更推进您使用 [Dubbo Spring Boot 开发微服务应用](../../microservice/develop/) diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/callback-parameter.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/callback-parameter.md index 2c6ff26c124e..2d42237f96ea 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/callback-parameter.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/callback-parameter.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/callback-parameter/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/callback-parameter/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/callback-parameter/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/callback-parameter/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/callback-parameter/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/callback-parameter/ description: 通过参数回调从服务器端调用客户端逻辑 linkTitle: 服务端对客户端进行回调 title: 服务端对客户端进行回调 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/concurrency-control.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/concurrency-control.md index 8c4d1764acff..977dfbe26a34 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/concurrency-control.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/concurrency-control.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/concurrency-control/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/performance/concurrency-control/ description: Dubbo 中的并发控制 linkTitle: 并发控制 title: 并发控制 @@ -75,7 +75,7 @@ weight: 28 ``` -> 如果 `` 和 `` 都配了actives,`` 优先,参见:[配置的覆盖策略](/zh-cn/overview/mannual/java-sdk/reference-manual/config/principle/)。 +> 如果 `` 和 `` 都配了actives,`` 优先,参见:[配置的覆盖策略](/en/overview/mannual/java-sdk/reference-manual/config/principle/)。 ### Load Balance 均衡 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/config-connections.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/config-connections.md index d7d0fa5d650e..26c5f5acbca6 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/config-connections.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/config-connections.md @@ -1,13 +1,13 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/config-connections/ - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/stickiness/ - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/lazy-connect/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/config-connections/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/stickiness/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/lazy-connect/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/config-connections/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/config-connections/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/config-connections/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/stickiness/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/lazy-connect/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/config-connections/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/stickiness/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/lazy-connect/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/config-connections/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/performance/config-connections/ description: Dubbo 中服务端和客户端的连接控制 linkTitle: 连接控制 title: 连接控制 @@ -57,7 +57,7 @@ weight: 29 ``` -如果 `` 和 `` 都配了 connections,`` 优先,参见:[配置的覆盖策略](/zh-cn/overview/mannual/java-sdk/reference-manual/config/principle/) +如果 `` 和 `` 都配了 connections,`` 优先,参见:[配置的覆盖策略](/en/overview/mannual/java-sdk/reference-manual/config/principle/) [^1]: 因为连接在 Server上,所以配置在 Provider 上 [^2]: 如果是长连接,比如 Dubbo 协议,connections 表示该服务对每个提供者建立的长连接数 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/echo-service.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/echo-service.md index 9e727ce84040..4b894d014057 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/echo-service.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/echo-service.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/echo-service/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/echo-service/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/echo-service/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/echo-service/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/echo-service/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/echo-service/ description: 通过回声测试检测 Dubbo 服务是否可用 linkTitle: 回声测试 title: 回声测试 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/events-notify.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/events-notify.md index 7cd69d3dc947..89bd541bbcc9 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/events-notify.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/events-notify.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/events-notify/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/events-notify/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/events-notify/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/events-notify/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/events-notify/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/events-notify/ description: 在调用前后出现异常时的事件通知 linkTitle: 调用触发事件通知 title: 调用触发事件通知 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/explicit-target.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/explicit-target.md index 68441fa858f5..d64ef21cff5c 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/explicit-target.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/explicit-target.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/explicit-target/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/explicit-target/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/explicit-target/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/explicit-target/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/explicit-target/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/explicit-target/ description: Dubbo 中点对点的直连方式 linkTitle: 直连提供者 title: 直连提供者 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/generic-impl.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/generic-impl.md index 21fa093de477..4dd4cfc25957 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/generic-impl.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/generic-impl.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/overview/tasks/develop/generic/ - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-reference/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-reference/ + - /en/overview/tasks/develop/generic/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-reference/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/generic/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-reference/ description: 泛化实现,用于在提供方没有 API(SDK)的情况下,对外提供和发布服务 linkTitle: 泛化实现 title: 泛化实现 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/local-call.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/local-call.md index 07e3c9afb6d2..2980f0bde6fb 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/local-call.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/local-call.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/local-call/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/local-call/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/local-call/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-call/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-call/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/local-call/ description: 在 Dubbo 中进行本地调用 linkTitle: 本地调用 title: 本地调用 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/local-mock.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/local-mock.md index 812828e7b0bf..b0408cfb8881 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/local-mock.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/local-mock.md @@ -1,10 +1,10 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/local-mock/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/local-mock/ - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/local-mock/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-mock/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-mock/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/local-mock/ description: 了解如何在 Dubbo 中利用本地伪装实现服务降级 linkTitle: 服务降级 title: 服务讲解(本地伪装) @@ -178,7 +178,7 @@ Mock 可以在方法级别上指定,假定 `com.foo.BarService` 上有好几 ### 使用专业限流组件 -如果您有更高级、专业的限流诉求,我们推荐使用专业的限流降级组件如 [Sentinel](https://sentinelguard.io/zh-cn/docs/open-source-framework-integrations.html),以达到最佳体验。参考示例实践:[微服务治理/限流降级](/zh-cn/overview/mannual/java-sdk/tasks/rate-limit/) +如果您有更高级、专业的限流诉求,我们推荐使用专业的限流降级组件如 [Sentinel](https://sentinelguard.io/zh-cn/docs/open-source-framework-integrations.html),以达到最佳体验。参考示例实践:[微服务治理/限流降级](/en/overview/mannual/java-sdk/tasks/rate-limit/) 服务降级是指服务在非正常情况下进行降级应急处理。 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/local-stub.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/local-stub.md index ed48ef9e9560..36409c55d9de 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/local-stub.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/local-stub.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/local-stub/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/local-stub/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/local-stub/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-stub/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-stub/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/local-stub/ description: 了解 Dubbo 中本地存根在客户端执行部分逻辑的使用 linkTitle: 本地存根 title: 本地存根 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/parameter-validation.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/parameter-validation.md index 13b6fb2f51bf..d47755660f57 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/parameter-validation.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/parameter-validation.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/parameter-validation/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/parameter-validation/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/parameter-validation/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/parameter-validation/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/parameter-validation/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/parameter-validation/ description: 在 Dubbo 中进行参数校验 linkTitle: 参数校验 title: 参数校验 @@ -197,4 +197,4 @@ public class ValidationConsumer { } ``` -> **验证方式可扩展,扩展方式参见开发者手册中的 [验证扩展](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/validation)** +> **验证方式可扩展,扩展方式参见开发者手册中的 [验证扩展](/en/overview/mannual/java-sdk/reference-manual/spi/description/validation)** diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/reactive.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/reactive.md index edf3d626596c..dac07da8df0c 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/reactive.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/reactive.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/reactive/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/reactive/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/reactive/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/reactive/ description: 使用 Reactive API 操作 Triple 流式调用 linkTitle: 响应式编程 title: 响应式编程 @@ -34,7 +34,7 @@ Dubbo + Reactive Stream Stub 的组合模式可以给用户带来最方便的流 ## 使用方式 -Triple 使用及配置可参考 [IDL 方式使用 Triple](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/idl/),并确保 Dubbo 版本 >= 3.1.0。 +Triple 使用及配置可参考 [IDL 方式使用 Triple](/en/overview/mannual/java-sdk/reference-manual/protocol/triple/idl/),并确保 Dubbo 版本 >= 3.1.0。 ### 添加必要的依赖 @@ -238,4 +238,4 @@ public class ReactorConsumer { 4. 启动服务端 -5. 启动消费者端 \ No newline at end of file +5. 启动消费者端 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/reference-config-cache.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/reference-config-cache.md index 7ff4e2c057a4..f966df6341c6 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/reference-config-cache.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/reference-config-cache.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/reference-config-cache/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/reference-config-cache/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/reference-config-cache/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/reference-config-cache/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/reference-config-cache/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/performance/reference-config-cache/ description: 在 Dubbo 中缓存 ReferenceConfig linkTitle: 服务引用配置对象缓存 title: 服务引用配置对象缓存 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/result-cache.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/result-cache.md index acda287196cb..371a76048318 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/result-cache.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/result-cache.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/result-cache/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/result-cache/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/result-cache/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/result-cache/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/result-cache/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/performance/result-cache/ description: 通过缓存结果加速访问速度 linkTitle: 调用结果缓存 title: 调用结果缓存 @@ -24,7 +24,7 @@ Dubbo支持了服务端结果缓存和客户端结果缓存。 * `threadlocal` 当前线程缓存,比如一个页面渲染,用到很多 portal,每个 portal 都要去查用户信息,通过线程缓存,可以减少这种多余访问。 * `jcache` 与 [JSR107](http://jcp.org/en/jsr/detail?id=107%27) 集成,可以桥接各种缓存实现。 -缓存类型可扩展 [缓存扩展](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/cache) +缓存类型可扩展 [缓存扩展](/en/overview/mannual/java-sdk/reference-manual/spi/description/cache) 关于 [示例代码](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-cache) diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/router-snapshot.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/router-snapshot.md index c1c823274e9d..0a45a87717ab 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/router-snapshot.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/router-snapshot.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/router-snapshot/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/router-snapshot/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/router-snapshot/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/router-snapshot/ description: 路由状态采集 linkTitle: 路由状态采集 title: 路由状态采集 @@ -27,7 +27,7 @@ Dubbo 的很多流量治理能力是基于 Router 进行实现的,在生产环 Dubbo 在收到地址变更的时候,会将地址信息推送给所有的 `Router`,这些 `Router` 可以在此阶段提前计算路由的分组,缓存起来,以避免在调用时需要遍历所有的提供者计算分组参数。 在 Dubbo 3 中引入的 `StateRouter` 提供了通过 qos 命令工具实时获取每个路由的状态的能力。 -运维人员可以通过 `getRouterSnapshot` 命令获取路由的状态。具体命令使用方式可以参考 [getRouterSnapshot 命令](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/qos-list/) 文档。 +运维人员可以通过 `getRouterSnapshot` 命令获取路由的状态。具体命令使用方式可以参考 [getRouterSnapshot 命令](/en/overview/mannual/java-sdk/reference-manual/qos/qos-list/) 文档。 **注:此功能仅支持 `StateRoute`,且 `StateRouter` 需要基于 `AbstractStateRouter` 实现 `doBuildSnapshot` 接口。** @@ -60,7 +60,7 @@ No provider available after route for the service 服务 from registry 注册中 #### 开启路由全采样 -在一些特殊情况下,请求可能调用到错误的服务端,但是因为选址非空,所以无法看到路由的过程信息,此时可以 [通过 qos 开启路由全采样](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/router-snapshot/)。通过 qos 的 `getRecentRouterSnapshot` 命令可以远程获取最近的路由快照。 +在一些特殊情况下,请求可能调用到错误的服务端,但是因为选址非空,所以无法看到路由的过程信息,此时可以 [通过 qos 开启路由全采样](/en/overview/mannual/java-sdk/reference-manual/qos/router-snapshot/)。通过 qos 的 `getRecentRouterSnapshot` 命令可以远程获取最近的路由快照。 ``` dubbo>getRecentRouterSnapshot diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/set-host.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/set-host.md index 8ab9cad87a89..c882d1848a73 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/set-host.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/set-host.md @@ -1,6 +1,6 @@ --- aliases: - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/set-host/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/others/set-host/ description: 自定义 Dubbo 服务对外暴露的主机地址 linkTitle: 主机配置 title: 主机配置 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/specify-ip.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/specify-ip.md index 3a2ede78ad72..8a8ae93cee4a 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/specify-ip.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/specify-ip.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip/ description: 在发起 Dubbo 调用之前指定本次调用的目标 IP linkTitle: 运行时动态指定 IP 调用 title: 动态指定 IP 调用 @@ -102,4 +102,4 @@ public class UserSpecifiedAddressUtil { } ``` -> **必须每次都设置,而且设置后必须马上发起调用**,如果出现拦截器报错(Dubbo 框架内 remove 此值是在选址过程进行的)建议设置 null 以避免 ThreadLocal 内存泄漏导致影响后续调用。 \ No newline at end of file +> **必须每次都设置,而且设置后必须马上发起调用**,如果出现拦截器报错(Dubbo 框架内 remove 此值是在选址过程进行的)建议设置 null 以避免 ThreadLocal 内存泄漏导致影响后续调用。 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/threading-model.md b/content/en/overview/mannual/java-sdk/tasks/framework/threading-model.md index 868e8d4a962e..766002954ef7 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/threading-model.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/threading-model.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/consumer/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/consumer/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/threading-model/consumer/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/threading-model/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/consumer/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/consumer/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/performance/threading-model/consumer/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/performance/threading-model/ description: Dubbo 消费端线程池模型用法 linkTitle: 线程模型 title: 消费端线程模型,提供者端线程模型 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/timeout.md b/content/en/overview/mannual/java-sdk/tasks/framework/timeout.md index cbad6a8863a6..e10df6137022 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/timeout.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/timeout.md @@ -1,10 +1,10 @@ --- aliases: - - /zh/overview/tasks/develop/async/ - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/async-call/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-call/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async-execute-on-provider/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/async/ + - /en/overview/tasks/develop/async/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/async-call/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/async-call/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/async-execute-on-provider/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/async/ description: 某些情况下希望dubbo接口异步调用,避免不必要的等待。 linkTitle: 超时时间 title: 为服务调用指定 timeout 超时时间 diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/version_group.md b/content/en/overview/mannual/java-sdk/tasks/framework/version_group.md index f0c7d7976367..1a3a71acbee8 100644 --- a/content/en/overview/mannual/java-sdk/tasks/framework/version_group.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/version_group.md @@ -1,14 +1,14 @@ --- aliases: - - /zh/overview/tasks/develop/version_group/ - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/service-group/ - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-versions/ - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/version_group/ - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/group-merger/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/service-group/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/service-version/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-versions/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/group-merger/ + - /en/overview/tasks/develop/version_group/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-group/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-versions/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/version_group/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/group-merger/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/service-group/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/service-version/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-versions/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/group-merger/ description: "" linkTitle: 版本与分组 title: 版本与分组 @@ -244,7 +244,7 @@ reference3.setGroup("*"); ``` ### 指定合并策略 -指定合并策略,缺省根据返回值类型自动匹配,如果同一类型有两个合并器时,需指定合并器的名称 [合并结果扩展](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/merger) +指定合并策略,缺省根据返回值类型自动匹配,如果同一类型有两个合并器时,需指定合并器的名称 [合并结果扩展](/en/overview/mannual/java-sdk/reference-manual/spi/description/merger) ```xml diff --git a/content/en/overview/mannual/java-sdk/tasks/gateway/dubbo.md b/content/en/overview/mannual/java-sdk/tasks/gateway/dubbo.md index 8909d162335e..ae6437b5a49e 100644 --- a/content/en/overview/mannual/java-sdk/tasks/gateway/dubbo.md +++ b/content/en/overview/mannual/java-sdk/tasks/gateway/dubbo.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/ecosystem/gateway/ - - /zh-cn/overview/tasks/ecosystem/gateway/ + - /en/overview/tasks/ecosystem/gateway/ + - /en/overview/tasks/ecosystem/gateway/ description: | 本文介绍借助 Apache Higress 实现 Dubbo Service 服务代理,后端服务使用 dubbo 通信协议。 linkTitle: dubbo协议 @@ -41,7 +41,7 @@ curl \ 此时,网关就可以直接以 http 方式接入后端 dubbo 服务,任何 http 网关都可以非常容易接入,操作非常简洁明了。 {{% alert title="注意" color="info" %}} -另外,关于 dubbo、triple 多协议发布的完整示例源码和讲解可参见 [dubbo+rest 双协议发布的示例](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols/)。 +另外,关于 dubbo、triple 多协议发布的完整示例源码和讲解可参见 [dubbo+rest 双协议发布的示例](/en/overview/mannual/java-sdk/reference-manual/protocol/multi-protocols/)。 {{% /alert %}} 如果你对 `/org.apache.dubbo.protocol.multiple.demo.DemoService/sayHello` 格式的前端访问路径不满意,可以选择发布 rest 风格的 http 接口,我们只需要在接口上增加注解即可(目前支持 Spring Web、JAX-RS 两种注解)。如下所示,假设我们已经有一个名为 DemoService 的 dubbo 服务,只需要增加以下注解: @@ -57,7 +57,7 @@ public interface DemoService { 这样,就能发布同时支持 dubbo、rest 两种协议的服务,对于 http 网关接入更为简单便捷,唯一成本是需要改造接口增加注解。 -为 dubbo 协议服务增加了 http 访问方式之后,就可以很容易的将 dubbo 服务接入网关了,具体可以参见下一小节中的 [triple 协议网关接入](/zh-cn/overview/mannual/java-sdk/tasks/gateway/triple/) 示例,那里有详细的说明。 +为 dubbo 协议服务增加了 http 访问方式之后,就可以很容易的将 dubbo 服务接入网关了,具体可以参见下一小节中的 [triple 协议网关接入](/en/overview/mannual/java-sdk/tasks/gateway/triple/) 示例,那里有详细的说明。 ## http 转 dubbo 协议 {{% alert title="注意" color="warning" %}} @@ -78,4 +78,4 @@ public interface DemoService { * [使用 Apache APISIX 代理 Dubbo 流量]({{< relref "../../../../../../blog/integration/how-to-proxy-dubbo-in-apache-apisix" >}}) * [使用 Apache Shenyu 代理 Dubbo 流量]({{< relref "../../../../../../blog/integration/how-to-proxy-dubbo-in-apache-shenyu" >}}) -如果您并没有使用现成的网关产品,而是使用自建的流量转换组件,您很有可能使用到了 Dubbo 框架中的 [**泛化调用**](/zh-cn/overview/mannual/java-sdk/tasks/framework/more/generic/) 机制,具体请参考相关文档了解详情。 +如果您并没有使用现成的网关产品,而是使用自建的流量转换组件,您很有可能使用到了 Dubbo 框架中的 [**泛化调用**](/en/overview/mannual/java-sdk/tasks/framework/more/generic/) 机制,具体请参考相关文档了解详情。 diff --git a/content/en/overview/mannual/java-sdk/tasks/gateway/triple.md b/content/en/overview/mannual/java-sdk/tasks/gateway/triple.md index ef5ebe542cf4..37e2c8f63f66 100644 --- a/content/en/overview/mannual/java-sdk/tasks/gateway/triple.md +++ b/content/en/overview/mannual/java-sdk/tasks/gateway/triple.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/ecosystem/gateway/ - - /zh-cn/overview/tasks/ecosystem/gateway/ + - /en/overview/tasks/ecosystem/gateway/ + - /en/overview/tasks/ecosystem/gateway/ description: | 通过 Higress 云原生网关实现 Dubbo Service 代理,支持 triple 协议。 linkTitle: triple协议 @@ -10,7 +10,7 @@ type: docs weight: 3 --- -在 [triple协议规范](/zh-cn/overview/reference/protocols/triple-spec/) 中我们曾详细介绍了 triple 对于浏览器、网关的友好性设计,其中非常重要的一点是 triple 同时支持跑在 HTTP/1、HTTP/2 上: +在 [triple协议规范](/en/overview/reference/protocols/triple-spec/) 中我们曾详细介绍了 triple 对于浏览器、网关的友好性设计,其中非常重要的一点是 triple 同时支持跑在 HTTP/1、HTTP/2 上: * 在后端服务之间使用高效的 triple 二进制协议。 * 对于前端接入层,则支持所有标准 HTTP 工具如 cURL 等以标准 `application/json` 、`application/yaml` 等格式请求后端服务。 @@ -191,7 +191,7 @@ $ curl "localhost/org.apache.dubbo.samples.gateway.api.DemoService/sayHello?name 在前面的示例中,如类似 `http://127.0.0.1:9080/triple/demo/hello` 会是更符合前端使用的访问方式,要做到这一点,我们可以通过在 Higress 等网关配置 uri rewrite 重写,实现前端 `/triple/demo/hello` 到后端 `/org.apache.dubbo.samples.gateway.api.DemoService/sayHello/` 的映射。 -除了配置网关 rewrite 重新规则之外,**Dubbo 框架还为 triple 服务暴露 REST 风格的 HTTP 访问路径提供了内置支持**,具体使用方式取决于你使用的是基于 [protobuf 的服务定义模式](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/),还是基于 [java 接口的服务定义模式](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/interface/): +除了配置网关 rewrite 重新规则之外,**Dubbo 框架还为 triple 服务暴露 REST 风格的 HTTP 访问路径提供了内置支持**,具体使用方式取决于你使用的是基于 [protobuf 的服务定义模式](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/),还是基于 [java 接口的服务定义模式](/en/overview/mannual/java-sdk/tasks/protocols/triple/interface/): * Java 接口模式,通过直接为 java 接口增加注解可以同时发布 REST 风格服务,目前支持 Spring Web 与 JAX-RS 两套注解标准。 * Protobuf 模式,通过使用 grpc-gateway 可发布 REST 风格服务。 @@ -212,7 +212,7 @@ public interface DemoService { {{% alert title="注意" color="info" %}} 关于接口注解 * 在之前的示例 [dubbo-samples-gateway-higress-triple](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-triple) 中已经启用,可查看源码了解实际用法。 -* 在[【进阶学习 - 协议 - rest】](/zh-cn/overview/mannual/java-sdk/tasks/protocols/rest/)一节中有详细的说明和使用示例,也可以前往查看。 +* 在[【进阶学习 - 协议 - rest】](/en/overview/mannual/java-sdk/tasks/protocols/rest/)一节中有详细的说明和使用示例,也可以前往查看。 {{% /alert %}} 这时我们的路由前缀配置如下,Nacos 地址配置与之前保持一致,path 前缀改为访问更为友好的 `/triple/demo`: @@ -252,5 +252,5 @@ $ curl "localhost/triple/demo/hello?name=HigressTriple" {{% /alert %}} ## 参考连接 -* [使用 Apache APISIX 代理 triple 协议流量](/zh-cn/blog/2024/04/22/使用-apache-apisix-代理-dubbo-服务triple协议/) -* [Higress 实现基于 http 协议微服务发现与路由配置](https://higress.io/zh-cn/docs/user/spring-cloud) \ No newline at end of file +* [使用 Apache APISIX 代理 triple 协议流量](/en/blog/2024/04/22/使用-apache-apisix-代理-dubbo-服务triple协议/) +* [Higress 实现基于 http 协议微服务发现与路由配置](https://higress.io/zh-cn/docs/user/spring-cloud) diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/_index.md index ccce599fb53b..2c8887cae02d 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/ - - /zh-cn/overview/tasks/mesh/ + - /en/overview/tasks/mesh/ + - /en/overview/tasks/mesh/ description: '演示多种部署形态的 Dubbo Mesh 解决方案,以及 Dubbo Mesh 如何帮助用户实现架构的平滑迁移。 ' linkTitle: 服务网格 no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/_index.md index 7b5fde9e4b20..ccfdc24f7732 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/bookinfo-proxyless/ - - /zh-cn/overview/tasks/mesh/bookinfo-proxyless/ + - /en/overview/tasks/mesh/bookinfo-proxyless/ + - /en/overview/tasks/mesh/bookinfo-proxyless/ description: 通过完整的 Bookinfo 示例操作演示 Dubbo Proxyless 接入 Istio 服务网格体系。 linkTitle: Proxyless Bookinfo no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/_index.md index c289f9e83829..1be4feb3ad39 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/bookinfo-proxyless/security/ - - /zh-cn/overview/tasks/mesh/bookinfo-proxyless/security/ + - /en/overview/tasks/mesh/bookinfo-proxyless/security/ + - /en/overview/tasks/mesh/bookinfo-proxyless/security/ description: Envoy Security Bookinfo 示例。 linkTitle: security no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/request-routing.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/request-routing.md index 331e4113dee0..b99afc0e7056 100644 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/request-routing.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/request-routing.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/bookinfo-proxyless/security/request-routing/ - - /zh-cn/overview/tasks/mesh/bookinfo-proxyless/security/request-routing/ + - /en/overview/tasks/mesh/bookinfo-proxyless/security/request-routing/ + - /en/overview/tasks/mesh/bookinfo-proxyless/security/request-routing/ description: This task shows you how to route requests dynamically to multiple versions of a microservice. linkTitle: Request Routing title: Request Routing diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/_index.md index 6eca306ef193..e7eb3bc5a260 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/bookinfo-proxyless/traffic/ - - /zh-cn/overview/tasks/mesh/bookinfo-proxyless/traffic/ + - /en/overview/tasks/mesh/bookinfo-proxyless/traffic/ + - /en/overview/tasks/mesh/bookinfo-proxyless/traffic/ description: Envoy Traffic Management Bookinfo 示例。 linkTitle: Traffic Management no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/request-routing.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/request-routing.md index 0dbdd0fd657f..2e0b8fcea690 100644 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/request-routing.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/request-routing.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/bookinfo-proxyless/traffic/request-routing/ - - /zh-cn/overview/tasks/mesh/bookinfo-proxyless/traffic/request-routing/ + - /en/overview/tasks/mesh/bookinfo-proxyless/traffic/request-routing/ + - /en/overview/tasks/mesh/bookinfo-proxyless/traffic/request-routing/ description: This task shows you how to route requests dynamically to multiple versions of a microservice. linkTitle: Request Routing title: Request Routing diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/_index.md index 5d1be6f6d536..7c849d94c10e 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/bookinfo-sidecar/ - - /zh-cn/overview/tasks/mesh/bookinfo-sidecar/ + - /en/overview/tasks/mesh/bookinfo-sidecar/ + - /en/overview/tasks/mesh/bookinfo-sidecar/ description: 通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系。 linkTitle: Envoy Bookinfo no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/_index.md index a3f7360997dd..1cd99c7a9699 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/bookinfo-sidecar/security/ - - /zh-cn/overview/tasks/mesh/bookinfo-sidecar/security/ + - /en/overview/tasks/mesh/bookinfo-sidecar/security/ + - /en/overview/tasks/mesh/bookinfo-sidecar/security/ description: Envoy Security Bookinfo 示例。 linkTitle: security no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/request-routing.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/request-routing.md index 1fe3ef2259e6..819f8f647fd8 100644 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/request-routing.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/request-routing.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/bookinfo-sidecar/security/request-routing/ - - /zh-cn/overview/tasks/mesh/bookinfo-sidecar/security/request-routing/ + - /en/overview/tasks/mesh/bookinfo-sidecar/security/request-routing/ + - /en/overview/tasks/mesh/bookinfo-sidecar/security/request-routing/ description: This task shows you how to route requests dynamically to multiple versions of a microservice. linkTitle: Request Routing title: Request Routing diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/_index.md index 0d89f84427f3..8a3a001d052b 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/bookinfo-sidecar/traffic/ - - /zh-cn/overview/tasks/mesh/bookinfo-sidecar/traffic/ + - /en/overview/tasks/mesh/bookinfo-sidecar/traffic/ + - /en/overview/tasks/mesh/bookinfo-sidecar/traffic/ description: Envoy Traffic Management Bookinfo 示例。 linkTitle: Traffic Management no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/request-routing.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/request-routing.md index c2e66be1380d..c179332ae2a3 100644 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/request-routing.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/request-routing.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/bookinfo-sidecar/traffic/request-routing/ - - /zh-cn/overview/tasks/mesh/bookinfo-sidecar/traffic/request-routing/ + - /en/overview/tasks/mesh/bookinfo-sidecar/traffic/request-routing/ + - /en/overview/tasks/mesh/bookinfo-sidecar/traffic/request-routing/ description: This task shows you how to route requests dynamically to multiple versions of a microservice. linkTitle: Request Routing title: Request Routing diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/_index.md index ed0ca6513731..e0e9adbc57d2 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/migration/ - - /zh-cn/overview/tasks/mesh/migration/ + - /en/overview/tasks/mesh/migration/ + - /en/overview/tasks/mesh/migration/ description: 演示 Dubbo Mesh 如何帮助用户实现架构的平滑迁移。 linkTitle: Dubbo2 平滑迁移 no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/deploy-on-k8s.md b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/deploy-on-k8s.md index 1dd6ba058287..9109795884c0 100644 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/deploy-on-k8s.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/deploy-on-k8s.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/migration/deploy-on-k8s/ - - /zh-cn/overview/tasks/mesh/migration/deploy-on-k8s/ + - /en/overview/tasks/mesh/migration/deploy-on-k8s/ + - /en/overview/tasks/mesh/migration/deploy-on-k8s/ description: 该示例演示了直接以 API-SERVER 为注册中心,将 Dubbo 应用部署到 Kubernetes 并复用 Kubernetes Native Service 的使用示例。 此示例的局限在于需要授予每个 Dubbo 应用访问 API-SERVER 特定资源的权限,同时直接访问和监听 API-SERVER 对中小集群来说并没有什么问题, 但对于较大规模集群而言可能给 API-SERVER 的稳定性带来一定的考验。除此之外,可以考虑配合 Dubbo 控制面将 Dubbo 应用部署到 Kuberntes 的方案, 该方案无需授予 Dubbo 应用访问 API-SERVER 的权限,也无需为 API-SERVER 引连接过多数据面造成的稳定性而担心。 linkTitle: 协议识别 title: 协议识别 diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/dubbo-mesh.md b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/dubbo-mesh.md index 2160c8358e30..c4d76f86074a 100644 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/dubbo-mesh.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/dubbo-mesh.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/migration/dubbo-mesh/ - - /zh-cn/overview/tasks/mesh/migration/dubbo-mesh/ + - /en/overview/tasks/mesh/migration/dubbo-mesh/ + - /en/overview/tasks/mesh/migration/dubbo-mesh/ description: 本示例演示了如何使用 Istio+Envoy 的 Service Mesh 部署模式开发 Dubbo3 服务。Dubbo3 服务使用 Triple 作为通信协议,通信过程经过 Envoy 数据面拦截,同时使用标准 Istio 的流量治理能力治理 Dubbo。 linkTitle: 地址同步 title: 地址同步 diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/proxyless.md b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/proxyless.md index d6a0b18d8584..595d1f907ff6 100644 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/proxyless.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/proxyless.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/mesh/migration/proxyless/ - - /zh-cn/overview/tasks/mesh/migration/proxyless/ + - /en/overview/tasks/mesh/migration/proxyless/ + - /en/overview/tasks/mesh/migration/proxyless/ description: "" linkTitle: 其他问题? title: 其他问题? @@ -47,7 +47,7 @@ public class AnnotatedGreetingService implements GreetingService { **由于原生 xDS 协议无法支持获取从接口到应用名的映射,因此需要配置 `providedBy` 参数来标记此服务来自哪个应用。** -未来我们将基于 Dubbo Mesh 的控制面实现自动的[服务映射](/zh-cn/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/)关系获取,届时将不需要独立配置参数即可将 Dubbo 运行在 Mesh 体系下,敬请期待。 +未来我们将基于 Dubbo Mesh 的控制面实现自动的[服务映射](/en/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/)关系获取,届时将不需要独立配置参数即可将 Dubbo 运行在 Mesh 体系下,敬请期待。 ```java @Component("annotatedConsumer") @@ -66,7 +66,7 @@ public class GreetingServiceConsumer { 我们建议将 `protocol` 配置为 tri 协议(全面兼容 grpc 协议),以获得在 istio 体系下更好的体验。 -为了使 Kubernetes 感知到应用的状态,需要配置 `qosAcceptForeignIp` 参数,以便 Kubernetes 可以获得正确的应用状态,[对齐生命周期](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/dubbo-kubernetes-probe/)。 +为了使 Kubernetes 感知到应用的状态,需要配置 `qosAcceptForeignIp` 参数,以便 Kubernetes 可以获得正确的应用状态,[对齐生命周期](/en/overview/mannual/java-sdk/advanced-features-and-usage/others/dubbo-kubernetes-probe/)。 ```properties dubbo.application.name=dubbo-samples-xds-provider @@ -216,7 +216,7 @@ spec: 3. providedBy 由于当前 Dubbo 版本受限于 istio 的通信模型无法获取接口所对应的应用名,因此需要配置 `providedBy` 参数来标记此服务来自哪个应用。 -未来我们将基于 Dubbo Mesh 的控制面实现自动的[服务映射](/zh-cn/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/)关系获取,届时将不需要独立配置参数即可将 Dubbo 运行在 Mesh 体系下,敬请期待。 +未来我们将基于 Dubbo Mesh 的控制面实现自动的[服务映射](/en/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/)关系获取,届时将不需要独立配置参数即可将 Dubbo 运行在 Mesh 体系下,敬请期待。 4. protocol name @@ -249,7 +249,7 @@ spec: dubbo.application.metadataServicePort=20885 ``` -未来我们将基于 Dubbo Mesh 的控制面实现自动的[服务元数据](/zh-cn/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/)获取,届时将不需要独立配置参数即可将 Dubbo 运行在 Mesh 体系下,敬请期待。 +未来我们将基于 Dubbo Mesh 的控制面实现自动的[服务元数据](/en/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/)获取,届时将不需要独立配置参数即可将 Dubbo 运行在 Mesh 体系下,敬请期待。 6. qosAcceptForeignIp diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/_index.md b/content/en/overview/mannual/java-sdk/tasks/observability/_index.md index e01bba132fd0..7d50be85d74b 100755 --- a/content/en/overview/mannual/java-sdk/tasks/observability/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/observability/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/observability/ - - /zh-cn/overview/tasks/observability/ + - /en/overview/tasks/observability/ + - /en/overview/tasks/observability/ description: 基于 Admin、Metrics、Grafana 等可视化的观测集群状态。 linkTitle: 观测服务 title: 观测服务 diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/console.md b/content/en/overview/mannual/java-sdk/tasks/observability/console.md index 8cd477158c51..e3bf9e88d51a 100755 --- a/content/en/overview/mannual/java-sdk/tasks/observability/console.md +++ b/content/en/overview/mannual/java-sdk/tasks/observability/console.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/observability/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/observability/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/observability/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/observability/ description: 可观测性 linkTitle: 控制台 title: 可观测性 diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/grafana.md b/content/en/overview/mannual/java-sdk/tasks/observability/grafana.md index 517ba25cba4c..26da3c94c10a 100644 --- a/content/en/overview/mannual/java-sdk/tasks/observability/grafana.md +++ b/content/en/overview/mannual/java-sdk/tasks/observability/grafana.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/observability/grafana/ - - /zh-cn/overview/tasks/observability/grafana/ + - /en/overview/tasks/observability/grafana/ + - /en/overview/tasks/observability/grafana/ description: "" linkTitle: Grafana no_list: true @@ -14,8 +14,8 @@ weight: 3 ## 在您开始之前 - 一个可以访问的 Kubernetes 集群 -- 正确安装并配置 [普罗米修斯服务](/zh-cn/overview/reference/integrations/prometheus/#安装) -- 安装 [Grafana](/zh-cn/overview/reference/integrations/grafana/) +- 正确安装并配置 [普罗米修斯服务](/en/overview/reference/integrations/prometheus/#安装) +- 安装 [Grafana](/en/overview/reference/integrations/grafana/) - 部署 [示例应用](https://github.com/apache/dubbo-samples/tree/master/4-governance/dubbo-samples-metrics-spring-boot) 并开启指标采集 ## 确认组件正常运行 diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/logging.md b/content/en/overview/mannual/java-sdk/tasks/observability/logging.md index b3f919c9862f..d7daa9f284a9 100644 --- a/content/en/overview/mannual/java-sdk/tasks/observability/logging.md +++ b/content/en/overview/mannual/java-sdk/tasks/observability/logging.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/observability/logging/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/observability/logging/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/observability/logging/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/observability/logging/ description: Dubbo 框架的日志配置, hide_summary: true linkTitle: 日志管理 @@ -187,7 +187,7 @@ dubbo: {{% /alert %}} ## 动态修改日志级别 -自 3.3 版本开始,Dubbo 框架支持通过 http 或 telnet 命令,在运行态动态修改日志配置(级别、框架等)。以下是使用示例,关于 telnet 命令的更多内容,可查看 [qos 命令指南](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/qos-list/)。 +自 3.3 版本开始,Dubbo 框架支持通过 http 或 telnet 命令,在运行态动态修改日志配置(级别、框架等)。以下是使用示例,关于 telnet 命令的更多内容,可查看 [qos 命令指南](/en/overview/mannual/java-sdk/reference-manual/qos/qos-list/)。 1. 查询日志配置 命令:`loggerInfo` diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/prometheus.md b/content/en/overview/mannual/java-sdk/tasks/observability/prometheus.md index 8c01c21322b6..c2231586e8a7 100644 --- a/content/en/overview/mannual/java-sdk/tasks/observability/prometheus.md +++ b/content/en/overview/mannual/java-sdk/tasks/observability/prometheus.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/observability/prometheus/ - - /zh-cn/overview/tasks/observability/prometheus/ + - /en/overview/tasks/observability/prometheus/ + - /en/overview/tasks/observability/prometheus/ description: "" linkTitle: Prometheus no_list: true @@ -15,7 +15,7 @@ weight: 2 本文演示如何在 Kubernetes 环境下部署 Prometheus 并实现对 Dubbo 集群的监控数据统计与查询,你需要完成或具备以下内容: * 本地或远端 Kubernetes 集群 -* 确保 [Prometheus 正确安装](/zh-cn/overview/reference/integrations/prometheus/#安装) +* 确保 [Prometheus 正确安装](/en/overview/reference/integrations/prometheus/#安装) * 部署 [示例应用](https://github.com/apache/dubbo-samples/tree/master/4-governance/dubbo-samples-metrics-spring-boot) 并开启指标采集 * 使用 Prometheus dashboard 查询数据指标 @@ -45,7 +45,7 @@ kubectl -n dubbo-demo get deployments 获得 Prometheus 访问地址 `kubectl port-forward service/prometheus-server 9090:9090`, 打开浏览器,访问 localhost:9090/graph 即可打开 Prometheus 控制台。 -接下来,执行 Prometheus 查询命令。可以在此确认 [Dubbo 支持的 Metrics 指标](/zh-cn/overview/reference/metrics/standard_metrics/)。 +接下来,执行 Prometheus 查询命令。可以在此确认 [Dubbo 支持的 Metrics 指标](/en/overview/reference/metrics/standard_metrics/)。 **1. 在 “Expression” 一览,输入 `dubbo_consumer_qps_total`,返回以下结果** diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/_index.md b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/_index.md index 575b24ef82bd..81ea28b4c741 100755 --- a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/observability/tracing/ - - /zh-cn/overview/tasks/observability/tracing/ + - /en/overview/tasks/observability/tracing/ + - /en/overview/tasks/observability/tracing/ description: "" linkTitle: 全链路追踪 no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/otlp.md b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/otlp.md index 99d5e1e63cdf..4a4704dfe3f6 100644 --- a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/otlp.md +++ b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/otlp.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/observability/tracing/otlp/ - - /zh-cn/overview/tasks/observability/tracing/otlp/ + - /en/overview/tasks/observability/tracing/otlp/ + - /en/overview/tasks/observability/tracing/otlp/ description: "这个案例展示了在 Dubbo 项目中以 OpenTelemetry 作为 Tracer,将 Trace 信息上报到 Otlp Collector,再由 collector 转发至 Zipkin、Jagger。" linkTitle: OpenTelemetry no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/skywalking.md b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/skywalking.md index c49b1e889863..caf76ebed8c7 100644 --- a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/skywalking.md +++ b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/skywalking.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/observability/tracing/skywalking/ - - /zh-cn/overview/tasks/observability/tracing/skywalking/ + - /en/overview/tasks/observability/tracing/skywalking/ + - /en/overview/tasks/observability/tracing/skywalking/ description: "本文演示如何将 Dubbo 接入 Skywalking 全链路监控体系" linkTitle: Skywalking no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/tracing.md b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/tracing.md index 9ea7be95c37f..2cfff892f075 100644 --- a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/tracing.md +++ b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/tracing.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/observability/tracing/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/observability/tracing/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/observability/tracing/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/observability/tracing/ description: Dubbo 内置了全链路追踪能力,你可以通过引入 spring-boot-starter 或者相关依赖开启链路跟踪能力,通过将跟踪数据导出到一些主流实现如 Zipkin、Skywalking、Jaeger 等后端系统,可以实现全链路跟踪数据的分析与可视化展示。 hide_summary: true linkTitle: 链路追踪 @@ -30,8 +30,8 @@ Dubbo 目前借助 Micrometer Observation 完成 Tracing 的所有埋点工作 ``` 更多完整示例请参见: -* [使用 Zipkin 实现 Dubbo 全链路追踪](/zh-cn/overview/tasks/observability/tracing/zipkin/) -* [使用 Skywalking 实现 Dubbo 全链路追踪](/zh-cn/overview/tasks/observability/tracing/skywalking/) +* [使用 Zipkin 实现 Dubbo 全链路追踪](/en/overview/tasks/observability/tracing/zipkin/) +* [使用 Skywalking 实现 Dubbo 全链路追踪](/en/overview/tasks/observability/tracing/skywalking/) ## 关联日志 diff --git a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/zipkin.md b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/zipkin.md index 42c00fe3496e..bf622652522e 100644 --- a/content/en/overview/mannual/java-sdk/tasks/observability/tracing/zipkin.md +++ b/content/en/overview/mannual/java-sdk/tasks/observability/tracing/zipkin.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/observability/tracing/zipkin/ - - /zh-cn/overview/tasks/observability/tracing/zipkin/ + - /en/overview/tasks/observability/tracing/zipkin/ + - /en/overview/tasks/observability/tracing/zipkin/ description: "这个示例演示了 Dubbo 集成 Zipkin 全链路追踪的基础示例" linkTitle: Zipkin no_list: true diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/_index.md b/content/en/overview/mannual/java-sdk/tasks/protocols/_index.md index d4009fbfd385..e952f7aeeb98 100755 --- a/content/en/overview/mannual/java-sdk/tasks/protocols/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/_index.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/overview/tasks/protocols/ - - /zh-cn/overview/tasks/protocols/ - - /zh-cn/overview/mannual/java-sdk/tasks/protocol/ + - /en/overview/tasks/protocols/ + - /en/overview/tasks/protocols/ + - /en/overview/mannual/java-sdk/tasks/protocol/ description: 演示 Dubbo 多协议的应用场景 hide: true linkTitle: 通信协议 diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/dubbo.md b/content/en/overview/mannual/java-sdk/tasks/protocols/dubbo.md index 057591a935ff..8a5b3e5a5fb6 100644 --- a/content/en/overview/mannual/java-sdk/tasks/protocols/dubbo.md +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/dubbo.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/protocols/dubbo/ - - /zh-cn/overview/tasks/protocols/dubbo/ + - /en/overview/tasks/protocols/dubbo/ + - /en/overview/tasks/protocols/dubbo/ description: "演示了如何开发基于 `dubbo` 协议通信的服务。" linkTitle: dubbo协议 title: "基于 TCP 的 RPC 通信协议 - dubbo" @@ -115,5 +115,5 @@ dubbo: ### 共享连接 对 dubbo 协议实现来说,**消费端机器A与提供者机器B之间默认是使用的同一个链接**,即不论在 A 与 B 之间有多少服务调用,默认都始终使用同一个 tcp 连接。当然,Dubbo 框架提供了方法可以让您调整 A 与 B 之间的 tcp 连接数。 -此外,dubbo 协议还支持配置如 payload 限制、序列化、连接数、连接超时时间、心跳等,具体请参见[【参考手册 - dubbo协议】](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/dubbo/)。 +此外,dubbo 协议还支持配置如 payload 限制、序列化、连接数、连接超时时间、心跳等,具体请参见[【参考手册 - dubbo协议】](/en/overview/mannual/java-sdk/reference-manual/protocol/dubbo/)。 diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/protocol.md b/content/en/overview/mannual/java-sdk/tasks/protocols/protocol.md index 40a7e7a3ec5a..02bd0afff6bc 100755 --- a/content/en/overview/mannual/java-sdk/tasks/protocols/protocol.md +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/protocol.md @@ -36,7 +36,7 @@ Dubbo 作为一款 RPC 框架内置了高效的 RPC 通信协议,帮助解决 | **rest** | tri 或 rest | - Java Interface + SpringMVC
- Java Interface + JAX-RS | 50051 | HTTP/1、HTTP/2 | JSON | 否 | {{% alert title="注意" color="info" %}} - 考虑到对过往版本的兼容性,当前 Dubbo 各个发行版本均默认使用 `dubbo` 通信协议。**对于新用户而言,我们强烈建议在一开始就明确配置使用 `triple` 协议**,老用户也尽快参考文档 [实现协议的平滑迁移](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/)。 + 考虑到对过往版本的兼容性,当前 Dubbo 各个发行版本均默认使用 `dubbo` 通信协议。**对于新用户而言,我们强烈建议在一开始就明确配置使用 `triple` 协议**,老用户也尽快参考文档 [实现协议的平滑迁移](/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/)。 {{% /alert %}} 接下来,我们一起看以下几个协议的基本使用方式。 @@ -66,7 +66,7 @@ public interface DemoService { } ``` -可以说只设置 `protocol="tri"` 就可以了,其他与老版本 dubbo 协议开发没有任何区别。请通过【进阶学习 - 通信协议】查看 [java Interface + Triple 协议的具体使用示例](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/interface/)。 +可以说只设置 `protocol="tri"` 就可以了,其他与老版本 dubbo 协议开发没有任何区别。请通过【进阶学习 - 通信协议】查看 [java Interface + Triple 协议的具体使用示例](/en/overview/mannual/java-sdk/tasks/protocols/triple/interface/)。 #### 2. Protobuf(IDL) 使用 Protobuf(IDL) 的方式定义服务,**适合于当前或未来有跨语言诉求的开发团队,同一份 IDL 服务可同时用于 Java/Go/Node.js 等多语言微服务开发,劣势是 protobuf 学习成本较高**。 @@ -101,7 +101,7 @@ public interface Greeter extends org.apache.dubbo.rpc.model.DubboStub { } ``` -Protobuf 模式支持的序列化方式有 Protobuf、Protobuf-json 两种模式。请通过【进阶学习 - 通信协议】查看 [Protobuf (IDL) + Triple 协议的具体使用示例](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/)。 +Protobuf 模式支持的序列化方式有 Protobuf、Protobuf-json 两种模式。请通过【进阶学习 - 通信协议】查看 [Protobuf (IDL) + Triple 协议的具体使用示例](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/)。 #### 3. 我该使用哪种编程模式,如何选择? @@ -125,7 +125,7 @@ curl \ 以上默认使用 `org.apache.dubbo.springboot.demo.idl.Greeter/greet` 这种 HTTP 访问路径,且仅支持 post 方法,如果你想对外发布 REST 风格服务,请参考下文 REST 协议小节。 -也可参考[【使用教程 - 前端网关接入】](/zh-cn/overview/mannual/java-sdk/tasks/gateway/triple/) +也可参考[【使用教程 - 前端网关接入】](/en/overview/mannual/java-sdk/tasks/gateway/triple/) ## Dubbo 协议 ### 基本配置 @@ -153,14 +153,14 @@ public interface DemoService { 由于 Dubbo2 默认序列化协议是 hessian2,对于部分有拦截rpc调用payload的场景,比如sidecar等对链路payload有拦截与解析,在升级过程中需留意兼容性问题。 {{% /alert %}} -* 关于 dubbo 协议的具体使用示例请参见【进阶学习 - 通信协议】中的 [dubbo 协议示例](/zh-cn/overview/mannual/java-sdk/tasks/protocols/dubbo/)。 +* 关于 dubbo 协议的具体使用示例请参见【进阶学习 - 通信协议】中的 [dubbo 协议示例](/en/overview/mannual/java-sdk/tasks/protocols/dubbo/)。 ### HTTP 接入方式 由于 dubbo 协议无法支持 http 流量直接接入,因此需要有一层网关实现前端 http 协议到后端 dubbo 协议的转换过程(`http -> dubbo`)。Dubbo 框架提供了 `泛化调用` 能力,可以让网关在无服务接口定义的情况下对后端服务发起调用。 -目前社区有很多开源网关产品(Higress、Shenyu、APISIX、Tengine等)支持 `http -> dubbo` 的,它们大部分都提供了可视化界面配置参数映射(泛化调用),同时还支持基于 Nacos、Zookeeper 等主流注册中心的自动地址发现,具体请查看 [【使用教程 - HTTP网关接入】](/zh-cn/overview/mannual/java-sdk/tasks/gateway/dubbo/)。 +目前社区有很多开源网关产品(Higress、Shenyu、APISIX、Tengine等)支持 `http -> dubbo` 的,它们大部分都提供了可视化界面配置参数映射(泛化调用),同时还支持基于 Nacos、Zookeeper 等主流注册中心的自动地址发现,具体请查看 [【使用教程 - HTTP网关接入】](/en/overview/mannual/java-sdk/tasks/gateway/dubbo/)。 ## REST 协议 在本文前面我们曾提到,自 3.3 版本开始 triple 协议支持以 rest 风格发布标准的 http 服务,因此,如果我们发布 rest 风格的服务等同于使用 triple 协议,只不过,我们要在服务定义上加入特定的注解(Spring Web、JAX-RS)。 diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/rest.md b/content/en/overview/mannual/java-sdk/tasks/protocols/rest.md index 985fee6fb06f..b3917619c03b 100644 --- a/content/en/overview/mannual/java-sdk/tasks/protocols/rest.md +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/rest.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/protocols/ - - /zh-cn/overview/tasks/protocols/ + - /en/overview/tasks/protocols/ + - /en/overview/tasks/protocols/ description: "演示了如何以标准 `rest` 请求访问 triple、dubbo 协议发布的服务。" hide: true linkTitle: rest协议 @@ -17,7 +17,7 @@ weight: 3 {{% alert title="注意" color="warning" %}} 从 Dubbo 3.3 版本开始,rest 协议已移至 extensions 库,由 triple 协议来对 Rest 提供更全面的支持,新版本的内置协议实现只剩下 triple 和 dubbo。 -
因此,当我们提到 rest 时,都是指 triple 协议的 rest 访问支持能力,具体参见 [Triple Rest用户手册](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual/) +
因此,当我们提到 rest 时,都是指 triple 协议的 rest 访问支持能力,具体参见 [Triple Rest用户手册](/en/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual/) {{% /alert %}} 在讲解 [triple 协议示例](../triple/interface/#curl) 时,我们曾提到 triple 协议支持以 `application/json` 格式直接访问: @@ -135,7 +135,7 @@ curl -v -H "c: 3" -d 'name=Yang' "http://127.0.0.1:8081/org.apache.dubbo.rest.de #Hello Mr. Yang, 3 ``` -代码讲解:
可以看到输出 Hello Mr. Yang, 3 ,没有双引号是因为通过指定后缀 txt 的方式要求用 `text/plain` 输出
通过这个例子可以了解如何通过 Mapping 注解来定制路径,通过 Param 注解来定制参数来源,并支持通过 post body 或 url方式传递参数,详细说明参见: [Basic使用指南](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual/#GdlnC) +代码讲解:
可以看到输出 Hello Mr. Yang, 3 ,没有双引号是因为通过指定后缀 txt 的方式要求用 `text/plain` 输出
通过这个例子可以了解如何通过 Mapping 注解来定制路径,通过 Param 注解来定制参数来源,并支持通过 post body 或 url方式传递参数,详细说明参见: [Basic使用指南](/en/overview/mannual/java-sdk/reference-manual/protocol/tripe-rest-manual/#GdlnC) ### 观察日志 @@ -177,7 +177,7 @@ DEBUG .d.r.h.AbstractServerHttpChannelObserver : [DUBBO] Http response headers 设想你是一条业务线负责人,你们有一套基于 Dubbo 开发的微服务集群,集群内服务间都是基于 triple 二进制协议通信;公司内还有一个重要业务,是跑在基于 Spring Cloud 开发的微服务集群上,而 Spring Cloud 集群内的服务间都是 http+json 协议通信。现在要实现这两个业务的互通,服务之间如何实现互调那?triple 协议支持 rest 格式访问可以解决这个问题,对于 Dubbo 微服务集群而言,相当于是对内使用 triple 二进制协议通信,对外交互使用 triple 提供的 rest 请求格式。 -关于这部分的具体使用示例,请参考博客 [微服务最佳实践零改造实现 Spring Cloud、Apache Dubbo 互通](/zh-cn/blog/2023/10/07/微服务最佳实践零改造实现-spring-cloud-apache-dubbo-互通/)。 +关于这部分的具体使用示例,请参考博客 [微服务最佳实践零改造实现 Spring Cloud、Apache Dubbo 互通](/en/blog/2023/10/07/微服务最佳实践零改造实现-spring-cloud-apache-dubbo-互通/)。 ### 网关流量接入 diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/triple/_index.md b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/_index.md index 7fc9974eac39..1d54d89d2e96 100755 --- a/content/en/overview/mannual/java-sdk/tasks/protocols/triple/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/protocols/ - - /zh-cn/overview/tasks/protocols/ + - /en/overview/tasks/protocols/ + - /en/overview/tasks/protocols/ description: "演示了如何开发基于 `triple` 协议通信的服务。" hide: true linkTitle: triple协议 diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/triple/grpc.md b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/grpc.md index 0841c9457e27..7ee9df8fe33d 100644 --- a/content/en/overview/mannual/java-sdk/tasks/protocols/triple/grpc.md +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/grpc.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/tasks/protocols/grpc/ + - /en/overview/tasks/protocols/grpc/ description: "演示了如何使用 triple 协议实现 Dubbo 服务与标准 gRPC 服务的互相调用。" linkTitle: 发布/调用标准gRPC服务 title: 使用 Dubbo 开发 gRPC 服务 diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/triple/interface.md b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/interface.md index 367b1138fb75..3cb43ba914e2 100644 --- a/content/en/overview/mannual/java-sdk/tasks/protocols/triple/interface.md +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/interface.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/pojo/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/pojo/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/pojo/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/pojo/ description: "Triple 协议完全兼容 gRPC,但易用性更好不绑定 Protobuf,你可以继续使用 `Java 接口` 直接定义服务。" linkTitle: Java接口方式 title: 使用 Java 接口方式开发 triple 通信服务 @@ -145,4 +145,4 @@ Protobuf 模式固然有一定的性能优势,但易用性与使用成本也 由于 gRPC 仅支持 protobuf 模式,因此本文介绍的 `接口+triple` 的模式无法与谷歌官方原生的 gRPC 协议互调。 ### 前端流量接入 -对于来自前端的 HTTP 流量(比如浏览器或 web 应用),要想通过网关接入 triple,就要走 triple 内置的 `application/json` 模式发起调用,具体请参见[【使用教程-HTTP网关接入】](/zh-cn/overview/mannual/java-sdk/tasks/gateway/triple/)。 \ No newline at end of file +对于来自前端的 HTTP 流量(比如浏览器或 web 应用),要想通过网关接入 triple,就要走 triple 内置的 `application/json` 模式发起调用,具体请参见[【使用教程-HTTP网关接入】](/en/overview/mannual/java-sdk/tasks/gateway/triple/)。 diff --git a/content/en/overview/mannual/java-sdk/tasks/protocols/triple/streaming.md b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/streaming.md index 19ac9a12db5e..f19c2b613b73 100644 --- a/content/en/overview/mannual/java-sdk/tasks/protocols/triple/streaming.md +++ b/content/en/overview/mannual/java-sdk/tasks/protocols/triple/streaming.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/reference-manual/protocol/triple/streaming/ - - /zh-cn/docs3-v2/java-sdk/reference-manual/protocol/triple/streaming/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/streaming/ + - /en/docs3-v2/java-sdk/reference-manual/protocol/triple/streaming/ description: "演示了服务端流、双向流等 Streaming 流式通信的基本使用方法。" linkTitle: Streaming流式通信 title: Streaming 通信 @@ -80,7 +80,7 @@ service Greeter{ * `serverStream(GreeterRequest) returns (stream GreeterReply)` 服务端流 ### 生成代码 -接下来,我们需要从 .proto 服务定义生成 Dubbo 客户端和服务器接口。protoc dubbo 插件可以帮助我们生成需要的代码,在使用 Gradle 或 Maven 时,protoc 构建插件可以生成必要的代码作为构建的一部分。具体 maven 配置及代码生成步骤我们在 [上一节](/zh-cn/overview/mannual/java-sdk/tasks/protocols/triple/idl/) 中有具体的描述。 +接下来,我们需要从 .proto 服务定义生成 Dubbo 客户端和服务器接口。protoc dubbo 插件可以帮助我们生成需要的代码,在使用 Gradle 或 Maven 时,protoc 构建插件可以生成必要的代码作为构建的一部分。具体 maven 配置及代码生成步骤我们在 [上一节](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/) 中有具体的描述。 target/generated-sources/protobuf/java/org/apache/dubbo/samples/tri/streaming/ 目录中可以发现如下生成代码,其中我们将重点讲解 `DubboGreeterTriple.java`: diff --git a/content/en/overview/mannual/java-sdk/tasks/rate-limit/_index.md b/content/en/overview/mannual/java-sdk/tasks/rate-limit/_index.md index dc231b35c7aa..b118f3398cbb 100755 --- a/content/en/overview/mannual/java-sdk/tasks/rate-limit/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/rate-limit/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/rate-limit/ - - /zh-cn/overview/tasks/rate-limit/ + - /en/overview/tasks/rate-limit/ + - /en/overview/tasks/rate-limit/ description: 演示 Dubbo 熔断、限流、降级等场景工作方式 hide: true linkTitle: 限流降级 diff --git a/content/en/overview/mannual/java-sdk/tasks/rate-limit/adaptive-concurrency-control.md b/content/en/overview/mannual/java-sdk/tasks/rate-limit/adaptive-concurrency-control.md index ebb60201fd1a..12780ff90f38 100644 --- a/content/en/overview/mannual/java-sdk/tasks/rate-limit/adaptive-concurrency-control.md +++ b/content/en/overview/mannual/java-sdk/tasks/rate-limit/adaptive-concurrency-control.md @@ -6,7 +6,7 @@ type: docs weight: 3 --- -自适应限流的设计与实现思路请参考 [Dubbo 自适应限流功能](/zh-cn/overview/reference/proposals/heuristic-flow-control/#自适应限流)。自适应限流能够确保分布式系统稳定性和可靠性,例如在服务提供商资源有限且多变的场景下。 +自适应限流的设计与实现思路请参考 [Dubbo 自适应限流功能](/en/overview/reference/proposals/heuristic-flow-control/#自适应限流)。自适应限流能够确保分布式系统稳定性和可靠性,例如在服务提供商资源有限且多变的场景下。 ## 使用场景 - 服务降级预防:当服务提供者因资源耗尽而性能下降时,使用自适应限流暂时减少其接受的请求数直至恢复正常。 diff --git a/content/en/overview/mannual/java-sdk/tasks/rate-limit/concurrency-control.md b/content/en/overview/mannual/java-sdk/tasks/rate-limit/concurrency-control.md index 46b9c13a30be..b6ce94afb3c8 100644 --- a/content/en/overview/mannual/java-sdk/tasks/rate-limit/concurrency-control.md +++ b/content/en/overview/mannual/java-sdk/tasks/rate-limit/concurrency-control.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control/ description: "Dubbo 框架内置的并发控制或者限流策略,通过限制从同一客户端到同一服务的并发请求数,防止恶意请求使服务器过载,确保服务的稳定性,并防止使用过多资源。" linkTitle: 框架内置限流 title: Dubbo 框架内置的并发控制策略 @@ -98,4 +98,4 @@ private DemoService demoService; ```xml -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/tasks/rate-limit/sentinel.md b/content/en/overview/mannual/java-sdk/tasks/rate-limit/sentinel.md index c375214ec0aa..b5e17067aefb 100644 --- a/content/en/overview/mannual/java-sdk/tasks/rate-limit/sentinel.md +++ b/content/en/overview/mannual/java-sdk/tasks/rate-limit/sentinel.md @@ -1,10 +1,10 @@ --- aliases: - - /zh-cn/overview/tasks/ecosystem/rate-limit/ - - /zh-cn/overview/what/ecosystem/rate-limit/ - - /zh-cn/overview/what/ecosystem/rate-limit/sentinel/ - - /zh/overview/tasks/rate-limit/sentinel/ - - /zh-cn/overview/tasks/rate-limit/sentinel/ + - /en/overview/tasks/ecosystem/rate-limit/ + - /en/overview/what/ecosystem/rate-limit/ + - /en/overview/what/ecosystem/rate-limit/sentinel/ + - /en/overview/tasks/rate-limit/sentinel/ + - /en/overview/tasks/rate-limit/sentinel/ description: "使用 Sentinel 保护您的 Dubbo 应用,防止应用因个别服务的突发流量过载而出现稳定性问题。" linkTitle: Sentinel限流 title: 使用 Sentinel 应对突发流量,保护您的应用 diff --git a/content/en/overview/mannual/java-sdk/tasks/security/_index.md b/content/en/overview/mannual/java-sdk/tasks/security/_index.md index 8a213e0f2de8..c2496db1897f 100755 --- a/content/en/overview/mannual/java-sdk/tasks/security/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/security/_index.md @@ -1,6 +1,6 @@ --- aliases: - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/security/ description: 演示 Dubbo 配置安全策略的方式 hide: true linkTitle: 安全策略 diff --git a/content/en/overview/mannual/java-sdk/tasks/security/auth.md b/content/en/overview/mannual/java-sdk/tasks/security/auth.md index aa3fe59d48b8..68fe80259d27 100644 --- a/content/en/overview/mannual/java-sdk/tasks/security/auth.md +++ b/content/en/overview/mannual/java-sdk/tasks/security/auth.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/security/auth/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/security/auth/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/auth/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/security/auth/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/security/auth/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/security/auth/ description: 了解 Dubbo 服务鉴权 linkTitle: 服务鉴权 title: 服务鉴权 diff --git a/content/en/overview/mannual/java-sdk/tasks/security/class-check.md b/content/en/overview/mannual/java-sdk/tasks/security/class-check.md index 56b12c0153fd..7476b822355a 100644 --- a/content/en/overview/mannual/java-sdk/tasks/security/class-check.md +++ b/content/en/overview/mannual/java-sdk/tasks/security/class-check.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/security/class-check/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/security/class-check/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/security/class-check/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/security/class-check/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/ description: 了解 Dubbo 类检查机制 linkTitle: 类检查机制 title: 类检查机制 diff --git a/content/en/overview/mannual/java-sdk/tasks/security/tls.md b/content/en/overview/mannual/java-sdk/tasks/security/tls.md index 06ae0537e3c8..78b0369ec17e 100644 --- a/content/en/overview/mannual/java-sdk/tasks/security/tls.md +++ b/content/en/overview/mannual/java-sdk/tasks/security/tls.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/security/tls/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/security/tls/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/tls/ - - /zh-cn/overview/mannual/java-sdk/reference-manual/protocol/tls/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/security/tls/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/security/tls/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/security/tls/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/tls/ description: ' 了解在 Dubbo 的 TLS 保证传输安全' linkTitle: TLS支持 title: TLS支持 @@ -58,7 +58,7 @@ if (!mutualTls) {} } ``` -为尽可能保证应用启动的灵活性,TLS Cert 的指定还能通过 -D 参数或环境变量等方式来在启动阶段根据部署环境动态指定,参考 Dubbo [配置读取规则](/zh-cn/docs/advanced/config-rule) +为尽可能保证应用启动的灵活性,TLS Cert 的指定还能通过 -D 参数或环境变量等方式来在启动阶段根据部署环境动态指定,参考 Dubbo [配置读取规则](/en/docs/advanced/config-rule) > 在服务调用的安全性上,Dubbo 在后续的版本中会持续投入,其中服务发现/调用的鉴权机制预计在接下来的版本中就会和大家见面。 diff --git a/content/en/overview/mannual/java-sdk/tasks/security/token-authorization.md b/content/en/overview/mannual/java-sdk/tasks/security/token-authorization.md index 24b380af2887..bba9bf31268d 100644 --- a/content/en/overview/mannual/java-sdk/tasks/security/token-authorization.md +++ b/content/en/overview/mannual/java-sdk/tasks/security/token-authorization.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/security/token-authorization/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/security/token-authorization/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/token-authorization/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/security/token-authorization/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/security/token-authorization/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/security/token-authorization/ description: 了解 Dubbo 权限控制的配置和使用 linkTitle: 权限控制 title: 权限控制 diff --git a/content/en/overview/mannual/java-sdk/tasks/service-discovery/_index.md b/content/en/overview/mannual/java-sdk/tasks/service-discovery/_index.md index 26f412b27334..a0ae0d3bb28e 100755 --- a/content/en/overview/mannual/java-sdk/tasks/service-discovery/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/service-discovery/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/others/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/others/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/others/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/others/ description: 注册中心与服务发现 linkTitle: 服务发现 title: 注册中心、服务发现与负载均衡 diff --git a/content/en/overview/mannual/java-sdk/tasks/service-discovery/kubernetes.md b/content/en/overview/mannual/java-sdk/tasks/service-discovery/kubernetes.md index 69278d23c6c3..58e6f31d7217 100644 --- a/content/en/overview/mannual/java-sdk/tasks/service-discovery/kubernetes.md +++ b/content/en/overview/mannual/java-sdk/tasks/service-discovery/kubernetes.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ description: "通过示例演示基于 Kubernetes Service 的服务发现模式。" linkTitle: 使用Kubernetes注册中心 title: 基于 Kubernetes Service 的服务发现 diff --git a/content/en/overview/mannual/java-sdk/tasks/service-discovery/loadbalance.md b/content/en/overview/mannual/java-sdk/tasks/service-discovery/loadbalance.md index a373e96ae62d..43f773d9322b 100644 --- a/content/en/overview/mannual/java-sdk/tasks/service-discovery/loadbalance.md +++ b/content/en/overview/mannual/java-sdk/tasks/service-discovery/loadbalance.md @@ -1,10 +1,10 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance/ description: "Dubbo 支持的消费端负载均衡策略及其使用方法" linkTitle: 负载均衡 title: 负载均衡策略与配置细节 @@ -117,4 +117,4 @@ referenceConfig.get(); ## 自适应负载均衡配置 -只需要在 consumer 或 provider 端将 `loadbalance` 设置为 `p2c` 或者 `adaptive` 即可,可在此查看 [工作原理](/zh-cn/overview/reference/proposals/heuristic-flow-control) +只需要在 consumer 或 provider 端将 `loadbalance` 设置为 `p2c` 或者 `adaptive` 即可,可在此查看 [工作原理](/en/overview/reference/proposals/heuristic-flow-control) diff --git a/content/en/overview/mannual/java-sdk/tasks/service-discovery/nacos.md b/content/en/overview/mannual/java-sdk/tasks/service-discovery/nacos.md index 871130d721c7..4c29041ff2dc 100644 --- a/content/en/overview/mannual/java-sdk/tasks/service-discovery/nacos.md +++ b/content/en/overview/mannual/java-sdk/tasks/service-discovery/nacos.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ description: "通过示例演示如何使用 Nacos 作为注册中心实现自动服务发现。" linkTitle: 使用Nacos注册中心 title: 使用 Nacos 作为注册中心实现自动服务发现 diff --git a/content/en/overview/mannual/java-sdk/tasks/service-discovery/registry.md b/content/en/overview/mannual/java-sdk/tasks/service-discovery/registry.md index 667c3cb0d22f..e08561832687 100644 --- a/content/en/overview/mannual/java-sdk/tasks/service-discovery/registry.md +++ b/content/en/overview/mannual/java-sdk/tasks/service-discovery/registry.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ description: "Dubbo 服务发现的工作方式、基本使用方法与配置细节,涵盖延迟注册、优雅上下线、启动时检查、断网恢复、推空保护等。" linkTitle: 服务发现 title: 服务发现的工作方式、基本使用方法与配置细节 @@ -13,7 +13,7 @@ weight: 1 Dubbo 支持基于注册中心的自动实例发现机制,即 Dubbo 提供者注册实例地址到注册中心,Dubbo 消费者通过订阅注册中心变更事件自动获取最新实例变化,从而确保流量始终转发到正确的节点之上。Dubbo 目前支持 Nacos、Zookeeper、Kubernetes Service 等多种注册中心接入。 ## 注册中心 -以下是 Dubbo 服务发现接入的一些主流注册中心实现,更多扩展实现与工作原理请查看 [注册中心参考手册](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/overview/): +以下是 Dubbo 服务发现接入的一些主流注册中心实现,更多扩展实现与工作原理请查看 [注册中心参考手册](/en/overview/mannual/java-sdk/reference-manual/registry/overview/): | 注册中心 | 配置值 | 服务发现模型 | 是否支持鉴权 | spring-boot-starter | | --- | --- | --- | --- | --- | @@ -39,7 +39,7 @@ dubbo: ``` {{% alert title="手动注册" color="warning" %}} -通过配置 `delay = -1`,可以禁止框架自动发布服务到注册中心,直到用户通过调用 [online](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/qos-list/) 等命令手动完成发布,可以用这个特性配合部署系统实现服务的优雅上线,让用户对上线时机有更好的控制。具体配置如下: +通过配置 `delay = -1`,可以禁止框架自动发布服务到注册中心,直到用户通过调用 [online](/en/overview/mannual/java-sdk/reference-manual/qos/qos-list/) 等命令手动完成发布,可以用这个特性配合部署系统实现服务的优雅上线,让用户对上线时机有更好的控制。具体配置如下: ```yaml dubbo: @@ -63,7 +63,7 @@ dubbo: ### 优雅下线 优雅下线的推荐步骤如下: -1. 在尝试停止 Dubbo 进程之前,先调用 [offline](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/qos-list/) 从注册中心摘除实例地址(建议操作完成后额外等待几秒钟,以确保注册中心地址下线事件生效)。 +1. 在尝试停止 Dubbo 进程之前,先调用 [offline](/en/overview/mannual/java-sdk/reference-manual/qos/qos-list/) 从注册中心摘除实例地址(建议操作完成后额外等待几秒钟,以确保注册中心地址下线事件生效)。 2. 通过 `kill pid` 尝试停止 Dubbo 进程,此时框架会依次检查以下环节: * 2.1 框架向所有消费方(通过遍历其持有的 channel 链接)发送 readonly 事件,收到事件的消费方将会停止往该实例发送新的请求。此动作默认开启。 * 2.2 框架会等待一定的时间,等待线程池中所有运行中的请求处理完成,默认是 `10000` 毫秒,可通过 `-Ddubbo.service.shutdown.wait=20000` 调整等待时间。 @@ -110,10 +110,10 @@ public class DemoServiceImpl implements DemoService {} private DemoService demoService ``` -关于多注册中心的更多配置、使用场景说明请参见[【参考手册 - 注册中心 - 多注册中心】](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/multiple-registry/) +关于多注册中心的更多配置、使用场景说明请参见[【参考手册 - 注册中心 - 多注册中心】](/en/overview/mannual/java-sdk/reference-manual/registry/multiple-registry/) ## 应用级vs接口级 -Dubbo3 在兼容 Dubbo2 `接口级服务发现`的同时,定义了新的`应用级服务发现`模型,关于它们的含义与工作原理请参考 [应用级服务发现](/zh-cn/overview/mannual/java-sdk/reference-manual/registry/service-discovery-application-vs-interface/)。Dubbo3 具备自动协商服务发现模型的能力,因此老版本 Dubbo2 用户可以无缝升级 Dubbo3。 +Dubbo3 在兼容 Dubbo2 `接口级服务发现`的同时,定义了新的`应用级服务发现`模型,关于它们的含义与工作原理请参考 [应用级服务发现](/en/overview/mannual/java-sdk/reference-manual/registry/service-discovery-application-vs-interface/)。Dubbo3 具备自动协商服务发现模型的能力,因此老版本 Dubbo2 用户可以无缝升级 Dubbo3。 {{% alert title="注意" color="warning" %}} 如果你是 Dubbo 新用户,强烈建议增加以下配置项目,以明确指示框架使用应用级服务发现: @@ -124,7 +124,7 @@ dubbo: register-mode: instance # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all ``` -老用户均建议参考 [应用级服务发现迁移指南](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery/) 完成平滑迁移。 +老用户均建议参考 [应用级服务发现迁移指南](/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration-service-discovery/) 完成平滑迁移。 {{% /alert %}} ## 只注册 @@ -262,12 +262,12 @@ dubbo: ``` ## 直连提供者 -如果你的项目开启了服务发现,但在测试中想调用某个特定的 ip,可通过设置对端 ip 地址的 [直连模式](/zh-cn/overview/mannual/java-sdk/tasks/framework/more/explicit-target/) 绕过服务发现机制进行调用。 +如果你的项目开启了服务发现,但在测试中想调用某个特定的 ip,可通过设置对端 ip 地址的 [直连模式](/en/overview/mannual/java-sdk/tasks/framework/more/explicit-target/) 绕过服务发现机制进行调用。 ## 问题排查 相比于 client 到 server 的 RPC 直连调用,开启服务发现后,常常会遇到各种个样奇怪的调用失败问题,以下是一些常见的问题与排查方法。 -1. **消费方找不到可用地址 (No Provider available)**,这里有详细的 [具体原因排查步骤](/zh-cn/overview/mannual/java-sdk/tasks/troubleshoot/no-provider/)。 +1. **消费方找不到可用地址 (No Provider available)**,这里有详细的 [具体原因排查步骤](/en/overview/mannual/java-sdk/tasks/troubleshoot/no-provider/)。 2. **忘记配置注册中心**,从 3.3.0 开始,不配置注册中心地址的情况下,应用也是能够正常启动的,只是应用的任何服务都不会注册到注册中心,或者从注册中心订阅地址列表。 3. **注册中心连不上**,如果配置了 `check=false`,虽然进程启动成功,可能服务注册、订阅并没有成功。 4. **消费方因没有有效的地址而启动报错**,可以通过配置ReferenceConfig跳过可用地址列表检查,注解示例为 `@DubboRerefence(check=false)`。 diff --git a/content/en/overview/mannual/java-sdk/tasks/service-discovery/zookeeper.md b/content/en/overview/mannual/java-sdk/tasks/service-discovery/zookeeper.md index faf88af98de8..3d4cb6adc4e9 100644 --- a/content/en/overview/mannual/java-sdk/tasks/service-discovery/zookeeper.md +++ b/content/en/overview/mannual/java-sdk/tasks/service-discovery/zookeeper.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/others/graceful-shutdown/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/consistent-hash/ description: "通过示例演示如何使用 Zookeeper 作为注册中心实现自动服务发现。" linkTitle: 使用Zookeeper注册中心 title: 使用 Zookeeper 作为注册中心实现自动服务发现 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/accesslog.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/accesslog.md index 71a04e45436d..49185b79058e 100644 --- a/content/en/overview/mannual/java-sdk/tasks/traffic-management/accesslog.md +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/accesslog.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/overview/tasks/traffic-management/accesslog/ - - /zh-cn/overview/tasks/traffic-management/accesslog/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/accesslog/ + - /en/overview/tasks/traffic-management/accesslog/ + - /en/overview/tasks/traffic-management/accesslog/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/accesslog/ description: "" linkTitle: 访问日志 title: 通过动态开启访问日志跟踪服务调用情况 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/architecture.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/architecture.md index b52f3ba13c42..46b0884123ff 100755 --- a/content/en/overview/mannual/java-sdk/tasks/traffic-management/architecture.md +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/architecture.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/traffic-management/ - - /zh-cn/overview/tasks/traffic-management/ + - /en/overview/tasks/traffic-management/ + - /en/overview/tasks/traffic-management/ description: 演示 Dubbo 流量治理特性的使用方式。 linkTitle: 示例应用架构 title: 示例应用架构 @@ -12,7 +12,7 @@ weight: 1 此任务基于一个简单的线上商城微服务系统演示了 Dubbo 的流量管控能力。 {{% alert title="注意" color="warning" %}} -本示例展示的所有能力均基于 [Dubbo 路由规则](/zh-cn/overview/what/core-features/traffic/introduction/) 实现,如想了解具体工作原理可查看详情。 +本示例展示的所有能力均基于 [Dubbo 路由规则](/en/overview/what/core-features/traffic/introduction/) 实现,如想了解具体工作原理可查看详情。 {{% /alert %}} diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/arguments.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/arguments.md index 91eaca43d7da..248da9da1fac 100644 --- a/content/en/overview/mannual/java-sdk/tasks/traffic-management/arguments.md +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/arguments.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/traffic-management/arguments/ - - /zh-cn/overview/tasks/traffic-management/arguments/ + - /en/overview/tasks/traffic-management/arguments/ + - /en/overview/tasks/traffic-management/arguments/ description: "" linkTitle: 参数路由 title: 根据请求参数引导流量分布 @@ -85,4 +85,4 @@ conditions: * arguments[0]=1~100 * url_key=value -更为灵活的是,条件路由的匹配条件支持扩展,用户可以自定义匹配条件的来源和格式,具体可参见 [条件路由规则说明](/zh-cn/overview/core-features/traffic/condition-rule/)。 +更为灵活的是,条件路由的匹配条件支持扩展,用户可以自定义匹配条件的来源和格式,具体可参见 [条件路由规则说明](/en/overview/core-features/traffic/condition-rule/)。 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/host.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/host.md index 59529b3a6ae0..a3d8bcf8c08f 100644 --- a/content/en/overview/mannual/java-sdk/tasks/traffic-management/host.md +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/host.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/traffic-management/host/ - - /zh-cn/overview/tasks/traffic-management/host/ + - /en/overview/tasks/traffic-management/host/ + - /en/overview/tasks/traffic-management/host/ description: "" linkTitle: 固定机器导流 title: 将流量点对点引导到一台机器 (如排查问题) diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/isolation.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/isolation.md index b9cc840a0cee..9470de028d9f 100644 --- a/content/en/overview/mannual/java-sdk/tasks/traffic-management/isolation.md +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/isolation.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/traffic-management/isolation/ - - /zh-cn/overview/tasks/traffic-management/isolation/ + - /en/overview/tasks/traffic-management/isolation/ + - /en/overview/tasks/traffic-management/isolation/ description: "" linkTitle: 环境隔离 title: 通过标签实现流量隔离环境(灰度、多套开发环境等) @@ -133,6 +133,6 @@ force: true ## 其他事项 -除了示例中演示的动态环境划分,也可以在部署态指定实例所属流量标签(通过一个特殊的 key `dubbo.provider.tag` 实现),这样当实例启动成功后就已经被自动圈定在某个流量环境,具体配置方式可参见 [标签路由](/zh-cn/overview/core-features/traffic/tag-rule/) 说明。 +除了示例中演示的动态环境划分,也可以在部署态指定实例所属流量标签(通过一个特殊的 key `dubbo.provider.tag` 实现),这样当实例启动成功后就已经被自动圈定在某个流量环境,具体配置方式可参见 [标签路由](/en/overview/core-features/traffic/tag-rule/) 说明。 通常,`dubbo.tag` 流量标的传递需要依赖全链路追踪工具的帮助,Dubbo 只会负责 A-B 的点对点标签传递,示例中也是通过在每次点对点 RPC 调用前重复设置达成的传递效果,在实践中,全链路灰度往往从 tag 设置进全链路上下文后自动启动,我们只需要扩展 Dubbo Filter 将全链路工具上下文中的 tag 标签读取并设置进 Dubbo 上下文即可实现全链路在 Dubbo 中的自动传递,具体可参见 [Dubbo 链路追踪集成示例](../../observability)。另外,除了 RPC 调用,在微服务体系的其他基础产品中也需要依赖全链路上下文保证灰度标识的传递,以保证完整的流量隔离环境。 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/mock.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/mock.md index f788b9ec8eda..f07e965e08b0 100644 --- a/content/en/overview/mannual/java-sdk/tasks/traffic-management/mock.md +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/mock.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/traffic-management/mock/ - - /zh-cn/overview/tasks/traffic-management/mock/ + - /en/overview/tasks/traffic-management/mock/ + - /en/overview/tasks/traffic-management/mock/ description: "" linkTitle: 服务降级 title: 在大促之前对弱依赖调用进行服务降级 @@ -69,4 +69,4 @@ configs: 服务降级功能也可以用于开发测试环境,由于微服务分布式的特点,不同的服务或应用之间都有相互依赖关系,因此,一个服务或应用很难不依赖其他服务而独立部署工作。但测试环境下并不是所有服务都是随时就绪的状态,这对于微服务强调的服务独立演进是一个很大的障碍,通过服务降级这个功能,我们可以模拟或短路应用对其他服务的依赖,从而可以让应用按照自己预期的行为 Mock 外部服务调用的返回结果。具体可参见 [Dubbo Admin 服务 Mock](../.././../reference/admin/mock/) 特性的使用方式。 -Dubbo 的降级规则用来设置发生降级时的行为和返回值,而对于何时应该执行限流降级动作,即限流降级时机的判断并没有过多涉猎,这一点 Dubbo 通过集成更专业的限流降级产品如 Sentinel 进行了补全,可以配合 Dubbo 降级规则一起使用,具体可参见 [限流降级](/zh-cn/overview/core-features/traffic/circuit-breaking/) 文档。 +Dubbo 的降级规则用来设置发生降级时的行为和返回值,而对于何时应该执行限流降级动作,即限流降级时机的判断并没有过多涉猎,这一点 Dubbo 通过集成更专业的限流降级产品如 Sentinel 进行了补全,可以配合 Dubbo 降级规则一起使用,具体可参见 [限流降级](/en/overview/core-features/traffic/circuit-breaking/) 文档。 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/region.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/region.md index b6939326d490..4f0ce3478d1b 100644 --- a/content/en/overview/mannual/java-sdk/tasks/traffic-management/region.md +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/region.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/traffic-management/region/ - - /zh-cn/overview/tasks/traffic-management/region/ + - /en/overview/tasks/traffic-management/region/ + - /en/overview/tasks/traffic-management/region/ description: 在 Dubbo-Admin 动态配置同机房/区域优先 linkTitle: 同区域优先 title: 同机房/区域优先 @@ -82,4 +82,4 @@ conditions: ## 其他事项 -我们上面的示例并未纳入多区域之间注册中心的复杂性,如果每个区域部署有独立的注册中心,则多区域间的地址同步就是一个需要考虑的问题。对于这种场景,Dubbo 通过多注册&多订阅机制也提供了同区域优先的支持,具体可以参见[多注册&多订阅](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-registry/)相关文档。 +我们上面的示例并未纳入多区域之间注册中心的复杂性,如果每个区域部署有独立的注册中心,则多区域间的地址同步就是一个需要考虑的问题。对于这种场景,Dubbo 通过多注册&多订阅机制也提供了同区域优先的支持,具体可以参见[多注册&多订阅](/en/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-registry/)相关文档。 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/retry.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/retry.md index 263f481a6004..f9880c231a68 100644 --- a/content/en/overview/mannual/java-sdk/tasks/traffic-management/retry.md +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/retry.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/traffic-management/retry/ - - /zh-cn/overview/tasks/traffic-management/retry/ + - /en/overview/tasks/traffic-management/retry/ + - /en/overview/tasks/traffic-management/retry/ description: "" linkTitle: 服务重试 title: 通过重试提高服务调用成功率 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/timeout.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/timeout.md index eb11f1c5428f..a88476a9d176 100644 --- a/content/en/overview/mannual/java-sdk/tasks/traffic-management/timeout.md +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/timeout.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/traffic-management/timeout/ - - /zh-cn/overview/tasks/traffic-management/timeout/ + - /en/overview/tasks/traffic-management/timeout/ + - /en/overview/tasks/traffic-management/timeout/ description: 在 Dubbo-Admin 动态调整服务超时时间 linkTitle: 调整超时时间 title: 动态调整服务超时时间 diff --git a/content/en/overview/mannual/java-sdk/tasks/traffic-management/weight.md b/content/en/overview/mannual/java-sdk/tasks/traffic-management/weight.md index 095fb25d7852..dd4d6ced5afa 100644 --- a/content/en/overview/mannual/java-sdk/tasks/traffic-management/weight.md +++ b/content/en/overview/mannual/java-sdk/tasks/traffic-management/weight.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/traffic-management/weight/ - - /zh-cn/overview/tasks/traffic-management/weight/ + - /en/overview/tasks/traffic-management/weight/ + - /en/overview/tasks/traffic-management/weight/ description: "" linkTitle: 权重比例 title: 基于权重值的比例流量转发 diff --git a/content/en/overview/mannual/java-sdk/tasks/trasaction/distributed-transaction.md b/content/en/overview/mannual/java-sdk/tasks/trasaction/distributed-transaction.md index 33dd863f54ba..fd6c85caf496 100644 --- a/content/en/overview/mannual/java-sdk/tasks/trasaction/distributed-transaction.md +++ b/content/en/overview/mannual/java-sdk/tasks/trasaction/distributed-transaction.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction/ - - /zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/distributed-transaction/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction/ + - /en/overview/mannual/java-sdk/advanced-features-and-usage/service/distributed-transaction/ description: "使用 Seata 解决 Dubbo 服务数据一致性问题,支持分布式事务。" linkTitle: 使用Seata让Dubbo支持分布式事务 title: 使用 Seata 支持分布式事务 diff --git a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/_index.md b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/_index.md index 96c7baa73055..60f913005cd5 100755 --- a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/troubleshoot/ - - /zh-cn/overview/tasks/troubleshoot/ + - /en/overview/tasks/troubleshoot/ + - /en/overview/tasks/troubleshoot/ description: 对常见的 Dubbo 异常场景进行排查的思路 linkTitle: 故障排查 title: 故障排查 diff --git a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/no-provider.md b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/no-provider.md index 50b70e0da9d7..7393ace8f19b 100644 --- a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/no-provider.md +++ b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/no-provider.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/troubleshoot/no-provider/ - - /zh-cn/overview/tasks/troubleshoot/no-provider/ + - /en/overview/tasks/troubleshoot/no-provider/ + - /en/overview/tasks/troubleshoot/no-provider/ description: 在 Dubbo 抛出地址找不到异常的时候的排查思路 linkTitle: 地址找不到异常 title: 地址找不到异常 @@ -364,7 +364,7 @@ As Consumer side: 如果您找到了您所发布的服务,但是对应的服务发现模型错误,请检查以下清单: -1. 是否配置的订阅迁移规则,如 `dubbo-migration.yaml` 或动态配置,请参考 [应用级服务发现地址迁移规则说明](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) +1. 是否配置的订阅迁移规则,如 `dubbo-migration.yaml` 或动态配置,请参考 [应用级服务发现地址迁移规则说明](/en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) 如果您找到了您所发布的服务,且对应的服务发现模型下地址数非 `0`,请跳转到第 7 步进行排查。 @@ -509,7 +509,7 @@ Disabled Invokers: 请检查对应迁移模型是否符合预期,默认为 `APPLCATION_FIRST`,如果对应的服务发现模型错误,请检查以下清单: -1. 是否配置的订阅迁移规则,如 `dubbo-migration.yaml` 或动态配置,请参考 [应用级服务发现地址迁移规则说明](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) +1. 是否配置的订阅迁移规则,如 `dubbo-migration.yaml` 或动态配置,请参考 [应用级服务发现地址迁移规则说明](/en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) 如果迁移模型正确,请检查对应模型下的**所有**地址是否符合预期,如果不符合预期,请检查以下清单: @@ -598,4 +598,4 @@ dubbo> ``` 注:采集路由信息会消耗一定的性能,排查完毕后请及时关闭。 -参考文档:[路由状态命令](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/router-snapshot/) +参考文档:[路由状态命令](/en/overview/mannual/java-sdk/reference-manual/qos/router-snapshot/) diff --git a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/profiler.md b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/profiler.md index 0c4c0a213e2f..296e64086739 100644 --- a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/profiler.md +++ b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/profiler.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/java-sdk/advanced-features-and-usage/performance/profiler/ - - /zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/performance/profiler/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/profiler/ + - /en/docs3-v2/java-sdk/advanced-features-and-usage/performance/profiler/ description: Dubbo 请求耗时采样 linkTitle: 请求耗时采样 title: 请求耗时采样 @@ -22,7 +22,7 @@ weight: 1 ## 使用方式 -`simple profiler` 默认自动开启,对于请求处理时间超过超时时间 3/4 的,都会通过日志打印出慢调用信息。如果需要开启 `detail profiler` 模式或者修改超时告警比例,可以参考[性能采样命令](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/profiler/)文档。 +`simple profiler` 默认自动开启,对于请求处理时间超过超时时间 3/4 的,都会通过日志打印出慢调用信息。如果需要开启 `detail profiler` 模式或者修改超时告警比例,可以参考[性能采样命令](/en/overview/mannual/java-sdk/reference-manual/qos/profiler/)文档。 ### 日志说明 diff --git a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/request-failed.md b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/request-failed.md index f5d3322f0514..7b752557b3ce 100644 --- a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/request-failed.md +++ b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/request-failed.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/troubleshoot/request-failed/ - - /zh-cn/overview/tasks/troubleshoot/request-failed/ + - /en/overview/tasks/troubleshoot/request-failed/ + - /en/overview/tasks/troubleshoot/request-failed/ description: 在 Dubbo 请求成功率低时的排查思路 linkTitle: 请求成功率低 title: 请求成功率低 diff --git a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/start-failed.md b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/start-failed.md index b89baf6503da..3b916c55d88b 100644 --- a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/start-failed.md +++ b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/start-failed.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/tasks/troubleshoot/start-failed/ - - /zh-cn/overview/tasks/troubleshoot/start-failed/ + - /en/overview/tasks/troubleshoot/start-failed/ + - /en/overview/tasks/troubleshoot/start-failed/ description: 在 Dubbo 应用启动失败时的排查思路 linkTitle: 应用启动失败 title: 应用启动失败 diff --git a/content/en/overview/mannual/java-sdk/versions.md b/content/en/overview/mannual/java-sdk/versions.md index e20d7459cba5..38da8613e231 100644 --- a/content/en/overview/mannual/java-sdk/versions.md +++ b/content/en/overview/mannual/java-sdk/versions.md @@ -1,8 +1,8 @@ --- aliases: - - /zh/docs3-v2/golang-sdk/refer/compatible_version/ - - /zh-cn/docs3-v2/golang-sdk/refer/compatible_version/ - - /zh-cn/overview/mannual/golang-sdk/preface/refer/compatible_version/ + - /en/docs3-v2/golang-sdk/refer/compatible_version/ + - /en/docs3-v2/golang-sdk/refer/compatible_version/ + - /en/overview/mannual/golang-sdk/preface/refer/compatible_version/ description: 依赖适配版本号 title: 版本信息 type: docs @@ -14,10 +14,10 @@ weight: 1 | Dubbo 分支 | 最新版本 | JDK | Spring Boot | 组件版本 | 详细说明 | | --- | --- | --- | --- | --- | --- | --- | --- | -| 3.3.x (当前文档) | 3.3.0 | 8, 17, 21 | [2.x、3.x](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://github.com/apache/dubbo/blob/dubbo-3.3.0/dubbo-dependencies-bom/pom.xml#L91) | - [版本变更记录](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.2-to-3.3-compatibility-guide/)

- **生产可用(推荐,长期维护)!** 最新Triple协议升级,内置Metrics、Tracing、GraalVM支持等 | -| [3.2.x](https://dubbo-202409.staged.apache.org/zh-cn/overview/mannual/java-sdk/) | 3.2.10 | 8, 17 | [2.x、3.x](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://github.com/apache/dubbo/blob/dubbo-3.2.10/dubbo-dependencies-bom/pom.xml#L91) | - [版本变更记录](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.1-to-3.2-compatibility-guide/)

- 生产可用(长期维护)! | -| [3.1.x](https://dubbo-202409.staged.apache.org/zh-cn/overview/mannual/java-sdk/) | 3.1.11 | 8, 17 | [2.x、3.x](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://github.com/apache/dubbo/blob/dubbo-3.1.11/dubbo-dependencies-bom/pom.xml#L91) | - [版本变更记录](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.0-to-3.1-compatibility-guide/)

- 仅修复安全漏洞! | -| [3.0.x](https://dubbo-202409.staged.apache.org/zh-cn/docs/) | 3.0.15 | 8 | [2.x](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://github.com/apache/dubbo/blob/dubbo-3.0.15/dubbo-dependencies-bom/pom.xml#L91) | - [版本变更记录](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/2.x-to-3.x-compatibility-guide/)

- 停止维护! | -| [2.7.x](https://dubbo-202409.staged.apache.org/zh-cn/docsv2.7/) | 2.7.23 | 8 | [2.x](/zh-cn/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://raw.githubusercontent.com/apache/dubbo/dubbo-2.7.23/dubbo-dependencies-bom/pom.xml) | - [了解如何升级到Dubbo3](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/)

- 停止维护! | -| 2.6.x | 2.6.20 | 6, 7 | - | _ | - [了解如何升级到Dubbo3](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/)

- 停止维护! | -| 2.5.x | 2.5.10 | 6, 7 | - | - | - [了解如何升级到Dubbo3](/zh-cn/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/)

- 停止维护! | +| 3.3.x (当前文档) | 3.3.0 | 8, 17, 21 | [2.x、3.x](/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://github.com/apache/dubbo/blob/dubbo-3.3.0/dubbo-dependencies-bom/pom.xml#L91) | - [版本变更记录](/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.2-to-3.3-compatibility-guide/)

- **生产可用(推荐,长期维护)!** 最新Triple协议升级,内置Metrics、Tracing、GraalVM支持等 | +| [3.2.x](https://dubbo-202409.staged.apache.org/zh-cn/overview/mannual/java-sdk/) | 3.2.10 | 8, 17 | [2.x、3.x](/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://github.com/apache/dubbo/blob/dubbo-3.2.10/dubbo-dependencies-bom/pom.xml#L91) | - [版本变更记录](/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.1-to-3.2-compatibility-guide/)

- 生产可用(长期维护)! | +| [3.1.x](https://dubbo-202409.staged.apache.org/zh-cn/overview/mannual/java-sdk/) | 3.1.11 | 8, 17 | [2.x、3.x](/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://github.com/apache/dubbo/blob/dubbo-3.1.11/dubbo-dependencies-bom/pom.xml#L91) | - [版本变更记录](/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.0-to-3.1-compatibility-guide/)

- 仅修复安全漏洞! | +| [3.0.x](https://dubbo-202409.staged.apache.org/zh-cn/docs/) | 3.0.15 | 8 | [2.x](/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://github.com/apache/dubbo/blob/dubbo-3.0.15/dubbo-dependencies-bom/pom.xml#L91) | - [版本变更记录](/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/2.x-to-3.x-compatibility-guide/)

- 停止维护! | +| [2.7.x](https://dubbo-202409.staged.apache.org/zh-cn/docsv2.7/) | 2.7.23 | 8 | [2.x](/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#dubbo-spring-boot-starter) | [详情](https://raw.githubusercontent.com/apache/dubbo/dubbo-2.7.23/dubbo-dependencies-bom/pom.xml) | - [了解如何升级到Dubbo3](/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/)

- 停止维护! | +| 2.6.x | 2.6.20 | 6, 7 | - | _ | - [了解如何升级到Dubbo3](/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/)

- 停止维护! | +| 2.5.x | 2.5.10 | 6, 7 | - | - | - [了解如何升级到Dubbo3](/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/migration/)

- 停止维护! | diff --git a/content/en/overview/mannual/nodejs-sdk/quick-start.md b/content/en/overview/mannual/nodejs-sdk/quick-start.md index d27fefb32237..e895f01fcd7c 100644 --- a/content/en/overview/mannual/nodejs-sdk/quick-start.md +++ b/content/en/overview/mannual/nodejs-sdk/quick-start.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/overview/quickstart/nodejs/ - - /zh-cn/overview/quickstart/nodejs/ + - /en/overview/quickstart/nodejs/ + - /en/overview/quickstart/nodejs/ description: 使用 Node.js 开发后端微服务 linkTitle: 快速开始 title: 快速开始 diff --git a/content/en/overview/mannual/rust-sdk/_index.md b/content/en/overview/mannual/rust-sdk/_index.md index cc146fb0aa73..3bd8c9ccfb3f 100755 --- a/content/en/overview/mannual/rust-sdk/_index.md +++ b/content/en/overview/mannual/rust-sdk/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/rust-sdk/ - - /zh-cn/docs3-v2/rust-sdk/ + - /en/docs3-v2/rust-sdk/ + - /en/docs3-v2/rust-sdk/ description: Rust SDK 使用手册 linkTitle: Rust SDK title: Rust SDK 手册 diff --git a/content/en/overview/mannual/rust-sdk/java-interoperability.md b/content/en/overview/mannual/rust-sdk/java-interoperability.md index dcf8a74f8361..afc3e5d1cf23 100644 --- a/content/en/overview/mannual/rust-sdk/java-interoperability.md +++ b/content/en/overview/mannual/rust-sdk/java-interoperability.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/rust-sdk/java-interoperability/ - - /zh-cn/docs3-v2/rust-sdk/java-interoperability/ + - /en/docs3-v2/rust-sdk/java-interoperability/ + - /en/docs3-v2/rust-sdk/java-interoperability/ description: 使用 Rust 调用 Java 开发的 Dubbo 服务。 linkTitle: Rust和Java互相调用 title: Rust和Java互相调用 @@ -75,4 +75,4 @@ reply: GreeterReply { message: "msg3 from server" } trailer: Some(Metadata { inner: {"content-type": "application/grpc", "grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity", "grpc-status": "0"} }) ``` -[Rust侧的接口定义](https://github.com/apache/dubbo-rust/blob/main/examples/greeter/proto/greeter.proto) \ No newline at end of file +[Rust侧的接口定义](https://github.com/apache/dubbo-rust/blob/main/examples/greeter/proto/greeter.proto) diff --git a/content/en/overview/mannual/rust-sdk/quick-start.md b/content/en/overview/mannual/rust-sdk/quick-start.md index 9fa9f61dd4a6..567603a79436 100644 --- a/content/en/overview/mannual/rust-sdk/quick-start.md +++ b/content/en/overview/mannual/rust-sdk/quick-start.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/rust-sdk/quick-start/ - - /zh-cn/docs3-v2/rust-sdk/quick-start/ - - /zh/overview/quickstart/rust/ - - /zh-cn/overview/quickstart/rust/ + - /en/docs3-v2/rust-sdk/quick-start/ + - /en/docs3-v2/rust-sdk/quick-start/ + - /en/overview/quickstart/rust/ + - /en/overview/quickstart/rust/ description: 使用 Rust 快速开发 Dubbo 服务。 linkTitle: 快速开始 title: 快速开始 diff --git a/content/en/overview/mannual/rust-sdk/router-module.md b/content/en/overview/mannual/rust-sdk/router-module.md index 6b78285c9c48..d4ce0da00900 100644 --- a/content/en/overview/mannual/rust-sdk/router-module.md +++ b/content/en/overview/mannual/rust-sdk/router-module.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/rust-sdk/router-module/ - - /zh-cn/docs3-v2/rust-sdk/router-module/ + - /en/docs3-v2/rust-sdk/router-module/ + - /en/docs3-v2/rust-sdk/router-module/ description: "服务路由" linkTitle: 服务路由 title: 服务路由规则 @@ -10,7 +10,7 @@ weight: 2 --- ## 条件路由 -使用模式与 [条件路由文档](/zh/overview/core-features/traffic/condition-rule/) 中的模式类似,但配置格式略有不同,以下是条件路由规则示例。 +使用模式与 [条件路由文档](/en/overview/core-features/traffic/condition-rule/) 中的模式类似,但配置格式略有不同,以下是条件路由规则示例。 基于以下示例规则,所有 `org.apache.dubbo.sample.tri.Greeter` 服务 `greet` 方法的调用都将被转发到有 `port=8888` 标记的地址子集 @@ -60,7 +60,7 @@ conditions: ## 标签路由 -使用模式与 [标签路由文档](/zh/overview/core-features/traffic/tag-rule/)中的模式类似,但配置格式略有不同,以下是标签路由规则示例 +使用模式与 [标签路由文档](/en/overview/core-features/traffic/tag-rule/)中的模式类似,但配置格式略有不同,以下是标签路由规则示例 ```yaml configVersion: v1.0 force: false @@ -150,4 +150,4 @@ enabled: true key: application conditions: - ip=127.0.0.1 => port=8000~8888 -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/rust-sdk/service-discovery.md b/content/en/overview/mannual/rust-sdk/service-discovery.md index d22c33572b27..d1fcaaea38c5 100644 --- a/content/en/overview/mannual/rust-sdk/service-discovery.md +++ b/content/en/overview/mannual/rust-sdk/service-discovery.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/rust-sdk/service-discovery/ - - /zh-cn/docs3-v2/rust-sdk/service-discovery/ + - /en/docs3-v2/rust-sdk/service-discovery/ + - /en/docs3-v2/rust-sdk/service-discovery/ description: 服务发现 linkTitle: 服务发现 title: 服务发现 diff --git a/content/en/overview/mannual/rust-sdk/streaming.md b/content/en/overview/mannual/rust-sdk/streaming.md index 2352eefc65a2..ad93bc4e3d2d 100644 --- a/content/en/overview/mannual/rust-sdk/streaming.md +++ b/content/en/overview/mannual/rust-sdk/streaming.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/rust-sdk/streaming/ - - /zh-cn/docs3-v2/rust-sdk/streaming/ + - /en/docs3-v2/rust-sdk/streaming/ + - /en/docs3-v2/rust-sdk/streaming/ description: 介绍使用 Dubbo Rust 快速开发 Client streaming、Server streaming、Bidirectional streaming 模型的服务。 linkTitle: Streaming通信模型 title: Streaming 通信模型 @@ -386,4 +386,4 @@ reply: GreeterReply { message: "msg1 from server" } reply: GreeterReply { message: "msg2 from server" } reply: GreeterReply { message: "msg3 from server" } trailer: Some(Metadata { inner: {"content-type": "application/grpc", "grpc-status": "0", "grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity"} }) -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/rust-sdk/unix-transport.md b/content/en/overview/mannual/rust-sdk/unix-transport.md index 48c0a4191c7f..8334061730fe 100644 --- a/content/en/overview/mannual/rust-sdk/unix-transport.md +++ b/content/en/overview/mannual/rust-sdk/unix-transport.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/rust-sdk/unix-transport/ - - /zh-cn/docs3-v2/rust-sdk/unix-transport/ + - /en/docs3-v2/rust-sdk/unix-transport/ + - /en/docs3-v2/rust-sdk/unix-transport/ description: 介绍使用 Dubbo Rust Triple 协议使用 Unix 套接字连接器实现通信。 linkTitle: 使用Unix套接字连接器通信 title: 使用Unix套接字连接器通信 @@ -81,4 +81,4 @@ reply: EchoResponse { message: "msg1 from server" } reply: EchoResponse { message: "msg2 from server" } reply: EchoResponse { message: "msg3 from server" } trailer: Some(Metadata { inner: {"grpc-status": "0", "content-type": "application/grpc", "grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity"} }) -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/web-sdk/quick-start.md b/content/en/overview/mannual/web-sdk/quick-start.md index b3690167fabb..aa080a983324 100644 --- a/content/en/overview/mannual/web-sdk/quick-start.md +++ b/content/en/overview/mannual/web-sdk/quick-start.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/rust-sdk/quick-start/ - - /zh-cn/docs3-v2/rust-sdk/quick-start/ + - /en/docs3-v2/rust-sdk/quick-start/ + - /en/docs3-v2/rust-sdk/quick-start/ description: 使用 dubbo-js 开发运行在浏览器页面的微服务。 linkTitle: Web浏览器访问Dubbo服务 title: Web 浏览器访问 Dubbo 服务 diff --git a/content/en/overview/notices/_index.md b/content/en/overview/notices/_index.md index 647a8a0dcd9d..e4a238300a76 100755 --- a/content/en/overview/notices/_index.md +++ b/content/en/overview/notices/_index.md @@ -1,23 +1,24 @@ --- -title: "安全公告" -linkTitle: "安全公告" -description: "Dubbo 安全公告" +title: "Security Announcements" +linkTitle: "Security Announcements" +description: "Dubbo Security Announcements" aliases: - - /zh-cn/blog/notices/ + - /en/blog/notices/ weight: 50 type: docs --- -## 报告安全问题 +## Reporting Security Issues -Apache 软件基金会在消除针对其产品的安全问题和拒绝服务攻击方面采取了非常积极的立场。 +The Apache Software Foundation takes a very proactive stance in eliminating security issues and denial-of-service attacks against its products. -我们强烈鼓励人们首先向我们的安全问题上报邮件列表报告此类问题,然后再在公共论坛上披露这些问题。 +We strongly encourage people to report such issues to our security mailing list before disclosing them in public forums. -请注意,安全邮件列表仅应用于报告未公开的安全漏洞和管理修复此类漏洞的过程。我们无法在此地址接受定期错误报告或其他查询。发送到此地址的所有与我们源代码中未公开的安全问题无关的邮件都将被忽略。 +Please note that the security mailing list is only intended for reporting unpublicized security vulnerabilities and managing the process of fixing such vulnerabilities. We cannot accept regular bug reports or other inquiries at this address. All mail sent to this address that is not related to undisclosed security problems in our source code will be ignored. -如果您需要报告非未公开安全漏洞的错误,请使用错误报告页面。 +If you need to report bugs that are not undisclosed security vulnerabilities, please use the bug report page. -安全问题上报邮件地址:security@dubbo.apache.org +Security issue reporting email: security@dubbo.apache.org + +For more information on how ASF handles potential security issues, please refer to https://www.apache.org/security/ -有关 ASF 如何处理安全潜在问题的更多信息,请参阅 https://www.apache.org/security/ diff --git a/content/en/overview/notices/admin.md b/content/en/overview/notices/admin.md index 306ed30f1a22..e796489af0bf 100644 --- a/content/en/overview/notices/admin.md +++ b/content/en/overview/notices/admin.md @@ -1,30 +1,27 @@ --- -title: "Dubbo Admin 安全" -linkTitle: "Dubbo Admin 安全" +title: "Dubbo Admin Security" +linkTitle: "Dubbo Admin Security" weight: 4 type: docs -description: "更安全地使用 Dubbo Admin" +description: "Using Dubbo Admin more securely" --- -为了便于使用 Dubbo,Dubbo 官方提供了 Dubbo Admin 控制台,以便于管理 Dubbo 应用。 +To facilitate the use of Dubbo, the official Dubbo team provides the Dubbo Admin console to manage Dubbo applications. -## 风险 +## Risks -Dubbo Admin 默认拥有整个集群的查询、调用权限,因此对于线上环境,需要更加谨慎地使用。 -此外,为了减低任意访问 Dubbo Admin 的风险,Dubbo Admin 还提供了简易的鉴权机制。 -为了使 Dubbo Admin 更安全,请参考下面的文档。 +Dubbo Admin by default has the permission to query and invoke the entire cluster, so it must be used more cautiously in a production environment. Additionally, to reduce the risk of arbitrary access to Dubbo Admin, a simple authentication mechanism is provided. To make Dubbo Admin more secure, please refer to the following documentation. -## 鉴权方案 +## Authentication Scheme -Dubbo Admin 默认提供基于用户名密码的登陆机制,在请求过程中基于 JWT Token 进行鉴权。 -从便于初学者的角度出发,Dubbo Admin 包含了一个默认的用户名密码、JWT Secret Token。 +Dubbo Admin by default provides a login mechanism based on username and password, and uses JWT Token for authentication during requests. To make it beginner-friendly, Dubbo Admin includes a default username, password, and JWT Secret Token. -> **由于 Dubbo Admin 是公开发行的,因此默认的用户名密码、JWT Secret Token 都是公开的。 -在您的生产环境中,请务必更换默认的用户名密码、JWT Secret Token。** +> **Because Dubbo Admin is publicly distributed, the default username, password, and JWT Secret Token are also public. +In your production environment, please be sure to replace the default username, password, and JWT Secret Token.** -## 如何更换默认的用户名密码、JWT Secret Token +## How to Replace the Default Username, Password, and JWT Secret Token -对于直接基于 Java 代码打包部署的用户,可以直接修改 `dubbo-admin-server/src/main/resources/application.properties` 中以下配置: +For users who package and deploy directly based on Java code, you can modify the following configurations in `dubbo-admin-server/src/main/resources/application.properties`: ```properties admin.root.user.name=root @@ -32,7 +29,7 @@ admin.root.user.password=root admin.check.signSecret=86295dd0c4ef69a1036b0b0c15158d77 ``` -对于通过 Docker 部署的用户,可以修改 `/dubbo/dubbo-admin/properties` 中以下配置: +For users deploying via Docker, you can modify the following configurations in `/dubbo/dubbo-admin/properties`: ```properties admin.root.user.name=root @@ -40,7 +37,7 @@ admin.root.user.password=root admin.check.signSecret=86295dd0c4ef69a1036b0b0c15158d77 ``` -对于通过 Kubernetes 部署的用户,可以修改 ConfigMap 中以下配置: +For users deploying via Kubernetes, you can modify the following configurations in the ConfigMap: ```properties admin.root.user.name=root @@ -48,7 +45,7 @@ admin.root.user.password=root admin.check.signSecret=86295dd0c4ef69a1036b0b0c15158d77 ``` -对于通过 Helm 部署的用户,可以指定以下配置: +For users deploying via Helm, you can specify the following configurations: ```yaml properties: @@ -57,7 +54,8 @@ properties: admin.check.signSecret: 86295dd0c4ef69a1036b0b0c15158d77 ``` -## 最佳实践 +## Best Practices + +1. Update the default username, password, and JWT Secret Token during private deployment. It is recommended to modify Dubbo Admin's authentication logic to integrate with your organization's personnel management system. +2. Do not expose Dubbo Admin's port directly to the Internet. -1. 请在私有化部署时更新默认的用户名密码、JWT Secret Token。建议修改 Dubbo Admin 的鉴权逻辑接入您所在组织的人员管理系统。 -2. 请勿直接把 Dubbo Admin 的端口暴露到互联网上。 diff --git a/content/en/overview/notices/log4j.md b/content/en/overview/notices/log4j.md index a2e670a1cc76..3bb9373517ef 100755 --- a/content/en/overview/notices/log4j.md +++ b/content/en/overview/notices/log4j.md @@ -1,26 +1,25 @@ - --- -title: "Log4j 漏洞影响" -linkTitle: "Log4j 漏洞影响" -description: "Log4j CVE-2021-44228 漏洞影响" +title: "Log4j Vulnerability Impact" +linkTitle: "Log4j Vulnerability Impact" +description: "Log4j CVE-2021-44228 Vulnerability Impact" aliases: -- /zh-cn/blog/1/01/01/安全漏洞/ +- /en/blog/1/01/01/security-vulnerabilities/ weight: 90 type: docs --- -最近,主流日志组件 [log4j2](https://logging.apache.org/log4j/2.x/) 爆出[安全漏洞 CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228)。 +Recently, the mainstream logging component [log4j2](https://logging.apache.org/log4j/2.x/) exposed a [security vulnerability CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228). -以下是漏洞 CVE-2021-44228 对 Apache Dubbo 框架的影响总结及用户应对指南。 +Below is a summary of the impact of vulnerability CVE-2021-44228 on the Apache Dubbo framework and user response guidelines. -## Dubbo 影响范围 -**该漏洞对 Dubbo 框架使用安全并无影响。** +## Dubbo Impact Range +**This vulnerability does not affect the security use of the Dubbo framework.** -Dubbo 本身不强依赖 log4j2 框架,也不会通过依赖传递将 log4j2 带到业务工程中去,因此,正在使用 Dubbo 2.7.x、3.0.x 等版本的用户均无需强制升级 Dubbo 版本。 +Dubbo itself does not strongly depend on the log4j2 framework, nor does it bring log4j2 into the business project through dependencies. Therefore, users using Dubbo versions 2.7.x, 3.0.x, etc., do not need to forcibly upgrade the Dubbo version. -以下是 Dubbo 各组件对 log4j2 的依赖分析,涉及 `dubbo-common`、`dubbo-spring-boot-starter`、`dubbo-spring-boot-actuator`: +Below is the dependency analysis of various Dubbo components on log4j2, involving `dubbo-common`, `dubbo-spring-boot-starter`, `dubbo-spring-boot-actuator`: -* dubbo-common 包含对 `log4j-core` 的可选依赖,请检查项目自身是否启用了 log4j 依赖,如启用则对应升级即可。 +* dubbo-common includes an optional dependency on `log4j-core`. Please check whether the project itself has enabled log4j dependencies. If enabled, upgrade accordingly. ```xml [INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ dubbo-common --- [INFO] org.apache.dubbo:dubbo-common:jar:2.7.14-SNAPSHOT @@ -29,7 +28,7 @@ Dubbo 本身不强依赖 log4j2 框架,也不会通过依赖传递将 log4j2 ``` -* dubbo-spring-boot-starter 通过 spring-boot 组件传递了 log4j-api 依赖,log4j-api 本身并无安全问题,升级 log4j-core 组件时注意与 log4j-api 的兼容性 +* dubbo-spring-boot-starter passes the log4j-api dependency through the spring-boot component. The log4j-api itself has no security issues. Pay attention to the compatibility with log4j-api when upgrading the log4j-core component. ```xml [INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ dubbo-spring-boot-starter --- @@ -41,7 +40,7 @@ Dubbo 本身不强依赖 log4j2 框架,也不会通过依赖传递将 log4j2 ``` -* dubbo-spring-boot-actuator 通过 spring-boot 组件传递了 log4j-api 依赖,log4j-api 本身并无安全问题,升级 log4j-core 组件时应注意与 log4j-api 的兼容性 +* dubbo-spring-boot-actuator passes the log4j-api dependency through the spring-boot component. The log4j-api itself has no security issues. Pay attention to the compatibility with log4j-api when upgrading the log4j-core component. ```xml [INFO] org.apache.dubbo:dubbo-spring-boot-actuator:jar:2.7.14-SNAPSHOT diff --git a/content/en/overview/notices/protocol.md b/content/en/overview/notices/protocol.md index 30c7eb620275..0011c987b547 100644 --- a/content/en/overview/notices/protocol.md +++ b/content/en/overview/notices/protocol.md @@ -1,14 +1,14 @@ --- -title: "RPC 协议安全" -linkTitle: "RPC 协议安全" +title: "RPC Protocol Security" +linkTitle: "RPC Protocol Security" weight: 2 type: docs -description: "在 Dubbo 中更安全的使用 RPC 协议" +description: "Using RPC protocols securely in Dubbo" --- -Dubbo 支持 RPC 协议的扩展,理论上用户可以基于该扩展机制启用任意的 RPC 协议,这带来了极大的灵活的,但同时也要意识到其中潜藏的安全性风险。 +Dubbo supports the extension of RPC protocols, allowing users to enable any RPC protocol based on this extension mechanism in theory. This provides great flexibility but also comes with potential security risks. -Dubbo 2.7 官方版本提供的序列化协议有如下几种: +The following serialization protocols are provided in the official version of Dubbo 2.7: * Dubbo * RMI * Hessian @@ -18,20 +18,21 @@ Dubbo 2.7 官方版本提供的序列化协议有如下几种: * gRPC * …… -从 Dubbo 3.0 开始默认仅提供以下序列化协议支持: +Starting from Dubbo 3.0, only the following serialization protocols are supported by default: * Dubbo * Triple / gRPC * Http / Rest -对于 Triple、gRPC、Http、Rest 协议都是基于 HTTP 协议构建的,可以严格区分请求的格式,如 Header 为纯文本,避免在读取 Token 时带来的 RCE 等风险。 -对于 Dubbo 协议,由于其基于 TCP 二进制直接设计,除了特定几个字段外均使用序列化协议写入,因此如果开启了有风险的序列化协议,仍然会存在 RCE 等风险。 -对于 RMI 协议,由于其基于 Java 序列化机制,存在 RCE 等风险。 -对于 Hessian 协议,由于其基于 Hessian 序列化机制,且默认 Hessian 协议(非 Dubbo Shade 的 Hessian-Lite 协议)无法配置黑白名单且无默认黑名单,存在 RCE 等风险。 +Triple, gRPC, Http, and Rest protocols are all built on the HTTP protocol, which can strictly distinguish the format of requests, such as headers being plain text, avoiding risks like RCE when reading tokens. +The Dubbo protocol, due to its direct TCP binary design, uses serialization protocols for most fields except specific ones, so enabling risky serialization protocols can still pose RCE risks. +The RMI protocol, based on Java serialization, poses RCE risks. +The Hessian protocol, based on Hessian serialization, poses RCE risks especially since the default Hessian protocol (not the Dubbo-shaded Hessian-Lite) cannot configure blacklists and whitelists and has no default blacklist. -(1)如果用户希望使用 Token 鉴权机制,防止未鉴权的不可信请求来源威胁 Provider 的安全性,应使用 Triple 等基于 Http 标准扩展的协议,避免 token 参数读取时的安全风险。 +(1) If users wish to use a token authentication mechanism to prevent unauthenticated requests from threatening the security of the Provider, they should use protocols like Triple based on HTTP standards to avoid security risks during token parameter reading. -(2)特别的,Dubbo 社区**非常不推荐**将 Dubbo 协议、RMI 协议、Hessian 协议等非基于 Http 标准扩展的协议暴露在公网环境下,因为 Dubbo 协议的设计初衷是为了在内网环境下提供高性能的 RPC 服务,而非公网环境下的服务。 +(2) Specifically, the Dubbo community **highly discourages** exposing Dubbo, RMI, Hessian protocols, and other non-HTTP-standard extended protocols to the public internet, as the Dubbo protocol was initially designed to provide high-performance RPC services within an intranet environment, not in a public internet environment. -(3)如果您的应用有暴露公网访问的需求,Dubbo 社区建议您使用 Triple 协议,并且避免使用非 Protobuf 模式或者是基于 Dubbo 3.3 及以上的版本仅暴露标准 application/json 格式的服务。 +(3) If your application needs public internet exposure, the Dubbo community recommends using the Triple protocol and avoiding the non-Protobuf mode or exposing services only in the standard application/json format based on Dubbo 3.3 and above. + +(4) Note that all networked servers are susceptible to denial-of-service (DoS) attacks. We cannot provide **specific** solutions for general issues (e.g., clients sending large amounts of data to your server or repeatedly requesting the same URL). Apache Dubbo aims to prevent any attacks that could cause server resource consumption disproportionate to the size or structure of input data. Therefore, to protect your server, ensure you have a Web Application Firewall (WAF) or other security devices in place before exposing Dubbo services to the public internet to prevent these attacks. -(4)请注意,所有联网服务器都可能遭受拒绝服务(DoS)攻击,我们无法对通用问题(例如客户端向您的服务器传输大量数据或重复请求相同的URL)提供**特殊**的解决方法。Apache Dubbo 的目标是避免任何会导致服务器资源消耗与输入数据大小或结构不成线性关系的攻击。因此,为了保护您的服务器,在您将 Dubbo 服务暴露到公网之前,请确保您的服务前置有网页应用程序防火墙(WAF)或其他安全设备,以防止这些攻击。 diff --git a/content/en/overview/notices/registry.md b/content/en/overview/notices/registry.md index 405ef404b9ac..bf0bda082182 100644 --- a/content/en/overview/notices/registry.md +++ b/content/en/overview/notices/registry.md @@ -1,14 +1,14 @@ --- -title: "注册中心安全" -linkTitle: "注册中心安全" +title: "Registry Center Security" +linkTitle: "Registry Center Security" weight: 3 type: docs -description: "在 Dubbo 中更安全的使用注册中心" +description: "Using the registry center more securely in Dubbo" --- -Dubbo 支持注册中心的扩展,理论上用户可以基于该扩展机制启用任意的注册中心,这带来了极大的灵活的,但同时也要意识到其中潜藏的安全性风险。 +Dubbo supports the extension of registry centers, theoretically allowing users to enable any registry center based on this extension mechanism. This brings great flexibility but also raises awareness of potential security risks. -Dubbo 2.7 官方版本提供的注册中心有如下几种: +The following registry centers are provided in the official version of Dubbo 2.7: * Zookeeper * Redis * Nacos @@ -16,11 +16,12 @@ Dubbo 2.7 官方版本提供的注册中心有如下几种: * Consul * …… -从 Dubbo 3.0 开始默认仅提供以下注册中心支持: +Starting from Dubbo 3.0, only the following registry centers are supported by default: * Zookeeper * Nacos -对于注册中心,Dubbo 只能完全信任其推送的数据,因此如果注册中心存在安全漏洞,可能会导致 Dubbo 服务被恶意注册或者是被恶意推送数据,从而导致服务被攻击。 -因此为了保证注册中心的安全性,Dubbo 官方建议您: -* 开启注册中心的鉴权机制,如 Zookeeper 的 ACL 机制、Nacos 的用户名密码机制等 -* 避免将注册中心暴露在公网环境下,尽量将注册中心部署在可信内网环境下 +For registry centers, Dubbo can only fully trust the data they push. Therefore, if there are security vulnerabilities in the registry center, it may lead to malicious registration or data being maliciously pushed, causing service attacks. +To ensure the security of the registry center, Dubbo officially recommends: +* Enabling the authentication mechanism of the registry center, such as Zookeeper's ACL mechanism, Nacos’s username and password mechanism, etc. +* Avoiding exposing the registry center to public networks and striving to deploy the registry center in a trusted internal network environment + diff --git a/content/en/overview/notices/serialization.md b/content/en/overview/notices/serialization.md index 77fd0baeea97..ab108c450a1f 100644 --- a/content/en/overview/notices/serialization.md +++ b/content/en/overview/notices/serialization.md @@ -1,21 +1,18 @@ --- -title: "序列化安全" -linkTitle: "序列化安全" +title: "Serialization Security" +linkTitle: "Serialization Security" weight: 1 type: docs aliases: - - /zh-cn/blog/1/01/01/序列化协议安全/ -description: "在 Dubbo 中更安全的使用序列化协议" + - /en/blog/1/01/01/序列化协议安全/ +description: "Using Serialization Protocols More Securely in Dubbo" --- -# 概述 +# Overview -Dubbo 支持序列化协议的扩展,理论上用户可以基于该扩展机制启用任意的序列化协议,这带来了极大的灵活的,但同时也要意识到其中潜藏的安全性风险。 -数据反序列化是最容易被被攻击者利用的一个环节,攻击者利用它执行 RCE 攻击等窃取或破坏服务端数据。 -用户在切换序列化协议或实现前, 应充分调研目标序列化协议及其框架实现的安全性保障,并提前设置相应的安全措施(如设置黑/白名单)。 -Dubbo 框架自身并不能直接保证目标序列化机制的安全性。 +Dubbo supports serialization protocol extensions, allowing users to enable any serialization protocol based on this mechanism theoretically. This brings great flexibility but also potential security risks. Data deserialization is the most susceptible to attacker exploitation, allowing them to execute RCE attacks, steal or damage server-side data. Before switching or implementing a serialization protocol, users should thoroughly research the security guarantees of the target protocol and its implementation and set up appropriate security measures (e.g., black/whitelists) in advance. Dubbo cannot directly ensure the security of the target serialization mechanism. -Dubbo 2.7 官方版本提供的序列化协议有如下几种: +Dubbo 2.7 officially supports the following serialization protocols: * Hessian2 * Fastjson * Kryo @@ -26,35 +23,35 @@ Dubbo 2.7 官方版本提供的序列化协议有如下几种: * Avro * Gson -从 Dubbo 3.0 开始默认仅提供以下序列化协议支持: +From Dubbo 3.0, the default supported serialization protocols are: * Hessian2 * JDK * Protocol Buffers -从 Dubbo 3.2 开始默认提供以下序列化协议支持: +From Dubbo 3.2, the default supported serialization protocols are: * Hessian2 * Fastjson2 * JDK * Protocol Buffers -处于安全性考虑,从 Dubbo 3.3 开始将默认仅提供以下序列化协议支持: +For security reasons, from Dubbo 3.3, the default supported serialization protocols are: * Hessian2 * Fastjson2 * Protocol Buffers -针对以上序列化扩展,在发现或收到相关的漏洞报告之后,Dubbo 官方会跟进并升级依赖到最新的安全版本,但最终的漏洞修复方案取决于序列化的框架实现。 +For the above serialization extensions, Dubbo will follow up and update dependencies to the latest secure versions upon discovering or receiving reports of vulnerabilities. However, the final solution to vulnerabilities depends on the serialization framework implementation. -> 针对使用 [dubbo hessian2](https://github.com/apache/dubbo-hessian-lite/releases) 版本的用户,Dubbo 官方会保证hessian2序列化机制的安全性并尽可能的修复上报的安全漏洞 +> For users of [dubbo hessian2](https://github.com/apache/dubbo-hessian-lite/releases) version, Dubbo ensures the security of the Hessian2 serialization mechanism and strives to fix reported security vulnerabilities. -此外,从 Dubbo 3.2 版本开始,对于 Hessian2 和 Fastjson2 默认采用白名单机制,如果您发现部分数据处理移除,可以参考[文档](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/)进行配置。 +Additionally, from Dubbo 3.2, Hessian2 and Fastjson2 utilize a default whitelist mechanism. If you find certain data processing removed, refer to [documentation](/en/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/) for configuration. -# 全面加固 +# Comprehensive Reinforcement -为了尽可能提高应用序列化的安全性,Dubbo3.0在序列化协议安全方面进行了升级加固,推荐使用 Tripe 协议的非 Wrapper 模式。 -该协议默认安全,但需要开发人员编写IDL文件。 +To enhance the security of application serialization as much as possible, Dubbo 3.0 upgrades the serialization protocol security and recommends using the Triple protocol in non-Wrapper mode. This protocol is secure by default but requires developers to write IDL files. -Triple 协议 Wrapper 模式下,允许兼容其它序列化数据,提供了良好的兼容性。但其它协议可能存在反序列化安全缺陷,对于 Hessian2 协议,高安全属性用户应当按照 samples 代码指示,开启白名单模式,框架默认会开启黑名单模式,拦截恶意调用。 +In Triple protocol Wrapper mode, compatibility with other serialized data is allowed, offering good compatibility. However, other protocols may have deserialization security flaws. High-security property users should enable whitelist mode for the Hessian2 protocol following the sample code instructions, while the framework defaults to blacklist mode to intercept malicious calls. -若必须使用其它序列化协议,同时希望具备一定安全性。应当开启Token鉴权机制,防止未鉴权的不可信请求来源威胁 Provider 的安全性。开启 Token 鉴权机制时,应当同步开启注册中心的鉴权功能。 +If other serialization protocols must be used, and some security is desired, the Token authentication mechanism should be enabled to prevent unauthenticated, untrusted request sources from threatening the Provider's security. When enabling Token authentication, the authentication function of the registry should be enabled simultaneously. + +[Reinforcement Reference](/en/overview/mannual/java-sdk/advanced-features-and-usage/security/) -[加固参考](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/) diff --git a/content/en/overview/reference/Metrics/standard_metrics.md b/content/en/overview/reference/Metrics/standard_metrics.md index 4b93d3a4ab0e..fa020c1489af 100644 --- a/content/en/overview/reference/Metrics/standard_metrics.md +++ b/content/en/overview/reference/Metrics/standard_metrics.md @@ -1,194 +1,98 @@ --- aliases: - - /zh-cn/overview/reference/Metrics/standard_metrics/ -linkTitle: 标准监控指标 -title: Dubbo 框架标准监控指标 + - /en/overview/reference/Metrics/standard_metrics/ +linkTitle: Standard Monitoring Metrics +title: Dubbo Framework Standard Monitoring Metrics type: docs weight: 1 description: | - 描述了 Dubbo 中统计的一些标准监控指标。 + Describes some standard monitoring metrics collected in Dubbo. --- -### Dubbo 指标含义 +### Dubbo Metrics Definitions #### Provider Metrics -| Metrics Name | Description | 说明 | -|---------------------------------------------------------|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| -| dubbo_provider_qps_total | The number of requests received by the provider per second | 提供者每秒接收的请求数 | -| dubbo_provider_requests_total | The total number of received requests by the provider | 提供者总的接收请求数 | -| dubbo_provider_requests_total_aggregate | The total number of received requests by the provider under the sliding window | 滑动窗口下的提供者总的接收请求数 | -| dubbo_provider_requests_processing | The number of received requests being processed by the provider | 提供者正在处理的接收的请求数 | -| dubbo_provider_requests_succeed_total | The number of requests successfully received by the provider | 提供者请求成功接收的请求数 | -| dubbo_provider_requests_succeed_aggregate | The number of successful requests received by the provider under the sliding window | 滑动窗口下的提供者成功的接收请求数 | -| dubbo_provider_rt_milliseconds_min | The minimum response time among all requests processed by the provider | 提供者所有处理请求中最小的响应时间 | -| dubbo_provider_rt_min_milliseconds_aggregate | The minimum response time of the provider under the sliding window | 滑动窗口下的提供者最小响应时间 | -| dubbo_provider_rt_milliseconds_avg | The average response time of all requests processed by the provider | 提供者所有处理请求的平均响应时间 | -| dubbo_provider_rt_avg_milliseconds_aggregate | The average response time of the provider under the sliding window | 滑动窗口下的提供者平均响应时间 | -| dubbo_provider_rt_milliseconds_sum | The total time taken by the provider to process all requests | 提供者所有处理请求的时间总和 | -| dubbo_provider_rt_milliseconds_max | The maximum response time among all requests from the provider | 提供者所有请求中最大的响应时间 | -| dubbo_provider_rt_max_milliseconds_aggregate | The maximum response time of the provider under the sliding window | 滑动窗口下的提供者最大响应时间 | -| dubbo_provider_rt_milliseconds_last | The current response time in the provider's processing of requests | 提供者处理请求中当前的响应时间 | -| dubbo_provider_rt_milliseconds_p50 | The total response time spent by providers processing 50% of requests | 提供者处理请求中50%的请求耗费的总响应时间 | -| dubbo_provider_rt_milliseconds_p90 | The total response time spent by providers processing 90% of requests | 提供者处理请求中90%的请求耗费的总响应时间 | -| dubbo_provider_rt_milliseconds_p95 | The total response time spent by providers processing 95% of requests | 提供者处理请求中95%的请求耗费的总响应时间 | -| dubbo_provider_rt_milliseconds_p99 | The total response time spent by providers processing 99% of requests | 提供者处理请求中99%的请求耗费的总响应时间 | -| dubbo_provider_requests_processing_total | The number of received requests being processed by the provider | 提供者正在处理的接收的请求数 | -| dubbo_provider_rt_milliseconds_histogram_seconds_bucket | The histogram of response time of the provider under the sliding window | 滑动窗口下的提供者响应时间直方图 | -| dubbo_provider_rt_milliseconds_histogram_seconds_count | The count of histogram of response time of the provider under the sliding window | 滑动窗口下的提供者响应时间直方图总数 | -| dubbo_provider_rt_milliseconds_histogram_seconds_max | The max of histogram of response time of the provider under the sliding window | 滑动窗口下的提供者响应时间直方图最大值 | -| dubbo_provider_rt_milliseconds_histogram_seconds_sum | The sum of histogram of response time of the provider under the sliding window | 滑动窗口下的提供者响应时间直方图总和 | -| dubbo_provider_requests_business_failed_total | Total Failed Business Requests | 当RPC请求异常状态码为 RpcException.BIZ_EXCEPTION | -| dubbo_provider_requests_timeout_total | Total Timeout Failed Requests | 当RPC请求异常为超时异常状态码为 RpcException.TIMEOUT_EXCEPTION | -| dubbo_provider_requests_limit_total | Total Limit Failed Requests | RPC请求中一般为并发数超过了限制 max concurrent invoke 或者是超过了系统的上限出现了异常状态码为RpcException.LIMIT_EXCEEDED_EXCEPTION或者异常类型为LimitExceededException LimitExceededException | -| dubbo_provider_requests_unknown_failed_total | Total Unknown Failed Requests | 暂为归类的其他类型的异常具体分析根据日志来看 | -| dubbo_provider_requests_failed_total | Total Failed Requests | 总的异常次数 | -| dubbo_provider_requests_failed_total_aggregate | Total Failed Aggregate Requests | 聚合请求失败次数,当聚合请求中有一个请求失败时候会触发此异常 | -| dubbo_provider_requests_failed_network_total | Total network Failed Requests | 一般发生在网络连接失败或者网络通信时候发生的异常,对应Java异常为RemotingException | -| dubbo_provider_requests_failed_service_unavailable_total | Total Service Unavailable Failed Requests | 当不存在提供者或者调用了被禁止访问提的提供者时候会出现此异常 ,对应异常码FORBIDDEN_EXCEPTION | -| dubbo_provider_requests_failed_codec_total | Total codec failed | 序列化相关的异常,异常码SERIALIZATION_EXCEPTION | -| dubbo_provider_requests_failed_aggregate | Total Failed Aggregate Requests | 聚合请求失败次数,当聚合请求中有一个请求失败时候会触发此异常 | -| dubbo_provider_requests_timeout_total | Total Timeout Failed Requests | 当RPC请求异常为超时异常状态码为 RpcException.TIMEOUT_EXCEPTION | -| dubbo_provider_requests_limit_total | Total Limit Failed Requests | RPC请求中一般为并发数超过了限制 max concurrent invoke 或者是超过了系统的上限出现了异常状态码为RpcException_LIMIT_EXCEEDED_EXCEPTION或者异常类型为LimitExceededException LimitExceededException | -| dubbo_provider_requests_unknown_failed_total | Total Unknown Failed Requests | 暂为归类的其他类型的异常具体分析根据日志来看 | -| dubbo_provider_requests_failed_total | Total Failed Requests | 总的异常次数 | -| dubbo_provider_requests_failed_network_total | Total network Failed Requests | 一般发生在网络连接失败或者网络通信时候发生的异常,对应Java异常为RemotingException | -| dubbo_provider_requests_failed_service_unavailable_total | Total Service Unavailable Failed Requests | 当不存在提供者或者调用了被禁止访问提的提供者时候会出现此异常 ,对应异常码FORBIDDEN_EXCEPTION | -| dubbo_provider_requests_failed_codec_total | Total codec failed | 序列化相关的异常,异常码SERIALIZATION_EXCEPTION | +| Metrics Name | Description | Explanation | +|---------------------------------------------------------|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------| +| dubbo_provider_qps_total | The number of requests received by the provider per second | The number of requests received by the provider per second | +| dubbo_provider_requests_total | The total number of received requests by the provider | The total number of received requests by the provider | +| dubbo_provider_requests_total_aggregate | The total number of received requests by the provider under the sliding window | The total number of received requests by the provider under the sliding window | +| dubbo_provider_requests_processing | The number of received requests being processed by the provider | The number of received requests being processed by the provider | +| dubbo_provider_requests_succeed_total | The number of requests successfully received by the provider | The number of requests successfully received by the provider | +| dubbo_provider_requests_succeed_aggregate | The number of successful requests received by the provider under the sliding window | The number of successful requests received by the provider under the sliding window | +| dubbo_provider_rt_milliseconds_min | The minimum response time among all requests processed by the provider | The minimum response time among all requests processed by the provider | +| dubbo_provider_rt_min_milliseconds_aggregate | The minimum response time of the provider under the sliding window | The minimum response time of the provider under the sliding window | +| dubbo_provider_rt_milliseconds_avg | The average response time of all requests processed by the provider | The average response time of all requests processed by the provider | +| dubbo_provider_rt_avg_milliseconds_aggregate | The average response time of the provider under the sliding window | The average response time of the provider under the sliding window | +| dubbo_provider_rt_milliseconds_sum | The total time taken by the provider to process all requests | The total time taken by the provider to process all requests | +| dubbo_provider_rt_milliseconds_max | The maximum response time among all requests from the provider | The maximum response time among all requests from the provider | +| dubbo_provider_rt_max_milliseconds_aggregate | The maximum response time of the provider under the sliding window | The maximum response time of the provider under the sliding window | +| dubbo_provider_rt_milliseconds_last | The current response time in the provider's processing of requests | The current response time in the provider's processing of requests | +| dubbo_provider_rt_milliseconds_p50 | The total response time spent by providers processing 50% of requests | The total response time spent by providers processing 50% of requests | +| dubbo_provider_rt_milliseconds_p90 | The total response time spent by providers processing 90% of requests | The total response time spent by providers processing 90% of requests | +| dubbo_provider_rt_milliseconds_p95 | The total response time spent by providers processing 95% of requests | The total response time spent by providers processing 95% of requests | +| dubbo_provider_rt_milliseconds_p99 | The total response time spent by providers processing 99% of requests | The total response time spent by providers processing 99% of requests | +| dubbo_provider_requests_processing_total | The number of received requests being processed by the provider | The number of received requests being processed by the provider | +| dubbo_provider_rt_milliseconds_histogram_seconds_bucket | The histogram of response time of the provider under the sliding window | The histogram of response time of the provider under the sliding window | +| dubbo_provider_rt_milliseconds_histogram_seconds_count | The count of histogram of response time of the provider under the sliding window | The count of histogram of response time of the provider under the sliding window | +| dubbo_provider_rt_milliseconds_histogram_seconds_max | The max of histogram of response time of the provider under the sliding window | The max of histogram of response time of the provider under the sliding window | +| dubbo_provider_rt_milliseconds_histogram_seconds_sum | The sum of histogram of response time of the provider under the sliding window | The sum of histogram of response time of the provider under the sliding window | +| dubbo_provider_requests_business_failed_total | Total Failed Business Requests | When the RPC request status code is RpcException.BIZ_EXCEPTION | +| dubbo_provider_requests_timeout_total | Total Timeout Failed Requests | When the RPC request status code is RpcException.TIMEOUT_EXCEPTION | +| dubbo_provider_requests_limit_total | Total Limit Failed Requests | RPC request status is RpcException.LIMIT_EXCEEDED_EXCEPTION or exception type is LimitExceededException | +| dubbo_provider_requests_unknown_failed_total | Total Unknown Failed Requests | Other types of exceptions not yet categorized, analyzing based on logs | +| dubbo_provider_requests_failed_total | Total Failed Requests | Total number of exceptions | +| dubbo_provider_requests_failed_total_aggregate | Total Failed Aggregate Requests | Total number of failed aggregate requests, triggered when one of the requests in the aggregate request fails | +| dubbo_provider_requests_failed_network_total | Total network Failed Requests | Exceptions occurring during network connection failure or network communication, corresponding to Java exception RemotingException | +| dubbo_provider_requests_failed_service_unavailable_total | Total Service Unavailable Failed Requests | When there is no provider or the provider is forbidden to access, corresponding exception code FORBIDDEN_EXCEPTION | +| dubbo_provider_requests_failed_codec_total | Total codec failed | Serialization related exceptions, exception code SERIALIZATION_EXCEPTION | +| Generally occurs during network connection failure or network communication issues, corresponding to Java exception RemotingException | +| dubbo_provider_requests_failed_service_unavailable_total | Total Service Unavailable Failed Requests | When there is no provider or the provider is forbidden, corresponding exception code FORBIDDEN_EXCEPTION | +| dubbo_provider_requests_failed_codec_total | Total codec failed | Serialization related exceptions, exception code SERIALIZATION_EXCEPTION | +| dubbo_provider_requests_failed_aggregate | Total Failed Aggregate Requests | Total number of failed aggregate requests, triggered when one of the requests in the aggregate request fails | +| dubbo_provider_requests_timeout_total | Total Timeout Failed Requests | When the RPC request status code is RpcException.TIMEOUT_EXCEPTION | +| dubbo_provider_requests_limit_total | Total Limit Failed Requests | RPC request status is RpcException.LIMIT_EXCEEDED_EXCEPTION or exception type is LimitExceededException; generally, this occurs when the concurrency limit exceeds max concurrent invoke or the system limit is exceeded. | +| dubbo_provider_requests_unknown_failed_total | Total Unknown Failed Requests | Other types of exceptions not yet categorized, analyzing based on logs | +| dubbo_provider_requests_failed_total | Total Failed Requests | Total number of exceptions | +| dubbo_provider_requests_failed_network_total | Total network Failed Requests | Generally occurs during network connection failure or network communication issues, corresponding to Java exception RemotingException | +| dubbo_provider_requests_failed_service_unavailable_total | Total Service Unavailable Failed Requests | When there is no provider or the provider is forbidden, corresponding exception code FORBIDDEN_EXCEPTION | +| dubbo_provider_requests_failed_codec_total | Total codec failed | Serialization related exceptions, exception code SERIALIZATION_EXCEPTION | #### Consumer Metrics -| Metrics Name | Description | 说明 | -|---------------------------------------------------------|------------------------------------------------------------------------------|------------------------| -| dubbo_consumer_qps_total | The number of requests sent by consumers per second | 消费者每秒发送的请求数 | -| dubbo_consumer_requests_total | Total number of sent requests by consumers | 消费者总的发送请求数 | -| dubbo_consumer_requests_total_aggregate | The total number of requests sent by consumers under the sliding window | 滑动窗口下的消费者总的发送请求数 | -| dubbo_consumer_requests_processing | The number of sent requests that consumers are currently processing | 消费者正在处理的发送的请求数 | -| dubbo_consumer_requests_succeed_total | The number of successful requests sent by consumers | 消费者请求成功发送的请求数 | -| dubbo_consumer_requests_succeed_aggregate | The number of successful requests sent by consumers under the sliding window | 滑动窗口下的消费者成功的发送请求数 | -| dubbo_consumer_rt_milliseconds_min | Minimum response time among all consumer requests | 消费者所有请求中最小的响应时间 | -| dubbo_consumer_rt_min_milliseconds_aggregate | The minimum response time of the consumer under the sliding window | 滑动窗口下的消费者最小响应时间 | -| dubbo_consumer_rt_milliseconds_avg | Average response time of all requests from consumers | 消费者所有请求的平均响应时间 | -| dubbo_consumer_rt_avg_milliseconds_aggregate | The average response time of the consumer under the sliding window | 滑动窗口下的消费者平均响应时间 | -| dubbo_consumer_rt_milliseconds_sum | The total time of all consumer requests | 消费者所有请求的时间总和 | -| dubbo_consumer_rt_milliseconds_max | Maximum response time among all requests from consumers | 消费者所有请求中最大的响应时间 | -| dubbo_consumer_rt_max_milliseconds_aggregate | The maximum response time of the consumer under the sliding window | 滑动窗口下的消费者最大响应时间 | -| dubbo_consumer_rt_milliseconds_last | The current response time in consumer processing requests | 消费者处理请求中当前的响应时间 | -| dubbo_consumer_rt_milliseconds_p50 | The total response time spent by consumers processing 50% of requests | 消费者处理请求中50%的请求耗费的总响应时间 | -| dubbo_consumer_rt_milliseconds_p90 | The total response time spent by consumers processing 90% of requests | 消费者处理请求中90%的请求耗费的总响应时间 | -| dubbo_consumer_rt_milliseconds_p95 | The total response time spent by consumers processing 95% of requests | 消费者处理请求中95%的请求耗费的总响应时间 | -| dubbo_consumer_rt_milliseconds_p99 | The total response time spent by consumers processing 99% of requests | 消费者处理请求中99%的请求耗费的总响应时间 | -| dubbo_consumer_rt_milliseconds_histogram_seconds_bucket | Histogram of response time of all requests from consumers | 消费者所有请求的响应时间直方图 | -| dubbo_consumer_rt_milliseconds_histogram_seconds_count | count of Histogram of all requests from consumers | 消费者所有请求的响应时间直方图总数量 | -| dubbo_consumer_rt_milliseconds_histogram_seconds_sum | sum of Histogram of all requests from consumers | 消费者所有请求的响应时间直方图总和 | -| dubbo_consumer_rt_milliseconds_histogram_seconds_max | max of Histogram of all requests from consumers | 消费者所有请求的响应时间直方图最大值 | -| dubbo_consumer_requests_business_failed_total | Total Failed Business Requests | 当RPC请求异常状态码为RpcException.BIZ_EXCEPTION | -| dubbo_consumer_requests_timeout_total | Total Timeout Failed Requests | 当RPC请求异常为超时异常状态码为RpcException.TIMEOUT_EXCEPTION | -| dubbo_consumer_requests_timeout_failed_aggregate | Total Timeout Failed Requests | 滑动窗口内的聚合指标 当RPC请求异常为超时异常状态码为RpcException.TIMEOUT_EXCEPTION | -| dubbo_consumer_requests_limit_total | Total Limit Failed Requests | RPC请求状态码为RpcException.LIMIT_EXCEEDED_EXCEPTION或者异常类型为LimitExceededException 一般为并发数超过了限制 max concurrent invoke 或者是超过了系统的上限出现了异常LimitExceededException | -| dubbo_consumer_requests_unknown_failed_total | Total Unknown Failed Requests | 暂为归类的其他类型的异常具体分析根据日志来看 | -| dubbo_consumer_requests_failed_total | Total Failed Requests | 总的异常次数 | -| dubbo_consumer_requests_failed_total_aggregate | Total Failed Requests | 滑动窗口内的聚合指标 总的异常次数 | -| dubbo_consumer_requests_failed_network_total | Total network Failed Requests | 一般发生在网络连接失败或者网络通信时候发生的异常,对应Java异常为RemotingException | -| dubbo_consumer_requests_failed_network_total_aggregate | Total network Failed Requests | 滑动窗口内的聚合指标 一般发生在网络连接失败或者网络通信时候发生的异常,对应Java异常为RemotingException | -| dubbo_consumer_requests_failed_service_unavailable_total | Total Service Unavailable Failed Requests | 当不存在提供者或者调用了被禁止访问提的提供者时候会出现此异常 ,对应异常码FORBIDDEN_EXCEPTION | -| dubbo_consumer_requests_failed_codec_total | Total codec failed | 序列化相关的异常,异常码SERIALIZATION_EXCEPTION | - -#### ThreadPool Metrics - -| Metrics Name | Description | 说明 | -|--------------------------------|--------------------------|-------------| -| dubbo_thread_pool_max_size | Thread Pool Max Size | 线程池最大大小 | -| dubbo_thread_pool_largest_size | Thread Pool Largest Size | 线程池最大大小 | -| dubbo_thread_pool_thread_count | Thread Pool Thread Count | 线程池线程计数 | -| dubbo_thread_pool_queue_size | Thread Pool Queue Size | 线程池队列大小 | -| dubbo_thread_pool_active_size | Thread Pool Active Size | 线程池活动大小 | -| dubbo_thread_pool_core_size | Thread Pool Core Size | 线程池核心大小 | -| dubbo_thread_pool_reject_thread_count | Thread Pool Reject Count | 线程池拒绝执行任务数量 | - -#### Registration Center Metrics - -| Metrics Name | Description | 说明 | -|----------------------------------------------------|-----------------------------------------|------------------------| -| dubbo_register_service_rt_milliseconds_avg | Average Service Register Time | **接口级** 服务接口注册平均时间 | -| dubbo_register_service_rt_milliseconds_last | Last Service Register Time | **接口级** 服务接口注册最新响应时间 | -| dubbo_register_service_rt_milliseconds_max | Max Service Register Time | **接口级** 服务接口注册总的最大时间 | -| dubbo_register_service_rt_milliseconds_min | Min Service Register Time | **接口级** 服务接口注册总的最小时间 | -| dubbo_register_service_rt_milliseconds_sum | Sum Service Register Time | **接口级** 服务接口注册总的注册时间 | -| dubbo_registry_directory_num_all | Total Directory Num | **接口级** 服务接口目录总数 | -| dubbo_registry_directory_num_disable_total | Total Disable Directory Num | **接口级** 服务接口目录禁用总数 | -| dubbo_registry_directory_num_to_reconnect_total | Total Directory Num To Reconnect | **接口级** 服务接口目录重连总数 | -| dubbo_registry_directory_num_valid_total | Total Valid Directory Num | **接口级** 服务接口目录有效总数 | -| dubbo_registry_notify_num_last | Last Notify Num | **接口级** 服务接口通知最新响应时间 | -| dubbo_registry_notify_requests_total | Total Notify Requests | **接口级** 服务接口通知总次数 | -| dubbo_register_rt_milliseconds_max | Max Response Time | **应用级** 实例注册总的最大时间 | -| dubbo_register_rt_milliseconds_avg | Average Response Time | **应用级** 实例注册总的平均时间 | -| dubbo_register_rt_milliseconds_sum | Sum Response Time | **应用级** 实例注册总的注册时间 | -| dubbo_register_rt_milliseconds_min | Min Response Time | **应用级** 实例注册总的最小时间 | -| dubbo_registry_register_requests_succeed_total | Succeed Register Requests | **应用级** 实例注册成功的次数 | -| dubbo_registry_register_requests_total | Total Register Requests | **应用级** 实例注册总次数包含成功与失败 | -| dubbo_registry_register_requests_failed_total | Failed Register Requests | **应用级** 实例注册失败次数 | -| dubbo_register_rt_milliseconds_last | Last Response Time | **应用级** 实例注册最新响应时间 | -| dubbo_registry_register_service_total | Total Service-Level Register Requests | **接口级** 服务接口注册总数 | -| dubbo_registry_register_service_succeed_total | Succeed Service-Level Register Requests | **接口级** 服务接口注册成功总数 | -| dubbo_registry_register_service_failed_total | Failed Service-Level Register Requests | **接口级** 服务接口注册失败总数 | -| dubbo_registry_subscribe_num_failed_total | Failed Subscribe Num | **应用级** 实例订阅失败总数 | -| dubbo_registry_subscribe_num_succeed_total | Succeed Subscribe Num | **应用级** 实例订阅成功总数 | -| dubbo_registry_subscribe_num_total | Total Subscribe Num | **应用级** 实例订阅总数 | -| dubbo_registry_subscribe_service_num_total | Total Service-Level Subscribe Num | **接口级** 服务接口订阅总数 | -| dubbo_registry_subscribe_service_num_succeed_total | Succeed Service-Level Num | **接口级** 服务接口订阅成功总数 | -| dubbo_registry_subscribe_service_num_failed_total | Failed Service-Level Num | **接口级** 服务接口订阅失败总数 | -| dubbo_notify_rt_milliseconds_avg | Average Notify Time | **接口级** 服务接口通知总的平均时间 | -| dubbo_notify_rt_milliseconds_last | Last Notify Time | **接口级** 服务接口通知最新响应时间 | -| dubbo_notify_rt_milliseconds_max | Max Notify Time | **接口级** 服务接口通知总的最大时间 | -| dubbo_notify_rt_milliseconds_min | Min Notify Time | **接口级** 服务接口通知总的最小时间 | -| dubbo_notify_rt_milliseconds_sum | Sum Notify Time | **接口级** 服务接口通知总的通知时间 | - -#### Metadata Center Metrics - -部分元数据指标生效范围:当元数据为集中式配置时(report-metadata为true或者metadataType为remote) - -| Metrics Name | Description | 说明 | -|-----------------------------------------------------|---------------------------------------|-------------------------------------------------| -| dubbo_metadata_push_num_total | Total Num | **提供者** 推送元数据到元数据中心的成功次数,当提供者元数据发生了变更时触发 | -| dubbo_metadata_push_num_succeed_total | Succeed Push Num | **提供者** 推送元数据到元数据中心的成功次数,当提供者元数据发生了变更时触发 | -| dubbo_metadata_push_num_failed_total | Failed Push Num | **提供者** 推送元数据到元数据中心的失败次数,当提供者元数据发生了变更时并且出现异常触发 | -| dubbo_metadata_subscribe_num_total | Total Metadata Subscribe Num | **消费者** 获取元数据的总次数,当消费者启动时本地磁盘缓存无元数据获取元数据的次数 | -| dubbo_metadata_subscribe_num_succeed_total | Succeed Metadata Subscribe Num | **消费者** 获取元数据的总次数,当消费者启动时本地磁盘缓存无元数据并且成功获取元数据的次数 | -| dubbo_metadata_subscribe_num_failed_total | Failed Metadata Subscribe Num | **消费者** 获取元数据的总次数,当消费者启动时本地磁盘缓存无元数据并且获取元数据失败的次数 | -| dubbo_push_rt_milliseconds_sum | Sum Response Time | **提供者** 推送元数据到元数据中心的总时间 | -| dubbo_push_rt_milliseconds_last | Last Response Time | **提供者** 推送元数据到元数据中心的最新耗时 | -| dubbo_push_rt_milliseconds_min | Min Response Time | **提供者** 推送元数据到元数据中心的最小时间 | -| dubbo_push_rt_milliseconds_max | Max Response Time | **提供者** 推送元数据到元数据中心的最大时间 | -| dubbo_push_rt_milliseconds_avg | Average Response Time | **提供者** 推送元数据到元数据中心的平均时间 | -| dubbo_subscribe_rt_milliseconds_sum | Sum Response Time | **消费者** 获取元数据从元数据中心的总时间 | -| dubbo_subscribe_rt_milliseconds_last | Last Response Time | **消费者** 推送元数据到元数据中心的最新耗时 | -| dubbo_subscribe_rt_milliseconds_min | Min Response Time | **消费者** 推送元数据到元数据中心的最小时间 | -| dubbo_subscribe_rt_milliseconds_max | Max Response Time | **消费者** 推送元数据到元数据中心的最大时间 | -| dubbo_subscribe_rt_milliseconds_avg | Average Response Time | **消费者** 推送元数据到元数据中心的平均时间 | -| dubbo_metadata_store_provider_failed_total | Total Failed Provider Metadata Store | **提供者** 元数据中心存储提供者元数据失败次数 | -| dubbo_metadata_store_provider_succeed_total | Total Succeed Provider Metadata Store | **提供者** 元数据中心存储提供者元数据成功次数 | -| dubbo_metadata_store_provider_total | Total Provider Metadata Store | **提供者** 元数据中心存储提供者元数据总次数 | -| dubbo_store_provider_interface_rt_milliseconds_avg | Average Store Provider Interface Time | **接口级** 服务接口存储提供者平均时间 | -| dubbo_store_provider_interface_rt_milliseconds_last | Last Store Provider Interface Time | **接口级** 服务接口存储提供者最新响应时间 | -| dubbo_store_provider_interface_rt_milliseconds_max | Max Store Provider Interface Time | **接口级** 服务接口存储提供者最大时间 | -| dubbo_store_provider_interface_rt_milliseconds_min | Min Store Provider Interface Time | **接口级** 服务接口存储提供者最小时间 | -| dubbo_store_provider_interface_rt_milliseconds_sum | Sum Store Provider Interface Time | **接口级** 服务接口存储提供者总的存储时间 | -| dubbo_subscribe_service_rt_milliseconds_last | Last Subscribe Service Time | **接口级** 服务接口订阅元数据最新响应时间 | -| dubbo_subscribe_service_rt_milliseconds_max | Max Subscribe Service Time | **接口级** 服务接口订阅元数据最大时间 | -| dubbo_subscribe_service_rt_milliseconds_min | Min Subscribe Service Time | **接口级** 服务接口订阅元数据最小时间 | -| dubbo_subscribe_service_rt_milliseconds_sum | Sum Subscribe Service Time | **接口级** 服务接口订阅元数据总的存储时间 | -| dubbo_subscribe_service_rt_milliseconds_avg | Average Subscribe Service Time | **接口级** 服务接口订阅元数据平均时间 | - -#### Configcenter - -| Metrics Name | Description | 说明 | -|--------------------------|----------------------|------------| -| dubbo_configcenter_total | Config Changed Total | 配置中心推送配置次数 | - -#### ApplicationInfo - -| Metrics Name | Description | 说明 | -|------------------------------|------------------------|----------------| -| dubbo_application_info_total | Total Application Info | 应用信息包含应用名、版本号等 | - +| Metrics Name | Description | Explanation | +|---------------------------------------------------------|------------------------------------------------------------------------------|--------------------------| +| dubbo_consumer_qps_total | The number of requests sent by consumers per second | The number of requests sent by consumers per second | +| dubbo_consumer_requests_total | Total number of sent requests by consumers | Total number of sent requests by consumers | +| dubbo_consumer_requests_total_aggregate | The total number of requests sent by consumers under the sliding window | The total number of requests sent by consumers under the sliding window | +| dubbo_consumer_requests_processing | The number of sent requests that consumers are currently processing | The number of sent requests that consumers are currently processing | +| dubbo_consumer_requests_succeed_total | The number of successful requests sent by consumers | The number of successful requests sent by consumers | +| dubbo_consumer_requests_succeed_aggregate | The number of successful requests sent by consumers under the sliding window | The number of successful requests sent by consumers under the sliding window | +| dubbo_consumer_rt_milliseconds_min | Minimum response time among all consumer requests | Minimum response time among all consumer requests | +| dubbo_consumer_rt_min_milliseconds_aggregate | The minimum response time of the consumer under the sliding window | The minimum response time of the consumer under the sliding window | +| dubbo_consumer_rt_milliseconds_avg | Average response time of all requests from consumers | Average response time of all requests from consumers | +| dubbo_consumer_rt_avg_milliseconds_aggregate | The average response time of the consumer under the sliding window | The average response time of the consumer under the sliding window | +| dubbo_consumer_rt_milliseconds_sum | The total time of all consumer requests | The total time of all consumer requests | +| dubbo_consumer_rt_milliseconds_max | Maximum response time among all requests from consumers | Maximum response time among all requests from consumers | +| dubbo_consumer_rt_max_milliseconds_aggregate | The maximum response time of the consumer under the sliding window | The maximum response time of the consumer under the sliding window | +| dubbo_consumer_rt_milliseconds_last | The current response time in consumer processing requests | The current response time in consumer processing requests | +| dubbo_consumer_rt_milliseconds_p50 | The total response time spent by consumers processing 50% of requests | The total response time spent by consumers processing 50% of requests | +| dubbo_consumer_rt_milliseconds_p90 | The total response time spent by consumers processing 90% of requests | The total response time spent by consumers processing 90% of requests | +| dubbo_consumer_rt_milliseconds_p95 | The total response time spent by consumers processing 95% of requests | The total response time spent by consumers processing 95% of requests | +| dubbo_consumer_rt_milliseconds_p99 | The total response time spent by consumers processing 99% of requests | The total response time spent by consumers processing 99% of requests | +| dubbo_consumer_rt_milliseconds_histogram_seconds_bucket | Histogram of response time of all requests from consumers | Histogram of response time of all requests from consumers | +| dubbo_consumer_rt_milliseconds_histogram_seconds_count | count of Histogram of all requests from consumers | Count of histogram of all requests from consumers | +| dubbo_consumer_rt_milliseconds_histogram_seconds_sum | sum of Histogram of all requests from consumers | Sum of histogram of all requests from consumers | +| dubbo_consumer_rt_milliseconds_histogram_seconds_max | max of Histogram of all requests from consumers | Max of histogram of all requests from consumers | +| dubbo_consumer_requests_business_failed_total | Total Failed Business Requests | When the RPC request status code is RpcException.BIZ_EXCEPTION | +| dubbo_consumer_requests_timeout_total | Total Timeout Failed Requests | When the RPC request status code is RpcException.TIMEOUT_EXCEPTION | +| dubbo_consumer_requests_timeout_failed_aggregate | Total Timeout Failed Requests | Aggregate metrics within the sliding window; when the RPC request status code is RpcException.TIMEOUT_EXCEPTION | +| dubbo_consumer_requests_limit_total | Total Limit Failed Requests | RPC request status is RpcException.LIMIT_EXCEEDED_EXCEPTION or exception type is LimitExceededException; generally, this occurs when the concurrency limit exceeds max concurrent invoke or the system limit is exceeded. | +| dubbo_consumer_requests_unknown_failed_total | Total Unknown Failed Requests | Other types of exceptions not yet categorized, analyzing based on logs | +| dubbo_consumer_requests_failed_total | Total Failed Requests | Total number of exceptions | +| dubbo_consumer_requests_failed_total_aggregate | Total Failed Requests | Aggregate metrics within the sliding window; total number of exceptions | +| dubbo_consumer_requests_failed_network_total | Total network Failed Requests | Generally occurs during network connection failure or network communication issues, corresponding to Java exception RemotingException | +| dubbo_consumer_requests_failed_network_total_aggregate | Total network Failed Requests | Aggregate metrics within the sliding window; generally occurs during network connection failure or network communication issues, corresponding to Java exception RemotingException | +| dubbo_consumer_requests_failed_service_unavailable_total | Total Service Unavailable Failed Requests | When there is no provider or the provider is forbidden, corresponding exception code FORBIDDEN_EXCEPTION | +| dubbo_consumer_requests_failed_codec_total | Total codec failed | Serialization related exceptions, exception code SERIALIZATION_EXCEPTION diff --git a/content/en/overview/reference/_index.md b/content/en/overview/reference/_index.md index d2c7cc2af825..8203868d7c66 100755 --- a/content/en/overview/reference/_index.md +++ b/content/en/overview/reference/_index.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/reference/ + - /en/overview/reference/ description: "" linkTitle: 其他 no_list: true diff --git a/content/en/overview/reference/erlang-sdk/_index.md b/content/en/overview/reference/erlang-sdk/_index.md index bbe745d36e1d..4c0c196e3ae7 100755 --- a/content/en/overview/reference/erlang-sdk/_index.md +++ b/content/en/overview/reference/erlang-sdk/_index.md @@ -1,12 +1,12 @@ --- aliases: - - /zh/docs3-v2/erlang-sdk/ - - /zh-cn/docs3-v2/erlang-sdk/ - - /zh-cn/overview/reference/erlang-sdk/ - - /zh-cn/overview/mannual/erlang-sdk/ -description: Erlang 支持 + - /en/docs3-v2/erlang-sdk/ + - /en/overview/reference/erlang-sdk/ + - /en/overview/manual/erlang-sdk/ +description: Erlang Support linkTitle: Erlang SDK -title: Erlang SDK 手册 +title: Erlang SDK Manual type: docs weight: 8 ---- +### + diff --git a/content/en/overview/reference/erlang-sdk/quick-start.md b/content/en/overview/reference/erlang-sdk/quick-start.md index 4ad051a37f0e..7c1bb7787c0f 100644 --- a/content/en/overview/reference/erlang-sdk/quick-start.md +++ b/content/en/overview/reference/erlang-sdk/quick-start.md @@ -1,62 +1,60 @@ --- aliases: - - /zh/docs3-v2/erlang-sdk/quick-start/ - - /zh-cn/docs3-v2/erlang-sdk/quick-start/ - - /zh-cn/overview/mannual/erlang-sdk/quick-start/ - - /zh-cn/overview/reference/erlang-sdk/quick-start/ -description: Erlang 快速开始 -linkTitle: 快速开始 -title: 快速开始 + - /en/docs3-v2/erlang-sdk/quick-start/ + - /en/overview/manual/erlang-sdk/quick-start/ +description: Erlang Quick Start +linkTitle: Quick Start +title: Quick Start type: docs weight: 1 --- -建议先使用 java 定义接口 jar,并使用 [erlanalysis](https://github.com/apache/dubbo-erlang/tree/master/tools/erlanalysis) 工具解析java接口至Erlang lib +It is recommended to first define the interface jar using Java, and use the [erlanalysis](https://github.com/apache/dubbo-erlang/tree/master/tools/erlanalysis) tool to parse Java interfaces into Erlang lib. -## 导入依赖库 +## Import Dependency Libraries -### 使用 Rebar 编译工具。 -Add dubblerl to rebar.config with your project +### Using the Rebar Build Tool. +Add dubblerl to your project's `rebar.config` ```erlang {deps, [ {dubboerl, {git, "https://github.com/apache/dubbo-erlang.git", {branch, "master"}}} ]}. ``` -### 使用 erlang.mk 编译工具 -`待补充` +### Using the `erlang.mk` Build Tool +`To be added` -## 导入接口库 -Suppose the interface lib you exported is called dubbo_service. -* If you didn't upload your lib to your git repository, It is recommended that you copy the `dubbo_service` lib +## Import Interface Libraries +Suppose the interface lib you exported is called `dubbo_service`. +* If you didn't upload your lib to your git repository, it is recommended that you copy the `dubbo_service` lib into the project's `apps` directory. -* If it is upload to your git repository, you can import like this: +* If it is uploaded to your git repository, you can import it like this: ```erlang {deps, [ {dubboerl, {git, "https://github.com/apache/dubbo-erlang.git", {branch, "master"}}}, - {dubbo_service,{git,"${INTERFACE_LIB_URL}",{branch,"master"}}} %% replace ${INTERFACE_LIB_URL} with your lib git repos url + {dubbo_service,{git,"${INTERFACE_LIB_URL}",{branch,"master"}}} %% replace ${INTERFACE_LIB_URL} with your lib git repo URL ]}. ``` -## 消费者配置 +## Consumer Configuration Please reference [Reference Config](../reference/) -## Init dubbolib in your project -It is need you +## Init `dubbolib` in Your Project +It is need you to ```erlang dubboerl:init(). ``` -## 如何调用? +## How to Call? -### 同步调用 +### Synchronous Call ```erlang Request = #userInfoRequest{requestId = 123, username = "testname"}, -{ok,RequestRef,Response,RpcContent} = userOperator:queryUserInfo(Request,#{sync=> true}). +{ok,RequestRef,Response,RpcContent} = userOperator:queryUserInfo(Request,#{sync => true}). ``` -If it occur error, is reponse `{error,Reason}`. +If an error occurs, the response is `{error,Reason}`. -### 异步调用 +### Asynchronous Call Default is Async call. ```erlang @@ -64,8 +62,9 @@ Request = #userInfoRequest{requestId = 123, username = "testname"}, {ok,RequestRef} = userOperator:queryUserInfo(Request). %% you can receive the message after. -handle_cast({msg_back,RequestRef,Response,RpcContent},State). +handle_cast({msg_back,RequestRef,Response,RpcContent}, State). ``` -## 示例 -参考项目 [dubboerl_demo](https://github.com/apache/dubbo-erlang/tree/master/samples) +## Example +Refer to the project [dubboerl_demo](https://github.com/apache/dubbo-erlang/tree/master/samples) + diff --git a/content/en/overview/reference/erlang-sdk/reference.md b/content/en/overview/reference/erlang-sdk/reference.md index 230601811fcb..c5a1443d4318 100644 --- a/content/en/overview/reference/erlang-sdk/reference.md +++ b/content/en/overview/reference/erlang-sdk/reference.md @@ -1,12 +1,12 @@ --- aliases: - - /zh/docs3-v2/erlang-sdk/reference/ - - /zh-cn/docs3-v2/erlang-sdk/reference/ - - /zh-cn/overview/mannual/erlang-sdk/reference/ - - /zh-cn/overview/reference/erlang-sdk/reference/ -description: 在 erlang 中配置消费者 -linkTitle: 消费者配置 -title: 消费者配置 + - /en/docs3-v2/erlang-sdk/reference/ + - /en-us/docs3-v2/erlang-sdk/reference/ + - /en-us/overview/manual/erlang-sdk/reference/ + - /en-us/overview/reference/erlang-sdk/reference/ +description: Configuring consumers in Erlang +linkTitle: Consumer Configuration +title: Consumer Configuration type: docs weight: 2 --- @@ -16,9 +16,9 @@ weight: 2 -## 基础配置 +## Basic Configuration -消费者配置项需要添加到 `sys.config` 文件 `dubboerl` 应用配置项里。 +Consumer configurations need to be added to the `sys.config` file under the `dubboerl` application configuration. ```erlang {dubboerl,[ @@ -31,4 +31,5 @@ weight: 2 ]} ``` -Option 配置项待添加中。 +Option configuration items are to be added. + diff --git a/content/en/overview/reference/erlang-sdk/serialization.md b/content/en/overview/reference/erlang-sdk/serialization.md index 20fe7f4b4e41..84a9e6dfe78a 100644 --- a/content/en/overview/reference/erlang-sdk/serialization.md +++ b/content/en/overview/reference/erlang-sdk/serialization.md @@ -1,28 +1,23 @@ --- aliases: - - /zh/docs3-v2/erlang-sdk/serialization/ - - /zh-cn/docs3-v2/erlang-sdk/serialization/ - - /zh-cn/overview/mannual/erlang-sdk/serialization/ - - /zh-cn/overview/reference/erlang-sdk/serialization/ -description: 在 erlang 中配置序列化方式 -linkTitle: 序列化配置项 -title: 序列化配置项 + - /en/docs3-v2/erlang-sdk/serialization/ + - /en/docs3-v2/erlang-sdk/serialization/ + - /en/overview/mannual/erlang-sdk/serialization/ + - /en/overview/reference/erlang-sdk/serialization/ +description: Configure serialization methods in Erlang +linkTitle: Serialization Configuration Options +title: Serialization Configuration Options type: docs weight: 4 --- +Currently, this library only implements the `dubbo://` communication protocol. +Two serialization methods are implemented: `hessian` and `json`. +## Configuration Example - - -当前该库只实现了 `dubbo://` 通讯协议。 - -序列化方式实现了 `hessian` 和 `json` 两种方式。 - -## 配置样例 - -序列化配置需要添加到 `sys.config` 文件 `dubboerl` 应用配置项里。 +The serialization configuration needs to be added to the `dubboerl` application configuration in the `sys.config` file. ```erlang {dubboerl,[ @@ -34,3 +29,4 @@ weight: 4 | ConfigName | Type | DefaultValue | Remarks | | --- | --- | --- | --- | | protocol | atom() | hessian | hessian,json | + diff --git a/content/en/overview/reference/erlang-sdk/service.md b/content/en/overview/reference/erlang-sdk/service.md index d0529ed2da3d..e651adb4c109 100644 --- a/content/en/overview/reference/erlang-sdk/service.md +++ b/content/en/overview/reference/erlang-sdk/service.md @@ -1,24 +1,19 @@ --- aliases: - - /zh/docs3-v2/erlang-sdk/service/ - - /zh-cn/docs3-v2/erlang-sdk/service/ - - /zh-cn/overview/mannual/erlang-sdk/service/ - - /zh-cn/overview/reference/erlang-sdk/service/ -description: 在 erlang 中配置服务提供者 -linkTitle: 提供者配置 -title: 提供者配置 + - /en/docs3-v2/erlang-sdk/service/ + - /en-us/docs3-v2/erlang-sdk/service/ + - /en-us/overview/mannual/erlang-sdk/service/ + - /en-us/overview/reference/erlang-sdk/service/ +description: Configuring service providers in Erlang +linkTitle: Provider Configuration +title: Provider Configuration type: docs weight: 3 --- +## Basic Configuration - - - - -## 基本配置 - -提供者配置项需要添加到 `sys.config` 文件 `dubboerl` 应用配置项里。 +Provider configuration items need to be added to the `sys.config` file under the `dubboerl` application configuration item. ```erlang {dubboerl,[ @@ -33,8 +28,9 @@ weight: 3 | ConfigName | Type | DefaultValue | Remarks | | --- | --- | --- | --- | -| module_implements | atom() | - | The service implements module name| -| interface_module | atom() | - | Interface module name is transfer form java jar | -| interface_fullname | binary() | - | Interface full name is the java class name | +| module_implements | atom() | - | The service implementation module name | +| interface_module | atom() | - | Interface module name converted from java jar | +| interface_fullname | binary() | - | Fully qualified name of the interface's Java class | Option is to be added. + diff --git a/content/en/overview/reference/integrations/_index.md b/content/en/overview/reference/integrations/_index.md index 9bb0b0c0c610..9ae61b587eac 100644 --- a/content/en/overview/reference/integrations/_index.md +++ b/content/en/overview/reference/integrations/_index.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/reference/integrations/ + - /en/overview/reference/integrations/ description: "" linkTitle: 集成适配 title: 集成适配 diff --git a/content/en/overview/reference/integrations/grafana.md b/content/en/overview/reference/integrations/grafana.md index 1a4f406c038c..6d15d7ce05a3 100644 --- a/content/en/overview/reference/integrations/grafana.md +++ b/content/en/overview/reference/integrations/grafana.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/reference/integrations/grafana/ + - /en/overview/reference/integrations/grafana/ description: 配置 Grafana 与 Dubbo 一起工作 linkTitle: Grafana title: Grafana diff --git a/content/en/overview/reference/integrations/higress.md b/content/en/overview/reference/integrations/higress.md index 6704c9eac49e..7890eb43e77e 100644 --- a/content/en/overview/reference/integrations/higress.md +++ b/content/en/overview/reference/integrations/higress.md @@ -1,6 +1,6 @@ --- aliases: -- /zh/overview/reference/integrations/skywalking/ +- /en/overview/reference/integrations/skywalking/ description: "如何安装与配置 Higress,涵盖本地、docker、kubernetes 等环境。" linkTitle: Higress title: Higress diff --git a/content/en/overview/reference/integrations/nacos.md b/content/en/overview/reference/integrations/nacos.md index 2c8012f3c9e9..a2a9c6b0cb3b 100644 --- a/content/en/overview/reference/integrations/nacos.md +++ b/content/en/overview/reference/integrations/nacos.md @@ -1,6 +1,6 @@ --- aliases: -- /zh/overview/reference/integrations/skywalking/ +- /en/overview/reference/integrations/skywalking/ description: "如何安装与配置 Nacos,涵盖本地、docker、kubernetes等环境。" linkTitle: Nacos title: Nacos diff --git a/content/en/overview/reference/integrations/prometheus.md b/content/en/overview/reference/integrations/prometheus.md index 89839a4de16d..5abd96dfddf6 100644 --- a/content/en/overview/reference/integrations/prometheus.md +++ b/content/en/overview/reference/integrations/prometheus.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/reference/integrations/prometheus/ + - /en/overview/reference/integrations/prometheus/ description: 配置 Prometheus 与 Dubbo 一起工作 linkTitle: Prometheus title: Prometheus diff --git a/content/en/overview/reference/integrations/skywalking.md b/content/en/overview/reference/integrations/skywalking.md index 55bb598b9853..0d16206f154f 100644 --- a/content/en/overview/reference/integrations/skywalking.md +++ b/content/en/overview/reference/integrations/skywalking.md @@ -1,6 +1,6 @@ --- aliases: -- /zh/overview/reference/integrations/skywalking/ +- /en/overview/reference/integrations/skywalking/ description: 配置 Skywalking 与 Dubbo 一起工作 linkTitle: Skywalking title: Skywalking diff --git a/content/en/overview/reference/integrations/zipkin.md b/content/en/overview/reference/integrations/zipkin.md index 27ee8fc17373..4db9f1032820 100644 --- a/content/en/overview/reference/integrations/zipkin.md +++ b/content/en/overview/reference/integrations/zipkin.md @@ -1,6 +1,6 @@ --- aliases: -- /zh/overview/reference/integrations/zipkin/ +- /en/overview/reference/integrations/zipkin/ description: 配置 Zipkin 与 Dubbo 一起工作 linkTitle: Zipkin title: Zipkin diff --git a/content/en/overview/reference/integrations/zookeeper.md b/content/en/overview/reference/integrations/zookeeper.md index dce003589532..cc2c71891875 100644 --- a/content/en/overview/reference/integrations/zookeeper.md +++ b/content/en/overview/reference/integrations/zookeeper.md @@ -1,6 +1,6 @@ --- aliases: -- /zh/overview/reference/integrations/skywalking/ +- /en/overview/reference/integrations/skywalking/ description: "如何安装与配置 Zookeeper,涵盖本地、docker、kubernetes等环境。" linkTitle: Zookeeper title: Zookeeper @@ -89,4 +89,4 @@ $ docker run --name some-zookeeper --restart always -e JVMFLAGS="-Dzookeeper.ad ```shell kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/deploy/kubernetes/zookeeper.yaml -``` \ No newline at end of file +``` diff --git a/content/en/overview/reference/pixiu/_index.md b/content/en/overview/reference/pixiu/_index.md index b7c369e7720e..f5fc015b6334 100755 --- a/content/en/overview/reference/pixiu/_index.md +++ b/content/en/overview/reference/pixiu/_index.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/ - - /zh-cn/overview/reference/pixiu/ + - /en/docs3-v2/dubbo-go-pixiu/ + - /en/docs3-v2/dubbo-go-pixiu/ + - /en/overview/mannual/dubbo-go-pixiu/ + - /en/overview/reference/pixiu/ description: Dubbo Go Pixiu 简介 linkTitle: Pixiu gateway title: Dubbo Go Pixiu 简介 diff --git a/content/en/overview/reference/pixiu/dev/_index.md b/content/en/overview/reference/pixiu/dev/_index.md index df862b67ff1b..422cbb61fecb 100755 --- a/content/en/overview/reference/pixiu/dev/_index.md +++ b/content/en/overview/reference/pixiu/dev/_index.md @@ -1,7 +1,7 @@ --- aliases: - - /zh-cn/overview/mannual/dubbo-go-pixiu/dev/ - - /zh-cn/overview/reference/pixiu/dev/ + - /en/overview/mannual/dubbo-go-pixiu/dev/ + - /en/overview/reference/pixiu/dev/ description: 开发者指南 linkTitle: 开发者指南 title: 开发者指南 diff --git a/content/en/overview/reference/pixiu/dev/dubbo-pilot.md b/content/en/overview/reference/pixiu/dev/dubbo-pilot.md index 8ad56b648b83..0b0a58fda877 100644 --- a/content/en/overview/reference/pixiu/dev/dubbo-pilot.md +++ b/content/en/overview/reference/pixiu/dev/dubbo-pilot.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/dev/dubbo-pilot/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/dev/dubbo-pilot/ - - /zh-cn/overview/reference/pixiu/dev/dubbo-pilot/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/dev/dubbo-pilot/ + - /en/docs3-v2/dubbo-go-pixiu/dev/dubbo-pilot/ + - /en/docs3-v2/dubbo-go-pixiu/dev/dubbo-pilot/ + - /en/overview/reference/pixiu/dev/dubbo-pilot/ + - /en/overview/mannual/dubbo-go-pixiu/dev/dubbo-pilot/ description: dubbo-pilot Control Plane 部署 linkTitle: dubbo-pilot Control Plane 部署 title: dubbo-pilot Control Plane 部署 diff --git a/content/en/overview/reference/pixiu/dev/filter-extension.md b/content/en/overview/reference/pixiu/dev/filter-extension.md index a7c4066c632f..e6cb752f2fb6 100644 --- a/content/en/overview/reference/pixiu/dev/filter-extension.md +++ b/content/en/overview/reference/pixiu/dev/filter-extension.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/dev/filter-extension/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/dev/filter-extension/ - - /zh-cn/overview/reference/pixiu/dev/filter-extension/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/dev/filter-extension/ + - /en/docs3-v2/dubbo-go-pixiu/dev/filter-extension/ + - /en/docs3-v2/dubbo-go-pixiu/dev/filter-extension/ + - /en/overview/reference/pixiu/dev/filter-extension/ + - /en/overview/mannual/dubbo-go-pixiu/dev/filter-extension/ description: Pixiu Filter体系介绍 linkTitle: Pixiu Filter体系介绍 title: Pixiu Filter体系介绍 diff --git a/content/en/overview/reference/pixiu/dev/trie.md b/content/en/overview/reference/pixiu/dev/trie.md index 3c9293505144..449ecd33e42e 100644 --- a/content/en/overview/reference/pixiu/dev/trie.md +++ b/content/en/overview/reference/pixiu/dev/trie.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/dev/trie/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/dev/trie/ - - /zh-cn/overview/reference/pixiu/dev/trie/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/dev/trie/ + - /en/docs3-v2/dubbo-go-pixiu/dev/trie/ + - /en/docs3-v2/dubbo-go-pixiu/dev/trie/ + - /en/overview/reference/pixiu/dev/trie/ + - /en/overview/mannual/dubbo-go-pixiu/dev/trie/ description: Trie 前缀树介绍 linkTitle: Trie 前缀树介绍 title: Trie 前缀树介绍 diff --git a/content/en/overview/reference/pixiu/overview/_index.md b/content/en/overview/reference/pixiu/overview/_index.md index 6815f4c36b9e..7f331e30b769 100755 --- a/content/en/overview/reference/pixiu/overview/_index.md +++ b/content/en/overview/reference/pixiu/overview/_index.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/overview/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/overview/ - - /zh-cn/overview/reference/pixiu/overview/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/overview/ + - /en/docs3-v2/dubbo-go-pixiu/overview/ + - /en/docs3-v2/dubbo-go-pixiu/overview/ + - /en/overview/reference/pixiu/overview/ + - /en/overview/mannual/dubbo-go-pixiu/overview/ description: 入门概述 linkTitle: 入门概述 title: 入门概述 diff --git a/content/en/overview/reference/pixiu/overview/faq.md b/content/en/overview/reference/pixiu/overview/faq.md index 22da713f34a0..6730744f66f0 100755 --- a/content/en/overview/reference/pixiu/overview/faq.md +++ b/content/en/overview/reference/pixiu/overview/faq.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/overview/faq/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/overview/faq/ - - /zh-cn/overview/reference/pixiu/overview/faq/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/overview/faq/ + - /en/docs3-v2/dubbo-go-pixiu/overview/faq/ + - /en/docs3-v2/dubbo-go-pixiu/overview/faq/ + - /en/overview/reference/pixiu/overview/faq/ + - /en/overview/mannual/dubbo-go-pixiu/overview/faq/ description: Pixiu 常见问题 linkTitle: Pixiu 常见问题 title: Pixiu 常见问题 diff --git a/content/en/overview/reference/pixiu/overview/terminology.md b/content/en/overview/reference/pixiu/overview/terminology.md index ca4fdbbf3bfd..d781e34b88eb 100755 --- a/content/en/overview/reference/pixiu/overview/terminology.md +++ b/content/en/overview/reference/pixiu/overview/terminology.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/overview/terminology/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/overview/terminology/ - - /zh-cn/overview/reference/pixiu/overview/terminology/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/overview/terminology/ + - /en/docs3-v2/dubbo-go-pixiu/overview/terminology/ + - /en/docs3-v2/dubbo-go-pixiu/overview/terminology/ + - /en/overview/reference/pixiu/overview/terminology/ + - /en/overview/mannual/dubbo-go-pixiu/overview/terminology/ description: Pixiu 术语 linkTitle: Pixiu 术语 title: Pixiu 术语 diff --git a/content/en/overview/reference/pixiu/overview/what-is-pixiu.md b/content/en/overview/reference/pixiu/overview/what-is-pixiu.md index 2cb6d8e13fbd..3a60dc823cc4 100755 --- a/content/en/overview/reference/pixiu/overview/what-is-pixiu.md +++ b/content/en/overview/reference/pixiu/overview/what-is-pixiu.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/overview/what-is-pixiu/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/overview/what-is-pixiu/ - - /zh-cn/overview/reference/pixiu/overview/what-is-pixiu/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/overview/what-is-pixiu/ + - /en/docs3-v2/dubbo-go-pixiu/overview/what-is-pixiu/ + - /en/docs3-v2/dubbo-go-pixiu/overview/what-is-pixiu/ + - /en/overview/reference/pixiu/overview/what-is-pixiu/ + - /en/overview/mannual/dubbo-go-pixiu/overview/what-is-pixiu/ description: Pixiu 是一款开源的 Dubbo 生态的 API 网关和 接入 dubbo 集群的语言解决方案。作为 API 网关形态。 linkTitle: Pixiu 是什么 title: Pixiu 是什么 diff --git a/content/en/overview/reference/pixiu/user/_index.md b/content/en/overview/reference/pixiu/user/_index.md index 1b21e015232c..01359302bbe7 100755 --- a/content/en/overview/reference/pixiu/user/_index.md +++ b/content/en/overview/reference/pixiu/user/_index.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/ - - /zh-cn/overview/reference/pixiu/user/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/ + - /en/docs3-v2/dubbo-go-pixiu/user/ + - /en/docs3-v2/dubbo-go-pixiu/user/ + - /en/overview/reference/pixiu/user/ + - /en/overview/mannual/dubbo-go-pixiu/user/ description: 用户文档 linkTitle: 用户文档 title: 用户文档 diff --git a/content/en/overview/reference/pixiu/user/adapter/_index.md b/content/en/overview/reference/pixiu/user/adapter/_index.md index c66262d179c9..ba72b9457d3e 100755 --- a/content/en/overview/reference/pixiu/user/adapter/_index.md +++ b/content/en/overview/reference/pixiu/user/adapter/_index.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/adapter/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/adapter/ - - /zh-cn/overview/reference/pixiu/user/adapter/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/adapter/ + - /en/docs3-v2/dubbo-go-pixiu/user/adapter/ + - /en/docs3-v2/dubbo-go-pixiu/user/adapter/ + - /en/overview/reference/pixiu/user/adapter/ + - /en/overview/mannual/dubbo-go-pixiu/user/adapter/ description: Adapter 介绍 linkTitle: Adapter 介绍 title: Adapter 介绍 diff --git a/content/en/overview/reference/pixiu/user/adapter/dubbo.md b/content/en/overview/reference/pixiu/user/adapter/dubbo.md index 56d634d99ea1..6dd714f1fe90 100644 --- a/content/en/overview/reference/pixiu/user/adapter/dubbo.md +++ b/content/en/overview/reference/pixiu/user/adapter/dubbo.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/adapter/dubbo/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/adapter/dubbo/ - - /zh-cn/overview/reference/pixiu/user/adapter/dubbo/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/adapter/dubbo/ + - /en/docs3-v2/dubbo-go-pixiu/user/adapter/dubbo/ + - /en/docs3-v2/dubbo-go-pixiu/user/adapter/dubbo/ + - /en/overview/reference/pixiu/user/adapter/dubbo/ + - /en/overview/mannual/dubbo-go-pixiu/user/adapter/dubbo/ description: Dubbo 集群中心 Adapter linkTitle: Dubbo 集群中心 Adapter title: Dubbo 集群中心 Adapter diff --git a/content/en/overview/reference/pixiu/user/adapter/springcloud.md b/content/en/overview/reference/pixiu/user/adapter/springcloud.md index 01339a53be88..e423820399e8 100644 --- a/content/en/overview/reference/pixiu/user/adapter/springcloud.md +++ b/content/en/overview/reference/pixiu/user/adapter/springcloud.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/adapter/springcloud/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/adapter/springcloud/ - - /zh-cn/overview/reference/pixiu/user/adapter/springcloud/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/adapter/springcloud/ + - /en/docs3-v2/dubbo-go-pixiu/user/adapter/springcloud/ + - /en/docs3-v2/dubbo-go-pixiu/user/adapter/springcloud/ + - /en/overview/reference/pixiu/user/adapter/springcloud/ + - /en/overview/mannual/dubbo-go-pixiu/user/adapter/springcloud/ description: Spring Cloud 集群中心 Adapter linkTitle: Spring Cloud 集群中心 Adapter title: Spring Cloud 集群中心 Adapter diff --git a/content/en/overview/reference/pixiu/user/appendix/_index.md b/content/en/overview/reference/pixiu/user/appendix/_index.md index 879e2baf0d11..e61568a62108 100755 --- a/content/en/overview/reference/pixiu/user/appendix/_index.md +++ b/content/en/overview/reference/pixiu/user/appendix/_index.md @@ -1,12 +1,12 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/appendix/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/appendix/ - - /zh-cn/overview/reference/pixiu/user/appendix/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/appendix/ -description: 附录 -linkTitle: 附录 -title: 附录 + - /en/docs3-v2/dubbo-go-pixiu/user/appendix/ + - /en/docs3-v2/dubbo-go-pixiu/user/appendix/ + - /en/overview/reference/pixiu/user/appendix/ + - /en/overview/mannual/dubbo-go-pixiu/user/appendix/ +description: Appendix +linkTitle: Appendix +title: Appendix type: docs weight: 90 ---- +### diff --git a/content/en/overview/reference/pixiu/user/appendix/http-to-dubbo-default-stragety.md b/content/en/overview/reference/pixiu/user/appendix/http-to-dubbo-default-stragety.md index e5c287f9f4df..200b2f9f8400 100644 --- a/content/en/overview/reference/pixiu/user/appendix/http-to-dubbo-default-stragety.md +++ b/content/en/overview/reference/pixiu/user/appendix/http-to-dubbo-default-stragety.md @@ -1,12 +1,12 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/appendix/http-to-dubbo-default-stragety/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/appendix/http-to-dubbo-default-stragety/ - - /zh-cn/overview/reference/pixiu/user/appendix/http-to-dubbo-default-stragety/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/appendix/http-to-dubbo-default-stragety/ -description: HTTP to Dubbo 默认转换协议 -linkTitle: HTTP to Dubbo 默认转换协议 -title: HTTP to Dubbo 默认转换协议 + - /en/docs3-v2/dubbo-go-pixiu/user/appendix/http-to-dubbo-default-stragety/ + - /en/docs3-v2/dubbo-go-pixiu/user/appendix/http-to-dubbo-default-stragety/ + - /en/overview/reference/pixiu/user/appendix/http-to-dubbo-default-stragety/ + - /en/overview/mannual/dubbo-go-pixiu/user/appendix/http-to-dubbo-default-stragety/ +description: HTTP to Dubbo Default Conversion Protocol +linkTitle: HTTP to Dubbo Default Conversion Protocol +title: HTTP to Dubbo Default Conversion Protocol type: docs weight: 10 --- @@ -16,18 +16,18 @@ weight: 10 -# 背景 +# Background -​ 通过 Http 提供一个统一的服务提供者视图,用户不用在乎后端Dubbo服务的版本差异,协议差异,通过简单地在Http请求中传递rpc调用的参数,完成一次Rpc调用,通过实现http调用后端dubbo服务,进一步简化后端服务设计的复杂性。 +​ By providing a unified service provider view through Http, users need not worry about backend Dubbo service version differences or protocol differences. They just need to pass RPC call parameters in an HTTP request to complete an RPC call, simplifying backend service design complexity by implementing HTTP calls to backend Dubbo services. -# 目的 +# Purpose -​ 统一Http调用后端dubbo服务的形式,方便网关产品实现 Http 调用转 dubbo 调用的实现,Dubbo能和网关更好的融合。 +​ To unify the format of HTTP calls to backend Dubbo services, facilitating gateway products to achieve HTTP-to-Dubbo call conversion and enhancing the integration of Dubbo with the gateway. # Conception -## Dubbo RPC 调用的基本形式 +## Basic Form of Dubbo RPC Calls @@ -35,7 +35,7 @@ weight: 10 -希望通过提供Http调用Dubbo的方式简化 Consumer 的Rpc调用流程 +It aims to simplify the RPC call process for consumers by providing an HTTP to Dubbo calling method. @@ -43,42 +43,42 @@ weight: 10 -网关会在整个服务调用的过程中承担更多的原本客户端的功能,比如负载均衡,服务治理,安全等能力,外部用户调用服务的时候将更多的关注与调用本身。 +In the service call process, the gateway will assume many of the client's original functions such as load balancing, service governance, and security, allowing external users to focus more on the call itself. -## Http request 和 Http response 的格式 +## Format of Http Request and Http Response -request的URL和Header中包含RPC调用的元信息,包含服务名,方法名,服务分组,服务版本,request 的 body 中包含请求的参数,参数是 **json list** 的格式, 如果没有参数则为 ***null*** +The URL and Header of the request contain RPC call meta-information, including service name, method name, service group, and service version. The request body contains parameters in **json list** format. If there are no parameters, it is ***null*** -http response 中包含请求的处理状态,返回结果或者调用的错误类型以及错误具体信息,返回的body中只包含一个 ***json object***,这个object中包含 ***code***,***result***,***error*** +The HTTP response includes the processing status, result, or error type and specific information. The returned body contains only one ***json object***, with ***code***, ***result***, and ***error*** fields. -通过 code 表示返回的具体状态,result 和 error 在返回中只会返回其中一个,分别是调用的返回结果,调用返回的错误信息。 +The code indicates the specific status, and result and error (only one will be returned) indicate the call's return result or error information. -### Http request +### Http Request -#### Http 请求的方法 +#### Http Request Method -只能为 **POST** 方法 +It must be **POST**. -#### Http 请求的 URL +#### Http Request URL -格式:`[http://host/ {service} / {method](http://host/service/method)}` or `[https://host/ {service} / {method](https://host/service/method)}` +Format: `[http://host/{service}/{method}` or `[https://host/{service}/{method}` -- service 是调用的服务名,对应于Dubbo message body中的 service Name -- method 是调用的方法名,对应于Dubbo message body中的 method Name +- service is the service name corresponding to the service name in the Dubbo message body. +- method is the method name corresponding to the method name in the Dubbo message body. -服务名和方法名都应该和后端服务的声明一致 +Service name and method name should be consistent with backend service declarations. -如果URL中无法获取到service和method,应该直接返回 +If the URL lacks service or method, it should directly return: | http code | code | detail | | --------- | ---- | ------------------------------ | @@ -86,242 +86,41 @@ http response 中包含请求的处理状态,返回结果或者调用的错误 -#### Http 请求的Header +#### Http Request Header -Header中必须包含以下条目: +Headers must contain the following items: - x-dubbo-service-protocol -表明这个Http 请求是一个Http转dubbo的请求,目前支持Dubbo 协议和 triple 协议,可配置的选项为: +Indicates this HTTP request is an HTTP to Dubbo request. Supported protocols are Dubbo and triple. Configurable options are: - - x-dubbo-service-protocol: triple - x-dubbo-service-protocol: dubbo -​ 前者表示这是转化为triple协议,后者表示转化为dubbo协议 + The former indicates conversion to the triple protocol, the latter to the Dubbo protocol. -可选参数: +Optional parameters: -- x-dubbo-service-version 如果提供了应该填充到Dubbo message 的Serviceversion字段中. -- x-dubbo-service-group 如果提供了应该在attachment 添加 group 字段并把对应的值进行填充。 +- x-dubbo-service-version If provided, it should fill the Serviceversion field in the Dubbo message. +- x-dubbo-service-group If provided, it should add the group field in the attachment. -#### Http 请求的Body +#### Http Request Body -body中包含请求的参数,body中只包含一个 ***Json object*** 对象 +The body contains request parameters, including only one ***Json object***. -这个对象目前包含两个字段: +This object currently includes two fields: - param -param 的值类型为 list,标识调用方法的参数,顺序和方法签名中的参数顺序一致 +The param value is a list indicating the method's parameters, in the same order as the method signature. -这里使用object组装请求参数是为了协议能够向后兼容,body中的对象可能会增加新的字段。 +Using the object to assemble request parameters allows the protocol to be backward compatible, and new fields may be added to the object in the future. - - -##### 基本类型在 Json Java Go 中的映射关系 - -| Json Type | Java Type | Golang Type | -| --------- | ----------------- | ----------- | -| Integer | java.lang.Long | int64 | -| Double | java.lang.Double | float64 | -| String | java.lang.String | string | -| Null | null | nil | -| Bool | java.lang.Boolean | bool | -| List | java.lang.List | silice | -| Object | java.lang.Map | map | - -通过对基本类型映射关系的定义简化网关配置,对于只使用基本配置的转化,网关应该可以在不使用额外配置的情况下完成转化的 - - - -##### Body 处理异常时的处理策略 - -1. 调用方提供的请求参数 Json 解析错误,返回状态码 400 -2. 调用的时候,无法确定参数的具体类型,例如,用户使用的自定义类型,但是没有在网关配置具体的类型名,应该返回状态码 400 - -| http code | code | detail | -| --------- | ---- | ---------------------------- | -| 400 | 3 | argument parse error | -| 400 | 3 | argument type info not found | - -在以上条件都符合时,一个Http 调用可以被转化成为 Dubbo 协议的调用,只要网关能够成功进行请求的转化,则网关回复调用方的时候,Http 状态码都应该是 200 OK,至于调用方调用后端服务出现错误的信息,应该放在 body 中的 code 以及 error 字段中。 - - - -### http response - -在请求经过后端返回之后,需要将一下信息传递给调用方: - -| name | description | -| -------- | -------------------------------------------------------- | -| status | 返回的状态,在dubbo response 的header的status 中 | -| 返回值 | 调用成功返回的结果,如果没有返回值,则result 的值为 null | -| 返回异常 | 调用失败,产生异常,返回异常的具体message | - -返回值和返回异常只能出现一项 - -code 和 grpc 中的 status code 一致 详细的 code 及其含义见 https://grpc.github.io/grpc/core/md_doc_statuscodes.html - - - -#### 返回异常的处理: - -dubbo 中的异常以hessian2 的 class 类型返回,返沪的error中只需要对应的message 字段即可 - - - - - -## Dubbo 协议的具体转化 - -### Dubbo 协议的具体介绍 可以见文章 - -https://dubbo.apache.org/en/blog/2018/10/05/introduction-to-the-dubbo-protocol/ - - - -### Dubbo 协议的 message 格式 - -![img](/imgs/dev/dubbo_protocol_header.png) - - - -#### Dubbo Header的封装要求 - -| bits | Name | description | -| -------- | -------------- | ----------------------------------------------------- | -| 0 - 15 | Magic Number | 必须为 0xdabb | -| 16 | message 的类型 | 必须为 1 (request) | -| 17 | 2-way | 必须为 1 (需要服务端返回值) | -| 18 | Event | 必须为 0 不支持事件类型 | -| 19 - 23 | 序列化类型 | 可以扩展实现Hessian,Json等序列化类型,类型编号如下表 | -| 24 - 31 | Status | 表示 response 的状态,见Status 处理要求 | -| 32 - 95 | Request Id | 客户端的请求ID,可以根据需要自行定义 | -| 96 - 127 | Data length | 请求体的长度,请求体的大小 | - - - -序列化类型编号: - -| Serialization Type | Code | -| ------------------ | ---- | -| Hessian2 | 2 | -| Java | 3 | -| Compact Java | 4 | -| Fast Json | 6 | -| Native Java | 7 | - - - -请求Header中的字段应该以大端的形式封装,发送到服务端 - - - -#### Dubbo Body - - - -请求的body应该包含以下内容: - -| name | description | -| ---------------------- | ------------------------------------------------------------ | -| Dubbo Version | 根据网关的配置,或者Http请求获取 | -| Service Name | 服务名 | -| Method Name | 调用方法名,采用泛化调用的方式,此项目固定为“$invoke” | -| Method parameter types | 参数类型,泛化调用有固定值 "Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/Object;" | -| Method arguments | 使用配置的序列化方式将对应的参数序列化,按照用户传入的参数的顺序放入参数 | - -以上的各个项目在使用了指定的序列化形式之后,按照上表指定的顺序进行序列化。 - -attachment 目前不转化 - - - -***注意***: - - - -使用文本类型的序列化(Json) 在每一个序列化对象后边要加上行分割符( ***"\n"*** or ***"\r\n"*** ) - -Java 中在使用FastJson 编解码的时候使用了BufferedReader,每次取buffer中的对象的时候,会先调用BufferReader的readLine方法,此方法分割行依靠 ‘/n’ , ’/r/n‘ - -以下给出了Dubbo 协议中返回header中的status对应于GRPC status的对应列表 - - - -##### Status 的处理 - -Dubbo resposne status 中,OK延续使用grpc的 OK code,其余的 status Number编号紧接着 grpc 的16个 code进行编号 - -对应的error详情是 response 中异常的 message。 - -| Dubbo State | Number | -| ---------------------------------------------- | ------ | -| ResponseStatus::Ok | 0 | -| ResponseStatus::ClientTimeout | 130 | -| ResponseStatus::ServerTimeout | 131 | -| ResponseStatus::ServiceNotFound | 12 | -| ResponseStatus::ServerThreadpoolExhaustedError | 13 | -| ResponseStatus::ClientError | \ | -| ResponseStatus::ServerError | 13 | -| ResponseStatus::ServiceError | 13 | -| ResponseStatus::BadResponse | 13 | -| ResponseStatus::BadRequest | 3 | - -## Triple 协议的具体转化 - -Triple 是基于GRPC的,定义在Http2 协议之上 - -### Triple中RPC调用的元信息 - - - -#### Triple 通过 URL 传递调用的服务名和方法名 - -格式: `[http://host/ {service} / {method](http://host/service/method)}` - -我们的规范兼容 Triple 通过http2传递参数的形式,尽量做到dubbo 和 triple 的统一。 - - - -#### Header Frame - -header 中应该包含以下条目 - -- Content-Type:***application/grpc-proto*** - -标识这是一个 triple 协议的rpc调用 - -- x-dubbo-service-group - -指明调用的服务的分组 - -- x-dubbo-service-version - -指明调用的服务的版本 - - - -#### Data frame - -Triple协议将请求参数放在Body中,在triple中,如果服务中的方法定义能够使用pb序列化,则只有一层序列化,如果需要用到其他的序列化,则需要使用TripleRequestWrapper - -对参数进行包装。 - - - -我们推广使用 ***Triple + pb*** 的序列化形式,服务的提供方需要给出服务的 proto 定义,对于triple协议网关对于***triple + pb*** 的转化是比较容易实现的,如果用户没有提供proto定义,需要返回信息: - -| http code | code | detail | -| --------- | ---- | ---------------------------- | -| 400 | 3 | argument type info not found | - -### diff --git a/content/en/overview/reference/pixiu/user/configurations.md b/content/en/overview/reference/pixiu/user/configurations.md index 3511e79939ca..d50e75935ca7 100755 --- a/content/en/overview/reference/pixiu/user/configurations.md +++ b/content/en/overview/reference/pixiu/user/configurations.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/configurations/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/configurations/ - - /zh-cn/overview/reference/pixiu/user/configurations/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/configurations/ + - /en/docs3-v2/dubbo-go-pixiu/user/configurations/ + - /en/docs3-v2/dubbo-go-pixiu/user/configurations/ + - /en/overview/reference/pixiu/user/configurations/ + - /en/overview/mannual/dubbo-go-pixiu/user/configurations/ description: 启动和配置 linkTitle: 启动和配置 title: 启动和配置 diff --git a/content/en/overview/reference/pixiu/user/deployment.md b/content/en/overview/reference/pixiu/user/deployment.md index 63bd461fa135..c5a84da9e4b2 100644 --- a/content/en/overview/reference/pixiu/user/deployment.md +++ b/content/en/overview/reference/pixiu/user/deployment.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/deployment/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/deployment/ - - /zh-cn/overview/reference/pixiu/user/deployment/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/deployment/ + - /en/docs3-v2/dubbo-go-pixiu/user/deployment/ + - /en/docs3-v2/dubbo-go-pixiu/user/deployment/ + - /en/overview/reference/pixiu/user/deployment/ + - /en/overview/mannual/dubbo-go-pixiu/user/deployment/ description: 部署操作 linkTitle: 部署操作 title: 部署操作 diff --git a/content/en/overview/reference/pixiu/user/httpfilter/_index.md b/content/en/overview/reference/pixiu/user/httpfilter/_index.md index 78dbdb9e5dc5..82b520b227a6 100755 --- a/content/en/overview/reference/pixiu/user/httpfilter/_index.md +++ b/content/en/overview/reference/pixiu/user/httpfilter/_index.md @@ -1,12 +1,12 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/httpfilter/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/httpfilter/ - - /zh-cn/overview/reference/pixiu/user/httpfilter/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/httpfilter/ -description: Http Filter 介绍 -linkTitle: Http Filter 介绍 -title: Http Filter 介绍 + - /en/docs3-v2/dubbo-go-pixiu/user/httpfilter/ + - /en/overview/reference/pixiu/user/httpfilter/ + - /en/overview/manual/dubbo-go-pixiu/user/httpfilter/ +description: Introduction to Http Filter +linkTitle: Introduction to Http Filter +title: Introduction to Http Filter type: docs weight: 60 ---- +### + diff --git a/content/en/overview/reference/pixiu/user/httpfilter/dubbo.md b/content/en/overview/reference/pixiu/user/httpfilter/dubbo.md index 31b8a66cbc0d..1acef13b2b69 100644 --- a/content/en/overview/reference/pixiu/user/httpfilter/dubbo.md +++ b/content/en/overview/reference/pixiu/user/httpfilter/dubbo.md @@ -1,17 +1,17 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/httpfilter/dubbo/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/httpfilter/dubbo/ -description: Dubbo HttpFilter 介绍 -linkTitle: Dubbo HttpFilter 介绍 -title: Dubbo HttpFilter 介绍 + - /en/docs3-v2/dubbo-go-pixiu/user/httpfilter/dubbo/ + - /en/docs3-v2/dubbo-go-pixiu/user/httpfilter/dubbo/ +description: Introduction to Dubbo HttpFilter +linkTitle: Introduction to Dubbo HttpFilter +title: Introduction to Dubbo HttpFilter type: docs weight: 10 --- -# 使用 HTTP 调用 Dubbo +# Using HTTP to Call Dubbo -## 定义Pixiu配置文件 +## Define Pixiu Configuration File ```yaml static_resources: @@ -59,9 +59,9 @@ static_resources: reject_policy: "immediacy" ``` -## 准备Dubbo服务 +## Prepare Dubbo Service -### 启动zookeeper,需要提前准备好docker和compose,如果本地有的话可以忽略 +### Start zookeeper, ensure docker and compose are prepared in advance. If available locally, this can be ignored. [docker-compose.yml](https://github.com/apache/dubbo-go-pixiu-samples/tree/main/dubbohttpproxy/server/dubbo/app) @@ -69,7 +69,7 @@ static_resources: docker-compose -f {CURRENT_PATH}/dubbo-go-pixiu-samples/dubbohttpproxy/docker/docker-compose.yml && docker-compose up -d ``` -### 启动 Dubbo Server +### Start Dubbo Server [Run](https://github.com/apache/dubbo-go-pixiu-samples/tree/main/dubbohttpproxy/server/dubbo/app) @@ -78,17 +78,17 @@ export DUBBO_GO_CONFIG_PATH={CURRENT_PATH}/dubbo-go-pixiu-samples/dubbohttpproxy go run . ``` -## 启动 Pixiu +## Start Pixiu ```shell ./dubbo-go-pixiu gateway start --config {CURRENT_PATH}pixiu/conf.yaml ``` -## 使用 curl 来做查询和更新 +## Use curl for querying and updating -使用以下命令运行命令 curl: +Run the following curl command: -> 查询 +> Query ```shell curl http://localhost:8888/UserService/com.dubbogo.pixiu.UserService/GetUserByName -X POST \ @@ -100,7 +100,7 @@ curl http://localhost:8888/UserService/com.dubbogo.pixiu.UserService/GetUserByNa -d '{"types":"string","values":"tc"}' ``` -> 更新 +> Update ```shell curl http://localhost:8888/UserService/com.dubbogo.pixiu.UserService/UpdateUserByName -X POST \ @@ -110,4 +110,4 @@ curl http://localhost:8888/UserService/com.dubbogo.pixiu.UserService/UpdateUserB -H 'x-dubbo-service-version: 1.0.0' \ -H 'x-dubbo-service-group: test' \ -d '{"types":"string,object","values":["tc",{"id":"0001","code":1,"name":"tc","age":15}]}' -``` \ No newline at end of file +``` diff --git a/content/en/overview/reference/pixiu/user/httpfilter/hystrix.md b/content/en/overview/reference/pixiu/user/httpfilter/hystrix.md index d848ed81f9c4..1227ddb7a534 100644 --- a/content/en/overview/reference/pixiu/user/httpfilter/hystrix.md +++ b/content/en/overview/reference/pixiu/user/httpfilter/hystrix.md @@ -1,19 +1,15 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/httpfilter/hystrix/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/httpfilter/hystrix/ - - /zh-cn/overview/reference/pixiu/user/httpfilter/hystrix/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/httpfilter/hystrix/ -description: 断路器介绍 -linkTitle: 断路器介绍 -title: 断路器介绍 + - /en/docs3-v2/dubbo-go-pixiu/user/httpfilter/hystrix/ + - /en-us/docs3-v2/dubbo-go-pixiu/user/httpfilter/hystrix/ + - /en-us/overview/reference/pixiu/user/httpfilter/hystrix/ + - /en-us/overview/manual/dubbo-go-pixiu/user/httpfilter/hystrix/ +description: Circuit Breaker Introduction +linkTitle: Circuit Breaker Introduction +title: Circuit Breaker Introduction type: docs weight: 30 --- +Welcome to contribute to supplement this documentation. - - - - -欢迎认领补充此文档。 diff --git a/content/en/overview/reference/pixiu/user/httpfilter/ratelimit.md b/content/en/overview/reference/pixiu/user/httpfilter/ratelimit.md index 892c72457141..47f2365d75ca 100644 --- a/content/en/overview/reference/pixiu/user/httpfilter/ratelimit.md +++ b/content/en/overview/reference/pixiu/user/httpfilter/ratelimit.md @@ -1,12 +1,11 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/httpfilter/ratelimit/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/httpfilter/ratelimit/ - - /zh-cn/overview/reference/pixiu/user/httpfilter/ratelimit/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/httpfilter/ratelimit/ -description: RateLimiter 介绍 -linkTitle: RateLimiter 介绍 -title: RateLimiter 介绍 + - /en/docs3-v2/dubbo-go-pixiu/user/httpfilter/ratelimit/ + - /en/overview/reference/pixiu/user/httpfilter/ratelimit/ + - /en/overview/manual/dubbo-go-pixiu/user/httpfilter/ratelimit/ +description: Introduction to RateLimiter +linkTitle: Introduction to RateLimiter +title: Introduction to RateLimiter type: docs weight: 20 --- @@ -16,4 +15,5 @@ weight: 20 -欢迎认领补充此文档。 +Welcome to contribute to this document. + diff --git a/content/en/overview/reference/pixiu/user/listener/_index.md b/content/en/overview/reference/pixiu/user/listener/_index.md index 43ebd115e266..ea8c255c9d1c 100755 --- a/content/en/overview/reference/pixiu/user/listener/_index.md +++ b/content/en/overview/reference/pixiu/user/listener/_index.md @@ -1,12 +1,11 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/listener/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/listener/ - - /zh-cn/overview/reference/pixiu/user/listener/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/listener/ -description: Listener 介绍 -linkTitle: Listener 介绍 -title: Listener 介绍 + - /en/docs3-v2/dubbo-go-pixiu/user/listener/ + - /en/overview/reference/pixiu/user/listener/ + - /en/overview/manual/dubbo-go-pixiu/user/listener/ +description: Introduction to Listener +linkTitle: Introduction to Listener +title: Introduction to Listener type: docs weight: 40 ---- +### diff --git a/content/en/overview/reference/pixiu/user/listener/http.md b/content/en/overview/reference/pixiu/user/listener/http.md index 8b4b6c1f9dec..ce6b8a685c39 100644 --- a/content/en/overview/reference/pixiu/user/listener/http.md +++ b/content/en/overview/reference/pixiu/user/listener/http.md @@ -1,41 +1,36 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/listener/http/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/listener/http/ - - /zh-cn/overview/reference/pixiu/user/listener/http/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/listener/http/ -description: Http Listener 介绍 -linkTitle: Http Listener 介绍 -title: Http Listener 介绍 + - /en/docs3-v2/dubbo-go-pixiu/user/listener/http/ + - /en/docs3-v2/dubbo-go-pixiu/user/listener/http/ + - /en/overview/reference/pixiu/user/listener/http/ + - /en/overview/mannual/dubbo-go-pixiu/user/listener/http/ +description: Introduction to Http Listener +linkTitle: Introduction to Http Listener +title: Introduction to Http Listener type: docs weight: 10 --- - - - - - -Http Listener 是专门负载接收 HTTP 请求的 Listener,它可以设置 HTTP 监听的地址和端口。它可以通过如下配置进行引入。 +Http Listener is a listener specifically designed to receive HTTP requests. It can set the address and port for HTTP listening. It can be introduced through the following configuration. ``` static_resources: listeners: - name: "net/http" - protocol_type: "HTTP" # 表明是引入 HTTP Listener + protocol_type: "HTTP" # Indicates the HTTP Listener is being introduced address: socket_address: - address: "0.0.0.0" # 地址 - port: 8883 # 端口 + address: "0.0.0.0" # Address + port: 8883 # Port ``` -Http Listener 的具体实现可以参考 `pkg/listener/http`。 +The specific implementation of the Http Listener can be referred to in `pkg/listener/http`. -有关 HTTP Listener 的案例,可以参考: -- HTTP to Dubbo 请求的转换,[案例](/zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/http_to_dubbo/) -- HTTP 请求代理,[案例](/zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/http_proxy/) +For cases related to HTTP Listener, you can refer to: +- Conversion of HTTP to Dubbo requests, [Case](/en/overview/mannual/dubbo-go-pixiu/user/samples/http_to_dubbo/) +- HTTP request proxy, [Case](/en/overview/mannual/dubbo-go-pixiu/user/samples/http_proxy/) -目前也支持 HTTPS 协议。可以将 `protocol_type` 修改为 `HTTPS`。并且添加 `domains` 和 `certs_dir` 来指定域名和 cert 文件目录。 +Currently, the HTTPS protocol is also supported. You can change `protocol_type` to `HTTPS` and add `domains` and `certs_dir` to specify the domain and certificate file directory. ``` listeners: @@ -50,4 +45,5 @@ Http Listener 的具体实现可以参考 `pkg/listener/http`。 certs_dir: $PROJECT_DIR/cert ``` -具体案例可以查看 [案例](/zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/https/) +For specific cases, you can check [Case](/en/overview/mannual/dubbo-go-pixiu/user/samples/https/) + diff --git a/content/en/overview/reference/pixiu/user/listener/http2.md b/content/en/overview/reference/pixiu/user/listener/http2.md index 24ed858fbbde..77721aa27d7f 100644 --- a/content/en/overview/reference/pixiu/user/listener/http2.md +++ b/content/en/overview/reference/pixiu/user/listener/http2.md @@ -1,19 +1,15 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/listener/http2/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/listener/http2/ - - /zh-cn/overview/reference/pixiu/user/listener/http2/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/listener/http2/ -description: Http2 Listener 介绍 -linkTitle: Http2 Listener 介绍 -title: Http2 Listener 介绍 + - /en/docs3-v2/dubbo-go-pixiu/user/listener/http2/ + - /en-cn/docs3-v2/dubbo-go-pixiu/user/listener/http2/ + - /en-cn/overview/reference/pixiu/user/listener/http2/ + - /en-cn/overview/mannual/dubbo-go-pixiu/user/listener/http2/ +description: Introduction to Http2 Listener +linkTitle: Introduction to Http2 Listener +title: Introduction to Http2 Listener type: docs weight: 20 --- +Welcome to contribute to this document. - - - - -欢迎认领补充此文档。 diff --git a/content/en/overview/reference/pixiu/user/listener/tcp.md b/content/en/overview/reference/pixiu/user/listener/tcp.md index fafe5f2d607b..39052a59e187 100644 --- a/content/en/overview/reference/pixiu/user/listener/tcp.md +++ b/content/en/overview/reference/pixiu/user/listener/tcp.md @@ -1,12 +1,12 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/listener/tcp/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/listener/tcp/ - - /zh-cn/overview/reference/pixiu/user/listener/tcp/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/listener/tcp/ -description: TCP Listener 介绍 -linkTitle: TCP Listener 介绍 -title: TCP Listener 介绍 + - /docs3-v2/dubbo-go-pixiu/user/listener/tcp/ + - /en/docs3-v2/dubbo-go-pixiu/user/listener/tcp/ + - /en/overview/reference/pixiu/user/listener/tcp/ + - /en/overview/manual/dubbo-go-pixiu/user/listener/tcp/ +description: Introduction to TCP Listener +linkTitle: Introduction to TCP Listener +title: Introduction to TCP Listener type: docs weight: 30 --- @@ -16,4 +16,5 @@ weight: 30 -欢迎认领补充此文档。 +Welcome to contribute to this document. + diff --git a/content/en/overview/reference/pixiu/user/listener/triple.md b/content/en/overview/reference/pixiu/user/listener/triple.md index 5d50b9d5dacb..ff33e4424c37 100644 --- a/content/en/overview/reference/pixiu/user/listener/triple.md +++ b/content/en/overview/reference/pixiu/user/listener/triple.md @@ -1,12 +1,12 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/listener/triple/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/listener/triple/ - - /zh-cn/overview/reference/pixiu/user/listener/triple/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/listener/triple/ -description: Triple Listener 介绍 -linkTitle: Triple Listener 介绍 -title: Triple Listener 介绍 + - /docs3-v2/dubbo-go-pixiu/user/listener/triple/ + - /en/docs3-v2/dubbo-go-pixiu/user/listener/triple/ + - /en/overview/reference/pixiu/user/listener/triple/ + - /en/overview/manual/dubbo-go-pixiu/user/listener/triple/ +description: Introduction to Triple Listener +linkTitle: Introduction to Triple Listener +title: Introduction to Triple Listener type: docs weight: 40 --- @@ -16,4 +16,5 @@ weight: 40 -欢迎认领补充此文档。 +Welcome to claim and enrich this document. + diff --git a/content/en/overview/reference/pixiu/user/networkfilter/_index.md b/content/en/overview/reference/pixiu/user/networkfilter/_index.md index 76d329902d2b..05d911605244 100755 --- a/content/en/overview/reference/pixiu/user/networkfilter/_index.md +++ b/content/en/overview/reference/pixiu/user/networkfilter/_index.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/networkfilter/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/networkfilter/ - - /zh-cn/overview/reference/pixiu/user/networkfilter/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/networkfilter/ + - /en/docs3-v2/dubbo-go-pixiu/user/networkfilter/ + - /en/docs3-v2/dubbo-go-pixiu/user/networkfilter/ + - /en/overview/reference/pixiu/user/networkfilter/ + - /en/overview/mannual/dubbo-go-pixiu/user/networkfilter/ description: Network Filter 介绍 linkTitle: Network Filter 介绍 title: Network Filter 介绍 diff --git a/content/en/overview/reference/pixiu/user/networkfilter/dubbo.md b/content/en/overview/reference/pixiu/user/networkfilter/dubbo.md index 74f000bdf9c4..657b7202693e 100644 --- a/content/en/overview/reference/pixiu/user/networkfilter/dubbo.md +++ b/content/en/overview/reference/pixiu/user/networkfilter/dubbo.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/networkfilter/dubbo/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/networkfilter/dubbo/ - - /zh-cn/overview/reference/pixiu/user/networkfilter/dubbo/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/networkfilter/dubbo/ + - /en/docs3-v2/dubbo-go-pixiu/user/networkfilter/dubbo/ + - /en/docs3-v2/dubbo-go-pixiu/user/networkfilter/dubbo/ + - /en/overview/reference/pixiu/user/networkfilter/dubbo/ + - /en/overview/mannual/dubbo-go-pixiu/user/networkfilter/dubbo/ description: Dubbo NetWorkFilter 介绍 linkTitle: Dubbo NetWorkFilter 介绍 title: Dubbo NetWorkFilter 介绍 diff --git a/content/en/overview/reference/pixiu/user/networkfilter/grpc.md b/content/en/overview/reference/pixiu/user/networkfilter/grpc.md index c9fa07536837..9c0c26943408 100644 --- a/content/en/overview/reference/pixiu/user/networkfilter/grpc.md +++ b/content/en/overview/reference/pixiu/user/networkfilter/grpc.md @@ -1,7 +1,7 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/networkfilter/grpc/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/networkfilter/grpc/ + - /en/docs3-v2/dubbo-go-pixiu/user/networkfilter/grpc/ + - /en/docs3-v2/dubbo-go-pixiu/user/networkfilter/grpc/ description: Grpc NetWorkFilter 介绍 linkTitle: Grpc NetWorkFilter 介绍 title: Grpc NetWorkFilter 介绍 diff --git a/content/en/overview/reference/pixiu/user/networkfilter/http.md b/content/en/overview/reference/pixiu/user/networkfilter/http.md index 5a03965f9a71..6451a5ddc27a 100644 --- a/content/en/overview/reference/pixiu/user/networkfilter/http.md +++ b/content/en/overview/reference/pixiu/user/networkfilter/http.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/networkfilter/http/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/networkfilter/http/ - - /zh-cn/overview/reference/pixiu/user/networkfilter/http/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/networkfilter/http/ + - /en/docs3-v2/dubbo-go-pixiu/user/networkfilter/http/ + - /en/docs3-v2/dubbo-go-pixiu/user/networkfilter/http/ + - /en/overview/reference/pixiu/user/networkfilter/http/ + - /en/overview/mannual/dubbo-go-pixiu/user/networkfilter/http/ description: Http NetWorkFilter 介绍 linkTitle: Http NetWorkFilter 介绍 title: Http NetWorkFilter 介绍 diff --git a/content/en/overview/reference/pixiu/user/quality/_index.md b/content/en/overview/reference/pixiu/user/quality/_index.md index b296bad52f99..498f40c3b8ef 100755 --- a/content/en/overview/reference/pixiu/user/quality/_index.md +++ b/content/en/overview/reference/pixiu/user/quality/_index.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/quality/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/quality/ - - /zh-cn/overview/reference/pixiu/user/quality/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/quality/ + - /en/docs3-v2/dubbo-go-pixiu/user/quality/ + - /en/docs3-v2/dubbo-go-pixiu/user/quality/ + - /en/overview/reference/pixiu/user/quality/ + - /en/overview/mannual/dubbo-go-pixiu/user/quality/ description: 质量指标 linkTitle: 质量指标 title: 质量指标 diff --git a/content/en/overview/reference/pixiu/user/quality/performance.md b/content/en/overview/reference/pixiu/user/quality/performance.md index 13633e789fb1..ba8885cead7e 100755 --- a/content/en/overview/reference/pixiu/user/quality/performance.md +++ b/content/en/overview/reference/pixiu/user/quality/performance.md @@ -1,19 +1,15 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/quality/performance/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/quality/performance/ - - /zh-cn/overview/reference/pixiu/user/quality/stability/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/quality/stability/ -description: 性能 -linkTitle: 性能 -title: 性能 + - /docs3-v2/dubbo-go-pixiu/user/quality/performance/ + - /docs3-v2/dubbo-go-pixiu/user/quality/performance/ + - /overview/reference/pixiu/user/quality/stability/ + - /overview/mannual/dubbo-go-pixiu/user/quality/stability/ +description: Performance +linkTitle: Performance +title: Performance type: docs weight: 10 --- +Welcome to contribute to this document. - - - - -欢迎认领补充此文档。 diff --git a/content/en/overview/reference/pixiu/user/quality/stability.md b/content/en/overview/reference/pixiu/user/quality/stability.md index 0da92f432ee0..4250f54ac05b 100644 --- a/content/en/overview/reference/pixiu/user/quality/stability.md +++ b/content/en/overview/reference/pixiu/user/quality/stability.md @@ -1,19 +1,15 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/quality/stability/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/quality/stability/ - - /zh-cn/overview/reference/pixiu/user/quality/stability/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/quality/stability/ -description: 稳定性 -linkTitle: 稳定性 -title: 稳定性 + - /docs3-v2/dubbo-go-pixiu/user/quality/stability/ + - /en/docs3-v2/dubbo-go-pixiu/user/quality/stability/ + - /en/overview/reference/pixiu/user/quality/stability/ + - /en/overview/manual/dubbo-go-pixiu/user/quality/stability/ +description: Stability +linkTitle: Stability +title: Stability type: docs weight: 10 --- +Welcome to claim and supplement this document. - - - - -欢迎认领补充此文档。 diff --git a/content/en/overview/reference/pixiu/user/quickstart.md b/content/en/overview/reference/pixiu/user/quickstart.md index 8f89a64b01a6..8c6bfcc976d1 100755 --- a/content/en/overview/reference/pixiu/user/quickstart.md +++ b/content/en/overview/reference/pixiu/user/quickstart.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/quickstart/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/quickstart/ - - /zh-cn/overview/reference/pixiu/user/quickstart/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/quickstart/ + - /en/docs3-v2/dubbo-go-pixiu/user/quickstart/ + - /en/docs3-v2/dubbo-go-pixiu/user/quickstart/ + - /en/overview/reference/pixiu/user/quickstart/ + - /en/overview/mannual/dubbo-go-pixiu/user/quickstart/ description: 快速开始 linkTitle: 快速开始 title: 快速开始 @@ -168,4 +168,4 @@ go run server.go user.go cd samples/dubbogo/simple/resolve/test go test pixiu_test.go -``` \ No newline at end of file +``` diff --git a/content/en/overview/reference/pixiu/user/samples/_index.md b/content/en/overview/reference/pixiu/user/samples/_index.md index 29f0f01d1015..817903731d69 100755 --- a/content/en/overview/reference/pixiu/user/samples/_index.md +++ b/content/en/overview/reference/pixiu/user/samples/_index.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/samples/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/samples/ - - /zh-cn/overview/reference/pixiu/user/samples/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/ + - /en/docs3-v2/dubbo-go-pixiu/user/samples/ + - /en/docs3-v2/dubbo-go-pixiu/user/samples/ + - /en/overview/reference/pixiu/user/samples/ + - /en/overview/mannual/dubbo-go-pixiu/user/samples/ description: 案例介绍 linkTitle: 案例介绍 title: 案例介绍 diff --git a/content/en/overview/reference/pixiu/user/samples/http_proxy.md b/content/en/overview/reference/pixiu/user/samples/http_proxy.md index 312762bb7dfe..d25dafa438c6 100644 --- a/content/en/overview/reference/pixiu/user/samples/http_proxy.md +++ b/content/en/overview/reference/pixiu/user/samples/http_proxy.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/samples/http_proxy/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/samples/http_proxy/ - - /zh-cn/overview/reference/pixiu/user/samples/http_proxy/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/http_proxy/ + - /en/docs3-v2/dubbo-go-pixiu/user/samples/http_proxy/ + - /en/docs3-v2/dubbo-go-pixiu/user/samples/http_proxy/ + - /en/overview/reference/pixiu/user/samples/http_proxy/ + - /en/overview/mannual/dubbo-go-pixiu/user/samples/http_proxy/ description: Http Proxy 案例介绍 linkTitle: Http Proxy 案例介绍 title: Http Proxy 案例介绍 diff --git a/content/en/overview/reference/pixiu/user/samples/http_to_dubbo.md b/content/en/overview/reference/pixiu/user/samples/http_to_dubbo.md index bf3ba20048ca..000b35bc5023 100644 --- a/content/en/overview/reference/pixiu/user/samples/http_to_dubbo.md +++ b/content/en/overview/reference/pixiu/user/samples/http_to_dubbo.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/samples/http_to_dubbo/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/samples/http_to_dubbo/ - - /zh-cn/overview/reference/pixiu/user/samples/http_to_dubbo/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/http_to_dubbo/ + - /en/docs3-v2/dubbo-go-pixiu/user/samples/http_to_dubbo/ + - /en/docs3-v2/dubbo-go-pixiu/user/samples/http_to_dubbo/ + - /en/overview/reference/pixiu/user/samples/http_to_dubbo/ + - /en/overview/mannual/dubbo-go-pixiu/user/samples/http_to_dubbo/ description: Http to Dubbo 案例介绍 linkTitle: Http to Dubbo 案例介绍 title: Http to Dubbo 案例介绍 diff --git a/content/en/overview/reference/pixiu/user/samples/https.md b/content/en/overview/reference/pixiu/user/samples/https.md index 2caa4212b7ea..73a92e6b1de7 100644 --- a/content/en/overview/reference/pixiu/user/samples/https.md +++ b/content/en/overview/reference/pixiu/user/samples/https.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/docs3-v2/dubbo-go-pixiu/user/samples/https/ - - /zh-cn/docs3-v2/dubbo-go-pixiu/user/samples/https/ - - /zh-cn/overview/reference/pixiu/user/samples/https/ - - /zh-cn/overview/mannual/dubbo-go-pixiu/user/samples/https/ + - /en/docs3-v2/dubbo-go-pixiu/user/samples/https/ + - /en/docs3-v2/dubbo-go-pixiu/user/samples/https/ + - /en/overview/reference/pixiu/user/samples/https/ + - /en/overview/mannual/dubbo-go-pixiu/user/samples/https/ description: Https 案例介绍 linkTitle: Https 案例介绍 title: Https 案例介绍 diff --git a/content/en/overview/reference/proposals/_index.md b/content/en/overview/reference/proposals/_index.md index a2cd48189f50..f00db1b0edcd 100644 --- a/content/en/overview/reference/proposals/_index.md +++ b/content/en/overview/reference/proposals/_index.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/reference/proposals/ + - /en/overview/reference/proposals/ description: "Dubbo 框架核心功能设计方案" linkTitle: 提案 title: 提案 diff --git a/content/en/overview/reference/proposals/admin.md b/content/en/overview/reference/proposals/admin.md index ec327d76e31f..4d4637631b53 100644 --- a/content/en/overview/reference/proposals/admin.md +++ b/content/en/overview/reference/proposals/admin.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/reference/proposals/admin/ + - /en/overview/reference/proposals/admin/ author: Jun Liu date: 2023-02-28T00:00:00Z description: | diff --git a/content/en/overview/reference/proposals/heuristic-flow-control.md b/content/en/overview/reference/proposals/heuristic-flow-control.md index ef26db667bf2..36d062c8c82e 100644 --- a/content/en/overview/reference/proposals/heuristic-flow-control.md +++ b/content/en/overview/reference/proposals/heuristic-flow-control.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/reference/proposals/heuristic-flow-control/ + - /en/overview/reference/proposals/heuristic-flow-control/ author: Quanlu Liu date: 2023-01-30T00:00:00Z description: 本文所说的柔性服务主要是指**consumer端的负载均衡**和**provider端的限流**两个功能。在之前的dubbo版本中,负载均衡部分更多的考虑的是公平性原则,即consumer端尽可能平等的从provider中作出选择,在某些情况下表现并不够理想。而限流部分只提供了静态的限流方案,需要用户对provider端设置静态的最大并发值,然而该值的合理选取对用户来讲并不容易。我们针对这些存在的问题进行了改进。 @@ -37,7 +37,7 @@ working_in_progress: true ![image.png](/imgs/overview/reference/proposals/heuristic-flow-control/1675265271198-5b045ced-8524-42a2-8b34-d7edbbd1f232.png) #### 使用方法 -[Dubbo Java 实现的使用方法](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance) 与原本的负载均衡方法相同。只需要在consumer端将"loadbalance"设置为"p2c"或者"adaptive"即可。 +[Dubbo Java 实现的使用方法](/en/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance) 与原本的负载均衡方法相同。只需要在consumer端将"loadbalance"设置为"p2c"或者"adaptive"即可。 #### 代码结构 负载均衡部分的算法实现只需要在原本负载均衡框架内继承 LoadBalance接口即可。 @@ -123,7 +123,7 @@ inflight为consumer端还未返回的请求的数量。 #### 使用方法 要确保服务端存在多个节点,并且消费端开启重试策略的前提下,限流功能才能更好的发挥作用。 -[Dubbo Java 实现的自适应限流开启方法](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance) 与静态的最大并发值设置类似,只需在provider端将"flowcontrol"设置为"autoConcurrencyLimier"或者"heuristicSmoothingFlowControl"即可。 +[Dubbo Java 实现的自适应限流开启方法](/en/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance) 与静态的最大并发值设置类似,只需在provider端将"flowcontrol"设置为"autoConcurrencyLimier"或者"heuristicSmoothingFlowControl"即可。 #### 代码结构 1. FlowControlFilter:在provider端的filter负责根据限流算法的结果来对provider端进行限流功能。 diff --git a/content/en/overview/reference/proposals/metrics.md b/content/en/overview/reference/proposals/metrics.md index 4724d9723575..abe2a53d89fb 100644 --- a/content/en/overview/reference/proposals/metrics.md +++ b/content/en/overview/reference/proposals/metrics.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/reference/proposals/metrics/ + - /en/overview/reference/proposals/metrics/ author: Song Xiaosheng date: 2023-02-20T00:00:00Z description: 指标埋点 diff --git a/content/en/overview/reference/proposals/protocol-http.md b/content/en/overview/reference/proposals/protocol-http.md index 63e39209fa1c..bf139cfe4f2e 100644 --- a/content/en/overview/reference/proposals/protocol-http.md +++ b/content/en/overview/reference/proposals/protocol-http.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/reference/proposals/protocol-http/ + - /en/overview/reference/proposals/protocol-http/ description: 本文将介绍 Dubbo 的 REST/HTTP 协议设计。 linkTitle: Rest 协议 title: Rest 协议 diff --git a/content/en/overview/reference/proposals/registry-config-meta.md b/content/en/overview/reference/proposals/registry-config-meta.md index 11c0f4c5f239..7ed9adc6ffee 100644 --- a/content/en/overview/reference/proposals/registry-config-meta.md +++ b/content/en/overview/reference/proposals/registry-config-meta.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/reference/proposals/registry-config-meta/ + - /en/overview/reference/proposals/registry-config-meta/ description: 本文介绍三中心架构设计 linkTitle: 注册&配置&元数据中心 title: 注册中心、配置中心和元数据中心 diff --git a/content/en/overview/reference/proposals/service-discovery.md b/content/en/overview/reference/proposals/service-discovery.md index 295ee58efc68..499e40ba6d2b 100644 --- a/content/en/overview/reference/proposals/service-discovery.md +++ b/content/en/overview/reference/proposals/service-discovery.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/reference/proposals/service-discovery/ + - /en/overview/reference/proposals/service-discovery/ author: Jun Liu date: 2023-01-30T00:00:00Z description: 应用级服务发现设计 diff --git a/content/en/overview/reference/proposals/support-more-content-types.md b/content/en/overview/reference/proposals/support-more-content-types.md index 35a4050dbb41..c396c33c4307 100644 --- a/content/en/overview/reference/proposals/support-more-content-types.md +++ b/content/en/overview/reference/proposals/support-more-content-types.md @@ -1,6 +1,6 @@ --- aliases: - - /zh/overview/reference/proposals/support-more-content-type/ + - /en/overview/reference/proposals/support-more-content-type/ author: 武钰皓 description: | 本文主要介绍Triple对更多Http标准Content-Type的支持方式,以及服务该如何接收这些请求。 @@ -169,4 +169,4 @@ Accept: application/xml ``` * 该实现与Rest的XMLCodec相同 -* 响应使用 application/xml 编码 \ No newline at end of file +* 响应使用 application/xml 编码 diff --git a/content/en/overview/reference/protoc-installation.md b/content/en/overview/reference/protoc-installation.md index c06bd064ef81..4adeb1182213 100644 --- a/content/en/overview/reference/protoc-installation.md +++ b/content/en/overview/reference/protoc-installation.md @@ -1,34 +1,34 @@ --- -title: 如何安装 Protocol Buffer Compiler -linkTitle: Protoc安装 -description: 如何安装 protocol buffer 编译器。 +title: How to Install Protocol Buffer Compiler +linkTitle: Protoc Installation +description: How to install the protocol buffer compiler. protoc-version: 3.15.8 toc_hide: true type: docs --- -虽然不是强制性的,但 Apache Dubbo 支持使用 [Protocol Buffers (proto3版本)](https://protobuf.dev/programming-guides/proto3) 作为服务定义和序列化协议。 +Although not mandatory, Apache Dubbo supports using [Protocol Buffers (proto3)](https://protobuf.dev/programming-guides/proto3) for service definitions and serialization protocols. -在 Protocol buffer 体系下,我们使用 `.proto` 文件定义服务和消息体格式,使用 `protoc` 编译器编译 `.proto` 文件,你可以使用以下几种方式安装 `protoc`。 +Within the protocol buffer framework, we use `.proto` files to define services and message body formats, and the `protoc` compiler to compile `.proto` files. You can install `protoc` in the following ways. -### 使用包管理器安装 +### Installing via Package Manager -在 Linux 或 macOS 环境下,你可以使用包管理器安装 `protoc`。 +On Linux or macOS, you can use a package manager to install `protoc`. {{% alert title="Warning" color="warning" %}} -**一定要注意检查所安装 `protoc` 的版本!** 检查方法如下文说述,因为有时一些包管理器安装的 `protoc` 版本是严重过时的。 +**Be sure to check the installed version of `protoc`!** This can be done as described below, since some package managers might install severely outdated versions of `protoc`. -下一节所展示的 [使用预先编译好的二进制文件安装](#binary-install) 可以确保你安装正确的 `protoc` 版本。 +The [Binary Installation](#binary-install) method mentioned in the next section ensures that you install the correct version of `protoc`. {{% /alert %}} -- Linux,使用 `apt` 或者 `apt-get`,比如: +- Linux, using `apt` or `apt-get`, for example: ```sh $ apt install -y protobuf-compiler $ protoc --version # Ensure compiler version is 3+ ``` -- MacOS,使用 [Homebrew](https://brew.sh): +- macOS, using [Homebrew](https://brew.sh): ```sh $ brew install protobuf @@ -37,33 +37,33 @@ type: docs -### 使用预先编译好的二进制文件安装(适用任何操作系统) +### Binary Installation (for any OS) -参考以下步骤安装 [最新版本](https://protobuf.dev/downloads#release-packages) 的 protoc 二进制包: +Follow these steps to install the [latest version](https://protobuf.dev/downloads#release-packages) of the `protoc` binary package: - 1. 根据你的操作系统类型,手动下载 [github.com/google/protobuf/releases](https://github.com/google/protobuf/releases) 二进制文件 - (`protoc---.zip`),你也可以使用以下命令直接下载: + 1. Manually download the binary files for your OS from [github.com/google/protobuf/releases](https://github.com/google/protobuf/releases) + (`protoc---.zip`), or use the following commands to download directly: ```sh $ PB_REL="https://github.com/protocolbuffers/protobuf/releases" $ curl -LO $PB_REL/download/v{{< param protoc-version >}}/protoc-{{< param protoc-version >}}-linux-x86_64.zip ``` - 2. 将文件解压到`$HOME/.local` 目录,或者任意你想要的目录也可以。比如: + 2. Unzip the file to the `$HOME/.local` directory, or any directory of your choice. For example: ```sh $ unzip protoc-{{< param protoc-version >}}-linux-x86_64.zip -d $HOME/.local ``` - 3. 修改系统 `PATH` 路径,将 `protoc` 加入可执行文件路径。比如: + 3. Modify the system `PATH` to include the `protoc` executable. For example: ```sh $ export PATH="$PATH:$HOME/.local/bin" ``` -### 其他安装方法 +### Other Installation Methods -如果你想要自行编译源码安装,或者想要安装老版本的二进制包。请参考 [下载 Protocol Buffers](https://protobuf.dev/downloads) +If you want to compile from the source yourself, or if you want to install an older version of the binary package, please refer to [Download Protocol Buffers](https://protobuf.dev/downloads) [download]: https://protobuf.dev/downloads [github.com/google/protobuf/releases]: https://github.com/google/protobuf/releases @@ -71,3 +71,4 @@ type: docs [latest release]: https://protobuf.dev/downloads#release-packages [pb]: https://developers.google.com/protocol-buffers [proto3]: https://protobuf.dev/programming-guides/proto3 + diff --git a/content/en/overview/reference/setup/_index.md b/content/en/overview/reference/setup/_index.md index fdcb7aa4bbf2..c793526a1e40 100755 --- a/content/en/overview/reference/setup/_index.md +++ b/content/en/overview/reference/setup/_index.md @@ -1,11 +1,12 @@ --- aliases: - - /zh/overview/reference/setup/ -description: 指导如何安装 Dubbo 控制面及依赖的相关服务治理组件。 -linkTitle: 安装 + - /en/overview/reference/setup/ +description: Guide on how to install Dubbo Control Plane and related service governance components. +linkTitle: Installation no_list: true -title: 安装 +title: Installation toc_hide: true type: docs weight: 50 ---- +### + diff --git a/content/en/overview/reference/setup/install.md b/content/en/overview/reference/setup/install.md index 2e9bd4d654b7..8c90e88e206d 100644 --- a/content/en/overview/reference/setup/install.md +++ b/content/en/overview/reference/setup/install.md @@ -1,72 +1,71 @@ --- aliases: - - /zh/overview/reference/setup/install/ -description: Dubbo 控制面是微服务治理的核心依赖,本文档描述了如何快速安装 Dubbo Admin 控制面、控制台以及服务发现、监控等组件。 -linkTitle: 安装 Dubbo -title: 安装 Dubbo Admin 及服务治理组件 + - /en/overview/reference/setup/install/ +description: Dubbo Control Plane is the core dependency for microservice governance. This document describes how to quickly install the Dubbo Admin control plane, console, and components such as service discovery and monitoring. +linkTitle: Install Dubbo +title: Install Dubbo Admin and Governance Components toc_hide: true type: docs weight: 50 --- - -## Dubboctl 安装 +## Dubboctl Installation ### Download -下载 Dubbo Admin 发行版本 +Download the Dubbo Admin release version ```shell curl -L https://dubbo.apache.org/installer.sh | VERSION=0.1.0 sh - -# Admin 要组织好发行版本 +# Admin needs to organize the release versions well ``` -将 dubboctl 放入可执行路径 +Put dubboctl into the executable path ```shell ln -s dubbo-admin-0.1.0/bin/dubboctl /usr/local/bin/dubboctl ``` ### Install -安装过程会依次: +The installation process will sequentially: -1. 安装 Admin 自定义的一些资源 -2. 拉起 Admin、Nacos、Zookeeper 等不同的组件服务 +1. Install some resources customized by Admin +2. Pull up different component services such as Admin, Nacos, Zookeeper, etc. ```shell -dubboctl install # 使用默认 manifests 安装 +dubboctl install # Install using default manifests # or -dubboctl manifests| kubectl apply -f - +dubboctl manifests | kubectl apply -f - ``` ```shell -dubboctl install --set profile=minimal # 指定不同的 profile,即安装组件的组合 +dubboctl install --set profile=minimal # Specify a different profile, i.e., combination of installation components ``` ```shell dubboctl install --set admin.nacos.enabled=true, admin.nacos.namespace=test -# 指定不同的覆盖参数 +# Specify different override parameters ``` -检查安装效果 +Check the installation result ```shell kubectl get pod -n dubbo-system ``` -### 打开 Admin 控制台 +### Open the Admin Console ```shell kubectl port-forward svc/dubbo-admin -n dubbo-system 38080:38080 ``` -打开浏览器,访问: `http://127.0.0.1:38080/` -## Helm 安装 -### 前置条件 +Open your browser and visit: `http://127.0.0.1:38080/` +## Helm Installation +### Prerequisites - [Install the Helm client](https://helm.sh/docs/intro/install/), version 3.6 or above. -- Kubernetes 集群 -- 配置 helm repository +- Kubernetes cluster +- Configure helm repository ```shell $ helm repo add dubbo https://dubbo.apache.org/charts $ helm repo update ``` -### 安装步骤 -#### 安装方式一 +### Installation Steps +#### Method One ```shell helm install dubbo-admin dubbo/dubbo-stack -n dubbo-system @@ -80,31 +79,31 @@ helm install dubbo-admin-grafana dubbo/dubbo-stack -n dubbo-system helm install dubbo-admin-prometheus dubbo/dubbo-stack -n dubbo-system ``` -#### 安装方式二 +#### Method Two ```shell helm install dubbo-admin-all dubbo/dubbo-stack -n dubbo-system ``` -> 引发的问题。需要明确哪些组件是保证生产可用的,哪些是仅作展示的,比如 nacos/zookeeper/admin 保障生产可用,prometheus/grafana 是仅作展示 -> 如果基于以上结论,则大部分情况下,dubbo-admin-all 是不推荐保生产安装的;更推荐使用类似 dubbo-admin-nacos 生产保障包,然后自己用 prometheus 社区的生产安装包 +> Issue. It needs to be clear which components are production-ready and which are for display only, such as nacos/zookeeper/admin for production readiness, prometheus/grafana for display only. +> Based on the above conclusion, in most cases, dubbo-admin-all is not recommended for production installation; more recommended is using similar dubbo-admin-nacos production-ready package and using the prometheus community production installation package yourself. -检查安装状态 +Check the installation status ```shell helm ls -n dubbo-system kubectl get deployments -n dubbo-system --output wide ``` -## VM 安装 +## VM Installation ### Download -下载 Dubbo Admin 发行版本 +Download the Dubbo Admin release version ```shell curl -L https://dubbo.apache.org/installer.sh | VERSION=0.1.0 sh - -# Admin 要组织好发行版本 +# Admin needs to organize the release versions well ``` -将 dubboctl 放入可执行路径 +Put dubboctl into the executable path ```shell ln -s dubbo-admin-0.1.0/bin/dubbo-admin /usr/local/bin/dubbo-admin ``` @@ -113,97 +112,5 @@ ln -s dubbo-admin-0.1.0/bin/dubbo-admin /usr/local/bin/dubbo-admin dubbo-admin run -f override-configuration.yml ``` ### Configuration -配置用于控制 dubbo-admin 的行为 - - -```yaml -# Environment type. Available values are: "kubernetes" or "universal" -environment: universal # ENV: DUBBO_ENVIRONMENT -# Mode in which Dubbo CP is running. Available values are: "standalone", "global", "zone" -mode: standalone # ENV: DUBBO_MODE - -# Resource Store configuration -store: - # Type of Store used in the Control Plane. Available values are: "kubernetes", "postgres" or "memory" - type: memory # ENV: DUBBO_STORE_TYPE - - # Kubernetes Store configuration (used when store.type=kubernetes) - kubernetes: - # Namespace where Control Plane is installed to. - systemNamespace: dubbo-system # ENV: DUBBO_STORE_KUBERNETES_SYSTEM_NAMESPACE - - # Postgres Store configuration (used when store.type=postgres) - mysql: - # Host of the Postgres DB - host: 127.0.0.1 # ENV: DUBBO_STORE_POSTGRES_HOST - # Port of the Postgres DB - port: 15432 # ENV: DUBBO_STORE_POSTGRES_PORT - # User of the Postgres DB - user: dubbo # ENV: DUBBO_STORE_POSTGRES_USER - # Password of the Postgres DB - password: dubbo # ENV: DUBBO_STORE_POSTGRES_PASSWORD - # Database name of the Postgres DB - dbName: dubbo # ENV: DUBBO_STORE_POSTGRES_DB_NAME - # Connection Timeout to the DB in seconds - connectionTimeout: 5 # ENV: DUBBO_STORE_POSTGRES_CONNECTION_TIMEOUT - # Maximum number of open connections to the database - # `0` value means number of open connections is unlimited - maxOpenConnections: 50 # ENV: DUBBO_STORE_POSTGRES_MAX_OPEN_CONNECTIONS - # Maximum number of connections in the idle connection pool - # <0 value means no idle connections and 0 means default max idle connections - maxIdleConnections: 50 # ENV: DUBBO_STORE_POSTGRES_MAX_IDLE_CONNECTIONS - # TLS settings - tls: - # Mode of TLS connection. Available values are: "disable", "verifyNone", "verifyCa", "verifyFull" - mode: disable # ENV: DUBBO_STORE_POSTGRES_TLS_MODE - # Path to TLS Certificate of the client. Used in verifyCa and verifyFull modes - certPath: # ENV: DUBBO_STORE_POSTGRES_TLS_CERT_PATH - # Path to TLS Key of the client. Used in verifyCa and verifyFull modes - keyPath: # ENV: DUBBO_STORE_POSTGRES_TLS_KEY_PATH - # Path to the root certificate. Used in verifyCa and verifyFull modes. - caPath: # ENV: DUBBO_STORE_POSTGRES_TLS_ROOT_CERT_PATH - # MinReconnectInterval controls the duration to wait before trying to - # re-establish the database connection after connection loss. After each - # consecutive failure this interval is doubled, until MaxReconnectInterval - # is reached. Successfully completing the connection establishment procedure - # resets the interval back to MinReconnectInterval. - minReconnectInterval: "10s" # ENV: DUBBO_STORE_POSTGRES_MIN_RECONNECT_INTERVAL - # MaxReconnectInterval controls the maximum possible duration to wait before trying - # to re-establish the database connection after connection loss. - maxReconnectInterval: "60s" # ENV: DUBBO_STORE_POSTGRES_MAX_RECONNECT_INTERVAL -server: - port: 38080 -registry: - address: xxx -metadata-center: - address: xxx -config-center: - address: xxx -external-services: - prometheus: - # Prometheus service name is "metrics" and is in the "telemetry" namespace - # http://prometheus.:9090 - url: "http://metrics.telemetry:9090/" - tracing: - # Enabled by default. Kiali will anyway fallback to disabled if - # Jaeger is unreachable. - enabled: true - # Jaeger service name is "tracing" and is in the "telemetry" namespace. - # Make sure the URL you provide corresponds to the non-GRPC enabled endpoint - # if you set "use_grpc" to false. - in_cluster_url: 'http://tracing.telemetry:16685/jaeger' - use_grpc: true - # Public facing URL of Jaeger - url: 'http://my-jaeger-host/jaeger' - grafana: - enabled: true - # Grafana service name is "grafana" and is in the "telemetry" namespace. - in_cluster_url: 'http://grafana.telemetry:3000/' - # Public facing URL of Grafana - url: 'http://my-ingress-host/grafana' - -# 更多配置 -``` -### 打开 Admin 控制台 +Configure to control the behavior of dubbo-admin -打开浏览器,访问: `http://127.0.0.1:38080/` \ No newline at end of file diff --git a/content/en/overview/what/_index.md b/content/en/overview/what/_index.md index fe233661ecf8..442d80ec233a 100644 --- a/content/en/overview/what/_index.md +++ b/content/en/overview/what/_index.md @@ -1,72 +1,72 @@ --- aliases: - - /zh/overview/what/ + - /en/overview/what/ description: "" hide_summary: true -linkTitle: 介绍 +linkTitle: Introduction no_list: true -title: Dubbo 介绍 +title: Introduction to Dubbo type: docs weight: 2 --- -[5 分钟快速掌握 Apache Dubbo]({{< relref "../../blog/news/dubbo-introduction" >}}) +[Master Apache Dubbo in 5 Minutes]({{< relref "../../blog/news/dubbo-introduction" >}}) -Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, -利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。 +Apache Dubbo is an RPC service development framework designed to address service governance and communication issues in microservice architectures. The official implementation provides multi-language SDKs such as Java and Golang. Microservices developed using Dubbo inherently possess the ability to discover and communicate with each other remotely. By leveraging Dubbo's rich service governance features, you can achieve service discovery, load balancing, traffic scheduling, and other service governance requirements. Dubbo is designed to be highly extensible, allowing users to easily implement various custom logics for traffic interception and routing. -在云原生时代,Dubbo 相继衍生出了 Dubbo3、Proxyless Mesh 等架构与解决方案,在易用性、超大规模微服务实践、云原生基础设施适配、安全性等几大方向上进行了全面升级。 +In the era of cloud-native, Dubbo has evolved into architectures and solutions like Dubbo3 and Proxyless Mesh, offering comprehensive upgrades in usability, large-scale microservice practices, cloud-native infrastructure adaptation, and security. -## Dubbo 的开源故事 +## The Open Source Story of Dubbo -Apache Dubbo 最初是为了解决阿里巴巴内部的微服务架构问题而设计并开发的,在十多年的时间里,它在阿里巴巴公司内部的很多业务系统得到了非常广泛的应用。最早在 2008 年,阿里巴巴就将 Dubbo 捐献到开源社区,它很快成为了国内开源服务框架选型的事实标准框架,得到了业界更广泛的应用。在 2017 年,Dubbo 被正式捐献 Apache 软件基金会并成为 Apache 顶级项目,开始了一段新的征程。 +Apache Dubbo was initially designed and developed to solve Alibaba's internal microservice architecture problems. Over more than a decade, it has been widely used in many business systems within Alibaba. As early as 2008, Alibaba donated Dubbo to the open-source community, and it quickly became the de facto standard framework for open-source service frameworks in China, gaining broader industry adoption. In 2017, Dubbo was officially donated to the Apache Software Foundation and became an Apache top-level project, embarking on a new journey. -Dubbo 被证实能很好的满足企业的大规模微服务实践,并且能有效降低微服务建设的开发与管理成本,不论是阿里巴巴还是工商银行、中国平安、携程、海尔等社区用户,它们都通过多年的大规模生产环境流量对 Dubbo 的稳定性与性能进行了充分验证。后来 Dubbo 在很多大企业内部衍生出了独立版本。自云原生概念推广以来,各大厂商都开始拥抱开源标准实现,阿里巴巴将其内部 HSF 系统与开源社区 Dubbo 相融合,与社区一同推出了云原生时代的 Dubbo3 架构,截止 2022 年双十一结束,**Dubbo3 已经在阿里巴巴内部广泛落地,实现了老版本 HSF2 框架升级,包括电商核心、阿里云等核心系统已经全面运行在 Dubbo3 之上**。 +Dubbo has proven to meet the large-scale microservice practices of enterprises effectively and can significantly reduce the development and management costs of microservice construction. Whether it is Alibaba, Industrial and Commercial Bank of China, Ping An Insurance, Ctrip, Haier, or other community users, they have fully verified Dubbo's stability and performance through years of large-scale production environment traffic. Later, Dubbo evolved into independent versions within many large enterprises. Since the promotion of the cloud-native concept, major vendors have begun to embrace open-source standard implementations. Alibaba integrated its internal HSF system with the open-source community Dubbo, jointly launching the Dubbo3 architecture for the cloud-native era. As of the end of Double 11 in 2022, **Dubbo3 has been widely implemented within Alibaba, achieving an upgrade from the old HSF2 framework, with core systems such as e-commerce and Alibaba Cloud fully running on Dubbo3**. -## 为什么需要 Dubbo,它能做什么? -按照微服务架构的定义,采用它的组织能够很好的提高业务迭代效率与系统稳定性,但前提是要先能保证微服务按照期望的方式运行,要做到这一点需要解决服务拆分与定义、数据通信、地址发现、流量管理、数据一致性、系统容错能力等一系列问题。 +## Why Do You Need Dubbo, and What Can It Do? -Dubbo 可以帮助解决如下微服务实践问题: +According to the definition of microservice architecture, adopting it can significantly improve business iteration efficiency and system stability. However, the prerequisite is to ensure that microservices run as expected. To achieve this, you need to address a series of issues such as service splitting and definition, data communication, address discovery, traffic management, data consistency, and system fault tolerance. -* **微服务编程范式和工具** +Dubbo can help solve the following microservice practice issues: -Dubbo 支持基于 IDL 或语言特定方式的服务定义,提供多种形式的服务调用形式(如同步、异步、流式等) +* **Microservice Programming Paradigm and Tools** -* **高性能的 RPC 通信** +Dubbo supports service definitions based on IDL or language-specific methods, providing various forms of service invocation (such as synchronous, asynchronous, streaming, etc.) -Dubbo 帮助解决微服务组件之间的通信问题,提供了基于 HTTP、HTTP/2、TCP 等的多种高性能通信协议实现,并支持序列化协议扩展,在实现上解决网络连接管理、数据传输等基础问题。 +* **High-Performance RPC Communication** -* **微服务监控与治理** +Dubbo helps solve communication issues between microservice components, offering multiple high-performance communication protocol implementations based on HTTP, HTTP/2, TCP, etc., and supports serialization protocol extensions, addressing fundamental issues like network connection management and data transmission. -Dubbo 官方提供的服务发现、动态配置、负载均衡、流量路由等基础组件可以很好的帮助解决微服务基础实践的问题。除此之外,您还可以用 Admin 控制台监控微服务状态,通过周边生态完成限流降级、数据一致性、链路追踪等能力。 +* **Microservice Monitoring and Governance** -* **部署在多种环境** +Dubbo provides official components for service discovery, dynamic configuration, load balancing, and traffic routing, effectively addressing basic microservice practice issues. Additionally, you can use the Admin console to monitor microservice status and leverage the surrounding ecosystem to achieve capabilities like rate limiting, degradation, data consistency, and link tracing. -Dubbo 服务可以直接部署在容器、Kubernetes、Service Mesh等多种架构下。 +* **Deployment in Various Environments** -* **活跃的社区** +Dubbo services can be directly deployed in various architectures such as containers, Kubernetes, and Service Mesh. -Dubbo 项目托管在 Apache 社区,有来自国际、国内的活跃贡献者维护着超 10 个生态项目,贡献者包括来自海外、阿里巴巴、工商银行、携程、蚂蚁、腾讯等知名企业技术专家,确保 Dubbo 及时解决项目缺陷、需求及安全漏洞,跟进业界最新技术发展趋势。 +* **Active Community** -* **庞大的用户群体** +The Dubbo project is hosted in the Apache community, maintained by active contributors from both international and domestic backgrounds, with over 10 ecosystem projects. Contributors include technical experts from well-known companies such as Alibaba, Industrial and Commercial Bank of China, Ctrip, Ant Financial, Tencent, and others, ensuring that Dubbo promptly addresses project defects, requirements, and security vulnerabilities, keeping up with the latest industry technology trends. -Dubbo3 已在阿里巴巴成功落地,实现了对老版本 HSF2 框架全面升级,成为阿里集团面向云原生时代的统一服务框架底座,庞大的用户群体是 Dubbo 保持稳定性、需求来源、先进性的基础。 +* **Large User Base** -## Dubbo 不是什么? +Dubbo3 has been successfully implemented within Alibaba, achieving a comprehensive upgrade from the old HSF2 framework, becoming the unified service framework foundation for Alibaba Group in the cloud-native era. The large user base is the foundation for Dubbo's stability, demand source, and advancement. -* **不是应用开发框架的替代者** +## What Dubbo Is Not? -Dubbo 设计为让开发者以主流的应用开发框架的开发模式工作,它不是各个语言应用开发框架的替代者,如它不是 Spring/Spring Boot 的竞争者,当你使用 Spring 时,Dubbo 可以无缝的与 Spring & Spring Boot 集成在一起。 +* **Not a Replacement for Application Development Frameworks** -* **不仅仅只是一款 RPC 框架** +Dubbo is designed to allow developers to work in the development mode of mainstream application development frameworks. It is not a replacement for application development frameworks in various languages. For example, it is not a competitor to Spring/Spring Boot. When you use Spring, Dubbo can seamlessly integrate with Spring & Spring Boot. -Dubbo 提供了内置 RPC 通信协议实现,但它不仅仅是一款 RPC 框架。首先,它不绑定某一个具体的 RPC 协议,开发者可以在基于 Dubbo 开发的微服务体系中使用多种通信协议;其次,除了 RPC 通信之外,Dubbo 提供了丰富的服务治理能力与生态。 +* **Not Just an RPC Framework** -* **不是 gRPC 协议的替代品** +Dubbo provides a built-in RPC communication protocol implementation, but it is not just an RPC framework. Firstly, it is not bound to a specific RPC protocol; developers can use multiple communication protocols in a microservice system based on Dubbo. Secondly, besides RPC communication, Dubbo offers rich service governance capabilities and an ecosystem. -Dubbo 支持基于 gRPC 作为底层通信协议,在 Dubbo 模式下使用 gRPC 可以带来更好的开发体验,享有统一的编程模型和更低的服务治理接入成本 +* **Not a replacement for the gRPC protocol** -* **不只有 Java 语言实现** +Dubbo supports using gRPC as the underlying communication protocol. Using gRPC under the Dubbo mode can bring a better development experience, offering a unified programming model and lower service governance access costs. -自 Dubbo3 开始,Dubbo 提供了 Java、Golang、Rust、Node.js 等多语言实现,未来会有更多的语言实现。 +* **Not limited to Java language implementation** + +Starting from Dubbo3, Dubbo provides implementations in multiple languages such as Java, Golang, Rust, and Node.js, with more language implementations to come in the future. diff --git a/content/en/overview/what/advantages/_index.md b/content/en/overview/what/advantages/_index.md index 60ad035cb5bd..b7fea711ca8f 100644 --- a/content/en/overview/what/advantages/_index.md +++ b/content/en/overview/what/advantages/_index.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/overview/what/advantages/ + - /en/overview/what/advantages/ description: "" -linkTitle: 核心优势 -title: 核心优势 +linkTitle: Core Advantages +title: Core Advantages type: docs weight: 4 --- diff --git a/content/en/overview/what/advantages/governance.md b/content/en/overview/what/advantages/governance.md index 7f7a2d6d17bc..efb98c258164 100644 --- a/content/en/overview/what/advantages/governance.md +++ b/content/en/overview/what/advantages/governance.md @@ -1,9 +1,9 @@ --- aliases: - - /zh/overview/what/advantages/governance/ -description: 服务治理 -linkTitle: 服务治理 -title: 服务治理 + - /en/overview/what/advantages/governance/ +description: Service Governance +linkTitle: Service Governance +title: Service Governance type: docs weight: 3 --- @@ -11,51 +11,51 @@ weight: 3 -## 流量管控 +## Traffic Control -在地址发现和负载均衡机制之外,Dubbo 丰富的流量管控规则可以控制服务间的流量走向和 API 调用,基于这些规则可以实现在运行期动态的调整服务行为如超时时间、重试次数、限流参数等,通过控制流量分布可以实现 A/B 测试、金丝雀发布、多版本按比例流量分配、条件匹配路由、黑白名单等,提高系统稳定性。 +Beyond address discovery and load balancing mechanisms, Dubbo's rich traffic control rules can manage the flow direction and API calls between services. Based on these rules, you can dynamically adjust service behaviors such as timeout periods, retry counts, and rate limiting parameters during runtime. By controlling traffic distribution, you can achieve A/B testing, canary releases, multi-version traffic allocation by ratio, conditional routing, black and white lists, etc., thereby improving system stability. -#### Dubbo 流量管控能解决哪些问题 -场景一:搭建多套独立的逻辑测试环境。 +#### What problems can Dubbo traffic control solve? +Scenario 1: Setting up multiple independent logical test environments. -场景二:搭建一套完全隔离的线上灰度环境用来部署新版本服务。 +Scenario 2: Setting up a completely isolated online gray environment for deploying new version services. ![gray1](/imgs/v3/tasks/gray/gray1.png) -场景三:金丝雀发布 +Scenario 3: Canary release ![weight1.png](/imgs/v3/tasks/weight/weight1.png) -场景四:同区域优先。当应用部署在多个不同机房/区域的时候,优先调用同机房/区域的服务提供者,避免了跨区域带来的网络延时,从而减少了调用的响应时间。 +Scenario 4: Same region priority. When applications are deployed in multiple different data centers/regions, prioritize calling service providers in the same data center/region to avoid network latency caused by cross-region calls, thereby reducing response time. ![region1](/imgs/v3/tasks/region/region1.png) -除了以上几个典型场景,我们还可以基于 Dubbo 支持的流量管控规则实现微服务场景中更丰富的流量管控,如: +In addition to the typical scenarios mentioned above, we can also achieve richer traffic control in microservice scenarios based on Dubbo's supported traffic control rules, such as: -* 动态调整超时时间 -* 服务重试 -* 访问日志 -* 同区域优先 -* 灰度环境隔离 -* 参数路由 -* 按权重比例分流 -* 金丝雀发布 -* 服务降级 -* 实例临时拉黑 -* 指定机器导流 +* Dynamic adjustment of timeout periods +* Service retries +* Access logs +* Same region priority +* Gray environment isolation +* Parameter routing +* Traffic splitting by weight ratio +* Canary release +* Service degradation +* Temporary blacklisting of instances +* Specified machine traffic redirection -可以在 [流量管理任务](../../../tasks/traffic-management/) 中了解以上实践场景细节。背后的规则定义与工作原理请参见 [Dubbo 流量管控规则设计与定义](../../../core-features/traffic/)。。 +You can learn more about the details of the above practical scenarios in [Traffic Management Tasks](../../../tasks/traffic-management/). For the underlying rule definitions and working principles, please refer to [Dubbo Traffic Control Rule Design and Definition](../../../core-features/traffic/). -## 微服务生态 -围绕 Dubbo 我们构建了完善的微服务治理生态,对于绝大多数服务治理需求,通过简单几行配置即可开启。对于官方尚未适配的组件或者用户内部系统,也可以通过 Dubbo 扩展机制轻松适配。 +## Microservice Ecosystem +Around Dubbo, we have built a comprehensive microservice governance ecosystem. For most service governance needs, you can enable them with just a few lines of configuration. For components not yet adapted by the official team or internal user systems, you can also easily adapt them through Dubbo's extension mechanism. ![governance](/imgs/v3/what/governance.png) -## 可视化控制台 -Dubbo Admin 是 Dubbo 官方提供的可视化 Web 交互控制台,基于 Admin 你可以实时监测集群流量、服务部署状态、排查诊断问题。 +## Visual Console +Dubbo Admin is a visual web interactive console provided by Dubbo. Based on Admin, you can monitor cluster traffic, service deployment status, and troubleshoot issues in real-time. -## 安全体系 -Dubbo 支持基于 TLS 的 HTTP、HTTP/2、TCP 数据传输通道,并且提供认证、鉴权策略,让开发者实现更细粒度的资源访问控制。 +## Security System +Dubbo supports HTTP, HTTP/2, and TCP data transmission channels based on TLS, and provides authentication and authorization strategies, allowing developers to achieve finer-grained resource access control. -## 服务网格 -基于 Dubbo 开发的服务可以透明的接入 Istio 等服务网格体系,Dubbo 支持基于 Envoy 的流量拦截方式,也支持更加轻量的 Proxyless Mesh 部署模式。 +## Service Mesh +Services developed based on Dubbo can transparently integrate into service mesh systems like Istio. Dubbo supports traffic interception based on Envoy and also supports a more lightweight Proxyless Mesh deployment mode. diff --git a/content/en/overview/what/advantages/performance.md b/content/en/overview/what/advantages/performance.md index 0066495d2edd..363260598dce 100644 --- a/content/en/overview/what/advantages/performance.md +++ b/content/en/overview/what/advantages/performance.md @@ -1,67 +1,67 @@ --- aliases: - - /zh/overview/what/advantages/performance/ -description: 超高性能 -linkTitle: 超高性能 -title: 超高性能 + - /en/overview/what/advantages/performance/ +description: Ultra-high performance +linkTitle: Ultra-high performance +title: Ultra-high performance type: docs weight: 2 --- -Dubbo 被设计用于解决阿里巴巴超大规模的电商微服务集群实践,并在各个行业头部企业经过多年的十万、百万规模的微服务实践检验,因此,Dubbo 在通信性能、稳定性方面具有无可比拟的优势,非常适合构建近乎无限水平伸缩的微服务集群,这也是 Dubbo 从实践层面优于业界很多同类的产品的巨大优势。 +Dubbo is designed to address Alibaba's large-scale e-commerce microservice cluster practices and has been tested in tens of thousands to millions of microservice practices in leading enterprises across various industries over the years. Therefore, Dubbo has unparalleled advantages in communication performance and stability, making it very suitable for building nearly infinitely scalable microservice clusters. This is also a significant advantage of Dubbo over many similar products in the industry from a practical perspective. -## 高性能数据传输 -Dubbo 内置支持 Dubbo2、Triple 两款高性能通信协议。其中 -* Dubbo2 是基于 TCP 传输协议之上构建的二进制私有 RPC 通信协议,是一款非常简单、紧凑、高效的通信协议。 -* Triple 是基于 HTTP/2 的新一代 RPC 通信协议,在网关穿透性、通用性以及 Streaming 通信上具备优势,Triple 完全兼容 gRPC 协议。 +## High-performance data transmission +Dubbo natively supports two high-performance communication protocols: Dubbo2 and Triple. Among them: +* Dubbo2 is a binary private RPC communication protocol built on top of the TCP transport protocol. It is a very simple, compact, and efficient communication protocol. +* Triple is a new generation RPC communication protocol based on HTTP/2, which has advantages in gateway penetration, generality, and streaming communication. Triple is fully compatible with the gRPC protocol. -以下是基于 Dubbo 3.2 版本得出的压测指标数据,您也可以通过 [dubbo-benchmark](https://github.com/apache/dubbo-benchmark) 项目自行压测。 +Below are the benchmark data based on Dubbo 3.2 version. You can also perform your own benchmarking through the [dubbo-benchmark](https://github.com/apache/dubbo-benchmark) project. ### TCP protocol benchmark -对比 Dubbo 2.x 及早期 3.x 版本 -* 较小报文场景 createUser、getUser 下,提升率约 180%。 -* 极小报文 existUser(仅一个boolean值)下提升率约 24% -* 较大报文 listUser 提升率最高,达到了 1000%! +Compared to Dubbo 2.x and early 3.x versions: +* In smaller message scenarios like createUser and getUser, the improvement rate is about 180%. +* In extremely small message scenarios like existUser (only a boolean value), the improvement rate is about 24%. +* In larger message scenarios like listUser, the improvement rate is the highest, reaching 1000%! ![dubbo-rpc-protocol-benchmark](/imgs/v3/performance/rpc-dubbo.png) ### Triple protocol benchmark -* 较小报文场景 createUser、existUser、getUser 下,较 3.1 版本性能提升约 40-45%,提升后的性能与 gRPC 同场景的性能基本持平。 -* 较大报文场景 listUser 下较 3.1 版本提升了约 17%,相较于同场景下的 gRPC 低 11%。 +* In smaller message scenarios like createUser, existUser, and getUser, the performance improvement is about 40-45% compared to version 3.1, and the improved performance is almost on par with gRPC in the same scenarios. +* In larger message scenarios like listUser, the improvement is about 17% compared to version 3.1, which is 11% lower than gRPC in the same scenario. ![dubbo-http2-protobuf-benchmark](/imgs/v3/performance/rpc-triple.png) -了解更多 -* [通信协议](../../../core-features/protocols) -* [Benchmark 指标 (不定期更新)](https://github.com/apache/dubbo/issues/10558#issuecomment-1473015636) +Learn more +* [Communication Protocols](../../../core-features/protocols) +* [Benchmark Metrics (periodically updated)](https://github.com/apache/dubbo/issues/10558#issuecomment-1473015636) -## 构建可伸缩的微服务集群 -业务增长带来了集群规模的快速增长,而集群规模的增长会对服务治理架构带来挑战: -* 注册中心的存储容量瓶颈 -* 节点动态变化带来的地址推送与解析效率下降 -* 消费端存储大量网络地址的资源开销 -* 复杂的网络链接管理 -* 高峰期的流量无损上下线 -* 异常节点的自动节点管理 +## Building scalable microservice clusters +Business growth brings rapid growth in cluster size, and the growth in cluster size poses challenges to the service governance architecture: +* Storage capacity bottleneck of the registry center +* Decreased efficiency in address pushing and parsing due to dynamic changes in nodes +* Resource overhead of storing a large number of network addresses on the consumer side +* Complex network link management +* Lossless online and offline traffic during peak periods +* Automatic node management of abnormal nodes -以上内容直接关系到微服务集群的稳定性,因此很容易成为影响集群和业务增长的瓶颈,集群规模越大,问题带来的影响面也就被进一步放大。很多开发者可能会想只有几个应用而已,当前不需要并不关心集群规模,但作为技术架构选型的关键因素之一,我们还是要充分考虑微服务集群未来的可伸缩性。并且基于对业界大量微服务架构和框架实现的调研,一些产品的性能瓶颈点可能很快就会到来(部分产品所能高效支持的瓶颈节点规模阈值都是比较低的,比如几十个应用、数百个节点)。 +The above issues are directly related to the stability of the microservice cluster, so they can easily become bottlenecks affecting cluster and business growth. The larger the cluster size, the more amplified the impact of these issues. Many developers might think that they only have a few applications and currently do not need to worry about cluster size. However, as a key factor in technical architecture selection, we must fully consider the future scalability of the microservice cluster. Based on extensive research on microservice architectures and framework implementations in the industry, some products' performance bottlenecks may arrive quickly (the threshold for efficiently supporting bottleneck nodes in some products is relatively low, such as dozens of applications and hundreds of nodes). -Dubbo 的优势在于近乎无限水平扩容的集群规模,在阿里巴巴双十一场景万亿次调用的实践检验,通过以下内容了解 Dubbo 构建生产可用的、可伸缩的大规模微服务集群背后的原理: -* [Dubbo3 服务发现](../../../core-features/service-discovery/) -* [流量管控](../../../core-features/traffic/) +Dubbo's advantage lies in its nearly infinite horizontal scalability of cluster size. Verified by the practice of trillions of calls in Alibaba's Double 11 scenario, understand the principles behind Dubbo's construction of production-ready, scalable large-scale microservice clusters through the following content: +* [Dubbo3 Service Discovery](../../../core-features/service-discovery/) +* [Traffic Control](../../../core-features/traffic/) -## 智能化流量调度 -Dubbo3 内置了具备自适应感知集群负载状态、智能调节流量分布的限流与调度算法实现,从消费者、提供者两个不同视角智能调整流量分布,最大限度确保将流量调度到具有最佳处理能力的实例上,从而提升整个集群的吞吐量与稳定性。 +## Intelligent traffic scheduling +Dubbo3 has built-in implementations of rate limiting and scheduling algorithms that can adaptively sense the cluster load status and intelligently adjust traffic distribution. From the perspectives of both consumers and providers, it intelligently adjusts traffic distribution to ensure that traffic is scheduled to instances with the best processing capabilities, thereby improving the throughput and stability of the entire cluster. -### 自适应负载均衡 -自适应负载均衡是从消费者视角考虑如何将请求分配到当前具有最优处理能力的机器实例。Dubbo3 新引入了两种负载均衡算法 -* 一种是基于公平性考虑的单纯 `P2C` 算法 -* 另一种是基于自适应的方法 `adaptive`,其试图自适应的衡量 provider 端机器的吞吐能力,然后将流量尽可能分配到吞吐能力高的机器上,以提高系统整体的性能。 +### Adaptive load balancing +Adaptive load balancing considers how to allocate requests to the machine instances with the best processing capabilities from the consumer's perspective. Dubbo3 introduces two new load balancing algorithms: +* One is the simple `P2C` algorithm based on fairness considerations. +* The other is the adaptive method `adaptive`, which attempts to adaptively measure the throughput capacity of provider-side machines and then allocate traffic to machines with high throughput capacity as much as possible to improve the overall performance of the system. -### 自适应限流 -与负载均衡运行在消费者端不同的是,限流功能运行在提供者端。其作用是限制提供端实例处理并发任务时的最大数量。从理论上讲,服务端机器的处理能力是存在上限的,因此当并发请求量达到或接近上限时,拒绝掉一部分请求反而是更好的选择。相比于人为提前设置静态最大并发值,自适应限流算法可以动态调整服务端机器的最大并发值,使其可以在保证机器不过载的前提下,尽可能多的处理接收到的请求。 +### Adaptive Rate Limiting +Unlike load balancing, which operates on the consumer side, rate limiting functions on the provider side. Its purpose is to limit the maximum number of concurrent tasks that a provider instance can handle. Theoretically, the processing capacity of a server machine has an upper limit. Therefore, when the number of concurrent requests reaches or approaches this limit, rejecting some requests is actually a better choice. Compared to manually setting a static maximum concurrency value in advance, the adaptive rate limiting algorithm can dynamically adjust the maximum concurrency value of the server machine, allowing it to handle as many incoming requests as possible without overloading the machine. -关于这部分请参考 [Dubbo3 服务柔性设计文档](../../../reference/proposals/heuristic-flow-control) \ No newline at end of file +For more details, please refer to the [Dubbo3 Service Resilience Design Document](../../../reference/proposals/heuristic-flow-control) diff --git a/content/en/overview/what/advantages/production-ready.md b/content/en/overview/what/advantages/production-ready.md index 4cbd3bb6f0c7..a6de9e807609 100644 --- a/content/en/overview/what/advantages/production-ready.md +++ b/content/en/overview/what/advantages/production-ready.md @@ -1,34 +1,34 @@ --- aliases: - - /zh/overview/what/advantages/production-ready/ -description: 生产环境验证 -linkTitle: 生产环境验证 -title: 生产环境验证 + - /en/overview/what/advantages/production-ready/ +description: Production Environment Verification +linkTitle: Production Environment Verification +title: Production Environment Verification type: docs weight: 4 --- -Apache Dubbo 是一款有着数以万计企业用户的国际化开源项目,经过了多年大规模集群生产环境的检验,影响了数百万开发者,带动了大量微服务开源生态发展。Dubbo 从企业实践中孵化并走向开源,又迅速在开源社区获得了成功,大量的生产实践用户是 Dubbo 长期保持先进性、稳定性和活跃度的核心驱动力。 +Apache Dubbo is an international open-source project with tens of thousands of enterprise users. It has been tested in large-scale cluster production environments for many years, influencing millions of developers and driving the development of a large microservices open-source ecosystem. Dubbo was incubated from enterprise practices and then open-sourced, quickly achieving success in the open-source community. A large number of production practice users are the core driving force for Dubbo's long-term advancement, stability, and activity. -## Dubbo 在阿里巴巴的应用 -Dubbo 设计用于解决阿里巴巴内部复杂的电商微服务集群的开发和治理问题,在 2020 年,阿里巴巴与 Apache Dubbo 社区共同合作,基于 Dubbo2 & HSF2 发布了面向云原生架构的下一代服务框架 - Dubbo3,目前,Dubbo3 已经完全升级 HSF2、Dubbo2 成为阿里巴巴内部统一的服务框架,成功的跑在了数十万应用、数百万节点的双十一集群之上。 +## Dubbo's Application in Alibaba +Dubbo was designed to solve the development and governance issues of Alibaba's complex e-commerce microservices clusters. In 2020, Alibaba collaborated with the Apache Dubbo community to release the next-generation service framework for cloud-native architecture - Dubbo3, based on Dubbo2 & HSF2. Currently, Dubbo3 has fully upgraded HSF2 and Dubbo2 to become Alibaba's unified service framework, successfully running on the Double Eleven cluster with hundreds of thousands of applications and millions of nodes. -Dubbo3 吸取了 HSF2 框架所有大规模微服务集群的治理经验,解决了 Dubbo2 架构设计上长期积累的一些缺陷,同时增加了一系列面向云原生架构的新特性。 +Dubbo3 has absorbed all the large-scale microservices cluster governance experience from the HSF2 framework, addressed some long-standing architectural design flaws in Dubbo2, and added a series of new features for cloud-native architecture. ![production-ready](/imgs/v3/advantages/production-ready.png) -* 阿里巴巴结合 HSF 框架的大规模集群实践经验,基于 Apache Dubbo、开源社区需求等推出了面向云原生架构的全新服务框架 - Dubbo3,Dubbo3 在完全兼容之前 API 模式的情况下,完成了彻底的云原生架构升级。 -* Dubbo 的高度可扩展能力是其广泛适用的重要前提,阿里巴巴基于 Dubbo3 内核维护了一套内部特有的适配插件体系以实现平滑升级,这包括注册中心扩展、路由组件扩展、监控组件扩展等。 -* 几乎所有主流云厂商、主流微服务开源社区都提供了 Dubbo 适配或托管服务。 +* Combining the large-scale cluster practice experience of the HSF framework, Alibaba, based on Apache Dubbo and the needs of the open-source community, launched a new service framework for cloud-native architecture - Dubbo3. Dubbo3 has completed a thorough cloud-native architecture upgrade while fully compatible with the previous API mode. +* Dubbo's high scalability is an important premise for its wide applicability. Alibaba maintains a set of internally unique adaptation plugin systems based on the Dubbo3 kernel to achieve smooth upgrades. This includes registry extensions, routing component extensions, monitoring component extensions, etc. +* Almost all mainstream cloud vendors and mainstream microservices open-source communities provide Dubbo adaptation or hosting services. -关于阿里巴巴 Dubbo3 应用的更多细节,请参见 [博客文章](/zh-cn/blog/) +For more details on Alibaba's Dubbo3 application, please refer to the [blog post](/en/blog/) -## 更多案例 -据 [Wanted, Who's Using Dubbo](https://github.com/apache/dubbo/issues/1012) 统计,Dubbo 已知部分典型用户包括: +## More Case Studies +According to [Wanted, Who's Using Dubbo](https://github.com/apache/dubbo/issues/1012), some known typical users of Dubbo include: -网联清算、银联商务、中国人寿、中国平安、中国银行、人民银行、工商银行、招商证券、平安保险、中国人寿、阿里巴巴、滴滴出行、携程网、小米、斗鱼直播、瓜子二手车、金蝶、亚信科技、中国电信、文思海辉、中科软、科大讯飞、恒生电子、红星凯美龙、海尔、新东方、软通动力、中远海运、昆明航空、中通快递、顺丰科技、普华永道等。 +UnionPay Clearing, UnionPay Commerce, China Life Insurance, Ping An Insurance, Bank of China, People's Bank of China, Industrial and Commercial Bank of China, China Merchants Securities, Ping An Insurance, China Life Insurance, Alibaba, Didi Chuxing, Ctrip, Xiaomi, Douyu Live, Guazi Used Cars, Kingdee, AsiaInfo, China Telecom, Pactera, Chinasoft International, iFlytek, Hundsun Technologies, Red Star Macalline, Haier, New Oriental, iSoftStone, COSCO Shipping, Kunming Airlines, ZTO Express, SF Technology, PwC, etc. {{< about/testimonials >}} diff --git a/content/en/overview/what/advantages/usability.md b/content/en/overview/what/advantages/usability.md index 822400230ad5..90c1a2e5ea4a 100644 --- a/content/en/overview/what/advantages/usability.md +++ b/content/en/overview/what/advantages/usability.md @@ -1,44 +1,43 @@ --- aliases: - - /zh/overview/what/advantages/usability/ -description: 快速易用 -linkTitle: 快速易用 -title: 快速易用 + - /en/overview/what/advantages/usability/ +description: Quick and Easy to Use +linkTitle: Quick and Easy to Use +title: Quick and Easy to Use type: docs weight: 1 --- -无论你是计划采用微服务架构开发一套全新的业务系统,还是准备将已有业务从单体架构迁移到微服务架构,Dubbo 框架都可以帮助到你。Dubbo 让微服务开发变得非常容易,它允许你选择多种编程语言、使用任意通信协议,并且它还提供了一系列针对微服务场景的开发、测试工具帮助提升研发效率。 +Whether you are planning to adopt a microservices architecture to develop a new business system or preparing to migrate an existing business from a monolithic architecture to a microservices architecture, the Dubbo framework can help you. Dubbo makes microservices development very easy, allowing you to choose multiple programming languages, use any communication protocol, and it also provides a series of development and testing tools for microservices scenarios to help improve development efficiency. -## 多语言 SDK -Dubbo 提供几乎所有主流语言的 SDK 实现,定义了一套统一的微服务开发范式。Dubbo 与每种语言体系的主流应用开发框架做了适配,总体编程方式、配置符合大多数开发者已有编程习惯。 +## Multi-language SDK +Dubbo provides SDK implementations for almost all mainstream languages, defining a unified microservices development paradigm. Dubbo is adapted to the mainstream application development frameworks of each language system, and the overall programming method and configuration conform to the existing programming habits of most developers. -比如在 Java 语言体系下,你可以使用 `dubbo-spring-boot-starter` 来开发符合 Spring、Spring Boot 模式的微服务应用,开发 Dubbo -应用只是为 Spring Bean 添加几个注解、完善 application.properties 配置文件。 +For example, in the Java language system, you can use `dubbo-spring-boot-starter` to develop microservices applications that conform to the Spring and Spring Boot patterns. Developing Dubbo applications is just a matter of adding a few annotations to Spring Beans and completing the application.properties configuration file. ![sdk](/imgs/v3/what/sdk.png) -## 任意通信协议 -Dubbo 微服务间远程通信实现细节,支持 HTTP、HTTP/2、gRPC、TCP 等所有主流通信协议。与普通 RPC 框架不同,Dubbo 不是某个单一 RPC 协议的实现,它通过上层的 RPC 抽象可以将任意 RPC 协议接入 Dubbo 的开发、治理体系。 +## Any Communication Protocol +Dubbo supports the implementation details of remote communication between microservices, supporting all mainstream communication protocols such as HTTP, HTTP/2, gRPC, TCP, etc. Unlike ordinary RPC frameworks, Dubbo is not an implementation of a single RPC protocol. Through the upper-layer RPC abstraction, any RPC protocol can be integrated into Dubbo's development and governance system. -多协议支持让用户选型,多协议迁移、互通等变得更灵活。 +Multi-protocol support makes user selection, multi-protocol migration, and interoperability more flexible. ![protocols](/imgs/v3/what/protocol.png) -## 加速微服务开发 +## Accelerate Microservices Development -### 项目脚手架 -项目脚手架 让 Dubbo 项目创建、依赖管理更容易。 +### Project Scaffold +Project Scaffold makes Dubbo project creation and dependency management easier. -比如通过如下可视化界面,勾选 Dubbo 版本、Zookeeper 注册中心以及必要的微服务生态选项后,一个完整的 Dubbo 项目模板就可以自动生成,接下来基于脚手架项目添加业务逻辑就可以了。更多脚手架使用方式的讲解,请参见任务模块的 [通过模板生成项目脚手架](../../../tasks/develop/template/) +For example, through the following visual interface, after selecting the Dubbo version, Zookeeper registry, and necessary microservices ecosystem options, a complete Dubbo project template can be automatically generated. Next, you can add business logic based on the scaffold project. For more explanations on how to use the scaffold, please refer to the task module [Generate Project Scaffold through Template](../../../tasks/develop/template/) -![脚手架示例图](/imgs/v3/advantages/initializer.png) +![Scaffold Example](/imgs/v3/advantages/initializer.png) -### 开发测试 -相比于单体应用,微服务分布式的特性会让不同组织之间的研发协同变得困难,这时我们需要有效的配套工具,用来提升整体的微服务研发效率。 +### Development and Testing +Compared to monolithic applications, the distributed nature of microservices can make R&D collaboration between different organizations more difficult. At this time, we need effective supporting tools to improve the overall microservices R&D efficiency. -Dubbo 从内核设计和实现阶段就考虑了如何解决开发、测试与运维问题,比如 Dubbo RPC 协议均支持 curl 访问,让开发协作更简单;配合官方提供的生态工具,可以实现服务测试、服务 Mock、文档管理、单机运维等能力,并通过 Dubbo Admin 控制台将所有操作都可视化的展现出来。 +Dubbo has considered how to solve development, testing, and operation and maintenance issues from the kernel design and implementation stage. For example, the Dubbo RPC protocol supports curl access, making development collaboration easier. Combined with the official ecosystem tools, it can achieve service testing, service mocking, document management, single-machine operation and maintenance capabilities, and visualize all operations through the Dubbo Admin console. ![admin](/imgs/v3/what/admin.png) diff --git a/content/en/overview/what/core-features/_index.md b/content/en/overview/what/core-features/_index.md index 39fca832de3b..f4bac2a16697 100755 --- a/content/en/overview/what/core-features/_index.md +++ b/content/en/overview/what/core-features/_index.md @@ -1,10 +1,10 @@ --- aliases: - - /zh/overview/core-features/ - - /zh-cn/overview/core-features/ -description: Dubbo 核心特性 -linkTitle: 功能 -title: Dubbo 核心特性 + - /en/overview/core-features/ + - /en/overview/core-features/ +description: Dubbo Core Features +linkTitle: Features +title: Dubbo Core Features type: docs weight: 4 --- diff --git a/content/en/overview/what/core-features/ecosystem.md b/content/en/overview/what/core-features/ecosystem.md index dec12eb049c9..918ab0493658 100644 --- a/content/en/overview/what/core-features/ecosystem.md +++ b/content/en/overview/what/core-features/ecosystem.md @@ -1,37 +1,36 @@ --- aliases: - - /zh-cn/overview/what/ecosystem/ - - /zh-cn/overview/core-features/ecosystem/ -description: 微服务生态 + - /en/overview/what/ecosystem/ + - /en/overview/core-features/ecosystem/ +description: Microservices Ecosystem feature: description: | - 一站式微服务生态适配:注册中心、网关、限流降级、负载均衡、一致性事务、异步消息、Tracing 等。 - title: 丰富生态 -linkTitle: 微服务生态 -title: 微服务生态 + One-stop microservices ecosystem adaptation: registry center, gateway, rate limiting and degradation, load balancing, consistent transactions, asynchronous messaging, tracing, etc. + title: Rich Ecosystem +linkTitle: Microservices Ecosystem +title: Microservices Ecosystem type: docs weight: 10 --- -Dubbo 社区和众多优秀的开源项目一起围绕 Dubbo 建立了丰富的微服务生态支持,这让开发者从选型 Dubbo 作为开发框架的第一天,就无需担心后续的服务治理诉求,Dubbo 对每一个常见问题均提供了生产级的解决方案。 +The Dubbo community, along with many excellent open-source projects, has established a rich microservices ecosystem around Dubbo. This ensures that developers do not need to worry about subsequent service governance demands from the first day they choose Dubbo as their development framework. Dubbo provides production-grade solutions for every common issue. -以下表格为基于最新 Dubbo Java 3.2.x 版本统计的生态组件支持情况,后续将根据开发进展持续更新。同时每个语言支持的组件完善度会有一定差异,具体请参见各个 [语言参考手册](../../mannual/) 内的详细说明 +The following table shows the support status of ecosystem components based on the latest Dubbo Java 3.2.x version. It will be continuously updated according to development progress. The completeness of components supported by each language may vary, so please refer to the detailed descriptions in each [language reference manual](../../mannual/). -| 功能 | 组件列表 | 组件列表 | 组件列表 | 组件列表 | 组件列表 | +| Function | Component List | Component List | Component List | Component List | Component List | | --- | --- | --- | --- | --- | --- | -| 服务发现 | [Zookeeper](../../mannual/java-sdk/reference-manual/registry/zookeeper) | [Nacos](../../mannual/java-sdk/reference-manual/registry/nacos) | [Kubernetes Service](/) | DNS【开发中】 | 更多 | -| 动态配置 | [Zookeeper](../../mannual/java-sdk/reference-manual/config-center/zookeeper) | [Nacos](../../mannual/java-sdk/reference-manual/config-center/nacos) | [Apollo](../../mannual/java-sdk/reference-manual/config-center/apollo) | Kubernetes【开发中】| 更多 | -| 元数据管理 | [Zookeeper](../../mannual/java-sdk/reference-manual/metadata-center/zookeeper) | [Nacos](../../mannual/java-sdk/reference-manual/metadata-center/nacos) | [Redis](../../mannual/java-sdk/reference-manual/metadata-center/redis) | Kubernetes【开发中】 | 更多 | -| RPC 协议 | [HTTP/2 (Triple)](../../reference/protocols/triple) | [TCP](../../reference/protocols/tcp) | [HTTP/REST【Alpha】](../../reference/protocols/http) | [gRPC](../../reference/protocols/triple) | [更多](../../reference/protocols/) | -| 可视化观测平台 | [Admin](../../tasks/observability/admin/) | [Grafana](../../tasks/observability/grafana/) | [Prometheus](../../tasks/observability/prometheus/) | - | - | -| 全链路追踪 | [Zipkin](../../tasks/observability/tracing/zipkin/) | [Skywalking](../../tasks/observability/tracing/skywalking/) | OpenTelemetry | - | - | -| 限流降级 | [Sentinel](../../tasks/rate-limit/sentinel) | [Resilience4j](../../tasks/rate-limit/resilience4j) | [Hystrix](../../tasks/rate-limit/hystrix) | - | - | -| 分布式事务 | [Seata](../../tasks/ecosystem/transaction/) | - | - | - | - | -| 网关 | [Higress]({{< relref "../../../../blog/integration/how-to-proxy-dubbo-in-higress" >}}) | [APISIX](../../tasks/ecosystem/gateway/) | [Shenyu]({{< relref "../../../../blog/integration/how-to-proxy-dubbo-in-apache-shenyu" >}}) | [Envoy](https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/network_filters/dubbo_proxy_filter) | - | -| 服务网格 | Istio【开发中】 | Aeraka | OpenSergo【开发中】 | Proxyless【Alpha】 | 更多 | - - -## 微服务生态示例架构 +| Service Discovery | [Zookeeper](../../mannual/java-sdk/reference-manual/registry/zookeeper) | [Nacos](../../mannual/java-sdk/reference-manual/registry/nacos) | [Kubernetes Service](/) | DNS [In Development] | More | +| Dynamic Configuration | [Zookeeper](../../mannual/java-sdk/reference-manual/config-center/zookeeper) | [Nacos](../../mannual/java-sdk/reference-manual/config-center/nacos) | [Apollo](../../mannual/java-sdk/reference-manual/config-center/apollo) | Kubernetes [In Development] | More | +| Metadata Management | [Zookeeper](../../mannual/java-sdk/reference-manual/metadata-center/zookeeper) | [Nacos](../../mannual/java-sdk/reference-manual/metadata-center/nacos) | [Redis](../../mannual/java-sdk/reference-manual/metadata-center/redis) | Kubernetes [In Development] | More | +| RPC Protocol | [HTTP/2 (Triple)](../../reference/protocols/triple) | [TCP](../../reference/protocols/tcp) | [HTTP/REST [Alpha]](../../reference/protocols/http) | [gRPC](../../reference/protocols/triple) | [More](../../reference/protocols/) | +| Visualization and Observability Platform | [Admin](../../tasks/observability/admin/) | [Grafana](../../tasks/observability/grafana/) | [Prometheus](../../tasks/observability/prometheus/) | - | - | +| Full Link Tracing | [Zipkin](../../tasks/observability/tracing/zipkin/) | [Skywalking](../../tasks/observability/tracing/skywalking/) | OpenTelemetry | - | - | +| Rate Limiting and Degradation | [Sentinel](../../tasks/rate-limit/sentinel) | [Resilience4j](../../tasks/rate-limit/resilience4j) | [Hystrix](../../tasks/rate-limit/hystrix) | - | - | +| Distributed Transactions | [Seata](../../tasks/ecosystem/transaction/) | - | - | - | - | +| Gateway | [Higress]({{< relref "../../../../blog/integration/how-to-proxy-dubbo-in-higress" >}}) | [APISIX](../../tasks/ecosystem/gateway/) | [Shenyu]({{< relref "../../../../blog/integration/how-to-proxy-dubbo-in-apache-shenyu" >}}) | [Envoy](https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/network_filters/dubbo_proxy_filter) | - | +| Service Mesh | Istio [In Development] | Aeraka | OpenSergo [In Development] | Proxyless [Alpha] | More | + +## Microservices Ecosystem Example Architecture {{< mse >}} @@ -42,5 +41,3 @@ Dubbo 社区和众多优秀的开源项目一起围绕 Dubbo 建立了丰富的 {{< /blocks/section >}} - - diff --git a/content/en/overview/what/core-features/extensibility.md b/content/en/overview/what/core-features/extensibility.md index 38c1b3b9a5aa..e2c7f74c41fc 100644 --- a/content/en/overview/what/core-features/extensibility.md +++ b/content/en/overview/what/core-features/extensibility.md @@ -1,123 +1,125 @@ --- aliases: - - /zh/overview/core-features/extensibility/ - - /zh-cn/overview/core-features/extensibility/ -description: 扩展适配 + - /en/overview/core-features/extensibility/ + - /en/overview/core-features/extensibility/ +description: Extension Adaptation feature: description: | - 一切皆可扩展,通过扩展 (Filter、Router、Service Discovery、Configuration 等) 自定义调用、管控行为,适配开源微服务生态。 - title: 可扩展性 -linkTitle: 扩展适配 -title: 扩展适配 + Everything is extensible. Customize invocation and control behaviors through extensions (Filter, Router, Service Discovery, Configuration, etc.) to adapt to the open-source microservice ecosystem. + title: Extensibility +linkTitle: Extension Adaptation +title: Extension Adaptation type: docs weight: 6 --- -Dubbo 从设计上是高度可扩展的,通过这些扩展点你可以做到: -* 拦截流量并控制流量行为 -* 按需调优 Dubbo 的一些默认策略与实现 -* 将 Dubbo 服务适配到公司内部微服务集群或其他主流的开源组件 +Dubbo is designed to be highly extensible. Through these extension points, you can: +* Intercept traffic and control traffic behavior +* Optimize some of Dubbo's default strategies and implementations as needed +* Adapt Dubbo services to internal microservice clusters or other mainstream open-source components -## 一切皆可扩展 +## Everything is Extensible -Dubbo 扩展能力使得 Dubbo 项目很方便的切分成一个一个的子模块,实现热插拔特性。用户完全可以基于自身需求,替换 Dubbo 原生实现,来满足自身业务需求。 +Dubbo's extensibility allows the Dubbo project to be conveniently divided into sub-modules, achieving hot-plug features. Users can completely replace Dubbo's native implementations based on their own needs to meet their business requirements. -![Admin 效果图](/imgs/v3/advantages/extensibility.png) +![Admin Effect Diagram](/imgs/v3/advantages/extensibility.png) -* **协议与编码扩展**。通信协议、序列化编码协议等 -* **流量管控扩展**。集群容错策略、路由规则、负载均衡、限流降级、熔断策略等 -* **服务治理扩展**。注册中心、配置中心、元数据中心、分布式事务、全链路追踪、监控系统等 -* **诊断与调优扩展**。流量统计、线程池策略、日志、QoS 运维命令、健康检查、配置加载等 +* **Protocol and Encoding Extensions**. Communication protocols, serialization encoding protocols, etc. +* **Traffic Control Extensions**. Cluster fault tolerance strategies, routing rules, load balancing, rate limiting, degradation, circuit breaker strategies, etc. +* **Service Governance Extensions**. Registry, configuration center, metadata center, distributed transactions, full-link tracing, monitoring systems, etc. +* **Diagnostics and Tuning Extensions**. Traffic statistics, thread pool strategies, logging, QoS operation commands, health checks, configuration loading, etc. -## 基于扩展点的微服务生态 -众多的扩展点与抽象,是 Dubbo 与众多微服务生态组件对接、实现微服务治理能力的基础。 +## Microservice Ecosystem Based on Extension Points +Numerous extension points and abstractions are the foundation for Dubbo to interface with many microservice ecosystem components and achieve microservice governance capabilities. -* [全链路追踪](../../tasks/observability/tracing/) -* [数据一致性](../../tasks/ecosystem/transaction/) -* [限流降级](../../core-features/traffic/circuit-breaking/) +* [Full-Link Tracing](../../tasks/observability/tracing/) +* [Data Consistency](../../tasks/ecosystem/transaction/) +* [Rate Limiting and Degradation](../../core-features/traffic/circuit-breaking/) -Dubbo 的各语言 sdk 实现都是采用的 "微内核+插件" 的设计模式,几乎所有流程中的核心节点都被定义为扩展点,官方发布的组件也是以扩展点的实现形式发布,因此 Dubbo 可以平等的对待所有官方与第三方组件扩展。 -* 扩展适配能力是实现 Dubbo 微服务生态的关键,Dubbo 生态组件如全链路追踪、注册中心实现等的适配都是基于 Filter、Registry、DynamicConfiguration 等扩展点实现。 -* 扩展适配给用户带来最大的灵活性,开发者可以随时接入公司内部组件、按需定制核心能力等。 +Dubbo's SDK implementations in various languages adopt the "microkernel + plugin" design pattern. Almost all core nodes in the process are defined as extension points. The components released by the official team are also released in the form of extension point implementations. Therefore, Dubbo can treat all official and third-party component extensions equally. +* Extension adaptation capability is key to realizing Dubbo's microservice ecosystem. Adaptations of Dubbo ecosystem components such as full-link tracing and registry implementations are based on extension points like Filter, Registry, DynamicConfiguration, etc. +* Extension adaptation brings maximum flexibility to users. Developers can integrate internal company components at any time and customize core capabilities as needed. ![extensibility-echosystem.png](/imgs/v3/feature/extensibility/arc.png) -以上是按架构层次划分的 Dubbo 内的一些核心扩展点定义及实现,从三个层次来展开: -* 协议通信层 -* 流量管控层 -* 服务治理层 +The above are some core extension point definitions and implementations within Dubbo, divided by architectural layers into three levels: +* Protocol Communication Layer +* Traffic Control Layer +* Service Governance Layer -## 协议通信层 -在通信协议一节我们强调过,Dubbo 不绑定任何协议,用户可以选择 Triple、gRPC、Dubbo2、REST、自定义协议等任一 RPC 远程通信协议,除此之外,RPC 协议之上的数据编码格式 (即序列化协议) 也是通过扩展点定义,用户可以灵活选择 RPC 与序列化的通信协议组合。 +## Protocol Communication Layer +In the communication protocol section, we emphasized that Dubbo does not bind to any protocol. Users can choose any RPC remote communication protocol such as Triple, gRPC, Dubbo2, REST, or custom protocols. In addition, the data encoding format (i.e., serialization protocol) above the RPC protocol is also defined through extension points. Users can flexibly choose the combination of RPC and serialization communication protocols. -![协议与编码原理图](/imgs/v3/feature/extensibility/protocol.png) +![Protocol and Encoding Diagram](/imgs/v3/feature/extensibility/protocol.png) ### Protocol -Protocol 扩展点定义对应的是 RPC 协议,利用这个扩展点可以让 Dubbo 作为统一的微服务开发和治理框架,而在下层通信协议上实现灵活切换。官方发布了对大多数主流 RPC 通信协议的适配,你可以通过几条简单的配置直接使用,如果你想使用公司自定义的 RPC 通信协议,请通过 Protocol 提供自定义扩展实现。 +The Protocol extension point defines the RPC protocol. Using this extension point allows Dubbo to serve as a unified microservice development and governance framework while achieving flexible switching on the underlying communication protocol. The official team has released adaptations for most mainstream RPC communication protocols, which you can use directly with a few simple configurations. If you want to use a custom RPC communication protocol for your company, please implement a custom extension through the Protocol. ### Serialization -Serialization 扩展点定义了序列化协议扩展,Dubbo 官方提供了 Fastjson、Protobuf、Hessian2、Kryo、FST 等序列化协议适配。 +The Serialization extension point defines the serialization protocol extension. Dubbo officially provides adaptations for serialization protocols such as Fastjson, Protobuf, Hessian2, Kryo, FST, etc. -## 流量管控层 -Dubbo 在服务调用链路上预置了大量扩展点,通过这些扩展点用户可以控制运行态的流量走向、改变运行时调用行为等,包括 Dubbo 内置的一些负载均衡策略、流量路由策略、超时等很多流量管控能力都是通过这类扩展点实现的。 +## Traffic Control Layer +Dubbo has preset many extension points in the service invocation chain. Through these extension points, users can control the runtime traffic direction and change runtime invocation behaviors. Many traffic control capabilities built into Dubbo, such as load balancing strategies, traffic routing strategies, timeouts, etc., are implemented through these extension points. -![协议与编码原理图](/imgs/v3/feature/extensibility/traffic.png) +![Protocol and Encoding Diagram](/imgs/v3/feature/extensibility/traffic.png) ### Filter -Filter 流量拦截器是 Dubbo 服务调用之上的 AOP 设计模式,Filter 用来对每次服务调用做一些预处理、后处理动作,使用 Filter 可以完成访问日志、加解密、流量统计、参数验证等任务,Dubbo 中的很多生态适配如限流降级 Sentinel、全链路追踪 Tracing 等都是通过 Fitler 扩展实现的。一次请求过程中可以植入多个 Filter,Filter 之间相互独立没有依赖。 -* 从消费端视角,它在请求发起前基于请求参数等做一些预处理工作,在接收到响应后,对响应结果做一些后置处理; -* 从提供者视角则,在接收到访问请求后,在返回响应结果前做一些预处理, +The Filter traffic interceptor is an AOP design pattern above Dubbo service invocation. Filters are used to perform some preprocessing and post-processing actions for each service invocation. Using Filters, you can complete tasks such as access logging, encryption and decryption, traffic statistics, parameter validation, etc. Many ecosystem adaptations in Dubbo, such as rate limiting and degradation with Sentinel, full-link tracing with Tracing, etc., are implemented through the Filter extension. Multiple Filters can be embedded in a single request process, and Filters are independent of each other without dependencies. +* From the consumer's perspective, it performs some preprocessing work based on request parameters before initiating the request and some post-processing on the response result after receiving the response. +* From the provider's perspective, it performs some preprocessing after receiving the access request and before returning the response result. ### Router -Router 路由器是 Dubbo 中流量管控的关键组件,它将符合一定条件的流量转发到特定分组的地址子集,是 Dubbo 流量管控中一些关键能力如按比例流量转发、流量隔离等的基础。每次服务调用请求都会流经一组路由器 (路由链),每个路由器根据预先设定好的规则、全量地址列表以及当前请求上下文计算出一个地址子集,再传给下一个路由器,重复这一过程直到最后得出一个有效的地址子集。 +The Router is a key component in Dubbo's traffic control, forwarding traffic that meets certain conditions to a subset of addresses in a specific group. It is the foundation for some of Dubbo's key traffic control capabilities, such as proportional traffic forwarding and traffic isolation. Each service call request flows through a set of routers (router chain), with each router calculating a subset of addresses based on predefined rules, the full address list, and the current request context, then passing it to the next router. This process repeats until a valid subset of addresses is obtained. -Dubbo 官方发布版本预置了丰富的流量管控规则与 router 实现,如 [流量管控](../traffic/) 一文中阐述的,用户通过下发规则即可实现各种模式的流量管控。如果有其他流量管控诉求,可以通过提供自定义的 router 扩展实现。 +The official Dubbo release comes with a rich set of traffic control rules and router implementations, as described in the [Traffic Control](../traffic/) document. Users can achieve various modes of traffic control by issuing rules. If there are other traffic control requirements, custom router extensions can be provided. ### Load Balance -在 Dubbo 中,Load Balance 负载均衡工作在 router 之后,对于每次服务调用,负载均衡负责在 router 链输出的地址子集中选择一台机器实例进行访问,保证一段时间内的调用都均匀的分布在地址子集的所有机器上。 +In Dubbo, Load Balance works after the router. For each service call, load balancing is responsible for selecting a machine instance from the subset of addresses output by the router chain, ensuring that calls are evenly distributed across all machines in the subset over time. -Dubbo 官方提供了加权随机、加权轮询、一致性哈希、最小活跃度优先、最短响应时间优先等负载均衡策略,还提供了根据集群负载自适应调度的负载均衡算法。 +Dubbo provides several load balancing strategies, including weighted random, weighted round-robin, consistent hashing, least active priority, and shortest response time priority. It also offers load balancing algorithms that adapt based on cluster load. -## 服务治理层 -以下是 Dubbo 部署的经典架构图,由注册中心 (服务发现)、配置中心和元数据中心构成了整个服务治理的核心。 +## Service Governance Layer +Below is a classic architecture diagram of Dubbo deployment, where the registry (service discovery), configuration center, and metadata center form the core of the entire service governance. -![服务治理架构图](/imgs/v3/concepts/threecenters.png) +![Service Governance Architecture Diagram](/imgs/v3/concepts/threecenters.png) -这里我们主要从架构、实现的视角来分析了 Dubbo 服务治理,Dubbo 很多服务治理的核心能力都是通过上图描述的几个关键组件实现的,用户通过控制面或者 Admin 下发的各种规则与配置、各类微服务集群状态的展示等都是直接与注册中心、配置中心和元数据中心交互。 +Here, we mainly analyze Dubbo service governance from the perspectives of architecture and implementation. Many of Dubbo's core service governance capabilities are implemented through the key components described in the diagram. Users interact directly with the registry, configuration center, and metadata center through various rules and configurations issued by the control plane or Admin, as well as the display of various microservice cluster states. -在具体实现或者部署上,注册中心、配置中心和元数据中心可以是同一组件,比如 Zookeeper 可同时作为注册、配置和元数据中心,Nacos 也是如此。因此,三个中心只是从架构职责上的划分,你甚至可以用同一个 Zookeeper 集群来承担所有三个职责,只需要在应用里将他们设置为同一个集群地址就可以了。 +In terms of specific implementation or deployment, the registry, configuration center, and metadata center can be the same component. For example, Zookeeper can serve as the registry, configuration center, and metadata center simultaneously, and the same goes for Nacos. Therefore, the three centers are only divided based on architectural responsibilities. You can even use the same Zookeeper cluster to handle all three responsibilities by setting them to the same cluster address in the application. -> 在云原生部署架构下,随着 Kubernetes、Service Mesh 架构的流行,微服务基础设施呈现下沉趋势,注册、配置和元数据中心的职责正被 Kubernetes、Istio 等组件取代,具体可参见 [服务网格](../service-mesh/) 一节的描述。 +> In cloud-native deployment architectures, with the popularity of Kubernetes and Service Mesh architectures, microservice infrastructure is trending towards decentralization. The responsibilities of the registry, configuration center, and metadata center are being replaced by components like Kubernetes and Istio. For more details, refer to the [Service Mesh](../service-mesh/) section. ### Registry -注册中心是 Dubbo 实现服务发现能力的基础,Dubbo 官方支持 Zookeeper、Nacos、Etcd、Consul、Eureka 等注册中心。 +The registry is the foundation for Dubbo's service discovery capabilities. Dubbo officially supports registries like Zookeeper, Nacos, Etcd, Consul, and Eureka. -通过对 Consul、Eureka 的支持,Dubbo 也实现了与 Spring Cloud 体系在地址和通信层面的互通,让用户同时部署 Dubbo 与 Spring Cloud,或者从 Spring Cloud 迁移到 Dubbo 变得更容易。 +By supporting Consul and Eureka, Dubbo also achieves address and communication layer interoperability with the Spring Cloud ecosystem, making it easier for users to deploy Dubbo and Spring Cloud simultaneously or migrate from Spring Cloud to Dubbo. ### Config Center -配置中心是用户实现动态控制 Dubbo 行为的关键组件,我们在 [流量管控](../../tasks/traffic-management) 任务中下发的所有规则,都是先下发到配置中心保存起来,进而 Dubbo 实例通过监听配置中心的变化,收到路由规则并达到控制流量的行为。 +The configuration center is a key component for users to dynamically control Dubbo's behavior. All rules issued in the [Traffic Management](../../tasks/traffic-management) tasks are first sent to the configuration center for storage. Dubbo instances then listen for changes in the configuration center, receive routing rules, and achieve traffic control behavior. -Dubbo 官方支持 Zookeeper、Nacos、Etcd、Redis、Apollo 等配置中心实现。 +Dubbo officially supports configuration centers like Zookeeper, Nacos, Etcd, Redis, and Apollo. ### Metadata Center -与配置中心相反,从用户视角来看元数据中心是只读的,元数据中心唯一的写入方是 Dubbo 进程实例,Dubbo 实例会在启动之后将一些内部状态(如服务列表、服务配置、服务定义格式等)上报到元数据中心,供一些治理能力作为数据来源,如服务测试、文档管理、服务状态展示等。 +In contrast to the configuration center, the metadata center is read-only from the user's perspective. The only writer to the metadata center is the Dubbo process instance. After startup, Dubbo instances report some internal states (such as service lists, service configurations, service definition formats, etc.) to the metadata center, which serves as a data source for governance capabilities like service testing, documentation management, and service status display. -Dubbo 官方支持 Zookeeper、Nacos、Etcd、Redis 等元数据中心实现。 +Dubbo officially supports metadata centers like Zookeeper, Nacos, Etcd, and Redis. -## 自定义扩展示例 +## Custom Extension Examples -以下示例演示了如何扩展 Dubbo 来解决实际问题,可以跟随示例学习。 +The following examples demonstrate how to extend Dubbo to solve practical problems. You can follow the examples to learn. -* [自定义 RPC 协议](../../tasks/extensibility/protocol/) -* [自定义流量路由规则](../../tasks/extensibility/router/) -* [自定义注册中心](../../tasks/extensibility/registry/) -* [自定义拦截器](../../tasks/extensibility/filter/) +* [Custom RPC Protocol](../../tasks/extensibility/protocol/) +* [Custom Traffic Routing Rules](../../tasks/extensibility/router/) +* [Custom Registry](../../tasks/extensibility/registry/) +* [Custom Interceptor](../../tasks/extensibility/filter/) -## 更多扩展点 -本文列出了 Dubbo 常用的一些扩展点,但还有大量的扩展点可供灵活定制,并且不同语言 sdk 的扩展定义和配置方式上也存在差异,以下是 Dubbo SDK 的扩展点手册。 +## More Extension Points +This document lists some commonly used extension points in Dubbo, but there are many more extension points available for flexible customization. The extension definitions and configuration methods also vary across different language SDKs. Below are the extension point manuals for Dubbo SDKs. -* [Java 扩展点手册](../../mannual/java-sdk/reference-manual/spi/description/) -* [Go 扩展点手册](../../mannual/golang-sdk/preface/design/aop_and_extension/) +* [Java Extension Point Manual](../../mannual/java-sdk/reference-manual/spi/description/) +* [Go Extension Point Manual](../../mannual/golang-sdk/preface/design/aop_and_extension/) + +It seems like you haven't pasted the Markdown content yet. Please provide the content you need translated, and I'll handle the translation while adhering to the specified rules. diff --git a/content/en/overview/what/core-features/load-balance.md b/content/en/overview/what/core-features/load-balance.md index fb888d68931c..981f4c300427 100644 --- a/content/en/overview/what/core-features/load-balance.md +++ b/content/en/overview/what/core-features/load-balance.md @@ -1,52 +1,52 @@ --- aliases: - - /zh/overview/core-features/load-balance/ - - /zh-cn/overview/core-features/load-balance/ -description: 负载均衡 -linkTitle: 负载均衡 -title: 负载均衡 + - /en/overview/core-features/load-balance/ + - /en/overview/core-features/load-balance/ +description: Load Balancing +linkTitle: Load Balancing +title: Load Balancing type: docs weight: 3 --- -在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 `weighted random` 基于权重的随机负载均衡策略。 +When it comes to cluster load balancing, Dubbo provides multiple balancing strategies, with the default being `weighted random`, a weighted random load balancing strategy. -具体实现上,Dubbo 提供的是客户端负载均衡,即由 Consumer 通过负载均衡算法得出需要将请求提交到哪个 Provider 实例。 +In terms of implementation, Dubbo provides client-side load balancing, meaning the Consumer determines which Provider instance to submit the request to using a load balancing algorithm. -## 负载均衡策略 -目前 Dubbo 内置了如下负载均衡算法,可通过调整配置项启用。 +## Load Balancing Strategies +Currently, Dubbo has the following built-in load balancing algorithms, which can be enabled by adjusting configuration items. -| 算法 | 特性 | 备注 | +| Algorithm | Features | Remarks | | :-------------------------- | :---------------------- | :---------------------------------------------- | -| Weighted Random LoadBalance | 加权随机 | 默认算法,默认权重相同 | -| RoundRobin LoadBalance | 加权轮询 | 借鉴于 Nginx 的平滑加权轮询算法,默认权重相同, | -| LeastActive LoadBalance | 最少活跃优先 + 加权随机 | 背后是能者多劳的思想 | -| Shortest-Response LoadBalance | 最短响应优先 + 加权随机 | 更加关注响应速度 | -| ConsistentHash LoadBalance | 一致性哈希 | 确定的入参,确定的提供者,适用于有状态请求 | -| P2C LoadBalance | Power of Two Choice | 随机选择两个节点后,继续选择“连接数”较小的那个节点。 | -| Adaptive LoadBalance | 自适应负载均衡 | 在 P2C 算法基础上,选择二者中 load 最小的那个节点 | +| Weighted Random LoadBalance | Weighted Random | Default algorithm, default weights are equal | +| RoundRobin LoadBalance | Weighted Round Robin | Inspired by Nginx's smooth weighted round-robin algorithm, default weights are equal, | +| LeastActive LoadBalance | Least Active First + Weighted Random | Based on the idea of rewarding the more capable | +| Shortest-Response LoadBalance | Shortest Response First + Weighted Random | Focuses more on response speed | +| ConsistentHash LoadBalance | Consistent Hash | Deterministic input, deterministic provider, suitable for stateful requests | +| P2C LoadBalance | Power of Two Choice | Randomly selects two nodes, then chooses the one with the smaller "number of connections". | +| Adaptive LoadBalance | Adaptive Load Balancing | Based on the P2C algorithm, selects the node with the smallest load among the two | ### Weighted Random -* **加权随机**,按权重设置随机概率。 -* 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。 -* 缺点:存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。 +* **Weighted Random**, sets random probability based on weight. +* High collision probability in a single section, but the larger the number of calls, the more evenly distributed it becomes. Using weights probabilistically also becomes more even, which is beneficial for dynamically adjusting provider weights. +* Disadvantage: There is an issue of slow providers accumulating requests. For example, the second machine is very slow but not down. When a request is routed to the second machine, it gets stuck there. Over time, all requests get stuck on the second machine. ### RoundRobin -* **加权轮询**,按公约后的权重设置轮询比率,循环调用节点 -* 缺点:同样存在慢的提供者累积请求的问题。 +* **Weighted Round Robin**, sets the round-robin ratio based on the agreed weight, and cycles through the nodes. +* Disadvantage: Similarly, there is an issue of slow providers accumulating requests. -加权轮询过程中,如果某节点权重过大,会存在某段时间内调用过于集中的问题。 -例如 ABC 三节点有如下权重:`{A: 3, B: 2, C: 1}` -那么按照最原始的轮询算法,调用过程将变成:`A A A B B C` +During weighted round-robin, if a node's weight is too large, there can be an issue of calls being overly concentrated in a certain period. +For example, if the weights of nodes A, B, and C are as follows: `{A: 3, B: 2, C: 1}` +Then according to the most primitive round-robin algorithm, the call process will become: `A A A B B C` -对此,Dubbo 借鉴 Nginx 的平滑加权轮询算法,对此做了优化,调用过程可抽象成下表: +To address this, Dubbo has optimized this by borrowing from Nginx's smooth weighted round-robin algorithm. The call process can be abstracted into the following table: -| 轮前加和权重 | 本轮胜者 | 合计权重 | 轮后权重(胜者减去合计权重) | +| Pre-round Sum Weights | Winner of This Round | Total Weight | Post-round Weights (Winner's weight minus total weight) | | :------------------ | :------- | :------- | :--------------------------- | -| 起始轮 | \ | \ | `A(0), B(0), C(0)` | +| Initial Round | \ | \ | `A(0), B(0), C(0)` | | `A(3), B(2), C(1)` | A | 6 | `A(-3), B(2), C(1)` | | `A(0), B(4), C(2)` | B | 6 | `A(0), B(-2), C(2)` | | `A(3), B(0), C(3)` | A | 6 | `A(-3), B(0), C(3)` | @@ -54,52 +54,50 @@ weight: 3 | `A(3), B(4), C(-1)` | B | 6 | `A(3), B(-2), C(-1)` | | `A(6), B(0), C(0)` | A | 6 | `A(0), B(0), C(0)` | -我们发现经过合计权重(3+2+1)轮次后,循环又回到了起点,整个过程中节点流量是平滑的,且哪怕在很短的时间周期内,概率都是按期望分布的。 +We found that after a total of weighted rounds (3+2+1), the cycle returns to the starting point. Throughout the process, the node traffic is smooth, and even within a very short time period, the probability is distributed as expected. -如果用户有加权轮询的需求,可放心使用该算法。 +If users have a need for weighted round-robin, they can use this algorithm with confidence. ### LeastActive -* **加权最少活跃调用优先**,活跃数越低,越优先调用,相同活跃数的进行加权随机。活跃数指调用前后计数差(针对特定提供者:请求发送数 - 响应返回数),表示特定提供者的任务堆积量,活跃数越低,代表该提供者处理能力越强。 -* 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大;相对的,处理能力越强的节点,处理更多的请求。 +* **Weighted Least Active Call First**, the lower the active count, the higher the priority of the call. For the same active count, weighted random is used. The active count refers to the difference in count before and after the call (for a specific provider: request sent count - response returned count), indicating the task backlog of a specific provider. The lower the active count, the stronger the processing capability of the provider. +* Slower providers receive fewer requests because the count difference before and after the call for slower providers will be larger; conversely, nodes with stronger processing capabilities handle more requests. ### ShortestResponse -* **加权最短响应优先**,在最近一个滑动窗口中,响应时间越短,越优先调用。相同响应时间的进行加权随机。 -* 使得响应时间越快的提供者,处理更多的请求。 -* 缺点:可能会造成流量过于集中于高性能节点的问题。 - -这里的响应时间 = 某个提供者在窗口时间内的平均响应时间,窗口时间默认是 30s。 +* **Weighted Shortest Response First**, in the most recent sliding window, the shorter the response time, the higher the priority of the call. For the same response time, weighted random is used. +* Providers with faster response times handle more requests. +* Disadvantage: It may cause traffic to be overly concentrated on high-performance nodes. +The response time here = the average response time of a provider within the window time, with the default window time being 30s. ### ConsistentHash -* **一致性 Hash**,相同参数的请求总是发到同一提供者。 -* 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。 -* 算法参见:[Consistent Hashing | WIKIPEDIA](http://en.wikipedia.org/wiki/Consistent_hashing) -* 缺省只对第一个参数 Hash,如果要修改,请配置 `` -* 缺省用 160 份虚拟节点,如果要修改,请配置 `` +* **Consistent Hash**, requests with the same parameters are always sent to the same provider. +* When a provider goes down, the requests originally sent to that provider are distributed to other providers based on virtual nodes, without causing drastic changes. +* For the algorithm, see: [Consistent Hashing | WIKIPEDIA](http://en.wikipedia.org/wiki/Consistent_hashing) +* By default, only the first parameter is hashed. To modify, configure `` +* By default, 160 virtual nodes are used. To modify, configure `` ### P2C Load Balance -Power of Two Choice 算法简单但是经典,主要思路如下: +The Power of Two Choice algorithm is simple yet classic, with the main idea as follows: -1. 对于每次调用,从可用的provider列表中做两次随机选择,选出两个节点providerA和providerB。 -2. 比较providerA和providerB两个节点,选择其“当前正在处理的连接数”较小的那个节点。 +1. For each call, make two random selections from the list of available providers, selecting two nodes: providerA and providerB. +2. Compare providerA and providerB, and choose the node with the smaller "current number of connections being processed." -以下是 [Dubbo P2C 算法实现提案](../../reference/proposals/heuristic-flow-control/#p2c算法) +Here is the [Dubbo P2C Algorithm Implementation Proposal](../../reference/proposals/heuristic-flow-control/#p2c算法) ### Adaptive Load Balance -Adaptive 即自适应负载均衡,是一种能根据后端实例负载自动调整流量分布的算法实现,它总是尝试将请求转发到负载最小的节点。 +Adaptive load balancing is an algorithm that automatically adjusts traffic distribution based on the load of backend instances. It always tries to forward requests to the node with the least load. -以下是 [Dubbo Adaptive 算法实现提案](../../reference/proposals/heuristic-flow-control/#adaptive算法) +Here is the [Dubbo Adaptive Algorithm Implementation Proposal](../../reference/proposals/heuristic-flow-control/#adaptive算法) -## 配置方式 -Dubbo 支持在服务提供者一侧配置默认的负载均衡策略,这样所有的消费者都将默认使用提供者指定的负载均衡策略,消费者可以自己配置要使用的负载均衡策略,如果都没有任何配置, -则默认使用随机负载均衡策略。 +## Configuration Method +Dubbo supports configuring the default load balancing strategy on the provider side, so all consumers will use the provider-specified load balancing strategy by default. Consumers can configure the load balancing strategy they want to use. If neither is configured, the default random load balancing strategy is used. -同一个应用内支持配置不同的服务使用不同的负载均衡策略,支持为同一服务的不同方法配置不同的负载均衡策略。 +Within the same application, different services can be configured to use different load balancing strategies, and different methods of the same service can be configured to use different load balancing strategies. -具体配置方式参加以下多语言实现 +For specific configuration methods, refer to the following multi-language implementations: * [Java](../../mannual/java-sdk/advanced-features-and-usage/performance/loadbalance/#使用方式) * [Golang](../../mannual/golang-sdk/) -## 自定义扩展 -负载均衡策略支持自定义扩展实现,具体请参见 [Dubbo 可扩展性](../extensibility) +## Custom Extension +Load balancing strategies support custom extension implementations. For details, see [Dubbo Extensibility](../extensibility) diff --git a/content/en/overview/what/core-features/more.md b/content/en/overview/what/core-features/more.md index 17f44509b4e3..7a51b5129848 100644 --- a/content/en/overview/what/core-features/more.md +++ b/content/en/overview/what/core-features/more.md @@ -1,72 +1,71 @@ --- aliases: - - /zh/overview/core-features/more/ - - /zh-cn/overview/core-features/more/ -description: 高级功能指南 -linkTitle: 更多高级功能 -title: 更多高级功能 + - /en/overview/core-features/more/ + - /en/overview/core-features/more/ +description: Advanced Features Guide +linkTitle: More Advanced Features +title: More Advanced Features type: docs weight: 11 --- +As a microservices framework closely related to application development and aimed at providing enterprise-level service governance capabilities for microservice clusters, Dubbo also offers many advanced features, covering service invocation behavior control, service diagnosis and tuning, service governance, and more. -作为一款与应用开发紧密相关的微服务框架,同时旨在为微服务集群提供企业级服务治理能力,Dubbo 还提供了很多高级功能,涵盖服务调用行为控制、服务诊断与调优、服务治理等。 - -多种语言 sdk 在功能实现、配置方式上会略有差异,具体功能列表和使用方式可参考如下文档: +There may be slight differences in feature implementation and configuration methods across different language SDKs. For specific feature lists and usage, please refer to the following documents: * [Java](../../mannual/java-sdk/advanced-features-and-usage/) * [Golang](../../mannual/golang-sdk/tutorial/) -## 控制服务调用行为 -* 服务版本 -* 服务分组 -* 分组聚合 -* 异步调用 -* 异步执行 -* 流式通信 -* 响应式编程 -* 泛化调用 -* 泛化实现 -* 调用链路传递隐式参数 -* RPC调用上下文 -* 调用触发事件通知 -* 服务端对客户端进行回调 -* 只订阅 -* 只注册 -* 运行时动态指定 IP 调用 -* 直连提供者 -* 启动时检查 -* 本地调用 -* 参数校验 -* 本地伪装 -* 本地存根 -* 回声测试 -* 调用信息记录 -* 延迟暴露 -* 集群容错 -* 服务降级 +## Controlling Service Invocation Behavior +* Service Versioning +* Service Grouping +* Group Aggregation +* Asynchronous Invocation +* Asynchronous Execution +* Streaming Communication +* Reactive Programming +* Generic Invocation +* Generic Implementation +* Implicit Parameter Passing in Invocation Chain +* RPC Invocation Context +* Invocation Trigger Event Notification +* Server Callback to Client +* Subscribe Only +* Register Only +* Dynamically Specify IP for Invocation at Runtime +* Direct Connection to Provider +* Startup Check +* Local Invocation +* Parameter Validation +* Local Mock +* Local Stub +* Echo Test +* Invocation Information Logging +* Delayed Exposure +* Cluster Fault Tolerance +* Service Degradation -## 诊断与调优 -* 端口协议复用 -* 线程池隔离 -* 多协议 -* 多注册中心 -* 请求耗时采样 -* 线程模型 -* 服务引用配置对象缓存 -* 路由状态采集 -* 负载均衡 -* 注册信息简化 -* 调用结果缓存 -* 并发控制 -* 连接控制 -* 延迟连接 -* 粘滞连接 -* 支持 Graal VM -* 导出线程堆栈 -* Kryo 和 FST 序列化 -* 自定义服务容器 -* 优雅停机 -* 主机地址自定义暴露 -* 一致性哈希选址 -* 日志框架适配及运行时管理 -* Kubernetes 生命周期探针 +## Diagnosis and Tuning +* Port Protocol Multiplexing +* Thread Pool Isolation +* Multiple Protocols +* Multiple Registries +* Request Time Sampling +* Thread Model +* Service Reference Configuration Object Caching +* Route Status Collection +* Load Balancing +* Simplified Registration Information +* Invocation Result Caching +* Concurrency Control +* Connection Control +* Delayed Connection +* Sticky Connection +* Graal VM Support +* Export Thread Stack +* Kryo and FST Serialization +* Custom Service Container +* Graceful Shutdown +* Custom Host Address Exposure +* Consistent Hashing Addressing +* Log Framework Adaptation and Runtime Management +* Kubernetes Lifecycle Probes diff --git a/content/en/overview/what/core-features/observability.md b/content/en/overview/what/core-features/observability.md index 230bae6d754e..87c588a057c8 100644 --- a/content/en/overview/what/core-features/observability.md +++ b/content/en/overview/what/core-features/observability.md @@ -1,60 +1,60 @@ --- aliases: - - /zh/overview/core-features/observability/ - - /zh-cn/overview/core-features/observability/ -description: 观测服务 + - /en/overview/core-features/observability/ + - /en/overview/core-features/observability/ +description: Observability Service feature: description: | - 多维度的可观测指标(Metrics、Tracing、Accesslog)帮助了解服务运行状态,Admin 控制台、Grafana 等帮助实现数据指标可视化展示。 - title: 可观测性 -linkTitle: 观测服务 -title: 观测服务 + Multi-dimensional observable metrics (Metrics, Tracing, Accesslog) help understand the service running status. Admin console, Grafana, etc., help achieve data metrics visualization. + title: Observability +linkTitle: Observability Service +title: Observability Service type: docs weight: 7 --- -Dubbo 内部维护了多个纬度的可观测指标,并且支持多种方式的可视化监测。可观测性指标从总体上来说分为三个度量纬度: +Dubbo internally maintains multiple dimensions of observable metrics and supports various ways of visual monitoring. Observable metrics are generally divided into three measurement dimensions: -* **Admin** Admin 控制台可视化展示了集群中的应用、服务、实例及依赖关系,支持流量治理规则下发,同时还提供如服务测试、mock、文档管理等提升研发测试效率的工具。 +* **Admin** The Admin console visually displays applications, services, instances, and dependencies in the cluster. It supports the issuance of traffic governance rules and provides tools such as service testing, mock, and document management to improve R&D testing efficiency. -* **Metrics** Dubbo 统计了一系列的流量指标如 QPS、RT、成功请求数、失败请求数等,还包括一系列的内部组件状态如线程池数、服务健康状态等。 +* **Metrics** Dubbo collects a series of traffic metrics such as QPS, RT, number of successful requests, number of failed requests, etc., as well as a series of internal component statuses such as thread pool count, service health status, etc. -* **Tracing** Dubbo 与业界主流的链路追踪工作做了适配,包括 Skywalking、Zipkin、Jaeger 都支持 Dubbo 服务的链路追踪。 +* **Tracing** Dubbo is adapted to mainstream link tracing works in the industry, including Skywalking, Zipkin, and Jaeger, all of which support Dubbo service link tracing. -* **Logging** Dubbo 支持多种日志框架适配。以 Java 体系为例,支持包括 Slf4j、Log4j2、Log4j、Logback、Jcl 等,用户可以基于业务需要选择合适的框架;同时 Dubbo 还支持 Access Log 记录请求踪迹。 +* **Logging** Dubbo supports multiple log framework adaptations. For example, in the Java ecosystem, it supports Slf4j, Log4j2, Log4j, Logback, Jcl, etc. Users can choose the appropriate framework based on business needs. Dubbo also supports Access Log to record request traces. ## Admin -Admin 控制台可视化展示了集群中的应用、服务、实例及依赖关系,支持流量治理规则下发,同时还提供如服务测试、mock、文档管理等提升研发测试效率的工具 +The Admin console visually displays applications, services, instances, and dependencies in the cluster. It supports the issuance of traffic governance rules and provides tools such as service testing, mock, and document management to improve R&D testing efficiency. -![Admin 效果图](/imgs/v3/feature/observability/admin.jpg) +![Admin Effect](/imgs/v3/feature/observability/admin.jpg) -* [Admin 部署与效果演示](../../tasks/observability/admin/) +* [Admin Deployment and Effect Demonstration](../../tasks/observability/admin/) ## Metrics -Dubbo 运行时统计了包括 qps、rt、调用总数、成功数、失败数,失败原因统计等在内的核心服务指标,同时,为了更好的监测服务运行状态,Dubbo 还提供了对核心组件状态的监控,如线程池数量、服务健康状态等。 +Dubbo runtime collects core service metrics including qps, rt, total calls, successful calls, failed calls, and failure reasons statistics. To better monitor the service running status, Dubbo also provides monitoring of core component statuses such as thread pool count and service health status. -可以通过 Grafana 可视化的查看 Metrics 指标 +Metrics can be visualized through Grafana. -![Grafana 效果图](/imgs/v3/feature/observability/provider-stat.png) +![Grafana Effect](/imgs/v3/feature/observability/provider-stat.png) -* [使用 Grafana 可视化展示 Metrics 指标](../../tasks/observability/grafana/) -* [如何从 Prometheus 查询特定 Metrics 指标](../../tasks/observability/prometheus/) +* [Visualize Metrics with Grafana](../../tasks/observability/grafana/) +* [How to Query Specific Metrics from Prometheus](../../tasks/observability/prometheus/) ## Tracing -全链路追踪对于监测分布式系统运行状态具有非常重要的价值,Dubbo 通过 Filter 拦截器实现了请求运行时的埋点跟踪,通过将跟踪数据导出到一些主流实现如 Zipkin、Skywalking、Jaeger 等,可以实现全链路跟踪数据的分析与可视化展示。 +Full link tracing is of great value for monitoring the running status of distributed systems. Dubbo implements runtime request tracking through Filter interceptors. By exporting tracking data to some mainstream implementations such as Zipkin, Skywalking, Jaeger, etc., full link tracking data analysis and visualization can be achieved. -![Tracing 效果图](/imgs/v3/feature/observability/tracing.png) +![Tracing Effect](/imgs/v3/feature/observability/tracing.png) -> 未来我们计划支持通过 Dubbo Admin 等治理平台动态调整 Dubbo 的链路追踪采样率。 +> In the future, we plan to support dynamically adjusting Dubbo's link tracing sampling rate through governance platforms such as Dubbo Admin. -* [基于 Skywalking 实现全链路追踪](../../tasks/observability/tracing/skywalking/) -* [基于 Zipkin 实现全链路追踪](../../tasks/observability/tracing/zipkin/) -* [通过链路追踪关联日志系统](../../mannual/java-sdk/advanced-features-and-usage/observability/tracing#关联日志) +* [Implement Full Link Tracing with Skywalking](../../tasks/observability/tracing/skywalking/) +* [Implement Full Link Tracing with Zipkin](../../tasks/observability/tracing/zipkin/) +* [Associate Logs with Link Tracing](../../mannual/java-sdk/advanced-features-and-usage/observability/tracing#关联日志) ## Logging -访问日志可以帮助分析系统的流量情况,在有些场景下,开启访问日志对于排查问题也非常有帮助。 +Access logs can help analyze the system's traffic situation. In some scenarios, enabling access logs is also very helpful for troubleshooting issues. -* [开启 Access Log](../../mannual/java-sdk/advanced-features-and-usage/service/accesslog/) -* [你还在运行态开启 Access Log](../../tasks/traffic-management/accesslog/) +* [Enable Access Log](../../mannual/java-sdk/advanced-features-and-usage/service/accesslog/) +* [Enable Access Log at Runtime](../../tasks/traffic-management/accesslog/) diff --git a/content/en/overview/what/core-features/protocols.md b/content/en/overview/what/core-features/protocols.md index befc5b87b2c1..3c2632e97656 100644 --- a/content/en/overview/what/core-features/protocols.md +++ b/content/en/overview/what/core-features/protocols.md @@ -1,89 +1,89 @@ --- aliases: - - /zh/overview/core-features/protocols/ - - /zh-cn/overview/core-features/protocols/ -description: 通信协议 + - /en/overview/core-features/protocols/ + - /en/overview/core-features/protocols/ +description: Communication Protocols feature: description: | - 支持 HTTP/2、gRPC、TCP、REST 等任意通信协议,切换协议只需要修改一行配置,支持单个端口上的多协议发布。 - title: 通信协议 -linkTitle: 通信协议 -title: 通信协议 + Supports any communication protocol such as HTTP/2, gRPC, TCP, REST, etc. Switching protocols only requires modifying one line of configuration, and supports multi-protocol publishing on a single port. + title: Communication Protocols +linkTitle: Communication Protocols +title: Communication Protocols type: docs weight: 5 --- -Dubbo 框架提供了自定义的高性能 RPC 通信协议:基于 HTTP/2 的 Triple 协议 和 基于 TCP 的 Dubbo2 协议。除此之外,Dubbo 框架支持任意第三方通信协议,如官方支持的 gRPC、Thrift、REST、JsonRPC、Hessian2 等,更多协议可以通过自定义扩展实现。这对于微服务实践中经常要处理的多协议通信场景非常有用。 +The Dubbo framework provides a custom high-performance RPC communication protocol: the Triple protocol based on HTTP/2 and the Dubbo2 protocol based on TCP. In addition, the Dubbo framework supports any third-party communication protocol, such as the officially supported gRPC, Thrift, REST, JsonRPC, Hessian2, etc. More protocols can be implemented through custom extensions. This is very useful for multi-protocol communication scenarios often encountered in microservice practices. -**Dubbo 框架不绑定任何通信协议,在实现上 Dubbo 对多协议的支持也非常灵活,它可以让你在一个应用内发布多个使用不同协议的服务,并且支持用同一个 port 端口对外发布所有协议。** +**The Dubbo framework does not bind to any communication protocol. In implementation, Dubbo's support for multiple protocols is very flexible. It allows you to publish multiple services using different protocols within one application and supports publishing all protocols externally using the same port.** ![protocols](/imgs/v3/feature/protocols/protocol1.png) -通过 Dubbo 框架的多协议支持,你可以做到: -* 将任意通信协议无缝地接入 Dubbo 服务治理体系。Dubbo 体系下的所有通信协议,都可以享受到 Dubbo 的编程模型、服务发现、流量管控等优势。比如 gRPC over Dubbo 的模式,服务治理、编程 API 都能够零成本接入 Dubbo 体系。 -* 兼容不同技术栈,业务系统混合使用不同的服务框架、RPC 框架。比如有些服务使用 gRPC 或者 Spring Cloud 开发,有些服务使用 Dubbo 框架开发,通过 Dubbo 的多协议支持可以很好的实现互通。 -* 让协议迁移变的更简单。通过多协议、注册中心的协调,可以快速满足公司内协议迁移的需求。比如如从自研协议升级到 Dubbo 协议,Dubbo 协议自身升级,从 Dubbo 协议迁移到 gRPC,从 HTTP 迁移到 Dubbo 协议等。 +With Dubbo framework's multi-protocol support, you can: +* Seamlessly integrate any communication protocol into the Dubbo service governance system. All communication protocols under the Dubbo system can enjoy the advantages of Dubbo's programming model, service discovery, traffic control, etc. For example, in the gRPC over Dubbo mode, service governance and programming APIs can be integrated into the Dubbo system at zero cost. +* Be compatible with different technology stacks, mixing different service frameworks and RPC frameworks in business systems. For example, some services are developed using gRPC or Spring Cloud, while others are developed using the Dubbo framework. Dubbo's multi-protocol support can achieve good interoperability. +* Make protocol migration simpler. Through the coordination of multiple protocols and the registry, the company's protocol migration needs can be quickly met. For example, upgrading from a self-developed protocol to the Dubbo protocol, upgrading the Dubbo protocol itself, migrating from the Dubbo protocol to gRPC, or migrating from HTTP to the Dubbo protocol. ## HTTP/2 (Triple) -Triple 协议是 Dubbo3 发布的面向云原生时代的通信协议,它基于 HTTP/2 并且完全兼容 gRPC 协议,原生支持 Streaming 通信语义,Triple 可同时运行在 HTTP/1 和 HTTP/2 传输协议之上,让你可以直接使用 curl、浏览器访问后端 Dubbo 服务。 +The Triple protocol is a communication protocol released by Dubbo3 for the cloud-native era. It is based on HTTP/2 and fully compatible with the gRPC protocol, natively supporting Streaming communication semantics. Triple can run on both HTTP/1 and HTTP/2 transport protocols, allowing you to directly use curl and browsers to access backend Dubbo services. -自 Triple 协议开始,Dubbo 还支持基于 Protocol Buffers 的服务定义与数据传输,但 Triple 实现并不绑定 IDL,比如你可以直接使用 Java Interface 定义和发布 Triple 服务。Triple 具备更好的网关、代理穿透性,因此非常适合于跨网关、代理通信的部署架构,如服务网格等。 +Starting from the Triple protocol, Dubbo also supports service definition and data transmission based on Protocol Buffers, but the Triple implementation is not bound to IDL. For example, you can directly use Java Interface to define and publish Triple services. Triple has better gateway and proxy penetration, making it very suitable for deployment architectures involving cross-gateway and proxy communication, such as service meshes. -Triple 协议的核心特性如下: -* 支持 TLS 加密、Plaintext 明文数据传输 -* 支持反压与限流 -* 支持 Streaming 流式通信 -* 同时支持 HTTP/1 和 HTTP/2 传输协议 +The core features of the Triple protocol are as follows: +* Supports TLS encryption and Plaintext data transmission +* Supports backpressure and rate limiting +* Supports Streaming communication +* Supports both HTTP/1 and HTTP/2 transport protocols -在编程与通信模型上,Triple 协议支持如下模式: -* 消费端异步请求(Client Side Asynchronous Request-Response) -* 提供端异步执行(Server Side Asynchronous Request-Response) -* 消费端请求流(Request Streaming) -* 提供端响应流(Response Streaming) -* 双向流式通信(Bidirectional Streaming) +In terms of programming and communication models, the Triple protocol supports the following modes: +* Client Side Asynchronous Request-Response +* Server Side Asynchronous Request-Response +* Request Streaming +* Response Streaming +* Bidirectional Streaming -开发实践 -* Triple 协议使用请参见 [Triple 协议开发任务](../../tasks/protocols/triple/) 或 [java sdk 示例文档](../../mannual/java-sdk/reference-manual/protocol/triple/) -* [Triple 设计思路与协议规范](../../reference/protocols/triple/) +Development Practices +* For using the Triple protocol, refer to [Triple Protocol Development Tasks](../../tasks/protocols/triple/) or [Java SDK Example Documentation](../../mannual/java-sdk/reference-manual/protocol/triple/) +* [Triple Design Ideas and Protocol Specifications](../../reference/protocols/triple/) ## Dubbo2 -Dubbo2 协议是基于 TCP 传输层协议之上构建的一套 RPC 通信协议,由于其紧凑、灵活、高性能的特点,在 Dubbo2 时代取得了非常广泛的应用,是企业构建高性能、大规模微服务集群的关键通信方案。在云原生时代,我们更推荐使用通用性、穿透性更好的 Triple 协议。 +The Dubbo2 protocol is an RPC communication protocol built on top of the TCP transport layer protocol. Due to its compact, flexible, and high-performance characteristics, it has been widely used in the Dubbo2 era and is a key communication solution for building high-performance, large-scale microservice clusters in enterprises. In the cloud-native era, we recommend using the more general and penetrative Triple protocol. -Dubbo2 协议也内置 HTTP 支持,因此你可以使用 curl 在开发阶段快速验证或调试服务。 +The Dubbo2 protocol also has built-in HTTP support, so you can use curl to quickly verify or debug services during the development phase. -* [Dubbo2 协议开发任务](../../tasks/protocols/dubbo/) -* [Dubbo2 设计思路与协议规范](../../reference/protocols/tcp/) +* [Dubbo2 Protocol Development Tasks](../../tasks/protocols/dubbo/) +* [Dubbo2 Design Concepts and Protocol Specifications](../../reference/protocols/tcp/) ## gRPC -你可以用 Dubbo 开发和治理微服务,然后设置使用 gRPC 协议进行底层通信。但为什么要这么做呢,与直接使用 gRPC 框架对比有什么优势?简单的答案是,这是使用 gRPC 进行微服务开发的常用模式,具体请往下看。 +You can develop and manage microservices with Dubbo, then set up gRPC protocol for underlying communication. But why do this? What are the advantages compared to using the gRPC framework directly? The simple answer is that this is a common pattern for microservice development using gRPC. Read on for more details. -gRPC 是谷歌开源的基于 HTTP/2 的通信协议,如同我们在 [产品对比](../../what/xyz-difference) 文档中提到的,gRPC 的定位是通信协议与实现,是一款纯粹的 RPC 框架,而 Dubbo 定位是一款微服务框架,为微服务实践提供解决方案。因此,相比于 Dubbo,gRPC 相对欠缺了微服务编程模型、服务治理等能力的抽象。 +gRPC is an open-source communication protocol based on HTTP/2 by Google. As mentioned in our [Product Comparison](../../what/xyz-difference) document, gRPC is positioned as a communication protocol and implementation, a purely RPC framework, while Dubbo is positioned as a microservice framework providing solutions for microservice practices. Therefore, compared to Dubbo, gRPC relatively lacks abstractions for microservice programming models and service governance. -在 Dubbo 体系下使用 gRPC 协议 (gRPC over Dubbo Framework) 是一个非常高效和轻量的选择,它让你既能使用原生的 gRPC 协议通信,又避免了基于 gRPC 进行二次定制与开发的复杂度 (二次开发与定制 gRPC,是很多企业规模化实践后证实不可避免的环节,Dubbo 框架替开发者完成了这一步,让开发者可以直接以最简单的方式使用 gRPC)。 +Using the gRPC protocol within the Dubbo framework (gRPC over Dubbo Framework) is a highly efficient and lightweight choice. It allows you to use the native gRPC protocol for communication while avoiding the complexity of secondary customization and development based on gRPC (secondary development and customization of gRPC is an unavoidable step confirmed by many enterprises after large-scale practice. The Dubbo framework completes this step for developers, allowing them to use gRPC in the simplest way). -[gRPC over Dubbo 示例](../../tasks/protocols/grpc/) +[gRPC over Dubbo Example](../../tasks/protocols/grpc/) ## REST -微服务领域常用的一种通信模式是 HTTP + JSON,包括 Spring Cloud、Microprofile 等一些主流的微服务框架都默认使用的这种通信模式,Dubbo 同样提供了对基于 HTTP 的编程、通信模式的支持。 +A common communication pattern in the microservice field is HTTP + JSON. Some mainstream microservice frameworks like Spring Cloud and Microprofile default to this communication pattern. Dubbo also provides support for HTTP-based programming and communication patterns. -* [HTTP over Dubbo 示例](../../tasks/protocols/web/) -* [Dubbo 与 Spring Cloud 体系互通](../../tasks/protocols/springcloud/) +* [HTTP over Dubbo Example](../../tasks/protocols/web/) +* [Dubbo and Spring Cloud Interoperability](../../tasks/protocols/springcloud/) -## 其他通信协议 -除了以上介绍的几种协议之外,你还可以将以下协议运行在 Dubbo 之上。对 Dubbo 而言,只需要修改一行简单的配置,就可以切换底层服务的通信协议,其他外围 API 和治理能力不受影响。 +## Other Communication Protocols +In addition to the protocols introduced above, you can also run the following protocols on top of Dubbo. For Dubbo, you only need to change a simple configuration line to switch the underlying service communication protocol, without affecting other peripheral APIs and governance capabilities. * Hessian2 * Thrift * JsonRPC -## 异构微服务体系互通 -关于协议迁移、多协议技术栈共存的实践方案,请参考本篇[博客文章](/zh-cn/blog/2023/01/05/dubbo-连接异构微服务体系-多协议多注册中心/)。 +## Interoperability with Heterogeneous Microservice Systems +For practical solutions on protocol migration and coexistence of multiple protocol technology stacks, please refer to this [blog post](/en/blog/2023/01/05/dubbo-连接异构微服务体系-多协议多注册中心/). -## 配置方式 -以上协议的配置和使用方式,包括如何配置 `单端口多协议` 支持等,请参照以下 sdk 示例文档: +## Configuration Methods +For the configuration and usage methods of the above protocols, including how to configure `single-port multi-protocol` support, please refer to the following SDK example documents: * [Java](../../mannual/java-sdk/reference-manual/protocol/) * [Golang](../../mannual/golang-sdk/tutorial/develop/protocol/) * [Rust](../../mannual/rust-sdk/) -## 自定义扩展 -除了以上官方版本支持的通信协议,Dubbo 支持扩展新协议支持,具体请参见 [【任务】-【可扩展性】-【protocol】](../../tasks/extensibility/protocol/) +## Custom Extensions +In addition to the communication protocols supported by the official version above, Dubbo supports extending new protocol support. For details, please refer to [Tasks - Extensibility - Protocol](../../tasks/extensibility/protocol/) diff --git a/content/en/overview/what/core-features/security.md b/content/en/overview/what/core-features/security.md index cc133bf260de..d6b1345e589c 100644 --- a/content/en/overview/what/core-features/security.md +++ b/content/en/overview/what/core-features/security.md @@ -1,109 +1,108 @@ --- aliases: - - /zh/overview/core-features/security/ - - /zh-cn/overview/core-features/security/ -description: 认证鉴权 + - /en/overview/core-features/security/ + - /en/overview/core-features/security/ +description: Authentication and Authorization feature: description: | - 支持基于 TLS 的传输链路认证与加密通信以及基于请求身份的权限校验,帮助构建零信任分布式微服务体系。 - title: 认证鉴权 -linkTitle: 认证鉴权 -title: 认证鉴权 + Supports TLS-based transport link authentication and encrypted communication, as well as request identity-based permission verification, helping to build a zero-trust distributed microservice system. + title: Authentication and Authorization +linkTitle: Authentication and Authorization +title: Authentication and Authorization type: docs weight: 8 --- -Dubbo 提供了构建安全微服务通信体系 (零信任体系) 的完善机制,这包括: -* 避免通信过程中的中间人攻击,Dubbo 提供了身份认证 (Authentication) 和基于 TLS 的通信链路加密能力 -* 控制服务间的访问鉴权 (Authorization),Dubbo 提供了 mTLS 和权限检查机制 +Dubbo provides a comprehensive mechanism for building a secure microservice communication system (zero-trust system), which includes: +* Avoiding man-in-the-middle attacks during communication, Dubbo provides identity authentication and TLS-based communication link encryption capabilities. +* Controlling inter-service access authorization, Dubbo provides mTLS and permission check mechanisms. -通过这篇文档,你将了解如果使用 Dubbo 的安全机制构建微服务零信任体系,实现身份认证、透明链路加密、鉴权、审计等能力。由于构建零信任是一套系统的工作,而 Dubbo 只是其中数据通信层的一环,因此你可能需要一系列基础设施的配合,包括证书生成、分发、安全策略管控等。 +Through this document, you will learn how to use Dubbo's security mechanisms to build a zero-trust microservice system, achieving identity authentication, transparent link encryption, authorization, auditing, and other capabilities. Since building zero trust is a systematic task and Dubbo is only a part of the data communication layer, you may need a series of infrastructure support, including certificate generation, distribution, and security policy management. -> **证书的生成和分发不在本文讨论范围,我们假设您已经有完善的基础设施解决了证书管理问题,因此,我们将更专注在讲解 Dubbo 体系的认证和鉴权机制与流程。** 如果您并没有这些证书管理设施,我们推荐您使用服务网格架构 (具体请参见 [Dubbo Mesh 服务网格](../service-mesh/) 文档说明),借助 [Istio](https://istio.io/latest/docs/concepts/security/) 等服务网格控制面的证书管理机制和安全策略,您可以很容易将 Dubbo 集群的认证和鉴权能力实施起来。 +> **Certificate generation and distribution are not within the scope of this document. We assume you already have a complete infrastructure to solve the certificate management problem. Therefore, we will focus more on explaining Dubbo's authentication and authorization mechanisms and processes.** If you do not have these certificate management facilities, we recommend using a service mesh architecture (see [Dubbo Mesh Service Mesh](../service-mesh/) documentation for details). With the certificate management mechanism and security policies of the service mesh control plane like [Istio](https://istio.io/latest/docs/concepts/security/), you can easily implement the authentication and authorization capabilities of the Dubbo cluster. -> 另外,以下默认讲的都是 Dubbo Proxyless Mesh 模式下的 Dubbo 数据面行为,对于部署 Envoy 的场景,由于 Dubbo 只是作为通信和编程 sdk,因此 Envoy 场景下认证鉴权能力请完全参考标准 Istio 文档即可。 +> Additionally, the following defaults to the behavior of Dubbo data plane in Dubbo Proxyless Mesh mode. For scenarios deploying Envoy, since Dubbo is only used as a communication and programming SDK, please refer to the standard Istio documentation for authentication and authorization capabilities in Envoy scenarios. -## 架构 +## Architecture -一套完整的零信任体系包含多个组成部分: +A complete zero-trust system consists of multiple components: -* 一个根证书机构 (CA) 来负责管理 key 和 certificate -* 一个安全策略的管理和分发中心,来负责将安全策略实时下发给数据面组件: - * 认证策略 - * 鉴权策略 - * 安全命名信息 (Secure Naming Information) -* 数据面组件 (Dubbo) 负责识别和执行身份认证、加密、策略解析等动作 -* 一系列的工具和生态,配合完成安全审计、数据链路监控等工作 +* A root certificate authority (CA) responsible for managing keys and certificates. +* A security policy management and distribution center responsible for distributing security policies to data plane components in real-time: + * Authentication policies + * Authorization policies + * Secure Naming Information +* Data plane components (Dubbo) responsible for identifying and executing identity authentication, encryption, policy parsing, and other actions. +* A series of tools and ecosystems to assist in security auditing, data link monitoring, and other tasks. -在服务网格 (Istio) 部署模式下,控制面通常负责安全策略、证书等的管理,控制面负责与基础设施如 Kubernetes API Server 等交互,将配置数据下发给 Dubbo 或者 Envoy 等数据面组件。但如我们前面提到的,我们假设控制面产品已经就绪,因此不会涉及控制面如何签发证书、定义认证鉴权策略的讨论,我们将专注在 Dubbo 作为数据面的职责及与控制面的交互流程上。 +In the service mesh (Istio) deployment mode, the control plane usually manages security policies, certificates, etc. The control plane interacts with infrastructure such as the Kubernetes API Server and distributes configuration data to data plane components like Dubbo or Envoy. However, as mentioned earlier, we assume the control plane product is ready, so we will not discuss how the control plane issues certificates or defines authentication and authorization policies. We will focus on Dubbo's responsibilities as the data plane and its interaction process with the control plane. -以下是完整的 Dubbo 零信任架构图 +Below is a complete Dubbo zero-trust architecture diagram: ![Authentication](/imgs/v3/feature/security/arch.png) -## Authentication 认证 +## Authentication -Dubbo 提供了两种认证模式: +Dubbo provides two authentication modes: -* **传输通道认证 (Channel Authentication)**:Dubbo 支持基于 TLS 的 HTTP/2 和 TCP 通信,通过 Channel Authentication API 或者控制面认证策略可以开启 TLS,实现 Server 身份端认证以及数据链路加密。另外,还可以开启 mTLS 实现 Client、Server 双向认证。Channel Authentication 是 service-to-service 模式的认证,代表的是服务或实例的身份认证。 -* **请求认证 (Request Authentication)**:Dubbo 提供了 API 用来在用户请求上下文中放入代表用户身份的 credential (如 JSON Web Token),Dubbo 框架将自动识别请求中的身份信息并进行权限校验。另外,你也可以定制请求上下文中的身份,如放入 Access Token 的如 OAuth2 tokens。Request Authentication 是 end-user 模式的认证,代表登录系统的用户身份的认证。 +* **Channel Authentication**: Dubbo supports TLS-based HTTP/2 and TCP communication. By enabling TLS through the Channel Authentication API or control plane authentication policies, server identity authentication and data link encryption can be achieved. Additionally, mTLS can be enabled for mutual authentication between client and server. Channel Authentication is service-to-service authentication, representing the identity authentication of services or instances. +* **Request Authentication**: Dubbo provides an API to place credentials representing user identity (such as JSON Web Token) in the user request context. The Dubbo framework will automatically recognize the identity information in the request and perform permission verification. Additionally, you can customize the identity in the request context, such as placing OAuth2 tokens like Access Tokens. Request Authentication is end-user authentication, representing the identity authentication of users logged into the system. -### 架构图 +### Architecture Diagram -你可以使用 Istio 控制面管理证书、认证策略等,不同的认证策略会影响 Dubbo 数据面的认证行为,如是否开启 mTLS、是否允许迁移阶段的 Plaintext 请求等。 +You can use the Istio control plane to manage certificates, authentication policies, etc. Different authentication policies will affect the authentication behavior of the Dubbo data plane, such as whether to enable mTLS, whether to allow plaintext requests during the migration phase, etc. -在 Istio 模式下,Dubbo 认证机制通过 xDS 实现了和 Istio 控制面的自动对接,即 Istio 控制面生成的证书、认证策略配置会自动的下发到 Dubbo 数据面,Dubbo 数据面通过 Authentication API 接收配置并将它们应用到后续的所有数据通信环节,如启用新的证书、执行新的认证策略等。 +In Istio mode, Dubbo's authentication mechanism achieves automatic integration with the Istio control plane through xDS. The certificates and authentication policy configurations generated by the Istio control plane are automatically delivered to the Dubbo data plane. The Dubbo data plane receives these configurations via the Authentication API and applies them to all subsequent data communication processes, such as enabling new certificates and executing new authentication policies. -如果认证策略开启了 Request Authentication,则 Dubbo 数据面要负责 JWT token 的读取与填充,即 token 要在请求发起前附加到请求上下文中。Request Authentication 使用的前提一定是开启了 Channel Authentication,否则 Request Authentication 无法生效。 +If the authentication policy enables Request Authentication, the Dubbo data plane is responsible for reading and filling the JWT token, meaning the token must be attached to the request context before the request is initiated. The prerequisite for using Request Authentication is that Channel Authentication must be enabled; otherwise, Request Authentication will not take effect. ![Authentication](/imgs/v3/feature/security/auth-1.png) -#### Dubbo mTLS 流程 +#### Dubbo mTLS Process -在 Istio 部署架构下,可以通过控制面认证策略开启或关闭 Channel Authentication 的双向认证,双向认证的工作流程如下: +In the Istio deployment architecture, the control plane authentication policy can enable or disable the bidirectional authentication of Channel Authentication. The workflow for bidirectional authentication is as follows: -1. 通过 Istio 下发认证策略,开启双向认证 -2. Dubbo 客户端同服务端开启双向 TLS 握手,在此期间,Dubbo 客户端会做 secure naming check 以检查服务端的身份(它被证实是有运行这个服务的合法身份)。 -3. 客户端和服务端之间建立一条双向的 mTLS 链接,随后发起正常的加密通信。 -4. Dubbo 服务端收到请求后,识别客户端身份并检查其是否有权限访问响应的资源。 +1. The Istio control plane delivers the authentication policy to enable bidirectional authentication. +2. The Dubbo client and server initiate a bidirectional TLS handshake. During this period, the Dubbo client performs a secure naming check to verify the server's identity (it is confirmed to be the legitimate entity running the service). +3. A bidirectional mTLS link is established between the client and server, followed by normal encrypted communication. +4. Upon receiving a request, the Dubbo server identifies the client's identity and checks whether it has permission to access the corresponding resource. -### 认证策略 -具体请查看 Istio 官方支持的认证规则,Dubbo 完全支持 Istio 定义的认证策略。 +### Authentication Policies +For details, please refer to the authentication rules supported by Istio. Dubbo fully supports the authentication policies defined by Istio. https://istio.io/latest/docs/concepts/security/#authentication-policies -## Authorization 鉴权 +## Authorization -Dubbo 抽象了一套鉴权的扩展机制,但当前在具体实现上只支持 Istio 体系,因此其鉴权能力与 Istio 官方描述对等。具体可参见 -[Istio 鉴权文档](https://istio.io/latest/docs/concepts/security/#authorization) +Dubbo abstracts an extension mechanism for authorization, but currently, it only supports the Istio system in specific implementations. Therefore, its authorization capabilities are equivalent to those described by Istio. For more details, refer to the +[Istio Authorization Documentation](https://istio.io/latest/docs/concepts/security/#authorization) -### 架构图 +### Architecture Diagram -Dubbo 通过 xDS 与 Istio 控制面的数据通道,接收用户配置的鉴权策略,当一个请求到达 Dubbo 实例时,Dubbo SDK 使用内置的鉴权策略引擎将请求参数和用户身份与鉴权策略进行匹配,如果匹配成功则允许访问,否则拒绝访问。 +Dubbo receives user-configured authorization policies through the xDS data channel with the Istio control plane. When a request reaches a Dubbo instance, the Dubbo SDK uses the built-in authorization policy engine to match the request parameters and user identity with the authorization policies. If the match is successful, access is granted; otherwise, access is denied. ![Authorization](/imgs/v3/feature/security/authz-1.png) -Dubbo 完整的鉴权工作流程如下: +The complete authorization workflow in Dubbo is as follows: ![Authorization](/imgs/v3/feature/security/authz-2.png) -### 鉴权策略 -具体请查看 Istio 官方支持的鉴权规则,Dubbo 完全支持 Istio 定义的鉴权策略。 +### Authorization Policies +For details, please refer to the authorization rules supported by Istio. Dubbo fully supports the authorization policies defined by Istio. https://istio.io/latest/docs/concepts/security/#authorization-policies +## Dubbo Authentication API +Dubbo defines a set of authentication APIs. For regular usage scenarios, developers can enable TLS/mTLS communication through these APIs. However, for scenarios where the Istio control plane is deployed, Dubbo will automatically recognize the certificates and authentication policies delivered by the Istio control plane. Therefore, only interaction with the Istio control plane is required, and no special configuration is needed on the Dubbo side. -## Dubbo 认证 API -Dubbo 定义了一套认证 API,对于常规使用的场景,开发者可以通过这套 API 启用 TLS/mTLS 通信;但对于 Istio 控制面部署的场景,Dubbo 会自动识别 Istio 控制面下发的证书和认证策略,因此只需要与 Istio 控制面交互即可,不需要 Dubbo 侧的特别配置。 +Regardless of whether the Istio control plane is used, the JWT token for Request Authentication still needs to be programmatically specified on the Dubbo side. -不论是否使用 Istio 控制面,对于 Request Authentication,JWT token 仍需要在 Dubbo 侧编程指定。 - -每种语言实现的认证 API 定义略有差异,具体定义请参考各 SDK 文档: +The definition of the authentication API varies slightly for each language implementation. For specific definitions, please refer to the respective SDK documentation: * [Java](/) * [Go](/) * [Rust](/) * [Node.js](/) -## 示例任务 +## Example Tasks -访问如下 [Dubbo 任务示例](/) 进行安全策略动手实践。 +Visit the following [Dubbo Task Examples](/) for hands-on practice with security policies. diff --git a/content/en/overview/what/core-features/service-definition.md b/content/en/overview/what/core-features/service-definition.md index 907564b35f0e..bb535d2ecd11 100644 --- a/content/en/overview/what/core-features/service-definition.md +++ b/content/en/overview/what/core-features/service-definition.md @@ -1,32 +1,32 @@ --- aliases: - - /zh/overview/core-features/service-definition/ - - /zh-cn/overview/core-features/service-definition/ -description: 微服务开发 -linkTitle: 微服务开发 -title: 微服务开发 + - /en/overview/core-features/service-definition/ + - /en/overview/core-features/service-definition/ +description: Microservices Development +linkTitle: Microservices Development +title: Microservices Development type: docs weight: 1 --- -Dubbo 解决企业微服务从开发、部署到治理运维的一系列挑战,Dubbo 为开发者提供从项目创建、开发测试,到部署、可视化监测、流量治理,再到生态集成的全套服务。 -* **开发层面**,Dubbo 提供了 Java、Go、Rust、Node.js 等语言实现并定义了一套微服务开发范式,配套脚手架可用于快速创建微服务项目骨架 -* **部署层面**,Dubbo 应用支持虚拟机、Docker 容器、Kubernetes、服务网格架构部署 -* **服务治理层面**,Dubbo 提供了地址发现、负载均衡、流量管控等治理能力,官方还提供 Admin 可视化控制台、丰富的微服务生态集成 +Dubbo addresses a series of challenges from development, deployment to governance and operation of enterprise microservices. Dubbo provides developers with a full set of services from project creation, development testing, to deployment, visual monitoring, traffic governance, and ecosystem integration. +* **Development**: Dubbo offers implementations in Java, Go, Rust, Node.js, and defines a microservices development paradigm. The accompanying scaffolding can be used to quickly create microservice project skeletons. +* **Deployment**: Dubbo applications support deployment on virtual machines, Docker containers, Kubernetes, and service mesh architectures. +* **Service Governance**: Dubbo provides governance capabilities such as address discovery, load balancing, and traffic control. The official Admin visual console and rich microservice ecosystem integration are also provided. -## 开发 +## Development -接下来以 Java 体系 Spring Boot 项目为例讲解 Dubbo 应用开发的基本步骤,整个过程非常直观简单,其他语言开发过程类似。 +Next, we will explain the basic steps of Dubbo application development using a Java-based Spring Boot project as an example. The entire process is very intuitive and simple, and the development process for other languages is similar. -### 创建项目 -Dubbo 微服务项目脚手架(支持浏览器页面、命令行和 IDE)可用于快速创建微服务项目,只需要告诉脚手架期望包含的功能或组件,脚手架最终可以帮助开发者生成具有必要依赖的微服务工程。更多脚手架使用方式的讲解,请参见任务模块的 [通过模板生成项目脚手架](../../tasks/develop/template/) +### Create Project +Dubbo Microservice Project Scaffolding (supports browser pages, command line, and IDE) can be used to quickly create microservice projects. You only need to tell the scaffolding the desired features or components, and the scaffolding can help developers generate microservice projects with the necessary dependencies. For more explanations on how to use the scaffolding, please refer to the task module [Generate Project Scaffolding through Templates](../../tasks/develop/template/) -![脚手架示例图](/imgs/v3/advantages/initializer.png) +![Scaffolding Example](/imgs/v3/advantages/initializer.png) -### 开发服务 +### Develop Service -**1. 定义服务** +**1. Define Service** ```java public interface DemoService { @@ -34,7 +34,7 @@ public interface DemoService { } ``` -**2. 提供业务逻辑实现** +**2. Provide Business Logic Implementation** ```java @DubboService @@ -45,14 +45,14 @@ public class DemoServiceImpl implements DemoService { } ``` -### 发布服务 -**1. 发布服务定义** +### Publish Service +**1. Publish Service Definition** -为使消费方顺利调用服务,服务提供者首先要将服务定义以 Jar 包形式发布到 Maven 中央仓库。 +To ensure that the consumer can successfully call the service, the service provider must first publish the service definition to the Maven central repository in the form of a Jar package. -**2. 对外暴露服务** +**2. Expose Service** -补充 Dubbo 配置并启动 Dubbo Server +Supplement Dubbo configuration and start Dubbo Server ```yaml dubbo: @@ -65,9 +65,9 @@ dubbo: address: zookeeper://127.0.0.1:2181 ``` -### 调用服务 +### Call Service -首先,消费方通过 Maven/Gradle 引入 `DemoService` 服务定义依赖。 +First, the consumer introduces the `DemoService` service definition dependency through Maven/Gradle. ```xml @@ -77,7 +77,7 @@ dubbo: ``` -编程注入远程 Dubbo 服务实例 +Programmatically inject the remote Dubbo service instance ```java @Bean @@ -87,21 +87,21 @@ public class Consumer { } ``` -以上是 Dubbo 微服务开发的流程性说明,实际开发的详细指导步骤请参见: -* [Java 微服务开发入门](../../quickstart/java) -* [Go 微服务开发入门](../../quickstart/go) -* [Rust 微服务开发入门](../../quickstart/rust) -* [Node.js 微服务开发入门](https://github.com/apache/dubbo-js) +The above is a procedural explanation of Dubbo microservice development. For detailed guidance steps in actual development, please refer to: +* [Java Microservice Development Quick Start](../../quickstart/java) +* [Go Microservice Development Quick Start](../../quickstart/go) +* [Rust Microservice Development Quick Start](../../quickstart/rust) +* [Node.js Microservice Development Quick Start](https://github.com/apache/dubbo-js) -## 部署 -Dubbo 原生服务可打包部署到 Docker 容器、Kubernetes、服务网格 等云原生基础设施和微服务架构。 +## Deployment +Dubbo native services can be packaged and deployed to cloud-native infrastructures and microservice architectures such as Docker containers, Kubernetes, and service meshes. -关于不同环境的部署示例,可参考: -* [部署 Dubbo 服务到 Docker 容器](../../tasks/deploy/deploy-on-docker) -* [部署 Dubbo 服务到 Kubernetes](../../tasks/deploy/deploy-on-k8s-docker) +For deployment examples in different environments, refer to: +* [Deploy Dubbo Services to Docker Containers](../../tasks/deploy/deploy-on-docker) +* [Deploy Dubbo Services to Kubernetes](../../tasks/deploy/deploy-on-k8s-docker) -## 治理 -对于服务治理,绝大多数应用只需要增加以下配置即可,Dubbo 应用将具备地址发现和负载均衡能力。 +## Governance +For service governance, most applications only need to add the following configuration, and Dubbo applications will have address discovery and load balancing capabilities. ```yaml dubbo: @@ -109,21 +109,21 @@ dubbo: address: zookeeper://127.0.0.1:2181 ``` -部署并打开 [Dubbo Admin 控制台](../../tasks/deploy),可以看到集群的服务部署和调用数据 +Deploy and open the [Dubbo Admin Console](../../tasks/deploy), where you can see the service deployment and call data of the cluster. ![Admin](/imgs/v3/what/admin.png) -除此之外,Dubbo Amin 还可以通过以下能力提升研发测试效率 -* 文档管理,提供普通服务、IDL 文档管理 -* 服务测试 & 服务 Mock -* 服务状态查询 - -对于更复杂的微服务实践场景,Dubbo 还提供了更多高级服务治理特性,具体请参见文档了解更多。包括: -* 流量治理 -* 动态配置 -* 限流降级 -* 数据一致性 -* 可观测性 -* 多协议 -* 多注册中心 -* 服务网格 +In addition, Dubbo Admin can also improve R&D testing efficiency through the following capabilities: +* Documentation management, providing ordinary service and IDL documentation management +* Service testing & service mocking +* Service status query + +For more complex microservice practice scenarios, Dubbo also offers more advanced service governance features. Please refer to the documentation for more details, including: +* Traffic governance +* Dynamic configuration +* Rate limiting and degradation +* Data consistency +* Observability +* Multiple protocols +* Multiple registries +* Service mesh diff --git a/content/en/overview/what/core-features/service-discovery.md b/content/en/overview/what/core-features/service-discovery.md index c077de55e061..104dad36921c 100644 --- a/content/en/overview/what/core-features/service-discovery.md +++ b/content/en/overview/what/core-features/service-discovery.md @@ -1,73 +1,73 @@ --- aliases: - - /zh/overview/core-features/service-discovery/ - - /zh-cn/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/ - - /zh-cn/overview/core-features/service-discovery/ -description: 服务发现 + - /en/overview/core-features/service-discovery/ + - /en/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/ + - /en/overview/core-features/service-discovery/ +description: Service Discovery feature: description: | - Dubbo 提供了高性能、可伸缩的服务发现机制,面向百万集群实例规模设计,默认提供 Nacos、Zookeeper 等注册中心适配并支持自定义扩展。 - title: 服务发现 -linkTitle: 服务发现 -title: 服务发现 + Dubbo provides a high-performance, scalable service discovery mechanism designed for clusters with millions of instances. It offers default registry center adapters like Nacos and Zookeeper and supports custom extensions. + title: Service Discovery +linkTitle: Service Discovery +title: Service Discovery type: docs weight: 2 --- -Dubbo 提供的是一种 Client-Based 的服务发现机制,依赖第三方注册中心组件来协调服务发现过程,支持常用的注册中心如 Nacos、Consul、Zookeeper 等。 +Dubbo provides a Client-Based service discovery mechanism that relies on third-party registry center components to coordinate the service discovery process. It supports common registry centers such as Nacos, Consul, Zookeeper, etc. -以下是 Dubbo 服务发现机制的基本工作原理图: +Below is a basic working principle diagram of Dubbo's service discovery mechanism: ![service-discovery](/imgs/v3/feature/service-discovery/arc.png) -服务发现包含提供者、消费者和注册中心三个参与角色,其中,Dubbo 提供者实例注册 URL 地址到注册中心,注册中心负责对数据进行聚合,Dubbo 消费者从注册中心读取地址列表并订阅变更,每当地址列表发生变化,注册中心将最新的列表通知到所有订阅的消费者实例。 +Service discovery involves three roles: provider, consumer, and registry center. Dubbo provider instances register URL addresses to the registry center, which aggregates the data. Dubbo consumers read the address list from the registry center and subscribe to changes. Whenever the address list changes, the registry center notifies all subscribed consumer instances with the latest list. -## 面向百万实例集群的服务发现机制 -区别于其他很多微服务框架的是,**Dubbo3 的服务发现机制诞生于阿里巴巴超大规模微服务电商集群实践场景,因此,其在性能、可伸缩性、易用性等方面的表现大幅领先于业界大多数主流开源产品**。是企业面向未来构建可伸缩的微服务集群的最佳选择。 +## Service Discovery Mechanism for Million-Instance Clusters +Unlike many other microservice frameworks, **Dubbo3's service discovery mechanism was born out of Alibaba's large-scale microservice e-commerce cluster practice scenarios. Therefore, its performance, scalability, and ease of use are significantly ahead of most mainstream open-source products in the industry**. It is the best choice for enterprises to build scalable microservice clusters for the future. ![service-discovery](/imgs/v3/feature/service-discovery/arc2.png) -* 首先,Dubbo 注册中心以应用粒度聚合实例数据,消费者按消费需求精准订阅,避免了大多数开源框架如 Istio、Spring Cloud 等全量订阅带来的性能瓶颈。 -* 其次,Dubbo SDK 在实现上对消费端地址列表处理过程做了大量优化,地址通知增加了异步、缓存、bitmap 等多种解析优化,避免了地址更新常出现的消费端进程资源波动。 -* 最后,在功能丰富度和易用性上,服务发现除了同步 ip、port 等端点基本信息到消费者外,Dubbo 还将服务端的 RPC/HTTP 服务及其配置的元数据信息同步到消费端,这让消费者、提供者两端的更细粒度的协作成为可能,Dubbo 基于此机制提供了很多差异化的治理能力。 +* Firstly, the Dubbo registry center aggregates instance data at the application granularity, and consumers subscribe precisely according to their consumption needs, avoiding the performance bottlenecks caused by full subscriptions in most open-source frameworks like Istio, Spring Cloud, etc. +* Secondly, the Dubbo SDK has made numerous optimizations in the process of handling the address list on the consumer side. Address notifications have been optimized with asynchronous, caching, bitmap, and other parsing optimizations, avoiding resource fluctuations in the consumer process that often occur with address updates. +* Finally, in terms of functionality richness and ease of use, besides synchronizing basic endpoint information like ip and port to consumers, Dubbo also synchronizes the metadata information of RPC/HTTP services and their configurations from the server side to the consumer side. This enables more granular collaboration between consumers and providers, and Dubbo provides many differentiated governance capabilities based on this mechanism. -### 高效地址推送实现 +### Efficient Address Push Implementation -从注册中心视角来看,它负责以应用名 (dubbo.application.name) 对整个集群的实例地址进行聚合,每个对外提供服务的实例将自身的应用名、实例ip:port 地址信息 (通常还包含少量的实例元数据,如机器所在区域、环境等) 注册到注册中心。 +From the registry center's perspective, it aggregates instance addresses for the entire cluster by application name (dubbo.application.name). Each service-providing instance registers its application name, instance ip:port address information (usually with a small amount of instance metadata, such as the machine's region, environment, etc.) to the registry center. -> Dubbo2 版本注册中心以服务粒度聚合实例地址,比应用粒度更细,也就意味着传输的数据量更大,因此在大规模集群下也遇到一些性能问题。 -> 针对 Dubbo2 与 Dubbo3 跨版本数据模型不统一的问题,Dubbo3 给出了[平滑迁移方案](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery/),可做到模型变更对用户无感。 +> In Dubbo2, the registry center aggregates instance addresses at the service granularity, which is finer than the application granularity, meaning more data is transmitted. Therefore, some performance issues were encountered in large-scale clusters. +> To address the inconsistency between Dubbo2 and Dubbo3 cross-version data models, Dubbo3 provides a [smooth migration solution](/en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery/), ensuring that model changes are transparent to users. ![service-discovery](/imgs/v3/feature/service-discovery/registry-data.png)
-每个消费服务的实例从注册中心订阅实例地址列表,相比于一些产品直接将注册中心的全量数据 (应用 + 实例地址) 加载到本地进程,Dubbo 实现了按需精准订阅地址信息。比如一个消费者应用依赖 app1、app2,则只会订阅 app1、app2 的地址列表更新,大幅减轻了冗余数据推送和解析的负担。 +Each consumer service instance subscribes to the instance address list from the registry center. Compared to some products that directly load the full data (application + instance address) from the registry center into the local process, Dubbo implements precise address information subscription as needed. For example, if a consumer application depends on app1 and app2, it will only subscribe to address list updates for app1 and app2, significantly reducing the burden of redundant data push and parsing.


![service-discovery](/imgs/v3/feature/service-discovery/subscription2.png) -### 丰富元数据配置 -除了与注册中心的交互,Dubbo3 的完整地址发现过程还有一条额外的元数据通路,我们称之为元数据服务 (MetadataService),实例地址与元数据共同组成了消费者端有效的地址列表。 +### Rich Metadata Configuration +In addition to interacting with the registry center, Dubbo3's complete address discovery process has an additional metadata channel, which we call the MetadataService. Instance addresses and metadata together form the effective address list on the consumer side. ![service-discovery](/imgs/v3/feature/service-discovery/metadata.png) -完整工作流程如上图所示,首先,消费者从注册中心接收到地址 (ip:port) 信息,然后与提供者建立连接并通过元数据服务读取到对端的元数据配置信息,两部分信息共同组装成 Dubbo 消费端有效的面向服务的地址列表。以上两个步骤都是在实际的 RPC 服务调用发生之前。 +The complete workflow is shown in the figure above. First, the consumer receives the address (ip:port) information from the registry, then establishes a connection with the provider and reads the metadata configuration information of the peer through the metadata service. The two pieces of information are combined to form an effective service-oriented address list for the Dubbo consumer. These two steps occur before the actual RPC service call happens. -> 关于 MetadataService 的定义及完整服务发现流程分析,请查看 [应用级服务发现详解]({{< relref "../../../blog/proposals/service-discovery/" >}})。 +> For the definition of MetadataService and a complete analysis of the service discovery process, please refer to [Detailed Explanation of Application-Level Service Discovery]({{< relref "../../../blog/proposals/service-discovery/" >}}). -> 对于微服务间服务发现模型的数据同步,REST 定义了一套非常有意思的成熟度模型,感兴趣的朋友可以参考这里的链接 https://www.martinfowler.com/articles/richardsonMaturityModel.html, 按照文章中的 4 级成熟度定义,Dubbo 当前基于接口粒度的模型可以对应到最高的 L4 级别。 +> For data synchronization in the service discovery model between microservices, REST has defined a very interesting maturity model. Interested readers can refer to this link https://www.martinfowler.com/articles/richardsonMaturityModel.html. According to the 4-level maturity definition in the article, Dubbo's current interface-granularity model corresponds to the highest L4 level. -## 配置方式 -Dubbo 服务发现扩展了多种注册中心组件支持,如 Nacos、Zookeeper、Consul、Redis、kubernetes 等,可以通过配置切换不同实现,同时还支持鉴权、命名空间隔离等配置。具体配置方式请查看 SDK 文档 +## Configuration Method +Dubbo service discovery extends support for multiple registry components such as Nacos, Zookeeper, Consul, Redis, Kubernetes, etc. You can switch between different implementations through configuration, and it also supports configurations like authentication and namespace isolation. For specific configuration methods, please refer to the SDK documentation: * [Java](../../mannual/java-sdk/reference-manual/registry) * [Golang](../../mannual/golang-sdk/tutorial/develop/registry) * [Rust](../../mannual/rust-sdk/) -Dubbo 还支持一个应用内配置多注册中心的情形如双注册、双订阅等,这对于实现不同集群地址数据互通、集群迁移等场景非常有用处,我们将在未来文档中添加 `最佳实践` 对这部分内容进行示例说明。 +Dubbo also supports scenarios where multiple registries are configured within an application, such as dual registration and dual subscription. This is very useful for scenarios like intercommunication of different cluster addresses and cluster migration. We will add examples of `Best Practices` for this part in future documentation. -## 自定义扩展 -注册中心适配支持自定义扩展实现,具体请参见 [Dubbo 可扩展性](../extensibility) +## Custom Extension +Registry adaptation supports custom extension implementations. For details, please refer to [Dubbo Extensibility](../extensibility) diff --git a/content/en/overview/what/core-features/service-mesh.md b/content/en/overview/what/core-features/service-mesh.md index a122d05b81ee..b18ed8c5aa99 100644 --- a/content/en/overview/what/core-features/service-mesh.md +++ b/content/en/overview/what/core-features/service-mesh.md @@ -1,15 +1,15 @@ --- aliases: - - /zh/overview/core-features/service-mesh/ - - /zh-cn/overview/mannual/java-sdk/concepts-and-architecture/mesh/ - - /zh-cn/overview/core-features/service-mesh/ -description: 服务网格 + - /en/overview/core-features/service-mesh/ + - /en/overview/mannual/java-sdk/concepts-and-architecture/mesh/ + - /en/overview/core-features/service-mesh/ +description: Service Mesh feature: description: | - 灵活的数据面 (Proxy & Proxyless) 部署形态支持,无缝接入 Istio 控制面治理体系。 - title: 服务网格(Service Mesh) -linkTitle: 服务网格 -title: 服务网格 + Flexible data plane (Proxy & Proxyless) deployment forms support, seamlessly integrating with the Istio control plane governance system. + title: Service Mesh +linkTitle: Service Mesh +title: Service Mesh type: docs weight: 9 working-in-progress: true @@ -17,74 +17,75 @@ working-in-progress: true -Dubbo Mesh 是 Dubbo 在云原生背景的微服务整体解决方案,它帮助开发者实现 Dubbo 服务与标准的 Kubernetes Native Service 体系的打通,让 Dubbo 应用能够无缝接入 Istio 等业界主流服务网格产品。 +Dubbo Mesh is Dubbo's comprehensive microservice solution in the context of cloud-native, helping developers integrate Dubbo services with the standard Kubernetes Native Service system, allowing Dubbo applications to seamlessly integrate with mainstream service mesh products like Istio. -以下是 Dubbo Mesh 的部署架构图 +Below is the deployment architecture diagram of Dubbo Mesh ![Dubbo-Mesh](/imgs/v3/mesh/mix-mesh.png) -* 控制面。Istio 作为统一控制面,为集群提供 Kubernetes 适配、服务发现、证书管理、可观测性、流量治理等能力。 -* 数据面。Dubbo 应用实例作为数据面组件,支持两种部署模式 - * Proxy 模式。Dubbo 进程与 Envoy 部署在同一 pod,进出 Dubbo 的流量都经 Envoy 代理拦截,由 Envoy 执行流量管控。 - * Proxyless 模式。Dubbo 进程独立部署,进程间直接通信,通过 xDS 协议与控制面直接交互。 +* Control Plane. Istio serves as the unified control plane, providing capabilities such as Kubernetes adaptation, service discovery, certificate management, observability, and traffic governance for the cluster. +* Data Plane. Dubbo application instances act as data plane components, supporting two deployment modes: + * Proxy Mode. The Dubbo process and Envoy are deployed in the same pod, with all traffic to and from Dubbo intercepted by the Envoy proxy, which performs traffic control. + * Proxyless Mode. The Dubbo process is deployed independently, with direct communication between processes, interacting directly with the control plane via the xDS protocol. -关于服务网格架构以及为何要接入 Istio 控制面,请参考 [Istio 官网](https://istio.io/),本文不包含这部分通用内容的讲解,而是会侧重在 Dubbo Mesh 解决方案本身。 +For more information on service mesh architecture and why to integrate with the Istio control plane, please refer to the [Istio official website](https://istio.io/). This document does not cover these general topics but focuses on the Dubbo Mesh solution itself. ## Dubbo Mesh ### Proxy Mesh -在 proxy 模式下,Dubbo 与 Envoy 等边车 (Proxy or Sidecar) 部署在一起 +In proxy mode, Dubbo is deployed together with Envoy and other sidecars (Proxy or Sidecar). ![dubbo-sidecar](/imgs/v3/mesh/dubbo-proxy.png) -以上是 Dubbo Proxy Mesh 部署架构图 -* Dubbo 与 Envoy 部署在同一个 Pod 中,Istio 实现对流量和治理的统一管控。 -* Dubbo 只提供面向业务应用的编程 API、RPC 通信能力,其余流量管控能力如地址发现、负载均衡、路由寻址等都下沉到 Envoy,Envoy 拦截所有进出流量并完成路由寻址等服务治理工作。 -* 控制面与 Envoy 之间通过图中虚线所示的 xDS 协议进行配置分发。 +Above is the deployment architecture diagram of Dubbo Proxy Mesh +* Dubbo and Envoy are deployed in the same Pod, with Istio achieving unified traffic and governance control. +* Dubbo only provides business application programming APIs and RPC communication capabilities, while other traffic control capabilities such as address discovery, load balancing, and routing are offloaded to Envoy. Envoy intercepts all incoming and outgoing traffic and performs routing and other service governance tasks. +* Configuration distribution between the control plane and Envoy is done via the xDS protocol, as shown by the dashed lines in the diagram. -在 Proxy 模式下,Dubbo3 通信层选用 Triple、gRPC、REST 等基于 HTTP 的通信协议可以获得更好的网关穿透性与性能体验。 +In Proxy mode, using HTTP-based communication protocols like Triple, gRPC, and REST in Dubbo3 can achieve better gateway penetration and performance experience. ### Proxyless Mesh -在 Proxyless 模式下,没有 Envoy 等代理组件,Dubbo 进程保持独立部署并直接通信,Istio 控制面通过 xDS 与 Dubbo 进程进行治理能力交互。 +In Proxyless mode, there are no proxy components like Envoy. The Dubbo process remains independently deployed and communicates directly, with the Istio control plane interacting with the Dubbo process for governance capabilities via the xDS protocol. ![dubbo-proxyless](/imgs/v3/mesh/dubbo-proxyless.png) -Proxyless 模式下 Dubbo 部署与服务网格之前基本一致,通过不同语言版本的 Dubbo3 SDK 直接实现 xDS 协议解析 +In Proxyless mode, Dubbo deployment remains largely consistent with the previous service mesh, directly implementing xDS protocol parsing through different language versions of the Dubbo3 SDK. -#### 为什么需要 Proxyless Mesh +#### Why Proxyless Mesh is Needed -Proxy 模式很好的实现了治理能力与有很多优势,如平滑升级、多语言、业务侵入小等,但也带来了一些额外的问题,比如: -* Sidecar 通信带来了额外的性能损耗,这在复杂拓扑的网络调用中将变得尤其明显。 -* Sidecar 的存在让应用的声明周期管理变得更加复杂。 -* 部署环境受限,并不是所有的环境都能满足 Sidecar 部署与请求拦截要求。 +Proxy mode effectively achieves governance capabilities and has many advantages, such as smooth upgrades, multi-language support, and minimal business intrusion. However, it also brings some additional issues, such as: +* Sidecar communication introduces additional performance overhead, which becomes particularly evident in complex network call topologies. +* The presence of sidecars complicates the lifecycle management of applications. +* Deployment environments are limited, and not all environments can meet the requirements for sidecar deployment and request interception. -在 Proxyless 模式下,Dubbo 进程之间继续保持直连通信模式: -* 没有额外的 Proxy 中转损耗,因此更适用于性能敏感应用 -* 更有利于遗留系统的平滑迁移 -* 架构简单,容易运维部署 -* 适用于几乎所有的部署环境 +In Proxyless mode, Dubbo processes continue to maintain direct communication: +* No additional proxy relay overhead, making it more suitable for performance-sensitive applications. +* More conducive to smooth migration of legacy systems. +* Simple architecture, easy to operate and deploy. +* Suitable for almost all deployment environments. -## 示例任务 -了解了足够多的原理知识,我们推荐你访问如下 [示例](../../tasks/mesh) 进行动手实践。 +## Example Tasks +Having understood enough theoretical knowledge, we recommend you visit the following [examples](../../tasks/mesh) for hands-on practice. -## 可视化 -推荐使用 [Dubbo Admin](../../tasks/deploy) 作为您 Dubbo 集群的可视化控制台,它兼容所有 Kubernetes、Mesh 和非 Mesh 架构的部署。 +## Visualization +We recommend using [Dubbo Admin](../../tasks/deploy) as the visual control console for your Dubbo cluster. It is compatible with all Kubernetes, Mesh, and non-Mesh architecture deployments. -除此之外,你也可以使用 [Istio 官方推荐的可视化工具](https://istio.io/latest/docs/tasks/observability/kiali/) 来管理您的 Dubbo Mesh 集群。 -## 接入非 Istio 控制面 -Dubbo Mesh 本身并不绑定任何控制面产品实现,你可以使用 Istio、Linkerd、Kuma 或者任一支持 xDS 协议的控制面产品,对于 Sidecar 亦是如此。 +In addition, you can use the [officially recommended visualization tool by Istio](https://istio.io/latest/docs/tasks/observability/kiali/) to manage your Dubbo Mesh cluster. -如果你已经完整的体验了 [基于 Istio 的 Dubbo Mesh](/) 示例任务,并且发现 Istio 很好的满足了你的 Dubbo Mesh 治理诉求,那么采用 Istio 作为你的控制面是首选的解决方案。 +## Integrating with Non-Istio Control Planes +Dubbo Mesh itself does not bind to any specific control plane product implementation. You can use Istio, Linkerd, Kuma, or any control plane product that supports the xDS protocol, and the same applies to Sidecar. -如果你发现 Istio 模式下 Dubbo 部分能力受限,而这部分能力正好是你需要的,那么你需要考虑接入 Dubbo 控制面,用 Dubbo 控制面来替代 Istio,以获得更多 Dubbo 体系原生能力支持、更好的性能体验。具体请参见 [基于 Dubbo 定制控制面的 Dubbo Mesh 示例任务](/)。 +If you have fully experienced the [Dubbo Mesh based on Istio](/) example task and found that Istio meets your Dubbo Mesh governance needs well, then adopting Istio as your control plane is the preferred solution. -> 简单来讲,这是 Dubbo 社区发布的一款基于 Istio 的定制版本控制面,Dubbo 控制面安装与能力差异请参见上面的示例任务链接。 +If you find that some Dubbo capabilities are limited under the Istio mode, and these capabilities are exactly what you need, then you need to consider integrating the Dubbo control plane. Use the Dubbo control plane to replace Istio to gain more native Dubbo system capabilities and better performance experience. For details, please refer to the [Dubbo Mesh example task based on the Dubbo custom control plane](/). -## 老系统迁移方案 -### 如何解决注册中心数据同步的问题? +> In short, this is a custom version control plane based on Istio released by the Dubbo community. For differences in Dubbo control plane installation and capabilities, please refer to the example task link above. + +## Migration Plan for Legacy Systems +### How to solve the problem of registry data synchronization? Address Synchronization -### 如何解决 Dubbo2 协议通信的问题? +### How to solve the problem of Dubbo2 protocol communication? Aeraki Mesh diff --git a/content/en/overview/what/core-features/traffic/_index.md b/content/en/overview/what/core-features/traffic/_index.md index a0c241b679ce..9b2b3fcfeb79 100755 --- a/content/en/overview/what/core-features/traffic/_index.md +++ b/content/en/overview/what/core-features/traffic/_index.md @@ -1,65 +1,65 @@ --- aliases: - - /zh/overview/core-features/traffic/ - - /zh-cn/overview/core-features/traffic/ -description: 流量管控 + - /en/overview/core-features/traffic/ + - /en/overview/core-features/traffic/ +description: Traffic Control feature: description: | - Dubbo 提供的基于路由规则的流量管控策略,可以帮助实现全链路灰度、金丝雀发布、按比例流量转发、动态调整调试时间、设置重试次数等服务治理能力。 - title: 流量管控 -linkTitle: 流量管控 + Dubbo provides traffic control strategies based on routing rules, which can help achieve full-link grayscale, canary release, proportional traffic forwarding, dynamic adjustment of debugging time, setting retry times, and other service governance capabilities. + title: Traffic Control +linkTitle: Traffic Control no_list: true -title: 流量管控 +title: Traffic Control type: docs weight: 4 --- -Dubbo 提供了丰富的流量管控策略 -* **地址发现与负载均衡**,地址发现支持服务实例动态上下线,负载均衡确保流量均匀的分布到每个实例上。 -* **基于路由规则的流量管控**,路由规则对每次请求进行条件匹配,并将符合条件的请求路由到特定的地址子集。 +Dubbo provides rich traffic control strategies +* **Address Discovery and Load Balancing**: Address discovery supports dynamic online and offline service instances, and load balancing ensures that traffic is evenly distributed to each instance. +* **Traffic Control Based on Routing Rules**: Routing rules perform conditional matching for each request and route requests that meet the conditions to a specific subset of addresses. -服务发现保证调用方看到最新的提供方实例地址,服务发现机制依赖注册中心 (Zookeeper、Nacos、Istio 等) 实现。在消费端,Dubbo 提供了多种负载均衡策略,如随机负载均衡策略、一致性哈希负载、基于权重的轮询、最小活跃度优先、P2C 等。 +Service discovery ensures that the caller sees the latest provider instance addresses. The service discovery mechanism relies on the registry (Zookeeper, Nacos, Istio, etc.). On the consumer side, Dubbo provides various load balancing strategies, such as random load balancing, consistent hash load balancing, weight-based round-robin, least active priority, P2C, etc. -Dubbo 的流量管控规则可以基于应用、服务、方法、参数等粒度精准的控制流量走向,根据请求的目标服务、方法以及请求体中的其他附加参数进行匹配,符合匹配条件的流量会进一步的按照特定规则转发到一个地址子集。流量管控规则有以下几种: -* 条件路由规则 -* 标签路由规则 -* 脚本路由规则 -* 动态配置规则 +Dubbo's traffic control rules can precisely control traffic direction based on the granularity of applications, services, methods, parameters, etc. They match the target service, method, and other additional parameters in the request body. Traffic that meets the matching conditions will be further forwarded to a subset of addresses according to specific rules. The traffic control rules include: +* Conditional Routing Rules +* Tag Routing Rules +* Script Routing Rules +* Dynamic Configuration Rules -如果底层用的是基于 HTTP 的 RPC 协议 (如 REST、gRPC、Triple 等),则服务和方法等就统一映射为 HTTP 路径 (path),此时 Dubbo 路由规则相当于是基于 HTTP path 和 headers 的流量分发机制。 +If the underlying RPC protocol is based on HTTP (such as REST, gRPC, Triple, etc.), then services and methods are uniformly mapped to HTTP paths. In this case, Dubbo routing rules are equivalent to traffic distribution mechanisms based on HTTP paths and headers. -> Dubbo 中有应用、服务和方法的概念,一个应用可以发布多个服务,一个服务包含多个可被调用的方法,从抽象的视角来看,一次 Dubbo 调用就是某个消费方应用发起了对某个提供方应用内的某个服务特定方法的调用,Dubbo 的流量管控规则可以基于应用、服务、方法、参数等粒度精准的控制流量走向。 +> In Dubbo, there are concepts of applications, services, and methods. An application can publish multiple services, and a service contains multiple callable methods. From an abstract perspective, a Dubbo call is an invocation of a specific method of a service within a provider application initiated by a consumer application. Dubbo's traffic control rules can precisely control traffic direction based on the granularity of applications, services, methods, parameters, etc. -## 工作原理 +## Working Principle -以下是 Dubbo 单个路由器的工作过程,路由器接收一个服务的实例地址集合作为输入,基于请求上下文 (Request Context) 和 (Router Rule) 实际的路由规则定义对输入地址进行匹配,所有匹配成功的实例组成一个地址子集,最终地址子集作为输出结果继续交给下一个路由器或者负载均衡组件处理。 +The following is the working process of a single router in Dubbo. The router receives a set of instance addresses of a service as input, matches the input addresses based on the request context and the actual routing rule definitions. All successfully matched instances form a subset of addresses, and the final subset of addresses is handed over to the next router or load balancing component for processing. ![Router](/imgs/v3/feature/traffic/router1.png) -通常,在 Dubbo 中,多个路由器组成一条路由链共同协作,前一个路由器的输出作为另一个路由器的输入,经过层层路由规则筛选后,最终生成有效的地址集合。 -* Dubbo 中的每个服务都有一条完全独立的路由链,每个服务的路由链组成可能不同,处理的规则各异,各个服务间互不影响。 -* 对单条路由链而言,即使每次输入的地址集合相同,根据每次请求上下文的不同,生成的地址子集结果也可能不同。 +Typically, in Dubbo, multiple routers form a routing chain that works together. The output of the previous router serves as the input for another router. After layer-by-layer routing rule filtering, an effective address set is finally generated. +* Each service in Dubbo has a completely independent routing chain. The composition of the routing chain for each service may differ, and the rules processed vary, with no mutual influence between services. +* For a single routing chain, even if the input address set is the same each time, the resulting subset of addresses may differ based on the different request contexts each time. ![Router](/imgs/v3/feature/traffic/router2.png) -## 路由规则分类 -### 标签路由规则 +## Classification of Routing Rules +### Tag Routing Rules -标签路由通过将某一个服务的实例划分到不同的分组,约束具有特定标签的流量只能在指定分组中流转,不同分组为不同的流量场景服务,从而实现流量隔离的目的。标签路由可以作为蓝绿发布、灰度发布等场景能力的基础。 +Tag routing divides instances of a service into different groups, constraining traffic with specific tags to flow only within designated groups. Different groups serve different traffic scenarios, achieving traffic isolation. Tag routing can serve as the foundation for scenarios like blue-green deployment and grayscale release. -标签路由规则是一个非此即彼的流量隔离方案,也就是匹配`标签`的请求会 100% 转发到有相同`标签`的实例,没有匹配`标签`的请求会 100% 转发到其余未匹配的实例。如果您需要按比例的流量调度方案,请参考示例 [基于权重的按比例流量路由](../../tasks/traffic-management/weight/)。 +Tag routing rules are an either-or traffic isolation solution, meaning requests that match the `tag` will be 100% forwarded to instances with the same `tag`, and requests that do not match the `tag` will be 100% forwarded to the remaining unmatched instances. If you need a proportional traffic scheduling solution, please refer to the example [Proportional Traffic Routing Based on Weight](../../tasks/traffic-management/weight/). -`标签`主要是指对 Provider 端应用实例的分组,目前有两种方式可以完成实例分组,分别是`动态规则打标`和`静态规则打标`。`动态规则打标` 可以在运行时动态的圈住一组机器实例,而 `静态规则打标` 则需要实例重启后才能生效,其中,动态规则相较于静态规则优先级更高,而当两种规则同时存在且出现冲突时,将以动态规则为准。 +`Tags` mainly refer to the grouping of provider application instances. Currently, there are two ways to complete instance grouping: `dynamic rule tagging` and `static rule tagging`. `Dynamic rule tagging` can dynamically enclose a group of machine instances at runtime, while `static rule tagging` requires instance restart to take effect. Among them, dynamic rules have higher priority than static rules, and when both rules exist and conflict, dynamic rules will prevail. -#### 标签规则示例 - 静态打标 +#### Tag Rule Example - Static Tagging -静态打标需要在服务提供者实例启动前确定,并且必须通过特定的参数 `tag` 指定。 +Static tagging needs to be determined before the service provider instance starts and must be specified through a specific parameter `tag`. ##### Provider -在 Dubbo 实例启动前,指定当前实例的标签,如部署在杭州区域的实例,指定 `tag=gray`。 +Before the Dubbo instance starts, specify the tag for the current instance, such as specifying `tag=gray` for instances deployed in the Hangzhou region. ```xml @@ -79,19 +79,19 @@ java -jar xxx-provider.jar -Ddubbo.provider.tag=gray ##### Consumer -发起调用的一方,在每次请求前通过 `tag` 设置流量标签,确保流量被调度到带有同样标签的服务提供方。 +The party initiating the call sets the traffic tag via `tag` before each request to ensure that the traffic is routed to the service provider with the same tag. ```java RpcContext.getContext().setAttachment(Constants.TAG_KEY, "gray"); ``` -#### 标签规则示例 - 动态打标 +#### Tag Rule Example - Dynamic Tagging -相比于静态打标只能通过 `tag` 属性设置,且在启动阶段就已经固定下来,动态标签可以匹配任意多个属性,根据指定的匹配条件将 Provider 实例动态的划分到不同的流量分组中。 +Compared to static tagging, which can only be set via the `tag` attribute and is fixed at startup, dynamic tags can match any number of attributes and dynamically divide Provider instances into different traffic groups based on specified matching conditions. ##### Provider -以下规则对 `shop-detail` 应用进行了动态归组,匹配 `env: gray` 的实例被划分到 `gray` 分组,其余不匹配 `env: gray` 继续留在默认分组 (无 tag)。 +The following rule dynamically groups the `shop-detail` application, with instances matching `env: gray` being grouped into the `gray` group, while others that do not match `env: gray` remain in the default group (no tag). ```yaml configVersion: v3.0 @@ -106,43 +106,42 @@ tags: exact: gray ``` -> 这里牵涉到如何给您的实例打各种原始 label 的问题,即上面示例中的 `env`,一种方式是直接写在配置文件中,如上面静态规则实例 provider 部分的配置所示,另一种方式是通过预设环境变量指定,关于这点请参考下文的 [如何给实例打标](#如何给实例打标) 一节。 +> This involves how to label your instances with various raw labels, such as `env` in the example above. One way is to write it directly in the configuration file, as shown in the provider section of the static rule example above. Another way is to specify it through preset environment variables. For more details, please refer to the section [How to Label Instances](#如何给实例打标) below. ##### Consumer -服务发起方的设置方式和之前静态打标规则保持一致,只需要在每次请求前通过 `tag` 设置流量标签,确保流量被调度到带有同样标签的服务提供方。 +The settings for the service initiator are consistent with the previous static tagging rules. You only need to set the traffic tag via `tag` before each request to ensure that the traffic is routed to the service provider with the same tag. ```java RpcContext.getContext().setAttachment(Constants.TAG_KEY, "Hangzhou"); ``` -设置了以上标签的流量,将全部导流到 `hangzhou-region` 划分的实例上。 +Traffic with the above tag will be routed to instances divided into the `hangzhou-region`. -> 请求标签的作用域仅为一次点对点的 RPC 请求。比如,在一个 A -> B -> C 调用链路上,如果 A -> B 调用通过 `setAttachment` 设置了 `tag` 参数,则该参数不会在 B -> C 的调用中生效,同样的,在完成了 A -> B -> C 的整个调用同时 A 收到调用结果后,如果想要相同的 `tag` 参数,则在发起其他调用前仍需要单独设置 `setAttachment`。可以参考 [示例任务 - 环境隔离](../../tasks/traffic-management/isolation/) 了解更多 `tag` 全链路传递解决方案。 +> The scope of the request tag is limited to a single point-to-point RPC request. For example, in an A -> B -> C call chain, if the A -> B call sets the `tag` parameter via `setAttachment`, this parameter will not be effective in the B -> C call. Similarly, after completing the entire A -> B -> C call and A receives the result, if you want the same `tag` parameter, you still need to set `setAttachment` separately before initiating another call. You can refer to [Example Task - Environment Isolation](../../tasks/traffic-management/isolation/) for more information on the full-link transmission solution of `tag`. -### 条件路由规则 +### Conditional Routing Rules -条件路由与标签路由的工作模式非常相似,也是首先对请求中的参数进行匹配,符合匹配条件的请求将被转发到包含特定实例地址列表的子集。相比于标签路由,条件路由的匹配方式更灵活: +Conditional routing works similarly to tag routing, where the parameters in the request are matched first, and requests that meet the matching conditions are forwarded to a subset of specific instance addresses. Compared to tag routing, conditional routing is more flexible in its matching method: -* 在标签路由中,一旦给某一台或几台机器实例打了标签,则这部分实例就会被立马从通用流量集合中移除,不同标签之间不会再有交集。有点类似下图,地址集合在输入阶段就已经划分明确。 +* In tag routing, once a tag is assigned to one or more machine instances, those instances are immediately removed from the general traffic pool, and there is no overlap between different tags. It's somewhat like the diagram below, where the address set is clearly divided at the input stage. ![tag-condition-compare](/imgs/v3/feature/traffic/tag-condition-compare1.png) -* 而从条件路由的视角,所有的实例都是一致的,路由过程中不存在分组隔离的问题,每次路由过滤都是基于全量地址中执行 +* From the perspective of conditional routing, all instances are consistent, and there is no grouping isolation during the routing process. Each routing filter is executed based on the full address set. ![tag-condition-compare](/imgs/v3/feature/traffic/tag-condition-compare2.png) -条件路由规则的主体 `conditions` 主要包含两部分内容: +The main content of the conditional routing rule `conditions` includes two parts: -* => 之前的为请求参数匹配条件,指定的 `匹配条件指定的参数` 将与 `消费者的请求上下文 (URL)、甚至方法参数` 进行对比,当消费者满足匹配条件时,对该消费者执行后面的地址子集过滤规则。 -* => 之后的为地址子集过滤条件,指定的 `过滤条件指定的参数` 将与 `提供者实例地址 (URL)` 进行对比,消费者最终只能拿到符合过滤条件的实例列表,从而确保流量只会发送到符合条件的地址子集。 - * 如果匹配条件为空,表示对所有请求生效,如:`=> status != staging` - * 如果过滤条件为空,表示禁止来自相应请求的访问,如:`application = product =>` +* The part before `=>` is the request parameter matching condition. The `matching condition specified parameter` will be compared with the `consumer's request context (URL) or even method parameters`. When the consumer meets the matching condition, the address subset filtering rule after `=>` will be executed for that consumer. +* The part after `=>` is the address subset filtering condition. The `filtering condition specified parameter` will be compared with the `provider instance address (URL)`. The consumer will ultimately get a list of instances that meet the filtering conditions, ensuring that traffic is only sent to the address subset that meets the conditions. + * If the matching condition is empty, it applies to all requests, such as: `=> status != staging` + * If the filtering condition is empty, it means access from the corresponding request is prohibited, such as: `application = product =>` +#### Conditional Routing Rule Example -#### 条件路由规则示例 - -基于以下示例规则,所有 `org.apache.dubbo.demo.CommentService` 服务调用都将被转发到与当前消费端机器具有相同 `region` 标记的地址子集。`$region` 是特殊引用符号,执行过程中将读取消费端机器的实际的 `region` 值替代。 +Based on the following example rule, all `org.apache.dubbo.demo.CommentService` service calls will be forwarded to the address subset with the same `region` tag as the current consumer machine. `$region` is a special reference symbol that will be replaced with the actual `region` value of the consumer machine during execution. ```yaml configVersion: v3.0 @@ -153,29 +152,29 @@ conditions: - '=> region = $region' ``` -> 针对条件路由,我们通常推荐配置 `scope: service` 的规则,因为它可以跨消费端应用对所有消费特定服务 (service) 的应用生效。关于 Dubbo 规则中的 `scope` 以及 `service`、`application` 的说明请阅读 [条件路由规则手册](./condition-rule)。 +> For conditional routing, we usually recommend configuring rules with `scope: service` because it can take effect across consumer applications for all applications consuming a specific service. For more information on `scope` and `service`, `application` in Dubbo rules, please read the [Conditional Routing Rule Manual](./condition-rule). -条件路由规则还支持设置具体的机器地址如 ip 或 port,这种情况下使用条件路由可以处理一些开发或线上机器的临时状况,实现**黑名单、白名单、实例临时摘除**等运维效果,如以下规则可以将机器 `172.22.3.91` 从服务的可用列表中排除。 +Conditional routing rules also support setting specific machine addresses such as IP or port. In this case, conditional routing can handle some temporary situations for development or online machines, achieving operational effects such as **blacklist, whitelist, temporary removal of instances**, etc. For example, the following rule can exclude the machine `172.22.3.91` from the available list of services. ```yaml => host != 172.22.3.91 ``` -条件路由还支持基于请求参数的匹配,示例如下: +Conditional routing also supports matching based on request parameters, as shown in the following example: ```yaml conditions: - method=getDetail&arguments[0]=dubbo => port=20880 ``` -### 动态配置规则 -通过 Dubbo 提供的动态配置规则,您可以动态的修改 Dubbo 服务进程的运行时行为,整个过程不需要重启,配置参数实时生效。基于这个强大的功能,基本上所有运行期参数都可以动态调整,比如超时时间、临时开启 Access Log、修改 Tracing 采样率、调整限流降级参数、负载均衡、线程池配置、日志等级、给机器实例动态打标签等。与上文讲到的流量管控规则类似,动态配置规则支持应用、服务两个粒度,也就是说您一次可以选择只调整应用中的某一个或几个服务的参数配置。 +### Dynamic Configuration Rules +Through the dynamic configuration rules provided by Dubbo, you can dynamically modify the runtime behavior of Dubbo service processes without restarting, and the configuration parameters take effect in real-time. Based on this powerful feature, almost all runtime parameters can be dynamically adjusted, such as timeout settings, temporarily enabling Access Log, modifying Tracing sampling rate, adjusting rate limiting and degradation parameters, load balancing, thread pool configuration, log levels, dynamically tagging machine instances, etc. Similar to the traffic control rules mentioned above, dynamic configuration rules support two granularities: application and service, meaning you can choose to adjust the parameter configuration of only one or several services in the application at a time. -当然,出于系统稳定性、安全性的考量,有些特定的参数是不允许动态修改的,但除此之外,基本上所有参数都允许动态修改,很多强大的运行态能力都可以通过这个规则实现,您可以找个示例应用去尝试一下。通常 URL 地址中的参数均可以修改,这在每个语言实现的参考手册里也记录了一些更详细的说明。 +Of course, for the sake of system stability and security, some specific parameters are not allowed to be dynamically modified. But other than that, almost all parameters can be dynamically modified, and many powerful runtime capabilities can be achieved through this rule. You can try it out with a sample application. Usually, the parameters in the URL address can be modified, which is also recorded in more detail in the reference manuals for each language implementation. -#### 动态配置规则示例 - 修改超时时间 +#### Dynamic Configuration Rule Example - Modify Timeout -以下示例将 `org.apache.dubbo.samples.UserService` 服务的超时参数调整为 2000ms +The following example adjusts the timeout parameter of the `org.apache.dubbo.samples.UserService` service to 2000ms ```yaml configVersion: v3.0 @@ -188,24 +187,24 @@ configs: timeout: 2000 ``` -以下部分指定这个配置是服务粒度,具体变更的服务名为 `org.apache.dubbo.samples.UserService`。`scope` 支持 `service`、`application` 两个可选值,如果 `scope: service`,则 `key` 应该配置为 `version/service:group` 格式。 +The following section specifies that this configuration is at the service granularity, and the specific service name to be changed is `org.apache.dubbo.samples.UserService`. `scope` supports two optional values: `service` and `application`. If `scope: service`, then `key` should be configured in the format `version/service:group`. ```yaml scope: service key: org.apache.dubbo.samples.UserService ``` -> 关于 Dubbo 规则中的 `scope` 以及 `service`、`application` 的说明请参考 [动态配置参考手册](./configuration-rule/) 或 [动态配置示例](../../tasks/traffic-management/timeout/)。 +> For more information on `scope` and `service`, `application` in Dubbo rules, please refer to the [Dynamic Configuration Reference Manual](./configuration-rule/) or [Dynamic Configuration Example](../../tasks/traffic-management/timeout/). -`parameters` 参数指定了新的修改值,这里将通过 `timeout: 2000` 将超时时间设置为 2000ms。 +The `parameters` parameter specifies the new modification value, here setting the timeout to 2000ms through `timeout: 2000`. ```yaml parameters: timeout: 2000 ``` -### 脚本路由规则 -脚本路由是最直观的路由方式,同时它也是当前最灵活的路由规则,因为你可以在脚本中定义任意的地址筛选规则。如果我们为某个服务定义一条脚本规则,则后续所有请求都会先执行一遍这个脚本,脚本过滤出来的地址即为请求允许发送到的、有效的地址集合。 +### Script Routing Rules +Script routing is the most intuitive routing method, and it is also the most flexible routing rule currently because you can define any address filtering rules in the script. If we define a script rule for a service, all subsequent requests will first execute this script, and the addresses filtered out by the script will be the set of valid addresses to which the request is allowed to be sent. ```yaml configVersion: v3.0 @@ -224,11 +223,11 @@ script: | } (invokers, invocation, context)); // 表示立即执行方法 ``` -## 如何给实例打标 +## How to Tag Instances -当前,有两种方式可以在启动阶段为 Dubbo 实例指定标签,一种是之前提到的应用内配置的方式,如在 xml 文件中设置 ``,应用打包部署后即自动被打标。 +Currently, there are two ways to specify tags for Dubbo instances at the startup stage. One is the method mentioned earlier, configuring within the application, such as setting `` in the XML file. The application will be automatically tagged after packaging and deployment. -还有一种更灵活的方式,那就是通过读取所部署机器上的环境信息给应用打标,这样应用的标签就可以跟随实例动态的自动填充,避免每次更换部署环境就重新打包应用镜像的问题。当前 Dubbo 能自动读取以下环境变量配置: +Another more flexible way is to tag the application by reading the environment information on the deployed machine. This way, the application's tags can dynamically and automatically populate with the instance, avoiding the need to repackage the application image every time the deployment environment changes. Currently, Dubbo can automatically read the following environment variable configurations: ```yaml spec: @@ -254,22 +253,22 @@ spec: value: "gray" ``` -如果您有不同的实例环境保存机制,可以通过扩展 `InfraAdapter 扩展点` 来自定义自己的标签加载方式。如果您的应用是部署在 Kubernetes 环境下,并且已经接入了服务网格体系,则也可以使用标准 deployment 标签的方式打标,具体请跟随 [服务网格任务示例](../../tasks/mesh/) 学习。 +If you have a different instance environment storage mechanism, you can customize your own tag loading method by extending the `InfraAdapter extension point`. If your application is deployed in a Kubernetes environment and has integrated with the service mesh system, you can also use the standard deployment tag method for tagging. For details, please follow the [Service Mesh Task Example](../../tasks/mesh/). -## 如何配置流量规则 -Dubbo 提供了控制台 Dubbo Admin,帮助您可视化的下发流量管控规则,并实时监控规则生效情况。 +## How to Configure Traffic Rules +Dubbo provides a console called Dubbo Admin to help you visualize and issue traffic control rules, and monitor the effectiveness of the rules in real-time. ![Admin](/imgs/v3/what/admin.png) -Dubbo 还提供了 `dubboctl` 命令行工具,需要有 Dubbo Admin 提前部署就绪,因为 dubboctl 是通过与 Admin 进行 http 通信完成规则下发的。 +Dubbo also provides the `dubboctl` command-line tool, which requires Dubbo Admin to be pre-deployed and ready, as dubboctl issues rules through HTTP communication with Admin. -如果您使用的是如 Istio 的服务网格架构,还可以使用 Istioctl、kubectl 等下发 Istio 标准规则。 +If you are using a service mesh architecture like Istio, you can also use Istioctl, kubectl, etc., to issue Istio standard rules. -## 接入服务网格 +## Integrating with Service Mesh -以上介绍的都是 Dubbo 体系内的流量治理规则,如果您对服务网格架构感兴趣,则可以将 Dubbo 服务接入服务网格体系,这样,您就可以使用服务网格提供的流量治理能力,如 Istio 体系的 VirtualService 等。 +The above introduces traffic governance rules within the Dubbo system. If you are interested in service mesh architecture, you can integrate Dubbo services into the service mesh system. This way, you can use the traffic governance capabilities provided by the service mesh, such as Istio's VirtualService. -具体请参见 [Dubbo 中的服务网格架构](../service-mesh)。 +For details, please refer to [Service Mesh Architecture in Dubbo](../service-mesh). -## 跟随示例学习 -我们搭建了一个 [线上商城系统](../../tasks/traffic-management/) 供您学习流量规则的具体使用。 +## Learn by Example +We have set up an [online shopping system](../../tasks/traffic-management/) for you to learn the specific usage of traffic rules. diff --git a/content/en/overview/what/core-features/traffic/circuit-breaking.md b/content/en/overview/what/core-features/traffic/circuit-breaking.md index 24d0af733f62..a3fd27c6dcb0 100644 --- a/content/en/overview/what/core-features/traffic/circuit-breaking.md +++ b/content/en/overview/what/core-features/traffic/circuit-breaking.md @@ -1,43 +1,44 @@ --- aliases: - - /zh-cn/overview/core-features/traffic/circuit-breaking/ + - /en/overview/core-features/traffic/circuit-breaking/ description: "" -linkTitle: 限流 & 熔断 -title: 限流 & 熔断 +linkTitle: Rate Limiting & Circuit Breaking +title: Rate Limiting & Circuit Breaking type: docs weight: 5 --- -由于微服务分布式的特点,如何构建稳定的微服务集群是一个很大的挑战,其中有两项非常关键的点值得关注 -* 流量控制 (Rate Limiting) -* 熔断降级 (Circuit Breaking) +Due to the distributed nature of microservices, building a stable microservice cluster is a significant challenge. Two critical points to focus on are: +* Rate Limiting +* Circuit Breaking -## 流量控制 -**流量控制更多的是站在 Dubbo 服务提供者视角来保证服务稳定性**,通过明确的为 Dubbo 服务设置请求上限阈值,确保服务所处理的请求数始终在一个合理范围之内,从而确保系统整体的稳定性。 +## Rate Limiting +**Rate limiting is more about ensuring service stability from the perspective of Dubbo service providers**. By explicitly setting request upper thresholds for Dubbo services, it ensures that the number of requests handled by the service is always within a reasonable range, thereby ensuring the overall stability of the system. ![provider-rate-limit](/imgs/v3/feature/circuit-breaking/provider-rate-limit.png) -根据服务的具体部署情况,服务所能处理的流量上限是一定的,当对服务的请求数量保持在合理的范围时,系统运行正常;而当请求数量严重超过服务处理能力时,如大促期间的流量洪峰等场景,就可能造成服务提供者端的资源过度消耗、负载过高,进而出现响应延迟、请求无应答、系统假死等情况。 +Depending on the specific deployment of the service, the upper limit of traffic that the service can handle is fixed. When the number of requests to the service remains within a reasonable range, the system operates normally. However, when the number of requests severely exceeds the service's handling capacity, such as during traffic peaks in promotional periods, it may cause excessive resource consumption, high load on the service provider side, leading to response delays, unanswered requests, and system hang-ups. -流量控制解决的问题和工作方式比较容易理解,而其使用的难点就是如何确定服务所能处理的流量最大值? -* 一种模式是由用户预先设定一个固定的限流值,如 Dubbo 通过集成 Sentinel 等产品实现的限流能力即是这种模式 - * [Dubbo Sentinel 流量控制](../../../tasks/rate-limit/sentinel/) -* 另一种方式是 Dubbo 框架自动根据系统或集群负载情况执行限流,相比用户预先设置限流值更加灵活方便,Dubbo 目前内置了自适应限流模式,具体可参见: - * [Java 自适应限流使用方式](../../../mannual/java-sdk/advanced-features-and-usage/performance/adaptive-concurrency-control/) - * [Go 自适应限流使用方式](../../../reference/proposals/heuristic-flow-control/) - * [自适应限流设计原理](../../../reference/proposals/heuristic-flow-control/) +The problem solved by rate limiting and its working mechanism are relatively easy to understand. The difficulty lies in determining the maximum traffic that the service can handle. +* One mode is for the user to preset a fixed rate limit value. For example, Dubbo achieves rate limiting capabilities by integrating products like Sentinel. + * [Dubbo Sentinel Rate Limiting](../../../tasks/rate-limit/sentinel/) +* Another way is for the Dubbo framework to automatically perform rate limiting based on system or cluster load conditions. This is more flexible and convenient compared to the user presetting the rate limit value. Dubbo currently has a built-in adaptive rate limiting mode. For details, see: + * [Java Adaptive Rate Limiting Usage](../../../mannual/java-sdk/advanced-features-and-usage/performance/adaptive-concurrency-control/) + * [Go Adaptive Rate Limiting Usage](../../../reference/proposals/heuristic-flow-control/) + * [Adaptive Rate Limiting Design Principles](../../../reference/proposals/heuristic-flow-control/) -## 熔断降级 -**熔断降级则是更多的从 Dubbo 服务消费者视角来保障系统稳定性的重要手段**。一个服务往往需要调用更多的下游 Dubbo 服务来完成业务逻辑,这时下游服务的稳定性就会影响当前服务甚至整个系统的稳定性,熔断(Circuit Breaking)即是面向不稳定服务场景设计的,它能最大限度避免下游服务不稳定对上游服务带来的影响。 +## Circuit Breaking +**Circuit breaking is a crucial means to ensure system stability from the perspective of Dubbo service consumers**. A service often needs to call more downstream Dubbo services to complete business logic. At this time, the stability of downstream services will affect the current service and even the stability of the entire system. Circuit breaking is designed for unstable service scenarios. It can minimize the impact of unstable downstream services on upstream services. -而相比于熔断后直接返回调用失败信息,配合服务降级能力,我们可以继续调用预先设置好的服务降级逻辑,以降级逻辑的结果作为最终调用结果,以更优雅的返回给服务调用方。 +Compared to directly returning a call failure message after circuit breaking, with service degradation capabilities, we can continue to call the pre-set service degradation logic and use the result of the degradation logic as the final call result, returning it more gracefully to the service caller. ![consumer-circuit-breaking](/imgs/v3/feature/circuit-breaking/consumer-circuit-breaking.png) -如上图所示,Dubbo Consumer 依赖的下游的三个 Dubbo 服务,当 Service 3 出现不稳定的情况时(如响应时间变长、错误率增加等),从而 Consumer 调用 Service 3 的线程等资源就会产生堆积,如果此时我们不在 Consumer 侧做任何限制,则 Service 1 与 Service 2 的调用都会受到稳定性影响。通过熔断 Service 3 我们就能保证整个 Dubbo Consumer 服务的稳定性,不拖垮整个 Consumer 服务,熔断 Service 3 的方式可以有很多种实现,包括线程数、信号量、错误率等。 +As shown in the figure above, Dubbo Consumer relies on three downstream Dubbo services. When Service 3 becomes unstable (e.g., response time increases, error rate rises), the threads and resources calling Service 3 from the Consumer will accumulate. If we do not impose any restrictions on the Consumer side at this time, the calls to Service 1 and Service 2 will also be affected in terms of stability. By circuit breaking Service 3, we can ensure the stability of the entire Dubbo Consumer service, preventing it from dragging down the entire Consumer service. There are many ways to implement circuit breaking for Service 3, including thread count, semaphore, error rate, etc. -Dubbo 通过集成业界主流的框架实现了服务熔断降级能力 +Dubbo has achieved service circuit breaking and degradation capabilities by integrating mainstream frameworks in the industry. * [Sentinel](../../../tasks/rate-limit/sentinel/) * [Hystrix](../../../tasks/rate-limit/hystrix/) * [Resilience4J](../../../tasks/rate-limit/resilience4j/) + diff --git a/content/en/overview/what/core-features/traffic/condition-rule.md b/content/en/overview/what/core-features/traffic/condition-rule.md index 5c9898444a6e..22c580df26a0 100644 --- a/content/en/overview/what/core-features/traffic/condition-rule.md +++ b/content/en/overview/what/core-features/traffic/condition-rule.md @@ -1,22 +1,20 @@ --- aliases: - - /zh/overview/core-features/traffic/condition-rule/ - - /zh-cn/overview/core-features/traffic/condition-rule/ + - /en/overview/core-features/traffic/condition-rule/ + - /en/overview/core-features/traffic/condition-rule/ description: "" -linkTitle: 条件路由 -title: 条件路由规则 +linkTitle: Condition Routing +title: Condition Routing Rules type: docs weight: 1 --- +Condition routing rules forward requests that meet specific conditions to a subset of specific address instances. The rules first match the request parameters that initiate the traffic, and requests that meet the matching conditions will be forwarded to a subset containing a specific list of instance addresses. +Below is an example of a condition routing rule. -条件路由规则将符合特定条件的请求转发到特定的地址实例子集上。规则首先对发起流量的请求参数进行匹配,符合匹配条件的请求将被转发到包含特定实例地址列表的子集。 - -以下是一个条件路由规则示例。 - -基于以下示例规则,所有 `org.apache.dubbo.samples.CommentService` 服务 `getComment` 方法的调用都将被转发到有 `region=Hangzhou` 标记的地址子集。 +Based on the following example rule, all calls to the `getComment` method of the `org.apache.dubbo.samples.CommentService` service will be forwarded to the subset of addresses marked with `region=Hangzhou`. ```yaml configVersion: v3.0 @@ -29,51 +27,51 @@ weight: 1 - method=getComment => region=Hangzhou ``` -可以看具体的例子代码: [条件路由](https://github.com/apache/dubbo-samples/tree/master/4-governance/dubbo-samples-configconditionrouter/src/main/java/org/apache/dubbo/samples/governance) +You can see the specific example code: [Condition Routing](https://github.com/apache/dubbo-samples/tree/master/4-governance/dubbo-samples-configconditionrouter/src/main/java/org/apache/dubbo/samples/governance) ## ConditionRule -条件路由规则主体。定义路由规则生效的目标服务或应用、流量过滤条件以及一些特定场景下的行为。 +The main body of the condition routing rule. Defines the target service or application where the routing rule takes effect, traffic filtering conditions, and behaviors in some specific scenarios. -| 字段名 | 类型 | **描述** | 必填 | +| Field Name | Type | **Description** | Required | | --- | --- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ---- | -| configVersion | string | 条件路由的版本,当前版本为 `v3.0` | 是 | -| scope | string | 支持 `service` 和 `application` 两种规则 | 是 | -| key | string | 应用到的目标服务或应用程序的标识符

- 当 `scope:service` 时, `key`应该是该规则生效的服务名比如 org.apache.dubbo.samples.CommentService
- 当 `scope:application` 时, then `key`应该是该规则应该生效的应用名称,比如说my-dubbo-service. | 是 | -| enabled | bool | 规则是否生效 当 `enabled:false` 时,规则不生效 | 是 | -| conditions | string[] | 配置中定义的条件规则,详情可以看[条件规则](https://cn.dubbo.apache.org/zh-cn/overview/core-features/traffic/condition-rule/#condition) | 是 | -| force | bool | T路由后实例子集为空时的行为。 `true` 则抛出一个No Provider Exception。 `false` 则忽略规则,直接去请求其他的实例。默认值是false | 否 | -| runtime | bool | 是否为每个 rpc 调用运行路由规则或使用路由缓存(如果可用)。默认值是false(false则走缓存,true不走缓存) | 否 | +| configVersion | string | The version of the condition routing, the current version is `v3.0` | Yes | +| scope | string | Supports two rules: `service` and `application` | Yes | +| key | string | Identifier of the target service or application to which it applies

- When `scope:service`, `key` should be the service name where the rule takes effect, such as org.apache.dubbo.samples.CommentService
- When `scope:application`, then `key` should be the application name where the rule should take effect, such as my-dubbo-service. | Yes | +| enabled | bool | Whether the rule is effective. When `enabled:false`, the rule is not effective | Yes | +| conditions | string[] | Condition rules defined in the configuration, see [Condition Rules](https://cn.dubbo.apache.org/zh-cn/overview/core-features/traffic/condition-rule/#condition) for details | Yes | +| force | bool | Behavior when the subset of instances after routing is empty. `true` throws a No Provider Exception. `false` ignores the rule and directly requests other instances. The default value is false | No | +| runtime | bool | Whether to run the routing rule for each RPC call or use the routing cache (if available). The default value is false (false uses the cache, true does not use the cache) | No | ## Condition -`Condition` 为条件路由规则的主体,类型为一个复合结构的 string 字符串,如 `method=getComment => region=Hangzhou`。其中, +`Condition` is the main body of the conditional routing rule, which is a composite string type, such as `method=getComment => region=Hangzhou`. Among them, -* => 之前的为请求参数匹配条件,指定的 `匹配条件指定的参数` 将与 `消费者的请求上下文 (URL)、甚至方法参数` 进行对比,当消费者满足匹配条件时,对该消费者执行后面的地址子集过滤规则。 -* => 之后的为地址子集过滤条件,指定的 `过滤条件指定的参数` 将与 `提供者实例地址 (URL)` 进行对比,消费者最终只能拿到符合过滤条件的实例列表,从而确保流量只会发送到符合条件的地址子集。 - * 如果匹配条件为空,表示对所有请求生效,如:`=> status != staging` - * 如果过滤条件为空,表示禁止来自相应请求的访问,如:`application = product =>` +* The part before `=>` is the request parameter matching condition. The `parameters specified in the matching condition` will be compared with the `consumer's request context (URL), and even method parameters`. When the consumer meets the matching condition, the address subset filtering rule after `=>` will be executed for that consumer. +* The part after `=>` is the address subset filtering condition. The `parameters specified in the filtering condition` will be compared with the `provider instance address (URL)`. The consumer will ultimately only get the list of instances that meet the filtering condition, ensuring that traffic is only sent to the address subset that meets the condition. + * If the matching condition is empty, it means it applies to all requests, such as: `=> status != staging` + * If the filtering condition is empty, it means access from the corresponding request is prohibited, such as: `application = product =>` -### 匹配/过滤条件 +### Matching/Filtering Conditions -**参数支持** +**Parameter Support** -* 服务调用上下文,如:interface, method, group, version 等 -* 请求上下文,如 attachments[key] = value -* 方法参数,如 arguments[0] = tom -* URL 本身的字段,如:protocol, host, port 等 -* URL 上任务扩展参数,如:application, organization 等 -* 支持开发者自定义扩展 +* Service invocation context, such as: interface, method, group, version, etc. +* Request context, such as attachments[key] = value +* Method parameters, such as arguments[0] = tom +* Fields of the URL itself, such as: protocol, host, port, etc. +* Extended parameters on the URL, such as: application, organization, etc. +* Support for developer-defined extensions -**条件支持** +**Condition Support** -* 等号 = 表示 "匹配",如:method = getComment -* 不等号 != 表示 "不匹配",如:method != getComment +* Equal sign = means "match", such as: method = getComment +* Not equal sign != means "not match", such as: method != getComment -**值支持** +**Value Support** -* 以逗号 , 分隔多个值,如:host != 10.20.153.10,10.20.153.11 -* 以星号 * 结尾,表示通配,如:host != 10.20.* -* 以美元符 $ 开头,表示引用消费者参数,如:region = $region -* 整数值范围,如:userId = 1~100、userId = 101~ -* 支持开发者自定义扩展 +* Multiple values separated by commas `,`, such as: host != 10.20.153.10,10.20.153.11 +* Ends with an asterisk `*`, indicating a wildcard, such as: host != 10.20.* +* Starts with a dollar sign `$`, indicating a reference to a consumer parameter, such as: region = $region +* Integer value ranges, such as: userId = 1~100, userId = 101~ +* Support for developer-defined extensions diff --git a/content/en/overview/what/core-features/traffic/configuration-rule.md b/content/en/overview/what/core-features/traffic/configuration-rule.md index 0eec2d23e523..23dce49a0320 100644 --- a/content/en/overview/what/core-features/traffic/configuration-rule.md +++ b/content/en/overview/what/core-features/traffic/configuration-rule.md @@ -1,23 +1,23 @@ --- aliases: - - /zh/overview/core-features/traffic/configuration-rule/ - - /zh-cn/overview/core-features/traffic/configuration-rule/ + - /en/overview/core-features/traffic/configuration-rule/ + - /en/overview/core-features/traffic/configuration-rule/ description: "" -linkTitle: 动态配置 -title: 动态配置规则 +linkTitle: Dynamic Configuration +title: Configuration Rule type: docs weight: 4 --- -动态配置规则 (ConfigurationRule) 是 Dubbo 设计的在无需重启应用的情况下,动态调整 RPC 调用行为的一种能力,也称为动态覆盖规则,因为它是通过在运行态覆盖 Dubbo 实例或者 Dubbo 实例中 URL 地址的各种参数值,实现改变 RPC 调用行为的能力。 +Configuration Rule (ConfigurationRule) is a capability designed by Dubbo to dynamically adjust RPC call behavior without restarting the application. It is also known as a dynamic override rule because it changes RPC call behavior by overriding various parameter values of Dubbo instances or URLs within Dubbo instances at runtime. -使用动态配置规则,有以下几条关键信息值得注意: -* **设置规则生效过滤条件。** 配置规则支持一系列的过滤条件,用来限定规则只对符合特定条件的服务、应用或实例才生效。 -* **设置规则生效范围。** 一个 rpc 服务有服务发起方(消费者)和服务处理方(提供者)两个角色,对某一个服务定义的规则,可以具体到限制是对消费者还是提供者生效。 -* **选择规则管理粒度。** Dubbo 支持从服务和应用两个粒度来管理和下发规则。 +When using configuration rules, there are several key points to note: +* **Set rule effective filter conditions.** Configuration rules support a series of filter conditions to limit the rules to only apply to services, applications, or instances that meet specific conditions. +* **Set rule effective scope.** An RPC service has two roles: the service initiator (consumer) and the service handler (provider). Rules defined for a service can be specifically limited to take effect on either the consumer or the provider. +* **Choose rule management granularity.** Dubbo supports managing and issuing rules from both service and application granularities. -以下一个应用级别的配置示例,配置生效后,`shop-detail` 应用下提供的所有服务都将启用 accesslog,对 `shop-detail` 部署的所有实例生效。 +The following is an application-level configuration example. After the configuration takes effect, all services provided under the `shop-detail` application will enable accesslog, and it will take effect on all instances deployed under `shop-detail`. ```yaml configVersion: v3.0 @@ -29,7 +29,7 @@ configs: accesslog: 'true' ``` -以下是一个服务级别的配置示例,`key: org.apache.dubbo.samples.UserService` 和 `side: consumer` 说明这条配置对所有正在消费 UserService 的 Dubbo 实例生效,在调用失败后都执行 4 次重试。`match` 条件进一步限制了消费端的范围,限定为只对应用名为 `shop-frontend` 的这个消费端应用生效。 +The following is a service-level configuration example. `key: org.apache.dubbo.samples.UserService` and `side: consumer` indicate that this configuration applies to all Dubbo instances consuming UserService, executing 4 retries after a call failure. The `match` condition further restricts the scope of the consumer to only the consumer application named `shop-frontend`. ```yaml configVersion: v3.0 @@ -45,42 +45,42 @@ configs: retries: '4' ``` ## ConfigurationRule -配置规则主体,定义要设置的目标服务或应用、具体的规则配置。具体配置规则 (configs) 可以设置多条。 +The main body of the configuration rule, defining the target service or application to be set and the specific rule configuration. Multiple specific configuration rules (configs) can be set. | Field | Type | Description | Required | | --- | --- | --- | --- | | configVersion | string | The version of the configuration rule definition, currently available version is `v3.0` | Yes | | scope | string | Supports `service` and `application` scope configurations. | Yes | | key | string | The identifier of the target service or application that this rule is about to apply to.

- If `scope:service`is set, then `key`should be specified as the Dubbo service key that this rule targets to control.
- If `scope:application` is set, then `key`should be specified as the name of the application that this rule targets to control.| Yes | -| enabled | bool | Whether enable this rule or not, set `enabled:false` to disable this rule. | Yes | +| enabled | bool | Whether to enable this rule or not, set `enabled:false` to disable this rule. | Yes | | configs | Config[] | The `match condition` and `configuration` of this rule. | Yes | ## Config -具体的规则配置定义,包含生效端 (consumer 或 provider) 和过滤条件。 +The specific rule configuration definition, including the effective side (consumer or provider) and filter conditions. | Field | Type | Description | Required | | --- | --- | --- | --- | | side | string | Especially useful when `scope:service`is set.

- `side: provider`means this Config will only take effect on the provider instances of the service key.
- `side:consumer`means this Config will only take effect on the consumer instances of the service key| Yes | | parameters | map | The keys and values this rule aims to change. | Yes | -| match | MatchCondition | A set of criterion to be met in order for the rule/config to be applied to the Dubbo instance. | No | -| enabled | bool | Whether enable this Config or not, will use the value in ConfigurationRule if not set | No | +| match | MatchCondition | A set of criteria to be met in order for the rule/config to be applied to the Dubbo instance. | No | +| enabled | bool | Whether to enable this Config or not, will use the value in ConfigurationRule if not set | No | | ~~addresses~~ | ~~string[]~~ | ~~replaced with address in MatchCondition~~ | ~~No~~ | | ~~providerAddresses~~ | ~~string[]~~ | ~~not supported anymore~~ | ~~No~~ | | ~~services~~ | ~~string[]~~ | ~~replaced with service in MatchCondition~~ | ~~No~~ | | ~~applications~~ | ~~string[]~~ | ~~replaced with application in MatchCondition~~ | ~~No~~ | ## MatchCondition -过滤条件,用来设置规则对哪个服务 (service)、应用 (application)、实例 (address),或者包含哪些参数 (param) 的实例生效。 +Filter conditions used to set rules for which service, application, instance (address), or instances containing specific parameters (param) are effective. | Field | Type | Description | Required | | --- | --- | --- | --- | -| address | StringMatch | The instance address matching condition for this config rule to take effect.

- xact: "value" for exact string match
- prefix: "value" for prefix-based match
- regex: "value" for RE2 style regex-based match ([https://github.com/google/re2/wiki/Syntax)](https://github.com/google/re2/wiki/Syntax)).| No | +| address | StringMatch | The instance address matching condition for this config rule to take effect.

- exact: "value" for exact string match
- prefix: "value" for prefix-based match
- regex: "value" for RE2 style regex-based match ([https://github.com/google/re2/wiki/Syntax)](https://github.com/google/re2/wiki/Syntax)).| No | | service | StringMatch (oneof) | The service matching condition for this config rule to take effect. Effective when `scope: application` is set.

- exact: "value" for exact string match
- prefix: "value" for prefix-based match
- regex: "value" for RE2 style regex-based match ([https://github.com/google/re2/wiki/Syntax)](https://github.com/google/re2/wiki/Syntax)).| No | | application | StringMatch (oneof) | The application matching condition for this config rule to take effect. Effective when `scope: service` is set.

- exact: "value" for exact string match
- prefix: "value" for prefix-based match
- regex: "value" for RE2 style regex-based match ([https://github.com/google/re2/wiki/Syntax)](https://github.com/google/re2/wiki/Syntax)).| No | | param | ParamCondition[] | The Dubbo url keys and values matching condition for this config rule to take effect. | No | ## ParamCondition -定义实例参数 (param) 过滤条件,对应到 Dubbo URL 地址参数。 +Defines instance parameter (param) filter conditions, corresponding to Dubbo URL address parameters. | Field | Type | Description | Required | | --- | --- | --- | --- | @@ -93,3 +93,5 @@ configs: | exact | string (oneof) | exact string match | No | | prefix | string (oneof) | prefix-based match | No | | regex | string (oneof) | RE2 style regex-based match ([https://github.com/google/re2/wiki/Syntax)](https://github.com/google/re2/wiki/Syntax)). | No | + +It seems like you haven't pasted the Markdown content yet. Please provide the content you need translated, and I'll assist you accordingly. diff --git a/content/en/overview/what/core-features/traffic/introduction.md b/content/en/overview/what/core-features/traffic/introduction.md index dd1ed1108222..2bb6575af7c6 100644 --- a/content/en/overview/what/core-features/traffic/introduction.md +++ b/content/en/overview/what/core-features/traffic/introduction.md @@ -1,58 +1,58 @@ --- aliases: - - /zh/overview/core-features/traffic/ - - /zh-cn/overview/core-features/traffic/ -description: "Dubbo 的流量管控规则可以基于应用、服务、方法、参数等粒度精准的控制流量走向,根据请求的目标服务、方法以及请求体中的其他附加参数进行匹配,符合匹配条件的流量会进一步的按照特定规则转发到一个地址子集" -linkTitle: 路由机制介绍 -title: Dubbo 路由(router)机制及其如何实现流量管控介绍 + - /en/overview/core-features/traffic/ + - /en/overview/core-features/traffic/ +description: "Dubbo's traffic control rules can precisely control traffic direction based on application, service, method, parameter, etc., matching the target service, method, and other additional parameters in the request body. Traffic that meets the matching conditions will be further forwarded to a subset of addresses according to specific rules." +linkTitle: Introduction to Routing Mechanism +title: Introduction to Dubbo Routing (router) Mechanism and How It Implements Traffic Control type: docs weight: 1 --- -Dubbo 提供了丰富的流量管控策略 -* **地址发现与负载均衡**,地址发现支持服务实例动态上下线,负载均衡确保流量均匀的分布到每个实例上。 -* **基于路由规则的流量管控**,路由规则对每次请求进行条件匹配,并将符合条件的请求路由到特定的地址子集。 +Dubbo provides a rich set of traffic control strategies: +* **Address discovery and load balancing**: Address discovery supports dynamic service instance registration and deregistration, and load balancing ensures that traffic is evenly distributed across each instance. +* **Traffic control based on routing rules**: Routing rules match each request based on conditions and route matching requests to a specific subset of addresses. -服务发现保证调用方看到最新的提供方实例地址,服务发现机制依赖注册中心 (Zookeeper、Nacos、Istio 等) 实现。在消费端,Dubbo 提供了多种负载均衡策略,如随机负载均衡策略、一致性哈希负载、基于权重的轮询、最小活跃度优先、P2C 等。 +Service discovery ensures that the caller sees the latest provider instance addresses. The service discovery mechanism relies on the registry (Zookeeper, Nacos, Istio, etc.). On the consumer side, Dubbo provides various load balancing strategies, such as random load balancing, consistent hash load balancing, weight-based round-robin, least active priority, P2C, etc. -Dubbo 的流量管控规则可以基于应用、服务、方法、参数等粒度精准的控制流量走向,根据请求的目标服务、方法以及请求体中的其他附加参数进行匹配,符合匹配条件的流量会进一步的按照特定规则转发到一个地址子集。流量管控规则有以下几种: -* 条件路由规则 -* 标签路由规则 -* 脚本路由规则 -* 动态配置规则 +Dubbo's traffic control rules can precisely control traffic direction based on application, service, method, parameter, etc., matching the target service, method, and other additional parameters in the request body. Traffic that meets the matching conditions will be further forwarded to a subset of addresses according to specific rules. The traffic control rules include: +* Conditional routing rules +* Tag routing rules +* Script routing rules +* Dynamic configuration rules -如果底层用的是基于 HTTP 的 RPC 协议 (如 REST、gRPC、Triple 等),则服务和方法等就统一映射为 HTTP 路径 (path),此时 Dubbo 路由规则相当于是基于 HTTP path 和 headers 的流量分发机制。 +If the underlying protocol is an HTTP-based RPC protocol (such as REST, gRPC, Triple, etc.), then services and methods are uniformly mapped to HTTP paths. In this case, Dubbo's routing rules are equivalent to traffic distribution mechanisms based on HTTP paths and headers. -> Dubbo 中有应用、服务和方法的概念,一个应用可以发布多个服务,一个服务包含多个可被调用的方法,从抽象的视角来看,一次 Dubbo 调用就是某个消费方应用发起了对某个提供方应用内的某个服务特定方法的调用,Dubbo 的流量管控规则可以基于应用、服务、方法、参数等粒度精准的控制流量走向。 +> In Dubbo, there are concepts of applications, services, and methods. An application can publish multiple services, and a service contains multiple callable methods. From an abstract perspective, a Dubbo call is an invocation of a specific method of a service within a provider application initiated by a consumer application. Dubbo's traffic control rules can precisely control traffic direction based on application, service, method, parameter, etc. -## Router工作原理 +## Router Working Principle -以下是 Dubbo 单个路由器的工作过程,路由器接收一个服务的实例地址集合作为输入,基于请求上下文 (Request Context) 和 (Router Rule) 实际的路由规则定义对输入地址进行匹配,所有匹配成功的实例组成一个地址子集,最终地址子集作为输出结果继续交给下一个路由器或者负载均衡组件处理。 +The following describes the working process of a single router in Dubbo. The router receives a set of instance addresses of a service as input, matches the input addresses based on the request context and the actual routing rule definitions, and forms a subset of addresses from all successfully matched instances. The final address subset is then passed to the next router or load balancing component for further processing. ![Router](/imgs/v3/feature/traffic/router1.png) -通常,在 Dubbo 中,多个路由器组成一条路由链共同协作,前一个路由器的输出作为另一个路由器的输入,经过层层路由规则筛选后,最终生成有效的地址集合。 -* Dubbo 中的每个服务都有一条完全独立的路由链,每个服务的路由链组成可能不通,处理的规则各异,各个服务间互不影响。 -* 对单条路由链而言,即使每次输入的地址集合相同,根据每次请求上下文的不同,生成的地址子集结果也可能不同。 +Typically, in Dubbo, multiple routers form a routing chain that works together. The output of the previous router serves as the input for the next router. After layer-by-layer routing rule filtering, an effective address set is finally generated. +* Each service in Dubbo has a completely independent routing chain. The composition of the routing chain for each service may vary, and the rules processed are different, with no mutual influence between services. +* For a single routing chain, even if the input address set is the same each time, the resulting address subset may differ based on the request context. ![Router](/imgs/v3/feature/traffic/router2.png) -## 路由规则分类 -### 标签路由规则 +## Classification of Routing Rules +### Tag Routing Rules -标签路由通过将某一个服务的实例划分到不同的分组,约束具有特定标签的流量只能在指定分组中流转,不同分组为不同的流量场景服务,从而实现流量隔离的目的。标签路由可以作为蓝绿发布、灰度发布等场景能力的基础。 +Tag routing divides instances of a service into different groups, constraining traffic with specific tags to flow only within designated groups. Different groups serve different traffic scenarios, achieving traffic isolation. Tag routing can serve as the foundation for scenarios such as blue-green deployment and canary release. -标签路由规则是一个非此即彼的流量隔离方案,也就是匹配`标签`的请求会 100% 转发到有相同`标签`的实例,没有匹配`标签`的请求会 100% 转发到其余未匹配的实例。如果您需要按比例的流量调度方案,请参考示例 [基于权重的按比例流量路由](../../tasks/traffic-management/weight/)。 +Tag routing rules are an either-or traffic isolation solution, meaning requests matching a `tag` will be 100% forwarded to instances with the same `tag`, and requests not matching a `tag` will be 100% forwarded to the remaining unmatched instances. If you need a proportional traffic scheduling solution, please refer to the example [Proportional Traffic Routing Based on Weight](../../tasks/traffic-management/weight/). -`标签`主要是指对 Provider 端应用实例的分组,目前有两种方式可以完成实例分组,分别是`动态规则打标`和`静态规则打标`。`动态规则打标` 可以在运行时动态的圈住一组机器实例,而 `静态规则打标` 则需要实例重启后才能生效,其中,动态规则相较于静态规则优先级更高,而当两种规则同时存在且出现冲突时,将以动态规则为准。 +`Tags` mainly refer to the grouping of provider-side application instances. Currently, there are two ways to complete instance grouping: `dynamic rule tagging` and `static rule tagging`. `Dynamic rule tagging` can dynamically enclose a group of machine instances at runtime, while `static rule tagging` requires instance restart to take effect. Among them, dynamic rules have a higher priority than static rules, and when both rules exist and conflict, dynamic rules will prevail. -#### 标签规则示例 - 静态打标 +#### Tag Rule Example - Static Tagging -静态打标需要在服务提供者实例启动前确定,并且必须通过特定的参数 `tag` 指定。 +Static tagging needs to be determined before the service provider instance starts and must be specified through a specific parameter `tag`. ##### Provider -在 Dubbo 实例启动前,指定当前实例的标签,如部署在杭州区域的实例,指定 `tag=gray`。 +Before the Dubbo instance starts, specify the tag for the current instance, such as specifying `tag=gray` for instances deployed in the Hangzhou region. ```xml @@ -72,19 +72,19 @@ java -jar xxx-provider.jar -Ddubbo.provider.tag=gray ##### Consumer -发起调用的一方,在每次请求前通过 `tag` 设置流量标签,确保流量被调度到带有同样标签的服务提供方。 +The party initiating the call sets the traffic tag through `tag` before each request to ensure that the traffic is routed to the service provider with the same tag. ```java RpcContext.getContext().setAttachment(Constants.TAG_KEY, "gray"); ``` -#### 标签规则示例 - 动态打标 +#### Tag Rule Example - Dynamic Tagging -相比于静态打标只能通过 `tag` 属性设置,且在启动阶段就已经固定下来,动态标签可以匹配任意多个属性,根据指定的匹配条件将 Provider 实例动态的划分到不同的流量分组中。 +Compared to static tagging which can only be set through the `tag` attribute and is fixed at startup, dynamic tags can match any number of attributes and dynamically divide Provider instances into different traffic groups based on specified matching conditions. ##### Provider -以下规则对 `shop-detail` 应用进行了动态归组,匹配 `env: gray` 的实例被划分到 `gray` 分组,其余不匹配 `env: gray` 继续留在默认分组 (无 tag)。 +The following rule dynamically groups the `shop-detail` application, where instances matching `env: gray` are grouped into the `gray` group, and those not matching `env: gray` remain in the default group (no tag). ```yaml configVersion: v3.0 @@ -99,43 +99,42 @@ tags: exact: gray ``` -> 这里牵涉到如何给您的实例打各种原始 label 的问题,即上面示例中的 `env`,一种方式是直接写在配置文件中,如上面静态规则实例 provider 部分的配置所示,另一种方式是通过预设环境变量指定,关于这点请参考下文的 [如何给实例打标](#如何给实例打标) 一节。 +> This involves how to label your instances with various original labels, such as `env` in the example above. One way is to write it directly in the configuration file, as shown in the static rule example provider section above. Another way is to specify it through preset environment variables. For more details, please refer to the section [How to Label Instances](#如何给实例打标) below. ##### Consumer -服务发起方的设置方式和之前静态打标规则保持一致,只需要在每次请求前通过 `tag` 设置流量标签,确保流量被调度到带有同样标签的服务提供方。 +The settings for the service initiator remain the same as the static tagging rules. You only need to set the traffic tag through `tag` before each request to ensure that the traffic is routed to the service provider with the same tag. ```java RpcContext.getContext().setAttachment(Constants.TAG_KEY, "Hangzhou"); ``` -设置了以上标签的流量,将全部导流到 `hangzhou-region` 划分的实例上。 +Traffic with the above tag will be routed to instances divided by the `hangzhou-region`. -> 请求标签的作用域仅为一次点对点的 RPC 请求。比如,在一个 A -> B -> C 调用链路上,如果 A -> B 调用通过 `setAttachment` 设置了 `tag` 参数,则该参数不会在 B -> C 的调用中生效,同样的,在完成了 A -> B -> C 的整个调用同时 A 收到调用结果后,如果想要相同的 `tag` 参数,则在发起其他调用前仍需要单独设置 `setAttachment`。可以参考 [示例任务 - 环境隔离](../../tasks/traffic-management/isolation/) 了解更多 `tag` 全链路传递解决方案。 +> The scope of the request tag is limited to a single point-to-point RPC request. For example, in an A -> B -> C call chain, if the A -> B call sets the `tag` parameter through `setAttachment`, this parameter will not be effective in the B -> C call. Similarly, after completing the entire A -> B -> C call and A receives the result, if you want the same `tag` parameter, you still need to set `setAttachment` separately before initiating other calls. You can refer to [Example Task - Environment Isolation](../../tasks/traffic-management/isolation/) to learn more about the full-link transmission solution of `tag`. -### 条件路由规则 +### Conditional Routing Rules -条件路由与标签路由的工作模式非常相似,也是首先对请求中的参数进行匹配,符合匹配条件的请求将被转发到包含特定实例地址列表的子集。相比于标签路由,条件路由的匹配方式更灵活: +Conditional routing works similarly to tag routing. It first matches the parameters in the request, and requests that meet the matching conditions are forwarded to a subset of specific instance addresses. Compared to tag routing, conditional routing is more flexible in its matching method: -* 在标签路由中,一旦给某一台或几台机器实例打了标签,则这部分实例就会被立马从通用流量集合中移除,不同标签之间不会再有交集。有点类似下图,地址集合在输入阶段就已经划分明确。 +* In tag routing, once a tag is assigned to one or several machine instances, those instances are immediately removed from the general traffic pool, and there is no overlap between different tags. It's somewhat like the diagram below, where the address set is clearly divided at the input stage. ![tag-condition-compare](/imgs/v3/feature/traffic/tag-condition-compare1.png) -* 而从条件路由的视角,所有的实例都是一致的,路由过程中不存在分组隔离的问题,每次路由过滤都是基于全量地址中执行 +* From the perspective of conditional routing, all instances are consistent, and there is no grouping isolation during the routing process. Each routing filter is executed based on the full address set. ![tag-condition-compare](/imgs/v3/feature/traffic/tag-condition-compare2.png) -条件路由规则的主体 `conditions` 主要包含两部分内容: +The main content of the conditional routing rule `conditions` includes two parts: -* => 之前的为请求参数匹配条件,指定的 `匹配条件指定的参数` 将与 `消费者的请求上下文 (URL)、甚至方法参数` 进行对比,当消费者满足匹配条件时,对该消费者执行后面的地址子集过滤规则。 -* => 之后的为地址子集过滤条件,指定的 `过滤条件指定的参数` 将与 `提供者实例地址 (URL)` 进行对比,消费者最终只能拿到符合过滤条件的实例列表,从而确保流量只会发送到符合条件的地址子集。 - * 如果匹配条件为空,表示对所有请求生效,如:`=> status != staging` - * 如果过滤条件为空,表示禁止来自相应请求的访问,如:`application = product =>` +* The part before `=>` is the request parameter matching condition. The specified `matching condition parameter` will be compared with the `consumer's request context (URL) or even method parameters`. When the consumer meets the matching condition, the address subset filtering rule after `=>` is executed for that consumer. +* The part after `=>` is the address subset filtering condition. The specified `filtering condition parameter` will be compared with the `provider instance address (URL)`. The consumer will ultimately get a list of instances that meet the filtering conditions, ensuring that traffic is only sent to the address subset that meets the conditions. + * If the matching condition is empty, it applies to all requests, such as: `=> status != staging` + * If the filtering condition is empty, it prohibits access from the corresponding request, such as: `application = product =>` +#### Conditional Routing Rule Example -#### 条件路由规则示例 - -基于以下示例规则,所有 `org.apache.dubbo.demo.CommentService` 服务调用都将被转发到与当前消费端机器具有相同 `region` 标记的地址子集。`$region` 是特殊引用符号,执行过程中将读取消费端机器的实际的 `region` 值替代。 +Based on the following example rule, all `org.apache.dubbo.demo.CommentService` service calls will be forwarded to the address subset with the same `region` tag as the current consumer machine. `$region` is a special reference symbol that will be replaced with the actual `region` value of the consumer machine during execution. ```yaml configVersion: v3.0 @@ -146,29 +145,29 @@ conditions: - '=> region = $region' ``` -> 针对条件路由,我们通常推荐配置 `scope: service` 的规则,因为它可以跨消费端应用对所有消费特定服务 (service) 的应用生效。关于 Dubbo 规则中的 `scope` 以及 `service`、`application` 的说明请阅读 [条件路由规则手册](./condition-rule)。 +> For conditional routing, we usually recommend configuring rules with `scope: service` because it can apply to all applications consuming a specific service across different consumers. For more information about `scope` and `service`, `application` in Dubbo rules, please read the [Conditional Routing Rule Manual](./condition-rule). -条件路由规则还支持设置具体的机器地址如 ip 或 port,这种情况下使用条件路由可以处理一些开发或线上机器的临时状况,实现**黑名单、白名单、实例临时摘除**等运维效果,如以下规则可以将机器 `172.22.3.91` 从服务的可用列表中排除。 +Conditional routing rules also support setting specific machine addresses such as IP or port. In such cases, conditional routing can handle temporary situations for development or production machines, achieving operational effects like **blacklisting, whitelisting, temporary instance removal**, etc. For example, the following rule can exclude the machine `172.22.3.91` from the service's available list. ```yaml => host != 172.22.3.91 ``` -条件路由还支持基于请求参数的匹配,示例如下: +Conditional routing also supports matching based on request parameters, as shown in the following example: ```yaml conditions: - method=getDetail&arguments[0]=dubbo => port=20880 ``` -### 动态配置规则 -通过 Dubbo 提供的动态配置规则,您可以动态的修改 Dubbo 服务进程的运行时行为,整个过程不需要重启,配置参数实时生效。基于这个强大的功能,基本上所有运行期参数都可以动态调整,比如超时时间、临时开启 Access Log、修改 Tracing 采样率、调整限流降级参数、负载均衡、线程池配置、日志等级、给机器实例动态打标签等。与上文讲到的流量管控规则类似,动态配置规则支持应用、服务两个粒度,也就是说您一次可以选择只调整应用中的某一个或几个服务的参数配置。 +### Dynamic Configuration Rules +With the dynamic configuration rules provided by Dubbo, you can dynamically modify the runtime behavior of Dubbo service processes without restarting, and the configuration parameters take effect immediately. Based on this powerful feature, almost all runtime parameters can be dynamically adjusted, such as timeout settings, temporarily enabling Access Log, modifying Tracing sampling rate, adjusting rate limiting and degradation parameters, load balancing, thread pool configuration, log levels, dynamically tagging machine instances, etc. Similar to the traffic control rules mentioned above, dynamic configuration rules support both application and service granularity, meaning you can choose to adjust the parameter configuration of one or several services within an application at a time. -当然,出于系统稳定性、安全性的考量,有些特定的参数是不允许动态修改的,但除此之外,基本上所有参数都允许动态修改,很多强大的运行态能力都可以通过这个规则实现,您可以找个示例应用去尝试一下。通常 URL 地址中的参数均可以修改,这在每个语言实现的参考手册里也记录了一些更详细的说明。 +Of course, for the sake of system stability and security, some specific parameters are not allowed to be dynamically modified. But other than that, almost all parameters can be dynamically modified, and many powerful runtime capabilities can be achieved through this rule. You can try it out with a sample application. Usually, the parameters in the URL address can be modified, and more detailed explanations are recorded in the reference manuals for each language implementation. -#### 动态配置规则示例 - 修改超时时间 +#### Dynamic Configuration Rule Example - Modifying Timeout -以下示例将 `org.apache.dubbo.samples.UserService` 服务的超时参数调整为 2000ms +The following example adjusts the timeout parameter of the `org.apache.dubbo.samples.UserService` service to 2000ms ```yaml configVersion: v3.0 @@ -181,24 +180,24 @@ configs: timeout: 2000 ``` -以下部分指定这个配置是服务粒度,具体变更的服务名为 `org.apache.dubbo.samples.UserService`。`scope` 支持 `service`、`application` 两个可选值,如果 `scope: service`,则 `key` 应该配置为 `version/service:group` 格式。 +The following section specifies that this configuration is at the service granularity, and the specific service name to be changed is `org.apache.dubbo.samples.UserService`. `scope` supports two optional values: `service` and `application`. If `scope: service`, then `key` should be configured in the `version/service:group` format. ```yaml scope: service key: org.apache.dubbo.samples.UserService ``` -> 关于 Dubbo 规则中的 `scope` 以及 `service`、`application` 的说明请参考 [动态配置参考手册](./configuration-rule/) 或 [动态配置示例](../../tasks/traffic-management/timeout/)。 +> For more information about `scope` and `service`, `application` in Dubbo rules, please refer to the [Dynamic Configuration Reference Manual](./configuration-rule/) or [Dynamic Configuration Example](../../tasks/traffic-management/timeout/). -`parameters` 参数指定了新的修改值,这里将通过 `timeout: 2000` 将超时时间设置为 2000ms。 +The `parameters` parameter specifies the new modification value. Here, the timeout is set to 2000ms through `timeout: 2000`. ```yaml parameters: timeout: 2000 ``` -### 脚本路由规则 -脚本路由是最直观的路由方式,同时它也是当前最灵活的路由规则,因为你可以在脚本中定义任意的地址筛选规则。如果我们为某个服务定义一条脚本规则,则后续所有请求都会先执行一遍这个脚本,脚本过滤出来的地址即为请求允许发送到的、有效的地址集合。 +### Script Routing Rules +Script routing is the most intuitive routing method, and it is also the most flexible routing rule currently available because you can define any address filtering rules in the script. If we define a script rule for a service, all subsequent requests will first execute this script, and the addresses filtered out by the script will be the valid addresses to which the request is allowed to be sent. ```yaml configVersion: v3.0 @@ -217,11 +216,11 @@ script: | } (invokers, invocation, context)); // 表示立即执行方法 ``` -## 如何给实例打标 +## How to Tag Instances -当前,有两种方式可以在启动阶段为 Dubbo 实例指定标签,一种是之前提到的应用内配置的方式,如在 xml 文件中设置 ``,应用打包部署后即自动被打标。 +Currently, there are two ways to specify tags for Dubbo instances at startup. One way is the previously mentioned method of configuring within the application, such as setting `` in the XML file, and the application will be automatically tagged after packaging and deployment. -还有一种更灵活的方式,那就是通过读取所部署机器上的环境信息给应用打标,这样应用的标签就可以跟随实例动态的自动填充,避免每次更换部署环境就重新打包应用镜像的问题。当前 Dubbo 能自动读取以下环境变量配置: +Another more flexible way is to tag the application by reading the environment information of the deployed machine. This way, the application's tags can dynamically and automatically populate with the instance, avoiding the need to repackage the application image every time the deployment environment changes. Currently, Dubbo can automatically read the following environment variable configurations: ```yaml spec: @@ -247,22 +246,23 @@ spec: value: "gray" ``` -如果您有不同的实例环境保存机制,可以通过扩展 `InfraAdapter 扩展点` 来自定义自己的标签加载方式。如果您的应用是部署在 Kubernetes 环境下,并且已经接入了服务网格体系,则也可以使用标准 deployment 标签的方式打标,具体请跟随 [服务网格任务示例](../../tasks/mesh/) 学习。 +If you have a different instance environment preservation mechanism, you can customize your own tag loading method by extending the `InfraAdapter extension point`. If your application is deployed in a Kubernetes environment and has already integrated with the service mesh system, you can also use the standard deployment tag method for tagging. For details, please follow the [Service Mesh Task Example](../../tasks/mesh/). +``` -## 如何配置流量规则 -Dubbo 提供了控制台 Dubbo Admin,帮助您可视化的下发流量管控规则,并实时监控规则生效情况。 +## How to Configure Traffic Rules +Dubbo provides a console called Dubbo Admin to help you visualize and issue traffic control rules, and monitor the effectiveness of the rules in real-time. ![Admin](/imgs/v3/what/admin.png) -Dubbo 还提供了 `dubboctl` 命令行工具,需要有 Dubbo Admin 提前部署就绪,因为 dubboctl 是通过与 Admin 进行 http 通信完成规则下发的。 +Dubbo also provides a command-line tool called `dubboctl`. Dubbo Admin needs to be deployed in advance because dubboctl issues rules through HTTP communication with Admin. -如果您使用的是如 Istio 的服务网格架构,还可以使用 Istioctl、kubectl 等下发 Istio 标准规则。 +If you are using a service mesh architecture like Istio, you can also use Istioctl, kubectl, etc., to issue Istio standard rules. -## 接入服务网格 +## Integrating with Service Mesh -以上介绍的都是 Dubbo 体系内的流量治理规则,如果您对服务网格架构感兴趣,则可以将 Dubbo 服务接入服务网格体系,这样,您就可以使用服务网格提供的流量治理能力,如 Istio 体系的 VirtualService 等。 +The above introduces traffic governance rules within the Dubbo system. If you are interested in service mesh architecture, you can integrate Dubbo services into the service mesh system. This way, you can use the traffic governance capabilities provided by the service mesh, such as Istio's VirtualService. -具体请参见 [Dubbo 中的服务网格架构](../service-mesh)。 +For details, please refer to [Service Mesh Architecture in Dubbo](../service-mesh). -## 跟随示例学习 -我们搭建了一个 [线上商城系统](../../tasks/traffic-management/) 供您学习流量规则的具体使用。 +## Learn by Example +We have set up an [online shopping system](../../tasks/traffic-management/) for you to learn the specific usage of traffic rules. diff --git a/content/en/overview/what/core-features/traffic/mesh-rule.md b/content/en/overview/what/core-features/traffic/mesh-rule.md index 924167bcae09..d6043f62db6d 100644 --- a/content/en/overview/what/core-features/traffic/mesh-rule.md +++ b/content/en/overview/what/core-features/traffic/mesh-rule.md @@ -1,34 +1,31 @@ --- type: docs -title: "Mesh 路由规则" -linkTitle: "Mesh 路由" +title: "Mesh Routing Rules" +linkTitle: "Mesh Routing" weight: 50 description: "" --- -Dubbo Mesh 路由规则是基于 Istio 的 VirtualService、DestinationRule 改造而来,总体思路和格式可以参考 Istio 流量管控规则参考手册:[Istio VirtualService](https://istio.io/latest/docs/reference/config/networking/virtual-service/) 和 [Istio DestinationRule](https://istio.io/latest/docs/reference/config/networking/destination-rule/) +Dubbo Mesh routing rules are based on Istio's VirtualService and DestinationRule modifications. The overall idea and format can refer to Istio's traffic control rules reference manual: [Istio VirtualService](https://istio.io/latest/docs/reference/config/networking/virtual-service/) and [Istio DestinationRule](https://istio.io/latest/docs/reference/config/networking/destination-rule/) -本文描述了 Dubbo Mesh 路由规则的设计原理,以及它和 Istio 规则的差异等。参考链接:https://www.yuque.com/docs/share/c132d5db-0dcb-487f-8833-7c7732964bd4?#。 +This article describes the design principles of Dubbo Mesh routing rules, as well as the differences between them and Istio rules. Reference link: https://www.yuque.com/docs/share/c132d5db-0dcb-487f-8833-7c7732964bd4?#. - -### 基本思想 -基于路由链,采用Pipeline的处理方式,如下图所示: +### Basic Idea +Based on the routing chain, the Pipeline processing method is adopted, as shown in the figure below: ![route-rule1.png](/imgs/user/route-rule1.png) - -可以把路由链的逻辑简单的理解为 target = rn(...r3(r2(r1(src))))。对于每一个 router 内部的逻辑,可以抽象为输入地址 addrs-in 与 router 中按全量地址 addrs-all 实现切分好的 n 个互不相交的地址池 addrs-pool-1 ... addrs-pool-n 按实现定义好的规则取交集作为输出 addrs-out。以此类推,完成整个路由链的计算。 +The logic of the routing chain can be simply understood as target = rn(...r3(r2(r1(src)))). For the internal logic of each router, it can be abstracted as the input address addrs-in and the n mutually exclusive address pools addrs-pool-1 ... addrs-pool-n that are split according to the full address addrs-all in the router. The intersection is taken as the output addrs-out according to the rules defined by the implementation. By analogy, the calculation of the entire routing chain is completed. ![route-rule2.png](/imgs/user/route-rule2.png) -另外一方面,如果 router(n) 需要执行 fallback 逻辑的时候,那么需要经过 router(n) 就应该决定好 fallback 逻辑 +On the other hand, if router(n) needs to execute fallback logic, then after passing through router(n), the fallback logic should be determined. +### Fallback Handling Principles -### fallback 处理原则 +Due to multiple conditional components between multiple routers, it is easy for the address to be filtered out. In this case, we need to perform fallback handling to ensure that the business can smoothly find a valid address under the premise of correctness. -由于多个 router 之间多个条件组件之后,很容易出现地址被筛选为空的情况,那么我们需要针对这情况进行 fallback 处理,保证业务在正确性的前提下,能够顺利找到有效地址。 - -首先我们看一下以下规则 +First, let's look at the following rule ```yaml apiVersion: service.dubbo.apache.org/v1alpha1 @@ -109,11 +106,11 @@ spec: ``` -我们以脚本路由为例,这个脚本路由的匹配条件是遵循一个原则的,就是匹配的范围是从精确到广泛的一个过程,在这个示例来说,就是 sayHello(string)参数 -> sayHello 方法 -> 接口级路由 的一个匹配查找过程。 +Taking script routing as an example, the matching condition of this script routing follows a principle, which is that the matching range is a process from precise to broad. In this example, it is a matching search process from the sayHello(string) parameter -> sayHello method -> interface-level routing. -那么如果我们已经满足某个条件,但是选到的 subset 地址为空,我们将如何进行 fallback 处理呢? +So if we have met a certain condition but the selected subset address is empty, how do we perform fallback handling? -以匹配 sayHello(string)参数 条件为例,我们选择到的是 v1 subset,如果是空,我们可以向上一级是寻找地址,也就是方法级去寻找地址,具体的配置为下 +Taking the matching sayHello(string) parameter condition as an example, we select the v1 subset. If it is empty, we can look for the address at the next level, which is to look for the address at the method level. The specific configuration is as follows ```yaml - name: sayHello-String-method-route @@ -138,10 +135,9 @@ spec: subset: v3 ``` -此时我们选到的地址是 v2 方法级地址,如果 v2 还是没有地址,根据规则的定义,我们是可以 fallback 到 v3 接口级。 - -假设我们有一个方法匹配时,如果没有地址,需要不进行 fallback,直接报错,我们可以这样配置 +At this time, the address we selected is the v2 method-level address. If v2 still has no address, according to the definition of the rule, we can fallback to the v3 interface level. +Suppose we have a method match, if there is no address, we need not to perform fallback and directly report an error. We can configure it like this ```yaml apiVersion: service.dubbo.apache.org/v1alpha1 @@ -230,22 +226,21 @@ spec: sigma.ali/mg: v3-host ``` -从这个规则我们看出来匹配到 some-method 条件时对应的是 v4 subset,那么 v4 为空时,因为没有配置 fallback ,此时会直接报错 +From this rule, we can see that when matching the some-method condition, the corresponding v4 subset is selected. When v4 is empty, because there is no fallback configured, an error will be reported directly. -#### fallback 处理原则总结 +#### Summary of Fallback Handling Principles -- 我们应该在 VirtualService route 中配置好 Destination 的 fallback 处理逻辑 -- 在 fallback subset 时,如果对应的 subset 也配置有 fallback subset 时,也应递归处理;fallback subset 之间的关系也应该是从具体到广泛 -- 我们在编写匹配条件时,应该遵循从 具体条件到广泛条件 的原则 +- We should configure the fallback handling logic of the Destination in the VirtualService route. +- When falling back to a subset, if the corresponding subset is also configured with a fallback subset, it should also be handled recursively; the relationship between fallback subsets should also be from specific to broad. +- When writing matching conditions, we should follow the principle of from specific conditions to broad conditions. -### RouteChain 的组装模式 (目前未实现) +### RouteChain Assembly Mode (Not yet implemented) ![route-rule3.png](/imgs/user/route-rule3.png) +As we can see in the above figure, in the routing process, we use the Pipeline processing method. The Router nodes in the Pipeline are sequential, and each Router has a unique corresponding VirtualService and **multiple** corresponding DestinationRules for description. -我们看到上面的图,在路由的过程当中,我们是 Pipeline 的处理方式,Pipeline 的 Router 节点存在顺序,并且每个 Router 都有一个唯一对应的 VirtualService 和 **多个** 相应的 DestinationRule 进行描述。 - -以 Nacos 上存着的路由规则配置为例,配置的格式如下: +Taking the routing rule configuration stored in Nacos as an example, the configuration format is as follows: ```yaml DataId: Demo.rule.yaml @@ -270,17 +265,17 @@ DestinationRule C ... ``` -`VirtualService A` 与 `DestinationRule A1` 、`DestinationRule A2` 组成一个 Router A,`VirtualService B` 与 `DestinationRule B` 组成 Router B,以此类推,完成整个 router 链的组装。 +`VirtualService A` and `DestinationRule A1`, `DestinationRule A2` form a Router A, `VirtualService B` and `DestinationRule B` form Router B, and so on, completing the assembly of the entire router chain. -### 示例:按比例流量路由规则 +### Example: Proportional Traffic Routing Rules -> 注意,虽然接下来的规则和 Istio 的 VirtualService、DestinationRule 很像,但工作过程和具体规则和 Istio 还是有一些差异,Dubbo 只是参考了 Istio 的设计。如果您想接入原生的 Istio 服务网格治理体系,请参考下文 [接入服务网格流量治理](#接入服务网格流量治理)。 +> Note, although the following rules are very similar to Istio's VirtualService and DestinationRule, there are some differences in the working process and specific rules compared to Istio. Dubbo only references Istio's design. If you want to integrate with the native Istio service mesh governance system, please refer to [Integrating Service Mesh Traffic Governance](#接入服务网格流量治理). -在一些场景下,我们需要将相同属性的流量按比例的分发到不同的实例分组。一个典型的示例场景是 A/B 测试,比如我们需要将 20% 流量转发到服务新版本 v2 的实例,以验证新版本的稳定性,或者是将公司内部的一部分用户导流到新版本 v2 的实例进行测试验证。另一个应用场景是实现服务的金丝雀发布,通过逐步调整流量分配比例值,使得新版本的流量逐步提升并最终将全部流量完全迁移到新版本之上。 +In some scenarios, we need to distribute traffic with the same attributes proportionally to different instance groups. A typical example scenario is A/B testing, where we need to forward 20% of the traffic to the new version v2 of the service to verify the stability of the new version, or to direct a portion of internal company users to the new version v2 for testing and verification. Another application scenario is to achieve canary releases of services, gradually adjusting the traffic distribution ratio so that the new version's traffic gradually increases and eventually fully migrates all traffic to the new version. -#### 按比例流量规则示例 +#### Example of Proportional Traffic Rules -以下示例会将访问服务 `org.apache.dubbo.demo.DetailService` 特定方法 `getDetail` 的所有请求按比例进行转发。 +The following example will proportionally forward all requests to the `getDetail` method of the service `org.apache.dubbo.demo.DetailService`. ```yaml ... @@ -324,9 +319,9 @@ spec: ##### Dubbo VirtualService -> 此部分完全可参考 Istio VirtualService 语义,两者几乎完全相同,Dubbo 增加了 `dubbo` 协议标签(对应 http 协议位置)并对 `match` 条件进行了丰富。 +> This part can fully refer to the semantics of Istio VirtualService, as they are almost identical. Dubbo adds the `dubbo` protocol label (corresponding to the http protocol position) and enriches the `match` conditions. -`match` 条件设置了流量规则只对访问服务 "org.apache.dubbo.demo.DetailService" 的 `getDetail` 方法的请求有效。 +The `match` condition sets the traffic rule to be effective only for requests to the `getDetail` method of the service "org.apache.dubbo.demo.DetailService". ```yaml match: @@ -338,7 +333,7 @@ match: exact: "getDetail" ``` -以下 `route` 指定匹配后流量的目标实例子集,实例子集 `details-v1` `details-v2` 是通过下面的 DestinationRule 定义的。对于没有匹配的流量,则默认可以访问任何实例,不会做任何过滤。 +The following `route` specifies the target instance subsets for the matched traffic. The instance subsets `details-v1` and `details-v2` are defined through the DestinationRule below. For unmatched traffic, it can access any instance by default without any filtering. ```yaml route: @@ -352,9 +347,9 @@ route: ##### Dubbo DestinationRule -> 此部分完全可参考 Istio DestinationRule 语义,两者完全相同。 +> This part can fully refer to the semantics of Istio DestinationRule, as they are identical. -以下规则通过匹配 `detail_version` 值将应用 details 划分为两个部署版本 `v1` 和 `v2`,分别命名为 `deatils-v1` 和 `details-v2`,同时 `deatils-v1` 和 `details-v2` 将成为 Dubbo VirtualService 的流量转发目标对象。 +The following rule divides the application details into two deployment versions `v1` and `v2` by matching the `detail_version` value, named `details-v1` and `details-v2` respectively. At the same time, `details-v1` and `details-v2` will become the traffic forwarding target objects of Dubbo VirtualService. ```yaml subsets: @@ -366,8 +361,6 @@ subsets: detail_version: v2 # 'version' is a reserved key in Dubbo, so must not be used. ``` -> 和标签路由类似,这里牵涉到如何给您的实例打标(这里是 `detail_version`)的问题,请参考下文的 [如何给实例打标](#如何给实例打标) 一节。 - -除了以上介绍的与 Istio 流量规则很相似的功能之外,Dubbo 的 VirtualService、DestinationRule 还可以实现方法参数路由等 Istio 规则不能做到的事情,具体查看 [参考手册]()。 - +> Similar to label routing, this involves how to label your instances (here it is `detail_version`). Please refer to the section [How to Label Instances](#如何给实例打标) below. +In addition to the functions introduced above that are very similar to Istio's traffic rules, Dubbo's VirtualService and DestinationRule can also achieve things that Istio rules cannot, such as method parameter routing. For details, see the [Reference Manual](). diff --git a/content/en/overview/what/core-features/traffic/script-rule.md b/content/en/overview/what/core-features/traffic/script-rule.md index 96cf57f40340..e2a0aed14ad0 100644 --- a/content/en/overview/what/core-features/traffic/script-rule.md +++ b/content/en/overview/what/core-features/traffic/script-rule.md @@ -1,21 +1,21 @@ --- aliases: - - /zh/overview/core-features/traffic/script-rule/ - - /zh-cn/overview/core-features/traffic/script-rule/ + - /en/overview/core-features/traffic/script-rule/ + - /en/overview/core-features/traffic/script-rule/ description: "" -linkTitle: 脚本路由 -title: 脚本路由规则 +linkTitle: Script Routing +title: Script Routing Rules type: docs weight: 3 --- -脚本路由为流量管理提供了最大的灵活性,所有流量在执行负载均衡选址之前,都会动态的执行一遍规则脚本,根据脚本执行的结果确定可用的地址子集。 +Script routing provides maximum flexibility for traffic management. All traffic will dynamically execute a rule script before performing load balancing selection, and the available address subset is determined based on the script execution results. -脚本路由只对消费者生效且只支持应用粒度管理,因此, `key` 必须设置为消费者应用名;脚本语法支持多种,以 Dubbo Java SDK 为例,脚本语法支持 Javascript、Groovy、Kotlin 等,具体可参见每个语言实现的限制。 +Script routing only affects consumers and only supports application-level management. Therefore, the `key` must be set to the consumer application name. The script syntax supports multiple languages. Taking the Dubbo Java SDK as an example, the script syntax supports Javascript, Groovy, Kotlin, etc. For specific limitations, refer to the implementation of each language. -> 脚本路由由于可以动态加载远端代码执行,因此存在潜在的安全隐患,在启用脚本路由前,一定要确保脚本规则在安全沙箱内运行。 +> Since script routing can dynamically load and execute remote code, there are potential security risks. Ensure that the script rules run in a secure sandbox before enabling script routing. ```yaml configVersion: v3.0 @@ -35,21 +35,21 @@ script: | ``` ## ScriptRule -脚本路由规则主体。定义脚本规则生效的目标消费者应用、流量过滤脚本以及一些特定场景下的行为。 +The main body of the script routing rule. It defines the target consumer application for which the script rule is effective, the traffic filtering script, and behaviors in specific scenarios. | Field | Type | Description | Required | | --- | --- | --- | --- | | configVersion | string | The version of the script rule definition, currently available version is `v3.0` | Yes | | key | string | The identifier of the target application that this rule is about to apply to.| Yes | | type | string | The script language used to define `script`. | Yes | -| enabled | bool | Whether enable this rule or not, set `enabled:false` to disable this rule. | Yes | +| enabled | bool | Whether to enable this rule or not, set `enabled:false` to disable this rule. | Yes | | script | string | The script definition used to filter dubbo provider instances. | Yes | -| force | bool | The behaviour when the instance subset is empty after after routing. `true` means return no provider exception while `false` means ignore this rule. | No | +| force | bool | The behavior when the instance subset is empty after routing. `true` means return no provider exception while `false` means ignore this rule. | No | ## Script -`script` 为脚本路由规则的主体,类型为一个具有符合结构的 string 字符串,具体取决于 `type` 指定的脚本语言。 +`script` is the main body of the script routing rule, and its type is a string with a specific structure, depending on the script language specified by `type`. -以下是 `type: javascript` 的一个脚本规则示例: +The following is an example of a script rule with `type: javascript`: ```javascript (function route(invokers,invocation,context) { diff --git a/content/en/overview/what/core-features/traffic/tag-rule.md b/content/en/overview/what/core-features/traffic/tag-rule.md index 6e382f401106..e1a5906d68f4 100644 --- a/content/en/overview/what/core-features/traffic/tag-rule.md +++ b/content/en/overview/what/core-features/traffic/tag-rule.md @@ -1,25 +1,25 @@ --- aliases: - - /zh/overview/core-features/traffic/tag-rule/ - - /zh-cn/overview/core-features/traffic/tag-rule/ + - /en/overview/core-features/traffic/tag-rule/ + - /en/overview/core-features/traffic/tag-rule/ description: "" -linkTitle: 标签路由 -title: 标签路由规则 +linkTitle: Tag Routing +title: Tag Routing Rules type: docs weight: 2 --- -标签路由通过将某一个服务的实例划分到不同的分组,约束具有特定标签的流量只能在指定分组中流转,不同分组为不同的流量场景服务,从而达到实现流量隔离的目的,可以作为蓝绿发布、灰度发布等场景能力的基础。目前有两种方式可以对实例打标,分别是`动态规则打标`和`静态规则打标`。`动态规则打标` 可以在运行时动态的圈住一组机器实例,而 `静态规则打标` 则需要实例重启后才能生效,其中,动态规则相较于静态规则优先级更高,而当两种规则同时存在且出现冲突时,将以动态规则为准。 +Tag routing divides instances of a service into different groups, constraining traffic with specific tags to flow only within designated groups. Different groups serve different traffic scenarios, achieving traffic isolation. This can be the basis for scenarios such as blue-green deployment and canary release. Currently, there are two ways to tag instances: `dynamic rule tagging` and `static rule tagging`. `Dynamic rule tagging` can dynamically enclose a group of machine instances at runtime, while `static rule tagging` requires instance restart to take effect. Dynamic rules have higher priority compared to static rules, and when both rules exist and conflict, dynamic rules will prevail. -本文要讲的就是标签路由规则就是 `动态规则打标`。 +This article discusses tag routing rules, specifically `dynamic rule tagging`. -标签路由是一套严格隔离的流量体系,对于同一个应用而言,一旦打了标签则这部分地址子集就被隔离出来,只有带有对应标签的请求流量可以访问这个地址子集,这部分地址不再接收没有标签或者具有不同标签的流量。 +Tag routing is a strictly isolated traffic system. For the same application, once tagged, the subset of addresses is isolated. Only requests with the corresponding tag can access this subset of addresses. This subset will no longer receive traffic without tags or with different tags. -举个例子,如果我们将一个应用进行打标,打标后划分为 tag-a、tag-b、无 tag 三个地址子集,则访问这个应用的流量,要么路由到 tag-a (当请求上下文 dubbo.tag=tag-a),要么路由到 tag-b (dubbo.tag=tag-b),或者路由到无 tag 的地址子集 (dubbo.tag 未设置),不会出现混调的情况。 +For example, if we tag an application and divide it into three address subsets: tag-a, tag-b, and no tag, then the traffic accessing this application will either route to tag-a (when the request context dubbo.tag=tag-a), route to tag-b (dubbo.tag=tag-b), or route to the no tag address subset (dubbo.tag not set). There will be no mixed routing. -标签路由的作用域是提供者应用,消费者应用无需配置标签路由规则。一个提供者应用内的所有服务只能有一条分组规则,不会有服务 A 使用一条路由规则、服务 B 使用另一条路由规则的情况出现。以下条件路由示例,在 `shop-detail` 应用中圈出了一个隔离环境 `gray`,`gray` 环境包含所有带有 `env=gray` 标识的机器实例。 +The scope of tag routing is the provider application, and the consumer application does not need to configure tag routing rules. All services within a provider application can only have one grouping rule. There will not be a situation where service A uses one routing rule and service B uses another. The following conditional routing example encloses an isolated environment `gray` in the `shop-detail` application. The `gray` environment includes all machine instances marked with `env=gray`. ```yaml configVersion: v3.0 @@ -34,29 +34,29 @@ tags: exact: gray ``` ## TagRule -标签路由规则主体。定义路由规则生效的目标应用、标签分类规则以及一些特定场景下的行为。 +The main body of the tag routing rule. Defines the target application for which the routing rule is effective, tag classification rules, and behaviors in specific scenarios. | Field | Type | Description | Required | | --- | --- | --- | --- | | configVersion | string | The version of the tag rule definition, currently available version is `v3.0` | Yes | | key | string | The identifier of the target application that this rule is about to control| Yes | -| enabled | bool | Whether enable this rule or not, set `enabled:false` to disable this rule. | Yes | +| enabled | bool | Whether to enable this rule or not, set `enabled:false` to disable this rule. | Yes | | tags | Tag[] | The tag definition of this rule. | Yes | -| force | bool | The behaviour when the instance subset is empty after routing. `true` means return no provider exception while `false` means fallback to subset without any tags. | No | -| runtime | bool | Whether run routing rule for every rpc invocation or use routing cache if available. | No | +| force | bool | The behavior when the instance subset is empty after routing. `true` means return no provider exception while `false` means fallback to subset without any tags. | No | +| runtime | bool | Whether to run the routing rule for every RPC invocation or use routing cache if available. | No | ## Tag -标签定义,根据 `match` 条件筛选出一部分地址子集。 +Tag definition, filtering out a subset of addresses based on `match` conditions. | Field | Type | Description | Required | | --- | --- | --- | --- | | name | string | The name of the tag used to match the `dubbo.tag` value in the request context. | Yes | -| match | MatchCondition | A set of criterion to be met for instances to be classified as member of this tag. | No | +| match | MatchCondition | A set of criteria to be met for instances to be classified as members of this tag. | No | ## MatchCondition -定义实例过滤条件,根据 Dubbo URL 地址中的特定参数进行过滤。 +Defines instance filtering conditions based on specific parameters in the Dubbo URL address. | Field | Type | Description | Required | | --- | --- | --- | --- | -| key | string | The name of the key in the Dubbo url address. | Yes | -| value | StringMatch (oneof) | The matching condition for the value in the Dubbo url address. | Yes | +| key | string | The name of the key in the Dubbo URL address. | Yes | +| value | StringMatch (oneof) | The matching condition for the value in the Dubbo URL address. | Yes | diff --git a/content/en/overview/what/overview.md b/content/en/overview/what/overview.md index 15f5ace8782d..023f7c3654b8 100644 --- a/content/en/overview/what/overview.md +++ b/content/en/overview/what/overview.md @@ -1,12 +1,12 @@ --- aliases: - - /zh/overview/what/overview/ - - /zh/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture/ - - /zh-cn/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture/ - - /zh-cn/overview/mannual/java-sdk/concepts-and-architecture/overall-architecture/ + - /en/overview/what/overview/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture/ + - /en/overview/mannual/java-sdk/concepts-and-architecture/overall-architecture/ description: "" -linkTitle: 概念与架构 -title: 了解 Dubbo 核心概念和架构 +linkTitle: Concepts and Architecture +title: Understanding Dubbo Core Concepts and Architecture type: docs weight: 1 --- @@ -15,102 +15,102 @@ weight: 1 ![architecture](/imgs/v3/concepts/architecture-2.png) -以上是 Dubbo 的工作原理图,从抽象架构上分为两层:**服务治理抽象控制面** 和 **Dubbo 数据面** 。 -* **服务治理控制面**。服务治理控制面不是特指如注册中心类的单个具体组件,而是对 Dubbo 治理体系的抽象表达。控制面包含协调服务发现的注册中心、流量管控策略、Dubbo Admin 控制台等,如果采用了 Service Mesh 架构则还包含 Istio 等服务网格控制面。 -* **Dubbo 数据面**。数据面代表集群部署的所有 Dubbo 进程,进程之间通过 RPC 协议实现数据交换,Dubbo 定义了微服务应用开发与调用规范并负责完成数据传输的编解码工作。 - * 服务消费者 (Dubbo Consumer),发起业务调用或 RPC 通信的 Dubbo 进程 - * 服务提供者 (Dubbo Provider),接收业务调用或 RPC 通信的 Dubbo 进程 +The above is a diagram of Dubbo's working principle, which is divided into two layers from an abstract architecture perspective: **Service Governance Abstract Control Plane** and **Dubbo Data Plane**. +* **Service Governance Control Plane**. The service governance control plane does not specifically refer to a single component like a registry but is an abstract expression of the Dubbo governance system. The control plane includes the registry that coordinates service discovery, traffic control strategies, Dubbo Admin console, etc. If the Service Mesh architecture is adopted, it also includes service mesh control planes like Istio. +* **Dubbo Data Plane**. The data plane represents all Dubbo processes deployed in the cluster. These processes exchange data through the RPC protocol. Dubbo defines the development and invocation specifications for microservice applications and is responsible for the encoding and decoding of data transmission. + * Service Consumer (Dubbo Consumer), the Dubbo process that initiates business calls or RPC communication + * Service Provider (Dubbo Provider), the Dubbo process that receives business calls or RPC communication -## Dubbo 数据面 -从数据面视角,Dubbo 帮助解决了微服务实践中的以下问题: -* Dubbo 作为 **服务开发框架** 约束了微服务定义、开发与调用的规范,定义了服务治理流程及适配模式 -* Dubbo 作为 **RPC 通信协议实现** 解决服务间数据传输的编解码问题 +## Dubbo Data Plane +From the data plane perspective, Dubbo helps solve the following problems in microservice practices: +* Dubbo, as a **service development framework**, constrains the definition, development, and invocation specifications of microservices, defining service governance processes and adaptation patterns. +* Dubbo, as an **RPC communication protocol implementation**, solves the encoding and decoding issues of data transmission between services. ![framework](/imgs/v3/what/framework1.png) -### 服务开发框架 -微服务的目标是构建足够小的、自包含的、独立演进的、可以随时部署运行的分布式应用程序,几乎每个语言都有类似的应用开发框架来帮助开发者快速构建此类微服务应用,比如 Java 微服务体系的 Spring Boot,它帮 Java 微服务开发者以最少的配置、最轻量的方式快速开发、打包、部署与运行应用。 +### Service Development Framework +The goal of microservices is to build sufficiently small, self-contained, independently evolving, and deployable distributed applications that can run at any time. Almost every language has similar application development frameworks to help developers quickly build such microservice applications. For example, Spring Boot in the Java microservice ecosystem helps Java microservice developers quickly develop, package, deploy, and run applications with minimal configuration and in the most lightweight manner. -微服务的分布式特性,使得应用间的依赖、网络交互、数据传输变得更频繁,因此不同的**应用需要定义、暴露或调用 RPC 服务,那么这些 RPC 服务如何定义、如何与应用开发框架结合、服务调用行为如何控制?这就是 Dubbo 服务开发框架的含义,Dubbo 在微服务应用开发框架之上抽象了一套 RPC 服务定义、暴露、调用与治理的编程范式**,比如 Dubbo Java 作为服务开发框架,当运行在 Spring 体系时就是构建在 Spring Boot 应用开发框架之上的微服务开发框架,并在此之上抽象了一套 RPC 服务定义、暴露、调用与治理的编程范式。 +The distributed nature of microservices makes dependencies, network interactions, and data transmission between applications more frequent. Therefore, different **applications need to define, expose, or invoke RPC services. How are these RPC services defined, how do they integrate with the application development framework, and how is service invocation controlled? This is the meaning of the Dubbo service development framework. Dubbo abstracts a set of RPC service definition, exposure, invocation, and governance programming paradigms on top of the microservice application development framework.** For example, Dubbo Java, as a service development framework, is a microservice development framework built on the Spring Boot application development framework when running in the Spring ecosystem. It abstracts a set of RPC service definition, exposure, invocation, and governance programming paradigms on top of it. ![framework](/imgs/v3/what/framework2.png) -Dubbo 作为服务开发框架包含的具体内容如下: -* **RPC 服务定义、开发范式**。比如 Dubbo 支持通过 IDL 定义服务,也支持编程语言特有的服务开发定义方式,如通过 Java Interface 定义服务。 -* **RPC 服务发布与调用 API**。Dubbo 支持同步、异步、Reactive Streaming 等服务调用编程模式,还支持请求上下文 API、设置超时时间等。 -* **服务治理策略、流程与适配方式等**。作为服务框架数据面,Dubbo 定义了服务地址发现、负载均衡策略、基于规则的流量路由、Metrics 指标采集等服务治理抽象,并适配到特定的产品实现。 +The specific contents included in Dubbo as a service development framework are as follows: +* **RPC service definition and development paradigm**. For example, Dubbo supports defining services through IDL and also supports service development definition methods specific to programming languages, such as defining services through Java Interface. +* **RPC service publishing and invocation API**. Dubbo supports synchronous, asynchronous, Reactive Streaming, and other service invocation programming models. It also supports request context API, setting timeout, etc. +* **Service governance strategies, processes, and adaptation methods**. As the data plane of the service framework, Dubbo defines service address discovery, load balancing strategies, rule-based traffic routing, Metrics collection, and other service governance abstractions, and adapts them to specific product implementations. -想了解如何使用 Dubbo 微服务框架进行业务编码?从以下 SDK 开始微服务项目开发之旅吧: -* [Java](/zh-cn/overview/quickstart/java/) -* [Golang](/zh-cn/overview/quickstart/go/) -* [Rust](/zh-cn/overview/quickstart/rust/) +Want to know how to use the Dubbo microservice framework for business coding? Start your microservice project development journey with the following SDKs: +* [Java](/en/overview/quickstart/java/) +* [Golang](/en/overview/quickstart/go/) +* [Rust](/en/overview/quickstart/rust/) * [Node](https://github.com/apache/dubbo-js) -### 通信协议 -**Dubbo 从设计上不绑定任何一款特定通信协议,HTTP/2、REST、gRPC、JsonRPC、Thrift、Hessian2 等几乎所有主流的通信协议,Dubbo 框架都可以提供支持。** 这样的 Protocol 设计模式给构建微服务带来了最大的灵活性,开发者可以根据需要如性能、通用型等选择不同的通信协议,不再需要任何的代理来实现协议转换,甚至你还可以通过 Dubbo 实现不同协议间的迁移。 +### Communication Protocol +**Dubbo is designed not to bind to any specific communication protocol. HTTP/2, REST, gRPC, JsonRPC, Thrift, Hessian2, and almost all mainstream communication protocols are supported by the Dubbo framework.** This Protocol design pattern brings maximum flexibility to building microservices. Developers can choose different communication protocols based on needs such as performance and generality, without requiring any proxies for protocol conversion. You can even achieve protocol migration through Dubbo. ![protocols](/imgs/v3/what/protocol.png) -Dubbo Protocol 被设计支持扩展,您可以将内部私有协议适配到 Dubbo 框架上,进而将私有协议接入 Dubbo 体系,以享用 Dubbo 的开发体验与服务治理能力。比如 Dubbo3 的典型用户阿里巴巴,就是通过扩展支持 HSF 协议实现了内部 HSF 框架到 Dubbo3 框架的整体迁移。 +Dubbo Protocol is designed to support extensions, allowing you to adapt internal private protocols to the Dubbo framework, thereby integrating private protocols into the Dubbo system to enjoy Dubbo's development experience and service governance capabilities. For example, Alibaba, a typical user of Dubbo3, achieved the overall migration from the internal HSF framework to the Dubbo3 framework by extending support for the HSF protocol. -Dubbo 还支持多协议暴露,您可以在单个端口上暴露多个协议,Dubbo Server 能够自动识别并确保请求被正确处理,也可以将同一个 RPC 服务发布在不同的端口(协议),为不同技术栈的调用方服务。 +Dubbo also supports multi-protocol exposure, allowing you to expose multiple protocols on a single port. The Dubbo Server can automatically recognize and ensure that requests are correctly processed. You can also publish the same RPC service on different ports (protocols) to serve callers from different technology stacks. -Dubbo 提供了两款内置高性能 Dubbo2、Triple (兼容 gRPC) 协议实现,以满足部分微服务用户对高性能通信的诉求,两者最开始都设计和诞生于阿里巴巴内部的高性能通信业务场景。 -* Dubbo2 协议是在 TCP 传输层协议之上设计的二进制通信协议 -* Triple 则是基于 HTTP/2 之上构建的支持流式模式的通信协议,并且 Triple 完全兼容 gRPC 但实现上做了更多的符合 Dubbo 框架特点的优化。 +Dubbo provides two built-in high-performance protocol implementations, Dubbo2 and Triple (compatible with gRPC), to meet the high-performance communication needs of some microservice users. Both were initially designed and born in Alibaba's internal high-performance communication business scenarios. +* The Dubbo2 protocol is a binary communication protocol designed on top of the TCP transport layer protocol. +* Triple is a streaming communication protocol built on top of HTTP/2, fully compatible with gRPC but optimized to better fit the Dubbo framework. -总的来说,Dubbo 对通信协议的支持具有以下特点: -* 不绑定通信协议 -* 提供高性能通信协议实现 -* 支持流式通信模型 -* 不绑定序列化协议 -* 支持单个服务的多协议暴露 -* 支持单端口多协议发布 -* 支持一个应用内多个服务使用不同通信协议 +In summary, Dubbo's support for communication protocols has the following characteristics: +* Not bound to a specific communication protocol +* Provides high-performance communication protocol implementations +* Supports streaming communication models +* Not bound to a specific serialization protocol +* Supports multi-protocol exposure for a single service +* Supports multi-protocol publishing on a single port +* Supports different communication protocols for multiple services within an application -## Dubbo 服务治理 -服务开发框架解决了开发与通信的问题,但在微服务集群环境下,我们仍需要解决无状态服务节点动态变化、外部化配置、日志跟踪、可观测性、流量管理、高可用性、数据一致性等一系列问题,我们将这些问题统称为服务治理。 +## Dubbo Service Governance +While a service development framework solves development and communication issues, in a microservice cluster environment, we still need to address a series of issues such as dynamic changes of stateless service nodes, externalized configuration, log tracing, observability, traffic management, high availability, and data consistency. We collectively refer to these issues as service governance. -Dubbo 抽象了一套微服务治理模式并发布了对应的官方实现,服务治理可帮助简化微服务开发与运维,让开发者更专注在微服务业务本身。 +Dubbo abstracts a set of microservice governance patterns and releases corresponding official implementations. Service governance helps simplify microservice development and operations, allowing developers to focus more on the microservice business itself. -### 服务治理抽象 +### Service Governance Abstraction -以下展示了 Dubbo 核心的服务治理功能定义 +The following shows the core service governance functions defined by Dubbo ![governance](/imgs/v3/what/governance.png) -* **地址发现** +* **Address Discovery** -Dubbo 服务发现具备高性能、支持大规模集群、服务级元数据配置等优势,默认提供 Nacos、Zookeeper、Consul 等多种注册中心适配,与 Spring Cloud、Kubernetes Service 模型打通,支持自定义扩展。 +Dubbo service discovery has advantages such as high performance, support for large-scale clusters, and service-level metadata configuration. It provides multiple registry adapters by default, including Nacos, Zookeeper, Consul, etc., integrates with Spring Cloud and Kubernetes Service models, and supports custom extensions. -* **负载均衡** +* **Load Balancing** -Dubbo 默认提供加权随机、加权轮询、最少活跃请求数优先、最短响应时间优先、一致性哈希和自适应负载等策略 +Dubbo provides default strategies such as weighted random, weighted round-robin, least active requests first, shortest response time first, consistent hashing, and adaptive load balancing. -* **流量路由** +* **Traffic Routing** -Dubbo 支持通过一系列流量规则控制服务调用的流量分布与行为,基于这些规则可以实现基于权重的比例流量分发、灰度验证、金丝雀发布、按请求参数的路由、同区域优先、超时配置、重试、限流降级等能力。 +Dubbo supports controlling the distribution and behavior of service call traffic through a series of traffic rules. Based on these rules, capabilities such as weighted traffic distribution, gray verification, canary release, routing by request parameters, region priority, timeout configuration, retries, rate limiting, and degradation can be achieved. -* **链路追踪** +* **Link Tracing** -Dubbo 官方通过适配 OpenTelemetry 提供了对 Tracing 全链路追踪支持,用户可以接入支持 OpenTelemetry 标准的产品如 Skywalking、Zipkin 等。另外,很多社区如 Skywalking、Zipkin 等在官方也提供了对 Dubbo 的适配。 +Dubbo officially provides support for full-link tracing through adaptation to OpenTelemetry. Users can integrate products that support the OpenTelemetry standard, such as Skywalking and Zipkin. Additionally, many communities like Skywalking and Zipkin also provide adaptations for Dubbo. -* **可观测性** +* **Observability** -Dubbo 实例通过 Prometheus 等上报 QPS、RT、请求次数、成功率、异常次数等多维度的可观测指标帮助了解服务运行状态,通过接入 Grafana、Admin 控制台帮助实现数据指标可视化展示。 +Dubbo instances report multi-dimensional observability metrics such as QPS, RT, request count, success rate, and exception count through Prometheus, helping to understand the service running status. By integrating with Grafana and the Admin console, data metrics can be visually displayed. -Dubbo 服务治理生态还提供了对 **API 网关**、**限流降级**、**数据一致性**、**认证鉴权**等场景的适配支持。 +The Dubbo service governance ecosystem also provides adaptation support for scenarios such as **API Gateway**, **Rate Limiting and Degradation**, **Data Consistency**, and **Authentication and Authorization**. ### Dubbo Admin -Admin 控制台提供了 Dubbo 集群的可视化视图,通过 Admin 你可以完成集群的几乎所有管控工作。 -* 查询服务、应用或机器状态 -* 创建项目、服务测试、文档管理等 -* 查看集群实时流量、定位异常问题等 -* 流量比例分发、参数路由等流量管控规则下发 +The Admin console provides a visual view of the Dubbo cluster. Through Admin, you can complete almost all management tasks of the cluster. +* Query the status of services, applications, or machines +* Create projects, service testing, document management, etc. +* View real-time cluster traffic, locate abnormal issues, etc. +* Issue traffic control rules such as traffic distribution and parameter routing ![Admin](/imgs/v3/what/admin.png) -### 服务网格 -将 Dubbo 接入 Istio 等服务网格治理体系。 +### Service Mesh +Integrate Dubbo into service mesh governance systems like Istio. ![Dubbo-Mesh](/imgs/v3/mesh/mix-mesh.png) diff --git a/content/en/overview/what/xyz-difference.md b/content/en/overview/what/xyz-difference.md index 1e12b8f08439..47bd4b821cfc 100644 --- a/content/en/overview/what/xyz-difference.md +++ b/content/en/overview/what/xyz-difference.md @@ -1,84 +1,86 @@ --- aliases: - - /zh/overview/what/xyz-difference/ + - /en/overview/what/xyz-difference/ description: "" -linkTitle: 与 gRPC、Spring Cloud、Istio 关系 -title: 与 gRPC、Spring Cloud、Istio 的关系 +linkTitle: Relationship with gRPC, Spring Cloud, Istio +title: Relationship with gRPC, Spring Cloud, Istio type: docs weight: 2 --- -很多开发者经常会问到 Apache Dubbo 与 Spring Cloud、gRPC 以及一些 Service Mesh 项目如 Istio 的关系,要解释清楚它们的关系并不困难,你只需要跟随这篇文章和 Dubbo 文档做一些更深入的了解,但总的来说,它们之间有些能力是重合的,但在一些场景你可以把它们放在一起使用。 +Many developers often ask about the relationship between Apache Dubbo and Spring Cloud, gRPC, and some Service Mesh projects like Istio. Explaining their relationships is not difficult; you just need to follow this article and delve deeper into the Dubbo documentation. In general, some of their capabilities overlap, but in some scenarios, you can use them together. -虽然这是一篇 Dubbo 维护者写的文档,我们仍会尽力将 Dubbo 与其他组件之间的联系与差异客观、透明的展现出来,但考虑到每个人对不同产品的熟悉程度不一,这里的个别表述可能并不完全准确,希望能给开发者带来帮助。 +Although this document is written by Dubbo maintainers, we will still strive to objectively and transparently present the connections and differences between Dubbo and other components. However, considering that everyone's familiarity with different products varies, some expressions here may not be entirely accurate. We hope this can help developers. -## Dubbo 与 Spring Cloud +## Dubbo and Spring Cloud ![dubbo-springcloud](/imgs/v3/difference/dubbo-springcloud.png) -从上图我们可以看出,Dubbo 和 Spring Cloud 有很多相似之处,它们都在整个架构图的相同位置并提供一些相似的功能。 +From the above diagram, we can see that Dubbo and Spring Cloud have many similarities. They are both positioned at the same level in the overall architecture and provide some similar functionalities. -* **Dubbo 和 Spring Cloud 都侧重在对分布式系统中常见问题模式的抽象(如服务发现、负载均衡、动态配置等)**,同时对每一个问题都提供了配套组件实现,形成了一套微服务整体解决方案,让使用 Dubbo 及 Spring Cloud 的用户在开发微服务应用时可以专注在业务逻辑开发上。 -* **Dubbo 和 Spring Cloud 都完全兼容 Spring 体系的应用开发模式**,Dubbo 对 Spring 应用开发框架、Spring Boot 微服务框架都做了很好的适配,由于 Spring Cloud 出自 Spring 体系,在这一点上自然更不必多说。 +* **Both Dubbo and Spring Cloud focus on abstracting common problem patterns in distributed systems (such as service discovery, load balancing, dynamic configuration, etc.)**. They provide supporting component implementations for each problem, forming a comprehensive microservice solution that allows users of Dubbo and Spring Cloud to focus on business logic development when developing microservice applications. +* **Both Dubbo and Spring Cloud are fully compatible with the Spring application development model**. Dubbo has well adapted to the Spring application development framework and the Spring Boot microservice framework. Since Spring Cloud originates from the Spring ecosystem, this point is naturally more evident. -虽然两者有很多相似之处,但由于它们在诞生背景与架构设计上的巨大差异,**两者在性能、适用的微服务集群规模、生产稳定性保障、服务治理等方面都有很大差异**。 +Although they have many similarities, due to their significant differences in background and architectural design, **they differ greatly in performance, applicable microservice cluster scale, production stability assurance, and service governance**. -Spring Cloud 的优势在于: -* 同样都支持 Spring 开发体系的情况下,Spring Cloud 得到更多的原生支持 -* 对一些常用的微服务模式做了抽象如服务发现、动态配置、异步消息等,同时包括一些批处理任务、定时任务、持久化数据访问等领域也有涉猎。 -* 基于 HTTP 的通信模式,加上相对比较完善的入门文档和演示 demo 和 starters,让开发者在第一感觉上更易于上手 +Spring Cloud's advantages include: +* While both support the Spring development ecosystem, Spring Cloud receives more native support. +* It abstracts some common microservice patterns such as service discovery, dynamic configuration, asynchronous messaging, etc., and also touches on areas like batch processing tasks, scheduled tasks, and persistent data access. +* Based on HTTP communication mode, along with relatively comprehensive introductory documentation, demo, and starters, it gives developers an easier initial experience. -Spring Cloud 的问题有: -* 只提供抽象模式的定义不提供官方稳定实现,开发者只能寻求类似 Netflix、Alibaba、Azure 等不同厂商的实现套件,而每个厂商支持的完善度、稳定性、活跃度各异 -* 有微服务全家桶却不是能拿来就用的全家桶,demo 上手容易,但落地推广与长期使用的成本非常高 -* 欠缺服务治理能力,尤其是流量管控方面如负载均衡、流量路由方面能力都比较弱 -* 编程模型与通信协议绑定 HTTP,在性能、与其他 RPC 体系互通上存在障碍 -* 总体架构与实现只适用于小规模微服务集群实践,当集群规模增长后就会遇到地址推送效率、内存占用等各种瓶颈的问题,但此时迁移到其他体系却很难实现 -* 很多微服务实践场景的问题需要用户独自解决,比如优雅停机、启动预热、服务测试,再比如双注册、双订阅、延迟注册、服务按分组隔离、集群容错等 +Spring Cloud's issues include: +* It only provides abstract pattern definitions without official stable implementations. Developers have to seek implementation suites from different vendors like Netflix, Alibaba, Azure, etc., each varying in completeness, stability, and activity. +* It offers a microservice full-stack solution but is not ready-to-use. While demos are easy to start with, the cost of implementation and long-term use is very high. +* Lacks service governance capabilities, especially in traffic control aspects like load balancing and traffic routing. +* The programming model and communication protocol are bound to HTTP, posing obstacles in performance and interoperability with other RPC systems. +* The overall architecture and implementation are only suitable for small-scale microservice cluster practices. As the cluster scale grows, issues like address push efficiency and memory usage bottlenecks arise, making migration to other systems difficult. +* Many microservice practice scenarios require users to solve problems independently, such as graceful shutdown, startup warm-up, service testing, dual registration, dual subscription, delayed registration, service isolation by group, cluster fault tolerance, etc. -而以上这些点,都是 **Dubbo 的优势**所在: -* 完全支持 Spring & Spring Boot 开发模式,同时在服务发现、动态配置等基础模式上提供与 Spring Cloud 对等的能力。 -* 是企业级微服务实践方案的整体输出,Dubbo 考虑到了企业微服务实践中会遇到的各种问题如优雅上下线、多注册中心、流量管理等,因此其在生产环境的长期维护成本更低 -* 在通信协议和编码上选择更灵活,包括 rpc 通信层协议如 HTTP、HTTP/2(Triple、gRPC)、TCP 二进制协议、rest等,序列化编码协议Protobuf、JSON、Hessian2 等,支持单端口多协议。 -* Dubbo 从设计上突出服务服务治理能力,如权重动态调整、标签路由、条件路由等,支持 Proxyless 等多种模式接入 Service Mesh 体系 -* 高性能的 RPC 协议编码与实现, -* Dubbo 是在超大规模微服务集群实践场景下开发的框架,可以做到百万实例规模的集群水平扩容,应对集群增长带来的各种问题 -* Dubbo 提供 Java 外的多语言实现,使得构建多语言异构的微服务体系成为可能 +All these points are **Dubbo's advantages**: +* Fully supports Spring & Spring Boot development models, while providing equivalent capabilities to Spring Cloud in basic patterns like service discovery and dynamic configuration. +* It is an overall output of enterprise-level microservice practice solutions. Dubbo considers various issues encountered in enterprise microservice practices, such as graceful online and offline, multiple registration centers, traffic management, etc., thus having lower long-term maintenance costs in production environments. +* Offers more flexible choices in communication protocols and encoding, including RPC communication layer protocols like HTTP, HTTP/2 (Triple, gRPC), TCP binary protocols, REST, etc., and serialization encoding protocols like Protobuf, JSON, Hessian2, supporting single-port multi-protocol. +* Dubbo emphasizes service governance capabilities in its design, such as dynamic weight adjustment, tag routing, conditional routing, etc., supporting multiple modes like Proxyless to integrate into the Service Mesh ecosystem. +* High-performance RPC protocol encoding and implementation. +* Dubbo is a framework developed for ultra-large-scale microservice cluster practice scenarios, capable of scaling to a million-instance cluster level, addressing various issues brought by cluster growth. +* Dubbo provides multi-language implementations beyond Java, making it possible to build a multi-language heterogeneous microservice system. -如果您的目标是构建企业级应用,并期待在未来的持久维护中能够更省心、更稳定,我们建议你能更深入的了解 Dubbo 的使用和其提供的能力。 -> Dubbo 在入门资料上的欠缺是对比 Spring Cloud 的一个劣势,这体现在依赖配置管理、文档、demo 示例完善度上,当前整个社区在重点投入这一部分的建设,期望能降低用户在第一天体验和学习 Dubbo 时的门槛,不让开发者因为缺乏文档而错失 Dubbo 这样一款优秀的产品。 +If your goal is to build enterprise-level applications and you expect more ease and stability in future maintenance, we recommend that you gain a deeper understanding of Dubbo's usage and its capabilities. +> The lack of introductory materials for Dubbo is a disadvantage compared to Spring Cloud. This is reflected in the completeness of dependency configuration management, documentation, and demo examples. The entire community is currently focusing on building this part, hoping to lower the threshold for users to experience and learn Dubbo on the first day, so that developers do not miss out on such an excellent product due to a lack of documentation. -## Dubbo 与 gRPC -Dubbo 与 gRPC 最大的差异在于两者的定位上: -* **gRPC 定位为一款 RPC 框架**,Google 推出它的核心目标是定义云原生时代的 rpc 通信规范与标准实现; -* **Dubbo 定位是一款微服务开发框架**,它侧重解决微服务实践从服务定义、开发、通信到治理的问题,因此 Dubbo 同时提供了 RPC 通信、与应用开发框架的适配、服务治理等能力。 +## Dubbo and gRPC +The biggest difference between Dubbo and gRPC lies in their positioning: +* **gRPC is positioned as an RPC framework**. Google's core goal in launching it is to define the rpc communication specification and standard implementation in the cloud-native era; +* **Dubbo is positioned as a microservice development framework**. It focuses on solving the problems of microservice practice from service definition, development, communication to governance. Therefore, Dubbo provides capabilities such as RPC communication, adaptation with application development frameworks, and service governance. -Dubbo 不绑定特定的通信协议,即 Dubbo 服务间可通过多种 RPC 协议通信并支持灵活切换。因此,你可以在 Dubbo 开发的微服务中选用 gRPC 通信,**Dubbo 完全兼容 gRPC,并将 gRPC 设计为内置原生支持的协议之一**。 +Dubbo does not bind to a specific communication protocol, meaning that Dubbo services can communicate through multiple RPC protocols and support flexible switching. Therefore, you can choose gRPC communication in microservices developed with Dubbo. **Dubbo is fully compatible with gRPC and has designed gRPC as one of the built-in native supported protocols**. ![dubbo-grpc](/imgs/v3/difference/dubbo-grpc.png) -如果您看中基于 HTTP/2 的通信协议、基于 Protobuf 的服务定义,并基于此决定选型 gRPC 作为微服务开发框架,那很有可能您会在未来的微服务业务开发中遇到障碍,这主要源于 gRPC 没有为开发者提供以下能力: -* 缺乏与业务应用框架集成的开发模式,用户需要基于 gRPC 底层的 RPC API 定义、发布或调用微服务,中间可能还有与业务应用开发框架整合的问题 -* 缺乏微服务周边生态扩展与适配,如服务发现、限流降级、链路追踪等没有多少可供选择的官方实现,且扩展起来非常困难 -* 缺乏服务治理能力,作为一款 rpc 框架,缺乏对服务治理能力的抽象 +If you value the communication protocol based on HTTP/2 and the service definition based on Protobuf, and based on this, decide to choose gRPC as the microservice development framework, you are likely to encounter obstacles in future microservice business development. This is mainly because gRPC does not provide the following capabilities for developers: +* Lack of a development model integrated with business application frameworks. Users need to define, publish, or call microservices based on the underlying RPC API of gRPC, and there may be issues with integration with business application development frameworks in between. +* Lack of microservice peripheral ecosystem extensions and adaptations, such as service discovery, rate limiting, degradation, and link tracing, with few official implementations to choose from, and very difficult to extend. +* Lack of service governance capabilities. As an RPC framework, it lacks abstraction for service governance capabilities. -因此,gRPC 更适合作为底层的通信协议规范或编解码包,而 Dubbo 则可用作微服务整体解决方案。**对于 gRPC 协议,我们推荐的使用模式 Dubbo + gRPC 的组合**,这个时候,gRPC 只是隐藏在底层的一个通信协议,不被微服务开发者感知,开发者基于 Dubbo 提供的 API 和配置开发服务,并基于 dubbo 的服务治理能力治理服务,在未来,开发者还能使用 Dubbo 生态和开源的 IDL 配套工具管理服务定义与发布。 +Therefore, gRPC is more suitable as an underlying communication protocol specification or codec package, while Dubbo can be used as an overall microservice solution. **For the gRPC protocol, we recommend the combination of Dubbo + gRPC**. At this time, gRPC is just a communication protocol hidden at the bottom, not perceived by microservice developers. Developers develop services based on the API and configuration provided by Dubbo and govern services based on Dubbo's service governance capabilities. In the future, developers can also use Dubbo's ecosystem and open-source IDL supporting tools to manage service definitions and publishing. -如果我们忽略 gRPC 在应用开发框架侧的空白,只考虑如何给 gRPC 带来服务治理能力,则另一种可以采用的模式就是在 Service Mesh 架构下使用 gRPC,这就引出了我们下一小节要讨论的内容:Dubbo 与 Service Mesh 架构的关系。 +If we ignore the gap of gRPC on the application development framework side and only consider how to bring service governance capabilities to gRPC, another mode that can be adopted is to use gRPC under the Service Mesh architecture. This leads to the content we will discuss in the next section: the relationship between Dubbo and the Service Mesh architecture. -## Dubbo 与 Istio -Service Mesh 是近年来在云原生背景下诞生的一种微服务架构,在 Kubernetes 体系下,让微服务开发中的更多能力如流量拦截、服务治理等下沉并成为基础设施,让微服务开发、升级更轻量。Istio 是 Service Mesh 的开源代表实现,它从部署架构上分为数据面与控制面,从这一点上与 [Dubbo 总体架构](../overview) 是基本一致的,Istio 带来的主要变化在于: -* 数据面,Istio 通过引入 Sidecar 实现了对服务流量的透明拦截,Sidecar 通常是与 Dubbo 等开发的传统微服务组件部署在一起 -* 控制面,将之前抽象的服务治理中心聚合为一个具有统一实现的具体组件,并实现了与底层基础设施如 Kubernetes 无缝适配 +## Dubbo and Istio +Service Mesh is a microservice architecture born in the context of cloud-native in recent years. Under the Kubernetes system, it allows more capabilities in microservice development, such as traffic interception and service governance, to sink and become infrastructure, making microservice development and upgrades lighter. Istio is an open-source representative implementation of Service Mesh. It is divided into data plane and control plane from the deployment architecture, which is basically consistent with the [Dubbo overall architecture](../overview). The main changes brought by Istio are: +* Data plane: Istio achieves transparent interception of service traffic by introducing Sidecar. Sidecar is usually deployed together with traditional microservice components developed by Dubbo, etc. +* Control plane: The previously abstract service governance center is aggregated into a specific component with a unified implementation and seamlessly adapted to underlying infrastructures such as Kubernetes. -**Dubbo 已经实现了对 Istio 体系的全面接入,可以用 Istio 控制面治理 Dubbo 服务,而在数据面部署架构上,针对 Sidecar 引入的复杂性与性能问题,Dubbo 还支持无代理的 Proxyless 模式。** 除此之外,Dubbo Mesh 体系还解决了 Istio 架构落地过程中的很多问题,包括提供更灵活的数据面部署架构、更低的迁移成本等。 +**Dubbo has fully integrated with the Istio system. You can use the Istio control plane to govern Dubbo services. In terms of data plane deployment architecture, Dubbo also supports a proxyless mode to address the complexity and performance issues introduced by Sidecar.** In addition, the Dubbo Mesh system also solves many problems in the implementation process of the Istio architecture, including providing a more flexible data plane deployment architecture and lower migration costs. ![Dubbo-Mesh](/imgs/v3/mesh/mix-mesh.png) -从**数据面**的视角,Dubbo 支持如下两种开发和部署模式,可以通过 Istio、Consul、Linkerd 等控制面组件实现对数据面服务的治理。 -* Proxy 模式,Dubbo 与 Envoy 一起部署,Dubbo 作为编程框架 & 协议通信组件存在,流量管控由 Envoy 与 Istio 控制面交互实现。 -* Proxyless 模式,Dubbo 进程保持独立部署,Dubbo 通过标准 xDS 协议直接接入 Istio 等控制面组件。 +From the perspective of the **data plane**, Dubbo supports the following two development and deployment modes, which can achieve governance of data plane services through control plane components such as Istio, Consul, and Linkerd. +* Proxy mode: Dubbo is deployed together with Envoy. Dubbo exists as a programming framework & protocol communication component, and traffic control is achieved through interaction between Envoy and the Istio control plane. +* Proxyless mode: The Dubbo process remains independently deployed, and Dubbo directly connects to control plane components such as Istio through the standard xDS protocol. -从**控制面**视角,Dubbo 可接入原生 Istio 标准控制面和规则体系,而对于一些 Dubbo 老版本用户,Dubbo Mesh 提供了平滑迁移方案,具体请查看 [Dubbo Mesh 服务网格](../../tasks/mesh/)。 +From the perspective of the **control plane**, Dubbo can connect to the native Istio standard control plane and rule system. For some old version Dubbo users, Dubbo Mesh provides a smooth migration solution. For details, please refer to [Dubbo Mesh Service Mesh](../../tasks/mesh/). + +It seems like you haven't pasted the Markdown content yet. Please provide the content you need translated, and I'll handle the translation for you. From c43a804ed3b0b77ccf42b971c5c4368c260c4b7f Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Mon, 30 Sep 2024 14:02:04 +0800 Subject: [PATCH 03/23] Replace addr --- content/en/docs3-v2/golang-sdk/preface/concept/registry.md | 2 +- .../performance/simplify-registry-data.md | 2 +- .../java-sdk/advanced-features-and-usage/security/tls.md | 2 +- .../advanced-features-and-usage/service/consistent-hash.md | 2 +- .../service/distributed-transaction.md | 2 +- .../advanced-features-and-usage/service/service-downgrade.md | 2 +- content/en/docs3-v2/java-sdk/faq/2/13.md | 2 +- .../docs3-v2/java-sdk/reference-manual/config-center/nacos.md | 2 +- .../en/docs3-v2/java-sdk/reference-manual/config/overview.md | 2 +- .../java-sdk/reference-manual/protocol/triple/overview.md | 2 +- .../java-sdk/upgrades-and-compatibility/migration-triple.md | 2 +- content/en/overview/reference/erlang-sdk/_index.md | 3 +-- 12 files changed, 12 insertions(+), 13 deletions(-) diff --git a/content/en/docs3-v2/golang-sdk/preface/concept/registry.md b/content/en/docs3-v2/golang-sdk/preface/concept/registry.md index 4b9a1229ba28..fa9ca49866ad 100644 --- a/content/en/docs3-v2/golang-sdk/preface/concept/registry.md +++ b/content/en/docs3-v2/golang-sdk/preface/concept/registry.md @@ -84,4 +84,4 @@ The registry types supported by Dubbo-go are as follows: | Etcd | etcd | | Consul | consul | -Related reading: [[Analysis of application-level service discovery]](https://developer.aliyun.com/article/764173) \ No newline at end of file +Related reading: [[Analysis of application-level service discovery]](https://developer.aliyun.com/article/764173) diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/simplify-registry-data.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/simplify-registry-data.md index 2555e6d6681c..60db7c0b6c14 100644 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/simplify-registry-data.md +++ b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/simplify-registry-data.md @@ -252,4 +252,4 @@ public RegistryConfig registryConfig() { #### hint: -This version also retains a large number of configuration items, and in the next version, all configuration items will be gradually deleted. \ No newline at end of file +This version also retains a large number of configuration items, and in the next version, all configuration items will be gradually deleted. diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/tls.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/tls.md index 50bf888900c2..31802fb6a815 100644 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/tls.md +++ b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/tls.md @@ -52,4 +52,4 @@ if (!mutualTls) {} In order to ensure the flexibility of application startup as much as possible, the specification of TLS Cert can also be dynamically specified during the startup phase according to the deployment environment through -D parameters or environment variables. Refer to Dubbo [Configuration Read Rules](/zh-cn/docs/advanced /config-rule) -> On the security of service calls, Dubbo will continue to invest in subsequent versions, and the authentication mechanism for service discovery/calling is expected to meet you in the next version. \ No newline at end of file +> On the security of service calls, Dubbo will continue to invest in subsequent versions, and the authentication mechanism for service discovery/calling is expected to meet you in the next version. diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/consistent-hash.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/consistent-hash.md index 18ef89c574fd..6ab48e08fe5e 100644 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/consistent-hash.md +++ b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/consistent-hash.md @@ -44,4 +44,4 @@ parameters. put("sayHello. hash. arguments", "0,1"); referenceConfig.setParameters(parameters); referenceConfig.setLoadBalance("consistenthash"); referenceConfig. get(); -``` \ No newline at end of file +``` diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction.md index 688161f38660..efd9919644ff 100644 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction.md +++ b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction.md @@ -12,4 +12,4 @@ Distributed transactions are implemented based on the JTA/XA specification. ![/user-guide/images/jta-xa.jpg](/imgs/user/jta-xa.jpg) -In Dubbo, you can use [seata](/zh-cn/blog/2019/01/17/How to use seata to ensure the consistency between dubbo microservices/) to complete the support for distributed transactions. \ No newline at end of file +In Dubbo, you can use [seata](/zh-cn/blog/2019/01/17/How to use seata to ensure the consistency between dubbo microservices/) to complete the support for distributed transactions. diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade.md index 533f049dba05..0cdfe52442ef 100644 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade.md +++ b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade.md @@ -83,4 +83,4 @@ When Dubbo starts, it will check the configuration. When the configuration of th - The configuration format is wrong, such as `return+null` will report an error, and it will be treated as a mock type. `return` can be omitted or followed by a space followed by the return value -- Type not found error, such as custom mock class, throw custom exception, please check if the type exists or if there is a typo \ No newline at end of file +- Type not found error, such as custom mock class, throw custom exception, please check if the type exists or if there is a typo diff --git a/content/en/docs3-v2/java-sdk/faq/2/13.md b/content/en/docs3-v2/java-sdk/faq/2/13.md index 40228c0065f6..fe5b0f9e7e78 100644 --- a/content/en/docs3-v2/java-sdk/faq/2/13.md +++ b/content/en/docs3-v2/java-sdk/faq/2/13.md @@ -14,4 +14,4 @@ weight: 2 -

\ No newline at end of file +

diff --git a/content/en/docs3-v2/java-sdk/reference-manual/config-center/nacos.md b/content/en/docs3-v2/java-sdk/reference-manual/config-center/nacos.md index cdaa841ca1e3..2dc71866133a 100644 --- a/content/en/docs3-v2/java-sdk/reference-manual/config-center/nacos.md +++ b/content/en/docs3-v2/java-sdk/reference-manual/config-center/nacos.md @@ -109,4 +109,4 @@ There are many types of traffic governance rules, and the suffixes of dataId for - configurators, [override rules](/zh-cn/overview/core-features/traffic/configuration-rule/) - tag-router, [tag routing](/zh-cn/overview/core-features/traffic/tag-rule/) -- condition-router, [conditional routing](/zh-cn/overview/core-features/traffic/condition-rule/) \ No newline at end of file +- condition-router, [conditional routing](/zh-cn/overview/core-features/traffic/condition-rule/) diff --git a/content/en/docs3-v2/java-sdk/reference-manual/config/overview.md b/content/en/docs3-v2/java-sdk/reference-manual/config/overview.md index fc7dc095d8d4..0246e4bdc243 100644 --- a/content/en/docs3-v2/java-sdk/reference-manual/config/overview.md +++ b/content/en/docs3-v2/java-sdk/reference-manual/config/overview.md @@ -163,4 +163,4 @@ Dubbo follows a [path-based configuration specification](../principle/), and eac - Externalized Configuration, [externalized configuration] (../principle/#33-externalized configuration), read from the configuration center - Application Configuration, application attribute configuration, extract the attribute set starting with "dubbo" from the Spring application Environment - The configuration collected by programming interfaces such as API/XML/annotation can be understood as a kind of configuration source, which is a configuration collection method directly oriented to user programming -- Read configuration file dubbo.properties from classpath \ No newline at end of file +- Read configuration file dubbo.properties from classpath diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview.md index 90cf1a4552eb..5b5bdb6e3df5 100644 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview.md +++ b/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview.md @@ -36,4 +36,4 @@ Since the bottom layer of the Triple protocol needs to rely on the protobuf prot protobuf-java 3.19.4
-``` \ No newline at end of file +``` diff --git a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple.md b/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple.md index 12ebb66babf6..0c1f60b9669d 100644 --- a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple.md +++ b/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple.md @@ -341,4 +341,4 @@ Grpc uses `compiler` to compile the written `proto` file into related protobuf o `stub` helps us shield the details of different calling methods in a unified way. However, currently `Dubbo3` only supports the traditional way of defining and calling interfaces. -In the near future, `Triple` will also implement various commonly used `Stub`, allowing users to write a `proto` file, which can be conveniently used in any scene through `comipler`, please wait and see. \ No newline at end of file +In the near future, `Triple` will also implement various commonly used `Stub`, allowing users to write a `proto` file, which can be conveniently used in any scene through `comipler`, please wait and see. diff --git a/content/en/overview/reference/erlang-sdk/_index.md b/content/en/overview/reference/erlang-sdk/_index.md index 4c0c196e3ae7..f5ced1570161 100755 --- a/content/en/overview/reference/erlang-sdk/_index.md +++ b/content/en/overview/reference/erlang-sdk/_index.md @@ -8,5 +8,4 @@ linkTitle: Erlang SDK title: Erlang SDK Manual type: docs weight: 8 -### - +--- From 5834cf2b9fd709966fddf062c23425e29aaff74a Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Mon, 30 Sep 2024 14:10:23 +0800 Subject: [PATCH 04/23] Add blog --- content/en/blog/ web/_index.md | 9 + content/en/blog/ web/web-announcement.md | 266 +++++ content/en/blog/golang/_index.md | 8 + content/en/blog/golang/dubbo-go-101.md | 191 +++ .../en/blog/golang/dubbo-go-app-registry.md | 116 ++ .../en/blog/golang/dubbo-go-cloud-native.md | 152 +++ content/en/blog/golang/dubbo-go-codewalk-1.md | 672 +++++++++++ content/en/blog/golang/dubbo-go-codewalk-2.md | 561 +++++++++ .../en/blog/golang/dubbo-go-config-center.md | 314 +++++ .../en/blog/golang/dubbo-go-first-glance.md | 205 ++++ content/en/blog/golang/dubbo-go-getty.md | 247 ++++ content/en/blog/golang/dubbo-go-grpc.md | 131 +++ .../golang/dubbo-go-hessian2-optimization.md | 245 ++++ content/en/blog/golang/dubbo-go-history.md | 139 +++ content/en/blog/golang/dubbo-go-intro.md | 160 +++ content/en/blog/golang/dubbo-go-k8s.md | 110 ++ content/en/blog/golang/dubbo-go-metrics.md | 156 +++ .../en/blog/golang/dubbo-go-moson-optimize.md | 501 ++++++++ content/en/blog/golang/dubbo-go-nacos.md | 117 ++ content/en/blog/golang/dubbo-go-oneyear.md | 204 ++++ content/en/blog/golang/dubbo-go-quickstart.md | 260 +++++ content/en/blog/golang/dubbo-go-rest.md | 245 ++++ content/en/blog/golang/dubbo-go-router.md | 295 +++++ content/en/blog/golang/dubbo-go-seata.md | 660 +++++++++++ content/en/blog/golang/dubbo-go-sentinel.md | 162 +++ content/en/blog/golang/dubbo-go-tps.md | 220 ++++ .../en/blog/golang/dubbo-go-trusted-call.md | 138 +++ content/en/blog/golang/dubbo-go-tuya.md | 285 +++++ .../en/blog/golang/dubbogo-from-scratch.md | 848 ++++++++++++++ content/en/blog/integration/_index.md | 9 + content/en/blog/integration/dubbo-admin.md | 90 ++ content/en/blog/integration/dubbo-fescar.md | 238 ++++ .../blog/integration/dubbo-graalvm-support.md | 298 +++++ .../dubbo-integrate-with-hystrix.md | 209 ++++ .../en/blog/integration/dubbo-meet-arthas.md | 367 ++++++ .../integration/dubbo-practice-from-guazi.md | 175 +++ .../dubbo-registry-nacos-integration.md | 562 +++++++++ .../en/blog/integration/dubbo-spring-cloud.md | 213 ++++ .../dubbo-triple-with-apisix-gateway.md | 154 +++ content/en/blog/integration/dubbo-zk.md | 346 ++++++ content/en/blog/integration/dubbo2-js.md | 278 +++++ .../how-to-proxy-dubbo-in-apache-apisix.md | 283 +++++ .../how-to-proxy-dubbo-in-apache-shenyu.md | 414 +++++++ .../how-to-proxy-dubbo-in-higress.md | 286 +++++ content/en/blog/integration/pinpoint.md | 424 +++++++ .../sentinel-introduction-for-dubbo.md | 141 +++ .../integration/tracing-with-skywalking.md | 142 +++ .../blog/integration/use-zipkin-in-dubbo.md | 605 ++++++++++ content/en/blog/java/_index.md | 9 + .../codeanalysis/3.0.8/1-learn-from-a-demo.md | 124 ++ ...\344\277\241\346\201\257RegistryConfig.md" | 230 ++++ ...\344\277\241\346\201\257ProtocolConfig.md" | 110 ++ ...37\345\221\275\345\221\250\346\234\237.md" | 350 ++++++ ...15\347\275\256\344\270\255\345\277\203.md" | 438 +++++++ ...75\345\205\250\350\247\243\346\236\220.md" | 522 +++++++++ ...20\347\240\201\350\247\243\346\236\220.md" | 896 ++++++++++++++ ...41\345\205\250\350\277\207\347\250\213.md" | 1034 +++++++++++++++++ ...50\345\206\214\345\216\237\347\220\206.md" | 987 ++++++++++++++++ ...ce\347\232\204\345\257\274\345\207\272.md" | 637 ++++++++++ ...47\232\204Demo\350\257\264\350\265\267.md" | 142 +++ .../3.0.8/2-serviceconfig-config.md | 265 +++++ ...351\205\215\347\275\256ReferenceConfig.md" | 54 + ...15\345\212\241\345\205\245\345\217\243.md" | 497 ++++++++ ...21\347\216\260\345\216\237\347\220\206.md" | 298 +++++ ...04\345\210\235\345\247\213\345\214\226.md" | 919 +++++++++++++++ ...51\345\261\225\346\234\272\345\210\266.md" | 400 +++++++ ...ptiveExtension\346\226\271\346\263\225.md" | 813 +++++++++++++ ...20\347\240\201\350\247\243\346\236\220.md" | 355 ++++++ ...20\347\240\201\350\247\243\346\236\220.md" | 226 ++++ ...04\345\210\235\345\247\213\345\214\226.md" | 121 ++ ...4\277\241\346\201\257ApplicationConfig.md" | 195 ++++ .../en/blog/java/codeanalysis/3.0.8/_index.md | 8 + content/en/blog/java/codeanalysis/_index.md | 9 + .../codeanalysis/introduction-to-dubbo-url.md | 195 ++++ .../metrics/0-\345\274\225\350\250\200.md" | 28 + ...06\344\270\216\345\255\230\345\202\250.md" | 106 ++ ...07\351\233\206\346\265\201\347\250\213.md" | 502 ++++++++ ...50\345\206\214\346\242\263\347\220\206.md" | 421 +++++++ ...42\344\270\216\345\257\274\345\207\272.md" | 223 ++++ .../blog/java/codeanalysis/metrics/_index.md | 8 + .../en/blog/java/codeanalysis/metrics/img.png | Bin 0 -> 43883 bytes content/en/blog/java/codeanalysis/models.md | 193 +++ .../multiple-protocols-on-one-port.md | 135 +++ .../java/codeanalysis/triple-backpressure.md | 112 ++ .../java/codeanalysis/triple-exception.md | 227 ++++ .../java/codeanalysis/url-perf-turning.md | 174 +++ .../java/codeanalysis/v3-service-discovery.md | 360 ++++++ content/en/blog/java/demos/_index.md | 8 + .../connect-heterogeneous-microservices.md | 298 +++++ content/en/blog/java/demos/dubbo-101.md | 383 ++++++ .../en/blog/java/demos/dubbo-27-features.md | 231 ++++ .../java/demos/dubbo-annotation-driven.md | 764 ++++++++++++ .../en/blog/java/demos/dubbo-annotation.md | 389 +++++++ content/en/blog/java/demos/dubbo-api-docs.md | 281 +++++ .../en/blog/java/demos/dubbo-async-client.md | 89 ++ .../en/blog/java/demos/dubbo-async-server.md | 95 ++ ...asic-usage-dubbo-consumer-configuration.md | 202 ++++ ...asic-usage-dubbo-provider-configuration.md | 284 +++++ .../demos/dubbo-cluster-error-handling.md | 273 +++++ .../en/blog/java/demos/dubbo-compatible.md | 198 ++++ .../dubbo-consistent-hash-implementation.md | 287 +++++ .../java/demos/dubbo-context-information.md | 61 + .../demos/dubbo-contribute-to-opensource.md | 191 +++ .../java/demos/dubbo-copywriting-style.md | 253 ++++ content/en/blog/java/demos/dubbo-echo-test.md | 101 ++ .../demos/dubbo-externalized-configuration.md | 696 +++++++++++ .../blog/java/demos/dubbo-generic-invoke.md | 180 +++ .../java/demos/dubbo-gracefully-shutdown.md | 115 ++ .../blog/java/demos/dubbo-heartbeat-design.md | 387 ++++++ content/en/blog/java/demos/dubbo-invoke.md | 223 ++++ content/en/blog/java/demos/dubbo-k8s.md | 111 ++ .../en/blog/java/demos/dubbo-loadbalance.md | 272 +++++ .../en/blog/java/demos/dubbo-local-call.md | 146 +++ .../blog/java/demos/dubbo-mesh-in-thinking.md | 134 +++ .../dubbo-mesh-service-mesh-exploring.md | 158 +++ .../java/demos/dubbo-network-interfaces.md | 527 +++++++++ content/en/blog/java/demos/dubbo-new-async.md | 462 ++++++++ content/en/blog/java/demos/dubbo-protocol.md | 207 ++++ content/en/blog/java/demos/dubbo-rest.md | 851 ++++++++++++++ content/en/blog/java/demos/dubbo-stub-mock.md | 319 +++++ ...ubbo-supporting-grpc-http2-and-protobuf.md | 731 ++++++++++++ .../en/blog/java/demos/dubbo2.7.14-java17.md | 78 ++ .../en/blog/java/demos/first-dubbo-filter.md | 202 ++++ content/en/blog/java/demos/hystrix.md | 189 +++ .../java/demos/introduction-to-dubbo-qos.md | 261 +++++ .../java/demos/introduction-to-dubbo-spi-2.md | 408 +++++++ .../java/demos/introduction-to-dubbo-spi.md | 232 ++++ .../demos/multiple-protocols-registries.md | 295 +++++ .../demos/optimization-branch-prediction.md | 143 +++ content/en/blog/java/demos/proxyless-guide.md | 509 ++++++++ content/en/blog/java/demos/resilience4j.md | 14 + .../en/blog/java/demos/rpc-introduction.md | 135 +++ .../en/blog/java/demos/service-and-version.md | 242 ++++ content/en/blog/java/demos/service-test.md | 166 +++ .../spring-boot-dubbo-start-stop-analysis.md | 235 ++++ .../en/blog/java/demos/test-verification.md | 99 ++ .../java/demos/v3.2_rest_protocol_design.md | 660 +++++++++++ content/en/blog/java/proposals/_index.md | 7 + .../proposals/service-discovery-migration.md | 401 +++++++ .../java/proposals/service-discovery-rule.md | Bin 0 -> 9455 bytes .../proposals/service-discovery-samples.md | 87 ++ .../en/blog/news/2022-review-2023-roadmap.md | 43 + content/en/blog/news/20230130-release.md | 142 +++ content/en/blog/news/Dubbo-proxyless.md | 186 +++ content/en/blog/news/apache-33-release.md | 192 +++ .../en/blog/news/apache-dubbo-2019-2020.md | 320 +++++ content/en/blog/news/apachecon-2023.md | 16 + .../blog/news/apachecon-asia-2023-summary.md | 57 + .../news/apachecon2023/dubbo-on-kubernetes.md | 181 +++ .../news/apachecon2023/ecosystem-opensergo.md | 200 ++++ .../news/apachecon2023/ecosystem-seata.md | 160 +++ .../apachecon2023/graalvm-native-image.md | 225 ++++ .../blog/news/apachecon2023/observability.md | 164 +++ .../triple-to-connect-frontend-and-backend.md | 127 ++ .../news/apachecon2023/usecase-zhengcaiyun.md | 202 ++++ .../build-new-docker-image-in-dockerhub.md | 59 + content/en/blog/news/dubbo-10years.md | 193 +++ content/en/blog/news/dubbo-history-gochina.md | 214 ++++ content/en/blog/news/dubbo-initializer.md | 64 + content/en/blog/news/dubbo-introduction.md | 116 ++ .../en/blog/news/glcc-project-announcement.md | 20 + .../news/how-to-involve-dubbo-community.md | 114 ++ content/en/blog/news/meet-dubbo.md | 65 ++ .../openatom-opensopurce-competition-2024.md | 238 ++++ .../en/blog/news/ospp-2023-announcement.md | 90 ++ content/en/blog/news/release-roadmap.md | 69 ++ content/en/blog/news/releases/2.7.14.md | 36 + content/en/blog/news/releases/2.7.5.md | 282 +++++ content/en/blog/news/releases/3.0.1.md | 39 + content/en/blog/news/releases/3.0.2.1.md | 17 + content/en/blog/news/releases/3.0.2.md | 134 +++ content/en/blog/news/releases/3.1.3.md | 43 + content/en/blog/news/releases/3.1.4.md | 68 ++ content/en/blog/news/releases/3.2.0-beta.2.md | 38 + content/en/blog/news/releases/3.2.0-beta.3.md | 63 + content/en/blog/news/releases/dubbo-go-1.4.md | 153 +++ .../en/blog/news/releases/dubbo-go-1.5.1.md | 180 +++ content/en/blog/news/releases/dubbo-go-1.5.md | 99 ++ .../news/releases/dubbo-go-hessian2-1.6.md | 62 + .../news/releases/dubbo-go-hessian2-1.7.md | 247 ++++ content/en/blog/nodejs/_index.md | 9 + .../first-nodejs-release-announcement.md | 201 ++++ content/en/blog/pixiu/_index.md | 8 + .../en/blog/pixiu/dubbo-go-pixiu-animal.md | 266 +++++ content/en/blog/pixiu/filter-intro.md | 218 ++++ .../google-service-weaver-paper-2023.md | 346 ++++++ .../blog/proposals/heuristic-flow-control.md | 221 ++++ content/en/blog/proposals/metrics.md | 523 +++++++++ content/en/blog/rust/_index.md | 7 + content/en/blog/rust/first-release.md | Bin 0 -> 9493 bytes content/en/blog/users/_index.md | 6 + content/en/blog/users/alibaba.md | 57 + content/en/blog/users/dianxiaomi.md | 119 ++ content/en/blog/users/eleme.md | 57 + content/en/blog/users/guazi.md | 175 +++ content/en/blog/users/icbc.md | 28 + content/en/blog/users/pingan.md | 228 ++++ content/en/blog/users/xiaomi.md | 78 ++ content/en/blog/users/zhengcaiyun.md | 312 +++++ content/en/blog/users/zhonglunwangluo.md | 61 + .../java-sdk/tasks/framework/_index.md | 1 - .../java-sdk/tasks/framework/more/_index.md | 2 - .../reference/pixiu/user/appendix/_index.md | 2 +- .../reference/pixiu/user/httpfilter/_index.md | 3 +- .../reference/pixiu/user/listener/_index.md | 2 +- content/en/overview/reference/setup/_index.md | 2 +- 206 files changed, 47286 insertions(+), 8 deletions(-) create mode 100644 content/en/blog/ web/_index.md create mode 100644 content/en/blog/ web/web-announcement.md create mode 100644 content/en/blog/golang/_index.md create mode 100644 content/en/blog/golang/dubbo-go-101.md create mode 100644 content/en/blog/golang/dubbo-go-app-registry.md create mode 100644 content/en/blog/golang/dubbo-go-cloud-native.md create mode 100644 content/en/blog/golang/dubbo-go-codewalk-1.md create mode 100644 content/en/blog/golang/dubbo-go-codewalk-2.md create mode 100644 content/en/blog/golang/dubbo-go-config-center.md create mode 100644 content/en/blog/golang/dubbo-go-first-glance.md create mode 100644 content/en/blog/golang/dubbo-go-getty.md create mode 100644 content/en/blog/golang/dubbo-go-grpc.md create mode 100644 content/en/blog/golang/dubbo-go-hessian2-optimization.md create mode 100644 content/en/blog/golang/dubbo-go-history.md create mode 100644 content/en/blog/golang/dubbo-go-intro.md create mode 100644 content/en/blog/golang/dubbo-go-k8s.md create mode 100644 content/en/blog/golang/dubbo-go-metrics.md create mode 100644 content/en/blog/golang/dubbo-go-moson-optimize.md create mode 100644 content/en/blog/golang/dubbo-go-nacos.md create mode 100644 content/en/blog/golang/dubbo-go-oneyear.md create mode 100644 content/en/blog/golang/dubbo-go-quickstart.md create mode 100644 content/en/blog/golang/dubbo-go-rest.md create mode 100644 content/en/blog/golang/dubbo-go-router.md create mode 100644 content/en/blog/golang/dubbo-go-seata.md create mode 100644 content/en/blog/golang/dubbo-go-sentinel.md create mode 100644 content/en/blog/golang/dubbo-go-tps.md create mode 100644 content/en/blog/golang/dubbo-go-trusted-call.md create mode 100644 content/en/blog/golang/dubbo-go-tuya.md create mode 100644 content/en/blog/golang/dubbogo-from-scratch.md create mode 100644 content/en/blog/integration/_index.md create mode 100644 content/en/blog/integration/dubbo-admin.md create mode 100644 content/en/blog/integration/dubbo-fescar.md create mode 100644 content/en/blog/integration/dubbo-graalvm-support.md create mode 100644 content/en/blog/integration/dubbo-integrate-with-hystrix.md create mode 100644 content/en/blog/integration/dubbo-meet-arthas.md create mode 100644 content/en/blog/integration/dubbo-practice-from-guazi.md create mode 100644 content/en/blog/integration/dubbo-registry-nacos-integration.md create mode 100644 content/en/blog/integration/dubbo-spring-cloud.md create mode 100644 content/en/blog/integration/dubbo-triple-with-apisix-gateway.md create mode 100644 content/en/blog/integration/dubbo-zk.md create mode 100644 content/en/blog/integration/dubbo2-js.md create mode 100644 content/en/blog/integration/how-to-proxy-dubbo-in-apache-apisix.md create mode 100644 content/en/blog/integration/how-to-proxy-dubbo-in-apache-shenyu.md create mode 100644 content/en/blog/integration/how-to-proxy-dubbo-in-higress.md create mode 100644 content/en/blog/integration/pinpoint.md create mode 100644 content/en/blog/integration/sentinel-introduction-for-dubbo.md create mode 100644 content/en/blog/integration/tracing-with-skywalking.md create mode 100644 content/en/blog/integration/use-zipkin-in-dubbo.md create mode 100644 content/en/blog/java/_index.md create mode 100644 content/en/blog/java/codeanalysis/3.0.8/1-learn-from-a-demo.md create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/10-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\346\267\273\345\212\240\346\263\250\345\206\214\344\270\255\345\277\203\351\205\215\347\275\256\344\277\241\346\201\257RegistryConfig.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/11-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\346\267\273\345\212\240\345\215\217\350\256\256\351\205\215\347\275\256\344\277\241\346\201\257ProtocolConfig.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/12-\345\205\250\345\261\200\350\247\206\351\207\216\346\235\245\347\234\213Dubbo3\347\232\204\346\234\215\345\212\241\345\220\257\345\212\250\347\224\237\345\221\275\345\221\250\346\234\237.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/13-Dubbo\347\232\204\344\270\211\345\244\247\344\270\255\345\277\203\344\271\213\351\205\215\347\275\256\344\270\255\345\277\203.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/14-Dubbo\351\205\215\347\275\256\345\212\240\350\275\275\345\205\250\350\247\243\346\236\220.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/15-Dubbo\347\232\204\344\270\211\345\244\247\344\270\255\345\277\203\344\271\213\345\205\203\346\225\260\346\215\256\344\270\255\345\277\203\346\272\220\347\240\201\350\247\243\346\236\220.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/16-\346\250\241\345\235\227\345\217\221\345\270\203\345\231\250\345\217\221\345\270\203\346\234\215\345\212\241\345\205\250\350\277\207\347\250\213.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/17-Dubbo\346\234\215\345\212\241\346\217\220\344\276\233\350\200\205\347\232\204\345\217\214\346\263\250\345\206\214\345\216\237\347\220\206.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/18-Dubbo3\345\205\203\346\225\260\346\215\256\346\234\215\345\212\241MetadataService\347\232\204\345\257\274\345\207\272.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/19-\351\207\215\346\226\260\346\235\245\350\277\207\344\273\216\344\270\200\344\270\252\346\234\215\345\212\241\346\266\210\350\264\271\350\200\205\347\232\204Demo\350\257\264\350\265\267.md" create mode 100644 content/en/blog/java/codeanalysis/3.0.8/2-serviceconfig-config.md create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/20-Dubbo3\346\234\215\345\212\241\345\274\225\347\224\250\351\205\215\347\275\256ReferenceConfig.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/21-Dubbo3\346\266\210\350\264\271\350\200\205\345\274\225\347\224\250\346\234\215\345\212\241\345\205\245\345\217\243.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/22-Dubbo3\346\266\210\350\264\271\350\200\205\350\207\252\345\212\250\346\204\237\345\272\224\345\206\263\347\255\226\345\272\224\347\224\250\347\272\247\346\234\215\345\212\241\345\217\221\347\216\260\345\216\237\347\220\206.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/3-\346\241\206\346\236\266,\345\272\224\347\224\250\347\250\213\345\272\217,\346\250\241\345\235\227\351\242\206\345\237\237\346\250\241\345\236\213Model\345\257\271\350\261\241\347\232\204\345\210\235\345\247\213\345\214\226.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/4-Dubbo\347\232\204\346\211\251\345\261\225\346\234\272\345\210\266.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/5 \350\207\252\351\200\202\345\272\224\346\211\251\345\261\225\345\257\271\350\261\241\347\232\204\345\210\233\345\273\272getAdaptiveExtension\346\226\271\346\263\225.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/6-Dubbo\347\232\204SPI\346\211\251\345\261\225\346\234\272\345\210\266\344\271\213\346\231\256\351\200\232\346\211\251\345\261\225\345\257\271\350\261\241\347\232\204\345\210\233\345\273\272\344\270\216Wrapper\346\234\272\345\210\266\347\232\204\346\272\220\347\240\201\350\247\243\346\236\220.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/7-Dubbo\347\232\204SPI\346\211\251\345\261\225\346\234\272\345\210\266\344\271\213\350\207\252\345\212\250\346\277\200\346\264\273\346\211\251\345\261\225Activate\346\272\220\347\240\201\350\247\243\346\236\220.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/8-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\345\200\237\345\212\251\345\217\214\351\207\215\346\240\241\351\252\214\351\224\201\347\232\204\345\215\225\344\276\213\346\250\241\345\274\217\350\277\233\350\241\214\345\257\271\350\261\241\347\232\204\345\210\235\345\247\213\345\214\226.md" create mode 100644 "content/en/blog/java/codeanalysis/3.0.8/9-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\346\267\273\345\212\240\345\272\224\347\224\250\347\250\213\345\272\217\347\232\204\351\205\215\347\275\256\344\277\241\346\201\257ApplicationConfig.md" create mode 100644 content/en/blog/java/codeanalysis/3.0.8/_index.md create mode 100644 content/en/blog/java/codeanalysis/_index.md create mode 100644 content/en/blog/java/codeanalysis/introduction-to-dubbo-url.md create mode 100644 "content/en/blog/java/codeanalysis/metrics/0-\345\274\225\350\250\200.md" create mode 100644 "content/en/blog/java/codeanalysis/metrics/1-\346\214\207\346\240\207\346\240\267\346\234\254\347\232\204\346\224\266\351\233\206\344\270\216\345\255\230\345\202\250.md" create mode 100644 "content/en/blog/java/codeanalysis/metrics/2-\346\214\207\346\240\207\346\224\266\351\233\206\345\231\250\347\232\204\346\214\207\346\240\207\351\207\207\351\233\206\346\265\201\347\250\213.md" create mode 100644 "content/en/blog/java/codeanalysis/metrics/3-\346\214\207\346\240\207\347\233\221\345\220\254\346\263\250\345\206\214\346\242\263\347\220\206.md" create mode 100644 "content/en/blog/java/codeanalysis/metrics/4-\346\214\207\346\240\207\350\275\254\346\215\242\344\270\216\345\257\274\345\207\272.md" create mode 100644 content/en/blog/java/codeanalysis/metrics/_index.md create mode 100644 content/en/blog/java/codeanalysis/metrics/img.png create mode 100644 content/en/blog/java/codeanalysis/models.md create mode 100644 content/en/blog/java/codeanalysis/multiple-protocols-on-one-port.md create mode 100644 content/en/blog/java/codeanalysis/triple-backpressure.md create mode 100644 content/en/blog/java/codeanalysis/triple-exception.md create mode 100644 content/en/blog/java/codeanalysis/url-perf-turning.md create mode 100644 content/en/blog/java/codeanalysis/v3-service-discovery.md create mode 100644 content/en/blog/java/demos/_index.md create mode 100644 content/en/blog/java/demos/connect-heterogeneous-microservices.md create mode 100644 content/en/blog/java/demos/dubbo-101.md create mode 100644 content/en/blog/java/demos/dubbo-27-features.md create mode 100644 content/en/blog/java/demos/dubbo-annotation-driven.md create mode 100644 content/en/blog/java/demos/dubbo-annotation.md create mode 100644 content/en/blog/java/demos/dubbo-api-docs.md create mode 100644 content/en/blog/java/demos/dubbo-async-client.md create mode 100644 content/en/blog/java/demos/dubbo-async-server.md create mode 100644 content/en/blog/java/demos/dubbo-basic-usage-dubbo-consumer-configuration.md create mode 100644 content/en/blog/java/demos/dubbo-basic-usage-dubbo-provider-configuration.md create mode 100644 content/en/blog/java/demos/dubbo-cluster-error-handling.md create mode 100644 content/en/blog/java/demos/dubbo-compatible.md create mode 100644 content/en/blog/java/demos/dubbo-consistent-hash-implementation.md create mode 100644 content/en/blog/java/demos/dubbo-context-information.md create mode 100644 content/en/blog/java/demos/dubbo-contribute-to-opensource.md create mode 100644 content/en/blog/java/demos/dubbo-copywriting-style.md create mode 100644 content/en/blog/java/demos/dubbo-echo-test.md create mode 100644 content/en/blog/java/demos/dubbo-externalized-configuration.md create mode 100644 content/en/blog/java/demos/dubbo-generic-invoke.md create mode 100644 content/en/blog/java/demos/dubbo-gracefully-shutdown.md create mode 100644 content/en/blog/java/demos/dubbo-heartbeat-design.md create mode 100644 content/en/blog/java/demos/dubbo-invoke.md create mode 100644 content/en/blog/java/demos/dubbo-k8s.md create mode 100644 content/en/blog/java/demos/dubbo-loadbalance.md create mode 100644 content/en/blog/java/demos/dubbo-local-call.md create mode 100644 content/en/blog/java/demos/dubbo-mesh-in-thinking.md create mode 100644 content/en/blog/java/demos/dubbo-mesh-service-mesh-exploring.md create mode 100644 content/en/blog/java/demos/dubbo-network-interfaces.md create mode 100644 content/en/blog/java/demos/dubbo-new-async.md create mode 100644 content/en/blog/java/demos/dubbo-protocol.md create mode 100644 content/en/blog/java/demos/dubbo-rest.md create mode 100644 content/en/blog/java/demos/dubbo-stub-mock.md create mode 100644 content/en/blog/java/demos/dubbo-supporting-grpc-http2-and-protobuf.md create mode 100644 content/en/blog/java/demos/dubbo2.7.14-java17.md create mode 100644 content/en/blog/java/demos/first-dubbo-filter.md create mode 100644 content/en/blog/java/demos/hystrix.md create mode 100644 content/en/blog/java/demos/introduction-to-dubbo-qos.md create mode 100644 content/en/blog/java/demos/introduction-to-dubbo-spi-2.md create mode 100644 content/en/blog/java/demos/introduction-to-dubbo-spi.md create mode 100644 content/en/blog/java/demos/multiple-protocols-registries.md create mode 100644 content/en/blog/java/demos/optimization-branch-prediction.md create mode 100644 content/en/blog/java/demos/proxyless-guide.md create mode 100644 content/en/blog/java/demos/resilience4j.md create mode 100644 content/en/blog/java/demos/rpc-introduction.md create mode 100644 content/en/blog/java/demos/service-and-version.md create mode 100644 content/en/blog/java/demos/service-test.md create mode 100644 content/en/blog/java/demos/spring-boot-dubbo-start-stop-analysis.md create mode 100644 content/en/blog/java/demos/test-verification.md create mode 100644 content/en/blog/java/demos/v3.2_rest_protocol_design.md create mode 100644 content/en/blog/java/proposals/_index.md create mode 100644 content/en/blog/java/proposals/service-discovery-migration.md create mode 100644 content/en/blog/java/proposals/service-discovery-rule.md create mode 100644 content/en/blog/java/proposals/service-discovery-samples.md create mode 100644 content/en/blog/news/2022-review-2023-roadmap.md create mode 100644 content/en/blog/news/20230130-release.md create mode 100644 content/en/blog/news/Dubbo-proxyless.md create mode 100644 content/en/blog/news/apache-33-release.md create mode 100644 content/en/blog/news/apache-dubbo-2019-2020.md create mode 100644 content/en/blog/news/apachecon-2023.md create mode 100644 content/en/blog/news/apachecon-asia-2023-summary.md create mode 100644 content/en/blog/news/apachecon2023/dubbo-on-kubernetes.md create mode 100644 content/en/blog/news/apachecon2023/ecosystem-opensergo.md create mode 100644 content/en/blog/news/apachecon2023/ecosystem-seata.md create mode 100644 content/en/blog/news/apachecon2023/graalvm-native-image.md create mode 100644 content/en/blog/news/apachecon2023/observability.md create mode 100644 content/en/blog/news/apachecon2023/triple-to-connect-frontend-and-backend.md create mode 100644 content/en/blog/news/apachecon2023/usecase-zhengcaiyun.md create mode 100644 content/en/blog/news/build-new-docker-image-in-dockerhub.md create mode 100644 content/en/blog/news/dubbo-10years.md create mode 100644 content/en/blog/news/dubbo-history-gochina.md create mode 100644 content/en/blog/news/dubbo-initializer.md create mode 100644 content/en/blog/news/dubbo-introduction.md create mode 100644 content/en/blog/news/glcc-project-announcement.md create mode 100644 content/en/blog/news/how-to-involve-dubbo-community.md create mode 100644 content/en/blog/news/meet-dubbo.md create mode 100644 content/en/blog/news/openatom-opensopurce-competition-2024.md create mode 100644 content/en/blog/news/ospp-2023-announcement.md create mode 100644 content/en/blog/news/release-roadmap.md create mode 100644 content/en/blog/news/releases/2.7.14.md create mode 100644 content/en/blog/news/releases/2.7.5.md create mode 100644 content/en/blog/news/releases/3.0.1.md create mode 100644 content/en/blog/news/releases/3.0.2.1.md create mode 100644 content/en/blog/news/releases/3.0.2.md create mode 100644 content/en/blog/news/releases/3.1.3.md create mode 100644 content/en/blog/news/releases/3.1.4.md create mode 100644 content/en/blog/news/releases/3.2.0-beta.2.md create mode 100644 content/en/blog/news/releases/3.2.0-beta.3.md create mode 100644 content/en/blog/news/releases/dubbo-go-1.4.md create mode 100644 content/en/blog/news/releases/dubbo-go-1.5.1.md create mode 100644 content/en/blog/news/releases/dubbo-go-1.5.md create mode 100644 content/en/blog/news/releases/dubbo-go-hessian2-1.6.md create mode 100644 content/en/blog/news/releases/dubbo-go-hessian2-1.7.md create mode 100644 content/en/blog/nodejs/_index.md create mode 100644 content/en/blog/nodejs/first-nodejs-release-announcement.md create mode 100644 content/en/blog/pixiu/_index.md create mode 100644 content/en/blog/pixiu/dubbo-go-pixiu-animal.md create mode 100644 content/en/blog/pixiu/filter-intro.md create mode 100644 content/en/blog/proposals/google-service-weaver-paper-2023.md create mode 100644 content/en/blog/proposals/heuristic-flow-control.md create mode 100644 content/en/blog/proposals/metrics.md create mode 100644 content/en/blog/rust/_index.md create mode 100644 content/en/blog/rust/first-release.md create mode 100644 content/en/blog/users/_index.md create mode 100644 content/en/blog/users/alibaba.md create mode 100644 content/en/blog/users/dianxiaomi.md create mode 100644 content/en/blog/users/eleme.md create mode 100644 content/en/blog/users/guazi.md create mode 100644 content/en/blog/users/icbc.md create mode 100644 content/en/blog/users/pingan.md create mode 100644 content/en/blog/users/xiaomi.md create mode 100644 content/en/blog/users/zhengcaiyun.md create mode 100644 content/en/blog/users/zhonglunwangluo.md diff --git a/content/en/blog/ web/_index.md b/content/en/blog/ web/_index.md new file mode 100644 index 000000000000..2a29d4c05e1c --- /dev/null +++ b/content/en/blog/ web/_index.md @@ -0,0 +1,9 @@ + +--- +title: "Web" +linkTitle: "Web" +weight: 32 +description: "使用 Javascript 开发运行在浏览器上的 Dubbo Web 应用" +--- + + diff --git a/content/en/blog/ web/web-announcement.md b/content/en/blog/ web/web-announcement.md new file mode 100644 index 000000000000..1dee4a76264b --- /dev/null +++ b/content/en/blog/ web/web-announcement.md @@ -0,0 +1,266 @@ +--- +title: "Web 浏览器页面也能访问dubbo、grpc微服务?Dubbo-js alpha版本正式发布" +linkTitle: "Web 浏览器页面也能访问dubbo、grpc微服务?Dubbo-js alpha版本正式发布" +tags: ["web", "dubbo-js", "browser"] +authors: ["蔡建怿"] +date: 2023-10-07 +description: "Dubbo-js 已于 9 月份发布支持 Dubbo3 协议的首个 alpha 版本,它的发布将有机会彻底改变微服务前后端的架构与通信模式,让你能直接在浏览器页面或web服务器中访问后端 Dubbo RPC 服务。" +--- + +基于 Dubbo3 定义的 Triple 协议,你可以轻松编写浏览器、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。[Dubbo TypeScript SDK](https://github.com/apache/dubbo-js/) 支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 APl 来发布或调用这些服务。 + +Dubbo-js 已于 9 月份发布支持 Dubbo3 协议的首个 alpha 版本,它的发布将有机会彻底改变微服务前后端的架构与通信模式,让你能直接在浏览器页面或web服务器中访问后端 Dubbo RPC 服务。目前项目快速发展中,对参与 apache/dubbo-js 项目感兴趣的开发者,欢迎搜索钉钉群:**29775027779** 加入开发者群组。 + +![Web 浏览器页面也能访问dubbo、grpc微服务](/imgs/blog/2023/9/web/img.png) +# 浏览器 Web 应用示例 +本示例演示了如何使用 dubbo-js 开发运行在浏览器上的 web 应用程序,web 页面将调用 dubbo node.js 开发的后端服务并生成页面内容。本示例演示基于 IDL 和非 IDL 两种编码模式。 + +![Web 浏览器页面也能访问dubbo、grpc微服务](/imgs/blog/2023/9/web/img_1.png) +## IDL 模式 +### 前置条件 +首先,我们将使用 Vite 来生成我们的前端项目模板,它内置了我们稍后需要的所有功能支持。 + +```shell +npm create vite@latest -- dubbo-web-example --template react-ts +cd dubbo-web-example +npm install +``` + +因为使用 Protocol Buffer 的原因,我们首先需要安装相关的代码生成工具,这包括 `@bufbuild/protoc-gen-es`、`@bufbuild/protobuf`、`@apachedubbo/protoc-gen-apache-dubbo-es`、`@apachedubbo/dubbo`。 + +```shell +npm install @bufbuild/protoc-gen-es @bufbuild/protobuf @apachedubbo/protoc-gen-apache-dubbo-es @apachedubbo/dubbo +``` + +### 使用 Proto 定义服务 + +现在,使用 Protocol Buffer (IDL) 来定义一个 Dubbo 服务。 + +src 下创建 util/proto 目录,并生成文件 + +```shell +mkdir -p src/util/proto && touch src/util/proto/example.proto +``` + +写入内容 + +```protobuf +syntax = "proto3"; + +package apache.dubbo.demo.example.v1; + +message SayRequest { + string sentence = 1; +} + +message SayResponse { + string sentence = 1; +} + +service ExampleService { + rpc Say(SayRequest) returns (SayResponse) {} +} +``` + +这个文件声明了一个叫做 `ExampleService` 的服务,为这个服务定义了 `Say` 方法以及它的请求参数 `SayRequest` 和返回值 `SayResponse`。 + +### 生成代码 + +创建 gen 目录,作为生成文件放置的目标目录 + +```shell +mkdir -p src/util/gen +``` + +运行以下命令,利用 `protoc-gen-es`、`protoc-gen-apache-dubbo-es` 等插件在 gen 目录下生成代码文件 + +```shell +PATH=$PATH:$(pwd)/node_modules/.bin \ + protoc -I src/util/proto \ + --es_out src/util/gen \ + --es_opt target=ts \ + --apache-dubbo-es_out src/util/gen \ + --apache-dubbo-es_opt target=ts \ + example.proto +``` + +运行命令后,应该可以在目标目录中看到以下生成的文件: + +``` +├── src +│ ├── util +│ │ ├── gen +│ │ │ ├── example_dubbo.ts +│ │ │ └── example_pb.ts +│ │ └── proto +│ │ └── example.proto +``` + +### 创建 App + +需要先下载 `@apachedubbo/dubbo-web` + +```shell +npm install @apachedubbo/dubbo-web +``` + +现在我们可以从包中导入服务并设置一个客户端。在 App.tsx 中添加以下内容: + +```typescript +import { useState } from "react"; +import "./App.css"; + +import { createPromiseClient } from "@apachedubbo/dubbo"; +import { createDubboTransport } from "@apachedubbo/dubbo-web"; + +// Import service definition that you want to connect to. +import { ExampleService } from "./util/gen/example_dubbo"; + +// The transport defines what type of endpoint we're hitting. +// In our example we'll be communicating with a Dubbo endpoint. +const transport = createDubboTransport({ + baseUrl: "http://localhost:8080", +}); + +// Here we make the client itself, combining the service +// definition with the transport. +const client = createPromiseClient(ExampleService, transport, { serviceGroup: 'dubbo', serviceVersion: '1.0.0' }); + +function App() { + const [inputValue, setInputValue] = useState(""); + const [messages, setMessages] = useState< + { + fromMe: boolean; + message: string; + }[] + >([]); + return ( + <> +
    + {messages.map((msg, index) => ( +
  1. {`${msg.fromMe ? "ME:" : "Dubbo Server:"} ${msg.message}`}
  2. + ))} +
+
{ + e.preventDefault(); + // Clear inputValue since the user has submitted. + setInputValue(""); + // Store the inputValue in the chain of messages and + // mark this message as coming from "me" + setMessages((prev) => [ + ...prev, + { + fromMe: true, + message: inputValue, + }, + ]); + const response = await client.say({ + sentence: inputValue, + }); + setMessages((prev) => [ + ...prev, + { + fromMe: false, + message: response.sentence, + }, + ]); + }} + > + setInputValue(e.target.value)} /> + +
+ + ); +} + +export default App; +``` + +执行以下命令,即可得到样例页面 + +```shell +npm run dev +``` + +### 启动 Server + +接下来我们需要启动 Server,可以使用 Java、Go、Node.js 等 Dubbo 支持的任一语言开发 Server。这里我们采用 Dubbo 服务嵌入的 Node.js 服务器,具体可参考 [Node.js 开发 Dubbo 后端服务](https://github.com/apache/dubbo-js/tree/dubbo3/example/dubbo-node-example) 中的操作步骤。 + +不过需要注意,我们额外需要修改 Node.js 示例:引入 @fastify/cors 来解决前端请求的跨域问题 + +```shell +npm install @fastify/cors +``` + +需要在 server.ts 文件下修改 + +```typescript +... +import cors from "@fastify/cors"; + +... +async function main() { + const server = fastify(); + ... + await server.register(cors, { + origin: true, + }); + ... + await server.listen({ host: "localhost", port: 8080 }); + ... +} + +void main(); +``` + +最后,运行代码启动服务 + +```shell +npx tsx server.ts +``` + +## 无 IDL 模式 +在接下来的版本中,我们将继续提供无 IDL 模式的通信支持,这样就可以更方便的访问无 IDL 的后端服务。在这里,我们先快速的看一下无 IDL 模式的使用方式。 + +同样需要先安装 `@apachedubbo/dubbo`、`@apachedubbo/dubbo-web` + +```shell +npm install @apachedubbo/dubbo @apachedubbo/dubbo-web +``` + +现在就可以一个启动一个客户端,并发起调用了。App.tsx 中的代码与 IDL 模式基本一致,区别点在于以下内容: + +```typescript +// ... +// set backend server to connect +const transport = createDubboTransport({ + baseUrl: "http://localhost:8080", +}); +// init client +const client = createPromiseClient(transport); + +function App() { + // ... + // call remote Dubbo service + const response = await client.call( + "apache.dubbo.demo.example.v1.ExampleService", + "say", + { + sentence: inputValue, + }); +} +``` + +执行以下命令,即可得到样例页面 + +```shell +npm run dev +``` +# 总结 +直接在浏览器页面或web服务器中访问后端 Dubbo RPC 服务!Dubbo Triple 协议升级以及 Dubbo javascript sdk 的发布,对整个微服务体系是一个非常有力的补充,期待看到它能改变未来整个微服务架构以及前后端通信模式。 + +Dubbo-js 刚刚在 9 月份发布了支持 Dubbo3 Triple 协议的首个 alpha 版本,目前项目正处于快速发展中,对参与 apache/dubbo-js 项目感兴趣的开发者,欢迎通过以下方式加入组织: + +- 搜索钉钉群:**29775027779** 加入开发者群组。 +- 关注该公众号 `apachedubbo`,回复 "dubbojs" 接受邀请加入开发组 diff --git a/content/en/blog/golang/_index.md b/content/en/blog/golang/_index.md new file mode 100644 index 000000000000..a3b964a46878 --- /dev/null +++ b/content/en/blog/golang/_index.md @@ -0,0 +1,8 @@ + +--- +title: "Golang" +linkTitle: "Golang" +weight: 30 +description: "Dubbo Blog for Golang" +--- + diff --git a/content/en/blog/golang/dubbo-go-101.md b/content/en/blog/golang/dubbo-go-101.md new file mode 100644 index 000000000000..ee8057b5dbef --- /dev/null +++ b/content/en/blog/golang/dubbo-go-101.md @@ -0,0 +1,191 @@ +--- +title: "Dubbo Go 快速开始" +linkTitle: "Dubbo Go 快速开始" +tags: ["Go"] +date: 2021-01-11 +description: 本文介绍了如何通过一个 `hellowworld` 例子带领大家快速上手 Dubbo Go 框架 +--- + +## 环境 + +- Go编程环境 +- 启动zookeeper服务,也可以使用远程实例 + +## 从服务端开始 + +### 第一步:编写 `Provider` 结构体和提供服务的方法 + +> https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-server/app/user.go + +1. 编写需要被编码的结构体,由于使用 `Hessian2` 作为编码协议,`User` 需要实现 `JavaClassName` 方法,它的返回值在dubbo中对应User类的类名。 + +```go +type User struct { + Id string + Name string + Age int32 + Time time.Time +} + +func (u User) JavaClassName() string { + return "com.ikurento.user.User" +} +``` + +1. 编写业务逻辑,`UserProvider` 相当于dubbo中的一个服务实现。需要实现 `Reference` 方法,返回值是这个服务的唯一标识,对应dubbo的 `beans` 和 `path` 字段。 + +```go +type UserProvider struct { +} + +func (u *UserProvider) GetUser(ctx context.Context, req []interface{}) (*User, error) { + println("req:%#v", req) + rsp := User{"A001", "hellowworld", 18, time.Now()} + println("rsp:%#v", rsp) + return &rsp, nil +} + +func (u *UserProvider) Reference() string { + return "UserProvider" +} +``` + +1. 注册服务和对象 + +```go +func init() { + config.SetProviderService(new(UserProvider)) + // ------for hessian2------ + hessian.RegisterPOJO(&User{}) +} +``` + +### 第二步:编写主程序 + +> https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-server/app/server.go + +1. 引入必需的dubbo-go包 + +```go +import ( + hessian "github.com/apache/dubbo-go-hessian2" + "github.com/apache/dubbo-go/config" + _ "github.com/apache/dubbo-go/registry/protocol" + _ "github.com/apache/dubbo-go/common/proxy/proxy_factory" + _ "github.com/apache/dubbo-go/filter/impl" + _ "github.com/apache/dubbo-go/cluster/cluster_impl" + _ "github.com/apache/dubbo-go/cluster/loadbalance" + _ "github.com/apache/dubbo-go/registry/zookeeper" + + _ "github.com/apache/dubbo-go/protocol/dubbo" +) +``` + +1. main 函数 + +```go +func main() { + config.Load() +} +``` + +### 第三步:编写配置文件并配置环境变量 + +1. 参考 [log](https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-server/profiles/release/log.yml) 和 [server](https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-server/profiles/release/server.yml) 编辑配置文件。 + +主要编辑以下部分: + +- `registries` 结点下需要配置zk的数量和地址 +- `services` 结点下配置服务的具体信息,需要配置 `interface` 配置,修改为对应服务的接口名,服务的key对应第一步中 `Provider` 的 `Reference` 返回值 + +1. 把上面的两个配置文件分别配置为环境变量 + +```shell +export CONF_PROVIDER_FILE_PATH="xxx" +export APP_LOG_CONF_FILE="xxx" +``` + +## 接着是客户端 + +### 第一步:编写客户端 `Provider` + +> https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-client/app/user.go + +1. 参考服务端第一步的第一点。 +2. 与服务端不同的是,提供服务的方法作为结构体的参数,不需要编写具体业务逻辑。另外,`Provider` 不对应dubbo中的接口,而是对应一个实现。 + +```go +type UserProvider struct { + GetUser func(ctx context.Context, req []interface{}, rsp *User) error +} + +func (u *UserProvider) Reference() string { + return "UserProvider" +} +``` + +1. 注册服务和对象 + +```go +func init() { + config.SetConsumerService(userProvider) + hessian.RegisterPOJO(&User{}) +} +``` + +### 第二步:编写客户端主程序 + +> https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-client/app/client.go + +1. 引入必需的dubbo-go包 + +```go +import ( + hessian "github.com/apache/dubbo-go-hessian2" + "github.com/apache/dubbo-go/config" + _ "github.com/apache/dubbo-go/registry/protocol" + _ "github.com/apache/dubbo-go/common/proxy/proxy_factory" + _ "github.com/apache/dubbo-go/filter/impl" + _ "github.com/apache/dubbo-go/cluster/cluster_impl" + _ "github.com/apache/dubbo-go/cluster/loadbalance" + _ "github.com/apache/dubbo-go/registry/zookeeper" + + _ "github.com/apache/dubbo-go/protocol/dubbo" +) +``` + +1. main 函数 + +```go +func main() { + config.Load() + time.Sleep(3e9) + + println("\n\n\nstart to test dubbo") + user := &User{} + err := userProvider.GetUser(context.TODO(), []interface{}{"A001"}, user) + if err != nil { + panic(err) + } + println("response result: %v\n", user) +} +func println(format string, args ...interface{}) { + fmt.Printf("\033[32;40m"+format+"\033[0m\n", args...) +} +``` + +### 第三步:编写配置文件并配置环境变量 + +1. 参考 [log](https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-client/profiles/release/log.yml) 和 [client](https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-client/profiles/release/client.yml) 编辑配置文件。 + +主要编辑以下部分: + +- `registries` 结点下需要配置zk的数量和地址 +- `references` 结点下配置服务的具体信息,需要配置 `interface` 配置,修改为对应服务的接口名,服务的key对应第一步中 `Provider` 的 `Reference` 返回值 + +1. 把上面的两个配置文件费别配置为环境变量,为防止log的环境变量和服务端的log环境变量冲突,建议所有的环境变量不要做全局配置,在当前起效即可。 + +```shell +export CONF_CONSUMER_FILE_PATH="xxx" +export APP_LOG_CONF_FILE="xxx" +``` \ No newline at end of file diff --git a/content/en/blog/golang/dubbo-go-app-registry.md b/content/en/blog/golang/dubbo-go-app-registry.md new file mode 100644 index 000000000000..5b343b2f7ab4 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-app-registry.md @@ -0,0 +1,116 @@ +--- +title: "Dubbo-go应用维度注册模型" +linkTitle: "Dubbo-go应用维度注册模型" +tags: ["Go"] +date: 2021-01-14 +description: Dubbo-go 中的应用维度注册模型 +--- + +Dubbo 3.0 将至。其最重要的一点就是服务自省,其基础即是应用维度的注册模型,作为目前与 Dubbo 在功能上完全对齐的 Dubbo-go,已于 本年【2020 年】7 月份发布了其 v1.5.0 版本,实现了该模型,为年底实现与 Dubbo 3.0 对齐的新版本奠定了基础。 + +Dubbo-go 作为 Dubbo 的 Go 语言版本,因跨语言之故,二者针对同一模型的实现必然有较大差异,故本文注重讨论 Dubbo-go 社区自身对该模型的理解和实现,以及其与 Dubbo 之间的差异。 + +## 1 引语 + +在 v1.5 以前,Dubbo-go 注册模型都是以服务为维度的,直观的理解可认为其是接口维度。譬如注册信息,按照服务维度模型其示例如下: + +```json +"com.xxx.User":[ + {"name":"instance1", "ip":"127.0.0.1", "metadata":{"timeout":1000}}, + {"name":"instance2", "ip":"127.0.0.2", "metadata":{"timeout":2000}}, + {"name":"instance3", "ip":"127.0.0.3", "metadata":{"timeout":3000}}, +] +``` + +这种模式的好处是不言而喻的,简单直观,提供了细粒度的服务控制手段。 + +而近两年,随着云时代的到来,这种模式就暴露了不足: + +1. 主流的注册模型都是应用维度的; +2. 以服务维度来注册,那么规模与服务数量成正比,大规模集群之下【工行软件中心的接口注册规模达到万级】,注册中心压力非常大; + +## 2 Dubbo-go v1.5.0 的新注册模型 + +这次 Dubbo-go 支持了新的注册模型,也就是应用维度的注册模型。简单而言,在应用维度注册下,其注册信息类似: + +```json +"application1": [ + {"name":"instance1", "ip":"127.0.0.1", "metadata":{}}, + {"name":"instance2", "ip":"127.0.0.2", "metadata":{}}, + {"name":"instanceN", "ip":"127.0.0.3", "metadata":{}} +] +``` + +在此模式之下,可以看到注册信息将会大幅度减少,集群规模只与实例数量相关。 + +与此同时,在实现这一个功能的时候,Dubbo-go 还希望保持两个目标: + +1. 对用户完全兼容,用户迁移无感知; +2. 保持住原本服务粒度上精细控制的能力——即保留现有的服务维度的元数据; + +因此 Dubbo-go 要着力解决以下几点: + +1. 目前 Consumer 的配置是以接口为准的,如何根据接口找到该接口对应的应用?例如,用户配置了 `com.xxx.User` 服务,那么,Dubbo-go 怎么知道这个服务是由哪个应用来提供的呢? +2. 在知道了是哪个应用之后,可以从注册中心拿到应用的注册信息,如实例信息等;那怎么知道 `com.xxx.User` 服务自身的元数据呢? + +为了解决这两个问题,在已有的注册模型的基础上,Dubbo-go 引入两个额外的组件:ServiceNameMapping 和 MetadataService。 + +前者用于解决服务-应用之间的映射,后者用于获取服务的元数据。 + +由此,Dubbo-go 的应用维度注册模型就变为: + +![img](/imgs/blog/dubbo-go/app-registry/app-registry-model.png) + +### 2.1 ServiceNameMapping + +ServiceNameMapping 并不复杂。考虑到一般人在 Consumer 侧想要调用一个服务,其十有八九是知道这个服务是哪个应用提供的,于是 Dubbo-go 引入了新的配置项 `provideBy` + +![img](/imgs/blog/dubbo-go/app-registry/provideby.png) + +当然,所谓 “十有八九”就是说有些时候确实不知道是服务是谁提供的,所以 Dubbo-go 还支持了基于配置中心的 ServiceNameMapping 实现。Dubbo-go 会用服务名作为 Key 从配置中心里面读出对应的应用名。这意味着, Provider 启动的时候,也会在配置中心将自身的 服务-应用名映射 写入配置中心。 + +### 2.2 MetadataService + +MetadataService 稍微要复杂一点,有 `remote` 和 `local` 两种模式。 + +类似于前面的 ServiceNameMapping,Dubbo-go 提供了基于配置中心的 MetadataService 的实现,即 `remote` 模式。Provider 启动的时候,就会将服务的元数据写进去。 + +另外一种模式是 `local` 模式。Dubbo-go 可以直接将 MetadataService 看做是一个普通的微服务,而后由 `Provider` 所提供。类似于: + +![img](/imgs/blog/dubbo-go/app-registry/local-metadata-service.png) + +由此带来一个问题: + +既然 Dubbo-go 将 MetadataService 看做是一个普通的服务,那么 MetadataService 的元数据,Consumer 该怎么获得呢?这是一个典型的鸡生蛋蛋生鸡的问题。 + +Dubbo-go 的方案非常简单粗暴,Provider 启动的时候,不仅仅往注册中心里面写入应用本身的信息,还要把它的 MetadataService 信息写入。 + +这是一个应用的注册信息: + +![img](/imgs/blog/dubbo-go/app-registry/registry-info.png) + +本质上来说,应用维度注册信息 + 服务元数据 = 服务维度注册信息。或者说,应用维度注册,只是一种重新组织这些信息的方式。 + +## 3 差异与改进 + +Dubbo-go v1.5.x 对标 Dubbo 2.7.5,可以认为是参照 Dubbo 2.7.5 直接实现其 Go 源码,但是考虑到 Java 和 Go 之间的语言差异,导致二者之间的实现不可能完全对等。 + +### 3.1 修订版本号revision比对 + +Dubbo v2.7.x 在 MetadataService 注册时,会对其 provider 应用的所有服务接口的 hash 值做为修订版本号写入元数据中心,此 revision 是对所有接口的方法以及其参数总体的计算结果。其目的是减少 consumer 端到注册中心的拉取次数。 + +在Go中用的计算 revision 的 hash 算法与 Java 是不一致的,而且 Go 与 Java 的方法签名信息是不相同的,所以计算出来的 hash 值一定是不一样的。 + +此不一致会导致如果Go应用和Java应用同时发布同一个服务的时候,Go服务和Java服务的修订版本号必定是不相同的,Consumer需要分别缓存这两个修订版本的元数据。 + +### 3.2 应用注册时机 + +Dubbo-go v1.5.0 实现时,其中一个考量是全面向后兼容 v1.4.x。Dubbo-go v1.5.x 应用 consumer 既可以调用 Dubbo-go v1.4.x 应用的服务,也可以调用 Dubbo v2.6.x 应用的服务,当然也可以调用其对标的 v2.7.x 应用的服务。 + +为了达到兼容性,Dubbo-go v1.5.x 实现时面临一个问题:Dubbo-go provider 应用启动时有一个服务启动成功,把应用信息注册到元数据中心之后,就会把实例注册到注册中心,而 Dubbo 2.7.x 的 provider 应用则是在其所有服务接口的信息注册到元数据中心后才会注册实例! + +这个问题的后果就是:Dubbo-go v1.5.0 的 provider 每次发布接口到元数据中心的同时,都会触发Dubbo-go v1.5.0 / Dubbo v2.7.x 的 consumer 应用拉取 Dubbo-go v1.5.0 应用信息,当provider 发布的服务过多时 consumer 侧性能损耗非常明显! + +Dubbo-go 在 v1.5.1 中已经修复了这个问题,provider 在启动时先将其全部服务接口发布到元数据中心,然后注册实例到注册中心,减少了 consumer 拉取元数据的次数。 + +> 本文作者: 白泽(蒋超),Github ID [@Patrick0308](https://github.com/Patrick0308),开源爱好者。 diff --git a/content/en/blog/golang/dubbo-go-cloud-native.md b/content/en/blog/golang/dubbo-go-cloud-native.md new file mode 100644 index 000000000000..1bd945caff10 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-cloud-native.md @@ -0,0 +1,152 @@ +--- +title: "dubbogo 3.0:牵手 gRPC 走向云原生时代" +linkTitle: "dubbogo 3.0:牵手 gRPC 走向云原生时代" +tags: ["Go"] +date: 2021-01-15 +description: 本文介绍了 dubbo-go 3.0 对云原生的支持和规划 +--- + +自从 2011 年 Dubbo 开源之后,被大量中小公司采用,一直是国内最受欢迎的 RPC 框架。2014 年,由于阿里内部组织架构调整,Dubbo 暂停维护了一段时间,之后随着 Spring Cloud 的面世,两个体系在融合中一起助推了微服务的火热。 + +不过这世界变化快,自从以 docker 为代表的的容器技术和以 K8s 为代表的容器编排技术登上舞台之后,云原生时代到来了。在云原生时代,不可变的基础设施给原有的中间件带来了不可变的中间件基础设施:gRPC 统一了底层通信层;protobuf 统一了序列化协议;以 envoy + istio 为代表的 service mesh 逐渐统一了服务的控制面与数据面。 + +dubbogo 的天然使命是:Bridging the gap between Java and Go。保持 Go 应用与 Java 应用互联互通的同时,借助 Go 语言(事实上的第一云原生语言)的优势拥抱云原生时代。dubbogo 社区 2020 年勠力打造三支箭: + +- 已经发布的对齐 dubbo 2.7 的 dubbogo v1.5 版本; +- 近期将要发布的 sidecar 形态的 dubbo-go-proxy 项目; +- 以及处于进行时的 dubbogo 3.0。 + +用一句话概括 dubbogo 3.0 即是:新通信协议、新序列化协议、新应用注册模型以及新的服务治理能力!本文主要着重讨论 dubbogo 3.0 的新通信协议和应用级服务注册发现模型。 + +## dubbogo 3.0 vs gRPC + +知己知彼,方能进步。dubbogo 3.0 的通信层改进主要借鉴了 gRPC。 + +gRPC 协议,简单来说就是 http2 协议的基础之上,增加了特定的协议 header:“grpc-” 开头的 header 字段,采用特定的打解包工具(protobuf)对数据进行序列化,从而实现 RPC 调用。 + +![img](/imgs/blog/dubbo-go/3.0-plan/p1.webp) + +众所周知,gRPC 几乎没有服务治理能力,而阿里云现有 dubbo 框架兼具 RPC 和服务治理能力,整体实力不逊于 gRPC。但在“大家都用 gRPC” 这样的背景之下,dubbogo 3.0 的新通信协议就必须**完美兼容 gRPC**,对开发者已部署的服务完全兼容,并在此基础之上延续已有 dubbo 协议和服务治理能力,进而推出一系列新策略:比如 mesh 支持、应用级服务注册等。 + +![img](/imgs/blog/dubbo-go/3.0-plan/p2.webp) + +## dubbogo 3.0 vs dubbogo 1.5 + +目前已有的 dubbo 2.7 协议已经尽可能实现了 gRPC 的支持。开发者可以通过 protoc-gen-dubbo 工具将 pb IDL 协议转换为框架支持的 stub,再借助底层 gRPC conn 的 RPC 过程,将已有的服务治理能力自上而下传递给 gRPC,因此实现了 gRPC 服务的支持。 + +dubbo-go v1.5.x 也支持 gRPC 的 Stream 调用。和 unary RPC 类似,通过产生框架支持的 stub,在底层 gRPC stream 调用的基础之上,将流式 RPC 的能力和并入框架。但由于 dubbo v2.7.x / dubbo-go v1.5.x 本身并不支持流式调用,所以没有对 gRPC stream 调用的进行上层服务治理支持。 + +开发者所面临的问题就是:我们在使用 dubbo-go2.7 进行 grpc 协议传输的时候,或多或少不是那么放心。 + +而即将推出的 dubbo-go 3.0 协议将从根源解决这个问题。 + +## 协议兼容的三种层次 + +笔者认为,一款服务框架对于第三方协议的支持可分为三个程度:应用层次、协议层次、传输层次。 + +一款框架如果在一个协议的 sdk 之上封装接口,可以认为它处于应用层次支持,这样的框架需要遵循下层 sdk 的接口,可扩展性较差。 + +处于协议层次的框架,从配置层到服务治理层均由本框架提供,而在此之下的协议层到网络传输层均使用某个固定的通信协议,这样的框架可以解决服务治理的问题,但框架本身无法与第三方协议完全适配,如果不适配就会出现对第三方协议支持的削弱,比如上面说到的 dubbo-go 1.5 对 stream rpc 支持的缺陷。 + +如果想进一步支持更多的第三方协议,需要从传输层下手,真正了解第三方协议的具体字段、所依赖的底层协议(比如 HTTP2)的帧模型和数据流,再开发出与第三方协议完全一致的数据交互模块,作为本框架的底层。这样做的好处是最大程度赋予了协议的可扩展性,可以在兼容已有协议的基础之上,可选地增加开发者需要的字段,从而实现已有协议无法实现的功能,就比如 dubbogo 3.0 将支持的反压策略。 + +## 基于 HTTP2 的通信流程 + +gRPC 一次基于 HTTP2 的 unary rpc 调用传输主要流程如下: + +- client 发送 Magic 信息: + PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n; +- server 收到并检查是否正确; +- client 和 server 互相发送 setting 帧,收到后发送 ACK 确认; +- client 发送 Header 帧,包含 gRPC 协议字段,以 End Headers 作为 Header 结束标志; +- client 紧接着发送 Data 帧,包含 RPC 调用的 request 信息,以 End Stream 作为 Data 结束标志; +- server 调用函数获得结果; +- server 发送 Header 帧,包含 gRPC 协议字段,以 End Headers 作为 Header 结束标志; +- server 紧接着发送 Data 帧,包含 RPC 调用回传的 response 信息; +- server 紧接着再次发送 Header 帧,包含 RPC 状态和 message 信息,以 End Stream 作为本次 RPC 调用结束标志。 + +其中包含 gRPC 调用信息的 HTTP2 Header 帧如下图: + +![img](/imgs/blog/dubbo-go/3.0-plan/p3.webp) + +另外,在 gRPC 的 stream 调用中,可在 server 端回传的过程中发送多次 Data,调用结束后再发送 Header 终止 RPC 过程,并汇报状态信息。 + +dubbogo 3.0 的通信层将在 HTTP2 通信协议之上采用同样的通信流程,以保证与 gRPC 的底层通信沟通能力。 + +## dubbogo 3.0 预期通信架构 + +除了通信协议采用 HTTP2 外,dubbogo 3.0 将采用基于 google protobuf 的 triple 协议【下面称为 dubbo3 协议】作为 dubbogo 3.0 的序列化协议,为 dubbo 将来支持更多的编程语言打下通信协议层面的基础。 + +目前设计的 dubbogo 3.0 传输模型如下: + +![img](/imgs/blog/dubbo-go/3.0-plan/p4.webp) + +- 为保证同时支持 unary RPC 和 stream RPC,在 server 端和 client 端增加数据流结构,以异步调用的形式完成数据传递; +- 继续支持原有的 TCP 通信能力; +- 在 HTTP2 的通信协议之上支持 dubbo3 协议,decode 过程兼容 gRPC 使用的 protobuf,保证与 gRPC 服务打通。 + +## 应用级服务注册发现 + +#### 1. 应用级服务注册发现介绍 + +dubbogo 3.0 使用的新一代服务注册发现体系,将摒弃旧版的“接口级注册发现”,使用“应用级别注册发现”。 + +简单地说,接口级别注册发现,在注册中心中以 RPC 服务为 key,以实例列表作为 value 来组织数据的,而我们新引入的“应用粒度的服务发现”,它以应用名(Application)作为 key,以这个应用部署的一组实例(Instance)列表作为 value。这带来两点不同: + +- 数据映射关系变了,从 RPC Service -> Instance 变为 Application -> Instance; +- 数据变少了,注册中心没有了 RPC Service 及其相关配置信息。 + +可以认为,基于应用粒度的模型所存储和推送的数据量是和应用、实例数成正比的,只有当我们的应用数增多或应用的实例数增长时,地址推送压力才会上涨。 + +而对于基于接口粒度的模型,数据量是和接口数量正相关的,鉴于一个应用通常发布多个接口的现状,其数量级一般是比应用粒度的数十倍。另外一个关键点在于,接口的定义更多的是业务侧的内部行为,接口粒度导致的集群规模评估的不透明,而实例、应用增长都通常是在运维侧的规划之中,可控性较好。 + +工商银行曾经对这两个模型进行生产测算:应用级服务注册模型可以让注册中心上的数据量变成原来的 1.68%,新模型可以让 zookeeper 轻松支撑 10 万级别的服务量和 10 万级别的节点量。 + +#### 2. 元数据中心同步机制的引入 + +数据中心的数据量变少所造成的结果,是 RPC 服务相关的数据在注册中心消失了,只有 application - instance 这两个层级的数据。为了保证这部分缺少的 RPC 服务数据仍然能被 Consumer 端正确的感知,我们在 Consumer 和 Provider 间建立了一条单独的通信通道,目前针对元数据同步有两种具体的可选方案,分别是: + +- 内建 MetadataService; +- 独立的元数据中心,通过中细化的元数据集群协调数据。 + +#### 3. 兼容旧版本 dubbo-go + +为了使整个开发流程对老的 dubbo-go 用户更透明,同时避免指定 provider 对可扩展性带来的影响),我们设计了一套 RPC服务到应用名的映射关系,以尝试在 consumer 自动完成 RPC 服务到 provider 应用名的转换。 + +![img](/imgs/blog/dubbo-go/3.0-plan/p5.webp) + +这套设计可以让 dubbogo 3.0 中同时保持对 dubbo v2.6.x、dubbo v2.7.x 和 dubbo v3.0.x 三个大版的互联互通。 + +## 统一路由的支持 + +路由在概念上可以理解为从已有的所有 IP 地址列表中,根据特定的路由规则,挑选出需要的 ip 地址子集。路由的过程需要根据配置好的路由规则进行筛选,最终取所有路由规则的交集获得结果。多个路由如同流水线一样,形成一条路由链,从所有的地址表中筛选出最终目的地址集合,再通过负载均衡策略选择访问的地址。 + +#### 1. 路由链 + +![img](/imgs/blog/dubbo-go/3.0-plan/p6.webp) + +可以把路由链的逻辑简单理解为 target = rn(...r3(r2(r1(src))))。对于每一个 router 内部的逻辑,可以抽象为输入地址 addrs-in 与 router 中按全量地址 addrs-all 实现切分好的 n 个**互不相交**的地址池 addrs-pool-1 ... addrs-pool-n 按实现定义好的规则取交集作为输出地址。以此类推,完成整个路由链的计算。 + +![img](/imgs/blog/dubbo-go/3.0-plan/p7.webp) + +#### 2. failover + +在路由规则配置文件中可以配置 failover 字段。在寻找地址失败时可以 failover, 选择其他 subset,并且顺序执行下来,直到找到地址,否则最后报地址找不到异常。 + +#### 3. 兜底路由 + +在的路由规则配置中,可以配置一个没有任何条件的 match, 最终的结果是至少会有一个 subset 被选到,以达到地址空保护的作用。 + +作为 2020 年 dubbogo 社区打造并将在 2021 年初亮出的的三支箭之一,dubbogo 3.0 将带来不同平常且焕然一新的开发体验,敬请广大开发者期待! + +如果你有任何疑问,欢迎钉钉扫码加入交流群【钉钉群号 31363295】: + +dubbogo 3.0 目前是社区和 dubbo 官方团队-- 阿里中间件团队共同合作开发。 + +阿里云-中间件团队招募对 dubbo3 (java & go)、dapr、arthas 有兴趣的开发者。可以钉钉联系 northlatitude,或者发送邮件至 beiwei.ly@alibaba-inc.com。 + +> 作者简介 +> +> **李志信** (GitHubID LaurenceLiZhixin),阿里云云原生中间件团队开发工程师,dubbogo 社区开发者,中山大学软件工程专业在校学生,擅长使用 Go 语言,专注于云原生和微服务等技术方向。 +> +> **于雨**(github @AlexStocks),dubbo-go 项目和社区负责人,一个有十多年服务端做着基础架构研发一线工作经验的程序员,陆续参与改进过 Muduo/Pika/Dubbo/Sentinel-go 等知名项目,目前在蚂蚁金服可信原生部从事容器编排和 service mesh 工作。 diff --git a/content/en/blog/golang/dubbo-go-codewalk-1.md b/content/en/blog/golang/dubbo-go-codewalk-1.md new file mode 100644 index 000000000000..ec33a83f1fc4 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-codewalk-1.md @@ -0,0 +1,672 @@ +--- +title: "Dubbo-go 源码笔记(一)Server 端开启服务过程" +linkTitle: "Dubbo-go 源码笔记(一)Server 端开启服务过程" +tags: ["Go", "源码解析"] +date: 2021-01-14 +description: 本文将介绍 dubbo-go 框架的基本使用方法,以及从 export 调用链的角度进行 server 端源码导读,希望能引导读者进一步认识这款框架。 +--- + +随着微服务架构的流行,许多高性能 rpc 框架应运而生,由阿里开源的 dubbo 框架 go 语言版本的 dubbo-go 也成为了众多开发者不错的选择。本文将介绍 dubbo-go 框架的基本使用方法,以及从 export 调用链的角度进行 server 端源码导读,希望能引导读者进一步认识这款框架。 + +当拿到一款框架之后,一种不错的源码阅读方式大致如下:从运行最基础的 helloworld demo 源码开始 —> 再查看配置文件 —> 开启各种依赖服务(比如zk、consul) —> 开启服务端 —> 再到通过 client 调用服务端 —> 打印完整请求日志和回包。调用成功之后,再根据框架的设计模型,从配置文件解析开始,自顶向下递阅读整个框架的调用栈。 + +对于 C/S 模式的 rpc 请求来说,整个调用栈被拆成了 client 和 server 两部分,所以可以分别从 server 端的配置文件解析阅读到 server 端的监听启动,从 client 端的配置文件解析阅读到一次 invoker Call 调用。这样一次完整请求就明晰了起来。 + +## 运行官网提供的 helloworld-demo + +**官方 demo 相关链接**:https://github.com/dubbogo/dubbo-samples/tree/master/golang/helloworld/dubbo + +### 1. dubbo-go 2.7 版本 QuickStart + +#### 1)开启一个 go-server 服务 + +- 将仓库 clone 到本地 + +```bash +$ git clone https://github.com/dubbogo/dubbo-samples.git +``` + +- 进入 dubbo 目录 + +```bash +$ cd dubbo-samples/golang/helloworld/dubbo +``` + +进入目录后可看到四个文件夹,分别支持 go 和 java 的 client 以及 server,我们尝试运行一个 go 的 server。进入 app 子文件夹内,可以看到里面保存了 go 文件。 + +```bash +$ cd go-server/app +``` + +- sample 文件结构 + +可以在 go-server 里面看到三个文件夹:app、assembly、profiles。 + +其中 app 文件夹下保存 go 源码,assembly 文件夹下保存可选的针对特定环境的 build 脚本,profiles 下保存配置文件。对于 dubbo-go 框架,配置文件非常重要,没有文件将导致服务无法启动。 + +- 设置指向配置文件的环境变量 + +由于 dubbo-go 框架依赖配置文件启动,让框架定位到配置文件的方式就是通过环境变量来找。对于 server 端需要两个必须配置的环境变量:CONF_PROVIDER_FILE_PATH、APP_LOG_CONF_FILE,分别应该指向服务端配置文件、日志配置文件。 + +在 sample 里面,我们可以使用 dev 环境,即 profiles/dev/log.yml 和 profiles/dev/server.yml 两个文件。在 app/ 下,通过命令行中指定好这两个文件: + +```bash +$ export CONF_PROVIDER_FILE_PATH="../profiles/dev/server.yml" +$ export APP_LOG_CONF_FILE="../profiles/dev/log.yml" +``` + +- 设置 go 代理并运行服务 + +```bash +$ go run . +``` + +如果提示 timeout,则需要设置 goproxy 代理。 + +```bash +$ export GOPROXY="http://goproxy.io" +``` + +再运行 go run 即可开启服务。 + +#### 2)运行 zookeeper + +安装 zookeeper,并运行 zkServer, 默认为 2181 端口。 + +#### 3)运行 go-client 调用 server 服务 + +- 进入 go-client 的源码目录 + +```bash +$ cd go-client/app +``` + +- 同理,在 /app 下配置环境变量 + +```bash +$ export CONF_CONSUMER_FILE_PATH="../profiles/dev/client.yml" +$ export APP_LOG_CONF_FILE="../profiles/dev/log.yml" +``` + +配置 go 代理: + +```bash +$ export GOPROXY="http://goproxy.io" +```` + +- 运行程序 + +```bash +$ go run . +``` + +即可在日志中找到打印出的请求结果: + +```bash +response result: &{A001 Alex Stocks 18 2020-10-28 14:52:49.131 +0800 CST} +``` + +同样,在运行的 server 中,也可以在日志中找到打印出的请求: + +```bash +req:[]interface {}{"A001"} +rsp:main.User{Id:"A001", Name:"Alex Stocks", Age:18, Time:time.Time{...} +``` + +恭喜!一次基于 dubbo-go 的 rpc 调用成功。 + +#### 4)常见问题 + +- 当日志开始部分出现 profiderInit 和 ConsumerInit 均失败的日志,检查环境变量中配置路径是否正确,配置文件是否正确。 +- 当日志中出现 register 失败的情况,一般为向注册中心注册失败,检查注册中心是否开启,检查配置文件中关于 register 的端口是否正确。 +- sample 的默认开启端口为 20000,确保启动前无占用。 + +### 2. 配置环境变量 + +```bash +export APP_LOG_CONF_FILE="../profiles/dev/log.yml" +export CONF_CONSUMER_FILE_PATH="../profiles/dev/client.yml" +``` + +### 3. 服务端源码 + +#### 1)目录结构 + +dubbo-go 框架的 example 提供的目录如下: + +![img](/imgs/blog/dubbo-go/code1/p1.png) + +- app/ 文件夹下存放源码,可以自己编写环境变量配置脚本 buliddev.sh +- assembly/ 文件夹下存放不同平台的构建脚本 +- profiles/ 文件夹下存放不同环境的配置文件 +- target/ 文件夹下存放可执行文件 + +### 2)关键源码 + +源码放置在 app/ 文件夹下,主要包含 server.go 和 user.go 两个文件,顾名思义,server.go 用于使用框架开启服务以及注册传输协议;user.go 则定义了 rpc-service 结构体,以及传输协议的结构。 + +- **user.go** + +```go +func init() { + config.SetProviderService(new(UserProvider)) + // ------for hessian2------ + hessian.RegisterPOJO(&User{}) +} +type User struct { + Id string + Name string + Age int32 + Time time.Time +} +type UserProvider struct { +} +func (u *UserProvider) GetUser(ctx context.Context, req []interface{}) (*User, error) { +``` + +可以看到,user.go 中存在 init 函数,是服务端代码中最先被执行的部分。User 为用户自定义的传输结构体,UserProvider 为用户自定义的 rpc_service;包含一个 rpc 函数,GetUser。当然,用户可以自定义其他的 rpc 功能函数。 + +在 init 函数中,调用 config 的 SetProviderService 函数,将当前 rpc_service 注册在框架 config 上。 + +**可以查看 dubbo 官方文档提供的设计图:** + +![img](/imgs/blog/dubbo-go/code1/p2.png) + +service 层下面就是 config 层,用户服务会逐层向下注册,最终实现服务端的暴露。 + +rpc-service 注册完毕之后,调用 hessian 接口注册传输结构体 User。 + +至此,init 函数执行完毕。 + +- **server.go** + +```go +// they are necessary: +// export CONF_PROVIDER_FILE_PATH="xxx" +// export APP_LOG_CONF_FILE="xxx" +func main() { + hessian.RegisterPOJO(&User{}) + config.Load() + initSignal() +} +func initSignal() { + signals := make(chan os.Signal, 1) + ... +``` + +之后执行 main 函数。 + +main 函数中只进行了两个操作,首先使用 hessian 注册组件将 User 结构体注册(与之前略有重复),从而可以在接下来使用 getty 打解包。 + +之后调用 config.Load 函数,该函数位于框架 config/config_loader.go 内,这个函数是整个框架服务的启动点,**下面会详细讲这个函数内重要的配置处理过程**。执行完 Load() 函数之后,配置文件会读入框架,之后根据配置文件的内容,将注册的 service 实现到配置结构里,再调用 Export 暴露给特定的 registry,进而开启特定的 service 进行对应端口的 tcp 监听,成功启动并且暴露服务。 + +最终开启信号监听 initSignal() 优雅地结束一个服务的启动过程。 + +### 4. 客户端源码 + +客户端包含 client.go 和 user.go 两个文件,其中 user.go 与服务端完全一致,不再赘述。 + +- **client.go** + +```go +// they are necessary: +// export CONF_CONSUMER_FILE_PATH="xxx" +// export APP_LOG_CONF_FILE="xxx" +func main() { + hessian.RegisterPOJO(&User{}) + config.Load() + time.Sleep(3e9) + println("\n\n\nstart to test dubbo") + user := &User{} + err := userProvider.GetUser(context.TODO(), []interface{}{"A001"}, user) + if err != nil { + panic(err) + } + println("response result: %v\n", user) + initSignal() +} +``` + +main 函数和服务端也类似,首先将传输结构注册到 hessian 上,再调用 config.Load() 函数。在下文会介绍,客户端和服务端会根据配置类型执行 config.Load() 中特定的函数 loadConsumerConfig() 和 loadProviderConfig(),从而达到“开启服务”、“调用服务”的目的。 + +加载完配置之后,还是通过实现服务、增加函数 proxy、申请 registry 和 reloadInvoker 指向服务端 ip 等操作,重写了客户端实例 userProvider 的对应函数,这时再通过调用 GetUser 函数,可以直接通过 invoker,调用到已经开启的服务端,实现 rpc 过程。 + +下面会从 server 端和 client 端两个角度,详细讲解服务启动、registry 注册和调用过程。 + +### 5. 自定义配置文件(非环境变量)方法 + +#### 1)服务端自定义配置文件 + +- var providerConfigStr = `xxxxx`// 配置文件内容,可以参考 log 和 client。在这里你可以定义配置文件的获取方式,比如配置中心,本地文件读取。 + +> **log 地址**:https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-client/profiles/release/log.yml +> +> **client 地址**:https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-client/profiles/release/client.yml + +- 在 `config.Load()` 之前设置配置,例如: + +```go +func main() { + hessian.RegisterPOJO(&User{}) + providerConfig := config.ProviderConfig{} + yaml.Unmarshal([]byte(providerConfigStr), &providerConfig) + config.SetProviderConfig(providerConfig) + defaultServerConfig := dubbo.GetDefaultServerConfig() + dubbo.SetServerConfig(defaultServerConfig) + logger.SetLoggerLevel("warn") // info,warn + config.Load() + select { + } +} +``` + +#### 2)客户端自定义配置文件 + +- var consumerConfigStr = `xxxxx`// 配置文件内容,可以参考 log 和 clien。在这里你可以定义配置文件的获取方式,比如配置中心,本地文件读取。 +- 在 `config.Load()` 之前设置配置,例如: + +```go +func main() { + p := config.ConsumerConfig{} + yaml.Unmarshal([]byte(consumerConfigStr), &p) + config.SetConsumerConfig(p) + defaultClientConfig := dubbo.GetDefaultClientConfig() + dubbo.SetClientConf(defaultClientConfig) + logger.SetLoggerLevel("warn") // info,warn + config.Load() + + user := &User{} + err := userProvider.GetUser(context.TODO(), []interface{}{"A001"}, user) + if err != nil { + log.Print(err) + return + } + log.Print(user) +} +``` + +## Server 端 + +服务暴露过程涉及到多次原始 rpcService 的封装、暴露,网上其他文章的图感觉太过笼统,在此,简要地绘制了一个用户定义服务的数据流图: + +![img](/imgs/blog/dubbo-go/code1/p3.png) + +### 1. 加载配置 + +#### 1)框架初始化 + +在加载配置之前,框架提供了很多已定义好的协议、工厂等组件,都会在对应模块 init 函数内注册到 extension 模块上,以供接下来配置文件中进行选用。 + +其中重要的有: + +- **默认函数代理工厂**:common/proxy/proxy_factory/default.go + +```go +func init() { + extension.SetProxyFactory("default", NewDefaultProxyFactory) +} +``` + +它的作用是将原始 rpc-service 进行封装,形成 proxy_invoker,更易于实现远程 call 调用,详情可见其 invoke 函数。 + +- **注册中心注册协议**: + registry/protocol/protocol.go + +```go +func init() { + extension.SetProtocol("registry", GetProtocol) +} +``` + +它负责将 invoker 暴露给对应注册中心,比如 zk 注册中心。 + +- **zookeeper 注册协议**:registry/zookeeper/zookeeper.go + +```go +func init() { + extension.SetRegistry("zookeeper", newZkRegistry) +} +``` + +它合并了 base_resiger,负责在服务暴露过程中,将服务注册在 zookeeper 注册器上,从而为调用者提供调用方法。 + +- **dubbo 传输协议**:protocol/dubbo/dubbo.go + +```go +func init() { + extension.SetProtocol(DUBBO, GetProtocol) +} +``` + +它负责监听对应端口,将具体的服务暴露,并启动对应的事件 handler,将远程调用的 event 事件传递到 invoker 内部,调用本地 invoker 并获得执行结果返回。 + +- **filter 包装调用链协议**:protocol/protocolwrapper/protocol_filter_wrapper.go + +```go +func init() { + extension.SetProtocol(FILTER, GetProtocol) +} +``` + +它负责在服务暴露过程中,将代理 invoker 打包,通过配置好的 filter 形成调用链,并交付给 dubbo 协议进行暴露。 + +上述提前注册好的框架已实现的组件,在整个服务暴露调用链中都会用到,会根据配置取其所需。 + +#### 2)配置文件 + +服务端需要的重要配置有三个字段:services、protocols、registries。 + +profiles/dev/server.yml: + +```yaml +registries : + "demoZk": + protocol: "zookeeper" + timeout : "3s" + address: "127.0.0.1:2181" +services: + "UserProvider": + # 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册 + registry: "demoZk" + protocol : "dubbo" + # 相当于dubbo.xml中的interface + interface : "com.ikurento.user.UserProvider" + loadbalance: "random" + warmup: "100" + cluster: "failover" + methods: + - name: "GetUser" + retries: 1 + loadbalance: "random" +protocols: + "dubbo": + name: "dubbo" + port: 20000 +``` + +其中 service 指定了要暴露的 rpc-service 名("UserProvider)、暴露的协议名("dubbo")、注册的协议名("demoZk")、暴露的服务所处的 interface、负载均衡策略、集群失败策略及调用的方法等等。 + +其中,中间服务的协议名需要和 registries 下的 mapkey 对应,暴露的协议名需要和 protocols 下的 mapkey 对应。 + +可以看到上述例子中,使用了 dubbo 作为暴露协议,使用了 zookeeper 作为中间注册协议,并且给定了端口。如果 zk 需要设置用户名和密码,也可以在配置中写好。 + +#### 3)配置文件的读入和检查 + +> config/config_loader.go:: Load() + +在上述 example 的 main 函数中,有 config.Load() 函数的直接调用,该函数执行细节如下: + +```go +// Load Dubbo Init +func Load() { + // init router + initRouter() + // init the global event dispatcher + extension.SetAndInitGlobalDispatcher(GetBaseConfig().EventDispatcherType) + // start the metadata report if config set + if err := startMetadataReport(GetApplicationConfig().MetadataType, GetBaseConfig().MetadataReportConfig); err != nil { + logger.Errorf("Provider starts metadata report error, and the error is {%#v}", err) + return + } + // reference config + loadConsumerConfig() + // service config + loadProviderConfig() + // init the shutdown callback + GracefulShutdownInit() +} +``` + +在本文中,我们重点关心 loadConsumerConfig() 和 loadProviderConfig() 两个函数。 + +对于 provider 端,可以看到 loadProviderConfig() 函数代码如下: + +![img](/imgs/blog/dubbo-go/code1/p4.png) + +前半部分是配置的读入和检查,进入 for 循环后,是单个 service 的暴露起始点。 + +前面提到,在配置文件中已经写好了要暴露的 service 的种种信息,比如服务名、interface 名、method 名等等。在图中 for 循环内,会将所有 service 的服务依次实现。 + +for 循环的第一行,根据 key 调用 GetProviderService 函数,拿到注册的 rpcService 实例,这里对应上述提到的 init 函数中,用户手动注册的自己实现的 rpc-service 实例: + +![img](/imgs/blog/dubbo-go/code1/p5.png) + +这个对象也就成为了 for 循环中的 rpcService 变量,将这个对象注册通过 Implement 函数写到 sys(ServiceConfig 类型)上,设置好 sys 的 key 和协议组,最终调用了 sys 的 Export 方法。 + +此处对应流程图的部分: + +![img](/imgs/blog/dubbo-go/code1/p6.png) + +至此,框架配置结构体已经拿到了所有 service 有关的配置,以及用户定义好的 rpc-service 实例,它触发了 Export 方法,旨在将自己的实例暴露出去。这是 Export 调用链的起始点。 + +### 2. 原始 service 封装入 proxy_invoker + +> config/service_config.go :: Export() + +接下来进入 ServiceConfig.Export() 函数. + +这个函数进行了一些细碎的操作,比如为不同的协议分配随机端口,如果指定了多个中心注册协议,则会将服务通过多个中心注册协议的 registryProtocol 暴露出去,我们只关心对于一个注册协议是如何操作的。还有一些操作比如生成调用 url 和注册 url,用于为暴露做准备。 + +#### 1)首先通过配置生成对应 registryUrl 和 serviceUrl + +![img](/imgs/blog/dubbo-go/code1/p7.png) + +registryUrl 是用来向中心注册组件发起注册请求的,对于 zookeeper 的话,会传入其 ip 和端口号,以及附加的用户名密码等信息。 + +这个 regUrl 目前只存有注册(zk)相关信息,后续会补写入 ServiceIvk,即服务调用相关信息,里面包含了方法名,参数等... + +#### 2)对于一个注册协议,将传入的 rpc-service 实例注册在 common.ServiceMap + +![img](/imgs/blog/dubbo-go/code1/p8.png) + +这个 Register 函数将服务实例注册了两次,一次是以 Interface 为 key 写入接口服务组内,一次是以 interface 和 proto 为 key 写入特定的一个唯一的服务。 + +后续会从 common.Map 里面取出来这个实例。 + +#### 3)获取默认代理工厂,将实例封装入代理 invoker + +```go +// 拿到一个proxyInvoker,这个invoker的url是传入的regUrl,这个地方将上面注册的service实例封装成了invoker +// 这个GetProxyFactory返回的默认是common/proxy/proxy_factory/default.go +// 这个默认工厂调用GetInvoker获得默认的proxyInvoker,保存了当前注册url +invoker := extension.GetProxyFactory(providerConfig.ProxyFactory).GetInvoker(*regUrl) +// 暴露出来 生成exporter,开启tcp监听 +// 这里就该跳到registry/protocol/protocol.go registryProtocol 调用的Export,将当前proxyInvoker导出 +exporter = c.cacheProtocol.Export(invoker) +``` + +这一步的 GetProxyFactory("default") 方法获取默认代理工厂,通过传入上述构造的 regUrl,将 url 封装入代理 invoker。 + +可以进入 common/proxy/proxy_factory/default.go::ProxyInvoker.Invoke() 函数里,看到对于 common.Map 取用为 svc 的部分,以及关于 svc 对应 Method 的实际调用 Call 的函数如下: + +![img](/imgs/blog/dubbo-go/code1/p9.png) + +到这里,上面 GetInvoker(*regUrl) 返回的 invoker 即为 proxy_invoker,它封装好了用户定义的 rpc_service,并将具体的调用逻辑封装入了 Invoke 函数内。 + +> 为什么使用 Proxy_invoker 来调用? +> +> 通过这个 proxy_invoke 调用用户的功能函数,调用方式将更加抽象化,可以在代码中看到,通过 ins 和 outs 来定义入参和出参,将整个调用逻辑抽象化为 invocation 结构体,而将具体的函数名的选择、参数向下传递和 reflect 反射过程封装在 invoke 函数内,这样的设计更有利于之后远程调用。个人认为这是 dubbo Invoke 调用链的设计思想。 +> +> 至此,实现了图中对应的部分: + +![img](/imgs/blog/dubbo-go/code1/p10.png) + +### 3. registry 协议在 zkRegistry 上暴露上面的 proxy_invoker + +上面,我们执行到了 exporter = c.cacheProtocol.Export(invoker)。 + +这里的 cacheProtocol 为一层缓存设计,对应到原始的 demo 上,这里是默认实现好的 registryProtocol。 + +> registry/protocol/protocol.go:: Export() + +这个函数内构造了多个 EventListener,非常有 java 的设计感。 + +我们只关心服务暴露的过程,先忽略这些监听器。 + +#### 1)获取注册 url 和服务 url + +![img](/imgs/blog/dubbo-go/code1/p11.png) + +#### 2)获取注册中心实例 zkRegistry + +![img](/imgs/blog/dubbo-go/code1/p12.png) + +一层缓存操作,如果 cache 没有需要从 common 里面重新拿 zkRegistry。 + +#### 3)zkRegistry 调用 Registry 方法,在 zookeeper 上注册 dubboPath + +上述拿到了具体的 zkRegistry 实例,该实例的定义在:registry/zookeeper/registry.go。 + +![img](/imgs/blog/dubbo-go/code1/p13.png) + +该结构体组合了 registry.BaseRegistry 结构,base 结构定义了注册器基础的功能函数,比如 Registry、Subscribe 等,但在这些默认定义的函数内部,还是会调用 facade 层(zkRegistry 层)的具体实现函数,这一设计模型能在保证已有功能函数不需要重复定义的同时,引入外层函数的实现,类似于结构体继承却又复用了代码。这一设计模式值得学习。 + +我们查看上述 registry/protocol/protocol.go:: Export() 函数,直接调用了: + +```go +// 1. 通过zk注册器,调用Register()函数,将已有@root@rawurl注册到zk上 + err := reg.Register(*registeredProviderUrl) +``` + +将已有 RegistryUrl 注册到了 zkRegistry 上。 + +这一步调用了 baseRegistry 的 Register 函数,进而调用 zkRegister 的 DoRegister 函数,进而调用: + +![img](/imgs/blog/dubbo-go/code1/p14.png) + +在这个函数里,将对应 root 创造一个新的节点。 + +![img](/imgs/blog/dubbo-go/code1/p15.png) + +并且写入具体 node 信息,node 为 url 经过 encode 的结果,**包含了服务端的调用方式。** + +这部分的代码较为复杂,具体可以看 baseRegistry 的 processURL() 函数:http://t.tb.cn/6Xje4bijnsIDNaSmyPc4Ot。 + +至此,将服务端调用 url 注册到了 zookeeper 上,而客户端如果想获取到这个 url,只需要传入特定的 dubboPath,向 zk 请求即可。目前 client 是可以获取到访问方式了,但服务端的特定服务还没有启动,还没有开启特定协议端口的监听,这也是 registry/protocol/protocol.go:: Export() 函数接下来要做的事情。 + +#### 4)proxy_invoker 封装入 wrapped_invoker,得到 filter 调用链 + +```go + // invoker封装入warppedInvoker + wrappedInvoker := newWrappedInvoker(invoker, providerUrl) + // 经过为invoker增加filter调用链,再使用dubbo协议Export,开启service并且返回了Exporter 。 + // export_1 + cachedExporter = extension.GetProtocol(protocolwrapper.FILTER).Export(wrappedInvoker) +``` + +新建一个 WrappedInvoker,用于之后链式调用。 + +拿到提前实现并注册好的 ProtocolFilterWrapper,调用 Export 方法,进一步暴露。 + +> protocol/protocolwrapped/protocol_filter_wrapper.go:Export() + +![img](/imgs/blog/dubbo-go/code1/p16.png) + +> protocol/protocolwrapped/protocol_filter_wrapper.go:buildInvokerChain + +![img](/imgs/blog/dubbo-go/code1/p17.png) + +可见,根据配置的内容,通过链式调用的构造,将 proxy_invoker 层层包裹在调用链的最底部,最终返回一个调用链 invoker。 + +对应图中部分: + +![img](/imgs/blog/dubbo-go/code1/p18.png) + +至此,我们已经拿到 filter 调用链,期待将这个 chain 暴露到特定端口,用于相应请求事件。 + +#### 5)通过 dubbo 协议暴露 wrapped_invoker + +> protocol/protocolwrapped/protocol_filter_wrapper.go:Export() + +```go +// 通过dubbo协议Export dubbo_protocol调用的 export_2 + return pfw.protocol.Export(invoker) +``` + +回到上述 Export 函数的最后一行,调用了 dubboProtocol 的 Export 方法,将上述 chain 真正暴露。 + +该 Export 方法的具体实现在:protocol/dubbo/dubbo_protocol.go: Export()。 + +![img](/imgs/blog/dubbo-go/code1/p19.png) + +这一函数做了两个事情:构造触发器、启动服务。 + +- 将传入的 Invoker 调用 chain 进一步封装,封装成一个 exporter,再将这个 export 放入 map 保存。**注意!这里把 exporter 放入了 SetExporterMap中,在下面服务启动的时候,会以注册事件监听器的形式将这个 exporter 取出!** +- 调用 dubboProtocol 的 openServer 方法,开启一个针对特定端口的监听。 + +![img](/imgs/blog/dubbo-go/code1/p20.png) + +如上图所示,一个 Session 被传入,开启对应端口的事件监听。 + +至此构造出了 exporter,完成图中部分: + +![img](/imgs/blog/dubbo-go/code1/p21.png) + +### 4. 注册触发动作 + +上述只是启动了服务,但还没有看到触发事件的细节,点进上面的 s.newSession 可以看到,dubbo 协议为一个 getty 的 session 默认使用了如下配置: + +![img](/imgs/blog/dubbo-go/code1/p22.png) + +其中很重要的一个配置是 EventListener,传入的是 dubboServer 的默认 rpcHandler。 + +> protocol/dubbo/listener.go:OnMessage() + +rpcHandler 有一个实现好的 OnMessage 函数,根据 getty 的 API,当 client 调用该端口时,会触发 OnMessage。 + +```go +// OnMessage notified when RPC server session got any message in connection +func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) { +``` + +这一函数实现了在 getty session 接收到 rpc 调用后的一系列处理: + +- 传入包的解析 + +![img](/imgs/blog/dubbo-go/code1/p23.png) + +- 根据请求包构造请求 url + +![img](/imgs/blog/dubbo-go/code1/p24.png) + +- 拿到对应请求 key,找到要被调用的 exporter + +![img](/imgs/blog/dubbo-go/code1/p25.png) + +- 拿到对应的 Invoker + +![img](/imgs/blog/dubbo-go/code1/p26.png) + +- 构造 invocation + +![img](/imgs/blog/dubbo-go/code1/p27.png) + +- 调用 + +![img](/imgs/blog/dubbo-go/code1/p28.png) + +- 返回 + +![img](/imgs/blog/dubbo-go/code1/p29.png) + +整个被调过程一气呵成。实现了从 getty.Session 的调用事件,到经过层层封装的 invoker 的调用。 + +至此,一次 rpc 调用得以正确返回。 + +## 小结 + +- **关于 Invoker 的层层封装** + +能把一次调用抽象成一次 invoke;能把一个协议抽象成针对 invoke 的封装;能把针对一次 invoke 所做出的特定改变封装到 invoke 函数内部,可以降低模块之间的耦合性。层层封装逻辑更加清晰。 + +- **关于 URL 的抽象** + +关于 dubbo 的统一化请求对象 URL 的极度抽象是之前没有见过的... 个人认为这样封装能保证请求参数列表的简化和一致。但在开发的过程中,滥用极度抽象的接口可能造成... debug 的困难?以及不知道哪些字段是当前已经封装好的,哪些字段是无用的。 + +- **关于协议的理解** + +之前理解的协议还是太过具体化了,而关于 dubbo-go 对于 dubboProtocol 的协议,我认为是基于 getty 的进一步封装,它定义了客户端和服务端,对于 getty 的 session 应该有哪些特定的操作,从而保证主调和被调的协议一致性,而这种保证也是一种协议的体现,是由 dubbo 协议来规范的。 + +如果你有任何疑问,欢迎钉钉扫码加入交流群:钉钉群号 23331795! + +> 作者简介 **李志信** (GitHubID LaurenceLiZhixin),中山大学软件工程专业在校学生,擅长使用 Java/Go 语言,专注于云原生和微服务等技术方向 diff --git a/content/en/blog/golang/dubbo-go-codewalk-2.md b/content/en/blog/golang/dubbo-go-codewalk-2.md new file mode 100644 index 000000000000..4065775fa914 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-codewalk-2.md @@ -0,0 +1,561 @@ +--- +title: "dubbo-go源码笔记(二)客户端调用过程" +linkTitle: "dubbo-go源码笔记(二)客户端调用过程" +tags: ["Go", "源码解析"] +date: 2021-01-15 +description: 本文将介绍 dubbo-go 框架的基本使用方法,以及从 export 调用链的角度进行 server 端源码导读,希望能引导读者进一步认识这款框架。 +--- + +随着微服务架构的流行,许多高性能 rpc 框架应运而生,由阿里开源的 dubbo 框架 go 语言版本的 dubbo-go 也成为了众多开发者不错的选择。本文将介绍 dubbo-go 框架的基本使用方法,以及从 export 调用链的角度进行 server 端源码导读,希望能引导读者进一步认识这款框架。 + +## 前言 + +有了上一篇文章[《dubbo-go 源码笔记(一)Server服务暴露过程详解》]({{}} "") 的铺垫,可以大致上类比客户端服务类似于服务端启动过程。其中最大的区别是服务端通过zk注册服务,发布自己的ivkURL并订阅事件开启监听;而服务端应该是通过zk注册组件,**拿到需要调用的serviceURL**,**更新invoker**并**重写用户的RPCService**,从而实现对远程过程调用细节的封装。 + +## 1. 配置文件和客户端源码 + +#### 1.1 client配置文件 + +helloworld提供的demo:profiles/client.yaml + +```yaml +registries : + "demoZk": + protocol: "zookeeper" + timeout : "3s" + address: "127.0.0.1:2181" + username: "" + password: "" +references: + "UserProvider": + # 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册 + registry: "demoZk" + protocol : "dubbo" + interface : "com.ikurento.user.UserProvider" + cluster: "failover" + methods : + - name: "GetUser" + retries: 3 +``` + +可看到配置文件与之前讨论过的server端非常类似,其refrences部分字段就是对当前服务要主调的服务的配置,其中详细说明了调用协议、注册协议、接口id、调用方法、集群策略等,这些配置都会在之后与注册组件交互,重写ivk、调用的过程中使用到。 + +#### 1.2 客户端使用框架源码 + +user.go + +```go +func init() { + config.SetConsumerService(userProvider) + hessian.RegisterPOJO(&User{}) +} +``` + +main.go + +```go +func main() { + hessian.RegisterPOJO(&User{}) + config.Load() + time.Sleep(3e9) + println("\n\n\nstart to test dubbo") + user := &User{} + err := userProvider.GetUser(context.TODO(), []interface{}{"A001"}, user) + if err != nil { + panic(err) + } + println("response result: %v\n", user) + initSignal() +} +``` + +官网提供的helloworld demo的源码。可看到与服务端类似,在user.go内注册了rpc-service,以及需要rpc传输的结构体user。 + +在main函数中,同样调用了config.Load()函数,之后就可以直接通过实现好的rpc-service:userProvider 直接调用对应的功能函数,即可实现rpc调用。 + +可以猜到,从hessian注册结构、SetConsumerService,到调用函数.GetUser()期间,用户定义的rpc-service也就是userProvider对应的函数被重写,重写后的GetUser函数已经包含了实现了远程调用逻辑的invoker。 + +接下来,就要通过阅读源码,看看dubbo-go是如何做到的。 + +## 2. 实现远程过程调用 + +#### 2.1 加载配置文件 + +config/config_loader.go :Load() + +```go +// Load Dubbo Init +func Load() { + // init router + initRouter() + // init the global event dispatcher + extension.SetAndInitGlobalDispatcher(GetBaseConfig().EventDispatcherType) + // start the metadata report if config set + if err := startMetadataReport(GetApplicationConfig().MetadataType, GetBaseConfig().MetadataReportConfig); err != nil { + logger.Errorf("Provider starts metadata report error, and the error is {%#v}", err) + return + } + // reference config + loadConsumerConfig() +``` + +在main函数中调用的config.Load()函数,进而调用了loadConsumerConfig,类似于之前讲到的server端配置读入函数。 + +在loadConsumerConfig函数中,进行了三步操作: + +![img](/imgs/blog/dubbo-go/code2/p1.png) + +1. 检查配置文件并将配置写入内存 +2. **在for循环内部**,依次引用(refer)并且实例化(implement)每个被调reference。 +3. 等待三秒钟所有invoker就绪 + +其中重要的就是for循环里面的引用和实例化,两步操作,会在接下来展开讨论。 + +至此,配置已经被写入了框架。 + +#### 2.2 获取远程Service URL,实现可供调用的invoker + +上述的ref.Refer完成的就是这部分的操作。 + +图(一) + +![img](/imgs/blog/dubbo-go/code2/p2.png) + +##### 2.2.1 构造注册url + +和server端类似,存在注册url和服务url,dubbo习惯将服务url作为注册url的sub。 + +config/reference_config.go: Refer() + +```go +/ Refer ... +func (c *ReferenceConfig) Refer(_ interface{}) { + //(一)配置url参数(serviceUrl),将会作为sub + cfgURL := common.NewURLWithOptions( + common.WithPath(c.id), + common.WithProtocol(c.Protocol), + common.WithParams(c.getUrlMap()), + common.WithParamsValue(constant.BEAN_NAME_KEY, c.id), + ) + ... + // (二)注册地址可以通过url格式给定,也可以通过配置格式给定 + // 这一步的意义就是配置->提取信息生成URL + if c.Url != "" {// 用户给定url信息,可以是点对点的地址,也可以是注册中心的地址 + // 1. user specified URL, could be peer-to-peer address, or register center's address. + urlStrings := gxstrings.RegSplit(c.Url, "\\s*[;]+\\s*") + for _, urlStr := range urlStrings { + serviceUrl, err := common.NewURL(urlStr) + ... + } + } else {// 配置读入注册中心的信息 + // assemble SubURL from register center's configuration mode + // 这是注册url,protocol = registry,包含了zk的用户名、密码、ip等等 + c.urls = loadRegistries(c.Registry, consumerConfig.Registries, common.CONSUMER) + ... + // set url to regUrls + for _, regUrl := range c.urls { + regUrl.SubURL = cfgURL// regUrl的subURl存当前配置url + } + } + //至此,无论通过什么形式,已经拿到了全部的regURL + // (三)获取registryProtocol实例,调用其Refer方法,传入新构建好的regURL + if len(c.urls) == 1 { + // 这一步访问到registry/protocol/protocol.go registryProtocol.Refer + // 这里是registry + c.invoker = extension.GetProtocol(c.urls[0].Protocol).Refer(*c.urls[0]) + } else { + // 如果有多个注册中心,即有多个invoker,则采取集群策略 + invokers := make([]protocol.Invoker, 0, len(c.urls)) + ... + } +``` + + + +这个函数中,已经处理完从Register配置到RegisterURL的转换,即图(一)中部分: + +![img](/imgs/blog/dubbo-go/code2/p3.png) + +接下来,已经拿到的url将被传递给RegistryProtocol,进一步refer。 + +##### 2.2.2 registryProtocol获取到zkRegistry实例,进一步Refer + +registry/protocol/protocol.go: Refer + +```go +// Refer provider service from registry center +// 拿到的是配置文件registries的url,他能够生成一个invoker = 指向目的addr,以供客户端直接调用。 +func (proto *registryProtocol) Refer(url common.URL) protocol.Invoker { + var registryUrl = url + // 这里拿到的是referenceConfig,serviceUrl里面包含了Reference的所有信息,包含interfaceName、method等等 + var serviceUrl = registryUrl.SubURL + if registryUrl.Protocol == constant.REGISTRY_PROTOCOL {// registryUrl.Proto = "registry" + protocol := registryUrl.GetParam(constant.REGISTRY_KEY, "") + registryUrl.Protocol = protocol//替换成了具体的值,比如"zookeeper" + } + // 接口对象 + var reg registry.Registry + // (一)实例化接口对象,缓存策略 + if regI, loaded := proto.registries.Load(registryUrl.Key()); !loaded { + // 缓存中不存在当前registry,新建一个reg + reg = getRegistry(®istryUrl) + // 缓存起来 + proto.registries.Store(registryUrl.Key(), reg) + } else { + reg = regI.(registry.Registry) + } + // 到这里,获取到了reg实例 zookeeper的registry + //(二)根据Register的实例zkRegistry和传入的regURL新建一个directory + // 这一步存在复杂的异步逻辑,从注册中心拿到了目的service的真实addr,获取了invoker并放入directory, + // 这一步将在下面详细给出步骤 + // new registry directory for store service url from registry + directory, err := extension.GetDefaultRegistryDirectory(®istryUrl, reg) + if err != nil { + logger.Errorf("consumer service %v create registry directory error, error message is %s, and will return nil invoker!", + serviceUrl.String(), err.Error()) + return nil + } + // (三)DoRegister 在zk上注册当前client service + err = reg.Register(*serviceUrl) + if err != nil { + logger.Errorf("consumer service %v register registry %v error, error message is %s", + serviceUrl.String(), registryUrl.String(), err.Error()) + } + // (四)new cluster invoker,将directory写入集群,获得具有集群策略的invoker + cluster := extension.GetCluster(serviceUrl.GetParam(constant.CLUSTER_KEY, constant.DEFAULT_CLUSTER)) + invoker := cluster.Join(directory) + // invoker保存 + proto.invokers = append(proto.invokers, invoker) + return invoker +} +``` + +可详细阅读上述注释,这个函数完成了从url到invoker的全部过程 + +(一)首先获得Registry对象,默认是之前实例化的zkRegistry,和之前server获取Registry的处理很类似。 +(二)通过构造一个新的directory,异步拿到之前在zk上注册的server端信息,生成invoker +(三)在zk上注册当前service +(四)集群策略,获得最终invoker + +这一步完成了图(一)中所有余下的绝大多数操作,接下来就需要详细的查看directory的构造过程: + +##### 2.2.3 构造directory(包含较复杂的异步操作) + +![img](/imgs/blog/dubbo-go/code2/p4.png) + +图(二) + +上述的 `extension.GetDefaultRegistryDirectory(®istryUrl, reg)`函数,本质上调用了已经注册好的`NewRegistryDirectory`函数: + +registry/directory/directory.go: NewRegistryDirectory() + +```go +// NewRegistryDirectory will create a new RegistryDirectory +// 这个函数作为default注册在extension上面 +// url为注册url,reg为zookeeper registry +func NewRegistryDirectory(url *common.URL, registry registry.Registry) (cluster.Directory, error) { + if url.SubURL == nil { + return nil, perrors.Errorf("url is invalid, suburl can not be nil") + } + dir := &RegistryDirectory{ + BaseDirectory: directory.NewBaseDirectory(url), + cacheInvokers: []protocol.Invoker{}, + cacheInvokersMap: &sync.Map{}, + serviceType: url.SubURL.Service(), + registry: registry, + } + dir.consumerConfigurationListener = newConsumerConfigurationListener(dir) + go dir.subscribe(url.SubURL) + return dir, nil +} +``` + +首先构造了一个注册directory,开启携程调用其subscribe函数,传入serviceURL。 + +这个directory目前包含了对应的zkRegistry,以及传入的URL,他cacheInvokers的部分是空的。 + +进入dir.subscribe(url.SubURL)这个异步函数: + +registry/directory/directory.go: subscribe() + +```go +// subscribe from registry +func (dir *RegistryDirectory) subscribe(url *common.URL) { + // 增加两个监听, + dir.consumerConfigurationListener.addNotifyListener(dir) + dir.referenceConfigurationListener = newReferenceConfigurationListener(dir, url) + // subscribe调用 + dir.registry.Subscribe(url, dir) +} +``` + +重点来了,他调用了zkRegistry的Subscribe方法,与此同时将自己作为ConfigListener传入 + +> 我认为这种传入listener的设计模式非常值得学习,而且很有java的味道。 +> +> 针对等待zk返回订阅信息这样的异步操作,需要传入一个Listener,这个Listener需要实现Notify方法,进而在作为参数传入内部之后,可以被异步地调用Notify,将内部触发的异步事件“传递出来”,再进一步处理加工。 +> +> 层层的Listener事件链,能将传入的原始serviceURL通过zkConn发送给zk服务,获取到服务端注册好的url对应的二进制信息。 +> +> 而Notify回调链,则将这串byte[]一步一步解析、加工;以事件的形式向外传递,最终落到directory上的时候,已经是成型的newInvokers了。 +> +> 具体细节不再以源码形式展示,可参照上图查阅源码。 + +至此已经拿到了server端注册好的真实invoker。 + +完成了图(一)中的部分: + +![img](/imgs/blog/dubbo-go/code2/p5.png) + +##### 2.2.4 构造带有集群策略的clusterinvoker + +经过上述操作,已经拿到了server端Invokers,放入了directory的cacheinvokers数组里面缓存。 + +后续的操作对应本文2.2.2的第四步,由directory生成带有特性集群策略的invoker + +```go +// (四)new cluster invoker,将directory写入集群,获得具有集群策略的invoker + cluster := extension.GetCluster(serviceUrl.GetParam(constant.CLUSTER_KEY, constant.DEFAULT_CLUSTER)) + invoker := cluster.Join(directory) +123 +``` + +Join函数的实现就是如下函数: + +cluster/cluster_impl/failover_cluster_invokers.go: newFailoverClusterInvoker() + +```go +func newFailoverClusterInvoker(directory cluster.Directory) protocol.Invoker { + return &failoverClusterInvoker{ + baseClusterInvoker: newBaseClusterInvoker(directory), + } +} +12345 +``` + +dubbo-go框架默认选择failover策略,既然返回了一个invoker,我们查看一下failoverClusterInvoker的Invoker方法,看他是如何将集群策略封装到Invoker函数内部的: + +cluster/cluster_impl/failover_cluster_invokers.go: Invoker() + +```go +// Invoker 函数 +func (invoker *failoverClusterInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result { + ... + //调用List方法拿到directory缓存的所有invokers + invokers := invoker.directory.List(invocation) + if err := invoker.checkInvokers(invokers, invocation); err != nil {// 检查是否可以实现调用 + return &protocol.RPCResult{Err: err} + } + // 获取来自用户方向传入的 + methodName := invocation.MethodName() + retries := getRetries(invokers, methodName) + loadBalance := getLoadBalance(invokers[0], invocation) + for i := 0; i <= retries; i++ { + // 重要!这里是集群策略的体现,失败后重试! + //Reselect before retry to avoid a change of candidate `invokers`. + //NOTE: if `invokers` changed, then `invoked` also lose accuracy. + if i > 0 { + if err := invoker.checkWhetherDestroyed(); err != nil { + return &protocol.RPCResult{Err: err} + } + invokers = invoker.directory.List(invocation) + if err := invoker.checkInvokers(invokers, invocation); err != nil { + return &protocol.RPCResult{Err: err} + } + } + // 这里是负载均衡策略的体现!选择特定ivk进行调用。 + ivk := invoker.doSelect(loadBalance, invocation, invokers, invoked) + if ivk == nil { + continue + } + invoked = append(invoked, ivk) + //DO INVOKE + result = ivk.Invoke(ctx, invocation) + if result.Error() != nil { + providers = append(providers, ivk.GetUrl().Key()) + continue + } + return result + } + ... +} +``` + +> 看了很多Invoke函数的实现,所有类似的Invoker函数都包含两个方向,一个是用户方向的invcation,一个是函数方向的底层invokers。 +> +> 而集群策略的invoke函数本身作为接线员,把invocation一步步解析,根据调用需求和集群策略,选择特定的invoker来执行 +> +> proxy函数也是这样,一个是用户方向的ins[] reflect.Type, 一个是函数方向的invoker。 +> +> proxy函数负责将ins转换为invocation,调用对应invoker的invoker函数,实现连通。 +> +> 而出于这样的设计,可以在一步步Invoker封装的过程中,每个Invoker只关心自己负责操作的部分,从而使整个调用栈解耦。 +> +> 妙啊!!! + +至此,我们理解了failoverClusterInvoker 的Invoke函数实现,也正是和这个集群策略Invoker被返回,接受来自上方的调用。 + +已完成图(一)中的: + +![img](/imgs/blog/dubbo-go/code2/p6.png) + +##### 2.2.5 在zookeeper上注册当前client + +拿到invokers后,可以回到: + +config/refrence_config.go: Refer()函数了。 + +```go + if len(c.urls) == 1 { + // 这一步访问到registry/protocol/protocol.go registryProtocol.Refer + c.invoker = extension.GetProtocol(c.urls[0].Protocol).Refer(*c.urls[0]) + // (一)拿到了真实的invokers + } else { + // 如果有多个注册中心,即有多个invoker,则采取集群策略 + invokers := make([]protocol.Invoker, 0, len(c.urls)) + ... + cluster := extension.GetCluster(hitClu) + // If 'zone-aware' policy select, the invoker wrap sequence would be: + // ZoneAwareClusterInvoker(StaticDirectory) -> + // FailoverClusterInvoker(RegistryDirectory, routing happens here) -> Invoker + c.invoker = cluster.Join(directory.NewStaticDirectory(invokers)) + } + // (二)create proxy,为函数配置代理 + if c.Async { + callback := GetCallback(c.id) + c.pxy = extension.GetProxyFactory(consumerConfig.ProxyFactory).GetAsyncProxy(c.invoker, callback, cfgURL) + } else { + // 这里c.invoker已经是目的addr了 + c.pxy = extension.GetProxyFactory(consumerConfig.ProxyFactory).GetProxy(c.invoker, cfgURL) + } +``` + +我们有了可以打通的invokers,但还不能直接调用,因为invoker的入参是invocation,而调用函数使用的是具体的参数列表。需要通过一层proxy来规范入参和出参。 + +接下来新建一个默认proxy,放置在c.proxy内,以供后续使用 + +至此,完成了图(一)中最后的操作 + +![img](/imgs/blog/dubbo-go/code2/p7.png) + +### 2.3 将调用逻辑以代理函数的形式写入rpc-service + +上面完成了config.Refer操作 + +回到config/config_loader.go: loadConsumerConfig() + +![img](/imgs/blog/dubbo-go/code2/p8.png) + +下一个重要的函数是Implement,他完的操作较为简单:旨在使用上面生成的c.proxy代理,链接用户自己定义的rpcService到clusterInvoker的信息传输。 + +函数较长,只选取了重要的部分: + +common/proxy/proxy.go: Implement() + +```go +// Implement +// proxy implement +// In consumer, RPCService like: +// type XxxProvider struct { +// Yyy func(ctx context.Context, args []interface{}, rsp *Zzz) error +// } +// Implement 实现的过程,就是proxy根据函数名和返回值,通过调用invoker 构造出拥有远程调用逻辑的代理函数 +// 将当前rpc所有可供调用的函数注册到proxy.rpc内 +func (p *Proxy) Implement(v common.RPCService) { + // makeDubboCallProxy 这是一个构造代理函数,这个函数的返回值是func(in []reflect.Value) []reflect.Value 这样一个函数 + // 这个被返回的函数是请求实现的载体,由他来发起调用获取结果 + makeDubboCallProxy := func(methodName string, outs []reflect.Type) func(in []reflect.Value) []reflect.Value { + return func(in []reflect.Value) []reflect.Value { + // 根据methodName和outs的类型,构造这样一个函数,这个函数能将in 输入的value转换为输出的value + // 这个函数具体的实现如下: + ... + // 目前拿到了 methodName、所有入参的interface和value,出参数reply + // (一)根据这些生成一个 rpcinvocation + inv = invocation_impl.NewRPCInvocationWithOptions( + invocation_impl.WithMethodName(methodName), + invocation_impl.WithArguments(inIArr), + invocation_impl.WithReply(reply.Interface()), + invocation_impl.WithCallBack(p.callBack), + invocation_impl.WithParameterValues(inVArr)) + for k, value := range p.attachments { + inv.SetAttachments(k, value) + } + // add user setAttachment + atm := invCtx.Value(constant.AttachmentKey) // 如果传入的ctx里面有attachment,也要写入inv + if m, ok := atm.(map[string]string); ok { + for k, value := range m { + inv.SetAttachments(k, value) + } + } + // 至此构造inv完毕 + // (二)触发Invoker 之前已经将cluster_invoker放入proxy,使用Invoke方法,通过getty远程过程调用 + result := p.invoke.Invoke(invCtx, inv) + // 如果有attachment,则加入 + if len(result.Attachments()) > 0 { + invCtx = context.WithValue(invCtx, constant.AttachmentKey, result.Attachments()) + } + ... + } + } + numField := valueOfElem.NumField() + for i := 0; i < numField; i++ { + t := typeOf.Field(i) + methodName := t.Tag.Get("dubbo") + if methodName == "" { + methodName = t.Name + } + f := valueOfElem.Field(i) + if f.Kind() == reflect.Func && f.IsValid() && f.CanSet() { // 针对于每个函数 + outNum := t.Type.NumOut() + // 规定函数输出只能有1/2个 + if outNum != 1 && outNum != 2 { + logger.Warnf("method %s of mtype %v has wrong number of in out parameters %d; needs exactly 1/2", + t.Name, t.Type.String(), outNum) + continue + } + // The latest return type of the method must be error. + // 规定最后一个返回值一定是error + if returnType := t.Type.Out(outNum - 1); returnType != typError { + logger.Warnf("the latest return type %s of method %q is not error", returnType, t.Name) + continue + } + // 获取到所有的出参类型,放到数组里 + var funcOuts = make([]reflect.Type, outNum) + for i := 0; i < outNum; i++ { + funcOuts[i] = t.Type.Out(i) + } + // do method proxy here: + // (三)调用make函数,传入函数名和返回值,获得能调用远程的proxy,将这个proxy替换掉原来的函数位置 + f.Set(reflect.MakeFunc(f.Type(), makeDubboCallProxy(methodName, funcOuts))) + logger.Debugf("set method [%s]", methodName) + } + } + ... +} +``` + +正如之前所说,proxy的作用是将用户定义的函数参数列表,转化为抽象的invocation传入Invoker,进行调用。 + +其中已标明有三处较为重要的地方: + +1. 在代理函数中实现由参数列表生成Invocation的逻辑 +2. 在代理函数实现调用Invoker的逻辑 +3. 将代理函数替换为原始rpc-service对应函数 + 至此,也就解决了一开始的问题: + client.go: main() + +```go + config.Load() + user := &User{} + err := userProvider.GetUser(context.TODO(), []interface{}{"A001"}, user) +``` + +这里直接调用用户定义的rpcService的函数GetUser,这里实际调用的是经过重写入的函数代理,所以就能实现远程调用了。 + +### 3. 从client到server的invoker嵌套链- 小结 + +在阅读dubbo-go源码的过程中,我能发现一条清晰的invoker-proxy嵌套链,我希望通过图的形式来展现: + +![img](/imgs/blog/dubbo-go/code2/p9.png) + +> 作者简介 李志信 (GitHubID LaurenceLiZhixin),中山大学软件工程专业在校学生,擅长使用 Java/Go 语言,专注于云原生和微服务等技术方向。 diff --git a/content/en/blog/golang/dubbo-go-config-center.md b/content/en/blog/golang/dubbo-go-config-center.md new file mode 100644 index 000000000000..47988830f32b --- /dev/null +++ b/content/en/blog/golang/dubbo-go-config-center.md @@ -0,0 +1,314 @@ +--- +title: "dubbo-go 中如何实现远程配置管理?" +linkTitle: "dubbo-go 中如何实现远程配置管理?" +tags: ["Go"] +date: 2021-01-11 +description: 本文介绍了如何在 dubbo-go 中使用配置中心进行远程配置管理 +--- + +之前在 Apache/dubbo-go(以下简称 dubbo-go )社区中,有同学希望配置文件不仅可以放于本地,还可以放于配置管理中心里。那么,放在本地和配置管理中心究竟有哪些不一样呢? + +放在本地,每次更新需要重启,配置文件管理困难,无法做到实时更新即刻生效。此外,本地文件还依赖人工版本控制,在微服务的场景下,大大的增加了运维的成本与难度。 + +而配置管理中心提供了统一的配置文件管理,支持文件更新、实时同步、统一版本控制、权限管理等功能。 + +## 目标 + +基于以上几个背景,可以总结出以下**目标** + +- 与 Dubbo 现有的配置中心内的配置文件兼容,降低新增语言栈的学习成本; +- 支持多种配置文件格式; +- 支持主流配置中心,适应不一样的使用场景,实现高扩展的配置下发; + +## 配置中心 + +配置中心在 dubbo-go 中主要承担以下场景的职责: + +1. 作为外部化配置中心,即存储 dubbo.properties 配置文件,此时,key 值通常为文件名如 dubbo.properties , value 则为配置文件内容。 +2. 存储单个配置项,如各种开关项、常量值等。 +3. 存储服务治理规则,此时 key 通常按照 “服务名 + 规则类型” 的格式来组织,而 value 则为具体的治理规则。 + +就目前而言,dubbo-go 首要支持的是 Dubbo 中支持的开源配置中心,包括: +1. Apollo:携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。 +2. ZooKeeper:一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 Hbase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。 +3. Nacos: Alibaba 开源的配置管理组件,提供了一组简单易用的特性集,帮助您实现动态服务发现、服务配置管理、服务及流量管理。 + +而考虑到某些公司内部有自身的研发的配置中心,又或者当前流行而 Dubbo 尚未支持的配置中心,如 etcd,我们的核心在于设计一套机制,允许我们,也包括用户,可以通过扩展接口新的实现,来快速接入不同的配置中心。 + +那在 dubbo-go 中究竟怎么实现呢?我们的答案是:**基于动态的插件机制在启动时按需加载配置中心的不同实现。** + +实现该部分功能放置于一个独立的子项目中,见: https://github.com/apache/dubbo-go/tree/master/config_center + +### dubbo-go 设计 + +原逻辑为:启动时读取本地配置文件,将其加载进内存,通过配置文件中的配置读取注册中心的信息获取服务提供者,注册服务消费者。 + +有些读者会有点困惑,不是说好了使用配置中心的,为什么现在又要读取本地配置呢?答案就是,读取的这部分信息分成两部分: + +- 使用什么作为配置中心; +- 该配置中心的元数据,比如说使用 zookeeper 作为配置中心,那么 zookeeper 的链接信息就是元数据,毕竟我们只有在知道了链接信息之后才能连上 zookeeper; + +在改造的时候,需要考虑以下的问题: + +**1、如何实现支持多个配置中心?如何实现按需加载?** + +通过抽象 DynamicConfiguration 让开发者可以快速支持多个配置中心。使用者导入指定的组件包后,在启动阶段将需要的组件加载进内存中,以便给程序按需调用,如下图绿色部分。 + +**2、配置中心的配置加载阶段在什么时候?** + +应在读取配置文件阶段后,读取并解析本地配置文件中配置中心信息。初始化配置中心链接,读取 /dubbo/config/dubbo/dubbo.properties 与 /dubbo/config/dubbo/应用名/dubbo.properties ,并将其加载到内存之中覆盖原有配置,监听其变更,实时更新至内存,如下图蓝色部分: +![img](/imgs/blog/dubbo-go/config-center/config-center-class.jpg) + +#### ConfigCenterFactory + +使用者加载对应配置中心模块后,在初始化阶段加入各配置中心模块往其中注册其初始化类。 + +```golang +package extension + +import ( + "github.com/apache/dubbo-go/config_center" +) + +var ( + configCenterFactories = make(map[string]func() config_center.DynamicConfigurationFactory) +) + +// SetConfigCenterFactory sets the DynamicConfigurationFactory with @name +func SetConfigCenterFactory(name string, v func() config_center.DynamicConfigurationFactory) { + configCenterFactories[name] = v +} + +// GetConfigCenterFactory finds the DynamicConfigurationFactory with @name +func GetConfigCenterFactory(name string) config_center.DynamicConfigurationFactory { + if configCenterFactories[name] == nil { + panic("config center for " + name + " is not existing, make sure you have import the package.") + } + return configCenterFactories[name]() +} +``` + +#### DynamicConfigurationFactory + +整个动态配置中心的关键点就在 DynamicConfigurationFactory 上,其中通过解析内部自定义的 URL ,获取其协议类型,反射其参数,用于创建配置中心的链接。 + +```golang +package config_center + +import ( + "github.com/apache/dubbo-go/common" +) + +// DynamicConfigurationFactory gets the DynamicConfiguration +type DynamicConfigurationFactory interface { + GetDynamicConfiguration(*common.URL) (DynamicConfiguration, error) +} +``` + +如: + +配置文件中配置: + +```yaml +config_center: + protocol: zookeeper + address: 127.0.0.1:2181 + namespace: test +``` + +dubbo-go 内部会解析为: + +``` +zookeeper://127.0.0.1:2181?namespace=test +``` + +在内部传递,用于初始化配置中心链接。 + +**PS:** 在 dubbo-go 中到处可见这种内部协议,透彻理解这个内部协议对阅读 dubbo-go 代码很有帮助。 + +#### DynamicConfiguration + +该接口规定了各个配置中心需要实现的功能: + +- 配置数据反序列化方式:目前只有 Properties 转换器,参见:DefaultConfigurationParser 。 +- 增加监听器:用于增加监听数据变化后增加特定逻辑(受限于配置中心 client 端实现)。 +- 删除监听器:删除已有监听器(受限于配置中心 client 端实现,目前所知 nacos client 没有提供该方法)。 +- 获取路由配置:获取路由表配置。 +- 获取应用级配置:获取应用层级配置,如:协议类型配置等。 + +```golang +// DynamicConfiguration for modify listener and get properties file +type DynamicConfiguration interface { + Parser() parser.ConfigurationParser + SetParser(parser.ConfigurationParser) + AddListener(string, ConfigurationListener, ...Option) + RemoveListener(string, ConfigurationListener, ...Option) + // GetProperties get properties file + GetProperties(string, ...Option) (string, error) + + // GetRule get Router rule properties file + GetRule(string, ...Option) (string, error) + + // GetInternalProperty get value by key in Default properties file(dubbo.properties) + GetInternalProperty(string, ...Option) (string, error) + + // PublishConfig will publish the config with the (key, group, value) pair + PublishConfig(string, string, string) error + + // RemoveConfig will remove the config white the (key, group) pair + RemoveConfig(string, string) error + + // GetConfigKeysByGroup will return all keys with the group + GetConfigKeysByGroup(group string) (*gxset.HashSet, error) +} +``` + +### 实现 + +![img](/imgs/blog/dubbo-go/config-center/design.png) + +优先考虑与现有 Dubbo 设计兼容,从而降低使用者的学习成本,dubbo-admin 作为服务提供者实现应用级配置管理, dubbo-go 作为消费端实现配置下发管理功能。下面以 ZooKeeper 为例,对服务提供者与服务消费者进行整体流程分析。 + +#### 如何存储配置管理 + +dubbo-admin 配置管理中增加 global 配置,ZooKeeper 中会自动生成其对应配置节点,内容均为 dubbo-admin 中设置的配置。 + +1. /dubbo/config/dubbo/dubbo.properties 对应全局配置文件。 +2. /dubbo/config/dubbo/ 应用名 /dubbo.properties 对应指定应用配置文件。 + +##### 节点路径 + +![img](/imgs/blog/dubbo-go/config-center/key-struct.png) + +上图展示了 dubbo.properties 文件在 ZooKeeper 和 Apollo 中的存储结构: + +**ZooKeeper** + +- 命名空间 namespace 都为:Dubbo +- 分组 group :全局级别为 dubbo , 所有应用共享;应用级别为应用名 demo-provider ,只对该应用生效 +- key : dubbo.properties + +**Apollo** + +- app_id : 自由指定,默认:dubbo ,最好与 zookeeper namespace 一致 +- cluster : 自由指定,最好与 zookeeper group 一致 +- 命名空间 namespace : dubbo.properties + +ZooKeeper 与 Apollo 最大的不一样就在于 dubbo.properties 所在的节点。 + +#### 实现配置管理中心支持 + +以 Apollo 为例,简单的介绍,如何实现支持一个新的配置管理中心。 + +##### 选择配置管理中心 Client / SDK + +本例中使用的 Apollo Go Client 为:https://github.com/zouyx/agollo 。 + +**PS:** 如没找到,自己实现也是可以的哦。 + +##### 节点路径 + +因为每个配置管理中心的存储结构各有特点,导致 Dubbo 在使用外部配置管理中心时,存储配置节点的结构不一样。在 dubbo-configcenter 找到希望支持的配置管理中心,而本例中 Apollo 则在 ApolloDynamicConfiguration.java 。 + +注释中表明,Apollo namespace = governance (governance .properties) 用于治理规则,namespace = dubbo (dubbo.properties) 用于配置文件。 + +##### 实现 DynamicConfiguration + +新建创建客户端方法,最好客户端保持为单例。 + +```golang +func newApolloConfiguration(url *common.URL) (*apolloConfiguration, error) { + c := &apolloConfiguration{ + url: url, + } + configAddr := c.getAddressWithProtocolPrefix(url) + configCluster := url.GetParam(constant.CONFIG_CLUSTER_KEY, "") + + appId := url.GetParam(constant.CONFIG_APP_ID_KEY, "") + namespaces := getProperties(url.GetParam(constant.CONFIG_NAMESPACE_KEY, cc.DEFAULT_GROUP)) + c.appConf = &config.AppConfig{ + AppID: appId, + Cluster: configCluster, + NamespaceName: namespaces, + IP: configAddr, + } + + agollo.InitCustomConfig(func() (*config.AppConfig, error) { + return c.appConf, nil + }) + + return c, agollo.Start() +} +``` + +以下为必须实现的方法,以下方法用于获取配置中心配置。 + +- GetInternalProperty:在配置文件(Apollo 为 namespace)中,根据 key 获取对应 value; +- GetRule:获取治理配置文件(Apollo 为 namespace); +- GetProperties:获取整个配置文件(Apollo 为 namespace); + +可选择实现的方法,如不实现,则不能动态更新 dubbo-go 中配置信息。 + +- RemoveListener +- AddListener + +而 Parser & SetParser 使用默认实现即可,默认为 Properties 转换器。 + +更多信息,参考:dubbo-go-apollo ,详情参考: https://github.com/apache/dubbo-go/tree/release-1.5/config_center/apollo + +### 使用方法 + +从上面的设计里面,也能大概猜到怎么使用了: + +![img](/imgs/blog/dubbo-go/config-center/zookeeper-usercase.png) + +很显然,使用配置中心并不复杂,只需要把对应的依赖引入进来。在包初始化的时候,会创建出来对应的配置中心的实现。比如说加载 ZooKeeper 或者 Apollo 作为配置中心: + +**ZooKeeper** + +```golang +_ "github.com/apache/dubbo-go/config_center/zookeeper" +``` + +**Apollo** + +```golang +_ "github.com/apache/dubbo-go/config_center/apollo" +``` + +当然仅仅加载还不够,比如说虽然我加载了 zookeeper,但是我还需要知道怎么连上这个配置中心,即前面提到的配置中心的元数据,这部分信息是需要在本地配置出来的。比如说: + +**ZooKeeper** + +```yaml +config_center: + protocol: "zookeeper" + address: "127.0.0.1:2181" +``` + +**Apollo** + +如果需要使用 Apollo 作为配置中心,请提前创建 namespace: dubbo.properties,用于配置管理。 + +```yaml +config_center: + protocol: "apollo" + address: "127.0.0.1:8070" + app_id: test_app + cluster: dev +``` + +## 总结 + +更加具体的实现,我就不详细论述,大家可以去看源码,欢迎大家持续关注,或者贡献代码。 + +整个配置中心的功能,麻雀虽小,但五脏俱全。目前并不算是十分完善,但是整个框架层面上来说,是走在了正确的路上。从扩展性来说,是比较便利。目前支持的配置中心还不够丰富,只有 ZooKeeper 与 Apollo ,支持的配置文件格式也只有 properties ,虽然能满足基本使用场景,距离完善还有还长远的路。 + +**未来计划:** + +- Nacos(等待发布 ) +- etcd(正在开发) +- consul(未支持) +- 丰富的文件配置格式,如:yml , xml 等 + +**本文作者:** 邹毅贤,Github ID @zouyx,开源爱好者,就职于 SheIn 供应链部门,负责供应链开放平台 diff --git a/content/en/blog/golang/dubbo-go-first-glance.md b/content/en/blog/golang/dubbo-go-first-glance.md new file mode 100644 index 000000000000..84d71b6a147d --- /dev/null +++ b/content/en/blog/golang/dubbo-go-first-glance.md @@ -0,0 +1,205 @@ +--- +title: "Dubbo Go 踩坑记" +linkTitle: "Dubbo Go 踩坑记" +tags: ["Go"] +date: 2021-01-11 +description: 本文记录了一个用户第一次接入 Dubbo Go 的体验 +--- + +## 扯淡 + +### 前尘 + +由于我的一个项目需要做公司用户鉴权,而组内其他小伙伴刚好有一个 *dubbo* 的鉴权 *rpc* ,一开始我是打算直接的读 *redis* 数据然后自己做解密。工作进行到一半,由于考虑到如果以后这个服务有任何变动,我这边要有联动行为,所以改用 *go* 来调用 *dubbo* 的 *rpc* ,于是我在 *github* 上找到了 [雨神](https://github.com/AlexStocks) 的 `https://github.com/apache/dubbo-go-samples/tree/master` (PS: 这个是 *dubbo-go* 前身)。不得不说,雨神是热心的人儿啊,当时还帮着我调试代码。最后也是接入了一个阉割版的吧,主要是当时 *hessian2* 对泛型支持的不怎么好。 + +### 现在 + +目前 [dubbo-go](https://github.com/apache/dubbo-go)隶属于 *apache* 社区,相比以前做了部分重构,并且维护也很活跃了。 + +## 接入 + +### 问题 + +目前整个项目在快速的迭代中,很多功能还没有完善,维护人员还没有时间来完善文档,所以在接入的时候要自己看源码或调试。 + +### 说明 + +目前我司在使用 *dubbo* 的过程使用的 *zookeeper* 作为注册中心,序列化是 *hessian2* ,所以我们要做如下初始化: + +```golang + import ( + _ "github.com/apache/dubbo-go/common/proxy/proxy_factory" + _ "github.com/apache/dubbo-go/registry/protocol" + + _ "github.com/apache/dubbo-go/filter/impl" + + _ "github.com/apache/dubbo-go/cluster/cluster_impl" + _ "github.com/apache/dubbo-go/cluster/loadbalance" + _ "github.com/apache/dubbo-go/registry/zookeeper" + ) +``` + +### 配置 + +由于我是接入客户端,所以我这边只配置了 *ConsumerConfig* 。 + +```yaml +dubbo: + # client + request_timeout: "3s" + # connect timeout + connect_timeout: "3s" + check: true + application: + organization: "dfire.com" + name: "soa.sso.ITokenService" + module: "dubbogo token service client" + version: "1.0.0" + owner: "congbai" + registries: + "hangzhouzk": + protocol: "zookeeper" + timeout: "3s" + address: "zk1.2dfire-daily.com:2181" + username: "" + password: "" + references: + "ITokenService": + registry: "hangzhouzk" + protocol: "dubbo" + interface: "com.dfire.soa.sso.ITokenService" + version: "1.0.0" + methods: + - name: "validate" + retries: "3" +``` + +我这里是把 *dubbo-go* 作为第三方库来用,所以我没使用官方 [dubbo-samples](https://github.com/apache/dubbo-go-samples/) 那样在 *init* 函数中读入配置。 + +配置代码如下: + +```golang + import ( + "github.com/apache/dubbo-go/config" + "github.com/apache/dubbo-go/protocol/dubbo" + ) + + type DubboCli struct { + } + + func NewCli(cconf config.ConsumerConfig) *DubboCli { + config.SetConsumerConfig(cconf) + + dubbo.SetClientConf(dubbo.GetDefaultClientConfig()) + + config.Load() + + return &DubboCli{} + } +``` + +### 接入 + +好了,配置加载完就说明我们的准备工作已经做好了,接下来就要接入 *rpc* 接口了。 + +#### 返回值 + +一般 *rpc* 调用的返回值都是自定义的,所以我们也要告诉 *dubbo-go* 长什么样子。这个结构体要跟 *java* 的类对应起来,这里我们是要实现 *hessian2* 的 *interface* : + +```golang +// POJO interface +// !!! Pls attention that Every field name should be upper case. +// Otherwise the app may panic. +type POJO interface { + JavaClassName() string // got a go struct's Java Class package name which should be a POJO class. +} +``` + +我的实现如下: + +```golang +type Result struct { + Model interface{} `json:"model,omitempty"` + Models []interface{} `json:"models,omitempty"` + ResultCode string `json:"resultCode"` + Success bool `json:"success"` + Message string `json:"message"` + TotalRecord int `json:"totalRecord"` +} + +func (r Result) JavaClassName() string { + return "com.twodfire.share.result.ResultSupport" +} +``` + +这里的 *JavaClassName* 接口的意义就如函数签名一样,返回的就是 *java* 的类名。 + +#### 接口 + +要想调用 *dubbo* 的接口就必须实现下面这个 *interface* + +```golang +// rpc service interface +type RPCService interface { + Reference() string // rpc service id or reference id +} +``` + +所以我需要构造一个 *struct* 来做这个事情,比如: + +```golang +type ITokenService struct { + Validate func(ctx context.Context, req []interface{}, resp *Result) error `dubbo:"validate"` +} + +func (i *ITokenService) Reference() string { + return "ITokenService" +} +``` + +这个结构体一般是不会有什么数据成员。 + +这里我们注意到 *Validate* 函数声明后面跟的 *dubbo tag* ,这个是为如果 *rpc* 名称的首字母是小写(比如我要调用的 *dubbo* 接口就是 *validate* )准备的 *MethodMapper* ,类似于 *json* 的映射 *tag* 功效。一开始我就是遇到这个坑,我按官方的例子实现,日志一直说找不到接口,后来我也在官方群里询问大佬才知道有这个功能。 + +#### 注册 + +好了,上面的准备全部完成后,我们要做最后一步,那就是告诉 *dubbo-go* 我们想要的是什么。代码如下: + +```golang + import ( + hessian "github.com/apache/dubbo-go-hessian2" + "github.com/apache/dubbo-go/config" + ) + + var tokenProvider = new(ITokenService) + + func init() { + config.SetConsumerService(tokenProvider) + hessian.RegisterPOJO(&Result{}) + } +``` + +#### 调用 + +接下来我们就可以完成我们的 *DubboCli* 接口了,代码如下: + +```golang +func (d *DubboCli) CheckUser(token, app string) (bool, error) { + args := []interface{}{token, app} + resp := &Result{} + + if err := tokenProvider.Validate(context.Background(), args, resp); err != nil { + return false, err + } + if resp.Success { + return resp.Success, nil + } + return resp.Success, errors.New(resp.Message) +} +``` + +好了,至此我们就完成了 *dubbo-go* 的全部接入工作。 Happy Coding... + +## 写在最后 + +其实代码格式这个问题,我在接入的时候跟官方群里的维护者大佬提过,使用 *go* 官方的代码格式工具 [goimports](https://github.com/golang/tools/tree/master/cmd/goimports) 来统一代码格式,这 样对于维护者以外的人提 *PR* 也是有利。我在接入的过程中遇到一个 *bug* ,我反馈给雨神,他就让我提了个 *PR* ,在整个过程就是这个 代码格式的问题,导致我反复的修改代码。 \ No newline at end of file diff --git a/content/en/blog/golang/dubbo-go-getty.md b/content/en/blog/golang/dubbo-go-getty.md new file mode 100644 index 000000000000..836da5b187b6 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-getty.md @@ -0,0 +1,247 @@ +--- +title: "Dubbo Go Getty 开发日志" +linkTitle: "getty 开发日志" +tags: ["Go"] +date: 2021-01-11 +description: 本文记录了于雨开发 dubbo-go 网络库 getty 的历程 +--- + +### 0 说明 + +[getty][3]是一个go语言实现的网络层引擎,可以处理TCP/UDP/websocket三种网络协议。 + +2016年6月我在上海做一个即时通讯项目时,接口层的底层网络驱动是当时的同事[sanbit](https://github.com/sanbit)写的,原始网络层实现了TCP +Server,其命名规范学习了著名的netty。当时这个引擎比较简洁,随着我对这个项目的改进这个网络层引擎也就随之进化了(添加了TCP Client、抽象出了 TCP connection 和 TCP +session),至2016年8月份(又添加了websocket)其与原始实现已经大异其趣了,征得原作者和相关领导同意后就放到了github上。 + +将近两年的时间我不间断地对其进行改进,年齿渐增但记忆速衰,觉得有必要记录下一些开发过程中遇到的问题以及解决方法,以备将来回忆之参考。 + +### 1 UDP connection + +2018年3月5日 起给 getty 添加了UDP支持。 + +#### 1.1 UDP connect + +UDP自身分为unconnected UDP和connected UDP两种,connected UDP的底层原理见下图。 + +![img](/imgs/blog/dubbo-go/connected_udp_socket.gif) + +当一端的UDP endpoint调用connect之后,os就会在内部的routing table上把udp socket和另一个endpoint的地址关联起来,在发起connect的udp +endpoint端建立起一个单向的连接四元组:发出的datagram packet只能发往这个endpoint(不管sendto的时候是否指定了地址)且只能接收这个endpoint发来的udp datagram +packet(如图???发来的包会被OS丢弃)。 + +UDP endpoint发起connect后,OS并不会进行TCP式的三次握手,操作系统共仅仅记录下UDP socket的peer udp endpoint 地址后就理解返回,仅仅会核查对端地址是否存在网络中。 + +至于另一个udp endpoint是否为connected udp则无关紧要,所以称udp connection是单向的连接。如果connect的对端不存在或者对端端口没有进程监听,则发包后对端会返回ICMP “port +unreachable” 错误。 + +如果一个POSIX系统的进程发起UDP write时没有指定peer UDP address,则会收到ENOTCONN错误,而非EDESTADDRREQ。 + +![img](/imgs/blog/dubbo-go/dns_udp.gif) + +一般发起connect的为 UDP client,典型的场景是DNS系统,DNS client根据/etc/resolv.conf里面指定的DNS server进行connect动作。 + +至于 UDP server 发起connect的情形有 TFTP,UDP client 和 UDP server 需要进行长时间的通信, client 和 server 都需要调用 connect 成为 connected UDP。 + +如果一个 connected UDP 需要更换 peer endpoint address,只需要重新 connect 即可。 + +#### 1.2 connected UDP 的性能 + +connected UDP 的优势详见参考文档1。假设有两个 datagram 需要发送,unconnected UDP 的进行 write 时发送过程如下: + +* Connect the socket +* Output the first datagram +* Unconnect the socket +* Connect the socket +* Output the second datagram +* Unconnect the socket + +每发送一个包都需要进行 connect,操作系统到 routine table cache 中判断本次目的地地址是否与上次一致,如果不一致还需要修改 routine table。 + +connected UDP 的两次发送过程如下: + +* Connect the socket +* Output first datagram +* Output second datagram + +这个 case 下,内核只在第一次设定下虚拟链接的 peer address,后面进行连续发送即可。所以 connected UDP 的发送过程减少了 1/3 的等待时间。 + +2017年5月7日 我曾用 python 程序(`https://github.com/alexStocks/python-practice/blob/master/tcp_udp_http_ws/udp/client.py`) +对二者之间的性能做过测试,如果 client 和 server 都部署在本机,测试结果显示发送 100 000 量的 UDP datagram packet 时,connected UDP 比 unconnected UDP 少用了 2 +/ 13 的时间。 + +这个测试的另一个结论是:不管是 connected UDP 还是 unconnected UDP,如果启用了 SetTimeout,则会增大发送延迟。 + +#### 1.3 Go UDP + +Go 语言 UDP 编程也对 connected UDP 和 unconnected UDP 进行了明确区分,参考文档2 详细地列明了如何使用相关 +API,根据这篇文档个人也写一个 程序(`https://github.com/alexstocks/go-practice/blob/master/udp-tcp-http/udp/connected-udp.go`) 测试这些 +API,测试结论如下: + +* connected UDP 读写方法是 Read 和 Write; +* unconnected UDP 读写方法是 ReadFromUDP 和 WriteToUDP(以及 ReadFrom 和 WriteTo); +* unconnected UDP 可以调用 Read,只是无法获取 peer addr; +* connected UDP 可以调用 ReadFromUDP(填写的地址会被忽略) +* connected UDP 不能调用 WriteToUDP,”即使是相同的目标地址也不可以”,否则会得到错误 “use of WriteTo with pre-connected connection”; +* unconnected UDP 不能调用 Write, “因为不知道目标地址”, error:”write: destination address requiredsmallnestMBP:udp smallnest”; +* connected UDP 可以调用 WriteMsgUDP,但是地址必须为 nil; +* unconnected UDP 可以调用 WriteMsgUDP,但是必须填写 peer endpoint address。 + +综上结论,读统一使用 ReadFromUDP,写则统一使用 WriteMsgUDP。 + +#### 1.4 Getty UDP + +版本 v0.8.1 Getty 中添加 connected UDP 支持时,其连接函数 dialUDP(`https://github.com/alexstocks/getty/blob/master/client.go#L141`) +这是简单调用了 net.DialUDP 函数,导致昨日(20180318 22:19 pm)测试的时候遇到一个怪现象:把 peer UDP endpoint 关闭,local udp endpoint 进行 connect 时 +net.DialUDP 函数返回成功,然后 lsof 命令查验结果时看到确实存在这个单链接: + + COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME + echo_clie 31729 alex 9u IPv4 0xa5d288135c97569d 0t0 UDP localhost:63410->localhost:10000 + +然后当 net.UDPConn 进行 read 动作的时候,会得到错误 “read: connection refused”。 + +于是模仿C语言中对 TCP client connect 成功与否判断方法,对 dialUDP(`https://github.com/alexstocks/getty/blob/master/client.go#L141`) 改进如下: + +* net.DialUDP 成功之后,判断其是否是自连接,是则退出; +* connected UDP 向对端发送一个无用的 datagram packet【”ping”字符串,对端会因其非正确 datagram 而丢弃】,失败则退出; +* connected UDP 发起读操作,如果对端返回 “read: connection refused” 则退出,否则就判断为 connect 成功。 + +### 2 Compression + +去年给 getty 添加了 TCP/Websocket compression 支持,Websocket +库使用的是 [gorilla/websocket](https://github.com/gorilla/websocket/),[Go +官网](https://godoc.org/golang.org/x/net/websocket)也推荐这个库,因为自 `This package("golang.org/x/net/websocket") currently lacks some features` +。 + +#### 2.1 TCP compression + +最近在对 Websocket compression 进行测试的时候,发现 CPU 很容易就跑到 100%,且程序启动后很快就 panic 退出了。 + +根据 panic 信息提示查到 [gorilla/websocket/conn.go:ReadMsg](https://github.com/gorilla/websocket/blob/master/conn.go#L1018) +函数调用 [gorilla/websocket/conn.go:NextReader](https://github.com/gorilla/websocket/blob/master/conn.go#L928) 后就立即 panic +退出了。panic 的 `表层原因` 到是很容易查明: + +* [gorrilla/websocket:Conn::advanceFrame](https://github.com/gorilla/websocket/blob/master/conn.go#L768) 遇到读超时错误(io + timeout); +* [gorrilla/websocket:ConnConn.readErr](https://github.com/gorilla/websocket/blob/master/conn.go#L941)记录这个error; +* [gorilla/websocket/conn.go:Conn::NextReader](https://github.com/gorilla/websocket/blob/master/conn.go#L959)开始读取之前则[检查这个错误](https://github.com/gorilla/websocket/blob/master/conn.go#L938),如以前发生过错误则不再读取 + websocket + frame,并对[gorrilla/websocket:ConnConn.readErr累积计数](https://github.com/gorilla/websocket/blob/master/conn.go#L957); +* [当gorrilla/websocket:ConnConn.readErr数值大于 1000](https://github.com/gorilla/websocket/blob/master/conn.go#L958) + 的时候,程序就会panic 退出。 + +但是为何发生读超时错误则毫无头绪。 + +2018/03/07 日测试 TCP compression 的时候发现启动 compression 后,程序 CPU 也会很快跑到 +100%,进一步追查后发现函数 getty/conn.go:gettyTCPConn::read(`https://github.com/alexstocks/getty/blob/master/conn.go#L228`) 里面的 log +有很多 “io timeout” error。当时查到这个错误很疑惑,因为我已经在 TCP read 之前进行了超时设置【SetReadDeadline】,难道启动 compression +会导致超时设置失效使得socket成了非阻塞的socket? + +于是在 getty/conn.go:gettyTCPConn::read(`https://github.com/alexstocks/getty/blob/master/conn.go#L228`) 中添加了一个逻辑:启用 TCP +compression 的时不再设置超时时间【默认情况下tcp connection是永久阻塞的】,CPU 100% 的问题很快就得到了解决。 + +至于为何 `启用 TCP compression 会导致 SetDeadline 失效使得socket成了非阻塞的socket`,囿于个人能力和精力,待将来追查出结果后再在此补充之。 + +#### 2.2 Websocket compression + +TCP compression 的问题解决后,个人猜想 Websocket compression +程序遇到的问题或许也跟 `启用 TCP compression 会导致 SetDeadline 失效使得socket成了非阻塞的socket` 有关。 + +于是借鉴 TCP 的解决方法,在 getty/conn.go:gettyWSConn::read(`https://github.com/alexstocks/getty/blob/master/conn.go#L527`) +直接把超时设置关闭,然后 CPU 100% 被解决,且程序运转正常。 + +### 3 unix socket + +本节与 getty 无关,仅仅是在使用 unix socket 过程中遇到一些 keypoint 的记录。 + +#### 3.1 reliable + +unix socket datagram 形式的包也是可靠的,每次写必然要求对应一次读,否则写方会被阻塞。如果是 stream 形式,则 buffer 没有满之前,写者是不会被阻塞的。datagram 的优势在于 api 简单。 + +> Unix sockets are reliable. If the reader doesn't read, the writer blocks. If the socket is a datagram socket, each write is paired with a read. If the socket is a stream socket, the kernel may buffer some bytes between the writer and the reader, but when the buffer is full, the writer will block. Data is never discarded, except for buffered data if the reader closes the connection before reading the buffer. ---[Do UNIX Domain Sockets Overflow?](https://unix.stackexchange.com/questions/283323/do-unix-domain-sockets-overflow) + +> On most UNIX implementations, UNIX domain datagram sockets are always reliable and don't reorder datagrams. ---[man 7 socketpair](http://www.man7.org/linux/man-pages/man7/unix.7.html) + + +#### 3.2 buffer size + +datagram 形式的 unix socket 的单个 datagram 包最大长度是 130688 B。 + +> AF_UNIX SOCK_DATAGRAM/SOCK_SEQPACKET datagrams need contiguous memory. Contiguous physical memory is hard to find, and the allocation fails. The max size actually is 130688 B. --- [the max size of AF_UNIX datagram message that can be sent in linux](https://stackoverflow.com/questions/4729315/what-is-the-max-size-of-af-unix-datagram-message-that-can-be-sent-in-linux) + + +> It looks like AF_UNIX sockets don't support scatter/gather on current Linux. it is a fixed size 130688 B. --- [Difference between UNIX domain STREAM and DATAGRAM sockets?](https://stackoverflow.com/questions/13953912/difference-between-unix-domain-stream-and-datagram-sockets) + + +### 4 Goroutine Pool + +随着 [dubbogo/getty][1] 被 [apache/dubbo-go][2] 用作底层 tcp 的 transport 引擎,处于提高系统吞吐的需要,[dubbogo/getty][1] 面临着下一步的进化要求:[**针对 +dubbo-go 和 Getty 的网络 I/O 与线程派发这一部分进行进一步优化**][4]。其中的关键就是添加 Goroutine Pool【下文简称 gr pool】,以分离网络 I/O 和 逻辑处理。 + +Gr Pool 成员有任务队列【其数目为 M】和 Gr 数组【其数目为 N】以及任务【或者称之为消息】,根据 N 的数目变化其类型分为可伸缩与固定大小,可伸缩 Gr Pool 好处是可以随着任务数目变化增减 N 以节约 CPU +和内存资源,但一般不甚常用,比人以前撸过一个后就躺在我的 [github repo][5] 里面了。 + +[dubbogo/getty][1] 只关注 N 值固定大小的 gr pool,且不考虑收到包后的处理顺序。譬如,[dubbogo/getty][1] 服务端收到了客户端发来的 A 和 B 两个网络包,不考虑处理顺序的 gr pool +模型可能造成客户端先收到 B 包的 response,后才收到 A 包的 response。 + +如果客户端的每次请求都是独立的,没有前后顺序关系,则带有 gr pool 特性的 [dubbogo/getty][1] 不考虑顺序关系是没有问题的。如果上层用户关注 A 和 B 请求处理的前后顺序,则可以把 A 和 B +两个请求合并为一个请求,或者把 gr pool 特性关闭。 + +### 4.1 固定大小 Gr Pool + +按照 M 与 N 的比例,固定大小 Gr Pool 又区分为 1:1、1:N、M:N 三类。 + +1:N 类型的 Gr Pool 最易实现,个人 2017 年在项目 [kafka-connect-elasticsearch][6] 中实现过此类型的 [Gr Pool][7]:作为消费者从 kafka 读取数据然后放入消息队列,然后各个 +worker gr 从此队列中取出任务进行消费处理。 + +向 [dubbogo/getty][1] 中添加 gr pool 时也曾实现过这个版本的 [gr pool][8]。这种模型的 gr pool 整个 pool 只创建一个 chan, 所有 gr 去读取这一个 +chan,其缺点是:队列读写模型是 一写多读,因为 go channel 的低效率【整体使用一个 mutex lock】造成竞争激烈,当然其网络包处理顺序更无从保证。 + +[dubbogo/getty][1] 初始版本的 [gr pool][9] 模型为 1:1,每个 gr 多有自己的 chan,其读写模型是一写一读,其优点是可保证网络包处理顺序性, 如读取 kafka 消息时候,按照 kafka +message 的 key 的 hash 值以取余方式【hash(message key) % N】将其投递到某个 task queue,则同一 key 的消息都可以保证处理有序。但望哥 +指出了这种模型的缺陷:每个task处理要有时间,此方案会造成某个 gr 的 chan 里面有 task 堵塞,就算其他 gr 闲着,也没办法处理之【任务处理“饥饿”】。 + +[wenwei86][12] 给出了更进一步的 1:1 模型的改进方案:每个 gr 一个 chan,如果 gr 发现自己的 chan 没有请求,就去找别的 chan,发送方也尽量发往消费快的协程。这个方案类似于 go runtime 内部的 +MPG 调度算法,但是对我个人来说算法和实现均太复杂,故而没有采用。 + +[dubbogo/getty][1] 目前采用了 M:N 模型版本的 [gr pool][11],每个 task queue 被 N/M 个 gr 消费,这种模型的优点是兼顾处理效率和锁压力平衡,可以做到总体层面的任务处理均衡。此版本下 +Task 派发采用 RoundRobin 方式。 + +## 总结 + +本文总结了 [getty][3] 近期开发过程中遇到的一些问题,囿于个人水平只能给出目前自认为最好的解决方法【如何你有更好的实现,请留言】。 + +随着 [getty][3] 若有新的 improvement 或者新 feature,我会及时补加此文。 + +此记。 + +## 参考文档 + +1. connect Function with UDP(`http://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch08lev1sec11.html`) +2. [深入Go UDP编程](http://colobu.com/2016/10/19/Go-UDP-Programming/) + + + +> 1: https://github.com/dubbogo/getty +> +> 2: https://github.com/apache/dubbo-go/ +> +> 3: https://github.com/alexstocks/getty +> +> 4: https://www.oschina.net/question/3820517_2306822 +> +> 5: https://github.com/alexstocks/goext/blob/master/sync/pool/worker_pool.go +> +> 6: https://github.com/AlexStocks/kafka-connect-elasticsearch +> +> 7: https://github.com/AlexStocks/kafka-connect-elasticsearch/blob/master/app/worker.go +> +> 8: https://github.com/dubbogo/getty/pull/6/commits/4b32c61e65858b3eea9d88d8f1c154ab730c32f1 +> +> 9: https://github.com/dubbogo/getty/pull/6/files/c4d06e2a329758a6c65c46abe464a90a3002e428#diff-9922b38d89e2ff9f820f2ce62f254162 +> +> 10: https://github.com/wongoo +> +> 11: https://github.com/dubbogo/getty/pull/6/commits/1991056b300ba9804de0554dbb49b5eb04560c4b +> +> 12: https://github.com/wenweihu86 diff --git a/content/en/blog/golang/dubbo-go-grpc.md b/content/en/blog/golang/dubbo-go-grpc.md new file mode 100644 index 000000000000..e113d3cabe82 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-grpc.md @@ -0,0 +1,131 @@ +--- +title: "无缝衔接 gRPC 与 dubbo-go" +linkTitle: "无缝衔接 gRPC 与 dubbo-go" +tags: ["Go"] +date: 2021-01-11 +description: 本文介绍了如何在 dubbo go 中如何支持 gRPC +--- + +最近我们 dubbo-go 社区里面,呼声很大的一个 feature 就是对 gRPC 的支持。在某位大佬的不懈努力之下,终于弄出来了。 + +今天我就给大家分析一下大佬是怎么连接 dubbo-go 和 gRPC 。 + +## gRPC + +先来简单介绍一下 gRPC 。它是 Google 推出来的一个 RPC 框架。gRPC是通过 IDL ( Interface Definition Language )——接口定义语言——编译成不同语言的客户端来实现的。可以说是RPC理论的一个非常非常标准的实现。 + +因而 gRPC 天然就支持多语言。这几年,它几乎成为了跨语言 RPC 框架的标准实现方式了,很多优秀的rpc框架,如 Spring Cloud 和 dubbo ,都支持 gRPC 。 + +server 端 + +在 Go 里面,server 端的用法是: + +![img](/imgs/blog/dubbo-go/grpc/p1.webp) + +它的关键部分是:s := grpc.NewServer()和pb.RegisterGreeterServer(s, &server{})两个步骤。第一个步骤很容易,唯独第二个步骤RegisterGreeterServer有点麻烦。为什么呢? + +因为pb.RegisterGreeterServer(s, &server{})这个方法是通过用户定义的protobuf编译出来的。 + +好在,这个编译出来的方法,本质上是: + +![img](/imgs/blog/dubbo-go/grpc/p2.webp) + +也就是说,如果我们在 dubbo-go 里面拿到这个 _Greeter_serviceDesc ,就可以实现这个 server 的注册。因此,可以看到,在 dubbo-go 里面,要解决的一个关键问题就是如何拿到这个 serviceDesc 。 + +## Client 端 + +Client 端的用法是: + +![img](/imgs/blog/dubbo-go/grpc/p3.webp) + +这个东西要复杂一点:1、创建连接:conn, err := grpc.Dial(address)2、创建client:c := pb.NewGreeterClient(conn)3、调用方法:r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name}) + +第一个问题其实挺好解决的,毕竟我们可以从用户的配置里面读出 address ; + +第二个问题就是最难的地方了。如同 RegisterGreeterServer 是被编译出来的那样,这个 NewGreeterClient 也是被编译出来的。 + +而第三个问题,乍一看是用反射就能解决,但是我们打开 SayHello 就能看到: + +![img](/imgs/blog/dubbo-go/grpc/p4.webp) + +结合 greetClient 的定义,很容易看到,我们的关键就在于 err := c.cc.Invoke ( ctx, "/helloworld.Greeter/SayHello", in, out, opts... )。换言之,我们只需要创建出来连接,并且拿到方法、参数就能通过类似的调用来模拟出 c.SayHello 。 + +通过对 gRPC 的简单分析,我们大概知道要怎么弄了。还剩下一个问题,就是我们的解决方案怎么和 dubbo-go 结合起来呢? + +## 设计 + +我们先来看一下 dubbo-go 的整体设计,思考一下,如果我们要做 gRPC 的适配,应该是在哪个层次上做适配。 + +![img](/imgs/blog/dubbo-go/grpc/p5.webp) + +我们根据前面介绍的 gRPC 的相关特性可以看出来,gRPC 已经解决了 codec 和 transport 两层的问题。 + +而从 cluster 往上,显然 gRPC 没有涉及。于是,从这个图里面我们就可以看出来,要做这种适配,那么 protocol 这一层是最合适的。即,我们可以如同 dubbo protocol 那般,扩展出来一个 grpc protocol 。 + +这个 gRPC protocol 大体上相当于一个适配器,将底层的 gRPC 的实现和我们自身的 dubbo-go 连接在一起。 + +![img](/imgs/blog/dubbo-go/grpc/p6.webp) + +## 实现 + +在 dubbo-go 里面,和 gRPC 相关的主要是: + +![img](/imgs/blog/dubbo-go/grpc/p7.webp) + +我们直接进去看看在 gRPC 小节里面提到的要点是如何实现的。 + +### server端 + +![img](/imgs/blog/dubbo-go/grpc/p8.webp) + +这样看起来,还是很清晰的。如同 dubbo- go 其它的 protocol 一样,先拿到 service ,而后通过 service 来拿到 serviceDesc ,完成服务的注册。 + +注意一下上图我红线标准的 ds, ok := service.(DubboGrpcService) 这一句。 + +为什么我说这个地方有点奇怪呢?是因为理论上来说,我们这里注册的这个 service 实际上就是 protobuf 编译之后生成的 gRPC 服务端的那个 service ——很显然,单纯的编译一个 protobuf 接口,它肯定不会实现 DubboGrpcService 接口: + +![img](/imgs/blog/dubbo-go/grpc/p9.webp) + +那么 ds, ok := service.(DubboGrpcService) 这一句,究竟怎么才能让它能够执行成功呢? + +我会在后面给大家揭晓这个谜底。 + +## Client端 + +dubbo-go 设计了自身的 Client ,作为对 gRPC 里面 Client 的一种模拟与封装: + +![img](/imgs/blog/dubbo-go/grpc/p10.webp) + +注意看,这个 Client 的定义与前面 greetClient 的定义及其相似。再看下面的 NewClient 方法,里面也无非就是创建了连接 conn ,而后利用 conn 里创建了一个 Client 实例。 + +注意的是,这里面维护的 invoker 实际上是一个 stub 。 + +当真正发起调用的时候: + +![img](/imgs/blog/dubbo-go/grpc/p11.webp) + +红色框框框住的就是关键步骤。利用反射从 invoker ——也就是 stub ——里面拿到调用的方法,而后通过反射调用。 + +### 代码生成 + +前面提到过 ds, ok := service.(DubboGrpcService) 这一句,面临的问题是如何让 protobuf 编译生成的代码能够实现 DubboGrpcService 接口呢? + +有些小伙伴可能也注意到,在我贴出来的一些代码里面,反射操作会根据名字来获取method实例,比如NewClient方法里面的method := reflect.ValueOf(impl).MethodByName("GetDubboStub")这一句。这一句的impl,即指服务的实现,也是 protobuf 里面编译出来的,怎么让 protobuf 编译出来的代码里面含有这个 GetDubboStub 方法呢? + +到这里,答案已经呼之欲出了:修改 protobuf 编译生成代码的逻辑! + +庆幸的是,在 protobuf 里面允许我们通过插件的形式扩展我们自己的代码生成的逻辑。 + +所以我们只需要注册一个我们自己的插件: + +![img](/imgs/blog/dubbo-go/grpc/p12.webp) + +然后这个插件会把我们所需要的代码给嵌入进去。比如说嵌入GetDubboStub方法: + +![img](/imgs/blog/dubbo-go/grpc/p13.webp) + +还有DubboGrpcService接口: + +![img](/imgs/blog/dubbo-go/grpc/p14.webp) + +这个东西,属于难者不会会者不难。就是如果你不知道可以通过plugin的形式来修改生成的代码,那就是真难;但是如果知道了,这个东西就很简单了——无非就是水磨工夫罢了。 diff --git a/content/en/blog/golang/dubbo-go-hessian2-optimization.md b/content/en/blog/golang/dubbo-go-hessian2-optimization.md new file mode 100644 index 000000000000..ad0cc14e4433 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-hessian2-optimization.md @@ -0,0 +1,245 @@ +--- +title: "记一次对 dubbo-go-hessian2 的性能优化" +linkTitle: "记一次对 dubbo-go-hessian2 的性能优化" +tags: ["Go"] +date: 2021-01-12 +description: > + 本文介绍了在 dubbo-go-hessian2 中的一次性能调优 +--- + + +> dubbo-go-hessian2 是一个用 Go 实现的 hessian 协议 v2.0 版本的序列化库。从项目名称里可以看到主要用在 dubbo-go 这个项目里。hessian 协议作为 dubbo 的默认协议,因此对性能有比较高的要求。 + +## 立项 + +譬如有网文 基于Go的马蜂窝旅游网分布式IM系统技术实践 把 dubbo-go 与其他 RPC 框架对比如下: + +1. Go STDPRC: Go 标准库的 RPC,性能最优,但是没有治理; +2. RPCX: 性能优势 2*GRPC + 服务治理; +3. GRPC: 跨语言,但性能没有 RPCX 好; +4. TarsGo: 跨语言,性能 5*GRPC,缺点是框架较大,整合起来费劲; +5. Dubbo-Go: 性能稍逊一筹,比较适合 Go 和 Java 间通信场景使用 + +有鉴于此,社区便开始组织部分人力,启动了对 dubbo-go 性能优化【同时也欢迎上文作者到钉钉群 23331795 与我们社区交流】。考察 dubbo-go 的各个组件,大家不约而同地决定首先优化比较独立的 dubbo-go-hessian2。 + +## 起步 + +在最开始的时候,并没有太想清楚需要做什么,改哪个地方,要优化到何种程度,所以最简单的办法就是看看现状。 + +首先,写了一个简单的例子,把常见的类型到一个结构体里,然后测一下耗时。 + +```go +type Mix struct { + A int + B string + CA time.Time + CB int64 + CC string + CD []float64 + D map[string]interface{} +} + +m := Mix{A: int('a'), B: `hello`} +m.CD = []float64{1, 2, 3} +// 再加一层,使得数据显得复杂一些 +m.D = map[string]interface{}{`floats`: m.CD, `A`: m.A, `m`: m} +``` + +> 看起来这个结构体跟真实环境里可能不太一样,但是用来分析瓶颈应该是足够了。 + +然后直接靠 Go Test 写个测试用例: + +```go +func BenchmarkEncode(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = encodeTarget(&m) + } +} + +func BenchmarkDecode(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = NewDecoder(bytes).Decode() + } +} +``` + +> go test -benchmem -run=^$ github.com/apache/dubbo-go-hessian2 -bench "^B" -vet=off -v + +得到下面结果: + +``` +BenchmarkEncode-8 89461 11485 ns/op 3168 B/op 122 allocs/op +BenchmarkDecode-8 64914 19595 ns/op 7448 B/op 224 allocs/op +``` + +***注:基于 MacBook Pro 2018【主频 Intel Core i7 2.6 GHz】测试。\*** + +不与同类库作横向比较,仅仅从这个测试结果里的数字上无法得出任何结论。对我们来说更重要的是:它到底慢在哪里。首先想到的手段便是:借助 pprof 生成火焰图,定位 CPU 消耗。 + +pprof 工具的用法可以参考官网文档。本文测试时直接使用了 Goland 内置 `CPU Profiler` 的测试工具:测试函数左边的 `Run xx with 'CPU Profiler'`。 + +![img](/imgs/blog/dubbo-go/hessian/p2.png) + +测试跑完后, Goland 直接显示火焰图如下: + +![img](/imgs/blog/dubbo-go/hessian/p3.png) + +从这个图里可以看到,测试代码大概占用了左边的70%,右边30%是运行时的一些消耗,运行时部分一般包括 gc、schedule 两大块,一般不能直接优化。图上左边可以清晰地看到 `encObject` 里 `RegisterPOJO` 和 `Encode` 各占了小一半。 + +完成序列化功能的 `Encode` 消耗 CPU 如此之多尚可理解,而直觉上,把类对象进行解析和注册 `RegisterPOJO` 是不应该成为消耗大户的。所以猜测这个地方要么注册有问题,要么有重复注册。 + +下一步分析,用了一个简单的办法:在这个函数里加日志。然后继续再跑一下 benchmark,可以看到性能瓶颈处:容器读写的地方。 + +既然知道这里做了许多重复的无用功,就很容易明确优化方法:加缓存。把已经解析过的结果缓存下来,下次需要的时候直接取出使用。改进后的代码简单如下: + +```go +if goName, ok := pojoRegistry.j2g[o.JavaClassName()]; ok { + return pojoRegistry.registry[goName].index +} +``` + +这里刚开始有个疑问,为什么要分两步先取 `JavaClassName` 再取 `GoName` 而不直接取后者?看起来好像是多此一举了,但其实 `JavaClassName` 是类直接定义的,而 `GoName` 却依赖一次反射。相较之下两次转换的消耗可以忽略了。改完之后再跑一下 benchmark: + +``` +BenchmarkEncode-8 197593 5601 ns/op 1771 B/op 51 allocs/op +``` + +非常惊讶地看到,吞吐量大概是原来的 200%。与上面的火焰图对比,可以粗略的计算,`RegiserPOJO` 大概占了整体的30%,改进后应该也只有原来的 `1 / 0.7 * 100% = 140%` 才对。答案也可以在火焰图里找到: + +![img](/imgs/blog/dubbo-go/hessian/p4.png) + +除了 `RegisterPOJO` 被干掉以外,与上图对比,还有哪些区别呢?可以看到,原来占用将近 20% 的 `GC` 也几乎看不到了。所以真实的 CPU 利用率也要加上这部分的增长,大约 `1 / 0.5 * 100% = 200%`。 + +> 需要提醒的是,benchmark 跑出来的结果并不算稳定,所以你自己压出来的结果跟我的可能不太一致,甚至多跑几次的结果也不完全一样。对于上面的数字你只要理解原因就好,上下浮动10%也都是正常范围。 +> +> 反过来看,这也算是 GC 优化的一个角度。碰到 GC 占用CPU过高,除了去一个个换对象池,也可以重点看看那些被频繁调用的模块。当然更科学的方法是看 `pprof heap` / `memory profiler` 。 + +针对这个结果,可以看到 `encObject` 以上都被切割成了不同的小格子,不再有像 `RegisterPOJO` 那样的大块占用,一般情况下,优化到这里就可以了。 + +看完了 `Encode` ,再来看看 `Decode` ,方法类似,直接看 Goland 生成的火焰图: + +![img](/imgs/blog/dubbo-go/hessian/p5.png) + +这个图有点迷惑性,好像也被分成差不多的小格子了。可以点开 `decObject` 这一层: + +![img](/imgs/blog/dubbo-go/hessian/p6.png) + +这个时候原来小的 `...` 会显示具体内容,需要注意的是里面有两个 `findField` ,在复杂的调用里经常会遇到这种情况:一个耗资源的函数被分到了许多函数里,导致在看火焰图时并不能直观地看到它就是瓶颈。比较常见的有序列化、日志、网络请求等每个模块都会干一点却又没有一个全局的函数只干他一件事。这个时候除了肉眼去找以外也可以借助于另外一个工具: + +![img](/imgs/blog/dubbo-go/hessian/p7.png) + +在这个 `Method List` 里可以明显看到 `findField` 已经被合并到一起了,总占用接近 CPU 的一半,看到这里你大概就知道它应该是个优化点了。 + +## 进一步 + +函数 `func findField(name string, typ reflect.Type) ([]int, error)` 的作用是在一个类型里寻找指定属性的位置(Index,反射包里用它来表示是第几个字段)。很容易想到,对于一个结构体来说,每个字段的位置从一开始就确定了,所以用缓存一样可以解决这个问题。一个简单的优化如下: + +```go +func findField(name string, typ reflect.Type) (indexes []int, err error) { + typCache, _ := findFieldCache.LoadOrStore(typ, &sync.Map{}) + indexes, _ := typCache.(*sync.Map).Load(name) + if len(indexes.([]int)) == 0 { + err = perrors.Errorf("failed to find field %s", name) + } + + return indexes.([]int), err + + // ... +} +``` + +``` +- BenchmarkDecode-8 57723 17987 ns/op 7448 B/op 224 allocs/op ++ BenchmarkDecode-8 82995 12272 ns/op 7224 B/op 126 allocs/op +``` + +可以看到,结果并不如预期的那样提升一倍效果。这个代码乍看起来,好像除了有一些啰嗦的断言,好像也没别的东西了,为什么只有60%的提升呢,我们还是借助下工具 + +![img](/imgs/blog/dubbo-go/hessian/p8.png) + +可以看到:读缓存耗费了 7% 的资源。其中,`sync.(*Map)` 不便优化,但 `newobejct` 是哪里来的呢?代码里可以看到,唯一定义新对象的地方就是函数第一行的 `&sync.Map` ,我抱着试一试的心态把 `LoadOrStore` 拆成了两步 + +```go +typCache, ok := findFieldCache.Load(typ) +if !ok { + typCache = &sync.Map{} + findFieldCache.Store(typ, typCache) +} +``` + +``` +- BenchmarkDecode-8 82995 12272 ns/op 7224 B/op 126 allocs/op ++BenchmarkDecode-8 103876 12385 ns/op 6568 B/op 112 allocs/op +``` + +看结果,着实出乎意料。想起来以前看 Java 代码时经常碰到这样的代码: + +```go +if ( logLevel >= `info` ) { + log.Info(...) +} +``` + +以前一直觉得这个 `if` 真是浪费感情,现在想来,别是一番认知了。如果能提供一个 `LoadOrStore(key, func() interface{})` 的方法, 会不会更好一些? + +到这里的话,我们做了两个比较大的优化,整体性能大约提升了一倍。如果仔细看火焰图,还会发现有很多小的优化点,但是由于没有什么特别质的飞跃,这里不再赘述。有兴趣的小伙伴可以到 PR Imp: cache in reflection 里阅读相关的讨论。 + +## 更进一步 + +优化到此,依然藏着一个更深层次的问题:找一个可靠的参考基准,以衡量目前的工作结果【毕竟没有对比就没有伤害】。一个很容易想到的比较对象是 Go 语言官方的 `json` 标准库。 + +把 dubbo-go-hessian2 与 `json` 标准库做比较如下: + +```bash +$ go test -benchmem -run=^$ github.com/apache/dubbo-go-hessian2 -bench "^B" -vet=off -v -count=5 +goos: darwin +goarch: amd64 +pkg: github.com/apache/dubbo-go-hessian2 +BenchmarkJsonEncode +BenchmarkJsonEncode-8 249114 4719 ns/op 832 B/op 15 allocs/op +BenchmarkJsonEncode-8 252224 4862 ns/op 832 B/op 15 allocs/op +BenchmarkJsonEncode-8 240582 4739 ns/op 832 B/op 15 allocs/op +BenchmarkJsonEncode-8 213283 4784 ns/op 832 B/op 15 allocs/op +BenchmarkJsonEncode-8 227101 4665 ns/op 832 B/op 15 allocs/op +BenchmarkEncode +BenchmarkEncode-8 182184 5615 ns/op 1771 B/op 51 allocs/op +BenchmarkEncode-8 183007 5565 ns/op 1771 B/op 51 allocs/op +BenchmarkEncode-8 218664 5593 ns/op 1771 B/op 51 allocs/op +BenchmarkEncode-8 214704 5886 ns/op 1770 B/op 51 allocs/op +BenchmarkEncode-8 181861 5605 ns/op 1770 B/op 51 allocs/op +BenchmarkJsonDecode +BenchmarkJsonDecode-8 123667 8412 ns/op 1776 B/op 51 allocs/op +BenchmarkJsonDecode-8 122796 8497 ns/op 1776 B/op 51 allocs/op +BenchmarkJsonDecode-8 132103 8471 ns/op 1776 B/op 51 allocs/op +BenchmarkJsonDecode-8 130687 8492 ns/op 1776 B/op 51 allocs/op +BenchmarkJsonDecode-8 127668 8476 ns/op 1776 B/op 51 allocs/op +BenchmarkDecode +BenchmarkDecode-8 107775 10092 ns/op 6424 B/op 98 allocs/op +BenchmarkDecode-8 110996 9950 ns/op 6424 B/op 98 allocs/op +BenchmarkDecode-8 111036 10760 ns/op 6424 B/op 98 allocs/op +BenchmarkDecode-8 113151 10063 ns/op 6424 B/op 98 allocs/op +BenchmarkDecode-8 109197 10002 ns/op 6424 B/op 98 allocs/op +PASS +ok github.com/apache/dubbo-go-hessian2 28.680s +``` + +虽然每次的结果不稳定,但就整体而言,目前的序列化和反序列化性能大概都是JSON标准库的85%左右。这个成绩并不能说好,但短期内能花20分的精力得到一个80分的结果,应该也是可以接受的。至于剩下的20%,就不是靠改几行代码就能搞定了。内存分配是否合理、执行流程是否有冗余,都是需要一点一滴地去改进。 + +## 总结 + +最后,我们来总结一下本文主要的优化步骤: + +- 利用火焰图 快速定位消耗 CPU 较高的模块; +- 利用缓存机制,快速消除重复的计算; +- 利用 CallTree、MethodList 等多种工具分析小段代码的精确消耗; +- 遵循二八定律,以最小的成本做出一个效果显著的收益。 + +### 欢迎加入 dubbo-go 社区 + +目前 dubbo-go 已经到了一个比较稳定成熟的状态。在接下来的版本里面,我们将集中精力在云原生上。下一个版本,我们将首先实现应用维度的服务注册,这是一个和现有注册模型完全不同的新的注册模型。也是我们朝着云原生努力的一个关键版本。 + +dubbo-go 钉钉群 **23331795** 欢迎你的加入。 + +#### 作者信息 + +张慧仁,github id: micln,任职 得到APP 后端开发。 diff --git a/content/en/blog/golang/dubbo-go-history.md b/content/en/blog/golang/dubbo-go-history.md new file mode 100644 index 000000000000..5d1f5f0c7ebf --- /dev/null +++ b/content/en/blog/golang/dubbo-go-history.md @@ -0,0 +1,139 @@ +--- +title: "Dubbo Go 的前世今生" +linkTitle: "Dubbo Go 的前世今生" +tags: ["Go", "新闻动态"] +date: 2021-01-11 +description: 本文记录了 Dubbo Go 的发展历程 +--- + +![img](/imgs/blog/dubbo-go/dubbo-go-history.png) + +dubbo-go 是目前 Dubbo 多语言生态最火热的项目。dubbo-go 最早的版本应该要追溯到 2016 年,由社区于雨同学编写 dubbo-go 的初版。当时很多东西没有现成的轮子,如 Go 语言没有像 netty 一样的基于事件的网络处理引擎、 hessian2 协议没有 Go 语言版本实现,加上当时 Dubbo 也没有开始重新维护。所以从协议库到网络引擎,再到上层 dubbo-go ,其实都是从零开始写的。 + +在 2018 年,携程开始做 Go 语言的一些中间件以搭建内部的 Go 语言生态,需要有一个 Go 的服务框架可以与携程的现有 dubbo soa 生态互通。所以由我负责重构了 dubbo-go 并开源出这个版本。当时调研了很多开源的 Go 语言服务框架,当时能够支持 hessian2 协议的并跟 Dubbo 可以打通的仅找到了当时于雨写的 dubbo-go 早期版本。由于携程对社区版本的 Dubbo 做了挺多的扩展,源于对扩展性的需求我们 Go 语言版本需要一个更易于扩展的版本,加上当时这个版本本身的功能也比较简单,所以我们找到了作者合作重构了一个更好的版本。经过了大半年时间,在上图第三阶段 19 年 6 月的时候,基本上已经把 dubbo-go 重构了一遍,总体的思路是参考的 Dubbo 整体的代码架构,用Go语言完全重写了一个完整的具备服务端跟消费端的 Golang rpc/ 微服务框架。 + +后来我们将重构后的版本 dubbo-go 1.0 贡献给 Apache 基金会,到现在已经过去了两个多月的时间,近期社区发布了1.1版本。目前为止,已经有包括携程在内的公司已经在生产环境开始了试用和推广。 + +### Start dubbo-go + +现在的 dubbo-go 已经能够跟 Java 版本做比较好的融合互通,同时 dubbo-go 自身也是一个完成的 Go 语言 rpc/ 微服务框架,它也可以脱离 java dubbo 来独立使用。 + +这边简单介绍一下用法,写一个 hello world 的例子。 + +![img](/imgs/blog/dubbo-go/java-provider.png) + +上图是一个简单的 java service ,注册为一个 Dubbo 服务,是一个简单的获取用户信息的例子。 + +![img](/imgs/blog/dubbo-go/go-consumer.png) + +上图是 dubbo-go 的客户端,来订阅和调用这个 Java 的 Dubbo 服务。Go 语言客户端需要显式调用 SetConsumerService 来注册需要订阅的服务,然后通过调用 dubbo-go-hessian2 库的 registerPOJO 方法来注册 user 对象,做 Java 和 Go 语言之间的自定义 pojo 类型转换。具体的服务调用方法就是声明一个的 GetUser 闭包,便可直接调用。 + +![img](/imgs/blog/dubbo-go/go-provider.png) + +上图,同样的可以基于 dubbo-go 发布一个 GetUser 的服务端,使用方式类似,发布完后可以被 dubbo java 的客户端调用。 + +![img](/imgs/blog/dubbo-go/java-go-interop.png) + +如上图所示,现在已经做到了这样一个程度,同样一份 dubbo-go 客户端代码,可以去调用 dubbo-go 的服务端,也可以去调用 Dubbo Java 的服务端;同样一份 dubbo-go 的服务端代码,可以被 dubbo-go 客户端和 Java 客户端调用,所以基本上使用 Dubbo 作为 PPC 框架的 Go 语言应用跟 Java 应用是没有什么阻碍的,是完全的跨语言 RPC 调用。更重要的是 dubbo-go 继承了 Dubbo 的许多优点,如易于扩展、服务治理功能强大,大家在用 Go 语言开发应用的过程中,如果也遇到类似需要与 Dubbo Java 打通的需求,或者需要找一个服务治理功能完备的 Go 微服务框架,可以看下我们 dubbo-go 项目。 + +### dubbo-go 的组成项目 + +下面介绍一下 dubbo-go 的组成项目,为了方便可以被其他项目直接复用, dubbo-go 拆分成了多个项目,并全部以 Apache 协议开源。 + +##### apache/dubbo-go + +dubbo-go 主项目, Dubbo 服务端、客户端完整 Go 语言实现。 + +##### apache/dubbo-go-hession2 + +目前应用最广泛,与 Java 版本兼容程度最高的 hessian2 协议 Go 语言实现,已经被多个 GolangRPC & Service Mesh 项目使用。 + +##### dubbo-go/getty + +dubbo-go 异步网络 I/O 库,将网络处理层解耦。 + +##### dubbo-go/gost + +基本类库,定义了 timeWheel、hashSet、taskPool 等。 + +##### dubbo-go/dubbo-go-benchmark + +用于对 dubbo-go 进行简单的压力测试,性能测试。 + +##### apache/dubbo-go-hessian2 + +![img](/imgs/blog/dubbo-go/dubbo-go-hessian2.png) + +先简单介绍一下 dubbo-go-hessian2 项目。该项目就是 hessian2 协议的 Go 语言实现,最基本的可以将 Java 的基本数据类型和复杂数据类型(如一些包装类和list接口实现类)与 golang 这边对应。 + +详情可以参考: + +*https://github.com/hessian-group/hessian-type-mapping* + +另外 Dubbo Java 服务端可以不捕获异常,将异常类通过 hession2 协议序列化通过网络传输给消费端,消费端进行反序列化对该异常对象并进行捕获。我们经过一段时间的整理,目前已经支持在 Go 消费端定义对应 Java 的超过 40 种 exception 类,来实现对 Java 异常的捕获,即使用 dubbo-go 也可以做到直接捕获 Java 服务端抛出的异常。 + +另外对于 Java 端 BigDecimal 高精度计算类的支持。涉及到一些金融相关的计算会有类似的需求,所以也对这个类进行了支持。 + +其他的,还有映射 java 端的方法别名,主要的原因是 Go 这边语言的规约,需要被序列化的方法名必须是首字母大写。而 Java 这边没有这种规范,所以我们加了一个 hessian 标签的支持,可以允许用户手动映射 Java 端的方法名称。 + +基本上现在的 dubbo-go 已经满足绝大多数与 Java 的类型互通需求,我们近期也在实现对 Java 泛型的支持。 + +##### dubbo-go/getty + +![img](/imgs/blog/dubbo-go/dubbo-go-getty.png) + +Go 语言天生就是一个异步网络 I/O 模型,在 linux 上 Go 语言写的网络服务器也是采用的 epoll 作为最底层的数据收发驱动,这跟 java 在 linux 的 nio 实现是一样的。所以 Go 语言的网络处理天生就是异步的。我们需要封装的其实是基于 Go 的异步网络读写以及之后的处理中间层。getty 将网络数据处理分为三层,入向方向分别经过对网络 i/o 封装的 streaming 层、根据不同协议对数据进行序列化反序列化的 codec 层,以及最后数据上升到需要上层消费的 handler 层。出向方向基本与入向经过的相反。每个链接的 IO 协程是成对出现的,比如读协程负责读取、 codec 逻辑然后数据到 listener 层,然后最后的事件由业务协程池来处理。 + +该项目目前是与 dubbo-go 解耦出来的,所以大家如果有类似需求可以直接拿来用,目前已经有对于 tcp/udp/websocket 的支持。 + +##### apache/dubbo-go + +![img](/imgs/blog/dubbo-go/dubbo-go-arch.png) + +dubbo-go 主项目,我们重构的这一版主要是基于 Dubbo 的分层代码设计,上图是 dubbo-go 的代码分层。基本上与 Java 版本 Dubbo 现有的分层一致,所以 dubbo-go 也继承了 Dubbo 的一些优良特性,比如整洁的代码架构、易于扩展、完善的服务治理功能。 + +我们携程这边,使用的是自己的注册中心,可以在 dubbo-go 扩展机制的基础上灵活扩展而无需去改动 dubbo-go 的源代码。 + +### dubbo-go 的功能介绍 + +##### dubbo-go 已实现功能 + +目前 dubbo-go 已经实现了 Dubbo 的常用功能(如负责均衡、集群策略、服务多版本多实现、服务多注册中心多协议发布、泛化调用、服务降级熔断等),其中服务注册发现已经支持 zookeeper/etcd/consul/nacos 主流注册中心。这里不展开详细介绍,目前 dubbo-go 支持的功能可以查看项目 readme 中的 feature list ,详情参考:*https://github.com/apache/dubbo-go#feature-list* + +目前社区正在开发中的功能,主要是早期用户使用过程中提出的一些需求,也是生产落地一些必需的需求,如监控、调用链跟踪以及服务路由、动态配置中心等更高级的服务治理需求。 + +##### dubbo-go 功能介绍之泛化调用 + +![img](/imgs/blog/dubbo-go/dubbo-go-generic-invoke.png) + +这里详细做几个重点功能的介绍。首先是泛化调用,如上图,这个也是社区同学提的需求。该同学公司内部有很多 Dubbo 服务,他们用 Go 做了一个 api gateway 网关,想要把 Dubbo 服务暴露成外网 http 接口。因为内部的 Dubbo 服务比较多,不可能每一个 Dubbo 服务都去做一个消费端接口去做适配,这样的话一旦服务端改动,客户端也要改。所以他这边的思路是做基于 dubbo-go 做泛化调用, api-gateway 解析出外网请求的地址,解析出想要调用的 Dubbo 服务的目标。基于dubbo-go consumer 泛化调用指定 service、method ,以及调用参数。 + +具体的原理是, dubbo-go 这边作为消费端,实际会通过本地 genericService.invoke 方法做代理,参数里面包含了 service name,method name ,还包含被调用目标 service 需要的参数类型、值等数据,这些数据后面会通过 dubbo-go-hession2 做转换,会将内容转化成 map 类型,经过网络发送到对应的 Java 服务端,然后 Java 那边是接收的 map 类型的参数,会自动反序列化成自己的 pojo 类型。这样就实现了 dubbo-go 作为客户端,泛化调用 Dubbo 服务端的目的。 + +##### dubbo-go 功能介绍之降级熔断 + +![img](/imgs/blog/dubbo-go/dubbo-go-curcuit-breaker.png) + +降级熔断这边是基于的是大家比较熟悉的 hystrix 的 Go 语言版本,基于 hystrix ,用户可以定义熔断规则和降级触发的代码段。降级熔断支持是作为一个独立的 dubbo-go filter ,可以灵活选择是否启用,如果不启用就可以在打包的时候不将依赖引入。Filter 层是 dubbo-go 中对于请求链路的一个责任链模式抽象,目前有许多功能都是基于动态扩展 filter 链来实现的,包括 trace、leastactive load balacne、log 等。降级熔断设计成一个服务调用端独立的filter可以灵活满足调用端视角对于微服务架构中“防雪崩“的服务治理需求。 + +##### dubbo-go 功能介绍之动态配置 + +关于动态配置中心, Dubbo 的 2.6 到 2.7 版本做了一个比较大的变化,从之前的 url 配置形式过渡到了支持配置中心 yaml 格式配置的形式,治理粒度也从单服务级别的配置支持到了应用级别的配置,不过在2.7版本中还是兼容 2.6 版本 url 形式进行服务配置的。dubbo-go 这边考虑到跟 Dubbo2.6 和 2.7 的互通性,同样支持 url 和配置文件方式的服务配置,同时兼容应用级别和服务级别的配置,跟 dubbo 保持一致,目前已经实现了zookeeper和apollo作为配置中心的支持。 + +### dubbo-go roadmap 2019-2020 + +![img](/imgs/blog/dubbo-go/dubbo-go-roadmap-2019.png) + +最后是大家比较关注的,社区关于 dubbo-go 2019 年下半年的计划,目前来看主要还是现有功能的补齐和一些问题的修复,我们的目标就是首先做到 Java 和 Go 在运行时的兼容互通和功能的一致,其次是查漏补缺 dubbo-go 作为一个完整 Go 语言微服务框架在功能上的可以改进之处。 + +另外值得关注的一点是,预计今年年底, dubbo-go 会发布一个支持 kubernetes 作为注册中心的扩展,积极拥抱云原生生态。关于云原生的支持,社区前期做了积极的工作,包括讨论关于 dubbo-go 与 Service Mesh 的关系以及在其中的定位,可以肯定的是, dubbo-go 将会配合 Dubbo 社区在 Service Mesh 方向的规划并扮演重要角色,我们初步预计会在明年给出与 Service Mesh开源社区项目集成的方案,请大家期待。 + +dubbo-go 社区目前属于快速健康成长状态,从捐赠给 Apache 后的不到3个月的时间里,吸引了大批量的活跃开发者和感兴趣的用户,欢迎各位同道在使用或者学习中遇到问题能够来社区讨论或者给予指正,也欢迎对 dubbo-go 有潜在需求或者对 dubbo-go 感兴趣的同道能加入到社区中。 + +
+ +
+ +### 关于作者 + +何鑫铭,目前就职于携程,基础中台研发部技术专家,dubbo-go 共同发起人、主要作者,Apache Dubbo committer,关注互联网中台以及中间件领域。 diff --git a/content/en/blog/golang/dubbo-go-intro.md b/content/en/blog/golang/dubbo-go-intro.md new file mode 100644 index 000000000000..075179b93d8c --- /dev/null +++ b/content/en/blog/golang/dubbo-go-intro.md @@ -0,0 +1,160 @@ +--- +title: "冲上云原生,Dubbo 发布 Go 版本" +linkTitle: "Dubbo Go 发布" +tags: ["Go"] +date: 2021-01-11 +description: 本文记录了 OSCHINA 对何鑫铭的采访,原文出处:https://www.oschina.net/question/3820517_2306822 +--- + +5 月 21 日,经过一年多的孵化,Apache Dubbo 从 Apache 软件基金会毕业,成为 Apache 顶级项目。 + +![img](/imgs/blog/dubbo-go/dubbo-tlp-twitter.jpg) + + +Dubbo 是阿里于 2011 年开源的一款高性能 RPC 框架,在 Java 生态中具有不小的影响力。当初经历过一段被外界诟病的“停止维护”灰暗时光,后来在 2017 年 Dubbo 浪子回头,官方宣布重新重点维护。 + +重新启航的 Dubbo 将首要目标定位于重新激活社区,赢回开发者的信任,并且逐渐将 Dubbo 打造成一个国际化与现代化的项目,目前距离宣布重启已经过了一年半的时间。 + +在这个过程中,Dubbo 发布了多个版本,并逐渐从一个 RPC 框架向微服务生态系统转变,18 年年初 Dubbo 入驻 Apache 软件基金会孵化器,开始以 Apache 之道发展社区。 + +一年之后,Dubbo 在 Apache 孵化器中发布了重启维护以来的首个里程碑版本 2.7.0,添加了社区呼声很高的异步化支持,以及注册中心与配置中心分离等特性。 + +这期间 Dubbo 3.0 的开发工作也被提上了日程,今年 4 月中旬,官方正式公布了 Dubbo 3.0 的进度,此版本新特性包括支持 Filter 链的异步化、响应式编程、云原生/Service Mesh 方向的探索,以及与阿里内外融合。 + +然后,Dubbo 毕业了。毕业后的 Dubbo 近期有什么消息呢?生态还在发展,Dubbo 社区在前几日公开了 [Dubbo Roadmap 2019](https://github.com/dubbo/awesome-dubbo/blob/master/slides/meetup/201905@beijing/DUBBO%20ROADMAP%202019.pdf),计划在 2020 年 2 月份发布 Dubbo 3.0 正式版,感兴趣的同学可以详细查阅。 + +![img](/imgs/blog/dubbo-go/dubbo-roadmap-2019.jpg) + +而最近官方又**宣布 Go 语言加入 Dubbo 生态**,发布了 [dubbo-go](https://github.com/dubbo/go-for-apache-dubbo) 项目。 + +![img](/imgs/blog/dubbo-go/dubbo-go-logo.jpg) + +在此之前 Dubbo 的跨语言可扩展性已经有一些实现,支持的语言包括 PHP、Node.js 与 Python,同时也基于标准 Java REST API - JAX-RS 2.0 实现了 REST 的调用支持,具体情况如下: + +* **PHP**:php-for-apache-dubbo,by 乐信,提供客户端和服务端 +* **Node.js**:dubbo2.js,by 千米网,提供客户端 +* **Node.js**:egg-dubbo-rpc,by 蚂蚁金服 egg 团队,提供客户端和服务端 +* **Python**:py-client-for-apache-dubbo,by 千米网,提供客户端 + +现在加入了 dubbo-go,Go 开发者也终于可以尝到 Dubbo 的滋味了。据悉,dubbo-go 项目将于**本周完成往 Apache 软件基金会的迁移**,作为 Apache Dubbo 顶级项目的子项目,届时 dubbo-go 项目的新地址也将变为:https://github.com/apache/dubbo-go。 + +关于项目的研发背景与具体技术细节等相关内容,我们第一时间采访了项目共同发起人,目前在携程基础中台研发部的何鑫铭。 + +*OSCHINA*:dubbo-go 是什么,定位是什么,为什么做这个项目? + +*dubbo-go 何鑫铭*: + +**dubbo-go 是 Dubbo 的完整 Go 语言实现**。 + +我们知道 Dubbo 本身基于 Java,很多公司也都以 Java 开发为主,并且使用 Dubbo 作 RPC 或微服务开发框架。 + +而最近 Go 语言生态发展比较迅速,因其语言优势,我们已经有部门开始尝试使用 Go 开发一些新的项目,就会存在亟需解决的问题: + +* 如何实现 Go 项目和 Java & Dubbo 项目的互通? +* 另外,Go 项目本身也有对 RPC 与微服务开发框架的诉求,如何解决? + +基于这两个问题,我们携程团队基于 dubbo-go 的早期项目,重构开发了更易于扩展且功能更加完善的 dubbo-go v1.0.0 版本,并贡献回了社区,它**首要目的就是解决 Go 项目与 Java & Dubbo 项目的互通问题,同时也为 Go 项目提供了一种 RPC 与微服务开发框架的选择**。 + +dubbo-go 提供客户端与服务器端,目前 dubbo-go 社区作为 Dubbo 生态最活跃的社区之一,后面的定位需要配合 Dubbo 官方的要求与社区用户的需求。 + +*OSCHINA*:我们知道 Dubbo 在 Java 生态上是有非常高的成就的,而目前 Go 生态本身也有一些知名的微服务框架,那 dubbo-go 之于 Go 生态,是否有与其它框架比拼的能力? + +*dubbo-go 何鑫铭*: + +我们最大的能力就是作为 Dubbo 的 Go 语言版本,打通了两种语言之间的 gap,**让 Dubbo 更加贴近云原生**,为开发者也提供了最大的灵活性,显著降低企业现有服务上云的成本,让企业在云原生时代多了一种选择。 + +*OSCHINA*:Go 的特性有没有在 dubbo-go 中得到相应的体现?(比如 Go 的高并发是怎么从基于 Java 的 Dubbo 中改造到 dubbo-go 中的?) + +*dubbo-go 何鑫铭*: + +我对于 Go 语言的认知是,首先学习成本比较小,相比于 Java 的学习成本,Go 语言更容易学习和上手。 + +其次 Go 在语言层面上,比如其 CSP 编程模型在高并发处理上的简单高效、轻量级协程的优势,相比较基于 JVM 的 Java 程序来说,基于 runtime 的 Go 程序瞬时启动能力等特性都吸引着很多开发者,这里就不详细阐述了。 + +最后就是作为云原生语言的优势,随着 Docker、k8s 与 Istio 等优秀项目的出现,云原生底层基本被 Go 语言统一了,相信企业在云原生模式下开发的日子已经不远了。我觉得 Go 语言的生态应该会越来越好,也会有越来越多的人使用它。 + +将基于 Java 的 Dubbo 引入到 Go 中,像前边讲的,dubbo-go 带来的优势就是可以快速融入云原生的领域。要说 Go 语言特性体现的话,可以参考一下 **dubbo-go 中异步网络 I/O 模型的设计,这部分将 Go 语言轻量级协程的优势体现了出来**。 + +这里也说一下 Go 语言不足的地方: + +* Go 相对 Java 来说还是很年轻的语言,没有模板库可用,所以社区在编写并维护Hessian 2 协议库上付出了很高的开发成本; +* 比起 Java 的 try/catch 错误处理方式,Go 的 error 处理能力偏弱; +* 总体生态还是不如 Java,如没有像 Netty 一样的强有力网络 I/O 库。 + +为什么提到这一点呢,因为 Dubbo 自身使用了 Netty 和 Hessian 2 协议官方 Java 库,而 dubbo-go 在开始做的时候这些都是没有的,这使得 **dubbo-go 一路走来非常艰辛,但是社区最终都克服了,并且额外贡献了开源的 Getty 和 Hessian2 项目**。 + +这里特别感谢 dubbo-go 社区早期的组织者于雨,项目的早期版本是 **2016 年**在其领导胡长城和同事刘畏三支持下开发的,他贡献的 Hessian2 和 Getty 项目,也为最新版本的 dubbo-go 打好了坚实的基础。 + +*OSCHINA*:前不久 Dubbo 才宣布之后会在 3.0 中强调 Service Mesh ,这就是语言无关的了,那 dubbo-go 还有必要在这时候加入生态吗? + +*dubbo-go 何鑫铭*: + +Service Mesh 确实是微服务未来发展的的一个大方向,但是现阶段在国内大公司还没有看到非常成功的案例,很多中小公司自身微服务还未拆分完毕甚至于还未开始,目前 dubbo-go 社区优先解决这种类型企业微服务技术落地环节中遇到的问题,专注于补齐相关功能、优化整体性能和解决 bug。至于未来,我相信随着 Dubbo Mesh 在 Service Mesh 领域的探索,dubbo-go 肯定会跟进并扮演重要角色。 + +*OSCHINA*:dubbo-go 与 Dubbo 的更新关系是怎么样的?是同步更新特性还是有自己的一些创新? + +*dubbo-go 何鑫铭*: + +我们现在发布的最新版本是 v1.0.0,我们在每一次 release 新的版本后,都会明确说明可以兼容的 Dubbo 版本。所以,dubbo-go 需要兼容对应 Dubbo 版本号的功能,会同步更新一些 Dubbo 特性。 + +*OSCHINA*:新发布版本带来什么值得关注的特性? + +*dubbo-go 何鑫铭*: + +当前发布的 v1.0.0 版本支持的功能如下: + +* 角色:Consumer(√)、Provider(√) +* 传输协议:HTTP(√)、TCP(√) +* 序列化协议:JsonRPC v2(√)、Hessian v2(√) +* 注册中心:ZooKeeper(√) +* 集群策略:Failover(√) +* 负载均衡:Random(√) +* 过滤器:Echo Health Check(√) +* extension 扩展机制 + +dubbo-go v1.0.0 版本,主要由我和同在携程的同事[方银城](https://github.com/fangyincheng)维护,社区成员[周子庆](https://github.com/u0x01)与[高辛格](https://github.com/gaoxinge)参与贡献,该版本沿用了 Dubbo 的代码分层解耦设计。Dubbo 2.6.x 的主要功能都会逐渐在 dubbo-go 中实现,包括 Dubbo 基于 SPI 的代码拓展机制,dubbo-go 也有对应的 extension 扩展机制与之对应。 + +我们在未来将逐渐推出目前可扩展模块的更多实现,如补齐更多的 Loadbalance 负载均衡、Cluster Strategy 集群策略实现(目前这些任务由社区伙伴主动认领,希望更多的 Go 语言爱好者朋友可以加入社区贡献);又如云原生领域非常流行的 k8s,我们也将同步 Dubbo 的 roadmap,跟进 k8s 作为注册中心的支持,目前由社区成员[张海彬](https://github.com/NameHaibinZhang)负责跟进。 + +当然广大开发者们也可以对这些模块接口进行新的实现,通过 extension 拓展,以完成自己的特殊需求而无需修改源代码。同时,我们非常欢迎开发者为社区贡献有用的拓展实现。 + +此版本解决了一大重点问题:与 **Dubbo Java 版本互通的解决方案**。我们将这部分提取出了 [Hessian2](https://github.com/dubbogo/hessian2) 项目,该项目源自社区[于雨](https://github.com/AlexStocks)的早期贡献,现在由社区成员[望哥](https://github.com/wongoo)负责维护,[周子庆](https://github.com/u0x01)与[高辛格](https://github.com/gaoxinge)参与贡献。目前该项目已经完成了对 Java 大部分类型的兼容支持。大家也可以单独将该项目集成到自己的项目中,它的开源协议是 Apache-2.0。 + +另外一个比较重要的就是 **dubbo-go 现在使用的 TCP 异步网络 I/O 库**,该库也是基于于雨早期写的 Getty 项目,目前由社区的[望哥](https://github.com/wongoo)与[方银城](https://github.com/fangyincheng)负责维护,它同样也是 Apache-2.0 的开源协议。下一版本我们**会针对 dubbo-go 和 Getty 的网络 I/O 与线程派发这一部分进行进一步优化**。 + +除此之外,我们计划下一步支持 Dubbo 的另外几大重要功能,如: + +* routing rule 路由规则(dubbo v2.6.x) +* dynamic configuration 动态配置中心(dubbo v2.* 7.x) +* metrics 指标与监控(dubbo v2.7.x) +* trace 链路监控(dubbo ecos) + +*OSCHINA*:目前项目的应用情况如何? + +*dubbo-go 何鑫铭*: + +dubbo-go 现在已经开始被一些企业尝试应用于 Go 语言应用融入企业已有 Java & Dubbo 技术栈,以及搭建全新 Go 语言分布式应用等场景。比如中通快递内部 Go 调用 Java Dubbo 服务;作为携程 Go 语言应用的服务框架以及 Go、Java 应用互通。 + +具体的应用情况可以查看: https://github.com/dubbo/go-for-apache-dubbo/issues/2 + +*OSCHINA*:接下来的演进方向是怎么样的? + +*dubbo-go 何鑫铭*: + +在 dubbo-go 迁往 Apache 软件基金会作为 Apache Dubbo 的子项目后,首先最重要的是**性能的进一步优化**,目前性能上虽然能够达到应用的生产级别要求,但我们觉得还没有发挥出 Go 语言的优势,还有比较大的优化空间。比如前边提到的 Getty,下一版本会针对 dubbo-go 应用 Getty 的网络 I/O 模型与线程派发做一些优化。 + +另外包含上面提到的我们近期需要补全一些重要功能,最大限度地在**功能完整性**上能够跟 Dubbo 兼容。关于未来 dubbo-go 的发展,也会向 Dubbo 2.7.x 版本这条线上的路线图演进。 + +*OSCHINA*:说到性能,当前性能情况具体如何? + +*dubbo-go 何鑫铭*: + +我们有做一个 [dubbo-go-benchmark](https://github.com/dubbogo/go-for-apache-dubbo-benchmark) 项目,在 CPU 型号为 Intel(R) Xeon(R) CPU E5-2609 0 @2.40GHz,CPU 核心数为 4*8 的硬件水平下,发送 1k 并返回 1k 的数据,100 并发数,100w 总请求数,qps 可以达到 1.2 万左右。 + +CPU 性能换成比较高的配置如 Intel Core i9 2.9GHz,qps 可以到达 2 万左右。 + +我们后面会对 Hessian2 库和 Getty 库进行持续性能优化,以给广大使用者节约资源。 + +#### 采访嘉宾介绍 + +**何鑫铭**,携程基础中台研发部技术专家,dubbo-go 主要作者。目前专注于 Golang & Java、中台架构、中间件与区块链等技术。 diff --git a/content/en/blog/golang/dubbo-go-k8s.md b/content/en/blog/golang/dubbo-go-k8s.md new file mode 100644 index 000000000000..82bd15484f45 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-k8s.md @@ -0,0 +1,110 @@ +--- +title: "dubbo-go 中将 Kubernets 原⽣作为注册中⼼的设计和实现" +linkTitle: "dubbo-go 中将 Kubernets 原⽣作为注册中⼼的设计和实现" +tags: ["Go"] +date: 2021-01-14 +description: > + 随着云原⽣的推⼴,越来越多的公司或组织将服务容器化,并将容器化后的服务部署在 Kubernetes 集群中。 +--- + +今天这篇⽂章将会介绍 dubbo-go 将 Kubernetes 作为注册中⼼的服务注册的初衷、设计⽅案,以及具体实现。 + +到⽬前为⽌该⽅案的实现已经被合并到 dubbo-go 的 master 分⽀。具体实现为关于 Kubernetes 的 [PullRequest](https://github.com/apache/dubbo-go/pull/400) 。 + +## Kubernetes管理资源的哲学 + +Kubernetes 作为容器集群化管理⽅案管理资源的维度可主观的分为服务进程管理和服务接⼊管理。 + +- 服务实例管理,主要体现⽅式为 Pod 设计模式加控制器模式,控制器保证具有特定标签 ( Kubernetes-Label )的 Pod 保持在恒定的数量(多删,少补)。 +- 服务管理,主要为 Kubernetes-Service ,该 Service 默认为具有特定标签( Kubernetes-Label )的 Pod 统⼀提供⼀个 VIP( Kubernetes-ClusterIP )所有需要请求该组 Pod 的请求都默认会按照 round-robin 的负载策略转发到真正提供服务的 Pod 。并且 CoreDNS 为该 Kubernetes-Service 提供集群内唯⼀的域名。 + +## Kubernetes的服务发现模型 + +为了明确 K8s 在服务接入管理提供的解决方案,我们以 kube-apiserver 提供的 API(HTTPS) 服务为例。K8s 集群为该服务分配了一个集群内有效的 ClusterIP ,并通过 CoreDNS 为其分配了唯一的域名 kubernetes 。如果集群内的 Pod 需要访问该服务时直接通过 https://kubernetes:443 即可完成。 + +![img](/imgs/blog/dubbo-go/k8s/k8s-service-discovery.png) + +具体流程如上图所示 ( 红⾊为客户端,绿⾊为 kube-apiserver ): + +1. ⾸先客户端通过 CoreDNS 解析域名为 **kubernetes** 的服务获得对应的 Cluster IP 为 10.96.0.1。 +2. 客户端向 10.96.0.1 发起 HTTP 请求。 +3. HTTP 请求 kube-proxy 所创建的 IP tables 拦截随机 DNAT 为 10.0.2.16 或者 10.0.2.15 。 +4. Client 与最终提供服务的 Pod 建⽴连接并交互。 + +由此可⻅,Kubernetes 提供的服务发现为域名解析级别。 + +## dubbo 的服务发现模型 + +同样为了明确 dubbo 服务发现的模型,以⼀个简单的 dubbo-consumer 发现并访问 Provider 的具体流程为例。 + +![img](/imgs/blog/dubbo-go/k8s/dubbo-service-discovery.png) + +具体流程如上图所示: + +1. Provider 将本进程的元数据注册到 Registry 中,包括 IP,Port,以及服务名称等。 +2. Consumer 通过 Registry 获取 Provider 的接⼊信息,直接发起请求 + +由此可⻅,dubbo 当前的服务发现模型是针对 Endpoint 级别的,并且注册的信息不只 IP 和端⼝包括其他的⼀些元数据。 + +## 无法直接使用 Kubernetes 服务发现模型的原因 + +通过上述两个⼩节,答案基本已经⽐较清晰了。总结⼀下,⽆法直接使⽤ Kubernetes 作为注册中⼼的原因主要为以下⼏点: + +1. Kubernetes-Service 标准的资源对象具有的服务描述字段 中并未提供完整的 dubbo 进程元数据字段因此,⽆法直接使⽤Kubernetes-Service 进⾏服务注册与发现。 +2. dubbo-go 的服务注册是基于每个进程的,每个 dubbo 进程均需进⾏独⽴的注册。 +3. Kubernetes-Service 默认为服务创建 VIP,提供 round-robin 的负载策略也与 dubbo-go⾃有的 Cluster 模块的负载策略形成了冲突。 + +## Dubbo-go 所采⽤的注册/发现⽅案 + +### 服务注册 + +Kubernetes 基于 Service 对象实现服务注册/发现。可是 dubbo 现有⽅案为每个 dubbo-go 进程独⽴注册,因此 dubbo-go选择将该进程具有的独有的元数据写⼊运⾏该 **dubbo-go** 进程的 **Pod** 在 **Kubernetes**中的 **Pod** 资源对象的描述信息中。每个运⾏ dubbo 进程的 Pod 将本进程的元数据写⼊ Kubernetes-Pod Annotations 字段。为了避免与其他使⽤Annotations 字段的 Operator 或者其他类型的控制器( Istio ) 的字段冲突。dubbo-go 使⽤ Key 为 **dubbo.io/annotation** value 为具体存储的 K/V 对的数组的 json 编码后的 base64 编码。 + +样例为: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + annotations: + dubbo.io/annotation: +W3siayI6Ii9kdWJibyIsInYiOiIifSx7ImsiOiIvZHViYm8vY29tLmlrdXJlbnRvLnVzZXIuVXNlcl +Byb3ZpZGVyIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb20uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlk +ZXIvY29uc3VtZXJzIiwidiI6IiJ9LHsiayI6Ii9kdWJibyIsInYiOiIifSx7ImsiOiIvZHViYm8vY2 +9tLmlrdXJlbnRvLnVzZXIuVXNlclByb3ZpZGVyIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb20uaWt1 +cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvcHJvdmlkZXJzIiwidiI6IiJ9LHsiayI6Ii9kdWJiby9jb2 +0uaWt1cmVudG8udXNlci5Vc2VyUHJvdmlkZXIvY29uc3VtZXJzL2NvbnN1bWVyJTNBJTJGJTJGMTcy +LjE3LjAuOCUyRlVzZXJQcm92aWRlciUzRmNhdGVnb3J5JTNEY29uc3VtZXJzJTI2ZHViYm8lM0RkdW +Jib2dvLWNvbnN1bWVyLTIuNi4wJTI2cHJvdG9jb2wlM0RkdWJibyIsInYiOiIifV0= +``` + +由于每个 dubbo-go 的 Pod 均只负责注册本进程的元数据,因此 Annotations 字段⻓度也不会因为运⾏ dubbo-go 进程的 Pod 数量增加⽽增加。 + +### 服务发现 + +依赖kubernetes Api-Server 提供了Watch的功能。可以观察特定namespace内各Pod对象的变化。 dubbo-go为了避免dubbo-go进程watch到与dubbo-go进程⽆关的Pod的变化,dubbo-go将watch的条件限制在当前Pod所在的namespace,以及 watch 具有 Key为**dubbo.io/label** Value为 **dubbo.io-value** 的Pod。在Watch到对应Pod的变化后实时更新本地Cache,并通过Registry提供的Subscribe通 + +知建⽴在注册中⼼之上的服务集群管理,或者其他功能。 + +### 总体设计图 + +![img](/imgs/blog/dubbo-go/k8s/design.png) + +具体流程如上图所示: + +1. 启动 dubbo-go 的 Deployment 或其他类型控制器使⽤ Kubernetes Downward-Api 将本 Pod 所在 namespace 通过环境变量的形式注⼊ dubbo-go 进程。 +2. dubbo-go 进程的 Pod 启动后通过环境变量获得当前的 namespace 以及该 Pod 名称,调⽤ Kubernetes-Apiserver PATCH 功能为本 Pod 添加 Key 为 **dubbo.io/label** Value为 **dubbo.io-value**的label。 +3. dubbo-go 进程调⽤ Kubernetes-Apiserver 将本进程的元数据通过 PATCH 接⼝写⼊当前 Pod 的 Annotations 字段。 +4. dubbo-go 进程 LIST 当前 namespace 下其他具有同样标签的 Pod,并解码对应的 Annotations 字段 获取其他 Pod 的信息。 +5. dubbo-go 进程 WATCH 当前 namespace 下其他具有同样标签的 Pod 的 Annotations 的字段变化。 + +## 总结 + +K8s 已经为其承载的服务提供了一套服务发现,服务注册,以及服务集群管理机制。而 dubbo-go 的同时也拥有自成体系的服务集群管理。这两个功能点形成了冲突,在无法调谐两者的情况, dubbo-go 团队决定保持 dubbo 自有的服务集群管理系,而选择性的放弃了 Service 功能,将元数据直接写入到 Pod 对象的 Annotations 中。 + + +当然这只是 dubbo-go 在将 K8s 作为服务注册中心的方案之一,后续社区会以更加“云原生”的形式对接 K8s ,让我们拭目以待吧。 + +dubbo-go 社区钉钉群 :23331795 ,欢迎你的加入。 + +> 作者信息: 王翔,GithubID: sxllwx,就职于成都达闼科技有限公司,golang开发工程师。 diff --git a/content/en/blog/golang/dubbo-go-metrics.md b/content/en/blog/golang/dubbo-go-metrics.md new file mode 100644 index 000000000000..c626fa8e0c2f --- /dev/null +++ b/content/en/blog/golang/dubbo-go-metrics.md @@ -0,0 +1,156 @@ +--- +title: "Dubbo Go 中 metrics 的设计" +linkTitle: "Dubbo Go 中 metrics 的设计" +tags: ["Go", "Proposals"] +date: 2021-01-11 +description: eBay 邓明:dubbo-go 中 metrics 的设计 +--- + +最近因为要在 Apache/dubbo-go(以下简称 dubbo-go )里面实现类似的这个 metrics 功能,于是花了很多时间去了解现在 Dubbo 里面的 metrics 是怎么实现的。该部分,实际上是被放在一个独立的项目里面,即 +metrics ,见 https://github.com/flycash/dubbo-go/tree/feature/MetricsFilter 下 metrics 子目录。 + +总体上来说,Dubbo 的 metrics 是一个从设计到实现都非常优秀的模块,理论上来说,大部分的 Java 项目是可以直接使用 metrics 的。但也因为兼顾性能、扩展性等各种非功能特性,所以初看代码会有种无从下手的感觉。 + +今天这篇文章将会从比较大的概念和抽象上讨论一下 dubbo-go 中的 metrics 模块的设计——实际上也就是 Dubbo 中的 metrics 的设计。因为我仅仅是将 Dubbo 里面的相关内容在 dubbo-go 中复制一份。 + +目前 dubbo-go 的 metrics 刚刚开始起步,第一个 PR 是: https://github.com/apache/dubbo-go/pull/278 + +## 总体设计 + +### Metrics + +要想理解 metrics 的设计,首先要理解,我们需要收集一些什么数据。我们可以轻易列举出来在 RPC 领域里面我们所关心的各种指标,诸如每个服务的调用次数,响应时间;如果更加细致一点,还有各种响应时间的分布,平均响应时间,999线…… + +但是上面列举的是从数据的内容上划分的。 metrics 在抽象上,则是摒弃了这种划分方式,而是结合了数据的特性和表现形式综合划分的。 + +从源码里面很容易找到这种划分的抽象。 + +![img](/imgs/blog/dubbo-go/metrics/p1.png) + +metrics 设计了 Metric 接口作为所有数据的顶级抽象: + +在 Dubbo 里面,其比较关键的子接口是: + +![img](/imgs/blog/dubbo-go/metrics/p2.webp) + +为了大家理解,这里我抄一下这些接口的用途: + +- Gauge: 一种实时数据的度量,反映的是瞬态的数据,不具有累加性,例如当前 JVM 的线程数; +- Counter: 计数器型指标,适用于记录调用总量等类型的数据; +- Histogram : 直方分布指标,例如,可以用于统计某个接口的响应时间,可以展示 50%, 70%, 90% 的请求响应时间落在哪个区间内; +- Meter: 一种用于度量一段时间内吞吐率的计量器。例如,一分钟内,五分钟内,十五分钟内的qps指标; +- Timer: Timer相当于Meter+Histogram的组合,同时统计一段代码,一个方法的qps,以及执行时间的分布情况; + +目前 dubbo-go 只实现了 FastCompass ,它也是 Metric 的子类: + +![img](/imgs/blog/dubbo-go/metrics/p3.webp) + +这个接口功能很简单,就是用于收集一段时间之内的 subCategory 执行的次数和响应时间。 subCategory 是一个比较宽泛的概念,无论是在 Dubbo 还是在 dubbo-go 里面,一个典型的 subCategory +就会是某个服务。 + +这里的设计要点在于,它是从什么角度上去做这些数据的抽象的。 + +很多人在开发这种采集数据的相关系统或者功能的时候,最容易陷入的就是从数据内容上做抽象,例如抽象一个接口,里面的方法就是获得服务的调用次数或者平均响应时间等。 + +这种抽象并非不可以,尤其是在简单系统里面,还非常好用。唯独在通用性和扩展性上要差很多。 + +### MetricManager + +在我们定义了 Metric 之后,很容易就想到,我要有一个东西来管理这些 Metric 。这就是 MetricManager ——对应到 Dubbo 里面的 IMetricManager 接口。 + +MetricManager 接口目前在 dubbo-go 里面还很简单: + +![img](/imgs/blog/dubbo-go/metrics/p4.webp) + +本质上来说,我在前面提到的那些 Metric 的子类,都可以从这个 MetricManager 里面拿到。它是对外的唯一入口。 + +因此无论是上报采集的数据,还是某些功能要用这些采集的数据,最重要的就是获得一个 MetricManager 的实例。例如我们最近正在开发的接入 Prometheus 就是拿到这个 MetriManger 实例,而后从里面拿到 +FastCompass 的实例,而后采集这些数据: + +![img](/imgs/blog/dubbo-go/metrics/p5.webp) + +### MetricRegistry + +MetricRegistry 是一个对 Metric 集合的抽象。 MetricManager 的默认实现里面,就是使用 MetricRegistry 来管理 Metric 的: + +![img](/imgs/blog/dubbo-go/metrics/p6.webp) + +所以,本质上它就是提供了一些注册 Metric 然后再从里面捞出来的方法。 + +于是,这就有一个问题了:为什么我在有了 MetricManager 之后,还有有一个MetricRegistry?似乎这两个功能有些重叠? + +答案大概是两个方面: + +1、除了管理所有的 Metric 之外,还承担着额外的功能,这些功能典型的就是 IsEnabled 。而实际上,在未来我们会赋予它管理生命周期的责任,比如说在 Dubbo 里面,该接口就还有一个 clear 方法; + +2、 metrics 里面还有一个 group 的概念,而这只能由 MetricManager 来进行管理,至少交给 MetricRegistry 是不合适的。 + +metrics 的 group 说起来也很简单。比如在 Dubbo 框架里面采集的数据,都会归属于 Dubbo 这个 group 。也就是说,如果我想将非框架层面采集的数据——比如纯粹的业务数据——分隔出来,就可以借用一个 business +group 。又或者我采集到的机器自身的数据,可以将其归类到 system 这个 group 下。 + +所以 MetricManger 和 MetricRegistry 的关系是: + +![img](/imgs/blog/dubbo-go/metrics/p7.webp) + +### Clock + +Clock 抽象是一个初看没什么用,再看会觉得其抽象的很好。Clock 里面就两个方法: + +![img](/imgs/blog/dubbo-go/metrics/p8.webp) + +一个是获得时间戳,另外一个则是获得时间周期(Tick)。比如通常采集数据可能是每一分钟采集一次,所以你得知道现在处在哪个时间周期里面。Clock 就提供了这种抽象。 + +很多人在实现自己的这种 metrics 的框架的时候,大多数都是直接使用系统的时钟,也就是系统的时间戳。于是所有的 Metic 在采集数据或者上报数据的时候,不得不自己去处理这种时钟方面的问题。 + +这样不同的 Metric 之间就很难做到时钟的同步。比如说可能在某个 Metric1 里面,采集周期是当前这一分钟,而 Metric2 是当前这一分钟的第三十秒到下一分钟的第三十秒。虽然它们都是一分钟采集一次,但是这个周期就对不上了。 + +另外一个有意思的地方在于,Clock 提供的这种抽象,允许我们不必真的按照现实时间的时间戳来处理。比如说,可以考虑按照 CPU 的运行时间来设计 Clock 的实现。 + +## 例子 + +就用这一次 PR 的内容来展示一下这个设计。 + +在 dubbo-go 里面这次实现了 metricsFilter ,它主要就是收集调用次数和响应时间,其核心是: + +![img](/imgs/blog/dubbo-go/metrics/p9.webp) + +report 其实就是把 metrics reports 给 MetricManager : + +![img](/imgs/blog/dubbo-go/metrics/p10.webp) + +所以,这里面可以看出来,如果我们要收集什么数据,也是要先获得 MetricManager 的实例。 + +FastCompass 的实现里面会将这一次调用的服务及其响应时间保存下来。而后在需要的时候再取出来。 + +所谓的需要的时候,通常就是上报给监控系统的时候。比如前面的提到的上报给 Prometheus。 + +所以这个流程可以抽象表达为: + +![img](/imgs/blog/dubbo-go/metrics/p11.webp) + +这是一个更加宽泛的抽象。也就是意味着,我们除了可以从这个 metricFilter 里面收集数据,也可以从自身的业务里面去收集数据。比如说统计某段代码的执行时间,一样可以使用 FastCompass 。 + +而除了 Prometheus ,如果用户自己的公司里面有监控框架,那么他们可以自己实现自己的上报逻辑。而上报的数据则只需要拿到 MetricManager 实例就能拿到。 + +## 总结 + +本质上来说,整个 metrics 可以看做是一个巨大无比的 provider-consumer 模型。 + +不同的数据会在不同的地方和不同时间点上被采集。有些人在读这些源码的时候会有点困惑,就是这些数据什么时间点会被采集呢? + +它们只会在两类时间点采集: + +1、实时采集。如我上面举例的 metricsFilter ,一次调用过来,它的数据就被采集了; + +2、另外一个则是如同 Prometheus 。每次 Prometheus 触发了 collect 方法,那么它就会把每种(如 Meter, Gauge )里面的数据收集过来,然后上报,可以称为是定时采集; + +Dubbo 里面采集了非常多的数据: + +![img](/imgs/blog/dubbo-go/metrics/p12.webp) + +这些具体的实现,我就不一一讨论了,大家有兴趣可以去看看源码。这些数据,也是我们 dubbo-go 后面要陆续实现的东西,欢迎大家持续关注,或者来贡献代码。 + +## 作者信息 + +邓明,毕业于南京大学,就职于 eBay Payment 部门,负责退款业务开发。 + diff --git a/content/en/blog/golang/dubbo-go-moson-optimize.md b/content/en/blog/golang/dubbo-go-moson-optimize.md new file mode 100644 index 000000000000..384fb7cf5d89 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-moson-optimize.md @@ -0,0 +1,501 @@ +--- +title: "记一次在 mosn 对 dubbo、dubbo-go-hessian2 的性能优化" +linkTitle: "记一次在 mosn 对 dubbo、dubbo-go-hessian2 的性能优化" +tags: ["Go"] +date: 2021-01-14 +description: > + 本文介绍在 mosn 对 dubbo、dubbo-go-hessian2 性能优化的全过程 +--- + + +### 背景 + +蚂蚁内部对 Service Mesh 的稳定性和性能要求是比较高的,内部 mosn 广泛用于生产环境。在云上和开源社区,RPC 领域 dubbo 和 spring cloud 同样广泛用于生产环境,我们在 mosn 基础上,支持了 dubbo 和 spring cloud 流量代理。我们发现在支持 dubbo 协议过程中,经过 Mesh 流量代理后,性能有非常大的性能损耗,在大商户落地 Mesh 中也对性能有较高要求,因此本文会重点描述在基于 Go 语言库 [dubbo-go-hessian2](https://github.com/apache/dubbo-go-hessian2) 、dubbo 协议中对 [mosn](https://github.com/mosn/mosn) 所做的性能优化。 + +### 性能优化概述 + +根据实际业务部署场景,并没有选用高性能机器,使用普通 linux 机器,配置和压测参数如下: + +- Intel(R) Xeon(R) Platinum 8163 CPU @ 2.50GHz 4 核 16G 。 +- pod 配置 `2c、1g`,JVM 参数 `-server -Xms1024m -Xmx1024m`。 +- 网络延迟 0.23 ms, 2 台 linux 机器,分别部署 server + mosn, 压测程序 [rpc-perfomance](https://github.com/zonghaishang/rpc-performance)。 + +经过 3 轮性能优化后,使用优化版本 mosn 将会获得以下性能收益(框架随机 512 和 1k 字节压测): + +- 512 字节数据:mosn + dubbo 服务调用 TPS 整体提升 55-82.8%,RT 降低 45% 左右,内存占用 40M, +- 1k 数据:mosn + dubbo 服务调用 TPS 整体提升 51.1-69.3%,RT 降低 41% 左右, 内存占用 41M。 + +### 性能优化工具 pprof + +磨刀不误砍柴工,在性能优化前首先要找到性能卡点,找到性能卡点后,另一个难点就是如何用高效代码优化替代 slow code。因为蚂蚁 Service Mesh 是基于 go 语言实现的,我们首选 go 自带的 pprof 性能工具,我们简要介绍这个工具如何使用。如果我们 go 库自带 http.Server 时并且在 main 头部导入`import _ "net/http/pprof"`,go 会帮我们挂载对应的 handler , 详细可以参考 [godoc](https://pkg.go.dev/net/http/pprof?tab=doc) 。 + +因为 mosn 默认会在`34902`端口暴露 http 服务,通过以下命令轻松获取 mosn 的性能诊断文件: + +```bash +go tool pprof -seconds 60 http://benchmark-server-ip:34902/debug/pprof/profile +# 会生成类似以下文件,该命令采样cpu 60秒 +# pprof.mosn.samples.cpu.001.pb.gz +``` + +然后继续用 pprof 打开诊断文件,方便在浏览器查看,在图 1-1 给出压测后 profiler 火焰图: + +```bash +# http=:8000代表pprof打开8000端口然后用于web浏览器分析 +# mosnd代表mosn的二进制可执行文件,用于分析代码符号 +# pprof.mosn.samples.cpu.001.pb.gz是cpu诊断文件 +go tool pprof -http=:8000 mosnd pprof.mosn.samples.cpu.001.pb.gz +``` + +![img](/imgs/blog/dubbo-go/moson-optimize/p1.png) + +图 1-1 mosn 性能压测火焰图 + +在获得诊断数据后,可以切到浏览器 Flame Graph(火焰图,go 1.11 以上版本自带),火焰图的 x 轴坐标代表 CPU 消耗情况, y 轴代码方法调用堆栈。在优化开始之前,我们借助 go 工具 pprof 可以诊断出大致的性能卡点在以下几个方面(直接压 server 端 mosn): + +- mosn 在接收 dubbo 请求,CPU 卡点在 streamConnection.Dispatch +- mosn 在转发 dubbo 请求,CPU 卡点在 downStream.Receive + +可以点击火焰图任意横条,进去查看长方块耗时和堆栈明细(请参考图 1-2 和 1-3 所示): + +![img](/imgs/blog/dubbo-go/moson-optimize/p2.png) + +图 1-2 Dispatch 火焰图明细 + +![img](/imgs/blog/dubbo-go/moson-optimize/p3.png) + +图 1-3 Receive 火焰图明细 + +### 性能优化思路 + +本文重点记录优化了哪些 case 才能提升 50% 以上的吞吐量和降低 RT,因此后面直接分析当前优化了哪些 case。在此之前,我们以 Dispatch 为例,看下它为甚么那么吃性能 。在 terminal 中通过以下命令可以查看代码行耗费 CPU 数据(代码有删减): + +```go +go tool pprof mosnd pprof.mosn.samples.cpu.001.pb.gz +(pprof) list Dispatch +Total: 1.75mins + 370ms 37.15s (flat, cum) 35.46% of Total + 10ms 10ms 123:func (conn *streamConnection) Dispatch(buffer types.IoBuffer) { + 40ms 630ms 125: log.DefaultLogger.Tracef("stream connection dispatch data string = %v", buffer.String()) + . . 126: + . . 127: // get sub protocol codec + . 250ms 128: requestList := conn.codec.SplitFrame(buffer.Bytes()) + 20ms 20ms 129: for _, request := range requestList { + 10ms 160ms 134: headers := make(map[string]string) + . . 135: // support dynamic route + 50ms 920ms 136: headers[strings.ToLower(protocol.MosnHeaderHostKey)] = conn.connection.RemoteAddr().String() + . . 149: + . . 150: // get stream id + 10ms 440ms 151: streamID := conn.codec.GetStreamID(request) + . . 156: // request route + . 50ms 157: requestRouteCodec, ok := conn.codec.(xprotocol.RequestRouting) + . . 158: if ok { + . 20.11s 159: routeHeaders := requestRouteCodec.GetMetas(request) + . . 165: } + . . 166: + . . 167: // tracing + 10ms 80ms 168: tracingCodec, ok := conn.codec.(xprotocol.Tracing) + . . 169: var span types.Span + . . 170: if ok { + 10ms 1.91s 171: serviceName := tracingCodec.GetServiceName(request) + . 2.17s 172: methodName := tracingCodec.GetMethodName(request) + . . 176: + . . 177: if trace.IsEnabled() { + . 50ms 179: tracer := trace.Tracer(protocol.Xprotocol) + . . 180: if tracer != nil { + 20ms 1.66s 181: span = tracer.Start(conn.context, headers, time.Now()) + . . 182: } + . . 183: } + . . 184: } + . . 185: + . 110ms 186: reqBuf := networkbuffer.NewIoBufferBytes(request) + . . 188: // append sub protocol header + 10ms 950ms 189: headers[types.HeaderXprotocolSubProtocol] = string(conn.subProtocol) + 10ms 4.96s 190: conn.OnReceive(ctx, streamID, protocol.CommonHeader(headers), reqBuf, span, isHearbeat) + 30ms 60ms 191: buffer.Drain(requestLen) + . . 192: } + . . 193:} +``` + +通过上面 `list Dispatch` 命令,性能卡点主要分布在 `159` 、 `171` 、`172` 、 `181` 、和 `190` 等行,主要卡点在解码 dubbo 参数、重复解参数、tracer、发序列化和 log 等。 + +#### 1. 优化 dubbo 解码 GetMetas + +我们通过解码 dubbo 的 body 可以获得以下信息,调用的目标接口( interface )和调用方法的服务分组( group )等信息,但是需要跳过所有业务方法参数,目前使用开源的 [dubbo-go-hessian2](https://github.com/apache/dubbo-go-hessian2) 库,解析 string 和 map 性能较差, 提升 hessian 库解码性能,会在本文后面讲解。 + +**优化思路:** + +在 mosn 的 ingress 端( mosn 直接转发请求给本地 java server 进程), 我们根据请求的 path 和 version 窥探用户使用的 interface 和 group , 构建正确的 dataID 可以进行无脑转发,无需解码 body,榨取性能提升。 + +我们可以在服务注册时,构建服务发布的 path 、version 和 group 到 interface 、group 映射。在 mosn 转发 dubbo 请求时可以通过读锁查 cache + 跳过解码 body,加速 mosn 性能。 + +因此我们构建以下 cache 实现(数组 + 链表数据结构), 可参见 [优化代码 diff](https://github.com/mosn/mosn/pull/1174/commits/9020ee9995cd15a7a4321a375a9506cf94dc70a8#diff-f5ff30debd68b8318c8236a0b5ccde07R6) : + +```go +// metadata.go +// DubboPubMetadata dubbo pub cache metadata +var DubboPubMetadata = &Metadata{} + +// DubboSubMetadata dubbo sub cache metadata +var DubboSubMetadata = &Metadata{} + +// Metadata cache service pub or sub metadata. +// speed up for decode or encode dubbo peformance. +// please do not use outside of the dubbo framwork. +type Metadata struct { + data map[string]*Node + mu sync.RWMutex // protect data internal +} + +// Find cached pub or sub metatada. +// caller should be check match is true +func (m *Metadata) Find(path, version string) (node *Node, matched bool) { + // we found nothing + if m.data == nil { + return nil, false + } + + m.mu.RLocker().Lock() + // for performance + // m.mu.RLocker().Unlock() should be called. + + // we check head node first + head := m.data[path] + if head == nil || head.count <= 0 { + m.mu.RLocker().Unlock() + return nil, false + } + + node = head.Next + // just only once, just return + // for dubbo framwork, that's what we're expected. + if head.count == 1 { + m.mu.RLocker().Unlock() + return node, true + } + + var count int + var found *Node + + for ; node != nil; node = node.Next { + if node.Version == version { + if found == nil { + found = node + } + count++ + } + } + + m.mu.RLocker().Unlock() + return found, count == 1 +} + +// Register pub or sub metadata +func (m *Metadata) Register(path string, node *Node) { + m.mu.Lock() + // for performance + // m.mu.Unlock() should be called. + + if m.data == nil { + m.data = make(map[string]*Node, 4) + } + + // we check head node first + head := m.data[path] + if head == nil { + head = &Node{ + count: 1, + } + // update head + m.data[path] = head + } + + insert := &Node{ + Service: node.Service, + Version: node.Version, + Group: node.Group, + } + + next := head.Next + if next == nil { + // fist insert, just insert to head + head.Next = insert + // record last element + head.last = insert + m.mu.Unlock() + return + } + + // we check already exist first + for ; next != nil; next = next.Next { + // we found it + if next.Version == node.Version && next.Group == node.Group { + // release lock and no nothing + m.mu.Unlock() + return + } + } + + head.count++ + // append node to the end of the list + head.last.Next = insert + // update last element + head.last = insert + m.mu.Unlock() +} +``` + +通过服务注册时构建好的 cache,可以在 mosn 的 stream 做解码时命中 cache , 无需解码参数获取接口和 group 信息,可参见[优化代码 diff](https://github.com/mosn/mosn/pull/1174/commits/9020ee9995cd15a7a4321a375a9506cf94dc70a8#diff-73d1153005841c788c91116915f460a5R188) : + +```go +// decoder.go +// for better performance. +// If the ingress scenario is not using group, +// we can skip parsing attachment to improve performance +if listener == IngressDubbo { + if node, matched = DubboPubMetadata.Find(path, version); matched { + meta[ServiceNameHeader] = node.Service + meta[GroupNameHeader] = node.Group + } +} else if listener == EgressDubbo { + // for better performance. + // If the egress scenario is not using group, + // we can skip parsing attachment to improve performance + if node, matched = DubboSubMetadata.Find(path, version); matched { + meta[ServiceNameHeader] = node.Service + meta[GroupNameHeader] = node.Group + } +} +``` + +在 mosn 的 egress 端( mosn 直接转发请求给本地 java client 进程), 我们采用类似的思路, 我们根据请求的 path 和 version 去窥探用户使用的 interface 和 group , 构建正确的 dataID 可以进行无脑转发,无需解码 body,榨取性能提升。 + +#### 2. 优化 dubbo 解码参数 + +在 dubbo 解码参数值的时候 ,mosn 采用的是 hessian 的正则表达式查找,非常耗费性能。我们先看下优化前后 benchmark 对比, 性能提升 50 倍。 + +```bash +go test -bench=BenchmarkCountArgCount -run=^$ -benchmem +BenchmarkCountArgCountByRegex-12 200000 6236 ns/op 1472 B/op 24 allocs/op +BenchmarkCountArgCountOptimized-12 10000000 124 ns/op 0 B/op 0 allocs/op +``` + +**优化思路:** + +可以消除正则表达式,采用简单字符串解析识别参数类型个数, [dubbo 编码参数个数字符串实现](https://github.com/zonghaishang/dubbo/blob/e0fd702825a274379fb609229bdb06ca0586122e/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java#L370) 并不复杂, 主要给对象加 L 前缀、数组加 [、primitive 类型有单字符代替。采用 go 可以实现同等解析, 可以参考[优化代码 diff](https://github.com/mosn/mosn/pull/1174/commits/9020ee9995cd15a7a4321a375a9506cf94dc70a8#diff-73d1153005841c788c91116915f460a5R245) : + +```go +func getArgumentCount(desc string) int { + len := len(desc) + if len == 0 { + return 0 + } + + var args, next = 0, false + for _, ch := range desc { + + // is array ? + if ch == '[' { + continue + } + + // is object ? + if next && ch != ';' { + continue + } + + switch ch { + case 'V', // void + 'Z', // boolean + 'B', // byte + 'C', // char + 'D', // double + 'F', // float + 'I', // int + 'J', // long + 'S': // short + args++ + default: + // we found object + if ch == 'L' { + args++ + next = true + // end of object ? + } else if ch == ';' { + next = false + } + } + + } + return args +} +``` + +#### 3. 优化 dubbo hessian go 解码 string 性能 + +在图 1-2 中可以看到 dubbo hessian go 在解码 string 占比 CPU 采样较高,我们在解码 dubbo 请求时,会解析 dubbo 框架版本、调用 path 、接口版本和方法名,这些都是 string 类型,dubbo hessian go 解析 string 会影响 RPC 性能。 + +我们首先跑一下 benchmar k 前后解码 string 性能对比,性能提升 56.11%, 对应到 RPC 中有 5% 左右提升。 + +```bash +BenchmarkDecodeStringOriginal-12 1967202 613 ns/op 272 B/op 6 allocs/op +BenchmarkDecodeStringOptimized-12 4477216 269 ns/op 224 B/op 5 allocs/op +``` + +**优化思路:** + +直接使用 UTF-8 byte 解码,性能最高,之前先解码 byte 成 rune , 对 rune 解码成 string ,及其耗费性能。增加批量 string chunk copy ,降低 read 调用,并且使用 unsafe 转换 string(避免一些校验),因为代码优化 diff 较多,这里给出[优化代码 PR](https://github.com/apache/dubbo-go-hessian2/pull/188) 。 + +go SDK 代码`runtime/string.go#slicerunetostring`( rune 转换成 string ), 同样是把 rune 转成 byte 数组,这里给了我优化思路启发。 + +#### 4. 优化 hessian 库编解码对象 + +虽然消除了 dubbo 的 body 解码部分,但是 mosn 在处理 dubbo 请求时,必须要借助 hessian 去 decode 请求头部的框架版本、请求 path 和接口版本值。但是每次在解码的时候都会创建序列化对象,开销非常高,因为 hessian 每次在创建 reader 的时候会 allocate 4k 数据并 reset。 + +```go + 10ms 10ms 75:func unSerialize(serializeId int, data []byte, parseCtl unserializeCtl) *dubboAttr { + 10ms 140ms 82: attr := &dubboAttr{} + 80ms 2.56s 83: decoder := hessian.NewDecoderWithSkip(data[:]) +ROUTINE ======================== bufio.NewReaderSize in /usr/local/go/src/bufio/bufio.go + 50ms 2.44s (flat, cum) 2.33% of Total + . 220ms 55: r := new(Reader) + 50ms 2.22s 56: r.reset(make([]byte, size), rd) + . . 57: return r + . . 58:} +``` + +我们可以写个池化内存前后性能对比, 性能提升 85.4% , [benchmark 用例](https://github.com/apache/dubbo-go-hessian2/blob/9b418c4e2700964f244e6b982855b4e89b45990d/string_test.go#L161) : + +```bash +BenchmarkNewDecoder-12 1487685 803 ns/op 4528 B/op 9 allocs/op +BenchmarkNewDecoderOptimized-12 10564024 117 ns/op 128 B/op 3 allocs/op +``` + +**优化思路:** + +在每次编解码时,池化 hessian 的 decoder 对象,新增 NewCheapDecoderWithSkip 并支持 reset 复用 decoder 。 + +```go +var decodePool = &sync.Pool{ + New: func() interface{} { + return hessian.NewCheapDecoderWithSkip([]byte{}) + }, +} + +// 在解码时按照如下方法调用 +decoder := decodePool.Get().(*hessian.Decoder) +// fill decode data +decoder.Reset(data[:]) +hessianPool.Put(decoder) +``` + +#### 5. 优化重复解码 service 和 methodName 值 + +xprotocol 在实现 xprotocol.Tracing 获取服务名称和方法时,会触发调用并解析 2 次,调用开销比较大。 + +```bash +10ms 1.91s 171: serviceName := tracingCodec.GetServiceName(request) + . 2.17s 172: methodName := tracingCodec.GetMethodName(request) +``` + +**优化思路:** + +因为在 GetMetas 里面已经解析过一次了,可以把解析过的 headers 传进去,如果 headers 有了就不用再去解析了,并且重构接口名称为一个,返回值为二元组,消除一次调用。 + +#### 6. 优化 streamID 类型转换 + +在 go 中将 byte 数组和 streamID 进行互转的时候,比较费性能。 + +**优化思路:** + +生产代码中, 尽量不要使用 fmt.Sprintf 和 fmt.Printf 去做类型转换和打印信息。可以使用 strconv 去转换。 + +```go + . 430ms 147: reqIDStr := fmt.Sprintf("%d", reqID) +60ms 4.10s 168: fmt.Printf("src=%s, len=%d, reqid:%v\n", streamID, reqIDStrLen, reqIDStr) +``` + +#### 7. 优化昂贵的系统调用 + +mosn 在解码 dubbo 的请求时,会在 header 中塞一份远程 host 的地址,并且在 for 循环中获取 remote IP,系统调用开销比较高。 + +**优化思路:** + +```go +50ms 920ms 136: headers[strings.ToLower(protocol.MosnHeaderHostKey)] = conn.connection.RemoteAddr().String() +``` + +在获取远程地址时,尽可能在 streamConnection 中 cache 远程 IP 值,不要每次都去调用 RemoteAddr。 + +#### 8. 优化 slice 和 map 触发扩容和 rehash + +在 mosn 处理 dubbo 请求时,会根据接口、版本和分组去构建 dataID ,然后匹配 cluster , 会创建默认 slice 和 map 对象,经过性能诊断,导致不断 allocate slice 和 grow map 容量比较费性能。 + +**优化思路:** + +使用 slice 和 map 时,尽可能预估容量大小,使用 make(type, capacity) 去指定初始大小。 + +#### 9. 优化 trace 日志级别输出 + +mosn 中不少代码在处理逻辑时,会打很多 trace 级别的日志,并且会传递不少参数值。 + +**优化思路:** + +调用 trace 输出前,尽量判断一下日志级别,如果有多个 trace 调用,尽可能把所有字符串写到 buf 中,然后把 buf 内容写到日志中,并且尽可能少的调用 trace 日志方法。 + +#### 10. 优化 tracer、log 和 metrics + +在大促期间,对机器的性能要求较高,经过性能诊断,tracer、mosn log 和 cloud metrics 写日志( IO 操作)非常耗费性能。 + +**优化思路:** + +通过配置中心下发配置或者增加大促开关,允许 API 调用这些 feature 的开关。 + +``` +/api/v1/downgrade/on +/api/v1/downgrade/off +``` + +#### 11. 优化 route header 解析 + +mosn 中在做路由前,需要做大量的 header 的 map 访问,比如 IDC、antvip 等逻辑判断,商业版或者开源 mosn 不需要这些逻辑,这些也会占用一些开销。 + +**优化思路:** + +如果是云上逻辑,主站的逻辑都不走。 + +#### 12. 优化 featuregate 调用 + +在 mosn 中处理请求时,为了区分主站和商业版路由逻辑,会通过 featuregate 判断逻辑走哪部分。通过 featuregate 调用开销较大,需要频繁的做类型转换和多层 map 去获取。 + +**优化思路:** + +通过一个 bool 变量记录 featuregate 对应开关,如果没有初始化过,就主动调用一下 featuregate。 + +### 未来性能优化思考 + +经过几轮性能优化 ,目前看火焰图,卡点都在 connection 的 read 和 write ,可以优化的空间比较小了。但是可能从以下场景中获得收益: + +- 减少 connection 的 read 和 write 次数 (syscall) 。 +- 优化 IO 线程模型,减少携程和上下文切换等。 + +作为结束,给出了最终优化后的火焰图 ,大部分卡点都在系统调用和网络读写, 请参考图 1-4。 + +![img](/imgs/blog/dubbo-go/moson-optimize/p4.png) + +图 1-4 优化版本 mosn + dubbo 火线图 + +### 其他 + +pprof 工具异常强大,可以诊断 CPU、memory、go 协程、tracer 和死锁等,该工具可以参考 [godoc](https://blog.golang.org/pprof),性能优化参考: + +- https://blog.golang.org/pprof +- https://www.cnblogs.com/Dr-wei/p/11742414.html + + +{{< youtube id="N3PWzBeLX2M" title="Profiling and Optimizing Go" >}} + +## 欢迎加入 dubbo-go 社区 + +Dubbo-go 的社区钉钉群: 23331795,欢迎感兴趣的小伙伴们加入! + +> 关于作者 诣极,github ID zonghaishang,Apache Dubbo PMC,目前就职于蚂蚁金服中间件团队,主攻 RPC 和 Service Mesh 方向。《深入理解 Apache Dubbo 与实战》一书作者。 diff --git a/content/en/blog/golang/dubbo-go-nacos.md b/content/en/blog/golang/dubbo-go-nacos.md new file mode 100644 index 000000000000..3a95c5f1ad25 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-nacos.md @@ -0,0 +1,117 @@ +--- +title: "解构 Dubbo-go 的核心注册引擎 Nacos" +linkTitle: "解构 Dubbo-go 的核心注册引擎 Nacos" +tags: ["Go"] +date: 2021-01-14 +description: > + dubbo-go 选择 Nacos 作为注册中心的原因 +--- + +近几年,随着Go语言社区逐渐发展和壮大,越来越多的公司开始尝试采用Go搭建微服务体系,也涌现了一批Go的微服务框架,如go-micro、go-kit、Dubbo-go等,跟微服务治理相关的组件也逐渐开始在Go生态发力,如Sentinel、Hystrix等都推出了Go语言版本,而作为微服务框架的核心引擎--注册中心,也是必不可缺少的组件,市面已经有多款注册中心支持Go语言,应该如何选择呢?我们可以对目前主流的支持Go语言的注册中心做个对比。 + +![img](/imgs/blog/dubbo-go/nacos/p1.png) + +根据上表的对比我们可以从以下几个维度得出结论: + +- 生态:各注册中心对Go语言都有支持,但是Nacos、 Consul、Etcd 社区活跃,zookeeper和Eureka社区活跃度较低; +- 易用性:Nacos、Eureka、Consul都有现成的管控平台,Etcd、zookeeper本身作为kv存储,没有相应的管控平台,Nacos支持中文界面,比较符合国人使用习惯; +- 场景支持:CP模型主要针对强一致场景,如金融类,AP模型适用于高可用场景,Nacos可以同时满足两种场景,Eureka主要满足高可用场景,Consul、Zookeepr、Etcd主要满足强一致场景,此外Nacos支持从其它注册中心同步数据,方便用户注册中心迁移; +- 功能完整性:所有注册中心都支持健康检查,Nacos、Consul支持的检查方式较多,满足不同应用场景,Zookeeper通过keep alive方式,能实时感知实例变化;Nacos、Consul和Eureka都支持负载均衡策略,Nacos通过Metadata selector支持更灵活的策略;此外,Nacos、Eureka都支持雪崩保护,避免因为过多的实例不健康对健康的实例造成雪崩效应。 + +综合上面各维度的对比,可以了解到Nacos作为注册中心有一定的优势,那么它对Go微服务生态的集成做得如何?接下来我们首先探索下Nacos是如何与Dubbo-go集成。 + +## 引言 + +Dubbo-go目前是Dubbo多语言生态中最火热的一个项目,从2016年发布至今,已经走过5个年头。最近,Dubbo-go发布了v1.5版本,全面兼容Dubbo 2.7.x版本,支持了应用维度的服务注册与发现,和主流的注册模型保持一致,标志着Dubbo-go向云原生迈出了关键的一步。作为驱动服务运转的核心引擎--注册中心,在切换到应用维度的注册模型后,也需要做相应的适配,本文将解析如何以Nacos为核心引擎实现应用维度的服务注册与发现,并且给出相应的实践案例。此外,本文代码基于Dubbo-go v1.5.1,Nacos-SDK-go v1.0.0和Nacos v1.3.2。 + +## 服务注册与发现架构 + +从架构中,我们可以看到,与接口级别的服务注册发现不同的是,Dubbo-go的provider启动后会调用Nacos-go-sdk的RegisterInstance接口向Nacos注册服务实例,注册的服务名即为应用名称,而不是接口名称。Conusmer启动后则会调用Subscribe接口订阅该应用的服务实例变化,并对的实例发起服务调用。 + +![img](/imgs/blog/dubbo-go/nacos/p2.png) + +## 服务模型 + +图3是我们Dubbo-go的应用维度服务发现模型,主要有服务和实例两个层级关系,服务实例的属性主要包含实例Id、主机地址、服务端口、激活状态和元数据。图4为Nacos的服务分级存储模型,包含服务、集群和实例三个层次。两者对比,多了一个集群维度的层级,而且实例属性信息能够完全匹配。所以在Dubbo-go将应用服务实例注册到Nacos时,我们只需要将集群设置为默认集群,再填充服务和实例的相关属性,即可完成服务模型上的匹配。此外Nacos可以将服务注册到不同的Namespace下,实现多租户的隔离。 + +![img](/imgs/blog/dubbo-go/nacos/p3.png) + +! +![img](/imgs/blog/dubbo-go/nacos/p4.png) + +## 服务实例心跳维持 + +Dubbo-go的Provider在向Nacos注册应用服务实例信息后,需要主动上报心跳,让Nacos服务端感知实例的存活与否,以判断是否将该节点从实例列表中移除。维护心跳的工作是在Nacos-SDK-go完成的,从图5代码中可以看到,当Dubbo-go调用RegisterInstance注册一个服务实例时,SDK除了调用Nacos的Register API之外,还会调用AddBeatInfo,将服务实例信息添加到本地缓存,通过后台协程定期向Nacos发送服务实例信息,保持心跳。当服务下线时,可以通过调用DeRegisterInstance执行反注册,并移除本地的心跳保持任务,Nacos实例列表中也会将该实例移除。 + +![img](/imgs/blog/dubbo-go/nacos/p5.png) + +# 订阅服务实例变化 + +Dubbo-go的Consumer在启动的时候会调用Nacos-SDK-go的Subscribe接口,该接口入参如图6,订阅的时候只需要传递ServiceName即应用名和回调函数SubscribeCallback,Nacos在服务实例发生变化的时候即可通过回调函数通知Dubbo-go。Nacos-SDK-go是如何感知Nacos的服务实例变化的呢?主要有两种方式: + +- Nacos服务端主动推送,Nacos-SDK-go在启动的时候会监听一个UDP端口,该端口在调用Nacos Register API的时候作为参数传递,Nacos会记录Ip和端口,当服务实例发生变化时,Nacos会对所有监听该服务的Ip和端口发送UDP请求,推送变化后的服务实例信息。 + +- Nacos-SDK-go定期查询,SDK会对订阅的服务实例定时调用查询接口,如果查询有变化则通过回调接口通知Dubbo-go。作为兜底策略保证Nacos服务端推送失败后,仍能感知到变化。 + +![img](/imgs/blog/dubbo-go/nacos/p6.png) + +此外Nacos-SDK-go还支持推空保护,当Nacos推送的实例列表为空时,不更新本地缓存,也不通知Dubbo-go变更,避免Consumer无可用实例调用,造成故障。同时,SDK还支持服务实例信息本地持久化存储,可以保证在Nacos服务故障过程中,Consumer重启也能获取到可用实例,具备容灾效果。 + +# 范例实践 + +## 环境准备 + +dubbo-go samples代码下载:https://github.com/apache/dubbo-go-samples/tree/master,基于Nacos注册中心的应用级服务发现的hello world代码目录在 registry/servicediscovery/nacos。 + +![img](/imgs/blog/dubbo-go/nacos/p7.png) + +Nacos服务端搭建,参考官方文档:https://nacos.io/zh-cn/docs/quick-start.html,或者使用官方提供的公共Nacos服务:http://console.nacos.io/nacos(账号密码:nacos,仅供测试),或者购买阿里云服务:https://help.aliyun.com/document_detail/139460.html?spm=a2c4g.11186623.6.559.d7e264b7bLpZIs + +## Server端搭建 + +进入registry/servicediscovery/nacos/go-server/profiles文件,可以看到有dev、release和test三个文件夹,分别对应开发、测试和生产配置。我们使用dev配置来搭建开发环境,dev文件下有log.yml和server.yml文件,下面对server.yml配置进行修改。 + +remote配置,这里使用公共的Nacos服务,address支持配置多个地址,用逗号分割。params参数配置nacos-sdk的日志目录。 + +```Yaml +remote: + nacos: + address: "console.nacos.io:80" + timeout: "5s" + params: + logDir: "/data/nacos-sdk/log" +configCenter配置 +config_center: + protocol: "nacos" + address: "console.nacos.io:80" +``` + +配置server端环境变量 + +```Bash +export CONF_PROVIDER_FILE_PATH=server端的server.yml文件路径 +export APP_LOG_CONF_FILE=server端的log.yml文件路径 +``` + +进入registry/servicediscovery/nacos/go-server/app,运行server.go的main方法,可以从Nacos的控制台(http://console.nacos.io/nacos/#/serviceManagement?dataId=&group=&appName=&namespace=) + +看到,应用user-info-server已经注册成功。 + +![img](/imgs/blog/dubbo-go/nacos/p8.png) + +## Client端搭建 + +client的配置文件在registry/servicediscovery/nacos/go-server/profiles目录下,需要修改的地方跟server端一样,这里不赘述。 + +配置client端环境变量 + +```Bash +export CONF_CONSUMER_FILE_PATH=client端的server.yml文件路径 +export APP_LOG_CONF_FILE=client端的log.yml文件路径 +``` + +进入registry/servicediscovery/nacos/go-client/app,运行client.go的main方法,看到如下日志输出,表示调用server端成功。 + +![img](/imgs/blog/dubbo-go/nacos/p9.png) + +> 作者:李志鹏 Github账号:Lzp0412,Nacos-SDK-go作者,Apache/Dubbo-go Contributor。现就职于阿里云云原生应用平台,主要参与服务发现、CoreDNS、ServiceMesh相关工作,负责推动Nacos Go微服务生态建设。 diff --git a/content/en/blog/golang/dubbo-go-oneyear.md b/content/en/blog/golang/dubbo-go-oneyear.md new file mode 100644 index 000000000000..97612573bc45 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-oneyear.md @@ -0,0 +1,204 @@ +--- +title: "Go 版本入 Dubbo 生态一周年" +linkTitle: "Go 版本入 Dubbo 生态一周年" +tags: ["Go", "新闻动态"] +date: 2021-01-14 +description: > + Go 版本入 Dubbo 生态一周年:已和 Spring Cloud、gRPC 互通 +--- + +去年 5 月,阿里开源的高性能 RPC 框架 Dubbo 从 ASF 毕业并晋升顶级项目,同时,还宣布 Go 语言版本的 Dubbo-go 正式加入 Dubbo 官方生态。 + +经过一年的发展, Dubbo-go 在技术和社区运营方面都已经有了不错的成绩。Dubbo-go 是 Dubbo 的完整 Go 语言实现,在功能实现和技术路径上与 Dubbo 有不同程度的对标,项目团队预计很快便可以追平 Java 版的功能。当然,也是因为基于 Go 语言开发,Dubbo-go 更易上手,未来或将反哺 Dubbo 的云原生化。 + +Dubbo-go 近期还实现了 REST 协议以及 gRPC 的支持,打通了 Spring Cloud 和 gRPC 生态,再加上与 Java Dubbo 的互通,应用场景广泛。因此,它被其开发者叫做“all-in-one”的 RPC 框架。 + +目前 Dubbo 官方已经投入人力参与 Dubbo-go 的开发,阿里集团今年完成 HSF 和 Dubbo 的融合后,会在集团内逐步推广使用 Dubbo-go。 + +开源中国采访了当前正在开发中的 v1.5 版本的主要推进者邓明,回顾 Dubbo-go 的过往,尤其是最近一年的发展情况,并展望项目未来的发展。 + +## Dubbo-go 过去发展回顾 + +**OSCHINA:** 作为项目主要推动者之一,可以简单回顾下 Dubbo-go 的发展历程吗? + +**Dubbo-go 邓明:** + +首先,个人代表社区,借助贵方平台,感谢 Dubbo-go 的使用者、曾经合作过的各个媒体平台以及 Dubbo 官方过去一年来对我们项目的关注,Dubbo-go 目前的发展离不开各方力量的帮助。 + +实际上,在 Dubbo-go 加入 Dubbo 官方生态之前,已经发展了两年。它最早由其创始人于雨在 2016 年 5 月构建,同年 9 月发布并开源的。如下时间轴图清晰记录了 Dubbo-go 的前世今生。 + +![img](/imgs/blog/dubbo-go/1year/dubbo-go-events.png) + +**OSCHINA:** 在去年项目刚加入 Dubbo 官方生态的时候,有开发团队成员说,Dubbo-go 当时还没能发挥出 Go 语言的优势,功能完整性还要完善。作为一个为解决 Go 项目与 Java & Dubbo 项目互通的项目,经过一年的发展,项目现在能发挥出 Go 语言的优势了吗,为什么? + +**Dubbo-go 邓明:** + +和去年比起来,在发挥 Go 语言自身优势上,有了很大的提高。 + +Go 语言协程的个数上限比 Java 线程数目多。Go 语言的协程只运行在用户态,初始堆栈小且可伸缩,而 Java 线程启动因用户态系统态之间切换带来的额外成本被线程池抹平,所以只有在较大并发需求的场景下(核数限制的情况下,Java 线程池中最大线程数被限制),才会发挥优势。Dubbo 中类似的场景:异步处理网络和协议化的处理。我们在网络库 Getty 中加入了协程池,实现了网络收发和逻辑处理的解耦。 + +另外,Go 语言上手速度确实比 Java 快好几个数量级,只要搭好具有良好扩展性的架子,社区 contributor 培养的成本比 Java 低很多。得益于此,Dubbo-go 的功能和性能将很快追平 Java。 + +****OSCHINA:** **关于 Dubbo-go 在 Java 和 Go 运行时的兼容互通和功能一致目标,目前进展如何? + +**Dubbo-go 邓明:** + +目前,Dubbo-go 已经完全对齐 Dubbo v2.6.x,正在全力开发 v1.5.0 版本可以全面对齐 v2.7.x。 + +Dubbo v2.7.5 之后开始支持应用维度的服务注册,这也是 v1.5.0 计划支持的核心特性。 + +可以剧透一下,目前 v1.5.0 版本的 Dubbo-go 开发工作已经进入了尾声,正处于测试阶段。等 v1.5.0 发布之后,我们会陆续发布几个小版本,用于对齐 Dubbo v2.7.5 之后的版本。可以说,v1.5.x 主要是为了配合 dubbo 的云原生化。 + +****OSCHINA:** **Dubbo-go 近期实现了 REST 协议支持,可以和 Spring Cloud 生态互联;年初实现了和 gRPC 的互联,这对 Dubbo-go 有什么意义? + +**Dubbo-go 邓明:** + +Dubbo-go 在支持了 REST 协议之后,已经可以做到跟绝大部分基于 HTTP 协议的微服务框架进行通信。 + +![img](/imgs/blog/dubbo-go/1year/dubbo-go-rest.png) + + +另外一个突出优点是,支持了 gRPC 和 REST 之后,Dubbo-go 就可以考虑和一些公司内部自研的框架进行通信了。通常一些比较大的公司会自研框架,或者深度定制某些开源框架。而只要它们支持 gRPC 或者 HTTP 协议,Dubbo-go 就可以保证与这些框架的无缝衔接。 + +还有一个优势,REST 协议对前端更友好,可以直接把 Dubbo-go 开发的服务给前端用,而不用加一层协议转换,也避免了前端直接发起 RPC 请求。因此,Dubbo-go 也就可以成为它们在 Go 微服务框架的一个比较优秀的选择。 + +**OSCHINA:** 1.4 版本中,Dubbo-go 在可观测性方面采用了 tracing 和 metric,metric 的实现参考了 Dubbo 的做法,也做了一些调整,具体是怎么样? + +**Dubbo-go 邓明:** + +可观测性是衡量一个微服务框架的重要方面。一般可观测性分成 tracing、metric 和 log 三个部分。 + +![img](/imgs/blog/dubbo-go/1year/dubbo-go-observe.png) + +在 v1.4 Dubbo-go 之前,tracing 和 metric 是 Dubbo-go 的薄弱环节。为了支持这两个,我们考察了比较多的开源框架的做法。我们发现,因为要考虑对接非常多诸如 zipkin/cat 等监控框架,所以它们往往会设计一整套监控和度量的 API。 + +Dubbo 也是如此。Dubbo 的 metric 比较依赖阿里内部一个开源的 metric 的项目。这个项目也不是只能给 Dubbo 应用,而是 Java 项目都可以考虑。本质上来说,它定义了一套 API,而后提供了对不同开源框架的适配实现。把握住这一核心之后,我们就要考虑一个问题:要不要自己设计一套 API?我们的答案是 NO,并且选择了 opentracing API 作为我们监控使用的 API。 + +首先,我们回顾那些自己设计了 API 的开源项目,它们的 API 和 opentracing API 还比较相像。我觉得我设计不出来一个明显比 opentracing API 更加优雅的 API 了。 + +另外从实现效率上来说,如果我们使用 opentracing API 作为 Dubbo-go 接入 metric 和 tracing 的 API,那么,任何支持 opentracing API 的框架,都可以做到开箱即用。 + +目前我们正在向社区用户征集监控意见,看社区希望我们在框架内什么地方进一步埋点。我们也得到了很多反馈,下一步就要考虑进一步优化采集的数据。 + +**OSCHINA:** Dubbo-go 的开发团队之前介绍,Dubbo-go 首要目的就是解决 Go 项目与 Java & Dubbo 项目的互通问题,同时也为 Go 项目提供了一种 RPC 与微服务开发框架的选择。但从之前的用户使用列表来看,直接把它作为 Go 的一个 RPC 框架来使用的好像并不是特别多,现在情况是这样吗? + +**Dubbo-go 邓明:** + +这个情况已经有了很大的改善了。最开始的时候,我们的用户大部分都是 Java Dubbo 那里过来的。但是到今年,据我们了解,已经有一些用户已经是直接把 Dubbo-go 作为 RPC 框架。在经过一年的发展以后,即便不考虑和 Dubbo 保持兼容这一特点,Dubbo-go 也可以说一个比较优秀的 Go 语言 RPC 框架。 + +尤其是在异构系统通信和服务治理方面,我们提供了非常多样化的支持。这是很多别的 RPC 框架所不具备,或者不如我们的。 + +**OSCHINA:** 总结一下这一年里,Dubbo-go 技术方面值得了解的进展吧? + +**Dubbo-go 邓明:** + +Dubbo-go 这一年的进步很大,实现了非常多非常重要的特性。 + +首先要提及的就是支持了很多协议,比如说基于 protobuf 的 gRPC 和 REST。这些协议保证了我们能够与市面上大多数的 RPC 框架进行通信,而且我们在 1.5.0 里面,还扩展支持支持基于 Json 的 gPRC 和 基于 protobuf 的 TCP 通信。 + +第二则是支持了配置中心。这个功能可以提供给用户极大的配置上的灵活性。 + +第三则是可观测性上改进,也就是前面提到的 metric 和 tracing。 + +第四则是现在正在进行的应用注册模型,它能让我们更好地拥抱 k8s 和 servise mesh。为了支持应用注册模型,我们还实现了一个元数据中心,这个元数据中心非常有利于做网关。此外还实现了很多功能,如新的限流算法,负载均衡算法和路由策略等。具体内容,欢迎大家去看我们的 release log。 + +![img](/imgs/blog/dubbo-go/1year/dubbo-go-arch.png) + + +**OSCHINA:** 上个月,Go 官方公布的最新调查报告显示,Go 语言的主要用途包括编写 RPC 服务,其次库和框架方面增量巨大。“竞争对手”变多会影响到 Dubbo-go 原本的计划实施吗,Dubbo-go 和其他同类项目比有什么不同? + +**Dubbo-go 邓明:** + +我们对 Go 社区的进步感同身受。实际上,Dubbo-go 这一年很多功能的实现,都离不开合作社区的支持。比如说我们提供的基于 Nacos 的配置中心支持,以及现在正在测试基于 Nacos 的应用维度服务注册与发现,都十分依赖 Nacos 的 Go 语言 SDK 支持。 + +而且我们也注意到,别的 Go 语言的微服务框架在这一年也取得了不错的进步,这是一种很好的鞭策。在 RPC 框架上,一直都是百家齐放百花争鸣局面,迫使我们朝着“人无我有,人有我精”的方向前进。到目前来说,我们感觉我们的竞争优势还是比较明显的: + +第一点就是保持了和 Dubbo 的兼容,那么原本的 Dubbo 用户在考虑 Go 语言框架的时候,我们就会是首选; + +第二个竞争优势则是支持多协议。这几年一个很明显的趋势就是,一个公司的技术栈难以保持单一,因为不同框架、不同语言会有不同优点。所以 Dubbo-go 也会是那些考虑连接异构系统用户的首选; + +第三则是软实力,也就是我们社区自身的优点。我们社区非常有活力,用户有什么问题都能够得到很快的响应;而我们的迭代速度,一直比较快。如果用户觉得自己能够很快获得帮助,那么他们也会倾向选择我们。 + +**OSCHINA:** 我们了解到,Dubbo-go/getty 是 Dubbo-go 中比较能体现 Go 语言优势的部分,目前已经被解耦出来,可以直接用。Dubbo-go 的其他组成部分会考虑同样解耦吗? + +**Dubbo-go 邓明:** + +这可以说是一个非常长远和理想化的计划了。我们现在正在做的一件事,是把项目里面用的公共方法、和框架无关的代码抽取出来,做成一个工具类库,也就是 dubbogo-gost 这个项目。 + +我们注意到,不管是在 Dubbo-go,还是别的框架,这些代码都很类似,比如说对不同类型的数据排序。之前我们找过开源的 lib,但是都不尽如人意,所以我们打算把自己的拿出来,做成类似瑞士军刀一样小巧高效的工具。 + +另外还要提到 dubbo-go-hessian2 开源仓库。我们可以自豪地说,这个库是 Go 里面对 hessian v2 协议支持最好的开源库。不仅仅是我们在用,阿里和蚂蚁金服也在用。我们也希望吸引更加多用户来使用,帮我们改进。 + +**OSCHINA:** Dubbo-go 今年 3 月 25 日的新版本 1.4.0 中“拿出了使用 k8s 作为注册中心的解决方案”,选择性放弃 Service 功能,将元数据直接写入到 Pod 对象的 Annotations 中。为什么做出这个决策,后续有什么落地计划? + +**Dubbo-go 邓明:** + +在使用 k8s 作为注册中心这个点上,讨论就花了很长的时间。 + +其实最初考虑的是直接使用 k8s 服务发现模型,后来发现 k8s service 和 Dubbo-go Interface 之间存在一些难以调和的矛盾。比如说 Kubernetes 已经为其承载的服务提供了⼀套服务发现,服务注册,以及服务集群管理机制。⽽ Dubbo-go 也拥有⾃成体系的服务集群管理。 + +这两个功能点形成了冲突,在无法调和两者的情况下,我们放弃了这个计划,并且提出了现在这个随 1.4.0 版本发布使用的模型。 + +![img](/imgs/blog/dubbo-go/1year/dubbo-go-k8s.png) + +后续,我们将主要考虑 k8s 本身提供的 CRD + Operator 的方案,毕竟越来越多的 k8s 周边的项目都在以 Operator 作为切入点。Dubbo-go 社区后续的方案将会以 CRD 的形式在 k8s 内注册和发现服务。这样做的原因有很多,首先是为了减少 Dubbo-go 对 kube-apiserver 的直接依赖。其次是为了标准化注册模型,当服务模型以 CRD 的形式存在在 k8s 集群中之后,其他围绕 k8s 的项目可以直接使用这些资源二次开发和拓展。而这种方式更加 CloudNative。 + +**OSCHINA:** Dubbo-go 现在在云原生应用上的布局是怎样的? + +**Dubbo-go 邓明:** + +社区的主要人力正与蚂蚁金服的 mosn 社区展开合作。目前有 5 个人力与 mosn 社区一起在 mosn 中实现 Dubbo 的服务发现、服务注册和基本的 RPC 通信等数据平面的能力,在 istio 层面支持通过 XDS 实现配置下发,以实现 mosn + Dubbo-go 【嵌入 mosn】 + istio 这种 sidecar 形式的云原生方案。已完成的工作已经在多点科技展开测试,近期 mosn 社区同学会在 A2M 大会上公布具体进展。 + +除了 sidecar 这种 proxy 形式的云原生方案,社区还计划实现 Dubbo-go【应用 sdk】 + istio 这种 proxyless 方式的云原生方案。Java 应用或者 Go 应用通过 istio 的 xDS 协议完成服务注册和发现以及路由分发。或者说,我们力求微服务和云原生共存,可以称之为“双模微服务”。这种“双模微服务”允许标准的 Dubbo-go + sidecar 和 Dubbo-go【应用 sdk】 + istio 两种模式部署的应用共存。这将是 Dubbo-go v1.6 的核心工作。 + +**OSCHINA:** Dubbo-go 几乎是刚一诞生就转移到 Apache,并且很快发布了 Apache Dubbo Go v1.1.0,这对社区运营的帮助是什么,可以分享下 Dubbo-go 的运营情况和经验吗? + +**Dubbo-go 邓明:** + +可以说,Apache 基金会对我们的帮助是很大的。 + +一方面,Apache 自身的光环十分有助于吸引开发关注和参与;另外一方面,Apache 的一些要求,也让社区运营更加规范。 + +社区运营需要进一步规范化,透明化,以吸引更加多的人参与。我注意到很多优秀的社区运营做得很好,他们对 issue 的管理很细致,打上了各种标签,做到了对 issue 的轻重缓急的管理。这种标签能够很容易吸引一些打算尝试开源的新人,给社区带来新的血液。 + +我们尝试使用 milestone 的方式来管理 Dubbo-go 的整体进度。现在也在尝试定期召开社区会议,讨论社区发展方向,重大特性的设计,以及解决争端会议会面向整个社区,想参与的人都可以参与。 + +Dubbo-go 应用及规划 **OSCHINA:** Dubbo-go 适合什么样的企业和场景? + +**Dubbo-go 邓明:** + +我们认为,如果用户需要一款 Go 语言方面 gRPC 框架,可以考虑 Dubbo-go;如果公司有和异构系统通信的需求,Dubbo-go 也是一个比较好的选择。特别是,公司内部还有 Java Dubbo 或者 Spring Clound 之类的应用,那么 Dubbo-go 优势就更加大了。 + +Dubbo-go 可以说是 " all-in-one " 性质的 RPC 框架,自身包含服务治理等功能,非常省时省力,而且能够降低使用微服务的门槛。 + +**OSCHINA:** GitHub 的用户列表中已经有来自 14 家企业的使用记录,Dubbo-go 一般会提供哪些后续支持? + +**Dubbo-go 邓明:** + +我们一直都快速响应用户的问题,而且积极鼓励用户参与到 Dubbo-go 的开发中来。目前涂鸦智能、携程等几家用户已经成为了社区贡献的主要力量。 + +有时候用户来做调研,进来社区咨询问题的时候,我们都会笑称他“如果选择了 Dubbo-go,就选择了一个强大的售后团队”。 + +社区一位很活跃的 Contributor 潘总【github id: pantianying】对我们的热情服务应该深有体会。比如他会提 issue,然后我们也会很快解决像 router、优雅退出功能就是在潘总提出之后,我们很快实现的, 还有早期一次重构之后,也是潘总尝鲜试用。尝鲜版通常有很多 BUG,所以我们都是上班打工,下班给潘总修 BUG,也算是服务周到热情用心了。 + +额外说下,目前 Dubbo 官方也已经投入人力参与 Dubbo-go 的开发,阿里集团今年完成 HSF 和 Dubbo 的融合后,会在集团内逐步推广使用 Dubbo-go。 + +**OSCHINA:** Dubbo-go 下一版本预计什么时候发布,有没有一些长远的发展计划? + +**Dubbo-go 邓明:** + +当前正在测试的是 v1.5 版本,希望六月份能发出来。v1.6 版本正在设计和规划中,v1.6 是和 Dubbo 3 对齐的,所以也会是一个比较大的版本。 + +今年我们社区主要集中在两件事上。第一件是云和云原生的支持,现在进行中的 v1.5 和 v1.6 都是围绕这一点的。今年几乎所有大的 feature 都是这方面的。 + +第二件事,则是进一步提高 Dubbo-go 的文档、注释和代码质量。坦白来说,Dubbo-go 的文档并不是特别好,尤其是用户文档。我们也收到了很多用户的批评正在加强 CI 和自动化测试这块。总而言之,文档与质量这件事是今年的头等大事。 + +**OSCHINA:** 最后,请介绍一下自己吧。 + +**Dubbo-go 邓明:** + +说起来挺有意思的,就是我本身是业务开发,并不是传统意义上的中间件开发或者基础架构开发。我目前在 eBay 做支付业务的开发。eBay 是一个 WLB 的公司,也就是在 eBay 我才有了足够的业余时间,开始投入到了开源社区中。 + +Dubbo-go 是我第一个深入参与的开源项目,也是我第一次尝试将个人对分布式系统和微服务治理的理解付诸实践的项目。它是我的第一个“孩子”。 + +因为工作的关系,我算是 Dubbo-go 社区投入时间最多的人之一,为 Dubbo-go 开发了一些很有意思的特性,也因此成了 Apache committer。另外我还扮演了编辑的角色,帮社区小伙伴写的博客文章把把关,润润色。我也算是 Dubbo-go 的主要管理人员了,比如说 v1.5 这个版本就是主要由我推进的——这大概还是因为我时间比较多。 diff --git a/content/en/blog/golang/dubbo-go-quickstart.md b/content/en/blog/golang/dubbo-go-quickstart.md new file mode 100644 index 000000000000..1ec990928f49 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-quickstart.md @@ -0,0 +1,260 @@ +--- +title: "快速上手 dubbo-go" +linkTitle: "快速上手 dubbo-go" +tags: ["Go"] +date: 2021-01-14 +description: > + 今天上手实战一把,告诉你如何快速用 go 上手 dubbo +--- + +## 前言 + +每次技术调研总会发现自己学不动了怎么办?用已有的知识来拓展要学习的新知识就好了~ by LinkinStar + +最近需要调研使用 dubbo,之前完全是 0 基础,对于 dubbo 只存在于听说,今天上手实战一把,告诉你如何快速用 go 上手 dubbo + +PS:以下的学习方式适用于很多新技术 + +## 基本概念 + +**首先学习一个技术首先要看看它的整体架构和基本概念**,每个技术都有着自己的名词解释和实现方式,如果文档齐全就简单很多。 + +[基本概念](/en/docs/languages/golang/dubbo-go-3.0/preface/architecture/) + +大致浏览了背景、需求、架构之后基本上有一个大致概念 + +![img](/imgs/blog/dubbo-architecture.png) + +其实整体架构和很多微服务的架构都是类似的,就是有一个注册中心管理所有的服务列表,服务提供方先向注册中心注册,而消费方向注册中心请求服务列表,通过服务列表调用最终的服务。总的来说 dubbo 将整个过程封装在了里面,而作为使用者的我们来说更加关心业务实现,它帮我们做好了治理的工作。 + +然后我抓住了几个我想要知道的重点: + +- 注册中心可替换,官方推荐的是 zk +- 如果有变更,注册中心将基于长连接推送变更数据给消费者,注册中心,服务提供者,服务消费者三者之间均为长连接 +- 基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用 +- 消费者在本地缓存了提供者列表 + +## 实际上手 + +官网文档中也给出如果使用 golang 开发,那么有 [https://github.com/apache/dubbo-go](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fapache%2Fdubbo-go) 可以用,那么废话不多说,上手实践一把先。因为你看再多,都比不上实践一把来学的快。 + +### 环境搭建 + +大多数教程就会跟你说,一个 helloWorld 需要 zookeeper 环境,但是不告诉你如何搭建,因为这对于他们来说太简单了,而我不一样,我是 0 基础,那如何快速搭建一个需要调研项目的环境呢?最好的方式就是 docker。 + +```yaml +version: '3' +services: + zookeeper: + image: zookeeper + ports: + - 2181:2181 + admin: + image: apache/dubbo-admin + depends_on: + - zookeeper + ports: + - 8080:8080 + environment: + - admin.registry.address=zookeeper://zookeeper:2181 + - admin.config-center=zookeeper://zookeeper:2181 + - admin.metadata-report.address=zookeeper://zookeeper:2181 +version: '3' +services: + zookeeper: + image: zookeeper + ports: + - 2181:2181 + admin: + image: chenchuxin/dubbo-admin + depends_on: + - zookeeper + ports: + - 8080:8080 + environment: + - dubbo.registry.address=zookeeper://zookeeper:2181 + - dubbo.admin.root.password=root + - dubbo.admin.guest.password=guest +``` + +上面两个 docker-compose 文件一个是官方提供的管理工具,一个包含的是个人修改之后的管理工具,记住这里有个用户名密码是 root-root,看你喜欢 + +废话不多说,直接创建 docker-compose.yaml 然后 `docker-compose up` 你就得到了一个环境,棒???? + +### 样例下载 + +有的技术会给出官方的实验样例,dubbo-go 也不例外 + +[https://github.com/apache/dubbo-go-samples](https://github.com/apache/dubbo-go-samples) + +里面包含了 go 和 java 的样例,有了它你就能快速上手了,把它下载到本地 + +### 样例运行 + +首先要做的第一步就是把 helloworld 给跑起来,进入 golang 目录,里面有个 README.md 看一下。然后开搞。 + +打开一个终端运行服务方 + +```bash +export ARCH=mac +export ENV=dev +cd helloworld/dubbo/go-server +sh ./assembly/$ARCH/$ENV.sh +cd ./target/linux/user_info_server-0.3.1-20190517-0930-release +sh ./bin/load.sh start +``` + +打开另一个终端运行客户端 + +```bash +export ARCH=mac +export ENV=dev +cd helloworld/dubbo/go-client +sh ./assembly/$ARCH/$ENV.sh +cd ./target/linux/user_info_client-0.3.1-20190517-0921-release +sh ./bin/load_user_info_client.sh start +``` + +启动过程中会出现一些警告,问题不大,如果成功,那么客户端会有一个调用服务端的请求,并在控制台中以白色底色进行打印 + +![img](/imgs/blog/dubbo-go/quickstart/console.png) + +java 的服务也有相对应的启动方式,按照 README 中所说明的也可以进行注册和调用,并且 java 和 go 之间是可以互相调用的 + +### 查看服务 + +因为我们部署的时候有一个 dubbo-admin 用于管理 zk 上注册的服务,我们可以访问本地的 8080 端口看到对应的服务情况 + +![img](/imgs/blog/dubbo-go/quickstart/admin.png) + +image.png + +至此你应该已经对于整体的链路调用有一个大致的认识,结合之前官网文档的中的架构图,应该也清晰了。 + +## 如何使用 + +那么现在你已经运行起来了,那么势必就要来看看具体是如何进行使用的了。 + +### 服务端 + +服务端,也就是服务提供者; + +位置在:`dubbo-samples/golang/helloworld/dubbo/go-server/app` + +```go +// 将服务进行注册 +config.SetProviderService(new(UserProvider)) +// 注册对象的hessian序列化 +hessian.RegisterPOJO(&User{}) +``` + +是不是看起来其实很简单,其实重点就是上面两句代码了 + +对于服务本身来说 + +```go +type UserProvider struct { +} + +func (u *UserProvider) GetUser(ctx context.Context, req []interface{}) (*User, error) { + println("req:%#v", req) + rsp := User{"A001", "Alex Stocks", 18, time.Now()} + println("rsp:%#v", rsp) + return &rsp, nil +} + +func (u *UserProvider) Reference() string { + return "UserProvider" +} +``` + +其实就是需要实现下面那个接口就可以了 + +```go +// rpc service interface +type RPCService interface { + Reference() string // rpc service id or reference id +} +``` + +其中有一步骤不要忘记了是config.Load(),会加载配置文件的相关配置,不然你以为注册中心的地址等等是在哪里配置的呢? + +### 客户端 + +看了服务端,其实客户端也就很简单了 + +```go +config.SetConsumerService(userProvider) +hessian.RegisterPOJO(&User{}) +``` + +其实也是差不多的,也需要注册一个消费服务,并将序列化方式给注册上去 + +```go +user := &User{} +err := userProvider.GetUser(context.TODO(), []interface{}{"A001"}, user) +``` + +使用也就很简单了,同样的也需要实现 Reference 接口 + +```go +type UserProvider struct { + GetUser func(ctx context.Context, req []interface{}, rsp *User) error +} + +func (u *UserProvider) Reference() string { + return "UserProvider" +} +``` + +### 回头想想 + +当我们看完了代码的上的使用,再回头想想 dubbo 的作用,你就会发现其实 dubbo 帮你做的事情真的屏蔽了很多。 + +- 你不需要关心服务是怎么注册的 +- 你不需要关心服务是怎么获取的 +- 你不需要关系服务是怎么调用的 +- 甚至序列化的过程都是基本透明的 + +想对比来说,如果让你自己去是实现微服务,那是不是说,你需要实现服务的拉取,服务的负载均衡,服务的发现,序列化..... + +这下你应该明白了 dubbo 是做什么的也就明白了它为什么会出现了 + +## 其他能力 + +当你学习了一个技术的基本使用之后,要学习其他的能力,以便在使用的过程中不会出现自己重复造轮子或者说有轮子没用到的情况,[https://github.com/apache/dubbo-samples](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fapache%2Fdubbo-samples) 不止有 helloworld 还要很多别的案例供你参考,你可以继续看看并进行试验。 + +### 支持扩展 + +[https://github.com/apache/dubbo-go](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fapache%2Fdubbo-go) + +在 Feature list 中列举了 dubbo-go 所支持的相关功能,比如序列化,比如注册中心,在比如过滤器。 + +也就是说,在使用 dubbo-go 的时候相关功能都是插件化的,想用什么就看你自己了,比如注册中心我想用 etcd,比如调用的协议我想换成 grpc 都可以。 + +## 相关问题 + +**对于一个技术调研,那么肯定会有相关问题等着你去发现去考虑。** + +下面是我能想到的一些问题: + +- 当前 dubbo-go 的版本最高在 1.4,所对应的 dubbo 版本应该是 2.6.x,如果调用更高版本的服务是否会有问题 +- java 和 go 之间互相调用,各种类型转换之间是否存在问题,是否容易出现无法正确反序列化的问题 +- .... + +## 后续学习 + +那么上面只是说能让你上手 dubbo-go,但是实际使用可能存在距离。为什么这么说呢?如果你在不动里面任何的原理情况下,那么如果遇到问题,你很可能就束手无策了。比如如果线上服务无法正常发现,你应该如何排查?调用过程中出现问题如何定位? + +所以后续你需要做的是: + +- 看看整体设计架构和思路,明白整条链路调用过程和规则 +- 学习它的接口设计,为什么别人设计的接口能兼容那么多的注册中心?如果让你来设计你怎么设计呢? +- 性能也很重要,网上说性能很不错,为什么呢?什么地方做了优化,负载均衡的算法是怎么样的,你能自定义吗? + +## 总结 + +总的来说,对于 dubbo-go 整体的使用上还是非常好上手的,自己想了一下,如果当前项目想要接入的话,主要是服务的暴露、序列化方式、鉴权调整等存在开发工作。 + +上面砖头也抛的差不多了,对于你快速上手应该没有问题了,剩下的就要靠你自己了 + diff --git a/content/en/blog/golang/dubbo-go-rest.md b/content/en/blog/golang/dubbo-go-rest.md new file mode 100644 index 000000000000..2485d444c772 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-rest.md @@ -0,0 +1,245 @@ +--- +title: "dubbo-go 中 REST 协议实现" +linkTitle: "dubbo-go 中 REST 协议实现" +tags: ["Go"] +date: 2021-01-14 +description: > + 在社区小伙伴们的努力下,Apache/dubbo-go 在 v1.4.0 中支持 REST 协议了。 +--- + +## 什么是 REST 协议 + +REST 是 **RE**presentational **S**tate **T**ransfer(表述性状态转移)的简写,是一种软件架构风格。虽然 REST 架构风格不是一定要基于 HTTP 协议进行传输,但是因为 HTTP +协议的通用性和易用性,现在越来越多的 web 服务采用基于 HTTP 协议实现 RESTful 架构。 + +在 dubbo-go 中的 REST 协议指的是一种基于 HTTP 协议的远程调用方式。简单的来讲,REST 协议就是把dubbo 服务发布成 RESTful 风格的 HTTP 接口并且能够能像调用 dubbo 接口一样的方式调用 HTTP +接口。 + +## 为什么要支持 REST 协议 + +在没有 REST 协议之前,小伙伴们是否一直在苦恼这样几个问题: + +1. 传统的 web 服务不能直接调用我们发布的 dubbo 服务 +2. 前端不能直接调用 dubbo 服务 +3. dubbo 服务不能发布 Open API + +上述问题,就是 REST 协议解决的核心问题。现在我们很多应用场景都是需要与异构的系统进行交互,而 REST 采用的 HTTP 通信协议非常适合用来打通异构系统,如图: + +![img](/imgs/blog/dubbo-go/rest/rest-call.webp) + +## REST 协议没那么简单 + +REST 协议核心要解决一个问题:**Go 方法到 HTTP 接口的双向映射**。普通 HTTP 调用 dubbo-go 服务,考虑的是HTTP 到 **Go** 方法的映射;而 dubbo-go 服务调用 HTTP 服务,则是 ** +Go** 方法到 HTTP 接口的映射。 + +下面是我们要与 **Go** 方法要做映射的 HTTP 请求协议内容: + +``` +POST /path/{pathParam}?queryParam=1 HTTP/1.1 +Accept: application/json +Content-Type: application/json +Host: http://localhost:8080 +{"id":1111} +``` + +在服务提供方,当上面这种请求发送到服务器时,我们要把它路由到下面这个 **Go** 方法中,在服务消费方,我们也可以通过调用下面的 **Go** 方法把方法参数转化为上面的HTTP请求: + +```go +type Provider struct { + // 该方法应该对应上面的http请求 + GetResult func(pathParam string, queryParam string, body interface{}, host string) (*Result, error) +} +``` + +在消费方调用 `GetResult` 时,传入各个参数的值: + +- 变量 pathParam 的内容应该是字符串 "pathParam"; +- 变量 queryParam 的内容应该是字符串 "1" ; +- 变量 body 应该是有以字符串 "id" 为 key ,1111 为 value 的一个map; +- 当然 host 变量的内容应该是字符串 "http://localhost:8080" 。 + +在服务端执行 `GetResult` 方法时,得到的参数会与消费方调用时传入的值相同。 + +总结下来,我们要建立以下这些映射关系 + +1. 路径映射 +2. Header 处理(固定 Header 和 Header 值也是参数两种情况) +3. POST or GET or ...(HTTP 方法映射) +4. 参数映射 + +要完成这种映射,我们首先要解决的是,如何知道这种映射关系? + +答案只有一个,通过用户配置。而用户配置所面临的困难是,复杂且琐碎。(解决思路是提供大量默认配置减轻配置的负担,自定义配置方式允许用户使用自己熟悉的配置形式) + +另外一个难点在于,使用何种 web 框架的问题。有些公司内部使用的是自研的 web 框架,他们有成熟的技术基础和运维能力。于是就会考虑说,能不能让 dubbo-go 在支持 REST 协议的时候,能够让他们将 REST 协议使用的web +框架替换成他们所期望的呢? + +## 如何建立HTTP接口与方法的映射关系 + +下面我举一个HTTP接口与方法映射的具体例子: + +**Go** 结构体定义如下: + +```go +type UserProvider struct { + GetUser func(id string, name string, age int) (*User, error) +} +``` + +要发布的HTTP接口形式是: http://127.0.0.1/UserProvider/GetUser/{id}?name=test&age=1 + +服务端配置如下: + +```yaml +services: + "UserProvider": + //注册中心 + registry: "zookeeper" + //启用REST协议 + protocol: "rest" + //DUBBO的接口名 + interface: "com.ikurento.user.UserProvider" + // 服务接口路径 + rest_path: "/UserProvider" + methods: + - name: "GetUser" + // 方法接口路径 + rest_path: "/GetUser/{id}" + // HTTP方法 + rest_method: "GET" + // HTTP查询参数 + rest_query_params: "1:name,2:age" + // HTTP路径参数 + rest_path_params: "0:id" + // 可以提供的内容类型 + rest_produces: "application/json;application/xml" + // 可以接受的客户端参数类型 + rest_consumes: "application/json;charset=utf-8,*/*" + // HTTP Body + rest_body: -1 +``` + +在配置文件中我们定义了方法的路径,HTTP方法等接口参数,这里需要注意的是路径参数和查询参数的配置方式,0:name 的意思是查询参数 name 对应 `GetUser` 方法的第一个参数,还有 rest_body +配置的数字也是对应这方法的参数,这里没有 body 参数所有就配置了 `-1`。 + +## REST协议的调用过程 + +![img](/imgs/blog/dubbo-go/rest/rest-call-process.webp) + +上图展示了用户在 Consumer 端调用 `GetUser` 方法到 Provdier 端 `GetUser` 方法被执行的整个过程,在 `RestClient` 和 `RestServer` 中分别**实现了 Go 方法参数到 HTTP +请求的转换和 HTTP 请求到 Go 方法的转换,这是最为核心和复杂的部分。**换言之,我们在这里实现了前面提到的 Go 方法和 HTTP 请求的双向映射。 + +这里我们可以注意到 `RestClient` 和 `RestServer` 是可以用户自行扩展的,下面我将具体介绍一下在REST协议中有哪些扩展点设计。 + +## REST协议的扩展点设计 + +基于 dubbo-go 良好的 extension 扩展设计,我们定义了多个扩展点,用户可以自定义功能实现。 + +### 自定义HTTP服务器 + +RestServer的扩展接口: + +```go +type RestServer interface { + + // sever启动函数 + Start(url common.URL) + + // 发布接口 + Deploy(restMethodConfig *rest_config.RestMethodConfig, routeFunc func(request RestServerRequest, response RestServerResponse)) + + // 删除接口 + UnDeploy(restMethodConfig *rest_config.RestMethodConfig) + + // server关闭 + Destroy() +} +``` + +在 dubbo-go 的 v1.4.0 中默认使用 go-restful 作为 HTTP 服务器,如果用户想用其他 HTTP 容器可以实现上面的接口,并在配置文件中配置使用自己自定义的服务器。 + +这个接口中,最核心的方法是 Deploy,在 restMethodConfig 方法参数中有用户配置的接口路径等一系列参数,routeFunc 是 HTTP 接口需要被路由执行的函数。不同的http服务器会有不同的 request 和 +response ,所以我们定义了 `RestServerRequest` 接口和 `RestServerResponse` 接口让用户进行适配。 + +### 自定义HTTP客户端 + +RestClient 的扩展接口: + +```go +// RestOptions +type RestOptions struct { + RequestTimeout time.Duration + ConnectTimeout time.Duration +} +// RestClientRequest +type RestClientRequest struct { + Header http.Header + Location string + Path string + Method string + PathParams map[string]string + QueryParams map[string]string + Body interface{} +} +// RestClient user can implement this client interface to send request +type RestClient interface { + Do(request *RestClientRequest, res interface{}) error +} +``` + +最后的请求到客户端时,都会被封装为 `RestRequest`,用户可以非常简单快速的扩展自己的 Client 端。`RestOptions` 中有一些客户端的超时配置,在创建自己的客户端时需要根据这些配置初始化客户端。 + +### 自定义 REST 配置形式 + +前面提到,REST 协议一个很麻烦的地方在于,配置很繁琐很琐碎。Go 不同于 Java,可以通过注解的形式来简化配置。 + +所以我们考虑到用户不同的使用习惯和公司的配置风格,提供了这个扩展点。 + +ConfigReader 的扩展接口: + +```go +type ConfigReader interface { + + // Consumer配置读取 + ReadConsumerConfig(reader *bytes.Buffer) error + + // Provider配置读取 + ReadProviderConfig(reader *bytes.Buffer) error +} +``` + +`ReadConsumerConfig` 和 `ReadProviderConfig` 方法的参数是配置文件的文件流,在实现方法中可以再次解析,也可以使用二次编译或者硬编码方式等其他方式读取配置。这是一个通用的配置读取接口,以后可以用来扩展 +REST 配置之外的其他配置,所以需要在方法中调用方法设置配置,如下: + +```go +// 设置Rest的消费者配置 +config.SetRestConsumerServiceConfigMap(restConsumerServiceConfigMap) +// 设置Rest的提供者配置 +config.SetRestProviderServiceConfigMap(restProviderServiceConfigMap) +``` + +## 如何添加 HTTP 过滤器 + +因为不同 HTTP 服务器的过滤器,拦截器或者是 middleware 添加方式都不同,所以我们很难定义一个接口满足所有服务器。因此我们单独为 go-restful 定义了一个添加 filter 的方法,这里我们需要注意的一点是必须在 REST 接口发布前添加filter。 + +```go +server_impl.AddGoRestfulServerFilter(func(request *restful.Request, response *restful.Response, chain *restful.FilterChain) { + // 鉴权等功能 + chain.ProcessFilter(request, response) +}) +// 启动dubbo服务,发布rest等接口 +config.Load() +``` + +## 展望 + +以上是关于 REST 协议的一些介绍,具体的实现我就不详细讲了,大家可以去参阅源码。 + +如果想看具体的Example,请参考: + +https://github.com/dubbogo/dubbo-samples/tree/master/golang/general/rest + +REST 未来需要支持 HTTPS 协议和基于 open tracing 标准 api 的链路追踪。REST 的配置信息未来也不是 REST协议独有的,这些配置信息未来可以作为每个 dubbo 接口的元数据,存储到元数据中心,为网关提供 +HTTP 协议与 dubbo 协议之间的映射关系。 + +> 作者:蒋超,github id Patrick0308,在 杭州贝安云科技有限公司 任职服务开发工程师。 diff --git a/content/en/blog/golang/dubbo-go-router.md b/content/en/blog/golang/dubbo-go-router.md new file mode 100644 index 000000000000..a38af3d84b6f --- /dev/null +++ b/content/en/blog/golang/dubbo-go-router.md @@ -0,0 +1,295 @@ +--- +title: "dubbo-go 中如何实现路由规则功能" +linkTitle: "dubbo-go 中如何实现路由规则功能" +tags: ["Go"] +date: 2021-01-12 +description: > + 本文介绍了在 dubbo-go 中路由规则功能的设计与实现 +--- + + +## Let‘s Go! + +最近在 Apache/dubbo-go(以下简称 dubbo-go )社区中,路由规则突然成了呼声最高的功能之一。那到底为什么需要路由规则? + +先路由规则需要实现的功能: + +路由规则( routing rule )是为了改变网络流量所经过的途径而修改路由信息的技术,主要通过改变路由属性(包括可达性)来实现。在发起一次 RPC 调用前起到过滤目标服务器地址的作用,过滤后的地址列表,将作为消费端最终发起 RPC 调用的备选地址。 + +试想该下场景:使用 dubbo-go 在生产环境上,排除预发布机。使用路由规则实现不是很合适吗? + +虽然知道了路由规则需要实现什么功能,但还不足以实现一个完整的路由规则功能。除此之外,还需要知道如何方便的管理路由规则。 + +## 目标 + +综上所述,可以总结出以下 **目标** + +- 支持方便扩展路由规则的配置; +- 可以方便的管理路由规则配置,如支持本地与远程配置中心管理; +- 与 Dubbo 现有的配置中心内的路由规则配置文件兼容,降低在新增语言栈的学习及使用成本; + +## 路由规则设计 + +在设计之初,首先要考虑的是路由规则应该放在整个服务治理周期的哪个阶段呢? + +有些读者可能会有点困惑,我连架构图都不知道,如何考虑在哪个阶段?不怕,下图马上给你解惑。 + +![img](/imgs/blog/dubbo-go/dubbo-go-arch-2.png) + +可以看到图中的 Router 就是路由规则插入的位置,目前路由规则主要用于控制 Consumer 到 Provider 之间的网络流量的路由路径。 + +除此之外,还有几个问题是需要优先考虑: + +1.需要什么功能? + +- 通过配置信息生成路由规则,包括:读取并解析本地配置文件,读取并解析配置中心的配置。以责任链模式串联起来。 +- 通过路由规则,匹配本地信息与远端服务信息,过滤出可以调用的远端节点,再进行负载均衡。 + +2.如何设计接口? + +通过第一点,我们能设计出以下接口来实现所需的功能。 + +- 路由规则接口:用于路由规则过滤出可以调用的远端节点。 +- 路由规则责任链接口:允许执行多个路由规则。 +- 配置信息生成路由规则接口:解析内部配置信息(common.URL)生成对应的路由规则。 +- 配置文件生成路由规则接口:解析配置文件生成对应的路由规则。 + +3.如何实现本地与远程路由规则配置加载? + +- 本地路由规则配置:在原配置加载阶段,新增读取路由配置文件。使用 `FIleRouterFactory` 解析后,生成对应路由规则,放置到内存中备用。 +- 远程路由规则配置:在 zookeeper 注册并监听静态资源目录后。读取静态资源,筛选符合路由规则配置信息,通过 `RouterFactory` 生成对应路由规则,放置到内存中备用。 + +### Router + +匹配及过滤远程实例的路由规则。 + +```golang +// Router +type Router interface { + // Route determine the target invoker list. + Route([]protocol.Invoker, *common.URL, protocol.Invocation) []protocol.Invoker + // Priority return priority in router + // 0 to ^int(0) is better + Priority() int64 + // URL return URL in router + URL() common.URL +} +``` + +目前已有实现类包括: + +- listenableRouter +- AppRouter +- ConditionRouter +- HealthCheckRouter +- FileConditionRouter + +### RouterChain + +执行多个路由规则的责任链。 + +```golang +// Chain +type Chain interface { + // Route determine the target invokers list with chain. + Route([]protocol.Invoker, *common.URL, protocol.Invocation) []protocol.Invoker + // AddRouters add routers + AddRouters([]Router) +} +``` + +### FIleRouterFactory + +生成解析配置文件生成路由规则的工厂类。 + +```golang +// RouterFactory router creates factory use for parse config file +type FileRouterFactory interface { + // NewFileRouter create file router with config file + NewFileRouter([]byte) (Router, error) +} +``` + +### RouterFactory + +通过配置信息生成路由规则的工厂类。 + +```golang +// RouterFactory router create factory +type RouterFactory interface { + // NewRouter creates router instance with URL + NewRouter(*common.URL) (Router, error) +} +``` + +## 实现 + +![img](/imgs/blog/dubbo-go/router/router-design.png) + +实现路由规则以兼容 dubbo 为首要目标,降低使用者的学习成本为辅助目标。与配置中心模块相结合,实现路由规则远程统一管理与下发。 + +### 规则类型 + +下面先来介绍一下有哪些具体的路由规则实现。 + +#### 条件路由 + +dubbo-go 中第一个支持的路由规则,允许用户通过配置文件及配置中心管理路由规则。 + +与之相似的一个概念是 dubbo-go 里面的 group 概念,但是条件路由提供了更加细粒度的控制手段和更加丰富的表达语义。比较典型的使用场景是黑白名单设置,灰度以及测试等。 + +#### 健康检查路由 + +在 RPC 调用中,我们希望尽可能地将请求命中到那些处理能力快、处于健康状态的实例,该路由的功能就是通过某种策略断定某个实例不健康,并将其排除在候选调用列表,优先调用那些健康的实例。这里的”健康”可以是我们自己定义的状态,默认实现即当错误比例到达某一个阈值时或者请求活跃数大于上限则认为其不健康,允许用户扩展健康检测策略。 + +在我们服务治理里面,核心的问题其实就在于如何判断一个实例是否可用。无论是负载均衡、 + +熔断还是限流,都是对这个问题的解答。所以,这个 feature 是一个很好的尝试。因为我们接下来计划提供的特性,基于规则的限流以及动态限流,都是要解决 “如何断定一个实例是否可用” 这么一个问题。 + +所以欢迎大家使用这个特性,并向社区反馈各自设定的健康指标。这对我们接下来的工作会有很大的帮助。 + +#### 标签路由 + +以 Provider 为维度,通过将某一个或多个服务的提供者划分到同一个分组,约束流量只在指定分组中流转,从而实现流量隔离的目的,可以作为蓝绿发布、灰度发布等场景的能力基础。 + +- 静态打标:根据配置文件所配置的标签,固定给 Provider 设置标签。 +- 动态打标:基于健康检查路由,根据服务不同时刻,不同状态,动态在 Provider 设置适合的标签。 + +### 分析 + +接着,以条件路由在 zookeeper 实现为例,对服务提供者与服务消费者进行整体流程分析。 + +#### 如何配置条件路由规则 + +配置条件路由规则既可以通过本地配置文件也能通过远程配置中心进行配置,配置生效流程都是:配置文件 => dubbo 内部协议 => 缓存至应用级内存 => 过滤出可调用节点。 + +**dubbo-admin** 【服务治理/条件路由】增加路由规则配置,zookeeper 中会自动生成其对应配置节点,内容均为 **dubbo-admin** 中设置的配置。 + +**全局配置** + +对应应用级全局路由规则配置。 + +``` +/dubbo/config/dubbo/user-info-server(应用名).condition-router +``` + +应用名:只对 user-info-server 应用生效 .condition-router: 路由类型。除此之外,还有 .tag-router 表示标签路由。 + +**服务配置** + +对应服务级所有路由规则配置。 + +``` +/dubbo/ com.ikurento.user.UserProvider(服务名) /routers +``` + +服务名:只对 com.ikurento.user.UserProvider 服务生效。 + +### 实现 Router + +```golang +func (c *ConditionRouter) Route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker { + if !c.Enabled() { + return invokers + } + if len(invokers) == 0 { + return invokers + } + isMatchWhen := c.MatchWhen(url, invocation) + if !isMatchWhen { + return invokers + } + var result []protocol.Invoker + if len(c.ThenCondition) == 0 { + return result + } + for _, invoker := range invokers { + invokerUrl := invoker.GetUrl() + isMatchThen := c.MatchThen(&invokerUrl, url) + if isMatchThen { + result = append(result, invoker) + } + } + if len(result) > 0 { + return result + } else if c.Force { + rult, _ := url.GetParamAndDecoded(constant.RULE_KEY) + localIP, _ := gxnet.GetLocalIP() + logger.Warnf("The route result is empty and force execute. consumer: %s, service: %s, route: %s", localIP, url.Service(), route) + return result + } + return invokers +} +``` + +以下为必须实现的方法,以下方法用于获取过滤服务端节点配置。 + +- Route: 根据配置,调用节点与被调用节点,过滤出可调用节点。 +- Priority: 路由规则优先级,需要是个正整数。 +- URL: 通过路由规则转换出来的 dubbo 内部协议。 + +更多实现参考: + +路由规则:https://github.com/apache/dubbo-go/tree/master/cluster/router/condition + +其中包含监听配置中心实现:https://github.com/apache/dubbo-go/blob/master/cluster/router/condition/listenable_router.go + +## 使用方法 + +经过上面设计与实现的分析,大概也能猜测到如何使用: + +```golang +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/protocol" + + _ "github.com/apache/dubbo-go/config_center/zookeeper" + _ "github.com/apache/dubbo-go/cluster/router/condition" +) +``` + +如图所示,使用路由规则并不复杂,只需要把对应的依赖引入进来。在包初始化的时候,会创建出来对应的路由规则的实现。比如说加载条件路由、健康检测路由或者标签作为路由规则: + +### 本地路由规则配置 + +```golang +_ "github.com/apache/dubbo-go/cluster/router/condition" +``` + +仅仅引用依赖包还不直接使用,还需要配置指定的配置文件: ***router_config.yml\*** ,内容如下: + +```golang +# dubbo router yaml configure file +priority: 1 +force: true +conditions : ["host = 1.1.1.1 => host = 192.168.199.214"] +``` + +更多配置方式:[条件路由配置](/en/docsv2.7/user/examples/routing-rule/) + +### 配置中心配置 + +```golang +_ "github.com/apache/dubbo-go/config_center/zookeeper" +``` + +目前仅支持 zookeeper 配置中心,与 dubbo-admin 结合即可使用。配置方式如下: + +![img](/imgs/blog/dubbo-go/router/dubbo-admin-1.png) + +![img](/imgs/blog/dubbo-go/router/dubbo-admin-2.png) + +## 总结 + +更加具体的实现,我就不详细论述,大家可以去看源码,欢迎大家持续关注,或者贡献代码。 + +整个路由规则功能,已经能跟上 dubbo 2.7.x 版本,已经支持本地及远端路由规则配置管理。从扩展性来说,是比较便利。目前已经支持条件路由、标签路由与健康检测路由,虽然能满足基本使用场景,距离完善还有还长远的路。 + +未来计划: + +1. 更多的配置中心支持,理论上已经支持,但还没测试。 +2. service-router(未支持) +3. 标签路由-配置中心(未支持) +4. 目前路由与配置中心结合的代码,对新增路由规则并不友好,有一定接入成本。 + +欢迎大家关注或者贡献代码,https://github.com/apache/dubbo-go diff --git a/content/en/blog/golang/dubbo-go-seata.md b/content/en/blog/golang/dubbo-go-seata.md new file mode 100644 index 000000000000..256fbc7ec34b --- /dev/null +++ b/content/en/blog/golang/dubbo-go-seata.md @@ -0,0 +1,660 @@ +--- +title: "分布式事务框架 seata-golang 通信模型详解" +linkTitle: "分布式事务框架 seata-golang 通信模型详解" +tags: ["Go", "生态"] +date: 2021-01-15 +description: > + 本文介绍了 seata 的 go 语言客户端通信模型的实现 +--- + +## 简介 + +Java 的世界里,大家广泛使用一个高性能网络通信框架 —— netty,很多 RPC 框架都是基于 netty 来实现的。在 golang 的世界里,getty 也是一个类似 netty 的高性能网络通信库。getty 最初由 dubbo-go 项目负责人于雨开发,作为底层通信库在 dubbo-go 中使用。随着 dubbo-go 捐献给 apache 基金会,在社区小伙伴的共同努力下,getty 也最终进入到 apache 这个大家庭,并改名 dubbo-getty。 + +18 年的时候,我在公司里实践微服务,当时遇到最大的问题就是分布式事务问题。同年,阿里在社区开源他们的分布式事务解决方案,我也很快关注到这个项目,起初还叫 fescar,后来更名 seata。由于我对开源技术很感兴趣,加了很多社区群,当时也很关注 dubbo-go 这个项目,在里面默默潜水。随着对 seata 的了解,逐渐萌生了做一个 go 版本的分布式事务框架的想法。 + +要做一个 golang 版的分布式事务框架,首先需要解决的一个问题就是如何实现 RPC 通信。dubbo-go 就是摆在眼前很好的一个例子,遂开始研究 dubbo-go 的底层 getty。 + +## 如何基于 getty 实现 RPC 通信 + +getty 框架的整体模型图如下: + +![img](/imgs/blog/dubbo-go/seata/p1.webp) + +下面结合相关代码,详述 seata-golang 的 RPC 通信过程。 + +### 1. 建立连接 + +实现 RPC 通信,首先要建立网络连接,这里先从 client.go 开始看起。 + +```go +func (c *client) connect() { + var ( + err error + ss Session + ) + + for { + // 建立一个 session 连接 + ss = c.dial() + if ss == nil { + // client has been closed + break + } + err = c.newSession(ss) + if err == nil { + // 收发报文 + ss.(*session).run() + // 此处省略部分代码 + + break + } + // don't distinguish between tcp connection and websocket connection. Because + // gorilla/websocket/conn.go:(Conn)Close also invoke net.Conn.Close() + ss.Conn().Close() + } +} +``` + +`connect()` 方法通过 `dial()` 方法得到了一个 session 连接,进入 `dial()` 方法: + +```go +func (c *client) dial() Session { + switch c.endPointType { + case TCP_CLIENT: + return c.dialTCP() + case UDP_CLIENT: + return c.dialUDP() + case WS_CLIENT: + return c.dialWS() + case WSS_CLIENT: + return c.dialWSS() + } + + return nil +} +``` + +我们关注的是 TCP 连接,所以继续进入 `c.dialTCP()` 方法: + +```go +func (c *client) dialTCP() Session { + var ( + err error + conn net.Conn + ) + + for { + if c.IsClosed() { + return nil + } + if c.sslEnabled { + if sslConfig, err := c.tlsConfigBuilder.BuildTlsConfig(); err == nil && sslConfig != nil { + d := &net.Dialer{Timeout: connectTimeout} + // 建立加密连接 + conn, err = tls.DialWithDialer(d, "tcp", c.addr, sslConfig) + } + } else { + // 建立 tcp 连接 + conn, err = net.DialTimeout("tcp", c.addr, connectTimeout) + } + if err == nil && gxnet.IsSameAddr(conn.RemoteAddr(), conn.LocalAddr()) { + conn.Close() + err = errSelfConnect + } + if err == nil { + // 返回一个 TCPSession + return newTCPSession(conn, c) + } + + log.Infof("net.DialTimeout(addr:%s, timeout:%v) = error:%+v", c.addr, connectTimeout, perrors.WithStack(err)) + <-wheel.After(connectInterval) + } +} +``` + +至此,我们知道了 getty 如何建立 TCP 连接,并返回 TCPSession。 + +### 2. 收发报文 + +那它是怎么收发报文的呢,我们回到 connection 方法接着往下看,有这样一行 `ss.(*session).run()`,在这行代码之后,代码都是很简单的操作,我们猜测这行代码运行的逻辑里面一定包含收发报文的逻辑,接着进入 `run()` 方法: + +```go +func (s *session) run() { + // 省略部分代码 + + go s.handleLoop() + go s.handlePackage() +} +``` + +这里起了两个 goroutine:`handleLoop` 和 `handlePackage`,看字面意思符合我们的猜想,进入 `handleLoop()` 方法: + +```go +func (s *session) handleLoop() { + // 省略部分代码 + + for { + // A select blocks until one of its cases is ready to run. + // It choose one at random if multiple are ready. Otherwise it choose default branch if none is ready. + select { + // 省略部分代码 + + case outPkg, ok = <-s.wQ: + // 省略部分代码 + + iovec = iovec[:0] + for idx := 0; idx < maxIovecNum; idx++ { + // 通过 s.writer 将 interface{} 类型的 outPkg 编码成二进制的比特 + pkgBytes, err = s.writer.Write(s, outPkg) + // 省略部分代码 + + iovec = append(iovec, pkgBytes) + + //省略部分代码 + } + // 将这些二进制比特发送出去 + err = s.WriteBytesArray(iovec[:]...) + if err != nil { + log.Errorf("%s, [session.handleLoop]s.WriteBytesArray(iovec len:%d) = error:%+v", + s.sessionToken(), len(iovec), perrors.WithStack(err)) + s.stop() + // break LOOP + flag = false + } + + case <-wheel.After(s.period): + if flag { + if wsFlag { + err := wsConn.writePing() + if err != nil { + log.Warnf("wsConn.writePing() = error:%+v", perrors.WithStack(err)) + } + } + // 定时执行的逻辑,心跳等 + s.listener.OnCron(s) + } + } + } +} +``` + +通过上面的代码,我们不难发现,`handleLoop()` 方法处理的是发送报文的逻辑,RPC 需要发送的消息首先由 `s.writer` 编码成二进制比特,然后通过建立的 TCP 连接发送出去。这个 `s.writer` 对应的 Writer 接口是 RPC 框架必须要实现的一个接口。 + +继续看 `handlePackage()` 方法: + +```go +func (s *session) handlePackage() { + // 省略部分代码 + + if _, ok := s.Connection.(*gettyTCPConn); ok { + if s.reader == nil { + errStr := fmt.Sprintf("session{name:%s, conn:%#v, reader:%#v}", s.name, s.Connection, s.reader) + log.Error(errStr) + panic(errStr) + } + + err = s.handleTCPPackage() + } else if _, ok := s.Connection.(*gettyWSConn); ok { + err = s.handleWSPackage() + } else if _, ok := s.Connection.(*gettyUDPConn); ok { + err = s.handleUDPPackage() + } else { + panic(fmt.Sprintf("unknown type session{%#v}", s)) + } +} +``` + +进入 `handleTCPPackage()` 方法: + +```go +func (s *session) handleTCPPackage() error { + // 省略部分代码 + + conn = s.Connection.(*gettyTCPConn) + for { + // 省略部分代码 + + bufLen = 0 + for { + // for clause for the network timeout condition check + // s.conn.SetReadTimeout(time.Now().Add(s.rTimeout)) + // 从 TCP 连接中收到报文 + bufLen, err = conn.recv(buf) + // 省略部分代码 + + break + } + // 省略部分代码 + + // 将收到的报文二进制比特写入 pkgBuf + pktBuf.Write(buf[:bufLen]) + for { + if pktBuf.Len() <= 0 { + break + } + // 通过 s.reader 将收到的报文解码成 RPC 消息 + pkg, pkgLen, err = s.reader.Read(s, pktBuf.Bytes()) + // 省略部分代码 + + s.UpdateActive() + // 将收到的消息放入 TaskQueue 供 RPC 消费端消费 + s.addTask(pkg) + pktBuf.Next(pkgLen) + // continue to handle case 5 + } + if exit { + break + } + } + + return perrors.WithStack(err) +} +``` + +从上面的代码逻辑我们分析出,RPC 消费端需要将从 TCP 连接收到的二进制比特报文解码成 RPC 能消费的消息,这个工作由 s.reader 实现,所以,我们要构建 RPC 通信层也需要实现 s.reader 对应的 Reader 接口。 + +### 3. 底层处理网络报文的逻辑如何与业务逻辑解耦 + +我们都知道,netty 通过 boss 线程和 worker 线程实现了底层网络逻辑和业务逻辑的解耦。那么,getty 是如何实现的呢? + +在 `handlePackage()` 方法最后,我们看到,收到的消息被放入了 `s.addTask(pkg)` 这个方法,接着往下分析: + +```go +func (s *session) addTask(pkg interface{}) { + f := func() { + s.listener.OnMessage(s, pkg) + s.incReadPkgNum() + } + if taskPool := s.EndPoint().GetTaskPool(); taskPool != nil { + taskPool.AddTaskAlways(f) + return + } + f() +} +``` + +`pkg` 参数传递到了一个匿名方法,这个方法最终放入了 `taskPool`。这个方法很关键,在我后来写 seata-golang 代码的时候,就遇到了一个坑,这个坑后面分析。 + +接着我们看一下 taskPool 的定义: + +```go +// NewTaskPoolSimple build a simple task pool +func NewTaskPoolSimple(size int) GenericTaskPool { + if size < 1 { + size = runtime.NumCPU() * 100 + } + return &taskPoolSimple{ + work: make(chan task), + sem: make(chan struct{}, size), + done: make(chan struct{}), + } +} +``` + +构建了一个缓冲大小为 size (默认为 `runtime.NumCPU() * 100`) 的 channel `sem`。再看方法 `AddTaskAlways(t task)`: + +```go +func (p *taskPoolSimple) AddTaskAlways(t task) { + select { + case <-p.done: + return + default: + } + + select { + case p.work <- t: + return + default: + } + select { + case p.work <- t: + case p.sem <- struct{}{}: + p.wg.Add(1) + go p.worker(t) + default: + goSafely(t) + } +} +``` + +加入的任务,会先由 len(p.sem) 个 goroutine 去消费,如果没有 goroutine 空闲,则会启动一个临时的 goroutine 去运行 t()。相当于有 len(p.sem) 个 goroutine 组成了 goroutine pool,pool 中的 goroutine 去处理业务逻辑,而不是由处理网络报文的 goroutine 去运行业务逻辑,从而实现了解耦。写 seata-golang 时遇到的一个坑,就是忘记设置 taskPool 造成了处理业务逻辑和处理底层网络报文逻辑的 goroutine 是同一个,我在业务逻辑中阻塞等待一个任务完成时,阻塞了整个 goroutine,使得阻塞期间收不到任何报文。 + +### 4. 具体实现 + +下面的代码见getty.go : + +```go +// Reader is used to unmarshal a complete pkg from buffer +type Reader interface { + Read(Session, []byte) (interface{}, int, error) +} + +// Writer is used to marshal pkg and write to session +type Writer interface { + // if @Session is udpGettySession, the second parameter is UDPContext. + Write(Session, interface{}) ([]byte, error) +} + +// ReadWriter interface use for handle application packages +type ReadWriter interface { + Reader + Writer +} +``` + +```go +// EventListener is used to process pkg that received from remote session +type EventListener interface { + // invoked when session opened + // If the return error is not nil, @Session will be closed. + OnOpen(Session) error + + // invoked when session closed. + OnClose(Session) + + // invoked when got error. + OnError(Session, error) + + // invoked periodically, its period can be set by (Session)SetCronPeriod + OnCron(Session) + + // invoked when getty received a package. Pls attention that do not handle long time + // logic processing in this func. You'd better set the package's maximum length. + // If the message's length is greater than it, u should should return err in + // Reader{Read} and getty will close this connection soon. + // + // If ur logic processing in this func will take a long time, u should start a goroutine + // pool(like working thread pool in cpp) to handle the processing asynchronously. Or u + // can do the logic processing in other asynchronous way. + // !!!In short, ur OnMessage callback func should return asap. + // + // If this is a udp event listener, the second parameter type is UDPContext. + OnMessage(Session, interface{}) +} +``` + +通过对整个 getty 代码的分析,我们只要实现 `ReadWriter` 来对 RPC 消息编解码,再实现 `EventListener` 来处理 RPC 消息的对应的具体逻辑,将 `ReadWriter` 实现和 `EventLister` 实现注入到 RPC 的 Client 和 Server 端,则可实现 RPC 通信。 + +### 1)编解码协议实现 + +下面是 seata 协议的定义: + +![img](/imgs/blog/dubbo-go/seata/p2.webp) + +在 ReadWriter 接口的实现 `RpcPackageHandler` 中,调用 Codec 方法对消息体按照上面的格式编解码: + +``` +// 消息编码为二进制比特 +func MessageEncoder(codecType byte, in interface{}) []byte { + switch codecType { + case SEATA: + return SeataEncoder(in) + default: + log.Errorf("not support codecType, %s", codecType) + return nil + } +} + +// 二进制比特解码为消息体 +func MessageDecoder(codecType byte, in []byte) (interface{}, int) { + switch codecType { + case SEATA: + return SeataDecoder(in) + default: + log.Errorf("not support codecType, %s", codecType) + return nil, 0 + } +} +``` + +### 2)Client 端实现 + +再来看 client 端 `EventListener` 的实现 `RpcRemotingClient`: + +```go +func (client *RpcRemoteClient) OnOpen(session getty.Session) error { + go func() + request := protocal.RegisterTMRequest{AbstractIdentifyRequest: protocal.AbstractIdentifyRequest{ + ApplicationId: client.conf.ApplicationId, + TransactionServiceGroup: client.conf.TransactionServiceGroup, + }} + // 建立连接后向 Transaction Coordinator 发起注册 TransactionManager 的请求 + _, err := client.sendAsyncRequestWithResponse(session, request, RPC_REQUEST_TIMEOUT) + if err == nil { + // 将与 Transaction Coordinator 建立的连接保存在连接池供后续使用 + clientSessionManager.RegisterGettySession(session) + client.GettySessionOnOpenChannel <- session.RemoteAddr() + } + }() + + return nil +} + +// OnError ... +func (client *RpcRemoteClient) OnError(session getty.Session, err error) { + clientSessionManager.ReleaseGettySession(session) +} + +// OnClose ... +func (client *RpcRemoteClient) OnClose(session getty.Session) { + clientSessionManager.ReleaseGettySession(session) +} + +// OnMessage ... +func (client *RpcRemoteClient) OnMessage(session getty.Session, pkg interface{}) { + log.Info("received message:{%v}", pkg) + rpcMessage, ok := pkg.(protocal.RpcMessage) + if ok { + heartBeat, isHeartBeat := rpcMessage.Body.(protocal.HeartBeatMessage) + if isHeartBeat && heartBeat == protocal.HeartBeatMessagePong { + log.Debugf("received PONG from %s", session.RemoteAddr()) + } + } + + if rpcMessage.MessageType == protocal.MSGTYPE_RESQUEST || + rpcMessage.MessageType == protocal.MSGTYPE_RESQUEST_ONEWAY { + log.Debugf("msgId:%s, body:%v", rpcMessage.Id, rpcMessage.Body) + + // 处理事务消息,提交 or 回滚 + client.onMessage(rpcMessage, session.RemoteAddr()) + } else { + resp, loaded := client.futures.Load(rpcMessage.Id) + if loaded { + response := resp.(*getty2.MessageFuture) + response.Response = rpcMessage.Body + response.Done <- true + client.futures.Delete(rpcMessage.Id) + } + } +} + +// OnCron ... +func (client *RpcRemoteClient) OnCron(session getty.Session) { + // 发送心跳 + client.defaultSendRequest(session, protocal.HeartBeatMessagePing) +} +``` + +`clientSessionManager.RegisterGettySession(session)` 的逻辑将在下文中分析。 + +### 3)Server 端 Transaction Coordinator 实现 + +代码见 `DefaultCoordinator`: + +```go +func (coordinator *DefaultCoordinator) OnOpen(session getty.Session) error { + log.Infof("got getty_session:%s", session.Stat()) + return nil +} + +func (coordinator *DefaultCoordinator) OnError(session getty.Session, err error) { + // 释放 TCP 连接 + SessionManager.ReleaseGettySession(session) + session.Close() + log.Errorf("getty_session{%s} got error{%v}, will be closed.", session.Stat(), err) +} + +func (coordinator *DefaultCoordinator) OnClose(session getty.Session) { + log.Info("getty_session{%s} is closing......", session.Stat()) +} + +func (coordinator *DefaultCoordinator) OnMessage(session getty.Session, pkg interface{}) { + log.Debugf("received message:{%v}", pkg) + rpcMessage, ok := pkg.(protocal.RpcMessage) + if ok { + _, isRegTM := rpcMessage.Body.(protocal.RegisterTMRequest) + if isRegTM { + // 将 TransactionManager 信息和 TCP 连接建立映射关系 + coordinator.OnRegTmMessage(rpcMessage, session) + return + } + + heartBeat, isHeartBeat := rpcMessage.Body.(protocal.HeartBeatMessage) + if isHeartBeat && heartBeat == protocal.HeartBeatMessagePing { + coordinator.OnCheckMessage(rpcMessage, session) + return + } + + if rpcMessage.MessageType == protocal.MSGTYPE_RESQUEST || + rpcMessage.MessageType == protocal.MSGTYPE_RESQUEST_ONEWAY { + log.Debugf("msgId:%s, body:%v", rpcMessage.Id, rpcMessage.Body) + _, isRegRM := rpcMessage.Body.(protocal.RegisterRMRequest) + if isRegRM { + // 将 ResourceManager 信息和 TCP 连接建立映射关系 + coordinator.OnRegRmMessage(rpcMessage, session) + } else { + if SessionManager.IsRegistered(session) { + defer func() { + if err := recover(); err != nil { + log.Errorf("Catch Exception while do RPC, request: %v,err: %w", rpcMessage, err) + } + }() + // 处理事务消息,全局事务注册、分支事务注册、分支事务提交、全局事务回滚等 + coordinator.OnTrxMessage(rpcMessage, session) + } else { + session.Close() + log.Infof("close a unhandled connection! [%v]", session) + } + } + } else { + resp, loaded := coordinator.futures.Load(rpcMessage.Id) + if loaded { + response := resp.(*getty2.MessageFuture) + response.Response = rpcMessage.Body + response.Done <- true + coordinator.futures.Delete(rpcMessage.Id) + } + } + } +} + +func (coordinator *DefaultCoordinator) OnCron(session getty.Session) { + +} +``` + +`coordinator.OnRegTmMessage(rpcMessage, session)` 注册 Transaction Manager,`coordinator.OnRegRmMessage(rpcMessage, session)` 注册 Resource Manager。具体逻辑分析见下文。 + +消息进入 `coordinator.OnTrxMessage(rpcMessage, session)` 方法,将按照消息的类型码路由到具体的逻辑当中: + +```go +switch msg.GetTypeCode() { + case protocal.TypeGlobalBegin: + req := msg.(protocal.GlobalBeginRequest) + resp := coordinator.doGlobalBegin(req, ctx) + return resp + case protocal.TypeGlobalStatus: + req := msg.(protocal.GlobalStatusRequest) + resp := coordinator.doGlobalStatus(req, ctx) + return resp + case protocal.TypeGlobalReport: + req := msg.(protocal.GlobalReportRequest) + resp := coordinator.doGlobalReport(req, ctx) + return resp + case protocal.TypeGlobalCommit: + req := msg.(protocal.GlobalCommitRequest) + resp := coordinator.doGlobalCommit(req, ctx) + return resp + case protocal.TypeGlobalRollback: + req := msg.(protocal.GlobalRollbackRequest) + resp := coordinator.doGlobalRollback(req, ctx) + return resp + case protocal.TypeBranchRegister: + req := msg.(protocal.BranchRegisterRequest) + resp := coordinator.doBranchRegister(req, ctx) + return resp + case protocal.TypeBranchStatusReport: + req := msg.(protocal.BranchReportRequest) + resp := coordinator.doBranchReport(req, ctx) + return resp + default: + return nil + } +``` + +### 4)session manager 分析 + +Client 端同 Transaction Coordinator 建立连接起连接后,通过 `clientSessionManager.RegisterGettySession(session)` 将连接保存在 `serverSessions = sync.Map{}` 这个 map 中。map 的 key 为从 session 中获取的 RemoteAddress 即 Transaction Coordinator 的地址,value 为 session。这样,Client 端就可以通过 map 中的一个 session 来向 Transaction Coordinator 注册 Transaction Manager 和 Resource Manager 了。具体代码见 `getty_client_session_manager.go`。 + +Transaction Manager 和 Resource Manager 注册到 Transaction Coordinator 后,一个连接既有可能用来发送 TM 消息也有可能用来发送 RM 消息。我们通过 RpcContext 来标识一个连接信息: + +```go +type RpcContext struct { + Version string + TransactionServiceGroup string + ClientRole meta.TransactionRole + ApplicationId string + ClientId string + ResourceSets *model.Set + Session getty.Session +} +``` + +当收到事务消息时,我们需要构造这样一个 RpcContext 供后续事务处理逻辑使用。所以,我们会构造下列 map 来缓存映射关系: + +```go +var ( + // session -> transactionRole + // TM will register before RM, if a session is not the TM registered, + // it will be the RM registered + session_transactionroles = sync.Map{} + + // session -> applicationId + identified_sessions = sync.Map{} + + // applicationId -> ip -> port -> session + client_sessions = sync.Map{} + + // applicationId -> resourceIds + client_resources = sync.Map{} +) +``` + +这样,Transaction Manager 和 Resource Manager 分别通过 `coordinator.OnRegTmMessage(rpcMessage, session)` 和 `coordinator.OnRegRmMessage(rpcMessage, session)` 注册到 Transaction Coordinator 时,会在上述 client_sessions map 中缓存 applicationId、ip、port 与 session 的关系,在 client_resources map 中缓存 applicationId 与 resourceIds(一个应用可能存在多个 Resource Manager) 的关系。 + +在需要时,我们就可以通过上述映射关系构造一个 RpcContext。这部分的实现和 java 版 seata 有很大的不同,感兴趣的可以深入了解一下。具体代码见 `getty_session_manager.go`。 + +至此,我们就分析完了 seata-golang 整个 RPC 通信模型的机制。 + +### seata-golang 的未来 + +seata-golang 从今年 4 月份开始开发,到 8 月份基本实现和 java 版 seata 1.2 协议的互通,对 mysql 数据库实现了 AT 模式(自动协调分布式事务的提交回滚),实现了 TCC 模式,TC 端使用 mysql 存储数据,使 TC 变成一个无状态应用支持高可用部署。下图展示了 AT 模式的原理: + +![img](/imgs/blog/dubbo-go/seata/p3.webp) + +后续,还有许多工作可以做,比如:对注册中心的支持、对配置中心的支持、和 java 版 seata 1.4 的协议互通、其他数据库的支持、raft transaction coordinator 的实现等,希望对分布式事务问题感兴趣的开发者可以加入进来一起来打造一个完善的 golang 的分布式事务框架。如果你有任何疑问,欢迎钉钉扫码加入交流群【钉钉群号 33069364】: + +另外,欢迎对 dubbogo 感兴趣的朋友到 dubbogo 社区钉钉群(钉钉群号 31363295)沟通 dubbogo 技术问题。 + +### 参考资料 + +- seata 官方: https://seata.io +- java 版 seata: https://github.com/seata/seata +- seata-golang 项目地址: https://github.com/opentrx/seata-golang +- seata-golang go 夜读 b 站分享: https://www.bilibili.com/video/BV1oz411e72T + +> 作者简介 +> +> **刘晓敏** (GitHubID dk-lockdown),目前就职于 h3c 成都分公司,擅长使用 Java/Go 语言,在云原生和微服务相关技术方向均有涉猎,目前专攻分布式事务。 +> **于雨**((github @AlexStocks),dubbo-go 项目和社区负责人,一个有十多年服务端基础架构研发一线工作经验的程序员,陆续参与改进过 Muduo/Pika/Dubbo/Sentinel-go 等知名项目,目前在蚂蚁金服可信原生部从事容器编排和 service mesh 工作。 diff --git a/content/en/blog/golang/dubbo-go-sentinel.md b/content/en/blog/golang/dubbo-go-sentinel.md new file mode 100644 index 000000000000..757a20c39abc --- /dev/null +++ b/content/en/blog/golang/dubbo-go-sentinel.md @@ -0,0 +1,162 @@ +--- +title: "在dubbo-go中使用sentinel" +linkTitle: "在dubbo-go中使用sentinel" +tags: ["Go"] +date: 2021-01-11 +description: 本文介绍了如何在 dubbo-go 中使用限流组件 sentinel +--- + + +时至今日,Apache/dubbo-go(以下简称 dubbo-go )项目在功能上已经逐步对齐java版本,稳定性也在不同的生产环境得到了验证。社区便开始再服务治理、监控等方向发力。随着 1.2和1.3 版本发布, dubbo-go 新增了大量此类新feature。 + +今天我们聊一聊限流相关话题,此前dubbo-go已经支持了[tps limit](https://github.com/apache/dubbo-go/pull/237)、[execute limit ](https://github.com/apache/dubbo-go/pull/246)、[hystrix](https://github.com/apache/dubbo-go/pull/133) 的内置filter,用户只要简单配置就能马上用上。但我们知道,在 java 的 dubbo 生态中,有一项限流工具被广泛使用,那就是sentinel。sentinel因为强大的动态规划配置、优秀的dashboard以及对dubbo的良好适配,成为众多使用dubbo的企业选用限流工具的不二之选。 + +就在前些日子,社区非常高兴得知 Sentinel Golang 首个版本 0.1.0 正式发布,这使得 dubbo-go也可以使用 sentinel 作为工具进行一些服务治理、监控的工作了。随着sentinel golang的健壮,我们相信用户马上可以像sentinel管理java dubbo服务那样管理dubbo-go的服务了。 + +完成sentinel golang的dubbo-adapter其实非常简单,这得益于dubbo-go早就完成了filter链的构造,用户可以自定义filter,并且灵活的安排其执行顺序。在1.3发布后,增加了filter中的context传递,构建sentinel/adapter/dubbo更为方便。 + +我们以其中的provider filter适配为例: + +![img](/imgs/blog/dubbo-go/sentinel/dubbo-go-sentinel-provider-filter.png) + +此 filter 实现了 dubbo-go的filter接口,只要用户在服务启动时将此filter加载到dubbo-go中,即可使用此filter。 + +![img](/imgs/blog/dubbo-go/sentinel/sentinel-golang.png) + +sentinel实现原理与其他限流、熔断库大同小异,底层是用的滑动窗口算法。与hystrix等框架相比不同点是设计理念,Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。 + +下面我整理了完整的使用流程:(注意:dubbo-go版本请使用1.3.0-rc3及其以上版本) + +在dubbo-go中使用sentinel主要分为以下几步: + +1. 初始化sentinel +2. 将sentinel注入dubbo-go的filter +3. 初始化dubbo-go +4. 配置规划 + +## 初始化sentinel + +示例代码: + +```go +import ( + sentinel "github.com/alibaba/sentinel-golang/api" +) + +func initSentinel() { + err := sentinel.InitWithLogDir(confPath, logDir) + if err != nil { + // 初始化 Sentinel 失败 + } +} +``` + +## 将sentinel注入dubbo-go的filter + +你可以通过import包的形式执行,执行其中的init()来注入filter + +```go +import ( + _ "github.com/alibaba/sentinel-golang/adapter/dubbo" +) +``` + +也可以手动执行,给你的filter取上自己想要的名字 + +```go +import ( + "github.com/apache/dubbo-go/common/extension" + sd "github.com/alibaba/sentinel-golang/adapter/dubbo" +) + +func main(){ + extension.SetFilter("myConsumerFilter",sd.GetConsumerFilter()) + extension.SetFilter("myProviderFilter",sd.GetConsumerFilter()) +} +``` + +完成以上步骤,你就可以在需要的dubbo接口配置里写入sentinel的filterName,构建起接口的filter链条。比如以下以consumer.yml配置文件为例 + +```yml +references: + "UserProvider": + registry: "hangzhouzk" + protocol : "dubbo" + interface : "com.ikurento.user.UserProvider" + cluster: "failover" + filter: "myConsumerFilter" + methods : + - name: "GetUser" + retries: 3 +``` + +## 初始化dubbo-go + +到这一步,你只需要正常启动dubbo-go程序就完成了服务启动。用以下代码做一个较为完整举例 + +```go +import ( + hessian "github.com/apache/dubbo-go-hessian2" + sd "github.com/alibaba/sentinel-golang/adapter/dubbo" +) + +import ( + "github.com/apache/dubbo-go/common/logger" + _ "github.com/apache/dubbo-go/common/proxy/proxy_factory" + "github.com/apache/dubbo-go/config" + _ "github.com/apache/dubbo-go/filter/impl" + _ "github.com/apache/dubbo-go/protocol/dubbo" + _ "github.com/apache/dubbo-go/registry/protocol" + + _ "github.com/apache/dubbo-go/cluster/cluster_impl" + _ "github.com/apache/dubbo-go/cluster/loadbalance" + _ "github.com/apache/dubbo-go/registry/zookeeper" + "github.com/apache/dubbo-go/common/extension" +) + +func main() { + + hessian.RegisterPOJO(&User{}) + extension.SetFilter("myConsumerFilter",sd.GetConsumerFilter()) + extension.SetFilter("myProviderFilter",sd.GetConsumerFilter()) + config.Load() + + // init finish, do your work + test() +} +``` + +## 规划配置 + +sentinel以强大的规划配置吸引了很多使用者,其提供动态数据源接口进行扩展,用户可以通过动态文件或 etcd 等配置中心来动态地配置规则。但目前sentinel-golang作为破蛋版本,动态配置还在开发中 + +### 动态数据源 + +(开发中)Sentinel 提供动态数据源接口进行扩展,用户可以通过动态文件或 etcd 等配置中心来动态地配置规则。 + +### 硬编码方式 + +Sentinel 也支持原始的硬编码方式加载规则,可以通过各个模块的 `LoadRules(rules)` 方法加载规则。以下是硬编码方式对某个method在consumer端的QPS流控: + +```go +_, err := flow.LoadRules([]*flow.FlowRule{ + { + ID: 666, + Resource: "dubbo:consumer:com.ikurento.user.UserProvider:myGroup:1.0.0:hello()", + MetricType: flow.QPS, + Count: 10, + ControlBehavior: flow.Reject, + }, +}) +if err != nil { + // 加载规则失败,进行相关处理 +} +``` + +# 总结 + +更加具体的实现,我就不详细论述,大家可以去看源码进一步了解。 + +最后,欢迎大家持续关注,或者贡献代码,期待dubbo-go在2020年在云原生领域继续突破。 + +dubbo-go仓库地址:https://github.com/apache/dubbo-go diff --git a/content/en/blog/golang/dubbo-go-tps.md b/content/en/blog/golang/dubbo-go-tps.md new file mode 100644 index 000000000000..9fb21a0b9c8c --- /dev/null +++ b/content/en/blog/golang/dubbo-go-tps.md @@ -0,0 +1,220 @@ +--- +title: "Dubbo Go 中的 TPS Limit 设计与实现" +linkTitle: "dubbo-go tps limit" +tags: ["Go"] +date: 2021-01-11 +description: 本文记录了 flycash 对 Dubbo Go 中 TPS Limit 的设计与实现,原文出处:https://www.jianshu.com/p/5e4d490f163c +--- + +# 前言 + +[Apache Dubbo](https://links.jianshu.com/go?to=http%3A%2F%2Fdubbo.apache.org%2Fen-us%2F)是由阿里开源的一个RPC框架,除了基本的RPC功能以外,还提供了一整套的服务治理相关功能。目前它已经是Apache基金会下的顶级项目。 + +而[dubbogo](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fapache%2Fdubbo-go)则是dubbo的go语言实现。 + +最近在`dubbogo`的`todo list`上发现,它还没有实现`TPS Limit`的模块,于是就抽空实现了这个部分。 + +`TPS limit`实际上就是限流,比如说限制一分钟内某个接口只能访问200次,超过这个次数,则会被拒绝服务。在`Dubbo`的Java版本上,只有一个实现,就是`DefaultTPSLimiter`。 + +`DefaultTPSLimiter`是在服务级别上进行限流。虽然`dubbo`的官方文档里面声称可以在`method`级别上进行限流,但是我看了一下它的源码,实际上这个是做不到的。当然,如果自己通过实现`Filter`接口来实现`method`级别的限流,那么自然是可以的——这样暴露了`dubbo`Java版本实现的另外一个问题,就是`dubbo`的`TpsLimitFilter`实现,是不允许接入自己`TpsLimiter`的实现的。这从它的源码也可以看出来: + +![img](/imgs/blog/dubbo-go/tps-limit-filter.png) + +它直接写死了`TpsLimiter`的实现。 + +这个实现的目前只是合并到了`develop`上,等下次发布正式版本的时候才会发布出来。 + +Github: [https://github.com/apache/dubbo-go/pull/237](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fapache%2Fdubbo-go%2Fpull%2F237) + +# 设计思路 + +于是我大概参考了一下`dubbo`已有的实现,做了一点改进。 + +`dubbo`里面的核心抽象是`TpsLimiter`接口。`TpsLimitFilter`只是简单调用了一下这个接口的方法而已: + +![img](/imgs/blog/dubbo-go/tps-limiter.png) + +这个抽象是很棒的。但是还欠缺了一些抽象。 + +实际上,一个TPS Limit就要解决三个问题: + +1. 对什么东西进行`limit`。比如说,对服务进行限流,或者对某个方法进行限流,或者对IP进行限流,或者对用户进行限流; +2. 如何判断已经`over limitation`。这是从算法层面上考虑,即用什么算法来判断某个调用进来的时候,已经超过配置的上限了; +3. 被拒绝之后该如何处理。如果一个请求被断定为已经`over limititation`了,那么该怎么处理; + +所以在`TpsLimiter`接口的基础上,我再加了两个抽象: + +```golang +type TpsLimiter interface { + // IsAllowable will check whether this invocation should be enabled for further process + IsAllowable(*common.URL, protocol.Invocation) bool +} +``` + +```golang +type TpsLimitStrategy interface { + // IsAllowable will return true if this invocation is not over limitation + IsAllowable() bool +} +``` + +```golang +type RejectedExecutionHandler interface { + // RejectedExecution will be called if the invocation was rejected by some component. + RejectedExecution(url *common.URL, invocation protocol.Invocation) protocol.Result +} +``` + +`TpsLimiter`对应到Java的`TpsLimiter`,两者是差不多。在我的设想里面,它既是顶级入口,还需要承担解决第一个问题的职责。 + +而`TpsLimitStrategy`则是第二个问题的抽象的接口定义。它代表的是纯粹的算法。该接口完全没有参数,实际上,所有的实现需要维护自身的状态——对于大部分实现而言,它大概只需要获取一下系统时间戳,所以不需要参数。 + +最后一个接口`RejectedExecutionHandler`代表的是拒绝策略。在`TpsLimitFilter`里面,如果它调用`TpsLimiter`的实现,发现该请求被拒绝,那么就会使用该接口的实现来获取一个返回值,返回给客户端。 + +# 实现 + +其实实现没太多好谈的。不过有一些微妙的地方,我虽然在代码里面注释了,但是我觉得在这里再多说一点也是可以的。 + +首先提及的就是拒绝策略`RejectedExecutionHandler`,我就是提供了一种实现,就是随便log了一下,什么都没做。因为这个东西是强业务相关的,我也不能提供更加多的通用的实现。 + +## 方法与服务双重支持的TpsLimiter + +`TpsLimiter`我只有一个实现,那就是`MethodServiceTpsLimiterImpl`。它就是根据配置,如果方法级别配置了参数,那么会在方法级别上进行限流。否则,如果在服务级别(ServiceKey)上有配置,那么会在服务级别进行限流。 + +举个最复杂的例子:服务A限制100,有四个方法,方法M1配置限制40,方法M2和方法M3无配置,方法M4配置限制-1:那么方法M1会单独限流40;M2和M3合并统计,被限制在100;方法M4则会被忽略。 + +用户可以配置具体的算法。比如说使用我接下来说的,我已经实现的三种实现。 + +## FixedWindow和ThreadSafeFixedWindow + +`FixedWindow`直接对应到Java的`DefaultTpsLimiter`。它采用的是`fixed-window`算法:比如说配置了一分钟内只能调用100次。假如从00:00开始计时,那么00:00-01:00内,只能调用100次。只有到达01:00,才会开启新的窗口01:00-02:00。如图: + +![img](/imgs/blog/dubbo-go/fixed-window.png) + +Fixed-Window 实现 + +```golang +// IsAllowable determines if the requests over the TPS limit within the interval. +// It is not thread-safe. +func (impl *FixedWindowTpsLimitStrategyImpl) IsAllowable() bool { + + current := time.Now().UnixNano() + if impl.timestamp+impl.interval < current { + // it's a new window + // if a lot of threads come here, the count will be set to 0 several times. + // so the return statement will be wrong. + impl.timestamp = current + impl.count = 0 + } + // this operation is thread-safe, but count + 1 may be overflow + return atomic.AddInt32(&impl.count, 1) <= impl.rate +} +``` + +这里有一个很有意思的地方。就是这个实现,是一个几乎线程安全但是其实并不是线程安全的实现。 + +在所有的实现里面,它是最为简单,而且性能最高的。我在衡量了一番之后,还是没把它做成线程安全的。事实上,Java版本的也不是线程安全的。 + +它只会在多个线程通过第67行的检测之后,才会出现并发问题,这个时候就不是线程安全了。但是在最后的`return`语句中,那一整个是线程安全的。它因为不断计数往上加,所以多个线程同时跑到这里,其实不会有什么问题。 + +现在我要揭露一个最为奇诡的特性了:**并发越高,那么这个`raise condition`就越严重,也就是说越不安全。** + +但是从实际使用角度而言,有极端TPS的还是比较少的。对于那些TPS只有几百每秒的,是没什么问题的。 + +**为了保持和dubbo一致的特性,我把它作为默认的实现。** + +此外,我还为它搞了一个线程安全版本,也就是`ThreadSafeFixedWindowTpsLimitStrategyImpl`,只是简单的用`sync`封装了一下,可以看做是一个`Decorator`模式的应用。 + +如果强求线程安全,可以考虑使用这个。 + +## SlidingWindow + +这是我比较喜欢的实现。它跟网络协议里面的滑动窗口算法在理念上是比较接近的。 + +![img](/imgs/blog/dubbo-go/sliding-window.png) + +具体来说,假如我设置的同样是一分钟1000次,它统计的永远是从当前时间点往前回溯一分钟内,已经被调用了多少次。如果这一分钟内,调用次数没超过1000,请求会被处理,如果已经超过,那么就会拒绝。 + +我再来描述一下,`SldingWindow`和`FixedWindow`两种算法的区别。这两者很多人会搞混。假如当前的时间戳是00:00,两个算法同时收到了第一个请求,开启第一个时间窗口。 + +那么`FixedWindow`就是00:00-01:00是第一个窗口,接下来依次是01:00-02:00, 02:00-03:00, ...。当然假如说01:00之后的三十秒内都没有请求,在01:31又来了一个请求,那么时间窗口就是01:31-02:31。 + +而`SildingWindow`则没有这种概念。假如在01:30收到一个请求,那么`SlidingWindow`统计的则是00:30-01:30内有没有达到1000次。**它永远计算的都是接收到请求的那一刻往前回溯一分钟的请求数量。** + +如果还是觉得有困难,那么简单来说就是`FixedWindow`往后看一分钟,`SlidingWindow`回溯一分钟。 + +> 这个说法并不严谨,只是为了方便理解。 + +在真正写这个实现的时候,我稍微改了一点点: + +```golang +// IsAllowable determins whether the number of requests within the time window overs the threshold +// It is thread-safe. +func (impl *SlidingWindowTpsLimitStrategyImpl) IsAllowable() bool { + impl.mutex.Lock() + defer impl.mutex.Unlock() + // quick path + size := impl.queue.Len() + current := time.Now().UnixNano() + if size < impl.rate { + impl.queue.PushBack(current) + return true + } + + // slow path + boundary := current - impl.interval + + timestamp := impl.queue.Front() + // remove the element that out of the window + for timestamp != nil && timestamp.Value.(int64) < boundary { + impl.queue.Remove(timestamp) + timestamp = impl.queue.Front() + } + if impl.queue.Len() < impl.rate { + impl.queue.PushBack(current) + return true + } + return false +} +``` + +我用了一个队列来保存每次访问的时间戳。一般的写法,都是请求进来,先把已经不在窗口时间内的时间戳删掉,然后统计剩下的数量,也就是后面的`slow path`的那一堆逻辑。 + +但是我改了的一点是,我进来直接统计队列里面的数量——也就是请求数量,如果都小于上限,那么我可以直接返回`true`。即`quick path`。 + +这种改进的核心就是:我只有在检测到当前队列里面有超过上限数量的请求数量时候,才会尝试删除已经不在窗口内的时间戳。 + +这其实就是,是每个请求过来,我都清理一下队列呢?还是只有队列元素超出数量了,我才清理呢?我选择的是后者。 + +我认为这是一种改进……当然从本质上来说,整体开销是没有减少的——因为`golang`语言里面`List`的实现,一次多删除几个,和每次删除一个,多删几次,并没有多大的区别。 + +### 算法总结 + +无论是`FixedWindow`算法还是`SlidingWindow`算法都有一个固有的缺陷,就是这个时间窗口难控制。 + +我们设想一下,假如说我们把时间窗口设置为一分钟,允许1000次调用。然而,在前十秒的时候就调用了1000次。在后面的五十秒,服务器虽然将所有的请求都处理完了,然是因为窗口还没到新窗口,所以这个时间段过来的请求,全部会被拒绝。 + +![img](/imgs/blog/dubbo-go/busy-idle-time-window.png) + +解决的方案就是调小时间窗口,比如调整到一秒。但是时间窗口的缩小,会导致`FixedWindow`算法的`raise condition`情况加剧。`SlidingWindow`也会受影响,但是影响要小很多。 + +## 那些没有实现的 + +### 基于特定业务对象的限流 + +举例来说,某些特殊业务用的针对用户ID进行限流和针对IP进行限流,我就没有在`dubbogo`里面实现。有需要的可以通过实现`TpsLimiter`接口来完成。 + +### 全局TPS limit + +这篇文章之前讨论的都是单机限流。如果全局限流,比如说针对某个客户,它购买的服务是每分钟调用100次,那么就需要全局限流——虽然这种case都不会用`Filter`方案,而是另外做一个`API`接入控制。 + +比如说,很常用的使用Redis进行限流的。针对某个客户,一分钟只能访问100次,那我就用客户ID做key,value设置成List,每次调用过来,随便塞一个值进去,设置过期时间一分钟。那么每次统计只需要统计当前key的存活的值的数量就可以了。 + +这种我也没实现,因为好像没什么需求。国内讨论TPS limit都是讨论单机TPS limit比较多。 + +这个同样可以通过实现`TpsLimiter`接口来实现。 + +### Leaky Bucket算法 + +这个本来可以是`TpsLimitStrategy`的一种实现的。后来我觉得,它其实并没有特别大的优势——虽然号称可以做到均匀,但是其实并做不到真正的均匀。通过调整`SlidingWindow`的窗口大小,是可以接近它宣称的均匀消费的效果的。比如说调整到一秒,那其实就已经很均匀了。而这并不会带来多少额外的开销。 + diff --git a/content/en/blog/golang/dubbo-go-trusted-call.md b/content/en/blog/golang/dubbo-go-trusted-call.md new file mode 100644 index 000000000000..4155de9f2ab3 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-trusted-call.md @@ -0,0 +1,138 @@ +--- +title: "dubbo-go 可信调用实现" +linkTitle: "dubbo-go 可信调用实现" +tags: ["Go"] +date: 2021-01-14 +description: > + 本文将讲解如何在 Dubbo/Dubbo-Go 中实现灵活,安全和高效的身份验证和授权方案。 +--- + +Apache Dubbo/Dubbo-Go 作为阿里巴巴开源的一款服务治理框架,因其适应 Java/Go 开发者面向接口的编程习惯、完全透明的调用方式、优越的性能以及强大的扩展性等优点,在国内使用非常广泛。除此之外,Dubbo 开源版本原生集成了很多开箱即用的服务治理功能,包括链路追踪,路由、负载均衡、服务注册发现、监控、认证等。 + +本文将讲解如何在 Dubbo/Dubbo-Go 中实现灵活,安全和高效的身份验证和授权方案。 + +## 可信的目的 + +为什么需要鉴权认证?实际生产中类似支付之类的安全性敏感的业务会有限制匿名系统调用的需求,其他业务在接入该类敏感业务之前,需要通过审批方可正常调用,这就需要对这类敏感服务进行权限管控。尽管 Dubbo 开源版本中支持 Token 方式的鉴权实现,但是该实现方式总体来说安全性并不高,并且无法满足我们需要动态下发以及变更的灵活性需求。 + +针对于此,我们内部着重从巩固安全性和拓展灵活性层面重新设计了一套 Dubbo/Dubbo-Go 的服务间调用的鉴权认证功能。本文我们将主要从实现层面讲解其大致实现思路。 + +## 可信方案 + +抽象来看鉴权认证主要围绕以下两个问题, + +- 身份认证:指验证应用的身份,每个应用在其生命周期内只有唯一身份,无法变更和伪造。 +- 权限鉴定:根据身份信息鉴定权限是否满足调用。权限粒度可以进行控制。 + +我们通过 Access Key ID/Secret Access Key (后文简称为 AK/SK) 信息标识应用和应用之间的身份关系。例如上游 应用A 依赖下游 服务B 和 C,则 A 对 B 和 C 分别有一套 AK/SK。其相互独立没有任何关系。就算 A服务 的 AK/SK 信息泄漏,也无法通过该 AK/SK 信息调用其他的服务。 + +在权限鉴定方面也借鉴了公有云开放 API 常用的 AK/SK 签名机制。 在请求过程中使用 SK 签名生成 SigningKey,并通过 Dubbo 的 attachment 机制将额外的元数据信息以及 SigningKey 传输到服务端,交由服务端计算和验签,验签通过方能正常处理和响应。 + +签名过程主要通过如下三个方式进行加强 SigningKey 的可靠性和安全性。 + +- 验证请求者的身份 + + 签名会通过对应应用的SK作为加密密钥对请求元数据(以及参数)进行加密,保证签名的唯一性和不可伪造性。 +- 支持对参数进行计算签名,防止非法篡改 + + 若请求参数在传输过程中遭到非法篡改,则收到请求后服务端验签匹配将失败,身份校验无法通过,从而防止请求参数被篡改。考虑到签名以及验签过程中加入请求参数的计算可能会影响性能,所以这个过程是可选的。 +- 防止重放攻击 + + 每一次请求生成的SigningKey都具有指定的有效时间。如请求被截获,该请求无法在有效时间外进行调用。一定程度避免了重放攻击。 + +同时为了去掉明文配置,防止AK/SK信息泄漏,我们通过鉴权系统分发和管理所有AK/SK信息。并且通过对接内部审批流程,达到流程化和规范化。需要鉴权的应用会通过启动获取的方式拉当前应用分发出去或者是已被授权的AK/SK信息。这种方式也带来了另一种好处,新增、吊销以及更新权限信息也无需重启应用。 + +## 可信流程 + +结合上面的这些需求和方案,整个接入和鉴权流程图如下所示: + +![img](/imgs/blog/dubbo-go/trusted-call/process.png) + +整体流程如下: + +1. 使用该功能的应用需要提前申请对应的证书,并向提供服务的应用提交申请访问工单,由双方负责人审批通过后,请求鉴权服务中心自动生成键值对。 +1. 除此之外,开启鉴权认证的服务在应用启动之后,会运行一个后台线程,长轮询远鉴权服务中心,查询是否有新增权限变动信息,如果有则进行全量/增量的拉取。 +1. 上游应用在请求需要鉴权的服务时,会通过SK作为签名算法的 key,对本次请求的元数据信息甚至是参数信息进行计算得到签名,通过 Dubbo协议 Attachment字段 传送到对端,除此之外还有请求时间戳、AK信息等信息。 +1. 下游应用在处理鉴权服务时会对请求验签,验签通过则继续处理请求,否则直接返回异常。 + +其中需要说明的是第三步,使用鉴权服务的应用和鉴权服务中心的交互需通过 HTTPS 的双向认证,并在 TLS 信道上进行数据交互,保证 AK/SK 信息传输的安全性。 + +该方案目前已经有 Java/Go 实现,均已合并到 dubbo/dubbo-go。除了默认的 Hmac 签名算法实现之外,我们将签名和认证方法进行抽象,以Dubbo Go中的实现为例。 + +```go +// Authenticator +type Authenticator interface { + + // Sign + // give a sign to request + Sign(protocol.Invocation, *common.URL) error + + // Authenticate + // verify the signature of the request is valid or not + Authenticate(protocol.Invocation, *common.URL) error +} +``` + +使用者可通过 SPI 机制定制签名和认证方式,以及适配公司内部基础设施的密钥服务下发 AK/SK。 + +## 示例 + +以 [Helloworld 示例](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/helloworld/) 中的代码接入当前社区版本中的默认鉴权认证功能实现为例: + +在无需改变代码的情况下,只需要在配置上增加额外的相关鉴权配置即可,dubbo-go 服务端配置示例如下: + +```yaml +services: + "UserProvider": + # 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册 + registry: "hangzhouzk" + protocol : "dubbo" + # 相当于dubbo.xml中的interface + interface : "com.ikurento.user.UserProvider" + loadbalance: "random" + # 本服务开启auth + auth: "true" + # 启用auth filter,对请求进行验签 + filter: "auth" + # 默认实现通过配置文件配置AK、SK + params: + .accessKeyId: "SYD8-23DF" + .secretAccessKey: "BSDY-FDF1" + warmup: "100" + cluster: "failover" + methods: + - name: "GetUser" + retries: 1 + loadbalance: "random" +``` + +dubbo-go 客户端配置示例如下: + +```yaml +references: + "UserProvider": + # 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册 + registry: "hangzhouzk" + protocol: "dubbo" + interface: "com.ikurento.user.UserProvider" + cluster: "failover" + # 本服务开启sign filter,需要签名 + filter: "sign" + # 默认实现通过配置文件配置AK、SK + params: + .accessKeyId: "SYD8-23DF" + .secretAccessKey: "BSDY-FDF1" + methods: + - name: "GetUser" + retries: 3 +``` + +可以看到,dubbo-go 接入鉴权认证的功能也十分简单。需要补充说明的是,配置文件文件中 ak/sk 都加了特殊前缀 ".",是为了说明该字段是敏感信息,不能在发起网络请求时传输出去,相关代码可参阅 [dubbo-go-pr-509](https://github.com/apache/dubbo-go/pull/509)。 + +## 总结 + +Apache Dubbo 作为一款老而弥新的服务治理框架,无论是其自身还是其生态都还在飞速进化中。本文描述的最新实现的可信服务调用,是为了避免敏感接口被匿名用户调用而在 SDK 层面提供的额外保障,在 RPC 层面保障安全性。 + +Dubbo-Go 作为 Dubbo 生态中发展最快的成员,目前基本上保持与 Dubbo 齐头并进的态势。Dubbo-Go 社区钉钉群号为 23331795, 欢迎你的加入。 + +> 作者信息: 郑泽超,Apache Dubbo/Dubbo-Go committer,GithubID: CodingSinger,目前就职于上海爱奇艺科技有限公司,Java/Golang 开发工程师。 diff --git a/content/en/blog/golang/dubbo-go-tuya.md b/content/en/blog/golang/dubbo-go-tuya.md new file mode 100644 index 000000000000..8464041f2a51 --- /dev/null +++ b/content/en/blog/golang/dubbo-go-tuya.md @@ -0,0 +1,285 @@ +--- +title: "涂鸦智能 dubbo-go 亿级流量的实践与探索" +linkTitle: "涂鸦智能 dubbo-go 亿级流量的实践与探索" +tags: ["Go", "用户案例"] +date: 2021-01-14 +description: > + 本文分为实践和快速接入两部分,分享在涂鸦智能的 dubbo-go 实战经验 +--- + +dubbo 是一个基于 Java 开发的高性能的轻量级 RPC 框架,dubbo 提供了丰富的服务治理功能和优秀的扩展能力。而 dubbo-go 在 java 与 golang 之间提供统一的服务化能力与标准,是涂鸦智能目前最需要解决的主要问题。本文分为实践和快速接入两部分,分享在涂鸦智能的 [dubbo-go](http://github.com/apache/dubbo-go) 实战经验,意在帮助用户快速接入 dubbo-go RPC 框架,希望能让大家少走些弯路。 + +另外,文中的测试代码基于 dubbo-go版本 [v1.4.0](https://github.com/apache/dubbo-go/releases/tag/v1.4.0)。 + +## dubbo-go 网关实践 + +![img](/imgs/blog/dubbo-go/tuya/p1.png) + +dubbo-go 在涂鸦智能的使用情况如上图,接下来会为大家详细介绍落地细节,希望这些在生产环境中总结的经验能够帮助到大家。 + +### 背景 + +在涂鸦智能,dubbo-go 已经作为了 golang 服务与原有 dubbo 集群打通的首选 RPC 框架。其中比较有代表性的 open-gateway 网关系统(下文统一称 gateway,开源版本见 https://github.com/dubbogo/dubbo-go-proxy)。该 gateway 动态加载内部 dubbo 接口信息,以HTTP API 的形式对外暴露。该网关意在解决上一代网关的以下痛点。 + +- `通过页面配置 dubbo 接口开放规则,步骤繁琐,权限难以把控。` +- `接口非 RESTful 风格,对外部开发者不友好。` +- `依赖繁重,升级风险大。` +- `并发性能问题。` + +### 架构设计 + +针对如上痛点,随即着手准备设计新的 gateway 架构。首先就是语言选型,golang 的协程调用模型使得 golang 非常适合构建 IO 密集型的应用,且应用部署上也较 java 简单。经过调研后我们敲定使用 golang 作为 proxy 的编码语言,并使用 dubbo-go 用于连接 dubbo provider 集群。provider 端的业务应用通过使用 java 的插件,以注解形式配置 API 配置信息,该插件会将配置信息和 dubbo 接口元数据更新到元数据注册中心(下图中的 redis )。这样一来,配置从管理后台页面转移到了程序代码中。开发人员在编码时,非常方便地看到 dubbo 接口对外的 API 描述,无需从另外一个管理后台配置 API 的使用方式。 + +![img](/imgs/blog/dubbo-go/tuya/p2.png) + +### 实践 + +从上图可以看到,网关能动态加载 dubbo 接口信息,调用 dubbo 接口是基于 dubbo 泛化调用。泛化调用使 client 不需要构建 provider 的 interface 代码,在 dubbo-go 中表现为无需调用 config.SetConsumerService 和 hessian.RegisterPOJO 方法,而是将请求模型纯参数完成,这使得 client 动态新增、修改接口成为可能。在 [apache/dubbo-sample/golang/generic/default/go-client](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/generic/default/go-client) 中的有泛化调用的演示代码。 + +```go +func test() { + var appName = "UserProviderGer" + var referenceConfig = config.ReferenceConfig{ + InterfaceName: "com.ikurento.user.UserProvider", + Cluster: "failover", + Registry: "hangzhouzk", + Protocol: dubbo.DUBBO, + Generic: true, + } + referenceConfig.GenericLoad(appName) // appName is the unique identification of RPCService + + time.Sleep(3 * time.Second) + + resp, err := referenceConfig.GetRPCService().(*config.GenericService). + Invoke([]interface{}{"GetUser", []string{"java.lang.String"}, []interface{}{"A003"}}) + if err != nil { + panic(err) + } +} +``` + +泛化调用的实现其实相当简单。其功能作用在 dubbo 的 Filter 层中。[Generic Filter](https://github.com/apache/dubbo-go/blob/master/filter/generic/filter.go) 已经作为默认开启的 Filter 加入到 dubbo Filter 链中。其核心逻辑如下: + +```go +func (ef *GenericFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { + if invocation.MethodName() == constant.GENERIC && len(invocation.Arguments()) == 3 { + oldArguments := invocation.Arguments() + + if oldParams, ok := oldArguments[2].([]interface{}); ok { + newParams := make([]hessian.Object, 0, len(oldParams)) + for i := range oldParams { + newParams = append(newParams, hessian.Object(struct2MapAll(oldParams[i]))) + } + newArguments := []interface{}{ + oldArguments[0], + oldArguments[1], + newParams, + } + newInvocation := invocation2.NewRPCInvocation(invocation.MethodName(), newArguments, invocation.Attachments()) + newInvocation.SetReply(invocation.Reply()) + return invoker.Invoke(ctx, newInvocation) + } + } + return invoker.Invoke(ctx, invocation) +} +``` + +Generic Filter 将用户请求的结构体参数转化为统一格式的 map(代码中的 struct2MapAll ),将类( golang 中为 struct )的正反序列化操作变成 map 的正反序列化操作。这使得无需 POJO 描述通过硬编码注入 hessain 库。 + +从上面代码可以看到,泛化调用实际需要动态构建的内容有 4 个,ReferenceConfig 中需要的 InterfaceName 、参数中的 method 、ParameterTypes、实际入参 requestParams。 + +**那么这些参数是如何从 HTTP API 匹配获取到的呢?** + +这里就会用到上文提到的 provider 用于收集元数据的插件。引入插件后,应用在启动时会扫描需要暴露的 dubbo 接口,将 dubbo 元数据和 HTTP API 关联。插件使用方法大致如下,这里调了几个简单的配置作为示例,实际生产时注解内容会更多。 + +![img](/imgs/blog/dubbo-go/tuya/p3.png) + +最终获得的 dubbo 元数据如下: + +```json +{ + "key": "POST:/hello/{uid}/add", + "interfaceName": "com.tuya.hello.service.template.IUserServer", + "methodName": "addUser", + "parameterTypes": ["com.tuya.gateway.Context", "java.lang.String", "com.tuya.hello.User"], + "parameterNames": ["context", "uid", "userInfo"], + "updateTimestamp": "1234567890", + "permissionDO":{}, + "voMap": { + "userInfo": { + "name": "java.lang.String", + "sex": "java.lang.String", + "age": "java.lang.Integer" + } + }, + "parameterNameHumpToLine": true, + "resultFiledHumpToLine": false, + "protocolName": "dubbo", + ....... +} +``` +Gateway 从元数据配置中心订阅到以上信息,就能把一个 API 请求匹配到一个 dubbo 接口。再从 API 请求中抓取参数作为入参。这样功能就完成了流量闭环。 + +以上内容,大家应该对此 gateway 的项目拓扑结构有了清晰的认知。我接着分享项目在使用 dubbo-go 过程中遇到的问题和调优经验。19 年初,当时的 dubbo-go 项目还只是构建初期,没有什么用户落地的经验。我也是一边参与社区开发,一边编码公司内部网关项目。在解决了一堆 hessain 序列化和 zookeeper 注册中心的问题后,项目最终跑通了闭环。但是,作为一个核心应用,跑通闭环离上生产环境还有很长的路要走,特别是使用了当时稳定性待测试的新框架。整个测试加上功能补全,整整花费了一个季度的时间,直到项目趋于稳定,压测效果也良好。**单台网关机器( 2C 8G )全链路模拟真实环境压测达到 2000 QPS。由于引入了比较重的业务逻辑(单个请求平均调用 3 个 dubbo 接口),对于这个压测结果,是符合甚至超出预期的。** + +总结了一些 dubbo-go 参数配置调优的经验,主要是一些网络相关配置。大家在跑 demo 时,应该会看到配置文件最后有一堆配置,但如果对 dubbo-go 底层网络模型不熟悉,就很难理解这些配置的含义。目前 dubbo-go 网络层以 [getty](https://github.com/AlexStocks/getty) 为底层框架,实现读写分离和协程池管理。getty 对外暴露 session 的概念,session 提供一系列网络层方法注入的实现,因为本文不是源码解析文档,在这里不过多论述。**读者可以简单的认为 dubbo-go 维护了一个 getty session池,session 又维护了一个 TCP 连接池。对于每个连接,getty 会有读协程和写协程伴生,做到读写分离。**这里我尽量用通俗的注释帮大家梳理下对性能影响较大的几个配置含义: + +```yaml +protocol_conf: + # 这里是协议独立的配置,在dubbo协议下,大多数配置即为getty session相关的配置。 + dubbo: + # 一个session会始终保证connection_number个tcp连接个数,默认是16, + # 但这里建议大家配置相对小的值,一般系统不需要如此多的连接个数。 + # 每隔reconnect_interval时间,检查连接个数,如果小于connection_number, + # 就建立连接。填0或不填都为默认值300ms + reconnect_interval: 0 + connection_number: 2 + # 客户端发送心跳的间隔 + heartbeat_period: "30s" + # OnCron时session的超时时间,超过session_timeout无返回就关闭session + session_timeout: "30s" + # 每一个dubbo interface的客户端,会维护一个最大值为pool_size大小的session池。 + # 每次请求从session池中select一个。所以真实的tcp数量是session数量*connection_number, + # 而pool_size是session数量的最大值。测试总结下来一般程序4个tcp连接足以。 + pool_size: 4 + # session保活超时时间,也就是超过session_timeout时间没有使用该session,就会关闭该session + pool_ttl: 600 + # 处理返回值的协程池大小 + gr_pool_size: 1200 + # 读数据和协程池中的缓冲队列长度,目前已经废弃。不使用缓冲队列 + queue_len: 64 + queue_number: 60 + getty_session_param: + compress_encoding: false + tcp_no_delay: true + tcp_keep_alive: true + keep_alive_period: "120s" + tcp_r_buf_size: 262144 + tcp_w_buf_size: 65536 + pkg_wq_size: 512 + tcp_read_timeout: "1s" # 每次读包的超时时间 + tcp_write_timeout: "5s" # 每次写包的超时时间 + wait_timeout: "1s" + max_msg_len: 102400 # 最大数据传输长度 + session_name: "client" +``` + +## dubbo-go 快速接入 + +前文已经展示过 dubbo-go 在涂鸦智能的实践成果,接下来介绍快速接入 dubbo-go 的方式。 + +### 第一步:hello world + +dubbo-go 使用范例目前和 dubbo 一致,放置在 [apache/dubbo-samples](https://github.com/apache/dubbo-samples) 项目中。在 dubbo-sample/golang 目录下,用户可以选择自己感兴趣的 feature 目录,快速测试代码效果。 + + + +```bash +tree dubbo-samples/golang -L 1 +dubbo-samples/golang +├── README.md +├── async +├── ci.sh +├── configcenter +├── direct +├── filter +├── general +├── generic +├── go.mod +├── go.sum +├── helloworld +├── multi_registry +└── registry +``` + +我们以 hello world 为例,按照 dubbo-samples/golang/README.md 中的步骤,分别启动 server 和 client 。可以尝试 golang 调用 java 、 java 调用 golang 、golang 调用 golang 、java 调用 java。dubbo-go 在协议上支持和 dubbo 互通。 + +我们以启动 go-server 为例,注册中心默认使用 zookeeper 。首先确认本地的 zookeeper 是否运行正常。然后执行以下命令,紧接着你就可以看到你的服务正常启动的日志了。 + +```bash +export ARCH=mac +export ENV=dev +cd dubbo-samples/golang/helloworld/dubbo/go-server +sh ./assembly/$ARCH/$ENV.sh +cd ./target/darwin/user_info_server-2.6.0-20200608-1056-dev/ +sh ./bin/load.sh start +``` + +### 第二步:在项目中使用 dubbo-go + +上面,我们通过社区维护的测试代码和启动脚本将用例跑了起来。接下来,我们需要在自己的代码中嵌入 dubbo-go 框架。很多朋友往往是在这一步遇到问题,这里我整理的一些常见问题,希望能帮到大家。 + +##### 1. 环境变量 + +目前 dubbo-go 有 3 个环境变量需要配置。 + +- `CONF_CONSUMER_FILE_PATH` : Consumer 端配置文件路径,使用 consumer 时必需。 +- `CONF_PROVIDER_FILE_PATH`:Provider 端配置文件路径,使用 provider 时必需。 +- `APP_LOG_CONF_FILE` :Log 日志文件路径,必需。 +- `CONF_ROUTER_FILE_PATH`:File Router 规则配置文件路径,使用 File Router 时需要。 + +##### 2. 代码注意点 + +- 注入服务: 检查是否执行以下代码 + + ```go + # 客户端 + func init() { + config.SetConsumerService(userProvider) + } + # 服务端 + func init() { + config.SetProviderService(new(UserProvider)) + } + ``` + +- 注入序列化描述:检查是否执行以下代码 + + ```go + hessian.RegisterJavaEnum(Gender(MAN)) + hessian.RegisterJavaEnum(Gender(WOMAN)) + hessian.RegisterPOJO(&User{}) + ``` + +##### 3. 正确理解配置文件 + +- references/services 下的 key ,如下面例子的 "UserProvider" 需要和服务 Reference() 返回值保持一致,此为标识改接口的 key。 + + ```yaml + references: + "UserProvider": + registry: "hangzhouzk" + protocol : "dubbo" + interface : "com.ikurento.user.UserProvider" + cluster: "failover" + methods : + - name: "GetUser" + retries: 3 + ``` + + +- 注册中心如果只有一个注册中心集群,只需配置一个。多个 IP 用逗号隔开,如下: + + ```yaml + registries : + "hangzhouzk": + protocol: "zookeeper" + timeout : "3s" + address: "172.16.120.181:2181,172.16.120.182:2181" + username: "" + password: "" + ``` + +##### 4. java 和 go 的问题 + +- `go 和 java 交互的大小写` :golang 为了适配 java 的驼峰格式,在调用 java 服务时,会自动将 method 和属性首字母变成小写。很多同学故意将 java 代码写成适配 golang 的参数定义,将首字母大写,最后反而无法序列化匹配。 + +### 第三步:拓展功能 + +dubbo-go 和 dubbo 都提供了非常丰富的拓展机制。可以实现自定义模块代替 dubbo-go 默认模块,或者新增某些功能。比如实现 Cluster、Filter 、Router 等来适配业务的需求。这些注入方法暴露在 dubbo-go/common/extension 中,允许用户调用及配置。 + +## 欢迎加入 dubbo-go 社区 + +有任何 dubbo-go 相关的问题,可以加我们的钉钉群 23331795 询问探讨,我们一定第一时间给出反馈。 + +> 本文作者 潘天颖,Github ID @pantianying,开源爱好者,就职于涂鸦智能。 diff --git a/content/en/blog/golang/dubbogo-from-scratch.md b/content/en/blog/golang/dubbogo-from-scratch.md new file mode 100644 index 000000000000..9993a8637be8 --- /dev/null +++ b/content/en/blog/golang/dubbogo-from-scratch.md @@ -0,0 +1,848 @@ +--- +title: "dubbo-go 白话文" +linkTitle: "dubbo-go 白话文" +tags: ["Go"] +date: 2021-02-20 +description: > + 本文手把手教你使用 dubbogo 调用 dubbogo 或 dubbo 提供的服务提供方 +--- + + + +## 一、前言 + + +> 本文基于 dubbogo [1.5.4](https://github.com/apache/dubbo-go/releases/tag/v1.5.4) 版本 + + + +最近开始参与 dubbogo 的一些开发测试,之前都是直接拿 [samples](https://github.com/apache/dubbo-go-samples) 的例子验证功能,而这次为了复现一个功能问题,打算从零开始搭建一个 dubbo-go 和 dubbo 调用的工程,踩到了一些新人使用 dubbogo 的坑,把这个过程记录下供大家参考。 + + +通过本文你可以了解到: + +- 如何常规配置 dubbogo 消费方去调用 dubbo 和 dubbogo 服务提供方 +- 通过一个实际的 BUG 介绍解决问题的思路 + + + +## 二、解决问题 + + +### 2.1 准备 dubbo 服务提供者 + + +#### 2.1.1 基本定义 + + +定义 `DemoService` 接口: + + +```java +public interface DemoService { + + String sayHello(String name); + + String sayHello(User user); + + String sayHello(User user, String name); + +} +``` + + +定义 `User` 对象: + + +```java +public class User implements Serializable { + + private String name; + + private int age; + + ...... +} +``` + + +#### 2.1.2 启动 dubbo 服务提供者 + + +用的 [dubbo 官方示例代码](/en/docsv2.7/user/configuration/api/): + + +```java +public static void main(String[] args) throws IOException { + // 服务实现 + DemoService demoService = new DemoServiceImpl(); + + // 当前应用配置 + ApplicationConfig application = new ApplicationConfig(); + application.setName("demoProvider"); + + // 连接注册中心配置 + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("127.0.0.1:2181"); + registry.setProtocol("zookeeper"); + registry.setUsername(""); + registry.setPassword(""); + + // 服务提供者协议配置 + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName("dubbo"); + protocol.setPort(12345); + protocol.setThreads(200); + + // 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口 + + // 服务提供者暴露服务配置 + ServiceConfig service = new ServiceConfig<>(); // 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏 + service.setApplication(application); + service.setRegistry(registry); // 多个注册中心可以用setRegistries() + service.setProtocol(protocol); // 多个协议可以用setProtocols() + service.setInterface(DemoService.class); + service.setRef(demoService); + service.setVersion("1.0.0"); + service.setGroup("tc"); + service.setTimeout(60 * 1000); + + // 暴露及注册服务 + service.export(); + + System.in.read(); +} +``` + + +查看 zookeeper 看是否注册成功: + + +```bash +$ls /dubbo/com.funnycode.DemoService/providers +[dubbo%3A%2F%2F127.0.0.1%3A12345%2Fcom.funnycode.DemoService%3Fanyhost%3Dtrue%26application%3DdemoProvider%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26group%3Dtc%26interface%3Dcom.funnycode.DemoService%26methods%3DsayHello%26pid%3D18167%26release%3D2.7.7%26revision%3D1.0.0%26side%3Dprovider%26threads%3D200%26timestamp%3D1606896020691%26version%3D1.0.0] +``` + + +如上的输出表示服务提供方已经启动。 + + +### 2.2 准备 dubbogo 服务消费者 + + +#### 2.2.1 基本定义 + + +定义 `User` 对象: + + +```go +type User struct { + Name string + Age int +} + +func (User) JavaClassName() string { + return "com.funnycode.User" +} +``` + + +定义 `DemoProvider` 接口: + + +```go +type DemoProvider struct { + SayHello func(ctx context.Context, name string) (string, error) `dubbo:"sayHello"` + SayHello2 func(ctx context.Context, user User) (string, error) `dubbo:"sayHello"` + SayHello3 func(ctx context.Context, user User, name string) (string, error) `dubbo:"sayHello"` +} + +func (p *DemoProvider) Reference() string { + return "DemoProvider" +} +``` + + +#### 2.2.2 启动 dubbogo 消费者 + + +```go +func main() { + config.Load() + gxlog.CInfo("\n\n\nstart to test dubbo") + + res, err := demoProvider.SayHello(context.TODO(), "tc") + if err != nil { + panic(err) + } + + gxlog.CInfo("response result: %v\n", res) + + user := User{ + Name: "tc", + Age: 18, + } + + res, err = demoProvider.SayHello2(context.TODO(), user) + if err != nil { + panic(err) + } + + gxlog.CInfo("response result: %v\n", res) + + res, err = demoProvider.SayHello3(context.TODO(), user, "tc") + if err != nil { + panic(err) + } + + gxlog.CInfo("response result: %v\n", res) + + initSignal() +} +``` + + +### 2.3 请求结果分析 + + +#### 2.3.1 直接调用 + + +> 确认问题的存在 + + + +第一个接口的参数是字符串,可以正常返回 `[2020-12-03/18:59:12 main.main: client.go: 29] response result: Hello tc` +第二、三两个接口存在 `User` 对象,无法调用成功。错误信息如下: + + +```bash +2020-12-02T17:10:47.739+0800 INFO getty/listener.go:87 session{session session-closed, Read Bytes: 924, Write Bytes: 199, Read Pkgs: 0, Write Pkgs: 1} got error{java exception:Fail to decode request due to: java.lang.IllegalArgumentException: Service not found:com.funnycode.DemoService, sayHello + at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:134) + at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:80) + at org.apache.dubbo.remoting.transport.DecodeHandler.decode(DecodeHandler.java:57) + at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:44) + at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:57) + at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) + at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) + at java.lang.Thread.run(Thread.java:748) +}, will be closed. +``` + + +错误正如 [issue](https://github.com/apache/dubbo-go/issues/900) 中描述的一模一样,因为错误信息返回到了消费端,可以看到 Java 那边的错误堆栈信息,所以直接去看 `DecodeableRpcInvocation.decode#134`。 + + +#### 2.3.2 断点查看 + + +代码如下: + + +```java +// 反序列化 +public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Decodeable { + public Object decode(Channel channel, InputStream input) throws IOException { + ...... + if (serviceDescriptor != null) { + // 方法描述里面根据方法名查找 + MethodDescriptor methodDescriptor = serviceDescriptor.getMethod(getMethodName(), desc); + if (methodDescriptor != null) { + pts = methodDescriptor.getParameterClasses(); + this.setReturnTypes(methodDescriptor.getReturnTypes()); + } + } + // 表示没有找到方法 + if (pts == DubboCodec.EMPTY_CLASS_ARRAY) { + if (!RpcUtils.isGenericCall(path, getMethodName()) && !RpcUtils.isEcho(path, getMethodName())) { + throw new IllegalArgumentException("Service not found:" + path + ", " + getMethodName()); + } + pts = ReflectUtils.desc2classArray(desc); + } + ...... + } +} +``` + + +- 查看 `MethodDescriptor`,即找方法是否存在,存在的话就会设置好 `ParameterClasses` +- 如果上面没找到,`pts == DubboCodec.EMPTY_CLASS_ARRAY` 就会满足条件,进而判断是否是泛化调用或者是 echo 调用,如果都不是则报服务找不到方法错误 +- desc 是 `Ljava/lang/Object` ,很明显并没有参数是 Object 的方法,所以必然是会报错的 + + + +补充说明: + + +**方法查询** + + +代码如下: + + +```java +public MethodDescriptor getMethod(String methodName, String params) { + Map methods = descToMethods.get(methodName); + if (CollectionUtils.isNotEmptyMap(methods)) { + return methods.get(params); + } + return null; +} +``` + + +优点: + + +比之前的版本加了方法的元信息缓存起来,不使用反射可以提高效率,可以理解用空间换时间。 + + +![dfsa01.jpg](/imgs/blog/dubbo-go/from-scratch/dfsa01.jpg) + + +### 2.4 解决问题 + + +> 因为直接撸代码并 hold 不住,所以通过比较来查看问题所在。 + + + +#### 2.4.1 启动 dubbo 服务消费者 + + +通过 api 模式启动,参考官方例子。启动这个是为了查看 Java 版本的传输内容。 + + +```java +public static void main(String[] args) throws InterruptedException { + // 当前应用配置 + ApplicationConfig application = new ApplicationConfig(); + application.setName("demoProvider2"); + + // 连接注册中心配置 + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("127.0.0.1:2181"); + registry.setProtocol("zookeeper"); + registry.setUsername(""); + registry.setPassword(""); + // 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接 + + // 引用远程服务 + ReferenceConfig reference + = new ReferenceConfig<>(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏 + reference.setApplication(application); + reference.setRegistry(registry); // 多个注册中心可以用setRegistries() + reference.setInterface(DemoService.class); + reference.setVersion("1.0.0"); + reference.setGroup("tc"); + reference.setCheck(true); + reference.setTimeout(1000 * 60); + + // 和本地bean一样使用xxxService + DemoService demoService = reference.get(); // 注意:此代理对象内部封装了所有通讯细节,对象较重,请缓存复用 + System.out.println(demoService.sayHello(new User("tc", 18))); + + TimeUnit.MINUTES.sleep(10); +} +``` + + +![dfsa02.png](/imgs/blog/dubbo-go/from-scratch/dfsa02.png) + + +desc 肉眼可见的是 `Lcom/funnycode/User`,这个就是正确的对象了。 + + +#### 2.4.2 查找 dubbogo 为什么不对 + + +代码位置: + + +`protocol/dubbo/impl/hessian.go:120#marshalRequest` + + +代码实现: + + +```go +func marshalRequest(encoder *hessian.Encoder, p DubboPackage) ([]byte, error) { + service := p.Service + request := EnsureRequestPayload(p.Body) + encoder.Encode(DEFAULT_DUBBO_PROTOCOL_VERSION) + encoder.Encode(service.Path) + encoder.Encode(service.Version) + encoder.Encode(service.Method) + + args, ok := request.Params.([]interface{}) + + if !ok { + logger.Infof("request args are: %+v", request.Params) + return nil, perrors.Errorf("@params is not of type: []interface{}") + } + types, err := getArgsTypeList(args) + if err != nil { + return nil, perrors.Wrapf(err, " PackRequest(args:%+v)", args) + } + encoder.Encode(types) + for _, v := range args { + encoder.Encode(v) + } + + ...... +} +``` + + +断点可以发现,types 返回的时候就已经是 `Object` 了,没有返回 `User`,那么继续跟进去查看代码。 + + +- `protocol/dubbo/impl/hessian.go:394#getArgsTypeList` +- `protocol/dubbo/impl/hessian.go:418#getArgType` + + + +```go +func getArgType(v interface{}) string { + // 常见的类型处理 + + ...... + + default: + t := reflect.TypeOf(v) + if reflect.Ptr == t.Kind() { + t = reflect.TypeOf(reflect.ValueOf(v).Elem()) + } + switch t.Kind() { + case reflect.Struct: + return "java.lang.Object" + } + ...... +} +``` + + +很明显当发现是 `reflect.Struct` 的时候就返回了 `java.lang.Object`,所以参数就变成了 `Object`,那么因为 Java 代码那边依赖这个类型所以就调用失败了。 + + +#### 2.4.3 其它版本验证 + + +因为反馈是 2.7.7 出错,所以先考虑到在之前的版本是否功能正常,于是把服务提供者切换到 dubbo 2.7.3,发现调用仍然有错误,如下: + + +```bash +2020-12-02T21:52:25.945+0800 INFO getty/listener.go:85 session{session session-closed, Read Bytes: 4586, Write Bytes: 232, Read Pkgs: 0, Write Pkgs: 1} got error{java exception:org.apache.dubbo.rpc.RpcException: Failed to invoke remote proxy method sayHello to registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demoProvider&dubbo=2.0.2&export=dubbo%3A%2F%2F192.168.0.113%3A12345%2Fcom.funnycode.DemoService%3Fanyhost%3Dtrue%26application%3DdemoProvider%26bind.ip%3D192.168.0.113%26bind.port%3D12345%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26group%3Dtc%26interface%3Dcom.funnycode.DemoService%26methods%3DsayHello%26pid%3D23889%26register%3Dtrue%26release%3D2.7.3%26revision%3D1.0.0%26side%3Dprovider%26threads%3D200%26timeout%3D60000%26timestamp%3D1606916702204%26version%3D1.0.0&pid=23889®istry=zookeeper&release=2.7.3×tamp=1606916702193, cause: Not found method "sayHello" in class com.funnycode.DemoServiceImpl. +org.apache.dubbo.rpc.RpcException: Failed to invoke remote proxy method sayHello to registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demoProvider&dubbo=2.0.2&export=dubbo%3A%2F%2F192.168.0.113%3A12345%2Fcom.funnycode.DemoService%3Fanyhost%3Dtrue%26application%3DdemoProvider%26bind.ip%3D192.168.0.113%26bind.port%3D12345%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26group%3Dtc%26interface%3Dcom.funnycode.DemoService%26methods%3DsayHello%26pid%3D23889%26register%3Dtrue%26release%3D2.7.3%26revision%3D1.0.0%26side%3Dprovider%26threads%3D200%26timeout%3D60000%26timestamp%3D1606916702204%26version%3D1.0.0&pid=23889®istry=zookeeper&release=2.7.3×tamp=1606916702193, cause: Not found method "sayHello" in class com.funnycode.DemoServiceImpl. + at org.apache.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:107) + at org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker.invoke(DelegateProviderMetaDataInvoker.java:56) + at org.apache.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:56) + at org.apache.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:55) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82) + at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:92) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82) + at org.apache.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:48) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82) + at org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:81) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82) + at org.apache.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:96) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82) + at org.apache.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:148) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82) + at org.apache.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82) + at org.apache.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:41) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:82) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$CallbackRegistrationInvoker.invoke(ProtocolFilterWrapper.java:157) + at org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:152) + at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:102) + at org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:193) + at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:51) + at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:57) + at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) + at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) + at java.lang.Thread.run(Thread.java:748) +Caused by: org.apache.dubbo.common.bytecode.NoSuchMethodException: Not found method "sayHello" in class com.funnycode.DemoServiceImpl. + at org.apache.dubbo.common.bytecode.Wrapper1.invokeMethod(Wrapper1.java) + at org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:47) + at org.apache.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:84) + ... 27 more +}, will be closed. +``` + + +虽然和 2.7.7 的代码是不一样的,但是通过错误也能看出来是在代理增强类里面方法找不到,大概率是反射找不到方法,所以归根结底也是参数的问题。 + + +#### 2.4.4 修复问题 + + +修复相对简单,就是拿到 `struct` 定义的 `JavaClassName`。 + + +```go +case reflect.Struct: + v, ok := v.(hessian.POJO) + if ok { + return v.JavaClassName() + } + return "java.lang.Object" +``` + + +#### 2.4.3 验证结果 + + +再次执行消费者,运行(提供方 2.7.7 和 2.7.3)正常,输出如下: + + +```bash +[2020-12-03/20:04:06 main.main: client.go: 29] response result: Hello tc +... +[2020-12-03/20:04:09 main.main: client.go: 41] response result: Hello tc You are 18 +... +[2020-12-03/20:04:09 main.main: client.go: 48] response result: Hello tc You are 18 +``` + + +## 三、细节叨叨 + + +### 3.1 如何配置 dubbgo 消费者 + + +细心的你是否已经发现,在我 dubbogo 的消费端接口叫 `DemoProvider`,然后发现提供者叫 `DemoService`,这个又是如何正常运行的? + + +实际上和 `client.yml` 中配置项 `references` 有关,在配置文件详细说明了 `interface`,`version`,`group` 等,你还可以通过 methods 配置方法的超时时间等信息。 + + +```yaml +references: + "DemoProvider": + # 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册 + registry: "zk1" + protocol: "dubbo" + interface: "com.funnycode.DemoService" + cluster: "failover" + version: "1.0.0" + group: "tc" + methods: + - name: "SayHello" + retries: 3 + ...... +``` + + +### 3.2 全局的 group 和 version 怎么配置 + + +配置文件如下: + + +```yaml +# application config +application: + organization: "dubbogoproxy.com" + name: "Demo Micro Service" + module: "dubbogoproxy tc client" + version: "1.0.0" + group: "tc" + owner: "ZX" + environment: "dev" + +references: + "DemoProvider": + # 可以指定多个registry,使用逗号隔开;不指定默认向所有注册中心注册 + registry: "zk1" + protocol: "dubbo" + interface: "com.funnycode.DemoService" + cluster: "failover" +# version: "1.0.0" +# group: "tc" + methods: + - name: "SayHello" + retries: 3 +``` + + +从使用的习惯来讲,肯定是 `application` 表示了全局的配置,但是我发现启动的时候在 `application` 配置的 `version` 和 `group` 并不会赋值给接口,启动会报服务提供方找不到,如下: + + +```bash +2020-12-03T20:15:42.208+0800 DEBUG zookeeper/registry.go:237 Create a zookeeper node:/dubbo/com.funnycode.DemoService/consumers/consumer%3A%2F%2F30.11.176.107%2FDemoProvider%3Fapp.version%3D1.0.0%26application%3DDemo+Micro+Service%26async%3Dfalse%26bean.name%3DDemoProvider%26cluster%3Dfailover%26environment%3Ddev%26generic%3Dfalse%26group%3D%26interface%3Dcom.funnycode.DemoService%26ip%3D30.11.176.107%26loadbalance%3D%26methods.SayHello.loadbalance%3D%26methods.SayHello.retries%3D3%26methods.SayHello.sticky%3Dfalse%26module%3Ddubbogoproxy+tc+client%26name%3DDemo+Micro+Service%26organization%3Ddubbogoproxy.com%26owner%3DZX%26pid%3D38692%26protocol%3Ddubbo%26provided-by%3D%26reference.filter%3Dcshutdown%26registry.role%3D0%26release%3Ddubbo-golang-1.3.0%26retries%3D%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1606997742%26version%3D +``` + + +`version` 和 `group` 都是空。必须把 `DemoProvider` 下的 `version` 和 `group` 注释打开。 + + +### 3.3 怎么指定调用的方法名 + + +#### 3.3.1 go 调用 java + + +dubbogo 调用 dubbo,因为 go 是大写的方法名,java 里面是小写的方法名,所以会出现如下错误: + + +```bash +2020-12-02T17:10:47.739+0800 INFO getty/listener.go:87 session{session session-closed, Read Bytes: 924, Write Bytes: 199, Read Pkgs: 0, Write Pkgs: 1} got error{java exception:Fail to decode request due to: java.lang.IllegalArgumentException: Service not found:com.funnycode.DemoService, SayHello +java.lang.IllegalArgumentException: Service not found:com.funnycode.DemoService, SayHello + at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:134) + at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:80) + at org.apache.dubbo.remoting.transport.DecodeHandler.decode(DecodeHandler.java:57) + at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:44) + at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:57) + at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) + at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) + at java.lang.Thread.run(Thread.java:748) +}, will be closed. +``` + + +细心的读者可能已经注意到了,我在消费端的接口声明是有个 `dubbo:"sayHello"` 的,表示方法名是 sayHello,这样在服务提供方就可以得到 sayHello 这个方法名。 + + +还有我声明的三个方法都指明它们的方法名叫 `dubbo:"sayHello"`,这是因为 Java 可以方法名字一样进行重载,而 go 是不能方法名重复的。 + + +#### 3.3.2 go 调用 go + + +> 直接贴能跑通的代码 + + + +我的提供者接口: + + +```go +type DemoProvider struct{} + +func (p *DemoProvider) SayHello(ctx context.Context, name string) (string, error) { + return "Hello " + name, nil +} + +func (p *DemoProvider) SayHello4(ctx context.Context, user *User) (string, error) { + return "Hello " + user.Name + " You are " + strconv.Itoa(user.Age), nil +} + +func (p *DemoProvider) SayHello5(ctx context.Context, user *User, name string) (string, error) { + return "Hello " + name + " You are " + strconv.Itoa(user.Age), nil +} + +func (p *DemoProvider) Reference() string { + return "DemoProvider" +} + +func (p *DemoProvider) MethodMapper() map[string]string { + return map[string]string{ + "SayHello": "sayHello", + } +} +``` + + +我的消费者接口: + + +```go +type DemoProvider struct { + // 调用 java 和 go + SayHello func(ctx context.Context, name string) (string, error) `dubbo:"sayHello"` + // 只调用 java + SayHello2 func(ctx context.Context, user *User) (string, error) `dubbo:"sayHello"` + SayHello3 func(ctx context.Context, user *User, name string) (string, error) `dubbo:"sayHello"` + // 只调用 go + SayHello4 func(ctx context.Context, user *User) (string, error) + SayHello5 func(ctx context.Context, user *User, name string) (string, error) +} +``` + + +启动服务消费者: + + +```go +func main() { + config.Load() + gxlog.CInfo("\n\n\nstart to test dubbo") + + res, err := demoProvider.SayHello(context.TODO(), "tc") + if err != nil { + panic(err) + } + + gxlog.CInfo("response result: %v\n", res) + + user := &User{ + Name: "tc", + Age: 18, + } + + res, err = demoProvider.SayHello4(context.TODO(), user) + if err != nil { + panic(err) + } + + gxlog.CInfo("response result: %v\n", res) + + res, err = demoProvider.SayHello5(context.TODO(), user, "tc") + if err != nil { + panic(err) + } + + gxlog.CInfo("response result: %v\n", res) + + initSignal() +} +``` + + +这里需要注意 `MethodMapper` 方法,有时候需要在这个方法中配置方法名的映射关系,否则还是会出现找不到方法的错误。 + + +比如因为配置 `dubbo:"sayHello"` ,所以在 go 里面请求 `SayHello` 变成了 `sayHello`,那么服务提供方通过 `MethodMapper` 方法配置后使得提供方也是 `sayHello`,这样 go 和 java 下暴露的都是小写的 `sayHello`。 + + +### 3.4 为什么会用 hessian2 + + +老司机都懂,在 dubbo 中 SPI 机制的默认值就是 hessian2 + + +```java +@SPI("hessian2") +public interface Serialization { +} +``` + + +而在 dubbo-go 中: + + +```go +func NewDubboCodec(reader *bufio.Reader) *ProtocolCodec { + s, _ := GetSerializerById(constant.S_Hessian2) + return &ProtocolCodec{ + reader: reader, + pkgType: 0, + bodyLen: 0, + headerRead: false, + serializer: s.(Serializer), + } +} +``` + + +### 3.5 hessian序列化源码 + + +> 可以自行断点查看,两边基本上一样,我也是通过两边比出来的,RpcInvocation.getParameterTypesDesc() 就是方法的参数 + + + +- go 代码 `protocol/dubbo/impl/hessian.go:120#marshalRequest` +- java 代码 `org.apache.dubbo.rpc.protocol.dubbo.DubboCodec#encodeRequestData(org.apache.dubbo.remoting.Channel, org.apache.dubbo.common.serialize.ObjectOutput, java.lang.Object, java.lang.String)` + + + +### 3.6 dubbogo 服务提供者的方法对象需要是指针对象 + + +之前的例子都是 copy 的,这次是纯手打的,才发现了这个问题。 + + +如果你的提供类似:`func (p *DemoProvider) SayHello4(ctx context.Context, user User) (string, error)`,那么会出现如下错误: + + +```bash +2020-12-03T12:42:32.834+0800 ERROR getty/listener.go:280 OnMessage panic: reflect: Call using *main.User as type main.User +github.com/apache/dubbo-go/remoting/getty.(*RpcServerHandler).OnMessage.func1 +``` + + +参数里面的 `User` 需要改成 `*User`。 + + +### 3.7 dubbogo 服务消费者的方法对象可以是非指针对象 + + +```go +SayHello4 func(ctx context.Context, user *User) (string, error) +// or +SayHello4 func(ctx context.Context, user User) (string, error) +``` + + +因为在参数序列化的时候会对指针做操作: + + +```go +t := reflect.TypeOf(v) +if reflect.Ptr == t.Kind() { + t = reflect.TypeOf(reflect.ValueOf(v).Elem()) +} +``` + + +[完整代码](https://github.com/apache/dubbo-go/blob/v1.5.4/protocol/dubbo/impl/hessian.go#L486) + + +### 3.8 配置文件说明 + + +dubbogo 主要有三个配置文件: + + +- server.yaml 服务提供方的配置文件 +- client.yaml 服务消费方的配置文件 +- log.yaml 日志文件 + + + +如果你什么都不配置,会出现: + + +```bash +2021/01/11 15:31:41 [InitLog] warn: log configure file name is nil +2021/01/11 15:31:41 [consumerInit] application configure(consumer) file name is nil +2021/01/11 15:31:41 [providerInit] application configure(provider) file name is nil +``` + + +这样是没法正常使用的。如果你是服务提供方,必须要配置 server.yaml 文件,如果你是服务消费方,必须要配置 client.yaml,实际我们的应用应该既是消费者又是提供者,所以往往两个文件都是需要配置的。 + + +服务提供方正常启动是会有如下输出的: + + +```bash +2021-01-11T15:36:55.003+0800 INFO protocol/protocol.go:205 The cached exporter keys is dubbo://:20000/DemoProvider?accesslog=&app.version=1.0.0&application=Demo+Micro+Service&auth=&bean.name=DemoProvider&cluster=failover&environment=dev&execute.limit=&execute.limit.rejected.handler=&group=tc&interface=com.funnycode.DemoService&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=3&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&methods.SayHello4.loadbalance=random&methods.SayHello4.retries=3&methods.SayHello4.tps.limit.interval=&methods.SayHello4.tps.limit.rate=&methods.SayHello4.tps.limit.strategy=&methods.SayHello4.weight=0&methods.SayHello5.loadbalance=random&methods.SayHello5.retries=3&methods.SayHello5.tps.limit.interval=&methods.SayHello5.tps.limit.rate=&methods.SayHello5.tps.limit.strategy=&methods.SayHello5.weight=0&module=dubbogoproxy+tc+client&name=Demo+Micro+Service&organization=dubbogoproxy.com&owner=ZX¶m.sign=®istry.role=3&release=dubbo-golang-1.3.0&retries=&serialization=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cgeneric_service%2Cexecute%2Cpshutdown&side=provider&ssl-enabled=false×tamp=1610350614&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=1.0.0&warmup=100! +2021-01-11T15:36:55.003+0800 INFO dubbo/dubbo_protocol.go:86 Export service: dubbo://:20000/DemoProvider?accesslog=&app.version=1.0.0&application=Demo+Micro+Service&auth=&bean.name=DemoProvider&cluster=failover&environment=dev&execute.limit=&execute.limit.rejected.handler=&group=tc&interface=com.funnycode.DemoService&loadbalance=random&methods.SayHello.loadbalance=random&methods.SayHello.retries=3&methods.SayHello.tps.limit.interval=&methods.SayHello.tps.limit.rate=&methods.SayHello.tps.limit.strategy=&methods.SayHello.weight=0&methods.SayHello4.loadbalance=random&methods.SayHello4.retries=3&methods.SayHello4.tps.limit.interval=&methods.SayHello4.tps.limit.rate=&methods.SayHello4.tps.limit.strategy=&methods.SayHello4.weight=0&methods.SayHello5.loadbalance=random&methods.SayHello5.retries=3&methods.SayHello5.tps.limit.interval=&methods.SayHello5.tps.limit.rate=&methods.SayHello5.tps.limit.strategy=&methods.SayHello5.weight=0&module=dubbogoproxy+tc+client&name=Demo+Micro+Service&organization=dubbogoproxy.com&owner=ZX¶m.sign=®istry.role=3&release=dubbo-golang-1.3.0&retries=&serialization=&service.filter=echo%2Ctoken%2Caccesslog%2Ctps%2Cgeneric_service%2Cexecute%2Cpshutdown&side=provider&ssl-enabled=false×tamp=1610350614&tps.limit.interval=&tps.limit.rate=&tps.limit.rejected.handler=&tps.limit.strategy=&tps.limiter=&version=1.0.0&warmup=100 +``` + + +### 3.9 复现代码 + + +- [https://github.com/cityiron/java_study/tree/master/dubbo2.7.7/dg-issue900](https://github.com/cityiron/java_study/tree/master/dubbo2.7.7/dg-issue900) +- [https://github.com/cityiron/golang_study/tree/master/dubbogo/1.5.4/arg-bug](https://github.com/cityiron/golang_study/tree/master/dubbogo/1.5.4/arg-bug) + + + +## 四、参考 + +- [https://dubbo.apache.org/zh-cn/docsv2.7/user/configuration/api/](/en/docsv2.7/user/configuration/api/) +- [https://github.com/apache/dubbo-go/issues/257](https://github.com/apache/dubbo-go/issues/257) + +--- + + + +篇幅有限,就介绍到这里。欢迎有兴趣的同学来参与 [dubbogo3.0](https://github.com/apache/dubbo-go/tree/release-3.0) 的建设,感谢阅读。 + + + diff --git a/content/en/blog/integration/_index.md b/content/en/blog/integration/_index.md new file mode 100644 index 000000000000..5a4ebc8f546f --- /dev/null +++ b/content/en/blog/integration/_index.md @@ -0,0 +1,9 @@ + +--- +title: "生态集成" +linkTitle: "生态集成" +weight: 11 +description: "Dubbo 生态集成相关博客" +--- + + diff --git a/content/en/blog/integration/dubbo-admin.md b/content/en/blog/integration/dubbo-admin.md new file mode 100644 index 000000000000..d153fb272be6 --- /dev/null +++ b/content/en/blog/integration/dubbo-admin.md @@ -0,0 +1,90 @@ +--- +title: "新版 Dubbo Admin 介绍" +linkTitle: "新版 Dubbo Admin 介绍" +date: 2019-01-07 +tags: ["生态", "Java"] +description: > + 当前版本的Dubbo Admin包含了之前版本中的绝大部分功能,包括服务治理,服务查询等,同时支持了Dubbo2.7中服务治理的新特性 +--- + +``` +github: https://github.com/apache/dubbo-ops +``` +Dubbo Admin之前的版本过于老旧,也长期疏于维护,因此在去年年中的时候,对该项目进行了一次重构,项目结构上的变化如下: +* 将后端框架从webx替换成spring boot +* 前端采用Vue和Vuetify.js作为开发框架 +* 移除velocity模板 +* 集成swagger,提供api管理功能 + +当前版本的Dubbo Admin包含了之前版本中的绝大部分功能,包括服务治理,服务查询等,同时支持了Dubbo2.7中服务治理的新特性。 + + +## 配置规范 +由于在Dubbo2.7中,配置中心和注册中心做了分离,并且增加了元数据中心,因此Dubbo Admin的配置方式也做了更新,`application.properties`中的配置如下: +```properties +admin.registry.address=zookeeper://127.0.0.1:2181 +admin.config-center=zookeeper://127.0.0.1:2181 +admin.metadata-report.address=zookeeper://127.0.0.1:2181 +``` +也可以和Dubbo2.7一样,在配置中心指定元数据和注册中心的地址,以zookeeper为例,配置的路径和内容如下: +```properties +# /dubbo/config/dubbo/dubbo.properties +dubbo.registry.address=zookeeper://127.0.0.1:2181 +dubbo.metadata-report.address=zookeeper://127.0.0.1:2181 +``` +配置中心里的地址会覆盖掉本地`application.properties`的配置 + +## 功能介绍 +功能上,主要延续了之前版本的功能,包括服务查询和服务治理,2.7版本在服务治理的功能上有了很大的改进,这些改进也大部分都会以Dubbo Admin作为入口来体现。 + +### 标签路由 +标签路由是Dubbo2.7引入的新功能,配置以应用作为维度,给不同的服务器打上不同名字的标签,配置如下图所示: + +![tag](/imgs/blog/admin/route.jpg) + +调用的时候,客户端可以通过`setAttachment`的方式,来设置不同的标签名称,比如本例中,`setAttachment(tag1)`,客户端的选址范围就在如图所示的三台机器中,可以通过这种方式来实现流量隔离,灰度发布等功能。 + +### 应用级别的服务治理 +在Dubbo2.6及更早版本中,所有的服务治理规则都只针对服务粒度,如果要把某条规则作用到应用粒度上,需要为应用下的所有服务配合相同的规则,变更,删除的时候也需要对应的操作,这样的操作很不友好,因此Dubbo2.7版本中增加了应用粒度的服务治理操作,对于条件路由(包括黑白名单),动态配置(包括权重,负载均衡)都可以做应用级别的配置: + +![condition](/imgs/blog/admin/conditionRoute.jpg) + +上图是条件路由的配置,可以按照应用名,服务名两个维度来填写,也可以按照这两个维度来查询。 + + +![weight](/imgs/blog/admin/weight.jpg) + +条件路由,标签路由和动态配置都采用了`yaml`格式的文本编写,其他的规则配置还是采用了表单的形式。 + +#### 关于兼容性 +Dubbo2.6到Dubbo2.7,服务治理发生了比较大的变化,Dubbo Admin兼容两个版本的用法: +* 对于服务级别的配置,会按照Dubbo2.6(URL)和Dubbo2.7(配置文件)两种格式进行写入,保证Dubbo2.6的客户端能够正确读取,解析规则 +* 对于应用级别的配置,包括标签路由,只会按照Dubbo2.7的格式进行写入,因为Dubbo2.6无此功能,不需要做向前兼容。 +* Dubbo Admin只会按照Dubbo2.7的格式进行配置读取,因此,所有在Dubbo Admin上做的配置都可以被读到,但是之前遗留的,Dubbo2.6格式的URL无法被读取。 +* 对于同一个应用或者服务,每种规则只能够配置一条,否则新的会覆盖旧的。 + +### 配置管理 +配置管理也是配合Dubbo2.7新增的功能,在Dubbo2.7中,增加了全局和应用维度的配置, +* 全局配置: + +![config](/imgs/blog/admin/config.jpg) + +全局配置里可以指定注册中心,元数据中心的地址,服务端和客户端的超时时间等,这些配置在全局内生效。除了配置写入,也可以用来查看。如果使用zookeeper作为注册中心和元数据中心,还可以看到配置文件所在位置的目录结构。 +* 应用, 服务配置 + +![appConfig](/imgs/blog/admin/appConfig.jpg) + +应用级别的配置可以为应用或者应用内的服务指定配置,在服务维度上,需要区分提供者和消费者。`dubbo.reference.{serviceName}`表示作为该服务消费者的配置,`dubbo.provider.{servcieName}`表示作为该服务提供者的配置。优先级服务 > 应用 > 全局。其中注册中心和元数据中心的地址,只能在全局配置中指定,这也是Dubbo2.7中推荐的使用方式。 + +### 元数据和服务测试 +元数据是Dubbo2.7中新引入的元素,主要的使用场景就在Dubbo Admin中,主要体现在两个地方: +* 服务详情展示: + +![metadata](/imgs/blog/admin/metadata.jpg) + +跟之前版本相比,Dubbo2.7中增加了对服务方法完整签名的记录,因此服务详情中也增加了方法信息的详情,可以看到方法名,方法参数列表以及返回值信息。 +* 服务测试: + +![test](/imgs/blog/admin/test.jpg) + +更重要的,元数据为服务测试提供了数据基础,可以在页面上调用真实的服务提供者,方便测试,也不需要为了调用服务去搭建一套Dubbo环境以及编写消费端代码。 diff --git a/content/en/blog/integration/dubbo-fescar.md b/content/en/blog/integration/dubbo-fescar.md new file mode 100644 index 000000000000..12ab205f53fe --- /dev/null +++ b/content/en/blog/integration/dubbo-fescar.md @@ -0,0 +1,238 @@ +--- +title: "如何使用Seata保证Dubbo微服务间的一致性" +linkTitle: "如何使用Seata保证Dubbo微服务间的一致性" +date: 2019-01-17 +tags: ["生态", "Java"] +description: > + 本文主要介绍如何使用Seata保证Dubbo微服务间的一致性 +--- + +## 案例 + +用户采购商品业务,整个业务包含3个微服务: + +- 库存服务: 扣减给定商品的库存数量。 +- 订单服务: 根据采购请求生成订单。 +- 账户服务: 用户账户金额扣减。 + +### 业务结构图 + +![Architecture](/imgs/blog/fescar/fescar-1.png) + + +### StorageService + +```java +public interface StorageService { + + /** + * 扣除存储数量 + */ + void deduct(String commodityCode, int count); +} +``` + +### OrderService + +```java +public interface OrderService { + + /** + * 创建订单 + */ + Order create(String userId, String commodityCode, int orderCount); +} +``` + +### AccountService + +```java +public interface AccountService { + + /** + * 从用户账户中借出 + */ + void debit(String userId, int money); +} +``` + +### 主要的业务逻辑: + +```java +public class BusinessServiceImpl implements BusinessService { + + private StorageService storageService; + + private OrderService orderService; + + /** + * 采购 + */ + public void purchase(String userId, String commodityCode, int orderCount) { + + storageService.deduct(commodityCode, orderCount); + + orderService.create(userId, commodityCode, orderCount); + } +} +``` + +```java +public class StorageServiceImpl implements StorageService { + + private StorageDAO storageDAO; + + @Override + public void deduct(String commodityCode, int count) { + Storage storage = new Storage(); + storage.setCount(count); + storage.setCommodityCode(commodityCode); + storageDAO.update(storage); + } +} +``` + +```java +public class OrderServiceImpl implements OrderService { + + private OrderDAO orderDAO; + + private AccountService accountService; + + public Order create(String userId, String commodityCode, int orderCount) { + + int orderMoney = calculate(commodityCode, orderCount); + + accountService.debit(userId, orderMoney); + + Order order = new Order(); + order.userId = userId; + order.commodityCode = commodityCode; + order.count = orderCount; + order.money = orderMoney; + + return orderDAO.insert(order); + } +} +``` + +## Seata 分布式事务解决方案 + +![undefined](/imgs/blog/fescar/fescar-2.png) + +此处仅仅需要一行注解 `@GlobalTransactional` 写在业务发起方的方法上: + +```java + + @GlobalTransactional + public void purchase(String userId, String commodityCode, int orderCount) { + ...... + } +``` + +## Dubbo 与 Seata 结合的例子 + +### Step 1: 安装数据库 + +- 要求: MySQL (InnoDB 存储引擎)。 + +**提示:** 事实上例子中3个微服务需要3个独立的数据库,但为了方便我们使用同一物理库并配置3个逻辑连接串。 + +更改以下xml文件中的数据库url、username和password + +dubbo-account-service.xml +dubbo-order-service.xml +dubbo-storage-service.xml + +```xml + + + +``` +### Step 2: 为 Seata 创建 undo_log 表 + +`UNDO_LOG` 此表用于 Seata 的AT模式。 + +```sql +-- 注意当 Seata 版本升级至 0.3.0+ 将由之前的普通索引变更为唯一索引。 +CREATE TABLE `undo_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `branch_id` bigint(20) NOT NULL, + `xid` varchar(100) NOT NULL, + `context` varchar(128) NOT NULL, + `rollback_info` longblob NOT NULL, + `log_status` int(11) NOT NULL, + `log_created` datetime NOT NULL, + `log_modified` datetime NOT NULL, + `ext` varchar(100) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; +``` + +### Step 3: 创建相关业务表 + +```sql + +DROP TABLE IF EXISTS `storage_tbl`; +CREATE TABLE `storage_tbl` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `commodity_code` varchar(255) DEFAULT NULL, + `count` int(11) DEFAULT 0, + PRIMARY KEY (`id`), + UNIQUE KEY (`commodity_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +DROP TABLE IF EXISTS `order_tbl`; +CREATE TABLE `order_tbl` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` varchar(255) DEFAULT NULL, + `commodity_code` varchar(255) DEFAULT NULL, + `count` int(11) DEFAULT 0, + `money` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +DROP TABLE IF EXISTS `account_tbl`; +CREATE TABLE `account_tbl` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` varchar(255) DEFAULT NULL, + `money` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +``` +### Step 4: 启动 Seata-Server 服务 + +- 下载[服务器软件包](https://github.com/seata/seata/releases),将其解压缩。 + +```shell +Usage: sh seata-server.sh(for linux and mac) or cmd seata-server.bat(for windows) [options] + Options: + --host, -h + The host to bind. + Default: 0.0.0.0 + --port, -p + The port to listen. + Default: 8091 + --storeMode, -m + log store mode : file、db + Default: file + --help + +e.g. + +sh seata-server.sh -p 8091 -h 127.0.0.1 -m file +``` + +### Step 5: 运行例子 + +- 启动账户服务 ([DubboAccountServiceStarter](https://github.com/apache/dubbo-samples/tree/c6a704900501289973b174670beb788eceee5cc4/99-integration/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboAccountServiceStarter.java)). +- 启动库存服务 ([DubboStorageServiceStarter](https://github.com/apache/dubbo-samples/tree/c6a704900501289973b174670beb788eceee5cc4/99-integration/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboStorageServiceStarter.java)). +- 启动订单服务 ([DubboOrderServiceStarter](https://github.com/apache/dubbo-samples/tree/c6a704900501289973b174670beb788eceee5cc4/99-integration/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboOrderServiceStarter.java)). +- 运行BusinessService入口 ([DubboBusinessTester](https://github.com/apache/dubbo-samples/tree/c6a704900501289973b174670beb788eceee5cc4/99-integration/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboBusinessTester.java)). + +### 相关项目 +* Seata: https://github.com/seata/seata +* Seata Samples : https://github.com/seata/seata-samples diff --git a/content/en/blog/integration/dubbo-graalvm-support.md b/content/en/blog/integration/dubbo-graalvm-support.md new file mode 100644 index 000000000000..f2fc838b088f --- /dev/null +++ b/content/en/blog/integration/dubbo-graalvm-support.md @@ -0,0 +1,298 @@ +--- +title: "走向 Native 化:Spring&Dubbo AOT 技术示例与原理讲解" +linkTitle: "走向 Native 化:Dubbo AOT 正式发布" +date: 2023-06-28 +tags: ["Java", "Native Image", "GraalVM"] +authors: ["刘军", "华钟明"] +description: > + 本文讲解了 GraavlVM 的基本工作原理,Native Image 的构建方式,如何使用 Dubbo AOT 构建打包静态化的 Dubbo 应用,解决应用“冷启动”慢、内存占用高、预热时间长等问题。 +--- + +Java 应用在云计算时代面临“冷启动”慢、内存占用高、预热时间长等问题,无法很好的适应 Serverless 等云上部署模式,GraalVM 通过静态编译、打包等技术在很大程度上解决了这些问题,同时针对 GraalVM 的一些使用限制,Spring 和 Dubbo 等主流框架也都提供了相应的 AOT 解决方案。 + +本文我们将详细分析 Java 应用在云时代面临的挑战,GraalVM Native Image 是如何解决这些问题,GraalVM 的基本概念与工作原理,最后我们通过一个 Spring6 + Dubbo3 的微服务应用示例演示了如何将一个普通微服务应用进行静态化打包。 + +本文主要分为以下四个部分展开 + +1. 首先我们会先看一下在云计算快速发展的当下,云上应用应该具备的特点,Java 应用在云上所面临的挑战有哪些。 +2. 其次,我会介绍一下 GraalVM,什么是 Native Image,如何通过 GraalVM 对 Java 应用进行静态化打出 Native Image 可执行的二进制程序。 +3. 第三部分,我们知道 GraalVM 的使用是有一定限制的,比如 Java 的反射等动态特性是不被支持的,因此我们需要提供特殊的 Metadata 配置来绕过这些限制,在这一部分我们会讲解如何加入引入 AOT Processing 来实现自动化的 Metadata 配置,包括 Spring6 框架中 AOT 处理、Dubbo3 框架的 AOT 处理等。 +4. 最后,我们将通过一个 Spring6+Dubbo3 的应用示例,来演示如何将这么一个 Java 应用进行静态化打包。 + +## Java 应用在云时代所面临的挑战 + +首先,我们先看一下云计算时代的应用特点,以及 Java 在云时代所面临的挑战。从各个统计机构给出的数据来看,Java 语言仍然是当今最受开发者欢迎的编程语言之一,仅次于一些脚本开发语言。使用 Java 语言可以非常高效的开发业务应用,丰富的生态使得 Java 具有非常高的开发和运行效率,有无数的应用基于 Java 语言开发。 + +![image.png](/imgs/blog/2023/6/graalvm/language-rank.png) + +但在来到云计算时代,Java 应用的部署和运行开始面临非常多的问题。我们以Serverless为例,Serverless是云上的一种越来越主流的部署模式,它让开发者更专注业务逻辑、通过快速弹性等帮助解决资源问题,根据最新的一些数据,Java在所有云计算厂商的 Serverless 运行时中所占比例并不高,远远不能和它在传统应用开发中所占的比例相匹配。 + +![image.png](/imgs/blog/2023/6/graalvm/serverless-lang-rank.png) + +出现这样的原因,主要是Java应用不能很好的满足Serverless场景的几个关键要求。 + +- **首先是启动速度问题,Java 冷启动的耗时是比较长的**。这对于Serverless需要快速弹起的场景是一个非常大的挑战,因为 Java 应用的拉起时间可能是秒、数十秒级别的; +- **第二点,Java应用往往都需要一定的预热时间,才能达到最佳的性能状态**,刚刚拉起的应用如果分配比较大的流量是不合适的,往往会出现请求超时、资源占用过高等问题,这就进一步拉长了 Java 应用的有效拉起时间; +- **第三点是 Java 应用对运行环境的要求,它往往需要较大的内存、计算资源**,而这些真正分配给业务自身的并不多,都消耗在一些JVM运行时上,这与用云降本提效的目标并不匹配; +- **最后,Java应用打出来的包或者镜像也是非常大**,从总体上也影响存储、拉取的效率。 + +接下来,我们具体看一下针对 Java 应用所面临的这些问题, GraalVM 这样一种打包和运行时技术是如何解决的。 + +## GraalVM 简介 + +> GraalVM compiles your Java applications ahead of time into standalone binaries that start instantly, provide peak performance with no warmup, and use fewer resources. + +引用官方介绍来看,GraalVM 为 Java 应用提供 AOT 编译和二进制打包能力,基于 GraalVM 打出的二进制包可以实现快速启动、具有超高性能、无需预热时间、同时需要非常少的资源消耗。这里所说的 AOT 是发生在编译期间的一个技术简称,即 Ahead-of-time,这一点我们后续会讲到。总的来说 GraalVM 可以分为两部分内容来看 + +- 首先,**GraalVM 是一个完整的 JDK 发行版本**,从这一点它是与 OpenJDK 对等的,可以运行任何面向jvm的语言开发的应用; +- 其次,**GraalVM提供了 Native Image 打包技术**,这可以将应用打包为可以独立运行的二进制包,这个包是自包含的、可脱离 JVM 运行的应用程序。 + +![image.png](/imgs/blog/2023/6/graalvm/graalvm-compilation.png) + +如上图所示,GraalVM 编译器提供了 JIT 和 AOT 两种模式。 + +- 对于 JIT 而言,我们都知道Java类会被编译为 .class 格式的文件,这里编译后就是 jvm 识别的字节码,在 Java 应用运行的过程中,而 JIT 编译器又将一些热点路径上的字节码编译为机器码,已实现更快的执行速度; +- 对于 AOT 模式来说,它直接在编译期间就将字节码转换为机器码,直接省去了运行时对jvm的依赖,由于省去了 jvm 加载和字节码运行期预热的时间,AOT 编译和打包的程序具有非常高的运行时效率。 + +![image.png](/imgs/blog/2023/6/graalvm/graalvm-compilation2.png) + +总的来说,JIT 使得应用可以具备更高的极限处理能力,可以降低请求的最大延迟这一关键指标;而 AOT 则可以进一步的提升应用的冷启动速度、具有更小的二进制包提及、在运行态需要更少的内存等资源。 + +## 什么是 Native Image? + +我们上面多次提到 GraalVM 中 Native Image 概念,Native Image 是一项将 Java 代码编译打包为可执行二进制程序的技术,打出的包中仅包含运行期所需要的代码,包括应用自身代码、标准依赖包、 语言运行时、JDK 库关联的静态代码。这个包的运行不再需要 jvm 环境,当然它是和具体的机器环境相绑定的,需要为不同的机器环境单独打包。 Native Image 有这里列出来的一系列特点: + +- 仅包含 JVM 运行所需的一部分资源,运行成本更低 +- 毫秒级的启动时间 +- 启动后即进入最佳状态,无需预热 +- 可打包为更轻量的二进制包,让部署速度更快更高效 +- 安全程度更高 + +![image.png](/imgs/blog/2023/6/graalvm/graalvm-advantages.png) + +总结起来就是这里的关键几项:更快的启动速度、更少的资源占用、更小的安全漏洞风险、更紧凑的二进制包体积。解决 Java 应用在 Sererless 等云计算应用场景中面临的突出问题。 + +## GraalVM Native Image 的基本原理与使用 + +接下来,我们看一下 GraalVM 的基本使用方式,首先,需要安装 native-image 需要的相关基础依赖,根据不同的操作系统环境会有所差异,接下来可以使用 GraalVM JDK 下载器下载 native-image。都安装好之后,第二步,就可以使用 native-image 命令编译和打包 Java 应用了,输入可以是 class 文件、jar文件、Java模块等,最终打包为一个可独立运行的可执行文件,比如这里的 HelloWorld。另外,GraalVM 也提供了对应的 Maven和Gradle构建工具插件,让打包过程更容易。 + +![image.png](/imgs/blog/2023/6/graalvm/graalvm-principal.png) + +GraalVM 基于叫做 “closed world assumption” 即封闭世界假设的概念,要求在编译期间程序的所有运行时资源和行为即能被完全确定下来。图中是具体的 AOT 编译和打包过程,左侧应用代码、仓库、jdk等全部作为输入,GraalVM以 main 为入口,扫描所有可触达的代码与执行路径,在处理过程中可能会涉及到一些前置初始化动作,最终 AOT 编译的机器码和一些初始化资源等状态数据,被打包为可执行的 Native 包。 + +相比于传统的 JVM 部署模式,GraalVM Native Image 模式带来的非常大的不同。 + +- GraalVM 在编译构建期间就会以 main 函数为入口,完成对应用代码的静态分析 +- 在静态分析期间无法被触达的代码,将会被移除,不会包含在最终的二进制包中 +- GraalVM 无法识别代码中的一些动态调用行为,如反射、resource资源加载、序列化、动态代理等都动态行为都将受限 +- Classpath 在构建阶段就固化下来,无法修改 +- 不再支持延迟的类加载,所有可用类和代码在程序启动阶段就确定了 +- 还有一些其他的 Java 应用能力是受限使用的(比如类初始化提前等) + +GraalVM 不支持反射等动态特性,而我们的很多应用和框架中却大量使用了反射、动态代理等特性,如何才能将这些应用打包为 Native Image 实现静态化那? GraalVM 提供了元数据配置入口,通过为所有动态特性提供配置文件,“closed world assumption” 模式还是成立的,可以让 GraalVM 在编译期知道所有的预期行为。这里给了两个例子: + +1. 编码方式上,比如这里反射的编码方式,可以让 GraalVM 通过代码分析计算 Metadata + +![image.png](/imgs/blog/2023/6/graalvm/metadata-1.png) + +![image.png](/imgs/blog/2023/6/graalvm/metadata-2.png) + +2. 另一个示例是提供额外的 json 配置文件并放在指定的目录 META-INF/native-image// 下。 + +![image.png](/imgs/blog/2023/6/graalvm/metadata-3.png) +## AOT Processing +Java 应用或框架中的反射等动态特性的使用是影响 GraalVM 使用的障碍,而大量的框架都存在这个限制,如果都要求应用或者开发者提供 Metadata 配置的话将会是一项非常有挑战的任务,因此,Spring 和 Dubbo 等框架都在 AOT Compilation 即 AOT 编译之前引入了 AOT Processing 即 AOT 预处理的过程,AOT Processing 用来完成自动化的 Metadata 采集,并将 Metadata 提供给 AOT 编译器使用。 + +![image.png](/imgs/blog/2023/6/graalvm/aot.png) + +AOT 编译机制是对所有 Java 应用通用的,但相比于 AOT 编译,AOT Processing 采集 Metadata 的过程是每个框架都不同的,因为每个框架对于反射、动态代理等都有自己的用法。 +我们以一个典型的 Spring + Dubbo 的微服务应用为例,要实现这个应用的静态化打包,这里涉及到 Spring、Dubbo 以及一众第三方依赖的 Metadata 处理过程。 + +- Spring - Spring AOT processing +- Dubbo - Dubbo AOT processing +- Third-party libraries - Reachability Metadata + +对于 Spring 来说,Spring6 中发布了 Spring AOT 机制,用来支持 Spring 应用的静态化预处理;Dubbo 最近也在 3.2 版本中发布了 Dubbo AOT 机制,让 Dubbo 相关组件可以自动化实现 Native 预处理;除了这两个与业务开发密切相关的框架,一个应用中往往还有大量的第三方依赖,这些依赖的 Metadata 也是影响静态化的关键,如果它们中有反射、类加载等行为,那么需要为它们提供 Metadata 配置,对于这些第三方应用目前有两个渠道,一个是 GraalVM 官方提供的共享空间,这里有相当一部分依赖的 Metadata 配置可供使用(https://github.com/oracle/graalvm-reachability-metadata),另一种方式则是要求组件官方发布的发布中包含 Metadata 配置,对于这两种情况 GraalVM 都可以做到对于 Metadata 的自动读取。 + +### Spring AOT + +接下来我们看一下 Spring AOT 做了哪些编译之前的预处理工作,Spring 框架中有非常多的动态特性,比如自动配置、条件 Bean 等特性。Spring AOT 就是针对针对这些动态特性,在构建阶段进行预处理,生成可供 GraalVM 使用的一系列 Metadata 输入,这里生成的内容包括: + +- Spring Bean 定义相关的代码预生成,如下图展示代码段 +- 在构建阶段生成动态代理相关代码 +- 关于一些反射等使用的 JSON 元数据文件 + +![image.png](/imgs/blog/2023/6/graalvm/spring-aot.png) + +### Dubbo AOT +Dubbo AOT 做的事情与 Spring AOT 非常类似,只不过 Dubbo AOT 是专门针对 Dubbo 框架特有的使用方式进行预处理,这包括: + +- SPI 扩展相关的源代码生成 +- 一些反射使用的 JSON 配置文件生成 +- RPC 代理类代码生成 + +![image.png](/imgs/blog/2023/6/graalvm/dubbo-aot-1.png) + +![image.png](/imgs/blog/2023/6/graalvm/dubbo-aot-2.png) + +## Spring6 + Dubbo3 示例演示 + +接下来,我们通过一个 Spring6 + Dubbo3 的示例微服务应用,演示如何使用 Spring AOT、Dubbo AOT 等,来实现应用的 Native Image 打包。 + +完整的代码示例可在这里下载:[dubbo-samples-native-image](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-native-image-registry) + +### 第一步:安装GraalVM + +1. 在Graalvm官网根据自己的系统选取对应Graalvm版本:[https://www.graalvm.org/downloads/](https://www.graalvm.org/downloads/) +2. 根据官方文档安装 native-image:[Getting Started with Native Image](https://www.graalvm.org/latest/reference-manual/native-image/#install-native-image) + +### 第二步:创建项目 + +这个示例应用就是普通的、常见的微服务应用,我们使用 SpringBoot3 进行应用配置开发,使用 Dubbo3 定义并发布 RPC 服务;应用构建工具使用 Maven。 + +![image.png](/imgs/blog/2023/6/graalvm/demo-1.png) + +![image.png](/imgs/blog/2023/6/graalvm/demo-2.png) + +### 第三步:配置 Maven 插件 + +重点是增加 spring-boot-maven-plugin、native-maven-plugin、dubbo-maven-plugin 三个插件配置,开启 AOT 处理过程,修改dubbo-maven-plugin中的mainClass为所需的启动类全路径。(其中API使用方式无需添加spring-boot-maven-plugin依赖。) + +```xml + + + native + + + + maven-compiler-plugin + + 17 + true + true + + + + org.springframework.boot + spring-boot-maven-plugin + + + process-aot + + process-aot + + + + + + org.graalvm.buildtools + native-maven-plugin + 0.9.20 + + ${project.build.outputDirectory} + + true + + 22.3 + + + + add-reachability-metadata + + add-reachability-metadata + + + + + + org.apache.dubbo + dubbo-maven-plugin + ${dubbo.version} + + com.example.nativedemo.NativeDemoApplication + + + + process-sources + + dubbo-process-aot + + + + + + + + +``` + +### 第四步:在Pom依赖中添加native相关的依赖 + +另外,对于 Dubbo 而言,由于当前一些 Native 机制依赖 JDK17 等版本,Dubbo 没有将一些包默认打包到发行版本中,因此需要增加两个额外的依赖 dubbo-spring6 适配和 dubbo-native 组件。 +```xml + + org.apache.dubbo + dubbo-config-spring6 + ${dubbo.version} + + + org.apache.dubbo + dubbo-native + ${dubbo.version} + +``` + +### 第五步:调整compiler、proxy、serialization和logger + +同时,这个示例对于第三方组件的支持目前也是受限的,主要是第三方组件的 Reachability Metadata 。比如目前支持的网络通信或编码组件有 Netty 和 Fastjson2;支持的日志等组件为 Logback;微服务组件有 Nacos、Zookeeper 等。 + +- 序列化方式目前支持的比较好的是Fastjson2 +- compiler、proxy目前只能选择jdk +- logger目前需要配置slf4j,目前仅支持logback + +示例配置如下: +```yaml +dubbo: + application: + name: ${spring.application.name} + logger: slf4j + protocol: + name: dubbo + port: -1 + serialization: fastjson2 + registry: + id: zk-registry + address: zookeeper://127.0.0.1:2181 + config-center: + address: zookeeper://127.0.0.1:2181 + metadata-report: + address: zookeeper://127.0.0.1:2181 + provider: + serialization: fastjson2 + consumer: + serialization: fastjson2 +``` + +### 第六步:编译 + +在项目根路径下执行以下编译命令: + +- API方式直接执行 + +``` + mvn clean install -P native -Dmaven.test.skip=true +``` + +- 注解和xml方式(Springboot3集成的方式) + +```shell + mvn clean install -P native native:compile -Dmaven.test.skip=true +``` + +### 第七步:执行二进制文件即可 + +二进制文件在 target/ 目录下,一般以工程名称为二进制包的名称,比如 target/native-demo + +## 总结 + +GraalVM 技术为 Java 在云计算时代的应用带来了新的变革,帮助解决了 Java 应用启动慢、资源占用,但同时我们也看到了 GraalVM 的使用也存在一些限制,因此 Spring6、SpringBoot3、Dubbo3 都提供了相应的 Native 解决方案。 Apache Dubbo 社区接下来将在周边生态组件等推进整体的 Native 静态化。 diff --git a/content/en/blog/integration/dubbo-integrate-with-hystrix.md b/content/en/blog/integration/dubbo-integrate-with-hystrix.md new file mode 100644 index 000000000000..a615ab8a0508 --- /dev/null +++ b/content/en/blog/integration/dubbo-integrate-with-hystrix.md @@ -0,0 +1,209 @@ +--- +title: "Spring应用快速集成Dubbo + Hystrix" +linkTitle: "Spring应用快速集成Dubbo + Hystrix" +date: 2018-08-22 +tags: ["生态", "Java"] +description: > + 本文介绍在spring应用里,怎么把Dubbo和Hystrix结合起来使用。 +--- + + +## 背景 + +Hystrix 旨在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以及监控和配置等功能。 + +Dubbo是Alibaba开源的,目前国内最流行的java rpc框架。 + +本文介绍在spring应用里,怎么把Dubbo和Hystrix结合起来使用。 + +- +- + +## Spring Boot应用 + +Demo地址: + +### 生成dubbo集成spring boot的应用 + +对于不熟悉dubbo 集成spring boot应用的同学,可以在这里直接生成dubbo + spring boot的工程: + +### 配置spring-cloud-starter-netflix-hystrix + +spring boot官方提供了对hystrix的集成,直接在pom.xml里加入依赖: + +```xml + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + 1.4.4.RELEASE + +``` + +然后在Application类上增加`@EnableHystrix`来启用hystrix starter: + +```java +@SpringBootApplication +@EnableHystrix +public class ProviderApplication { +``` + +### 配置Provider端 + +在Dubbo的Provider上增加`@HystrixCommand`配置,这样子调用就会经过Hystrix代理。 + +```java +@Service(version = "1.0.0") +public class HelloServiceImpl implements HelloService { + @HystrixCommand(commandProperties = { + @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), + @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") }) + @Override + public String sayHello(String name) { + // System.out.println("async provider received: " + name); + // return "annotation: hello, " + name; + throw new RuntimeException("Exception to show hystrix enabled."); + } +} +``` + +### 配置Consumer端 + +对于Consumer端,则可以增加一层method调用,并在method上配置`@HystrixCommand`。当调用出错时,会走到`fallbackMethod = "reliable"`的调用里。 + +```java + @Reference(version = "1.0.0") + private HelloService demoService; + + @HystrixCommand(fallbackMethod = "reliable") + public String doSayHello(String name) { + return demoService.sayHello(name); + } + public String reliable(String name) { + return "hystrix fallback value"; + } +``` + +通过上面的配置,很简单地就完成了Spring Boot里Dubbo + Hystrix的集成。 + +## 传统Spring Annotation应用 + +Demo地址: + +传统spring annotation应用的配置其实也很简单,和spring boot应用不同的是: + +1. 显式配置Spring AOP支持:`@EnableAspectJAutoProxy` +2. 显式通过`@Configuration`配置`HystrixCommandAspect` Bean。 + +```java + @Configuration + @EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.annotation.action") + @PropertySource("classpath:/spring/dubbo-consumer.properties") + @ComponentScan(value = {"com.alibaba.dubbo.samples.annotation.action"}) + @EnableAspectJAutoProxy + static public class ConsumerConfiguration { + + @Bean + public HystrixCommandAspect hystrixCommandAspect() { + return new HystrixCommandAspect(); + } + } +``` + +## Hystrix集成Spring AOP原理 + +在上面的例子里可以看到,Hystrix对Spring的集成是通过Spring AOP来实现的。下面简单分析下实现。 + +```java +@Aspect +public class HystrixCommandAspect { + @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)") + public void hystrixCommandAnnotationPointcut() { + } + @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)") + public void hystrixCollapserAnnotationPointcut() { + } + + @Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()") + public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable { + Method method = getMethodFromTarget(joinPoint); + Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint); + if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) { + throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " + + "annotations at the same time"); + } + MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method)); + MetaHolder metaHolder = metaHolderFactory.create(joinPoint); + HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder); + ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ? + metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType(); + + Object result; + try { + if (!metaHolder.isObservable()) { + result = CommandExecutor.execute(invokable, executionType, metaHolder); + } else { + result = executeObservable(invokable, executionType, metaHolder); + } + } catch (HystrixBadRequestException e) { + throw e.getCause() != null ? e.getCause() : e; + } catch (HystrixRuntimeException e) { + throw hystrixRuntimeExceptionToThrowable(metaHolder, e); + } + return result; + } +``` + +1. `HystrixCommandAspect`里定义了两个注解的AspectJ Pointcut:`@HystrixCommand`, `@HystrixCollapser`。所有带这两个注解的spring bean都会经过AOP处理 +2. 在`@Around` AOP处理函数里,可以看到Hystrix会创建出`HystrixInvokable`,再通过`CommandExecutor`来执行 + +## spring-cloud-starter-netflix-hystrix的代码分析 + +1. `@EnableHystrix` 引入了`@EnableCircuitBreaker`,`@EnableCircuitBreaker`引入了`EnableCircuitBreakerImportSelector` + + ```java + @EnableCircuitBreaker + public @interface EnableHystrix { + } + + @Import(EnableCircuitBreakerImportSelector.class) + public @interface EnableCircuitBreaker { + } + ``` + +2. `EnableCircuitBreakerImportSelector`继承了`SpringFactoryImportSelector`,使spring加载`META-INF/spring.factories`里的`EnableCircuitBreaker`声明的配置 + + 在`META-INF/spring.factories`里可以找到下面的配置,也就是引入了`HystrixCircuitBreakerConfiguration`。 + + ```properties + org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\ + org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration + ``` + +3. 在`HystrixCircuitBreakerConfiguration`里可以发现创建了`HystrixCommandAspect` + + ```java + @Configuration + public class HystrixCircuitBreakerConfiguration { + + @Bean + public HystrixCommandAspect hystrixCommandAspect() { + return new HystrixCommandAspect(); + } + ``` + +可见`spring-cloud-starter-netflix-hystrix`实际上也是创建了`HystrixCommandAspect`来集成Hystrix。 + +另外`spring-cloud-starter-netflix-hystrix`里还有metrics, health, dashboard等集成。 + +## 总结 + +- 对于dubbo provider的`@Service`是一个spring bean,直接在上面配置`@HystrixCommand`即可 +- 对于dubbo consumer的`@Reference`,可以通过加一层简单的spring method包装,配置`@HystrixCommand`即可 +- Hystrix本身提供`HystrixCommandAspect`来集成Spring AOP,配置了`@HystrixCommand`和`@HystrixCollapser`的spring method都会被Hystrix处理 + +## 链接 + +- +- +- +- diff --git a/content/en/blog/integration/dubbo-meet-arthas.md b/content/en/blog/integration/dubbo-meet-arthas.md new file mode 100644 index 000000000000..ffc626b46fb6 --- /dev/null +++ b/content/en/blog/integration/dubbo-meet-arthas.md @@ -0,0 +1,367 @@ +--- +title: "当Dubbo遇上Arthas:排查问题的实践" +linkTitle: "当Dubbo遇上Arthas:排查问题的实践" +date: 2019-02-02 +tags: ["生态", "Java"] +description: > + 使用Alibaba开源的应用诊断利器Arthas来排查Dubbo应用的问题。 +--- + + + +Apache Dubbo是Alibaba开源的高性能RPC框架,在国内有非常多的用户。 + +* Github: https://github.com/apache/dubbo +* 文档:http://dubbo.apache.org/zh-cn/ + +Arthas是Alibaba开源的应用诊断利器,9月份开源以来,Github Star数三个月超过6000。 + +* Github: https://github.com/alibaba/arthas +* 文档:https://arthas.aliyun.com/doc/ +* Arthas开源交流QQ群: 916328269 +* Arthas开源交流钉钉群: 21965291 + +当Dubbo遇上Arthas,会碰撞出什么样的火花呢?下面来分享Arthas排查Dubbo问题的一些经验。 + +### dubbo-arthas-demo + +下面的排查分享基于这个`dubbo-arthas-demo`,非常简单的一个应用,浏览器请求从Spring MVC到Dubbo Client,再发送到Dubbo Server。 + +Demo里有两个spring boot应用,可以先启动`server-demo`,再启动`client-demo`。 + +* https://github.com/hengyunabc/dubbo-arthas-demo + +``` + /user/{id} -> UserService -> UserServiceImpl + Browser Dubbo Client Dubbo Server +``` + +Client端: + +```java +@RestController +public class UserController { + + @Reference(version = "1.0.0") + private UserService userService; + + @GetMapping("/user/{id}") + public User findUserById(@PathVariable Integer id) { + return userService.findUser(id); + } +``` + +Server端: + +```java +@Service(version = "1.0.0") +public class UserServiceImpl implements UserService { + @Override + public User findUser(int id) { + if (id < 1) { + throw new IllegalArgumentException("user id < 1, id: " + id); + } + for (User user : users) { + if (user.getId() == id) { + return user; + } + } + throw new RuntimeException("Can not find user, id: " + id); + } +``` + +### Arthas快速开始 + +* https://arthas.aliyun.com/doc/install-detail.html + +```bash +$ wget https://arthas.aliyun.com/arthas-boot.jar +$ java -jar arthas-boot.jar +``` + +启动后,会列出所有的java进程,选择1,然后回车,就会连接上`ServerDemoApplication` + +```bash +$ java -jar arthas-boot.jar +* [1]: 43523 ServerDemoApplication + [2]: 22342 + [3]: 44108 ClientDemoApplication +1 +[INFO] arthas home: /Users/hengyunabc/.arthas/lib/3.0.5/arthas +[INFO] Try to attach process 43523 +[INFO] Attach process 43523 success. +[INFO] arthas-client connect 127.0.0.1 3658 + ,---. ,------. ,--------.,--. ,--. ,---. ,---. + / O \ | .--. ''--. .--'| '--' | / O \ ' .-' +| .-. || '--'.' | | | .--. || .-. |`. `-. +| | | || |\ \ | | | | | || | | |.-' | +`--' `--'`--' '--' `--' `--' `--'`--' `--'`-----' + +wiki: https://arthas.aliyun.com/doc +version: 3.0.5 +pid: 43523 +time: 2018-12-05 16:23:52 + +$ +``` + + +### Dubbo线上服务抛出异常,怎么获取调用参数? + +* https://arthas.aliyun.com/doc/watch.html + +当线上服务抛出异常时,最着急的是什么参数导致了抛异常? + +在demo里,访问 http://localhost:8080/user/0 ,`UserServiceImpl`就会抛出一个异常,因为user id不合法。 + +在Arthas里执行 `watch com.example.UserService * -e -x 2 '{params,throwExp}'` ,然后再次访问,就可以看到watch命令把参数和异常都打印出来了。 + +``` +$ watch com.example.UserService * -e -x 2 '{params,throwExp}' +Press Ctrl+C to abort. +Affect(class-cnt:1 , method-cnt:4) cost in 230 ms. +ts=2018-12-05 16:26:44; [cost=3.905523ms] result=@ArrayList[ + @Object[][ + @Integer[0], + ], + java.lang.IllegalArgumentException: user id < 1, id: 0 + at com.example.UserServiceImpl.findUser(UserServiceImpl.java:24) + at com.alibaba.dubbo.common.bytecode.Wrapper1.invokeMethod(Wrapper1.java) + at com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:45) + at com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:71) + at com.alibaba.dubbo.config.invoker.DelegateProviderMetaDataInvoker.invoke(DelegateProviderMetaDataInvoker.java:48) + at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:52) + at com.alibaba.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:61) +``` + +### 怎样线上调试Dubbo服务代码? + +* https://arthas.aliyun.com/doc/redefine.html + +在本地开发时,可能会用到热部署工具,直接改代码,不需要重启应用。但是在线上环境,有没有办法直接动态调试代码?比如增加日志。 + +在Arthas里,可以通过`redefine`命令来达到线上不重启,动态更新代码的效果。 + +比如我们修改下`UserServiceImpl`,用`System.out`打印出具体的`User`对象来: + +```java + public User findUser(int id) { + if (id < 1) { + throw new IllegalArgumentException("user id < 1, id: " + id); + } + for (User user : users) { + if (user.getId() == id) { + System.out.println(user); + return user; + } + } + throw new RuntimeException("Can not find user, id: " + id); + } +``` + +本地编绎后,把`server-demo/target/classes/com/example/UserServiceImpl.class`传到线上服务器,然后用`redefine`命令来更新代码: + +``` +$ redefine -p /tmp/UserServiceImpl.class +redefine success, size: 1 +``` + +这样子更新成功之后,访问 http://localhost:8080/user/1 ,在`ServerDemoApplication`的控制台里就可以看到打印出了user信息。 + +### 怎样动态修改Dubbo的logger级别? + +* https://arthas.aliyun.com/doc/ognl.html +* https://arthas.aliyun.com/doc/sc.html +* https://commons.apache.org/dormant/commons-ognl/language-guide.html + +在排查问题时,需要查看到更多的信息,如果可以把logger级别修改为`DEBUG`,就非常有帮助。 + +`ognl`是apache开源的一个轻量级表达式引擎。下面通过Arthas里的`ognl`命令来动态修改logger级别。 + +首先获取Dubbo里`TraceFilter`的一个logger对象,看下它的实现类,可以发现是log4j。 + +```bash +$ ognl '@com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter@logger.logger' +@Log4jLogger[ + FQCN=@String[com.alibaba.dubbo.common.logger.support.FailsafeLogger], + logger=@Logger[org.apache.log4j.Logger@2f19bdcf], +] +``` + +再用`sc`命令来查看具体从哪个jar包里加载的: + +```bash +$ sc -d org.apache.log4j.Logger + class-info org.apache.log4j.Logger + code-source /Users/hengyunabc/.m2/repository/org/slf4j/log4j-over-slf4j/1.7.25/log4j-over-slf4j-1.7.25.jar + name org.apache.log4j.Logger + isInterface false + isAnnotation false + isEnum false + isAnonymousClass false + isArray false + isLocalClass false + isMemberClass false + isPrimitive false + isSynthetic false + simple-name Logger + modifier public + annotation + interfaces + super-class +-org.apache.log4j.Category + +-java.lang.Object + class-loader +-sun.misc.Launcher$AppClassLoader@5c647e05 + +-sun.misc.Launcher$ExtClassLoader@59878d35 + classLoaderHash 5c647e05 + +Affect(row-cnt:1) cost in 126 ms. +``` + +**可以看到log4j是通过slf4j代理的。** + +那么通过`org.slf4j.LoggerFactory`获取`root` logger,再修改它的level: + +``` +$ ognl '@org.slf4j.LoggerFactory@getLogger("root").setLevel(@ch.qos.logback.classic.Level@DEBUG)' +null +$ ognl '@org.slf4j.LoggerFactory@getLogger("root").getLevel().toString()' +@String[DEBUG] +``` +可以看到修改之后,`root` logger的level变为`DEBUG`。 + +### 怎样减少测试小姐姐重复发请求的麻烦? + +* https://arthas.aliyun.com/doc/tt.html + +在平时开发时,可能需要测试小姐姐发请求过来联调,但是我们在debug时,可能不小心直接跳过去了。这样子就尴尬了,需要测试小姐姐再发请求过来。 + +Arthas里提供了`tt`命令,可以减少这种麻烦,可以直接重放请求。 + +```bash +$ tt -t com.example.UserServiceImpl findUser +Press Ctrl+C to abort. +Affect(class-cnt:1 , method-cnt:1) cost in 145 ms. + INDEX TIMESTAMP COST(ms) IS-RET IS-EXP OBJECT CLASS METHOD +---------------------------------------------------------------------------------------------------------------- + 1000 2018-12-05 17:47:52 1.56523 true false 0x3233483 UserServiceImpl findUser + 1001 2018-12-05 17:48:03 0.286176 false true 0x3233483 UserServiceImpl findUser + 1002 2018-12-05 17:48:11 90.324335 true false 0x3233483 UserServiceImpl findUser +``` + +上面的`tt -t`命令捕获到了3个请求。然后通过`tt --play`可以重放请求: + +```bash +$ tt --play -i 1000 + RE-INDEX 1000 + GMT-REPLAY 2018-12-05 17:55:50 + OBJECT 0x3233483 + CLASS com.example.UserServiceImpl + METHOD findUser + PARAMETERS[0] @Integer[1] + IS-RETURN true + IS-EXCEPTION false + RETURN-OBJ @User[ + id=@Integer[1], + name=@String[Deanna Borer], + ] +Time fragment[1000] successfully replayed. +Affect(row-cnt:1) cost in 4 ms. +``` + +### Dubbo运行时有哪些Filter? 耗时是多少? + +* https://arthas.aliyun.com/doc/trace.html + +Dubbo运行时会加载很多的Filter,那么一个请求会经过哪些Filter处理,Filter里的耗时又是多少呢? + +通过Arthas的`trace`命令,可以很方便地知道Filter的信息,可以看到详细的调用栈和耗时。 + +```bash +$ trace com.alibaba.dubbo.rpc.Filter * +Press Ctrl+C to abort. +Affect(class-cnt:19 , method-cnt:59) cost in 1441 ms. +`---ts=2018-12-05 19:07:26;thread_name=DubboServerHandler-30.5.125.152:20880-thread-10;id=3e;is_daemon=true;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@5c647e05 + `---[8.435844ms] com.alibaba.dubbo.rpc.filter.EchoFilter:invoke() + +---[0.124572ms] com.alibaba.dubbo.rpc.Invocation:getMethodName() + +---[0.065123ms] java.lang.String:equals() + `---[7.762928ms] com.alibaba.dubbo.rpc.Invoker:invoke() + `---[7.494124ms] com.alibaba.dubbo.rpc.filter.ClassLoaderFilter:invoke() + +---[min=0.00355ms,max=0.049922ms,total=0.057637ms,count=3] java.lang.Thread:currentThread() + +---[0.0126ms] java.lang.Thread:getContextClassLoader() + +---[0.02188ms] com.alibaba.dubbo.rpc.Invoker:getInterface() + +---[0.004115ms] java.lang.Class:getClassLoader() + +---[min=0.003906ms,max=0.014058ms,total=0.017964ms,count=2] java.lang.Thread:setContextClassLoader() + `---[7.033486ms] com.alibaba.dubbo.rpc.Invoker:invoke() + `---[6.869488ms] com.alibaba.dubbo.rpc.filter.GenericFilter:invoke() + +---[0.01481ms] com.alibaba.dubbo.rpc.Invocation:getMethodName() +``` + +### Dubbo动态代理是怎样实现的? + +* https://arthas.aliyun.com/doc/jad.html +* com.alibaba.dubbo.common.bytecode.Wrapper + +通过Arthas的`jad`命令,可以看到Dubbo通过javaassist动态生成的Wrappr类的代码: + +```java +$ jad com.alibaba.dubbo.common.bytecode.Wrapper1 + +ClassLoader: ++-sun.misc.Launcher$AppClassLoader@5c647e05 + +-sun.misc.Launcher$ExtClassLoader@59878d35 + +Location: +/Users/hengyunabc/.m2/repository/com/alibaba/dubbo/2.5.10/dubbo-2.5.10.jar + +package com.alibaba.dubbo.common.bytecode; + +public class Wrapper1 +extends Wrapper +implements ClassGenerator.DC { + + public Object invokeMethod(Object object, String string, Class[] arrclass, Object[] arrobject) throws InvocationTargetException { + UserServiceImpl userServiceImpl; + try { + userServiceImpl = (UserServiceImpl)object; + } + catch (Throwable throwable) { + throw new IllegalArgumentException(throwable); + } + try { + if ("findUser".equals(string) && arrclass.length == 1) { + return userServiceImpl.findUser(((Number)arrobject[0]).intValue()); + } + if ("listUsers".equals(string) && arrclass.length == 0) { + return userServiceImpl.listUsers(); + } + if ("findUserByName".equals(string) && arrclass.length == 1) { + return userServiceImpl.findUserByName((String)arrobject[0]); + } + } +``` + +### 获取Spring context + +除了上面介绍的一些排查技巧,下面分享一个获取Spring Context,然后“为所欲为”的例子。 + +在Dubbo里有一个扩展`com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory`,把Spring Context保存到了里面。 +因此,我们可以通过`ognl`命令获取到。 + +```bash +$ ognl '#context=@com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory@contexts.iterator.next, #context.getBean("userServiceImpl").findUser(1)' +@User[ + id=@Integer[1], + name=@String[Deanna Borer], +] +``` + +* `SpringExtensionFactory@contexts.iterator.next` 获取到`SpringExtensionFactory`里保存的spring context对象 +* `#context.getBean("userServiceImpl").findUser(1)` 获取到`userServiceImpl`再执行一次调用 + +只要充分发挥想像力,组合Arthas里的各种命令,可以发挥出神奇的效果。 + +## 总结 + +本篇文章来自杭州Dubbo Meetup的分享《当DUBBO遇上Arthas - 排查问题的实践》,希望对大家线上排查Dubbo问题有帮助。 + +分享的PDF可以在 https://github.com/alibaba/arthas/issues/327 里下载。 diff --git a/content/en/blog/integration/dubbo-practice-from-guazi.md b/content/en/blog/integration/dubbo-practice-from-guazi.md new file mode 100644 index 000000000000..e3579b8e5815 --- /dev/null +++ b/content/en/blog/integration/dubbo-practice-from-guazi.md @@ -0,0 +1,175 @@ +--- +title: "Dubbo 在瓜子二手车的实践" +linkTitle: "Dubbo 在瓜子二手车的实践" +date: 2019-01-05 +description: > + 目前在瓜子的私有云上已经运行着数百个dubbo应用,上千个dubbo实例 +--- + +## 前言 + +  随着瓜子业务的不断发展,系统规模在逐渐扩大,目前在瓜子的私有云上已经运行着数百个dubbo应用,上千个dubbo实例。瓜子各部门业务迅速发展,版本没有来得及统一,各个部门都有自己的用法。随着第二机房的建设,dubbo版本统一的需求变得越发迫切。几个月前,公司发生了一次与dubbo相关的生产事故,成为了公司dubbo版本升级的诱因。 + +  接下来,我会从这次事故开始,讲讲我们这段时间所做的dubbo版本升级的历程以及dubbo后续多机房的方案。 + +## 一、Ephermal节点未及时删除导致provider不能恢复注册的问题修复 + +### 事故背景 + +  在生产环境,瓜子内部各业务线共用一套zookeeper集群作为dubbo的注册中心。2019年9月份,机房的一台交换机发生故障,导致zookeeper集群出现了几分钟的网络波动。在zookeeper集群恢复后,正常情况下dubbo的provider应该会很快重新注册到zookeeper上,但有一小部分的provider很长一段时间没有重新注册到zookeeper上,直到手动重启应用后才恢复注册。 + +### 排查过程 + +  首先,我们统计了出现这种现象的dubbo服务的版本分布情况,发现在大多数的dubbo版本中都存在这种问题,且发生问题的服务比例相对较低,在github中我们也未找到相关问题的issues。因此,推断这是一个尚未修复的且在网络波动情况的场景下偶现的问题。 + +  接着,我们便将出现问题的应用日志、zookeeper日志与dubbo代码逻辑进行相互印证。在应用日志中,应用重连zookeeper成功后provider立刻进行了重新注册,之后便没有任何日志打印。而在zookeeper日志中,注册节点被删除后,并没有重新创建注册节点。对应到dubbo的代码中,只有在`FailbackRegistry.register(url)`的`doRegister(url)`执行成功或线程被挂起的情况下,才能与日志中的情况相吻合。 + +```java + public void register(URL url) { + super.register(url); + failedRegistered.remove(url); + failedUnregistered.remove(url); + try { + // Sending a registration request to the server side + doRegister(url); + } catch (Exception e) { + Throwable t = e; + + // If the startup detection is opened, the Exception is thrown directly. + boolean check = getUrl().getParameter(Constants.CHECK_KEY, true) + && url.getParameter(Constants.CHECK_KEY, true) + && !Constants.CONSUMER_PROTOCOL.equals(url.getProtocol()); + boolean skipFailback = t instanceof SkipFailbackWrapperException; + if (check || skipFailback) { + if (skipFailback) { + t = t.getCause(); + } + throw new IllegalStateException("Failed to register " + url + " to registry " + getUrl().getAddress() + ", cause: " + t.getMessage(), t); + } else { + logger.error("Failed to register " + url + ", waiting for retry, cause: " + t.getMessage(), t); + } + + // Record a failed registration request to a failed list, retry regularly + failedRegistered.add(url); + } + } +``` +  在继续排查问题前,我们先普及下这些概念:dubbo默认使用curator作为zookeeper的客户端,curator与zookeeper是通过session维持连接的。当curator重连zookeeper时,若session未过期,则继续使用原session进行连接;若session已过期,则创建新session重新连接。而ephemeral节点与session是绑定的关系,在session过期后,会删除此session下的ephemeral节点。 + +  继续对`doRegister(url)`的代码进行进一步排查,我们发现在`CuratorZookeeperClient.createEphemeral(path)`方法中有这么一段逻辑:在`createEphemeral(path)`捕获了`NodeExistsException`,创建ephemeral节点时,若此节点已存在,则认为ephemeral节点创建成功。这段逻辑初看起来并没有什么问题,且在以下两种常见的场景下表现正常: + +1. Session未过期,创建Ephemeral节点时原节点仍存在,不需要重新创建 +1. Session已过期,创建Ephemeral节点时原节点已被zookeeper删除,创建成功 + +```java + public void createEphemeral(String path) { + try { + client.create().withMode(CreateMode.EPHEMERAL).forPath(path); + } catch (NodeExistsException e) { + } catch (Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } +``` +  但是实际上还有一种极端场景,**zookeeper的Session过期与删除Ephemeral节点不是原子性的**,也就是说客户端在得到Session过期的消息时,Session对应的Ephemeral节点可能还未被zookeeper删除。此时dubbo去创建Ephemeral节点,发现原节点仍存在,故不重新创建。待Ephemeral节点被zookeeper删除后,便会出现dubbo认为重新注册成功,但实际未成功的情况,也就是我们在生产环境遇到的问题。 + +  此时,问题的根源已被定位。定位问题之后,我们与dubbo社区交流,发现考拉的同学也遇到过同样的问题,更确定了这个原因。 + +### 问题的复现与修复 + +  定位到问题之后,我们便开始尝试本地复现。由于zookeeper的Session过期但Ephemeral节点未被删除的场景直接模拟比较困难,我们通过修改zookeeper源码,在Session过期与删除Ephemeral节点的逻辑中增加了一段休眠时间,间接模拟出这种极端场景,并在本地复现了此问题。 + +  在排查问题的过程中,我们发现kafka的旧版本在使用zookeeper时也遇到过类似的问题,并参考kafka关于此问题的修复方案,确定了dubbo的修复方案。在创建Ephemeral节点捕获到`NodeExistsException`时进行判断,若Ephemeral节点的SessionId与当前客户端的SessionId不同,则删除并重建Ephemeral节点。在内部修复并验证通过后,我们向社区提交了issues及pr。 + +  kafka类似问题issues:https://issues.apache.org/jira/browse/KAFKA-1387 + +  dubbo注册恢复问题issues:https://github.com/apache/dubbo/issues/5125 + +## 二、瓜子的dubbo升级历程 + +  上文中的问题修复方案已经确定,但我们显然不可能在每一个dubbo版本上都进行修复。在咨询了社区dubbo的推荐版本后,我们决定在dubbo2.7.3版本的基础上,开发内部版本修复来这个问题。并借这个机会,开始推动公司dubbo版本的统一升级工作。 + +### 为什么要统一dubbo版本 +1. 统一dubbo版本后,我们可以在此版本上内部紧急修复一些dubbo问题(如上文的dubbo注册故障恢复失效问题)。 +2. 瓜子目前正在进行第二机房的建设,部分dubbo服务也在逐渐往第二机房迁移。统一dubbo版本,也是为dubbo的多机房做铺垫。 +3. 有利于我们后续对dubbo服务的统一管控。 +4. dubbo社区目前的发展方向与我们公司现阶段对dubbo的一些诉求相吻合,如支持gRPC、云原生等。 + +### 为什么选择dubbo2.7.3 +1. 在我们之前,携程与dubbo社区合作进行了携程dubbo内部版本的升级,并在社区2.7.3版本上修复了很多兼容性问题。感谢携程的同学帮我们踩坑~ +2. dubbo2.7.3版本在当时虽然是最新的版本,但已经发布了2个月的时间,从社区issues反馈来看,dubbo2.7.3相对dubbo2.7之前的几个版本,在兼容性方面要好很多。 +3. 我们也咨询了dubbo社区的同学,推荐升级版本为2.7.3。 + +### 内部版本定位 + +  基于社区dubbo2.7.3版本开发的dubbo内部版本属于过渡性质的版本,目的是为了修复线上provider不能恢复注册的问题,以及一些社区dubbo2.7.3的兼容性问题。瓜子的dubbo最终还是要跟随社区的版本,而不是开发自已的内部功能。因此我们在dubbo内部版本中修复的所有问题均与社区保持了同步,以保证后续可以兼容升级到社区dubbo的更高版本。 + +### 兼容性验证与升级过程 + +  我们在向dubbo社区的同学咨询了版本升级方面的相关经验后,于9月下旬开始了dubbo版本的升级工作。 +1. **初步兼容性验证** +首先,我们梳理了一些需要验证的兼容性case,针对公司内部使用较多的dubbo版本,与dubbo2.7.3一一进行了兼容性验证。经验证,除dubboX外,dubbo2.7.3与其他dubbo版本均兼容。dubboX由于对dubbo协议进行了更改,与dubbo2.7.3不兼容。 +1. **生产环境兼容性验证** +在初步验证兼容性通过后,我们与业务线合作,挑选了一些重要程度较低的项目,在生产环境对dubbo2.7.3与其他版本的兼容性进行了进一步验证。并在内部版本修复了一些兼容性问题。 +1. **推动公司dubbo版本升级** +在10月初,完成了dubbo兼容性验证后,我们开始在各个业务线推动dubbo的升级工作。截止到12月初,已经有30%的dubbo服务的完成了版本升级。按照排期,预计于2020年3月底前完成公司dubbo版本的统一升级。 + +### 兼容性问题汇总 + +  在推动升级dubbo2.7.3版本的过程整体上比较顺利,当然也遇到了一些兼容性问题: +* **创建zookeeper节点时提示没有权限** + dubbo配置文件中已经配置了zookeeper的用户名密码,但在创建zookeeper节点时却抛出`KeeperErrorCode = NoAuth`的异常,这种情况分别对应两个兼容性问题: + * issues:https://github.com/apache/dubbo/issues/5076 + dubbo在未配置配置中心时,默认使用注册中心作为配置中心。通过注册中心的配置信息初始化配置中心配置时,由于遗漏了用户名密码,导致此问题。 + * issues:https://github.com/apache/dubbo/issues/4991 + dubbo在建立与zookeeper的连接时会根据zookeeper的address复用之前已建立的连接。当多个注册中心使用同一个address,但权限不同时,就会出现`NoAuth`的问题。 + 参考社区的pr,我们在内部版本进行了修复。 + +* **curator版本兼容性问题** + * dubbo2.7.3与低版本的curator不兼容,因此我们默认将curator版本升级至4.2.0 + ```xml + + org.apache.curator + curator-framework + 4.2.0 + + + org.apache.curator + curator-recipes + 4.2.0 + + ``` + * 分布式调度框架elastic-job-lite强依赖低版本的curator,与dubbo2.7.3使用的curator版本不兼容,这给dubbo版本升级工作带来了一定阻塞。考虑到elastic-job-lite已经很久没有人进行维护,目前一些业务线计划将elastic-job-lite替换为其他的调度框架。 +* **openFeign与dubbo兼容性问题** + issues: https://github.com/apache/dubbo/issues/3990 + dubbo的ServiceBean监听spring的ContextRefreshedEvent,进行服务暴露。openFeign提前触发了ContextRefreshedEvent,此时ServiceBean还未完成初始化,于是就导致了应用启动异常。 + 参考社区的pr,我们在内部版本修复了此问题。 +* **RpcException兼容性问题** + dubbo低版本consumer不能识别dubbo2.7版本provider抛出的`org.apache.dubbo.rpc.RpcException`。因此,在consumer全部升级到2.7之前,不建议将provider的`com.alibaba.dubbo.rpc.RpcException`改为`org.apache.dubbo.rpc.RpcException` +* **qos端口占用** + dubbo2.7.3默认开启qos功能,导致一些混部在物理机的dubbo服务升级时出现qos端口占用问题。关闭qos功能后恢复。 +* **自定义扩展兼容性问题** + 业务线对于dubbo的自定义扩展比较少,因此在自定义扩展的兼容性方面暂时还没有遇到比较难处理的问题,基本上都是变更package导致的问题,由业务线自行修复。 +* **skywalking agent兼容性问题** + 我们项目中一般使用skywalking进行链路追踪,由于skywalking agent6.0的plugin不支持dubbo2.7,因此统一升级skywalking agent到6.1。 + +## 三、dubbo多机房方案 + +  瓜子目前正在进行第二机房的建设工作,dubbo多机房是第二机房建设中比较重要的一个话题。在dubbo版本统一的前提下,我们就能够更顺利的开展dubbo多机房相关的调研与开发工作。 + +### 初步方案 + +  我们咨询了dubbo社区的建议,并结合瓜子云平台的现状,初步确定了dubbo多机房的方案。 +1. 在每个机房内,部署一套独立的zookeeper集群。集群间信息不同步。这样就没有了zookeeper集群跨机房延迟与数据不同步的问题。 +1. dubbo服务注册时,仅注册到本机房的zookeeper集群;订阅时,同时订阅两个机房的zookeeper集群。 +1. 实现同机房优先调用的路由逻辑。以减少跨机房调用导致的不必要网络延迟。 + +### 同机房优先调用 + +  dubbo同机房优先调用的实现比较简单,相关逻辑如下: +1. 瓜子云平台默认将机房的标志信息注入容器的环境变量中。 +1. provider暴露服务时,读取环境变量中的机房标志信息,追加到待暴露服务的url中。 +1. consumer调用provider时,读取环境变量中的机房标志信息,根据路由策略优先调用具有相同标志信息的provider。 + +  针对以上逻辑,我们简单实现了dubbo通过环境变量进行路由的功能,并向社区提交了pr。 +  dubbo通过环境变量路由pr: https://github.com/apache/dubbo/pull/5348 diff --git a/content/en/blog/integration/dubbo-registry-nacos-integration.md b/content/en/blog/integration/dubbo-registry-nacos-integration.md new file mode 100644 index 000000000000..9530926e99bc --- /dev/null +++ b/content/en/blog/integration/dubbo-registry-nacos-integration.md @@ -0,0 +1,562 @@ +--- +title: "Dubbo 融合 Nacos 成为注册中心" +linkTitle: "Dubbo 融合 Nacos 成为注册中心" +date: 2018-11-07 +tags: ["生态", "Java"] +description: 本文介绍了如何在 Dubbo 中使用 Nacos 作为服务注册中心 +--- + + +Nacos 作为 Dubbo 生态系统中重要的注册中心实现,其中 [`dubbo-registry-nacos`](https://github.com/apache/dubbo/tree/master/dubbo-registry/dubbo-registry-nacos) 则是 Dubbo 融合 Nacos 注册中心的实现。 + + + +## 预备工作 + +当您将 [`dubbo-registry-nacos`](https://github.com/apache/dubbo/tree/master/dubbo-registry/dubbo-registry-nacos) 整合到您的 Dubbo 工程之前,请确保后台已经启动 Nacos 服务。如果您尚且不熟悉 Nacos 的基本使用的话,可先行参考 [Nacos 快速入门](https://nacos.io/en-us/docs/quick-start.html):https://nacos.io/en-us/docs/quick-start.html。建议使用 Nacos `0.6.1` 以上的版本。 + + + +## 快速上手 + +Dubbo 融合 Nacos 成为注册中心的操作步骤非常简单,大致步骤可分为“增加 Maven 依赖”以及“配置注册中心“。 + + + +### 增加 Maven 依赖 + +首先,您需要 `dubbo-registry-nacos` 的 Maven 依赖添加到您的项目中 `pom.xml` 文件中,并且强烈地推荐您使用 Dubbo `2.6.5`: + +```xml + + + ... + + + + com.alibaba + dubbo-registry-nacos + 0.0.2 + + + + + com.alibaba.nacos + nacos-client + [0.6.1,) + + + + + com.alibaba + dubbo + 2.6.5 + + + + + com.alibaba.spring + spring-context-support + 1.0.2 + + + ... + + +``` + + + +当项目中添加 `dubbo-registry-nacos` 后,您无需显示地编程实现服务发现和注册逻辑,实际实现由该三方包提供,接下来配置 Naocs 注册中心。 + + + +### 配置注册中心 + +假设您 Dubbo 应用使用 Spring Framework 装配,将有两种配置方法可选,分别为:[Dubbo Spring 外部化配置](https://mercyblitz.github.io/2018/01/18/Dubbo-%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE/)以及 Spring XML 配置文件以及 ,笔者强烈推荐前者。 + + + +### [Dubbo Spring 外部化配置](https://mercyblitz.github.io/2018/01/18/Dubbo-%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE/) + +Dubbo Spring 外部化配置是由 Dubbo `2.5.8` 引入的新特性,可通过 Spring `Environment` 属性自动地生成并绑定 Dubbo 配置 Bean,实现配置简化,并且降低微服务开发门槛。 + +假设您 Dubbo 应用的使用 Zookeeper 作为注册中心,并且其服务器 IP 地址为:`10.20.153.10`,同时,该注册地址作为 Dubbo 外部化配置属性存储在 `dubbo-config.properties` 文件,如下所示: + +```properties +## application +dubbo.application.name = your-dubbo-application + +## Zookeeper registry address +dubbo.registry.address = zookeeper://10.20.153.10:2181 +... +``` + + + +假设您的 Nacos Server 同样运行在服务器 `10.20.153.10` 上,并使用默认 Nacos 服务端口 `8848`,您只需将 `dubbo.registry.address` 属性调整如下: + + + +```properties +## 其他属性保持不变 + +## Nacos registry address +dubbo.registry.address = nacos://10.20.153.10:8848 +... +``` + + + +随后,重启您的 Dubbo 应用,Dubbo 的服务提供和消费信息在 Nacos 控制台中可以显示: + +![image-20181213103845976](/imgs/blog/dubbo-registry-nacos-1.png) + + + +如图所示,服务名前缀为 `providers:` 的信息为服务提供者的元信息,`consumers:` 则代表服务消费者的元信息。点击“**详情**”可查看服务状态详情: + +![image-20181213104145998](/imgs/blog/dubbo-registry-nacos-2.png) + + + +如果您正在使用 Spring XML 配置文件装配 Dubbo 注册中心的话,请参考下一节。 + + + +### Spring XML 配置文件 + +同样,假设您 Dubbo 应用的使用 Zookeeper 作为注册中心,并且其服务器 IP 地址为:`10.20.153.10`,并且装配 Spring Bean 在 XML 文件中,如下所示: + +```xml + + + + + + + + + ... + +``` + + + +与 [Dubbo Spring 外部化配置](https://mercyblitz.github.io/2018/01/18/Dubbo-%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE/) 配置类似,只需要调整 `address` 属性配置即可: + +```xml + + + + + + + + + ... + +``` + + + +重启 Dubbo 应用后,您同样也能发现服务提供方和消费方的注册元信息呈现在 Nacos 控制台中: + +![image-20181213113049185](/imgs/blog/dubbo-registry-nacos-3.png) + + + +您是否绝对配置或切换 Nacos 注册中心超级 Easy 呢?如果您仍旧意犹未尽或者不甚明白的话,可参考以下完整的示例。 + + + +## 完整示例 + +以上图片中的元数据源于 Dubbo Spring 注解驱动示例以及 Dubbo Spring XML 配置驱动示例,下面将分别介绍两者,您可以选择自己偏好的编程模型。在正式讨论之前,先来介绍两者的预备工作,因为它们皆依赖 Java 服务接口和实现。同时,**请确保本地(`127.0.0.1`)环境已启动 Nacos 服务**。 + + + +### 示例接口与实现 + + + +首先定义示例接口,如下所示: + +```java +package com.alibaba.dubbo.demo.service; + +/** + * DemoService + * + * @since 2.6.5 + */ +public interface DemoService { + + String sayName(String name); + +} +``` + + + +提供以上接口的实现类: + +```java +package com.alibaba.dubbo.demo.service; + +import com.alibaba.dubbo.config.annotation.Service; +import com.alibaba.dubbo.rpc.RpcContext; + +import org.springframework.beans.factory.annotation.Value; + +/** + * Default {@link DemoService} + * + * @since 2.6.5 + */ +@Service(version = "${demo.service.version}") +public class DefaultService implements DemoService { + + @Value("${demo.service.name}") + private String serviceName; + + public String sayName(String name) { + RpcContext rpcContext = RpcContext.getContext(); + return String.format("Service [name :%s , port : %d] %s(\"%s\") : Hello,%s", + serviceName, + rpcContext.getLocalPort(), + rpcContext.getMethodName(), + name, + name); + } +} +``` + + + +接口与实现准备妥当后,下面将采用注解驱动和 XML 配置驱动各自实现。 + + + +### Spring 注解驱动示例 + + Dubbo `2.5.7` 重构了 Spring 注解驱动的编程模型。 + + + +#### 服务提供方注解驱动实现 + +- 定义 Dubbo 提供方外部化配置属性源 - `provider-config.properties` + +```properties +## application +dubbo.application.name = dubbo-provider-demo + +## Nacos registry address +dubbo.registry.address = nacos://127.0.0.1:8848 + +## Dubbo Protocol +dubbo.protocol.name = dubbo +dubbo.protocol.port = -1 + +# Provider @Service version +demo.service.version=1.0.0 +demo.service.name = demoService +``` + + + +- 实现服务提供方引导类 - `DemoServiceProviderBootstrap` + +```java +package com.alibaba.dubbo.demo.provider; + +import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; +import com.alibaba.dubbo.demo.service.DemoService; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.PropertySource; + +import java.io.IOException; + +/** + * {@link DemoService} provider demo + */ +@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.demo.service") +@PropertySource(value = "classpath:/provider-config.properties") +public class DemoServiceProviderBootstrap { + + public static void main(String[] args) throws IOException { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(DemoServiceProviderBootstrap.class); + context.refresh(); + System.out.println("DemoService provider is starting..."); + System.in.read(); + } +} + +``` + +其中注解 `@EnableDubbo` 激活 Dubbo 注解驱动以及外部化配置,其 `scanBasePackages` 属性扫描指定 Java 包,将所有标注 `@Service` 的服务接口实现类暴露为 Spring Bean,随即被导出 Dubbo 服务。 + + `@PropertySource` 是 Spring Framework 3.1 引入的标准导入属性配置资源注解,它将为 Dubbo 提供外部化配置。 + + + +#### 服务消费方注解驱动实现 + +- 定义 Dubbo 消费方外部化配置属性源 - `consumer-config.properties` + +```properties +## Dubbo Application info +dubbo.application.name = dubbo-consumer-demo + +## Nacos registry address +dubbo.registry.address = nacos://127.0.0.1:8848 + +# @Reference version +demo.service.version= 1.0.0 +``` + +同样地,`dubbo.registry.address` 属性指向 Nacos 注册中心,其他 Dubbo 服务相关的元信息通过 Nacos 注册中心获取。 + + + +- 实现服务消费方引导类 - `DemoServiceConsumerBootstrap` + +```java +package com.alibaba.dubbo.demo.consumer; + +import com.alibaba.dubbo.config.annotation.Reference; +import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; +import com.alibaba.dubbo.demo.service.DemoService; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.PropertySource; + +import javax.annotation.PostConstruct; +import java.io.IOException; + +/** + * {@link DemoService} consumer demo + */ +@EnableDubbo +@PropertySource(value = "classpath:/consumer-config.properties") +public class DemoServiceConsumerBootstrap { + + @Reference(version = "${demo.service.version}") + private DemoService demoService; + + @PostConstruct + public void init() { + for (int i = 0; i < 10; i++) { + System.out.println(demoService.sayName("小马哥(mercyblitz)")); + } + } + + public static void main(String[] args) throws IOException { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(DemoServiceConsumerBootstrap.class); + context.refresh(); + context.close(); + } +} + +``` + + + +同样地,`@EnableDubbo` 注解激活 Dubbo 注解驱动和外部化配置,不过当前属于服务消费者,无需指定 Java 包名扫描标注 `@Service` 的服务实现。 + +`@Reference` 是 Dubbo 远程服务的依赖注入注解,需要服务提供方和消费端约定接口(interface)、版本(version)以及分组(group)信息。在当前服务消费示例中,`DemoService` 的服务版本来源于属性配置文件 `consumer-config.properties`。 + +`@PostConstruct` 部分代码则说明当 `DemoServiceConsumerBootstrap` Bean 初始化时,执行十次 Dubbo 远程方法调用。 + + + +#### 运行注解驱动示例 + +在本地启动两次 `DemoServiceProviderBootstrap`,注册中心将出现两个健康服务: + +![image-20181213123909636](/imgs/blog/dubbo-registry-nacos-4.png) + +再运行 `DemoServiceConsumerBootstrap`,运行结果如下: + +``` +Service [name :demoService , port : 20880] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :demoService , port : 20881] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :demoService , port : 20880] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :demoService , port : 20880] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :demoService , port : 20881] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :demoService , port : 20881] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :demoService , port : 20880] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :demoService , port : 20880] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :demoService , port : 20881] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :demoService , port : 20881] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +``` + +运行无误,并且服务消费方使用了负载均衡策略,将十次 RPC 调用平均分摊到两个 Dubbo 服务提供方实例中。 + + + +### Spring XML 配置驱动示例 + +Spring XML 配置驱动是传统 Spring 装配组件的编程模型。 + + + +#### 服务提供方 XML 配置驱动 + +- 定义服务提供方 XML 上下文配置文件 - `/META-INF/spring/dubbo-provider-context.xml` + +```xml + + + + + + + + + + + + + + + + + + +``` + + + +- 实现服务提供方引导类 - `DemoServiceProviderXmlBootstrap` + +```xml +package com.alibaba.dubbo.demo.provider; + +import com.alibaba.dubbo.demo.service.DemoService; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import java.io.IOException; + +/** + * {@link DemoService} provider demo XML bootstrap + */ +public class DemoServiceProviderXmlBootstrap { + + public static void main(String[] args) throws IOException { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(); + context.setConfigLocation("/META-INF/spring/dubbo-provider-context.xml"); + context.refresh(); + System.out.println("DemoService provider (XML) is starting..."); + System.in.read(); + } +} +``` + + + +#### 服务消费方 XML 配置驱动 + +- 定义服务消费方 XML 上下文配置文件 - `/META-INF/spring/dubbo-consumer-context.xml` + +```xml + + + + + + + + + + + + + +``` + + + +- 实现服务消费方引导类 - `DemoServiceConsumerXmlBootstrap` + +```java +package com.alibaba.dubbo.demo.consumer; + +import com.alibaba.dubbo.demo.service.DemoService; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import java.io.IOException; + +/** + * {@link DemoService} consumer demo XML bootstrap + */ +public class DemoServiceConsumerXmlBootstrap { + + public static void main(String[] args) throws IOException { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(); + context.setConfigLocation("/META-INF/spring/dubbo-consumer-context.xml"); + context.refresh(); + System.out.println("DemoService consumer (XML) is starting..."); + DemoService demoService = context.getBean("demoService", DemoService.class); + for (int i = 0; i < 10; i++) { + System.out.println(demoService.sayName("小马哥(mercyblitz)")); + } + context.close(); + } +} +``` + + + +#### 运行 XML 配置驱动示例 + +同样地,先启动两个 `DemoServiceProviderXmlBootstrap` 引导类,观察 Nacos 注册中心服务提供者变化: + +![image-20181213125527201](/imgs/blog/dubbo-registry-nacos-5.png) + +XML 配置驱动的服务版本为 `2.0.0`,因此注册服务无误。 + + + +再运行服务消费者引导类 `DemoServiceConsumerXmlBootstrap`,观察控制台输出内容: + +``` +Service [name :null , port : 20882] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :null , port : 20882] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :null , port : 20883] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :null , port : 20882] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :null , port : 20882] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :null , port : 20883] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :null , port : 20882] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :null , port : 20883] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :null , port : 20883] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +Service [name :null , port : 20883] sayName("小马哥(mercyblitz)") : Hello,小马哥(mercyblitz) +``` + +结果同样运行和负载均衡正常,不过由于当前示例尚未添加属性 `demo.service.name` 的缘故,因此,“name”部分信息输出为 `null`。更多内容请参考:https://github.com/apache/dubbo/tree/master/dubbo-registry/dubbo-registry-nacos。 + + + +如果您关注或喜爱 Dubbo 以及 Nacos 等开源工程,不妨为它们点 “star”,加油打气链接: + +- Apache Dubbo:https://github.com/apache/dubbo +- Dubbo Nacos Registry:https://github.com/apache/dubbo/tree/master/dubbo-registry/dubbo-registry-nacos +- Alibaba Nacos:https://github.com/alibaba/nacos diff --git a/content/en/blog/integration/dubbo-spring-cloud.md b/content/en/blog/integration/dubbo-spring-cloud.md new file mode 100644 index 000000000000..8cc1b73889fa --- /dev/null +++ b/content/en/blog/integration/dubbo-spring-cloud.md @@ -0,0 +1,213 @@ +--- +title: "微服务最佳实践,零改造实现 Spring Cloud & Apache Dubbo 互通" +linkTitle: "微服务最佳实践,零改造实现 Spring Cloud & Apache Dubbo 互通" +tags: ["spring-cloud"] +authors: ["孙彩荣"] +date: 2023-10-07 +description: "步演示如何以最低成本实现 Apache Dubbo 体系与 Spring Cloud 体系的互通,进而实现不同微服务体系的混合部署、迁移等,帮助您解决实际架构及业务问题。" +--- + +**本文以实际项目和代码为示例,一步一步演示如何以最低成本实现 Apache Dubbo 体系与 Spring Cloud 体系的互通,进而实现不同微服务体系的混合部署、迁移等,帮助您解决实际架构及业务问题。** +## 背景与目标 +如果你在微服务开发过程中正面临以下一些业务场景需要解决,那么这篇文章可以帮到您: + +- 您已经有一套基于 Dubbo 构建的微服务应用,这时你需要将部分服务通过 REST HTTP 的形式(非接口、方法模式)发布出去,供一些标准的 HTTP 端调用(如 Spring Cloud 客户端),整个过程最好是不用改代码,直接为写好的 Dubbo 服务加一些配置、注解就能实现。 +- 您已经有一套基于 Spring Cloud 构建的微服务体系,而后又构建了一套 Dubbo 体系的微服务,你想两套体系共存,因此现在两边都需要调用到对方发布的服务。也就是 Dubbo 应用作为消费方要调用到 Spring Cloud 发布的 HTTP 接口,Dubbo 应用作为提供方还能发布 HTTP 接口给 Spring Cloud 调用 +- 出于一些历史原因,你正规划从一个微服务体系迁移到另外一个微服务体系,前提条件是要保证中间过程的平滑迁移。 + +![image.png](/imgs/blog/2023/9/springcloud/img.png) + +对于以上几个场景,我们都可以借助 Dubbo3 内置的 REST 编程范式支持实现,这让 Dubbo 既可以作为消费方调用 HTTP 接口的服务,又可以作为提供方对外发布 REST 风格的 HTTP 服务,同时整个编码过程支持业界常用的 REST 编程范式(如 JAX-RS、Spring MVC 等),因此可以做到基本不改动任何代码的情况下实现 Dubbo 与 Spring Cloud 体系的互相调用。 + +- 关于这一部分更多的设计与理论阐述请参见这里的 [博客文章](https://dubbo.apache.org/zh-cn/blog/2023/01/05/dubbo-%E8%BF%9E%E6%8E%A5%E5%BC%82%E6%9E%84%E5%BE%AE%E6%9C%8D%E5%8A%A1%E4%BD%93%E7%B3%BB-%E5%A4%9A%E5%8D%8F%E8%AE%AE%E5%A4%9A%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83/)。 +- 关于 Dubbo REST 的更多配置方式请参见 [rest 使用参考手册](/en/overview/mannual/java-sdk/reference-manual/protocol/rest/) +## 示例一:Dubbo 调用 Spring Cloud +在已经有一套 Spring Cloud 微服务体系的情况下,演示如何使用 Dubbo 调用 Spring Cloud 服务(包含自动的地址发现与协议传输)。在注册中心方面,本示例使用 Nacos 作为注册中心,对于 Zookeeper、Consul 等两种体系都支持的注册中心同样适用。 + +![dubbo-call-spring-cloud](/imgs/blog/2023/9/springcloud/img_1.png) + +设想你已经有一套 Spring Cloud 的微服务体系,现在我们将引入 Dubbo 框架,让 Dubbo 应用能够正常的调用到 Spring Cloud 发布的服务。本示例完整源码请参见 [samples/dubbo-call-sc](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-springcloud/dubbo-call-sc)。 + +### 启动 Spring Cloud Server + +示例中 Spring Cloud 应用的结构如下 + +![springcloud-server.png](/imgs/blog/2023/9/springcloud/img_2.png) + +应用配置文件如下: +```yaml +server: + port: 8099 +spring: + application: + name: spring-cloud-provider-for-dubbo + cloud: + nacos: + serverAddr: 127.0.0.1:8848 #注册中心 +``` + +以下是一个非常简单的 Controller 定义,发布了一个 `/users/list/`的 http 端点 +```java +@RestController +@RequestMapping("/users") +public class UserController { + @GetMapping("/list") + public List getUser() { + return Collections.singletonList(new User(1L, "spring cloud server")); + } +} +``` + +启动 `SpringCloudApplication`,通过 cURL 或浏览器访问 `http://localhost:8099/users/list` 可以测试应用启动成功。 +### 使用 Dubbo Client 调用服务 +Dubbo client 也是一个标准的 Dubbo 应用,项目基本结构如下: + +![dubbo-consumer.png](/imgs/blog/2023/9/springcloud/img_3.png) + +其中,一个比较关键的是如下接口定义(正常情况下,以下接口可以直接从原有的 Spring Cloud client 应用中原样拷贝过来即可,无需做任何修改)。 +> 如果之前没有基于 OpenFeign 的 Spring Cloud 消费端应用,那么就需要自行定义一个接口,此时不一定要使用 OpenFeign 注解,使用 Spring MVC 标准注解即可。 + +```java +@FeignClient(name = "spring-cloud-provider-for-dubbo") +public interface UserServiceFeign { + @RequestMapping(value="/users/list", method = RequestMethod.GET, produces = "application/json") + List users(); +} +``` + +通过 `DubboReference` 注解将 UserServiceFeign 接口注册为 Dubbo 服务 +```java +@DubboReference +private UserServiceFeign userService; +``` + +接下来,我们就可以用 Dubbo 标准的方式对服务发起调用了 +```java +List users = userService.users(); +``` + +通过 `DubboConsumerApplication` 启动 Dubbo 应用,验证可以成功调用到 Spring Cloud 服务。 +## 示例二:Spring Cloud 调用 Dubbo +在接下来的示例中,我们将展示如何将 Dubbo server 发布的服务开放给 Spring Cloud client 调用。 + +![spring-cloud-call-dubbo](/imgs/blog/2023/9/springcloud/img_4.png) + +示例的相关源码在 [samples/sc-call-dubbo](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-springcloud/sc-call-dubbo) +### 启动 Dubbo Server +Dubbo server 应用的代码结构非常简单,是一个典型的 Dubbo 应用。 + +![dubbo-server.png](/imgs/blog/2023/9/springcloud/img_5.png) + +相比于普通的 Dubbo 服务定义,我们要在接口上加上如下标准 Spring MVC 注解: + +```java +@RestController +@RequestMapping("/users") +public interface UserService { + @GetMapping(value = "/list") + List getUsers(); +} +``` + +除了以上注解之外,其他服务发布等流程都一致,使用 `DubboService` 注解发布服务即可: + +```java +@DubboService +public class UserServiceImpl implements UserService { + @Override + public List getUsers() { + return Collections.singletonList(new User(1L, "Dubbo provider!")); + } +} +``` + +在服务配置上,特别注意我们需要将服务的协议配置为 rest `protocol: rest`,地址发现模式使用 `register-mode: instance`: + +```yaml +dubbo: + registry: + address: nacos://127.0.0.1:8848 + register-mode: instance + protocol: + name: rest + port: 8090 +``` + +启动 Dubbo 应用,此时访问以下地址可以验证服务运行正常:`http://localhost:8090/users/list` + +### 使用 Spring Cloud 调用 Dubbo +使用 OpenFeign 开发一个标准的 Spring Cloud 应用,即可调用以上发布的 Dubbo 服务,项目代码结构如下: + +![springcloud-consumer.png](/imgs/blog/2023/9/springcloud/img_6.png) + +其中,我们定义了一个 OpenFeign 接口,用于调用上面发布的 Dubbo rest 服务。 +```java +@FeignClient(name = "dubbo-provider-for-spring-cloud") +public interface UserServiceFeign { + @RequestMapping(value = "/users/list", method = RequestMethod.GET) + List getUsers(); +} +``` + +定义以下 controller 作为 OpenFeign 和 RestTemplate 测试入口。 +```java +public class UserController { + + private final RestTemplate restTemplate; + private final UserServiceFeign userServiceFeign; + + public UserController(RestTemplate restTemplate, + UserServiceFeign userServiceFeign) { + this.restTemplate = restTemplate; + this.userServiceFeign = userServiceFeign; + } + + @RequestMapping("/rest/test1") + public String doRestAliveUsingEurekaAndRibbon() { + String url = "http://dubbo-provider-for-spring-cloud/users/list"; + System.out.println("url: " + url); + return restTemplate.getForObject(url, String.class); + } + + @RequestMapping("/rest/test2") + public List doRestAliveUsingFeign() { + return userServiceFeign.getUsers(); + } +} +``` + +根据以上 Controller 定义,我们可以分别访问以下地址进行验证: + +- OpenFeign 方式:`http://localhost:8099/dubbo/rest/test1`、 +- RestTemplate 方式:`http://localhost:8099/dubbo/rest/test1` + +### 为 Dubbo Server 发布更多的服务 +我们可以利用 Dubbo 的多协议发布机制,为一些服务配置多协议发布。接下来,我们就为上面提到的 Dubbo server 服务增加 dubbo tcp 协议发布,从而达到以下部署效果,让这个 Dubbo 应用同时服务 Dubbo 微服务体系和 Spring Cloud 微服务体系。 + +![dubbo-multiple-protocols.png](/imgs/blog/2023/9/springcloud/img_7.png) + +为了实现这个效果,我们只需要在配置中增加多协议配置即可: +```yaml +dubbo: + protocols: + - id: rest + name: rest + port: 8090 + - id: dubbo + name: dubbo + port: 20880 +``` + +同时,服务注解中也配置为多协议发布 +```java +@DubboService(protocol="rest,dubbo") +public class UserServiceImpl implements UserService {} +``` + +这样,我们就成功的将 UserService 服务以 dubbo 和 rest 两种协议发布了出去(多端口多协议的方式),dubbo 协议为 Dubbo 体系服务,rest 协议为 Spring Cloud 体系服务。 + +> **注意:**Dubbo 为多协议发布提供了单端口、多端口两种方式,这样的灵活性对于不同部署环境下的服务会有比较大的帮助。在确定您需要的多协议发布方式前,请提仔细阅读以下 [多协议配置](/en/overview/mannual/java-sdk/advanced-features-and-usage/service/multi-protocols) 文档。 + + +## 总结 +基于 Dubbo 的 rest 编程范式、多协议发布等特性,可以帮助你轻松的实现从 Dubbo 到 Spring Cloud 或者从 Spring Cloud 到 Dubbo 的平滑迁移(无改造成本),同时也可以实现 Dubbo 与 Spring Cloud 两套体系的共存。 diff --git a/content/en/blog/integration/dubbo-triple-with-apisix-gateway.md b/content/en/blog/integration/dubbo-triple-with-apisix-gateway.md new file mode 100644 index 000000000000..ffd3d6521ef7 --- /dev/null +++ b/content/en/blog/integration/dubbo-triple-with-apisix-gateway.md @@ -0,0 +1,154 @@ +--- +description: | + 本文为大家介绍了如何借助 Apache APISIX 实现 triple 协议代理,使用 nacos 作为注册中心。 +linkTitle: 使用 Apache APISIX 代理 Dubbo 服务(triple协议) +title: 使用 Apache APISIX 代理 Dubbo 服务(triple协议) +type: docs +date: 2024-04-22 +weight: 2 +--- + +关于如何用网关代理 triple 协议服务的原理介绍,请参见 [HTTP 网关接入](/en/overview/mannual/java-sdk/tasks/gateway/triple/) 一节文档。 + +本文我们使用 `Apache APISIX + triple 协议 + Nacos 注册中心` 的组合,演示如何使用 Apache APISIX 代理 Dubbo 服务。 + +## 示例应用说明 + +本示例完整源码与部署资源文件可查看 [dubbo-samples-gateway-triple-apisix](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-apisix/dubbo-samples-gateway-apisix-triple),示例架构图如下: + + + +在该示例中定义并发布了一个 `org.apache.dubbo.samples.gateway.apisix.DemoService` 的 triple 服务,接口定义为: + +```java +public interface DemoService { + String sayHello(String name); +} +``` + +接口实现如下: + +```java +@DubboService +public class DemoServiceImpl implements DemoService { + @Override + public String sayHello(String name) { + return "Hello " + name; + } +} +``` + +Dubbo服务相关配置: + +```yaml +dubbo: + application: + name: gateway-apisix-triple + registry: + address: nacos://${nacos.address:127.0.0.1}:8848 + username: nacos + password: nacos + protocol: + name: tri + port: 50052 +``` + +## 部署应用 + +1. 在 [本地下载并启动 Nacos](/en/overview/reference/integrations/nacos/#本地下载) + +2. 运行以下命令,启动 Dubbo 应用。 + +下载源码: + +```shell +$ git clone -b main --depth 1 https://github.com/apache/dubbo-samples +$ cd dubbo-samples/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-apisix/dubbo-samples-gateway-apisix-triple +``` + +在 `dubbo-samples-gateway-apisix-triple` 目录,运行以下命令启动应用: + +```shell +$ mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.gateway.apisix.ProviderApplication" +``` + +运行以下命令,测试服务已经正常启动: + +```shell +curl \ + --header "Content-Type: application/json" \ + --data '["dubbo"]' \ + http://localhost:50052/org.apache.dubbo.samples.gateway.apisix.DemoService/sayHello/ +``` + +## 接入 APISIX 网关 + +本文档使用 Docker 安装 APISIX。确保本地先安装 [Docker](https://www.docker.com/) 和 [Docker Compose](https://docs.docker.com/compose/)。 + +首先,下载 [apisix-docker](https://github.com/apache/apisix-docker) 仓库。 + +```shell +$ git clone https://github.com/apache/apisix-docker.git +$ cd apisix-docker/example +``` + +由于本示例要接入到 Nacos 注册中心,因此需要修改 `apisix-docker/example` 目录下安装用的 `docker-compose.yaml`,添加如下 docker compose 配置内容: + +```yaml + nacos: + image: nacos/nacos-server:v2.1.1 + container_name: nacos-standalone + environment: + - PREFER_HOST_MODE=hostname + - MODE=standalone + ports: + - "8848:8848" + - "9848:9848" + networks: + apisix: +``` + +启动 APISIX 前,在 `conf/config.yaml` 文件中增加如下配置,[让 APISIX 连接到 Nacos 注册中心](https://apisix.apache.org/docs/apisix/discovery/nacos/#service-discovery-via-nacos): + +```yaml +discovery: + nacos: + host: + - "http://192.168.33.1:8848" +``` + +最后使用 `docker-compose` 启用 APISIX:`docker-compose -p docker-apisix up -d`。 + +### 配置服务源与路由 + +在 APISIX 中配置 Nacos upstream 及路由,即可实现后端实例地址自动发现(假设 APISIX 端口是 9080): + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d ' +{ + "uri": "/org.apache.dubbo.samples.gateway.apisix.DemoService/sayHello/", + "upstream": { + "service_name": "gateway-apisix-triple", + "type": "roundrobin", + "discovery_type": "nacos" + } +}' +``` + +> 在上述命令中,请求头 X-API-KEY 是 Admin API 的访问 token,可以在 conf/config.yaml 文件中的 apisix.admin_key.key 查看。 + +### 验证服务调用 + +使用以下命令发送请求至需要配置的路由: + +```shell +curl -i http://127.0.0.1:9080/org.apache.dubbo.samples.gateway.apisix.DemoService/sayHello/ +``` + +### REST 模式 + +如果您觉得 `/org.apache.dubbo.samples.gateway.apisix.DemoService/sayHello/` 这样的 http 端口对于网关访问不够友好,可参考 [为 triple 协议发布 rest 风格 http 接口](/en/overview/mannual/java-sdk/tasks/gateway/triple/#rest-风格接口)。 + + + + diff --git a/content/en/blog/integration/dubbo-zk.md b/content/en/blog/integration/dubbo-zk.md new file mode 100644 index 000000000000..9397641c4064 --- /dev/null +++ b/content/en/blog/integration/dubbo-zk.md @@ -0,0 +1,346 @@ +--- +title: "在 Dubbo 应用中使用 Zookeeper" +linkTitle: "在 Dubbo 应用中使用 Zookeeper" +date: 2018-08-07 +tags: ["生态", "Java"] +description: > + 本文介绍了 Zookeeper 的基本概念、用法,以及如何在 Dubbo 应用中使用 Zookeeper 作为注册中心。 +--- + +## Zookeeper 介绍 + +### 基本概念 + +在现代的分布式应用中,往往会出现节点和节点之间的协调问题,其中就包括了:选主、集群管理、分布式锁、分布式配置管理、统一命名服务、状态同步等诉求。[Apache Zookeeper](https://zookeeper.apache.org),正如它的名字所暗示的那样,*动物园管理员*,就是为了解决这些诉求的一个分布式协调服务框架。 + +为了保证高可用,ZooKeeper 本身也可以部署成集群模式,称之为 *ZooKeeper ensemble*。ZooKeeper 集群中始终确保其中的一台为 leader 的角色,并通过 *ZAB (Zookeeper Atomic Broadcast Protocol) [^1]* 协议确保所有节点上的信息的一致。客户端可以访问集群中的任何一台进行读写操作,而不用担心数据出现不一致的现象。 + +![Diagram shows client-server architecture of ZooKeeper](/imgs/blog/zk-emsemble.png) +*Image Credit : ebook -Zookeeper-Distributed Process Coordination from O'Reilly* + +Zookeeper 中的数据存储方式与传统的 UNIX 文件系统相似,节点按照树状结构来组织,其中,节点被称之为 *znodes (ZooKeeper data nodes)* + +![zk-tree](/imgs/blog/zk-tree.png) +*Image Credit : ebook -Zookeeper-Distributed Process Coordination from O'Reilly* + +### 基本用法 + +可以通过直接下载的方式 [^2]安装并运行 Zookeeper ,在 Mac 上也可以通过 Homebrew [^3] `brew install zookeeper` 来安装,考虑到通用性,本文采用 docker 的方式来运行 Zookeeper。如果没有安装 docker,请先准备好 docker 环境 [^4]。 + +#### 1. 启动 Zookeeper + +执行命令将 Zookeeper 运行在 docker 容器中 + +```shell +docker run --rm --name zookeeper -p 2181:2181 zookeeper +``` + +#### 2. 进入 Zookeeper 容器 + +```shell +docker exec -it zookeeper bash +``` + +在 `bin` 目录下有启动 Zookeeper 的命令 `zkServer` 以及管理控制台 `zkCli` + +```shell +bash-4.4# ls -l bin +total 36 +-rwxr-xr-x 1 zookeepe zookeepe 232 Mar 27 04:32 README.txt +-rwxr-xr-x 1 zookeepe zookeepe 1937 Mar 27 04:32 zkCleanup.sh +-rwxr-xr-x 1 zookeepe zookeepe 1056 Mar 27 04:32 zkCli.cmd +-rwxr-xr-x 1 zookeepe zookeepe 1534 Mar 27 04:32 zkCli.sh +-rwxr-xr-x 1 zookeepe zookeepe 1759 Mar 27 04:32 zkEnv.cmd +-rwxr-xr-x 1 zookeepe zookeepe 2696 Mar 27 04:32 zkEnv.sh +-rwxr-xr-x 1 zookeepe zookeepe 1089 Mar 27 04:32 zkServer.cmd +-rwxr-xr-x 1 zookeepe zookeepe 6773 Mar 27 04:32 zkServer.sh +``` + +#### 3. 通过 zkCli 进入 Zookeeper 管理界面 + +由于是通过 Docker 启动,Zookeeper 进程已经启动,并通过 2181 端口对外提供服务。 + +```shell +bash-4.4# ps +PID USER TIME COMMAND + 1 zookeepe 0:02 /usr/lib/jvm/java-1.8-openjdk/jre/bin/java -Dzookeeper.log.dir=. -Dzookeeper.root + 32 root 0:00 bash + 42 root 0:00 ps +``` + +因此可以直接通过 `zkCli` 来访问 Zookeeper 的控制台来进行管理。 + +```shell +bash-4.4# bin/zkCli.sh -server 127.0.0.1:2181 +Connecting to 127.0.0.1:2181 +... +WATCHER:: + +WatchedEvent state:SyncConnected type:None path:null + +[zk: 127.0.0.1:2181(CONNECTED) 0] help +ZooKeeper -server host:port cmd args + stat path [watch] + set path data [version] + ls path [watch] + delquota [-n|-b] path + ls2 path [watch] + setAcl path acl + setquota -n|-b val path + history + redo cmdno + printwatches on|off + delete path [version] + sync path + listquota path + rmr path + get path [watch] + create [-s] [-e] path data acl + addauth scheme auth + quit + getAcl path + close + connect host:port +``` + +#### 4. zkCli 上的一些基本操作 + +创建 `/hello-zone` 节点: + +```shell +[zk: 127.0.0.1:2181(CONNECTED) 19] create /hello-zone 'world' +Created /hello-zone +``` + +列出 `/` 下的子节点,确认 `hello-zone` 被创建: + +```shell +[zk: 127.0.0.1:2181(CONNECTED) 20] ls / +[zookeeper, hello-zone] +``` + +列出 `/hello-zone` 的子节点,确认为空: + +```shell +[zk: 127.0.0.1:2181(CONNECTED) 21] ls /hello-zone +[] +``` + +获取存储在 `/hello-zone` 节点上的数据: + +```shell +[zk: 127.0.0.1:2181(CONNECTED) 22] get /hello-zone +world +``` + + + +## 在 Dubbo 中使用 Zookeeper + +Dubbo 使用 Zookeeper 用于服务的注册发现和配置管理,在 Zookeeper 中数据的组织由下图所示: + +![dubbo-in-zk](/imgs/blog/dubbo-in-zk.jpg) + +首先,所有 Dubbo 相关的数据都组织在 `/dubbo` 的根节点下。 + +二级目录是服务名,如 `com.foo.BarService`。 + +三级目录有两个子节点,分别是 `providers` 和 `consumers`,表示该服务的提供者和消费者。 + +四级目录记录了与该服务相关的每一个应用实例的 URL 信息,在 `providers` 下的表示该服务的所有提供者,而在 `consumers` 下的表示该服务的所有消费者。举例说明,`com.foo.BarService` 的服务提供者在启动时将自己的 URL 信息注册到 `/dubbo/com.foo.BarService/providers` 下;同样的,服务消费者将自己的信息注册到相应的 `consumers` 下,同时,服务消费者会订阅其所对应的 `providers` 节点,以便能够感知到服务提供方地址列表的变化。 + +### 准备示例代码 + +本文的代码可以在 https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-zookeeper 中找到。 + +#### 1. 接口定义 + +定义一个简单的 `GreetingService` 接口,里面只有一个简单的方法 `sayHello` 向调用者问好。 + +```java +public interface GreetingService { + String sayHello(String name); +} +``` + +#### 2. 服务端:服务实现 + +实现 `GreetingService` 接口,并通过 `@Service` 来标注其为 Dubbo 的一个服务。 + +```java +@Service +public class AnnotatedGreetingService implements GreetingService { + public String sayHello(String name) { + return "hello, " + name; + } +} +``` + +#### 3. 服务端:组装 + +定义 ProviderConfiguration 来组装 Dubbo 服务。 + +```java +@Configuration +@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.impl") +@PropertySource("classpath:/spring/dubbo-provider.properties") +static class ProviderConfiguration {} +``` + +dubbo-provider.properties 是在 Spring 应用中外置配置的方式,内容如下: + +```properties +dubbo.application.name=demo-provider +dubbo.registry.address=zookeeper://$DOCKER_HOST:2181 +dubbo.protocol.name=dubbo +dubbo.protocol.port=20880 +``` + +由于 Zookeeper 运行在 Docker 容器中,需要注意的是: + +* 本文假定 Dubbo 应用运行在宿主机上,也就是 Docker 容器外,需要将 Zookeeper 的地址替换成环境变量 *${DOCKER_HOST}* 所指定的 IP 地址,相关信息请查阅 Docker 官方文档 +* 如果 Dubbo 应用也是 Docker 化的应用,只需要用 Zookeeper 的容器名,在本文中容器名是 **zookeeper** +* 当然,如果不用容器方式启动 Zookeeper,只需要简单的将这里的 *$DOCKER_HOST* 换成 **localhost** 即可 + +#### 4. 服务端:启动服务 + +在 `main` 方法中通过启动一个 Spring Context 来对外提供 Dubbo 服务。 + +```java +public class ProviderBootstrap { + public static void main(String[] args) throws Exception { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class); + context.start(); + System.in.read(); + } +} +``` + +启动服务端的 `main` 方法,将会看到下面的输出,代表服务端启动成功,并在注册中心(ZookeeperRegistry)上注册了 `GreetingService` 这个服务: + +```sh +[03/08/18 10:50:33:033 CST] main INFO zookeeper.ZookeeperRegistry: [DUBBO] Register: dubbo://192.168.99.1:20880/com.alibaba.dubbo.samples.api.GreetingService?anyhost=true&application=demo-provider&dubbo=2.6.2&generic=false&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=12938&side=provider×tamp=1533264631849, dubbo version: 2.6.2, current host: 192.168.99.1 +``` + +通过 Zookeeper 管理终端观察服务提供方的注册信息: + +```sh +$ docker exec -it zookeeper bash +bash-4.4# bin/zkCli.sh -server localhost:218 +Connecting to localhost:2181 +... +Welcome to ZooKeeper! +JLine support is enabled +... +[zk: localhost:2181(CONNECTED) 0] ls /dubbo/com.alibaba.dubbo.samples.api.GreetingService/providers +[dubbo%3A%2F%2F192.168.99.1%3A20880%2Fcom.alibaba.dubbo.samples.api.GreetingService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26dubbo%3D2.6.2%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.samples.api.GreetingService%26methods%3DsayHello%26pid%3D12938%26side%3Dprovider%26timestamp%3D1533264631849] +``` + +可以看到刚刚启动的 Dubbo 的服务在 `providers` 节点下注册了自己的 URL 地址:*dubbo://192.168.99.1:20880/com.alibaba.dubbo.samples.api.GreetingService?anyhost=true&application=demo-provider&dubbo=2.6.2&generic=false&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=12938&side=provider×tamp=1533264631849* + +#### 5. 客户端:引用服务 + +通过 `@Reference` 来在客户端声明服务的引用,运行时将会通过该引用发起全程调用,而服务的目标地址将会从 Zookeeper 的 `provider` 节点下查询。 + +```java +@Component("annotatedConsumer") +public class GreetingServiceConsumer { + @Reference + private GreetingService greetingService; + + public String doSayHello(String name) { + return greetingService.sayHello(name); + } +} +``` + +#### 6. 客户端:组装 + +定义 ConsumerConfiguration 来组装 Dubbo 服务。 + +```java +@Configuration +@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.action") +@PropertySource("classpath:/spring/dubbo-consumer.properties") +@ComponentScan(value = {"com.alibaba.dubbo.samples.action"}) +static class ConsumerConfiguration {} +``` + +dubbo-consumer.properties 是在 Spring 应用中外置配置的方式,内容如下: + +```properties +dubbo.application.name=demo-consumer +dubbo.registry.address=zookeeper://$DOCKER_HOST:2181 +dubbo.consumer.timeout=3000 +``` + +与 **3. 服务端:组装** 相同,需要根据自己的运行环境来修改 *dubbo.registry.address* 中定义的 *$DOCKER_HOST*。请参阅步骤 3 的说明部分。 + +#### 7. 客户端:发起远程调用 + +运行 `main` 向已经启动的服务提供方发起一次远程调用。Dubbo 会先向 Zookeeper 订阅服务地址,然后从返回的地址列表中选取一个,向对端发起调用: + +```java +public class ConsumerBootstrap { + public static void main(String[] args) { +public class ConsumerBootstrap { + + public static void main(String[] args) throws IOException { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class); + context.start(); + GreetingServiceConsumer greetingServiceConsumer = context.getBean(GreetingServiceConsumer.class); + String hello = greetingServiceConsumer.doSayHello("zookeeper"); + System.out.println("result: " + hello); + System.in.read(); + } +} +``` + +运行结果如下: + +```shell +[03/08/18 01:42:31:031 CST] main INFO zookeeper.ZookeeperRegistry: [DUBBO] Register: consumer://192.168.99.1/com.alibaba.dubbo.samples.api.GreetingService?application=demo-consumer&category=consumers&check=false&default.timeout=3000&dubbo=2.6.2&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=82406&side=consumer×tamp=1533274951195, dubbo version: 2.6.2, current host: 192.168.99.1 #1 +[03/08/18 01:42:31:031 CST] main INFO zookeeper.ZookeeperRegistry: [DUBBO] Subscribe: consumer://192.168.99.1/com.alibaba.dubbo.samples.api.GreetingService?application=demo-consumer&category=providers,configurators,routers&default.timeout=3000&dubbo=2.6.2&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=82406&side=consumer×tamp=1533274951195, dubbo version: 2.6.2, current host: 192.168.99.1 #2 +... +result: hello, zookeeper +``` + +说明: + +1. **Register**: consumer://192.168.99.1/...&**category=consumers**&:消费者向 Zookeeper 注册自己的信息,并放在 `consumers` 节点下 +2. **Subscribe**: consumer://192.168.99.1/...&**category=providers,configurators,routers**&:消费者同时向 Zookeeper 订阅了 `providers`、`configurators`、`routers` 节点,其中 `configurations` 与 Dubbo 配置相关,`routers` 与路由规则相关,值得注意的是 `providers` 节点的订阅,当有新的服务提供方加入后,由于订阅的关系,新的地址列表会推送给订阅方,服务的消费者也因此动态感知到了地址列表的变化。 + +通过 Zookeeper 管理终端观察服务提供方的注册信息: + +```sh +$ docker exec -it zookeeper bash +bash-4.4# bin/zkCli.sh -server localhost:218 +Connecting to localhost:2181 +... +Welcome to ZooKeeper! +JLine support is enabled +... +[zk: localhost:2181(CONNECTED) 4] ls /dubbo/com.alibaba.dubbo.samples.api.GreetingService/consumers +[consumer%3A%2F%2F192.168.99.1%2Fcom.alibaba.dubbo.samples.api.GreetingService%3Fapplication%3Ddemo-consumer%26category%3Dconsumers%26check%3Dfalse%26default.timeout%3D3000%26dubbo%3D2.6.2%26interface%3Dcom.alibaba.dubbo.samples.api.GreetingService%26methods%3DsayHello%26pid%3D82406%26side%3Dconsumer%26timestamp%3D1533274951195] +``` + +可以看到 Dubbo 的服务消费者在 `consumers` 节点下注册了自己的 URL 地址:*consumer://192.168.99.1/com.alibaba.dubbo.samples.api.GreetingService?application=demo-consumer&category=providers,configurators,routers&default.timeout=3000&dubbo=2.6.2&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=82406&side=consumer×tamp=1533274951195* + +## 总结 + +本文侧重介绍了如何在 Dubbo 应用中使用 Zookeeper 做为注册中心,当然,本文也提到了 Zookeeper 在 Dubbo 的应用场景下还承担了配置中心和服务治理的职责。本文中的 Zookeeper 是单节点、Standalone 的模式,在生产环境中为了高可用的诉求,往往会组件 Zookeeper 集群,也就是 *Zookeeper ensemble* 模式。 + +通过本文的学习,读者可以掌握到: + +* Zookeeper 的基本概念和基本用法 +* Zookeeper 在 Dubbo 应用中的作用 +* 通过实战了解 Zookeeper 与 Dubbo 的交互 +* Dubbo 在 Zookeeper 中服务注册、消费信息的存储方式 + + + +[^1]: https://en.wikipedia.org/wiki/Atomic_broadcast +[^2]: https://www.apache.org/dyn/closer.cgi/zookeeper/ +[^3]: https://brew.sh +[^4]: https://www.docker.com/community-edition + diff --git a/content/en/blog/integration/dubbo2-js.md b/content/en/blog/integration/dubbo2-js.md new file mode 100644 index 000000000000..dc95310b626c --- /dev/null +++ b/content/en/blog/integration/dubbo2-js.md @@ -0,0 +1,278 @@ +--- +title: "从跨语言调用到dubbo2.js" +linkTitle: "从跨语言调用到dubbo2.js" +date: 2018-08-14 +tags: ["Node.js"] +description: > + 本文介绍了如何使用 dubbo2.js 进行跨语言的 dubbo 调用。 +--- + +> [dubbo2.js](https://github.com/dubbo/dubbo2.js) 是 [千米网](https://www.qianmi.com/) 贡献给 dubbo 社区的一款 nodejs dubbo 客户端,它提供了 nodejs 对原生 dubbo 协议的支持,使得 nodejs 和 java 这两种异构语言的 rpc 调用变得便捷,高效。 + +## 微服务跨语言调用 + +微服务架构已成为目前互联网架构的趋势,关于微服务的讨论,几乎占据了各种技术大会的绝大多数版面。国内使用最多的服务治理框架非阿里开源的 dubbo 莫属,千米网也选择了 dubbo 作为微服务治理框架。另一方面,和大多数互联网公司一样,千米的开发语言是多样的,大多数后端业务由 java 支撑,而每个业务线有各自开发语言的选择权,便出现了 nodejs,python,go 多语言调用的问题。 +跨语言调用是一个很大的话题,也是一个很有挑战的技术活,目前业界经常被提及的解决方案有如下几种,不妨拿出来老生常谈一番: + +- spring cloud。spring cloud 提供了一整套微服务开发组件,它主要面向 java 开发,但由于其使用的协议是基于 restful 风格的 http 协议,这使得其天然具备跨语言能力,异构语言只需要提供 http 客户端,便可以实现跨语言调用。 +- service mesh。号称下一代微服务框架的 service mesh,其解决跨语言问题的核心在于 SideCar ,SideCar 在 service mesh 的发展过程中概念不断的迁移,但本质都是完成了一件事:处理服务间通信,负责实现请求的可靠传递。 +- motan。[motan](https://github.com/weibocom/motan) 是新浪微博开源的一款跨语言服务治理框架,在其早期版本中仅支持 motan-java,随着版本演进,在目前最新版本(1.1.0)中,提供了 motan-go,motan-php,motan-openresty 等跨语言特性。类似于 service mesh 中的 SideCar,motan 借助于 motan-go 作为 agent 完成协议的转发,并且依赖于定制协议:motan2,实现跨语言调用。 + +当我们再聊跨语言调用时我们在聊什么?纵观上述几个较为通用,成熟的解决方案,可以得出结论:解决跨语言调用的思路无非是两种: + +- 寻找一个通用的协议 +- 使用 agent 完成协议的适配 + +如果一个新型的团队面临技术选型,我认为上述的方案都可以纳入参考,可考虑到遗留系统的兼容性问题 + +- 旧系统的迁移成本 + +这也关键的选型因素。我们做出的第一个尝试,便是在 RPC 协议上下功夫。 + + ## 通用协议的跨语言支持 + +### springmvc的美好时代 + +![springmvc](/imgs/blog/springmvc.png) + +在没有实现真正的跨语言调用之前,想要实现“跨语言”大多数方案是使用 http 协议做一层转换,最常见的手段莫过于借助 springmvc 提供的 controller/restController,间接调用 dubbo provider。这种方案的优势和劣势显而易见 + +- 优势是简单,是最通俗的解决方案。 +- 劣势是使得调用链路变长,tcp 通信之上又多了一层 http 通信;开发体验差,为了将 rpc 接口暴露出去,需要额外编写一份 controller 层的代码。 + +### 通用协议的支持 + +事实上,大多数服务治理框架都支持多种协议,dubbo 框架除默认的 dubbo 协议之外,还有当当网扩展的 [rest](https://dangdangdotcom.github.io/dubbox/rest.html) 协议和千米网扩展的 [json-rpc](https://github.com/apache/dubbo-rpc-jsonrpc) 协议可供选择。这两者都是通用的跨语言协议。 + +rest 协议为满足 JAX-RS 2.0 标准规范,在开发过程中引入了 @Path,@POST,@GET 等注解,习惯于编写传统 rpc 接口的人可能不太习惯 rest 风格的 rpc 接口。一方面这样会影响开发体验,另一方面,独树一帜的接口风格使得它与其他协议不太兼容,旧接口的共生和迁移都无法实现。如果没有遗留系统,rest 协议无疑是跨语言方案最简易的实现,绝大多数语言支持 rest 协议。 + +和 rest 协议类似,json-rpc 的实现也是文本序列化&http 协议。dubbox 在 restful 接口上已经做出了尝试,但是 rest 架构和 dubbo 原有的 rpc 架构是有区别的,rest 架构需要对资源(Resources)进行定义, 需要用到 http 协议的基本操作 GET、POST、PUT、DELETE。在我们看来,restful 更合适互联网系统之间的调用,而 rpc 更适合一个系统内的调用。使用 json-rpc 协议使得旧接口得以兼顾,开发习惯仍旧保留,同时获得了跨语言的能力。 + +千米网在早期实践中采用了 json-rpc 作为 dubbo 的跨语言协议实现,并开源了基于 json-rpc 协议下的 python 客户端 [dubbo-client-py](https://github.com/dubbo/dubbo-client-py) 和 node 客户端 [dubbo-node-client](https://github.com/QianmiOpen/dubbo-node-client),使用 python 和 nodejs 的小伙伴可以借助于它们直接调用 dubbo-provider-java 提供的 rpc 服务。系统中大多数 java 服务之间的互相调用还是以 dubbo 协议为主,考虑到新旧协议的适配,在不影响原有服务的基础上,我们配置了双协议。 + +```xml + + +``` + +dubbo 协议主要支持 java 间的相互调用,适配老接口;json-rpc 协议主要支持异构语言的调用。 + +### 定制协议的跨语言支持 + +微服务框架所谓的协议(protocol)可以简单理解为:报文格式和序列化方案。服务治理框架一般都提供了众多的协议配置项供使用者选择,除去上述两种通用协议,还存在一些定制化的协议,如 dubbo 框架的默认协议:dubbo 协议以及 motan 框架提供的跨语言协议:motan2。 + + #### motan2协议的跨语言支持 + +![motan2](/imgs/blog/motan-protocol.png) + +motan2 协议被设计用来满足跨语言的需求主要体现在两个细节中—MetaData 和 motan-go。在最初的 motan 协议中,协议报文仅由 Header+Body 组成,这样导致 path,param,group 等存储在 Body 中的数据需要反序列得到,这对异构语言来说是很不友好的,所以在 motan2 中修改了协议的组成;weibo 开源了 [motan-go](https://github.com/weibocom/motan-go/) ,[motan-php](https://github.com/weibocom/motan-php),[motan-openresty](https://github.com/weibocom/motan-openresty) ,并借助于 motan-go 充当了 agent 这一翻译官的角色,使用 simple 序列化方案来序列化协议报文的 Body 部分(simple 序列化是一种较弱的序列化方案)。 + +![agent](/imgs/blog/motan-agent.png) + +仔细揣摩下可以发现这么做和双协议的配置区别并不是大,只不过这里的 agent 是隐式存在的,与主服务共生。明显的区别在于 agent 方案中异构语言并不直接交互。 + +#### dubbo协议的跨语言支持 + +dubbo 协议设计之初只考虑到了常规的 rpc 调用场景,它并不是为跨语言而设计,但跨语言支持从来不是只有支持、不支持两种选择,而是要按难易 + +程度来划分。是的,dubbo 协议的跨语言调用可能并不好做,但并非无法实现。千米网便实现了这一点,nodejs 构建的前端业务是异构语言的主战场,最终实现了 dubbo2.js,打通了 nodejs 和原生 dubbo 协议。作为本文第二部分的核心内容,重点介绍下我们使用 dubbo2.js 干了什么事。 + +##### Dubbo协议报文格式 + +![dubbo协议](/imgs/blog/dubbo-protocol.png) + +dubbo协议报文消息头详解: + +- magic:类似java字节码文件里的魔数,用来判断是不是 dubbo 协议的数据包。魔数是常量 0xdabb +- flag:标志位, 一共8个地址位。低四位用来表示消息体数据用的序列化工具的类型(默认 hessian),高四位中,第一位为 1 表示是 request 请求,第二位为 1 表示双向传输(即有返回 response),第三位为 1 表示是心跳 ping 事件。 +- status:状态位, 设置请求响应状态,dubbo 定义了一些响应的类型。具体类型见`com.alibaba.dubbo.remoting.exchange.Response` +- invoke id:消息 id, long 类型。每一个请求的唯一识别 id(由于采用异步通讯的方式,用来把请求 request 和返回的 response 对应上) +- body length:消息体 body 长度, int 类型,即记录 Body Content 有多少个字节 +- body content:请求参数,响应参数的抽象序列化之后存储于此。 + +协议报文最终都会变成字节,使用 tcp 传输,任何语言只要支持网络模块,有类似 Socket 之类的封装,那么通信就不成问题。那,跨语言难在哪儿?以其他语言调用 java 来说,主要有两个难点: + +1. 异构语言如何表示 java 中的数据类型,特别是动态语言,可能不存在严格的数据类型 +2. 序列化方案如何做到跨语言 + +## dubbo2.js解决方案 + +上面我们分析出了两个难点,dubbo2.js 解决这两个问题的关键依赖于两个类库:[js-to-java](https://github.com/node-modules/js-to-java),[hessian.js](https://github.com/node-modules/hessian.js) 。js-to-java 使得 nodejs 具备 java 对象的表达能力,而 hessian.js 提供了序列化能力。借助于 nodejs 的 socket ,复制一套 dubbo 协议的报文格式,最终便实现了 nodejs 对 java-dubbo-provider 的调用。 + + ## dubbo2.js快速入门 + +为了让对 dubbo2.js 感兴趣的读者有一个直观的体验,本节呈现一个快速入门示例,让你体会到使用 dubbo2.js 调用 dubbo 服务是一件多么轻松的事。 + +### 1. 创建 dubbo-java-provider + +后端 dubbo 服务使用 java 来提供,这服务大多数的业务场景。首先定义服务接口: + +```java +public interface DemoProvider { + String sayHello(String name); + String echo() ; + void test(); + UserResponse getUserInfo(UserRequest request); +} +``` + +其次,实现服务: + +```java +public class DemoProviderImpl implements DemoProvider { + public String sayHello(String name) { + System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); + return "Hello " + name + ", response form provider: " + RpcContext.getContext().getLocalAddress(); + } + @Override + public String echo() { + System.out.println("receive...."); + return "pang"; + } + @Override + public void test() { + System.out.println("test"); + } + @Override + public UserResponse getUserInfo(UserRequest request) { + System.out.println(request); + UserResponse response = new UserResponse(); + response.setStatus("ok"); + Map map = new HashMap(); + map.put("id", "1"); + map.put("name", "test"); + response.setInfo(map); + return response; + } +} +``` + +暴露服务: + +```xml + + + + + + + + + + + + + + + + + + +``` + +我们完成了服务端的所有配置,启动启动类即可在本地注册一个 dubbo 服务。 + +```java +public class Provider { + public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-provider.xml"}); + context.start(); + System.in.read(); + } +} +``` + +### 2. 实现 nodejs 的 dubbo 客户端 + +安装 dubbo2.js: + +```sh +npm install dubbo2.js --save +``` + +配置 dubboConfig.ts: + +```typescript +import { Dubbo, java, TDubboCallResult } from 'dubbo2.js' + +const dubbo = new Dubbo({ + application: {name: 'demo-provider'}, + register: 'localhost:2181', + dubboVersion: '2.0.0', + interfaces: [ + 'com.alibaba.dubbo.demo.DemoProvider', + ], +}); + +interface IDemoService { + sayHello(name: string): TDubboCallResult; +} + +export const demoService = dubbo.proxyService({ + dubboInterface: 'com.alibaba.dubbo.demo.DemoProvider', + version: '1.0.0', + methods: { + sayHello(name: string) { + return [java.String(name)]; + }, + + echo() {}, + + test() {}, + + getUserInfo() { + return [ + java.combine('com.alibaba.dubbo.demo.UserRequest', { + id: 1, + name: 'nodejs', + email: 'node@qianmi.com', + }), + ]; + }, + }, +}); +``` + +> 使用 typescript 可以带来更好的开发体验。 + +编写调用类 main.ts: + +```typescript +import {demoService} from './dubboConfig' + +demoService.sayHello('kirito').then(({res,err})=>{ + console.log(res) +}); +``` + +### 3. 执行调用 + +Debug 模式启动 nodejs 客户端: + +```sh +DEBUG=dubbo* ts-node main.ts +``` + +查看运行结果: + +```sh +Hello kirito, response form provider: 172.19.6.151:20880 +``` + +Congratulation! + +## dubbo2.js特性 + +- 支持 zookeeper 注册中心 +- 支持原生 dubbo 协议 +- 支持服务直连 +- 全链路跟踪 +- dubbo 接口自动生成 + +## 更多细节 + +本文中的示例代码,提供在此处, 。如果你对 dubbo 协议不甚了解,想要理解它的工作原理,项目中提供了一个子 moudle — java-socket-consumer,使用面向过程的思路实现了 java-socket-consumer,完成了原生 socket 发送 dubbo 协议报文,完成方法调用,并获取响应的全流程。 diff --git a/content/en/blog/integration/how-to-proxy-dubbo-in-apache-apisix.md b/content/en/blog/integration/how-to-proxy-dubbo-in-apache-apisix.md new file mode 100644 index 000000000000..09a236bb912b --- /dev/null +++ b/content/en/blog/integration/how-to-proxy-dubbo-in-apache-apisix.md @@ -0,0 +1,283 @@ +--- +title: "使用 Apache APISIX 代理 Dubbo 服务 (dubbo 协议)" +linkTitle: "从原理到操作,让你在 Apache APISIX 中代理 Dubbo 服务更便捷" +date: 2024-04-25 +tags: ["网关", "生态", "Java"] +description: > + 本文为大家介绍了如何借助 Apache APISIX 实现 Dubbo Service 的代理,通过引入 dubbo-proxy 插件便可为 Dubbo 框架的后端系统构建更简单更高效的流量链路 +aliases: + - /en/overview/what/gateway/apisix/ + - /en/overview/what/gateway/higress/ +--- + +{{% alert title="注意" color="warning" %}} +本文仅适用于 dubbo 协议通信场景。如果您是 Dubbo3 用户,建议您使用 triple 协议,可参见 [使用 Apache APISIX 代理 Dubbo 服务(triple协议)](/en/blog/2024/04/22/使用-apache-apisix-代理-dubbo-服务triple协议/) 学习具体示例。 +{{% /alert %}} + + +[Apache APISIX](https://apisix.apache.org/) 是 Apache 软件基金会的顶级开源项目,也是当前最活跃的开源网关项目。作为一个动态、实时、高性能的开源 API 网关,Apache APISIX 提供了负载均衡、动态上游、灰度发布、服务熔断、身份认证、可观测性等丰富的流量管理功能。 + +Apache APISIX 基于开源项目 tengine/mod_dubbo 模块为 Apache Dubbo 服务配备了HTTP 网关能力。通过 dubbo-proxy 插件,可以轻松地将 Dubbo Service 发布为 HTTP 服务。 + +![架构图](/imgs/blog/apisix-plugin/1.png) + + +## 入门篇 + +### 安装 APISIX + +本文档使用 Docker 安装 APISIX。确保本地先安装 [Docker](https://www.docker.com/) 和 [Docker Compose](https://docs.docker.com/compose/)。 + +首先,下载 [apisix-docker](https://github.com/apache/apisix-docker) 仓库。 + +```shell +$ git clone https://github.com/apache/apisix-docker.git +$ cd apisix-docker/example +``` + +由于本示例要接入到 Nacos 注册中心,因此 `apisix-docker/example` 目录下安装用的 `docker-compose.yaml`,添加如下内容: + +```yaml + nacos: + image: nacos/nacos-server:v2.1.1 + container_name: nacos-standalone + environment: + - PREFER_HOST_MODE=hostname + - MODE=standalone + ports: + - "8848:8848" + - "9848:9848" + networks: + apisix: +``` + +在 config.yaml 文件中增加 nacos 注册中心配置: + +```yaml +discovery: + nacos: + host: + - "http://192.168.33.1:8848" +``` + +在 config.yaml 文件中进行 dubbo-proxy 插件启用: + +```yaml +# Add this in config.yaml +plugins: + - ... # plugin you need + - dubbo-proxy +``` + +> 如果你使用了 Apache APISIX 2.11 版本镜像,则可以省去 `dubbo-proxy` 配置环节,该版本的 APISIX-Base 中已默认编译了 Dubbo 模块,可直接使用。 + +最后,使用 `docker-compose` 启用 APISIX:`docker-compose -p docker-apisix up -d` + +### 示例说明 + +在接下来的操作中,我们将使用 [dubbo-samples-gateway-triple-apisix](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-apisix/dubbo-samples-gateway-apisix-dubbo) 项目进行部分展示。 + +在进入正式操作前,我们先简单看下 Dubbo 接口的定义、配置以及相关实现。 + +#### 接口实现一览 + +```java +public interface ApisixService { + + /** + * standard samples dubbo infterace demo + * @param context pass http infos + * @return Map pass to response http + **/ + Map apisixDubbo(Map httpRequestContext); +} +``` + +如上所示,Dubbo 接口的定义是固定的。即方法参数中 `Map` 表示 APISIX 传递给 Dubbo Provider 关于 HTTP request 的一些信息(如:header、body...)。而方法返回值的 `Map` 表示 Dubbo Provider 传递给 APISIX 要如何返回 HTTP response 的一些信息。 + +通过上述配置后,Consumer 可通过 `org.apache.dubbo.samples.gateway.apisix.dubbo.api.ApisixService` 访问其中的`apisixDubbo` 方法。具体接口实现如下: + +```java +public class ApisixServiceImpl implements ApisixService { + @Override + public Map apisixDubbo(Map httpRequestContext) { + for (Map.Entry entry : httpRequestContext.entrySet()) { + System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); + } + + Map ret = new HashMap(); + ret.put("body", "dubbo success\n"); // http response body + ret.put("status", "200"); // http response status + ret.put("test", "123"); // http response header + + return ret; + } +} +``` + +上述代码中,`ApisixServiceImpl` 会打印接收到的 `httpRequestContext`,并通过返回包含有指定 Key 的 Map 对象去描述该 Dubbo 请求的 HTTP 响应。 + +在 `dubbo-samples-gateway-apisix-dubbo` 目录,运行以下命令启动应用(或者选择使用 IDE 启动应用): + +```shell +$ git clone -b main --depth 1 https://github.com/apache/dubbo-samples +$ cd dubbo-samples/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-apisix/dubbo-samples-gateway-apisix-dubbo + +$ mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.gateway.apisix.dubbo.provider.ProviderApplication" +``` + +启动 consumer 进程,验证服务正常启动,可以被调用: + +```shell +$ mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.gateway.apisix.dubbo.consumer.ConsumerApplication" +``` + +### 接入APISIX + +1. 创建指向 Dubbo 服务的 Upstream。 + +```shell +curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "service_name": "gateway-apisix-dubbo", + "type": "roundrobin", + "discovery_type": "nacos" +}' +``` + +4. 为 DemoService 暴露一个 HTTP 路由。 + +```shell +curl http://127.0.0.1:9180/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "uris": [ + "/demo" + ], + "plugins": { + "dubbo-proxy": { + "service_name": "org.apache.dubbo.samples.gateway.apisix.dubbo.api.ApisixService", + "method": "apisixDubbo" + } + }, + "upstream_id": 1 +}' +``` + +5. 使用 curl 命令请求 Apache APISIX,并查看返回结果。 + +```shell +curl http://127.0.0.1:9080/demo -H "Host: example.org" -X POST --data '{"name": "hello"}' + +< HTTP/1.1 200 OK +< Date: Sun, 26 Dec 2021 11:33:27 GMT +< Content-Type: text/plain; charset=utf-8 +< Content-Length: 14 +< Connection: keep-alive +< test: 123 +< Server: APISIX/2.11.0 +< +dubbo success +``` + +:::note 说明 +上述代码返回中包含了 `test: 123` Header,以及 `dubbo success` 字符串作为 Body 体。这与我们在 `DemoServiceImpl` 编码的预期效果一致。 +::: + +6. 查看 Dubbo Provider 的日志。 + +``` +Key = content-length, Value = 17 +Key = host, Value = example.org +Key = content-type, Value = application/x-www-form-urlencoded +Key = body, Value = [B@70754265 +Key = accept, Value = */* +Key = user-agent, Value = curl/7.80.0 +``` + +:::note 说明 +通过 `httpRequestContext` 可以拿到 HTTP 请求的 Header 和 Body。其中 Header 会作为 Map 元素,而 Body 中 Key 值是固定的字符串"body",Value 则代表 Byte 数组。 +::: + +### 进阶篇:复杂场景示例 + +在上述的简单用例中可以看出,我们确实通过 Apache APISIX 将 Dubbo Service 发布为一个 HTTP 服务,但是在使用过程中的限制也非常明显。比如:接口的参数和返回值都必须要是 `Map`。 + +那么,如果项目中出现已经定义好、但又不符合上述限制的接口,该如何通过 Apache APISIX 来暴露 HTTP 服务呢? + +#### 操作步骤 + +针对上述场景,我们可以通过 HTTP Request Body 描述要调用的 Service 和 Method 以及对应参数,再利用 Java 的反射机制实现目标方法的调用。最后将返回值序列化为 JSON,并写入到 HTTP Response Body 中。 + +这样就可以将 Apache APISIX 的 「HTTP to Dubbo」 能力进一步加强,并应用到所有已存在的 Dubbo Service 中。具体操作可参考下方: + +1. 为已有项目增加一个 Dubbo Service 用来统一处理 HTTP to Dubbo 的转化。方法定义如下: + +```java +public class DubboInvocationParameter { + private String type; + private String value; +} + +public class DubboInvocation { + private String service; + private String method; + private DubboInvocationParameter[] parameters; +} + +public interface HTTP2DubboService { + Map invoke(Map context) throws Exception; +} +``` + +2. 提供服务实现并将其发布为标准的 Dubbo 服务。网关将所有流量都转发到这个服务,由这个服务在后端进程内完成调用转发。 + +```java +@DubboService +public class HTTP2DubboServiceImpl implements HTTP2DubboService { + + @Autowired + private ApplicationContext appContext; + + @Override + public Map invoke(Map context) throws Exception { + DubboInvocation invocation = JSONObject.parseObject((byte[]) context.get("body"), DubboInvocation.class); + Object[] args = new Object[invocation.getParameters().size()]; + for (int i = 0; i < args.length; i++) { + DubboInvocationParameter parameter = invocation.getParameters().get(i); + args[i] = JSONObject.parseObject(parameter.getValue(), Class.forName(parameter.getType())); + } + + Object svc = appContext.getBean(Class.forName(invocation.getService())); + Object result = svc.getClass().getMethod(invocation.getMethod()).invoke(args); + Map httpResponse = new HashMap<>(); + httpResponse.put("status", 200); + httpResponse.put("body", JSONObject.toJSONString(result)); + return httpResponse; + } + +} +``` + +3. 在 APISIX 中为 `HTTP2DubboService` 服务配置路由规则(此处省略)。接下来,就可以通过类似如下方式发起对后端 Dubbo 服务的调用了: + +```shell +curl http://127.0.0.1:9080/demo -H "Host: example.org" -X POST --data ' +{ + "service": "org.apache.dubbo.samples.apisix.UserService", + "method": "createUser", + "parameters": [ + { + "type": "org.apache.dubbo.samples.apisix.User", + "value": "{'name': 'hello'}" + } + ] +}' +``` + +## 总结 + +本文为大家介绍了如何借助 Apache APISIX 实现 Dubbo Service 的代理,通过引入 `dubbo-proxy` 插件便可为 Dubbo 框架的后端系统构建更简单更高效的流量链路。 + +希望通过上述操作步骤和用例场景分享,能为大家在相关场景的使用提供借鉴思路。更多关于 `dubbo-proxy` 插件的介绍与使用可参考[官方文档](https://apisix.apache.org/docs/apisix/plugins/dubbo-proxy/)。 + +关于这部分的更多示例,还可以参考 https://github.com/chickenlj/APISIX-Dubbo-Nacos diff --git a/content/en/blog/integration/how-to-proxy-dubbo-in-apache-shenyu.md b/content/en/blog/integration/how-to-proxy-dubbo-in-apache-shenyu.md new file mode 100644 index 000000000000..8dd65db9fb47 --- /dev/null +++ b/content/en/blog/integration/how-to-proxy-dubbo-in-apache-shenyu.md @@ -0,0 +1,414 @@ +--- +title: "如何通过 Apache ShenYu 网关代理 Dubbo 服务" +linkTitle: "如何通过 Apache ShenYu 网关代理 Dubbo 服务" +date: 2022-05-04 +tags: ["网关", "生态", "Java"] +description: > + 本文介绍了如何通过`Apache ShenYu`网关访问`Dubbo`服务,主要内容包括从简单示例到核心调用流程分析,并对设计原理进行了总结。 +aliases: + - /en/overview/what/gateway/shenyu/ +--- + +![img](/imgs/blog/shenyu-dubbo/ApacheShenYu-Dubbo-zh.png) + + +## 1. 介绍 + +- Apache ShenYu + +![img](/imgs/blog/shenyu-dubbo/shenyu.png) + + +[Apache ShenYu(Incubating)](https://shenyu.apache.org/zh/docs/index) 是一个异步的,高性能的,跨语言的,响应式的 `API` 网关。兼容各种主流框架体系,支持热插拔,用户可以定制化开发,满足用户各种场景的现状和未来需求,经历过大规模场景的锤炼。 + +2021年5月,`ShenYu`捐献给 `Apache` 软件基金会,Apache 基金会全票通过,顺利进入孵化器。 + + +- Apache Dubbo + +`Apache Dubbo` 是一款微服务开发框架,它提供了 `RPC` 通信 与 微服务治理 两大关键能力。这意味着,使用 `Dubbo` 开发的微服务,将具备相互之间的远程发现与通信能力, 同时利用 Dubbo 提供的丰富服务治理能力,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。同时 `Dubbo` 是高度可扩展的,用户几乎可以在任意功能点去定制自己的实现,以改变框架的默认行为来满足自己的业务需求。 + + +## 2. Dubbo快速开始 + +本小节介绍如何将`Dubbo`服务接入到`ShenYu`网关,您可以直接在工程下找到本小节的[示例代码](https://github.com/apache/shenyu/tree/master/shenyu-examples/shenyu-examples-dubbo) 。 + + +### 2.1 启动shenyu-admin + +`shenyu-admin`是`Apache ShenYu`后台管理系统, 启动的方式有多种,本文通过 `[本地部署](https://shenyu.apache.org/zh/docs/deployment/deployment-local)` 的方式启动。启动成功后,需要在基础配置`->`插件管理中,把`dubbo` 插件设置为开启,并设置你的注册地址,请确保注册中心已经开启。 + +![img](/imgs/blog/shenyu-dubbo/dubbo-enable-zh.png) + + +### 2.2 启动shenyu网关 + +在这里通过 [源码](https://github.com/apache/incubator-shenyu/tree/master/shenyu-bootstrap) 的方式启动,直接运行`shenyu-bootstrap`中的`ShenyuBootstrapApplication`。 + +在启动前,请确保网关已经引入相关依赖。如果客户端是`apache dubbo`,注册中心使用`zookeeper`,请参考如下配置: + +```java + + + org.apache.shenyu + shenyu-spring-boot-starter-plugin-apache-dubbo + ${project.version} + + + org.apache.dubbo + dubbo + 2.7.5 + + + + org.apache.curator + curator-client + 4.0.1 + + + log4j + log4j + + + + + org.apache.curator + curator-framework + 4.0.1 + + + org.apache.curator + curator-recipes + 4.0.1 + + + +``` + +### 2.3 启动shenyu-examples-dubbo + +以官网提供的例子为例 [shenyu-examples-dubbo](https://github.com/apache/shenyu/tree/master/shenyu-examples/shenyu-examples-dubbo) 。 假如`dubbo`服务定义如下: + +```xml + + + + + + + + + +``` + +声明应用服务名称,注册中心地址,使用`dubbo`协议,声明服务接口,对应接口实现类: + +```java +/** + * DubboTestServiceImpl. + */ +@Service("dubboTestService") +public class DubboTestServiceImpl implements DubboTestService { + + @Override + @ShenyuDubboClient(path = "/findById", desc = "Query by Id") + public DubboTest findById(final String id) { + return new DubboTest(id, "hello world shenyu Apache, findById"); + } + + //...... +} +``` + +在接口实现类中,使用注解`@ShenyuDubboClient`向`shenyu-admin`注册服务。 + +在配置文件`application.yml`中的配置信息: + +```yaml +server: + port: 8011 + address: 0.0.0.0 + servlet: + context-path: / +spring: + main: + allow-bean-definition-overriding: true +dubbo: + registry: + address: zookeeper://localhost:2181 # dubbo使用的注册中心 + +shenyu: + register: + registerType: http #注册方式 + serverLists: http://localhost:9095 #注册地址 + props: + username: admin + password: 123456 + client: + dubbo: + props: + contextPath: /dubbo + appName: dubbo + +``` + +在配置文件中,声明`dubbo`使用的注册中心地址,`dubbo`服务向`shenyu-admin`注册,使用的方式是`http`,注册地址是`http://localhost:9095`。 + +关于注册方式的使用,请参考 `[应用客户端接入](https://shenyu.apache.org/docs/design/register-center-design/)` 。 + + +### 2.4 调用dubbo服务 + +`shenyu-examples-dubbo`项目成功启动之后会自动把加 `@ShenyuDubboClient` 注解的接口方法注册到网关。 + + +打开 `插件列表 -> Proxy -> dubbo` 可以看到插件规则配置列表: + + +![img](/imgs/blog/shenyu-dubbo/dubbo-service-list-zh.png) + +注册成功的选择器信息: + +![img](/imgs/blog/shenyu-dubbo/dubbo-selector-zh.png) + +注册成功的规则信息: + +![img](/imgs/blog/shenyu-dubbo/dubbo-rule-zh.png) + +> 选择器和规则是 `Apache ShenYu` 网关中最灵魂的东西。掌握好它,你可以对任何流量进行管理。对应为选择器与规则里面的匹配条件(conditions),根据不同的流量筛选规则,我们可以处理各种复杂的场景。流量筛选可以从`Header`, `URI`, `Query`, `Cookie` 等等Http请求获取数据。 +> +> 然后可以采用 `Match`,`=`,`Regex`,`Groovy`,`Exclude`等匹配方式,匹配出你所预想的数据。多组匹配添加可以使用`And/Or`的匹配策略。 +> +> 具体的介绍与使用请看: `[选择器与规则管理](https://shenyu.apache.org/zh/docs/user-guide/admin-usage/selector-and-rule)` 。 + + +发起`GET`请求,通过`ShenYu`网关调用`dubbo`服务: + +``` +GET http://localhost:9195/dubbo/findById?id=100 +Accept: application/json +``` + +成功响应之后,结果如下: + +``` +{ + "name": "hello world shenyu Apache, findById", + "id": "100" +} +``` + +至此,就成功的通过`http`请求访问`dubbo`服务了,`ShenYu`网关通过`shenyu-plugin-dubbo`模块将`http`协议转成了`dubbo`协议。 + + +## 3. 深入理解Dubbo插件 + +在运行上述`demo`的过程中,是否存在一些疑问: + +- `dubbo`服务是如何注册到`shenyu-admin`? +- `shenyu-admin`是如何将数据同步到`ShenYu`网关? +- `DubboPlugin`是如何将`http`协议转换到到dubbo协议? + +带着这些疑问,来深入理解`dubbo`插件。 + + +### 3.1 应用客户端接入 + +应用客户端接入是指将微服务接入到`Apache ShenYu`网关,当前支持`Http`、 `Dubbo`、 `Spring Cloud`、 `gRPC`、 `Motan`、 `Sofa`、 `Tars`等协议的接入。 + +将应用客户端接入到`Apache ShenYu`网关是通过注册中心来实现的,涉及到客户端注册和服务端同步数据。注册中心支持`Http`、`Zookeeper`、`Etcd`、`Consul`和`Nacos`。默认是通过`Http`方式注册。 + +客户端接入的相关配置请参考 `[客户端接入配置](https://shenyu.apache.org/zh/docs/user-guide/register-center-access)` 。 + +#### 3.1.1 客户端注册 + +![img](/imgs/blog/shenyu-dubbo/register-client.png) + +在你的微服务配置中声明注册中心客户端类型,如`Http`或`Zookeeper`。 +应用程序启动时使用`SPI`方式加载并初始化对应注册中心客户端,通过实现`Spring Bean`相关的后置处理器接口,在其中获取需要进行注册的服务接口信息,将获取的信息放入`Disruptor`中。 + +注册中心客户端从`Disruptor`中读取数据,并将接口信息注册到`shenyu-admin`,`Disruptor`在其中起数据与操作解耦的作用,利于扩展。 + +#### 3.1.2 服务端注册 + +![img](/imgs/blog/shenyu-dubbo/register-server.png) + +在`shenyu-admin`配置中声明注册中心服务端类型,如`Http`或`Zookeeper`。当`shenyu-admin`启动时,读取配置类型,加载并初始化对应的注册中心服务端,注册中心服务端收到`shenyu-client`注册的接口信息后,将其放入`Disruptor`中,然后会触发注册处理逻辑,将服务接口信息更新并发布同步事件。 + +`Disruptor`在其中起到数据与操作解耦,利于扩展。如果注册请求过多,导致注册异常,也有数据缓冲作用。 + +### 3.2 数据同步原理 + +数据同步是指在 `shenyu-admin` 后台操作数据以后,使用何种策略将数据同步到 `Apache ShenYu` 网关。`Apache ShenYu` 网关当前支持`ZooKeeper`、`WebSocket`、`Http长轮询`、`Nacos` 、`Etcd` 和 `Consul` 进行数据同步。默认是通过`WebSocket`进行数据同步。 + +数据同步的相关配置请参考 `[数据同步配置](https://shenyu.apache.org/zh/docs/user-guide/use-data-sync)` 。 + +#### 3.2.1 数据同步的意义 + +网关是流量请求的入口,在微服务架构中承担了非常重要的角色,网关高可用的重要性不言而喻。在使用网关的过程中,为了满足业务诉求,经常需要变更配置,比如流控规则、路由规则等等。因此,网关动态配置是保障网关高可用的重要因素。 + +当前数据同步特性如下: + +- 所有的配置都缓存在 `Apache ShenYu` 网关内存中,每次请求都使用本地缓存,速度非常快。 +- 用户可以在 `shenyu-admin` 后台任意修改数据,并马上同步到网关内存。 +- 支持 `Apache ShenYu` 的插件、选择器、规则数据、元数据、签名数据等数据同步。 +- 所有插件的选择器,规则都是动态配置,立即生效,不需要重启服务。 +- 数据同步方式支持 `Zookeeper`、`Http 长轮询`、`Websocket`、`Nacos`、`Etcd` 和 `Consul`。 + +#### 3.2.2 数据同步原理分析 + +下图展示了 `Apache ShenYu` 数据同步的流程,`Apache ShenYu` 网关在启动时,会从配置服务同步配置数据,并且支持推拉模式获取配置变更信息,然后更新本地缓存。管理员可以在管理后台(`shenyu-admin`),变更用户权限、规则、插件、流量配置,通过推拉模式将变更信息同步给 `Apache ShenYu` 网关,具体是 `push` 模式,还是 `pull` 模式取决于使用哪种同步方式。 + +![img](/imgs/blog/shenyu-dubbo/data-sync.png) + +在最初的版本中,配置服务依赖 `Zookeeper` 实现,管理后台将变更信息 `push` 给网关。而现在可以支持 `WebSocket`、`Http长轮询`、`Zookeeper`、`Nacos`、`Etcd` 和 `Consul`,通过在配置文件中设置 `shenyu.sync.${strategy}` 指定对应的同步策略,默认使用 `webosocket` 同步策略,可以做到秒级数据同步。但是,有一点需要注意的是,`Apache ShenYu`网关 和 `shenyu-admin` 必须使用相同的同步策略。 + +如下图所示,`shenyu-admin` 在用户发生配置变更之后,会通过 `EventPublisher` 发出配置变更通知,由 `EventDispatcher` 处理该变更通知,然后根据配置的同步策略(`http、weboscket、zookeeper、naocs、etcd、consul`),将配置发送给对应的事件处理器。 + +- 如果是 `websocket` 同步策略,则将变更后的数据主动推送给 `shenyu-web`,并且在网关层,会有对应的 `WebsocketDataHandler` 处理器来处理 `shenyu-admin` 的数据推送。 +- 如果是 `zookeeper` 同步策略,将变更数据更新到 `zookeeper`,而 `ZookeeperSyncCache` 会监听到 `zookeeper` 的数据变更,并予以处理。 +- 如果是 `http` 同步策略,由网关主动发起长轮询请求,默认有 `90s` 超时时间,如果 `shenyu-admin` 没有数据变更,则会阻塞 `http` 请求,如果有数据发生变更则响应变更的数据信息,如果超过 `60s` 仍然没有数据变更则响应空数据,网关层接到响应后,继续发起 `http` 请求,反复同样的请求。 + +### 3.3 流程分析 + +流程分析是从源码的角度,展示服务注册流程,数据同步流程和服务调用流程。 + +#### 3.3.1 服务注册流程 + +- 读取dubbo服务 + +使用注解`@ShenyuDubboClient`标记需要注册到网关的`dubbo`服务。 + +注解扫描通过`ApacheDubboServiceBeanListener`完成,它实现了`ApplicationListener`接口,在`Spring`容器启动过程中,发生上下文刷新事件时,开始执行事件处理方法`onApplicationEvent()`。在重写的方法逻辑中,读取`Dubbo`服务`ServiceBean`,构建元数据对象和`URI`对象,并向`shenyu-admin`注册。 + +具体的注册逻辑由注册中心实现,请参考 `[客户端接入原理](https://shenyu.apache.org/zh/docs/design/register-center-design/)` 。 + + +- 处理注册信息 + +客户端通过注册中心注册的元数据和`URI`数据,在`shenyu-admin`端进行处理,负责存储到数据库和同步给`shenyu`网关。`Dubbo`插件的客户端注册处理逻辑在`ShenyuClientRegisterDubboServiceImpl`中。继承关系如下: + +![img](/imgs/blog/shenyu-dubbo/ShenyuClientRegisterDubboServiceImpl.png) + +- ShenyuClientRegisterService:客户端注册服务,顶层接口; +- FallbackShenyuClientRegisterService:注册失败,提供重试操作; +- AbstractShenyuClientRegisterServiceImpl:抽象类,实现部分公共注册逻辑; +- ShenyuClientRegisterDubboServiceImpl:实现`Dubbo`插件的注册; + +注册信息包括选择器,规则和元数据。 + + +整体的`dubbo`服务注册流程如下: + +![img](/imgs/blog/shenyu-dubbo/dubbo-register-zh.png) + +#### 3.3.2 数据同步流程 + +- admin更新数据 + +假设在在后台管理系统中,新增一条选择器数据,请求会进入`SelectorController`类中的`createSelector()`方法,它负责数据的校验,添加或更新数据,返回结果信息。 + +在`SelectorServiceImpl`类中通过`createOrUpdate()`方法完成数据的转换,保存到数据库,发布事件,更新`upstream`。 + +在`Service`类完成数据的持久化操作,即保存数据到数据库。发布变更数据通过`eventPublisher.publishEvent()`完成,这个`eventPublisher`对象是一个`ApplicationEventPublisher`类,这个类的全限定名是`org.springframework.context.ApplicationEventPublisher`,发布数据的功能正是是通过`Spring`相关的功能来完成的。 + +当事件发布完成后,会自动进入到`DataChangedEventDispatcher`类中的`onApplicationEvent()`方法,根据不同数据类型和数据同步方式进行事件处理。 + +- 网关数据同步 + +网关在启动时,根据指定的数据同步方式加载不同的配置类,初始化数据同步相关类。 + +在接收到数据后,进行反序列化操作,读取数据类型和操作类型。不同的数据类型,有不同的数据处理方式,所以有不同的实现类。但是它们之间也有相同的处理逻辑,所以可以通过模板方法设计模式来实现。相同的逻辑放在抽象类`AbstractDataHandler`中的`handle()`方法中,不同逻辑就交给各自的实现类。 + +新增一条选择器数据,是新增操作,会进入到`SelectorDataHandler.doUpdate()`具体的数据处理逻辑中。 + +在通用插件数据订阅者`CommonPluginDataSubscriber`,负责处理所有插件、选择器和规则信息 + +将数据保存到网关的内存中,`BaseDataCache`是最终缓存数据的类,通过单例模式实现。选择器数据就存到了`SELECTOR_MAP`这个`Map`中。在后续使用的时候,也是从这里拿数据。 + +上述逻辑用流程图表示如下: + +![img](/imgs/blog/shenyu-dubbo/data-sync-seq-zh.png) + +#### 3.3.3 服务调用流程 + +在`Dubbo`插件体系中,类继承关系如下: + +![img](/imgs/blog/shenyu-dubbo/ApacheDubboPlugin.png) + +> ShenyuPlugin:顶层接口,定义接口方法; +> +> AbstractShenyuPlugin:抽象类,实现插件共有逻辑; +> +> AbstractDubboPlugin:dubbo插件抽象类,实现`dubbo`共有逻辑(ShenYu网关支持ApacheDubbo和AlibabaDubbo); +> +> ApacheDubboPlugin:ApacheDubbo插件。 + + +- org.apache.shenyu.web.handler.ShenyuWebHandler.DefaultShenyuPluginChain#execute() + +通过`ShenYu`网关代理后,请求入口是`ShenyuWebHandler`,它实现了`org.springframework.web.server.WebHandler`接口,通过责任链设计模式将所有插件连接起来。 + +- org.apache.shenyu.plugin.base.AbstractShenyuPlugin#execute() + +当请求到网关时,判断某个插件是否执行,是通过指定的匹配逻辑来完成。在`execute()`方法中执行选择器和规则的匹配逻辑。 + + +- org.apache.shenyu.plugin.global.GlobalPlugin#execute() + +最先被执行的是`GlobalPlugin` ,它是一个全局插件,在`execute()`方法中构建上下文信息。 + +- org.apache.shenyu.plugin.base.RpcParamTransformPlugin#execute() + +接着被执行的是`RpcParamTransformPlugin` , 它负责从`http`请求中读取参数,保存到`exchange`中,传递给`rpc`服务。在`execute()`方法中,执行该插件的核心逻辑:从`exchange`中获取请求信息,根据请求传入的内容形式处理参数。 + +- org.apache.shenyu.plugin.dubbo.common.AbstractDubboPlugin + +然后被执行的是`DubboPlugin` 。在`doExecute()`方法中,主要是检查元数据和参数。在`doDubboInvoker()`方法中设置特殊的上下文信息,然后开始`dubbo`的泛化调用。 + +在`genericInvoker()`方法中: + +- 获取`ReferenceConfig`对象; +- 获取泛化服务`GenericService`对象; +- 构造请求参数`pair`对象; +- 发起异步的泛化调用。 + +通过泛化调用就可以实现在网关调用`dubbo`服务了。 + +`ReferenceConfig`对象是支持泛化调用的关键对象 ,它的初始化操作是在数据同步的时候完成的。 + +- org.apache.shenyu.plugin.response.ResponsePlugin#execute() + +最后被执行的是`ResponsePlugin` ,它统一处理网关的响应结果信息。处理类型由`MessageWriter`决定,类继承关系如下: + +![img](/imgs/blog/shenyu-dubbo/MessageWriter.png) + +> MessageWriter:接口,定义消息处理方法; +> +> NettyClientMessageWriter:处理`Netty`调用结果; +> +> RPCMessageWriter:处理`RPC`调用结果; +> +> WebClientMessageWriter:处理`WebClient`调用结果; + +`Dubbo`服务调用,处理结果是`RPCMessageWriter`。 + +- org.apache.shenyu.plugin.response.strategy.RPCMessageWriter#writeWith() + +在`writeWith()`方法中处理响应结果,获取结果或处理异常。 + +分析至此,关于`Dubbo`插件的源码分析就完成了,分析流程图如下: + +![img](/imgs/blog/shenyu-dubbo/dubbo-execute-zh.png) + + +## 4. 小结 + +本文从实际案例出发,由浅入深分析了`ShenYu`网关对Dubbo服务的代理过程。涉及到的主要知识点如下: + +- 通过责任链设计模式执行插件; +- 使用模板方法设计模式实现`AbstractShenyuPlugin`,处理通用的操作类型; +- 使用单例设计模式实现缓存数据类`BaseDataCache`; +- 通过`springboot starter`即可引入不同的注册中心和数同步方式,扩展性很好; +- 通过`admin`支持规则热更新,方便流量管控; +- `Disruptor`队列是为了数据与操作解耦,以及数据缓冲。 diff --git a/content/en/blog/integration/how-to-proxy-dubbo-in-higress.md b/content/en/blog/integration/how-to-proxy-dubbo-in-higress.md new file mode 100644 index 000000000000..7be2a43ca849 --- /dev/null +++ b/content/en/blog/integration/how-to-proxy-dubbo-in-higress.md @@ -0,0 +1,286 @@ +--- +aliases: + - /en/overview/what/ecosystem/gateway/higress/ +description: "使用 Higress 作为 Dubbo 网关,代理 dubbo 协议服务。" +linkTitle: 如何通过 Higress 网关代理 Dubbo 服务 +title: 如何通过 Higress 网关代理 Dubbo 服务 +date: 2024-04-01 +tags: ["网关", "生态"] +--- +{{% alert title="注意" color="warning" %}} +本文仅适用于 dubbo 协议通信场景。如果您是 Dubbo3 用户,建议您使用 triple 协议,具体可参见 [使用 Apache APISIX 代理 Dubbo 服务(triple协议)](/en/overview/mannual/java-sdk/tasks/gateway/triple/) 学习具体示例。 +{{% /alert %}} + + +Higress提供了从HTTP协议到Dubbo协议进行转换的功能,用户通过配置协议转换,可以将一个Dubbo服务以HTTP接口暴露出来,从而用HTTP请求实现对Dubbo接口的调用。本文将通过一个示例来介绍如何用Higress配置HTTP到Dubbo的协议转换。该示例会引导您轻松地部署一个Nacos server和一个Dubbo服务,然后通过Ingress将HTTP请求转发到注册在Nacos上的Dubbo服务,并通过Higress的协议转换能力完成对Dubbo服务的HTTP调用。 + + + +以下是一个使用 `Higress + dubbo协议 + Nacos注册中心` 的完整示例:[dubbo-samples-gateway-higress-dubbo](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-dubbo)。 + +## 前提条件 +1. 已安装Higress,并开启了对Istio CRD的支持,参考[Higress安装部署文档](https://higress.io/zh-cn/docs/ops/deploy-by-helm)。 + +## 部署Nacos和Dubbo服务 + +首先在K8s集群中apply以下资源,以部署一个Nacos注册中心,同时通过K8s service将这个Nacos server暴露出来。 + +```yaml +# Nacos Server配置 +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nacos-server +spec: + replicas: 1 + selector: + matchLabels: + app: nacos-server + template: + metadata: + labels: + app: nacos-server + spec: + containers: + - env: + - name: MODE + value: standalone + image: nacos/nacos-server:v2.2.0 + imagePullPolicy: Always + name: nacos-server + ports: + - containerPort: 8848 + name: server + dnsPolicy: ClusterFirst + restartPolicy: Always + +# Nacos Server Service配置 +--- +apiVersion: v1 +kind: Service +metadata: + name: nacos-server +spec: + ports: + - port: 8848 + name: server + protocol: TCP + targetPort: 8848 + selector: + app: nacos-server + type: ClusterIP +``` +在 K8s 集群中 apply 以下资源,以部署一个Dubbo服务,该 Dubbo 服务将注册到上述的 Naocs 中(你可以选择重新打包,我们接下来直接使用社区提前准备好的镜像包)。 +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nacos-provider +spec: + replicas: 1 + selector: + matchLabels: + app: nacos-provider + template: + metadata: + labels: + app: nacos-provider + spec: + containers: + - name: server + image: higress-registry.cn-hangzhou.cr.aliyuncs.com/samples/nacos-dubbo-provider:v1.0.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 20880 + env: + - name: DUBBO_REGISTRY_ADDRESS + value: nacos-server.default.svc.cluster.local +``` +该Dubbo服务的代码可以在 [dubbo-samples-gateway-higress-dubbo](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-dubbo) 仓库中找到,其接口定义为: + +```java +package org.apache.dubbo.samples.gateway.api; + +public interface DemoService { + String sayHello(String name); +} +``` +接口实现如下: + +```java +@Service(version = "${demo.service.version}", group = "${demo.service.group}") +public class DemoServiceImpl implements DemoService { + @Override + public String sayHello(String name) { + return "Hello " + name; + } +} +``` +在本示例中,该Dubbo服务的服务名为 `org.apache.dubbo.samples.gateway.api.DemoService`,服务版本为 `1.0.0`,服务分组为 `dev`。 + +为了测试方便,我们可以通过运行以下命令来将我们部署在 K8S 集群中的 Naocs 服务映射到本地端口: + +```bash +kubectl port-forward svc/nacos-server 8848:8848 --address='0.0.0.0' +``` + +然后请求Nacos的服务发现接口,可以查看到我们Dubbo服务的元数据信息,从而对以上部署进行验证。 + +```bash +$ curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=providers:com.alibaba.nacos.example.dubbo.service.DemoService:1.0.0:dev' + +{"name":"DEFAULT_GROUP@@providers:com.alibaba.nacos.example.dubbo.service.DemoService:1.0.0:dev","groupName":"DEFAULT_GROUP","clusters":"","cacheMillis":10000,"hosts":[{"ip":"10.244.0.58","port":20880,"weight":1.0,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"DEFAULT","serviceName":"DEFAULT_GROUP@@providers:com.alibaba.nacos.example.dubbo.service.DemoService:1.0.0:dev","metadata":{"side":"provider","release":"dubbo_demo","methods":"sayName","deprecated":"false","dubbo":"2.0.2","pid":"3034042","interface":"com.alibaba.nacos.example.dubbo.service.DemoService","service-name-mapping":"true","version":"1.0.0","generic":"false","revision":"dubbo_demo","path":"com.alibaba.nacos.example.dubbo.service.DemoService","protocol":"dubbo","metadata-type":"remote","application":"dubbo-provider-demo","background":"false","dynamic":"true","category":"providers","group":"dev","anyhost":"true","timestamp":"1680176973875"},"ipDeleteTimeout":30000,"instanceHeartBeatInterval":5000,"instanceHeartBeatTimeOut":15000}],"lastRefTime":1680178336936,"checksum":"","allIPs":false,"reachProtectionThreshold":false,"valid":true}% +``` +## 通过Ingress转发请求到Dubbo服务 +Higress 可以通过 McpBridge 来对接 Nacos 作为服务来源,在 K8s 集群中 apply 以下资源来配置 McpBridge + +```yaml +apiVersion: networking.higress.io/v1 +kind: McpBridge +metadata: + name: default + namespace: higress-system +spec: + registries: + - domain: nacos-server.default.svc.cluster.local + nacosGroups: + - DEFAULT_GROUP + name: nacos-service-resource + port: 8848 + type: nacos2 +``` + +通过McpBridge,我们可以直接从Nacos中发现Dubbo服务,并为其创建路由,而无需为每一个Dubbo服务创建service资源。 + +接下来我们创建如下Ingress,从而创建一条指向Dubbo服务的HTTP路由: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + higress.io/destination: gateway-higress-dubbo-provider.DEFAULT-GROUP.public.nacos + name: demo + namespace: higress-system +spec: + ingressClassName: higress + rules: + - http: + paths: + - backend: + resource: + apiGroup: networking.higress.io + kind: McpBridge + name: default + path: /dubbo + pathType: Prefix +``` + +这样,path前缀为 `/dubbo` 的请求就会被路由到我们刚刚创建的 Dubbo 服务上。 + + +{{% alert title="注意" color="info" %}} +以上 `higress.io/destination` 用来指定本路由的地址来源,它使用 `服务名称.服务分组.命名空间ID.nacos` 的固定格式,其中, +* `服务名称` 可以是应用名或者接口名,Dubbo3 建议直接配置应用名,只有使用接口级服务发现时配置接口名,其格式为完整 `nacos dataid`,如 `providers:{service-name}:{version}:{group}` +* `服务分组`,nacos 分组,未明确设置时,使用 `DEFAULT-GROUP` 即可。注意这里需要遵循 DNS 域名格式,因此服务分组中的下划线'_'被转换成了横杠'-' +* `命名空间ID`,nacos 命空间,未明确设置时,使用 `public` 即可 +* `nacos`,使用固定值 `nacos` 代表数据来源 +{{% /alert %}} + +## 通过EnvoyFilter配置HTTP到Dubbo的协议转换规则 + +经过上述步骤,我们已经在K8s环境下部署了一套Naocs和Dubbo,并通过Ingress将path前缀为/dubbo的请求路由到我们配好的Dubbo服务上。但光是这样是无法正常通信的,因为Dubbo服务使用的是定制的Dubbo协议,无法天然与HTTP协议进行兼容。因此接下来我们将通过EnvoyFilter来配置HTTP到Dubbo的协议转换规则,从而实现用HTTP请求来调用Dubbo服务。 + +在K8s集群中apply以下资源,要注意的是,EnvoyFilter是属于Istio的CRD,因此需要参照前提条件中的第2点来开启Higress对Istio CRD的支持。 + +```yaml +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: http-dubbo-transcoder-test + namespace: higress-system +spec: + configPatches: + - applyTo: HTTP_FILTER + match: + context: GATEWAY + listener: + filterChain: + filter: + name: envoy.filters.network.http_connection_manager + subFilter: + name: envoy.filters.http.router + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.http_dubbo_transcoder + typed_config: + '@type': type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.extensions.filters.http.http_dubbo_transcoder.v3.HttpDubboTranscoder + - applyTo: HTTP_ROUTE + match: + context: GATEWAY + routeConfiguration: + vhost: + route: + name: demo + patch: + operation: MERGE + value: + route: + upgrade_configs: + - connect_config: + allow_post: true + upgrade_type: CONNECT + typed_per_filter_config: + envoy.filters.http.http_dubbo_transcoder: + '@type': type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.extensions.filters.http.http_dubbo_transcoder.v3.HttpDubboTranscoder + value: + request_validation_options: + reject_unknown_method: true + reject_unknown_query_parameters: true + services_mapping: + - group: dev + method_mapping: + - name: sayName + parameter_mapping: + - extract_key: p + extract_key_spec: ALL_QUERY_PARAMETER + mapping_type: java.lang.String + passthrough_setting: + passthrough_all_headers: true + path_matcher: + match_http_method_spec: ALL_GET + match_pattern: /dubbo/hello + name: org.apache.dubbo.samples.gateway.api.DemoService + version: 1.0.0 + url_unescape_spec: ALL_CHARACTERS_EXCEPT_RESERVED + - applyTo: CLUSTER + match: + cluster: + service: gateway-higress-dubbo.DEFAULT-GROUP.public.nacos + context: GATEWAY + patch: + operation: MERGE + value: + upstream_config: + name: envoy.upstreams.http.dubbo_tcp + typed_config: + '@type': type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.extensions.upstreams.http.dubbo_tcp.v3.DubboTcpConnectionPoolProto +``` +在以上EnvoyFilter中,我们配置了将path为/dubbo/hello的HTTP请求转发到Dubbo服务com.alibaba.nacos.example.dubbo.service.DemoService:1.0.0:dev中,并调用其sayName方法,而该方法的参数则通过HTTP url中的的query参数p来指定。 + +## 请求验证 + +通过以上配置,我们就可以执行以下curl命令来调用这个dubbo服务了: +```bash +$curl "localhost/dubbo/hello?p=abc" +{"result":"Service [name :demoService , port : 20880] sayName(\"abc\") : Hello,abc"} +``` + +## 参考资料 + +* EnvoyFilter的相关配置项参考[HTTP转Dubbo配置说明](https://higress.io/zh-cn/docs/user/dubbo-envoyfilter) +* 完整示例源码 [dubbo-samples-gateway-higress-dubbo](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-gateway/dubbo-samples-gateway-higress/dubbo-samples-gateway-higress-dubbo) diff --git a/content/en/blog/integration/pinpoint.md b/content/en/blog/integration/pinpoint.md new file mode 100644 index 000000000000..ca40f035784b --- /dev/null +++ b/content/en/blog/integration/pinpoint.md @@ -0,0 +1,424 @@ +--- +title: "使用Pinpoint做分布式跟踪" +linkTitle: "使用Pinpoint做分布式跟踪" +date: 2018-07-12 +tags: ["生态", "Java"] +description: > + 本文介绍了利用Pinpoint对Dubbo分布式应用进行调用链跟踪与性能监控。 +--- + +在使用Dubbo进行服务化或者整合应用后,假设某个服务后台日志显示有异常,这个服务又被多个应用调用的情况下,我们通常很难判断是哪个应用调用的,问题的起因是什么,因此我们需要一套分布式跟踪系统来快速定位问题,Pinpoint可以帮助我们快速定位问题(当然,解决方案也不止这一种)。 + +## 什么是Pinpoint + +> 摘自[Pinpoint学习笔记](https://skyao.gitbooks.io/learning-pinpoint/content/index.html) + +[Pinpoint](https://github.com/naver/pinpoint)是一个开源的 APM (Application Performance Management/应用性能管理)工具,用于基于java的大规模分布式系统。 +仿照Google Dapper,Pinpoint通过跟踪分布式应用之间的调用来提供解决方案,以帮助分析系统的总体结构和内部模块之间如何相互联系。 + +> 注:对于各个模块之间的通讯英文原文中用的是transaction一词,但是我觉得如果翻译为"事务"容易引起误解,所以替换为"交互"或者"调用"这种比较直白的字眼。 + +在使用上力图简单高效: + +* 安装agent,不需要修改哪怕一行代码 +* 最小化性能损失 + +### 服务器地图(ServerMap) + +通过可视化分布式系统的模块和他们之间的相互联系来理解系统拓扑。点击某个节点会展示这个模块的详情,比如它当前的状态和请求数量。 + +### 实时活动线程图表(Realtime Active Thread Chart) + +实时监控应用内部的活动线程。 + +### 请求/应答分布图表(Request/Response Scatter Chart) + +长期可视化请求数量和应答模式来定位潜在问题。通过在图表上拉拽可以选择请求查看更多的详细信息。 + +### 调用栈(CallStack) + +在分布式环境中为每个调用生成代码级别的可视图,在单个视图中定位瓶颈和失败点。 + +### 巡查(Inspector) + +查看应用上的其他详细信息,比如CPU使用率,内存/垃圾回收,TPS,和JVM参数。 + +### 支持模块 + +* JDK 6+ +* Tomcat 6/7/8, Jetty 8/9, JBoss EAP 6, Resin 4, Websphere 6/7/8, Vertx 3.3/3.4/3.5 +* Spring, Spring Boot (Embedded Tomcat, Jetty) +* Apache HTTP Client 3.x/4.x, JDK HttpConnector, GoogleHttpClient, OkHttpClient, NingAsyncHttpClient +* Thrift Client, Thrift Service, DUBBO PROVIDER, DUBBO CONSUMER +* ActiveMQ, RabbitMQ +* MySQL, Oracle, MSSQL, CUBRID,POSTGRESQL, MARIA +* Arcus, Memcached, Redis, CASSANDRA +* iBATIS, MyBatis +* DBCP, DBCP2, HIKARICP +* gson, Jackson, Json Lib +* log4j, Logback +* 自定义模块 + +## Pinpoint与Dubbo的结合 + +### 启动Pinpoint + +参考Pinpoint的[Quick start](https://pinpoint-apm.github.io/pinpoint/quickstart.html)搭建环境(不需要启动TestApp) + +### 准备Dubbo示例程序 + +#### 创建API包 + +pom.xml +```xml + + + 4.0.0 + + com.example + demo-api + 0.0.1-SNAPSHOT + +``` + +新建API接口: +``` +package com.example.demoapi; + +public interface HelloService { + String sayHello(String name); +} +``` + +#### 实现 Dubbo 服务提供方 + +pom.xml +```xml + + + 4.0.0 + + com.example + demo-provider + 0.0.1-SNAPSHOT + jar + + demo-provider + + + org.springframework.boot + spring-boot-starter-parent + 2.0.3.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + sonatype-nexus-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + org.springframework.boot + spring-boot-starter + + + com.alibaba.boot + dubbo-spring-boot-starter + 0.2.0 + + + com.example + demo-api + 0.0.1-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + +``` + +1. 实现 `HelloService` 接口: +```java +package com.example.demoprovider.provider; + +import com.alibaba.dubbo.config.annotation.Service; +import com.example.demoapi.HelloService; + +@Service(version = "${demo.service.version}", + application = "${dubbo.application.id}", + protocol = "${dubbo.protocol.id}", + registry = "${dubbo.registry.id}") +public class HelloServiceImpl implements HelloService { + static int i = 0; + @Override + public String sayHello(String name) { + i++; + if (i % 3 == 0) { + throw new RuntimeException("ex"); + } + return "Hello " + name + "!"; + } +} +``` + +2. 编写 Spring Boot 引导程序: +```java +package com.example.demoprovider; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DemoProviderApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoProviderApplication.class, args); + } +} +``` + +3. 配置 `application.properties`: + +```properties +# Spring boot application +spring.application.name = dubbo-provider-demo +server.port = 9090 +management.port = 9091 + +# Service version +demo.service.version = 1.0.0 + +# Base packages to scan Dubbo Components (e.g @Service , @Reference) +dubbo.scan.basePackages = com.example.demoprovider + +# Dubbo Config properties +## ApplicationConfig Bean +dubbo.application.id = dubbo-provider-demo +dubbo.application.name = dubbo-provider-demo + +## ProtocolConfig Bean +dubbo.protocol.id = dubbo +dubbo.protocol.name = dubbo +dubbo.protocol.port = 12345 + +## RegistryConfig Bean +dubbo.registry.id = my-registry +dubbo.registry.address = N/A +``` + +#### 实现 Dubbo 服务消费方 + +pom.xml +```xml + + + 4.0.0 + + com.example + demo-consumer + 0.0.1-SNAPSHOT + jar + + demo-consumer + + + org.springframework.boot + spring-boot-starter-parent + 2.0.3.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + sonatype-nexus-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + org.springframework.boot + spring-boot-starter-web + + + com.alibaba.boot + dubbo-spring-boot-starter + 0.2.0 + + + com.example + demo-api + 0.0.1-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + exec + + + + + + +``` + +1. 通过 `@Reference` 注入 `HelloService` +```java +package com.example.democonsumer.controller; + +import com.alibaba.dubbo.config.annotation.Reference; +import com.example.demoapi.HelloService; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class DemoConsumerController { + @Reference(version = "${demo.service.version}", + application = "${dubbo.application.id}", + url = "dubbo://<注意,这里填写具体IP>:12345") + private HelloService helloService; + + @RequestMapping("/sayHello") + public String sayHello(@RequestParam String name) { + return helloService.sayHello(name); + } +} +``` +> 直连提供者调用需要填写具体IP地址,如果写localhost也可以,但是会被Pinpoint额外识别为一个未知服务 + +2. 编写 Spring Boot 引导程序(Web 应用): +```java +package com.example.democonsumer; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DemoConsumerApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoConsumerApplication.class, args); + } +} +``` + +3. 配置 `application.properties`: +```properties +# Spring boot application +spring.application.name=dubbo-consumer-demo +server.port=8080 +management.port=8081 + +# Service Version +demo.service.version=1.0.0 + +# Dubbo Config properties +## ApplicationConfig Bean +dubbo.application.id=dubbo-consumer-demo +dubbo.application.name=dubbo-consumer-demo + +## ProtocolConfig Bean +dubbo.protocol.id=dubbo +dubbo.protocol.name=dubbo +dubbo.protocol.port=12345 +``` + +### 使用Pinpoint-agent启动服务提供方和服务消费方 + +#### 启动服务提供方 + +1. 编译打包 +``` +mvn clean package +``` + +2. 附加参数启动服务提供方 +``` +java -jar -javaagent:$AGENT_PATH/pinpoint-bootstrap-$VERSION.jar -Dpinpoint.agentId=demo-provider -Dpinpoint.applicationName=DP target/demo-provider-0.0.1-SNAPSHOT.jar +``` + +3. 附加参数启动服务消费方 +``` +java -jar -javaagent:$AGENT_PATH/pinpoint-bootstrap-$VERSION.jar -Dpinpoint.agentId=demo-consumer -Dpinpoint.applicationName=DC target/demo-comsumer-0.0.1-SNAPSHOT-exec.jar +``` + +4. 访问消费方地址模拟用户请求 + +`http://localhost:8080/sayHello?name=ABC` + +## 使用Pinpoint快速定位问题 + +### 首页 + +![/admin-guide/images/pinpoint-home.png](/imgs/blog/pinpoint-home.png) + +> 这里的用户请求是请求DubboProvider数量的双倍,原因是记录了favicon.ico图标请求导致的 + +### 调用树 + +![/admin-guide/images/pinpoint-calltree.png](/imgs/blog/pinpoint-calltree.png) + +### 深入跟踪 + +![/admin-guide/images/pinpoint-mixedview.png](/imgs/blog/pinpoint-mixedview.png) + +### 其他 + +示例简单的模拟了Dubbo的提供和调用,并没有进行数据库等其他中间件的应用,详细使用请参照Pinpoint文档。 diff --git a/content/en/blog/integration/sentinel-introduction-for-dubbo.md b/content/en/blog/integration/sentinel-introduction-for-dubbo.md new file mode 100644 index 000000000000..22b8216ee3ee --- /dev/null +++ b/content/en/blog/integration/sentinel-introduction-for-dubbo.md @@ -0,0 +1,141 @@ +--- +title: "Sentinel 为 Dubbo 服务保驾护航" +linkTitle: "Sentinel 为 Dubbo 服务保驾护航" +date: 2018-07-27 +tags: ["生态", "Java"] +description: > + 本文主要介绍了面向分布式服务架构的轻量级流量控制组件 Sentinel 以及在 Dubbo 中整合使用 Sentinel 的最佳实践。 +--- + +在复杂的生产环境下可能部署着成千上万的 Dubbo 服务实例,流量持续不断地进入,服务之间进行相互调用。但是分布式系统中可能会因流量激增、系统负载过高、网络延迟等一系列问题,导致某些服务不可用,如果不进行相应的控制可能导致级联故障,影响服务的可用性,因此如何对流量进行合理的控制,成为保障服务稳定性的关键。 + +[Sentinel](https://github.com/alibaba/Sentinel) 是阿里中间件团队开源的,面向分布式服务架构的轻量级流量控制产品,主要以流量为切入点,从**流量控制**、**熔断降级**、**系统负载保护**等多个维度来帮助用户保护服务的稳定性。本文将基于 Dubbo,看看 Sentinel 是如何进行流量控制的,并且提供 Dubbo 整合 Sentinel 的最佳实践。 + +## 快速接入 Sentinel + +Sentinel 意为**哨兵**,这个命名形象的诠释了 Sentinel 在分布式系统中的工作角色和重要性。以 Sentinel 在 Dubbo 生态系统中的作用为例,Dubbo 的核心模块包括注册中心、服务提供方、服务消费方(服务调用方)和监控四个模块。Sentinel 通过对服务提供方和服务消费方的限流来进一步提升服务的可用性。接下来我们看看 Sentinel 对服务提供方和服务消费方限流的技术实现方式。 + +![Dubbo Arch](/imgs/architecture.png) + +Sentinel 提供了与 Dubbo 适配的模块 – [Sentinel Dubbo Adapter](https://github.com/dubbo/dubbo-sentinel-support),包括针对服务提供方的过滤器和服务消费方的过滤器(Filter)。使用时我们只需引入以下模块(以 Maven 为例): + +```xml + + com.alibaba.csp + sentinel-dubbo-adapter + x.y.z + +``` + +引入此依赖后,Dubbo 的服务接口和方法(包括调用端和服务端)就会成为 Sentinel 中的资源,在配置了规则后就可以自动享受到 Sentinel 的防护能力。同时提供了灵活的配置选项,例如若不希望开启 Sentinel Dubbo Adapter 中的某个 Filter,可以手动关闭对应的 Filter。 + +接入 Sentinel Dubbo Adapter 后,即使未配置规则,Sentinel 也会对相应的 Dubbo 服务的调用信息进行统计。那么我们怎么知道 Sentinel 接入成功了呢?这时候就要请出一大利器 —— Sentinel 控制台了。 + +## 限流必备 - 监控管理 + +流量具有很强的实时性,之所以需要限流,是因为我们无法对流量的到来作出精确的预判,不然的话我们完全可以通过弹性的计算资源来处理,所以这时候为了保证限流的准确性,限流框架的监控功能就非常重要了。 + +Sentinel 的控制台(Dashboard)是流量控制、熔断降级规则统一配置和管理的入口,同时它为用户提供了多个维度的监控功能。在 Sentinel 控制台上,我们可以配置规则并实时查看流量控制效果。 + +接入 Sentinel 控制台的步骤如下(**缺一不可**): + +1. 按照 [Sentinel 控制台文档](https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0) 启动控制台 +2. 应用引入 `sentinel-transport-simple-http` 依赖,以便控制台可以拉取对应应用的相关信息 +3. 给应用添加相关的启动参数,启动应用。需要配置的参数有: + - `-Dcsp.sentinel.api.port`:客户端的 port,用于上报相关信息(默认为 8719) + - `-Dcsp.sentinel.dashboard.server`:控制台的地址 + - `-Dproject.name`:应用名称,会在控制台中显示 + +注意某些环境下本地运行 Dubbo 服务还需要加上 `-Djava.net.preferIPv4Stack=true` 参数。比如中 Service Provider 的启动参数可以配成: + +```bash +-Djava.net.preferIPv4Stack=true -Dcsp.sentinel.api.port=8720 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=dubbo-provider-demo +``` + +这样在启动应用后就能在控制台找到对应的应用了。以下是常用功能: + +- **单台设备监控**:当在机器列表中看到您的机器,就代表着已经成功接入控制台,可以查看单台设备的设备名称、IP地址、端口号、健康状态和心跳时间等信息。 + +![Discovery](/imgs/blog/2018/07/27/sentinel/machinediscover.png) + +- **链路监控**:簇点链路实时的去拉取指定客户端资源的运行情况,它提供了两种展示模式,一种用书状结构展示资源的调用链路;另外一种则不区分调用链路展示资源的运行情况。通过链路监控,可以查看到每个资源的流控和降级的历史状态。 + +| 树状链路| 平铺链路 +| :----: | :---- +|![resourceTree](/imgs/blog/2018/07/27/sentinel/resourceTree.png)|![cluster](/imgs/blog/2018/07/27/sentinel/sentine_dashboard.gif) + +- **聚合监控**:同一个服务下的所有机器的簇点信息会被汇总,实现实时监控,精确度达秒级。 + +![秒级实时监控](/imgs/blog/sentinel-dashboard-metrics.png) + +- **规则配置**:可以查看已有的限流、降级和系统保护规则,并实时地进行配置。 + +![规则配置](/imgs/blog/sentinel-dashboard-view-rules.png) + +## Sentinel 基于 Dubbo 的最佳实践 + +> 具体 Demo 代码请见 [sentinel-demo-dubbo](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-dubbo)。 + +### Service Provider + +> 对服务提供方的流量控制可分为**服务提供方的自我保护能力**和**服务提供方对服务消费方的请求分配能力**两个维度。 +> + +Service Provider 用于向外界提供服务,处理各个消费者的调用请求。为了保护 Provider 不被激增的流量拖垮影响稳定性,可以给 Provider 配置 **QPS 模式**的限流,这样当每秒的请求量超过设定的阈值时会自动拒绝多的请求。限流粒度可以是 *服务接口* 和 *服务方法* 两种粒度。若希望整个服务接口的 QPS 不超过一定数值,则可以为对应服务接口资源(resourceName 为**接口全限定名**)配置 QPS 阈值;若希望服务的某个方法的 QPS 不超过一定数值,则可以为对应服务方法资源(resourceName 为**接口全限定名:方法签名**)配置 QPS 阈值。有关配置详情请参考 [流量控制 | Sentinel](https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6)。 + +我们看一下这种模式的限流产生的效果。假设我们已经定义了某个服务接口 `com.alibaba.csp.sentinel.demo.dubbo.FooService`,其中有一个方法 `sayHello(java.lang.String)`,Provider 端该方法设定 QPS 阈值为 10。在 Consumer 端在 1s 之内连续发起 15 次调用,可以通过日志文件看到 Provider 端被限流。拦截日志统一记录在 `~/logs/csp/sentinel-block.log` 中: + +``` +2018-07-24 17:13:43|1|com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String),FlowException,default,|5,0 +``` + +在 Provider 对应的 metrics 日志中也有记录: + +``` +1532423623000|2018-07-24 17:13:43|com.alibaba.csp.sentinel.demo.dubbo.FooService|15|0|15|0|3 +1532423623000|2018-07-24 17:13:43|com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String)|10|5|10|0|0 +``` + +根据**调用方**的需求来分配服务提供方的处理能力也是常见的限流方式。比如有两个服务 A 和 B 都向 Service Provider 发起调用请求,我们希望只对来自服务 B 的请求进行限流,则可以设置限流规则的 `limitApp` 为服务 B 的名称。Sentinel Dubbo Adapter 会自动解析 Dubbo 消费者(调用方)的 application name 作为调用方名称(`origin`),在进行资源保护的时候都会带上调用方名称。若限流规则未配置调用方(`default`),则该限流规则对所有调用方生效。若限流规则配置了调用方则限流规则将仅对指定调用方生效。 + +> 注:Dubbo 默认通信不携带对端 application name 信息,因此需要开发者在调用端手动将 application name 置入 attachment 中,provider 端进行相应的解析。Sentinel Dubbo Adapter 实现了一个 Filter 用于自动从 consumer 端向 provider 端透传 application name。若调用端未引入 Sentinel Dubbo Adapter,又希望根据调用端限流,可以在调用端手动将 application name 置入 attachment 中,key 为 `dubboApplication`。 + +在限流日志中会也会记录调用方的名称,如下面的日志中的 `demo-consumer` 即为调用方名称: + +``` +2018-07-25 16:26:48|1|com.alibaba.csp.sentinel.demo.dubbo.FooService:sayHello(java.lang.String),FlowException,default,demo-consumer|5,0 +``` + +### Service Consumer + +> 对服务提供方的流量控制可分为**控制并发线程数**和**服务降级**两个维度。 + +#### 并发线程数限流 + +Service Consumer 作为客户端去调用远程服务。每一个服务都可能会依赖几个下游服务,若某个服务 A 依赖的下游服务 B 出现了不稳定的情况,服务 A 请求 服务 B 的响应时间变长,从而服务 A 调用服务 B 的线程就会产生堆积,最终可能耗尽服务 A 的线程数。我们通过用并发线程数来控制对下游服务 B 的访问,来保证下游服务不可靠的时候,不会拖垮服务自身。基于这种场景,推荐给 Consumer 配置**线程数模式**的限流,来保证自身不被不稳定服务所影响。采用基于线程数的限流模式后,我们不需要再显式地去进行线程池隔离,Sentinel 会控制资源的线程数,超出的请求直接拒绝,直到堆积的线程处理完成,可以达到**信号量隔离**的效果。 + +我们看一下这种模式的效果。假设当前服务 A 依赖两个远程服务方法 `sayHello(java.lang.String)` 和 `doAnother()`。前者远程调用的响应时间 为 1s-1.5s 之间,后者 RT 非常小(30 ms 左右)。服务 A 端设两个远程方法 thread count 为 5。然后每隔 50 ms 左右向线程池投入两个任务,作为消费者分别远程调用对应方法,持续 10 次。可以看到 `sayHello` 方法被限流 5 次,因为后面调用的时候前面的远程调用还未返回(RT 高);而 `doAnother()` 调用则不受影响。线程数目超出时快速失败能够有效地防止自己被慢调用所影响。 + +#### 服务降级 + +当服务依赖于多个下游服务,而某个下游服务调用非常慢时,会严重影响当前服务的调用。这里我们可以利用 Sentinel 熔断降级的功能,为调用端配置基于平均 RT 的[降级规则](https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7)。这样当调用链路中某个服务调用的平均 RT 升高,在一定的次数内超过配置的 RT 阈值,Sentinel 就会对此调用资源进行降级操作,接下来的调用都会立刻拒绝,直到过了一段设定的时间后才恢复,从而保护服务不被调用端短板所影响。同时可以配合 fallback 功能使用,在被降级的时候提供相应的处理逻辑。 + +### Fallback + +从 0.1.1 版本开始,Sentinel Dubbo Adapter 还支持配置全局的 fallback 函数,可以在 Dubbo 服务被限流/降级/负载保护的时候进行相应的 fallback 处理。用户只需要实现自定义的 [`DubboFallback`](https://github.com/alibaba/Sentinel/blob/master/sentinel-adapter/sentinel-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/fallback/DubboFallback.java) 接口,并通过 `DubboFallbackRegistry` 注册即可。默认情况会直接将 `BlockException` 包装后抛出。同时,我们还可以配合 [Dubbo 的 fallback 机制](/en/docsv2.7/user/examples/local-mock/) 来为降级的服务提供替代的实现。 + +## Sentinel 与 Hystrix 的比较 + +目前业界常用的熔断降级/隔离的库是 Netflix 的 [Hystrix](https://github.com/Netflix/Hystrix),那么 Sentinel 与 Hystrix 有什么异同呢?Hystrix 的关注点在于以 *隔离* 和 *熔断* 为主的容错机制,而 Sentinel 的侧重点在于多样化的流量控制、熔断降级、系统负载保护、实时监控和控制台,可以看到解决的问题还是有比较大的不同的。 + +Hystrix 采用命令模式封装资源调用逻辑,并且资源的定义与隔离规则是强依赖的,即在创建 HystrixCommand 的时候就要指定隔离规则(因其执行模型依赖于隔离模式)。Sentinel 的设计更为简单,不关注资源是如何执行的,资源的定义与规则的配置相分离。用户可以先定义好资源,然后在需要的时候配置规则即可。Sentinel 的原则非常简单:根据对应资源配置的规则来为资源执行相应的限流/降级/负载保护策略,若规则未配置则仅进行统计。从 0.1.1 版本开始,Sentinel 还引入了[注解支持](https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81),可以更方便地定义资源。 + +隔离是 Hystrix 的核心功能。Hystrix 通过线程池或信号量的方式来对依赖(即 Sentinel 中对应的资源)进行隔离,其中最常用的是资源隔离。Hystrix 线程池隔离的好处是比较彻底,但是不足之处在于要开很多线程池,在应用本身线程数目比较多的时候上下文切换的 overhead 会非常大;Hystrix 的信号量隔离模式可以限制调用的并发数而不显式创建线程,这样的方式比较轻量级,但缺点是无法对慢调用自动进行降级,只能等待客户端自己超时,因此仍然可能会出现级联阻塞的情况。Sentinel 可以通过并发线程数模式的流量控制来提供信号量隔离的功能。并且结合基于响应时间的熔断降级模式,可以在不稳定资源的平均响应时间比较高的时候自动降级,防止过多的慢调用占满并发数,影响整个系统。 + +Hystrix 熔断降级功能采用熔断器模式,在某个服务失败比率高时自动进行熔断。Sentinel 的熔断降级功能更为通用,支持平均响应时间与失败比率两个指标。Sentinel 还提供各种调用链路关系和流量控制效果支持,同时还可以根据系统负载去实时地调整流量来保护系统,应用场景更为丰富。同时,Sentinel 还提供了实时的监控 API 和控制台,可以方便用户快速了解目前系统的状态,对服务的稳定性了如指掌。 + +更详细的对比请参见 [Sentinel 与 Hystrix 的对比](https://github.com/alibaba/Sentinel/wiki/Sentinel-%E4%B8%8E-Hystrix-%E7%9A%84%E5%AF%B9%E6%AF%94)。 + +## 总结 + +以上介绍的只是 Sentinel 的一个最简单的场景 —— 限流。Sentinel 还可以处理更复杂的各种情况,比如超时熔断、冷启动、请求匀速等。可以参考 [Sentinel 文档](https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5),更多的场景等待你去挖掘! diff --git a/content/en/blog/integration/tracing-with-skywalking.md b/content/en/blog/integration/tracing-with-skywalking.md new file mode 100644 index 000000000000..a47ec44dc354 --- /dev/null +++ b/content/en/blog/integration/tracing-with-skywalking.md @@ -0,0 +1,142 @@ +--- +title: "使用Apache Skywalking (Incubator) 做分布式跟踪" +linkTitle: "使用Apache Skywalking (Incubator) 做分布式跟踪" +date: 2019-08-11 +tags: ["生态", "Java"] +description: > + 本文介绍如何使用 Apache Skywalking 对 Dubbo 应用做分布式链路追踪。 +--- + +## Apache Skywalking(Incubator)简介 +[Apache Skywalking(Incubator)](https://github.com/apache/skywalking) 专门为微服务架构和云原生架构系统而设计并且支持分布式链路追踪的APM系统。[Apache Skywalking(Incubator)](https://github.com/apache/skywalking)通过加载探针的方式收集应用调用链路信息,并对采集的调用链路信息进行分析,生成应用间关系和服务间关系以及服务指标。[Apache Skywalking (Incubating)](https://github.com/apache/skywalking)目前支持多种语言,其中包括[Java](https://github.com/apache/skywalking),[.Net Core](https://github.com/OpenSkywalking/skywalking-netcore),[Node.js](https://github.com/OpenSkywalking/skywalking-nodejs)和[Go](https://github.com/SkyAPM/go2sky)语言。 + +目前Skywalking已经支持从6个可视化维度剖析分布式系统的运行情况。总览视图是应用和组件的全局视图,其中包括组件和应用数量,应用的告警波动,慢服务列表以及应用吞吐量;拓扑图从应用依赖关系出发,展现整个应用的拓扑关系;应用视图则是从单个应用的角度,展现应用的上下游关系,TopN的服务和服务器,JVM的相关信息以及对应的主机信息。服务视图关注单个服务入口的运行情况以及此服务的上下游依赖关系,依赖度,帮助用户针对单个服务的优化和监控;调用链展现了调用的单次请求经过的所有埋点以及每个埋点的执行时长;告警视图根据配置阈值针对应用、服务器、服务进行实时告警。 + +## Dubbo与Apache Skywalking(Incubator) +### 编写Dubbo示例程序 +Dubbo实例程序已上传到[Github仓库](https://github.com/SkywalkingTest/dubbo-trace-example)中。方便大家下载使用。 +#### API工程 +服务接口: + +``` +package org.apache.skywalking.demo.interfaces; + +public interface HelloService { + String sayHello(String name); +} +``` + +#### Dubbo服务提供工程 + +``` +package org.apache.skywalking.demo.provider; + +@Service(version = "${demo.service.version}", + application = "${dubbo.application.id}", + protocol = "${dubbo.protocol.id}", + registry = "${dubbo.registry.id}", timeout = 60000) +public class HelloServiceImpl implements HelloService { + + public String sayHello(String name) { + LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1)); + return "Hello, " + name; + } + +} +``` + +#### Consumer工程 + +``` +package org.apache.skywalking.demo.consumer; + +@RestController +public class ConsumerController { + + private static int COUNT = 0; + + @Reference(version = "${demo.service.version}", + application = "${dubbo.application.id}", + url = "dubbo://localhost:20880", timeout = 60000) + private HelloService helloService; + + @GetMapping("/sayHello/{name}") + public String sayHello(@PathVariable(name = "name") String name) { + if ((COUNT++) % 3 == 0){ + throw new RuntimeException(); + } + LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2)); + return helloService.sayHello(name); + } +} +``` + +### 部署Apache Skywalking(Incubator) +Apache Skywalking(Incubator)共提供两种部署模式:单节点模式和集群模式,以下为单节点模式部署步骤,集群模式部署详情参考[文档](https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-setup/)。 +#### 依赖第三方组件 +1. JDK8+ +2. Elasticsearch 5.x +#### 部署步骤 +1. 下载[ Apache Skywalking Collector](http://skywalking.apache.org/downloads/) +2. 部署ElasticSearch + * 修改elasticsearch.yml文件,并设置`cluster.name`设置成`CollectorDBCluster`。此名称需要和collector配置文件一致。 + * 修改ES配置`network.host`值,将`network.host`的值修改成`0.0.0.0`。 + * 启动Elasticsearch +3. 解压并启动Skywalking Collector。运行`bin/startup.sh`命令即可启动Skywalking Collector +#### 启动示例程序 +在启动示例程序之前,执行编译打包的命令: + +``` +./mvnw clean package +``` + +#### 启动服务提供端 + +``` +java -jar -javaagent:$AGENT_PATH/skywalking-agent.jar -Dskywalking.agent.application_code=dubbo-provider -Dskywalking.collector.servers=localhost:10800 dubbo-provider/target/dubbo-provider.jar +``` + +#### 启动服务消费端 + +``` +java -jar -javaagent:$AGENT_PATH/skywalking-agent.jar -Dskywalking.agent.application_code=dubbo-consumer -Dskywalking.collector.servers=localhost:10800 dubbo-consumer/target/dubbo-consumer.jar +``` + +#### 访问消费端提供的服务 + +``` +curl http://localhost:8080/sayHello/test +``` + +## Skywalking监控截图: + +### 首页 + +![/admin-guide/images/skywalking-dashboard.png](/imgs/blog/skywalking-dashboard.png) + +### 拓扑图 +![/admin-guide/images/skywalking-topology.png](/imgs/blog/skywalking-topology.png) + +### 应用视图 +![/admin-guide/images/skywalking-application.png](/imgs/blog/skywalking-application.png) + +JVM信息 +![/admin-guide/images/skywalking-application_instance.png](/imgs/blog/skywalking-application_instance.png) + +### 服务视图 + +服务消费端: +![/admin-guide/images/skywalking-service-consumer.png](/imgs/blog/skywalking-service-consumer.png) + +服务提供端: +![/admin-guide/images/skywalking-service-provider.png](/imgs/blog/skywalking-service-provider.png) + +### Trace视图 +![/admin-guide/images/skywalking-trace.png](/imgs/blog/skywalking-trace.png) + +Span信息: +![/admin-guide/images/skywalking-span-Info.png](/imgs/blog/skywalking-span-Info.png) + +### 告警视图 +![/admin-guide/images/skywalking-alarm.png](/imgs/blog/skywalking-alarm.png) + diff --git a/content/en/blog/integration/use-zipkin-in-dubbo.md b/content/en/blog/integration/use-zipkin-in-dubbo.md new file mode 100644 index 000000000000..328ff3542959 --- /dev/null +++ b/content/en/blog/integration/use-zipkin-in-dubbo.md @@ -0,0 +1,605 @@ +--- +title: "在 Dubbo 中使用 Zipkin" +linkTitle: "在 Dubbo 中使用 Zipkin" +date: 2018-06-17 +tags: ["生态", "Java"] +description: > + 本文介绍如何在 Dubbo 中使用 Zipkin 进行全链路追踪 +--- + +随着业务的发展,应用的规模不断的扩大,传统的应用架构无法满足诉求,服务化架构改造势在必行,以 Dubbo 为代表的分布式服务框架成为了服务化改造架构中的基石。随着微服务理念逐渐被大众接受,应用进一步向更细粒度拆分,并且,不同的应用由不同的开发团队独立负责,整个分布式系统变得十分复杂。没有人能够清晰及时的知道当前系统整体的依赖关系。当出现问题时,也无法及时知道具体是链路上的哪个环节出了问题。 + +在这个背景下,Google 发表了 [Dapper](https://ai.google/research/pubs/pub36356) 的论文,描述了如何通过一个分布式追踪系统解决上述问题。基于该论文,各大互联网公司实现并部署了自己的分布式追踪系统,其中比较出名的有阿里巴巴的 EagleEye。本文中提到的 Zipkin 是 Twitter 公司开源的分布式追踪系统。下面会详细介绍如何在 Dubbo 中使用 Zipkin 来实现分布式追踪。 + +## Zipkin 简介 + +Zipkin 是基于 [Dapper](https://ai.google/research/pubs/pub36356) 论文实现,由 Twitter 开源的分布式追踪系统,通过收集分布式服务执行时间的信息来达到追踪服务调用链路、以及分析服务执行延迟等目的。 + +### Zipkin 架构 + +![Zipkin architecture](/imgs/blog/zipkin-architecture.png) + +Collector 收集器、Storage 存储、API、UI 用户界面等几部分构成了 Zipkin Server 部分,对应于 GitHub 上 [openzipkin/zipkin](https://github.com/openzipkin/zipkin) 这个项目。而收集应用中调用的耗时信息并将其上报的组件与应用共生,并拥有各个语言的实现版本,其中 Java 的实现是 GitHub 上 [openzipkin/brave](https://github.com/openzipkin/brave)。除了 Java 客户端实现之外,openzipkin 还提供了许多其他语言的实现,其中包括了 go、php、JavaScript、.net、ruby 等,具体列表可以参阅 Zipkin 的 [Exiting instrumentations](https://zipkin.io/pages/tracers_instrumentation.html)。 + +### Zipkin 的工作过程 + +当用户发起一次调用时,Zipkin 的客户端会在入口处为整条调用链路生成一个全局唯一的 trace id,并为这条链路中的每一次分布式调用生成一个 span id。span 与 span 之间可以有父子嵌套关系,代表分布式调用中的上下游关系。span 和 span 之间可以是兄弟关系,代表当前调用下的两次子调用。一个 trace 由一组 span 组成,可以看成是由 trace 为根节点,span 为若干个子节点的一棵树。 + +![Related image](/imgs/blog/trace-sample.png) + +Span 由调用边界来分隔,在 Zipkin 中,调用边界由以下四个 annotation 来表示: + +* cs - Clent Sent 客户端发送了请求 +* sr - Server Receive 服务端接受到请求 +* ss - Server Send 服务端处理完毕,向客户端发送回应 +* cr - Client Receive 客户端收到结果 + +显然,通过这四个 annotation 上的时间戳,可以轻易的知道一次完整的调用在不同阶段的耗时,比如: + +* sr - cs 代表了请求在网络上的耗时 +* ss - sr 代表了服务端处理请求的耗时 +* cr - ss 代表了回应在网络上的耗时 +* cr - cs 代表了一次调用的整体耗时 + +Zipkin 会将 trace 相关的信息在调用链路上传递,并在每个调用边界结束时异步的把当前调用的耗时信息上报给 Zipkin Server。Zipkin Server 在收到 trace 信息后,将其存储起来,Zipkin 支持的存储类型有 inMemory、MySql、Cassandra、以及 ElasticsSearch 几种方式。随后 Zipkin 的 Web UI 会通过 API 访问的方式从存储中将 trace 信息提取出来分析并展示,如下图所示: + +![Web interface screenshot](/imgs/blog/zipkin-web-screenshot.png) + + + +## 在 Dubbo 中使用 + +由于 [Brave](https://github.com/openzipkin/brave) 对 Dubbo 已经主动做了支持,在 Dubbo 中集成基于 Zipkin 的链路追踪变的十分简单。下面会按照 Brave 中关于 [Dubbo RPC 支持的指引](https://github.com/openzipkin/brave/blob/master/instrumentation/dubbo/README.md)来说明如何在 Dubbo 中使用 Zipkin。 + +### 安装 Zipkin Server + +按照 [Zipkin 官方文档中的快速开始](https://github.com/openzipkin/zipkin/tree/master/zipkin-server#quick-start) 来安装 Zipkin,如下所示: + +```bash +$ curl -sSL https://zipkin.io/quickstart.sh | bash -s +$ java -jar zipkin.jar +``` + +按照这种方式安装的 Zipkin Server 使用的存储类型是 inMemory 的。当服务器停机之后,所有收集到的 trace 信息会丢失,不适用于生产系统。如果在生产系统中使用,需要配置另外的存储类型。Zipkin 支持 MySql、Cassandra、和 ElasticSearch。推荐使用 Cassandra 和 ElasticSearch,相关的配置请自行查阅[官方文档](https://github.com/openzipkin/zipkin/tree/master/zipkin-server)。 + +本文为了演示方便,使用的存储是 inMemory 类型。成功启动之后,可以在终端看到如下的提示: + +```bash +$ java -jar zipkin.jar +Picked up JAVA_TOOL_OPTIONS: -Djava.awt.headless=true + ******** + ** ** + * * + ** ** + ** ** + ** ** + ** ** + ******** + **** + **** + **** **** + ****** **** *** + **************************************************************************** + ******* **** *** + **** **** + ** + ** + + + ***** ** ***** ** ** ** ** ** + ** ** ** * *** ** **** ** + ** ** ***** **** ** ** *** + ****** ** ** ** ** ** ** ** + +:: Powered by Spring Boot :: (v2.0.5.RELEASE) + +... + +o.s.b.w.e.u.UndertowServletWebServer : Undertow started on port(s) 9411 (http) with context path '' +2018-10-10 18:40:31.605 INFO 21072 --- [ main] z.s.ZipkinServer : Started ZipkinServer in 6.835 seconds (JVM running for 8.35) +``` + +然后在浏览器中访问 http://localhost:9411 验证 WEB 界面。 + +### 配置 Maven 依赖 + +#### 引入 Brave 依赖 + +新建一个新的 Java 工程,并在 pom.xml 中引入 Brave 相关的依赖如下: + +```xml + + 5.4.2 + 2.7.9 + + + + + + + io.zipkin.brave + brave-bom + ${brave.version} + pom + import + + + + + io.zipkin.reporter2 + zipkin-reporter-bom + ${zipkin-reporter.version} + pom + import + + + + + + + + io.zipkin.brave + brave-instrumentation-dubbo-rpc + + + + + io.zipkin.brave + brave-spring-beans + + + + + io.zipkin.brave + brave-context-slf4j + + + + + io.zipkin.reporter2 + zipkin-sender-okhttp3 + + +``` + +其中: + +1. 引入 brave-instrumentation-dubbo-rpc,brave 对 dubbo 的支持:https://github.com/openzipkin/brave/blob/master/instrumentation/dubbo/README.md +2. 引入 brave-spring-beans,brave 对 spring bean 的支持:https://github.com/openzipkin/brave/blob/master/spring-beans/README.md +3. 引入 brave-context-slf4j,brave 对 SLF4J 的支持,可以在 MDC 中使用 traceId 和 spanId:https://github.com/openzipkin/brave/blob/master/context/slf4j/README.md +4. 引入 zipkin-sender-okhttp3,使用 okhttp3 上报数据:https://github.com/openzipkin/zipkin-reporter-java + +#### 引入 Dubbo 相关依赖 + +Dubbo 相关的依赖是 Dubbo 本身以及 Zookeeper 客户端,在下面的例子中,我们将会使用独立的 Zookeeper Server 作为服务发现。 + +```xml + + + + org.apache.curator + curator-framework + 2.12.0 + + + io.netty + netty + + + + + + com.alibaba + dubbo + 2.6.2 + + +``` + +其中: + +1. Dubbo 这里依赖独立的 Zookeeper Server 做服务发现,这里使用的客户端是 Curator +2. 引入 Dubbo 框架的依赖,原则上 2.6 的任何版本都是工作的,这里使用的是 2.6.2 版本 + +### 实现 + +我们这里构造的场景是一个有两个节点的服务依赖链,也就是,当一个 Dubbo 客户端调用服务 A 时,服务 A 将会继续调用服务 B。在这个例子中,服务 A 是 greeting service,它所依赖的下游服务服务 B 是 hello service。 + +#### 定义服务接口 + +为此需要事先定义两个服务接口 GreetingService 以及 HelloService + +1. com.alibaba.dubbo.samples.api.GreetingService + + ```java + package com.alibaba.dubbo.samples.api; + + public interface GreetingService { + String greeting(String message); + } + ``` + +2. com.alibaba.dubbo.samples.api.HelloService + + ```java + package com.alibaba.dubbo.samples.api; + + public interface HelloService { + String hello(String message); + } + ``` + +#### 实现服务接口 + +为了区分对待,所有和 HelloService 相关的实现代码都放在 hello 子包下,同理 GreetingService 相关的放在 greeting 子包下。 + +1. 实现 com.alibaba.dubbo.samples.api.HelloService + + ```java + package com.alibaba.dubbo.samples.service.hello; + + import com.alibaba.dubbo.samples.api.HelloService; + + import java.util.Random; + + public class HelloServiceImpl implements HelloService { + @Override + public String hello(String message) { + try { + // 通过 sleep 模拟业务逻辑处理时间 + Thread.sleep(new Random(System.currentTimeMillis()).nextInt(1000)); + } catch (InterruptedException e) { + // no op + } + return "hello, " + message; + } + } + ``` + +2. 实现 com.alibaba.dubbo.samples.api.GreetingService + + ```java + package com.alibaba.dubbo.samples.service.greeting; + + import com.alibaba.dubbo.samples.api.GreetingService; + import com.alibaba.dubbo.samples.api.HelloService; + + import java.util.Random; + + public class GreetingServiceImpl implements GreetingService { + // 下游依赖服务,运行时靠 spring 容器注入 HelloService 的服务代理 + private HelloService helloService; + + public void setHelloService(HelloService helloService) { + this.helloService = helloService; + } + + @Override + public String greeting(String message) { + try { + // 通过 sleep 模拟业务逻辑处理时间 + Thread.sleep(new Random(System.currentTimeMillis()).nextInt(1000)); + } catch (InterruptedException e) { + // no op + } + return "greeting, " + helloService.hello(message); + } + } + ``` + + 这里需要注意的是,GreetingServiceImpl 的实现中声明了一个类型是 HelloService 的成员变量,并在 greeting 方法中,执行完自己逻辑之后又调用了 HelloService 上的 hello 方法。这里的 helloService 的实现将会在运行态由外部注入,注入的不是 HelloServiceImpl 的实现,而是 HelloService 的远程调用代理。通过这样的方式,完成了在一个 Dubbo 服务中继续调用另一个远程 Dubbo 服务的目的。从链路追踪的角度来说,客户端调用 GreetingService 是一个 span,GreetingService 调用 HelloService 是另一个 span,并且两者有父子关系,同属于一个 trace,也就是属于同一条调用链路。 + + 另外,在 GreetingServiceImpl 和 HelloServiceImpl 的实现中,通过 Thread.sleep 来模拟了处理业务逻辑的耗时,以便在 Zipkin UI 上更好的展示。 + +#### 配置 + +为了专注在展示如何使用 Zipkin 这一点上,本文在配置和编程模型上没有采用更多的高级技术,而是使用了最传统的 Spring XML 的配置方式,帮助读者理解。更高级的通过 annotation 甚至 spring boot 的方式,读者可以自行查阅 Dubbo 和 Zipkin 相关的文档。 + +1. 暴露 HelloService 服务 + + 在 resouces/spring/hello-service.xml 中增加以下的配置来将 HelloServiceImpl 暴露成一个 Dubbo 服务: + + * 使用了本地启动的 Zookeeper Server 作为注册中心,地址为默认值 zookeeper://127.0.0.1:2181 + * 用 Dubbo 原生服务在端口 20880 上暴露服务 + * 将 HelloServiceImpl 注册成 id 是 `helloService` 的 Spring Bean,这样就可以在后续的 `` 中引用到这个实现类 + * 通过 `` 将 HelloServiceImpl 暴露成 Dubbo 服务 + + ```xml + + + + + + + + + + + + + + + ``` + +2. 增加 Zipkin 相关的配置 + + 在 resources/spring/hello-service.xml 中增加 Zipkin 相关的配置: + + * 修改 dubbo 服务暴露的配置,添加 Zipkin 的 tracing filter 到 Dubbo 的 filter chain 中 + * 按照 https://github.com/openzipkin/brave/blob/master/spring-beans/README.md 来配置 Zipkin 的 sender 和 tracing 的 spring bean + + ```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + ``` + +3. 增加 HelloService 的启动类 + + 在 com.alibaba.dubbo.samples.service.hello.Application 中通过 ClassPathXmlApplicationContext 读取 刚才配置的 spring/hello-service.xml 来初始化一个 spring context 并启动 + + ```java + package com.alibaba.dubbo.samples.service.hello; + + import org.springframework.context.support.ClassPathXmlApplicationContext; + + import java.io.IOException; + + public class Application { + public static void main(String[] args) throws IOException { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/hello-service.xml"); + context.start(); + + System.out.println("Hello service started"); + // press any key to exit + System.in.read(); + } + } + ``` + +4. 暴露 GreetingService 服务,并使用 Zipkin + + 在 resources/spring/greeting-service.xml 中配置 GreetingService。相关步骤与 HelloService 类似,不再赘述,重点关注如何在 GreetingService 中配置下游服务的依赖。完整的 XML 配置如下: + + ```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ``` + + 这里的配置与上面的 HelloService 类似,需要重点关注的有两点: + + * 第 3 步中注意服务需要暴露在不同的端口上,否则会和 HelloService 冲突,本例中选择的是 20881 这个端口 + + * 通过第 4 步先声明 HelloService 的远程代理,然后在第 5 步中将其组装给 GreetingService 来完成服务上下游依赖的声明 + + + 增加 GreeeingService 的启动类,与 HelloService 类似,通过 spring/greeting-service.xml 的配置来初始化一个新的 spring context 来完成。 + + ```java + package com.alibaba.dubbo.samples.service.greeting; + + import org.springframework.context.support.ClassPathXmlApplicationContext; + + import java.io.IOException; + + public class Application { + public static void main(String[] args) throws IOException { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/greeting-service.xml"); + context.start(); + + System.out.println("Greeting service started"); + // press any key to exit + System.in.read(); + } + } + ``` + +5. 实现客户端 + + 通过 resources/spring/client.xml 初始化一个 spring context,从其中获取 GreetingService 的远程代理,发起远程调用。 + + ```java + package com.alibaba.dubbo.samples.client; + + import com.alibaba.dubbo.samples.api.GreetingService; + import org.springframework.context.support.ClassPathXmlApplicationContext; + + public class Application { + + public static void main(String[] args) { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/client.xml"); + context.start(); + // 获取远程代理并发起调用 + GreetingService greetingService = (GreetingService) context.getBean("greetingService"); + System.out.println(greetingService.greeting("world")); + } + } + ``` + + resource/spring/client.xml 中的配置与 Dubbo 服务的配置类似,主要是配置远程代理,以及配置 Zipkin + + ```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ``` + +完成之后的工程的目录结构如下: + +![zipkin dubbo project structure](/imgs/blog/zipkin-dubbo-project.png) + +### 运行 + +现在让我们把整个链路运行起来,看看 Zipkin 链路追踪的效果。 + +#### 启动 Zookeeper Server + +执行以下命令在本地启动一个 Zookeeper Server,如果没有安装,请自行从 [ZooKeeper 官网](https://zookeeper.apache.org) 下载: + +```bash +$ zkServer start +``` + +#### 启动 Zipkin Server + +执行以下命令在本地启动一个 Zipkin Server: + +```bash +$ curl -sSL https://zipkin.io/quickstart.sh | bash -s +$ java -jar zipkin.jar +``` + +#### 启动 HelloService + +使用下面的命令启动 HelloService,当然也可以直接在 IDE 中启动: + +```bash +$ mvn exec:java -Dexec.mainClass=com.alibaba.dubbo.samples.service.hello.Application +``` + +启动成功后应该可以在终端上看到 “Hello service started” 的字样。 + +#### 启动 GreetingService + +使用下面的命令启动 GreetingService,当然也可以直接在 IDE 中启动: + +```bash +$ mvn exec:java -Dexec.mainClass=com.alibaba.dubbo.samples.service.greeting.Application +``` + +启动成功后应该可以在终端上看到 “Greeting service started” 的字样。 + +#### 运行 Dubbo 客户端 + +使用下面的命令运行 Dubbo 客户端向 GreetingService 发起远程调用,当然也可以直接在 IDE 中运行: + +```bash +$ mvn exec:java -Dexec.mainClass=com.alibaba.dubbo.samples.client.Application +``` + +执行成功后,客户端会在终端上输出 “greeting, hello, world”。 + +#### 链路追踪 + +打开浏览器访问 "http://localhost:9411" 并通过 "Find Traces" 按钮来搜索,可以找到刚刚调用的链路追踪,效果如下图所示: + +![zipkin trace](/imgs/blog/zipkin-trace.png) + +还可以进一步的选择每一个 span 来查看本次调用边界内的详情,比如,hello-service 这个 span 的详情如下: + +![zipkin span](/imgs/blog/zipkin-span.png) + + + +## 总结 + +本文介绍了链路追踪的基本概念以及 Zipkin 的基本用法,然后用 Dubbo 构建了一条最简单的调用链路,并引入了 Zipkin 做全链路追踪。由于 Zipkin 对 Dubbo 做了很好的支持,整个集成的过程还是十分简单明了的。 + +Zipkin 对 Dubbo 的支持是构建在 Dubbo 的 filter 扩展机制上的,有兴趣的读者可以通过 https://github.com/openzipkin/brave/blob/master/instrumentation/dubbo/src/main/java/brave/dubbo/TracingFilter.java 了解其实现细节。 + +本文中涉及的例子可以从 https://github.com/dubbo/dubbo-samples 中的 "dubbo-samples-zipkin" 子模块中获取。另外,spring-cloud-sleth 2.0 中开始正式支持 Dubbo,相关的文章和例子后续计划提供。 diff --git a/content/en/blog/java/_index.md b/content/en/blog/java/_index.md new file mode 100644 index 000000000000..d972057e1a4c --- /dev/null +++ b/content/en/blog/java/_index.md @@ -0,0 +1,9 @@ + +--- +title: "Java" +linkTitle: "Java" +weight: 20 +description: "Dubbo Java 相关博客" +--- + + diff --git a/content/en/blog/java/codeanalysis/3.0.8/1-learn-from-a-demo.md b/content/en/blog/java/codeanalysis/3.0.8/1-learn-from-a-demo.md new file mode 100644 index 000000000000..3971ac5b83d7 --- /dev/null +++ b/content/en/blog/java/codeanalysis/3.0.8/1-learn-from-a-demo.md @@ -0,0 +1,124 @@ +--- +title: "01 从一个服务提供者的Demo说起" +linkTitle: "1-从一个服务提供者的Demo说起" +date: 2022-08-01 +author: 宋小生 +tags: ["源码解析", "Java"] +description: Dubbo 源码解析之从一个服务提供者的Demo说起 +--- + +# 1 从一个服务提供者的Demo说起 + +为了更方便了解原理,我们先来编写一个Demo,从例子中来看源码实现: + +## 1.1 启动Zookeeper + +为了Demo可以正常启动,需要我们先在本地启动一个Zookeeper如下图所示: +![在这里插入图片描述](/imgs/blog/source-blog/1-zookeeper.png) + + +## 1.2 服务提供者 +接下来给大家贴一下示例源码,这个源码来源于Dubbo源码目录的 dubbo-demo/dubbo-demo-api 目录下面的dubbo-demo-api-provider子项目,这里我做了删减,方便看核心代码: +首先我们定义一个服务接口如下所示: + +```java +import java.util.concurrent.CompletableFuture; +public interface DemoService { + /** + * 同步处理的服务方法 + * @param name + * @return + */ + String sayHello(String name); + + /** + * 用于异步处理的服务方法 + * @param name + * @return + */ + default CompletableFuture sayHelloAsync(String name) { + return CompletableFuture.completedFuture(sayHello(name)); + } +} +``` + + +```java +服务实现类如下: + +import org.apache.dubbo.rpc.RpcContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.CompletableFuture; + +public class DemoServiceImpl implements DemoService { + private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class); + + @Override + public String sayHello(String name) { + logger.info("Hello " + name + ", request from consumer: " + RpcContext.getServiceContext().getRemoteAddress()); + return "Hello " + name + ", response from provider: " + RpcContext.getServiceContext().getLocalAddress(); + } + + @Override + public CompletableFuture sayHelloAsync(String name) { + return null; + } + +} +``` + +## 1.3 启用服务 +有了服务接口之后我们来启用服务,启用服务的源码如下: + +```java +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.MetadataReportConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.ServiceConfig; +import org.apache.dubbo.config.bootstrap.DubboBootstrap; +import org.apache.dubbo.demo.DemoService; + +public class Application { + public static void main(String[] args) throws Exception { + startWithBootstrap(); + } + private static void startWithBootstrap() { + ServiceConfig service = new ServiceConfig<>(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider")) + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) + .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) + .service(service) + .start() + .await(); + } +} +``` + +## 1.4 启用服务后写入Zookeeper的节点数据 +启动服务,这个时候我们打开Zookeeper图形化客户端来看看这个服务在Zookeeper上面写入来哪些数据,如下图: +![在这里插入图片描述](/imgs/blog/source-blog/1-zookeeper-data.png) +写入Zookeper上的节点用于服务在分布式场景下的协调,这些节点是比较重要的。 + +如果了解过Dubbo的同学,应该会知道Dubbo在低版本的时候会向注册中心中写入服务接口,具体路径在上面的 **dubbo目录下** ,然后在 **/dubbo/服务接口/** 路径下写入如下信息: +* **服务提供者**配置信息URL形式 +* **服务消费者**的配置信息URL形式 +* 服务**路由信息** +* **配置信息** + +上面这个图就是Dubbo3的注册信息了,后面我们也会围绕细节来说明下,这里可以看下新增了: +* /dubbo/metadata **元数据信息** +* /dubbo/mapping 服务和应用的**映射信息** +* /dubbo/config **注册中心配置** + * /services目录**应用信息** + +在这里可以大致了解下,在后面会有更详细的源码解析这个示例代码.通过透析代码来看透Dubbo3服务注册原理,服务提供原理。 + + +原文: [<<从一个服务提供者的Demo说起>>](https://blog.elastic.link/2022/07/10/dubbo/1-cong-yi-ge-demo-shuo-qi/ ) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/10-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\346\267\273\345\212\240\346\263\250\345\206\214\344\270\255\345\277\203\351\205\215\347\275\256\344\277\241\346\201\257RegistryConfig.md" "b/content/en/blog/java/codeanalysis/3.0.8/10-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\346\267\273\345\212\240\346\263\250\345\206\214\344\270\255\345\277\203\351\205\215\347\275\256\344\277\241\346\201\257RegistryConfig.md" new file mode 100644 index 000000000000..dadc823769bf --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/10-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\346\267\273\345\212\240\346\263\250\345\206\214\344\270\255\345\277\203\351\205\215\347\275\256\344\277\241\346\201\257RegistryConfig.md" @@ -0,0 +1,230 @@ +--- +title: "10-Dubbo启动器DubboBootstrap添加注册中心配置信息RegistryConfig" +linkTitle: "10-Dubbo启动器DubboBootstrap添加注册中心配置信息RegistryConfig" +date: 2022-08-10 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] RegistryConfig注册中心配置包含了一些比较基础的注册信息相关的配置信息,注册中心是服务在分布式场景下的基础服务。 +--- + +# 10-Dubbo启动器DubboBootstrap添加注册中心配置信息RegistryConfig +## 10.1 简介 +先贴个代码用来参考: + +```java + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider")) + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) + .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) + .service(service) + .start() + .await(); + +``` + +上个博客我们说了启动器ApplicationConfig对象的创建,启动器对象在启动之前是要初始化一些配置信息的,这里我们来看这一行代码注册中心配置信息: +```java +registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) +``` + + +## 10.2 注册中心的配置相关 + +下面的配置来源于官网 + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| ---------- | -------------------- | ------- | -------- | ------ | -------- | ------------------------------------------------------------ | -------------- | +| id | | string | 可选 | | 配置关联 | 注册中心引用BeanId,可以在中引用此ID | 1.0.16以上版本 | +| address | | string | **必填** | | 服务发现 | 注册中心服务器地址,如果地址没有端口缺省为9090,同一集群内的多个地址用逗号分隔,如:ip:port,ip:port,不同集群的注册中心,请配置多个标签 | 1.0.16以上版本 | +| protocol | | string | 可选 | dubbo | 服务发现 | 注册中心地址协议,支持`dubbo`, `multicast`, `zookeeper`, `redis`, `consul(2.7.1)`, `sofa(2.7.2)`, `etcd(2.7.2)`, `nacos(2.7.2)`等协议 | 2.0.0以上版本 | +| port | | int | 可选 | 9090 | 服务发现 | 注册中心缺省端口,当address没有带端口时使用此端口做为缺省值 | 2.0.0以上版本 | +| username | | string | 可选 | | 服务治理 | 登录注册中心用户名,如果注册中心不需要验证可不填 | 2.0.0以上版本 | +| password | | string | 可选 | | 服务治理 | 登录注册中心密码,如果注册中心不需要验证可不填 | 2.0.0以上版本 | +| transport | registry.transporter | string | 可选 | netty | 性能调优 | 网络传输方式,可选mina,netty | 2.0.0以上版本 | +| timeout | registry.timeout | int | 可选 | 5000 | 性能调优 | 注册中心请求超时时间(毫秒) | 2.0.0以上版本 | +| session | registry.session | int | 可选 | 60000 | 性能调优 | 注册中心会话超时时间(毫秒),用于检测提供者非正常断线后的脏数据,比如用心跳检测的实现,此时间就是心跳间隔,不同注册中心实现不一样。 | 2.1.0以上版本 | +| file | registry.file | string | 可选 | | 服务治理 | 使用文件缓存注册中心地址列表及服务提供者列表,应用重启时将基于此文件恢复,注意:两个注册中心不能使用同一文件存储 | 2.0.0以上版本 | +| wait | registry.wait | int | 可选 | 0 | 性能调优 | 停止时等待通知完成时间(毫秒) | 2.0.0以上版本 | +| check | check | boolean | 可选 | true | 服务治理 | 注册中心不存在时,是否报错 | 2.0.0以上版本 | +| register | register | boolean | 可选 | true | 服务治理 | 是否向此注册中心注册服务,如果设为false,将只订阅,不注册 | 2.0.5以上版本 | +| subscribe | subscribe | boolean | 可选 | true | 服务治理 | 是否向此注册中心订阅服务,如果设为false,将只注册,不订阅 | 2.0.5以上版本 | +| dynamic | dynamic | boolean | 可选 | true | 服务治理 | 服务是否动态注册,如果设为false,注册后将显示为disable状态,需人工启用,并且服务提供者停止时,也不会自动取消注册,需人工禁用。 | 2.0.5以上版本 | +| group | group | string | 可选 | dubbo | 服务治理 | 服务注册分组,跨组的服务不会相互影响,也无法相互调用,适用于环境隔离。 | 2.0.5以上版本 | +| simplified | simplified | boolean | 可选 | false | 服务治理 | 注册到注册中心的URL是否采用精简模式的(与低版本兼容) | 2.7.0以上版本 | +| extra-keys | extraKeys | string | 可选 | | 服务治理 | 在simplified=true时,extraKeys允许你在默认参数外将额外的key放到URL中,格式:“interface,key1,key2”。 | 2.7.0以上版本 | + + + + 同样官网提供的参数里面并未包含所有的属性 下面我就将其余的属性列举一下方便学习参考: + +| 变量 | 类型 | 说明 | +|--|--|--| +| server |String | +| client |String | +| cluster |String |影响流量在注册中心之间的分布,在订阅多个注册中心时很有用,可用选项:1。区域感知,特定类型的流量总是根据流量的来源进入一个注册表。| +| zone |String |注册表所属的区域,通常用于隔离流量| +| parameters |Map |自定义参数| +| useAsConfigCenter |Boolean |该地址是否用作配置中心| +| useAsMetadataCenter |Boolean |该地址是否用作远程元数据中心| +| accepts |String |此注册表接受的rpc协议列表,例如“dubbo,rest”| +| preferred |Boolean |如果设置为true,则始终首先使用此注册表,这在订阅多个注册表时非常有用| +| weight |Integer |影响注册中心之间的流量分布,当订阅多个注册中心仅在未指定首选注册中心时才生效时,此功能非常有用。| +| registerMode |String |注册模式:实例级,接口级,所有| +| enableEmptyProtection |Boolean |收到的空url地址列表和空保护被禁用,将清除当前可用地址| + + + +## 10.3 注册中心配置对象创建与添加 +前面例子中调用的代码 +```java +.registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) +``` + +首先我们要来看的是RegistryConfig类型的构造器 + +```java +public RegistryConfig(String address) { + setAddress(address); + } +``` + +继续看setAddress方法 + +```java + public void setAddress(String address) { + //保存地址 + this.address = address; + //下面是支持将参数在url地址后面 比如用户名,密码,协议,端口,这几个参数提前做解析放入成员变量中 + if (address != null) { + try { + //地址转Dubbo的URL对象 这个URL是Dubbo自行实现的URL封装信息的类型 + URL url = URL.valueOf(address); + + // Refactor since 2.7.8 + //值不存在时候更新属性,非常巧妙的代码 重构了多个if判断 + //第一个参数值不存在则调用第二个方法,第二个方法的参数为第三方方法 + updatePropertyIfAbsent(this::getUsername, this::setUsername, url.getUsername()); + updatePropertyIfAbsent(this::getPassword, this::setPassword, url.getPassword()); + updatePropertyIfAbsent(this::getProtocol, this::setProtocol, url.getProtocol()); + updatePropertyIfAbsent(this::getPort, this::setPort, url.getPort()); + + //移除掉url中的backup自定义参数 (备份的注册中心地址) + Map params = url.getParameters(); + if (CollectionUtils.isNotEmptyMap(params)) { + params.remove(BACKUP_KEY); + } + //将自定义参数存储到成员变量中 + updateParameters(params); + } catch (Exception ignored) { + } + } + } +``` + + +然后再回过头来看DubboBootstrap的registry方法: + +```java + public DubboBootstrap registry(RegistryConfig registryConfig) { + //将applicationModel对象设置给注册中心配置对象 + registryConfig.setScopeModel(applicationModel); + //将注册中心配置对象添加到配置管理器中 + configManager.addRegistry(registryConfig); + return this; + } +``` + + +直接来看配置管理器configManager的添加注册中心配置addRegistry方法: + +```java +public void addRegistry(RegistryConfig registryConfig) { + addConfig(registryConfig); +} +``` + +configManager 的addConfig方法: + +```java +public final T addConfig(AbstractConfig config) { + if (config == null) { + return null; + } + // ignore MethodConfig + //检查当前配置管理器支持管理的配置对象 + //目前支持的配置有ApplicationConfig,MonitorConfig,MetricsConfig,SslConfig, + //ProtocolConfig,RegistryConfig,ConfigCenterConfig,MetadataReportConfig + if (!isSupportConfigType(config.getClass())) { + throw new IllegalArgumentException("Unsupported config type: " + config); + } + + if (config.getScopeModel() != scopeModel) { + config.setScopeModel(scopeModel); + } + //缓存中是否存在 + Map configsMap = configsCache.computeIfAbsent(getTagName(config.getClass()), type -> new ConcurrentHashMap<>()); + //不是服务级接口配置则直接从缓存中读取到配置之后直接返回 + // fast check duplicated equivalent config before write lock + if (!(config instanceof ReferenceConfigBase || config instanceof ServiceConfigBase)) { + for (AbstractConfig value : configsMap.values()) { + if (value.equals(config)) { + return (T) value; + } + } + } + + // lock by config type + //添加配置 + synchronized (configsMap) { + return (T) addIfAbsent(config, configsMap); + } + } +``` + + + +ConfigManager配置管理器的addIfAbsent方法: + +```java +private C addIfAbsent(C config, Map configsMap) + throws IllegalStateException { + //配置信息为空直接返回 + if (config == null || configsMap == null) { + return config; + } + + // find by value + //根据配置规则判断,配置存在则返回 + Optional prevConfig = findDuplicatedConfig(configsMap, config); + if (prevConfig.isPresent()) { + return prevConfig.get(); + } + + //生成配置key + String key = config.getId(); + if (key == null) { + do { + // generate key if id is not set + key = generateConfigId(config); + } while (configsMap.containsKey(key)); + } + + //不相同的配置key重复则抛出异常 + C existedConfig = configsMap.get(key); + if (existedConfig != null && !isEquals(existedConfig, config)) { + String type = config.getClass().getSimpleName(); + logger.warn(String.format("Duplicate %s found, there already has one default %s or more than two %ss have the same id, " + + "you can try to give each %s a different id, override previous config with later config. id: %s, prev: %s, later: %s", + type, type, type, type, key, existedConfig, config)); + } + + // override existed config if any + //将配置对象存入configsMap对象中,configsMap来源于configsCache + configsMap.put(key, config); + return config; + } +``` + + + 原文: [<>](https://blog.elastic.link/2022/07/10/dubbo/10-dubbo-qi-dong-qi-dubbobootstrap-tian-jia-zhu-ce-zhong-xin-pei-zhi-xin-xi-registryconfig//) \ No newline at end of file diff --git "a/content/en/blog/java/codeanalysis/3.0.8/11-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\346\267\273\345\212\240\345\215\217\350\256\256\351\205\215\347\275\256\344\277\241\346\201\257ProtocolConfig.md" "b/content/en/blog/java/codeanalysis/3.0.8/11-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\346\267\273\345\212\240\345\215\217\350\256\256\351\205\215\347\275\256\344\277\241\346\201\257ProtocolConfig.md" new file mode 100644 index 000000000000..55a51d5dc5c8 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/11-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\346\267\273\345\212\240\345\215\217\350\256\256\351\205\215\347\275\256\344\277\241\346\201\257ProtocolConfig.md" @@ -0,0 +1,110 @@ +--- +title: "11-Dubbo启动器DubboBootstrap添加协议配置信息ProtocolConfig" +linkTitle: "11-Dubbo启动器DubboBootstrap添加协议配置信息ProtocolConfig" +date: 2022-08-11 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] ProtocolConfig协议配置是RPC调用过程中一些必要信息的基础。 +--- + +# 11-Dubbo启动器DubboBootstrap添加协议配置信息ProtocolConfig +## 11.1 简介 +先贴个代码用来参考: + +```java + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider")) + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) + .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) + .service(service) + .start() + .await(); + +``` + +上个博客我们说了 RegistryConfig对象的创建,启动器对象在启动之前是要初始化一些配置信息的,这里我们来看这一行代码协议配置信息: +```java +.protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) +``` + + +## 11.2 协议的配置相关 + +下面的配置来源于官网 + +服务提供者协议配置。对应的配置类: org.apache.dubbo.config.ProtocolConfig。同时,如果需要支持多协议,可以声明多个 标签,并在 中通过 protocol 属性指定使用的协议。 + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| ------------- | ------------- | -------------- | -------- | ------------------------------------------------------------ | -------- | ------------------------------------------------------------ | -------------- | +| id | | string | 可选 | dubbo | 配置关联 | 协议BeanId,可以在中引用此ID,如果ID不填,缺省和name属性值一样,重复则在name后加序号。 | 2.0.5以上版本 | +| name | | string | **必填** | dubbo | 性能调优 | 协议名称 | 2.0.5以上版本 | +| port | | int | 可选 | dubbo协议缺省端口为20880,rmi协议缺省端口为1099,http和hessian协议缺省端口为80;如果**没有**配置port,则自动采用默认端口,如果配置为**-1**,则会分配一个没有被占用的端口。Dubbo 2.4.0+,分配的端口在协议缺省端口的基础上增长,确保端口段可控。 | 服务发现 | 服务端口 | 2.0.5以上版本 | +| host | | string | 可选 | 自动查找本机IP | 服务发现 | -服务主机名,多网卡选择或指定VIP及域名时使用,为空则自动查找本机IP,-建议不要配置,让Dubbo自动获取本机IP | 2.0.5以上版本 | +| threadpool | threadpool | string | 可选 | fixed | 性能调优 | 线程池类型,可选:fixed/cached | 2.0.5以上版本 | +| threads | threads | int | 可选 | 200 | 性能调优 | 服务线程池大小(固定大小) | 2.0.5以上版本 | +| iothreads | threads | int | 可选 | cpu个数+1 | 性能调优 | io线程池大小(固定大小) | 2.0.5以上版本 | +| accepts | accepts | int | 可选 | 0 | 性能调优 | 服务提供方最大可接受连接数 | 2.0.5以上版本 | +| payload | payload | int | 可选 | 8388608(=8M) | 性能调优 | 请求及响应数据包大小限制,单位:字节 | 2.0.5以上版本 | +| codec | codec | string | 可选 | dubbo | 性能调优 | 协议编码方式 | 2.0.5以上版本 | +| serialization | serialization | string | 可选 | dubbo协议缺省为hessian2,rmi协议缺省为java,http协议缺省为json | 性能调优 | 协议序列化方式,当协议支持多种序列化方式时使用,比如:dubbo协议的dubbo,hessian2,java,compactedjava,以及http协议的json等 | 2.0.5以上版本 | +| accesslog | accesslog | string/boolean | 可选 | | 服务治理 | 设为true,将向logger中输出访问日志,也可填写访问日志文件路径,直接把访问日志输出到指定文件 | 2.0.5以上版本 | +| path | | string | 可选 | | 服务发现 | 提供者上下文路径,为服务path的前缀 | 2.0.5以上版本 | +| transporter | transporter | string | 可选 | dubbo协议缺省为netty | 性能调优 | 协议的服务端和客户端实现类型,比如:dubbo协议的mina,netty等,可以分拆为server和client配置 | 2.0.5以上版本 | +| server | server | string | 可选 | dubbo协议缺省为netty,http协议缺省为servlet | 性能调优 | 协议的服务器端实现类型,比如:dubbo协议的mina,netty等,http协议的jetty,servlet等 | 2.0.5以上版本 | +| client | client | string | 可选 | dubbo协议缺省为netty | 性能调优 | 协议的客户端实现类型,比如:dubbo协议的mina,netty等 | 2.0.5以上版本 | +| dispatcher | dispatcher | string | 可选 | dubbo协议缺省为all | 性能调优 | 协议的消息派发方式,用于指定线程模型,比如:dubbo协议的all, direct, message, execution, connection等 | 2.1.0以上版本 | +| queues | queues | int | 可选 | 0 | 性能调优 | 线程池队列大小,当线程池满时,排队等待执行的队列大小,建议不要设置,当线程池满时应立即失败,重试其它服务提供机器,而不是排队,除非有特殊需求。 | 2.0.5以上版本 | +| charset | charset | string | 可选 | UTF-8 | 性能调优 | 序列化编码 | 2.0.5以上版本 | +| buffer | buffer | int | 可选 | 8192 | 性能调优 | 网络读写缓冲区大小 | 2.0.5以上版本 | +| heartbeat | heartbeat | int | 可选 | 0 | 性能调优 | 心跳间隔,对于长连接,当物理层断开时,比如拔网线,TCP的FIN消息来不及发送,对方收不到断开事件,此时需要心跳来帮助检查连接是否已断开 | 2.0.10以上版本 | +| telnet | telnet | string | 可选 | | 服务治理 | 所支持的telnet命令,多个命令用逗号分隔 | 2.0.5以上版本 | +| register | register | boolean | 可选 | true | 服务治理 | 该协议的服务是否注册到注册中心 | 2.0.8以上版本 | +| contextpath | contextpath | String | 可选 | 缺省为空串 | 服务治理 | | 2.0.6以上版本 | + + + 同样官网提供的参数里面并未包含所有的属性 下面我就将其余的属性列举一下方便学习参考: + +| 变量 | 类型 | 说明 | +|--|--|--| +|threadname|String|线程池名称| +|corethreads|Integer|线程池核心线程大小| +|alive|Integer|线程池keepAliveTime,默认单位时间单位。毫秒| +|exchanger|String|交换器配置信息如何交换| +|prompt|String|命令行提示符| +|status|String|状态检查| +|sslEnabled|Boolean|ssl是否启用| + + +## 11.3 协议配置对象创建与添加 +前面例子中调用的代码 +```java + .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) +``` +这里我们配置了协议类型为dubbo 端口为-1则会分配一个没有被占用的端口 + +继续看下DubboBootstrap的protocol方法 + +```java +public DubboBootstrap protocol(ProtocolConfig protocolConfig) { + //配置信息转List + return protocols(singletonList(protocolConfig)); + } +``` + +继续看protocols方法 ,这个代码与前面两个博客中看到的向配置管理器添加配置对象的逻辑是一样的 +这里就不说了可以看前面的博客[《9-Dubbo启动器DubboBootstrap添加应用程序的配置信息ApplicationConfig》](https://blog.elastic.link/2022/07/10/dubbo/9-dubbo-qi-dong-qi-dubbobootstrap-tian-jia-ying-yong-cheng-xu-de-pei-zhi-xin-xi-applicationconfig/) +```java + public DubboBootstrap protocols(List protocolConfigs) { + if (CollectionUtils.isEmpty(protocolConfigs)) { + return this; + } + for (ProtocolConfig protocolConfig : protocolConfigs) { + protocolConfig.setScopeModel(applicationModel); + configManager.addProtocol(protocolConfig); + } + return this; + } +``` + +原文:[Dubbo启动器DubboBootstrap添加协议配置信息ProtocolConfig](https://blog.elastic.link/2022/07/10/dubbo/11-dubbo-qi-dong-qi-dubbobootstrap-tian-jia-xie-yi-pei-zhi-xin-xi-protocolconfig/) \ No newline at end of file diff --git "a/content/en/blog/java/codeanalysis/3.0.8/12-\345\205\250\345\261\200\350\247\206\351\207\216\346\235\245\347\234\213Dubbo3\347\232\204\346\234\215\345\212\241\345\220\257\345\212\250\347\224\237\345\221\275\345\221\250\346\234\237.md" "b/content/en/blog/java/codeanalysis/3.0.8/12-\345\205\250\345\261\200\350\247\206\351\207\216\346\235\245\347\234\213Dubbo3\347\232\204\346\234\215\345\212\241\345\220\257\345\212\250\347\224\237\345\221\275\345\221\250\346\234\237.md" new file mode 100644 index 000000000000..a2ee29d18e56 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/12-\345\205\250\345\261\200\350\247\206\351\207\216\346\235\245\347\234\213Dubbo3\347\232\204\346\234\215\345\212\241\345\220\257\345\212\250\347\224\237\345\221\275\345\221\250\346\234\237.md" @@ -0,0 +1,350 @@ +--- +title: "12 全局视野来看Dubbo3的服务启动生命周期" +linkTitle: "12 全局视野来看Dubbo3的服务启动生命周期" +date: 2022-08-12 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] 全局视野来看Dubbo3的服务启动生命周期,了解了Dubbo3的启动生命周期,可以有效的了解整个Dubbo应用的启动阶段。 +--- + +# 12 全局视野来看Dubbo3的服务启动生命周期 +## 12.1 启动方法简介 +在说启动方法之前先把视野拉回第一章[《1-从一个服务提供者的Demo说起》](https://blog.elastic.link/2022/07/10/dubbo/1-cong-yi-ge-demo-shuo-qi/ )我们的Demo代码,下面只贴一下核心代码: + +```java +public class Application { + public static void main(String[] args) throws Exception { + startWithBootstrap(); + } + private static void startWithBootstrap() { + //前面的文章都在说这个服务配置对象的创建,中间又说了分层域模型,扩展加载机制 + ServiceConfig service = new ServiceConfig<>(); + //为服务配置下服务接口和服务实现,下面两行用来初始化对象就不详细说了 + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + //这一个篇章主要说这里: + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + //初始化应用配置 + bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider")) + //初始化注册中心配置 + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) + //初始化协议配置 + .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) + //初始化服务配置 + .service(service) + //启动 + .start() + .await(); + } +} +``` + +前面我们介绍了Dubbo启动器DubboBootstrap类型对象的创建,又介绍了为DubboBootstrap启动器初始化各种配置信息,这一个博客就开始到了分析启动方法的位置了,Dubbo启动器借助Deployer发布器来启动和发布服务,发布器的启动过程包含了启动配置中心,加载配置,启动元数据中心,启动服务等操作都是比较重要又比较复杂的过程,这里我们先来看下启动过程的生命周期来为后面的内容做好铺垫。 + +## 12.2 启动器启动方法的调用逻辑start() +这里我们就直接来看DubboBootstrap的start()方法: + +```java + public DubboBootstrap start() { + //调用重载的方法进行启动参数代表是否等待启动结束 + this.start(true); + return this; + } +``` + +我们再来看重载的start方法: + +```java +public DubboBootstrap start(boolean wait) { + //这个发布器是在ApplicationModel对象创建之后初始化的时候进行初始化的具体类型为DefaultApplicationDeployer + Future future = applicationDeployer.start(); + + if (wait) { + try { + //等待异步启动的结果 + future.get(); + } catch (Exception e) { + //启动失败则抛出一个异常 + throw new IllegalStateException("await dubbo application start finish failure", e); + } + } + return this; + } +``` + + +## 12.3 应用程序发布器DefaultApplicationDeployer的启动方法 +发布器是帮助我们发布服务和引用服务的,在Dubbo3中不论是服务提供者还是服务消费者如果想要启动服务都需要走这个启动方法的逻辑,所以务必重视 + +我们直接来看DefaultApplicationDeployer的start()代码: + +```java +@Override + public Future start() { + //启动锁,防止重复启动 + synchronized (startLock) { + //发布器,状态已经设置为停止或者失败了就直接抛出异常 + if (isStopping() || isStopped() || isFailed()) { + throw new IllegalStateException(getIdentifier() + " is stopping or stopped, can not start again"); + } + + try { + // maybe call start again after add new module, check if any new module + //可能在添加新模块后再次调用start,检查是否有任何新模块 + //这里遍历当前应用程序下的所有模块如果某个模块是PENDING状态则这里hasPendingModule的值为true + boolean hasPendingModule = hasPendingModule(); + //发布器状态正在启动中 + if (isStarting()) { + // currently, is starting, maybe both start by module and application + // if it has new modules, start them + //存在挂起的模块 + if (hasPendingModule) { + //启动模块 + startModules(); + } + // if it is starting, reuse previous startFuture + //模块异步启动中 + return startFuture; + } + + // if is started and no new module, just return + //如果已启动且没有新模块,直接返回 + if (isStarted() && !hasPendingModule) { + return CompletableFuture.completedFuture(false); + } + + // pending -> starting : first start app + // started -> starting : re-start app + //启动状态切换,将启动状态切换到STARTING(pending和started状态无需切换) + onStarting(); + //核心初始化逻辑,这里主要做一些应用级别启动比如配置中心,元数据中心 + initialize(); + //启动模块(我们的服务提供和服务引用是在这个模块级别的) + doStart(); + } catch (Throwable e) { + onFailed(getIdentifier() + " start failure", e); + throw e; + } + + return startFuture; + } + } +``` + +这个启动方法逻辑不多 主要三个方法我们重点来看: +- onStarting() 这个是启动之前的状态切换 +- initialize() 应用的初始化逻辑 比如配置中心,元数据中心的初始化 +- doStart() 启动模块比如启动我们的服务提供和服务引用的) + +继续看后面的细节吧,代码胜千言。 + +## 12.4 应用程序发布器对应用级别的初始化逻辑 +这个我们先来看DefaultApplicationDeployer的初始化方法initialize(): + +```java +@Override + public void initialize() { + //状态判断 如果已经初始化过了就直接返回 + if (initialized) { + return; + } + // Ensure that the initialization is completed when concurrent calls + //启动锁,确保在并发调用时完成初始化 + synchronized (startLock) { + //双重校验锁 如果已经初始化过了就直接返回 + if (initialized) { + return; + } + // register shutdown hook + //注册关闭钩子,这个逻辑基本每个中间件应用都必须要要做的事情了,正常关闭应用回收资源,一般没这个逻辑情况下容易出现一些异常,让我们开发人员很疑惑,而这个逻辑往往并不好处理的干净。 + registerShutdownHook(); + + //启动配置中心,感觉Dubbo3耦合了这个玩意 + startConfigCenter(); + + //加载配置,一般配置信息当前机器的来源:环境变量,JVM启动参数,配置文字 + loadApplicationConfigs(); + + //初始化模块发布器 (发布服务提供和服务引用使用) + initModuleDeployers(); + + // @since 2.7.8 + //启动元数据中心 + startMetadataCenter(); + + //初始化完成 + initialized = true; + + if (logger.isInfoEnabled()) { + logger.info(getIdentifier() + " has been initialized!"); + } + } + } + +``` + +这个是个生命周期整体概览的方法,将具体逻辑拆分到各个子方法中,是代码重构的一种策略,上面注释也很清楚了就不细说了,上面每个方法在后面会有单独的博客来分析。 + + +## 12.5 应用下模块的启动(服务的发布与引用) + +我们回过头来详细看DefaultApplicationDeployer的doStart()代码: + +```java +private void doStart() { + // 启动模块 + startModules(); +``` + +DefaultApplicationDeployer的 startModules()方法 +```java +private void startModules() { + // ensure init and start internal module first + //确保初始化并首先启动内部模块,Dubbo3中将模块分为内部和外部,内部是核心代码已经提供的一些服务比如元数据服务,外部是我们自己写的服务 + prepareInternalModule(); + + // filter and start pending modules, ignore new module during starting, throw exception of module start + //启动所有的模块 (启动所有的服务) + for (ModuleModel moduleModel : new ArrayList<>(applicationModel.getModuleModels())) { + //这个状态默认就是PENDING的 + if (moduleModel.getDeployer().isPending()) { + //模块启动器,发布服务 + moduleModel.getDeployer().start(); + } + } + } +``` + +这个模块的启动其实就是用来启动服务的 先启动内部服务,再启动外部服务 +内部服务有个元数据服务Dubbo3中每个服务都可以对外提供服务的元数据信息,来简化服务配置,不论是内部服务还是外部服务调用的代码逻辑都是模块发布器ModuleDeployer的start()方法,接下来我们详细看下模块发布器的生命周期函数。 + + +## 12.6 模块发布器发布服务的过程 + +前面我们说到了所有的服务都是经过模块发布器,ModuleDeployer的start()方法来启动的,那我们接下来就来看看这个模块发布器的启动方法。 + +ModuleDeployer的start()方法代码: + +```java +@Override + public synchronized Future start() throws IllegalStateException { + //模块发布器已经停止或者启动失败则直接抛出异常返回 + if (isStopping() || isStopped() || isFailed()) { + throw new IllegalStateException(getIdentifier() + " is stopping or stopped, can not start again"); + } + + try { + //启动中或者已经启动了则直接返回一个Future对象 + if (isStarting() || isStarted()) { + return startFuture; + } + //切换模块启动状态为STARTING + onModuleStarting(); + + // initialize + //如果应用未初始化则初始化(非正常逻辑) + applicationDeployer.initialize(); + //模块发布器进行初始化 + initialize(); + + // export services + //暴露服务 + exportServices(); + + // prepare application instance + // exclude internal module to avoid wait itself + if (moduleModel != moduleModel.getApplicationModel().getInternalModule()) { + applicationDeployer.prepareInternalModule(); + } + + // refer services + //引用服务 + referServices(); + + // if no async export/refer services, just set started + //非异步启动则直接切换状态为STARTED + if (asyncExportingFutures.isEmpty() && asyncReferringFutures.isEmpty()) { + onModuleStarted(); + } else { + //如果是异步的则等待服务发布和服务引用异步回调 + frameworkExecutorRepository.getSharedExecutor().submit(() -> { + try { + // wait for export finish + waitExportFinish(); + // wait for refer finish + waitReferFinish(); + } catch (Throwable e) { + logger.warn("wait for export/refer services occurred an exception", e); + } finally { + //异步回调完成 所有服务都启动了,再切换状态 + onModuleStarted(); + } + }); + } + } catch (Throwable e) { + onModuleFailed(getIdentifier() + " start failed: " + e, e); + throw e; + } + return startFuture; + } +``` + +好了整体的服务启动生命周期就如上代码,后续我们再详细来看每个细节。 + + + +## 12.7 发布器简介 +前面主要说了应用和模块的发布器的启动和初始化,下面简单了解下它们的关系,如下所示 +![在这里插入图片描述](https://img-blog.csdnimg.cn/37e7c05796ab4b38aa7658377e16c0aa.png) +可以发布器主要包含 +- 应用的发布器ApplicationDeployer用于初始化并启动应用程序实例 +- 模块发布器ModuleDeployer 模块(服务)的导出/引用服务 + +两种发布器有各自的接口,他们都继承了抽象的发布器AbstractDeployer 封装了一些公共的操作比如状态切换,状态查询的逻辑。 + +另外我们再来看下发布过程的状态枚举DeployState如下: + +```java +public enum DeployState { + /** + * Unknown state + */ + UNKNOWN, + + /** + * Pending, wait for start + */ + PENDING, + + /** + * Starting + */ + STARTING, + + /** + * Started + */ + STARTED, + + /** + * Stopping + */ + STOPPING, + + /** + * Stopped + */ + STOPPED, + + /** + * Failed + */ + FAILED +} +``` + + +Dubbo这一块后续可以优化以下,这里的状态切换全部耦合在一起了,可以考虑使用状态机将状态与行为解耦。 + + 原文:[Dubbo启动器DubboBootstrap添加协议配置信息ProtocolConfig](https://blog.elastic.link/2022/07/10/dubbo/12-quan-ju-shi-ye-lai-kan-dubbo3.0.8-de-fu-wu-qi-dong-sheng-ming-zhou-qi/) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/13-Dubbo\347\232\204\344\270\211\345\244\247\344\270\255\345\277\203\344\271\213\351\205\215\347\275\256\344\270\255\345\277\203.md" "b/content/en/blog/java/codeanalysis/3.0.8/13-Dubbo\347\232\204\344\270\211\345\244\247\344\270\255\345\277\203\344\271\213\351\205\215\347\275\256\344\270\255\345\277\203.md" new file mode 100644 index 000000000000..49903b1158d2 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/13-Dubbo\347\232\204\344\270\211\345\244\247\344\270\255\345\277\203\344\271\213\351\205\215\347\275\256\344\270\255\345\277\203.md" @@ -0,0 +1,438 @@ +--- +title: "13-Dubbo的三大中心之配置中心" +linkTitle: "13-Dubbo的三大中心之配置中心" +date: 2022-08-13 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] 一套统一的,通用的管理配置机制是不可缺少的主要组成部分。常见的做法就是通过配置服务器进行管理。 +--- +# 13-Dubbo的三大中心之配置中心 +## 13.1 配置中心简介 +百度了一段不错的文字来介绍配置中心,我看了下肯定比我写的好多了,那我就直接拷贝过来一起看: + +*对于传统的单体应用而言,常使用配置文件来管理所有配置,比如SpringBoot的application.yml文件,但是在微服务架构中全部手动修改的话很麻烦而且不易维护。微服务的配置管理一般有以下需求:* +- ***集中配置管理**,一个微服务架构中可能有成百上千个微服务,所以集中配置管理是很重要的。* +- ***不同环境不同配置**,比如数据源配置在不同环境(开发,生产,测试)中是不同的。* +- ***运行期间可动态调整**。例如,可根据各个微服务的负载情况,动态调整数据源连接池大小等。* +- ***配置修改后可自动更新**。如配置内容发生变化,微服务可以自动更新配置。* + +综上所述对于微服务架构而言,一套统一的,通用的管理配置机制是不可缺少的主要组成部分。常见的做法就是通过配置服务器进行管理。 + +不过对于来看这个文章的小伙伴应该大部分对配置中心都会比较了解,分布式配置中心实现简单一点就是借助Zookeeper来协助存储,变更推送,不过为了实现各种不同的业务需求,市面上已经有很多很可靠的配置中心可用了,比如我从其他地方拷贝过来的图(虽然不是最新的但是可以供大家参考下): + +![在这里插入图片描述](/imgs/blog/source-blog/register.png) + +每个配置中心都有自己的实现,如果对配置中心感兴趣的小伙伴可以自行去对应开源项目官网查看,我们这里来看Dubbo对配置中心的支持 + +***多配置中心:** Dubbo支持多配置中心,来 **保证其中一个配置中心集群出现不可用时能够切换到另一个配置中心集群** ,保证能够正常从配置中心获取全局的配置、路由规则等信息。这也能够满足配置中心在部署上适应各类高可用的部署架构模式。-来自官网* + +做中间件可能考虑更多的的不仅仅是性能,还要过多的考虑高可用,高可用怎么做呢,其实就是失效转移,主备切换,降级,降级再降级这些理论的运用,多多考虑某一个服务挂了怎么办,Dubbo的多配置中心支持增加了复杂性,不过降低了服务不可用的风险,有一定的人手的公司还是值得做的。 + +关于Dubbo的配置中心这里我来贴个官网的图: +![在这里插入图片描述](/imgs/v3/concepts/centers-config.png) +关于官网的介绍可以自行去官网看详细内容: [部署架构(注册中心、配置中心、元数据中心](/en/docs/concepts/registry-configcenter-metadata/) + + +## 13.2 启动配置中心 +在上一个博客中说到了[《12-全局视野来看Dubbo3.0.8的服务启动生命周期》](https://blog.elastic.link/2022/07/10/dubbo/12-quan-ju-shi-ye-lai-kan-dubbo3.0.8-de-fu-wu-qi-dong-sheng-ming-zhou-qi/)Dubbo应用的启动过程DefaultApplicationDeployer的initialize()方法的全生命周期,在初始化方法中通过调用startConfigCenter();方法来启动配置中心的加载。后面就来详细看下: + +DefaultApplicationDeployer类型的startConfigCenter()代码如下: + +```java +private void startConfigCenter() { + + // load application config + //加载应用程序配置 (配置可能有多个地方可以配置需要遵循Dubbo约定的优先级进行设置,也可能是多应用,多注册中心这样的配置) + configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class); + + // try set model name + if (StringUtils.isBlank(applicationModel.getModelName())) { + //设置一下模块名字和模块描述(我们再Debug里面经常会看到这个描述信息 toString直接返回了Dubbo为我们改造的对象信息) + applicationModel.setModelName(applicationModel.tryGetApplicationName()); + } + + // load config centers + //加载配置中心配置 + //配置可能有多个地方可以配置需要遵循Dubbo约定的优先级进行设置,也可能是多应用,多注册中心这样的配置) + configManager.loadConfigsOfTypeFromProps(ConfigCenterConfig.class); + //出于兼容性目的,如果没有明确指定配置中心,并且registryConfig的UseAConfigCenter为null或true,请使用registry作为默认配置中心 + useRegistryAsConfigCenterIfNecessary(); + + // check Config Center + //配置管理器中获取配置中心 + Collection configCenters = configManager.getConfigCenters(); + //配置中心配置不为空则刷新配置中心配置将其放入配置管理器中 + //下面开始刷新配置中心配置,如果配置中心配置为空则执行空刷新 + if (CollectionUtils.isEmpty(configCenters)) { + //配置中心不存在的配置刷新 + ConfigCenterConfig configCenterConfig = new ConfigCenterConfig(); + configCenterConfig.setScopeModel(applicationModel); + configCenterConfig.refresh(); + //验证配置 + ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig); + if (configCenterConfig.isValid()) { + //配置合法则将配置放入配置管理器中 + configManager.addConfigCenter(configCenterConfig); + configCenters = configManager.getConfigCenters(); + } + } else { + //一个或者多个配置中心配置存在的情况下的配置刷新 + for (ConfigCenterConfig configCenterConfig : configCenters) { + configCenterConfig.refresh(); + //验证配置 + ConfigValidationUtils.validateConfigCenterConfig(configCenterConfig); + } + } + + //配置中心配置不为空则将配置中心配置添加到environment中 + if (CollectionUtils.isNotEmpty(configCenters)) { + //多配置中心本地动态配置对象创建CompositeDynamicConfiguration + CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration(); + //获取配置中心的相关配置 + for (ConfigCenterConfig configCenter : configCenters) { + // Pass config from ConfigCenterBean to environment + //将配置中心的外部化配置,更新到环境里面 + environment.updateExternalConfigMap(configCenter.getExternalConfiguration()); + //将配置中心的应用配置,添加到环境里面 + environment.updateAppExternalConfigMap(configCenter.getAppExternalConfiguration()); + + // Fetch config from remote config center + //从配置中心拉取配置添加到组合配置中 + compositeDynamicConfiguration.addConfiguration(prepareEnvironment(configCenter)); + } + //将配置中心中的动态配置信息 设置到environment的动态配置属性中 + environment.setDynamicConfiguration(compositeDynamicConfiguration); + } + } +``` + +### 13.2.1 配置管理器加载配置 + +前面我们看到了配置管理器会从系统属性中加载配置这里我们来详细看下,配置往往是我们使用者比较关注的内容, +```java +configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class); +``` + +配置管理器加载配置代码: +来自ConfigManager的父类型AbstractConfigManager中 +```java +public List loadConfigsOfTypeFromProps(Class cls) { + List tmpConfigs = new ArrayList<>(); + //获取属性配置 dubbo properties in classpath + //这个配置信息回头说 + PropertiesConfiguration properties = environment.getPropertiesConfiguration(); + + // load multiple configs with id + //多注册中心配置id查询 + + /* + 搜索属性并提取指定类型的配置ID。 + 例如如下配置 + # 配置信息 properties + dubbo.registries.registry1.address=xxx + dubbo.registries.registry2.port=xxx + + # 提取配置的id extract + Set configIds = getConfigIds(RegistryConfig.class) + + # 提取的配置id结果 result + configIds: ["registry1", "registry2"] + */ + Set configIds = this.getConfigIdsFromProps(cls); + configIds.forEach(id -> { + //遍历这些配置id 判断配置缓存(configsCache成员变量)中是否已经存在当前配置 + if (!this.getConfig(cls, id).isPresent()) { + T config; + try { + //创建配置对象 为配置对象初始化配置id + config = createConfig(cls, scopeModel); + config.setId(id); + } catch (Exception e) { + throw new IllegalStateException("create config instance failed, id: " + id + ", type:" + cls.getSimpleName()); + } + + String key = null; + boolean addDefaultNameConfig = false; + try { + // add default name config (same as id), e.g. dubbo.protocols.rest.port=1234 + key = DUBBO + "." + AbstractConfig.getPluralTagName(cls) + "." + id + ".name"; + if (properties.getProperty(key) == null) { + properties.setProperty(key, id); + addDefaultNameConfig = true; + } + //刷新配置信息 好理解点就是Dubbo配置属性重写 + config.refresh(); + //将当前配置信息添加到配置缓存中configsCache成员变量 + this.addConfig(config); + tmpConfigs.add(config); + } catch (Exception e) { + logger.error("load config failed, id: " + id + ", type:" + cls.getSimpleName(), e); + throw new IllegalStateException("load config failed, id: " + id + ", type:" + cls.getSimpleName()); + } finally { + if (addDefaultNameConfig && key != null) { + properties.remove(key); + } + } + } + }); + + // If none config of the type, try load single config + //如果没有该类型的配置,请尝试加载单个配置 + if (this.getConfigs(cls).isEmpty()) { + // load single config + List> configurationMaps = environment.getConfigurationMaps(); + if (ConfigurationUtils.hasSubProperties(configurationMaps, AbstractConfig.getTypePrefix(cls))) { + T config; + try { + config = createConfig(cls, scopeModel); + config.refresh(); + } catch (Exception e) { + throw new IllegalStateException("create default config instance failed, type:" + cls.getSimpleName()); + } + + this.addConfig(config); + tmpConfigs.add(config); + } + } + + return tmpConfigs; + } +``` + +## 13.2.2 默认使用注册中心地址为配置中心 +出于兼容性目的,如果没有明确指定配置中心,并且registryConfig的UseAConfigCenter为null或true,请使用registry作为默认配置中心 +调用方法useRegistryAsConfigCenterIfNecessary()来处理逻辑 +我们来看下代码: + +```java +private void useRegistryAsConfigCenterIfNecessary() { + // we use the loading status of DynamicConfiguration to decide whether ConfigCenter has been initiated. + //我们使用DynamicConfiguration的加载状态来决定是否已启动ConfigCenter。配置中心配置加载完成之后会初始化动态配置defaultDynamicConfiguration + if (environment.getDynamicConfiguration().isPresent()) { + return; + } + //从配置缓存中查询是否存在config-center相关配置 ,如果已经存在配置了就无需使用注册中心的配置地址直接返回 + if (CollectionUtils.isNotEmpty(configManager.getConfigCenters())) { + return; + } + + // load registry + //加载注册中心相关配置 + configManager.loadConfigsOfTypeFromProps(RegistryConfig.class); + + //查询是否有注册中心设置了默认配置isDefault 设置为true的注册中心则为默认注册中心列表,如果没有注册中心设置为默认注册中心,则获取所有未设置默认配置的注册中心列表 + List defaultRegistries = configManager.getDefaultRegistries(); + //存在注册中心 + if (defaultRegistries.size() > 0) { + defaultRegistries + .stream() + //判断当前注册中心是否可以作为配置中心 + .filter(this::isUsedRegistryAsConfigCenter) + //将注册中心配置映射转换为配置中心 + .map(this::registryAsConfigCenter) + //遍历配置中心流 + .forEach(configCenter -> { + if (configManager.getConfigCenter(configCenter.getId()).isPresent()) { + return; + } + //配置管理器中添加配置中心,方便后去读取配置中心的配置信息 + configManager.addConfigCenter(configCenter); + logger.info("use registry as config-center: " + configCenter); + + }); + } + } +``` + +#### 13.2.2.1 如何判断当前注册中心是否可以为配置中心 +isUsedRegistryAsConfigCenter + +```java +private boolean isUsedRegistryAsCenter(RegistryConfig registryConfig, Supplier usedRegistryAsCenter, + String centerType, + Class extensionClass) { + final boolean supported; + //这个useAsConfigCenter参数是来自注册中心的配置 如果配置了这个值则以这个值为准,如果配置了false则这个注册中心不能做为配置中心 + Boolean configuredValue = usedRegistryAsCenter.get(); + if (configuredValue != null) { // If configured, take its value. + supported = configuredValue.booleanValue(); + } else { // Or check the extension existence + //这个逻辑的话是判断下注册中心的协议是否满足要求,我们例子代码中使用的是zookeeper + String protocol = registryConfig.getProtocol(); + //这个扩展是否支持的逻辑判断是这样的扫描扩展类 看一下当前扩展类型是否有对应协议的扩展 比如在扩展文件里面这样配置过后是支持的 protocol=xxxImpl + //动态配置的扩展类型为:interface org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory + //zookeeper协议肯定是支持的因为zookeeper协议实现了这个动态配置工厂 ,这个扩展类型为ZookeeperDynamicConfigurationFactory + //代码位置在dubbo-configcenter-zookeeper包中的org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory扩展配置中内容为zookeeper=org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfigurationFactory + supported = supportsExtension(extensionClass, protocol); + //配置中心走注册中心会打印一条日志 + if (logger.isInfoEnabled()) { + logger.info(format("No value is configured in the registry, the %s extension[name : %s] %s as the %s center" + , extensionClass.getSimpleName(), protocol, supported ? "supports" : "does not support", centerType)); + } + } + + //配置中心走注册中心会打印一条日志 + if (logger.isInfoEnabled()) { + logger.info(format("The registry[%s] will be %s as the %s center", registryConfig, + supported ? "used" : "not used", centerType)); + } + return supported; + } +``` +这个扩展是否支持的逻辑判断是这样的扫描扩展类 看一下当前扩展类型是否有对应协议的扩展 比如在扩展文件里面这样配置过后是支持的 protocol=xxxImpl +配置中心的动态配置的扩展类型为 org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory + +zookeeper协议肯定是支持的因为zookeeper协议实现了这个动态配置工厂 ,这个扩展类型为ZookeeperDynamicConfigurationFactory代码位置在dubbo-configcenter-zookeeper包中的org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory扩展配置中内容为 +``` +zookeeper=org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfigurationFactory +``` + + + +#### 13.2.2.2 注册中心配置转配置中心配置 +这个逻辑是registryAsConfigCenter方法,我来贴一下代码: + +```java +private ConfigCenterConfig registryAsConfigCenter(RegistryConfig registryConfig) { + //注册中心协议获取这里例子中的是zookeeper协议 + String protocol = registryConfig.getProtocol(); + //注册中心端口 2181 + Integer port = registryConfig.getPort(); + //在Dubbo中配置信息 很多情况下都以URL形式表示,这里转换后的地址为zookeeper://127.0.0.1:2181 + URL url = URL.valueOf(registryConfig.getAddress(), registryConfig.getScopeModel()); + //生成当前配置中心的id 封装之后的内容为: + //config-center-zookeeper-127.0.0.1-2181 + String id = "config-center-" + protocol + "-" + url.getHost() + "-" + port; + //配置中心配置对象创建 + ConfigCenterConfig cc = new ConfigCenterConfig(); + //config-center-zookeeper-127.0.0.1-2181 + cc.setId(id); + cc.setScopeModel(applicationModel); + if (cc.getParameters() == null) { + cc.setParameters(new HashMap<>()); + } + if (CollectionUtils.isNotEmptyMap(registryConfig.getParameters())) { + cc.getParameters().putAll(registryConfig.getParameters()); // copy the parameters + } + cc.getParameters().put(CLIENT_KEY, registryConfig.getClient()); + //zookeeper + cc.setProtocol(protocol); + //2181 + cc.setPort(port); + if (StringUtils.isNotEmpty(registryConfig.getGroup())) { + cc.setGroup(registryConfig.getGroup()); + } + //这个方法转换地址是修复bug用的可以看bug https://github.com/apache/dubbo/issues/6476 + cc.setAddress(getRegistryCompatibleAddress(registryConfig)); + //注册中心分组做为配置中心命名空间 这里为null + cc.setNamespace(registryConfig.getGroup()); + //zk认证信息 + cc.setUsername(registryConfig.getUsername()); + //zk认证信息 + cc.setPassword(registryConfig.getPassword()); + if (registryConfig.getTimeout() != null) { + cc.setTimeout(registryConfig.getTimeout().longValue()); + } + //这个属性注释中已经建议了已经弃用了默认就是false了 + //如果配置中心被赋予最高优先级,它将覆盖所有其他配置, + cc.setHighestPriority(false); + return cc; + } +``` + + +## 13.3 配置刷新逻辑 +来自AbstractConfig类型的refresh()方法 + +```java +public void refresh() { + refreshed.set(true); + try { + // check and init before do refresh + //刷新之前执行的逻辑 这里并做什么逻辑 + preProcessRefresh(); + + //获取当前域模型的环境信息对象 + Environment environment = getScopeModel().getModelEnvironment(); + List> configurationMaps = environment.getConfigurationMaps(); + + // Search props starts with PREFIX in order + String preferredPrefix = null; + for (String prefix : getPrefixes()) { + if (ConfigurationUtils.hasSubProperties(configurationMaps, prefix)) { + preferredPrefix = prefix; + break; + } + } + if (preferredPrefix == null) { + preferredPrefix = getPrefixes().get(0); + } + // Extract sub props (which key was starts with preferredPrefix) + Collection> instanceConfigMaps = environment.getConfigurationMaps(this, preferredPrefix); + Map subProperties = ConfigurationUtils.getSubProperties(instanceConfigMaps, preferredPrefix); + InmemoryConfiguration subPropsConfiguration = new InmemoryConfiguration(subProperties); + + if (logger.isDebugEnabled()) { + String idOrName = ""; + if (StringUtils.hasText(this.getId())) { + idOrName = "[id=" + this.getId() + "]"; + } else { + String name = ReflectUtils.getProperty(this, "getName"); + if (StringUtils.hasText(name)) { + idOrName = "[name=" + name + "]"; + } + } + logger.debug("Refreshing " + this.getClass().getSimpleName() + idOrName + + " with prefix [" + preferredPrefix + + "], extracted props: " + subProperties); + } + + assignProperties(this, environment, subProperties, subPropsConfiguration); + + // process extra refresh of subclass, e.g. refresh method configs + processExtraRefresh(preferredPrefix, subPropsConfiguration); + + } catch (Exception e) { + logger.error("Failed to override field value of config bean: " + this, e); + throw new IllegalStateException("Failed to override field value of config bean: " + this, e); + } + + postProcessRefresh(); + } +``` + +![在这里插入图片描述](/imgs/blog/source-blog/13-config-1.png) + +![在这里插入图片描述](/imgs/blog/source-blog/13-config2.png) + + + + + +## 13.4 配置中心配置大全 +ConfigCenterConfig类型 + 下面配置信息来自官网 +dubbo:config-center 配置 + +配置中心。对应的配置类:`org.apache.dubbo.config.ConfigCenterConfig` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 描述 | 兼容性 | +| ------------------ | ---------------------- | ------------------- | -------- | ---------------- | ------------------------------------------------------------ | ------ | +| protocol | config.protocol | string | 可选 | zookeeper | 使用哪个配置中心:apollo、zookeeper、nacos等。 以zookeeper为例 1. 指定protocol,则address可以简化为`127.0.0.1:2181`; 2. 不指定protocol,则address取值为`zookeeper://127.0.0.1:2181` | 2.7.0+ | +| address | config.address | string | 必填 | | 配置中心地址。 取值参见protocol说明 | 2.7.0+ | +| highest-priority | config.highestPriority | boolean | 可选 | true | 来自配置中心的配置项具有最高优先级,即会覆盖本地配置项。 | 2.7.0+ | +| namespace | config.namespace | string | 可选 | dubbo | 通常用于多租户隔离,实际含义视具体配置中心而不同。 如: zookeeper - 环境隔离,默认值`dubbo`; apollo - 区分不同领域的配置集合,默认使用`dubbo`和`application` | 2.7.0+ | +| cluster | config.cluster | string | 可选 | | 含义视所选定的配置中心而不同。 如Apollo中用来区分不同的配置集群 | 2.7.0+ | +| group | config.group | string | 可选 | dubbo | 含义视所选定的配置中心而不同。 nacos - 隔离不同配置集 zookeeper - 隔离不同配置集 | 2.7.0+ | +| check | config.check | boolean | 可选 | true | 当配置中心连接失败时,是否终止应用启动。 | 2.7.0+ | +| config-file | config.configFile | string | 可选 | dubbo.properties | 全局级配置文件所映射到的key zookeeper - 默认路径/dubbo/config/dubbo/dubbo.properties apollo - dubbo namespace中的dubbo.properties键 | 2.7.0+ | +| timeout | config.timeout | integer | | 3000ms | 获取配置的超时时间 | 2.7.0+ | +| username | | string | | | 如果配置中心需要做校验,用户名 Apollo暂未启用 | 2.7.0+ | +| password | | string | | | 如果配置中心需要做校验,密码 Apollo暂未启用 | 2.7.0+ | +| parameters | | Map | | | 扩展参数,用来支持不同配置中心的定制化配置参数 | 2.7.0+ | +| include-spring-env | | boolean | 可选 | false | 使用Spring框架时支持,为true时,会自动从Spring Environment中读取配置。 默认依次读取 key为dubbo.properties的配置 key为dubbo.properties的PropertySource | 2.7.0+ | + + + + 原文:[Dubbo的三大中心之配置中心](https://blog.elastic.link/2022/07/10/dubbo/13-dubbo-de-san-da-zhong-xin-zhi-pei-zhi-zhong-xin-yuan-ma-jie-xi/) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/14-Dubbo\351\205\215\347\275\256\345\212\240\350\275\275\345\205\250\350\247\243\346\236\220.md" "b/content/en/blog/java/codeanalysis/3.0.8/14-Dubbo\351\205\215\347\275\256\345\212\240\350\275\275\345\205\250\350\247\243\346\236\220.md" new file mode 100644 index 000000000000..21057090c37e --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/14-Dubbo\351\205\215\347\275\256\345\212\240\350\275\275\345\205\250\350\247\243\346\236\220.md" @@ -0,0 +1,522 @@ +--- +title: "14-Dubbo配置加载全解析" +linkTitle: "14-Dubbo配置加载全解析" +date: 2022-08-14 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] Dubbo框架的配置项比较繁多,为了更好地管理各种配置,将其按照用途划分为不同的组件,最终所有配置项都会汇聚到URL中,传递给后续处理模块。 +--- +# 14-Dubbo配置加载全解析 +## 14.1 回到启动器的初始化过程 +在应用程序启动的时候会调用发布器的启动方法 ,然后调用初始化方法,在发布器DefaultApplicationDeployer中的初始化方法initialize() 如下: + +```java +@Override + public void initialize() { + if (initialized) { + return; + } + // Ensure that the initialization is completed when concurrent calls + synchronized (startLock) { + if (initialized) { + return; + } + // register shutdown hook + registerShutdownHook(); + + startConfigCenter(); + + loadApplicationConfigs(); + + initModuleDeployers(); + + // @since 2.7.8 + startMetadataCenter(); + + initialized = true; + + if (logger.isInfoEnabled()) { + logger.info(getIdentifier() + " has been initialized!"); + } + } + } +``` + + +初始化过程中会先启动配置中心配置信息处理,然后 调用加载初始化应用程序配置方法loadApplicationConfigs();进行配置加载 +关于配置的官方文档链接为 [配置概述](/en/docs/references/configuration/overview/) + +Dubbo框架的配置项比较繁多,为了更好地管理各种配置,将其按照用途划分为不同的组件,最终所有配置项都会汇聚到URL中,传递给后续处理模块。 + +**常用配置组件如下**: + +- application: Dubbo应用配置 +- registry: 注册中心 +- protocol: 服务提供者RPC协议 +- config-center: 配置中心 +- metadata-report: 元数据中心 +- service: 服务提供者配置 +- reference: 远程服务引用配置 +- provider: service的默认配置或分组配置 +- consumer: reference的默认配置或分组配置 +- module: 模块配置 +- monitor: 监控配置 +- metrics: 指标配置 +- ssl: SSL/TLS配置 + +配置还有几个比较重要的点: + +**配置来源** +从Dubbo支持的配置来源说起,默认有6种配置来源: + +- JVM System Properties,JVM -D 参数 +- System environment,JVM进程的环境变量 +- Externalized Configuration,外部化配置,从配置中心读取 +- Application Configuration,应用的属性配置,从Spring应用的Environment中提取"dubbo"打头的属性集 +- API / XML /注解等编程接口采集的配置可以被理解成配置来源的一种,是直接面向用户编程的配置采集方式 +- 从classpath读取配置文件 dubbo.properties + +**覆盖关系** +下图展示了配置覆盖关系的优先级,从上到下优先级依次降低: ![在这里插入图片描述](/imgs/blog/configuration.jpg) + +**配置方式** +- Java API配置 +- XML配置 +- Annotation配置 +- 属性配置 + +配置虽然非常多,但是我们掌握一下配置加载的原理,再了解下官网的文档说明路径应该基础的配置搞定是没问题的,更深入的配置很多参数还是需要了解下源码的. + + + +## 14.2 配置信息的初始化回顾 +前面我们在讲ModuleModel对象的创建的时候ModuleModel模型中包含了一个成员变量为ModuleEnvironment 代表当前的模块环境和ModuleConfigManager配置管理器 +而ModuleModel模型对象的父模型对象ApplicationModel中包含了一个成员变量Environment环境和ConfigManager配置管理器. + +在回顾调用过程之前我们先看下模型,配置管理器和环境与配置之间的关系如下图: + ![在这里插入图片描述](/imgs/blog/source-blog/14-config.png) + + + +在ModuleModel对象初始化方法initialize()中创建了模块配置管理器:ModuleConfigManager +如下代码所示: + +```java + @Override + protected void initialize() { + super.initialize(); + this.serviceRepository = new ModuleServiceRepository(this); + this.moduleConfigManager = new ModuleConfigManager(this); + this.moduleConfigManager.initialize(); + +``` +ModuleEnvironment环境信息对象也会在配置管理器创建的时候被调用到: +如下代码所示: +```java + @Override + public ModuleEnvironment getModelEnvironment() { + if (moduleEnvironment == null) { + moduleEnvironment = (ModuleEnvironment) this.getExtensionLoader(ModuleExt.class) + .getExtension(ModuleEnvironment.NAME); + } + return moduleEnvironment; + } +``` + +在扩展对象ExtensionLoader进行对象ModuleEnvironment创建之后会对对象进行初始化调用 initExtension(instance)方法 初始化的时候调用如下代码: +ExtensionLoader中的初始化方法如下: + + +```java + private void initExtension(T instance) { + if (instance instanceof Lifecycle) { + Lifecycle lifecycle = (Lifecycle) instance; + lifecycle.initialize(); + } + } +``` + + ## 14.3 属性加载 + + ### 14.3.1 Environment中属性的初始化方法 + + 这个初始化方法对应ModuleEnvironment的父类型Environment中的初始化方法如下:initialize() + +```java + @Override + public void initialize() throws IllegalStateException { + if (initialized.compareAndSet(false, true)) { + //加载在JVM或者环境变量指定的dubbo.properties配置文件 配置的key为dubbo.properties.file ,如果未指定则查找类路径下的dubbo.properties + this.propertiesConfiguration = new PropertiesConfiguration(scopeModel); + //系统JVM参数的配置无需我们来加载到内存,系统已经加载好了放到了System中,我们只需System.getProperty(key)来调用 + this.systemConfiguration = new SystemConfiguration(); + //系统环境变量的配置,无需我们来加载到内存,系统已经加载好了放到了System中,我们只需System.getenv(key)来获取就可以 + this.environmentConfiguration = new EnvironmentConfiguration(); + //从远程配置中心的全局配置获取对应配置 + this.externalConfiguration = new InmemoryConfiguration("ExternalConfig"); + //从远程配置中心的应用配置获取对应配置 + this.appExternalConfiguration = new InmemoryConfiguration("AppExternalConfig"); + //应用内的配置比如: Spring Environment/PropertySources/application.properties + this.appConfiguration = new InmemoryConfiguration("AppConfig"); + //加载迁移配置,用户在JVM参数或者环境变量中指定的dubbo.migration.file,如果用户未指定测尝试加载类路径下的dubbo-migration.yaml + loadMigrationRule(); + } + } +``` + + ### 14.4.2 属性变量说明 + 前面我们已经基本上介绍了各个属性的含义下面用一个表格列举一下方便查看: + +|属性变量名 | 属性类型 |说明| +|--|--|--| +|propertiesConfiguration | PropertiesConfiguration |dubbo.properties文件中的属性| +|systemConfiguration |SystemConfiguration |JVM参数 启动进程时指定的 (-D)配置| +|environmentConfiguration|EnvironmentConfiguration|环境变量中的配置| +|externalConfiguration|InmemoryConfiguration|外部配置全局配置 例如配置中心中 config-center global/default config| +|appExternalConfiguration|InmemoryConfiguration|外部的应用配置 例如配置中心中执行的当前应用的配置 config-center app config| +appConfiguration|InmemoryConfiguration|来自应用中的配置例如:Spring Environment/PropertySources/application.properties| +|globalConfiguration|CompositeConfiguration|前面6个配置属性放到一起就是这个| +|globalConfigurationMaps| List>|最前面的6个属性转换为map放到一起就是这个可以理解为将全局配置globalConfiguration转换成了列表 这个列表顺序在这里是:SystemConfiguration -> EnvironmentConfiguration -> AppExternalConfiguration -> ExternalConfiguration -> AppConfiguration -> AbstractConfig -> PropertiesConfiguration| +|defaultDynamicGlobalConfiguration|CompositeConfiguration|这个也是一个组合配置将defaultDynamicConfiguration动态配置(来自配置中心的配置)和全局配置添加到了自己的配置列表中 列表顺序为defaultDynamicConfiguration -> globalConfiguration| +|localMigrationRule|String|,用户在JVM参数或者环境变量中指定的dubbo.migration.file,如果用户未指定测尝试加载类路径下的dubbo-migration.yaml| + + +关于每个配置信息这里还是来了解下细节,方便大家了解原理. +### 14.3.3 dubbo.properties配置文件加载解析原理 +如前面所示: + +```java +//加载在JVM或者环境变量指定的dubbo.properties配置文件 配置的key为dubbo.properties.file ,如果未指定则查找类路径下的dubbo.properties + this.propertiesConfiguration = new PropertiesConfiguration(scopeModel); +``` + +下面就直接提构造器的PropertiesConfiguration代码了: + +```java +public PropertiesConfiguration(ScopeModel scopeModel) { + this.scopeModel = scopeModel; + refresh(); + } + + public void refresh() { + //配置获取的过程是借助工具类ConfigUtils来获取的 + properties = ConfigUtils.getProperties(scopeModel.getClassLoaders()); + } +``` + +继续看ConfigUtils的getProperties方法: + +```java +public static Properties getProperties(Set classLoaders) { + //这个配置的KEY是dubbo.properties.file System.getProperty是从JVM参数中获取配置的 一般情况下我们在启动Java进程的时候会指定Dubbo配置文件 如配置: + //-Ddubbo.properties.file=/dubbo.properties + String path = System.getProperty(CommonConstants.DUBBO_PROPERTIES_KEY); + + if (StringUtils.isEmpty(path)) { + //优先级最高的JVM参数拿不到数据则从 环境变量中获取,这个配置key也是dubbo.properties.file System.getenv是从环境变量中获取数据 + //例如我们在环境变量中配置 dubbo.properties.file=/dubbo.properties + path = System.getenv(CommonConstants.DUBBO_PROPERTIES_KEY); + if (StringUtils.isEmpty(path)) { + //如果在JVM参数和环境变量都拿不到这个配置文件的路径我们就用默认的吧 + //默认的路径是类路径下的资源文件 这个路径是: dubbo.properties + path = CommonConstants.DEFAULT_DUBBO_PROPERTIES; + } + } + return ConfigUtils.loadProperties(classLoaders, path, false, true); + } +``` + +路径获取之后加载详细的配置内容: + +ConfigUtils的loadProperties代码如下: +```java +ConfigUtils.loadProperties(classLoaders, path, false, true); +``` + +代码如下: + +```java +public static Properties loadProperties(Set classLoaders, String fileName, boolean allowMultiFile, boolean optional) { + Properties properties = new Properties(); + // add scene judgement in windows environment Fix 2557 + //检查文件是否存在 直接加载配置文件如果加载到了配置文件则直接返回 + if (checkFileNameExist(fileName)) { + try { + FileInputStream input = new FileInputStream(fileName); + try { + properties.load(input); + } finally { + input.close(); + } + } catch (Throwable e) { + logger.warn("Failed to load " + fileName + " file from " + fileName + "(ignore this file): " + e.getMessage(), e); + } + return properties; + } + + //为什么会有下面的逻辑呢,如果仅仅使用上面的加载方式只能加载到本系统下的配置文件,无法加载封装在jar中的根路径的配置 + Set set = null; + try { + List classLoadersToLoad = new LinkedList<>(); + classLoadersToLoad.add(ClassUtils.getClassLoader()); + classLoadersToLoad.addAll(classLoaders); + //这个方法loadResources在扩展加载的时候说过 + set = ClassLoaderResourceLoader.loadResources(fileName, classLoadersToLoad).values().stream().reduce(new LinkedHashSet<>(), (a, i) -> { + a.addAll(i); + return a; + }); + } catch (Throwable t) { + logger.warn("Fail to load " + fileName + " file: " + t.getMessage(), t); + } + + if (CollectionUtils.isEmpty(set)) { + if (!optional) { + logger.warn("No " + fileName + " found on the class path."); + } + return properties; + } + + if (!allowMultiFile) { + if (set.size() > 1) { + String errMsg = String.format("only 1 %s file is expected, but %d dubbo.properties files found on class path: %s", + fileName, set.size(), set); + logger.warn(errMsg); + } + + // fall back to use method getResourceAsStream + try { + properties.load(ClassUtils.getClassLoader().getResourceAsStream(fileName)); + } catch (Throwable e) { + logger.warn("Failed to load " + fileName + " file from " + fileName + "(ignore this file): " + e.getMessage(), e); + } + return properties; + } + + logger.info("load " + fileName + " properties file from " + set); + + for (java.net.URL url : set) { + try { + Properties p = new Properties(); + InputStream input = url.openStream(); + if (input != null) { + try { + p.load(input); + properties.putAll(p); + } finally { + try { + input.close(); + } catch (Throwable t) { + } + } + } + } catch (Throwable e) { + logger.warn("Fail to load " + fileName + " file from " + url + "(ignore this file): " + e.getMessage(), e); + } + } + + return properties; + } +``` + +完整的配置加载流程这里用简单的话描述下: +- 项目内配置查询 + - 路径查询 + - 从JVM参数中获取配置的 dubbo.properties.file配置文件路径 + - 如果前面未获取到路径则从环境变量参数中获取配置的dubbo.properties.file配置文件路径 + - 如果前面未获取到路径则使用默认路径dubbo.propertie + - 配置加载 + - 将路径转为FileInputStream 然后使用Properties加载 +- 依赖中的配置扫描查询 + - 使用类加载器扫描所有资源URL + - url转InputStream 如 url.openStream() 然后使用Properties加载 + + +### 14.3.4 加载JVM参数的配置 +这里我们继续看SystemConfiguration配置的加载 +这个直接看下代码就可以了: + +这个类型仅仅是使用System.getProperty来获取JVM配置即可 +```java + public class SystemConfiguration implements Configuration { + + @Override + public Object getInternalProperty(String key) { + return System.getProperty(key); + } + + public Map getProperties() { + return (Map) System.getProperties(); + } +} +``` +### 14.3.5 加载环境变量参数的配置 +这里我们来看EnvironmentConfiguration,这里我们直接来看代码: + +```java +public class EnvironmentConfiguration implements Configuration { + + @Override + public Object getInternalProperty(String key) { + String value = System.getenv(key); + if (StringUtils.isEmpty(value)) { + value = System.getenv(StringUtils.toOSStyleKey(key)); + } + return value; + } + + public Map getProperties() { + return System.getenv(); + } +} +``` + +### 14.3.6 内存配置的封装:InmemoryConfiguration +这里我们看下InmemoryConfiguration的设计,这个直接看代码吧内部使用了一个LinkedHashMap来存储配置 + +```java +public class InmemoryConfiguration implements Configuration { + + private String name; + + // stores the configuration key-value pairs + private Map store = new LinkedHashMap<>(); + + public InmemoryConfiguration() { + } + + public InmemoryConfiguration(String name) { + this.name = name; + } + + public InmemoryConfiguration(Map properties) { + this.setProperties(properties); + } + + @Override + public Object getInternalProperty(String key) { + return store.get(key); + } + + /** + * Add one property into the store, the previous value will be replaced if the key exists + */ + public void addProperty(String key, String value) { + store.put(key, value); + } + + /** + * Add a set of properties into the store + */ + public void addProperties(Map properties) { + if (properties != null) { + this.store.putAll(properties); + } + } + + /** + * set store + */ + public void setProperties(Map properties) { + if (properties != null) { + this.store = properties; + } + } + + public Map getProperties() { + return store; + } + +} +``` + +### 14.3.7 Dubbo迁移新版本的配置文件加载dubbo-migration.yaml + +关于配置迁移文件的用法可以看下这个Dubbo官方的[地址迁移规则说明](/en/docs/advanced/migration-invoker/) + +这个配置文件的文件名字为:dubbo-migration.yaml + +这个和14.3.4加载JVM参数配置的过程是相似的细节可以看14.3.4节 + +```java + private void loadMigrationRule() { + //JVM参数的dubbo.migration.file配置 + String path = System.getProperty(CommonConstants.DUBBO_MIGRATION_KEY); + if (StringUtils.isEmpty(path)) { + //环境变量的dubbo.migration.file配置 + path = System.getenv(CommonConstants.DUBBO_MIGRATION_KEY); + if (StringUtils.isEmpty(path)) { + //默认的迁移配置文件 dubbo-migration.yaml + path = CommonConstants.DEFAULT_DUBBO_MIGRATION_FILE; + } + } + this.localMigrationRule = ConfigUtils.loadMigrationRule(scopeModel.getClassLoaders(), path); + } +``` + + + + + + +## 14.4 初始化加载应用配置 +加载配置涉及到了配置优先级的处理, + +下面来看加载配置代码 loadApplicationConfigs()方法 + +```java +private void loadApplicationConfigs() { + //发布器还是不处理配置加载的逻辑还是交给配置管理器 + configManager.loadConfigs(); + } +``` + +配置管理器加载配置: + +```java + @Override + public void loadConfigs() { + // application config has load before starting config center + // load dubbo.applications.xxx + //加载应用配置 + loadConfigsOfTypeFromProps(ApplicationConfig.class); + + // load dubbo.monitors.xxx + //加载监控配置 + loadConfigsOfTypeFromProps(MonitorConfig.class); + + // load dubbo.metrics.xxx + //加载指标监控配置 + loadConfigsOfTypeFromProps(MetricsConfig.class); + + // load multiple config types: + // load dubbo.protocols.xxx + //加载协议配置 + loadConfigsOfTypeFromProps(ProtocolConfig.class); + + // load dubbo.registries.xxx + loadConfigsOfTypeFromProps(RegistryConfig.class); + + // load dubbo.metadata-report.xxx + //加载元数据配置 + loadConfigsOfTypeFromProps(MetadataReportConfig.class); + + // config centers has bean loaded before starting config center + //loadConfigsOfTypeFromProps(ConfigCenterConfig.class); + + //刷新配置 + refreshAll(); + + //检查配置 + checkConfigs(); + + // set model name + if (StringUtils.isBlank(applicationModel.getModelName())) { + applicationModel.setModelName(applicationModel.getApplicationName()); + } + } +``` + + + +原文地址:[Dubbo配置加载全解析](https://blog.elastic.link/2022/07/10/dubbo/14-dubbo-pei-zhi-jia-zai-quan-jie-xi/) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/15-Dubbo\347\232\204\344\270\211\345\244\247\344\270\255\345\277\203\344\271\213\345\205\203\346\225\260\346\215\256\344\270\255\345\277\203\346\272\220\347\240\201\350\247\243\346\236\220.md" "b/content/en/blog/java/codeanalysis/3.0.8/15-Dubbo\347\232\204\344\270\211\345\244\247\344\270\255\345\277\203\344\271\213\345\205\203\346\225\260\346\215\256\344\270\255\345\277\203\346\272\220\347\240\201\350\247\243\346\236\220.md" new file mode 100644 index 000000000000..e142e24b5dd1 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/15-Dubbo\347\232\204\344\270\211\345\244\247\344\270\255\345\277\203\344\271\213\345\205\203\346\225\260\346\215\256\344\270\255\345\277\203\346\272\220\347\240\201\350\247\243\346\236\220.md" @@ -0,0 +1,896 @@ +--- +title: "15-Dubbo的三大中心之元数据中心源码解析" +linkTitle: "15-Dubbo的三大中心之元数据中心源码解析" +date: 2022-08-15 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] Dubbo 3 会需要一个元数据中心来维护RPC服务与应用的映射关系(即接口与应用的映射关系),因为如果采用了应用级别的服务发现和服务注册,在注册中心中将采用“应用 —— 实例列表”结构的数据组织形式,不再是以往的“接口 —— 实例列表”结构的数据组织形式,而以往用接口级别的服务注册和服务发现的应用服务在迁移到应用级别时,得不到接口与应用之间的对应关系,从而无法从注册中心得到实例列表信息,所以Dubbo为了兼容这种场景,在Provider端启动时,会往元数据中心存储接口与应用的映射关系。 +--- + + + + +# 15-Dubbo的三大中心之元数据中心源码解析 + +## 15.1 简介 +关于元数据中心的概念对于大部分用户来说是比较陌生的,配置中心的话我们还好理解,对于元数据中心是什么,我们来看下我从官网拷贝过来的一段文字: + +元数据中心在2.7.x版本开始支持,随着应用级别的服务注册和服务发现在Dubbo中落地,**元数据中心也变的越来越重要**。在以下几种情况下会需要部署元数据中心: + +- 对于一个原先采用老版本Dubbo搭建的应用服务,在迁移到Dubbo 3时,Dubbo 3 会需要一个**元数据中心来维护RPC服务与应用的映射关系(即接口与应用的映射关系)**,因为如果采用了**应用级别的服务发现和服务注册**,在注册中心中将**采用“应用 —— 实例列表”结构**的数据组织形式,**不再是以往的“接口 —— 实例列表”结构的数据组织形式**,而以往用接口级别的服务注册和服务发现的应用服务在**迁移到应用级别**时,**得不到接口与应用之间的对应关系**,从而无法从注册中心得到实例列表信息,所以**Dubbo为了兼容这种场景,在Provider端启动时,会往元数据中心存储接口与应用的映射关系**。 +- 为了让**注册中心更加聚焦与地址的发现和推送能力**,**减轻注册中心的负担**,元数据中心承载了所有的服务元数据、大量接口/方法级别配置信息等,无论是接口粒度还是应用粒度的服务发现和注册,元数据中心都起到了重要的作用。 +- 如果有以上两种需求,都可以选择部署元数据中心,并通过Dubbo的配置来集成该元数据中心。 + +**元数据中心并不依赖于注册中心和配置中心**,用户可以自由选择是否集成和部署元数据中心,如下图所示: + +![/imgs/v3/concepts/centers-metadata.png](/imgs/v3/concepts/centers-metadata.png) + + +该图中不配备配置中心,意味着可以不需要全局管理配置的能力。该图中不配备注册中心,意味着可能采用了Dubbo mesh的方案,也可能不需要进行服务注册,仅仅接收直连模式的服务调用。 +官网参考文章地址: +- [部署架构(注册中心 配置中心 元数据中心](/en/docs/concepts/registry-configcenter-metadata/) +- [元数据参考手册](/en/docs/references/metadata/) + + +综上所述可以用几句话概括下: +- 元数据中心来维护RPC服务与应用的映射关系(即接口与应用的映射关系)来兼容接口与应用之间的对应关系 +- 让注册中心更加聚焦与地址的发现和推送能力 + +元数据中心的启动是在DefaultApplicationDeployer中的初始化方法 initialize() 中:如下所示 + +这里只看下 startMetadataCenter();方法即可 + +```java + @Override + public void initialize() { + if (initialized) { + return; + } + // Ensure that the initialization is completed when concurrent calls + synchronized (startLock) { + if (initialized) { + return; + } + // register shutdown hook + registerShutdownHook(); + + startConfigCenter(); + + loadApplicationConfigs(); + + initModuleDeployers(); + + // @since 2.7.8 + startMetadataCenter(); + + initialized = true; + + if (logger.isInfoEnabled()) { + logger.info(getIdentifier() + " has been initialized!"); + } + } + } + +``` + +## 15.2 深入探究元数据中心的启动过程 + ### 15.2.1 启动元数据中心的代码全貌 + +关于元数据中心我们看下 startMetadataCenter()方法来大致了解下整个流程 + +```java +private void startMetadataCenter() { + //如果未配置元数据中心的地址等配置则使用注册中心的地址等配置做为元数据中心的配置 + useRegistryAsMetadataCenterIfNecessary(); + //获取应用的配置信息 + ApplicationConfig applicationConfig = getApplication(); + //元数据配置类型 元数据类型, local 或 remote,,如果选择远程,则需要进一步指定元数据中心 + String metadataType = applicationConfig.getMetadataType(); + // FIXME, multiple metadata config support. + //查询元数据中心的地址等配置 + Collection metadataReportConfigs = configManager.getMetadataConfigs(); + + if (CollectionUtils.isEmpty(metadataReportConfigs)) { + //这个就是判断 如果选择远程,则需要进一步指定元数据中心 否则就抛出来异常 + if (REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) { + throw new IllegalStateException("No MetadataConfig found, Metadata Center address is required when 'metadata=remote' is enabled."); + } + return; + } + //MetadataReport实例的存储库对象获取 + MetadataReportInstance metadataReportInstance = applicationModel.getBeanFactory().getBean(MetadataReportInstance.class); + List validMetadataReportConfigs = new ArrayList<>(metadataReportConfigs.size()); + for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) { + ConfigValidationUtils.validateMetadataConfig(metadataReportConfig); + validMetadataReportConfigs.add(metadataReportConfig); + } + //初始化元数据 + metadataReportInstance.init(validMetadataReportConfigs); + //MetadataReport实例的存储库对象初始化失败则抛出异常 + if (!metadataReportInstance.inited()) { + throw new IllegalStateException(String.format("%s MetadataConfigs found, but none of them is valid.", metadataReportConfigs.size())); + } + } +``` + + + +### 15.2.2 元数据中心未配置则使用注册中心配置 +前面在说配置中心的时候有说过配置中心如果未配置会使用注册中心的地址等信息作为默认配置,这里元数据做了类似的操作:如代码: +DefaultApplicationDeployer类型的 useRegistryAsMetadataCenterIfNecessary()方法 + +```java +private void useRegistryAsMetadataCenterIfNecessary() { + //配置缓存中查询元数据配置 + Collection metadataConfigs = configManager.getMetadataConfigs(); + //配置存在则直接返回 + if (CollectionUtils.isNotEmpty(metadataConfigs)) { + return; + } + ////查询是否有注册中心设置了默认配置isDefault 设置为true的注册中心则为默认注册中心列表,如果没有注册中心设置为默认注册中心,则获取所有未设置默认配置的注册中心列表 + List defaultRegistries = configManager.getDefaultRegistries(); + if (defaultRegistries.size() > 0) { + //多注册中心遍历 + defaultRegistries + .stream() + //筛选符合条件的注册中心 (筛选逻辑就是查看是否有对应协议的扩展支持) + .filter(this::isUsedRegistryAsMetadataCenter) + //注册中心配置映射为元数据中心 映射就是获取需要的配置 + .map(this::registryAsMetadataCenter) + //将元数据中心配置存储在配置缓存中方便后续使用 + .forEach(metadataReportConfig -> { + + if (metadataReportConfig.getId() == null) { + Collection metadataReportConfigs = configManager.getMetadataConfigs(); + if (CollectionUtils.isNotEmpty(metadataReportConfigs)) { + for (MetadataReportConfig existedConfig : metadataReportConfigs) { + if (existedConfig.getId() == null && existedConfig.getAddress().equals(metadataReportConfig.getAddress())) { + return; + } + } + } + configManager.addMetadataReport(metadataReportConfig); + } else { + Optional configOptional = configManager.getConfig(MetadataReportConfig.class, metadataReportConfig.getId()); + if (configOptional.isPresent()) { + return; + } + configManager.addMetadataReport(metadataReportConfig); + } + logger.info("use registry as metadata-center: " + metadataReportConfig); + }); + } + } +``` + +这个代码有些细节就不细说了 我们概括下顺序梳理下思路: +- 配置缓存中查询元数据配置,配置存在则直接返回 +- 查询所有可用的默认注册中心列表 + - 多注册中心遍历 + - 选符合条件的注册中心 (筛选逻辑就是查看是否有对应协议的扩展支持) + - 注册中心配置RegistryConfig映射转换为元数据中心配置类型MetadataReportConfig 映射就是获取需要的配置 + - 将元数据中心配置存储在配置缓存中方便后续使用 + + 元数据的配置可以参考官网:[元数据参考手册](/en/docs/references/metadata/) + + 这里主要看下可配置项有哪些 对应类型为MetadataReportConfig 在官网暂时未找到合适的文档,这里整理下属性列表方便后续配置说明查看: + +| 配置变量 | 类型 | 说明| +|--|--|--| +| id | String|配置id +|protocol|String|元数据协议| +|address|String|元数据中心地址| +|port|Integer|元数据中心端口| +|username|String|元数据中心认证用户名| +|password|String|元数据中心认证密码| +|timeout|Integer|元数据中心的请求超时(毫秒)| +|group|String|该组将元数据保存在中。它与注册表相同| +|parameters|Map|自定义参数| +|retryTimes|Integer|重试次数| +|retryPeriod|Integer|重试间隔| +|cycleReport|Boolean|默认情况下, 是否每天重复存储完整的元数据| +|syncReport|Boolean|Sync or Async report. +|cluster|Boolean|需要群集支持,默认为false| +|registry|String|注册表配置id| +|file|String|元数据报告文件存储位置| +|check|Boolean|连接到元数据中心时要应用的失败策略| + + +### 15.2.3 元数据中心的初始化逻辑 +#### 15.2.3.1 元数据中心的初始化调用逻辑 +主要看这一行比较重要的逻辑: + +```java + //初始化元数据 + metadataReportInstance.init(validMetadataReportConfigs); +``` + +在了解这一行逻辑之前我们先来看下元数据相关联的类型: + + + +MetadataReportInstance中的初始化方法init +```java + public void init(List metadataReportConfigs) { + //CAS判断是否有初始化过 + if (!init.compareAndSet(false, true)) { + return; + } + //元数据类型配置如果未配置则默认为local + this.metadataType = applicationModel.getApplicationConfigManager().getApplicationOrElseThrow().getMetadataType(); + if (metadataType == null) { + this.metadataType = DEFAULT_METADATA_STORAGE_TYPE; + } + //获取MetadataReportFactory 工厂类型 + MetadataReportFactory metadataReportFactory = applicationModel.getExtensionLoader(MetadataReportFactory.class).getAdaptiveExtension(); + //多元数据中心初始化 + for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) { + init(metadataReportConfig, metadataReportFactory); + } + } + + private void init(MetadataReportConfig config, MetadataReportFactory metadataReportFactory) { + //配置转url + URL url = config.toUrl(); + if (METADATA_REPORT_KEY.equals(url.getProtocol())) { + String protocol = url.getParameter(METADATA_REPORT_KEY, DEFAULT_DIRECTORY); + url = URLBuilder.from(url) + .setProtocol(protocol) + .setScopeModel(config.getScopeModel()) + .removeParameter(METADATA_REPORT_KEY) + .build(); + } + url = url.addParameterIfAbsent(APPLICATION_KEY, applicationModel.getCurrentConfig().getName()); + String relatedRegistryId = isEmpty(config.getRegistry()) ? (isEmpty(config.getId()) ? DEFAULT_KEY : config.getId()) : config.getRegistry(); + //从元数据工厂中获取元数据 + MetadataReport metadataReport = metadataReportFactory.getMetadataReport(url); + //缓存元数据到内存 + if (metadataReport != null) { + metadataReports.put(relatedRegistryId, metadataReport); + } + } +``` + + +关于元数据的初始化我们主要看两个位置: +- 一个是元数据工厂对象的创建与初始化MetadataReportFactory +- 一个是元数据对象的创建与初始化MetadataReport + + +#### 15.2.3.2 元数据工厂对象MetadataReportFactory +关于元数据工厂类型MetadataReportFactory,元数据工厂 用于**创建与管理元数据对象**, 相关类型如下: +![在这里插入图片描述](/imgs/blog/source-blog/15-config.png) + +我们这里主要以为Zookeeper扩展的元数据工厂ZookeeperMetadataReportFactory类型为例子: +实现类型逻辑不复杂,这里就直接贴代码看看: + +```java +public class ZookeeperMetadataReportFactory extends AbstractMetadataReportFactory { + //与Zookeeper交互的传输器 + private ZookeeperTransporter zookeeperTransporter; + //应用程序模型 + private ApplicationModel applicationModel; + + public ZookeeperMetadataReportFactory(ApplicationModel applicationModel) { + this.applicationModel = applicationModel; + this.zookeeperTransporter = ZookeeperTransporter.getExtension(applicationModel); + } + + @DisableInject + public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) { + this.zookeeperTransporter = zookeeperTransporter; + } + + @Override + public MetadataReport createMetadataReport(URL url) { + return new ZookeeperMetadataReport(url, zookeeperTransporter); + } + +} +``` + +元数据工厂的实现比较简单 +- 继承抽象的元数据工厂AbstractMetadataReportFactory +- 实现工厂方法createMetadataReport来创建一个元数据操作类型 + +如果我们想要实现一个元数据工厂扩展可以参考Zookeeper的这个方式 + + +#### 15.2.3.3 元数据操作对象MetadataReport的创建与初始化 + +前面的从元数据工厂中获取元数据操作对象的逻辑处理代码如下: + +```java +//从元数据工厂中获取元数据 ,url对象可以理解为配置 + MetadataReport metadataReport = metadataReportFactory.getMetadataReport(url); +``` + +关于元数据对象,用于元数据信息的增删改查等逻辑的操作与元数据信息的缓存 + +![在这里插入图片描述](/imgs/blog/source-blog/15-config2.png) + +我们这里还是以Zookeeper的实现ZookeeperMetadataReportFactory类型做为参考: + +我们先来看这个逻辑 +```java +//从元数据工厂中获取元数据 ,url对象可以理解为配置 + MetadataReport metadataReport = metadataReportFactory.getMetadataReport(url); +``` +ZookeeperMetadataReportFactory的父类型AbstractMetadataReportFactory中的getMetadataReport方法如下: + +```java + @Override + public MetadataReport getMetadataReport(URL url) { + //url值参考例子zookeeper://127.0.0.1:2181?application=dubbo-demo-api-provider&client=&port=2181&protocol=zookeeper + //如果存在export则移除 + url = url.setPath(MetadataReport.class.getName()) + .removeParameters(EXPORT_KEY, REFER_KEY); + //生成元数据缓存key 元数据维度 地址+名字 + //如: zookeeper://127.0.0.1:2181/org.apache.dubbo.metadata.report.MetadataReport + String key = url.toServiceString(); + //缓存中查询 查到则直接返回 + MetadataReport metadataReport = serviceStoreMap.get(key); + if (metadataReport != null) { + return metadataReport; + } + + // Lock the metadata access process to ensure a single instance of the metadata instance + //存在写操作 加个锁 + lock.lock(); + try { + //双重校验锁在查一下 + metadataReport = serviceStoreMap.get(key); + if (metadataReport != null) { + return metadataReport; + } + //check参数 查元数据报错是否抛出异常 + boolean check = url.getParameter(CHECK_KEY, true) && url.getPort() != 0; + try { + //关键模版方法 调用扩展实现的具体业务(创建元数据操作对象) + metadataReport = createMetadataReport(url); + } catch (Exception e) { + if (!check) { + logger.warn("The metadata reporter failed to initialize", e); + } else { + throw e; + } + } + //check逻辑检查 + if (check && metadataReport == null) { + throw new IllegalStateException("Can not create metadata Report " + url); + } + //缓存对象 + if (metadataReport != null) { + serviceStoreMap.put(key, metadataReport); + } + //返回 + return metadataReport; + } finally { + // Release the lock + lock.unlock(); + } + } + +``` + +上面这个抽象类AbstractMetadataReportFactory中的获取元数据操作对象的模版方法getMetadataReport(URL url), 用了双重校验锁的逻辑来创建对象缓存对象,又用了模版方法设计模式,来让抽象类做通用的逻辑,让实现类型去做扩展, 虽然代码写的太长了些整体还是用了不少的设计思想. + +我们直接看这个代码: +```java +metadataReport = createMetadataReport(url); +``` + +这个创建元数据操作对象的代码实际上走的是实现类型的逻辑: + + +来自工厂Bean ZookeeperMetadataReportFactory的工厂方法如下所示: + + +```java +@Override + public MetadataReport createMetadataReport(URL url) { + return new ZookeeperMetadataReport(url, zookeeperTransporter); + } +``` + +创建了元数据操作对象,这里我们继续看下元数据操作对象ZookeeperMetadataReport创建做了哪些逻辑: +来自ZookeeperMetadataReport的构造器: + +```java +public ZookeeperMetadataReport(URL url, ZookeeperTransporter zookeeperTransporter) { + //url即配置 配置传递给抽象类 做一些公共的逻辑 + //url参考:zookeeper://127.0.0.1:2181/org.apache.dubbo.metadata.report.MetadataReport?application=dubbo-demo-api-provider&client=&port=2181&protocol=zookeeper + super(url); + if (url.isAnyHost()) { + throw new IllegalStateException("registry address == null"); + } + String group = url.getGroup(DEFAULT_ROOT); + if (!group.startsWith(PATH_SEPARATOR)) { + group = PATH_SEPARATOR + group; + } + this.root = group; + //连接Zookeeper + zkClient = zookeeperTransporter.connect(url); + } +``` + + +核心的公共的操作逻辑封装在父类AbstractMetadataReport里面 +我们来看前面super调用的构造器逻辑: +如下所示: +```java + public AbstractMetadataReport(URL reportServerURL) { + //设置url 如:zookeeper://127.0.0.1:2181/org.apache.dubbo.metadata.report.MetadataReport?application=dubbo-demo-api-provider&client=&port=2181&protocol=zookeeper + setUrl(reportServerURL); + // Start file save timer + //缓存的文件名字 + //格式为: 用户目录+/.dubbo/dubbo-metadata- + 应用程序名字application + url地址(IP+端口) + 后缀.cache 如下所示 + ///Users/song/.dubbo/dubbo-metadata-dubbo-demo-api-provider-127.0.0.1-2181.cache + String defaultFilename = System.getProperty(USER_HOME) + DUBBO_METADATA + + reportServerURL.getApplication() + "-" + + replace(reportServerURL.getAddress(), ":", "-") + CACHE; + //如果用户配置了缓存文件名字则以用户配置为准file + String filename = reportServerURL.getParameter(FILE_KEY, defaultFilename); + File file = null; + //文件名字不为空 + if (ConfigUtils.isNotEmpty(filename)) { + file = new File(filename); + //文件和父目录不存在则创建文件目录 + if (!file.exists() && file.getParentFile() != null && !file.getParentFile().exists()) { + if (!file.getParentFile().mkdirs()) { + throw new IllegalArgumentException("Invalid service store file " + file + ", cause: Failed to create directory " + file.getParentFile() + "!"); + } + } + // if this file exists, firstly delete it. + //还未初始化则已存在的历史文件删除掉 + if (!initialized.getAndSet(true) && file.exists()) { + file.delete(); + } + } + //赋值给成员变量后续继续可以用 + this.file = file; + //文件存在则直接加载文件中的内容 + loadProperties(); + //sync-report配置的值为同步配置还异步配置,true是同步配置,默认为false为异步配置 + syncReport = reportServerURL.getParameter(SYNC_REPORT_KEY, false); + //重试属性与逻辑也封装了一个类型 创建对象 + //retry-times重试次数配置 默认为100次 + //retry-period 重试间隔配置 默认为3000 + metadataReportRetry = new MetadataReportRetry(reportServerURL.getParameter(RETRY_TIMES_KEY, DEFAULT_METADATA_REPORT_RETRY_TIMES), + reportServerURL.getParameter(RETRY_PERIOD_KEY, DEFAULT_METADATA_REPORT_RETRY_PERIOD)); + + // cycle report the data switch + //是否定期从元数据中心同步配置 + //cycle-report配置默认为true + if (reportServerURL.getParameter(CYCLE_REPORT_KEY, DEFAULT_METADATA_REPORT_CYCLE_REPORT)) { + //开启重试定时器 24个小时间隔从元数据中心同步一次 + reportTimerScheduler = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboMetadataReportTimer", true)); + reportTimerScheduler.scheduleAtFixedRate(this::publishAll, calculateStartTime(), ONE_DAY_IN_MILLISECONDS, TimeUnit.MILLISECONDS); + } + + this.reportMetadata = reportServerURL.getParameter(REPORT_METADATA_KEY, false); + this.reportDefinition = reportServerURL.getParameter(REPORT_DEFINITION_KEY, true); + } + +``` + + + +#### 15.2.3.4 内存中元数据自动同步到Zookeeper和本地文件 +这里来总结下元数据操作的初始化逻辑: + +- 首次初始化清理历史元数据文件如: + Users/song/.dubbo/dubbo-metadata-dubbo-demo-api-provider-127.0.0.1-2181.cache +- 如果非首次进来则直接加载缓存在本地的缓存文件,赋值给properties成员变量 +- 初始化同步配置是否异步(默认为false), sync-report配置的值为同步配置还异步配置,true是同步配置,默认为false为异步配置 +- 初始化重试属性 +- 是否定期从元数据中心同步配置初始化 默认为true 24小时自动同步一次 + + + +关于元数据同步可以看AbstractMetadataReport类型的publishAll方法: + +```java + reportTimerScheduler = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboMetadataReportTimer", true)); + reportTimerScheduler.scheduleAtFixedRate(this::publishAll, calculateStartTime(), ONE_DAY_IN_MILLISECONDS, TimeUnit.MILLISECONDS); +``` + +这里有个方法叫做calculateStartTime 这个代码是随机时间的between 2:00 am to 6:00 am, the time is random. 2点到6点之间启动, 低峰期启动自动同步 +返回值: + + +AbstractMetadataReport类型的 +```java + void publishAll() { + logger.info("start to publish all metadata."); + this.doHandleMetadataCollection(allMetadataReports); + } +``` +AbstractMetadataReport类型的doHandleMetadataCollection +```java +private boolean doHandleMetadataCollection(Map metadataMap) { + if (metadataMap.isEmpty()) { + return true; + } + Iterator> iterable = metadataMap.entrySet().iterator(); + while (iterable.hasNext()) { + Map.Entry item = iterable.next(); + if (PROVIDER_SIDE.equals(item.getKey().getSide())) { + //提供端的元数据则存储提供端元数据 + this.storeProviderMetadata(item.getKey(), (FullServiceDefinition) item.getValue()); + } else if (CONSUMER_SIDE.equals(item.getKey().getSide())) { + //消费端的元数据则存储提供端元数据 + this.storeConsumerMetadata(item.getKey(), (Map) item.getValue()); + } + + } + return false; + } +``` + + +提供端元数据的存储: +AbstractMetadataReport类型的storeProviderMetadata +```java + @Override + public void storeProviderMetadata(MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition) { + if (syncReport) { + storeProviderMetadataTask(providerMetadataIdentifier, serviceDefinition); + } else { + reportCacheExecutor.execute(() -> storeProviderMetadataTask(providerMetadataIdentifier, serviceDefinition)); + } + } +``` + + + +AbstractMetadataReport类型的storeProviderMetadataTask +具体同步代码:storeProviderMetadataTask +```java +private void storeProviderMetadataTask(MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition) { + try { + if (logger.isInfoEnabled()) { + logger.info("store provider metadata. Identifier : " + providerMetadataIdentifier + "; definition: " + serviceDefinition); + } + allMetadataReports.put(providerMetadataIdentifier, serviceDefinition); + failedReports.remove(providerMetadataIdentifier); + Gson gson = new Gson(); + String data = gson.toJson(serviceDefinition); + //内存中的元数据同步到元数据中心 + doStoreProviderMetadata(providerMetadataIdentifier, data); + //内存中的元数据同步到本地文件 + saveProperties(providerMetadataIdentifier, data, true, !syncReport); + } catch (Exception e) { + // retry again. If failed again, throw exception. + failedReports.put(providerMetadataIdentifier, serviceDefinition); + metadataReportRetry.startRetryTask(); + logger.error("Failed to put provider metadata " + providerMetadataIdentifier + " in " + serviceDefinition + ", cause: " + e.getMessage(), e); + } + } + +``` + +上面代码我们主要看本地内存中的元数据同步到元数据中心和存本地的两个点: + +```java +//内存中的元数据同步到元数据中心 +doStoreProviderMetadata(providerMetadataIdentifier, data); +//内存中的元数据同步到本地文件 +saveProperties(providerMetadataIdentifier, data, true, +``` + +//内存中的元数据同步到元数据中心 + + +这个方法会调用当前子类重写的具体存储逻辑:这里我们以 +ZookeeperMetadataReport的doStoreProviderMetadata举例: + + +```java + private void storeMetadata(MetadataIdentifier metadataIdentifier, String v) { + //使用zkClient创建一个节点数据为参数V v是前面说的服务定义数据 + zkClient.create(getNodePath(metadataIdentifier), v, false); + } +``` + + +这里参数我们举个例子: 提供者的元数据内容如下: +节点路径为: + +- /dubbo/metadata/link.elastic.dubbo.entity.DemoService/provider/dubbo-demo-api-provider + +格式: +- /dubbo/metadata前缀 +- 服务提供者接口 +- 提供者类型provider +- 应用名 + +具体的元数据内容如下: +比较详细的记录了应用信息,服务接口信息和服务接口对应的方法信息 + + +```json +{ + "parameters": { + "side": "provider", + "interface": "link.elastic.dubbo.entity.DemoService", + "pid": "38680", + "application": "dubbo-demo-api-provider", + "dubbo": "2.0.2", + "release": "3.0.8", + "anyhost": "true", + "bind.ip": "192.168.1.9", + "methods": "sayHello,sayHelloAsync", + "background": "false", + "deprecated": "false", + "dynamic": "true", + "service-name-mapping": "true", + "generic": "false", + "bind.port": "20880", + "timestamp": "1653097653865" + }, + "canonicalName": "link.elastic.dubbo.entity.DemoService", + "codeSource": "file:/Users/song/Desktop/Computer/A/code/gitee/weaving-a-net/weaving-test/dubbo-test/target/classes/", + "methods": [ + { + "name": "sayHello", + "parameterTypes": [ + "java.lang.String" + ], + "returnType": "java.lang.String", + "annotations": [ + + ] + }, + { + "name": "sayHelloAsync", + "parameterTypes": [ + "java.lang.String" + ], + "returnType": "java.util.concurrent.CompletableFuture", + "annotations": [ + + ] + } + ], + "types": [ + { + "type": "java.util.concurrent.CompletableFuture", + "properties": { + "result": "java.lang.Object", + "stack": "java.util.concurrent.CompletableFuture.Completion" + } + }, + { + "type": "java.lang.Object" + }, + { + "type": "java.lang.String" + }, + { + "type": "java.util.concurrent.CompletableFuture.Completion", + "properties": { + "next": "java.util.concurrent.CompletableFuture.Completion", + "status": "int" + } + }, + { + "type": "int" + } + ], + "annotations": [ + + ] +} +``` + + + +本地缓存文件的写入 可以看下如下代码 +AbstractMetadataReport类型的saveProperties方法 +```java + private void saveProperties(MetadataIdentifier metadataIdentifier, String value, boolean add, boolean sync) { + if (file == null) { + return; + } + + try { + if (add) { + properties.setProperty(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), value); + } else { + properties.remove(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY)); + } + long version = lastCacheChanged.incrementAndGet(); + if (sync) { + //获取最新修改版本持久化到磁盘 + new SaveProperties(version).run(); + } else { + reportCacheExecutor.execute(new SaveProperties(version)); + } + + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + } + } +``` + +主要看如下代码: + +```java + new SaveProperties(version).run(); +``` + +SaveProperties类型代码如下: +```java + private class SaveProperties implements Runnable { + private long version; + + private SaveProperties(long version) { + this.version = version; + } + + @Override + public void run() { + doSaveProperties(version); + } + } +``` + + +继续看doSaveProperties方法: + +```java +private void doSaveProperties(long version) { + //不是最新的就不要持久化了 + if (version < lastCacheChanged.get()) { + return; + } + if (file == null) { + return; + } + // Save + try { + //创建本地文件锁: + //路径为: + ///Users/song/.dubbo/dubbo-metadata-dubbo-demo-api-provider-127.0.0.1-2181.cache.lock + File lockfile = new File(file.getAbsolutePath() + ".lock"); + //锁文件不存在则创建锁文件 + if (!lockfile.exists()) { + lockfile.createNewFile(); + } + //随机访问文件工具类对象创建 读写权限 + try (RandomAccessFile raf = new RandomAccessFile(lockfile, "rw"); + //文件文件Channel + //返回与此文件关联的唯一FileChannel对象。 + FileChannel channel = raf.getChannel()) { + //FileChannel中的lock()与tryLock()方法都是尝试去获取在某一文件上的独有锁(以下简称独有锁),可以实现进程间操作的互斥。区别在于lock()会阻塞(blocking)方法的执行,tryLock()则不会。 + FileLock lock = channel.tryLock(); + //如果多个线程同时进来未获取锁的则抛出异常 + if (lock == null) { + throw new IOException("Can not lock the metadataReport cache file " + file.getAbsolutePath() + ", ignore and retry later, maybe multi java process use the file, please config: dubbo.metadata.file=xxx.properties"); + } + // Save + try { + //文件不存在则创建本地元数据缓存文件 + ///Users/song/.dubbo/dubbo-metadata-dubbo-demo-api-provider-127.0.0.1-2181.cache + if (!file.exists()) { + file.createNewFile(); + } + + Properties tmpProperties; + if (!syncReport) { + // When syncReport = false, properties.setProperty and properties.store are called from the same + // thread(reportCacheExecutor), so deep copy is not required + tmpProperties = properties; + } else { + // Using store method and setProperty method of the this.properties will cause lock contention + // under multi-threading, so deep copy a new container + //异步存储会导致锁争用 使用此的store方法和setProperty方法。属性将导致多线程下的锁争用,因此深度复制新容器 + tmpProperties = new Properties(); + Set> entries = properties.entrySet(); + for (Map.Entry entry : entries) { + tmpProperties.setProperty((String) entry.getKey(), (String) entry.getValue()); + } + } + + try (FileOutputStream outputFile = new FileOutputStream(file)) { + //Properties类型自带的方法: + //将此属性表中的属性列表(键和元素对)以适合使用load(Reader)方法的格式写入输出字符流。 + tmpProperties.store(outputFile, "Dubbo metadataReport Cache"); + } + } finally { + lock.release(); + } + } + } catch (Throwable e) { + if (version < lastCacheChanged.get()) { + return; + } else { + reportCacheExecutor.execute(new SaveProperties(lastCacheChanged.incrementAndGet())); + } + //这个代码太诡异了如果是lock失败也会打印异常给人非常疑惑的感觉 后续会修复 + logger.warn("Failed to save service store file, cause: " + e.getMessage(), e); + } + } +``` + +写入文件的内容大致如下 + +```json +link.elastic.dubbo.entity.DemoService:::provider:dubbo-demo-api-provider -> { + "parameters": { + "side": "provider", + "interface": "link.elastic.dubbo.entity.DemoService", + "pid": "41457", + "application": "dubbo-demo-api-provider", + "dubbo": "2.0.2", + "release": "3.0.8", + "anyhost": "true", + "bind.ip": "192.168.1.9", + "methods": "sayHello,sayHelloAsync", + "background": "false", + "deprecated": "false", + "dynamic": "true", + "service-name-mapping": "true", + "generic": "false", + "bind.port": "20880", + "timestamp": "1653100253548" + }, + "canonicalName": "link.elastic.dubbo.entity.DemoService", + "codeSource": "file:/Users/song/Desktop/Computer/A/code/gitee/weaving-a-net/weaving-test/dubbo-test/target/classes/", + "methods": [ + { + "name": "sayHelloAsync", + "parameterTypes": [ + "java.lang.String" + ], + "returnType": "java.util.concurrent.CompletableFuture", + "annotations": [ + + ] + }, + { + "name": "sayHello", + "parameterTypes": [ + "java.lang.String" + ], + "returnType": "java.lang.String", + "annotations": [ + + ] + } + ], + "types": [ + { + "type": "java.util.concurrent.CompletableFuture", + "properties": { + "result": "java.lang.Object", + "stack": "java.util.concurrent.CompletableFuture.Completion" + } + }, + { + "type": "java.lang.Object" + }, + { + "type": "java.lang.String" + }, + { + "type": "java.util.concurrent.CompletableFuture.Completion", + "properties": { + "next": "java.util.concurrent.CompletableFuture.Completion", + "status": "int" + } + }, + { + "type": "int" + } + ], + "annotations": [ + + ] +} +``` + + +原文地址:[15-Dubbo的三大中心之元数据中心源码解析](https://blog.elastic.link/2022/07/10/dubbo/15-dubbo-de-san-da-zhong-xin-zhi-yuan-shu-ju-zhong-xin-yuan-ma-jie-xi/) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/16-\346\250\241\345\235\227\345\217\221\345\270\203\345\231\250\345\217\221\345\270\203\346\234\215\345\212\241\345\205\250\350\277\207\347\250\213.md" "b/content/en/blog/java/codeanalysis/3.0.8/16-\346\250\241\345\235\227\345\217\221\345\270\203\345\231\250\345\217\221\345\270\203\346\234\215\345\212\241\345\205\250\350\277\207\347\250\213.md" new file mode 100644 index 000000000000..e088ad33fc02 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/16-\346\250\241\345\235\227\345\217\221\345\270\203\345\231\250\345\217\221\345\270\203\346\234\215\345\212\241\345\205\250\350\277\207\347\250\213.md" @@ -0,0 +1,1034 @@ +--- +title: "16-模块发布器发布服务全过程" +linkTitle: "16-模块发布器发布服务全过程" +date: 2022-08-16 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] DefaultModuleDeployer模块器启动的流程,其中在start代码的模版方法中开始了导出服务的功能,。 +--- + + +# 16-模块发布器发布服务全过程 +## 16.1 简介 +Dubbo做为服务治理框架,比较核心的就是服务相关的概念,这里我先贴个找到的关于Dubbo工作原理的架构图: + ![在这里插入图片描述](/imgs/blog/source-blog/16-deploy.png) + 如果按完整服务启动与订阅的顺序我们可以归结为以下6点: +- 导出服务(提供者) + - 服务提供方通过指定端口对外暴露服务 +- 注册服务(提供者) + - 提供方向注册中心注册自己的信息 +- (服务发现)-订阅服务(消费者) + - 服务调用方通过注册中心订阅自己感兴趣的服务 +- (服务发现)-服务推送(消费者) + - 注册中心向调用方推送地址列表 +- 调用服务(消费者调用提供者) + - 调用方选择一个地址发起RPC调用 +- 监控服务 + - 服务提供方和调用方的统计数据由监控模块收集展示 + +上面的完整的服务启动订阅与调用流程不仅仅适用于Dubbo 同样也适用于其他服务治理与发现的模型, 一般服务发现与服务调用的思路就是这样的,我们将以上内容扩展,暴漏服务可以使用http,tcp,udp等各种协议,注册服务可以注册到Redis,Dns,Etcd,Zookeeper等注册中心中,订阅服务可以主动去注册中心查询服务列表,服务发现可以让注册中心将服务数据动态推送给消费者.Dubbo其实就是基于这种简单的服务模型来扩展出各种功能的支持,来满足服务治理的各种场景,了解了这里可能各位同学就想着自行开发一个简单的微服务框架了。 + + + +回到主题,从以上的服务完整发布调用流程可以看到,所有的功能都是由导出服务(提供者)开始的,只有提供者先提供了服务才可以有真正的服务让消费者调用。 + + +之前的博客内容 链接:[<<12-全局视野来看Dubbo3.0.8的服务启动生命周期>>](https://blog.elastic.link/2022/07/10/dubbo/12-quan-ju-shi-ye-lai-kan-dubbo3.0.8-de-fu-wu-qi-dong-sheng-ming-zhou-qi/) 我们了解了 DefaultModuleDeployer模块器启动的流程,其中在start代码的模版方法中开始了导出服务的功能,这里我们来详细看下服务发布的全过程: + + +入口代码: DefaultModuleDeployer的发布服务方法 +```java + private void exportServices() { + //从配置管缓存中查询缓存的所有的服务配置然后逐个服务发布 + for (ServiceConfigBase sc : configManager.getServices()) { + exportServiceInternal(sc); + } + } +``` + + +## 16.2 导出服务的入口 +入口代码: DefaultModuleDeployer的发布服务方法 + +```java + private void exportServices() { + //从配置管缓存中查询缓存的所有的服务配置然后逐个服务发布 + for (ServiceConfigBase sc : configManager.getServices()) { + exportServiceInternal(sc); + } + } +``` + +主要流程为遍历初始化的服务配置列表然后逐个服务开始到处 +内部导出服务代码: +exportServiceInternal方法: + +```java + private void exportServiceInternal(ServiceConfigBase sc) { + + ServiceConfig serviceConfig = (ServiceConfig) sc; + //服务配置刷新 配置优先级覆盖 + if (!serviceConfig.isRefreshed()) { + serviceConfig.refresh(); + } + //服务已经导出过了就直接返回 + if (sc.isExported()) { + return; + } + //是否异步方式导出 全局配置或者服务级其中一个配置了异步则异步处理 + if (exportAsync || sc.shouldExportAsync()) { + //异步其实就是使用线程来导出服务serviceExportExecutor + ExecutorService executor = executorRepository.getServiceExportExecutor(); + CompletableFuture future = CompletableFuture.runAsync(() -> { + try { + if (!sc.isExported()) { + sc.export(); + exportedServices.add(sc); + } + } catch (Throwable t) { + logger.error(getIdentifier() + " export async catch error : " + t.getMessage(), t); + } + }, executor); + + asyncExportingFutures.add(future); + } else { + //同步导出服务 + if (!sc.isExported()) { + sc.export(); + exportedServices.add(sc); + } + } + } +``` + +这个逻辑里面做了一些基本的操作,可以直接看注释然后调用ServiceConfig的export的来导出服务,继续往后看服务配置的导出服务方法。 + + + +## 16.3 服务配置导出服务模板方法 +核心的服务导出代码是在服务配置中来做的ServiceConfig的 export() 方法 +ServiceConfig的 export() 方法代码如下: + +```java + + @Override + public void export() { + //已经导出过服务直接放那会 + if (this.exported) { + return; + } + + // ensure start module, compatible with old api usage + //确保模块启动了(基本的初始化操作执行了) + getScopeModel().getDeployer().start(); + //悲观锁 + synchronized (this) { + //双重校验 + if (this.exported) { + return; + } + //配置是否刷新 前面初始化时候已经刷新过配置 + if (!this.isRefreshed()) { + this.refresh(); + } + //服务导出配置配置为false则不导出 + if (this.shouldExport()) { + //服务发布前初始化一下元数据对象 + this.init(); + + if (shouldDelay()) { + //配置了服务的延迟发布配置则走延迟发布逻辑 + doDelayExport(); + } else { + //导出服务 + doExport(); + } + } + } + } +``` + +### 16.3.1 服务配置导出服务前的初始化方法 +ServiceConfig 导出服务之前的初始化方法init +```java +public void init() { + if (this.initialized.compareAndSet(false, true)) { + //加载服务监听器 这里暂时没有服务监听器扩展 + // load ServiceListeners from extension + ExtensionLoader extensionLoader = this.getExtensionLoader(ServiceListener.class); + this.serviceListeners.addAll(extensionLoader.getSupportedExtensionInstances()); + } + //服务提供者配置传递给元数据配置对象 一个服务提供者配置会有一个元数据配置,服务配置 + initServiceMetadata(provider); + //元数据 + serviceMetadata.setServiceType(getInterfaceClass()); + + serviceMetadata.setTarget(getRef()); + //元数据的key格式为 group/服务接口:版本号 + serviceMetadata.generateServiceKey(); + } +``` + + +## 16.4 服务配置导出服务模板方法2 +ServiceConfig 导出服务核心逻辑 +```java +protected synchronized void doExport() { + //取消发布 + if (unexported) { + throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!"); + } + //已经发布 + if (exported) { + return; + } + //服务路径 为空则设置为接口名,本例子中为link.elastic.dubbo.entity.DemoService + if (StringUtils.isEmpty(path)) { + path = interfaceName; + } + //导出URL + doExportUrls(); + // + exported(); + } +``` + +### 16.4.1 导出服务的URL配置逻辑 + +ServiceConfig 导出URL核心逻辑 +```java + private void doExportUrls() { + //模块服务存储库 + ModuleServiceRepository repository = getScopeModel().getServiceRepository(); + ServiceDescriptor serviceDescriptor; + //ref为服务实现类型 这里对应我们例子的DemoServiceImpl + final boolean serverService = ref instanceof ServerService; + if(serverService){ + serviceDescriptor=((ServerService) ref).getServiceDescriptor(); + repository.registerService(serviceDescriptor); + }else{ + //我们代码走这个逻辑 注册服务 这个注册不是向注册中心注册 这个是解析服务接口将服务方法等描述信息存放在了服务存储ModuleServiceRepository类型对象的成员变量services中 + serviceDescriptor = repository.registerService(getInterfaceClass()); + } + //提供者领域模型, 提供者领域模型 封装了一些提供者需要的就基本属性同时内部解析封装方法信息 ProviderMethodModel 列表 , 服务标识符 格式group/服务接:版本号 + providerModel = new ProviderModel(getUniqueServiceName(), + //服务实现类DemoServiceImpl + ref, + //服务描述符 描述符里面包含了服务接口的方法信息,不过服务接口通过反射也可以拿到方法信息 + serviceDescriptor, + //服务配置 + this, + //当前所处模型 + getScopeModel(), + //当前服务接口的元数据对象 + serviceMetadata); + + //模块服务存储库存储提供者模型对象ModuleServiceRepository + repository.registerProvider(providerModel); + //获取配置的注册中心列表 ,同时将注册中心配置转URL (在Dubbo中URL就是配置信息的一种形式) + //这里会获取到两个 由dubbo.application.register-mode 双注册配置决定 + //注册中心 registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=9008®istry=zookeeper&release=3.0.8×tamp=1653703292768 + //service-discovery-registry://8.131.79.126:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=10275®istry=zookeeper&release=3.0.8×tamp=1653704425920 + //参数dubbo是dubbo协议的版本不是Dubbo版本 Dubbo RPC protocol version, for compatibility, it must not be between 2.0.10 ~ 2.6.2 + //这里后面详细说下 服务双注册 dubbo.application.register-mode + List registryURLs = ConfigValidationUtils.loadRegistries(this, true); + + for (ProtocolConfig protocolConfig : protocols) { + String pathKey = URL.buildKey(getContextPath(protocolConfig) + .map(p -> p + "/" + path) + .orElse(path), group, version); + // stub service will use generated service name + if(!serverService) { + // In case user specified path, register service one more time to map it to path. + //模块服务存储库ModuleServiceRepository存储服务接口信息 + repository.registerService(pathKey, interfaceClass); + } + //导出根据协议导出配置到注册中心 + doExportUrlsFor1Protocol(protocolConfig, registryURLs); + } + } + +``` + + + +### 16.4.2 应用级和接口级服务注册地址获取 +这里主要看下注册中心的获取,这里涉及到服务的双注册配置 + +```java +List registryURLs = ConfigValidationUtils.loadRegistries(this, true); +``` + +关于loadRegistries方法的详情我们就不看了主要看loadRegistries方法中调用的genCompatibleRegistries添加服务发现注册中心 +```java + /** + * @param scopeModel 域模型 + * @param registryList 配置的注册中心列表 例如:registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=9008®istry=zookeeper&release=3.0.8×tamp=1653703292768 + * + * @param provider 是否为服务提供者 这里Demo为true + */ +private static List genCompatibleRegistries(ScopeModel scopeModel, List registryList, boolean provider) { + List result = new ArrayList<>(registryList.size()); + //遍历所有的注册中心 为每个注册中心增加兼容的服务发现注册中心地址配置 + registryList.forEach(registryURL -> { + //是否为提供者 + if (provider) { + // for registries enabled service discovery, automatically register interface compatible addresses. + + String registerMode; + //注册协议配置了service-discovery-registry 走这个逻辑 + //前面这个逻辑是直接接给result结果中添加应用级注册,如果是all配置则增加接口级注册信息 + if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) { + registerMode = registryURL.getParameter(REGISTER_MODE_KEY, ConfigurationUtils.getCachedDynamicProperty(scopeModel, DUBBO_REGISTER_MODE_DEFAULT_KEY, DEFAULT_REGISTER_MODE_INSTANCE)); + if (!isValidRegisterMode(registerMode)) { + registerMode = DEFAULT_REGISTER_MODE_INSTANCE; + } + //这里配置的就是应用级配置 则先添加应用级地址,再根据条件判断是否添加接口级注册中心地址 + result.add(registryURL); + if (DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode) + && registryNotExists(registryURL, registryList, REGISTRY_PROTOCOL)) { + URL interfaceCompatibleRegistryURL = URLBuilder.from(registryURL) + .setProtocol(REGISTRY_PROTOCOL) + .removeParameter(REGISTRY_TYPE_KEY) + .build(); + result.add(interfaceCompatibleRegistryURL); + } + } else { + //正常情况下我们的配置会走这个逻辑 + // 获取服务注册的注册模式 配置为dubbo.application.register-mode 默认值为all 既注册接口数据又注册应用级信息 + registerMode = registryURL.getParameter(REGISTER_MODE_KEY, ConfigurationUtils.getCachedDynamicProperty(scopeModel, DUBBO_REGISTER_MODE_DEFAULT_KEY, DEFAULT_REGISTER_MODE_ALL)); + + if (!isValidRegisterMode(registerMode)) { + registerMode = DEFAULT_REGISTER_MODE_INTERFACE; + } + //根据逻辑条件判断是否添加应用级注册中心地址 + if ((DEFAULT_REGISTER_MODE_INSTANCE.equalsIgnoreCase(registerMode) || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)) + && registryNotExists(registryURL, registryList, SERVICE_REGISTRY_PROTOCOL)) { + URL serviceDiscoveryRegistryURL = URLBuilder.from(registryURL) + .setProtocol(SERVICE_REGISTRY_PROTOCOL) + .removeParameter(REGISTRY_TYPE_KEY) + .build(); + result.add(serviceDiscoveryRegistryURL); + } + //根据逻辑条件判断是否添加接口级注册中心地址 + if (DEFAULT_REGISTER_MODE_INTERFACE.equalsIgnoreCase(registerMode) || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)) { + result.add(registryURL); + } + } + + FrameworkStatusReportService reportService = ScopeModelUtil.getApplicationModel(scopeModel).getBeanFactory().getBean(FrameworkStatusReportService.class); + reportService.reportRegistrationStatus(reportService.createRegistrationReport(registerMode)); + } else { + result.add(registryURL); + } + }); + + return result; + } +``` + +这个方法是根据服务注册模式来判断使用接口级注册地址还是应用级注册地址分别如下所示: +配置信息: +dubbo.application.register-mode +配置值: +- interface + - 接口级注册 +- instance + - 应用级注册 +- all + - 接口级别和应用级都注册 + +接口级注册地址: + +```java +registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=9008®istry=zookeeper&release=3.0.8×tamp=1653703292768 +``` + + +应用级注册地址: + +```java +service-discovery-registry://8.131.79.126:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=10275®istry=zookeeper&release=3.0.8×tamp=1653704425920 +``` + + + + + + + + ## 16.5 导出服务配置到本地和注册中心 + + +```java + doExportUrlsFor1Protocol(protocolConfig, registryURLs); +``` +protocolConfig为:dubbo协议的配置 + + +registryURLs目前有两个 应用级注册地址和接口级注册地址: +```java +registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=9008®istry=zookeeper&release=3.0.8×tamp=1653703292768 +``` + +```java +service-discovery-registry://8.131.79.126:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=10275®istry=zookeeper&release=3.0.8×tamp=1653704425920 +``` + +### 16.5.1 导出服务配置的doExportUrlsFor1Protocol方法 +```java + private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs) { + //生成协议配置具体可见下图中的元数据配置中的attachments + Map map = buildAttributes(protocolConfig); + + // remove null key and null value + //移除空值 简化配置 + map.keySet().removeIf(key -> key == null || map.get(key) == null); + // init serviceMetadata attachments + //协议配置放到元数据对象中 + serviceMetadata.getAttachments().putAll(map); + + //协议配置 + 默认协议配置转URL类型的配置存储 + URL url = buildUrl(protocolConfig, map); + //导出url + exportUrl(url, registryURLs); + } + +``` + + ![在这里插入图片描述](/imgs/blog/source-blog/16-deploy2.png) + + +### 16.5.2 导出服务配置模板方法 +继续看导出服务的模板方法,分为本地导出和注册中心导出 +//参数url为协议配置url可以参考: + +```java +dubbo://192.168.1.9:20880/link.elastic.dubbo.entity.DemoService?anyhost=true&application=dubbo-demo-api-provider&background=false&bind.ip=192.168.1.9&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=link.elastic.dubbo.entity.DemoService&methods=sayHello,sayHelloAsync&pid=10953&release=3.0.8&side=provider×tamp=1653705630518 +``` + +```java +private void exportUrl(URL url, List registryURLs) { + String scope = url.getParameter(SCOPE_KEY); + // don't export when none is configured + if (!SCOPE_NONE.equalsIgnoreCase(scope)) { + + // export to local if the config is not remote (export to remote only when config is remote) + //未明确指定远程导出 则开启本地导出 + if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) { + exportLocal(url); + } + //未明确指定本地导出 则开启远程导出 + // export to remote if the config is not local (export to local only when config is local) + if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) { + url = exportRemote(url, registryURLs); + if (!isGeneric(generic) && !getScopeModel().isInternal()) { + MetadataUtils.publishServiceDefinition(url, providerModel.getServiceModel(), getApplicationModel()); + } + } + } + this.urls.add(url); + } +``` + + +## 16.6 导出服务到本地 +本地调用使用了 injvm 协议,是一个伪协议,它不开启端口,不发起远程调用,只在 JVM 内直接关联,但执行 Dubbo 的 Filter 链。 + +直接通过代码来看吧 +```java + private void exportLocal(URL url) { + //协议转为injvm 代表本地导出 host为127.0.0.1 + URL local = URLBuilder.from(url) + .setProtocol(LOCAL_PROTOCOL) + .setHost(LOCALHOST_VALUE) + .setPort(0) + .build(); + local = local.setScopeModel(getScopeModel()) + .setServiceModel(providerModel); + doExportUrl(local, false); + logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry url : " + local); + } +``` + +### 16.6.1 doExportUrl方法 +```java +private void doExportUrl(URL url, boolean withMetaData) { + //这里是由adaptor扩展类型处理过的 我们直接看默认的类型javassist 对应JavassistProxyFactory代理工厂 获取调用对象 ( + Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url); + if (withMetaData) { + invoker = new DelegateProviderMetaDataInvoker(invoker, this); + } + Exporter exporter = protocolSPI.export(invoker); + exporters.add(exporter); + } +``` + +### 16.6.2 JavassistProxyFactory类型的getInvoker方法 + +```java +@Override + public Invoker getInvoker(T proxy, Class type, URL url) { + try { + // TODO Wrapper cannot handle this scenario correctly: the classname contains '$' + // 创建实际服务提供者的代理类型,代理类型后缀为DubboWrap在这里类型为 link.elastic.dubbo.entity.DemoServiceImplDubboWrap0 + final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type); + //创建一个匿名内部类对象 继承自AbstractProxyInvoker的Invoker对象 + return new AbstractProxyInvoker(proxy, type, url) { + @Override + protected Object doInvoke(T proxy, String methodName, + Class[] parameterTypes, + Object[] arguments) throws Throwable { + return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); + } + }; + } catch (Throwable fromJavassist) { + // try fall back to JDK proxy factory + ... + } + } + } +``` + +### 16.6.3 使用协议导出调用对象 export + +```java + Exporter exporter = protocolSPI.export(invoker); +``` +这个使用了Adaptor扩展和Wrapper机制Debug起来不太方便这里贴一下调用堆栈![在这里插入图片描述](/imgs/blog/source-blog/16-deploy3.png) + +### 16.6.3.1 协议序列化机制ProtocolSerializationWrapper + +```java + @Override + public Exporter export(Invoker invoker) throws RpcException { + //这里主要逻辑是将服务提供者url添加到服务存储仓库中 + getFrameworkModel(invoker.getUrl().getScopeModel()).getServiceRepository().registerProviderUrl(invoker.getUrl()); + return protocol.export(invoker); + } +``` + + +### 16.6.3.2 协议过滤器Wrapper ProtocolFilterWrapper + +```java + @Override + public Exporter export(Invoker invoker) throws RpcException { + //注册中心的协议导出直接执行 + if (UrlUtils.isRegistry(invoker.getUrl())) { + return protocol.export(invoker); + } + //过滤器调用链FilterChainBuilder的扩展对象查询 + FilterChainBuilder builder = getFilterChainBuilder(invoker.getUrl()); + //这里分为2步 生成过滤器调用链 然后使用链表中的节点调用 这里值查询provider类型的过滤器 + return protocol.export(builder.buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER)); + } +``` + +过滤器调用链的生成 对用DefaultFilterChainBuilder类型的buildInvokerChain方法 + +```java +@Override + public Invoker buildInvokerChain(final Invoker originalInvoker, String key, String group) { + //originalInvoker代表真正的服务调用器 + Invoker last = originalInvoker; + URL url = originalInvoker.getUrl(); + List moduleModels = getModuleModelsFromUrl(url); + List filters; + if (moduleModels != null && moduleModels.size() == 1) { + //类型Filter key为service.filter 分组为provider 所有提供者过滤器拉取 + filters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModels.get(0)).getActivateExtension(url, key, group); + } else if (moduleModels != null && moduleModels.size() > 1) { + filters = new ArrayList<>(); + List directors = new ArrayList<>(); + for (ModuleModel moduleModel : moduleModels) { + List tempFilters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModel).getActivateExtension(url, key, group); + filters.addAll(tempFilters); + directors.add(moduleModel.getExtensionDirector()); + } + filters = sortingAndDeduplication(filters, directors); + + } else { + filters = ScopeModelUtil.getExtensionLoader(Filter.class, null).getActivateExtension(url, key, group); + } + + //倒序拼接,将过滤器的调用对象添加到链表中 最后倒序遍历之后 last节点指向了调用链路链表头节点的对象 + if (!CollectionUtils.isEmpty(filters)) { + for (int i = filters.size() - 1; i >= 0; i--) { + final Filter filter = filters.get(i); + final Invoker next = last; + //每个invoker对象中都有originalInvoker对象 + last = new CopyOfFilterChainNode<>(originalInvoker, next, filter); + } + return new CallbackRegistrationInvoker<>(last, filters); + } + + return last; + } +``` + +![在这里插入图片描述](/imgs/blog/source-blog/16-deploy4.png) + + +### 16.6.3.3 协议监听器Wrapper ProtocolListenerWrapper + +```java + @Override + public Exporter export(Invoker invoker) throws RpcException { + //注册中心地址则直接导出 + if (UrlUtils.isRegistry(invoker.getUrl())) { + return protocol.export(invoker); + } + // 先导出对象 再创建过滤器包装对象 执行监听器逻辑 + return new ListenerExporterWrapper(protocol.export(invoker), + Collections.unmodifiableList(ScopeModelUtil.getExtensionLoader(ExporterListener.class, invoker.getUrl().getScopeModel()) + .getActivateExtension(invoker.getUrl(), EXPORTER_LISTENER_KEY))); + } +``` + +### 16.6.3.4 QOS的协议Wrapper QosProtocolWrapper + +```java +@Override + public Exporter export(Invoker invoker) throws RpcException { + //注册中心导出的时候开启QOS 默认端口22222 + if (UrlUtils.isRegistry(invoker.getUrl())) { + startQosServer(invoker.getUrl()); + return protocol.export(invoker); + } + return protocol.export(invoker); + } +``` + +### 16.6.3.5 InjvmProtocol 的导出方法 + +```java + @Override + public Exporter export(Invoker invoker) throws RpcException { + return new InjvmExporter(invoker, invoker.getUrl().getServiceKey(), exporterMap); + } + +``` + +## 16.7 导出服务到注册中心 + 16.5.2 导出服务配置模板方法 中我们看到了服务导出会导出到本地和远程,接下来就看下导出到远程的方法exportRemote + 参数url: + + +```java +dubbo://192.168.1.9:20880/link.elastic.dubbo.entity.DemoService?anyhost=true&application=dubbo-demo-api-provider&background=false&bind.ip=192.168.1.9&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=link.elastic.dubbo.entity.DemoService&methods=sayHello,sayHelloAsync&pid=12865&release=3.0.8&side=provider×tamp=1653708351378 +``` + +参数registryURLs目前有两个 应用级注册地址和接口级注册地址: +```java +registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=9008®istry=zookeeper&release=3.0.8×tamp=1653703292768 +``` + +```java +service-discovery-registry://8.131.79.126:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=10275®istry=zookeeper&release=3.0.8×tamp=1653704425920 +``` + +```java +private URL exportRemote(URL url, List registryURLs) { + + if (CollectionUtils.isNotEmpty(registryURLs)) { + //遍历所有注册地址与注册模式 逐个注册 + for (URL registryURL : registryURLs) { + //为协议URL 添加应用级注册service-discovery-registry参数service-name-mapping为true + if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) { + url = url.addParameterIfAbsent(SERVICE_NAME_MAPPING_KEY, "true"); + } + + //if protocol is only injvm ,not register + if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) { + continue; + } + //为协议url 添加动态配置dynamic + url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY)); + //监控配置暂时为null + URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryURL); + if (monitorUrl != null) { + url = url.putAttribute(MONITOR_KEY, monitorUrl); + } + + // For providers, this is used to enable custom proxy to generate invoker + String proxy = url.getParameter(PROXY_KEY); + if (StringUtils.isNotEmpty(proxy)) { + registryURL = registryURL.addParameter(PROXY_KEY, proxy); + } + + //开始注册服务了 打印个认知 提示下 + if (logger.isInfoEnabled()) { + if (url.getParameter(REGISTER_KEY, true)) { + logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL.getAddress()); + } else { + logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url); + } + } + + doExportUrl(registryURL.putAttribute(EXPORT_KEY, url), true); + } + + } else { + + if (logger.isInfoEnabled()) { + logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url); + } + + doExportUrl(url, true); + } + + + return url; + } +``` + + +### 16.7.1 doExportUrl方法 +与 16.6.1 doExportUrl方法 导出本地协议是一样的逻辑 ,我们来看看点不同地方 +```java +private void doExportUrl(URL url, boolean withMetaData) { + Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url); + if (withMetaData) { + //远程服务导出逐个值为true 元数据invoker包装一下 + invoker = new DelegateProviderMetaDataInvoker(invoker, this); + } + Exporter exporter = protocolSPI.export(invoker); + exporters.add(exporter); + } +``` + +与本地导出ProtocolFilterWrapper的不同之处 + 服务发现service-discovery-registry的导出UrlUtils.isRegistry(invoker.getUrl() 判断结果为true会走这个逻辑 +```java + @Override + public Exporter export(Invoker invoker) throws RpcException { + //注册中心的协议导出直接执行 + // 服务发现service-discovery-registry的导出会走这个逻辑 + if (UrlUtils.isRegistry(invoker.getUrl())) { + return protocol.export(invoker); + } + //过滤器调用链FilterChainBuilder的扩展对象查询 + FilterChainBuilder builder = getFilterChainBuilder(invoker.getUrl()); + //这里分为2步 生成过滤器调用链 然后使用链表中的节点调用 这里值查询provider类型的过滤器 + return protocol.export(builder.buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER)); + } +``` + + +与 协议监听器Wrapper ProtocolListenerWrapper 的不同之处 + + 服务发现service-discovery-registry的导出UrlUtils.isRegistry(invoker.getUrl() 判断结果为true会走这个逻辑 +```java + @Override + public Exporter export(Invoker invoker) throws RpcException { + //注册中心地址则直接导出 + // 服务发现service-discovery-registry的导出会走这个逻辑 + if (UrlUtils.isRegistry(invoker.getUrl())) { + return protocol.export(invoker); + } + // 先导出对象 再创建过滤器包装对象 执行监听器逻辑 + return new ListenerExporterWrapper(protocol.export(invoker), + Collections.unmodifiableList(ScopeModelUtil.getExtensionLoader(ExporterListener.class, invoker.getUrl().getScopeModel()) + .getActivateExtension(invoker.getUrl(), EXPORTER_LISTENER_KEY))); + } +``` + + +与 16.6.3.4 QOS的协议Wrapper QosProtocolWrapper 不同之处 + + 服务发现service-discovery-registry的导出UrlUtils.isRegistry(invoker.getUrl() 判断结果为true会走这个逻辑 + +```java +@Override + public Exporter export(Invoker invoker) throws RpcException { + //注册中心导出的时候开启QOS 默认端口22222 + if (UrlUtils.isRegistry(invoker.getUrl())) { + startQosServer(invoker.getUrl()); + return protocol.export(invoker); + } + return protocol.export(invoker); + } +``` + +启动QOS服务startQosServer +```java +private void startQosServer(URL url) { + try { + if (!hasStarted.compareAndSet(false, true)) { + return; + } + + boolean qosEnable = url.getParameter(QOS_ENABLE, true); + if (!qosEnable) { + logger.info("qos won't be started because it is disabled. " + + "Please check dubbo.application.qos.enable is configured either in system property, " + + "dubbo.properties or XML/spring-boot configuration."); + return; + } + + String host = url.getParameter(QOS_HOST); + int port = url.getParameter(QOS_PORT, QosConstants.DEFAULT_PORT); + boolean acceptForeignIp = Boolean.parseBoolean(url.getParameter(ACCEPT_FOREIGN_IP, "false")); + Server server = frameworkModel.getBeanFactory().getBean(Server.class); + server.setHost(host); + server.setPort(port); + server.setAcceptForeignIp(acceptForeignIp); + server.start(); + + } catch (Throwable throwable) { + logger.warn("Fail to start qos server: ", throwable); + } +``` + +QOS的Server的启动方法start + +```java +public void start() throws Throwable { + if (!started.compareAndSet(false, true)) { + return; + } + //1个主线程 + boss = new NioEventLoopGroup(1, new DefaultThreadFactory("qos-boss", true)); + //0个从线程 + worker = new NioEventLoopGroup(0, new DefaultThreadFactory("qos-worker", true)); + //服务端启动器,和参数设置 + ServerBootstrap serverBootstrap = new ServerBootstrap(); + serverBootstrap.group(boss, worker); + serverBootstrap.channel(NioServerSocketChannel.class); + serverBootstrap.option(ChannelOption.SO_REUSEADDR, true); + serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true); + serverBootstrap.childHandler(new ChannelInitializer() { + + @Override + protected void initChannel(Channel ch) throws Exception { + ch.pipeline().addLast(new QosProcessHandler(frameworkModel, welcome, acceptForeignIp)); + } + }); + try { + if (StringUtils.isBlank(host)) { + serverBootstrap.bind(port).sync(); + } else { + serverBootstrap.bind(host, port).sync(); + } + + logger.info("qos-server bind localhost:" + port); + } catch (Throwable throwable) { + logger.error("qos-server can not bind localhost:" + port, throwable); + throw throwable; + } + } +``` + +QOS处理器为QosProcessHandler关于QosProcessHandler的细节这里先不说 + + + + +最后一个不同的地方调用链路走的这个 RegistryProtocol + +### 16.7.2 通过注册协议导出服务与注册服务的流程 +RegistryProtocol的导出方法: +这个方法非常重要也是服务注册的核心代码,先概括下包含了哪些步骤 +- 覆盖配置 +- 导出协议端口开启TCP服务 +- 注册到注册中心 +- 通知服务启动了 + +```java + @Override + public Exporter export(final Invoker originInvoker) throws RpcException { + //service-discovery-registry://8.131.79.126:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=14256®istry=zookeeper&release=3.0.8×tamp=1653710477057 + URL registryUrl = getRegistryUrl(originInvoker); + // url to export locally + //dubbo://192.168.1.9:20880/link.elastic.dubbo.entity.DemoService?anyhost=true&application=dubbo-demo-api-provider&background=false&bind.ip=192.168.1.9&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=link.elastic.dubbo.entity.DemoService&methods=sayHello,sayHelloAsync&pid=14256&release=3.0.8&service-name-mapping=true&side=provider×tamp=1653710479073 + URL providerUrl = getProviderUrl(originInvoker); + + // Subscribe the override data + // FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call + // the same service. Because the subscribed is cached key with the name of the service, it causes the + // subscription information to cover. + //provider://192.168.1.9:20880/link.elastic.dubbo.entity.DemoService?anyhost=true&application=dubbo-demo-api-provider&background=false&bind.ip=192.168.1.9&bind.port=20880&category=configurators&check=false&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=link.elastic.dubbo.entity.DemoService&methods=sayHello,sayHelloAsync&pid=14256&release=3.0.8&service-name-mapping=true&side=provider×tamp=1653710479073 + + final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl); + //override配置 + final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker); + Map overrideListeners = getProviderConfigurationListener(providerUrl).getOverrideListeners(); + overrideListeners.put(registryUrl, overrideSubscribeListener); + + providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener); + + //export invoker + final ExporterChangeableWrapper exporter = doLocalExport(originInvoker, providerUrl); + + // url to registry + //通过URL获取 注册中心Registry操作对象 + final Registry registry = getRegistry(registryUrl); + //需要向注册中心注册地址转换 + //dubbo://192.168.1.9:20880/link.elastic.dubbo.entity.DemoService?anyhost=true&application=dubbo-demo-api-provider&background=false&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=link.elastic.dubbo.entity.DemoService&methods=sayHello,sayHelloAsync&pid=14656&release=3.0.8&service-name-mapping=true&side=provider×tamp=1653711086189 + final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl); + + // decide if we need to delay publish (provider itself and registry should both need to register) + boolean register = providerUrl.getParameter(REGISTER_KEY, true) && registryUrl.getParameter(REGISTER_KEY, true); + //是否向注册中心注册 + if (register) { + register(registry, registeredProviderUrl); + } + + // register stated url on provider model + registerStatedUrl(registryUrl, registeredProviderUrl, register); + + + exporter.setRegisterUrl(registeredProviderUrl); + exporter.setSubscribeUrl(overrideSubscribeUrl); + + if (!registry.isServiceDiscovery()) { + // Deprecated! Subscribe to override rules in 2.6.x or before. + registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener); + } + //内置监听器通知 这个不是通知消费者的 + notifyExport(exporter); + //Ensure that a new exporter instance is returned every time export + return new DestroyableExporter<>(exporter); + } +``` + +## 16.8 doLocalExport本地导出协议开启端口 +前面已经看过了本地协议JVM协议的服务导出和注册中心配置的导出,这里可以直接看一些关键代码: + +```java + private ExporterChangeableWrapper doLocalExport(final Invoker originInvoker, URL providerUrl) { + String key = getCacheKey(originInvoker); + + return (ExporterChangeableWrapper) bounds.computeIfAbsent(key, s -> { + Invoker invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl); + //代码中用的这个protoco对象是dubbo自动生成的适配器对象protocol$Adaptive 适配器对象会根据当前协议的参数来查询具体的协议扩展对象 + return new ExporterChangeableWrapper<>((Exporter) protocol.export(invokerDelegate), originInvoker); + }); + } +``` + +上面这个protocol$Adaptive 协议的export导出方法与之前的一样也会经历下面几个过程,具体细节可以参考JVM协议的导出: +- ProtocolSerializationWrapper +- ProtocolFilterWrapper +- ProtocolListenerWrapper +- QosProtocolWrapper +- 唯一不同的是我们这里对应的协议扩展类型为DubboProtocol、 +接下来来看下DubboProtocol的导出服务export方法实现: + +```java + @Override + public Exporter export(Invoker invoker) throws RpcException { + checkDestroyed(); + //服务提供者的url参考例子dubbo://192.168.1.9:20880/link.elastic.dubbo.entity.DemoService?anyhost=true&application=dubbo-demo-api-provider&background=false&bind.ip=192.168.1.9&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=link.elastic.dubbo.entity.DemoService&methods=sayHello,sayHelloAsync&pid=6043&release=3.0.8&service-name-mapping=true&side=provider×tamp=1654224285437 + URL url = invoker.getUrl(); + + // export service. + //生成服务的key参考:link.elastic.dubbo.entity.DemoService:20880 + String key = serviceKey(url); + //创建导出服务用的导出器DubboExporter + DubboExporter exporter = new DubboExporter(invoker, key, exporterMap); + + //export a stub service for dispatching event + //stub配置校验 + Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT); + Boolean isCallbackservice = url.getParameter(IS_CALLBACK_SERVICE, false); + if (isStubSupportEvent && !isCallbackservice) { + String stubServiceMethods = url.getParameter(STUB_EVENT_METHODS_KEY); + if (stubServiceMethods == null || stubServiceMethods.length() == 0) { + if (logger.isWarnEnabled()) { + logger.warn(new IllegalStateException("consumer [" + url.getParameter(INTERFACE_KEY) + + "], has set stubproxy support event ,but no stub methods founded.")); + } + + } + } + //创建服务开启服务端口 + openServer(url); + // + optimizeSerialization(url); + + return exporter; + } +``` +### 开启服务端口 +这里就到了RPC协议的TCP通信模块了,对应DubboProtocol 的 openServer(url);方法 + +```java + private void openServer(URL url) { + checkDestroyed(); + // find server. 地址作为key这里是192.168.1.9:20880 + String key = url.getAddress(); + // client can export a service which only for server to invoke + //默认提供者开启服务,消费者是不能开启服务的 + boolean isServer = url.getParameter(IS_SERVER_KEY, true); + if (isServer) { + //协议服务器 下面一个双重校验锁检查,如果为空则创建服务 + ProtocolServer server = serverMap.get(key); + if (server == null) { + synchronized (this) { + server = serverMap.get(key); + if (server == null) { + serverMap.put(key, createServer(url)); + }else { + server.reset(url); + } + } + } else { + // server supports reset, use together with override + server.reset(url); + } + } + } +``` + +为当前地址创建协议服务对应方法如下: +DubboProtocol的createServer方法 +```java +private ProtocolServer createServer(URL url) { + //下面将url增加了心跳参数最终如下dubbo://192.168.1.9:20880/link.elastic.dubbo.entity.DemoService?anyhost=true&application=dubbo-demo-api-provider&background=false&bind.ip=192.168.1.9&bind.port=20880&channel.readonly.sent=true&codec=dubbo&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&heartbeat=60000&interface=link.elastic.dubbo.entity.DemoService&methods=sayHello,sayHelloAsync&pid=6700&release=3.0.8&service-name-mapping=true&side=provider×tamp=1654225251112 + url = URLBuilder.from(url) + // send readonly event when server closes, it's enabled by default + .addParameterIfAbsent(CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString()) + // enable heartbeat by default + .addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT)) + .addParameter(CODEC_KEY, DubboCodec.NAME) + .build(); + //这里服务端使用的网络库这里是默认值netty + String str = url.getParameter(SERVER_KEY, DEFAULT_REMOTING_SERVER); + + if (StringUtils.isNotEmpty(str) && !url.getOrDefaultFrameworkModel().getExtensionLoader(Transporter.class).hasExtension(str)) { + throw new RpcException("Unsupported server type: " + str + ", url: " + url); + } + //dubbo交换器层对象创建 + ExchangeServer server; + try { + //这个方法会绑定端口,关于交换器与传输网络层到后面统一说 + //这里通过绑定url和请求处理器来创建交换器对象 + server = Exchangers.bind(url, requestHandler); + } catch (RemotingException e) { + throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e); + } + + str = url.getParameter(CLIENT_KEY); + if (StringUtils.isNotEmpty(str)) { + Set supportedTypes = url.getOrDefaultFrameworkModel().getExtensionLoader(Transporter.class).getSupportedExtensions(); + if (!supportedTypes.contains(str)) { + throw new RpcException("Unsupported client type: " + str); + } + } + + DubboProtocolServer protocolServer = new DubboProtocolServer(server); + //关闭等待时长默认为10秒 + loadServerProperties(protocolServer); + return protocolServer; + } +``` + +## 16.9 向注册中心注册服务register + 这个细节在下个博客中说涉及到Dubbo3的双注册 + + + +原文地址:[16-模块发布器发布服务全过程](https://blog.elastic.link/2022/07/10/dubbo/16-mo-kuai-fa-bu-qi-fa-bu-fu-wu-quan-guo-cheng/) \ No newline at end of file diff --git "a/content/en/blog/java/codeanalysis/3.0.8/17-Dubbo\346\234\215\345\212\241\346\217\220\344\276\233\350\200\205\347\232\204\345\217\214\346\263\250\345\206\214\345\216\237\347\220\206.md" "b/content/en/blog/java/codeanalysis/3.0.8/17-Dubbo\346\234\215\345\212\241\346\217\220\344\276\233\350\200\205\347\232\204\345\217\214\346\263\250\345\206\214\345\216\237\347\220\206.md" new file mode 100644 index 000000000000..523c48ba3359 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/17-Dubbo\346\234\215\345\212\241\346\217\220\344\276\233\350\200\205\347\232\204\345\217\214\346\263\250\345\206\214\345\216\237\347\220\206.md" @@ -0,0 +1,987 @@ +--- +title: "17-Dubbo服务提供者的双注册原理" +linkTitle: "17-Dubbo服务提供者的双注册原理" +date: 2022-08-17 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] 对于直接使用Dubbo3的用户还好,可以仅仅开启应用级注册,但是对于Dubbo2.x的用户升级到Dubbo3的用户来说前期都是要开启双注册来慢慢迁移的,既注册传统的接口信息到注册中心,又注册应用信息到注册中心,同时注册应用与接口关系的元数据信息。 +--- + +# 17-Dubbo服务提供者的双注册原理 +## 17.1 简介 +上个博客[《15-Dubbo的三大中心之元数据中心源码解析》](https://blog.elastic.link/2022/07/10/dubbo/15-dubbo-de-san-da-zhong-xin-zhi-yuan-shu-ju-zhong-xin-yuan-ma-jie-xi/)导出服务端的时候多次提到了元数据中心,注册信息的注册。 +Dubbo3出来时间不太长,对于现在的用户来说大部分使用的仍旧是Dubbo2.x, +Dubbo3 比较有特色也是会直接使用到的功能就是**应用级服务发现**: + +- 应用级服务发现 +*从服务/接口粒度到应用粒度的升级,使得 Dubbo 在集群可伸缩性、连接异构微服务体系上更具优势。应用粒度能以更低的资源消耗支持超百万实例规模集群程; 实现与 Spring Cloud、Kubernetes Service 等异构微服务体系的互联互通。* + +对于直接使用Dubbo3的用户还好,可以仅仅开启应用级注册,但是对于Dubbo2.x的用户升级到Dubbo3的用户来说前期都是要开启双注册来慢慢迁移的,既注册传统的接口信息到注册中心,又注册应用信息到注册中心,同时注册应用与接口关系的元数据信息。 +关于双注册与服务迁移的过程的使用可以参考官网: +[应用级地址发现迁移指南](/en/docs/migration/migration-service-discovery/) + +关于官网提供者双注册的图我这里贴一下,方便了解: +![在这里插入图片描述](/imgs/v3/migration/provider-registration.png) + + +## 17.2 双注册配置的读取 +### 17.2.1 注册中心地址作为元数据中心 +这个配置的解析过程在前面的博客介绍元数据中心的时候很详细的说了相关链接:[15-Dubbo的三大中心之元数据中心源码解析](https://blog.elastic.link/2022/07/10/dubbo/15-dubbo-de-san-da-zhong-xin-zhi-yuan-shu-ju-zhong-xin-yuan-ma-jie-xi/) + +对应代码位于:DefaultApplicationDeployer类型的startMetadataCenter()方法 + +```java +private void startMetadataCenter() { + //如果未配置元数据中心的地址等配置则使用注册中心的地址等配置做为元数据中心的配置 + useRegistryAsMetadataCenterIfNecessary(); + //...省略掉其他代码防止受到干扰 + } + +``` +具体逻辑是这个方法: +useRegistryAsMetadataCenterIfNecessary + +```java +private void useRegistryAsMetadataCenterIfNecessary() { + //配置缓存中查询元数据配置 + Collection metadataConfigs = configManager.getMetadataConfigs(); + + //...省略掉空判断 + //查询是否有注册中心设置了默认配置isDefault 设置为true的注册中心则为默认注册中心列表,如果没有注册中心设置为默认注册中心,则获取所有未设置默认配置的注册中心列表 + List defaultRegistries = configManager.getDefaultRegistries(); + if (defaultRegistries.size() > 0) { + //多注册中心遍历 + defaultRegistries + .stream() + //筛选符合条件的注册中心 (筛选逻辑就是查看是否有对应协议的扩展支持) + .filter(this::isUsedRegistryAsMetadataCenter) + //注册中心配置映射为元数据中心 映射就是获取需要的配置 + .map(this::registryAsMetadataCenter) + //将元数据中心配置存储在配置缓存中方便后续使用 + .forEach(metadataReportConfig -> { + //...省略掉具体的逻辑 + }); + } + } +``` +关于元数据中心地址的获取,主要经过如下逻辑: +- **查询:** 所有可用的默认注册中心列表 +- **遍历:** 多注册中心遍历 +- **筛选:** 选符合条件的注册中心 (筛选逻辑就是查看是否有对应协议的扩展支持) +- **转化:** 注册中心配置RegistryConfig映射转换为元数据中心配置类型MetadataReportConfig + +MetadataReportConfig 映射就是获取需要的配置。 + +最后会把查询到的元数据中心配置存储在配置缓存中方便后续使用。 + +### 17.2.2 双注册模式配置 +双注册配置类型是这个 + +```java +dubbo.application.register-mode=all +``` +默认值为all代表应用级注册和接口级注册,当前在完全迁移到应用级注册之后可以将服务直接迁移到应用级配置上去。 +配置值解释: +- all 双注册 +- instance 应用级注册 +- interface 接口级注册 + +后面的代码如果想要看更详细的代码可以看博客[《16-模块发布器发布服务全过程》](https://blog.elastic.link/2022/07/10/dubbo/16-mo-kuai-fa-bu-qi-fa-bu-fu-wu-quan-guo-cheng/) +关于这个配置的使用我们详细来看下,在Dubbo服务注册时候会先通过此配置查询需要注册服务地址,具体代码位于ServiceConfig的doExportUrls()方法中: + +```java +private void doExportUrls() { + //省略掉前面的代码... + List registryURLs = ConfigValidationUtils.loadRegistries(this, true); + //省略掉后面的代码... + } +``` +然后就是具体注册中心地址的获取过程我们看下: +ConfigValidationUtils的加载注册中心地址方法loadRegistries +```java + public static List loadRegistries(AbstractInterfaceConfig interfaceConfig, boolean provider) { + // check && override if necessary + //省略掉前面的代码... + //这里会获取到一个接口配置注册地址例如:registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=9008®istry=zookeeper&release=3.0.8×tamp=1653703292768 + List registries = interfaceConfig.getRegistries(); + //省略掉中间的的代码... + return genCompatibleRegistries(interfaceConfig.getScopeModel(), registryList, provider); + } +``` + +ConfigValidationUtils的双注册地址的获取genCompatibleRegistries方法. +前面代码获取到了一个注册中心地址列表例如: + +```java +registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=9008®istry=zookeeper&release=3.0.8×tamp=1653703292768 +``` +下面可以看下如果根据配置来转换为应用级注册地址+接口级注册地址 + +```java +private static List genCompatibleRegistries(ScopeModel scopeModel, List registryList, boolean provider) { + List result = new ArrayList<>(registryList.size()); + registryList.forEach(registryURL -> { + if (provider) { + // for registries enabled service discovery, automatically register interface compatible addresses. + String registerMode; + if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) { + //为了更好理解这里简化掉服务发现注册地址配置的逻辑判断过程仅仅看当前例子提供的值走的逻辑 + } else { + //双注册模式配置查询 对应参数为dubbo.application.register-mode 默认值为all + registerMode = registryURL.getParameter(REGISTER_MODE_KEY, ConfigurationUtils.getCachedDynamicProperty(scopeModel, DUBBO_REGISTER_MODE_DEFAULT_KEY, DEFAULT_REGISTER_MODE_ALL)); + //如果用户配置了一个错误的注册模式配置则只走接口级配置 这里默认值为interface + if (!isValidRegisterMode(registerMode)) { + registerMode = DEFAULT_REGISTER_MODE_INTERFACE; + } + //这个逻辑是满足应用级注册就添加一个应用级注册的地址 + if ((DEFAULT_REGISTER_MODE_INSTANCE.equalsIgnoreCase(registerMode) || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)) + && registryNotExists(registryURL, registryList, SERVICE_REGISTRY_PROTOCOL)) { + URL serviceDiscoveryRegistryURL = URLBuilder.from(registryURL) + .setProtocol(SERVICE_REGISTRY_PROTOCOL) + .removeParameter(REGISTRY_TYPE_KEY) + .build(); + result.add(serviceDiscoveryRegistryURL); + } + //这个逻辑是满足接口级注册配置就添加一个接口级注册地址 + if (DEFAULT_REGISTER_MODE_INTERFACE.equalsIgnoreCase(registerMode) || DEFAULT_REGISTER_MODE_ALL.equalsIgnoreCase(registerMode)) { + result.add(registryURL); + } + } + //省略掉若干代码和括号 + + return result; + } +``` +可以看到这里简化的配置比较容易理解了 +- 双注册模式配置查询 对应参数为dubbo.application.register-mode ,默认值为all +- 如果用户配置了一个错误的注册模式配置则只走接口级配置 这里默认值为interface +- 满足应用级注册就添加一个应用级注册的地址 +- 满足接口级注册配置就添加一个接口级注册地址 + +这个方法是根据服务注册模式来判断使用接口级注册地址还是应用级注册地址分别如下所示: +配置信息: +dubbo.application.register-mode +配置值: +- interface + - 接口级注册 +- instance + - 应用级注册 +- all + - 接口级别和应用级都注册 + +最终的注册地址配置如下: +接口级注册地址: + +```java +registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=9008®istry=zookeeper&release=3.0.8×tamp=1653703292768 +``` + + +应用级注册地址: + +```java +service-discovery-registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=10275®istry=zookeeper&release=3.0.8×tamp=1653704425920 +``` + + +## 17.3 双注册服务数据的注册 +### 17.3.1 双注册代码逻辑调用简介 +前面说了这个注册服务的配置地址会由Dubbo内部进行判断如果判断是all的话会自动将一个配置的注册地址转变为两个一个是传统的接口级注册,一个是应用级注册使用的配置地址 + +然后我们先看注册中心,注册服务数据的源码 +如果想要查看源码细节可以在RegistryProtocol类型的export(final Invoker originInvoker) 方法的如下代码位置打断点: + +RegistryProtocol的export方法的注册中心注册数据代码如下: + +```java + // url to registry 注册服务对外的接口 + //如果url为service-discovery-registry发现则这个实现类型为ServiceDiscoveryRegistry + final Registry registry = getRegistry(registryUrl); + //服务发现的提供者url: dubbo://192.168.1.9:20880/link.elastic.dubbo.entity.DemoService?anyhost=true&application=dubbo-demo-api-provider&background=false&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=link.elastic.dubbo.entity.DemoService&methods=sayHello,sayHelloAsync&pid=19559&release=3.0.8&service-name-mapping=true&side=provider×tamp=1654938441023 + final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl); + + // decide if we need to delay publish (provider itself and registry should both need to register) + //register参数是否 注册数据到注册中心 + boolean register = providerUrl.getParameter(REGISTER_KEY, true) && registryUrl.getParameter(REGISTER_KEY, true); + if (register) { + //这里有两种情况 接口级注册会将接口级服务提供者数据直接注册到Zookeper上面,服务发现(应用级注册)这里仅仅会将注册数据转换为服务元数据等后面来发布元数据 + register(registry, registeredProviderUrl); + } + + // register stated url on provider model + //向提供者模型注册提供者配置ProviderModel + registerStatedUrl(registryUrl, registeredProviderUrl, register); + + + exporter.setRegisterUrl(registeredProviderUrl); + exporter.setSubscribeUrl(overrideSubscribeUrl); + + if (!registry.isServiceDiscovery()) { + // Deprecated! Subscribe to override rules in 2.6.x or before. + registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener); + } +``` + +在上个博客中我们整体说了下服务注册时候的一个流程,关于数据向注册中心的注册细节这里可以详细看下 + + +### 17.3.2 注册中心领域对象的初始化 +前面的代码使用url来获取注册中心操作对象如下调用代码: + +```java +// url to registry 注册服务对外的接口 +final Registry registry = getRegistry(registryUrl); +``` + +对应代码如下: +```java + protected Registry getRegistry(final URL registryUrl) { + //这里分为两步先获取注册中心工厂对象 + RegistryFactory registryFactory = ScopeModelUtil.getExtensionLoader(RegistryFactory.class, registryUrl.getScopeModel()).getAdaptiveExtension(); + //使用注册中心工厂对象获取注册中心操作对象 + return registryFactory.getRegistry(registryUrl); + } +``` + +关于参数URL有两个在前面已经说过,url信息如下: + +接口级注册地址: +```java +registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=9008®istry=zookeeper&release=3.0.8×tamp=1653703292768 +``` + + +应用级注册地址: + +```java +service-discovery-registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=10275®istry=zookeeper&release=3.0.8×tamp=1653704425920 +``` + +注册中心工厂对象与注册中心操作对象的获取与执行我们通过Debug来看比较麻烦,这里涉及到很多扩展机制动态生成的代码我们无法看到,这里我直接来贴一下比较关键的一些类型,以Zookeeper注册中心来举例子: + + 先来看下注册工厂相关的类型: +![在这里插入图片描述](/imgs/blog/source-blog/17-register.png) +- RegistryFactory 注册中心对象获取 +- AbstractRegistryFactory 模板类型封装注册中心对象获取的基本逻辑,比如缓存和基本的逻辑判断 +- ServiceDiscoveryRegistryFactory 用于创建服务发现注册中心工厂对象 用于创建ServiceDiscoveryRegistry对象 +- ZookeeperRegistryFactory 用于创建ZookeeperRegistry类型对象 +- NacosRegistryFactory Nacos注册中心工厂对象 用于创建NacosRegistry + + +接下来看封装了注册中心操作逻辑的注册中心领域对象: + + +![在这里插入图片描述](/imgs/blog/source-blog/17-register2.png) + + - Node 节点信息开放接口 比如节点 url的获取 ,销毁 + - RegistryService 注册服务接口,比如注册,订阅,查询等操作 + - Registry 注册中心接口,是否服务发现查询,注册,取消注册方法 + - AbstractRegistry 注册中心逻辑抽象模板类型,封装了注册,订阅,通知的基本逻辑,和本地缓存注册中心信息的基本逻辑 + - FailbackRegistry 封装了失败重试的逻辑 + - NacosRegistry 封装了以nacos作为注册中心的基本逻辑 + - ServiceDiscoveryRegistry 应用级服务发现注册中心逻辑,现在不需要这种网桥实现,协议可以直接与服务发现交互。ServiceDiscoveryRegistry是一种非常特殊的注册表实现,用于以兼容的方式将旧的接口级服务发现模型与3.0中引入的新服务发现模型连接起来。 +它完全符合注册表SPI的扩展规范,但与zookeeper和Nacos的具体实现不同,因为它不与任何真正的第三方注册表交互,而只与过程中ServiceDiscovery的相关组件交互。简而言之,它架起了旧接口模型和新服务发现模型之间的桥梁:register()方法主要通过与MetadataService交互,将接口级数据聚合到MetadataInfo中subscribe() 触发应用程序级服务发现模型的整个订阅过程。-根据ServiceNameMapping将接口映射到应用程序。-启动新的服务发现侦听器(InstanceListener),并使NotifierListener成为InstanceListener的一部分。 +- CacheableFailbackRegistry 提供了一些本地内存缓存的逻辑 对注册中心有用,注册中心的sdk将原始字符串作为提供程序实例返回,例如zookeeper和etcd +- ZookeeperRegistry Zookeeper作为注册中心的基本操作逻辑封装 + + +了解了这几个领域对象这里我们回到代码逻辑,这里直接看将会执行的一些核心逻辑: + + +```java + protected Registry getRegistry(final URL registryUrl) { + //这里分为两步先获取注册中心工厂对象 + RegistryFactory registryFactory = ScopeModelUtil.getExtensionLoader(RegistryFactory.class, registryUrl.getScopeModel()).getAdaptiveExtension(); + //使用注册中心工厂对象获取注册中心操作对象 + return registryFactory.getRegistry(registryUrl); + } +``` + +前面注册中心工厂不论那种协议的地址信息获取到的都是一个RegistryFactory$Adaptive类型(由扩展机制的字节码工具自动生成的代码) + +如果getRegistry参数为应用级注册地址。如下所示将获取到的类型为ServiceDiscoveryRegistryFactory逻辑来获取注册中心: +(这个逻辑是@Adaptive注解产生的了逻辑具体原理可以看扩展机制中@Adaptive的实现) + +```java +service-discovery-registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=10275®istry=zookeeper&release=3.0.8×tamp=1653704425920 +``` + +getRegistry方法优先走的逻辑是这里:AbstractRegistryFactory模板类型中的getRegistry方法 + +```java +@Override + public Registry getRegistry(URL url) { + if (registryManager == null) { + throw new IllegalStateException("Unable to fetch RegistryManager from ApplicationModel BeanFactory. " + + "Please check if `setApplicationModel` has been override."); + } + //销毁状态直接返回 + Registry defaultNopRegistry = registryManager.getDefaultNopRegistryIfDestroyed(); + if (null != defaultNopRegistry) { + return defaultNopRegistry; + } + + url = URLBuilder.from(url) + .setPath(RegistryService.class.getName()) + .addParameter(INTERFACE_KEY, RegistryService.class.getName()) + .removeParameter(TIMESTAMP_KEY) + .removeAttribute(EXPORT_KEY) + .removeAttribute(REFER_KEY) + .build(); + //这个key为 service-discovery-registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService + String key = createRegistryCacheKey(url); + Registry registry = null; + //check配置 是否检查注册中心连通 默认为true + boolean check = url.getParameter(CHECK_KEY, true) && url.getPort() != 0; + // Lock the registry access process to ensure a single instance of the registry + //给写操作加锁方式并发写问题 + registryManager.getRegistryLock().lock(); + try { + //锁内检查是否销毁的逻辑 + // double check + // fix https://github.com/apache/dubbo/issues/7265. + defaultNopRegistry = registryManager.getDefaultNopRegistryIfDestroyed(); + if (null != defaultNopRegistry) { + return defaultNopRegistry; + } + //锁内检查是否缓存中存在存在则直接返回 + registry = registryManager.getRegistry(key); + if (registry != null) { + return registry; + } + //create registry by spi/ioc + //使用url创建注册中心操作的逻辑 + registry = createRegistry(url); + } catch (Exception e) { + //check配置检查 + if (check) { + throw new RuntimeException("Can not create registry " + url, e); + } else { + LOGGER.warn("Failed to obtain or create registry ", e); + } + } finally { + // Release the lock + registryManager.getRegistryLock().unlock(); + } + + if (check && registry == null) { + throw new IllegalStateException("Can not create registry " + url); + } + //缓存逻辑 + if (registry != null) { + registryManager.putRegistry(key, registry); + } + return registry; + } +``` + +逻辑其实吧比较简单,概括下上面的逻辑: +- 销毁逻辑判断 +- 缓存获取,存在则直接返回 +- 根据注册中心url配置,创建注册中心操作对象 +- 注册中心连接失败的check配置逻辑处理 +- 将注册中心操作对象存入缓存 + +上面比较重要的逻辑是createRegistry这个 +整个调用过程我给大家看下Debug的详情,这里很多逻辑由扩展机制产生的这里直接看下逻辑调用栈,有几个需要关注的地方我圈了起来: +![在这里插入图片描述](/imgs/blog/source-blog/17-register3.png) +我们继续看服务发现的注册中心工厂对象的获取,代码如下: +ServiceDiscoveryRegistryFactory类型的createRegistry方法 + +```java + @Override + protected Registry createRegistry(URL url) { + //判断url是否是这个前缀:service-discovery-registry + if (UrlUtils.hasServiceDiscoveryRegistryProtocol(url)) { + //切换下协议:将服务发现协议切换为配置的注册中心协议这里是Zookeeper如下: + //zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=39884&release=3.0.8 + String protocol = url.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY); + url = url.setProtocol(protocol).removeParameter(REGISTRY_KEY); + } + //创建服务发现注册中心对象对象 + return new ServiceDiscoveryRegistry(url, applicationModel); + } +``` +通过以上代码可以看到其实最终创建的是一个ServiceDiscoveryRegistry注册中心对象,这个url协议被转换为了对应注册中心的协议,也就是说双注册会有两个协议一个是原先的接口级注册注册中心对象(这个还未说到)和这里对应注册中心协议的服务发现注册中心对象ServiceDiscoveryRegistry + + + +### 17.3.3 ServiceDiscoveryRegistry + + +ServiceDiscoveryRegistry服务发现注册中心对象的初始化过程: + +#### 17.3.3.1 ServiceDiscoveryRegistry的构造器: + +```java + public ServiceDiscoveryRegistry(URL registryURL, ApplicationModel applicationModel) { + super(registryURL); + //根据url创建一个服务发现对象类型为ServiceDiscovery + this.serviceDiscovery = createServiceDiscovery(registryURL); + //这个类型为是serviceNameMapping类型是MetadataServiceNameMapping类型 + this.serviceNameMapping = (AbstractServiceNameMapping) ServiceNameMapping.getDefaultExtension(registryURL.getScopeModel()); + super.applicationModel = applicationModel; + } +``` + + ServiceDiscoveryRegistry中创建服务发现对象createServiceDiscovery方法 + +```java +protected ServiceDiscovery createServiceDiscovery(URL registryURL) { + return getServiceDiscovery(registryURL.addParameter(INTERFACE_KEY, ServiceDiscovery.class.getName()) + .removeParameter(REGISTRY_TYPE_KEY)); + } +``` + + + ServiceDiscoveryRegistry中创建服务发现对象getServiceDiscovery方法 + +```java +private ServiceDiscovery getServiceDiscovery(URL registryURL) { +//服务发现工厂对象的获取这里是ServiceDiscoveryFactory类型, + ServiceDiscoveryFactory factory = getExtension(registryURL); + //服务发现工厂对象获取服务发现对象 + return factory.getServiceDiscovery(registryURL); + } +``` +ServiceDiscoveryFactory和ServiceDiscovery类型可以往后看 + +#### 17.3.3.2 父类型FailbackRegistry的构造器 +```java + public FailbackRegistry(URL url) { + super(url); + //重试间隔配置retry.period ,默认为5秒 + this.retryPeriod = url.getParameter(REGISTRY_RETRY_PERIOD_KEY, DEFAULT_REGISTRY_RETRY_PERIOD); + + // since the retry task will not be very much. 128 ticks is enough. + //因为重试任务不会太多。128个刻度就足够了。Dubbo封装的时间轮用于高效率的重试,这个在Kafka也自定义实现了后续可以单独来看看 + retryTimer = new HashedWheelTimer(new NamedThreadFactory("DubboRegistryRetryTimer", true), retryPeriod, TimeUnit.MILLISECONDS, 128); + } +``` + +#### 17.3.3.3 AbstractRegistry的构造器 +参数url如下所示: +```java +zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=39884&release=3.0.8 +``` + +```java + + public AbstractRegistry(URL url) { + setUrl(url); + registryManager = url.getOrDefaultApplicationModel().getBeanFactory().getBean(RegistryManager.class); + //是否本地缓存默认为true + localCacheEnabled = url.getParameter(REGISTRY_LOCAL_FILE_CACHE_ENABLED, true); + registryCacheExecutor = url.getOrDefaultFrameworkModel().getBeanFactory() + .getBean(FrameworkExecutorRepository.class).getSharedExecutor(); + if (localCacheEnabled) { + // Start file save timer 是否同步缓存默认为false + syncSaveFile = url.getParameter(REGISTRY_FILESAVE_SYNC_KEY, false); + //默认缓存的文件路径与文件名字为:/Users/song/.dubbo/dubbo-registry-dubbo-demo-api-provider-127.0.0.1-2181.cache + String defaultFilename = System.getProperty(USER_HOME) + DUBBO_REGISTRY + + url.getApplication() + "-" + url.getAddress().replaceAll(":", "-") + CACHE; + //未指定缓存的文件名字则用默认的文件名字 + String filename = url.getParameter(FILE_KEY, defaultFilename); + File file = null; + //父目录创建,保证目录存在 + if (ConfigUtils.isNotEmpty(filename)) { + file = new File(filename); + if (!file.exists() && file.getParentFile() != null && !file.getParentFile().exists()) { + if (!file.getParentFile().mkdirs()) { + throw new IllegalArgumentException("Invalid registry cache file " + file + ", cause: Failed to create directory " + file.getParentFile() + "!"); + } + } + } + this.file = file; + // When starting the subscription center, + // we need to read the local cache file for future Registry fault tolerance processing. + //加载本地磁盘文件 + loadProperties(); + //变更推送 + notify(url.getBackupUrls()); + } + } +``` + + +### 17.3.4 将服务提供者数据转换到本地内存的元数据信息中 +在前面我们看到了RegistryProtocol中调用register来注册服务提供者的数据到注册的中心,接下来详细看下实现原理: +下面参数为ServiceDiscoveryRegistry为情况下举例子:ServiceDiscoveryRegistry类型的register方法与ZookeeperRegister注册不一样传统的接口级注册在这个方法里面就将服务数据注册到注册中心了,服务发现的数据注册分为了两步,这里仅仅将数据封装到内存中如下: +url例子为: + +```java +dubbo://192.168.1.9:20880/link.elastic.dubbo.entity.DemoService?anyhost=true&application=dubbo-demo-api-provider&background=false&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=link.elastic.dubbo.entity.DemoService&methods=sayHello,sayHelloAsync&pid=19559&release=3.0.8&service-name-mapping=true&side=provider×tamp=1654938441023 +``` +RegistryProtocol中的register方法: +```java + private void register(Registry registry, URL registeredProviderUrl) { + registry.register(registeredProviderUrl); + } +``` +上面这个代码会优先走ListenerRegistryWrapper的一些逻辑来执行register方法来触发一些监听器的逻辑,我们直接跳到ServiceDiscoveryRegistry中的register方法来看 + +ServiceDiscoveryRegistry的register方法 +```java +@Override + public final void register(URL url) { + //逻辑判断比如只有side为提供者时候才能注册 + if (!shouldRegister(url)) { // Should Not Register + return; + } + doRegister(url); + } +``` + +ServiceDiscoveryRegistry的doRegister方法: +```java + @Override + public void doRegister(URL url) { + // fixme, add registry-cluster is not necessary anymore + url = addRegistryClusterKey(url); + serviceDiscovery.register(url); + } + +``` + +AbstractServiceDiscovery的register方法: +```java +@Override + public void register(URL url) { + //metadaInfo类型为MetadataInfo类型,用来操作元数据的 + metadataInfo.addService(url); + } + +``` + + +MetadataInfo 类型的addService方法 + +```java +public synchronized void addService(URL url) { + // fixme, pass in application mode context during initialization of MetadataInfo. + //元数据参数过滤器扩展获取:MetadataParamsFilter + if (this.loader == null) { + this.loader = url.getOrDefaultApplicationModel().getExtensionLoader(MetadataParamsFilter.class); + } + //元数据参数过滤器获取 + List filters = loader.getActivateExtension(url, "params-filter"); + // generate service level metadata + //生成服务级别的元数据 + ServiceInfo serviceInfo = new ServiceInfo(url, filters); + this.services.put(serviceInfo.getMatchKey(), serviceInfo); + // extract common instance level params + extractInstanceParams(url, filters); + + if (exportedServiceURLs == null) { + exportedServiceURLs = new ConcurrentSkipListMap<>(); + } + addURL(exportedServiceURLs, url); + updated = true; + } +``` + +### 17.3.5 接口级服务提供者配置的注册 +前面我们通过服务发现的的url进行了举例子,其实在RegistryProtocol协议的export方法中还会注册接口级信息: +例如如下关键代码: +当registryUrl参数不是服务发现协议service-discovery-registry配置而是zookeeper如下时候获取到的扩展类型将是与Zookeeper相关的扩展对象 + +```java +zookeeper://8.131.79.126:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&pid=29386&release=3.0.8×tamp=1655023329438 +``` + +RegistryProtocol协议的export方法中接口级数据注册的核心代码如下: +如下代码的操作类型可以看注释 +```java +// url to registry 这里registry对象的类型为ZookeeperRegistry + final Registry registry = getRegistry(registryUrl); + + final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl); + // decide if we need to delay publish (provider itself and registry should both need to register) + boolean register = providerUrl.getParameter(REGISTER_KEY, true) && registryUrl.getParameter(REGISTER_KEY, true); + //这一个方法里面会将提供者的url配置写入Zookeeper的provider节点下面 + if (register) { + register(registry, registeredProviderUrl); + } +``` +如上代码是获取Zookeeper操作对象和向Zookeeper中写入服务提供者信息的代码,关于与Zookeeper连接和注册数据本地缓存的代码可以看ZookeeperRegistry类型和它的几个父类型比如:CacheableFailbackRegistry类型,关于接口级数据的注册可以看register方法,这个就不详细说了,下面我贴一下接口级数据注册的Zookeeper信息可以了解下就行: +![在这里插入图片描述](/imgs/blog/source-blog/17-register4.png) +接口信息如下,上面我们需要注意的是这个 url配置为临时节点,当与Zookeeper断开连接或者Session超时的时候这个信息会被移除: +```java +/dubbo/link.elastic.dubbo.entity.DemoService/providers/dubbo%3A%2F%2F192.168.1.9%3A20880%2Flink.elastic.dubbo.entity.DemoService%3Fanyhost%3Dtrue%26application%3Ddubbo-demo-api-provider%26background%3Dfalse%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26interface%3Dlink.elastic.dubbo.entity.DemoService%26methods%3DsayHello%2CsayHelloAsync%26pid%3D29386%26release%3D3.0.8%26service-name-mapping%3Dtrue%26side%3Dprovider%26timestamp%3D1655023329514 +``` + + +## 17.4 应用级服务发现功能的实现ServiceDiscovery + +在说这个实现之前我们先看看相关类型,这个服务发现相关的类型与注册中心相关的类型有点类似: + +服务发现工厂类型: +![在这里插入图片描述](/imgs/blog/source-blog/17-register5.png) +服务发现类型: +![在这里插入图片描述](/imgs/blog/source-blog/17-register6.png) + +刚刚在 ServiceDiscoveryRegistry中创建服务发现对象getServiceDiscovery方法看到了两个类型一个是服务发现工厂类型ServiceDiscoveryFactory,一个是服务发现类型ServiceDiscovery + + +```java +private ServiceDiscovery getServiceDiscovery(URL registryURL) { +//服务发现工厂对象的获取这里是ServiceDiscoveryFactory类型,这里对应ZookeeperServiceDiscoveryFactory + ServiceDiscoveryFactory factory = getExtension(registryURL); + //服务发现工厂对象获取服务发现对象 + return factory.getServiceDiscovery(registryURL); + } +``` + + AbstractServiceDiscoveryFactory类型的getServiceDiscovery方法 + +```java + @Override + public ServiceDiscovery getServiceDiscovery(URL registryURL) { + //这个key是 zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.client.ServiceDiscovery + //一个地址需要创建一个服务发现对象 + String key = registryURL.toServiceStringWithoutResolving(); + return discoveries.computeIfAbsent(key, k -> createDiscovery(registryURL)); + } +``` +createDiscovery方法对应ZookeeperServiceDiscoveryFactory类型中的createDiscovery方法 + +如下代码所示: + +```java +@Override + protected ServiceDiscovery createDiscovery(URL registryURL) { + return new ZookeeperServiceDiscovery(applicationModel, registryURL); + } + +``` + +### 17.4.1 ZookeeperServiceDiscovery +ZookeeperServiceDiscovery的构造器 +```java + public ZookeeperServiceDiscovery(ApplicationModel applicationModel, URL registryURL) { + //先调用父类AbstractServiceDiscovery 模板类构造器 + super(applicationModel, registryURL); + try { + //创建 创建CuratorFramework 类型对象用于操作Zookeeper + this.curatorFramework = buildCuratorFramework(registryURL); + //获取应用级服务发现的根路径 值为/services 这个可以在Zookeeper上面看到 + this.rootPath = ROOT_PATH.getParameterValue(registryURL); + //创建服务发现对象 实现类型为ServiceDiscoveryImpl 这个实现来源于Curator框架中的discovery模块 + this.serviceDiscovery = buildServiceDiscovery(curatorFramework, rootPath); + //启动服务发现 + this.serviceDiscovery.start(); + } catch (Exception e) { + throw new IllegalStateException("Create zookeeper service discovery failed.", e); + } + } +``` +这个方法比较重要是应用级服务发现的实现,这里主要关注下serviceDiscovery类型的创建与启动,这个应用级服务发现的实现其实是Dubbo使用了Curator来做的,Dubbo只是在这里封装了一些方法来进行调用Curator的实现: +关于Curator的官方文档可以看[curator官网](https://curator.apache.org/) + +关于Zookeeper上面注册服务应用级服务注册信息可以看如下图所示(后面会具体讲到数据注册时的调用): +![在这里插入图片描述](/imgs/blog/source-blog/17-register7.png) +我这个服务提供者注册的应用数据如下: + +```java +{ + "name" : "dubbo-demo-api-provider", + "id" : "192.168.1.9:20880", + "address" : "192.168.1.9", + "port" : 20880, + "sslPort" : null, + "payload" : { + "@class" : "org.apache.dubbo.registry.zookeeper.ZookeeperInstance", + "id" : "192.168.1.9:20880", + "name" : "dubbo-demo-api-provider", + "metadata" : { + "dubbo.endpoints" : "[{\"port\":20880,\"protocol\":\"dubbo\"}]", + "dubbo.metadata-service.url-params" : "{\"connections\":\"1\",\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"3.0.8\",\"side\":\"provider\",\"port\":\"20880\",\"protocol\":\"dubbo\"}", + "dubbo.metadata.revision" : "a662fd2213a8a49dc6ff43a4c2ae7b9e", + "dubbo.metadata.storage-type" : "local", + "timestamp" : "1654916298616" + } + }, + "registrationTimeUTC" : 1654917265499, + "serviceType" : "DYNAMIC", + "uriSpec" : null +} +``` + + +如果感兴趣的话可以看更详细的curator服务发现文档[curator-x-discovery](https://curator.apache.org/docs/service-discovery/index.html) + +### 17.4.2 AbstractServiceDiscovery的构造器 + +```java + public AbstractServiceDiscovery(ApplicationModel applicationModel, URL registryURL) { + //调用重载的构造器 + this(applicationModel.getApplicationName(), registryURL); + this.applicationModel = applicationModel; + MetadataReportInstance metadataReportInstance = applicationModel.getBeanFactory().getBean(MetadataReportInstance.class); + metadataType = metadataReportInstance.getMetadataType(); + this.metadataReport = metadataReportInstance.getMetadataReport(registryURL.getParameter(REGISTRY_CLUSTER_KEY)); +// if (REMOTE_METADATA_STORAGE_TYPE.equals(metadataReportInstance.getMetadataType())) { +// this.metadataReport = metadataReportInstance.getMetadataReport(registryURL.getParameter(REGISTRY_CLUSTER_KEY)); +// } else { +// this.metadataReport = metadataReportInstance.getNopMetadataReport(); +// } + } +``` + +重载的构造器 +```java + public AbstractServiceDiscovery(String serviceName, URL registryURL) { + this.applicationModel = ApplicationModel.defaultModel(); + //这个url参考:zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-provider&dubbo=2.0.2&interface=org.apache.dubbo.registry.client.ServiceDiscovery&pid=4570&release=3.0.8 + this.registryURL = registryURL; + //这个serviceName参考dubbo-demo-api-provider + this.serviceName = serviceName; + //MetadataInfo 用来封装元数据信息 + this.metadataInfo = new MetadataInfo(serviceName); + //这个是元数据缓存信息管理的类型 缓存文件使用LRU策略 感兴趣的可以详细看看 + //对应缓存路径为:/Users/song/.dubbo/.metadata.zookeeper127.0.0.1%003a2181.dubbo.cache + this.metaCacheManager = new MetaCacheManager(getCacheNameSuffix(), + applicationModel.getFrameworkModel().getBeanFactory() + .getBean(FrameworkExecutorRepository.class).getCacheRefreshingScheduledExecutor()); + } +``` + +## 17.5 服务映射类型AbstractServiceNameMapping +服务映射主要是通过服务名字来反查应用信息的应用名字如下图所示 +![在这里插入图片描述](/imgs/blog/source-blog/17-register8.png) +这里我们来看下服务映射相关的类型主要通过如下代码来获取扩展对象: + +```java +this.serviceNameMapping = (AbstractServiceNameMapping) ServiceNameMapping.getDefaultExtension(registryURL.getScopeModel()); +``` +对应类型如下: +![在这里插入图片描述](/imgs/blog/source-blog/17-register9.png) + +最终获取的扩展实现类型为:MetadataServiceNameMapping +构造器如下: + +```java + public MetadataServiceNameMapping(ApplicationModel applicationModel) { + super(applicationModel); + metadataReportInstance = applicationModel.getBeanFactory().getBean(MetadataReportInstance.class); + } +``` + +服务映射元数据父类型AbstractServiceNameMapping如下: + +```java + public AbstractServiceNameMapping(ApplicationModel applicationModel) { + this.applicationModel = applicationModel; + //LRU缓存保存服务映射数据 + this.mappingCacheManager = new MappingCacheManager("", + applicationModel.getFrameworkModel().getBeanFactory() + .getBean(FrameworkExecutorRepository.class).getCacheRefreshingScheduledExecutor()); + } + +``` + +## 17.4 双注册元数据信息发布到注册中心 +### 17.4.1 回顾简介 +前面注册数据的时候并没有把服务配置的元数据直接注册在注册中心而是需要在导出服务之后在ServiceConfig中来发布元数据,这个就需要我们回到ServiceConfig的exportUrl方法来看了如下所示: + +```java +private void exportUrl(URL url, List registryURLs) { + String scope = url.getParameter(SCOPE_KEY); + // don't export when none is configured + ...省略到若干代码 + if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) { + url = exportRemote(url, registryURLs); + if (!isGeneric(generic) && !getScopeModel().isInternal()) { + MetadataUtils.publishServiceDefinition(url, providerModel.getServiceModel(), getApplicationModel()); + } + } + } + this.urls.add(url); + } +``` + +### 17.4.2 元数据服务定义数据的发布 + +在exportRemote之后单独调用发布元数据的方法来发布,通过调用元数据工具类来发布元数据信息接下来我们详细看下: +MetadataUtils类型的publishServiceDefinition方法: + +```java +public static void publishServiceDefinition(URL url, ServiceDescriptor serviceDescriptor, ApplicationModel applicationModel) { + //查询是否存在元数据存储对象 对应接口MetadataReport 这里对应实现类 ZookeeperMetadataReport + if (getMetadataReports(applicationModel).size() == 0) { + String msg = "Remote Metadata Report Server is not provided or unavailable, will stop registering service definition to remote center!"; + logger.warn(msg); + } + + try { + String side = url.getSide(); + //服务提供者走这个逻辑 + if (PROVIDER_SIDE.equalsIgnoreCase(side)) { + String serviceKey = url.getServiceKey(); + //获取当前服务元数据信息 + FullServiceDefinition serviceDefinition = serviceDescriptor.getFullServiceDefinition(serviceKey); + + if (StringUtils.isNotEmpty(serviceKey) && serviceDefinition != null) { + serviceDefinition.setParameters(url.getParameters()); + for (Map.Entry entry : getMetadataReports(applicationModel).entrySet()) { + MetadataReport metadataReport = entry.getValue(); + if (!metadataReport.shouldReportDefinition()) { + logger.info("Report of service definition is disabled for " + entry.getKey()); + continue; + } + //存储服务提供者的元数据 metadataReport类型为ZookeeperMetadataReport 方法来源于父类模板方法: AbstractMetadataReport类型的storeProviderMetadata模板方法 + metadataReport.storeProviderMetadata( + new MetadataIdentifier( + url.getServiceInterface(), + url.getVersion() == null ? "" : url.getVersion(), + url.getGroup() == null ? "" : url.getGroup(), + PROVIDER_SIDE, + applicationModel.getApplicationName()) + , serviceDefinition); + } + } + } else { + //服务消费者走这个逻辑 + for (Map.Entry entry : getMetadataReports(applicationModel).entrySet()) { + MetadataReport metadataReport = entry.getValue(); + if (!metadataReport.shouldReportDefinition()) { + logger.info("Report of service definition is disabled for " + entry.getKey()); + continue; + } + metadataReport.storeConsumerMetadata( + new MetadataIdentifier( + url.getServiceInterface(), + url.getVersion() == null ? "" : url.getVersion(), + url.getGroup() == null ? "" : url.getGroup(), + CONSUMER_SIDE, + applicationModel.getApplicationName()), + url.getParameters()); + } + } + } catch (Exception e) { + //ignore error + logger.error("publish service definition metadata error.", e); + } + } +``` + +AbstractMetadataReport的storeProviderMetadata方法如下所示: + +```java + @Override + public void storeProviderMetadata(MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition) { + //是否同步配置对应sync-report 默认为异步 + if (syncReport) { + storeProviderMetadataTask(providerMetadataIdentifier, serviceDefinition); + } else { + reportCacheExecutor.execute(() -> storeProviderMetadataTask(providerMetadataIdentifier, serviceDefinition)); + } + } +``` + + +AbstractMetadataReport的存储元数据方法storeProviderMetadataTask + +```java +private void storeProviderMetadataTask(MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition) { + try { + if (logger.isInfoEnabled()) { + logger.info("store provider metadata. Identifier : " + providerMetadataIdentifier + "; definition: " + serviceDefinition); + } + allMetadataReports.put(providerMetadataIdentifier, serviceDefinition); + failedReports.remove(providerMetadataIdentifier); + Gson gson = new Gson(); + String data = gson.toJson(serviceDefinition); + doStoreProviderMetadata(providerMetadataIdentifier, data); + saveProperties(providerMetadataIdentifier, data, true, !syncReport); + } catch (Exception e) { + // retry again. If failed again, throw exception. + failedReports.put(providerMetadataIdentifier, serviceDefinition); + metadataReportRetry.startRetryTask(); + logger.error("Failed to put provider metadata " + providerMetadataIdentifier + " in " + serviceDefinition + ", cause: " + e.getMessage(), e); + } + } +``` + +![在这里插入图片描述](/imgs/blog/source-blog/17-register10.png) + +元数据信息如下:可以分为两类 应用元数据,服务元数据 + +```json +{ + "parameters": { + "side": "provider", + "interface": "link.elastic.dubbo.entity.DemoService", + "pid": "22099", + "application": "dubbo-demo-api-provider", + "dubbo": "2.0.2", + "release": "3.0.8", + "anyhost": "true", + "bind.ip": "192.168.1.9", + "methods": "sayHello,sayHelloAsync", + "background": "false", + "deprecated": "false", + "dynamic": "true", + "service-name-mapping": "true", + "generic": "false", + "bind.port": "20880", + "timestamp": "1654942353902" + }, + "canonicalName": "link.elastic.dubbo.entity.DemoService", + "codeSource": "file:/Users/song/Desktop/dubbo-test/target/classes/", + "methods": [{ + "name": "sayHelloAsync", + "parameterTypes": ["java.lang.String"], + "returnType": "java.util.concurrent.CompletableFuture", + "annotations": [] + }, { + "name": "sayHello", + "parameterTypes": ["java.lang.String"], + "returnType": "java.lang.String", + "annotations": [] + }], + "types": [{ + "type": "java.util.concurrent.CompletableFuture", + "properties": { + "result": "java.lang.Object", + "stack": "java.util.concurrent.CompletableFuture.Completion" + } + }, { + "type": "java.lang.Object" + }, { + "type": "java.lang.String" + }, { + "type": "java.util.concurrent.CompletableFuture.Completion", + "properties": { + "next": "java.util.concurrent.CompletableFuture.Completion", + "status": "int" + } + }, { + "type": "int" + }], + "annotations": [] +} +``` +Zookeeper扩展类型ZookeeperMetadataReport实现的存储方法如下所示doStoreProviderMetadata: + +如果我们自己实现一套元数据就可以重写这个方法来进行元数据的额存储 + +ZookeeperMetadataReport的doStoreProviderMetadata +```java + @Override + protected void doStoreProviderMetadata(MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) { + storeMetadata(providerMetadataIdentifier, serviceDefinitions); + } +``` + +ZookeeperMetadataReport的storeMetadata +```java + private void storeMetadata(MetadataIdentifier metadataIdentifier, String v) { + //参数false为非临时节点,这个元数据为持久节点,这个细节就暂时不看了就是将刚刚的json元数据存储到对应路径上面:路径为:/dubbo/metadata/link.elastic.dubbo.entity.DemoService/provider/dubbo-demo-api-provider + zkClient.create(getNodePath(metadataIdentifier), v, false); + } + +``` + +原文地址:[17-Dubbo服务提供者的双注册原理](https://blog.elastic.link/2022/07/10/dubbo/17-dubbo3-ying-yong-ji-zhu-ce-zhi-fu-wu-ti-gong-zhe-de-shuang-zhu-ce-yuan-li/) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/18-Dubbo3\345\205\203\346\225\260\346\215\256\346\234\215\345\212\241MetadataService\347\232\204\345\257\274\345\207\272.md" "b/content/en/blog/java/codeanalysis/3.0.8/18-Dubbo3\345\205\203\346\225\260\346\215\256\346\234\215\345\212\241MetadataService\347\232\204\345\257\274\345\207\272.md" new file mode 100644 index 000000000000..efcba2198491 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/18-Dubbo3\345\205\203\346\225\260\346\215\256\346\234\215\345\212\241MetadataService\347\232\204\345\257\274\345\207\272.md" @@ -0,0 +1,637 @@ +--- +title: "18-Dubbo3元数据服务MetadataService的导出" +linkTitle: "18-Dubbo3元数据服务MetadataService的导出" +date: 2022-08-18 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] 使用者查询提供者的元数据信息,以列出接口和每个接口的配置,控制台(dubbo admin)查询特定进程的元数据,或聚合所有进程的数据。在Dubbo2.x的时候,所有的服务数据都是以接口的形式注册在注册中心。 +--- + +# 18-Dubbo3元数据服务MetadataService的导出 + +## 18.1 简介 +MetadataService +此服务用于公开Dubbo进程内的元数据信息。典型用途包括: +- 使用者查询提供者的元数据信息,以列出接口和每个接口的配置 +- 控制台(dubbo admin)查询特定进程的元数据,或聚合所有进程的数据。在Dubbo2.x的时候,所有的服务数据都是以接口的形式注册在注册中心. + +Dubbo3将部分数据抽象为元数据的形式来将数据存放在元数据中心,然后元数据由服务提供者提供给消费者而不是再由注册中心进行推送,如下图所示: + +![在这里插入图片描述](/imgs/blog/source-blog/18-metadata.png) + +![在这里插入图片描述](/imgs/blog/source-blog/18-metadata3.png) +引入 MetadataService 元数据服务服务的好处 +• 由中心化推送转向点对点拉取(Consumer - Proroder) +• 易于扩展更多的参数 +• 更多的数据量 +• 对外暴露更多的治理数据 + +## 18.2 MetadataService的导出过程 +了解元数据的到处过程,这个就要继续前面博客往后的代码了前面博客说了一个服务发布之后的服务信息的双注册数据,这里继续看下导出服务之后的代码: +先来简单回顾下模块发布的启动生命周期方法: + +DefaultModuleDeployer类型的start方法: + +```java + @Override + public synchronized Future start() throws IllegalStateException { + ... + + try { + ... + onModuleStarting(); + + // initialize + applicationDeployer.initialize(); + initialize(); + + // export services + exportServices(); + + // prepare application instance + // exclude internal module to avoid wait itself + if (moduleModel != moduleModel.getApplicationModel().getInternalModule()) { + applicationDeployer.prepareInternalModule(); + } + + // refer services + referServices(); + + // if no async export/refer services, just set started + if (asyncExportingFutures.isEmpty() && asyncReferringFutures.isEmpty()) { + onModuleStarted(); + } else { + .... + return startFuture; + } +``` + +前面的博客我们已经说了服务提供者导出服务的方法如下: + +```java + // export services + exportServices(); +``` + +在导出服务之后如果代码中配置了引用服务的代码将会执行引用服务的功能,调用代码如下: + +```java +referServices(); +``` + +不过我们样例代码并没有介绍引用服务的功能,这里先不说,等服务提供者完全启动成功之后我们再来看消费者的逻辑。 + +接下来我们要看的是模块启动成功之后的方法 onModuleStarted();,在这个方法中会去发布服务元数据信息。 + +## 18.3 模块启动成功时候的逻辑 onModuleStarted(); + +这里我们直接先看代码再来分析下逻辑: + +DefaultModuleDeployer类型的onModuleStarted方法如下所示: +```java + private void onModuleStarted() { + try { + //状态判断是否为启动中如果是则将状态设置为STARTED + if (isStarting()) { + //先修改状态 + setStarted(); + logger.info(getIdentifier() + " has started."); + //状态修改成功之后开始通知应用程序发布器模块发布器启动成功了 + applicationDeployer.notifyModuleChanged(moduleModel, DeployState.STARTED); + } + } finally { + // complete module start future after application state changed + completeStartFuture(true); + } + } +``` + + + +应用程序发布器处理启动成功的逻辑: +DefaultApplicationDeployer类型的notifyModuleChanged方法: + +```java + @Override + public void notifyModuleChanged(ModuleModel moduleModel, DeployState state) { + //根据所有模块的状态来判断应用发布器的状态 + checkState(moduleModel, state); + + // notify module state changed or module changed + //通知所有模块状态更新 + synchronized (stateLock) { + stateLock.notifyAll(); + } + } +``` +应用发布器模型DefaultApplicationDeployer检查状态方法checkState代码如下: + +```java + @Override + public void checkState(ModuleModel moduleModel, DeployState moduleState) { + //存在写操作 先加个锁 + synchronized (stateLock) { + //非内部模块,并且模块的状态是发布成功了 + if (!moduleModel.isInternal() && moduleState == DeployState.STARTED) { + + prepareApplicationInstance(); + } + //应用下所有模块状态进行汇总计算 + DeployState newState = calculateState(); + switch (newState) { + case STARTED: + onStarted(); + break; + case STARTING: + onStarting(); + break; + case STOPPING: + onStopping(); + break; + case STOPPED: + onStopped(); + break; + case FAILED: + Throwable error = null; + ModuleModel errorModule = null; + for (ModuleModel module : applicationModel.getModuleModels()) { + ModuleDeployer deployer = module.getDeployer(); + if (deployer.isFailed() && deployer.getError() != null) { + error = deployer.getError(); + errorModule = module; + break; + } + } + onFailed(getIdentifier() + " found failed module: " + errorModule.getDesc(), error); + break; + case PENDING: + // cannot change to pending from other state + // setPending(); + break; + } + } + } +``` + +## 18.4 准备发布元数据信息和应用实例信息 +前面有个代码调用比较重要: + +```java +prepareApplicationInstance() +``` + + + +DefaultApplicationDeployer类型的prepareApplicationInstance方法如下所示 +```java + @Override + public void prepareApplicationInstance() { + //已经注册过应用实例数据了 直接返回 (下面CAS逻辑判断了) + if (hasPreparedApplicationInstance.get()) { + return; + } + //注册开关控制默认为true + //通过将registerConsumer默认设置为“false”来关闭纯使用者进程实例的注册。 + if (isRegisterConsumerInstance()) { + exportMetadataService(); + if (hasPreparedApplicationInstance.compareAndSet(false, true)) { + // register the local ServiceInstance if required + registerServiceInstance(); + } + } + } +``` + + + +### 18.4.1 导出元数据服务方法exportMetadataService + + 这里我们就先直接来贴一下代码: + +DefaultApplicationDeployer类型的exportMetadataService方法如下所示: +```java + private void exportMetadataService() { + if (!isStarting()) { + return; + } + //这里监听器我们主要关注的类型是ExporterDeployListener类型 + for (DeployListener listener : listeners) { + try { + if (listener instanceof ApplicationDeployListener) { + // 回调监听器的模块启动成功方法 + ((ApplicationDeployListener) listener).onModuleStarted(applicationModel); + } + } catch (Throwable e) { + logger.error(getIdentifier() + " an exception occurred when handle starting event", e); + } + } + } +``` + +前面我们主要关注ExporterDeployListener类型的监听器的回调方法,这里我贴一下代码: +ExporterDeployListener类型的onModuleStarted方法如下: + +```java + @Override + public synchronized void onModuleStarted(ApplicationModel applicationModel) { + // start metadata service exporter + //MetadataServiceDelegation类型为实现提供远程RPC服务以方便元数据信息的查询功能的类型。 + MetadataServiceDelegation metadataService = applicationModel.getBeanFactory().getOrRegisterBean(MetadataServiceDelegation.class); + if (metadataServiceExporter == null) { + metadataServiceExporter = new ConfigurableMetadataServiceExporter(applicationModel, metadataService); + // fixme, let's disable local metadata service export at this moment + //默认我们是没有配置这个元数据类型的这里元数据类型默认为local 条件是不是remote则开始导出,在前面的博客<> 中有提到这个配置下面我再说下 + if (!REMOTE_METADATA_STORAGE_TYPE.equals(getMetadataType(applicationModel))) { + metadataServiceExporter.export(); + } + } + } +``` + +在前面的博客[<>](https://blog.elastic.link/2022/07/10/dubbo/9-dubbo-qi-dong-qi-dubbobootstrap-tian-jia-ying-yong-cheng-xu-de-pei-zhi-xin-xi-applicationconfig/) 中有提到这个配置下面我再说下 + +metadata-type + + +metadata 传递方式,是以 Provider 视角而言的,Consumer 侧配置无效,可选值有: +- remote - Provider 把 metadata 放到远端**注册中心**,Consumer 从**注册中心获取**。 +- local - Provider **把 metadata 放在本地**,**Consumer 从 Provider 处直接获取** 。 + +可以看到默认的local配置元数据信息的获取是由消费者从提供者拉的,那提供者怎么拉取对应服务的元数据信息那就要要用到这个博客说到的MetadataService服务,传递方式为remote的方式其实就要依赖注册中心了相对来说增加了注册中心的压力。 + + + +### 18.4.2 可配置元数据服务的导出ConfigurableMetadataServiceExporter的export +前面了解了导出服务的调用链路,这里详细看下ConfigurableMetadataServiceExporter的export过程源码如下所示: + +```java +public synchronized ConfigurableMetadataServiceExporter export() { + //元数据服务配置已经存在或者已经导出或者不可导出情况下是无需导出的 + if (serviceConfig == null || !isExported()) { + //创建服务配置 + this.serviceConfig = buildServiceConfig(); + // export + //导出服务 ,导出服务的具体过程这里就不再说了可以看上一个博客,这个导出服务的过程会绑定端口 + serviceConfig.export(); + metadataService.setMetadataURL(serviceConfig.getExportedUrls().get(0)); + if (logger.isInfoEnabled()) { + logger.info("The MetadataService exports urls : " + serviceConfig.getExportedUrls()); + } + } else { + if (logger.isWarnEnabled()) { + logger.warn("The MetadataService has been exported : " + serviceConfig.getExportedUrls()); + } + } + + return this; + } +``` + + +### 18.4.3 元数据服务配置对象的创建 +前面我们看到了构建元数据服务对象的代码调用ServiceConfig,接下来我们详细看下构建源码如下所示: +ConfigurableMetadataServiceExporter类型的buildServiceConfig构建元数据服务配置对象方法如下: + +```java + private ServiceConfig buildServiceConfig() { + //1 获取当前的应用配置 然后初始化应用配置 + ApplicationConfig applicationConfig = getApplicationConfig(); + //创建服务配置对象 + ServiceConfig serviceConfig = new ServiceConfig<>(); + //设置域模型 + serviceConfig.setScopeModel(applicationModel.getInternalModule()); + serviceConfig.setApplication(applicationConfig); + + //2 创建注册中心配置对象 然后并初始化 + RegistryConfig registryConfig = new RegistryConfig("N/A"); + registryConfig.setId("internal-metadata-registry"); + + //3 创建服务配置对象,并初始化 + serviceConfig.setRegistry(registryConfig); + serviceConfig.setRegister(false); + //4 生成协议配置 ,这里会配置一下元数据使用的服务端口号默认使用其他服务的端口20880 + serviceConfig.setProtocol(generateMetadataProtocol()); + serviceConfig.setInterface(MetadataService.class); + serviceConfig.setDelay(0); + //这里也是需要注意的地方服务引用的类型为MetadataServiceDelegation + serviceConfig.setRef(metadataService); + serviceConfig.setGroup(applicationConfig.getName()); + serviceConfig.setVersion(MetadataService.VERSION); + //5 生成方法配置 这里目前提供的服务方法为getAndListenInstanceMetadata方法 后续可以看下这个方法的视线 + serviceConfig.setMethods(generateMethodConfig()); + serviceConfig.setConnections(1); // separate connection + serviceConfig.setExecutes(100); // max tasks running at the same time + + return serviceConfig; + } + +``` + + +这个服务配置对象的创建非常像我们第一个博客提到的服务配置过程,不过这个元数据服务对象有几个比较特殊的配置 +- 注册中心的配置register设置为了false 则为不向注册中心注册具体的服务配置信息 +- 对每个提供者的最大连接数connections为1 +- 服务提供者每服务每方法最大可并行执行请求数executes为100 + +在使用过程中可以知道上面这几个配置值 + +## 18.5 应用级数据注册 registerServiceInstance() +在前面导出元数据服务之后也会调用一行代码来注册应用级数据来保证应用上线 + +主要涉及到的代码为DefaultApplicationDeployer类型中的registerServiceInstance方法如下所示 +```java + private void registerServiceInstance() { + try { + //标记变量设置为true + registered = true; + ServiceInstanceMetadataUtils.registerMetadataAndInstance(applicationModel); + } catch (Exception e) { + logger.error("Register instance error", e); + } + if (registered) { + // scheduled task for updating Metadata and ServiceInstance + asyncMetadataFuture = frameworkExecutorRepository.getSharedScheduledExecutor().scheduleWithFixedDelay(() -> { + + // ignore refresh metadata on stopping + if (applicationModel.isDestroyed()) { + return; + } + try { + if (!applicationModel.isDestroyed() && registered) { + ServiceInstanceMetadataUtils.refreshMetadataAndInstance(applicationModel); + } + } catch (Exception e) { + if (!applicationModel.isDestroyed()) { + logger.error("Refresh instance and metadata error", e); + } + } + }, 0, ConfigurationUtils.get(applicationModel, METADATA_PUBLISH_DELAY_KEY, DEFAULT_METADATA_PUBLISH_DELAY), TimeUnit.MILLISECONDS); + } + } + +``` + +这个方法先将应用元数据注册到注册中心,然后开始开启定时器每隔30秒同步一次元数据向注册中心。 + +### 18.5.1 服务实例元数据工具类注册服务发现的元数据信息 +前面通过调用类型ServiceInstanceMetadataUtils工具类的registerMetadataAndInstance方法来进行服务实例数据和元数据的注册这里我们详细看下代码如下所示: + +```java + public static void registerMetadataAndInstance(ApplicationModel applicationModel) { + LOGGER.info("Start registering instance address to registry."); + RegistryManager registryManager = applicationModel.getBeanFactory().getBean(RegistryManager.class); + // register service instance +//注意这里服务发现的类型只有ServiceDiscoveryRegistry类型的注册协议才满足 registryManager.getServiceDiscoveries().forEach(ServiceDiscovery::register); + } +``` + + +### 18.5.2 AbstractServiceDiscovery中的服务发现数据注册的模版方法 + +AbstractServiceDiscovery类型的注册方法register()方法这个是一个模版方法,真正执行的注册逻辑封装在了doRegister方法中由扩展的服务发现子类来完成 +```java + @Override + public synchronized void register() throws RuntimeException { + //第一步创建应用的实例信息等待下面注册到注册中心 + this.serviceInstance = createServiceInstance(this.metadataInfo); + if (!isValidInstance(this.serviceInstance)) { + logger.warn("No valid instance found, stop registering instance address to registry."); + return; + } + + //是否需要更新 + boolean revisionUpdated = calOrUpdateInstanceRevision(this.serviceInstance); + if (revisionUpdated) { + reportMetadata(this.metadataInfo); + //应用的实例信息注册到注册中心之上 ,这个 + doRegister(this.serviceInstance); + } + } +``` + +### 18.5.3 应用级实例对象创建 +可以看到在AbstractServiceDiscovery服务发现的第一步创建应用的实例信息等待下面注册到注册中心 + +```java +this.serviceInstance = createServiceInstance(this.metadataInfo); +``` +最终创建的serviceInstance类型为ServiceInstance 这个是Dubbo封装的一个接口,具体实现类型为DefaultServiceInstance,我们可以看下应用级的元数据有哪些 + +```java + protected ServiceInstance createServiceInstance(MetadataInfo metadataInfo) { + //这里的服务名字为:dubbo-demo-api-provider + DefaultServiceInstance instance = new DefaultServiceInstance(serviceName, applicationModel); + //应用服务的元数据 ,可以看下面debug的数据信息 + instance.setServiceMetadata(metadataInfo); + //metadataType的值为local 这个方法是将元数据类型存储到英勇的元数据对象中 对应内容为dubbo.metadata.storage-type:local + setMetadataStorageType(instance, metadataType); + // 这个是自定义元数据数据 我们也可以通过实现扩展ServiceInstanceCustomizer来自定义一些元数据 + ServiceInstanceMetadataUtils.customizeInstance(instance, applicationModel); + return instance; + } + +``` + +这个方法的主要目的就是将应用的元数据信息都封装到ServiceInstance类型中,不过额外提供了一个扩展性比较好的方法可以自定义元数据信息 + +前面的metadataInfo对象的信息如下图所示: +![在这里插入图片描述](/imgs/blog/source-blog/18-metadata2.png) + + +自定义元数据类型Dubbo官方提供了一个默认的实现类型为:ServiceInstanceMetadataCustomizer + +最终封装好的元数据信息如下所示: + +```java +DefaultServiceInstance{ +serviceName='dubbo-demo-api-provider', +host='192.168.1.169', +port=20880, +enabled=true, +healthy=true, + metadata={ + dubbo.metadata-service.url-params={"connections":"1", + "version":"1.0.0", + "dubbo":"2.0.2", + "release":"3.0.9", + "side":"provider", + "port":"20880", + "protocol":"dubbo" + }, + dubbo.endpoints=[ + {"port":20880,"protocol":"dubbo"}], + dubbo.metadata.storage-type=local, + timestamp=1656227493387}} +``` + + + +### 18.5.4 应用级实例数据配置变更的的版本号获取 +前面创建元应用的实例信息后开始创建版本号来判断是否需要更新,对应AbstractServiceDiscovery类型的calOrUpdateInstanceRevision +```java + protected boolean calOrUpdateInstanceRevision(ServiceInstance instance) { + //获取元数据版本号对应字段dubbo.metadata.revision + String existingInstanceRevision = getExportedServicesRevision(instance); + //获取实例的服务元数据信息:metadata{app='dubbo-demo-api-provider',revision='null',size=1,services=[link.elastic.dubbo.entity.DemoService:dubbo]} + MetadataInfo metadataInfo = instance.getServiceMetadata(); + //必须在不同线程之间同步计算此实例的状态,如同一实例的修订和修改。此方法的使用仅限于某些点,例如在注册期间。始终尝试使用此选项。改为getRevision()。 + String newRevision = metadataInfo.calAndGetRevision(); + //版本号发生了变更(元数据发生了变更)版本号是md5元数据信息计算出来HASH验证 + if (!newRevision.equals(existingInstanceRevision)) { + //版本号添加到dubbo.metadata.revision字段中 + instance.getMetadata().put(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, metadataInfo.getRevision()); + return true; + } + return false; + } +``` + + + + +#### 18.5.4.1 元数据版本号的计算与HASH校验 calAndGetRevision +这个方法其实比较重要,决定了什么时候会更新元数据,Dubbo使用了一种Hash验证的方式将元数据转MD5值与之前的存在的版本号(也是元数据转MD5得到的) 如果数据发生了变更则MD5值会发生变化 以此来更新元数据,不过发生了MD5冲突的话就会导致配置不更新这个冲突的概率非常小。 +好了直接来看代码吧: +MetadataInfo类型的calAndGetRevision方法: + +```java +public synchronized String calAndGetRevision() { + if (revision != null && !updated) { + return revision; + } + + updated = false; + //应用下没有服务则使用一个空的版本号 + if (CollectionUtils.isEmptyMap(services)) { + this.revision = EMPTY_REVISION; + } else { + StringBuilder sb = new StringBuilder(); + //app是应用名 + sb.append(app); + for (Map.Entry entry : new TreeMap<>(services).entrySet()) { + sb.append(entry.getValue().toDescString()); + } + String tempRevision = RevisionResolver.calRevision(sb.toString()); + if (!StringUtils.isEquals(this.revision, tempRevision)) { + //元数据重新注册的话我们可以看看这个日志metadata revision change + if (logger.isInfoEnabled()) { + logger.info(String.format("metadata revision changed: %s -> %s, app: %s, services: %d", this.revision, tempRevision, this.app, this.services.size())); + } + this.revision = tempRevision; + this.rawMetadataInfo = JsonUtils.getJson().toJson(this); + } + } + return revision; + } +``` + +RevisionResolver类型的Md5运算计算版本号 +```java +md5Utils.getMd5(metadata); +``` + + + +### 18.5.5 reportMetadata +回到18.5.2 AbstractServiceDiscovery中的模版方法register,这里我们来看下reportMetadata方法,不过这个方法目前并不会走到,因为我们默认的配置元数据是local不会直接把应用的元数据注册在元数据中心 + +```java + protected void reportMetadata(MetadataInfo metadataInfo) { + if (metadataReport != null) { + //订阅元数据的标识符 + SubscriberMetadataIdentifier identifier = new SubscriberMetadataIdentifier(serviceName, metadataInfo.getRevision()); + //是否远程发布元数据,这里我们是本地注册这个就不会在元数据中心发布这个元数据信息 + if ((DEFAULT_METADATA_STORAGE_TYPE.equals(metadataType) && metadataReport.shouldReportMetadata()) || REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) { + metadataReport.publishAppMetadata(identifier, metadataInfo); + } + } + } +``` + +### 18.5.6 扩展的注册中心来注册应用级服务发现数据doRegister方法 +前面我们说了AbstractServiceDiscovery中的模版方法register,在register会调用一个doRegister方法来注册应用级数据,这个方法是需要扩展注册中心的服务发现来自行实现的,我们这里以官方实现的Zookeeper服务发现模型为例: + +ZookeeperServiceDiscovery中的doRegister方法 + +```java + @Override + public void doRegister(ServiceInstance serviceInstance) { + try { + //Dubbo实现的ServiceInstance类型对象转 Curator的ServiceInstance + serviceDiscovery.registerService(build(serviceInstance)); + } catch (Exception e) { + throw new RpcException(REGISTRY_EXCEPTION, "Failed register instance " + serviceInstance.toString(), e); + } + } +``` +前面我们介绍了ZookeeperServiceDiscovery发现的构造器连接注册中心,这里来看下服务注册, +应用级实例数据注册一共分为两步 +第一步是:Dubbo实现的ServiceInstance类型对象转 Curator的ServiceInstance +第二步是:执行registerService方法将数据注册到注册中心 + + +先来看第一步:Dubbo实现的ServiceInstance类型对象转 Curator的ServiceInstance +关于Curator的服务发现原理可以参考官网的文章博客[curator-x-discovery](https://curator.apache.org/docs/service-discovery/index.html) + + +**什么是发现服务?** +在 SOA/分布式系统中,服务需要找到彼此。即,Web 服务可能需要找到缓存服务等。DNS 可以用于此,但对于不断变化的服务来说,它远不够灵活。服务发现系统提供了一种机制: + +- 注册其可用性的服务 +- 定位特定服务的单个实例 +- 在服务实例更改时通知 + + +服务实例由类表示:ServiceInstance。ServiceInstances 具有名称、id、地址、端口和/或 ssl 端口,以及可选的有效负载(用户定义)。ServiceInstances 通过以下方式序列化并存储在 ZooKeeper 中: + + +```java +base path + |_______ service A name + |__________ instance 1 id --> (serialized ServiceInstance) + |__________ instance 2 id --> (serialized ServiceInstance) + |__________ ... + |_______ service B name + |__________ instance 1 id --> (serialized ServiceInstance) + |__________ instance 2 id --> (serialized ServiceInstance) + |__________ ... + |_______ ... +``` + +这个应用最终注册应用级服务数据如下: +![在这里插入图片描述](/imgs/blog/source-blog/18-metadata4.png) +这里需要注意的是这个 应用的IP+端口的服务元数据信息是临时节点 +build方法内容对应着上图的JSON数据 可以看菜build方法封装的过程: + +```java +public static org.apache.curator.x.discovery.ServiceInstance build(ServiceInstance serviceInstance) { + ServiceInstanceBuilder builder; + + String serviceName = serviceInstance.getServiceName(); + String host = serviceInstance.getHost(); + int port = serviceInstance.getPort(); + Map metadata = serviceInstance.getSortedMetadata(); + String id = generateId(host, port); + //ZookeeperInstance是Dubbo封装的用于存放payload数据 包含服务id,服务名字和元数据 + ZookeeperInstance zookeeperInstance = new ZookeeperInstance(id, serviceName, metadata); + try { + builder = builder() + .id(id) + .name(serviceName) + .address(host) + .port(port) + .payload(zookeeperInstance); + } catch (Exception e) { + throw new RuntimeException(e); + } + return builder.build(); + } + +``` + +在《18.5 应用级数据注册 registerServiceInstance() 》 小节中介绍了应用元数据信息的注册调用代码,其实后面还有个update的逻辑定期30秒同步元数据到元数据中心,这里就不详细介绍了。 + + + +原文地址:[18-Dubbo3元数据服务MetadataService的导出](https://blog.elastic.link/2022/07/10/dubbo/18-dubbo3-yuan-shu-ju-fu-wu-metadataservice-de-dao-chu/) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/19-\351\207\215\346\226\260\346\235\245\350\277\207\344\273\216\344\270\200\344\270\252\346\234\215\345\212\241\346\266\210\350\264\271\350\200\205\347\232\204Demo\350\257\264\350\265\267.md" "b/content/en/blog/java/codeanalysis/3.0.8/19-\351\207\215\346\226\260\346\235\245\350\277\207\344\273\216\344\270\200\344\270\252\346\234\215\345\212\241\346\266\210\350\264\271\350\200\205\347\232\204Demo\350\257\264\350\265\267.md" new file mode 100644 index 000000000000..39e8a192ea20 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/19-\351\207\215\346\226\260\346\235\245\350\277\207\344\273\216\344\270\200\344\270\252\346\234\215\345\212\241\346\266\210\350\264\271\350\200\205\347\232\204Demo\350\257\264\350\265\267.md" @@ -0,0 +1,142 @@ +--- +title: "19 重新来过从一个服务消费者的Demo说起" +linkTitle: "19 重新来过从一个服务消费者的Demo说起" +date: 2022-08-19 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] 重新来过从一个服务消费者的Demo说起。 +--- +# 19 重新来过从一个服务消费者的Demo说起 + +为了更方便了解原理,我们先来编写一个Demo,从例子中来看源码实现:,前面说了提供者现在已经有服务注册上去了,那接下来我们编写一个消费者的例子来进行服务发现与服务RPC调用。 + +## 19.1 启动Zookeeper + +为了Demo可以正常启动,需要我们先在本地启动一个Zookeeper如下图所示: +![在这里插入图片描述](/imgs/blog/source-blog/19-zk.png) + + +## 19.2 服务消费者 +接下来给大家贴一下示例源码,这个源码来源于Dubbo源码目录的 dubbo-demo/dubbo-demo-api 目录下面的dubbo-demo-api-consumer子项目,这里我做了删减,方便看核心代码: +首先我们定义一个服务接口如下所示: + +```java +import java.util.concurrent.CompletableFuture; +public interface DemoService { + /** + * 同步处理的服务方法 + * @param name + * @return + */ + String sayHello(String name); + + /** + * 用于异步处理的服务方法 + * @param name + * @return + */ + default CompletableFuture sayHelloAsync(String name) { + return CompletableFuture.completedFuture(sayHello(name)); + } +} + +服务实现类如下: + +import org.apache.dubbo.rpc.RpcContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.CompletableFuture; + +public class DemoServiceImpl implements DemoService { + private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class); + + @Override + public String sayHello(String name) { + logger.info("Hello " + name + ", request from consumer: " + RpcContext.getServiceContext().getRemoteAddress()); + return "Hello " + name + ", response from provider: " + RpcContext.getServiceContext().getLocalAddress(); + } + + @Override + public CompletableFuture sayHelloAsync(String name) { + return null; + } + +} +``` + +## 19.3 启用服务消费者 +有了服务接口之后我们来启用服务,启用服务的源码如下: +这里如果要启动消费者,主要要修改QOS端口这里我已经配置可以直接复用 +```java + +package link.elastic.dubbo.consumer; + +import link.elastic.dubbo.entity.DemoService; +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.MetadataReportConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.ReferenceConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.bootstrap.DubboBootstrap; +import org.apache.dubbo.rpc.service.GenericService; + +public class ConsumerApplication { + public static void main(String[] args) { + runWithBootstrap(); + } + private static void runWithBootstrap() { + ReferenceConfig reference = new ReferenceConfig<>(); + reference.setInterface(DemoService.class); + reference.setGeneric("true"); + reference.setProtocol(""); + + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-demo-api-consumer"); + applicationConfig.setQosEnable(false); + applicationConfig.setQosPort(-1); + bootstrap.application(applicationConfig) + .registry(new RegistryConfig("zookeeper://8.131.79.126:2181")) + .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) + .reference(reference) + .start(); + + DemoService demoService = bootstrap.getCache().get(reference); + String message = demoService.sayHello("dubbo"); + System.out.println(message); + + // generic invoke + GenericService genericService = (GenericService) demoService; + Object genericInvokeResult = genericService.$invoke("sayHello", new String[]{String.class.getName()}, + new Object[]{"dubbo generic invoke"}); + System.out.println(genericInvokeResult); + } +} + +``` + +## 1.4 启用服务后写入Zookeeper的节点数据 +启动服务,这个时候我们打开Zookeeper图形化客户端来看看这个服务在Zookeeper上面写入来哪些数据,如下图: +在这里插入图片描述 +![在这里插入图片描述](/imgs/blog/source-blog/19-zk2.png) + +写入Zookeper上的节点用于服务在分布式场景下的协调,这些节点是比较重要的。 + +如果了解过Dubbo的同学,应该会知道Dubbo在低版本的时候会向注册中心中写入服务接口,具体路径在上面的 **dubbo目录下** ,然后在 **/dubbo/服务接口/** 路径下写入如下信息: +* **服务提供者**配置信息URL形式 +* **服务消费者**的配置信息URL形式 +* 服务**路由信息** +* **配置信息** + +上面这个图就是Dubbo3的注册信息了,后面我们也会围绕细节来说明下,这里可以看下新增了: +* /dubbo/metadata **元数据信息** +* /dubbo/mapping 服务和应用的**映射信息** +* /dubbo/config **注册中心配置** + * /services目录**应用信息** + +在这里可以大致了解下,在后面会有更详细的源码解析这个示例代码.通过透析代码来看透Dubbo3服务注册原理,服务提供原理。 + + +原文地址:[19-重新来过从一个服务消费者的Demo说起](https://blog.elastic.link/2022/07/10/dubbo/19-chong-xin-lai-guo-cong-yi-ge-fu-wu-xiao-fei-zhe-de-demo-shuo-qi/) \ No newline at end of file diff --git a/content/en/blog/java/codeanalysis/3.0.8/2-serviceconfig-config.md b/content/en/blog/java/codeanalysis/3.0.8/2-serviceconfig-config.md new file mode 100644 index 000000000000..e90d74758042 --- /dev/null +++ b/content/en/blog/java/codeanalysis/3.0.8/2-serviceconfig-config.md @@ -0,0 +1,265 @@ +--- +title: "02-启动服务前服务配置ServiceConfig类型是如何初始化的?" +linkTitle: "2-ServiceConfig类型是如何初始化的?" +date: 2022-08-02 +author: 宋小生 +tags: ["源码解析", "Java"] +description: Dubbo 源码解析之 ServiceConfig 类型是如何初始化的? +--- + + +# 2-启动服务前服务配置ServiceConfig类型是如何初始化的? +## 2.1 示例源码回顾: +为了方便我们理解记忆,这里先来回顾下上一章我们说的示例代码,如下所示: +```java +public class Application { + public static void main(String[] args) throws Exception { + startWithBootstrap(); + } + private static void startWithBootstrap() { + ServiceConfig service = new ServiceConfig<>(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider")) + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) + .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) + .service(service) + .start() + .await(); + } +} + +``` +上面这几行代码虽然看似简单,仅仅几行的启动,但是完全掌握也得下一翻大功夫,接下来我们重点看启动代码中的第一行,创建一个服务配置对象: + +```java +ServiceConfig service = new ServiceConfig<>(); +``` + +## 2.2 了解一下服务配置的建模 +下面是一个简单的UML继承关系图,当然这个图很是简单的,这里仅仅列出了当前服务提供者的相关服务配置继承关系, 服务提供者独有的配置标注颜色为蓝色,一些可能与服务引用配置所共有的父类型我们用红色背景,当然这里为了简便起见不会提起服务引用相关的配置类型,这里列举了如下服务提供者类型,他们各司其职: + ![在这里插入图片描述](/imgs/blog/source-blog/2-ServiceConfig.png) +
图2.1 服务引用类继承关系UML
+ +- AbstractConfig + - **抽象的配置类型**,也是最顶层的服务配置类型,封装着解析配置的实用方法和公共方法,比如服务id的设置,服务标签名字的处理,服务参数的添加,属性的提取等等 +- AbstractMethodConfig + - **抽象的方法配置**,同样这个类型也是见名知意,服务方法的相关配置处理,这个类型主要用于对服务方法的一些配置信息建模比如服务方法的调用超时时间,重试次数,最大并发调用数,负载均衡策略,是否异步调用,是否确认异步发送等等配置信息. +- AbstractInterfaceConfig + - **抽象的接口配置**,与前面介绍的方法配置类似,这个类型是对服务接口的建模,主要的配置信息有暴漏服务的接口名字,服务接口的版本号,客户/提供方将引用的远程服务分组,**服务元数据**,服务接口的本地impl类名,服务监控配置,对于生成动态代理的策略,可以选择两种策略:jdk和javassist,容错类型等等配置 +- AbstractServiceConfig + - **抽象的服务配置**,这个就与我们的服务提供者有了具体的关系了,主要记录了一些服务提供者的公共配置,如服务版本,服务分组,服务延迟注册毫秒数,是否暴漏服务,服务权重,是否为动态服务,服务协议类型,是否注册等等. +- ServiceConfigBase + - **服务的基础配置类**,这个类型仍旧是个抽象的类型提取了一些基础的配置:导出服务的接口类,服务名称,接口实现的引用类型,提供者配置,是否是通用服务GenericService +- ServiceConfig + - **服务配置实现类**, 上面的类型都是抽象类型不能做为具体存在的事物,这个类型是我们出现的第一个服务配置实现类型,服务配置实现类已经从父类型中继承了这么多的属性,这里主要为实现服务提供了一些配置如服务的协议配置,服务的代理工厂JavassistProxyFactory是将生成导出服务代理的ProxyFactory实现,是其默认实现,服务提供者模型,是否导出服务,导出的服务列表,服务监听器等等. +- ServiceBean + - **服务工厂Bean** ,这个主要是Spring模块来简化配置的一个服务工厂Bean这里就先不详细介绍Spring相关的配置. + + + +## 2.3 ServiceConfig构造器的初始化调用链 +有了上面的类型继承关系我们就比较好分析了,接下来我们开始创建服务配置对象如下代码所示: +```java +ServiceConfig service = new ServiceConfig<>(); +``` +根据Java基础的构造器知识,在每个构造器的第一行都会有个super方法来调用父类的构造器,当前这个super方法我们可以不写但是Java编译器底层还是会为我们默认加上这么一行super()代码来调用父类构造器的. + + +对于上面我提到的这几个构造器**根据代码被调用的先后顺序**,这里重点说几个重要的,这里我仍旧按代码执行的先后顺序来说: + +### 2.3.1 父类型AbstractMethodConfig构造器的初始化 +根据super调用链这里先来看AbstractMethodConfig抽象方法配置 +```java + public AbstractMethodConfig() { + super(ApplicationModel.defaultModel().getDefaultModule()); + } +``` +在这个构造器中只有个super方法用来调用父类型的构造器,但是在调用之前会先使用代码 **ApplicationModel.defaultModel().getDefaultModule()** 创建一个模块模型对象**ModuleModel** +关于模型对象的细节我们会在下个章节来说,这里我们继续来看调用链 + +### 2.3.2 最顶层类型AbstractConfig构造器的初始化 +**AbstractConfig**的构造器初始化一共有两个,第一个步骤就是创建一个应用程序模型对象**ApplicationModel**,刚刚我们在**AbstractMethodConfig**的构造器中了解到使用这个代码**ApplicationModel.defaultModel().getDefaultModule()**创建了个模块模型对象**ModuleModel**,具体他们细节我们下一章细说,了解了子类型**AbstractMethodConfig**的构造器是带参数的那我们就直接看第二个构造器 +```java +public AbstractConfig() { + this(ApplicationModel.defaultModel()); + } +``` +将会调用第二个构造器初始化域模型 +```java + public AbstractConfig(ScopeModel scopeModel) { + this.setScopeModel(scopeModel); + } +``` + +当前类型设置ScopeModel类型对象 +```java + public final void setScopeModel(ScopeModel scopeModel) { + //第一次初始化的当前成员变量是空的可以设置变量 + if (this.scopeModel != scopeModel) { + //检查参数是否合法 + checkScopeModel(scopeModel); + //初始化对象 + ScopeModel oldScopeModel = this.scopeModel; + this.scopeModel = scopeModel; + // reinitialize spi extension and change referenced config's scope model + //被子类重写的方法,根据多态会调用具体子类型的这个方法我们下面来看 + //子类应该重写此方法以初始化其SPI扩展并更改引用的配置的范围模型。 + this.postProcessAfterScopeModelChanged(oldScopeModel, this.scopeModel); + } + } +``` +检查ScopeModel参数是否合法,合法的参数是不能为空并且必须是ApplicationModel类型或者子类型 +```java + protected void checkScopeModel(ScopeModel scopeModel) { + if (scopeModel == null) { + throw new IllegalArgumentException("scopeModel cannot be null"); + } + if (!(scopeModel instanceof ApplicationModel)) { + throw new IllegalArgumentException("Invalid scope model, expect to be a ApplicationModel but got: " + scopeModel); + } + } +``` + +#### 2.3.2.1 重写的postProcessAfterScopeModelChanged调用逻辑 +当ScopeModel模型对象发生了改变,上面调用了postProcessAfterScopeModelChanged方法来通知模型对象改变的时候要执行的操作,根据多态重写的逻辑我们从实现类的postProcessAfterScopeModelChanged来看,在下面的调用链路中部分父类型并未实现postProcessAfterScopeModelChanged方法我们就直接忽略了 + +第一个被调用到的是**ServiceConfig**类型的postProcessAfterScopeModelChanged方法 +```java + @Override + protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) { + super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel); + //初始化当前协议对象,通过扩展机制获取协议Protocol类型的对象 + protocolSPI = this.getExtensionLoader(Protocol.class).getAdaptiveExtension(); + //初始化当前代理工厂对象,通过扩展机制获取ProxyFactory类型的对象 + proxyFactory = this.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + } +``` + +第二个被调用到的方法为**ServiceConfigBase**的postProcessAfterScopeModelChanged方法 + +```java +@Override + protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) { + super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel); + //当服务提供者配置对象不为空时候为服务提供者对象设置域模型,这里服务提供者对象仍旧为空,这个一般用在兼容Dubbo低版本 + if (this.provider != null && this.provider.getScopeModel() != scopeModel) { + this.provider.setScopeModel(scopeModel); + } + } +``` + +第三个被调用到的是**AbstractInterfaceConfig**类型的postProcessAfterScopeModelChanged方法 + +```java +@Override + protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) { + super.postProcessAfterScopeModelChanged(oldScopeModel, newScopeModel); + // remove this config from old ConfigManager +// if (oldScopeModel != null && oldScopeModel instanceof ModuleModel) { +// ((ModuleModel)oldScopeModel).getConfigManager().removeConfig(this); +// } + + // change referenced config's scope model + //获取应用程序模型对象 + ApplicationModel applicationModel = ScopeModelUtil.getApplicationModel(scopeModel); + //为配置中心对象设置ApplicationModel类型对象(当前阶段配置中心配置对象为空) + if (this.configCenter != null && this.configCenter.getScopeModel() != applicationModel) { + this.configCenter.setScopeModel(applicationModel); + } + //为元数据配置对象设置ApplicationModel类型对象(当前阶段数据配置配置对象为空) + if (this.metadataReportConfig != null && this.metadataReportConfig.getScopeModel() != applicationModel) { + this.metadataReportConfig.setScopeModel(applicationModel); + } + //为MonitorConfig服务监控配置对象设置ApplicationModel类型对象(当前阶段数据配置配置对象为空) + if (this.monitor != null && this.monitor.getScopeModel() != applicationModel) { + this.monitor.setScopeModel(applicationModel); + } + //这个if判断和上面的上面是重复的估计是写代码人加班加的太久了,没注意看 + if (this.metadataReportConfig != null && this.metadataReportConfig.getScopeModel() != applicationModel) { + this.metadataReportConfig.setScopeModel(applicationModel); + } + //如果注册中心配置列表不为空则为每个注册中心配置设置一个ApplicationModel类型对象(当前注册中心对象都为空) + if (CollectionUtils.isNotEmpty(this.registries)) { + this.registries.forEach(registryConfig -> { + if (registryConfig.getScopeModel() != applicationModel) { + registryConfig.setScopeModel(applicationModel); + } + }); + } + } +``` + + +最后被调用到的是最顶层父类型**AbstractConfig**的postProcessAfterScopeModelChanged方法 +这个方法什么也没干只是在父类型创建的模版方法让子类型来重写用的 +```java +protected void postProcessAfterScopeModelChanged(ScopeModel oldScopeModel, ScopeModel newScopeModel) { + // remove this config from old ConfigManager +// if (oldScopeModel != null && oldScopeModel instanceof ApplicationModel) { +// ((ApplicationModel)oldScopeModel).getApplicationConfigManager().removeConfig(this); +// } + } +``` + + +### 2.3.3 ServiceConfigBase构造器的初始化 + +```java +public ServiceConfigBase() { + //服务元数据对象创建 + serviceMetadata = new ServiceMetadata(); + //为服务元数据对象 + serviceMetadata.addAttribute("ORIGIN_CONFIG", this); + } +``` +**注意,** **ServiceMetadata**这个类目前在Dubbo中没有用法。与服务级别相关的数据,例如名称、版本、业务服务的类加载器、安全信息等,还带有用于扩展的AttributeMap。 + +**服务配置对象的创建过程就这样结束了**,当然有一些细节会**放到后面来写** +上面主要顺序是按照代码执行的顺序来写的部分地方可能稍微做了调整,如果有条件的同学一定要**自己进行DEBUG**了解下细节. + + +关于服务配置官网提供了xml的配置信息这里我拷贝过来,可以做为参考: +当然这个配置不是最新的比如服务配置的**标签配置tag**, +**warmup 预热时间**单位毫秒,暂时还没有说明 + + +| 属性 | 对应URL参数 |类型 | 是否必填| 缺省值| 作用| 描述 |兼容性| +|--|--|--|--|--|--|--|--| +|interface | |class |必填 | | 服务发现| 服务接口名 |1.0.0以上版本| +|ref | |object| 必填 | |服务发现 |服务对象实现引用| 1.0.0以上版本| +|version |version| string |可选 |0.0.0 |服务发现| 服务版本,建议使用两位数字版本,如:1.0,通常在接口不兼容时版本号才需要升级 |1.0.0以上版本| +|group |group |string |可选 | | 服务发现 | 服务分组,当一个接口有多个实现,可以用分组区分 |1.0.7以上版本| +|path | `` |string |可选 |缺省为接口名 |服务发现 | 服务路径 (注意:1.0不支持自定义路径,总是使用接口名,如果有1.0调2.0,配置服务路径可能不兼容) |1.0.12以上版本| +|delay |delay |int |可选 |0 |性能调优 | 延迟注册服务时间(毫秒) ,设为-1时,表示延迟到Spring容器初始化完成时暴露服务 |1.0.14以上版本| +|timeout |timeout |int |可选 |1000 |性能调优 |远程服务调用超时时间(毫秒) |2.0.0以上版本| +|retries |retries| int |可选| 2 |性能调优| 远程服务调用重试次数,不包括第一次调用,不需要重试请设为0 |2.0.0以上版本| +|connections |connections| int |可选 |100 |性能调优 | 对每个提供者的最大连接数,rmi、http、hessian等短连接协议表示限制连接数,dubbo等长连接协表示建立的长连接个数 |2.0.0以上版本| +|loadbalance| loadbalance |string |可选| random |性能调优 | 负载均衡策略,可选值:random,roundrobin,leastactive,分别表示:随机,轮询,最少活跃调用 |2.0.0以上版本| +|async| async |boolean| 可选| false| 性能调优| 是否缺省异步执行,不可靠异步,只是忽略返回值,不阻塞执行线程 |2.0.0以上版本| +|local |local |class/boolean |可选| false |服务治理 | 设为true,表示使用缺省代理类名,即:接口名 + Local后缀,已废弃,请使用stub| 2.0.0以上版本| +|stub| stub |class/boolean| 可选| false| 服务治理| 设为true,表示使用缺省代理类名,即:接口名 + Stub后缀,服务接口客户端本地代理类名,用于在客户端执行本地逻辑,如本地缓存等,该本地代理类的构造函数必须允许传入远程代理对象,构造函数如:public XxxServiceStub(XxxService xxxService) |2.0.0以上版本| +|mock |mock| class/boolean |可选 |false |服务治理| 设为true,表示使用缺省Mock类名,即:接口名 + Mock后缀,服务接口调用失败Mock实现类,该Mock类必须有一个无参构造函数,与Local的区别在于,Local总是被执行,而Mock只在出现非业务异常(比如超时,网络异常等)时执行,Local在远程调用之前执行,Mock在远程调用后执行。 |2.0.0以上版本| +|token |token| string/boolean| 可选 |false |服务治理| 令牌验证,为空表示不开启,如果为true,表示随机生成动态令牌,否则使用静态令牌,令牌的作用是防止消费者绕过注册中心直接访问,保证注册中心的授权功能有效,如果使用点对点调用,需关闭令牌功能 |2.0.0以上版本| +|registry | | string| 可选 |缺省向所有registry注册| 配置关联| 向指定注册中心注册,在多个注册中心时使用,值为的id属性,多个注册中心ID用逗号分隔,如果不想将该服务注册到任何registry,可将值设为N/A| 2.0.0以上版本| +|provider | |string |可选| 缺省使用第一个provider配置| 配置关联 | 指定provider,值为的id属性 |2.0.0以上版本| +|deprecated |deprecated |boolean |可选 |false |服务治理| 服务是否过时,如果设为true,消费方引用时将打印服务过时警告error日志 |2.0.5以上版本 +|dynamic |dynamic |boolean |可选 |true |服务治理 | 服务是否动态注册,如果设为false,注册后将显示后disable状态,需人工启用,并且服务提供者停止时,也不会自动取消册,需人工禁用。 2.0.5以上版本| +|accesslog| accesslog| string/boolean |可选 |false |服务治理| 设为true,将向logger中输出访问日志,也可填写访问日志文件路径,直接把访问日志输出到指定文件 |2.0.5以上版本| +|owner |owner |string |可选 || 服务治理 | 服务负责人,用于服务治理,请填写负责人公司邮箱前缀 |2.0.5以上版本 +|document |document |string |可选 | | 服务治理 | 服务文档URL| 2.0.5以上版本 +|weight |weight |int |可选 | | 性能调优 | 服务权重| 2.0.5以上版本| +|executes |executes |int |可选| 0 | 性能调优| 服务提供者每服务每方法最大可并行执行请求数| 2.0.5以上版本| +|proxy| proxy| string |可选 | javassist | 性能调优| 生成动态代理方式,可选:jdk/javassist| 2.0.5以上版本| +|cluster| cluster| string| 可选| failover |性能调优| 集群方式,可选:failover/failfast/failsafe/failback/forking |2.0.5以上版本 +|filter |service.filter |string |可选 | default | 性能调优| 服务提供方远程调用过程拦截器名称,多个名称用逗号分隔 |2.0.5以上版本| +|listener |exporter.listener |string |可选| default | 性能调优| 服务提供方导出服务监听器名称,多个名称用逗号分隔 | +|protocol | | string |可选| | 配置关联| 使用指定的协议暴露服务,在多协议时使用,值为的id属性,多个协议ID用逗号分隔| 2.0.5以上版本| +|layer| layer| string |可选| 服务治理 | 服务提供者所在的分层。如:biz、dao、intl:web、china:acton。 |2.0.7以上版本| +|register |register| boolean |可选 |true| 服务治理|该协议的服务是否注册到注册中心 |2.0.8以上版本| + + + + +原文: [<>](https://blog.elastic.link/2022/07/10/dubbo/2-qi-dong-fu-wu-qian-fu-wu-pei-zhi-serviceconfig-lei-xing-shi-ru-he-chu-shi-hua-de/ ) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/20-Dubbo3\346\234\215\345\212\241\345\274\225\347\224\250\351\205\215\347\275\256ReferenceConfig.md" "b/content/en/blog/java/codeanalysis/3.0.8/20-Dubbo3\346\234\215\345\212\241\345\274\225\347\224\250\351\205\215\347\275\256ReferenceConfig.md" new file mode 100644 index 000000000000..fc4e7a774bc8 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/20-Dubbo3\346\234\215\345\212\241\345\274\225\347\224\250\351\205\215\347\275\256ReferenceConfig.md" @@ -0,0 +1,54 @@ +--- +title: "20-Dubbo3服务引用配置ReferenceConfig" +linkTitle: "20-Dubbo3服务引用配置ReferenceConfig" +date: 2022-08-20 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] 消费者创建的第一步就是先进行消费者信息的配置对应类型为ReferenceConfig,这里详细来看ReferenceConfig包含哪些信息?。 +--- +# 20-Dubbo3服务引用配置ReferenceConfig +## 20.1 简介 +前面简单介绍了一下消费者的例子,消费者创建的第一步就是先进行消费者信息的配置对应类型为ReferenceConfig,这里详细来看ReferenceConfig包含哪些信息?先简单了解下消费者配置的类型关系如下图所示:引用配置与服务配置类型都是通过继承接口配置来扩展的,在分析生产者的时候详细介绍过服务相关的配置,这里来详细看消费者引用者的相关配置信息. +![在这里插入图片描述](/imgs/blog/source-blog/20-refe.png) + +前面例子说了消费者配置对象的创建主要是通过如下代码: + +```java +ReferenceConfig reference = new ReferenceConfig<>(); +``` +这个配置类型的对象创建过程并没有太多的逻辑这里主要来说下各种配置信息: +服务消费者引用服务配置。对应的配置类: `org.apache.dubbo.config.ReferenceConfig` + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| ----------- | ---------------- | -------------- | -------- | ---------------------------------------- | -------- | ------------------------------------------------------------ | --------------------------- | +| id | | string | **必填** | | 配置关联 | 服务引用BeanId | 1.0.0以上版本 | +| interface | | class | **必填** | | 服务发现 | 服务接口名 | 1.0.0以上版本 | +| version | version | string | 可选 | | 服务发现 | 服务版本,与服务提供者的版本一致 | 1.0.0以上版本 | +| group | group | string | 可选 | | 服务发现 | 服务分组,当一个接口有多个实现,可以用分组区分,必需和服务提供方一致 | 1.0.7以上版本 | +| timeout | timeout | long | 可选 | 缺省使用的timeout | 性能调优 | 服务方法调用超时时间(毫秒) | 1.0.5以上版本 | +| retries | retries | int | 可选 | 缺省使用的retries | 性能调优 | 远程服务调用重试次数,不包括第一次调用,不需要重试请设为0 | 2.0.0以上版本 | +| connections | connections | int | 可选 | 缺省使用的connections | 性能调优 | 对每个提供者的最大连接数,rmi、http、hessian等短连接协议表示限制连接数,dubbo等长连接协表示建立的长连接个数 | 2.0.0以上版本 | +| loadbalance | loadbalance | string | 可选 | 缺省使用的loadbalance | 性能调优 | 负载均衡策略,可选值:random,roundrobin,leastactive,分别表示:随机,轮询,最少活跃调用 | 2.0.0以上版本 | +| async | async | boolean | 可选 | 缺省使用的async | 性能调优 | 是否异步执行,不可靠异步,只是忽略返回值,不阻塞执行线程 | 2.0.0以上版本 | +| generic | generic | boolean | 可选 | 缺省使用的generic | 服务治理 | 是否缺省泛化接口,如果为泛化接口,将返回GenericService | 2.0.0以上版本 | +| check | check | boolean | 可选 | 缺省使用的check | 服务治理 | 启动时检查提供者是否存在,true报错,false忽略 | 2.0.0以上版本 | +| url | url | string | 可选 | | 服务治理 | 点对点直连服务提供者地址,将绕过注册中心 | 1.0.6以上版本 | +| stub | stub | class/boolean | 可选 | | 服务治理 | 服务接口客户端本地代理类名,用于在客户端执行本地逻辑,如本地缓存等,该本地代理类的构造函数必须允许传入远程代理对象,构造函数如:public XxxServiceLocal(XxxService xxxService) | 2.0.0以上版本 | +| mock | mock | class/boolean | 可选 | | 服务治理 | 服务接口调用失败Mock实现类名,该Mock类必须有一个无参构造函数,与Local的区别在于,Local总是被执行,而Mock只在出现非业务异常(比如超时,网络异常等)时执行,Local在远程调用之前执行,Mock在远程调用后执行。 | Dubbo1.0.13及其以上版本支持 | +| cache | cache | string/boolean | 可选 | | 服务治理 | 以调用参数为key,缓存返回结果,可选:lru, threadlocal, jcache等 | Dubbo2.1.0及其以上版本支持 | +| validation | validation | boolean | 可选 | | 服务治理 | 是否启用JSR303标准注解验证,如果启用,将对方法参数上的注解进行校验 | Dubbo2.1.0及其以上版本支持 | +| proxy | proxy | boolean | 可选 | javassist | 性能调优 | 选择动态代理实现策略,可选:javassist, jdk | 2.0.2以上版本 | +| client | client | string | 可选 | | 性能调优 | 客户端传输类型设置,如Dubbo协议的netty或mina。 | Dubbo2.0.0以上版本支持 | +| registry | | string | 可选 | 缺省将从所有注册中心获服务列表后合并结果 | 配置关联 | 从指定注册中心注册获取服务列表,在多个注册中心时使用,值为的id属性,多个注册中心ID用逗号分隔 | 2.0.0以上版本 | +| owner | owner | string | 可选 | | 服务治理 | 调用服务负责人,用于服务治理,请填写负责人公司邮箱前缀 | 2.0.5以上版本 | +| actives | actives | int | 可选 | 0 | 性能调优 | 每服务消费者每服务每方法最大并发调用数 | 2.0.5以上版本 | +| cluster | cluster | string | 可选 | failover | 性能调优 | 集群方式,可选:failover/failfast/failsafe/failback/forking | 2.0.5以上版本 | +| filter | reference.filter | string | 可选 | default | 性能调优 | 服务消费方远程调用过程拦截器名称,多个名称用逗号分隔 | 2.0.5以上版本 | +| listener | invoker.listener | string | 可选 | default | 性能调优 | 服务消费方引用服务监听器名称,多个名称用逗号分隔 | 2.0.5以上版本 | +| layer | layer | string | 可选 | | 服务治理 | 服务调用者所在的分层。如:biz、dao、intl:web、china:acton。 | 2.0.7以上版本 | +| init | init | boolean | 可选 | false | 性能调优 | 是否在afterPropertiesSet()时饥饿初始化引用,否则等到有人注入或引用该实例时再初始化。 | 2.0.10以上版本 | +| protocol | protocol | string | 可选 | | 服务治理 | 只调用指定协议的服务提供方,其它协议忽略。 | | + + +原文地址:[20-Dubbo3服务引用配置ReferenceConfig](https://blog.elastic.link/2022/07/10/dubbo/20-dubbo3-fu-wu-yin-yong-pei-zhi-referenceconfig/) \ No newline at end of file diff --git "a/content/en/blog/java/codeanalysis/3.0.8/21-Dubbo3\346\266\210\350\264\271\350\200\205\345\274\225\347\224\250\346\234\215\345\212\241\345\205\245\345\217\243.md" "b/content/en/blog/java/codeanalysis/3.0.8/21-Dubbo3\346\266\210\350\264\271\350\200\205\345\274\225\347\224\250\346\234\215\345\212\241\345\205\245\345\217\243.md" new file mode 100644 index 000000000000..bca6e1aadebe --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/21-Dubbo3\346\266\210\350\264\271\350\200\205\345\274\225\347\224\250\346\234\215\345\212\241\345\205\245\345\217\243.md" @@ -0,0 +1,497 @@ +--- +title: "21-Dubbo3消费者引用服务入口 " +linkTitle: "21-Dubbo3消费者引用服务入口 " +date: 2022-08-21 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] Dubbo3消费者引用服务入口 。 +--- +# 21-Dubbo3消费者引用服务入口 +## 21.1 简介 +前面我们通过Demo说了一个服务引用配置的创建。另外也在前面的文章说了服务提供者的启动完整过程,不过在说服务提供者启动的过程中并未提到服务消费者是如何发现服务,如果调用服务的,这里先就不再说关于服务消费者启动的一个细节了,直接来看前面未提到的服务消费者是如何引用到服务提供者提供的服务的。 +先来回顾下样例代码: + +```java +public class ConsumerApplication { + public static void main(String[] args) { + runWithBootstrap(); + } + private static void runWithBootstrap() { + ReferenceConfig reference = new ReferenceConfig<>(); + reference.setInterface(DemoService.class); + reference.setGeneric("true"); + reference.setProtocol(""); + + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-demo-api-consumer"); + applicationConfig.setQosEnable(false); + applicationConfig.setQosPort(-1); + bootstrap.application(applicationConfig) + .registry(new RegistryConfig("zookeeper://8.131.79.126:2181")) + .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) + .reference(reference) + .start(); + + DemoService demoService = bootstrap.getCache().get(reference); + String message = demoService.sayHello("dubbo"); + System.out.println(message); + + // generic invoke + GenericService genericService = (GenericService) demoService; + Object genericInvokeResult = genericService.$invoke("sayHello", new String[]{String.class.getName()}, + new Object[]{"dubbo generic invoke"}); + System.out.println(genericInvokeResult); + } +} + +``` +这段代码我们前面详细说了服务引用的配置ReferenceConfig和Dubbo启动器启动应用的过程DubboBootstrap,后面我们直接定位到消费者引用服务的代码位置来看。 +## 21.2 入口代码 + +### 21.2.1 DefaultModuleDeployer的start方法 +第一个要关注的就是模块发布器DefaultModuleDeployer的start方法,这个start方法包含了Dubbo应用启动的过程 + +DefaultModuleDeployer的start方法 +```java +public synchronized Future start() throws IllegalStateException { + ...省略掉若干代码 + + onModuleStarting(); + + // initialize + applicationDeployer.initialize(); + initialize(); + + // export services + exportServices(); + + // prepare application instance + // exclude internal module to avoid wait itself + if (moduleModel != moduleModel.getApplicationModel().getInternalModule()) { + applicationDeployer.prepareInternalModule(); + } + + // refer services + referServices(); + + ...省略掉若干代码 + return startFuture; + } +``` + +这个方法大部分代码已经省略,也不会详细去说了,感兴趣的可以看之前讲到的博客,这里主要来看引用服务方法referServices + + +### 21.2.2 DefaultModuleDeployer的referServices方法 + +下面就要来看消费者应用如何引用的服务的入口了,这个方法主要从大的方面做了一些服务引用生命周期的代码,看懂了这个方法我们就可以不依赖Dubbo负载的启动逻辑可以单独调用ReferenceConfigBase类型的对应方法来刷新,启动,销毁引用的服务了这里先来看下代码再详细介绍内容: + + +DefaultModuleDeployer的referServices方法 + +```java + private void referServices() { + //这个是获取配置的所有的ReferenceConfigBase类型对象 + configManager.getReferences().forEach(rc -> { + try { + ReferenceConfig referenceConfig = (ReferenceConfig) rc; + if (!referenceConfig.isRefreshed()) { + //刷新引用配置 + referenceConfig.refresh(); + } + + if (rc.shouldInit()) { + if (referAsync || rc.shouldReferAsync()) { + ExecutorService executor = executorRepository.getServiceReferExecutor(); + CompletableFuture future = CompletableFuture.runAsync(() -> { + try { + //间接的通过缓存对象来引用服务配置 + referenceCache.get(rc); + } catch (Throwable t) { + logger.error(getIdentifier() + " refer async catch error : " + t.getMessage(), t); + } + }, executor); + + asyncReferringFutures.add(future); + } else { + //间接的通过缓存对象来引用服务配置 + referenceCache.get(rc); + } + } + } catch (Throwable t) { + logger.error(getIdentifier() + " refer catch error."); + //出现异常销毁引用配置 + referenceCache.destroy(rc); + throw t; + } + }); + } +``` +在这个代码中我们核心需要关心的就是SimpleReferenceCache类型的get方法了,在获取服务对象之外包装了一层缓存。 + +如果出现了异常则执行referenceCache的destroy方法进行销毁引用配置。 + +## 21.3 开始引用服务 +### 21.3.1 SimpleReferenceCache是什么? +一个用于缓存引用ReferenceConfigBase的util工具类。 +ReferenceConfigBase是一个重对象,对于频繁创建ReferenceConfigBase的框架来说,有必要缓存这些对象。 +如果需要使用复杂的策略,可以实现并使用自己的ReferenceConfigBase缓存 +这个Cache是引用服务的开始如果我们想在代码中自定义一些服务引用的逻辑,可以直接创建SimpleReferenceCache类型对象然后调用其get方法进行引用服务。那这个缓存对象是和缓存与引用服务的可以继续往下看。 +### 21.3.2 引用服务之前的缓存处理逻辑? +关于逻辑的处理,看代码有时候比文字更清晰明了,这里可以直接来看 SimpleReferenceCache类型的get方法 +```java + @Override + @SuppressWarnings("unchecked") + public T get(ReferenceConfigBase rc) { + //这个生成的key规则是这样的 服务分组/服务接口:版本号 详细的代码就不看了 + //例如: group/link.elastic.dubbo.entity.DemoService:1.0 + String key = generator.generateKey(rc); + //服务类型 如果是泛化调用则这个类型为GenericService + Class type = rc.getInterfaceClass(); + + //服务是否为单例的这里默认值都为空,为单例模式 + boolean singleton = rc.getSingleton() == null || rc.getSingleton(); + T proxy = null; + // Check existing proxy of the same 'key' and 'type' first. + if (singleton) { + //一般为单例的 这个方法是从缓存中获取 + proxy = get(key, (Class) type); + } else { + //非单例容易造成内存泄露,无法从缓存中获取 + logger.warn("Using non-singleton ReferenceConfig and ReferenceCache at the same time may cause memory leak. " + + "Call ReferenceConfig#get() directly for non-singleton ReferenceConfig instead of using ReferenceCache#get(ReferenceConfig)"); + } + //前面是从缓存中拿,如果缓存中获取不到则开始引用服务 + if (proxy == null) { + //获取或者创建值,为引用类型referencesOfType对象(类型为Map, List>>)缓存对象生成值(值不存咋时候会生成一个) + List> referencesOfType = referenceTypeMap.computeIfAbsent(type, _t -> Collections.synchronizedList(new ArrayList<>())); + //每次走到这里都会添加一个ReferenceConfigBase 引用配置对象(单例的从缓存中拿到就可以直接返回了) + referencesOfType.add(rc); + + //与前面一样 前面是类型映射,这里是key映射 + List> referenceConfigList = referenceKeyMap.computeIfAbsent(key, _k -> Collections.synchronizedList(new ArrayList<>())); + referenceConfigList.add(rc); + //开始引用服务 + proxy = rc.get(); + } + + return proxy; + } +``` +可以看到这个逻辑使用了享元模式(其实就是先查缓存,缓存不存在则创建对象存入缓存)来进行引用对象的管理这样一个过程,这里一共有两个缓存对象referencesOfType和referenceConfigList +key分别为引用类型和引用的服务的key,值是引用服务的基础配置对象列表List> + +后面可以详细看下如果借助ReferenceConfigBase类型对象来进行具体类型的引用。 + +## 21.4 初始化引用服务的过程 +### 21.4.1 初始化引用服务的调用入口 +引用服务的逻辑其实是相对复杂一点的,包含了服务发现,引用对象的创建等等,接下来就让我们详细看下: + +ReferenceConfig类型的get方法 +```java +@Override + public T get() { + if (destroyed) { + throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!"); + } + + //ref类型为 transient volatile T ref; + if (ref == null) { + // ensure start module, compatible with old api usage + //这个前面已经调用了模块发布器启动过了,这里有这么一行代码是有一定作用的,如果使用方直接调用了ReferenceConfigBase的get方法或者缓存对象SimpleReferenceCache类型的对象的get方法来引用服务端的时候就会造成很多配置没有初始化下面执行逻辑的时候出现问题,这个代码其实就是启动模块进行一些基础配置的初始化操作 比如元数据中心默认配置选择,注册中心默认配置选择这些都是比较重要的 + getScopeModel().getDeployer().start(); + + synchronized (this) { + if (ref == null) { + init(); + } + } + } + + return ref; + } +``` + +这里有一段代码是:getScopeModel().getDeployer().start(); +这个前面已经调用了模块发布器启动过了,这里有这么一行代码是有一定作用的,如果使用方直接调用了ReferenceConfigBase的get方法或者缓存对象SimpleReferenceCache类型的对象的get方法来引用服务端的时候就会造成很多配置没有初始化下面执行逻辑的时候出现问题,这个代码其实就是启动模块进行一些基础配置的初始化操作 比如元数据中心默认配置选择,注册中心默认配置选择这些都是比较重要的。 + +另外可以看到的是这里使用了双重校验锁来保证单例对象的创建,发现Dubbo种大量的使用了双重校验锁的逻辑。 + +### 21.4.2 初始化引用服务 + +这个就直接看代码了这,初始化过程相对复杂一点,我们一点点来看 +ReferenceConfig类型init()方法 + + +```java +protected synchronized void init() { + //初始化标记变量保证只初始化一次,这里又是加锁🔐又是加标记变量的 + if (initialized) { + return; + } + initialized = true; + //刷新配置 + if (!this.isRefreshed()) { + this.refresh(); + } + + // init serviceMetadata + //初始化ServiceMetadata类型对象serviceMetadata 为其设置服务基本属性比如版本号,分组,服务接口名 + initServiceMetadata(consumer); + + //继续初始化元数据信息 服务接口类型和key + serviceMetadata.setServiceType(getServiceInterfaceClass()); + // TODO, uncomment this line once service key is unified + serviceMetadata.setServiceKey(URL.buildKey(interfaceName, group, version)); + + //配置转Map类型 + Map referenceParameters = appendConfig(); + // init service-application mapping + //来自本地存储和url参数的初始化映射。 参数转URL配置初始化 Dubbo中喜欢用url作为配置的一种处理方式 + initServiceAppsMapping(referenceParameters); + //本地内存模块服务存储库 + ModuleServiceRepository repository = getScopeModel().getServiceRepository(); + //ServiceModel和ServiceMetadata在某种程度上是相互重复的。我们将来应该合并它们。 + ServiceDescriptor serviceDescriptor; + if (CommonConstants.NATIVE_STUB.equals(getProxy())) { + serviceDescriptor = StubSuppliers.getServiceDescriptor(interfaceName); + repository.registerService(serviceDescriptor); + } else { + //本地存储库注册服务接口类型 + serviceDescriptor = repository.registerService(interfaceClass); + } + //消费者模型对象 + consumerModel = new ConsumerModel(serviceMetadata.getServiceKey(), proxy, serviceDescriptor, this, + getScopeModel(), serviceMetadata, createAsyncMethodInfo()); + //本地存储库注册消费者模型对象 + repository.registerConsumer(consumerModel); + + //与前面代码一样基础初始化服务元数据对象为其设置附加参数 + serviceMetadata.getAttachments().putAll(referenceParameters); + //创建服务的代理对象 !!!核心代码在这里 + ref = createProxy(referenceParameters); + + //为服务元数据对象设置代理对象 + serviceMetadata.setTarget(ref); + serviceMetadata.addAttribute(PROXY_CLASS_REF, ref); + + consumerModel.setProxyObject(ref); + consumerModel.initMethodModels(); + + //检查invoker对象初始结果 + checkInvokerAvailable(); + } + +``` + + +## 21.5 ReferenceConfig创建服务引用代理对象的原理 +### 21.5.1 代理对象的创建过程 +这里就要继续看 ReferenceConfig类型的创建代理方法createProxy了 +直接贴一下源码: +```java + private T createProxy(Map referenceParameters) { + //本地引用 这里为false + if (shouldJvmRefer(referenceParameters)) { + createInvokerForLocal(referenceParameters); + } else { + urls.clear(); + if (StringUtils.isNotEmpty(url)) { + //url存在则为点对点引用 + // user specified URL, could be peer-to-peer address, or register center's address. + parseUrl(referenceParameters); + } else { + // if protocols not in jvm checkRegistry + //这里不是local协议默认这里为空 + if (!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())) { + //从注册表中获取URL并将其聚合。这个其实就是初始化一下注册中心的url配置 + aggregateUrlFromRegistry(referenceParameters); + } + } + //这个代码非常重要 创建远程引用,创建远程引用调用器 + createInvokerForRemote(); + } + + if (logger.isInfoEnabled()) { + logger.info("Referred dubbo service: [" + referenceParameters.get(INTERFACE_KEY) + "]." + + (Boolean.parseBoolean(referenceParameters.get(GENERIC_KEY)) ? + " it's GenericService reference" : " it's not GenericService reference")); + } + + URL consumerUrl = new ServiceConfigURL(CONSUMER_PROTOCOL, referenceParameters.get(REGISTER_IP_KEY), 0, + referenceParameters.get(INTERFACE_KEY), referenceParameters); + consumerUrl = consumerUrl.setScopeModel(getScopeModel()); + consumerUrl = consumerUrl.setServiceModel(consumerModel); + MetadataUtils.publishServiceDefinition(consumerUrl, consumerModel.getServiceModel(), getApplicationModel()); + + // create service proxy + return (T) proxyFactory.getProxy(invoker, ProtocolUtils.isGeneric(generic)); + } +``` + +### 21.5.2 创建远程引用,创建远程引用调用器 + + +ReferenceConfig类型的createInvokerForRemote方法 + +```java +private void createInvokerForRemote() { + //这个url 为注册协议如registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-consumer&dubbo=2.0.2&pid=6204&qos.enable=false&qos.port=-1®istry=zookeeper&release=3.0.9×tamp=1657439419495 + if (urls.size() == 1) { + URL curUrl = urls.get(0); + //这个SPI对象是由字节码动态生成的自适应对象Protocol$Adaptie直接看看不到源码,后续可以解析一个字节码生成的类型,这里后续来调用链路即可 + invoker = protocolSPI.refer(interfaceClass, curUrl); + if (!UrlUtils.isRegistry(curUrl)) { + List> invokers = new ArrayList<>(); + invokers.add(invoker); + invoker = Cluster.getCluster(scopeModel, Cluster.DEFAULT).join(new StaticDirectory(curUrl, invokers), true); + } + } else { + List> invokers = new ArrayList<>(); + URL registryUrl = null; + for (URL url : urls) { + // For multi-registry scenarios, it is not checked whether each referInvoker is available. + // Because this invoker may become available later. + invokers.add(protocolSPI.refer(interfaceClass, url)); + + if (UrlUtils.isRegistry(url)) { + // use last registry url + registryUrl = url; + } + } + + if (registryUrl != null) { + // registry url is available + // for multi-subscription scenario, use 'zone-aware' policy by default + String cluster = registryUrl.getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME); + // The invoker wrap sequence would be: ZoneAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker + // (RegistryDirectory, routing happens here) -> Invoker + invoker = Cluster.getCluster(registryUrl.getScopeModel(), cluster, false).join(new StaticDirectory(registryUrl, invokers), false); + } else { + // not a registry url, must be direct invoke. + if (CollectionUtils.isEmpty(invokers)) { + throw new IllegalArgumentException("invokers == null"); + } + URL curUrl = invokers.get(0).getUrl(); + String cluster = curUrl.getParameter(CLUSTER_KEY, Cluster.DEFAULT); + invoker = Cluster.getCluster(scopeModel, cluster).join(new StaticDirectory(curUrl, invokers), true); + } + } + } +``` + +### 21.5.3 Invoker对象创建的全过程 +为了更好理解Protocol$Adaptie内部的引用执行过程这里我把Debug的链路截图了过来 +按照固定的顺序先执行AOP的逻辑再执行具体的逻辑: +- Protocol$Adaptie的refer方法 +- ProtocolSerializationWrapper AOP类型的协议序列化器refer方法 +- ProtocolFilterWrapper AOP类型的协议过滤器的refer方法 +- QosProtocolWrapper AOP类型的QOS协议包装器的refer方法 +- ProtocolListenerWrapper APO类型监听器包装器的refer方法 +- RegistryProtocol 注册协议的refer方法 (会添加容错逻辑) +- RegistryProtocol 注册协议的doRefer方法(调用方法创建Invoker对象) + +[](/imgs/blog/source-blog/21-createInvokerRemote.png) + +这里我们不再详细说这个引用链的具体过程直接定位到RegistryProtocol中创建Invoker类型的地方。 +先来看RegistryProtocol类型的refer方法,如下代码所示: + +RegistryProtocol类型的refer方法 +```java +@Override + @SuppressWarnings("unchecked") + public Invoker refer(Class type, URL url) throws RpcException { + //这个url已经被转换为具体的注册中心协议类型了 + //zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=dubbo-demo-api-consumer&dubbo=2.0.2&pid=7944&qos.enable=false&qos.port=-1&release=3.0.9×tamp=1657440673100 + url = getRegistryUrl(url); + //获取用于操作Zookeeper的Registry类型 + Registry registry = getRegistry(url); + if (RegistryService.class.equals(type)) { + return proxyFactory.getInvoker((T) registry, type, url); + } + + // group="a,b" or group="*" + Map qs = (Map) url.getAttribute(REFER_KEY); + String group = qs.get(GROUP_KEY); + if (StringUtils.isNotEmpty(group)) { + if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) { + return doRefer(Cluster.getCluster(url.getScopeModel(), MergeableCluster.NAME), registry, type, url, qs); + } + } + //降级容错的逻辑处理对象 类型为Cluster 实际类型为MockClusterWrapper 内部包装的是FailoverCluster + //后续调用服务失败时候会先失效转移再降级 + Cluster cluster = Cluster.getCluster(url.getScopeModel(), qs.get(CLUSTER_KEY)); + //这里才是具体的Invoker对象的创建 + return doRefer(cluster, registry, type, url, qs); + } +``` + + +RegistryProtocol类型的doRefer方法创建Invoker对象 +直接来看代码了 + +```java + protected Invoker doRefer(Cluster cluster, Registry registry, Class type, URL url, Map parameters) { + Map consumerAttribute = new HashMap<>(url.getAttributes()); + consumerAttribute.remove(REFER_KEY); + String p = isEmpty(parameters.get(PROTOCOL_KEY)) ? CONSUMER : parameters.get(PROTOCOL_KEY); + URL consumerUrl = new ServiceConfigURL ( + p, + null, + null, + parameters.get(REGISTER_IP_KEY), + 0, getPath(parameters, type), + parameters, + consumerAttribute + ); + url = url.putAttribute(CONSUMER_URL_KEY, consumerUrl); + //重点看这一行 带迁移性质的Invoker对象 + ClusterInvoker migrationInvoker = getMigrationInvoker(this, cluster, registry, type, url, consumerUrl); + //这一行回来执行迁移规则创建应用级优先的服务发现Invoker对象 + return interceptInvoker(migrationInvoker, url, consumerUrl); + } +``` +这里代码比较重要的其实只有两行getMigrationInvoker和interceptInvoker方法 +比较核心也是Dubbo3比较重要的消费者启动逻辑基本都在这个方法里面interceptInvoker,这个方法执行了消费者应用级发现和接口级发现迁移的逻辑,会自动帮忙决策一个Invoker类型对象,不过这个逻辑这里先简单看下,后续单独整个文章来说。 + +这里我们先来看 ClusterInvoker对象的创建,下面先看代码: + +RegistryProtocol类型的getMigrationInvoker方法 + +```java + protected ClusterInvoker getMigrationInvoker(RegistryProtocol registryProtocol, Cluster cluster, Registry registry, Class type, URL url, URL consumerUrl) { + return new ServiceDiscoveryMigrationInvoker(registryProtocol, cluster, registry, type, url, consumerUrl); + } +``` +详细的逻辑这里就不再看了,我们继续看RegistryProtocol类型的interceptInvoker方法: + +具体代码如下: +RegistryProtocol类型的interceptInvoker方法 + +```java + protected Invoker interceptInvoker(ClusterInvoker invoker, URL url, URL consumerUrl) { + //获取激活的注册协议监听器扩展里面registry.protocol.listener,这里激活的类型为MigrationRuleListener + List listeners = findRegistryProtocolListeners(url); + if (CollectionUtils.isEmpty(listeners)) { + return invoker; + } + + for (RegistryProtocolListener listener : listeners) { + //这里执行MigrationRuleListener类型的onRefer方法 + listener.onRefer(this, invoker, consumerUrl, url); + } + return invoker; + } +``` + +该方法尝试加载所有RegistryProtocolListener定义,这些定义通过与定义的交互来控制调用器的行为,然后使用这些侦听器更改MigrationInvoker的状态和行为。 +当前可用的监听器是MigrationRuleListener,用于通过动态变化的规则控制迁移行为。 + + +可以看到核心的逻辑集中在了这个位置MigrationRuleListener类型的onRefer方法,这个这里就不深入往下说了,后续会有个文章专门来看Dubbo2迁移Dubbo3时候处理的逻辑。 + +Invoker对象的创建完成其实就代表了服务引用执行完成,不过这里核心的协议并没有来说 + + +原文地址:[21-Dubbo3消费者引用服务入口](https://blog.elastic.link/2022/07/10/dubbo/21-dubbo-xiao-fei-zhe-yin-yong-fu-wu-de-ru-kou/) \ No newline at end of file diff --git "a/content/en/blog/java/codeanalysis/3.0.8/22-Dubbo3\346\266\210\350\264\271\350\200\205\350\207\252\345\212\250\346\204\237\345\272\224\345\206\263\347\255\226\345\272\224\347\224\250\347\272\247\346\234\215\345\212\241\345\217\221\347\216\260\345\216\237\347\220\206.md" "b/content/en/blog/java/codeanalysis/3.0.8/22-Dubbo3\346\266\210\350\264\271\350\200\205\350\207\252\345\212\250\346\204\237\345\272\224\345\206\263\347\255\226\345\272\224\347\224\250\347\272\247\346\234\215\345\212\241\345\217\221\347\216\260\345\216\237\347\220\206.md" new file mode 100644 index 000000000000..a5c5098c3e0f --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/22-Dubbo3\346\266\210\350\264\271\350\200\205\350\207\252\345\212\250\346\204\237\345\272\224\345\206\263\347\255\226\345\272\224\347\224\250\347\272\247\346\234\215\345\212\241\345\217\221\347\216\260\345\216\237\347\220\206.md" @@ -0,0 +1,298 @@ +--- +title: "22-Dubbo3消费者自动感应决策应用级服务发现原理 " +linkTitle: "22-Dubbo3消费者自动感应决策应用级服务发现原理 " +date: 2022-08-22 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] Dubbo3消费者自动感应决策应用级服务发现原理 。 +--- + +# 22-Dubbo3消费者自动感应决策应用级服务发现原理 +## 22.1 简介 +这里要说的内容对Dubbo2迁移到Dubbo3的应用比较有帮助,消费者应用级服务发现做了一些自动决策的逻辑来决定当前消费者是应用级发现还是接口级服务发现,这里与前面说的提供者双注册的原理是对等的,提供者默认同时进行应用级注册和接口级注册,消费者对提供者注册的数据来决定使用应用级发现或者接口级发现。这些都是默认的行为,当然对于消费者来说还可以自定义其他的迁移规则,具体的需要我们详细来看逻辑。 + +如果说对于迁移过程比较感兴趣可以直接去官网看文档相对来说还是比较清晰:[https://dubbo.apache.org/zh-cn/docs/migration/migration-service-discovery/](/en/docs/migration/migration-service-discovery/) + +这里再借官网的图来用用,迁移过程主要如下所示: +第一个图是提供者双注册的图: +![在这里插入图片描述](/imgs/v3/migration/provider-registration.png) + +第二个图是消费者订阅决策的图: +![在这里插入图片描述](/imgs/v3/migration/consumer-subscription.png) + +第三个图就是精确到消费者订阅的代码层的逻辑了,消费者服务间调用通过一个Invoker类型对象来进行对象,如下图所示消费者代理对象通过创建一个迁移容错的调用器对象来对应用级或者接口级订阅进行适配如下所示 +![在这里插入图片描述](/imgs/v3/migration/migration-cluster-invoker.png) + +第二个图和第三个图是重点要关注的这一个文章的内容主要就是说这里的逻辑。 + + 关于代码位置如果不知道是如何调用到这一块逻辑的可以查看博文[《21-Dubbo3消费者引用服务入口》](https://blog.elastic.link/2022/07/10/dubbo/21-dubbo-xiao-fei-zhe-yin-yong-fu-wu-de-ru-kou/) + + 这里直接将代码位置定位到:RegistryProtocol类型的interceptInvoker方法中: + 如下所示: + + RegistryProtocol类型的interceptInvoker方法 + ```java + protected Invoker interceptInvoker(ClusterInvoker invoker, URL url, URL consumerUrl) { + //目前存在的扩展类型为RegistryProtocolListener监听器的实现类型MigrationRuleListener + List listeners = findRegistryProtocolListeners(url); + if (CollectionUtils.isEmpty(listeners)) { + return invoker; + } + + for (RegistryProtocolListener listener : listeners) { + listener.onRefer(this, invoker, consumerUrl, url); + } + return invoker; + } + ``` + +该方法尝试加载所有RegistryProtocolListener定义,这些定义通过与定义的交互来控制调用器的行为,然后使用这些侦听器更改MigrationInvoker的状态和行为。当前可用的监听器是MigrationRuleListener,用于通过动态变化的规则控制迁移行为。 + +## 22.2 MigrationRuleListener 类型的onRefer方法 + + +直接来看代码: +```java +@Override + public void onRefer(RegistryProtocol registryProtocol, ClusterInvoker invoker, URL consumerUrl, URL registryURL) { + //创建一个对应invoker对象的MigrationRuleHandler类型对象 然后将其存放在缓存Map类型对象handles中 + MigrationRuleHandler migrationRuleHandler = handlers.computeIfAbsent((MigrationInvoker) invoker, _key -> { + ((MigrationInvoker) invoker).setMigrationRuleListener(this); + return new MigrationRuleHandler<>((MigrationInvoker) invoker, consumerUrl); + }); + + //迁移规则执行 rule是封装了迁移的配置规则的信息对应类型MigrationRule类型,在初始化对象的时候进行了配置初始化 + migrationRuleHandler.doMigrate(rule); + } +``` + +关于这个igrationRule的文可以直接看官方的文档比较详细:[地址迁移规则说明](/en/docs/advanced/migration-invoker/#1-%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%8B%E5%8F%91%E6%8E%A8%E8%8D%90) + + +这个迁移规则是为了更细粒度的迁移决策: +相关配置可以参考下面这个样例: +```yaml +key: 消费者应用名(必填) +step: 状态名(必填) +threshold: 决策阈值(默认1.0) +proportion: 灰度比例(默认100) +delay: 延迟决策时间(默认0) +force: 强制切换(默认 false) +interfaces: 接口粒度配置(可选) + - serviceKey: 接口名(接口 + : + 版本号)(必填) + threshold: 决策阈值 + proportion: 灰度比例 + delay: 延迟决策时间 + force: 强制切换 + step: 状态名(必填) + - serviceKey: 接口名(接口 + : + 版本号) + step: 状态名 +applications: 应用粒度配置(可选) + - serviceKey: 应用名(消费的上游应用名)(必填) + threshold: 决策阈值 + proportion: 灰度比例 + delay: 延迟决策时间 + force: 强制切换 + step: 状态名(必填) +``` + +不过为了简单起见暂时先不详细说这个配置细节,我们继续往下看 + +## 22.3 迁移规则处理器执行迁移规则MigrationRuleHandler类型的doMigrate方法 +### 22.3.1 迁移规则的模版方法: + +MigrationRuleHandler类型的doMigrate方法代码如下: +```java +public synchronized void doMigrate(MigrationRule rule) { + //默认情况下这个类型是MigrationInvoker + if (migrationInvoker instanceof ServiceDiscoveryMigrationInvoker) { + refreshInvoker(MigrationStep.FORCE_APPLICATION, 1.0f, rule); + return; + } + + //迁移步骤,MigrationStep 一共有3种枚举情况:FORCE_INTERFACE, APPLICATION_FIRST, FORCE_APPLICATION + // initial step : APPLICATION_FIRST + MigrationStep step = MigrationStep.APPLICATION_FIRST; + float threshold = -1f; + + try { + //获取配置的类型 默认走APPLICATION_FIRST + step = rule.getStep(consumerURL); + //threshold: 决策阈值(默认-1.0)计算与获取 + threshold = rule.getThreshold(consumerURL); + } catch (Exception e) { + logger.error("Failed to get step and threshold info from rule: " + rule, e); + } + //刷洗调用器对象 来进行决策服务发现模式 + if (refreshInvoker(step, threshold, rule)) { + // refresh success, update rule + setMigrationRule(rule); + } + } +``` +### 22.3.2 服务发现调用器对象的选择(决策服务发现策略) + +这里就是关键代码了:通过迁移配置和当前提供者注册信息来决定创建什么类型的调用器对象(Invoker)来为后续服务调用做准备 + +MigrationRuleHandler的refreshInvoker,注意默认情况下这个step参数为APPLICATION_FIRST + +```java + private boolean refreshInvoker(MigrationStep step, Float threshold, MigrationRule newRule) { + if (step == null || threshold == null) { + throw new IllegalStateException("Step or threshold of migration rule cannot be null"); + } + MigrationStep originStep = currentStep; + + if ((currentStep == null || currentStep != step) || !currentThreshold.equals(threshold)) { + boolean success = true; + switch (step) { + case APPLICATION_FIRST: + //默认和配置了应用级优先的服务发现则走这里 + migrationInvoker.migrateToApplicationFirstInvoker(newRule); + break; + case FORCE_APPLICATION: + //配置了应用级服务发现则走这里 + success = migrationInvoker.migrateToForceApplicationInvoker(newRule); + break; + case FORCE_INTERFACE: + //配置了接口级服务发现则走这里 + default: + success = migrationInvoker.migrateToForceInterfaceInvoker(newRule); + } + + if (success) { + setCurrentStepAndThreshold(step, threshold); + logger.info("Succeed Migrated to " + step + " mode. Service Name: " + consumerURL.getDisplayServiceKey()); + report(step, originStep, "true"); + } else { + // migrate failed, do not save new step and rule + logger.warn("Migrate to " + step + " mode failed. Probably not satisfy the threshold you set " + + threshold + ". Please try re-publish configuration if you still after check."); + report(step, originStep, "false"); + } + + return success; + } + // ignore if step is same with previous, will continue override rule for MigrationInvoker + return true; + } +``` + + +可以看到这个代码做了判断的逻辑分别对应了Dubbo3消费者迁移的一个状态逻辑: +三种状态分别如下枚举类型: +当前共存在三种状态, +- FORCE_INTERFACE(强制接口级) +- APPLICATION_FIRST(应用级优先) +- FORCE_APPLICATION(强制应用级) + +通过代码我们可以看到默认情况下都会走APPLICATION_FIRST(应用级优先)的策略,这里我们也重点来说 APPLICATION_FIRST(应用级优先)来看下Dubbo3是如何决策使用接口级还是应用级发现模型来兼容迁移的服务的。 + + + + + ### 22.3.3 应用级优先的服务发现规则逻辑 + 这个规则就是智能选择应用级还是接口级的代码了,对应类型为MigrationInvoker的migrateToApplicationFirstInvoker方法,接下来我们详细看下: + + MigrationInvoker类型的migrateToApplicationFirstInvoker方法: + ```java + @Override + public void migrateToApplicationFirstInvoker(MigrationRule newRule) { + CountDownLatch latch = new CountDownLatch(0); + //刷新接口级服务发现Invoker + refreshInterfaceInvoker(latch); + //刷新应用级服务发现Invoker类型对象 + refreshServiceDiscoveryInvoker(latch); + + // directly calculate preferred invoker, will not wait until address notify + // calculation will re-occurred when address notify later + //计算当前使用应用级还是接口级服务发现的Invoker对象 + calcPreferredInvoker(newRule); + } + ``` + +### 22.3.4 刷新接口级服务发现Invoker + +MigrationInvoker类型的refreshInterfaceInvoker方法 +```java +protected void refreshInterfaceInvoker(CountDownLatch latch) { + clearListener(invoker); + if (needRefresh(invoker)) { + if (logger.isDebugEnabled()) { + logger.debug("Re-subscribing interface addresses for interface " + type.getName()); + } + + if (invoker != null) { + invoker.destroy(); + } + invoker = registryProtocol.getInvoker(cluster, registry, type, url); + } + setListener(invoker, () -> { + latch.countDown(); + if (reportService.hasReporter()) { + reportService.reportConsumptionStatus( + reportService.createConsumptionReport(consumerUrl.getServiceInterface(), consumerUrl.getVersion(), consumerUrl.getGroup(), "interface")); + } + if (step == APPLICATION_FIRST) { + calcPreferredInvoker(rule); + } + }); + } +``` +### 22.3.5 刷新应用级服务发现Invoker类型对象 +MigrationInvoker类型的refreshServiceDiscoveryInvoker方法 +```java +protected void refreshServiceDiscoveryInvoker(CountDownLatch latch) { + clearListener(serviceDiscoveryInvoker); + if (needRefresh(serviceDiscoveryInvoker)) { + if (logger.isDebugEnabled()) { + logger.debug("Re-subscribing instance addresses, current interface " + type.getName()); + } + + if (serviceDiscoveryInvoker != null) { + serviceDiscoveryInvoker.destroy(); + } + serviceDiscoveryInvoker = registryProtocol.getServiceDiscoveryInvoker(cluster, registry, type, url); + } + setListener(serviceDiscoveryInvoker, () -> { + latch.countDown(); + if (reportService.hasReporter()) { + reportService.reportConsumptionStatus( + reportService.createConsumptionReport(consumerUrl.getServiceInterface(), consumerUrl.getVersion(), consumerUrl.getGroup(), "app")); + } + if (step == APPLICATION_FIRST) { + calcPreferredInvoker(rule); + } + }); + } +``` +### 22.3.6 计算当前使用应用级还是接口级服务发现的Invoker对象 + +MigrationInvoker类型的的calcPreferredInvoker方法 + +```java +private synchronized void calcPreferredInvoker(MigrationRule migrationRule) { + if (serviceDiscoveryInvoker == null || invoker == null) { + return; + } + Set detectors = ScopeModelUtil.getApplicationModel(consumerUrl == null ? null : consumerUrl.getScopeModel()) + .getExtensionLoader(MigrationAddressComparator.class).getSupportedExtensionInstances(); + if (CollectionUtils.isNotEmpty(detectors)) { + // pick preferred invoker + // the real invoker choice in invocation will be affected by promotion + if (detectors.stream().allMatch(comparator -> comparator.shouldMigrate(serviceDiscoveryInvoker, invoker, migrationRule))) { + this.currentAvailableInvoker = serviceDiscoveryInvoker; + } else { + this.currentAvailableInvoker = invoker; + } + } + } +``` + +currentAvailableInvoker是后期服务调用使用的Invoker对象 + + + + +原文地址:[22-Dubbo3消费者自动感应决策应用级服务发现原理](https://blog.elastic.link/2022/07/10/dubbo/22-dubbo3-xiao-fei-zhe-zi-dong-gan-ying-jue-ce-ying-yong-ji-fu-wu-fa-xian-yuan-li/) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/3-\346\241\206\346\236\266,\345\272\224\347\224\250\347\250\213\345\272\217,\346\250\241\345\235\227\351\242\206\345\237\237\346\250\241\345\236\213Model\345\257\271\350\261\241\347\232\204\345\210\235\345\247\213\345\214\226.md" "b/content/en/blog/java/codeanalysis/3.0.8/3-\346\241\206\346\236\266,\345\272\224\347\224\250\347\250\213\345\272\217,\346\250\241\345\235\227\351\242\206\345\237\237\346\250\241\345\236\213Model\345\257\271\350\261\241\347\232\204\345\210\235\345\247\213\345\214\226.md" new file mode 100644 index 000000000000..63f2f47b7e77 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/3-\346\241\206\346\236\266,\345\272\224\347\224\250\347\250\213\345\272\217,\346\250\241\345\235\227\351\242\206\345\237\237\346\250\241\345\236\213Model\345\257\271\350\261\241\347\232\204\345\210\235\345\247\213\345\214\226.md" @@ -0,0 +1,919 @@ +--- +title: "03-框架,应用程序,模块领域模型Model对象的初始化" +linkTitle: "3-框架,应用程序,模块领域模型Model对象的初始化" +date: 2022-08-03 +author: 宋小生 +tags: ["源码解析", "Java"] +description: Dubbo 源码解析之框架,应用程序,模块领域模型 Model 对象的初始化 +--- + +# 3-框架,应用程序,模块领域模型Model对象的初始化 +在上一章中我们详细看了服务配置ServiceConfig类型的初始化,不过我们跳过了AbstractMethodConfig的构造器中创建模块模型对象的过程,那这一章我们就来看下模块模型对象的初始化过程: + +```java +public AbstractMethodConfig() { + super(ApplicationModel.defaultModel().getDefaultModule()); + } +``` +**那为什么会在Dubbo3的新版本中加入这个域模型呢**,主要有如下原因 +之前dubbo都是只有一个作用域的,通过静态类 属性共享 +增加域模型是为了: +1. 让Dubbo支持多应用的部署,这块一些大企业有诉求 +2. 从架构设计上,解决静态属性资源共享、清理的问题 +3. 分层模型将应用的管理和服务的管理分开 + +可能比较抽象,可以具体点来看。Dubbo3中在启动时候需要启动配置中心、元数据中心,这个配置中心和元数据中心可以归应用模型来管理。Dubbo作为RPC框架又需要启动服务和引用服务,服务级别的管理就交给了这个模块模型来管理。分层次的管理方便我们理解和处理逻辑,父子级别的模型又方便了数据传递。 + +了解过JVM类加载机制的同学应该就比较清楚JVM类加载过程中的数据访问模型。子类加载器先交给父类加载器查找,找不到再从子类加载器中查找。Dubbo的分层模型类似这样一种机制,这一章先来简单了解下,后面用到时候具体细说。 + +## 3.1 模型对象的关系 +为了不增加复杂性,我们这里仅仅列出模型对象类型类型之间的继承关系如下所示: +![在这里插入图片描述](/imgs/blog/source-blog/3-model.png) +
图3.1 模型对象的继承关系
+ +模型对象一共有4个,公共的属性和操作放在了域模型类型中,下面我们来详细说下这几个模型类型: + + - **ExtensionAccessor** 扩展的统一访问器 + - 用于获取扩展加载管理器ExtensionDirector对象 + - **获取扩展对象ExtensionLoader** + - 根据扩展名字**获取具体扩展对象** + - 获取自适应扩展对象 + - 获取默认扩展对象 + - **ScopeModel** 模型对象的公共抽象父类型 + - 内部id用于表示模型树的层次结构 + - 公共模型名称,可以被用户设置 + - 描述信息 + - 类加载器管理 + - 父模型管理parent + - 当前模型的所属域ExtensionScope有:**FRAMEWORK(框架)**,**APPLICATION(应用)**,**MODULE(模块)**,**SELF(自给自足**,为每个作用域创建一个实例,用于特殊的SPI扩展,如ExtensionInjector) + - 具体的扩展加载程序管理器对象的管理:**ExtensionDirector** + - 域Bean工厂管理,一个内部共享的Bean工厂**ScopeBeanFactory** + - 等等 + + - **FrameworkModel** dubbo框架模型,可与多个应用程序共享 + - FrameworkModel实例对象集合,allInstances + - 所有ApplicationModel实例对象集合,applicationModels + - 发布的ApplicationModel实例对象集合pubApplicationModels + - 框架的服务存储库**FrameworkServiceRepository**类型对象(数据存储在内存中) + - 内部的应用程序模型对象internalApplicationModel + - **ApplicationModel** 表示正在使用Dubbo的应用程序,并存储基本**元数据信息**,以便在RPC调用过程中使用。 +ApplicationModel包括许多关于**发布服务**的ProviderModel和许多关于订阅服务的Consumer Model。 + - ExtensionLoader、DubboBootstrap和这个类目前被设计为单例或静态(本身完全静态或使用一些静态字段)。因此,从它们返回的实例属于流程范围。如果想在一个进程中支持多个dubbo服务器,可能需要重构这三个类。 + - **所有ModuleModel实例**对象集合moduleModels + - **发布的ModuleModel实例**对象集合pubModuleModels + - **环境信息Environment实例**对象environment + - **配置管理ConfigManager实例**对象configManager + - **服务存储库ServiceRepository实例**对象serviceRepository + - **应用程序部署器ApplicationDeployer实例**对象deployer + - **所属框架FrameworkModel实例**对象frameworkModel + - **内部的模块模型ModuleModel实例**对象internalModule + - **默认的模块模型ModuleModel实例**对象defaultModule +- **ModuleModel** 服务模块的模型 + - **所属应用程序模型ApplicationModel实例**对象applicationModel + - **模块环境信息ModuleEnvironment实例**对象moduleEnvironment + - **模块服务存储库ModuleServiceRepository实例**对象serviceRepository + - **模块的服务配置管理ModuleConfigManager实例**对象moduleConfigManager + - **模块部署器ModuleDeployer实例**对象deployer用于导出和引用服务 + + +了解了这几个模型对象的关系我们可以了解到这几个模型对象的管理层级从框架到应用程序,然后到模块的管理(FrameworkModel->ApplicationModel->ModuleModel),他们主要用来针对框架,应用程序,模块的**存储**,**发布管理,**,**配置管理** + +看来Dubbo3 针对应用服务治理与运维这一块也是在努力尝试. + + +### 3.1.1 AbstractMethodConfig 配置对象中获取模型对象的调用 + +模块模型(ModuleModel)参数对象的创建 +这个AbstractMethodConfig构造器在初始化的时候调调用了这么一行代码做为参数向父类型传递对象. + +```java +ApplicationModel.defaultModel().getDefaultModule() +``` +默认情况下使用ApplicationModel的静态方法获取默认的模型对象和默认的模块对象 + +**ApplicationModel**(应用程序领域模型)类型中获取默认模型对象的方法: + +```java + public static ApplicationModel defaultModel() { + // should get from default FrameworkModel, avoid out of sync + return FrameworkModel.defaultModel().defaultApplication(); + } +``` +这里可以看到要想获取应用程序模型必须先通过框架领域模型来获取层级也是框架领域模型到应用程序领域模型 + +### 3.1.2 使用双重校验锁获取框架模型对象 +FrameworkModel(框架模型)的默认模型获取工厂方法defaultModel() +```java + /** + * 在源码的注释上有这么一句话:在销毁默认的 FrameworkModel 时, FrameworkModel.defaultModel() + *或ApplicationModel.defaultModel() 将返回一个损坏的模型 + *可能会导致不可预知的问题。建议:尽量避免使用默认模型。 + */ + public static FrameworkModel defaultModel() { + //双重校验锁的形式创建单例对象 + FrameworkModel instance = defaultInstance; + if (instance == null) { + synchronized (globalLock) { + //重置默认框架模型 + resetDefaultFrameworkModel(); + if (defaultInstance == null) { + defaultInstance = new FrameworkModel(); + } + instance = defaultInstance; + } + } + Assert.notNull(instance, "Default FrameworkModel is null"); + return instance; + } +``` + +### 3.1.3 刷新重置默认框架模型对象 +FrameworkModel中的重置默认框架模型resetDefaultFrameworkModel +```java + private static void resetDefaultFrameworkModel() { + //全局悲观锁,同一个时刻只能有一个线程执行重置操作 + synchronized (globalLock) { + //defaultInstance为当前成员变量FrameworkModel类型代表当前默认的FrameworkModel类型的实例对象 + if (defaultInstance != null && !defaultInstance.isDestroyed()) { + return; + } + FrameworkModel oldDefaultFrameworkModel = defaultInstance; + //存在实例模型列表则直接从内存缓存中查后续不需要创建了 + if (allInstances.size() > 0) { + //当前存在的有FrameworkModel框架实例多个列表则取第一个为默认的 + defaultInstance = allInstances.get(0); + } else { + defaultInstance = null; + } + if (oldDefaultFrameworkModel != defaultInstance) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Reset global default framework from " + safeGetModelDesc(oldDefaultFrameworkModel) + " to " + safeGetModelDesc(defaultInstance)); + } + } + } + } +``` + + +上面单例做了很多的初始化操作,这里开始调用构造器来创建框架模型对象,如下代码: +## 3.2 创建FrameworkModel对象 + FrameworkModel()构造器 +```java +public FrameworkModel() { + //调用父类型ScopeModel传递参数,这个构造器的第一个参数为空代表这是一个顶层的域模型,第二个代表了这个是框架FRAMEWORK域,第三个false不是内部域 + super(null, ExtensionScope.FRAMEWORK, false); + //内部id用于表示模型树的层次结构,如层次结构: + //FrameworkModel(索引=1)->ApplicationModel(索引=2)->ModuleModel(索引=1,第一个用户模块) + //这个index变量是static类型的为静态全局变量默认值从1开始,如果有多个框架模型对象则internalId编号从1开始依次递增 + this.setInternalId(String.valueOf(index.getAndIncrement())); + // register FrameworkModel instance early + //将当前新创建的框架实例对象添加到容器中 + synchronized (globalLock) { + //将当前框架模型实例添加到所有框架模型缓存对象中 + allInstances.add(this); + //如上面代码所示重置默认的框架模型对象,这里将会是缓存实例列表的第一个,新增了一个刷新默认实例对象 + resetDefaultFrameworkModel(); + } + if (LOGGER.isInfoEnabled()) { + LOGGER.info(getDesc() + " is created"); + } + //初始化框架模型领域对象 + initialize(); + } +``` + + ExtensionScope.FRAMEWORK + +### 3.2.1 初始化FrameworkModel +FrameworkModel框架模型的初始化方法initialize() +```java +@Override + protected void initialize() { + //这里初始化之前先调用下父类型ScopeModel的初始化方法我们在下面来看 + super.initialize(); + //使用TypeDefinitionBuilder的静态方法initBuilders来初始化类型构建器TypeBuilder类型集合 + TypeDefinitionBuilder.initBuilders(this); + //框架服务存储仓库对象,可以用于快速查询服务提供者信息 + serviceRepository = new FrameworkServiceRepository(this); + //获取ScopeModelInitializer类型(域模型初始化器)的扩展加载器ExtensionLoader,每个扩展类型都会创建一个扩展加载器缓存起来 + ExtensionLoader initializerExtensionLoader = this.getExtensionLoader(ScopeModelInitializer.class); + //获取ScopeModelInitializer类型的支持的扩展集合,这里当前版本存在8个扩展类型实现 + Set initializers = initializerExtensionLoader.getSupportedExtensionInstances(); + //遍历这些扩展实现调用他们的initializeFrameworkModel方法来传递FrameworkModel类型对象,细节我们待会再详细说下 + for (ScopeModelInitializer initializer : initializers) { + initializer.initializeFrameworkModel(this); + } + //创建一个内部的ApplicationModel类型,细节下面说 + internalApplicationModel = new ApplicationModel(this, true); + //创建ApplicationConfig类型对象同时传递应用程序模型对象internalApplicationModel + //获取ConfigManager类型对象,然后设置添加当前应用配置对象 + internalApplicationModel.getApplicationConfigManager().setApplication( + new ApplicationConfig(internalApplicationModel, CommonConstants.DUBBO_INTERNAL_APPLICATION)); + //设置公开的模块名字为常量DUBBO_INTERNAL_APPLICATION + internalApplicationModel.setModelName(CommonConstants.DUBBO_INTERNAL_APPLICATION); + } +``` + + + +继续上面代码的调用链路,我们来看 +FrameworkModel的super.initialize();方法 调用父类型ScopeModel的initialize()方法 + +### 3.2.2 初始化ScopeModel +ScopeModel类型的初始化方法initialize(): +```java +protected void initialize() { + //初始化ExtensionDirector是一个作用域扩展加载程序管理器。 + //ExtensionDirector支持多个级别,子级可以继承父级的扩展实例。 + //查找和创建扩展实例的方法类似于Java classloader。 + this.extensionDirector = new ExtensionDirector(parent != null ? parent.getExtensionDirector() : null, scope, this); + //这个参考了Spring的生命周期回调思想,添加一个扩展初始化的前后调用的处理器,在扩展初始化之前或之后调用的后处理器,参数类型为ExtensionPostProcessor + this.extensionDirector.addExtensionPostProcessor(new ScopeModelAwareExtensionProcessor(this)); + //创建一个内部共享的域工厂对象,用于注册Bean,创建Bean,获取Bean,初始化Bean等 + this.beanFactory = new ScopeBeanFactory(parent != null ? parent.getBeanFactory() : null, extensionDirector); + //使用数据结构链表,创建销毁监听器容器,一般用于关闭进程,重置应用程序对象等操作时候调用 + this.destroyListeners = new LinkedList<>(); + //使用ConcurrentHashMap属性集合 + this.attributes = new ConcurrentHashMap<>(); + //使用ConcurrentHashSet存储当前域下的类加载器 + this.classLoaders = new ConcurrentHashSet<>(); + + // Add Framework's ClassLoader by default + //将当前类的加载器存入加载器集合classLoaders中 + ClassLoader dubboClassLoader = ScopeModel.class.getClassLoader(); + if (dubboClassLoader != null) { + this.addClassLoader(dubboClassLoader); + } + } +``` + + +### 3.2.3 初始类型定义构建器 + +TypeDefinitionBuilder的初始化类型构造器方法initBuilders + +```java +public static void initBuilders(FrameworkModel model) { + Set tbs = model.getExtensionLoader(TypeBuilder.class).getSupportedExtensionInstances(); + BUILDERS = new ArrayList<>(tbs); + } +``` + + +#### 3.2.3.1 服务存储仓库对象的创建 +FrameworkServiceRepository对象的初始化 + +```java +public FrameworkServiceRepository(FrameworkModel frameworkModel) { + this.frameworkModel = frameworkModel; + } +``` + +### 3.2.4 域模型初始化器的获取与初始化回调 +域模型初始化器的获取与初始化(ScopeModelInitializer类型和initializeFrameworkModel方法) +加载到的ScopeModelInitializer类型的SPI扩展实现 + +```java +ExtensionLoader initializerExtensionLoader = this.getExtensionLoader(ScopeModelInitializer.class); + //获取ScopeModelInitializer类型的支持的扩展集合,这里当前版本存在8个扩展类型实现 + Set initializers = initializerExtensionLoader.getSupportedExtensionInstances(); + //遍历这些扩展实现调用他们的initializeFrameworkModel方法来传递FrameworkModel类型对象,细节我们待会再详细说下 + for (ScopeModelInitializer initializer : initializers) { + initializer.initializeFrameworkModel(this); + } +``` + +通过Debug查到域模型初始化器的SPI扩展类型有如下8个: + +![在这里插入图片描述](/imgs/blog/source-blog/3-initextent.png) + +这里我随机找两个说一下吧: +容错域模型初始化器:ClusterScopeModelInitializer的initializeFrameworkModel方法: + +```java +public class ClusterScopeModelInitializer implements ScopeModelInitializer { + @Override + public void initializeFrameworkModel(FrameworkModel frameworkModel) { + ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); + beanFactory.registerBean(RouterSnapshotSwitcher.class); + } +``` + + +```java +public class CommonScopeModelInitializer implements ScopeModelInitializer { + @Override + public void initializeFrameworkModel(FrameworkModel frameworkModel) { + ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); + beanFactory.registerBean(FrameworkExecutorRepository.class); + } +``` + +```java +public class ConfigScopeModelInitializer implements ScopeModelInitializer { + + @Override + public void initializeFrameworkModel(FrameworkModel frameworkModel) { + frameworkModel.addDestroyListener(new FrameworkModelCleaner()); + } +``` + +### 3.2.5 将内部应用配置对象创建与添加至应用模型中 +创建ApplicationConfig对象让后将其添加至应用模型中 +内部应用程序模型,这里为应用配置管理器设置一个应用配置对象,将这个应用配置的模块名字配置名字设置为DUBBO_INTERNAL_APPLICATION,应用配置记录着我们常见的应用配置信息,如下面表格所示: +```java + //获取ConfigManager类型对象,然后设置添加当前应用配置对象 + internalApplicationModel.getApplicationConfigManager().setApplication( + new ApplicationConfig(internalApplicationModel, CommonConstants.DUBBO_INTERNAL_APPLICATION)); + //设置公开的模块名字为常量DUBBO_INTERNAL_APPLICATION + internalApplicationModel.setModelName(CommonConstants.DUBBO_INTERNAL_APPLICATION); +``` + 来自官网目前版本的配置解释: + 官网当前的配置描述知道到了元数据类型,后面我再补充几个 + +| 属性 | 对应URL参数 |类型 | 是否必填 |缺省值 | 作用 | 描述|兼容性| +|--|--|--|--|--|--|--|--| +| name| application | string| 必填 | | 服务治理 | 当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样,此参数不是匹配条件,你当前项目叫什么名字就填什么,和提供者消费者角色无关,比如:kylin应用调用了morgan应用的服务,则kylin项目配成kylin,morgan项目配成morgan,可能kylin也提供其它服务给别人使用,但kylin项目永远配成kylin,这样注册中心将显示kylin依赖于morgan | 1.0.16以上版本| +| version| application.version | string| 可选| | 服务治理 | 当前应用的版本| 2.2.0以上版本| +| owner| owner| string | 可选| | 服务治理| 应用负责人,用于服务治理,请填写负责人公司邮箱前缀 | 2.0.5以上版本| +| organization | organization | string| 可选| | 服务治理 | 组织名称(BU或部门),用于注册中心区分服务来源,此配置项建议不要使用autoconfig,直接写死在配置中,比如china,intl,itu,crm,asc,dw,aliexpress等 | 2.0.0以上版本| +| architecture| architecture| string| 可选 | | 服务治理| 用于服务分层对应的架构。如,intl、china。不同的架构使用不同的分层。 | 2.0.7以上版本 +| environment | environment| string| 可选 | | 服务治理| 应用环境,如:develop/test/product,不同环境使用不同的缺省值,以及作为只用于开发测试功能的限制条件 | 2.0.0以上版本| +| compiler| compiler| string | 可选| javassist | 性能优化| Java字节码编译器,用于动态类的生成,可选:jdk或javassist | 2.1.0以上版本| +| logger | logger| string | 可选| slf4j | 性能优化| 日志输出方式,可选:slf4j,jcl,log4j,log4j2,jdk | 2.2.0以上版本| +| metadata-type | metadata-type | String | 可选| local | 服务治理 | metadata 传递方式,是以 Provider 视角而言的,Consumer 侧配置无效,可选值有:remote - Provider 把 metadata 放到远端注册中心,Consumer 从注册中心获取local - Provider 把 metadata 放在本地,Consumer 从 Provider 处直接获取 | 2.7.6以上版本| + +当前在Dubbo3.0.7中还有一些的配置我下面列举下: +| 属性 | 对应URL参数 |类型 | 是否必填 |缺省值 | 作用 | 描述|兼容性| +|--|--|--|--|--|--|--|--| +|register-consumer| register-consumer|boolean|可选|false|服务治理|是否注册使用者实例,默认为false。|| +|register-mode|register-mode|string|可选|all|服务治理|将interface/instance/all 地址注册到注册中心,默认为all。| +|enable-empty-protection|enable-empty-protection|boolean|可选|true|服务治理|在空地址通知上启用空保护,默认为true|| +|protocol|protocol|string|可选|dubbo|服务治理|此应用程序的首选协议(名称)|| + + + + +## 3.3 创建ApplicationModel对象 +ApplicationModel对象的初始化调用 + 在前面 3.2.4 FrameworkModel框架模型的初始化方法initialize() 章节中,我们看到了代码ApplicationModel对象的初始化调用如下代码,这里我们来详细说一下: +```java + internalApplicationModel = new ApplicationModel(this, true); + internalApplicationModel.getApplicationConfigManager().setApplication( + new ApplicationConfig(internalApplicationModel, CommonConstants.DUBBO_INTERNAL_APPLICATION)); + internalApplicationModel.setModelName(CommonConstants.DUBBO_INTERNAL_APPLICATION); + +``` + +### 3.3.1 ApplicationModel的构造器 +ApplicationModel(FrameworkModel frameworkModel, boolean isInternal) +刚刚3.2.9那个地方我们看到了使用代码**new ApplicationModel(this, true)** 来创建对象这里我们详细看下代码细节: + + +```java +public ApplicationModel(FrameworkModel frameworkModel, boolean isInternal) { + //调用父类型ScopeModel传递参数,这个构造器的传递没与前面看到的FrameworkModel构造器的中的调用参数有些不同第一个参数我们为frameworkModel代表父域模型,第二个参数标记域为应用程序级别APPLICATION,第三个参数我们传递的为true代表为内部域 + super(frameworkModel, ExtensionScope.APPLICATION, isInternal); + Assert.notNull(frameworkModel, "FrameworkModel can not be null"); + //应用程序域成员变量记录frameworkModel对象 + this.frameworkModel = frameworkModel; + //frameworkModel对象添加当前应用程序域对象 + frameworkModel.addApplication(this); + if (LOGGER.isInfoEnabled()) { + LOGGER.info(getDesc() + " is created"); + } + //初始化应用程序 + initialize(); + } +``` + + +#### 3.3.1.1 将ApplicationModel添加至FrameworkModel容器中 +FrameworkModel的添加应用程序方法addApplication: + +```java +void addApplication(ApplicationModel applicationModel) { + // can not add new application if it's destroying + //检查FrameworkModel对象是否已经被标记为销毁状态,如果已经被销毁了则抛出异常无需执行逻辑 + checkDestroyed(); + synchronized (instLock) { + //如果还未添加过当前参数传递应用模型 + if (!this.applicationModels.contains(applicationModel)) { + //为当前应用模型生成内部id + applicationModel.setInternalId(buildInternalId(getInternalId(), appIndex.getAndIncrement())); + //添加到成员变量集合applicationModels中 + this.applicationModels.add(applicationModel); + //如果非内部的则也向公开应用模型集合pubApplicationModels中添加一下 + if (!applicationModel.isInternal()) { + this.pubApplicationModels.add(applicationModel); + } + resetDefaultAppModel(); + } + } + } +``` +内部id生成算法buildInternalId方法代码如下: +看代码胜过,文字解释 +```java + protected String buildInternalId(String parentInternalId, long childIndex) { + // FrameworkModel 1 + // ApplicationModel 1.1 + // ModuleModel 1.1.1 + if (StringUtils.hasText(parentInternalId)) { + return parentInternalId + "." + childIndex; + } else { + return "" + childIndex; + } + } +``` + + **重置默认的应用模型对象** +FrameworkModel 重置默认的应用模型对象 resetDefaultAppModel()方法 +与默认框架模型设置方式类似取集合的第一个,这里应用模型需要使用公开的应用模型的第一个做为默认应用模型,代码如下所示: +```java +private void resetDefaultAppModel() { + synchronized (instLock) { + if (this.defaultAppModel != null && !this.defaultAppModel.isDestroyed()) { + return; + } + //取第一个公开的应用模型做为默认应用模型 + ApplicationModel oldDefaultAppModel = this.defaultAppModel; + if (pubApplicationModels.size() > 0) { + this.defaultAppModel = pubApplicationModels.get(0); + } else { + this.defaultAppModel = null; + } + if (defaultInstance == this && oldDefaultAppModel != this.defaultAppModel) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Reset global default application from " + safeGetModelDesc(oldDefaultAppModel) + " to " + safeGetModelDesc(this.defaultAppModel)); + } + } + } + } +``` + +### 3.3.2 初始化ApplicationModel +ApplicationModel的初始化initialize()方法 +在前面**3.2.10 ApplicationModel的构造器ApplicationModel(FrameworkModel frameworkModel, boolean isInternal)** 中的最后一行开始初始化应用模型我们还未详细说明下面可以来看下 + +```java +@Override + protected void initialize() { + //这个是调用域模型来初始化基础信息如扩展访问器等,可以参考 3.2.5 ScopeModel类型的初始化方法initialize()章节 + super.initialize(); + //创建一个内部的模块模型对象 + internalModule = new ModuleModel(this, true); + //创建一个独立服务存储对象 + this.serviceRepository = new ServiceRepository(this); + //获取应用程序初始化监听器ApplicationInitListener扩展 + ExtensionLoader extensionLoader = this.getExtensionLoader(ApplicationInitListener.class); + //如果存在应用程序初始化监听器扩展则执行这个初始化方法,在当前的版本还未看到有具体的扩展实现类型 + Set listenerNames = extensionLoader.getSupportedExtensions(); + for (String listenerName : listenerNames) { + extensionLoader.getExtension(listenerName).init(); + } + //初始化扩展(这个是应用程序生命周期的方法调用,这里调用初始化方法 + initApplicationExts(); + + //获取域模型初始化器扩展对象列表,然后执行初始化方法 + ExtensionLoader initializerExtensionLoader = this.getExtensionLoader(ScopeModelInitializer.class); + Set initializers = initializerExtensionLoader.getSupportedExtensionInstances(); + for (ScopeModelInitializer initializer : initializers) { + initializer.initializeApplicationModel(this); + } + } +``` + + ### 3.3.4 initApplicationExts() 初始化应用程序扩展方法 +```java + private void initApplicationExts() { + //这个扩展实现一共有两个可以看下面那个图扩展类型为ConfigManager和Environment + Set exts = this.getExtensionLoader(ApplicationExt.class).getSupportedExtensionInstances(); + for (ApplicationExt ext : exts) { + ext.initialize(); + } + } +``` + +![在这里插入图片描述](/imgs/blog/source-blog/3-extension.png) + +#### 3.3.4.1 ConfigManager类型的initialize方法 +先简单说下ConfigManager的作用,无锁配置管理器(通过ConcurrentHashMap),用于快速读取操作。写入操作锁带有配置类型的子配置映射,用于安全检查和添加新配置。 +其实ConfigManager实现类中并没有这个初始化方法initialize,不过ConfigManager的父类型AbstractConfigManager中是有initialize方法的,如下所示: + +AbstractConfigManager的初始化方法initialize +```java +@Override + public void initialize() throws IllegalStateException { + //乐观锁判断是否初始化过 + if (!initialized.compareAndSet(false, true)) { + return; + } + //从模块环境中获取组合配置,目前Environment中有6种重要的配置,我们后面详细说 + CompositeConfiguration configuration = scopeModel.getModelEnvironment().getConfiguration(); + + // dubbo.config.mode获取配置模式,配置模式对应枚举类型ConfigMode,目前有这么几个STRICT,OVERRIDE,OVERRIDE_ALL,OVERRIDE_IF_ABSENT,IGNORE,这个配置决定了属性覆盖的顺序,当有同一个配置key多次出现时候,以最新配置为准,还是以最老的那个配置为准,还是配置重复则抛出异常,默认值为严格模式STRICT重复则抛出异常 + String configModeStr = (String) configuration.getProperty(ConfigKeys.DUBBO_CONFIG_MODE); + try { + if (StringUtils.hasText(configModeStr)) { + this.configMode = ConfigMode.valueOf(configModeStr.toUpperCase()); + } + } catch (Exception e) { + String msg = "Illegal '" + ConfigKeys.DUBBO_CONFIG_MODE + "' config value [" + configModeStr + "], available values " + Arrays.toString(ConfigMode.values()); + logger.error(msg, e); + throw new IllegalArgumentException(msg, e); + } + + // dubbo.config.ignore-duplicated-interface + //忽略重复的接口(服务/引用)配置。默认值为false + String ignoreDuplicatedInterfaceStr = (String) configuration + .getProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE); + if (ignoreDuplicatedInterfaceStr != null) { + this.ignoreDuplicatedInterface = Boolean.parseBoolean(ignoreDuplicatedInterfaceStr); + } + + // print 打印配置信息 + Map map = new LinkedHashMap<>(); + map.put(ConfigKeys.DUBBO_CONFIG_MODE, configMode); + map.put(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE, this.ignoreDuplicatedInterface); + logger.info("Config settings: " + map); + } +``` + + +#### 3.3.4.2 Environment类型的initialize方法 +这是一个与环境配置有关系的类型,我们先来简单了解下它的初始化方法,后期再详细说明: + +Environment类型的initialize方法 +```java + @Override + public void initialize() throws IllegalStateException { + //乐观锁判断是否进行过初始化 + if (initialized.compareAndSet(false, true)) { + //PropertiesConfiguration从系统属性和dubbo.properties中获取配置 + this.propertiesConfiguration = new PropertiesConfiguration(scopeModel); + //SystemConfiguration获取的是JVM参数 启动命令中-D指定的 + this.systemConfiguration = new SystemConfiguration(); + //EnvironmentConfiguration是从环境变量中获取的配置 + this.environmentConfiguration = new EnvironmentConfiguration(); + //外部的Global配置config-center global/default config + this.externalConfiguration = new InmemoryConfiguration("ExternalConfig"); + //外部的应用配置如:config-center中的应用配置 + this.appExternalConfiguration = new InmemoryConfiguration("AppExternalConfig"); + //本地应用配置 , 如Spring Environment/PropertySources/application.properties + this.appConfiguration = new InmemoryConfiguration("AppConfig"); + //服务迁移配置加载 dubbo2升级dubbo3的一些配置 + loadMigrationRule(); + } + } + //服务迁移配置加载 JVM > env > 代码路径dubbo-migration.yaml + private void loadMigrationRule() { + //文件路径配置的key dubbo.migration.file + // JVM参数中获取 + String path = System.getProperty(CommonConstants.DUBBO_MIGRATION_KEY); + if (StringUtils.isEmpty(path)) { + //env环境变量中获取 + path = System.getenv(CommonConstants.DUBBO_MIGRATION_KEY); + if (StringUtils.isEmpty(path)) { + //类路径下获取文件dubbo-migration.yaml + path = CommonConstants.DEFAULT_DUBBO_MIGRATION_FILE; + } + } + this.localMigrationRule = ConfigUtils.loadMigrationRule(scopeModel.getClassLoaders(), path); + } +``` + +**ConfigUtils中读取迁移规则配置文件loadMigrationRule** +这个我们不细说了,贴一下代码感兴趣可以了解下,这个代码主要是读取文件到内存字符串: + +```java + public static String loadMigrationRule(Set classLoaders, String fileName) { + String rawRule = ""; + if (checkFileNameExist(fileName)) { + try { + try (FileInputStream input = new FileInputStream(fileName)) { + return readString(input); + } + } catch (Throwable e) { + logger.warn("Failed to load " + fileName + " file from " + fileName + "(ignore this file): " + e.getMessage(), e); + } + } + + try { + List classLoadersToLoad = new LinkedList<>(); + classLoadersToLoad.add(ClassUtils.getClassLoader()); + classLoadersToLoad.addAll(classLoaders); + for (Set urls : ClassLoaderResourceLoader.loadResources(fileName, classLoadersToLoad).values()) { + for (URL url : urls) { + InputStream is = url.openStream(); + if (is != null) { + return readString(is); + } + } + } + } catch (Throwable e) { + logger.warn("Failed to load " + fileName + " file from " + fileName + "(ignore this file): " + e.getMessage(), e); + } + return rawRule; + } + + private static String readString(InputStream is) { + StringBuilder stringBuilder = new StringBuilder(); + char[] buffer = new char[10]; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { + int n; + while ((n = reader.read(buffer)) != -1) { + if (n < 10) { + buffer = Arrays.copyOf(buffer, n); + } + stringBuilder.append(String.valueOf(buffer)); + buffer = new char[10]; + } + } catch (IOException e) { + logger.error("Read migration file error.", e); + } + + return stringBuilder.toString(); + } + + /** + * check if the fileName can be found in filesystem + * + * @param fileName + * @return + */ + private static boolean checkFileNameExist(String fileName) { + File file = new File(fileName); + return file.exists(); + } +``` + +​ + +## 3.4 创建ModuleModel对象 +前面ApplicationModel对象初始化的时候创建了ModuleModel如下代码: + +```java +internalModule = new ModuleModel(this, true); +``` + +这里我们来看下这个它所对应的构造器 + + +```java +public ModuleModel(ApplicationModel applicationModel, boolean isInternal) { + //调用ScopeModel传递3个参数父模型,模型域为模块域,是否为内部模型参数为true + super(applicationModel, ExtensionScope.MODULE, isInternal); + Assert.notNull(applicationModel, "ApplicationModel can not be null"); + //初始化成员变量applicationModel + this.applicationModel = applicationModel; + //将模块模型添加至应用模型中 + applicationModel.addModule(this, isInternal); + if (LOGGER.isInfoEnabled()) { + LOGGER.info(getDesc() + " is created"); + } + //初始化模块模型 + initialize(); + Assert.notNull(serviceRepository, "ModuleServiceRepository can not be null"); + Assert.notNull(moduleConfigManager, "ModuleConfigManager can not be null"); + Assert.assertTrue(moduleConfigManager.isInitialized(), "ModuleConfigManager can not be initialized"); + + // notify application check state + //获取应用程序发布对象,通知检查状态 + ApplicationDeployer applicationDeployer = applicationModel.getDeployer(); + if (applicationDeployer != null) { + applicationDeployer.notifyModuleChanged(this, DeployState.PENDING); + } + } +``` + +### 3.4.1 将模块模型添加至应用模型中 +如上面代码所示调用如下代码将模块模型添加到应用模型中: + +```java + applicationModel.addModule(this, isInternal); +``` +这里我们来看下添加过程 + +```java + +void addModule(ModuleModel moduleModel, boolean isInternal) { + //加锁 + synchronized (moduleLock) { + //不存在则添加 + if (!this.moduleModels.contains(moduleModel)) { + //检查应用模型是否已销毁 + checkDestroyed(); + //添加至模块模型成员变量中 + this.moduleModels.add(moduleModel); + //设置模块模型内部id,这个内部id生成过程与上面将应用模型添加到框架模型中的方式是一致的 + //可以参考 3.3.2 将ApplicationModel添加至FrameworkModel容器中 + moduleModel.setInternalId(buildInternalId(getInternalId(), moduleIndex.getAndIncrement())); + //如果不是内部模型则添加到公开模块模型中 + if (!isInternal) { + pubModuleModels.add(moduleModel); + } + } + } + } +``` + +### 3.4.2 初始化模块模型 +前面ModuleModel构造器中通过initialize()方法来进行初始化操作如下代码: + +```java +@Override + protected void initialize() { + //调用域模型ScopeModel的初始化,可以参考 3.2.5 ScopeModel类型的初始化方法initialize()章节 + super.initialize(); + //创建模块服务存储库对象 + this.serviceRepository = new ModuleServiceRepository(this); + //创建模块配置管理对象 + this.moduleConfigManager = new ModuleConfigManager(this); + //初始化模块配置管理对象 + this.moduleConfigManager.initialize(); + + //初始化模块配置扩展 + initModuleExt(); + + //初始化域模型扩展 + ExtensionLoader initializerExtensionLoader = this.getExtensionLoader(ScopeModelInitializer.class); + Set initializers = initializerExtensionLoader.getSupportedExtensionInstances(); + for (ScopeModelInitializer initializer : initializers) { + initializer.initializeModuleModel(this); + } + } +``` +#### 3.4.2.1 模块服务存储库的创建 +ModuleServiceRepository是模块模型中用来存储服务的通过如下代码调用 + +```java +//创建模块服务存储库对象 + this.serviceRepository = new ModuleServiceRepository(this); + +``` +这里我们来看下模块服务存储库的构造器代码: + +```java + public ModuleServiceRepository(ModuleModel moduleModel) { + //初始化模块模型 + this.moduleModel = moduleModel; + // + frameworkServiceRepository = ScopeModelUtil.getFrameworkModel(moduleModel).getServiceRepository(); + } +``` + +ModuleServiceRepository存储库中使用框架存储库frameworkServiceRepository来间接存储 +这里我们看下怎么通过模块模型获取框架服务存储库frameworkServiceRepository:通过代码 + +```java +ScopeModelUtil.getFrameworkModel(moduleModel).getServiceRepository() +``` + +ScopeModelUtil工具类获取getFrameworkModel代码如下: +```java +public static FrameworkModel getFrameworkModel(ScopeModel scopeModel) { + if (scopeModel == null) { + return FrameworkModel.defaultModel(); + } + //通过成员变量获取(构造器初始化的时候将FrameworkModel赋值给了ApplicationModel的成员变量 + if (scopeModel instanceof ApplicationModel) { + //直接获取 + return ((ApplicationModel) scopeModel).getFrameworkModel(); + } else if (scopeModel instanceof ModuleModel) { + ModuleModel moduleModel = (ModuleModel) scopeModel; + //间接通过ApplicationModel获取,不越级获取 + return moduleModel.getApplicationModel().getFrameworkModel(); + } else if (scopeModel instanceof FrameworkModel) { + return (FrameworkModel) scopeModel; + } else { + throw new IllegalArgumentException("Unable to get FrameworkModel from " + scopeModel); + } + } +``` + +#### 3.4.2.2 模块配置管理器对象的创建与初始化 + + +```java + //创建模块配置管理对象 + this.moduleConfigManager = new ModuleConfigManager(this); + //初始化模块配置管理对象 + this.moduleConfigManager.initialize(); +``` + + +ModuleConfigManager的构造器代码如下: +```java +public ModuleConfigManager(ModuleModel moduleModel) { + //向抽象的配置管理器AbstractConfigManager传递参数 + //模块模型参数,模块支持的配置类型集合 + super(moduleModel, Arrays.asList(ModuleConfig.class, ServiceConfigBase.class, ReferenceConfigBase.class, ProviderConfig.class, ConsumerConfig.class)); + //获取应用程序配置管理器 + applicationConfigManager = moduleModel.getApplicationModel().getApplicationConfigManager(); + } + +``` + +ModuleConfigManager类型的初始化方法代码如下: + +```java +@Override + public void initialize() throws IllegalStateException { + if (!initialized.compareAndSet(false, true)) { + return; + } + //获取组合配置对象 + CompositeConfiguration configuration = scopeModel.getModelEnvironment().getConfiguration(); + + // dubbo.config.mode + //3.3.4.1提到过这里再重复一次 dubbo.config.mode获取配置模式,配置模式对应枚举类型ConfigMode,目前有这么几个STRICT,OVERRIDE,OVERRIDE_ALL,OVERRIDE_IF_ABSENT,IGNORE,这个配置决定了属性覆盖的顺序,当有同一个配置key多次出现时候,以最新配置为准,还是以最老的那个配置为准,还是配置重复则抛出异常,默认值为严格模式STRICT重复则抛出异常 + String configModeStr = (String) configuration.getProperty(ConfigKeys.DUBBO_CONFIG_MODE); + try { + if (StringUtils.hasText(configModeStr)) { + this.configMode = ConfigMode.valueOf(configModeStr.toUpperCase()); + } + } catch (Exception e) { + String msg = "Illegal '" + ConfigKeys.DUBBO_CONFIG_MODE + "' config value [" + configModeStr + "], available values " + Arrays.toString(ConfigMode.values()); + logger.error(msg, e); + throw new IllegalArgumentException(msg, e); + } + + // dubbo.config.ignore-duplicated-interface + //忽略重复的接口(服务/引用)配置。默认值为false + String ignoreDuplicatedInterfaceStr = (String) configuration + .getProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE); + if (ignoreDuplicatedInterfaceStr != null) { + this.ignoreDuplicatedInterface = Boolean.parseBoolean(ignoreDuplicatedInterfaceStr); + } + + // print 打印配置信息到控制台 + Map map = new LinkedHashMap<>(); + map.put(ConfigKeys.DUBBO_CONFIG_MODE, configMode); + map.put(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE, this.ignoreDuplicatedInterface); + logger.info("Config settings: " + map); + } +``` + +#### 3.4.2.3 模块配置扩展的初始化 + +```java +initModuleExt(); +``` + +```java +private void initModuleExt() { +//目前这里的扩展只支持有一个类型ModuleEnvironment + Set exts = this.getExtensionLoader(ModuleExt.class).getSupportedExtensionInstances(); + for (ModuleExt ext : exts) { + ext.initialize(); + } + } +``` +ModuleEnvironment的初始化 + +```java + @Override + public void initialize() throws IllegalStateException { + this.orderedPropertiesConfiguration = new OrderedPropertiesConfiguration(moduleModel); + } +``` + +OrderedPropertiesConfiguration对象的创建 + +```java +public OrderedPropertiesConfiguration(ModuleModel moduleModel) { + this.moduleModel = moduleModel; + refresh(); + } + + public void refresh() { + properties = new Properties(); + //有序的配置提供器扩展获取 + ExtensionLoader propertiesProviderExtensionLoader = moduleModel.getExtensionLoader(OrderedPropertiesProvider.class); + Set propertiesProviderNames = propertiesProviderExtensionLoader.getSupportedExtensions(); + if (CollectionUtils.isEmpty(propertiesProviderNames)) { + return; + } + List orderedPropertiesProviders = new ArrayList<>(); + for (String propertiesProviderName : propertiesProviderNames) { + orderedPropertiesProviders.add(propertiesProviderExtensionLoader.getExtension(propertiesProviderName)); + } + + //order the propertiesProvider according the priority descending + //根据优先级进行排序,值越小优先级越高 + orderedPropertiesProviders.sort((a, b) -> b.priority() - a.priority()); + + + //override the properties. 目前没看到有具体的扩展实现 + for (OrderedPropertiesProvider orderedPropertiesProvider : orderedPropertiesProviders) { + properties.putAll(orderedPropertiesProvider.initProperties()); + } + + } +``` + + + +原文: [<<框架,应用程序,模块领域模型Model对象的初始化>>](https://blog.elastic.link/2022/07/10/dubbo/3-kuang-jia-ying-yong-cheng-xu-mo-kuai-ling-yu-mo-xing-model-dui-xiang-de-chu-shi-hua/ ) + diff --git "a/content/en/blog/java/codeanalysis/3.0.8/4-Dubbo\347\232\204\346\211\251\345\261\225\346\234\272\345\210\266.md" "b/content/en/blog/java/codeanalysis/3.0.8/4-Dubbo\347\232\204\346\211\251\345\261\225\346\234\272\345\210\266.md" new file mode 100644 index 000000000000..c8d38ddd0829 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/4-Dubbo\347\232\204\346\211\251\345\261\225\346\234\272\345\210\266.md" @@ -0,0 +1,400 @@ +--- +title: "04-Dubbo的扩展机制" +linkTitle: "4-Dubbo的扩展机制" +date: 2022-08-04 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] Dubbo是一个微内核框架,所有的实现都是通过扩展机制来实现的,了解扩展加载机制可以有效的逻辑代码的抽象与具体逻辑 +--- + + +# 4-Dubbo的扩展机制 +## 4.1 回顾我们前面使用到扩展场景 +在上一章中我们初始化应用模型对象的时候,了解到有几个地方用到了扩展机制来创建对象,这一章我们会详细来讲一下这个扩展对象的加载过程,这里我们先来回顾下哪些地方用到了扩展机制: + + +```java +// 使用扩展机制获取TypeBuilder +Set tbs = model.getExtensionLoader(TypeBuilder.class).getSupportedExtensionInstances(); + +//获取域模型初始化器ScopeModelInitializer扩展对象,执行初始化方法 +ExtensionLoader initializerExtensionLoader = this.getExtensionLoader(ScopeModelInitializer.class); + Set initializers = initializerExtensionLoader.getSupportedExtensionInstances(); + +// OrderedPropertiesConfiguration 中获取有序配置提供器对象 +ExtensionLoader propertiesProviderExtensionLoader = moduleModel.getExtensionLoader(OrderedPropertiesProvider.class); + +// ApplicationModel中获取配置管理器对象 + configManager = (ConfigManager) this.getExtensionLoader(ApplicationExt.class) + .getExtension(ConfigManager.NAME); + +//ModuleModel中获取模块扩展对象 +Set exts = this.getExtensionLoader(ModuleExt.class).getSupportedExtensionInstances(); + +// ApplicationModel中获Environment对象 +environment = (Environment) this.getExtensionLoader(ApplicationExt.class) + .getExtension(Environment.NAME); + +// ApplicationModel中获取应用初始化监听器ApplicationInitListener扩展对象 +ExtensionLoader extensionLoader = this.getExtensionLoader(ApplicationInitListener.class); +Set listenerNames = extensionLoader.getSupportedExtensions(); + +//ScopeModel中创建扩展访问器: +this.extensionDirector = new ExtensionDirector(parent != null ? parent.getExtensionDirector() : null, scope, this); + +``` + +有了以上的应用场景我们可以来看下扩展机制了 + +## 4.2 为什么要用到扩展机制? +为什么要用到扩展这个想必每个编程人员都比较了解,一个好的程序是要遵循一定的设计规范比如设计模式中的**开闭原则** 英文全称是 Open Closed Principle,简写为 OCP,对扩展开放、对修改关闭: + +**对扩展开放:** 指的是我们系统中的模块、类、方法对它们的提供者(开发者)应该是开放的,提供者可以对系统进行扩展(新增)新的功能。 + +**对修改关闭:** 指的是系统中的模块、类、方法对它们的使用者(调用者)应该是关闭的。使用者使用这些功能时,不会因为提供方新增了功能而导致使用者也进行相应修改。 + +我们再来了解下Dubbo的一些基本特性: +下面这句话是我摘自官网的: +*Apache Dubbo 是一款微服务开发框架,它提供了 **RPC通信** 与 **微服务治理** 两大关键能力。这意味着,使用 Dubbo 开发的微服务,将具备相互之间的远程发现与通信能力, 同时利用 Dubbo 提供的丰富服务治理能力,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。同时 Dubbo 是高度可扩展的,用户几乎可以在**任意功能点去定制自己的实现**,以改变框架的默认行为来满足自己的业务需求。 +Dubbo3 基于 Dubbo2 演进而来,在保持原有核心功能特性的同时, Dubbo3 在易用性、超大规模微服务实践、云原生基础设施适配、安全设计等几大方向上进行了全面升级。 以下文档都将基于 Dubbo3 展开。* + +**对修改关闭的地方:** 对于Apache Dubbo来说 不变的是RPC调用流程,微服务治理这些抽象的概念,我们可以用摘自官网的下面几个图表示: +![在这里插入图片描述](/imgs/blog/source-blog/4-dubbo-arch.png) +
图4.1 Dubbo架构图
+ +再来看一个调用链路的架构图 + +![在这里插入图片描述](/imgs/blog/source-blog/4-dubbo-arch2.png) +
图4.2 Dubbo RPC调用链路
+ +
+上面两个图整体来看都是Dubbo不变的地方涉及到服务的RPC调用和服务治理的一些概念与流程,但是对于每个环节又可以使用各种方式实现,比如序列化机制可以是Json,Java序列化,Hession2或者Protobuf等等,网络传输层可以是netty实现的tcp通信,也可以使用http协议,那Dubbo又是如何封装不变部分扩展这种可变部分呢?,那就是接下来要说的**微内核机制**,这个我们待会说 + +**对扩展开放:** : 对于Apache Dubbo来说 变化的是RPC调用流程和微服务治理这些抽象的概念的具体实现,每个点应该用什么技术实现,又是用什么场景,这个可以用如下图来表示下: +![在这里插入图片描述](/imgs/blog/source-blog/4-dubbo-arch3.png) +
图4.3 Dubbo的扩展生态
+ +
+ +看到这里 应该各位就明白了,我们写程序是为了业务,而针对不同的业务需求很多场景下我们是需要使用不同的实现来满足的,Dubbo使用微内核的架构,将具体的实现开放出来,让使用者可以根据自己的需求来选择,定制. Dubbo开放了很多的扩展点供大家扩展,可想而知使用Dubbo的灵活性是非常高的。 + +**微内核架构:** +微内核架构由两大架构模块组成:**核心系统**与**插件模块**,设计一个微内核体系关键工作全部集中于核心系统怎么构建。 +**核心系统** : 负责和具体业务功能无关的通用功能,例如模块加载、模块间通信等,这个其实对应着Dubbo的SPI机制。 +**插件模块** : 负责实现具体的业务逻辑,Dubbo,SPI接口与实现。 + + + +## 4.3 Dubbo的扩展机制包含了哪些重要的组成部分? +前面我们说了为什么要使用扩展机制,这里我们来看下具体实现 + +先将扩展包里面的代码截个图认识认识各类型的单词 +![在这里插入图片描述](/imgs/blog/source-blog/4-dubbo-extension.png) + +顺便我们先简单看下类结构图,后续再详细看每个类型的解释: +![在这里插入图片描述](/imgs/blog/source-blog/4-dubbo-extension2.png) + +为了后续看具体的扩展加载流程我们先看下以上类型的解释说明: + + - **ExtensionAccessor** + - 扩展的统一访问器 + - **ExtensionDirector** + - ExtensionDirector是一个作用域扩展加载程序管理器。 + - ExtensionDirector支持多个级别,子级可以继承父级的扩展实例。 +查找和创建扩展实例的方法类似于Java classloader。 +- **ExtensionScope** + - 扩展SPI域,目前有FRAMEWORK,APPLICATION,MODULE,SELF + - **FRAMEWORK** : 扩展实例在框架内使用,与所有应用程序和模块共享。 +框架范围SPI扩展只能获取FrameworkModel,无法获取ApplicationModel和ModuleModel。 +考虑: +一些SPI需要在框架内的应用程序之间共享数据 +无状态SPI在框架内是安全共享的 + - **APPLICATION** 扩展实例在一个应用程序中使用,与应用程序的所有模块共享,不同的应用程序创建不同的扩展实例。 +应用范围SPI扩展可以获取FrameworkModel和ApplicationModel,无法获取ModuleModel。 +考虑: +在框架内隔离不同应用程序中的扩展数据 +在应用程序内部的所有模块之间共享扩展数据 + - **MODULE** 扩展实例在一个模块中使用,不同的模块创建不同的扩展实例。 +模块范围SPI扩展可以获得FrameworkModel、ApplicationModel和ModuleModel。 +考虑: +隔离应用程序内部不同模块中的扩展数据 + - **SELF** 自给自足,为每个作用域创建一个实例,用于特殊的SPI扩展,如ExtensionInjector + +- **ExtensionLoader** + - ApplicationModel、DubboBootstrap和这个类目前被设计为单例或静态(本身完全静态或使用一些静态字段)。因此,从它们返回的实例属于process或classloader范围。如果想在一个进程中支持多个dubbo服务器,可能需要重构这三个类。 + - 加载dubbo扩展 + - 自动注入依赖项扩展 + - 包装器中的自动包装扩展 + - 默认扩展是一个自适应实例 + - JDK自带SPI参考地址 [点击查看](https://docs.oracle.com/javase/1.5.0/docs/guide/jar/jar.html#Service%20Provider) + - @SPI 服务扩展接口 详细内容看后面 + - @Adaptive自适应扩展点注解 详细内容看后面 + - @Activate自动激活扩展点注解 详细内容看后面 + +- **ExtensionPostProcessor** + - 在扩展初始化之前或之后调用的后处理器。 +- **LoadingStrategy** + - 扩展加载策略,目前有3个扩展加载策略分别从不同文件目录加载扩展 +- **DubboInternalLoadingStrategy** + - Dubbo内置的扩展加载策略,将加载文件目录为META-INF/dubbo/internal/的扩展 +- **DubboLoadingStrategy** + - Dubbo普通的扩展加载策略,将加载目录为META-INF/dubbo/的扩展 +- **ServicesLoadingStrategy** + - JAVA SPI加载策略 ,将加载目录为META-INF/services/的扩展 +- **Wrapper**注解 +- SPI注解 +- **ExtensionInjector**接口 + - 为SPI扩展提供资源的注入器。 +- **ExtensionAccessorAware** + - SPI扩展可以实现这个感知接口,以获得适当的xtensionAccessor实例。 +- DisableInject注解 +- **AdaptiveClassCodeGenerator** + - 自适应类的代码生成器 +- **Adaptive**注解 + - 为ExtensionLoader注入依赖扩展实例提供有用信息。 + - **Activate**注解 + - Activate。此注解对于使用给定条件自动激活某些扩展非常有用,例如:@Activate可用于在有多个实现时加载某些筛选器扩展。 +**group()**指定组条件。框架SPI定义了有效的组值。 +**value()**指定URL条件中的参数键。 +SPI提供程序可以调用ExtensionLoader。getActivateExtension(URL、String、String)方法以查找具有给定条件的所有已激活扩展。 +- **ActivateComparator** + - Activate扩展的排序器 +- **MultiInstanceActivateComparator** +- **WrapperComparator** +- **AdaptiveExtensionInjector** +- **SpiExtensionInjector** + + + +## 4.4 扩展加载创建之前的调用过程 +### 4.4.1 扩展的调用代码示例 +了解了这么多与扩展相关的概念,接下来我们就来从前面的代码调用中找几个例子来看下扩展的调用过程: + +代码来源于FrameworkModel对象的初始化initialize()中的如下代码调用: + +```java + TypeDefinitionBuilder.initBuilders(this); +``` + + +TypeDefinitionBuilder中初始化类型构建器代码如下: +```java + public static void initBuilders(FrameworkModel model) { + Set tbs = model.getExtensionLoader(TypeBuilder.class).getSupportedExtensionInstances(); + BUILDERS = new ArrayList<>(tbs); + } +``` +### 4.4.2 Dubbo的分层模型获取扩展加载器对象 +以上扩展调用的时候对于扩展加载器对象的获取代码如下所示,我们来看下它的调用链路 +```java +model.getExtensionLoader(TypeBuilder.class) +``` + +getExtensionLoader方法来源于FrameworkModel类型的父类型ScopeModel的实现的接口ExtensionAccessor中的默认方法(JDK8 默认方法) + +ExtensionAccessor接口中的getExtensionLoader方法如下代码: + +```java +default ExtensionLoader getExtensionLoader(Class type) { + return this.getExtensionDirector().getExtensionLoader(type); + } +``` + +获取扩展加载器之前需要先获取扩展访问器: +这里的链路先梳理下: + +**模型对象(FrameworkModel)-**--> **扩展访问器(ExtensionAccessor)** ---> **作用域扩展加载程序管理器(ExtensionDirector)** ---> + +这个getExtensionDirector()方法来源于FrameworkModel的抽象父类型ScopeModel中的getExtensionDirector()如下代码: + +```java +@Override + public ExtensionDirector getExtensionDirector() { + return extensionDirector; + } +``` + +这里直接返回了extensionDirector,,不知道介绍到这里记得这个扩展加载程序管理器extensionDirector对象的由来不, 在上个章节[《3-框架,应用程序,模块领域模型Model对象的初始化》](https://blog.elastic.link/2022/07/10/dubbo/3-kuang-jia-ying-yong-cheng-xu-mo-kuai-ling-yu-mo-xing-model-dui-xiang-de-chu-shi-hua/)中3.2.2 初始化ScopeModel的章节中的ScopeModel类型的初始化方法initialize()方法中我们提到过这个对象的创建,具体代码如下所示(这个代码比较简单): +```java +this.extensionDirector = new ExtensionDirector(parent != null ? parent.getExtensionDirector() : null, scope, this); + +``` + +我们继续前面getExtensionLoader(type)方法调用逻辑,前面我们知道了这个扩展访问器的对象是ExtensionDirector,接下来我们看下ExtensionDirector中获取扩展加载器的代码(如下所示): +在详细介绍扩展加载器对象获取之前我们先来看下当前我们要加载的扩展类型的源码,后续会用到: +我们要加载的扩展类型TypeBuilder接口 +```java +@SPI(scope = ExtensionScope.FRAMEWORK) +public interface TypeBuilder extends Prioritized { + + /** + * Whether the build accept the class passed in. + */ + boolean accept(Class clazz); + + /** + * Build type definition with the type or class. + */ + TypeDefinition build(Type type, Class clazz, Map typeCache); + +} +``` + + +ExtensionDirector类型中获取扩展加载器的代码 +这个代码非常有意思 **其实就是前面说到的域模型架构的数据访问架构**类似于JVM类加载器访问加载类的情况,但是这个顺序可能有所不同,Dubbo的扩展加载器是如何访问的呢? 遵循以下顺序: +- 先从**缓存中**查询扩展加载器 +- 如果前面没找到则查询扩展类型的scope所属域,如果是**当前域扩展**则从直接创建扩展加载器 +- 如果前面没找到就从**父扩展访问器**中查询,查询这个扩展是否数据父扩展域 +- 前面都没找到就尝试创建 + +```java +@Override + public ExtensionLoader getExtensionLoader(Class type) { + //如果扩展加载器已经被销毁则抛出异常 + checkDestroyed(); + //这里参数类型传的是TypeBuilder.class不为空 + if (type == null) { + throw new IllegalArgumentException("Extension type == null"); + } + //扩展类型不为接口也要抛出异常,这个TypeBuilder.class具体类型代码往上看,这个类型是一个接口 + if (!type.isInterface()) { + throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!"); + } + //这个判断逻辑是判断这个扩展接口是有有@SPI注解,TypeBuilder是有的 + if (!withExtensionAnnotation(type)) { + throw new IllegalArgumentException("Extension type (" + type + + ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!"); + } + + // 1. find in local cache + //被加载的扩展类型对应的扩展加载器会放到extensionLoadersMap这个ConcurrentHashMap类型的集合中方便缓存 + ExtensionLoader loader = (ExtensionLoader) extensionLoadersMap.get(type); + //查询扩展所属域,这个类型的扩展域是框架级别的ExtensionScope.FRAMEWORK + //extensionScopeMap为ConcurrentHashMap类型的扩展域缓存集合 + ExtensionScope scope = extensionScopeMap.get(type); + if (scope == null) { + SPI annotation = type.getAnnotation(SPI.class); + scope = annotation.scope(); + extensionScopeMap.put(type, scope); + } + //首次访问的时候当前类型的扩展加载器类型肯定是空的,会走如下两个逻辑中的其中一个进行创建扩展加载器 + //1)如果 扩展域为SELF 自给自足,为每个作用域创建一个实例,用于特殊的SPI扩展,如{@link ExtensionInjector} + if (loader == null && scope == ExtensionScope.SELF) { + // create an instance in self scope + loader = createExtensionLoader0(type); + } + + // 2. find in parent + //3) 从父扩展加载器中查询当前扩展加载器是否存在,这里parent是空的先不考虑 + if (loader == null) { + if (this.parent != null) { + loader = this.parent.getExtensionLoader(type); + } + } + + // 3. create it + //4) 这个是我们本次会走的逻辑,大部分是会走这个逻辑来创建扩展加载器对象的 + if (loader == null) { + loader = createExtensionLoader(type); + } + + return loader; + } +``` + + + +前面提到的withExtensionAnnotation判断代码如下: +```java +private static boolean withExtensionAnnotation(Class type) { + return type.isAnnotationPresent(SPI.class); + } +``` + + +ExtensionDirector类型的createExtensionLoader方法 + +```java +private ExtensionLoader createExtensionLoader(Class type) { + ExtensionLoader loader = null; + //当前类型注解的scope与当前扩展访问器ExtensionDirector的scope是否一致,不一致则抛出异常 + //当前类型ExtensionDirector的scope是在构造器中传递的,在Model对象初始化的时候创建的本类型 + if (isScopeMatched(type)) { + // if scope is matched, just create it + loader = createExtensionLoader0(type); + } else { + // if scope is not matched, ignore it + } + return loader; + } +``` + +ExtensionDirector类型的createExtensionLoader0方法 +```java + private ExtensionLoader createExtensionLoader0(Class type) { + //检查当前扩展访问器是否被销毁掉了 + checkDestroyed(); + ExtensionLoader loader; + //为当前扩展类型创建一个扩展访问器并缓存到,当前成员变量extensionLoadersMap中 + extensionLoadersMap.putIfAbsent(type, new ExtensionLoader(type, this, scopeModel)); + loader = (ExtensionLoader) extensionLoadersMap.get(type); + return loader; + } +``` +### 4.4.3 扩展加载器对象ExtensionLoader的构造器 +扩展加载器相对来说是比较复杂的实现内容比较多,用到哪里我们说下哪里,这里先来看ExtensionLoader的构造器代码如下所示: + +```java + ExtensionLoader(Class type, ExtensionDirector extensionDirector, ScopeModel scopeModel) { + //当前扩展加载器,需要加载的扩展的类型 + this.type = type; + //创建扩展加载器的扩展访问器对象 + this.extensionDirector = extensionDirector; + //从扩展访问器中获取扩展执行前后的回调器 + this.extensionPostProcessors = extensionDirector.getExtensionPostProcessors(); + //创建实例化对象的策略对象 + initInstantiationStrategy(); + //如果当前扩展类型为扩展注入器类型则设置当前注入器变量为空,否则的话获取一个扩展注入器扩展对象 + this.injector = (type == ExtensionInjector.class ? null : extensionDirector.getExtensionLoader(ExtensionInjector.class) + .getAdaptiveExtension()); + //创建Activate注解的排序器 + this.activateComparator = new ActivateComparator(extensionDirector); + //为扩展加载器下的域模型对象赋值 + this.scopeModel = scopeModel; + } +``` + + +先来看 创建实例化对象的策略对象代码 initInstantiationStrategy(); + +```java +private void initInstantiationStrategy() { + for (ExtensionPostProcessor extensionPostProcessor : extensionPostProcessors) { + //ScopeModelAwareExtensionProcessor在域模型对象时候为扩展访问器添加了这个域模型扩展处理器对象ScopeModelAwareExtensionProcessor,这个类型实现了ScopeModelAccessor域模型访问器可以用来获取域模型对象 + if (extensionPostProcessor instanceof ScopeModelAccessor) { + + instantiationStrategy = new InstantiationStrategy((ScopeModelAccessor) extensionPostProcessor); + break; + } + } + if (instantiationStrategy == null) { + instantiationStrategy = new InstantiationStrategy(); + } + } +``` + +再来看ExtensionInjector扩展对象的获取 + +```java +//1)这里有个type为空的判断,普通的扩展类型肯定不是ExtensionInjector类型 这里必定会为每个非扩展注入ExtensionInjector类型创建一个ExtensionInjector类型的扩展对象, +//2) 这里代码会走extensionDirector.getExtensionLoader(ExtensionInjector.class)这一步进去之后的代码刚刚看过就不再看了,这个代码会创建一个为ExtensionInjector扩展对象的加载器对象ExtensionLoader +//3) getAdaptiveExtension() 这个方法就是通过扩展加载器获取具体的扩展对象的方法我们会详细说 + this.injector = (type == ExtensionInjector.class ? null : extensionDirector.getExtensionLoader(ExtensionInjector.class) + .getAdaptiveExtension()); +``` + + + +原文: [<>](https://blog.elastic.link/2022/07/10/dubbo/4-dubbo-de-spi-kuo-zhan-ji-zhi-yu-extensionloader-dui-xiang-de-chuang-jian-yuan-ma-jie-xi/ ) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/5 \350\207\252\351\200\202\345\272\224\346\211\251\345\261\225\345\257\271\350\261\241\347\232\204\345\210\233\345\273\272getAdaptiveExtension\346\226\271\346\263\225.md" "b/content/en/blog/java/codeanalysis/3.0.8/5 \350\207\252\351\200\202\345\272\224\346\211\251\345\261\225\345\257\271\350\261\241\347\232\204\345\210\233\345\273\272getAdaptiveExtension\346\226\271\346\263\225.md" new file mode 100644 index 000000000000..e89dd0f491a2 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/5 \350\207\252\351\200\202\345\272\224\346\211\251\345\261\225\345\257\271\350\261\241\347\232\204\345\210\233\345\273\272getAdaptiveExtension\346\226\271\346\263\225.md" @@ -0,0 +1,813 @@ +--- +title: "05-自适应扩展对象的创建getAdaptiveExtension方法" +linkTitle: "5-自适应扩展对象的创建getAdaptiveExtension方法" +date: 2022-08-05 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] Dubbo是一个微内核框架,所有的实现都是通过扩展机制来实现的,了解扩展加载机制可以有效的逻辑代码的抽象与具体逻辑 +--- + + +## 5 自适应扩展对象的创建getAdaptiveExtension方法 +自适应扩展又称为动态扩展,可以在运行时生成扩展对象 + +ExtensionLoader中的getAdaptiveExtension()方法,这个方法也是我们看到的第一个获取扩展对象的方法. ,这个方法可以帮助我们通过SPI机制从扩展文件中找到需要的扩展类型并创建它的对象, +**自适应扩展:**如果对设计模式比较了解的可能会联想到**适配器模式**,自适应扩展其实就是适配器模式的思路,自适应扩展有两种策略: + +- 一种是我们自己实现自适应扩展:然后使用@Adaptive修饰这个时候适配器的逻辑由我们自己实现,当扩展加载器去查找具体的扩展的时候可以通过找到我们这个对应的适配器扩展,然后适配器扩展帮忙去查询真正的扩展,这个比如我们下面要举的扩展注入器的例子,具体扩展通过扩展注入器适配器,注入器适配器来查询具体的注入器扩展实现来帮忙查找扩展。 + +- 还有一种方式是我们未实现这个自适应扩展,Dubbo在运行时通过字节码动态代理的方式在运行时生成一个适配器,使用这个适配器映射到具体的扩展. 第二种情况往往用在比如 Protocol、Cluster、LoadBalance 等。有时,有些拓展并不想在框架启动阶段被加载,而是希望在拓展方法被调用时,根据运行时参数进行加载。(如果还不了解可以考虑看下@Adaptive注解加载方法上面的时候扩展是如何加载的) + +```java + public T getAdaptiveExtension() { + //检查当前扩展加载器是否已经被销毁 + checkDestroyed(); + //从自适应扩展缓存中查询扩展对象如果存在就直接返回,这个自适应扩展类型只会有一个扩展实现类型如果是多个的话根据是否可以覆盖参数决定扩展实现类是否可以相互覆盖 + Object instance = cachedAdaptiveInstance.get(); + //这个if判断不太优雅 容易多层嵌套,上面instance不为空就可以直接返回了 + if (instance == null) { + //创建异常则抛出异常直接返回(多线程场景下可能第一个线程异常了第二个线程进来之后走到这里) + if (createAdaptiveInstanceError != null) { + throw new IllegalStateException("Failed to create adaptive instance: " + + createAdaptiveInstanceError.toString(), + createAdaptiveInstanceError); + } + //加锁排队 (单例模式创建对象的思想 双重校验锁) + synchronized (cachedAdaptiveInstance) { + //加锁的时候对象都是空的,进来之后先判断下防止重复创建 + instance = cachedAdaptiveInstance.get(); + //只有第一个进来锁的对象为空开始创建扩展对象 + if (instance == null) { + try { + //根据SPI机制获取类型,创建对象 + instance = createAdaptiveExtension(); + //存入缓存 + cachedAdaptiveInstance.set(instance); + } catch (Throwable t) { + createAdaptiveInstanceError = t; + throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t); + } + } + } + } + + return (T) instance; + } +``` + +前面使用单例思想来调用创建自适应扩展对象的方法,下面就让我们深入探究下创建自适应扩展对象的整个过程createAdaptiveExtension();方法: + + +## 5.1 创建扩展对象的生命周期方法-注意这个后续会详细解析这个声明周期方法的细节 + +createAdaptiveExtension() +我们先来看ExtensionLoader类型中的createAdaptiveExtension();方法,这个方法包含了扩展对象创建初始化的整个生命周期,如下代码所示: + +```java +private T createAdaptiveExtension() { + try { + //获取扩展类型实现类, 创建扩展对象 + T instance = (T) getAdaptiveExtensionClass().newInstance(); + //注入扩展对象之前的回调方法 + instance = postProcessBeforeInitialization(instance, null); + //注入扩展对象 + instance = injectExtension(instance); + //注入扩展对象之后的回调方法 + instance = postProcessAfterInitialization(instance, null); + //初始化扩展对象的属性,如果当前扩展实例的类型实现了Lifecycle则调用当前扩展对象的生命周期回调方法initialize()(来自Lifecycle接口) + //参考样例第一个instance为ExtensionInjector的自适应扩展对象类型为AdaptiveExtensionInjector,自适应扩展注入器(适配器)用来查询具体支持的扩展注入器比如scope,spi,spring注入器 + initExtension(instance); + return instance; + } catch (Exception e) { + throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e); + } + } +``` + +## 5.2 SPI机制获取扩展对象实现类型getAdaptiveExtensionClass() +这个方法可以帮助我们了解具体的Dubbo SPI机制 如果找到扩展类型的实现类,会寻找哪些文件,扩展文件的优先级又是什么,对我们自己写扩展方法很有帮助,接下来我们就来看下它的源码: + +```java + private Class getAdaptiveExtensionClass() { + //获取扩展类型,将扩展类型存入成员变量cachedClasses中进行缓存 + getExtensionClasses(); + //在上个方法的详细解析中的最后一步loadClass方法中如果扩展类型存在Adaptive注解将会将扩展类型赋值给cachedAdaptiveClass,否则的话会把扩展类型都缓存起来存储在扩展集合extensionClasses中 + if (cachedAdaptiveClass != null) { + return cachedAdaptiveClass; + } + //扩展实现类型没有一个这个自适应注解Adaptive时候会走到这里 + //刚刚我们扫描到了扩展类型然后将其存入cachedClasses集合中了 接下来我们看下如何创建扩展类型 + return cachedAdaptiveClass = createAdaptiveExtensionClass(); + } +``` + +继续看获取扩展类型的方法**getExtensionClasses()**: + +```java + private Map> getExtensionClasses() { + //缓存中查询扩展类型是否存在 + Map> classes = cachedClasses.get(); + if (classes == null) { + //单例模式双重校验锁判断 + synchronized (cachedClasses) { + classes = cachedClasses.get(); + if (classes == null) { + //加载扩展类型 + classes = loadExtensionClasses(); + //将我们扫描到的扩展类型存入成员变量cachedClasses中 + cachedClasses.set(classes); + } + } + } + return classes; + } +``` + +### 5.2.1 使用不同的的策略加载加载不同目录下的扩展 +加载扩展类型的方法**loadExtensionClasses()** + +```cpp + private Map> loadExtensionClasses() { + //检查扩展加载器是否被销毁 + checkDestroyed(); + //缓存默认的扩展名到成员变量cachedDefaultName中 + cacheDefaultExtensionName(); + //加载到的扩展集合 + Map> extensionClasses = new HashMap<>(); + //扩展策略,在4.3章节中我们介绍了这个类型的UML与说明 + //LoadingStrategy扩展加载策略,目前有3个扩展加载策略 + //DubboInternalLoadingStrategy:Dubbo内置的扩展加载策略,将加载文件目录为META-INF/dubbo/internal/的扩展 + //DubboLoadingStrategy:Dubbo普通的扩展加载策略,将加载目录为META-INF/dubbo/的扩展 + //ServicesLoadingStrategy:JAVA SPI加载策略 ,将加载目录为META-INF/services/的扩展 + //扩展策略集合对象在什么时候初始化的呢在成员变量初始化的时候就创建了集合对象,这个可以看方法loadLoadingStrategies() 通过Java的 SPI加载策略 + for (LoadingStrategy strategy : strategies) { + //根据策略从指定文件目录中加载扩展类型 + loadDirectory(extensionClasses, strategy, type.getName()); + + // compatible with old ExtensionFactory + //如果当前要加载的扩展类型是扩展注入类型则扫描下ExtensionFactory类型的扩展 + if (this.type == ExtensionInjector.class) { + //这个方法和上面那个方法是一样的就不详细说了 扫描文件 找到扩展类型 + loadDirectory(extensionClasses, strategy, ExtensionFactory.class.getName()); + } + } + //通过loadDirectory扫描 扫描到了ExtensionInjector类型的扩展实现类有3个 我们将会得到这样一个集合例子: + //"spring" -> "class org.apache.dubbo.config.spring.extension.SpringExtensionInjector" + //"scopeBean" -> "class org.apache.dubbo.common.beans.ScopeBeanExtensionInjector" + //"spi" -> "class org.apache.dubbo.common.extension.inject.SpiExtensionInjector" + return extensionClasses; + } +``` + + + 从文件中加载扩展实现loadDirectory方法: + +```java + private void loadDirectory(Map> extensionClasses, LoadingStrategy strategy, String type) { + //加载并根据策略的参数来加载 + loadDirectory(extensionClasses, strategy.directory(), type, strategy.preferExtensionClassLoader(), + strategy.overridden(), strategy.includedPackages(), strategy.excludedPackages(), strategy.onlyExtensionClassLoaderPackages()); + //下面两行就是要兼容alibaba的扩展包了 + String oldType = type.replace("org.apache", "com.alibaba"); + loadDirectory(extensionClasses, strategy.directory(), oldType, strategy.preferExtensionClassLoader(), + strategy.overridden(), strategy.includedPackagesInCompatibleType(), strategy.excludedPackages(), strategy.onlyExtensionClassLoaderPackages()); + } +``` + +带扩展策略参数的loadDirectory方法 + +关于扩展策略的参数列表我这里列个表格方便大家来看 + +|扩展类型|dir(目录) | extensionLoaderClassLoaderFirst(优先扩展类型的类加载器)|overridden(是否允许覆盖同名扩展)|includedPackages (明确包含的扩展包) | excludedPackages (明确排除的扩展包)|onlyExtensionClassLoaderPackages(限制应该从Dubbo的类加载器加载的类)| +|--|--|--|--|--|--|--| +| DubboInternalLoadingStrategy | META-INF/dubbo/internal/ |false|false|null|null|[]| +|DubboLoadingStrategy|META-INF/dubbo/|false|true|null|null|[]| +|ServicesLoadingStrategy|META-INF/services/|false|true|null|null|[]| + + +```java + /** + * 不同的扩展策略传递了不同的参数,但是扩展的加载流程是相同的,这里我们可以参考上面表格 + * @param extensionClasses + * @param dir + * @param type 这里我们参考的示例这个值为org.apache.dubbo.common.extension.ExtensionInjector + * @param extensionLoaderClassLoaderFirst + * @param overridden false + * @param includedPackages + * @param excludedPackages + * @param onlyExtensionClassLoaderPackages + */ +private void loadDirectory(Map> extensionClasses, String dir, String type, + boolean extensionLoaderClassLoaderFirst, boolean overridden, String[] includedPackages, + String[] excludedPackages, String[] onlyExtensionClassLoaderPackages) { + //扩展目录 + 扩展类型全路径 比如: META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionInjector + String fileName = dir + type; + try { + List classLoadersToLoad = new LinkedList<>(); + + // try to load from ExtensionLoader's ClassLoader first + //是否优先使用扩展加载器的 类加载器 + if (extensionLoaderClassLoaderFirst) { + ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader(); + if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) { + classLoadersToLoad.add(extensionLoaderClassLoader); + } + } + + // load from scope model + //获取域模型对象的类型加载器 ,这个域模型对象在初始化的时候会将自己的类加载器放入集合中可以参考《3.2.2 初始化ScopeModel》章节 + Set classLoaders = scopeModel.getClassLoaders(); + + //没有可用的类加载器则从使用 + if (CollectionUtils.isEmpty(classLoaders)) { + //从用于加载类的搜索路径中查找指定名称的所有资源。 + Enumeration resources = ClassLoader.getSystemResources(fileName); + if (resources != null) { + while (resources.hasMoreElements()) { + loadResource(extensionClasses, null, resources.nextElement(), overridden, includedPackages, excludedPackages, onlyExtensionClassLoaderPackages); + } + } + } else { + classLoadersToLoad.addAll(classLoaders); + } + //使用类加载资源加载器(ClassLoaderResourceLoader)来加载具体的资源 + Map> resources = ClassLoaderResourceLoader.loadResources(fileName, classLoadersToLoad); + //遍历从所有资源文件中读取到资源url地址,key为类加载器,值为扩展文件url如夏所示 + //jar:file:/Users/song/.m2/repository/org/apache/dubbo/dubbo/3.0.7/dubbo-3.0.7.jar!/META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionInjector + resources.forEach(((classLoader, urls) -> { + //从文件中加载完资源之后开始根据类加载器和url加载具体的扩展类型,最后将扩展存放进extensionClasses集合 + loadFromClass(extensionClasses, overridden, urls, classLoader, includedPackages, excludedPackages, onlyExtensionClassLoaderPackages); + })); + } catch (Throwable t) { + logger.error("Exception occurred when loading extension class (interface: " + + type + ", description file: " + fileName + ").", t); + } + } +``` + +### 5.2.2 借助类加载器的getResources方法遍历所有文件进行扩展文件的查询 + +查找扩展类型对应的扩展文件的url方法:ClassLoaderResourceLoader类型的loadResources源码: + +```cpp +public static Map> loadResources(String fileName, List classLoaders) { + // + Map> resources = new ConcurrentHashMap<>(); + //不同的类加载器之间使用不同的线程异步的方式进行扫描 + CountDownLatch countDownLatch = new CountDownLatch(classLoaders.size()); + for (ClassLoader classLoader : classLoaders) { + //多线程扫描,这个是个newCachedThreadPool的类型的线程池 + GlobalResourcesRepository.getGlobalExecutorService().submit(() -> { + // + resources.put(classLoader, loadResources(fileName, classLoader)); + countDownLatch.countDown(); + }); + } + try { + countDownLatch.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return Collections.unmodifiableMap(new LinkedHashMap<>(resources)); + } +``` + + +加载具体类加载器中的资源文件的loadResources方法 +```cpp +public static Set loadResources(String fileName, ClassLoader currentClassLoader) { + Map>> classLoaderCache; + //第一次进来类加载器资源缓存是空的 + if (classLoaderResourcesCache == null || (classLoaderCache = classLoaderResourcesCache.get()) == null) { + //类对象锁 + synchronized (ClassLoaderResourceLoader.class) { + if (classLoaderResourcesCache == null || (classLoaderCache = classLoaderResourcesCache.get()) == null) { + classLoaderCache = new ConcurrentHashMap<>(); + //创建一个类资源映射url的软引用缓存对象 + //软引用(soft references),用于帮助垃圾收集器管理内存使用和消除潜在的内存泄漏。当内存快要不足的时候,GC会迅速的把所有的软引用清除掉,释放内存空间 + classLoaderResourcesCache = new SoftReference<>(classLoaderCache); + } + } + } + //第一次进来时候类加载器url映射缓存是空的,给类加载器缓存对象新增一个值,key是类加载器,值是map类型用来存储文件名对应的url集合 + if (!classLoaderCache.containsKey(currentClassLoader)) { + classLoaderCache.putIfAbsent(currentClassLoader, new ConcurrentHashMap<>()); + } + + Map> urlCache = classLoaderCache.get(currentClassLoader); + //缓存中没有就从文件里面找 + if (!urlCache.containsKey(fileName)) { + Set set = new LinkedHashSet<>(); + Enumeration urls; + try { + //getResources这个方法是这样的:加载当前类加载器以及父类加载器所在路径的资源文件,将遇到的所有资源文件全部返回!这个可以理解为使用双亲委派模型中的类加载器 加载各个位置的资源文件 + urls = currentClassLoader.getResources(fileName); + //native配置 是否为本地镜像(k可以参考官方文档:https://dubbo.apache.org/zh-cn/docs/references/graalvm/support-graalvm/ + boolean isNative = NativeUtils.isNative(); + if (urls != null) { + //遍历找到的对应扩展的文件url将其加入集合 + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + if (isNative) { + //In native mode, the address of each URL is the same instead of different paths, so it is necessary to set the ref to make it different + //动态修改jdk底层url对象的ref变量为可访问,让我们在用反射时访问私有变量 + setRef(url); + } + set.add(url); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + //存入缓存 + urlCache.put(fileName, set); + } + //返回结果 + return urlCache.get(fileName); + } +``` + + +### 5.2.3 使用找到的扩展资源url加载具体扩展类型到内存 + +ExtensionLoader类型中的loadFromClass方法 遍历url 开始加载扩展类型 +```java + private void loadFromClass(Map> extensionClasses, boolean overridden, Set urls, ClassLoader classLoader, + String[] includedPackages, String[] excludedPackages, String[] onlyExtensionClassLoaderPackages) { + if (CollectionUtils.isNotEmpty(urls)) { + for (java.net.URL url : urls) { + loadResource(extensionClasses, classLoader, url, overridden, includedPackages, excludedPackages, onlyExtensionClassLoaderPackages); + } + } + } +``` + +ExtensionLoader类型中的loadResource方法 使用IO流读取扩展文件的内容 +读取内容之前我这里先贴一下我们参考的扩展注入类型的文件中的内容如下所示: + +```cpp +adaptive=org.apache.dubbo.common.extension.inject.AdaptiveExtensionInjector +spi=org.apache.dubbo.common.extension.inject.SpiExtensionInjector +scopeBean=org.apache.dubbo.common.beans.ScopeBeanExtensionInjector +``` + +扩展中的文件都是一行一行的,并且扩展名字和扩展类型之间使用等号隔开= +了解了文件内容之后 应该下面的代码大致思路就知道了,我们可以详细看下 + +```java +private void loadResource(Map> extensionClasses, ClassLoader classLoader, + java.net.URL resourceURL, boolean overridden, String[] includedPackages, String[] excludedPackages, String[] onlyExtensionClassLoaderPackages) { + try { + //这里固定了文件的格式为utf8 + try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) { + String line; + String clazz; + //按行读取 例如读取到的内容:spring=org.apache.dubbo.config.spring.extension.SpringExtensionInjector + while ((line = reader.readLine()) != null) { + //不知道为何会有这么一行代码删除#之后的字符串 + final int ci = line.indexOf('#'); + if (ci >= 0) { + line = line.substring(0, ci); + } + line = line.trim(); + // + if (line.length() > 0) { + try { + String name = null; + //扩展文件可能如上面我贴的那样 名字和类型等号隔开,也可能是无类型的,例如扩展加载策略使用的是JDK自带的方式services内容中只包含具体的扩展类型 + int i = line.indexOf('='); + if (i > 0) { + name = line.substring(0, i).trim(); + clazz = line.substring(i + 1).trim(); + } else { + clazz = line; + } + //isExcluded是否为加载策略要排除的配置,参数这里为空代表全部类型不排除 + //isIncluded是否为加载策略包含的类型,参数这里为空代表全部文件皆可包含 + //onlyExtensionClassLoaderPackages参数是否只有扩展类的类加载器可以加载扩展,其他扩展类型的类加载器不能加载扩展 这里结果为false 不排除任何类加载器 + if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages) && isIncluded(clazz, includedPackages) + && !isExcludedByClassLoader(clazz, classLoader, onlyExtensionClassLoaderPackages)) { + //根据类全路径加载类到内存 + loadClass(extensionClasses, resourceURL, Class.forName(clazz, true, classLoader), name, overridden); + } + } catch (Throwable t) { + IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t); + exceptions.put(line, e); + } + } + } + } + } catch (Throwable t) { + logger.error("Exception occurred when loading extension class (interface: " + + type + ", class file: " + resourceURL + ") in " + resourceURL, t); + } + } +``` + + +ExtensionLoader类型中的loadClass方法加载具体的类到内存 +```java +private void loadClass(Map> extensionClasses, java.net.URL resourceURL, Class clazz, String name, + boolean overridden) throws NoSuchMethodException { + //当前clazz是否为type的子类型 + //这里第一次访问到的type是ExtensionInjector,clazz是SpringExtensionInjector 父子类型关系满足情况 + if (!type.isAssignableFrom(clazz)) { + throw new IllegalStateException("Error occurred when loading extension class (interface: " + + type + ", class line: " + clazz.getName() + "), class " + + clazz.getName() + " is not subtype of interface."); + } + //扩展子类型是否存在这个注解@Adaptive + if (clazz.isAnnotationPresent(Adaptive.class)) { + cacheAdaptiveClass(clazz, overridden); + } else if (isWrapperClass(clazz)) { + //扩展子类型构造器中是否有这个类型的接口 (这个可以想象下我们了解的Java IO流中的类型使用到的装饰器模式 构造器传个类型) + cacheWrapperClass(clazz); + } else { + //无自适应注解,也没有构造器是扩展类型参数 ,这个name我们在扩展文件中找到了就是等号前面那个 + if (StringUtils.isEmpty(name)) { + //低版本中可以使用@Extension 扩展注解来标注扩展类型,这里获取注解有两个渠道: + //先查询@Extension注解是否存在如果存在则取value值,如果不存在@Extension注解则获取当前类型的名字 + name = findAnnotationName(clazz); + if (name.length() == 0) { + throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL); + } + } + //获取扩展名字数组,扩展名字可能为逗号隔开的 + String[] names = NAME_SEPARATOR.split(name); + if (ArrayUtils.isNotEmpty(names)) { + //@Activate注解修饰的扩展 + cacheActivateClass(clazz, names[0]); + for (String n : names) { + //cachedNames缓存集合缓存当前扩展类型的扩展名字 + cacheName(clazz, n); + //将扩展类型加入结果集合extensionClasses中,不允许覆盖的话出现同同名字扩展将抛出异常 + saveInExtensionClass(extensionClasses, clazz, n, overridden); + } + } + } + } +``` + + + +ExtensionLoader类型中cacheAdaptiveClass +Adaptive 机制,即扩展类的自适应机制。即其可以指定想要加载的扩展名,也可以不指定。若不指定,则直接加载默认的扩展类。即其会自动匹配,做到自适应。其是通过@Adaptive注解实现的。 +自适应注解修饰的扩展同一个扩展名字只能有一个扩展实现类型, 扩展策略中提供的参数overridden是否允许覆盖扩展覆盖 +```java +private void cacheAdaptiveClass(Class clazz, boolean overridden) { + if (cachedAdaptiveClass == null || overridden) { + //成员变量存储这个自适应扩展类型 + cachedAdaptiveClass = clazz; + } else if (!cachedAdaptiveClass.equals(clazz)) { + throw new IllegalStateException("More than 1 adaptive class found: " + + cachedAdaptiveClass.getName() + + ", " + clazz.getName()); + } + } +``` + +ExtensionLoader类型中cacheWrapperClass +Wrapper 机制,即扩展类的包装机制。就是对扩展类中的 SPI 接口方法进行增强,进行包装,是 AOP 思想的体现,是 Wrapper 设计模式的应用。一个 SPI 可以包含多个 Wrapper。这个也是可以同一个类型多个 +```java +private void cacheWrapperClass(Class clazz) { + if (cachedWrapperClasses == null) { + cachedWrapperClasses = new ConcurrentHashSet<>(); + } + //缓存这个Wrapper类型的扩展 + cachedWrapperClasses.add(clazz); + } +``` + + + +ExtensionLoader类型中cacheActivateClass +Activate用于激活扩展类的。 这个扩展类型可以出现多个比如过滤器可以同一个扩展名字多个过滤器实现,所以不需要有override判断 +Activate 机制,即扩展类的激活机制。通过指定的条件来激活当前的扩展类。其是通过@Activate 注解实现的。 + +```cpp +private void cacheActivateClass(Class clazz, String name) { + Activate activate = clazz.getAnnotation(Activate.class); + if (activate != null) { + //缓存Activate类型的扩展 + cachedActivates.put(name, activate); + } else { + // support com.alibaba.dubbo.common.extension.Activate + com.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class); + if (oldActivate != null) { + cachedActivates.put(name, oldActivate); + } + } + } +``` + +ExtensionLoader类型中的saveInExtensionClass方法 + + 上面扩展对象加载了这么多最终的目的就是将这个扩展类型存放进结果集合extensionClasses中,扩展策略中提供的参数overridden是否允许覆盖扩展覆盖 +```cpp +private void saveInExtensionClass(Map> extensionClasses, Class clazz, String name, boolean overridden) { + Class c = extensionClasses.get(name); + if (c == null || overridden) { + //上面扩展对象加载了这么多最终的目的就是将这个扩展类型存放进结果集合中 + extensionClasses.put(name, clazz); + } else if (c != clazz) { + // duplicate implementation is unacceptable + unacceptableExceptions.add(name); + String duplicateMsg = "Duplicate extension " + type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName(); + logger.error(duplicateMsg); + throw new IllegalStateException(duplicateMsg); + } + } +``` + + +## 5.3 自适应扩展代理对象的代码生成与编译 +### 5.3.1 自适应扩展对象的创建 + +Dubbo 的**自适应扩展机制**中如果 **自己生成了自适应扩展的代理类** + +Dubbo 的自适应扩展为了做什么:**在运行时动态调用扩展方法**。以及怎么做的:生成扩展代理类。比如: 代理类中根据 URL 获取扩展名,使用 SPI 加载扩展类,并调用同名方法,返回执行结果。 + +看了上一个章节,我们了解到了Dubbo是如何通过扫描目录来查询扩展实现类的这一次我们看下扩展类我们找到了之后,如果这个扩展类型未加上这个@Adaptive注解那么是如何创建这个类型的,接下来看createAdaptiveExtensionClass方法,这个方法是借助字节码工具来动态生成所需要的扩展类型的包装类型的代码,这个代码在编译时我们可能看不到,但是在Debug的时候,我们还是可以看到这个对象名字的,但是往往Debug的时候又进不到具体的代码位置,这里可以注意下 + +当扩展点的方法被@Adaptive修饰时,在Dubbo初始化扩展点时会自动生成和编译一个动态的Adaptive类。 + +下面我们可以以interface org.apache.dubbo.rpc.Protocol 这个协议扩展类型来看 协议扩展类型目前没有一个是带有自适应注解的 +```java +private Class createAdaptiveExtensionClass() { + // Adaptive Classes' ClassLoader should be the same with Real SPI interface classes' ClassLoader + //获取加载器 + ClassLoader classLoader = type.getClassLoader(); + try { + // //native配置 是否为本地镜像(可以参考官方文档:https://dubbo.apache.org/zh-cn/docs/references/graalvm/support-graalv + if (NativeUtils.isNative()) { + return classLoader.loadClass(type.getName() + "$Adaptive"); + } + } catch (Throwable ignore) { + + } + //创建一个代码生成器,来生成代码 详细内容我们就下一章来看 + String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate(); + //获取编译器 + org.apache.dubbo.common.compiler.Compiler compiler = extensionDirector.getExtensionLoader( + org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); + //生成的代码进行编译 + return compiler.compile(type, code, classLoader); + } +``` + + + +## 5.4 为扩展对象的set方法注入自适应扩展对象 +在4.4.5小节中我们已经讲解了获取扩展类型实现类, 创建扩展对象 + +```java + T instance = (T) getAdaptiveExtensionClass().newInstance(); + +``` + +接下来就让我们来看下为扩展对象的set方法注入自适应的扩展对象 +调用方法代码如下: + +```java + //注入扩展对象之前的回调方法 +injectExtension(instance); +``` + +ExtensionLoader类型的injectExtension方法具体代码如下: +```cpp +private T injectExtension(T instance) { + //如果注入器为空则直接返回当前对象 + if (injector == null) { + return instance; + } + + try { + //获取当前对象的当前类的所有方法 + for (Method method : instance.getClass().getMethods()) { + //是否为set方法 不是的话则跳过,在这里合法的set方法满足3个条件: + //set开头,参数只有一个,public修饰 + if (!isSetter(method)) { + continue; + } + /** + * Check {@link DisableInject} to see if we need auto injection for this property + */ + //方法上面是否有注解DisableInject修饰,这种情况也直接跳过 + if (method.isAnnotationPresent(DisableInject.class)) { + continue; + } + //方法的参数如果是原生类型也跳过 + Class pt = method.getParameterTypes()[0]; + if (ReflectUtils.isPrimitives(pt)) { + continue; + } + try { + //获取set方法对应的成员变量如setProtocol 属性为protocol + String property = getSetterProperty(method); + //根据参数类型如Protocol和属性名字如protocol获取应该注入的对象 + Object object = injector.getInstance(pt, property); + if (object != null) { + //执行对应对象和对应参数的这个方法 + method.invoke(instance, object); + } + } catch (Exception e) { + logger.error("Failed to inject via method " + method.getName() + + " of interface " + type.getName() + ": " + e.getMessage(), e); + } + + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return instance; + } +``` +### 5.4.1 获取注入对象 +这里我们主要来看下如何通过注入器找到需要注入的那个对象 调用代码如下: +```cpp + Object object = injector.getInstance(pt, property); +``` + 在前面看注入器扩展对象的获取的时候是会获取到ExtensionInjector扩展的一个自适应扩展注入器实现类型 AdaptiveExtensionInjector,这个地方对应的getInstance也是这个扩展里面的,我们来看下它的方法: + +```java + @Override + public T getInstance(Class type, String name) { + //遍历所有的扩展注入器 + for (ExtensionInjector injector : injectors) { + //遍历所有的扩展注入器,如果可以获取到扩展对象则直接返回 + T extension = injector.getInstance(type, name); + if (extension != null) { + return extension; + } + } + return null; + } +``` +可以看到上面代码按扩展注入器顺序来遍历的第一个找到的对象就直接返回了, + + 这个AdaptiveExtensionInjector在初始化的时候会获取所有的ExtensionInjector的扩展,非自适应的,它本身自适应的扩展,这里会获取非自适应的扩展列表一共有3个按顺序为: +- ScopeBeanExtensionInjector +- SpiExtensionInjector +- SpringExtensionInjector + + +接下来我们详细看下每种扩展注入器加载扩展对象的策略: + +### 5.4.2 域模型中的Bean扩展注入器ScopeBeanExtensionInjector + +ScopeBeanExtensionInjector的getInstance方法: +每个域模型都会有个ScopeBeanFactory类型的对象用于存储共享对象,并且域模型之间按照层级子类型的Bean工厂可以从父域的Bean工厂中查询对象, + +```cpp +@Override + public T getInstance(Class type, String name) { + return beanFactory.getBean(name, type); + } +``` + +ScopeBeanFactory的getBean方法 +先从当前域空间查询对象,如果找不到对应类型的扩展对象则从父域工厂查询扩展对象 +```cpp +public T getBean(String name, Class type) { + //当前域下注册的扩展对象 + T bean = getBeanInternal(name, type); + if (bean == null && parent != null) { + //父域中查找扩展对象 + return parent.getBean(name, type); + } + return bean; + } +``` + +ScopeBeanFactory的getBeanInternal方法 +从当前域下找注册的参数类型的对象 +```cpp +private T getBeanInternal(String name, Class type) { + checkDestroyed(); + // All classes are derived from java.lang.Object, cannot filter bean by it + if (type == Object.class) { + return null; + } + List candidates = null; + BeanInfo firstCandidate = null; + //遍历列表查询 + for (BeanInfo beanInfo : registeredBeanInfos) { + // if required bean type is same class/superclass/interface of the registered bean + if (type.isAssignableFrom(beanInfo.instance.getClass())) { + if (StringUtils.isEquals(beanInfo.name, name)) { + return (T) beanInfo.instance; + } else { + // optimize for only one matched bean + if (firstCandidate == null) { + firstCandidate = beanInfo; + } else { + if (candidates == null) { + candidates = new ArrayList<>(); + candidates.add(firstCandidate); + } + candidates.add(beanInfo); + } + } + } + } + + // if bean name not matched and only single candidate + if (candidates != null) { + if (candidates.size() == 1) { + return (T) candidates.get(0).instance; + } else if (candidates.size() > 1) { + List candidateBeanNames = candidates.stream().map(beanInfo -> beanInfo.name).collect(Collectors.toList()); + throw new ScopeBeanException("expected single matching bean but found " + candidates.size() + " candidates for type [" + type.getName() + "]: " + candidateBeanNames); + } + } else if (firstCandidate != null) { + return (T) firstCandidate.instance; + } + return null; + } +``` + +### 5.4.3 SPI扩展机制注入器SpiExtensionInjector + +SPI是Dubbo自行实现的一套扩展机制,我们来看下它是如何查找扩展对象的 + +```cpp +@Override + public T getInstance(Class type, String name) { + //如果是一个标准的被@SPI注解修饰的扩展接口则满足条件 + if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { + //使用扩展访问器来获取对应类型的扩展加载器 + ExtensionLoader loader = extensionAccessor.getExtensionLoader(type); + if (loader == null) { + return null; + } + //使用对应类型的扩展加载器来加载自适应扩展 这个加载的扩展可以参考4.4.6小节 + if (!loader.getSupportedExtensions().isEmpty()) { + return loader.getAdaptiveExtension(); + } + } + return null; + } +``` + + + +### 5.4.4 Spring扩展注入器 +SpringExtensionInjector + +Spring扩展注入器主要是用来从Spring容器中查询当前类型的Bean是否存在的,如下代码直接看代码吧 +```cpp +@Override + @SuppressWarnings("unchecked") + public T getInstance(Class type, String name) { + + if (context == null) { + // ignore if spring context is not bound + return null; + } + + //check @SPI annotation ,类型需要满足SPI机制 @SPI修饰的接口 + if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { + return null; + } + //从Spring容器中查询Bean + T bean = getOptionalBean(context, name, type); + if (bean != null) { + return bean; + } + + //logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName()); + return null; + } +``` + + +```cpp +private T getOptionalBean(ListableBeanFactory beanFactory, String name, Class type) { + //要搜索的扩展名字为空就根据类型搜索 + if (StringUtils.isEmpty(name)) { + //返回与给定类型(包括子类)匹配的bean的名称,对于FactoryBeans + String[] beanNamesForType = beanFactory.getBeanNamesForType(type, true, false); + if (beanNamesForType != null) { + if (beanNamesForType.length == 1) { + //返回指定bean的实例,该实例可以是共享的,也可以是独立的。 + //根据Bean Name和类型 查询具体的扩展对象 + return beanFactory.getBean(beanNamesForType[0], type); + } else if (beanNamesForType.length > 1) { + throw new IllegalStateException("Expect single but found " + beanNamesForType.length + " beans in spring context: " + + Arrays.toString(beanNamesForType)); + } + } + } else { + //扩展名字不为空则直接通过名字搜索Bean + if (beanFactory.containsBean(name)) { + return beanFactory.getBean(name, type); + } + } + return null; + } +``` + + +原文: [《自适应扩展对象的创建getAdaptiveExtension方法》](https://blog.elastic.link/2022/07/10/dubbo/5-dubbo-de-spi-kuo-zhan-ji-zhi-yu-zi-gua-ying-kuo-zhan-dui-xiang-de-chuang-jian-yu-kuo-zhan-wen-jian-de-sao-miao-yuan-ma-jie-xi/) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/6-Dubbo\347\232\204SPI\346\211\251\345\261\225\346\234\272\345\210\266\344\271\213\346\231\256\351\200\232\346\211\251\345\261\225\345\257\271\350\261\241\347\232\204\345\210\233\345\273\272\344\270\216Wrapper\346\234\272\345\210\266\347\232\204\346\272\220\347\240\201\350\247\243\346\236\220.md" "b/content/en/blog/java/codeanalysis/3.0.8/6-Dubbo\347\232\204SPI\346\211\251\345\261\225\346\234\272\345\210\266\344\271\213\346\231\256\351\200\232\346\211\251\345\261\225\345\257\271\350\261\241\347\232\204\345\210\233\345\273\272\344\270\216Wrapper\346\234\272\345\210\266\347\232\204\346\272\220\347\240\201\350\247\243\346\236\220.md" new file mode 100644 index 000000000000..047a6d6dae06 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/6-Dubbo\347\232\204SPI\346\211\251\345\261\225\346\234\272\345\210\266\344\271\213\346\231\256\351\200\232\346\211\251\345\261\225\345\257\271\350\261\241\347\232\204\345\210\233\345\273\272\344\270\216Wrapper\346\234\272\345\210\266\347\232\204\346\272\220\347\240\201\350\247\243\346\236\220.md" @@ -0,0 +1,355 @@ +--- +title: "06-Dubbo的SPI扩展机制之普通扩展对象的创建与Wrapper机制的源码解析" +linkTitle: "6-Dubbo的SPI扩展机制之普通扩展对象的创建与Wrapper机制的源码解析" +date: 2022-08-06 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] 了解Spring的同学可能比较熟悉AOP机制的逻辑,Dubbo Wrapper机制就是类似AOP这样的切面机制用来增强扩展方法,Wrapper机制,即扩展点自动包装。Wrapper 类同样实现了扩展点接口,但是 Wrapper 不是扩展点的真正实现。它的用途主要是用于从 ExtensionLoader 返回扩展点时,包装在真正的扩展点实现外 +--- + + +# 6 Dubbo的SPI扩展机制之普通扩展对象的创建与Wrapper机制的源码解析 +## 6.1 普通扩展对象的加载与创建 +这里我们要分析的是ExtensionLoader类型的getExtension(String name)方法, 有了前面自适应扩展的铺垫,这里就更容易来看了getExtension是根据扩展名字获取具体扩展的通用方法,我们来根据某个类型来获取扩展的时候就是走的这里,比如在这个博客开头的介绍: + +- ApplicationModel中获取配置管理器对象 +```java + configManager = (ConfigManager) this.getExtensionLoader(ApplicationExt.class) + .getExtension(ConfigManager.NAME); + +``` + +### 6.1.1 getExtension方法源码 +先来看下getExtension方法的源码,根据扩展名字查询扩展对象 +```cpp + +public T getExtension(String name) { + //这里并不能看到什么,只多传了个参数wrap为true调用另外一个重载的方法 + T extension = getExtension(name, true); + if (extension == null) { + throw new IllegalArgumentException("Not find extension: " + name); + } + return extension; + } +``` + + + + +```java +public T getExtension(String name, boolean wrap) { + //检查扩展加载器是否已被销毁 + checkDestroyed(); + if (StringUtils.isEmpty(name)) { + throw new IllegalArgumentException("Extension name == null"); + } + //扩展名字为true则加载默认扩展 + if ("true".equals(name)) { + return getDefaultExtension(); + } + //非wrap类型则将缓存的扩展名字key加上_origin后缀 + //wrap是aop机制 俗称切面,这个origin在aop里面可以称为切点,下面的wrap扩展可以称为增强通知的类型,普通扩展和wrap扩展的扩展名字是一样的 + String cacheKey = name; + if (!wrap) { + cacheKey += "_origin"; + } + //从cachedInstances缓存中查询 + final Holder holder = getOrCreateHolder(cacheKey); + Object instance = holder.get(); + //缓存中不存在则创建扩展对象 双重校验锁 + if (instance == null) { + synchronized (holder) { + //双重校验锁的方式 + instance = holder.get(); + if (instance == null) { + //创建扩展对象 + instance = createExtension(name, wrap); + holder.set(instance); + } + } + } + return (T) instance; + } +``` + + +我们先来看一下默认扩展的加载代码: + +```java +public T getDefaultExtension() { + //加载扩展类型对应的所有扩展SPI实现类型,在加载所有扩展实现类型的时候会缓存这个扩展的默认实现类型,将对象缓存在cachedDefaultName中 + getExtensionClasses(); + if (StringUtils.isBlank(cachedDefaultName) || "true".equals(cachedDefaultName)) { + return null; + } + //再回到加载扩展的方法 + return getExtension(cachedDefaultName); + } +``` + + +创建扩展对象方法这个和自适应扩展的创建扩展类似 +createExtension: +具体过程如下: +- 加载扩展类型:getExtensionClasses() +- 创建扩展对象:createExtensionInstance(clazz) +- 注入自适应扩展: injectExtension(instance); +- wrap处理 + +```cpp +private T createExtension(String name, boolean wrap) { + //扩展的创建的第一步扫描所有jar中的扩展实现,这里扫描完之后获取对应扩展名字的扩展实现类型的Class对象 + Class clazz = getExtensionClasses().get(name); + //出现异常了 转换下异常信息 再抛出 + if (clazz == null || unacceptableExceptions.contains(name)) { + throw findException(name); + } + try { + //当前扩展对象是否已经创建过了则直接从缓存中获取 + T instance = (T) extensionInstances.get(clazz); + if (instance == null) { + //第一次获取缓存中肯定没有则创建扩展对象然后缓存起来 + //createExtensionInstance 这个是与自适应扩展对象创建对象的不同之处 + extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz)); + instance = (T) extensionInstances.get(clazz); + instance = postProcessBeforeInitialization(instance, name); + //注入扩展自适应方法,这个方法前面讲自适应扩展时候说了,注入自适应扩展方法的自适应扩展对象 + injectExtension(instance); + instance = postProcessAfterInitialization(instance, name); + } + //是否开启了wrap + //Dubbo通过Wrapper实现AOP的方法 + if (wrap) { + //这个可以参考下Dubbo扩展的加载 + List> wrapperClassesList = new ArrayList<>(); + //wrap类型排序 这个wrap类型是如何来的呢,在前面扫描扩展类型的时候如果当前扩展类型不是Adaptive注解修饰的,并且当前类型type有个构造器参数是type自身的也是前面加载扩展类型时候说的装饰器模式 可以参考DubboProtocol的构造器 + if (cachedWrapperClasses != null) { + wrapperClassesList.addAll(cachedWrapperClasses); + //根据Wrapper注解的order值来进行排序值越小越在列表的前面 + wrapperClassesList.sort(WrapperComparator.COMPARATOR); + //反转之后值越大就会在列表的前面 + Collections.reverse(wrapperClassesList); + } + //从缓存中查到了wrapper扩展则遍历这些wrapp扩展进行筛选 + if (CollectionUtils.isNotEmpty(wrapperClassesList)) { + for (Class wrapperClass : wrapperClassesList) { + Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class); + //需要包装的扩展名。当此数组为空时,默认值为匹配 + //看下当前扩展是否匹配这个wrap,如何判断呢? + //wrapper注解不存在或者matches匹配,或者mismatches不包含当前扩展 + //如果匹配到了当前扩展对象是需要进行wrapp的就为当前扩展创建当前wrapper扩展对象进行包装 + boolean match = (wrapper == null) || + ((ArrayUtils.isEmpty(wrapper.matches()) || ArrayUtils.contains(wrapper.matches(), name)) && + !ArrayUtils.contains(wrapper.mismatches(), name)); + //这是扩展类型是匹配wrapp的则开始注入 + if (match) { + //匹配到了就创建所有的wrapper类型的对象同时构造器参数设置为当前类型 + instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); + instance = postProcessAfterInitialization(instance, name); + } + } + } + } + + // Warning: After an instance of Lifecycle is wrapped by cachedWrapperClasses, it may not still be Lifecycle instance, this application may not invoke the lifecycle.initialize hook. + //初始化扩展,如果当前扩展是Lifecycle类型则调用初始化方法 + initExtension(instance); + return instance; + } catch (Throwable t) { + throw new IllegalStateException("Extension instance (name: " + name + ", class: " + + type + ") couldn't be instantiated: " + t.getMessage(), t); + } + } +``` + + + +### 6.1.2 创建扩展对象 + +前面加载扩展类型在自适应扩展的时候已经说过了这里就不重复了,这里我们来看下 +扩展对象的创建过程:createExtensionInstance(clazz) + +前面看自适应扩展对象创建的时候自适应扩展对象仅仅是使用反射newInstance了一个扩展对象,而普通的扩展类型创建对象的过程就相对复杂一点,接下来我们来看下: + + +ExtensionLoader的createExtensionInstance方法 +```cpp +private Object createExtensionInstance(Class type) throws ReflectiveOperationException { + //在ExtensionLoader构造器中,有个initInstantiationStrategy()方法中new了一个初始化策略InstantiationStrategy类型对象 + return instantiationStrategy.instantiate(type); + } +``` + + +InstantiationStrategy的实例化对象方法instantiate +```cpp +public T instantiate(Class type) throws ReflectiveOperationException { + + // should not use default constructor directly, maybe also has another constructor matched scope model arguments + // 1. try to get default constructor + Constructor defaultConstructor = null; + try { + //反射获取对应类型的无参构造器 + defaultConstructor = type.getConstructor(); + } catch (NoSuchMethodException e) { + // ignore no default constructor + } + + // 2. use matched constructor if found + List matchedConstructors = new ArrayList<>(); + //获取所有构造器 + Constructor[] declaredConstructors = type.getConstructors(); + //遍历构造器列表, + for (Constructor constructor : declaredConstructors) { + //如果存在构造器则构造器参数类型是否为ScopeModel类型,如果为ScopeModel则为匹配的构造器 说明我们扩展类型在这个版本如果想要让这个构造器生效必须参数类型为ScopeModel + if (isMatched(constructor)) { + matchedConstructors.add(constructor); + } + } + // remove default constructor from matchedConstructors + if (defaultConstructor != null) { + matchedConstructors.remove(defaultConstructor); + } + + // match order: + // 1. the only matched constructor with parameters + // 2. default constructor if absent + + Constructor targetConstructor; + //匹配的参数ScopeModel的构造器太多了就抛出异常 + if (matchedConstructors.size() > 1) { + throw new IllegalArgumentException("Expect only one but found " + + matchedConstructors.size() + " matched constructors for type: " + type.getName() + + ", matched constructors: " + matchedConstructors); + } else if (matchedConstructors.size() == 1) { + //一个参数一般为一个参数类型ScopeModel的构造器 + targetConstructor = matchedConstructors.get(0); + } else if (defaultConstructor != null) { + //如果没有自定义构造器则使用空参数构造器 + targetConstructor = defaultConstructor; + } else { + //一个构造器也没匹配上也要报错 + throw new IllegalArgumentException("None matched constructor was found for type: " + type.getName()); + } + + // create instance with arguments + //反射获取构造器参数的参数类型列表 + Class[] parameterTypes = targetConstructor.getParameterTypes(); + //如果存在参数则为参数设置值 + Object[] args = new Object[parameterTypes.length]; + for (int i = 0; i < parameterTypes.length; i++) { + //借助scopeModelAccessor工具获取参数类型,这个参数类型为当前的域模型对象 + args[i] = getArgumentValueForType(parameterTypes[i]); + } + //创建扩展对象 + return (T) targetConstructor.newInstance(args); + } +``` + + +## 6.2 wrap机制 +### 6.2.1 Wrapper机制说明 +Dubbo通过Wrapper实现AOP的方法 + +Wrapper机制,即扩展点自动包装。Wrapper 类同样实现了扩展点接口,但是 Wrapper 不是扩展点的真正实现。它的用途主要是用于从 ExtensionLoader 返回扩展点时,包装在真正的扩展点实现外。即从 ExtensionLoader 中返回的实际上是 Wrapper 类的实例,Wrapper 持有了实际的扩展点实现类。 +扩展点的 Wrapper 类可以有多个,也可以根据需要新增。 +通过 Wrapper 类可以把所有扩展点公共逻辑移至 Wrapper 中。新加的 Wrapper 在所有的扩展点上添加了逻辑,有些类似 AOP,即 Wrapper 代理了扩展点。 + +Wrapper的规范 +Wrapper 机制不是通过注解实现的,而是通过一套 Wrapper 规范实现的。 +Wrapper 类在定义时需要遵循如下规范。 + +- 该类要实现 SPI 接口 +- 该类中要有 SPI 接口的引用 +- 该类中必须含有一个含参的构造方法且参数只能有一个类型为SPI接口 +- 在接口实现方法中要调用 SPI 接口引用对象的相应方法 +- 该类名称以 Wrapper 结尾 + +比如如下几个扩展类型 + +```cpp + class org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper + class org.apache.dubbo.qos.protocol.QosProtocolWrapper + class org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper + class org.apache.dubbo.qos.protocol.QosProtocolWrapper +``` + + +回顾下Wrapper扩展类型的扫描于对象的创建 +### 6.2.2 Wrapper类型的扫描 +**Wrapper类型的扫描代码如下:** + +来自4.5.2.3小节ExtensionLoader类型中的loadClass方法 + +```cpp + //扩展子类型是否存在这个注解@Adaptive + if (clazz.isAnnotationPresent(Adaptive.class)) { + cacheAdaptiveClass(clazz, overridden); + } else if (isWrapperClass(clazz)) { + //扩展子类型构造器中是否有这个类型的接口 (这个可以想象下我们了解的Java IO流中的类型使用到的装饰器模式 构造器传个类型) + cacheWrapperClass(clazz); + } else { +``` + +isWrapperClass方法通过判断构造器类型是否为当前类型来判断是否为Wrapper类型 +```cpp + private boolean isWrapperClass(Class clazz) { + try { + clazz.getConstructor(type); + return true; + } catch (NoSuchMethodException e) { + return false; + } + } +``` + + +### 6.2.3 Wrapper类型的创建 +这个可以看下4.6.1 getExtension方法源码的获取扩展对象时候查询扩展对象是否有对应的Wrapper类型的扩展为其创建Wrapper扩展对象,如下代码 + +```cpp +//Dubbo通过Wrapper实现AOP的方法 + if (wrap) { + //这个可以参考下Dubbo扩展的加载 + List> wrapperClassesList = new ArrayList<>(); + //wrap类型排序 这个wrap类型是如何来的呢,在前面扫描扩展类型的时候如果当前扩展类型不是Adaptive注解修饰的,并且当前类型type有个构造器参数是type自身的也是前面加载扩展类型时候说的装饰器模式 可以参考DubboProtocol的构造器 + if (cachedWrapperClasses != null) { + wrapperClassesList.addAll(cachedWrapperClasses); + //根据Wrapper注解的order值来进行排序值越小越在列表的前面 + wrapperClassesList.sort(WrapperComparator.COMPARATOR); + //反转之后值越大就会在列表的前面 + Collections.reverse(wrapperClassesList); + } + //从缓存中查到了wrapper扩展则遍历这些wrapp扩展进行筛选 + if (CollectionUtils.isNotEmpty(wrapperClassesList)) { + for (Class wrapperClass : wrapperClassesList) { + Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class); + //需要包装的扩展名。当此数组为空时,默认值为匹配 + //看下当前扩展是否匹配这个wrap,如何判断呢? + //wrapper注解不存在或者matches匹配,或者mismatches不包含当前扩展 + //如果匹配到了当前扩展对象是需要进行wrapp的就为当前扩展创建当前wrapper扩展对象进行包装 + boolean match = (wrapper == null) || + ((ArrayUtils.isEmpty(wrapper.matches()) || ArrayUtils.contains(wrapper.matches(), name)) && + !ArrayUtils.contains(wrapper.mismatches(), name)); + //这是扩展类型是匹配wrapp的则开始注入 + if (match) { + //匹配到了就创建所有的wrapper类型的对象同时构造器参数设置为当前类型 + instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); + instance = postProcessAfterInitialization(instance, name); + } + } + } + } +``` + +主要来看下什么情况下才为当前扩展类型创建Wrapper包装类型: +- wrapper注解不存在(前面判断过Wrapper类型是构造器满足条件的) +- 存在Wrapper注解: + - matches匹配, + - 或者mismatches不包含当前扩展 + +如果匹配到了当前扩展对象是需要进行wrapp的就为当前扩展创建当前wrapper扩展对象进行包装 + + + 原文: [《Dubbo的SPI扩展机制之普通扩展对象的创建与Wrapper机制的源码解析》](https://blog.elastic.link/2022/07/10/dubbo/6-dubbo-de-spi-kuo-zhan-ji-zhi-zhi-pu-tong-kuo-zhan-dui-xiang-de-chuang-jian-yu-wrapper-ji-zhi-de-yuan-ma-jie-xi/) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/7-Dubbo\347\232\204SPI\346\211\251\345\261\225\346\234\272\345\210\266\344\271\213\350\207\252\345\212\250\346\277\200\346\264\273\346\211\251\345\261\225Activate\346\272\220\347\240\201\350\247\243\346\236\220.md" "b/content/en/blog/java/codeanalysis/3.0.8/7-Dubbo\347\232\204SPI\346\211\251\345\261\225\346\234\272\345\210\266\344\271\213\350\207\252\345\212\250\346\277\200\346\264\273\346\211\251\345\261\225Activate\346\272\220\347\240\201\350\247\243\346\236\220.md" new file mode 100644 index 000000000000..e37d09a1f463 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/7-Dubbo\347\232\204SPI\346\211\251\345\261\225\346\234\272\345\210\266\344\271\213\350\207\252\345\212\250\346\277\200\346\264\273\346\211\251\345\261\225Activate\346\272\220\347\240\201\350\247\243\346\236\220.md" @@ -0,0 +1,226 @@ +--- +title: "7-Dubbo的SPI扩展机制之自动激活扩展Activate源码解析" +linkTitle: "7-Dubbo的SPI扩展机制之自动激活扩展Activate源码解析" +date: 2022-08-07 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] @Activate可用于在有多个实现时加载某些筛选器扩展,一般带有同种类型多个扩展都要执行的情况,比如过滤器。 +--- + +# 7-Dubbo的SPI扩展机制之自动激活扩展Activate源码解析 +## 7.1 Activate扩展的说明 +此注解对于使用给定条件自动激活某些扩展非常有用,例如:@Activate可用于在有多个实现时加载某些筛选器扩展。 +- **group()** 指定组条件。框架SPI定义了有效的组值。 +- **value()** 指定URL条件中的参数键。 + +SPI提供程序可以调用ExtensionLoader。getActivateExtension(URL、String、String)方法以查找具有给定条件的所有已激活扩展。 + +比如后面我们会说到的**过滤器扩展对象**的获取,如下通过调用**getActivateExtension方法的**代码: + +```java + List filters; + filters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModels.get(0)).getActivateExtension(url, key, group); +``` + + +## 7.2 获取自动激活扩展的源码 + +前面我们看了激活扩展是通过调用getActivateExtension方法来获取对象的,那接下来就来看下这个方法做了什么操作: + +```java +/** +* @param url 服务的url +* @param key 用于获取扩展点名称的url参数键 比如监听器:exporter.listener,过滤器:params-filter,telnet处理器:telnet +*/ + public List getActivateExtension(URL url, String key) { + return getActivateExtension(url, key, null); + } +``` + +继续调用重载的方法 +```java +/** + * + * + * @param url 服务的url + * @param key 用于获取扩展点名称的url参数键 比如监听器:exporter.listener,过滤器:params-filter,telnet处理器:telnet + * @param group group 用于筛选的分组,比如过滤器中使用此参数来区分消费者使用这个过滤器还是提供者使用这个过滤器他们的group参数分表为consumer,provider + * @return 已激活的扩展列表。 + */ + public List getActivateExtension(URL url, String key, String group) { + //从参数中获取url指定的值 + String value = url.getParameter(key); + //调用下个重载的方法 + return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group); + } +``` + + +上面的重载方法都是用来转换参数的,下面这个方法才是真正的逻辑 +```java + /** + * 获取激活扩展. + * + * @param url 服务的url + * @param values 这个value是扩展点的名字 当指定了时候会使用指定的名字的扩展 + * @param group group 用于筛选的分组,比如过滤器中使用此参数来区分消费者使用这个过滤器还是提供者使用这个过滤器他们的group参数分表为consumer,provider + * @return 获取激活扩展. + */ + public List getActivateExtension(URL url, String[] values, String group) { + //检查扩展加载器是否被销毁了 + checkDestroyed(); + // solve the bug of using @SPI's wrapper method to report a null pointer exception. + //创建个有序的Map集合,用来对扩展进行排序 + Map, T> activateExtensionsMap = new TreeMap<>(activateComparator); + //初始化扩展名字,指定了扩展名字values不为空 + List names = values == null ? new ArrayList<>(0) : asList(values); + //扩展名字使用Set集合进行去重 + Set namesSet = new HashSet<>(names); + //参数常量是 -default 扩展名字是否不包含默认的 + if (!namesSet.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) { + //第一次进来肯定是没有缓存对象双重校验锁检查下 + if (cachedActivateGroups.size() == 0) { + synchronized (cachedActivateGroups) { + // cache all extensions + if (cachedActivateGroups.size() == 0) { + //加载扩展类型对应的扩展类,这个具体细节参考源码或者《[Dubbo3.0.7源码解析系列]-5-Dubbo的SPI扩展机制与自适应扩展对象的创建与扩展文件的扫描源码解析》章节 + getExtensionClasses(); + for (Map.Entry entry : cachedActivates.entrySet()) { + String name = entry.getKey(); + Object activate = entry.getValue(); + + String[] activateGroup, activateValue; + //遍历所有的activates列表获取group()和value()值 + if (activate instanceof Activate) { + activateGroup = ((Activate) activate).group(); + activateValue = ((Activate) activate).value(); + } else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) { + activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group(); + activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value(); + } else { + continue; + } + //缓存分组值 + cachedActivateGroups.put(name, new HashSet<>(Arrays.asList(activateGroup))); + String[][] keyPairs = new String[activateValue.length][]; + //遍历指定的激活扩展的扩展名字列表 + for (int i = 0; i < activateValue.length; i++) { + if (activateValue[i].contains(":")) { + keyPairs[i] = new String[2]; + String[] arr = activateValue[i].split(":"); + keyPairs[i][0] = arr[0]; + keyPairs[i][1] = arr[1]; + } else { + keyPairs[i] = new String[1]; + keyPairs[i][0] = activateValue[i]; + } + } + //缓存指定扩展信息 + cachedActivateValues.put(name, keyPairs); + } + } + } + } + + // traverse all cached extensions + //遍历所有激活的扩展名字和扩展分组集合 + cachedActivateGroups.forEach((name, activateGroup) -> { + //筛选当前扩展的扩展分组与激活扩展的扩展分组是否可以匹配 + if (isMatchGroup(group, activateGroup) + //不能是指定的扩展名字 + && !namesSet.contains(name) + //也不能是带有 -指定扩展名字 + && !namesSet.contains(REMOVE_VALUE_PREFIX + name) + //如果在Active注解中配置了value则当指定的键出现在URL的参数中时,激活当前扩展名。 + //如果未配置value属性则默认都是匹配的(cachedActivateValues中不存在对应扩展名字的缓存的时候默认为true) + && isActive(cachedActivateValues.get(name), url)) { + //缓存激活的扩展类型映射的扩展名字 + activateExtensionsMap.put(getExtensionClass(name), getExtension(name)); + } + }); + } + + if (namesSet.contains(DEFAULT_KEY)) { + // will affect order + // `ext1,default,ext2` means ext1 will happens before all of the default extensions while ext2 will after them + ArrayList extensionsResult = new ArrayList<>(activateExtensionsMap.size() + names.size()); + for (int i = 0; i < names.size(); i++) { + String name = names.get(i); + if (!name.startsWith(REMOVE_VALUE_PREFIX) + && !namesSet.contains(REMOVE_VALUE_PREFIX + name)) { + if (!DEFAULT_KEY.equals(name)) { + if (containsExtension(name)) { + extensionsResult.add(getExtension(name)); + } + } else { + extensionsResult.addAll(activateExtensionsMap.values()); + } + } + } + return extensionsResult; + } else { + // add extensions, will be sorted by its order + for (int i = 0; i < names.size(); i++) { + String name = names.get(i); + if (!name.startsWith(REMOVE_VALUE_PREFIX) + && !namesSet.contains(REMOVE_VALUE_PREFIX + name)) { + if (!DEFAULT_KEY.equals(name)) { + if (containsExtension(name)) { + activateExtensionsMap.put(getExtensionClass(name), getExtension(name)); + } + } + } + } + return new ArrayList<>(activateExtensionsMap.values()); + } + } + ``` + + +再来回顾下扫描扩展类型的时候,与激活扩展的相关扫描代码: +与激活注解关键的代码位置在这里ExtensionLoader的loadClass方法中 +我来贴下loadClass方法核心的代码: + +```java +if (clazz.isAnnotationPresent(Adaptive.class)) { + cacheAdaptiveClass(clazz, overridden); + } else if (isWrapperClass(clazz)) { + cacheWrapperClass(clazz); + } else { + if (StringUtils.isEmpty(name)) { + name = findAnnotationName(clazz); + if (name.length() == 0) { + throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL); + } + } + + String[] names = NAME_SEPARATOR.split(name); + if (ArrayUtils.isNotEmpty(names)) { + //位置在这里其他地方就不标记注释了,前面判断了如果不是Adaptive也不是Wrapper类型则我们可以来判断是否为Activate 类型如果是的话调用cacheActivateClass方法将扩展缓存进cachedActivates缓存中 + cacheActivateClass(clazz, names[0]); + for (String n : names) { + cacheName(clazz, n); + saveInExtensionClass(extensionClasses, clazz, n, overridden); + } + } + } +``` + +```java +private void cacheActivateClass(Class clazz, String name) { + Activate activate = clazz.getAnnotation(Activate.class); + if (activate != null) { + //注解存在则加入激活注解缓存 + cachedActivates.put(name, activate); + } else { + // support com.alibaba.dubbo.common.extension.Activate + com.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class); + if (oldActivate != null) { + cachedActivates.put(name, oldActivate); + } + } + } +``` + + 原文: [《Dubbo的SPI扩展机制之自动激活扩展Activate源码解析》](https://blog.elastic.link/2022/07/10/dubbo/7-dubbo-de-spi-kuo-zhan-ji-zhi-zhi-zi-dong-ji-huo-kuo-zhan-activate-yuan-ma-jie-xi/) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/8-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\345\200\237\345\212\251\345\217\214\351\207\215\346\240\241\351\252\214\351\224\201\347\232\204\345\215\225\344\276\213\346\250\241\345\274\217\350\277\233\350\241\214\345\257\271\350\261\241\347\232\204\345\210\235\345\247\213\345\214\226.md" "b/content/en/blog/java/codeanalysis/3.0.8/8-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\345\200\237\345\212\251\345\217\214\351\207\215\346\240\241\351\252\214\351\224\201\347\232\204\345\215\225\344\276\213\346\250\241\345\274\217\350\277\233\350\241\214\345\257\271\350\261\241\347\232\204\345\210\235\345\247\213\345\214\226.md" new file mode 100644 index 000000000000..0906eff07c09 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/8-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\345\200\237\345\212\251\345\217\214\351\207\215\346\240\241\351\252\214\351\224\201\347\232\204\345\215\225\344\276\213\346\250\241\345\274\217\350\277\233\350\241\214\345\257\271\350\261\241\347\232\204\345\210\235\345\247\213\345\214\226.md" @@ -0,0 +1,121 @@ +--- +title: "8-Dubbo启动器DubboBootstrap借助双重校验锁的单例模式进行对象的初始化" +linkTitle: "8-Dubbo启动器DubboBootstrap借助双重校验锁的单例模式进行对象的初始化" +date: 2022-08-08 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] 启动器是为使用者提供简化的API功能来进行Dubbo应用的启动,手写Dubbo服务的启动使用启动器是必要的。 +--- + +# 8-Dubbo启动器DubboBootstrap借助双重校验锁的单例模式进行对象的初始化 +## 8.1 启动器简介 +在说启动器之前先把视野拉回第一章[《1-从一个服务提供者的Demo说起》](https://blog.elastic.link/2022/07/10/dubbo/1-cong-yi-ge-demo-shuo-qi/ )我们的Demo代码,下面只贴一下核心代码: + +```java +public class Application { + public static void main(String[] args) throws Exception { + startWithBootstrap(); + } + private static void startWithBootstrap() { + //前面的文章都在说这个服务配置对象的创建,中间又说了分层域模型,扩展加载机制 + ServiceConfig service = new ServiceConfig<>(); + //为服务配置下服务接口和服务实现,下面两行用来初始化对象就不详细说了 + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + //这一个篇章主要说这里: + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider")) + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) + .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) + .service(service) + .start() + .await(); + } +} +``` + +Dubbo3 往云原生的方向走自然要针对云原生应用的应用启动,应用运行,应用发布等信息做一些建模,这个DubboBootstrap就是用来启动Dubbo服务的.类似于Netty的Bootstrap类型和ServerBootstrap启动器 + +## 8.2 双重校验锁的单例模式创建启动器对象的 +Dubbo的bootstrap类为啥要用单例模式: + +通过调用静态方法getInstance()获取单例实例。之所以设计为单例,是因为Dubbo中的一些类(如ExtensionLoader)只为每个进程设计一个实例。 + +下面就来直接看代码吧,代码胜千言: +对象的调用代码如下: + +```java +DubboBootstrap bootstrap = DubboBootstrap.getInstance(); +``` + +DubboBootstrap获取对象的getInstance()方法: +```java + public static DubboBootstrap getInstance() { + //双重校验锁第一次判断空 + if (instance == null) { + //为空都进行排队 + synchronized (DubboBootstrap.class) { + //双重校验锁第二次判断空 上面为空的都排队了这里得判断下 + if (instance == null) { + //调用重载方法获取对象 + instance = DubboBootstrap.getInstance(ApplicationModel.defaultModel()); + } + } + } + return instance; + } +``` + +DubboBootstrap获取对象重载的getInstance(ApplicationModel applicationModel)方法: + +*computeIfAbsent() 方法对 hashMap 中指定 key 的值进行重新计算,如果不存在这个 key,则添加到 hashMap 中。* + +instanceMap设计为Map类型 Key,意味着可以为多个应用程序模型创建不同的启动器,启动多个服务 +```java + public static DubboBootstrap getInstance(ApplicationModel applicationModel) { + return instanceMap.computeIfAbsent(applicationModel, _k -> new DubboBootstrap(applicationModel)); + } +``` + +## 8.3 DubboBootstrap的构造器代码 + +构造器代码是逻辑比较复杂的地方,我们先来看下代码 + +```java +private DubboBootstrap(ApplicationModel applicationModel) { + //存储应用程序启动模型 + this.applicationModel = applicationModel; + //获取配置管理器ConfigManager: 配置管理器的扩展类型ApplicationExt ,扩展名字config + configManager = applicationModel.getApplicationConfigManager(); + //获取环境信息Environment: 环境信息的扩展类型为ApplicationExt,扩展名字为environment + environment = applicationModel.getModelEnvironment(); + //执行器存储仓库(线程池)ExecutorRepository: 扩展类型为ExecutorRepository,默认扩展扩展名字为default + executorRepository = applicationModel.getExtensionLoader(ExecutorRepository.class).getDefaultExtension(); + //初始化并启动应用程序实例ApplicationDeployer,DefaultApplicationDeployer类型 + applicationDeployer = applicationModel.getDeployer(); + // listen deploy events + //为发布器 设置生命周期回调 + applicationDeployer.addDeployListener(new DeployListenerAdapter() { + @Override + public void onStarted(ApplicationModel scopeModel) { + notifyStarted(applicationModel); + } + + @Override + public void onStopped(ApplicationModel scopeModel) { + notifyStopped(applicationModel); + } + + @Override + public void onFailure(ApplicationModel scopeModel, Throwable cause) { + notifyStopped(applicationModel); + } + }); + //将启动器对象注册到应用程序模型applicationModel的Bean工厂中 + // register DubboBootstrap bean + applicationModel.getBeanFactory().registerBean(this); + } +``` + + 原文: [<>](https://blog.elastic.link/2022/07/10/dubbo/8-dubbo-qi-dong-qi-dubbobootstrap-jie-zhu-shuang-chong-xiao-yan-suo-de-dan-li-mo-shi-jin-xing-dui-xiang-de-chu-shi-hua/) diff --git "a/content/en/blog/java/codeanalysis/3.0.8/9-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\346\267\273\345\212\240\345\272\224\347\224\250\347\250\213\345\272\217\347\232\204\351\205\215\347\275\256\344\277\241\346\201\257ApplicationConfig.md" "b/content/en/blog/java/codeanalysis/3.0.8/9-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\346\267\273\345\212\240\345\272\224\347\224\250\347\250\213\345\272\217\347\232\204\351\205\215\347\275\256\344\277\241\346\201\257ApplicationConfig.md" new file mode 100644 index 000000000000..595b2035faf9 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/3.0.8/9-Dubbo\345\220\257\345\212\250\345\231\250DubboBootstrap\346\267\273\345\212\240\345\272\224\347\224\250\347\250\213\345\272\217\347\232\204\351\205\215\347\275\256\344\277\241\346\201\257ApplicationConfig.md" @@ -0,0 +1,195 @@ +--- +title: "9-Dubbo启动器DubboBootstrap添加应用程序的配置信息ApplicationConfig" +linkTitle: "9-Dubbo启动器DubboBootstrap添加应用程序的配置信息ApplicationConfig" +date: 2022-08-09 +author: 宋小生 +tags: ["源码解析", "Java"] +description: > + [Dubbo 3.0.8源码解析] ApplicationConfig应用配置包含了一些比较基础的配置信息。 +--- + +# 9-Dubbo启动器DubboBootstrap添加应用程序的配置信息ApplicationConfig + +## 9.1 简介 +先贴个代码用来参考: + +```java + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider")) + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) + .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) + .service(service) + .start() + .await(); +``` + +上个博客我们说了启动器对象的创建,启动器对象在启动之前是要初始化一些配置信息的,这里我们来看这一行代码: + +```java +bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider")) +``` + +## 9.2 应用程序ApplicationConfig的配置信息 +ApplicationConfig的构造器比较简单就是为他的成员变量name赋值来标识这个应用程序的名字 +下面我们直接参考下官网的配置表格: + +| 属性 | 对应URL参数 | 类型 | 是否必填 | 缺省值 | 作用 | 描述 | 兼容性 | +| ------------- | ------------------- | ------ | -------- | --------- | -------- | ------------------------------------------------------------ | -------------- | +| name | application | string | **必填** | | 服务治理 | 当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样,此参数不是匹配条件,你当前项目叫什么名字就填什么,和提供者消费者角色无关,比如:kylin应用调用了morgan应用的服务,则kylin项目配成kylin,morgan项目配成morgan,可能kylin也提供其它服务给别人使用,但kylin项目永远配成kylin,这样注册中心将显示kylin依赖于morgan | 1.0.16以上版本 | +| version | application.version | string | 可选 | | 服务治理 | 当前应用的版本 | 2.2.0以上版本 | +| owner | owner | string | 可选 | | 服务治理 | 应用负责人,用于服务治理,请填写负责人公司邮箱前缀 | 2.0.5以上版本 | +| organization | organization | string | 可选 | | 服务治理 | 组织名称(BU或部门),用于注册中心区分服务来源,此配置项建议不要使用autoconfig,直接写死在配置中,比如china,intl,itu,crm,asc,dw,aliexpress等 | 2.0.0以上版本 | +| architecture | architecture | string | 可选 | | 服务治理 | 用于服务分层对应的架构。如,intl、china。不同的架构使用不同的分层。 | 2.0.7以上版本 | +| environment | environment | string | 可选 | | 服务治理 | 应用环境,如:develop/test/product,不同环境使用不同的缺省值,以及作为只用于开发测试功能的限制条件 | 2.0.0以上版本 | +| compiler | compiler | string | 可选 | javassist | 性能优化 | Java字节码编译器,用于动态类的生成,可选:jdk或javassist | 2.1.0以上版本 | +| logger | logger | string | 可选 | slf4j | 性能优化 | 日志输出方式,可选:slf4j,jcl,log4j,log4j2,jdk | 2.2.0以上版本 | +| metadata-type | metadata-type | String | 可选 | local | 服务治理 | metadata 传递方式,是以 Provider 视角而言的,Consumer 侧配置无效,可选值有: remote - Provider 把 metadata 放到远端注册中心,Consumer 从注册中心获取 local - Provider 把 metadata 放在本地,Consumer 从 Provider 处直接获取 | 2.7.6以上版本 | + + +官网的配置很详细了上面有一些属性是值得注意的比如这个name,compiler,logger,metadata-type 我们可能要多看下默认值是什么,方便我们在使用过程中遇到问题的排查 + +常用的属性参考官网的表格已经足够了,不过上面的属性不是列举了所有的属性,后续应该官方文档回更新: +我这里把缺失的一些属性列举出来: + +| 变量 | 类型 |说明 +|--|--|--| +| registries| List|应用级注册中心列表| +|registryIds|String|注册中心id列表| +|monitor|MonitorConfig|应用级监控配置| +|dumpDirectory|String|保存线程转储的目录| +|qosEnable|Boolean|是否启用qos| +|qosHost|String|要侦听的qos主机地址| +|qosPort|Integer|要侦听的qos端口| +|qosAcceptForeignIp|Boolean|qos是否接收外部IP| +|parameters|Map|自定义参数| +|shutwait|String|应用程序关闭时间|赋值属性的时候会想系统属性dubbo.service.shutdown.wait里面存一份| +|hostname|String|主机名| +|registerConsumer|Boolean|用于控制是否将实例注册到注册表。仅当实例是纯消费者时才设置为“false”。| +|repository|String|没找到哪里用了| +|enableFileCache|Boolean|是否开启本地文件缓存| +|protocol|String|此应用程序的首选协议(名称)适用于难以确定哪个是首选协议的地方| +|metadataServiceProtocol|String|用于点对点的元数据传输的协议| +|metadataServicePort|Integer|元数据服务端口号,用于服务发现| +|livenessProbe|String|Liveness 存活探针 用于设置qos中探测器的扩展| +|readinessProbe|String|Readiness 就绪探针| +|startupProbe|String|Startup 启动探针| +|registerMode|String|注册模式,实例级,接口集,所有| +|enableEmptyProtection|Boolean|接收到的空url地址列表和空保护被禁用,将清除当前可用地址| + +这里我们先来简单了解下这个实体类型的基本配置,直接看配置可能不太好理解,后面我们讲到每个配置的时候可以回来参考一下 + + + +## 应用程序配置对象添加到启动器中的配置管理器中 +了解了配置信息再回过头来看下这个配置信息如何存放到启动器里面的: + +我们的Demo调用代码如下: +```java + DubboBootstrap bootstrap = DubboBootstrap.getInstance(); + bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider")) +``` + +DubboBootstrap的application方法设置一个应用程序配置ApplicationConfig对象 + +```java + public DubboBootstrap application(ApplicationConfig applicationConfig) { + //将启动器构造器中初始化的默认应用程序模型对象传递给配置对象 + applicationConfig.setScopeModel(applicationModel); + //将配置信息添加到配置管理器中 + configManager.setApplication(applicationConfig); + return this; + } +``` + +ConfigManager配置管理器的setApplication方法 +```java + @DisableInject + public void setApplication(ApplicationConfig application) { + addConfig(application); + } +``` + +ConfigManager配置管理器的addConfig方法 +```java +public final T addConfig(AbstractConfig config) { + + if (config == null) { + return null; + } + // ignore MethodConfig + //检查当前配置管理器支持管理的配置对象 + //目前支持的配置有ApplicationConfig,MonitorConfig,MetricsConfig,SslConfig, + //ProtocolConfig,RegistryConfig,ConfigCenterConfig,MetadataReportConfig + if (!isSupportConfigType(config.getClass())) { + throw new IllegalArgumentException("Unsupported config type: " + config); + } + + if (config.getScopeModel() != scopeModel) { + config.setScopeModel(scopeModel); + } + + //缓存中是否存在 + Map configsMap = configsCache.computeIfAbsent(getTagName(config.getClass()), type -> new ConcurrentHashMap<>()); + + // fast check duplicated equivalent config before write lock + //不是服务级配置则直接从缓存中读取到配置之后直接返回 + if (!(config instanceof ReferenceConfigBase || config instanceof ServiceConfigBase)) { + for (AbstractConfig value : configsMap.values()) { + if (value.equals(config)) { + return (T) value; + } + } + } + + // lock by config type + //添加配置 + synchronized (configsMap) { + return (T) addIfAbsent(config, configsMap); + } + } +``` + + +ConfigManager配置管理器的addIfAbsent方法: + +```java +private C addIfAbsent(C config, Map configsMap) + throws IllegalStateException { + //配置信息为空直接返回 + if (config == null || configsMap == null) { + return config; + } + + // find by value + //根据配置规则判断,配置存在则返回 + Optional prevConfig = findDuplicatedConfig(configsMap, config); + if (prevConfig.isPresent()) { + return prevConfig.get(); + } + + //生成配置key + String key = config.getId(); + if (key == null) { + do { + // generate key if id is not set + key = generateConfigId(config); + } while (configsMap.containsKey(key)); + } + + //不相同的配置key重复则抛出异常 + C existedConfig = configsMap.get(key); + if (existedConfig != null && !isEquals(existedConfig, config)) { + String type = config.getClass().getSimpleName(); + logger.warn(String.format("Duplicate %s found, there already has one default %s or more than two %ss have the same id, " + + "you can try to give each %s a different id, override previous config with later config. id: %s, prev: %s, later: %s", + type, type, type, type, key, existedConfig, config)); + } + + // override existed config if any + //将配置对象存入configsMap对象中,configsMap来源于configsCache + configsMap.put(key, config); + return config; + } +``` + + 原文: [<>](https://blog.elastic.link/2022/07/10/dubbo/9-dubbo-qi-dong-qi-dubbobootstrap-tian-jia-ying-yong-cheng-xu-de-pei-zhi-xin-xi-applicationconfig/) \ No newline at end of file diff --git a/content/en/blog/java/codeanalysis/3.0.8/_index.md b/content/en/blog/java/codeanalysis/3.0.8/_index.md new file mode 100644 index 000000000000..5748b6d8f702 --- /dev/null +++ b/content/en/blog/java/codeanalysis/3.0.8/_index.md @@ -0,0 +1,8 @@ + +--- +title: "Dubbo 3.0.8 源码解析" +linkTitle: "Dubbo3 [v3.0.8] 源码解析" +weight: 20 +--- + + diff --git a/content/en/blog/java/codeanalysis/_index.md b/content/en/blog/java/codeanalysis/_index.md new file mode 100644 index 000000000000..67c62469433e --- /dev/null +++ b/content/en/blog/java/codeanalysis/_index.md @@ -0,0 +1,9 @@ + +--- +title: "源码分析" +linkTitle: "源码分析" +weight: 20 +description: "Dubbo Java 源码分析" +--- + + diff --git a/content/en/blog/java/codeanalysis/introduction-to-dubbo-url.md b/content/en/blog/java/codeanalysis/introduction-to-dubbo-url.md new file mode 100644 index 000000000000..7585186537bd --- /dev/null +++ b/content/en/blog/java/codeanalysis/introduction-to-dubbo-url.md @@ -0,0 +1,195 @@ +--- +title: "Dubbo 中的 URL 统一模型" +linkTitle: "Dubbo 中的 URL 统一模型" +date: 2019-10-17 +tags: ["源码解析", "Java"] +description: > + URL 是 Dubbo 中一个重要的领域模型,了解它可以更加轻松的理解 Dubbo 的设计理念。 +--- + +### 定义 + +在不谈及 dubbo 时,我们大多数人对 URL 这个概念并不会感到陌生。统一资源定位器 ([RFC1738](https://www.ietf.org/rfc/rfc1738.txt)――Uniform Resource Locators (URL))应该是最广为人知的一个 RFC 规范,它的定义也非常简单 + +> 因特网上的可用资源可以用简单字符串来表示,该文档就是描述了这种字符串的语法和语 +> 义。而这些字符串则被称为:“统一资源定位器”(URL) + +**一个标准的 URL 格式**至多可以包含如下的几个部分 + +``` +protocol://username:password@host:port/path?key=value&key=value +``` + +**一些典型 URL** + +``` +http://www.facebook.com/friends?param1=value1&param2=value2 +https://username:password@10.20.130.230:8080/list?version=1.0.0 +ftp://username:password@192.168.1.7:21/1/read.txt +``` + +当然,也有一些**不太符合常规的 URL**,也被归类到了 URL 之中 + +``` +192.168.1.3:20880 +url protocol = null, url host = 192.168.1.3, port = 20880, url path = null + +file:///home/user1/router.js?type=script +url protocol = file, url host = null, url path = home/user1/router.js + +file://home/user1/router.js?type=script
+url protocol = file, url host = home, url path = user1/router.js + +file:///D:/1/router.js?type=script +url protocol = file, url host = null, url path = D:/1/router.js + +file:/D:/1/router.js?type=script +同上 file:///D:/1/router.js?type=script + +/home/user1/router.js?type=script +url protocol = null, url host = null, url path = home/user1/router.js + +home/user1/router.js?type=script +url protocol = null, url host = home, url path = user1/router.js +``` + +### Dubbo 中的 URL + +在 dubbo 中,也使用了类似的 URL,主要用于在各个扩展点之间传递数据,组成此 URL 对象的具体参数如下: + +- protocol:一般是 dubbo 中的各种协议 如:dubbo thrift http zk +- username/password:用户名/密码 +- host/port:主机/端口 +- path:接口名称 +- parameters:参数键值对 + +```java +public URL(String protocol, String username, String password, String host, int port, String path, Map parameters) { + if ((username == null || username.length() == 0) + && password != null && password.length() > 0) { + throw new IllegalArgumentException("Invalid url, password without username!"); + } + this.protocol = protocol; + this.username = username; + this.password = password; + this.host = host; + this.port = (port < 0 ? 0 : port); + this.path = path; + // trim the beginning "/" + while(path != null && path.startsWith("/")) { + path = path.substring(1); + } + if (parameters == null) { + parameters = new HashMap(); + } else { + parameters = new HashMap(parameters); + } + this.parameters = Collections.unmodifiableMap(parameters); +} +``` + +可以看出,dubbo 认为 protocol,username,passwored,host,port,path 是主要的 URL 参数,其他键值对存放在 parameters 之中。 + +**一些典型的 Dubbo URL** + +``` +dubbo://192.168.1.6:20880/moe.cnkirito.sample.HelloService?timeout=3000 +描述一个 dubbo 协议的服务 + +zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demo-consumer&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=1214&qos.port=33333×tamp=1545721981946 +描述一个 zookeeper 注册中心 + +consumer://30.5.120.217/org.apache.dubbo.demo.DemoService?application=demo-consumer&category=consumers&check=false&dubbo=2.0.2&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=1209&qos.port=33333&side=consumer×tamp=1545721827784 +描述一个消费者 +``` + +可以说,任意的一个领域中的一个实现都可以认为是一类 URL,dubbo 使用 URL 来统一描述了元数据,配置信息,贯穿在整个框架之中。 + +### URL 相关的生命周期 + +#### RPC调用 + +从地址发现的视角,URL 代表了一条可用的 provider 实例地址,除了地址信息之外还有相关的配置信息,这些配置信息是层次化的,有 provider 侧指定的配置值、consumer 侧指定的配置值、接口级别的配置值、方法级别的配置值等。这些 URL 配置值将直接影响消费端的 RPC 调用行为。 + +以 timeout 为例,下图显示了配置的查找顺序,其它 retries, loadbalance, actives 等类似: + +* 方法级优先,接口级次之,全局配置再次之。 +* 如果级别一样,则消费方优先,提供方次之。 + +其中,服务提供方配置,通过 URL 经由注册中心传递给消费方。 + +![dubbo-config-override](/imgs/user/dubbo-config-override.jpg) + +(建议由服务提供方设置超时,因为一个方法需要执行多长时间,服务提供方更清楚,如果一个消费方同时引用多个服务,就不需要关心每个服务的超时设置)。 + +理论上 ReferenceConfig 中除了`interface`这一项,其他所有配置项都可以缺省不配置,框架会自动使用ConsumerConfig,ServiceConfig, ProviderConfig等提供的缺省配置。 + +#### 解析服务 + +基于 dubbo.jar 内的 `META-INF/spring.handlers` 配置,Spring 在遇到 dubbo 名称空间时,会回调 `DubboNamespaceHandler`。 + +所有 dubbo 的标签,都统一用 `DubboBeanDefinitionParser` 进行解析,基于一对一属性映射,将 XML 标签解析为 Bean 对象。 + +在 `ServiceConfig.export()` 或 `ReferenceConfig.get()` 初始化时,将 Bean 对象转换 URL 格式,所有 Bean 属性转成 URL 的参数。 + +然后将 URL 传给协议扩展点,基于扩展点自适应机制,根据 URL 的协议头,进行不同协议的服务暴露或引用。 + +#### 暴露服务 + +**1. 只暴露服务端口:** + +在没有注册中心,直接暴露提供者的情况下,`ServiceConfig` 解析出的 URL 的格式为:`dubbo://service-host/com.foo.FooService?version=1.0.0`。 + +基于扩展点自适应机制,通过 URL 的 `dubbo://` 协议头识别,直接调用 `DubboProtocol`的 `export()` 方法,打开服务端口。 + +**2. 向注册中心暴露服务:** + +在有注册中心,需要注册提供者地址的情况下,`ServiceConfig` 解析出的 URL 的格式为: `registry://registry-host/org.apache.dubbo.registry.RegistryService?export=URL.encode("dubbo://service-host/com.foo.FooService?version=1.0.0")`, + +基于扩展点自适应机制,通过 URL 的 `registry://` 协议头识别,就会调用 `RegistryProtocol` 的 `export()` 方法,将 `export` 参数中的提供者 URL,先注册到注册中心。 + +再重新传给 `Protocol` 扩展点进行暴露: `dubbo://service-host/com.foo.FooService?version=1.0.0`,然后基于扩展点自适应机制,通过提供者 URL 的 `dubbo://` 协议头识别,就会调用 `DubboProtocol` 的 `export()` 方法,打开服务端口。 + +#### 引用服务 + +**1. 直连引用服务:** + +在没有注册中心,直连提供者的情况下,`ReferenceConfig` 解析出的 URL 的格式为:`dubbo://service-host/com.foo.FooService?version=1.0.0`。 + +基于扩展点自适应机制,通过 URL 的 `dubbo://` 协议头识别,直接调用 `DubboProtocol` 的 `refer()` 方法,返回提供者引用。 + +**2. 从注册中心发现引用服务:** + +在有注册中心,通过注册中心发现提供者地址的情况下,`ReferenceConfig` 解析出的 URL 的格式为:`registry://registry-host/org.apache.dubbo.registry.RegistryService?refer=URL.encode("consumer://consumer-host/com.foo.FooService?version=1.0.0")`。 + +基于扩展点自适应机制,通过 URL 的 `registry://` 协议头识别,就会调用 `RegistryProtocol` 的 `refer()` 方法,基于 `refer` 参数中的条件,查询提供者 URL,如: `dubbo://service-host/com.foo.FooService?version=1.0.0`。 + +基于扩展点自适应机制,通过提供者 URL 的 `dubbo://` 协议头识别,就会调用 `DubboProtocol` 的 `refer()` 方法,得到提供者引用。 + +然后 `RegistryProtocol` 将多个提供者引用,通过 `Cluster` 扩展点,伪装成单个提供者引用返回。 + +### URL 统一模型的意义 + +对于 dubbo 中的 URL,有人理解为配置总线,有人理解为统一配置模型,说法虽然不同,但都是在表达一个意思,这样的 URL 在 dubbo 中被当做是[公共契约](/en/docsv2.7/dev/contract/),所有扩展点参数都包含 URL 参数,URL 作为上下文信息贯穿整个扩展点设计体系。 + +在没有 URL 之前,只能以字符串传递参数,不停的解析和拼装,导致相同类型的接口,参数时而 Map, 时而 Parameters 类包装: + +```java +export(String url) +createExporter(String host, int port, Parameters params) +``` + +使用 URL 一致性模型: + +```java +export(URL url) +createExporter(URL url) +``` + +在最新的 dubbo 代码中,我们可以看到大量使用 URL 来进行上下文之间信息的传递,这样的好处是显而易见的: + +1. 使得代码编写者和阅读者能够将一系列的参数联系起来,进而形成规范,使得代码易写,易读。 +2. 可扩展性强,URL 相当于参数的集合(相当于一个 Map),他所表达的含义比单个参数更丰富,当我们在扩展代码时,可以将新的参数追加到 URL 之中,而不需要改变入参,返参的结构。 +3. 统一模型,它位于 org.apache.dubbo.common 包中,各个扩展模块都可以使用它作为参数的表达形式,简化了概念,降低了代码的理解成本。 + +如果你能够理解 final 契约和 restful 契约,那我相信你会很好地理解 URL 契约。契约的好处我还是啰嗦一句:大家都这么做,就形成了默契,沟通是一件很麻烦的事,统一 URL 模型可以省去很多沟通成本,这边是 URL 统一模型存在的意义。 diff --git "a/content/en/blog/java/codeanalysis/metrics/0-\345\274\225\350\250\200.md" "b/content/en/blog/java/codeanalysis/metrics/0-\345\274\225\350\250\200.md" new file mode 100644 index 000000000000..405f04bde34a --- /dev/null +++ "b/content/en/blog/java/codeanalysis/metrics/0-\345\274\225\350\250\200.md" @@ -0,0 +1,28 @@ +--- +title: "引言" +linkTitle: "0-引言" +date: 2023-04-28 +author: 武钰皓 +tags: ["源码解析", "Java"] +description: Dubbo 指标模块源码分析-引言 +--- + ## 引言 +服务指标统计体系是 Dubbo 可观测能力的重要组成部分。 +dubbo-metrics 指标模块旨在将 dubbo 内部零散的 Metrics 相关类综合到一个单独的模块中,提供一套更加完善、全面、可拓展、解耦合的指标采样-统计-导出解决方案。 + +dubbo-metrics 模块包括: + +* dubbo-metrics-api 公用接口包 +* dubbo-metrics-prometheus 普罗米修斯适配包 +* dubbo-metrics-metadata 元数据中心指标监控包 +* dubbo-metrics-registry 注册中心指标监控包 +* dubbo-metrics-config-center 配置中心指标监控包 +* dubbo-metrics-default 接口默认实现包,提供dubbo内部核心指标的监控功能 + + +在设计上,dubbo-metrics 深入应用事件驱动编程思想,总体体现出下图的事件处理链路: + +![metrics-event-struct](/imgs/blog/metrics-source-blog/metrics-event-struct.png) + + +在拓展上,dubbo-metrics 抽象了一套指标导出接口与抽象实现,可实现兼容多种指标统计监控中心,默认提供了普罗米修斯实现。 \ No newline at end of file diff --git "a/content/en/blog/java/codeanalysis/metrics/1-\346\214\207\346\240\207\346\240\267\346\234\254\347\232\204\346\224\266\351\233\206\344\270\216\345\255\230\345\202\250.md" "b/content/en/blog/java/codeanalysis/metrics/1-\346\214\207\346\240\207\346\240\267\346\234\254\347\232\204\346\224\266\351\233\206\344\270\216\345\255\230\345\202\250.md" new file mode 100644 index 000000000000..34e953f7aa8d --- /dev/null +++ "b/content/en/blog/java/codeanalysis/metrics/1-\346\214\207\346\240\207\346\240\267\346\234\254\347\232\204\346\224\266\351\233\206\344\270\216\345\255\230\345\202\250.md" @@ -0,0 +1,106 @@ +--- +title: "1-指标样本的收集与存储" +linkTitle: "1-指标样本的收集与存储" +date: 2023-04-28 +author: 武钰皓 +tags: ["源码解析", "Java"] +description: "Dubbo 指标模块源码分析-指标样本的收集与存储" +--- + +## 一、指标样本的收集与存储 + + + +### 指标样本收集 + +**指标收集器(Collector)是指标对外导出的入口**。最终导出到指标统计中心的指标采样实际均直接来源于各个指标采样器。因此,我们将从各个收集器实现开始,分析 dubbo-metrics 模块是如何工作的。 + +指标收集操作定义在 MetricsCollector (指标采集器,SPI)接口中,可以通过它的实现收集某一类的指标样本(MetricSample)。它主要有以下实现,对应着不同类型的指标: + +* ConfigCenterMetricsCollector **配置中心操作相关指标收集器** ,收集配置信息的变化次数 +* MetadataMetricsCollector **元数据中心操作相关指标收集器**,收集提供者、消费者对元数据中心操作(推送数据、拉取数据)情况的计数、耗时统计。 +* RegistryMetricsCollector **注册中心相关操作指标收集器**,收集应用级、接口级服务注册成功、失败、耗时的相关计数。 +* DefaultMetricsCollector **默认指标收集器**,内置多种采样器来完成不同类型的内部指标采样。 +* HistogramMetricsCollector **直方图指标收集器**,利用 micrometer API 处理直方图类型的指标,它的实现较为特殊。 + +配置中心 、元数据、服务注册及默认指标收集器均实现自混合指标收集器(CombMetricsCollector)。混合指标收集器实现了 ApplicationMetricsCollector 、ServiceMetricsCollector 、MethodMetricsCollector 三个接口(定义按应用名收集、按应用名-服务名收集和按应用-方法名收集指标的操作),因此它们可以进行应用、服务和方法三个层面的指标收集工作。 + +默认指标收集器的特点是通过内部的指标采样器(MetricsSampler)完成指标事件的处理操作,而不是其它收集器的指标监听器(MetricsListener) + +直方图指标收集器则负责收集直方图类型的指标。它利用直方图度量寄存器(HistogramMetricRegister)借助 micrometer API 完成直方图样本的采集。直方图类型包括百分位数、服务水平目标、最小预期值、最大预期值、统计数据分布有效期等。 + + + +**Collector的继承关系:** + +![collectors](/imgs/blog/metrics-source-blog/collectors.png) + +可以看出,每个指标收集器都具有来自 MetricsListener 的监听指标事件的能力。为什么指标收集器本身需要监听指标事件? 在后文中,我们将讨论指标收集器是如何利用内置的子转发器(SubDispatcher)转发指标事件,并完成计数处理的。 + + + +### 指标样本存储 + +前文中,我们了解了指标收集的入口是指标收集器(Collector)。那么各个收集器从哪里收集指标样本? + +**对于配置中心、元数据中心、 注册中心的指标收集器:** + +它们分别负责采集三大中心模块的指标,均继承于**混合数据收集器(CombMetricsCollector)**,而混合数据收集器中实现了 export 方法 。 + +混合数据收集器内部有一个**基本数据聚合器(BaseStatComposite)**,它实现了 MetricsExport 接口,该接口定义了指标导出操作,混合数据收集器则利用它的 export 方法导出指标。 + +基本数据聚合器是一个抽象类,内有三个属性:ApplicationStatComposite 、ServiceStatComposite 和 RtStatComposite 。它们的作用: + +* **ApplicationStatComposite 应用数据聚合器**,应用程序级别相关事件的计数 ,根据指标Key( MetricsKey )和应用名统计指标,提供计数递增操作 +* **ServiceStatComposite 服务数据聚合器**,服务级别相关事件的计数,根据指标Key、应用名和服务名统计指标,提供计数递增操作 +* **MethodStatComposite 方法数据聚合器**,方法级别相关事件的计数,存储各方法RPC调用相关计数。 +* **RtStatComposite,Rt(Response Time,响应时间)数据聚合器**,包括应用级别和服务级别。根据应用名、服务名、注册的指标名及相应相应时间统计指标,提供添加操作。 + +对于以上四个聚合器,他们的职责就是存储某一类型的采样样本。 + + +**基本数据聚合器 (BaseStatComposite)** 对这三个子聚合器的操作进行了简单整合,统一提供给外界。**而混合指标收集器(CombMetricsCollector)** 也基本保留了内部基本数据聚合器的所有操作,将其封装为 `increment`、`setNum`、`addRt `三个方法(及它们的重载,分别收集应用级数据和服务级数据)向上提供。外部组件可以直接调用这些收集器完成指标更新操作。 + +**当调用元数据中心指标收集器、注册中心指标收集器的 collect 方法时,最终会调用`BaseStatComposite.export(MetricsCategory category)` , 该方法会收集内部三个聚合器的指标并返回。** + +需要注意的是, 配置中心指标收集器不依赖于基本数据聚合器 导出数据,它在创建时将基本数据聚合器置为null,而使用自己的 updatedMetrics 字段存储采样: + +```java +//ConfigCenterMetricsCollector +private final Map updatedMetrics = new ConcurrentHashMap<>(); + + public ConfigCenterMetricsCollector(ApplicationModel applicationModel) { + //BaseStatComposite = null + super(null); + ... + } +``` + +混合指标收集器和数据聚合器之间呈现如下的包含关系: + +![composite-struct](/imgs/blog/metrics-source-blog/composite-struct.png) + +**DefaultMetricsCollector 默认指标采集器:** + +它不直接存储采样数据,而是通过收集其下**指标采样器(MetricsSampler)** 的样本来完成采样工作。这些采样器包括: + +* 方法采样器 +* 应用采样器 +* 线程池采样器 + +这些采样器完成采样后,还会利用采集器中的**事件多播器(Multicaster)** 将指标事件发布出去,可以被其它监听器处理。详细流程将在后文中探讨。 + + +**HistogramMetricsCollector 直方图指标采集器:** + +由于需要使用Timer完成直方图属性的统计,它使用自己的容器存储采样数据。 + +```java +public class HistogramMetricsCollector implements MetricsListener { + //方法指标样本与对应的Timer + private final ConcurrentHashMap rt = new ConcurrentHashMap(); + ... +} +``` + +Timer(计时器)由 micrometer API 提供,常用于统计一分钟内的大量事件。 diff --git "a/content/en/blog/java/codeanalysis/metrics/2-\346\214\207\346\240\207\346\224\266\351\233\206\345\231\250\347\232\204\346\214\207\346\240\207\351\207\207\351\233\206\346\265\201\347\250\213.md" "b/content/en/blog/java/codeanalysis/metrics/2-\346\214\207\346\240\207\346\224\266\351\233\206\345\231\250\347\232\204\346\214\207\346\240\207\351\207\207\351\233\206\346\265\201\347\250\213.md" new file mode 100644 index 000000000000..fcc4d6b490e7 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/metrics/2-\346\214\207\346\240\207\346\224\266\351\233\206\345\231\250\347\232\204\346\214\207\346\240\207\351\207\207\351\233\206\346\265\201\347\250\213.md" @@ -0,0 +1,502 @@ +--- +title: "2-指标收集器的指标采集流程" +linkTitle: "2-指标收集器的指标采集流程" +date: 2023-04-28 +author: 武钰皓 +tags: ["源码解析", "Java"] +description: "Dubbo 指标模块源码分析-指标收集器的指标采集流程" +--- + + + +## 二、指标收集器的指标采集流程 + +在前文中,我们了解了指标收集器(Collector)最终收集的数据只有三个来源: + +* 实现自混合指标收集器(CombMetricsCollector) 的元数据指标收集器(MetadataMetricsCollector)和注册中心指标收集器(RegistryMetricsCollector),它们的样本均存储在内置的基本数据聚合器中。具体来说,是基本数据聚合器下的四个子数据聚合器中: + + ![composite-struct](/imgs/blog/metrics-source-blog/composite-struct.png) + +* **DefaultMetricsCollector 默认指标收集器**,它的样本不仅来自于指标事件,还来自其下**采样器(Sampler)** 中,用于Dubbo核心模块的采样。 + +* **HistogramMetricsCollector 直方图指标收集器**,由于采样数据的特殊性,它的样本直接以 Map 存储在内部。 + +接下来,我们需要明确它们存储的指标是如何添加进去的。 + + + +### 1,服务治理模块的指标采集流程 + +通过之前的分析,我们知道服务治理模块的指标采集器均实现自混合指标收集器(CombMetricsCollector)。它对基本数据聚合器(BaseStatComposite) 的大部分方法做了封装。基本数据聚合器又封装了四个负责存储不同类型指标采样的子聚合器。 + +这四个子聚合器包括: + +* ApplicationStatComposite +* ServiceStatComposite +* MethodStatComposite +* RtStatComposite + +实际上,**元数据、注册中心指标收集器**更新、添加指标的操作都是通过混合指标收集器暴露的方法进行。而具体的,是通过 `setNum`、`increment`、`addRt` 这三个方法(及它们的重载)进行操作。 + +```java +//CombMetricsCollector +... + private final BaseStatComposite stats; +... +@Override + public void setNum(MetricsKey metricsKey, String applicationName, String serviceKey, int num) { + this.stats.setServiceKey(metricsKey, applicationName, serviceKey, num); + } + + @Override + public void increment(String applicationName, MetricsKey metricsKey) { + this.stats.incrementApp(metricsKey, applicationName, SELF_INCREMENT_SIZE); + } + + public void increment(String applicationName, String serviceKey, MetricsKey metricsKey, int size) { + this.stats.incrementServiceKey(metricsKey, applicationName, serviceKey, size); + } + + @Override + public void addRt(String applicationName, String registryOpType, Long responseTime) { + stats.calcApplicationRt(applicationName, registryOpType, responseTime); + } + + public void addRt(String applicationName, String serviceKey, String registryOpType, Long responseTime) { + stats.calcServiceKeyRt(applicationName, serviceKey, registryOpType, responseTime); + } +... +``` + +由于几个方法实际上的调用链路类似,我们选择从其中的 setNum 方法开始分析。 + +其在**数据聚合器层面的调用链路**可以总结为:setNum 方法调用基本数据聚合器的 setServiceKey 方法,该方法又会调用服务数据聚合器(ServiceStatComposite)的同名 setServiceKey 方法(我们已经知道基本数据聚合器内封装了四个不同类型的子聚合器),这个方法实质上是**对应用层面的特定指标(由指标Key决定)进行注册并赋初始值(参数中的 num)。** + +setNum 的用法均位于注册中心事件多播器(RegistryMetricsEventMulticaster)中声明的 MCat 接口中,在 APPLICATION_NOTIFY_FINISH 和 APPLICATION_DIRECTORY_POST 两个常量初始化时被调用。MCat 接口本身作为常量类使用,并在初始化时**注册真正的指标常量**: +```java +//RegistryMetricsEventMulticaster.MCat +MetricsCat APPLICATION_NOTIFY_FINISH = new MetricsCat(MetricsKey.NOTIFY_METRIC_NUM_LAST, + (key, placeType, collector) -> AbstractMetricsListener.onFinish(key, + event -> { + collector.addRt(event.appName(), placeType.getType(), event.getTimePair().calc()); + Map lastNumMap = Collections.unmodifiableMap(event.getAttachmentValue(ATTACHMENT_KEY_LAST_NUM_MAP)); + lastNumMap.forEach( + (k, v) -> collector.setNum(key, event.appName(), k, v)); + + } + )); + + MetricsCat APPLICATION_DIRECTORY_POST = new MetricsCat(MetricsKey.DIRECTORY_METRIC_NUM_VALID, (key, placeType, collector) -> AbstractMetricsListener.onEvent(key, + event -> + { + Map> summaryMap = event.getAttachmentValue(ATTACHMENT_DIRECTORY_MAP); + summaryMap.forEach((metricsKey, map) -> + map.forEach( + (k, v) -> collector.setNum(metricsKey, event.appName(), k, v))); + } + )); +//... +``` + +此处声明的指标常量都是 MetricsCat 类型的。其中部分常量在创建时还传入了该指标的收集逻辑,如Key 为 NOTIFY_METRIC_NUM_LAST 的常量。以下为 MetricsCat 的定义: + +```java +public class MetricsCat { + + private MetricsPlaceType placeType; + private final Function, AbstractMetricsListener> eventFunc; + + public MetricsCat(MetricsKey metricsKey, BiFunction, AbstractMetricsListener> biFunc) { + this.eventFunc = collector -> biFunc.apply(metricsKey, collector); + } + + public MetricsCat(MetricsKey metricsKey, TpFunction, AbstractMetricsListener> tpFunc) { + this.eventFunc = collector -> tpFunc.apply(metricsKey, placeType, collector); + } + + public MetricsCat setPlaceType(MetricsPlaceType placeType) { + this.placeType = placeType; + return this; + } + + public Function, AbstractMetricsListener> getEventFunc() { + return eventFunc; + } + + //一个接受三个入参,一个返回值的函数接口。通过构造函数我们可以知道这三个入参分别是MetricsKey, MetricsPlaceType, CombMetricsCollector,返回值为AbstractMetricsListener。 + @FunctionalInterface + public interface TpFunction { + R apply(T t, U u, K k); + } +} +``` + +MetricsCat 类除了构造器,只提供了两个public方法,都是获取其内部属性的。 + +其实质上 eventFunc 字段的载体,提供了为特定指标生产监听器的逻辑,因此 `MetricsCat ` 可以看做**为特定指标生产指标监听器的工厂**,用户在创建时传入这个监听器的处理逻辑。 + +通过泛型,我们可以知道它构造时使用的两个参数分别为 MetricsKey(指标Key)和一个接受 `MetricsKey, MetricsPlaceType, CombMetricsCollector` 三个参数,返回一个 `AbstractMetricsListener` 的函数。之所以要多封装一层函数,是因为 `placeType` 字段在 `MetricsKey` 实例构造之后才会提供,借此实现延迟初始化。 + +回到之前两个**在 MCat 中定义了监听器生产方法**的两个常量的初始化流程:它们在创建 MetricsCat 时传入的TpFunction中定义的操作为:返回通过 AbstractMetricsListener.onFinish获取的事件完成监听器。当指定MetricsKey 的指标统计事件完成时,这个监听器中的 onEventFinish 方法就会被调用。 而 MetricsCat 构造时传入的 MetricsKey 会被作为 AbstractMetricsListener 的构造参数,用于指定监听的指标。 +```java +//RegistryMetricsEventMulticaster.MCat +new MetricsCat(MetricsKey.NOTIFY_METRIC_NUM_LAST, + (key, placeType, collector) -> AbstractMetricsListener.onFinish(key, + event -> { + collector.addRt(event.appName(), placeType.getType(), event.getTimePair().calc()); + Map lastNumMap = Collections.unmodifiableMap(event.getAttachmentValue(ATTACHMENT_KEY_LAST_NUM_MAP)); + lastNumMap.forEach( + (k, v) -> collector.setNum(key, event.appName(), k, v)); + + } + )); +``` + +```java + //AbstractMetricsListener + public static AbstractMetricsListener onFinish(MetricsKey metricsKey, Consumer finishFunc) { + + return new AbstractMetricsListener(metricsKey) { + @Override + public void onEventFinish(TimeCounterEvent event) { + //此处是finishFunc就是之前 event ->{...} 中定义的lambda函数 + finishFunc.accept(event); + } + }; + } +``` + +三个形参 (key, placeType, collector) 中的 collector 为 `CombMetricsCollector`,意味着它的三个实现(ConfigCenterMetricsCollector 、MetadataMetricsCollector、RegistryMetricsCollector)都可以作为参数。 + +至此,我们可以总结,对于这两个参数, `MetricsCat` 创建时嵌套的两层 lambda 函数最终是为了注册特定指标的监听器,并定义事件结束时的处理逻辑(内层的lambda)。在处理事件时,会调用混合指标收集器(CombMetricsCollector) 的 `addRT` 方法添加响应时间计时,还会调用 `setNum` 来添加指标计数。 + +由于此处的 `MetricsKey` 在 MetricsCat创建时就被传入,我们可以确定这两个字段存储了以下两个指标的统计逻辑: + +* NOTIFY_METRIC_NUM_LAST:Last Notify Nums , 最后一个事件完成时的计数 。监听器中使用的是 `setNum`,事件结束时直接更新指定key指标的计数为传入的值,同时使用 `addRt ` 来统计事件持续时长 + +* DIRECTORY_METRIC_NUM_VALID:Valid Directory Urls,服务目录中注册成功的url数量。监听器中同样使用的是 `setNum`,事件结束后直接更新为服务目录中的最新计数 + + + +之后,三个相关的 MetricsCat(指标类型) 实例会被绑定到一个 CategoryOverall(指标综合) 实例中,绑定的逻辑按一个事件进行的三个过程:**事件发生、事件结束、事件失败**,分别对应 CategoryOverall 的第2、3、4个参数,其中事件发生时的逻辑不能为 null。而第一个参数为 `MetricsPlaceType`,该参数封装了指标类型标识(如 register 服务注册、subscribe 服务订阅)和该指标的收集级别(应用还是服务)。 + +还记得 `MetricsCat` 中 `TpFunction` 的三个入参吗?其中第二个 placeType 就是这个参数。 `CategoryOverall` 在构造时会将它设置到其中的三个 MetricsCat 中。 + +```java +// CategorySet:常量接口,同样位于RegistryMetricsEventMulticaster中 +interface CategorySet { + //... + + CategoryOverall APPLICATION_NOTIFY = new CategoryOverall(OP_TYPE_NOTIFY, MCat.APPLICATION_NOTIFY_POST, MCat.APPLICATION_NOTIFY_FINISH, null); + + CategoryOverall SERVICE_DIRECTORY = new CategoryOverall(OP_TYPE_DIRECTORY, MCat.APPLICATION_DIRECTORY_POST, null, null); + + CategoryOverall SERVICE_REGISTER = new CategoryOverall(OP_TYPE_REGISTER_SERVICE, MCat.SERVICE_REGISTER_POST, MCat.SERVICE_REGISTER_FINISH, MCat.SERVICE_REGISTER_ERROR); + + //... + List ALL = Arrays.asList(APPLICATION_REGISTER, APPLICATION_SUBSCRIBE, APPLICATION_NOTIFY, SERVICE_DIRECTORY, SERVICE_REGISTER, SERVICE_SUBSCRIBE); + } +``` + +`CategorySet` 中的常量都会被封装到List中,在 `RegistryMetricsEventMulticaster` 创建时统一调用: + +```java +public class RegistryMetricsCollector extends CombMetricsCollector { + public RegistryMetricsEventMulticaster(RegistryMetricsCollector collector) { + + CategorySet.ALL.forEach(categorySet -> + { + //通过 MetricsCat 实例中的定义的监听器创建逻辑,逐个注册监听器 + super.addListener(categorySet.getPost().getEventFunc().apply(collector)); + if (categorySet.getFinish() != null) { + super.addListener(categorySet.getFinish().getEventFunc().apply(collector)); + } + if (categorySet.getError() != null) { + super.addListener(categorySet.getError().getEventFunc().apply(collector)); + } + }); + } +//... +``` + +**由此,我们也明确了 RegistryMetricsEventMulticaster (指标注册事件多播器)的作用**:统一定义、管理事件,并在初始化时注册其中定义各种事件的**监听器**。 + +它继承了 SimpleMetricsEventMulticaster,其中的 publishEvent 方法在被调用时就会尝试调用所有监听器,判断其是否对当前事件类型感兴趣,选择是否进行调用。同时,这些监听器会对特定指标数据进行计算,更新到对应的收集器中。 + +```java +//SimpleMetricsEventMulticaster +public void publishEvent(MetricsEvent event) { + if (event instanceof EmptyEvent) { + return; + } + if (validateIfApplicationConfigExist(event)) return; + for (MetricsListener listener : listeners) { + if (listener.isSupport(event)) { + listener.onEvent(event); + } + } + } +``` + +我们通过分析混合指标收集器(CombMetricsCollector) 中的 setNum 方法的用法,了解到了 Composite 中的数据来源之一是注册指标事件多播器(RegistryMetricsEventMulticaster)中为服务注册相关指标创建的指标监听器。实际上,increment、addRt方法都是由指标监听器的各个实现调用的。 + +应用程序指标监听器(MetricsApplicationListener)中提供了 AbstractMetricsListener 的几个匿名实现,提供**应用层面事件发生、完成、抛出异常三种情况下对给定指标的计数或RT的计算**,大多数用做处理应用层面指标事件的 MetricsListener 都是它提供的三个监听器实现: + +```java +public class MetricsApplicationListener extends AbstractMetricsListener { + + public MetricsApplicationListener(MetricsKey metricsKey) { + super(metricsKey); + } + //此处的Event均为TimeCounterEvent,在它被创建时就会自动开始计时 + public static AbstractMetricsListener onPostEventBuild(MetricsKey metricsKey, CombMetricsCollector collector) { + return AbstractMetricsListener.onEvent(metricsKey, + event -> collector.increment(event.appName(), metricsKey) + ); + } + + public static AbstractMetricsListener onFinishEventBuild(MetricsKey metricsKey, MetricsPlaceType placeType, CombMetricsCollector collector) { + return AbstractMetricsListener.onFinish(metricsKey, + event -> { + collector.increment(event.appName(), metricsKey); + collector.addRt(event.appName(), placeType.getType(), event.getTimePair().calc()); + } + ); + } + + public static AbstractMetricsListener onErrorEventBuild(MetricsKey metricsKey, MetricsPlaceType placeType, CombMetricsCollector collector) { + return AbstractMetricsListener.onError(metricsKey, + event -> { + collector.increment(event.appName(), metricsKey); + collector.addRt(event.appName(), placeType.getType(), event.getTimePair().calc()); + } + ); + } +} +``` + +还有 MetricsServiceListener(服务指标监听器),它和 MetricsApplicationListener 十分类似,提供的是服务层面的指标监听器的通用实现,不再重复分析。 + +**可以用一句话简单的总结这三个 Collector 注册指标监听器的流程 : Collector 内部的 Mulicaster/Dispatcher 在被 Collector 创建时直接向自己注册已声明的指标监听器。** + +至此,我们可以总结出 MetricsEvent 的部分消息转发路径 : + +![event-dispatch-simple](/imgs/blog/metrics-source-blog/event-dispatch-simple.png) + + + + + + + +### 2,Dubbo 核心模块的指标采集流程 + +DefaultMetricsCollector(默认指标采集器) 作为指标采集器的默认实现,其主要通过采样器(Sampler)收集dubbo应用核心RPC功能的相关指标。 采样器包括以下几种: + +* 线程池线程状态(最大线程数、最小线程数、活跃线程数等),对应 **ThreadPoolMetricsSampler,线程池指标采样器** +* 线程池中线程耗尽事件的计数,对应 **ThreadRejectMetricsCountSampler, 线程耗尽次数采样器** +* 应用指标收集情况(收集次数),对应 DefaultMetricsCollector 中实现的 SimpleMetricsCountSampler 匿名子类 + +**这些采样器内部会存储其负责采样类型指标的样本。由于默认指标采集器同样继承自 CombMetricsCollector,它也同时具有与前文中分析的三大中心指标收集器相似的指标转发流程。** + +除了线程池指标采样器,其它两个采样器均实现自简单指标计数采样器(SimpleMetricsCountSampler)。它实现了通用的指标存取操作。 + +![sampler-struct](/imgs/blog/metrics-source-blog/sampler-struct.png) + +简单指标计数采样器内部的指标样本容器: + +```java +public abstract class SimpleMetricsCountSampler + implements MetricsCountSampler { +... + private final Map> metricCounter = new ConcurrentHashMap<>(); +... +} +``` + +**其中:泛型 M 为指标类型,如方法指标 MethodMetric;泛型 K 为指标名称类型,如 String;泛型 S 为请求源类型,如 String 或 Invocation。请求源用于定位触发采样的请求来源,指标名称则用于对指标进行分组,便于按名称来分组检索指标数据。** + +以及对特定指标的增减操作: + +```java +//SimpleMetricsCountSampler + public void inc(S source, K metricName) { + doExecute(source, metricName, counter -> { + counter.incrementAndGet(); + return false; + }); + } + public void dec(S source, K metricName) { + doExecute(source, metricName, counter -> { + counter.decrementAndGet(); + return false; + }); + } + public void incOnEvent(S source, K metricName) { + doExecute(source, metricName, counter -> { + counter.incrementAndGet(); + return true; + }); + } + public void decOnEvent(S source, K metricName) { + doExecute(source, metricName, counter -> { + counter.decrementAndGet(); + return true; + }); + } +``` + +对于四个增加、减少计数的方法,它们最终都会调用 `doExecute` 方法来完成计数操作,其中 counter 函数定义了对计数器的操作(增加、减少)。 + +```java +//SimpleMetricsCountSampler +private void doExecute(S source, K metricsName, Function counter) { + MetricsCountSampleConfigurer sampleConfigure = new MetricsCountSampleConfigurer<>(); + sampleConfigure.setSource(source); + sampleConfigure.setMetricsName(metricsName); + + //利用子类重写的countConfigure为 sampleConfigure 设置事件发布函数 + this.countConfigure(sampleConfigure); + + //通过指标名获取对应的指标计数器 + Map metricAtomic = metricCounter.get(metricsName); + + if (metricAtomic == null) { + metricAtomic = metricCounter.computeIfAbsent(metricsName, k -> new ConcurrentHashMap<>()); + } + + Assert.notNull(sampleConfigure.getMetric(), "metrics is null"); + + AtomicLong atomicCounter = metricAtomic.get(sampleConfigure.getMetric()); + + if (atomicCounter == null) { + atomicCounter = metricAtomic.computeIfAbsent(sampleConfigure.getMetric(), k -> new AtomicLong()); + } + // counter函数定义了对atomicCounter的增减操作,如 inc方法定义的counter是对atomicCounter+1,dec方法定义的是对atomicCounter-1 + Boolean isEvent = counter.apply(atomicCounter); + //如果本次计数操作应该触发事件... + if (isEvent) { + //获取子类设置的事件发布函数,发布事件 + sampleConfigure.getFireEventHandler().accept(sampleConfigure); + } + } +``` + +`doExecute` 做了两件事: + +1,判断当前指标是否存在,如果不存在就放到容器中。 + +2,调用提供的计数函数对指标进行修改,对应 counter 字段。 + +以下为各采样器在 countConfigure 方法中提供的创建指标实例的逻辑: +* DefaultMetricsCollector 中 SimpleMetricsCountSampler 的匿名实现 (applicationSampler)提供的`countConfigure` 方法: +```java + @Override + protected void countConfigure( + MetricsCountSampleConfigurer sampleConfigure) { + //提供根据 configure 创建指标实例的函数 + sampleConfigure.configureMetrics(configure -> new ApplicationMetric(sampleConfigure.getSource())); + } +``` + +* ThreadRejectMetricsCountSampler 中提供的 `countConfigure` 方法: +```java + @Override + protected void countConfigure(MetricsCountSampleConfigurer sampleConfigure) { + //提供根据 configure 创建指标实例的函数 + sampleConfigure.configureMetrics(configure -> new ThreadPoolRejectMetric(collector.getApplicationName(),configure.getSource())); + } +``` + +--- + +默认指标收集器继承自 CombMetricsCollector,内部包含一个 DefaultSubDispatcher,因此它自身也可以作为指标事件的转发器,接受其它指标监听器的注册。 + +在之前,我们发现了 AggregateMetricsCollector(聚合指标收集器)会将自己注册为 DefaultMetricsCollector 的监听器: + +```java + public AggregateMetricsCollector(ApplicationModel applicationModel) { + ... + registerListener(); + ... + } + } + + private void registerListener() { +applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).addListener(this); + } +``` + +还有 HistogramMetricsCollector (直方图指标收集器)也会将自己注册为它的监听器。 + +```java + public HistogramMetricsCollector(ApplicationModel applicationModel) { + ... + registerListener(); + ... + } + + private void registerListener() { applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).getEventMulticaster().addListener(this); + } +``` + + + +**因此,聚合指标收集器和直方图指标收集器的指标事件来源于默认指标收集器转发的指标事件**。通过默认指标转发器的 isSupport 方法,还可以发现这些指标事件的类型是 RequestEvent (RPC请求事件)或 RequestBeforeEvent(请求前失败事件:实际请求发送之前在 ClusterFilter 中产生的异常)。 + + +```java + @Override + public boolean isSupport(MetricsEvent event) { + return event instanceof RequestEvent || event instanceof RequestBeforeEvent; + } +``` + +![default-metrics-collector-struct](/imgs/blog/metrics-source-blog/default-metrics-collector-struct.png) + +**至此,我们也明确了 Dubbo 应用内部核心模块的相关指标是如何收集的:默认指标收集器除了接受上层指标转发器的指标事件之外,还会通过各种采样器对埋点采样,通过 SubDispatcher 统一转发指标事件,通知注册为它的监听器的其它 Collector 完成采样。** + + + +### 3, 直方图相关指标的采集流程 + +直方图指标收集器(HistogramMetricsCollector)也是一个较为特殊的收集器,它主要负责RPC调用响应时间直方图指标这一种指标的收集。 + +由于直方图指标收集器只需要采集单一类型的指标,它直接使用Map来存储采样数据,而非更复杂的数据聚合器(Composite)。 + +```java +//HistogramMetricsCollector +private final ConcurrentHashMap rt = new ConcurrentHashMap<>(); +``` + +**其中,key为方法指标,Timer则是该方法对应的RT计时器。该计时器由 micrometer 提供,在跟踪短时间内的大量事件时具有良好的性能。** + + + +前文中已经提到,直方图指标收集器在初始化时会将自己注册为默认指标收集器(DefaultMetricsCollector)中的监听器,与聚合指标收集器相同(AggregateMetricsCollector)。 + +```java + private void registerListener() { applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).getEventMulticaster().addListener(this); + } +``` + +这意味着它接收的指标事件实际也来自于默认指标收集器中的采样器。之前的分析中,我们知道默认指标收集器目前实际只转发来自 MetricsDispatcher 的请求相关事件,因此直方图指标收集器也只会收集请求响应时间相关的指标采样。 + +```java +//HistogramMetricsCollector +private void onRTEvent(RequestEvent event) { + if (metricRegister != null) { + MethodMetric metric = new MethodMetric(applicationModel.getApplicationName(), event.getAttachmentValue(MetricsConstants.INVOCATION)); + long responseTime = event.getTimePair().calc(); + + HistogramMetricSample sample = new HistogramMetricSample(MetricsKey.METRIC_RT_HISTOGRAM.getNameByType(metric.getSide()), + MetricsKey.METRIC_RT_HISTOGRAM.getDescription(), metric.getTags(), RT); + + Timer timer = ConcurrentHashMapUtils.computeIfAbsent(rt, metric, k -> metricRegister.register(sample)); + timer.record(responseTime, TimeUnit.MILLISECONDS); + } + } +``` + +当接收到事件时,直方图指标收集器会先计算当前调用花费的时间,然后为计时器(Time)添加一条响应时间记录。 + diff --git "a/content/en/blog/java/codeanalysis/metrics/3-\346\214\207\346\240\207\347\233\221\345\220\254\346\263\250\345\206\214\346\242\263\347\220\206.md" "b/content/en/blog/java/codeanalysis/metrics/3-\346\214\207\346\240\207\347\233\221\345\220\254\346\263\250\345\206\214\346\242\263\347\220\206.md" new file mode 100644 index 000000000000..f842e4a99d6f --- /dev/null +++ "b/content/en/blog/java/codeanalysis/metrics/3-\346\214\207\346\240\207\347\233\221\345\220\254\346\263\250\345\206\214\346\242\263\347\220\206.md" @@ -0,0 +1,421 @@ +--- +title: "3-指标监听注册梳理" +linkTitle: "3-指标监听注册梳理" +date: 2023-04-28 +author: 武钰皓 +tags: ["源码解析", "Java"] +description: "Dubbo 指标模块源码分析-指标监听注册梳理" +--- + +## 三、指标监听注册梳理 + +在前一章中,我们了解了不同收集器中的指标样本是如何被监听器添加进去的。接下来,我们将归纳指标监听器 的创建位置,及它们对应统计的指标。 + +通过之前的分析,我们已经知道指标 注册事件多播器(RegistryMetricsEventMulticaster)中定义了并绑定了服务注册相关的指标。这种绑定操作同样存在于其它几个简单指标事件多播器(SimpleMetricsEventMulticaster)的几个实现中。 + + + +### 转发器注册 + + + +**RegistrySubDispatcher (服务注册指标转发器)注册了服务注册相关指标:** + +* 应用级实例注册成功/失败/总数计数 (APPLICATION_REGISTER_...) +* 应用级服务接口订阅成功/失败/总数计数 (APPLICATION_SUBSCRIBE_...) +* 服务级注册成功/失败/总数计数 (SERVICE_REGISTER_...) +* 特殊的 APPLICATION_NOTIFY_FINISH 和 APPLICATION_DIRECTORY_POST (应用服务目录变化次数) + + + +**MetadataSubDispatcher(元数据指标转发器)注册应用元数据相关指标** + +* 应用推送元数据相关计数 (APPLICATION_PUSH_...) + +* 应用订阅元数据相关计数 (APPLICAITON_SUBSCRIBE_...) + +* 服务订阅元数据相关计数 (SERVICE_SUBSCRIBE_...) + + + +**ConfigCenterSubDispatcher (配置中心指标转发器) 注册配置中心配置更新次数指标** + +* 配置中心推送新配置次数 (CONFIGCENTER_METRIC_TOTAL) + + + +**DefaultSubDispatcher (默认转发器) 注册核心RPC调用次数指标** + +* 请求次数 (METRIC_REQUESTS) +* 请求成功次数(METRIC_REQUESTS_SUCCEED) +* 请求失败次数(METRIC_REQUEST_BUSINESS_FAILED) + + + +**MetricsDispatcher** + +MetricsDispatcher 较为特殊,它负责 ApplicationModel 下所有 MetricsCollector(前文中提到的指标收集器) 的初始化注册工作,并将它们添加到自己的监听器列表中。 + +```java +public class MetricsDispatcher extends SimpleMetricsEventMulticaster { + + @SuppressWarnings({"rawtypes"}) + public MetricsDispatcher(ApplicationModel applicationModel) { + ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); + ExtensionLoader extensionLoader = applicationModel.getExtensionLoader(MetricsCollector.class); + if (extensionLoader != null) { + List customizeCollectors = extensionLoader + .getActivateExtensions(); + for (MetricsCollector customizeCollector : customizeCollectors) { + beanFactory.registerBean(customizeCollector); + } + customizeCollectors.forEach(this::addListener); + } + } + +} +``` + + + +需要注意,以上几个实现均继承自 SimpleMetricsEventMulticaster,因此它们都具有注册监听、转发事件的能力。它们将自己注册到对应领域的指标 Collector 中,并在收到指标事件时转发到自己注册的监听器中。 + +```java +//SimpleMetricsEventMulticaster + + public void addListener(MetricsListener listener) { + listeners.add(listener); + } + + public void publishEvent(MetricsEvent event) { + if (event instanceof EmptyEvent) { + return; + } + if (validateIfApplicationConfigExist(event)) return; + for (MetricsListener listener : listeners) { + if (listener.isSupport(event)) { + listener.onEvent(event); + } + } + } +//... +``` + + + +**SubDispatcher 和 Collector 之间的对应关系:** + +* MetadataSubDispatcher -> MetadataMetricsCollector 元数据指标事件 +* RegistrySubDispatcher -> RegistryMetricsCollector 服务注册指标事件 +* ConfigCenterSubDispatcher -> ConfigCenterMetricsCollector 配置中心指标事件 +* MetricsDispatcher 由 MetricsEventBus 通过 BeanFactory 加载。它是所有事件转发的入口。 + + + +### 事件触发 + +剩下的问题就是这些监听器是如何被触发的。 + +可以发现三大中心的指标转发器都是在它们对应的Collector中创建的: + +```java +public ConfigCenterMetricsCollector(ApplicationModel applicationModel) { + ... + super.setEventMulticaster(new ConfigCenterMetricsDispatcher(this)); + ... +} +``` + +```java +public MetadataMetricsCollector(ApplicationModel applicationModel) { + ... + super.setEventMulticaster(new MetadataMetricsEventMulticaster(this)); + ... +} +``` + +```java +public RegistryMetricsCollector(ApplicationModel applicationModel) { + ... + super.setEventMulticaster(new RegistryMetricsEventMulticaster(this)); + ... +} +``` + +这意味这想要通过它们发布事件,需要通过它们对应的 `Collector` 来访问。 + + + +如前文所述, MetricsDispatcher 在初始化时会尝试获取并加载所有 MetricsCollector 的SPI拓展, + +三大中心的MetricsCollector (Metadata/Registry/ConfigCenter)也会在这里被初始化,并添加为 MetricsDispatcher 的监听器: + +```java + public MetricsDispatcher(ApplicationModel applicationModel) { +... + ExtensionLoader extensionLoader = applicationModel.getExtensionLoader(MetricsCollector.class); +... + for (MetricsCollector customizeCollector : customizeCollectors) { + beanFactory.registerBean(customizeCollector); + } + customizeCollectors.forEach(this::addListener); + } +``` + +对于 MetricsDispatcher,它由 MetricsEventBus 创建。而 MetricsEventBus 自身作为指标相关消息的总线,会接收所有指标消息,并将它们转发给监听者。 + + + +MetricsEvenetBus 提供了三个方法来发布指标事件: + +* `publish(MetricsEvent event)` ,将事件发布给所有订阅者,只发布一次且不关心事件处理结果 +* `post(MetricsEvent event, Supplier targetSupplier)` ,将事件发布给所有订阅者,并根据是否产生异常判断事件成功或失败,调用 MetricsDispatcher 发布对应的事件。 +* `post(MetricsEvent event, Supplier targetSupplier, Function trFunction)` ,额外的 trFunction 可用于通过业务结果判断事件成功或失败。 `targetSupplier` 为业务操作函数,泛型T为业务结果类型。 + +这三个方法均会通过 MetricsDispatcher 来转发事件。 + + + +在之前的分析中,我们知道 MetricsDispatcher 创建了所有 MetricsCollector 拓展,并将它们注册为自己的监听者。 + +因此,当 MetricsEventBus 接收到发布的信息时,它会将信息转发到所有 MetricsCollector 中。对于 CombMetricsCollector 的实现,它们又会调用自己创建的 MetricsEventMulticaster 再次转发消息,到具体指标的监听器。 + +之后,这些监听器就会根据自己的逻辑修改Collector中的指标计数。 + +![image-20230629160012950](/imgs/blog/metrics-source-blog/metris-event-dispatch-full.png) + + + + + + + +### 事件发布 + +接下来,我们将寻找指标事件发布的源头。 + +通过前文的分析,我们知道 MetricsEventBus 是所有指标事件发布的入口。具体来说,它有以下的用法: + +* AbstractDirectory +* ServiceConfig +* DefaultApplicationDeployer +* ApolloDynamicConfiguration +* NacosDynamicConfiguration +* ZookeeperDataListener +* AbstractMetadataReport + +我们将逐个分析每个用法。 + + + +**AbstractDirectory** + +AbstractDirectory 在修改 Invoker 状态相关的操作完成后都会通过 MetricsEventBus 发布 refreshDirectoryEvent(服务目录更新事件,类型为 RegistryEvent ),将当前目录中各种状态 Invoker 实例的最新数量作为附件添加到 RegistryEvent 中。 + +```java +//AbstractDirectory + + public void recoverDisabledInvoker(Invoker invoker) { + ... + MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary())); + } + + + protected void setInvokers(BitList> invokers) { + ... + MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary())); + } + + protected void setInvokers(BitList> invokers) { + ... + MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary())); + } + + private Map> getSummary() { + Map> summaryMap = new HashMap<>(); + //目录中可用的Invoker数量 + summaryMap.put(MetricsKey.DIRECTORY_METRIC_NUM_VALID, groupByServiceKey(getValidInvokers())); + //目录中不可用的Invoker数量 + summaryMap.put(MetricsKey.DIRECTORY_METRIC_NUM_DISABLE, groupByServiceKey(getDisabledInvokers())); + //目录中等待重连的Invoker数量 + summaryMap.put(MetricsKey.DIRECTORY_METRIC_NUM_TO_RECONNECT, groupByServiceKey(getInvokersToReconnect())); + summaryMap.put(MetricsKey.DIRECTORY_METRIC_NUM_ALL, groupByServiceKey(getInvokers())); + return summaryMap; + } +... +``` + +该事件最终会由 RegistryMetricsCollector 中的 RegistryMetricsDispatcher 转发到关系该事件的监听器中。**事件和监听器之间通过 MetricsKey匹配** 。 + +最终,MetricsKey 为 `**DIRECTORY_METRIC_NUM_VALID** ` 的监听器会处理这个事件,并更新 Collector中的计数。 + +```java +//DIRECTORY_METRIC_NUM_VALID 对应的 Listener。 +MetricsCat APPLICATION_DIRECTORY_POST = new MetricsCat(MetricsKey.DIRECTORY_METRIC_NUM_VALID, (key, placeType, collector) -> AbstractMetricsListener.onEvent(key, + event -> + { + Map> summaryMap = event.getAttachmentValue(ATTACHMENT_DIRECTORY_MAP); + summaryMap.forEach((metricsKey, map) -> + map.forEach( + (k, v) -> collector.setNum(metricsKey, event.appName(), k, v))); + } + )); +``` + +这样,服务目录中不同状态 Invoker 的计数就通过 RegistryMetricsCollector 更新到了 ServiceStatComposite 中。 + + + +**ServiceConfig** + +当通过 ServiceConfig 导出、注册一个服务时,它会发布一个服务导出事件。 + +```java +//ServiceConfig + protected synchronized void doExport() { + ... + doExportUrls(); + exported(); + } +``` + +```java +private void doExportUrls() { + ... + MetricsEventBus.post(RegistryEvent.toRsEvent(module.getApplicationModel(), getUniqueServiceName(), protocols.size() * registryURLs.size()), + //该函数会被同步执行,如果抛出异常则触发 MetricsEvent 的 onError方法,否则触发 onFinish + () -> { + for (ProtocolConfig protocolConfig : protocols) { + String pathKey = URL.buildKey(getContextPath(protocolConfig) + .map(p -> p + "/" + path) + .orElse(path), group, version); + if (!serverService) { + repository.registerService(pathKey, interfaceClass); + } + doExportUrlsFor1Protocol(protocolConfig, registryURLs); + } + return null; + } + ); + providerModel.setServiceUrls(urls); + } +``` + +事件发布时,该事件会被转发到 RegistryMetricsCollector,触发对应的 Listener 增加 **SERVICE_REGISTER_METRIC_REQUESTS** (当前服务级注册请求总数)的计数,然后执行定义的 provider 函数。根据是否抛出异常,之后执行 onError 方法 或 onFinish 方法,增加 **SERVICE_REGISTER_METRIC_REQUESTS_FAILED** (当前服务级注册请求失败总数)或**SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED** (当前服务级注册请求成功总数) 的计数。 + + + +**DefaultApplicationDeployer** + +它在应用部署过程中,初始化配置中心时,发布配置发生改变的事件。 + +```java + private void startConfigCenter() { + ... + compositeDynamicConfiguration.addConfiguration( + prepareEnvironment(configCenter) + ); + ... + } +``` + +```java + private DynamicConfiguration prepareEnvironment(ConfigCenterConfig configCenter) { +... + // Add metrics + MetricsEventBus.publish(ConfigCenterEvent.toChangeEvent(applicationModel, configCenter.getConfigFile(), configCenter.getGroup(),configCenter.getProtocol(), ConfigChangeType.ADDED.name(), configMap.size())); + if (isNotEmpty(appGroup)) { + MetricsEventBus.publish(ConfigCenterEvent.toChangeEvent(applicationModel, appConfigFile, appGroup, configCenter.getProtocol(), ConfigChangeType.ADDED.name(), appConfigMap.size())); + } + ... + + } +``` + +在 `prepareEnvironment` 方法中,会按配置中心设置的组(group)和当前应用程序的名称作为组名发布两次事件。该事件会被转发到 ConfigCenterMetricsCollector,增加 **CONFIGCENTER_METRIC_TOTAL** (配置中心配置变化次数)的计数。 + + + +**ApolloDynamicConfiguration** + +动态配置功能的 Apollo 配置中心实现。 + +```java +//ApolloDynamicConfiguration +@Override +public void onChange(com.ctrip.framework.apollo.model.ConfigChangeEvent changeEvent) { + ... + MetricsEventBus.publish(ConfigCenterEvent.toChangeEvent(applicationModel, event.getKey(), event.getGroup(),ConfigCenterEvent.APOLLO_PROTOCOL, ConfigChangeType.ADDED.name(), SELF_INCREMENT_SIZE)); + } +``` + +当Apollo配置中心的配置发生变化时,它的 `onChange` 方法会被触发,并在最后发布一个 ConfigCenterEvent。该事件最终转发到ConfigCenterMetricsCollector 中,同样增加 **CONFIGCENTER_METRIC_TOTAL** 的计数。 + + + +**NacosDynamicConfiguration** + +动态配置功能的 Nacos 配置中心实现。 + +```java +//NacosDynamicConfiguration +@Override + public void innerReceive(String dataId, String group, String configInfo) { + ... + MetricsEventBus.publish(ConfigCenterEvent.toChangeEvent(applicationModel, event.getKey(), event.getGroup(), + ConfigCenterEvent.NACOS_PROTOCOL, ConfigChangeType.ADDED.name(), SELF_INCREMENT_SIZE)); + } +``` + +当Nacos配置中心的配置发生变化时,它的 `innerReceive` 方法被触发,发布一个 ConfigCenterEvent。它的处理流程和 ApolloDynamicConfiguration 一致,最终增加 **CONFIGCENTER_METRIC_TOTAL** 的计数。 + + + +**ZookeeperDataListener** + +动态配置功能的 Zookeeper 实现。 + +```java +//ZookeeperDataListener +@Override + public void dataChanged(String path, Object value, EventType eventType) { + ... + MetricsEventBus.publish(ConfigCenterEvent.toChangeEvent(applicationModel, configChangeEvent.getKey(), configChangeEvent.getGroup(), + ConfigCenterEvent.ZK_PROTOCOL, ConfigChangeType.ADDED.name(), SELF_INCREMENT_SIZE)); + } +``` + +在指标收集层面,它的行为和前文中两个配置中心一致,此处不详细展开三个配置中心具体实现的异同。 + + + +**AbstractMetadataReport** + +元数据报告接口的抽象实现。它的三个实现 (NacosMetadataReport、RedisMetadataReport、ZookeeperMetadataReport)均使用它的指标事件逻辑。 + +当订阅新服务并获取它的元数据时,它会发布一个 MetadataEvent 触发相关指标的修改。 + +```java +private void storeProviderMetadataTask(MetadataIdentifier providerMetadataIdentifier, ServiceDefinition serviceDefinition) { +... + MetricsEventBus.post(metadataEvent, () -> + { + boolean result = true; + try { + ... + doStoreProviderMetadata(providerMetadataIdentifier, data); + saveProperties(providerMetadataIdentifier, data, true, !syncReport); + ... + } catch (Exception e) { + ... + result = false; + } + return result; + }, aBoolean -> aBoolean + ); + } +``` + +在前文中,我们提到 MetricsEventBus.post 的第二个参数是实际要进行的业务操作,第三个参数则是根据业务操作返回值判断操作是否成功的逻辑。 + +此处的业务操作是尝试存储目标服务的元数据。执行操作之前,会先发布事件,最终增加 **STORE_PROVIDER_METADATA** (尝试存储服务元数据次数)的计数。如果产生异常,会增加 **STORE_PROVIDER_METADATA_ERROR** (存储服务元数据失败) 的计数,否则增加**STORE_PROVIDER_METADATA_SUCCEED**(存储服务元数据成功) 的计数。 diff --git "a/content/en/blog/java/codeanalysis/metrics/4-\346\214\207\346\240\207\350\275\254\346\215\242\344\270\216\345\257\274\345\207\272.md" "b/content/en/blog/java/codeanalysis/metrics/4-\346\214\207\346\240\207\350\275\254\346\215\242\344\270\216\345\257\274\345\207\272.md" new file mode 100644 index 000000000000..7c3c854a7822 --- /dev/null +++ "b/content/en/blog/java/codeanalysis/metrics/4-\346\214\207\346\240\207\350\275\254\346\215\242\344\270\216\345\257\274\345\207\272.md" @@ -0,0 +1,223 @@ +--- +title: "4-指标转换与导出" +linkTitle: "4-指标转换与导出" +date: 2023-04-28 +author: 武钰皓 +tags: ["源码解析", "Java"] +description: "Dubbo 指标模块源码分析-指标转换与导出" +--- + +## 四、指标转换与导出 + +本章主要梳理指标收集完成后,向外部收集器导出的流程。 + + + +通过之前的分析,我们知道不同类型指标的收集分别由各个 Collector 实现进行。它们底层的 MetricsCollector 接口定义了指标导出的操作。 + +```java +@SPI +public interface MetricsCollector extends MetricsLifeListener { + + default boolean isCollectEnabled() { + return false; + } + + /** + * Collect metrics as {@link MetricSample} + * + * @return List of MetricSample + */ + List collect(); +} +``` + + + +而指标报告器 (MetricsReporter) 的实现会定时调用Collector 的 `collect` 方法,更新并导出指标数据。 + +```java +public interface MetricsReporter { + //初始化 + void init(); + + //刷新统计数据,定时调用collect() + void refreshData(); + + //获取指标数据 + String getResponse(); + + //获取带指标名的指标样本(单个指标) + default String getResponseWithName(String metricsName) { return null; } +} +``` + + + +指标报告器有两个实现:DefaultMetricsReporter 和 PrometheusMetricsReporter,它们都实现自 AbstractMetricsRepoter,并使用它的指标刷新逻辑 (`refreshData`方法)。 + +AbstractMetricsRepoter 初始化时会获取并保存所有 Collector 的实现,每次刷新数据,调用`refreshData`方法时都会遍历这些收集器,更新指标数据。 + +```java +//AbstractMetricsRepoter + + private void initCollectors() { + ... + List otherCollectors = beanFactory.getBeansOfType(MetricsCollector.class); + collectors.addAll(otherCollectors); + } + + public void refreshData() { + collectors.forEach(collector -> { + List samples = collector.collect(); + for (MetricSample sample : samples) { + ... + //将Dubbo的度量类型适配为micrometer的度量类型,并将其添加到CompositeMeterRegistry中,借此实现多监控系统的支持。 + } + }); +``` + + + +DefaultMetricsReporter 和 PrometheusMetricsReporter 各自实现了自己的指标采样逻辑 (`getResponse`方法)。 + + + +**PrometheusMetricsReporter** + +它通过 PrometheusMeterRegistry 获取普罗米修斯支持格式的样本数据: + +```java +//PrometheusMetricsReporter + public String getResponse() { + return prometheusRegistry.scrape(); + } +``` + + + +在初始化时,它会开启一个定时任务,定时向普罗米修斯服务端推送采样数据: + +```java +//PrometheusMetricsReporter + + SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); + + @Override + public void doInit() { + addMeterRegistry(prometheusRegistry); + schedulePushJob(); + } + + private void schedulePushJob() { + //这里的URL是DefaultMetricsReporter中定义的指标报告URL,提供了指标服务的具体地址 + boolean pushEnabled = url.getParameter(PROMETHEUS_PUSHGATEWAY_ENABLED_KEY, false); + if (pushEnabled) { + ... + pushJobExecutor.scheduleWithFixedDelay(() -> push(pushGateway, job), pushInterval, pushInterval, TimeUnit.SECONDS); + } + } + + protected void push(PushGateway pushGateway, String job) { + ... + refreshData(); + //将本次采样数据添加到pushGateway,等待下次抓取 + pushGateway.pushAdd(prometheusRegistry.getPrometheusRegistry(), job); + ... + } + +``` + +PushGateway 和 PrometheusRegistry 均为 micrometer 提供的 API。 + +**PrometheusRegistry 将度量数据转换为普罗米修斯支持的格式,而 PushGateway 存储样本,暴露一个HTTP端点供普罗米修斯服务端抓取。** + +PushGateway 本身只是一个度量数据的缓存区,普罗米修斯服务端每从其中抓取一次数据,其内部的样本就会被清除。 + + + +**DefaultMetricsReporter** + +指标报告器的默认实现,提供了按指标名称导出特定指标的方法。 + +```java +//DefaultMetricsReporter + + @Override + public String getResponse() { + return null; + } + + @Override + public String getResponseWithName(String metricsName) { + ... + meterRegistry.getMeters().stream().filter(meter -> { + //根据名称过滤样本 + }); + metricsValue.forEach((key, value) -> { + //按格式拼装结果 + }); + return sb.toString(); + } + + @Override + protected void doInit() { + addMeterRegistry(meterRegistry); + } + + @Override + protected void doDestroy() {} +} + +``` + +该实现使用的 SimpleMeterRegistry 本身只会存储指标数据的功能,而不像 PrometheusMeterRegistry 那样提供发布数据的方法。 + +**因此该指标报告器不会主动向外部发布数据,而是被动的通过 `getResponseWithName` 提供数据。** + + + +而且,该报告器在任何情况下都会被初始化: + +```java +//DefaultApplicationDeployer#initMetricsReporter +//If the protocol is not the default protocol, the default protocol is also initialized. + if (!PROTOCOL_DEFAULT.equals(metricsConfig.getProtocol())) { + DefaultMetricsReporterFactory defaultMetricsReporterFactory = new DefaultMetricsReporterFactory(applicationModel); + MetricsReporter defaultMetricsReporter = defaultMetricsReporterFactory.createMetricsReporter(metricsConfig.toUrl()); + defaultMetricsReporter.init(); + applicationModel.getBeanFactory().registerBean(defaultMetricsReporter); + } +... +``` + + + +实际上,该类主要在用户使用Qos命令查询时提供指定指标数据,而非提供给某个特定的外部指标中心。 + +```java +//Qos命令 +public class DefaultMetricsReporterCmd implements BaseCommand { +... +private String getResponseByApplication(ApplicationModel applicationModel, String metricsName) { + String response = "DefaultMetricsReporter not init"; + MetricsReporter metricsReporter = applicationModel.getBeanFactory().getBean(DefaultMetricsReporter.class); + if (metricsReporter != null) { + metricsReporter.refreshData(); + //获取指定名称指标的数据 + response = metricsReporter.getResponseWithName(metricsName); + } + return response; + } +} +... +} +``` + +*需要注意的是,PrometheusMetricsReporter 也支持使用 Qos 命令查询内部指标数据,同样有对应的 PrometheusMetricsReporterCmd 实现,它们的工作原理相似。 + + + +以上就是指标样本从收集完成到最终导出到外部指标中心的大致流程。 + + diff --git a/content/en/blog/java/codeanalysis/metrics/_index.md b/content/en/blog/java/codeanalysis/metrics/_index.md new file mode 100644 index 000000000000..6713f4138352 --- /dev/null +++ b/content/en/blog/java/codeanalysis/metrics/_index.md @@ -0,0 +1,8 @@ + +--- +title: "dubbo-metrics 指标模块源码浅析" +linkTitle: "dubbo-metrics 指标模块源码浅析" +weight: 20 +description: "Dubbo Java Metrics 模块源码分析" +--- + diff --git a/content/en/blog/java/codeanalysis/metrics/img.png b/content/en/blog/java/codeanalysis/metrics/img.png new file mode 100644 index 0000000000000000000000000000000000000000..ae54471c917e497d281cf4a627d88c0857c8a2f5 GIT binary patch literal 43883 zcmeEu_dnJD|9)FEBs(iq4noJumdq%-B3b8tE`NSvNsvw93+yFy=Cvc z`QE+W^}4;k|G{^B&QB7@^E{vTaow-$xmF3ToTp~GguIzD~3|=jH)ihTRzf)j{y9oad?zti7hrwVJ zENK#D;FTnZQ#<@`b-G%_;m@a?Lx;kDW7>U?iiiJiR`Wl<{(t+e3!y4;UP7s={(QsC zv@yTe!s{@)!(0aarF4b zix+<%ShKXc;M7`492^|@Ony{*Ref35Z|dl<`X0`;v#}s~S7vo}t}CZz&~pnz#=2Db zp;=-lJvCKf-xI+yS4(p>;{qe&Qjn+H>VWHliLr5ig}aW#JIo||Z~2$y&snvHSC%0A zfPsNw`J2om98&R-;Xv8*tg>ZSC8h7=Y|8a1WMty*ote7+I2`@}Q?b82<9V<%`1gmU z@K0~ux}~J#?{Qo&-cb zZ7ss|Bt(8113FaU>i;4CNUio%r;&D2Tm zFDdbq^BdK_ftqrLn!Db_z4c8QqD9K<)Y#bAw-k1G(Tdn3e5e^21AR1Ny`y#Wo-~Or zl(iLE56WlBBuh(qeCEIm5tCmlJJ{cO_wL=YY0#M^OGCq@?U}5D=7Zhlm1fC<6v;i) z`M#1(r4Kuv$1lsx&CZ6RDTF0VTa(`LnJ|hv&Q?8VVmeRe)82Gk_6k%qbw3EN_#LFn z{_YmRpW1V^MP4KMF7cT&-q~V^2b1!WyaEDYdSO(Vk4sRdrdxS&d+9215;SGYN%GR2kF>R!`NzmhgTe(J8Vb)YXZK zh&Xy`$}~Wg=0M8b;k4(IQ+xK~#}D_N^|i&t)U2$C*l=@mb5Z9-18M0RuRO`;gY0r~ zp8LGu>ehvR?$-aP)Pyu7@<{VJ3b7FO1* z$0aOryC2LuGnri)o0=r|H%C49X7rzi!aXS{DpKMzGBUawBO)LyOna4rg2LO8UfhLW zF(*F$XrAR@MSpASv&oZVfoR4=dNSPniuySC(e*REajI(6>0T88eI_1&$N z)&{afnv{r$h%aBhynWl&k|bRR#i1HGV+eOcjrzO@^Ps> zyWG`rvg}U~Zd}^ACyvhyR!Rn*T~}Hi%g`y};N-N$B;S3}ojb-cQeBCC9$+e*_-{pVw0q>{TA=t5#y2qOgr1yxm5 zLO3rX(%P1q^1;5o>lx&u_<6L4=Jk2)*;j#qfy*tdTvdN_NEC@piWGI4Ct`BTe!lW# zE1#&KuyA{G^K!{g&XtK~dFA-lYy)-mkkBwKzsyYTLVwQ`mAK55l#L+I-BD7{&Et>A z1q2;uwTuwz#7j5L+EWt}SaKlUjvhbdw)X4cq##Z{eb?G^hpu#`ufz@|h)0C93=T2{ zW4n5aZ4-+bf_=07{rt#eISGgdQDI@PFER2x!F~SBNrg{FZm!LAqO)4`gm_aCv&UGj zOGrrY@TgdD^7B(j;RXl>6}!tyXOokXPSn{{y*jByUvptbUOQnlN7iU$wmUDUvx{o| z5+9lab$-lOwMOd9>C=&Em%|A@s=bI&d3}1Hi(K5?v4WPDPWc(=2^(ww`BB_g>5M+{yGppCXJCVUxntLLiS|oOUm4N{J8IIRS6A8Ac+_T5Vc~=H>Be__4<0;dXtq!I ztt!jN$Y^YAe7fV;=ZA?w1cz0BDz4jCxb(`LA*)(<1q1}T5U9zaDz6bL&Gua5?>1U^ zN+px#*cbux4sT*|qh?i>cs-9TL~Gfwr)~9sjt?y9d3=cEO;a zOUkxFMoCEt%HqEF;`%z3wJkQ$5E{#O{rzXt?P;6mruKDCyzv3toQ4PV@-v2pa0QRJ zl$oEeDRGauy1KRXV!yV!dctGM`i6}G*XFi1jk1jtj2aIQ&lIJn(YcNwkLu$g_G>D# zvL`vnEqzC3-RgxCpB6VZ-fd^(P~`uNQM0EBfA;Lz?XwKR&rbAveL6!-EOnAwJ6A?n zuBN*Bjh6y)%wa@6pNxZCGFHSv@!> zQ6!#LZBHsG5oY{Na^{TM$C3A|#^1y5AbSP|=7)wBA(&AMV*AHiaJsjoup1=qS~w^_ zZkxltlU!qT#z^cQ!D|L;wBuaQN3p0AI|yYD0Z6FvP?c4D5JqiwnROtJ>5CW10wm7e zySU}K(;E8v`t(%!qcNgR6#{Yu*CDhM6!?#$Lz9!3U^HW&d-0jo)m6EGOCQ~c*k>*! z-n8obs+j!)kCzz}j(Y#zX2IY-L~ab0Mz`38IgqBA{MR!;nqh#gDND%{PhU# z;!R-H6X53Lls*!FU}U|ht)bzy`VNWqab|yPjC=q7eFJKBak!@VWX3g#tCNOE><{S% zg{DvRiIWO+bWtx}9ML2*vpCq_i@%7)nsl}3y zl9`an$jhUnacUR;1ublHWaqTCwGVMRHP<6eeSMy|T_%N0wM4n8si|*_%0Fo}Qj}#$ z{nFiXk=VK$ni0@`oU=5>Xe_O*Nza{w2PJ(TMMRj{gobs=<&1+WZmxO`(knu@d8 zZ||9d!`}4gEWGYlnyW97ib)sIq4~F+Q283R@r?i)e9zK`#KdrknqN5Sbz7Du{(zpI zzG8Faj94aOL&Lz}@@+w0UiHWCSKLvW>$V^2@8Pd@P?3|f{>ab_RNIB{lw0L2b904yCz%kEvj#;KQCae<1|De5*RNmu z`}d$@#bEuh5(m3>^p4#%dCsjH@QX3nGf5Y|D45xXzsmMJ@W@YIl^HLpMLd|Cn+sS2 zyp(!YKfQ`T7~9(zT-av*d@R>>X@o#UMKv;Ia`=6jElVrMl`Fqjr`izpK0ZGA`T1ED+hzdBN17HPzObimn+?&~%K=_h zR3yPFs;EF|a7T#;F(d+5@!YIoTI3N){`m3aOi(}o0}^$@QOf1EGF2j*a`X*|fcf_J zb_}f%gj-&IzKl^~7+K#<>j4=H!zXS$nKpHf!JksE&a!v-C0@zQn^MNH%x33})&@v_ zNJ&nHw@BI#h1d9;Q&Lu**A)9$>bCU^Cy79u?#G?9mGA25L0N3l-FhtSEndxnc{Zh?V{5^t z5{p|58;~K65dj?2hdGK)D=ZXDHv_oa+WVS{ni@R~=pG8HP37q3s7I9{g$fOtZ0W}l zz-l$GMi7QyPn+W`#~Q*=!Jj^H(9iAf?fClmV9g6@{_9SA;1U!X8XCqM-+4tk&lPn3 ze0>OgcUGqov$A-~y#t=(dmTM?m+B7FsbYvuS66q8)0t6JuEi53b$&rXIYGm-o)03C z=u>i6#pBrgTa*cQrI*E{I1j(NFEh#9hZq>ql$R%3!?A=8e4#K5aHoY^7Rs&xrH_+? zL*xrJ1g4>NPd+i(LE*7eeE@K0W$)Y}?%)|X$EeZN)RZ#?S*@+5g@`l2mSeEkYLbK1 z6v^_0#qlWXgwr)OH6M!t<@>Q4pQ{b)gphp482B&=bDDkZn>$B0sP~mGY=jCC4LMcr z#CUmmb=}KHLkCwk`1wI*)0U{HdC*vF;Ot zP^Q1rXP!WoBP548PDxA4J|L|0o{Nj?99=bYb!w@H79!B`$&+Lt2~OddVMSmgq0Z--H1F@OGzZ5^Znp&CJ@qR$2|Q=do;5Qw3*B#P z=l=UvrL_n~%KfcoPi$TN%>n0{*4AYh(xs%v@htfnmIIvw3c=XfP0m zYyUw#Py2_4sYmg%u#7a_9Hbx(fF^TDp1B=maY+bd6gRW7+V|JrJ$BGizS^p^zP=7c zarqtpzr^Ag4G=ezzdlnllIgq72}nv-0`IZaC$mb?2Q&~T=V$#&kIk$F0=0g$s8eR4 zxMahhJ0*o}$~T!3ID2##~6WE?-+` z+FzVL!&9~hGZ62!Ysuy1x)S7M;+$JsTTJe&!9u1wu9;aTe+Hr#Gz?CmlI4Tx7TJ~zI-XU)7|U=pbrX4J)1e=?_~)J76PB!0Ds_y{p8QwT;46C`||_k zUmPt%UK6TMo}s$_xcKL{Z^8lsl$5SB9b8-KgE~;u=KH_ESeFwvIY}d?+F$luL!u2` z;<9E2oLWjsL}DUZQBhG>mtkE=LL*2`LxY@>vH&Qdz`*lc{H;Qp;+<`6HG{rDE-j3E zhDqB0{lL3>5tZB1pLr@aQTF!sH_b2R!7z(&Z|7%bW)>G`y>3wu9Gp{8A<>f=Wj>kQ z(ZLDg3Csv_H?3py^77*2Taxa)g-;GB#||h`ip4+%?|&~ffjyRgS~?g2o8uCrapEw?203nol% zi&Z+-<&@OaY;nncf1&hsox<6o$~{Yf{4leQwK3ktr}}@-h3<~gfo`$3`h@7zDZL7} zt*Ymh5p%so&5=k}F|iToF`G+(jiEyUn)J40Dmurqr zvvY8;v(YMpMq*pV>r?J|un!p}k!_^%YSYTXB2>cVvZ$!&<;%BRl@aZ?pXO@kJt>Ez z4G#}rHhquzgNI+`!RQuAxC(Dg1hX zpP#tf<_#a_SRQ;w&L%LX%5f6zd)ws=_#5Zxg@$HlLEy4o9Fpn_+yhlXHeF z!mJ=a-{4JMAVbZiBs%0!X{m?>gDq|et&viCGMOyyU%BsS!M$Y!OiLC7F zu&}jsZ5Q%ucj-kPA8U1)E$wfePV@FY;eGj{9i*$W@{eD?9jBqCMYB^= zQ(t)kXzh{}M3|%Fx~O9)JGG^iRcu;Xw=dH^`ggrbPWyWSbKp?~tp~~ss*Z`5ceBdj z@N+N|X(bgGcU7Z?ftx3@0&GZ38g%RTYabsM7Z;YRA1OI%)J;vNiE9(&uQjAB=A+)#B{rnHUfbX{<_IBl1}N=UM<=(e)7%*e9-kd1>7nfT%IL_*h4*S|YR8GrZ%;_>G({qTQ?LO7Q|JNEP*_s&N+%2CL~TGx z?)pcjXb6=EeUImdc=24QN}JH1B;NugCLeI=HI3{b#$>2e8jo1E+O}uF59XV;smeMJ zS(uuV@ljA)b0QEIR9INT#(%_s^zxuD&>%N2uZ9aMcs;Mh-Uz|JSRANg5DVb7xda)H z7!BimI1;5y;9M&$Ev=W((fJY*qMjD1_IZ8%{7lD3%ml^4K)FAWMWfqr^~v8o)4x79 zH8uukM;?ygKqc1^2>!-ddgWMExqA|`;sdmE^PEdJQ#I zUPMbpQg`oO_j&ozMjuL!1$>Bx9a%}CO}YhWhWnF=L4p=tm*bLc|J0=wKbk!#_2D5Q zEOF~LhixZc2F2o4XjSfXPb7q&m-mzTFmoi;_3T>$g+)aVH8msOy^C*6vY6A1-Ycn`zRiAC9}a!?y!qdn0RTV7sXS_+G;mbr{l5f>K+*lNp)y&)td6HWQz z4&rvB+y3tJT?_->EG9-5%H|SUQ!_s-EG(b8>z?Pqn4aE%7D=}_=wJEy{8OYaR#)vc zH1h6638GDGEs)Om)W|D{y2%3b&fVQzki!U{i;Axzk!13-c)z!(C#yFFL&L)M2FIp| zQsD&^bfNNK-)Xyfg$Vnf0?8kTX^GHtVdvx1keC}Tjpf6#K%oNal=7hzbI{KZ&|y+< zg-&+mphrhXgH`LBW@jxR?g$z|IcsYhuSn6661o#_ReYMFg_ZON4c0C8fR~AiYVI#E zkFZF5{ra_wOP(ydV?fJHXBMmD!*ne}6BBF0oS$7?#o5^kIr~JY)!G2T#-X9?&Bk{k zV{2z1dTw1~Sxe%~0X6XWv12d{t9h`{Bi1bud9i793z|}kkLgkXC$ZN9l*H2_GCnyF7L3QW5apQ3g3yq!LHtBEO&JFT% z_Z`REw~v{TzGm}Rv#{S%EzvisXP0 z$jI1eCVFaS24Q4tXICRsse(ggiHnJGaZ$%#CMd0+Jh>5DOld=JqjbCa5>jE7f-&Uy zaWCKlFOrknPBM}uYVnQZ70xqBTxa+S%IwlA*Paa$92ZE%_Y1_e@W!9~{O;J=+CtTf zk2ge(JX*T6>POC2R#ujqn`_kBc6qj}y!>rQ2*^8b?(XhxZiF$_2GxgkK}->P-z#hr z&k;<`&7Bm0vjNB_|Cmf)RTUH2TlPFJ(hj8Yz(8ddIW>#S%ji?yQ-zkj7v7K7sc3=D3sS;Oi>?dw^wDu~ zL5IAM{F|`}>JP&=Qr^8QiHf2dmzPgYPM+(1=&&;01ZnppHe+FYJT|7h;=>060@i?) zb@cadhso-Wj*hQiZ{hU~4aqtRpRZ6s(!O}{0*l4M{C0_Nf6<>HR?%ybtoVnb>Jx+Y`AU8%Wp9~D~A)&h+I8un95OV;`n~UX->+RLoXso<^@VwTAGz!dX_>CQ)N)6HoVE`@9XW&FCf5P zhv<00YWm~}6&abDo?ak2@SW`{6?Z-m_I-IKq&@)`s22=wNgl#*V9&>0%V=aBwl+7F zBX6ihkNMq_DgT(9jAgq-=snB4e?bRyA|TiKE*?(uNSF25555kMz zS7_LZ3q9)i9VU(|<-_<3=X5wYPL|$t5E#zapQ2TJav@a#K zu=a>N56^;SuVOe4X;oW({8nvK(qjN6v zs=0(yy9Ngb8=98XfBkylAi;}=eSn@KCLl!S?&vK8&HAUd0^*KUwY5~fYS#lRkN(_< zBx0pl*zpQrF@aLz+n--pSleGkvloy46L6!1)EARwpBJ+ue3)!^oMKk9dqtW08fwPL zG?nMZ-!r)<$~^yM|KsTfwc2`iZ> z#BpldvC!XOQf;cEad!!15G{0d`e?6yy~PO(B`n|)k*Gze1^qwrb%j;!Bw%SQWp#D+ zV@yR+WMt%_+s3nbQtEF|+T&0h$J(o_N5%kT1x~VWZjJ`gCX*go!{BCA$m3H}QcM8N zBt6~yrsA;-H2L~Wr!^oQeR6T`-Tl>t!Ahrvfz1GQED$TQ*(~ra~7M7cU2#8gy43h=6~dNT-0@Qh;VcoX55)C=2rP zbzW!4#P7f$UdO}in$HPd9EQiy1Idxw>%G?g zXC@9w+br$8aj;4(Z((A?@OV6s5XUP6L_|amOT0?QwSRx*P`9-$9RMeVa*W8;IKN3+ z;42nSr~@r#2!nZk&zLm(sAj} zTT0`8#7R~@%+jmeYO;naNU8M?w;HU7foUx`xCMm%IJq98$^g%;@A@tq^9+oP+;PbQ zf9|^PA$jpNaUYm$7~9z6b`=0MK{Wz;#Nz4GH!3^xR{f;~_GyVA|g+Q zt6!f#e;$xFl*-cXu}stwf}Zp(?Jo7kdS)`h;o`;1ca&t4@FgU`vj7FgEGf-P74*&(`HkIr`k9c$E8T`H4I3l%Qd@Q+#Nvz3QCYw zr-(80p-&{7GMQOeS_cN0xwsfs&{tARp(+`)HHi28{Hb;Sz5~qpV;Ms`=sGhV4tfbU z8jT!XB=IoirP9_PKlEIx@3(e!VM6gq4m0Z6vP(VU4YM${(dgX&wLd=YfAB7k9cc^M z!LUyt`)W0Ey12O5Ab+xl=)tEG-M&klfnCAy1eJ==OX#}5_>(z=y`7Cw*G9iyML$(Y%I%O+^-8o?e<{`SRlLZ*Nii z%Ch#?u3j}950coPSe+8-LV?&beJ;;0=iYn%Zan@(ypPwLkdW=Mh=b~A=bte!9EWpl zVIJbnp~FdZPSH+}jlCA1?#wz!Rf_}8j;5de+OS?t($LV*$urk&ZV;WNc_C_C;}f7Y z47kNs$-v-)a|Y8KrrYMXu5Q0v5Tn;#^@}BH%%mE<8;-W_=-b+W9kY(><=)-`Bc_i+ zCxJJyITPp=AJ06`YO9~6`=tZO5-0XUkZNs$vpp&@J-_ zQPD40Y|Q3@D5YTk6)0Zp(=D~2u*`Azq`baEl}FbY&t>K-v%Q> zi8Qmc6!+M5mSLMO*xt?qHWn%xisq@}>@};ZY}>31{YpK3eI|F@9$^ulM_z7jwgWxq z?iTa;*A$7Hj5kY5N@Rf>iLI4*Vv^-#V}s!0BFx8$I)Ur$EN7+7@T=uach2^2;9)J; z>X!pz{}AVGI3r6zls5kUSPhF%I1wHcq~h!>^ejb#EOC4LRKvo>u(x@KcI4Dw%Cfiw zgCr+D*|g0a9(k{k;R!M%mV+1hPUF#bfR^IN@$o0WuXS9G&BH-We0ygC$5A)=j?dv~ z)&0*8?qvO75_3MCNODfsukrS;ckkcFOAw|$A#Tj3MbXJQC^zE5Sh>+?G+7^*8>F5H z@bh2BkB*WvI&x8${%mV&>*%0j_hTX(gvJ~GgI0EqmX;REutavFrvXQ)whIZlpk3O7>{<23gUC;Wc{#dub$yL+UW_q#dd_4z>lia#hrNh=fmI%>;r=j z)bTL^H-KD!FcBk1SAg$5jmK*{0-~y zc!h`Z!*cRv)=VCu`u z_kf-mZ`Qv&aQY5a;^rwG{0Iln!-ntQYhFd&9Q^WB_p2flJ#ui2hDHz&=LH;-J`C;q z_e7F^my?xE43otH;fWy^83tM=5+)lg*qA>Qg43F#Jm#3(D@nE+lJkd(zvi)dR*DtK zY=SUlOb|{@CObBE06f_yP48dppQ5(}!8rZg7H9Yz(8GUk7^_@VR8)CcnY8r71P5hK zaIIcm!}>3js}BOorSU?MPb4*k9d%VS4ja+>itv}zm!p@RhMU9WO!xOjNv zscQ*@_+vToINVwAsD>f2$1x|7f;pqS7*J6(#`s)f10a|e$ol@VLOoLE{~($4;RJGz41zvWPG|6Eq? z4p0iH6>xupRrfT{n3GHO?vEebv9Wq1w>|hffLtYW!>HwVLW#4ons0S|4mk$^#Ldku zM~y!<66*sMTIt@s8WAS4M2sN*X!Xqg>G>D~m#*4c$FYX{sl$DJVisz6S~H=`mqCBJ zV{z;khM_LgkA@JhQ`qPLqlUOYIA8&Z;=gw7Nec_-)G@oG%$Ocgo1r8Bp#GVx z6nt&1Rd+}b;+?pT{$p?~Vp>3Mc%;({@NHszTtrByF-G(daEN=KmsarW>=tFhwInBB z%MX0{QVOaYV-5;EibA1+7(}UPXfQs~nwGtVTvx8x_Z4UT)Ilu)p>3PY+F>((H)i(O zHSeM7*WsC&R$YqEmPII{A|i^MC3ofVlT&ReWOiK)-cO!9c>r|QiRhS^7-vBW=mAd! z^2gIOQi5LquZ4v-Vw3L&w$RT-x0X{mO0fdpnBK%6s>Ewij1eheRUb$kh4{2r} zWZ$9=e*K<;JJ41RT}mnO)?n;V^R1`g=PczDbrrw;^ZR!tu@J*)2f^)IjfFvL6DOWe__micItB(8#>JfG2liR|FZd$} zurmSNjlipm_pT3&66=6vUb@-ON3IOA-q1j=cHOQ;{fmgVdK zi&!&{mIs)`XWo$xLc&x{!VTh=U+kyUf3u1(av{ns*+eKs5wTZagUmSk1{E_RKYPXl zcj+b>8^NbmHGi6RVEn(Epl*Lw@4cBhk z^tH9$K~}=Dz*s+i4zQWf>CJtRuY%XlE)-z(}|L9c?g4(|g6 z;UD_JRn=^|Jm^K;Ls?k@*k5hF!!AO$7o>}Yxw-WB?X4~7-wo6nw*pE^O2&R$TsYJ4 zVHhgC+umAecOI1Tb3lY&0}$^pt?3rT(+BhP7ps1e#*Q?a8-gOBWp;0jSKRcPJ>wr0 z8Hphc9R%G1M(*Wy?Yz}wl}@m~j(hnx>g8QqS|0lj4u&q^I+t4r1Y;OJo;(@9cFivP zbVY3tlcZ%&{_8VbK+AJ-E_fP=wRd!kL|XJdXicksV03eRY_bI%gT2WFf^h&ATVbEZ zRrv*)0jmRQ4tJ@80d_4EJs6mns>8Nyj zenj#7ihjv6V{rBv8h$2alECQz<{)zeE17&CeN_;2%%ewNg4C)ope%coh67p->|^=(+L zrJYWnh%vP{^yPqQTJ9c}W{v~=D>rUTk_FXiaWNJK6E^qT(=@usX0wD&ciFqSmHGRh z+19#y4*c%nbCZ+a);}lPQf6RJ#sL)XqiT#~WZlQ(=#Bq&&n%PL)TH?M zs=B(HU}h;P(H^j8IM^$0f#H5uIU_4e{$9ep;1`=@RnWg9f`jAf6ZJi| zc=+RH(;hFqKGfb*+<05@gbu~*Lu(B9KwDznhi|Eapoxl#IKK=ZU zv!kId&)4AJ56o7FP$zvoF+ZOJ4w$YktrO80VcWoQ0KnBXtUuKw!9lwUyOum!24pbd z)6-v{ZmOw4AHrWYWqN_>JecQW#GWsMJpR)tBjaHb4Hp6dxR=Q68PumqrKyuMv$Jau zwh+N&k}Pt^j~{2d_x_3=K91LT8nQ0?HlQDOf_7}Naet`;n6|gnTD4ZV?gP!pH9~p- z6}6-FSqql3s@{q~8^@@iKKlxI#PV`!d;5G?$Pzi+VcZDvAHi}1nuY%Drmv^>a;R1n zxaCWtu4lD^2eWA{Ir8JsLJETpYnmtjMFD?) z>}_pfI5jah=L{#fh%AT?_h43Ka9~uVo2QCCoX;_Ec9zl9Tm{I9SGbU< zW%=mQHZ0p@Guks37JIn=0Ns5F4Zb86A@RM+3EU~*ajuhLoZWQGMd-~n_N%!fwZ$UX zQSGoe3sT^l$a>XX&O#c9sfePqm4P!GbRai}q4Qyofky#VcC(_`nJ)ZOT3XdOh=!j& zFA(Lws7ila@@(j<6r=+M6%{HChr3IUc=+%p00>aEA*HndAZj!ytz7^Vy#TKEH_XyE zo^A2Zft~#y62G;z6*kQF!LzGdWEJD~{t<(uM_*4*EtoC<5;PRCrhxwrB;t=Ax6eZ% zfpSt?SH~poLU9k=OI~j*Ei3?p73SvFdeMI()4rz5?g>Tv&6^8JY|p3)uwF0jU@AeY z)1qTMqvkvET>hxPyo`+FN^}d97NV0U4bOGG&dps0_f_{pMMX2UmIt=%Vb|sQ`})Yb z6Z9GA=>@I&y0#2(37?SX_%J+;PplUVP`q_*ZJfNk93mo@M)7l}RhONKFP(o{!#vpg2JJN`kw}F346&+zL&x8cVO2n?i(pB z`;F~0anI=jest|!rSGz$PWw0If~|m5e#$;|LXnuUFbqv`{W{h9+|CAUwM*< z1nqHhV%P1}cQ6$L;)D4-Q!9sslXC|+Te_R$Ec3t=0wR5oL89R?bB|zAW!`x$M%=X! zB;bVs_kjTkVq$aHwe@4l`7tzfVd|Y4ysFbsNm6>qNN(P2$t@w$C^iBS91X zQu|a}yPM-Iw}n8(;yK>cey4-=2F}WZ5q}=&hzs}B?p8nLF-U0-u0K$l`ajqBtU``0i#gt%A+}uyI|WJc*X}==XtmX!lR>c zf)MH8U821?{}}=lSfyeP8TqD91RinPErcF@ofz!f zjU2nyZmFPvc3V^gC)YhVCVm|35Q`?-8 zdwmqv*BYa4dP2uVpvP!I?O-A!^SeR0z~=&Myg1e9>1+pcTh*T=Ib2^O32U3;M5nA_ ztRB3}zz}2Y?yr6CkD_--Py}gsrGRB^w#?uNaXxIX+FQ&G%}W=l?qjX9KVVwG<;cV|h{cjD?E(B+UlSJJ+?D>f!zSekl$))Lq>3s4*3Ti*GhLADkHN!ZH!wyHfP&^HlCGL+N|7 zux$Fs>(6|L2!o}xM433(`4U)!Ro(i;P;jWjyC}zH@>%sgOiSCq+Vz))0vU;^PEVf| zFrP2K>j~RI?ab;6v)y)0P1I5Qqp$-MC1^=P@(5zI2ebzrfKK)RzSh?r`BC6Q@u28+ zk-?3)x{+VH1o#P*CrWE;Cb8m#Wgf)Pi=E9)7@+<1D3F&fUVQajHAhViaBpw6=~)BV zCXV!0Go((UA#CPofNSFR3v7{87%G2dAcZq#d3Ck5r6mA^v3Od1a4oGsk%@?7YS?;C zQ%h?T7S;VzWL=+dO49w60O=srr@creoME?isVk@)C>#(H(~^onnAB8eFkd|m=ahrdG73-l$;Em>~56cy)7|iuop&Z zZ{t+K2M2Qlvj~t~A6I8Jv1;j-8}kjz%OtR8k$$1uWxh`sIy$~tqf${NVG?y+Zzvq7rq~J&zFt2afJOgY|Uua%*m2T?oV$z=Sk|iQ^-N5p4x!g4M zP#23m2PzymT(}X%o-NI!+;T7*1oqcjCkpD99r^}Fg19>ju`jr&OmxRS_<{FUrrlNMYb_Up6VK>H0j zc5BCz9-axH$uOd_70J)ff8|;x7cB9$a_N?WaE<@|UB^wr1WuuFu1i%W7^{P10<#=| z>Qp2CaG`R_;|h20%6!MZ92*~pF`P4QhTY3BODpGgdfrT%w@%@2A|hW*#%J#g9(~5k z1G$>7GFWGft)qUC8xW~|tK6HjF4(nDgYC0_%nK}X`e6KqN@=U@4j2eDxZf*qxCIEO zu+2WwmT>G}sk%uMU^1!5khSNI&fU9r4-d%zWqTZkL)Zp9T+UmfI}DaQ8PWgH;g%l` z*U-Lu$pm3HoZRsKl`<*-%zVL4f2jQVUmUYr`TOQZ$ey&x7C0&b%P1R}shuYmJ*BY9 z59`h!KYnzFCCrhBfmc7lVIKcnu`XJ(Z?oGZ&QHjBe`|t_1PuIeHbXH`3o1L&jN8m$ z5c{ex1olpF;e*q22h0R49^Lj14h8Eq;jmr$&xjq@KtlhBl^Qg{U8P%h6Ls{wkPH!0rFFD7=Y{WxR0V!{^Wb&y(ygyRZznZ|K79ZfH>4 z%3@&u6D$ir=HCHiT<)?KauR=dv;;b#ZY_~%Php*IjXsXn{q!G@nTAu-_8G~sft@&T zbAcxf>bJSI^}|O;Tb#TGcA`@cBV)z!hMso}Ot4RdyHOG_}Q0e_4u`kgfQD_n?! zUV+jKLbJOKa{^m(PEJd6^FqMQfgz0~-M_9evIRcum5kKX$?dJTGAe!0o|7bBb|qf? zdm+0gl0i@u78Zs%@!P~T7qcHRq7!3dYdz*!evD&mHyr*$CH8!nF=?xWLsLLZ2Qe?W zS#fn0?zCSe1{enC{lAoS63rf%JYjVkx~rv`SxB?|>fOg*4*A_RIAnv}gA%Y9*dWgS zi7gpi1*|@Ush@;#9~gv6>p=!u+V-9FEFHbwzpGIQig?wLMDqknAL27JE!O{E$dBp5hNnmYg=H!cpdE@plH+}o0< zVxa^4&JAAP!n{1sGXE?%1Y>SyM)XNzmx|;b#Q{V=)PxvGPsX=!>PwDEGvkSmZtu9W zLx2uwh$*$zop}cyEovuVi@cvk1YY>N1p~kPLVQk+Xr0$AWQ(TP+33&!9 zDcxeEI>Y1uJ~qJRWVRyk_r@y0P_Z*t1O&hsn0B}F*{%o(+*h$)2m2(4ikuh_VqokC zFE1-A8X_261b!R6q@+Pw6=Ih~T@M}RK%RA`Yoo0sU}*}tUpiD3EK1A`55um;i)FiK z&q#=gElo>`Jg!&RO=J@MBfxThYIkoh$4{9+v${v^5pZskz9=C}BUzcKp=YXffKLAbnuJ_u(%KDS`@%5O*_F$eFX#l}aEBp5t?xE9l6&?hcFmv@ zJhQm_z#TrHZa3YOa~YvZY-nmK$jz;e*DC(W%gTEEi%$h;s*g(Ba|#O`LEZ+{s~H25Rbgzq%Rm@h6bgK0wB!$V^FXJ=biq@D@w+#pd*_?MMX(@^;)K^w_&1` z6zA+51Gwk2LGT0(K0*Fa(%e$BK-@4I47sYbG50w{PtMw^0<(5#frptpH5106LrMK8 z3Gt{Do|OfTgSsJ^45u5QegO6EFN_of^TCP1y*;-JpU!_2H3>9zbE}5_@TOmjvVpS5 zY2b_eMU$ph&_MNzxQ*MAo1n45**!8k=y5KcWu!%DQN1EP!ot4VoA_|iGaDc|c)<+o z2ouE*?%!voNAjJo2cMYjo0b?F;cGBVB+3M5!^iB;Hzlvt*4GcB0Z>jEXmqbhZT8ry zCxD>@SVxvvlSeA@@*h*s(G|Hm89#bdT2LTxo}l55rKo%hp*IPAQAWnw?Y*PHpMH*M zaT<6|B#ek#|9!dTjZA$OVDtz;gV+lvyVIOo+rNF&c8S^p85nZD;31A~RfZj%`M_&P4J_M8ctpS;nc zu0^72j6(5x?4F>|f~W?#3eSBQ=wK3=X!b0{Tm1>tVD&}5fLh2pN)JMgIiVen?BL6D zjo=h7{^_pp8w8z9og(GgOSLb!qrs5(sc2SCZ*MTL~1VK9vu5HGJz zQUPl}uZf@B-8usnDWJw8nb}N^pFeq?>{QSTol^TW{wrc%VUpS2*@03dEG~YWv%9oF zYirGEjD`?2`3&qJ-Q6>Ub~vqPi05T!s3!6(P7FM5YtxG<+j<7Ybx<4Y|FxS`n2;xi zz^#G`I5jy5_OmTuAUr%gfEMb4v7P-o95s}Nm6I7@u6`3cdD~RmK1j%a34kE9L^xl8 zz2U575}Yy71BCp@$VjNZ9Z~xLto}nyAo$QT#NcqaH`NV1iTYn0Gm4#~UK4Kf@vXpY z3)(RfOrDY)93)q_zp>R&aXqph!TV(*-^avQ8W_Ad7EYzg7s}qH;;xV=5v5W#*?SX0D4FR|%Bn=mh%(BEvXYTPWJSn&Klk(edY*oNyzgf-<>;WSr(?snXY01QMM%V$eFWEuK7ya$ zS{IK~;Ck+9*WR*=57=7!6$2JucXVuCSIzS{#rQ8>dyNf}}o~WibK(tWt z0DjTY(baWAW(1+=*imIUzzi_4yL&9CA3`VV?dch5S^x~L)HyEW(*$0i?!96=MExF)Cx8pSH>hS1j5?qfUFPKe~i|zoW z-%-c4!?WoVx4e=k&-tR_Vk7q}r@g&Nk$kaS3sOc0EuKT9K zzFQVU$;_wuu3Rv_UAfzfB{a6yC;gtk48?ld-jaT`nE;%0RNFc0$0rs;~n$nY>L z+Pk^U&M*8{pXB8w-?;uT{XV5b0biaBc%t}wUMDsw9RO^+}TFHTu;v>>EkbAa!yE30l4Rm-lqE(BJOg} z&i?oTp+cRUa8H|XOL0>ac} zH-DjMmF)xQpSP4-eaZFo3KDLhc*ey^DTFK;Hi%i6>FBUst8g1P5YznV?U6DX4z=3Z zf`Wpk#>R#warFa8atU;*5k&OHG}nf}#>O3sT&%26M~jpnY}rQKb9wso(Rav$tn}Zo zpNE-QVCT-*&BTlJ^s$eYo2B)2_vvm7;v)zPWrp+RZcY`5x&Qbv$JQN}pV01Bl9mq0 z2kbm~WeJYKiEw|4o7K#M3YT((oVj>;!w;3*7}%UdesE%HYNX#J10I~MTfdEsVdxuD zdlJH3c#>yoa#Eu?sJHcR(W9@0Dr9M0x+01`?(SRi91S$Gtyitf*|c;llOnpdiF;GQB%0?beP76;49yZFaK62)9W(_BcM~Y78@_hU|WQRiWJ4C!zlxRDOc+ zhn+&X|NTQ^C71C3{r*8-u*mjwc3PS(jkUJMOAno-rlEmOq1!-132Jqxi>IXqhou5T z;(M)8sbAJqFjDW;-f-CD=uu3iPDOGj)UqzwLH7A@z}Rr~F^DYO%Y;R?{gBu|bZr3z zy|Faii{{EC(ekHY`V}&}Tey7u?13P}RU(JGQn;qj(L3yUf* zV_?Jp2}ee~SPV^CF`a~j1m6#+zsjO*q<5ni78cIK6J1+64dWbs9saWsd<%yTiR5nE zmcgjUF0i5Vc)oOETXNPQ>S1i`!I}uE)Qk*W6+K;D?Isq^UjujWeo1@-nAY;OtsNZ_3JMI~gYzd2#a!0h>Z{W)u9Ns5YFU*~i7al`R zEy>^mO>=ogMc%Dj&ayp7kYr&w4YPV)9(^5a8+xO?-pq0L~dzx9!b99#)VPY-S)iOv4RIA(&tD~i?qJkbad#dZu zp+jg&_z5S%QG)&{Hscn$$SC4>q@tpN*4N$r^-fQ9IwsmgmdMvzk&%F72uq~hg$pkw zUGWhhyy5_nxbfs-^WG_hvT2b4Hh_1N@q)d*&tkDWIWn3zlzg^HQWJGb37{a4vpxVSbEd=XmuV|F&gY5hDHXH>wK zF9pFnOIg0KIDVXNrsgl;qP3AMxYzLNn;$zyxwf{}Rc8q^<|6kkmNmMOmtWrY_UaiJ z>{V1e<})CQO0Ws-2~sdNZ?3V75Oh_RlPf4LuCK4xKk`G&`4le&#Y^y0VxJN2xP~|l zDuGSQM~#h-5Q%QCuG-|~_i#qgBOO1!rz3u&`0U*5th_la@nIw3 zpuRp31Wkc_D{XDc^P$r~Tv3O9QW_sRR2UvEYN-o)j7XprE4y(1JZ!^HpFDxv*GNo3 zAxRK!qEL>LA@>B=!O~@2b-XZ_4a2}Kcd+aHP1T`9!Ez2)bb^XE-0EH<;SMLM_umG-`T88;q^fxO($ zQ>}^-okK&1@qpLL3kxT6eYWZ7v<%7EEidorqRXFKuVHSEKk~S|oHA{%k`k&_b+A>* zlP6x&N1-nmb-*KZBNbNy>K4?*+S+!c6eF01jjc(5mJm9^{}@1}|M~_U9pTAyqCbg; zk7tl?+R5(ApPP{(>h0xalo=my6v1(nP2kGAZYfH1iAxc98^2e9swJp$e)Q{CKU_%wimnFk?qzrGZ2!h5>^8c(pjKsh^wpa;+&AA$ zWxA0cdP@S4|9;K8>PekI3*2c4aV~>#9_aAQ%_+-G2LS%M0*t{Co;V}_daQllIAnXsV#T*_5A6EhHPZ-W87Dt3V&=z>(+2i6&-re)mgDL9{Q7$d@#x$> zS66xGuukwAS7KwU1*aBLJuw@#>sf_x&Y+_NqsFLV^^uNJ_Pnhv{gIHxy9F1-#Knt} z+HTzv!UrqzsP$vzn%hFV;reWYsQ(MJhth{qg`(l!FS;m?K0fBbAo1Dd^y7kRp@jvc#f`{gfO zgZQtQ+gHHqhaE>dd^7^3hliJ!BT}k2JqA||)!=$snpP7e!i-&geLz3yBGD9bME*rQ zf9_nh>!8cKcd`>?w=v zJK5PAi))`y+bECofjwqAzz8C4=0{dmmeIqWi(ap$ zr)iUp12DkPV{E)rRn_YJ`KZhdhe)jcn z^4gxuqPkM`g_x6+DNpa*A?!hK97lOT7p15~MOvEgSkK1u=!_wt+ME(<tA!=e|#PY<6x6ClssVFK6!RJRrLuSOXX_JBfdcfDO>_$M){1AWg z)Hx3W9X05#q!}{rl6Pk)@mY_13{Jc+*K-7U^G>`@OyQ z+RW92N?D3f0{K1VAf7V)%)>^Wj$`-eO+*ULHPzLz@j}ZbCYVUP6>_6yt7)Me-6^+k z-?j!h6YvnWTIO>tTopAkHRWJr+|Xq66gN@-i1DLm&h03jNp02DOx8P?rB=qid|~6^ zp{KWvq>_!QMI&IJQFYfvmtcS256E#(&z^djD>a^P8X5v?YO*Wdgoo?J@6=9j7{#=D z{IPxQ&YgC<&Qp0_WZx_Mi~iu}Sxbfi?e#$h|1Mx~t0D&WlxWfao^*KiW75+<#`(?V zf|DQ-kK^B7d{;;$=0jhG{GS7kj>Y)9ot$LMUC{e6=1>!EW@d(apoN4IWyV%sS(#f{ zQy4@of3En*5tK0Gt3YyQY-;)=Wgl8K!0%Rq(eX_|LFD?UMeg@T=IT zaRr%b{-4^~m>yXx`OL^aUpQ~rF4ZK)JZ;O`D3&32%I3_OSBKc$`E$$t1Z~l=`{0kV z`@Nx0p!-x+du-(Km=iNXaw4XL{(k-J9Z7QsP4gU*6OqflRJk@@`Jwj>F)&863<$0@ zIyE8D++t%btz7sPW-k6Z<>^U<*L2seN9fcw#%h~(#v(!h#~u0dpJ9%`n~3^c&ZsF5 zlj*?&2dvJCb;7I>cwp@IUw;+cy?fx`+bl19PChI*)6?f>W&#yUy?-HPsvbQp-5{eX zS`Y4^RRB309Hs^a;ygTkD&C)@rKN2iY)XyUro1RKLC7RIBpHQ;ZIzTfDRY_;z0ie{ z6c8ip_9~7B$Gy6m--PUtuGys&NjF7B#m4&jufxN|l>JHsolIUezZDv_#cEwY*GP<5 z|4d=h1mBdrGu3rTj$|BcI+oSw(a}-l6I&a$<5u-`c5EUhHwS(%F+b0k3+;0kFj#V0ZpDT*?X zM)qudZFzinpGf)Ed(m8BwLdXDK55YW3FaBBW{YfW)>F1 z2H*FP-F|`GSXm0R<6TIxmlz8G}h(sg0~b}>x#`T8s6zmN`Bm9BpL z`1OOvLJ^O0@83tL=2*De3jYgdKk0YiAK=WLA;Ju9!+C8SsQYYZbEIFdWk~o_Yu3dBUeIMQ8D$%;pw?{LlQNPR|!vz z3FXYe>IJ=%C)dElBSp}!dfmM(V08cQQj@vdASNg$*Z%3#wiFuVX$kcr?i{p>->>#e z=PeqH{TsU8XRfb|fTOAW*>eE`;!;G;jEyn*Edkpip$d_)Rcc9XxU8!S{_BrhMQDer z$$0aO(@g*@{DXg0WX1@rAf#`|b@0w#88tdJuU?5LDspb$L_2gNXv$DuKLQv4kTIb9 zOZ)e;=u-VVG88oCLo97Ra4zvO{R+6nGFzq0)wsgnCM^o-oLvocTW7@50Fwe z3Nzk`Gda=}9v%yAZNxzt${F>v)YNH2x8Tjt(z-?d`&Z`;jDdz-j{h>!l+mPx-q~pV zHXr$DkFWTy!qsuk=cx8SpKb}$K$DpF>N~+WW$R0qRF#z_4(w;V@CL* z{{u}#b0IgJsGGyQfZSB}+kz3{nhp*{Xi#nlYZm<_`un?1jamC%wT+Rh)nQ`th@8|B|NCP<90w17N*-z|Pb(McV77`tKv7t_yfN!|U4}IIhdE z+JcGW}_y~V90Ds)WawWuj~sKyj-RDwQXX^F~y zQ*I|gao1>rLwhVkJm3wSRn&SVdHJK9kFEawZn`f1!gB@@E0!wIR-BVT+gI)YBi z{vRtpq_`CwrFZT6PF9%H|LGHi3-*^TwRLui#w>5GVugb*@79*pFH+|2Q+_8bEi2K` z5#%-_YinkFbnNbSA}3fAm>RcB#YVX{R~EoOMsIw%Ydk}rg*`{n+dfI_(C(QCk_}% z4xp1G5}6(z=3LmNZ)k|Tg)Z2`KysjyQdTj9Urp1|EGaIorPItDEnq7|?)UGPM_E?_0Bd)6$})0x>91x=<&} z#!)t_S~{FeKul>hL8w-kRDhz@Q!12~`yF3(Lx?ui*l(Mg*>#n*Q3W%7W*hJw4~Zs9 zUpoEonW&vx zD?&m--^RJH!UGr>T%nGa6qJ=Wn`@TgTZOZyp<(;SEJ01o9q9AEPh5d_yJQ+tGuT!z z*@5&20tc))y7qxk9PeY~UvgNi8;K_YN?53-@rLH+R-P?*q^XY;?RY~uI1s&e{`6^p z)xKKzlI}ixMt&GC^bmfs_KuE_!#TNzn676Yd}|`om1AaRRBA_! z$U2HEE7gD(0YXyg@92o}DKGsHgx?r<^4i}p(Qa81G7OQ%0>WQ@b|S@4*^qM~V02<4 zgyY5Xq&F<(tE&_~!lAn~!?NzS7J-uha*o6(6u-98#GB4ePPqMWTfa&!zkQqi91^(z ze{_|=0V1t=nbV>jg2lIQeVv^T3uS21y+&m8>p^sk^@D)eUIGj6Tu%>?h>J+Guxq5n$O(!$~{V7IwZ88^3BCpD{rk&c)RUH0 z*BE`Q(C=fQr`P%6Lo;%-zlW0I2}`<5P*!y*+72geiL{ACu{Tr8%54?J(bkVsf7n-7 zmj`};2<{y1aIt^7ub!T$&%ld#;=@g$Bn;#)iQT(R3=FuwoH;A?bl11dGI;c5rKKUp zz}H^WaC}^$9_7`cyVO=tYWja308+oQ+BfBAYGEM})7ixSypZ4M0WZ%W|wMqFZC9bpZ7~JT6q|=;K3f-5q}s8V7i7 zeGk4P!XL%8$c@`7dfK||TGKkoKW+7ue+ zAji+4EU3B@o#XF*$WrPn?#NyhWEk+Q&Uq>=AyT?4Pp{UP+=Oy|U^! zr;H--@-hgr){8x3iBuwl){q{wofkcWrtpUf_7>gogw31%ktP+XTlLJz7kYxYt(^P! z>3b1bqR99P3`AN+2AS~cd4f&_?k%ssL@1>NZw*to@A{v-spq2X9>o6Q+q`WLp%5S( zr!B9~=EX$SKAuNJ68Jym=1S+M|v%lVF$rh{d@@9f` zgFKy!%e?F%ONbOqVAa*xxw)UOa7Nq#Aeo3nYR3x~Zj_Zhr6=(4yvO0Hcb2nQN>}y$ zRnO$MrlkZGGFn#PEM056Wuw-Jrk!~5^-KrEXlV2f>0(yPS_2#5!=!p>9#`YgJSWVz<8h@%;OtKfbwqQ7d1qH}HF7!OwJ|lnd0pQ-ktr41L@tvsp z(Ce85*463Mr(N$!z~_%C1L-vIg`q8ssQpA;5fYQL<(^1H4UKH$ZD&n$rC{x^t%_!5 zN)K-)N614?3MVxfFfjBb5B6?(WSe+|hK2^32>vS*C+@8$#Q?&AI1>ix$lCTj3GYyr z2lLetdG5*3-Y+$Xhp`5laVsOZGS(XCP&DDMX>-#~#?6XS0bM?>Rh+ z*-QD#1smTL&0k&oyEOdGZnhk65)+b;l49_Ji?XP&&~LGLPLKC{aJ%$O(A%mOtj|FC zMQYH%VKCM9S+4k;^bwH)PP@LgHpyFi-?aSmuAB+L`G_&Uot=HBu#kAtkKG!4Roum{ zURZvh|3O#F?*rgRMn(o>QhsVq&O1oL$uv_nYOq4ZZP2lv@zdt#d!4oW8XJ2W8VJV5 zxQuRY!7&1Pm)UPave%4qXKdUQcT8h`ptRm|eT@RPfO-oJ4H;F{ZFF0XtPCewcN{$O zBmdDO`aPJHQ`+D9@7F~y^vQGN1oxGkwwLwA4<9BSBnFIyK`SaQ4!EC>#@05uxOf_w zn(_p;_BOM^yTH9OGE|eE+`oUq@y50-bSyetZKl%4>&5nP@4@~SmA;An&g((uC6OQ zZefOs zIrZ`{_&`6NaAe-tc`woPYYX(&;MC?|0Tw7Ns#}po;DQuWA zclZ8%ol{<3)K`Z3b@f6a`vs_LbauCKQmEiT4-bW3D{uw^)V}As+xu z^h}fI_1a5{b+a>PM?^%6`pTWOIA>Y_RAHOg!cGo)9q;AkWxP9*%#}wsdgic{9}BUB z6Ttk#k8A)_zlT8l)esYHWngH5C4^RRG7mfp_(xM$MFK}EUeuJ7@OYAVkazOnjehE3 z0#vu~i7;2b_eB!b4Lw6ctXbkbTNVEqt)Hc(T6NQ*_I5cm&O~89KB%?7egA%%clbkB zS8ApuBP*-Dwe{V5_l8DB;)cp=(f3$c4Z68C6_tg1P*YJ2vc5Db*+hfc2h8!Ad5iTw zKHYw{zadWN!5vf{NY#M1*~3GPtaIX6HN0Ja`NCj?_7O|n981v%Ao%I$PXi$1Sk{1< z27Dt-iEr#MF#s=QWlPTT0FnZntX%$(p<%RK=I?cZxc^T*D%U=` zRQfJ|_rQ`N;={18+sVns*gkbVK;Gy58CfjoERFGlSww%}>sM-jwn&Z!Fv9x|92kyE zE2D)L%_`sA!^04>*L6+|(&#H; zl}D*P&9Mg0LBm}dvQX*j;F6n(i3pP=@3SG2l1W@YG&My_zL)hiDl#-Iy9UDejM!MQaE)GX!JN(I>z^6=pH}HCK zJSqa<6PJv))Cc*o$w+IuXKpSAV8+^-U)Onz)^KG$rD{d*#awu!8&4)dxVv zm&Z?0{`aOcB(|N+@VpJdCFkR{0Bda3s(AWTOU7v|=n@2_gQu;mvTxu138G(99&crW zEOfXK!Nd~*&I4DxbN8-@kPx7Tv>P`r*x5~V|G-kN%@T~%h#W&++oQv}fcIgoWFr4; z!!K@|B%`Esr^q3o)}HR1yZaT~bL12_$uL?1&8HPu->pJp0r-5XU~eTdlZAwCJ$bUV z*XTV^FLa3(#R;Of+|# zIASKgAk&kcUm`^_&}%ckx~~St0N0Q23ONOmX09S8LOCW)EFG_0e|IN;w{T{^!u5mofgEvu&TQBKz#vIxI%?S4l zc!?{$UxP{&B@s_bCfFxteS@ZmOv!J<9FRPc!k{rXjO{eqXh4bw?4Yc3V(9r{i>!dY zwzf!>2Q8{%o+CDmMn=Qvk&)Sbnn8q6fWR zysDyN?Wa$ldV7}<0V7Zn1E}LxUf$qzdATAW6k4VZD|D{|0tzfF?eX!g5fQYgM5DI> zZ$nzS|20h@JW2?)4~WU}%FS&ud@aWp4ZQ5B`|}-AMMfqj&7l-!vSM>v_2{ECG;qwZ zG|@7{_oot?`J=)2Pg4Q?2WxhLa}%2B2+~sqN7x@KtsJ@U&l&6U<>(NA&(F!yLpRvLibQy$dUuQwWoQKPo_?=yQQuZ0LZKtY+Ty(`}e^u0MVp z_uxTvZ0uWHa99XP*e>sfNelo&pTp`k=UX05Sy$Z}Fq5k8eqv|%mT1otkvXU{}-?AR?R~61B z%L11f9v_F1`{wmuU$|0Vd`)lb?lwDWc;ZAZL?|i_&;%wVR9n8tI1N5mSXjrjr;q~_$h0Tdy@zyzv8gi1h?ml^{#3!iNkCytGvUI%E-F3DL;FXOn9TN9C80TBXMgn`Ln;r1 zO|-N}vDisXVGA!)&!zWaYkHtlNi`ygsfptk|dE+HW#EL^?B=PuoWk3+-y zkS;h`U`1V@&4AI^Z_fj{f*2C9F$$vmix|8Tib_g|V`GijzT@~whWD>uBO}T;rS{dhZSQb(Oq;g|mOU5l&v3<(ShaAZlGq1SpkGZ~7 z)ob~eut|+kovCHP;*=$9MWLn$=)K;_au)sy?e;KQ|z}zuw@3z5BKl?mY}z- zy3+y1G_DnD6$p<1DSd-YV!giO_aCRmsV;mZAv9nOYEIJ*1c zfK8H#@o8yGHJhZQd8rV$eh(;IW~L<$FHi{~4WA>B?@lWyDlU$;X%8iL)78A zf&Rb$@IoSyI%y68@V!W+25k#>N8^WA;ETz*QH?Fb?FV~p9UKfPa>OB{`iEm)%Z{0S zt+&xSHp?@o03zIfBnlr5b*Z-gdabsG>~v)`Rk#PIPGQdWy2kf{33lVDu`wVihxGMZ zKYZ}}ns!!y-xSSndi=rNnAwAKBtJeH1^m*UG)%P=C}&LlByn0oT;ad0xY_nx`!R33 z>O@1;F$`{(Qy4VvQ2}eh#O66s@_Kh$;sNDeHq=S#B|tV$tHqe^R0!Ke>ZDP-S9>+k0-UJSi5U{Hpbpskki~QybUi12Mr>tkL42z;sMkqj; zG>?X|1a_dJL54Jkx9zRhzo)Wc6e@tljw6N|x@g(3y)1;p&juCcK~MJ7%#u`$KmAvX z59oH^-Q)0VMiX$x{R&nysTj$18lvx^-Xg#-REtR zD3-X!-OoH-?CkQTFa5y*vm-F`)u$g&HtkYS5Ir#SUEi<;fkKs-mT-+715vJ_Yr+7! z6R1J~Z9WAy7dMPulCC>6Mk4|1E;d) zb@cSY$(pZaGqD6=f6c@Er^`()3$3Z?>DmW(FTVNL(?BD8-o_@Rpiizv8LQ~TV%9!D zTmtv9li3&YlIQTZtF4Z;tQ+ZqJb{h|6mNyi1^(Q4B*}<#b|s77?843f1Q3D}ICkt< z71qO9T)w>czF_^bww$Eorf zE4eY0wXLt;H6Fzd1`>4|yK?M*&Qr)R1pys_H_kUgu z%)~Z`?xXvU76MTr*TZiX#4#il;?{KSKA;mxsUk)W4mBmEjf7n?GLf;dj~+kPTSWE( zX6uTLS8xzfk9mEHJvs|bLE&KVEf*6r-M8<~wQD~!R2=ve(3ZQo(Tn6l6Ky1^4ZM3g zuNbKaeSN+d-+LcV#b3LoF~37xEwmzM7DHG#gF#b61HzjR7#c#)bJ=^DPgs=}joMC0 zNl7s=toxGOzTM0?TEoz=2t$52uixA&E{B>kp`l#z$t%YbaoZ;Set{&|$qdk}*xF7ki2jW%kGGmOK3eIf- zITNND-jA8?Z6p>odAPc2+Mhq)<305}Ztb-KdSDUc4E|Ii$@r%)V(?Ty7RovdzR&CSq@uQEc>ru|t`++e6Bcx4_icUGDrOa!Tp2$qbw#;xp8A9j~ zbko;UQ_)8t%Se+EmCMOCNFSjMpITd|fulO|l?|{S7`^{^jhY1)r|ABDELIFXS29vK zP$aF1ei!^5^kqonyTVNjZz&ne0K6>L*8W3CehaTy=cnhq&MvydcmQ!pNvyKiPZwAb zRjU;Me?q>R&65WYe!Pn1@|g6wmYF#S-HNMbhqA$iP zI&ja#U*WS}p=}Mgx*-;8f=vVQx^?v#! z$t*PjX9r-CNL4gt+R^yIT1~MH4+7*-#}3MKfMHrQ7as+v26|wd1~#*Ot{oJc+c})N z%YUbOCN}UDOa1kyZo=Y)&k__+HS?d|zKtDg3Z`Xh>i}f z#?r)?1~KhcP~%tXwgk=q0|fS=9su<(-vJ$+Oh<(T{#;}->A&$IZSG@y0Ya3P`_@4% zEf#+>R!wZ#0{u<`^h88XIb=P4obm-g-%J01eL@+Tcu8*;7M3{l`*oc(FetDyBfK6k zhdSKk`TI}({fL!g-?r^Vd3nT3{#;CxXrD>NZkP6tPr;Kxd*Bg4_{*#7VcZrc`UX4| z1@kKqmZ_W^Ypr>a=n}DO^9>$IWY98H$#c92+7cL9DkgL#DoVH6j_=0_WJ6R}Yp_Ra zwSEUAJE1)~Hl}sQj5Sy)w`=G2?HZ<4c4iWO`d9{8ZPYEfvKQI*XZIH$tqCTd2lX%V zw`?$WGf6h+DC;#;yRkZ^frdPhIC{pgo`J(+=9m@7=o$Tj=l?HUKb# z?u)>D!waNX&l?lIs8w~mdzVvKn30+alMqi=a$um9udj;fo+MMyy;4$@5a(fZR#pz` zqv5!J`Fh4__z$wOrZLSQrARBs9%se z@uW5svN0JIwx)ckU$H7iRPVJq30ya_*d&~son;)DRn{e%`SLm za-bz=;^uyHaB^aNJlp~kKdfwkNwIDKu9w_`w!@_brWetv(O8kc=l77drv2)OL@$5Z`cOvw}j4e>r{d#%|!os0D^J;1KP(A;w zMlr`GOQ(b5AFSa#$p-K@FVAhTCKO9>g~L}*Ma3n)ULh$ zS`4B!m)~yhCNKbH;o&s5xL++@v|)|p{}O*{PU$YH``7XDrZ>zOsIzGy&L8irOurg< z#K_2qc1$k}Jp4S!{_?z=1EUbvC`S-^w2GH$`|A4P#)mEX8L1cA4x@^ ze}7PF&9|&b;Ne>m+d4Xqo;!!=RONy55zig7KOsdR6KaWUFKl9}e~^!mVTtB?62#&hCzm+HH1Q(%&PR z3kuVl!96u~#z&7Du{YPKiRU^y&$6>$WAqpfX5TJepslAT_n@UkN?lZ2FPFj_hg3zy z5T)#8GjR}6#^ACW8ZL-2or&RAU46KpFBfn&x{P}G2sWsRqCUg8nf*X9S&{B3I0Ii_ zk1xxCzz}}VH}@XJoU!rQo*Nw<-O8~$|CNorlvG@wf4Cil1y!^#P|u`zPtqJmKqQhb zMPa@fZur6$&F4c-cn_2G0p+*4S{TIv&Trw_6XOHnGQZX5&mQ5LD75Ih0JzL!=MAb2 zmPDh@+MYcdU0a}vasji0J%oClm44JI{#gHvHHy2rH}PvV#;IL9Y}zR%ArbVQXYcLM zm6?rnbU|jXYHMW)KztDcr?DRj^q;zJmxn99%%@7g=|A&EuF?~|d5vm?XO0+Dv|p#K zNPEM8zTt&`aD>lqu91N{=4(W)3z8tn`EuFLV~z zZRL8+7D?lqa7;(XtpdQ7lVsP`Wk*|!;u*o)ISYa#0r2Tu=CNcMvteOv;5AjRTTSrw|K-|t2pi{kd$s^Dz zt)A?pGcM0?@aBY=CPpQ`bn`=&4=sk?)z%JUW?5ucXrKF(UjhRRH*N5+X@Ck-+_CDN z-U*la4<8NKq}Oa(BxzWrebb3mO~yUpa4Tg}&}mQwRD%*xY&%kO0!|!_+r@HU-7Nj} z18BkQQ~GYl#m4HWuI!)HxFkmI*Wgez8r>rhWiEcyhy4tZy(ruvt35uZfPYqR`^15b zvOdLskT8&E)E<8@OC}N-_#Y|7PgpI~lHF1L@8m6%+wX?eGuZd|=1kCj&i_6J(8d4D zHU0lb_2TdUe;KydcR*oNfc^rHC6n$)5FZA3!z!(DtQCuq2`%KeD`9}g03lc`kWgAW z83VPrnf^>fk^6bV&6~d9?fm#Y14w^rX~qx&bv?Qe+@py9G*c-l3-jYk7ypnStO=9K zKPx9EOh43utgmJQ_=QD85D1o>l7doHs-B9n=jgd)mauq#1}wpW15{`w5d)FA$Bk|* z)M>~x1{lztf(u}MevHG4{dtNvz~1v*3a%3^?n#J7sFefOFksTSvS5Aj;t3NI>X$5$ zu}V@>{qNs@_v6K50`PCv7<3q}*t4fkxq9d4If(RrUfAV?VBX2tAESh%&?b%1)z3{>n-@M z>IQ2yu7TT-J&dm7Cz4$4`GZ|omM2|iNJ&YgBIu@&u_FJz)tT3aG35SS7#bL$Wjjsb z#+VflP&F~Zol2mjH4cq8JANGH@}(fqP$)MCbrDKXQ&Y>1U^gt3h;a^evNo#4*5w3q z%moXw3q3tg;ARQwzu~@QI|qglK2&r>Sm}Z^&CN)|7fV;75S0ivsriXQ1&yPb$>_fP zVt5QE7**-1Iy#hL-@7SB?S+loWDTDywKJqh%Xddbx$zIiw7@`UcMq!OXxpkygYAG= z)3foR=d2?Mb!jR({Cw`+*R^)%&S_mI?ssxHB=+rn{j^u=iK(v65KH(^ zO;+t8s-Jj@a9k^DFVOw3SMA}02jU6}3@53e8bI^Pf4J+!Qs7Y;LS5Z%XilZYVMG&~y+12_E`0HKChm_ZeABY8lWpO7g z?oUEV2x(l+E<8KyKOa9vrBC3T4P##NJq++AB?W@H@Z;6Ye2$8YZ#6ak&JZoI>=~ouwQbCTpvZ1G8tob=z(-E z+PP$}ynKjBRW?3&t3u2ki>m>0R0*H~UYqqkUC1SgVbP>1DG}Vt%`0~Ok&-|X3?lOk zAxGpi&^dA7z7e~-c@}18tra5FSYFmZkjZxzm^I8#=_?vF-^QgtfoidX?M8q&$(1+t zWvDJJFt8eOF}g-Py1`!sG)zp`?B*MnPCg5Eof07Z(2tB>ct zuT6FUckoF8fleag7U}Aq0Ww_l;#bdWUV}kLN&yi`$&9@>j1D0DCpGohsNkEuDk?n2 zwx93hgEumV)|7}at7tiKVRA~nchZzS0^N2hc;H)J2-?t z$8F?M%GpA-G7$WHvA#(hs@jP+X|js!rj*?_XGb|6)w9pG^*`4%>O9^Qnn!= zAQPU=!0>~I4wXH&{599U(0;s0QfrA3X|{E$u_2DZd-u z?nI&u)!0!ZBk1{t4hDL9Etkcce5Y(|Ze?XL-jrfC z+>JR~Z{!rk)e~k*clexOYER#gV`*v0V6biLR?R6$#~`N8`6_K%&E5X!k2^MK(}4~) zNG!%LOZ_t(b#LD8L@07CLuP6!jPqsaiXpL&p?iggZQ%QN`uD;5xW=zui_Xo@zl;TK z)6sEd;7OhTuW&<9s#mTw15d&ik7MylwY-L~b?dHOI}5hG1|S1vPdcEnt&uZIm!}8d zj_>!L@GNpncBPfpQ{Ydrr#>`*Uo~!}vlnusqY!5Qdz>|lx2K71w{{OtM8 z!mN&@ItG9zOD(X$l4hFHGN=3#S(IoKUc2J7p)|>@G3%Ijb5X*5slTmcXGw*(E76CwZq?^ zd+U~sz5N^aLC*;u&7cILMNZ+#=Q~b*mV0<82FmyS`{^w4>q45Zy4G~Ife>E@V-L-48=h*wHq+6w@9HGWzSa<&Be&+2*ro%qKtFE*}rbz&fe-nDyVxr z-xXwKIa<8I)(o@~_$km~6gSCl-5*<<4{&+`p0O;R6*pZgn6Egx2lL&rc>|8}!H>Wi zM-QVcC3W@pOX*k1?A}dUYgUUWnAZKn4t91)Nl9;}#5hHjRb^)66G==r7#mssYgey& zt* zC##blmBDeEaUo6&TSanHB>SF|?PTr`zH&tsZF`I5-J8`ZZP=Wd&-~HgS?aU2Oio}= zSg)O1Pqz)3Y^LVkEu&unT+)Twm6Dmh>ga%xgX0!sSvUoeUEGV1T}7#KFaV^dq;$fVdu(pa z&qcR_F+tHBk1M`N$kX_~LEGVa<G$yRSKB?JxhNkW zKI}Gn5*g`z(nLu?AzXcw)qnFmHqq+83Da@Pdj9++zIDD_MzeeddD@&;l{0 zV`CJei)YTPjs0b8F+vLi|K&x4z1by3GCn*1NnHp=Q;FR|%Ams+&(Qt(ft*P zsz19j9)MM!S1SnlCZSiJNCvu@!G2B3WE5a*T*6<)tZ zrrC~81x3G)+a&F*t;tud4JLCV(4&lQUlX9a7SN;V+08OKtz%!sk?jj^4xEF=MJy{R zA1P5J==hRcsYqMG&vxzFE1M+#__pP@1X9wjd>iJ!LlekhS(^RQQhCgnl?!@JM-xm^ zi?+zTPh$O002|`F3cUnHf^E2ZXV>9b(zSA0J&>1{)DIK84) zOA2Q)|M{R=GqY}3of(bF`Mg<}&0AmOk0uJs7`>mEfCAjiq5@})-*|_<;vMwf4gwaobrBxuyON_<&Hx<5a%`7l{W4RtAs z_iQ<$Z3|6Q*4JXsIWF@@8JQFmeGy{Vz{x3BhC0}_)zE^x{DhGa_e#et+)qox@^^pq zuzmU=sJZzNX6Z9ITrOp#1vStfC^Y99Z2q?#Y#{i~He>=Ccs^aTseDakzT*gvdyO{b zj8VW8dR9cWeCBd56Z5{b@$LE-DSraiQ^j1f`1i#kOKby(|9{Fm|6i!%IF5gmkV+|a zMlgsk0+s<4?lj$;RN;>`0b=W!D)p1On0K7 zj@qf@j^RqU>v_NQPxR|&pM8G$d_M2jx5xAO0>@(UA4WVw7))o)fO5dH_7K=Y+Jo6G zpMCQt)2HF#HC>Is(MN&J>m8>eUH*Mb!v5xtj)9TZFGz>%f8c2Y*tG~O9)mg`qzl;y zc7Vk)!HvQ}C4g{$JTK6`Iwst6N79ln|EoJF4^j|oE}{YYS~AK(UB#o{-0lb2n>vC4 z^k!6ub{ynWcJOo3->LQ;GH=UnX8Bp#LYv(pd{IN`;>rw*K^1b$SqBGyf`DZ#`IfFP zk^;Ip+R+G~fQs`PSP>l=eIFpUk8s-kl9|j2a_&r)ledr0=V&-dAD7nH&k)o{cQ&hI zs$FI#Aj?6sN?B^N+SawUTs<8x;QrD2dz{_@fk*`xf)}gE0T$otKzoag|QTCvWR?%Edy0g7KuQdnCT-f2p2E{MD(rNM_FOT^Avfyi5X5?t-~fXQ$;&3G^S5 z8hu`P{m{*gjbEvz*RO_jX=_%i>dNgshPvLv1QC|wK?tc~t^}isx`jBHShb1RMN4!b m#O_ZCqF0%_}=PWfLiU<=^@ literal 0 HcmV?d00001 diff --git a/content/en/blog/java/codeanalysis/models.md b/content/en/blog/java/codeanalysis/models.md new file mode 100644 index 000000000000..8ea11d2f5232 --- /dev/null +++ b/content/en/blog/java/codeanalysis/models.md @@ -0,0 +1,193 @@ +--- +title: "Dubbo 3 中的三层配置隔离" +linkTitle: "配置隔离" +weight: 100 +description: >- + Dubbo 3 中的三层配置隔离 +--- + +## Models提供的隔离 + +Dubbo目前提供了三个级别上的隔离:JVM级别、应用级别、服务(模块)级别,从而实现各个级别上的生命周期及配置信息的单独管理。这三个层次上的隔离由 FrameworkModel、ApplicationModel 和 ModuleModel 及它们对应的 Config 来完成。 + + +![image](/imgs/blog/models.png) + + + +* FrameworkModel :Dubbo 框架的顶级模型,表示 Dubbo 框架的全局运行环境,适配多应用混合部署的场景,降低资源成本。 + + 如:假设我们有一个在线教育平台,平台下有多个租户,而我们希望使这些租户的服务部署在同一个 JVM 上以节省资源,但它们之间可能使用不同的注册中心、监控设施、协议等,因此我们可以为每个租户分配一个 FrameWorkModel 实例来实现这种隔离。 + + FrameworkModel负责管理整个Dubbo框架的各种全局配置、元数据以及默认配置。 + + + +* ApplicationModel :应用程序级别模型,表示一个 Dubbo 应用(通常为一个 SpringApplication)。适配单JVM多应用场景,通常结合热发布使用,降低热发布对整个应用的影响范围。 + + 如,以上的在线教育平台有多个子系统,如课程管理、学生管理,而每个子系统都是独立的 Spring 应用,在同个 JVM 中运行,共享一个 FrameworkModel,也会共享 Framework 级别的默认配置和资源: + + ```java + //课程管理应用 + @SpringBootApplication + public class ClassApplication { + private static ApplicationModel classAppModel; + + public static void main(String[] args) { + classAppModel + .getApplicationConfigManager() + .addRegistry(new RegistryConfig(REGISTRY_URL_CLASS)); + //...其它设置 + SpringApplication.run(ClassApplication.class, args); + } + + public static void setApplicationModel(ApplicationModel classAppModel){ + this.classAppModel = classAppModel; + } + + } + ``` + + ```java + //学生管理应用 + @SpringBootApplication + public class StudentApplication { + + private static ApplicationModel studentAppModel; + + public static void main(String[] args) { + studentAppModel + .getApplicationConfigManager() + .addRegistry(new RegistryConfig(REGISTRY_URL_STUDENT)); + //...其它设置 + SpringApplication.run(StudentApplication.class, args); + } + + public static void setApplicationModel(ApplicationModel studentAppModel){ + this.studentAppModel = studentAppModel; + } + + } + ``` + + ```java + //单机发布多应用 + public class MultiContextLauncher { + + private static FrameworkModel frameworkModel = new FrameworkModel(); + + public static void main(String[] args) { + //使用同一个FrameworkModel + ClassApplication.setApplicationModel(frameworkModel.newApplication()); + StudenAppication.setApplicationModel(frameworkModel.newApplication()); + + new SpringApplicationBuilder(ClassApplication.class) + .run(args); + new SpringApplicationBuilder(StudentApplication.class.class) + .run(args); + } + } + ``` + + 由此,我们可以重新部署单个应用与其对应的ApplicationModel,实现热发布,而不会影响到另一个应用。 + + + +* ModuleModel :模块级别模型,表示应用下的子模块。适配一个应用下的多个模块(容器)。 + + 如,上述的课程管理子系统内,新增课程和发布课程两个业务模块可能使用不同的spring容器。我们可以为每个spirng容器提供一个ModuleModel实例来管理、隔离模块级别的配置和资源: + +```java +@Configuration +@ComponentScan("com.example.demo.class") +public class ClassManageConfig { + // 课程管理模块配置 +} +``` + +```java +@Configuration +@ComponentScan("com.example.demo.student") +public class ClassPublishConfig { + // 课程发布模块配置 +} +``` + +```java +public class EducationPlatformApplication { + public static void main(String[] args) { + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + + // 创建课程管理模块,使用自己的ApplicationContext与ModuleModel + ModuleModel classManageModuleModel = applicationModel.newModule(); + AnnotationConfigApplicationContext classManageContext = new AnnotationConfigApplicationContext(classManageModuleModel); + classManageContext.register(ClassManagementConfig.class); + classManageContext.refresh(); + + // 创建学生管理模块,使用自己的ApplicationContext与ModuleModel + ModuleModel classPublishModuleModel = applicationModel.newModule(); + AnnotationConfigApplicationContext classPublishContext = new AnnotationConfigApplicationContext(classPublishModuleModel); + classPublishContext.register(ClassPublishConfig.class); + classPublishContext.refresh(); + } +} +``` + +三层的模型设计让Dubbo在处理复杂业务场景时具有更强的适应性和可扩展性。 + + + +​ 以下是一个以传统方式(而非 DubboBootstrap)启动 Dubbo 的 Demo,可以帮助我们了解 FrameworkModel、ApplicationModel 和 ModuleModel 之间的组织关系。 + +```java +private static void startWithExportNew() throws InterruptedException { + //创建三个层级的Model + FrameworkModel frameworkModel = new FrameworkModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + ModuleModel moduleModel = applicationModel.newModule(); + + //提供配置中心、元数据中心、协议的配置 + RegistryConfig registryConfig = new RegistryConfig(REGISTRY_URL); + MetadataReportConfig metadataReportConfig = new MetadataReportConfig(METADATA_REPORT_URL); + ProtocolConfig protocolConfig = new ProtocolConfig(CommonConstants.DUBBO, -1); + + //如果之后需要获取注册中心或元数据中心,需要设置id,之后通过它们的Id获取(适配多注册中心) + final String registryId = "registry-1"; + registryConfig.setId(registryId); + + //Model的配置管理通过对应的ConfigManager进行 + ConfigManager appConfigManager = applicationModel.getApplicationConfigManager(); + appConfigManager.setApplication(new ApplicationConfig("dubbo-demo-api-provider-app-1")); + //提供应用层级的配置中心、元数据中心、协议默认设置 + appConfigManager.addRegistry(registryConfig); + appConfigManager.addMetadataReport(metadataReportConfig); + appConfigManager.addProtocol(protocolConfig); + + ModuleConfigManager moduleConfigManager = moduleModel.getConfigManager(); + moduleConfigManager.setModule(new ModuleConfig("dubbo-demo-api-provider-app-1-module-1")); + + + ServiceConfig serviceConfig = new ServiceConfig<>(); + //设置该ServiceConfig对应的ModuleModel + serviceConfig.setScopeModel(moduleModel); + serviceConfig.setProtocol(protocolConfig); + serviceConfig.setInterface(DemoService.class); + serviceConfig.setRef(new DemoServiceImpl()); + //为ModuleModel添加ServiceConfig + moduleConfigManager.addConfig(serviceConfig); + + serviceConfig.export(); + + new CountDownLatch(1).await(); + } +``` + +* ApplicationModel 由 FrameWorkModel 创建,ModuleModel 由 ApplicationModel 创建,由此完成它们之间层级关系的引用。 +* ServiceConfig 和 ReferenceConfig 需要设置其所属的 ScopeModel(实际只能为 ModuleModel )。然后,还需将它们设置到对应的ModuleModel 中。 + + + + + + diff --git a/content/en/blog/java/codeanalysis/multiple-protocols-on-one-port.md b/content/en/blog/java/codeanalysis/multiple-protocols-on-one-port.md new file mode 100644 index 000000000000..2a981d7df1f5 --- /dev/null +++ b/content/en/blog/java/codeanalysis/multiple-protocols-on-one-port.md @@ -0,0 +1,135 @@ +--- +aliases: + - /en/overview/tasks/protocols/multi-protocols/ + - /en/overview/tasks/protocols/multi-protocols/ +description: "" +linkTitle: 单端口多协议 +title: 发布使用不同协议的多个服务,通过单端口监听 +date: 2024-3-19 +author: 陈景明 +tags: ["源码解析", "协议"] +description: > + Dubbo3 框架支持在单个端口发布多个不同的协议,比如可以同时发布 dubbo、triple 协议,本文介绍 Dubbo 是如何实现单端口多协议发布的。 +--- + + +通过对protocol进行配置,dubbo3可以支持端口的协议复用。 +比如使用Triple协议启动端口复用后,可以在相同的端口上为服务增加 +Dubbo协议支持,以及Qos协议支持。这些协议的识别都是由一个统一的端口复用 +服务器进行处理的,可以用于服务的协议迁移,并且可以节约端口以及相关的资源,减少运维的复杂性。 + +![pu-server-image1](/imgs/blog/pu-server/pu-server-flow.png) + +- 在服务的创建阶段,通过从Config层获取到服务导出的协议配置从而创建不同的Protocol对象进行导出。在导出的过程 +中,如果不是第一次创建端口复用的Server,那么Exchanger会将Protcol层传递的数据保存到Server,用于后续处理该协议类型的消息。 + +- 当客户端的消息传递过来后,首先会通过Server传递给ProtocolDetector,如果完成了识别,那么就会标记该客户端为对应的协议。并通过WireProtocol配置对应的处理逻辑,最后交给ChannelOperator完成底层的IO框架和对应的Dubbo框架的处理逻辑的绑定。 + +- 以上的协议识别完成之后,Channel已经确定了如何处理远程的客户端消息,通过对应的ServerPipeline进行处理即可(在处理的过程中也会根据配置信息决定消息的处理线程)。 + +## 使用方式 +在同一主机上部署多个服务或需要通过负载均衡器访问多个服务。 + +## 参考用例 +[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-port-unification](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-port-unification) + + +## 配置方式 + +关于Dubbo支持的配置方式,可以参考[配置说明](/en/overview/mannual/java-sdk/reference-manual/config/) + +### 服务多协议导出 + +ext-protocol参数支持配置多个不同的协议,协议之间通过","进行分隔。 + +#### xml 配置 + +```xml + + + + + + +``` + +#### API 配置 + +```java +ProtocolConfig config = new ProtocolConfig(CommonConstants.TRIPLE, -1); + +config.setExtProtocol(CommonConstants.DUBBO+","); +``` + +#### yaml 配置 + +``` yaml +dubbo: + application: + name: dubbo-springboot-demo-provider + protocol: + name: tri + port: -1 + ext-protocol: dubbo, +``` + +#### properties 配置 +```properties +dubbo.protocol.name=tri +dubbo.protocol.ext-protocol=dubbo, +dubbo.protocol.port=20880 +``` + +### Qos接入 + +#### Qos模块导入 + +```xml + + org.apache.dubbo + dubbo-qos + +``` + +完成Qos模块的导入之后,相关的配置项可参考[Qos操作手册](/en/overview/mannual/java-sdk/reference-manual/qos/overview/)进行配置。 + +默认情况下,基于端口复用的Qos服务在模块导入后是启动的。 + +## 使用方式 + +### Qos使用 + +将Qos协议接入到端口复用的场景下,需要在建立连接之后,客户端先向服务端发送消息,对比将Qos协议通过单个端口提供服务,端口复用版的Qos协议在处理telnet连接的情况下需要用户执行一些操作,完成协议识别(二选一)。 + +1. 直接调用命令 + + 直接调用telnet支持的命令也可以完成识别,在用户不熟悉的情况下可以调用help指令完成识别 + + ![pu-server-image2](/imgs/blog/pu-server/qos-telnet-directcall.png) + +2. 发送telnet命令识别 + + 通过telnet命令建立连接之后,执行以下几个步骤: + + 1. 使用 crtl + "]" 进入到telnet交互界面(telnet默认的escape character) + 2. 调用 "send ayt" 向服务端发送特殊识别字段(为telnet协议的一个特殊字段) + 3. 回车完成消息发送并进入到dubbo的交互界面 + + ![pu-server-imgs3](/imgs/blog/pu-server/qos-telnet-sendayt.png) + + +### 服务引用 + +以[dubbo-samples-port-unification](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-port-unification)中的例子作为基础, 引用不同协议的服务和非端口复用情况下的配置是一致的,下面通过Consumer端的InvokerListener输出调用过程中的URL信息。 + +```java +ReferenceConfig reference = new ReferenceConfig<>(); +reference.setInterface(GreetingService.class); +reference.setListener("consumer"); +reference.setProtocol(this.protocol); +// reference.setProtocol(CommonConstants.DUBBO); +// reference.setProtocol(CommonConstants.TRIPLE); +``` + +![pu-server-imgs4](/imgs/blog/pu-server/reference-service.png) + diff --git a/content/en/blog/java/codeanalysis/triple-backpressure.md b/content/en/blog/java/codeanalysis/triple-backpressure.md new file mode 100644 index 000000000000..3d331ba55d69 --- /dev/null +++ b/content/en/blog/java/codeanalysis/triple-backpressure.md @@ -0,0 +1,112 @@ +--- +title: "Dubbo 3 之 Triple 流控反压原理解析" +linkTitle: "Dubbo 3 之 Triple 流控反压原理解析" +date: 2022-12-28 +author: 顾欣 +tags: ["源码解析", "Java"] +description: > + 一文了解 Dubbo 3 中基于Triple 协议实现的流控反压原理。。 +--- + +Triple 是 Dubbo 3 提出的基于 HTTP2 的开放协议, +旨在解决 Dubbo 2 私有协议带来的互通性问题。 +Triple 基于 HTTP/2 定制自己的流控,支持通过特定的异常通知客户端业务层服务端负载高情况, +保护了服务端被大流量击垮,提高系统高可用能力。 + +## 一、流控反压现状 + +客户端和服务器端在接收数据的时候有一个缓冲区来临时存储数据, +但是缓冲区的大小是有限制的,所以有可能会出现缓冲区溢出的情况, +HTTP 通过流控保护数据溢出丢失风险。 + +### 1、HTTP/1 流控 + +在 HTTP/1.1 中,流量的控制依赖的是底层TCP协议,在客户端和服务器端建立连接的时候, +会使用系统默认的设置来建立缓冲区。在数据进行通信的时候,会告诉对方它的接收窗口的大小, +这个接收窗口就是缓冲区中剩余的可用空间。如果接收窗口大小为零,则说明接收方缓冲区已满, +则发送方将不再发送数据,直到客户端清除其内部缓冲区,然后请求恢复数据传输。 + +### 2、HTTP/2 流控 + +HTTP/2 使用了多路复用机制,一个TCP连接可以有多个 HTTP/2 连接, +故在 HTTP/2 中,有更加精细的流控制机制,允许服务端实现自己数据流和连接级的流控制。 +服务端与客户端第一次连接时,会通过发送 `HTTP/2 SettingsFrame`设置初始化的流控窗口大小, +用于 `Stream` 级别流控,默认为 65,535 字节。 +定好流控窗口后,每次客户端发送数据就会减少流控窗口的大小, +服务端收到数据后会发送窗口更新包(`WINDOW_UPDATE frame`)通知客户端更新窗口。 +客户端收到窗口更新包后就会增加对应值的流控窗口,从而达到动态控制的目的。 + +![1.png](/imgs/blog/2022/12/28/triple/1.png) + +## 二、Triple流控反压 + +Netty 基于 HTTP/2 实现了基础的流控,当服务端负载过高,客户端发送窗口为 0 时, +新增请求就无法被发送出去,会在缓存到客户端待发送请求队列中,缓存数据过大, +就会造成客户端内存溢出,影响业务程序。 + +Triple 基于 Netty 实现了 HTTP/2 协议,通过 `HTTP/2 FlowController`接口统一封装, +在实现分为进站(inbound)和出站(outbound)两个维度的实现。 +Triple 在 inbound 流量上使用了 Netty 的默认流控实现, +在 outbound 上实现了自己流控,基于服务端负载, +将服务端流量压力透传到客户端业务层,实现客户端的业务反压,暂停业务继续发送请求, +保护服务端不被大流量击垮。 + +### 1、连接初始化 + +Triple在初次建立连接时,通过 `TripleHttpProtocol` 初始化 HTTP/2 配置, +默认流控窗口 `DEFAULT_WINDOW_INIT_SIZE = MIB_8`, +并在服务端和客户端加入自己的 outbound 流控接口。 + +![2.png](/imgs/blog/2022/12/28/triple/2.png) + +### 2、Inbound流控 + +Inbound 流量会通过 `DefaultHttpLocalFlowController` 的 `consumeBytes` 方法实现流控窗口更新与发送。 + +#### 1) 入口传入HTTP 流与更新数据大小 + +![3.png](/imgs/blog/2022/12/28/triple/3.png) + +#### 2) 找到对应连接实现数据消费 + +![4.png](/imgs/blog/2022/12/28/triple/4.png) + +#### 3) 更新流控窗口 + +![5.png](/imgs/blog/2022/12/28/triple/5.png) + +#### 4) 发送流控更新数据包(window_update) + +![6.png](/imgs/blog/2022/12/28/triple/6.png) + +### 3、Outbound流控 + +Outbound 通过 Triple 自己的流控实现 `TriHttpRemoteFlowController`, +将服务端压力反馈到业务层,保护服务端被大流量击垮。 + +#### 1) 发送数据时判断是否还有窗口 + +![7.png](/imgs/blog/2022/12/28/triple/7.png) + +#### 2) 窗口为0时抛出特定异常 + +![8.png](/imgs/blog/2022/12/28/triple/8.png) + +#### 3) 反馈客户端流控异常 + +![9.png](/imgs/blog/2022/12/28/triple/9.png) + +### 4、总结 + +Triple 通过将底层客户端发送窗口为 0 场景封装为特定流控异常, +透传至客户端上层业务,阻止客户端业务继续数据发送, +有效的保护了服务端被大流量击垮和客户端的内存溢出的问题。 + +## 三、未来展望 + +目前 Triple 已经基本实现了流控反压能力,未来我们将深度联动业务, +基于业务负载自适应调整反压流控, +一是在 inbound 上将流控窗口包发送时机调整到服务端业务处理完成后, +二是在 outbound 流量上关联客户端业务层,动态调整客户端发送速率。 +从而实现基于服务端业务负载动态反压流控机制。 + diff --git a/content/en/blog/java/codeanalysis/triple-exception.md b/content/en/blog/java/codeanalysis/triple-exception.md new file mode 100644 index 000000000000..1a22cb930920 --- /dev/null +++ b/content/en/blog/java/codeanalysis/triple-exception.md @@ -0,0 +1,227 @@ +--- +title: "Triple 协议支持 Java 异常回传的设计与实现" +linkTitle: "Triple 协议支持 Java 异常回传的设计与实现" +date: 2022-12-19 +author: 陈景明 +tags: ["源码解析", "Java"] +description: > + 一文了解 Dubbo 3 中 Triple 协议支持 Java 异常回传的设计与实现 +--- + +## 背景 + +在一些业务场景, 往往需要自定义异常来满足特定的业务, 主流用法是在catch里抛出异常, 例如: + +```java +public void deal() { + try{ + //doSomething + ... + } catch(IGreeterException e) { + ... + throw e; + } +} +``` + +或者通过ExceptionBuilder,把相关的异常对象返回给consumer: + +```java +provider.send(new ExceptionBuilders.IGreeterExceptionBuilder() + .setDescription('异常描述信息'); +``` + +在抛出异常后, 通过捕获和instanceof来判断特定的异常, 然后做相应的业务处理,例如: + +```java +try { + greeterProxy.echo(REQUEST_MSG); +} catch (IGreeterException e) { + //做相应的处理 + ... +} +``` + +在 Dubbo 2.x 版本,可以通过上述方法来捕获 Provider 端的异常。 +而随着云原生时代的到来, Dubbo 也开启了 3.0 的里程碑。 + +Dubbo 3.0 的一个很重要的目标就是全面拥抱云原生, +在 3.0 的许多特性中,很重要的一个改动就是支持**新的一代Rpc协议Triple**。 + +Triple 协议基于 HTTP 2.0 进行构建,对网关的穿透性强,**兼容 gRPC**, +提供 Request Response、Request Streaming、Response Streaming、 +Bi-directional Streaming 等通信模型; +从 Triple 协议开始,Dubbo 还支持基于 IDL 的服务定义。 + +采用 Triple 协议的用户可以在 provider 端生成用户定义的异常信息, +记录异常产生的堆栈,triple 协议可保证将用户在客户端获取到异常的message。 + +Triple 的回传异常会在 `AbstractInvoker` 的 `waitForResultIfSync` +中把异常信息堆栈统一封装成 `RpcException`, +所有来自 Provider 端的异常都会被封装成 `RpcException` 类型并抛出, +这会导致用户无法根据特定的异常类型捕获来自 Provider 的异常, +只能通过捕获 RpcException 异常来返回信息, +且 Provider 携带的异常 message 也无法回传,只能获取打印的堆栈信息: + +```java + try { + greeterProxy.echo(REQUEST_MSG); + } catch (RpcException e) { + e.printStackTrace(); + } +``` + +自定义异常信息在社区中的呼声也比较高, +因此本次改动将支持自定义异常的功能, 使得服务端能抛出自定义异常后被客户端捕获到。 + +## Dubbo异常处理简介 + +我们从Consumer的角度看一下一次Triple协议 Unary请求的大致流程: + +Dubbo Consumer 从 Spring 容器中获取 bean 时获取到的是一个代理接口, +在调用接口的方法时会通过代理类远程调用接口并返回结果。 + +Dubbo提供的代理工厂类是 `ProxyFactory`,通过 SPI 机制默认实现的是 `JavassistProxyFactory`, +`JavassistProxyFactory` 创建了一个继承自 `AbstractProxyInvoker` 类的匿名对象, +并重写了抽象方法 `doInvoke`。 +重写后的 `doInvoke` 只是将调用请求转发给了 `Wrapper` 类的 `invokeMethod` 方法, +并生成 `invokeMethod` 方法代码和其他一些方法代码。 + +代码生成完毕后,通过 `Javassist` 生成 `Class` 对象, +最后再通过反射创建 `Wrapper` 实例,随后通过 `InvokerInvocationHandler` -> `InvocationUtil` -> `AbstractInvoker` -> 具体实现类发送请求到Provider端。 + +Provider 进行相应的业务处理后返回相应的结果给 Consumer 端,来自 Provider 端的结果会被封装成 `AsyncResult` ,在 `AbstractInvoker` 的具体实现类里, +接受到来自 Provider 的响应之后会调用 `appResponse` 到 `recreate` 方法,若 `appResponse` 里包含异常, +则会抛出给用户,大体流程如下: + +![1.jpeg](/imgs/blog/2022/12/19/triple/1.jpeg) + +上述的异常处理相关环节是在 Consumer 端,在 Provider 端则是由 `org.apache.dubbo.rpc.filter.ExceptionFilter` 进行处理, +它是一系列责任链 Filter 中的一环,专门用来处理异常。 + +Dubbo 在 Provider 端的异常会在封装进 `appResponse` 中。下面的流程图揭示了 `ExceptionFilter` 源码的异常处理流程: + +![2.jpeg](/imgs/blog/2022/12/19/triple/2.jpeg) + +而当 `appResponse` 回到了 Consumer 端,会在 `InvocationUtil` 里调用 `AppResponse` 的 `recreate` 方法抛出异常, +最终可以在 Consumer 端捕获: + +```java +public Object recreate() throws Throwable { + if (exception != null) { + try { + Object stackTrace = exception.getStackTrace(); + if (stackTrace == null) { + exception.setStackTrace(new StackTraceElement[0]); + } + } catch (Exception e) { + // ignore + } + throw exception; +} +return result; +} +``` + +## Triple 通信原理 + +在上一节中,我们已经介绍了 Dubbo 在 Consumer 端大致发送数据的流程, +可以看到最终依靠的是 `AbstractInvoker` 的实现类来发送数据。 +在 Triple 协议中,`AbstractInvoker` 的具体实现类是 `TripleInvoker` , +`TripleInvoker` 在发送前会启动监听器,监听来自 Provider 端的响应结果, +并调用 `ClientCallToObserverAdapter` 的 `onNext` 方法发送消息, +最终会在底层封装成 Netty 请求发送数据。 + +在正式的请求发起前,TripleServer 会注册 `TripleHttp2FrameServerHandler`, +它继承自 Netty 的 `ChannelDuplexHandler`, +其作用是会在 `channelRead` 方法中不断读取 Header 和 Data 信息并解析, +经过层层调用, +会在 `AbstractServerCall` 的 `onMessage` 方法里把来自 consumer 的信息流进行反序列化, +并最终由交由 `ServerCallToObserverAdapter` 的 `invoke` 方法进行处理。 + +在 `invoke` 方法中,根据 consumer 请求的数据调用服务端相应的方法,并异步等待结果;' +若服务端抛出异常,则调用 `onError` 方法进行处理, +否则,调用 `onReturn` 方法返回正常的结果,大致代码逻辑如下: + +```java +public void invoke() { + ... + try { + //调用invoke方法请求服务 + final Result response = invoker.invoke(invocation); + //异步等待结果 + response.whenCompleteWithContext((r, t) -> { + //若异常不为空 + if (t != null) { + //调用方法过程出现异常,调用onError方法处理 + responseObserver.onError(t); + return; + } + if (response.hasException()) { + //调用onReturn方法处理业务异常 + onReturn(response.getException()); + return; + } + ... + //正常返回结果 + onReturn(r.getValue()); + }); + } + ... +} +``` + +大体流程如下: + +![3.jpeg](/imgs/blog/2022/12/19/triple/3.jpeg) + +## 实现版本 + +了解了上述原理,我们就可以进行相应的改造了, +能让 consumer 端捕获异常的**关键在于把异常对象以及异常信息序列化后再发送给consumer端**。 +常见的序列化协议很多,例如 Dubbo/HSF 默认的 hessian2 序列化; +还有使用广泛的 JSON 序列化;以及 gRPC 原生支持的 protobuf(PB) 序列化等等。 +Triple协议因为兼容grpc的原因,默认采用 Protobuf 进行序列化。 +上述提到的这三种典型的序列化方案作用类似,但在实现和开发中略有不同。 +PB 不可由序列化后的字节流直接生成内存对象, +而 Hessian 和 JSON 都是可以的。后两者反序列化的过程不依赖“二方包”, +其序列化和反序列化的代码由 proto 文件相同,只要客户端和服务端用相同的 proto 文件进行通信, +就可以构造出通信双方可解析的结构。 + +单一的 protobuf 无法序列化异常信息, +因此我们采用 `Wrapper + PB` 的形式进行序列化异常信息, +抽象出一个 `TripleExceptionWrapperUtils` 用于序列化异常, +并在 `trailer` 中采用 `TripleExceptionWrapperUtils` 序列化异常,大致代码流程如下: + +![4.jpeg](/imgs/blog/2022/12/19/triple/4.jpeg) + +上面的实现方案看似非常合理,已经能把 Provider 端的异常对象和信息回传, +并在 Consumer 端进行捕获。但仔细想想还是有问题的: +通常在 HTTP2 为基础的通信协议里会对 header 大小做一定的限制, +太大的header size 会导致性能退化严重,为了保证性能, +往往以 HTTP2 为基础的协议在建立连接的时候是要协商最大 header size 的, +超过后会发送失败。对于 Triple 协议来说,在设计之初就是基于 HTTP 2.0, +能无缝兼容 Grpc,而 Grpc header 头部只有 8KB 大小, +异常对象大小可能超过限制,从而丢失异常信息; +且多一个 header 携带序列化的异常信息意味着用户能加的 header 数量会减少, +挤占了其他 header 所能占用的空间。 + +经过讨论,考虑将异常信息放置在 Body,将序列化后的异常从 trailer 挪至 body, +采用 `TripleWrapper + protobuf` 进行序列化,把相关的异常信息序列化后回传。 +社区围绕这个问题进行了一系列的争论,读者也可尝试先思考一下: + +1.在 body 中携带回传的异常信息,其对应HTTP header状态码该设置为多少? + +2.基于 http2 构建的协议,按照主流的 grpc 实现方案,相关的错误信息放在 `trailer`,理论上不存在body,上层协议也需要保持语义一致性,若此时在payload回传异常对象,且grpc并没有支持在Body回传序列化对象的功能, 会不会破坏Http和grpc协议的语义?从这个角度出发,异常信息更应该放在trailer里。 + +3.作为开源社区,不能一味满足用户的需求,非标准化的用法注定是会被淘汰的,应该尽量避免更改 Protobuf的语义,是否在Wrapper层去支持序列化异常就能满足需求? + +首先回答第二、三个问题:HTTP 协议并没有约定在状态码非 2xx 的时候不能返回 body,返回之后是否读取取决于用户。grpc 采用protobuf进行序列化,所以无法返回 exception;且try catch机制为java独有,其他语言并没有对应的需求,但Grpc暂时不支持的功能并一定是unimplemented,Dubbo的设计目标之一是希望能和主流协议甚至架构进行对齐,但对于用户合理的需求也希望能进行一定程度的修改。且从throw本身的语义出发,throw 的数据不只是一个 error message,序列化的异常信息带有业务属性,根据这个角度,更不应该采用类似trailer的设计。至于单一的Wrapper层,也没办法和grpc进行互通。至于Http header状态码设置为200,因为其返回的异常信息已经带有一定的业务属性,不再是单纯的error,这个设计也与grpc保持一致,未来考虑网关采集可以增加新的triple-status。 + +更改后的版本只需在异常不为空时返回相关的异常信息,采用 `TripleWrapper + Protobuf` 进行序列化异常信息,并在consumer端进行解析和反序列化,大体流程如下: + +![5.jpeg](/imgs/blog/2022/12/19/triple/5.jpeg) + +## 总结 + +通过对 Dubbo 3.0 新增自定义异常的版本迭代中可以看出,尽管只能新增一个小小的特性,流程下并不复杂,但由于要考虑互通、兼容和协议的设计理念,因此思考和讨论的时间可能比写代码的时间更多。 diff --git a/content/en/blog/java/codeanalysis/url-perf-turning.md b/content/en/blog/java/codeanalysis/url-perf-turning.md new file mode 100644 index 000000000000..e351bf57c493 --- /dev/null +++ b/content/en/blog/java/codeanalysis/url-perf-turning.md @@ -0,0 +1,174 @@ +--- +title: "浅析 Dubbo 3.0 中接口级地址推送性能的优化" +linkTitle: "浅析 Dubbo 3.0 中接口级地址推送性能的优化" +date: 2022-06-23 +tags: ["源码解析", "Java"] +description: > + Dubbo URL 的基本工作原理以及在地址推送链路的优化过程。 +--- + +## URL 简介 +在阐述地址推送性能的具体优化之前,我们有必要先了解一下与之息息相关的内容 --- URL。 + +### 定义 +在不谈及 dubbo 时,我们大多数人对 URL 这个概念并不会感到陌生。统一资源定位器 ([RFC1738](https://www.ietf.org/rfc/rfc1738.txt)――Uniform Resource Locators (URL))应该是最广为人知的一个 RFC 规范,它的定义也非常简单。 +> 因特网上的可用资源可以用简单字符串来表示,该文档就是描述了这种字符串的语法和语 义。而这些字符串则被称为:“统一资源定位器”(URL) + +**一个标准的 URL 格式**至多可以包含如下的几个部分 +``` +protocol://username:password@host:port/path?key=value&key=value +``` +**一些典型 URL** +``` +http://www.facebook.com/friends?param1=value1&param2=value2 +https://username:password@10.20.130.230:8080/list?version=1.0.0 +ftp://username:password@192.168.1.7:21/1/read.txt +``` +当然,也有一些**不太符合常规的 URL**,也被归类到了 URL 之中 +``` +192.168.1.3:20880 +url protocol = null, url host = 192.168.1.3, port = 20880, url path = null + +file:///home/user1/router.js?type=script +url protocol = file, url host = null, url path = home/user1/router.js + +file://home/user1/router.js?type=script
+url protocol = file, url host = home, url path = user1/router.js + +file:///D:/1/router.js?type=script +url protocol = file, url host = null, url path = D:/1/router.js + +file:/D:/1/router.js?type=script +同上 file:///D:/1/router.js?type=script + +/home/user1/router.js?type=script +url protocol = null, url host = null, url path = home/user1/router.js + +home/user1/router.js?type=script +url protocol = null, url host = home, url path = user1/router.js +``` + +### Dubbo 中的 URL +在 dubbo 中,也使用了类似的 URL,主要用于在各个扩展点之间传递数据,组成此 URL 对象的具体参数如下: + +- protocol:一般是 dubbo 中的各种协议 如:dubbo thrift http zk +- username/password:用户名/密码 +- host/port:主机/端口 +- path:接口名称 +- parameters:参数键值对 + + **一些典型的 Dubbo URL** +``` +dubbo://192.168.1.6:20880/moe.cnkirito.sample.HelloService?timeout=3000 +描述一个 dubbo 协议的服务 + +zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?application=demo-consumer&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=1214&qos.port=33333×tamp=1545721981946 +描述一个 zookeeper 注册中心 + +consumer://30.5.120.217/org.apache.dubbo.demo.DemoService?application=demo-consumer&category=consumers&check=false&dubbo=2.0.2&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=1209&qos.port=33333&side=consumer×tamp=1545721827784 +描述一个消费者 +``` +可以说,任意的一个领域中的一个实现都可以认为是一类 URL,dubbo 使用 URL 来统一描述了元数据,配置信息,贯穿在整个框架之中。 + +## Dubbo 2.7 +### URL 结构 +在 Dubbo 2.7 中,URL 的结构非常简单,一个类就涵盖了所有内容,如下图所示。 + +![Dubbo2 URL类图.png](/imgs/blog/url-perf-tuning-1.png) + +### 地址推送模型 +接下来我们再来看看 Dubbo 2.7 中的地址推送模型方案,主要性能问题由下列过程引起。 + +![Dubbo2 地址推送模型.png](/imgs/blog/url-perf-tuning-2.png) + +上图中主要的流程为 +1、用户新增/删除DemoService的某个具体Provider实例(常见于扩容缩容、网络波动等原因) +2、ZooKeeper将DemoService下所有实例推送给Consumer端 +3、Consumer端根据Zookeeper推送的数据重新全量生成URL +根据该方案可以看出在Provider实例数量较小时,Consumer端的影响比较小,但当某个接口有大量Provider实例时,便会有大量不必要的URL创建过程。 +而Dubbo 3.0中则主要针对上述推送流程进行了一系列的优化,接下来我们便对其进行具体的讲解。 + +## Dubbo 3.0 +### URL 结构 +当然,地址推送模型的优化依然离不开 URL 的优化,下图是Dubbo 3.0中优化地址推送模型的过程中使用的新的URL结构。 + +![Dubbo3 URL类图.png](/imgs/blog/url-perf-tuning-3.png) + +根据上图我们可以看出,在 Dubbo 2.7 的 URL 中的几个重要属性在 Dubbo 3.0 中已经不存在了,取而代之的是 URLAddress 和 URLParam 两个类。原来的 parameters 属性被移动到了 URLParam 中的 params,其他的属性则移动到了 URLAddress 及其子类中。 +再来介绍 URL 新增的 3 个子类,其中 InstanceAddressURL 属于应用级接口地址,本篇章中不做介绍。 +而 ServiceConfigURL 及 ServiceAddressURL 主要的差别就是,ServiceConfigURL 是程序读取配置文件时生成的 URL。而 ServiceAddressURL 则是注册中心推送一些信息(如 providers)过来时生成的 URL。 +在这里我们顺便提一下为什么会有 DubboServiceAddressURL 这个子类,按照目前的结构来看,ServiceAddressURL 只有这一个子类,所以完全可以将他们两个的属性全都放到 ServiceAddressURL 中,那么为什么还要有这个子类呢?其实是 Dubbo 3.0 为了兼容 HSF 框架所设计的,抽象出了一个 ServiceAddressURL,而 HSF 框架则可以继承这个类,使用 HSFServiceAddressURL,当然,这个类目前没有体现出来,所以此处我们简单一提,不过多讲解。 +那么,我们接下来就讨论一下 Dubbo 3.0 为什么要改为此种数据结构,并且该结构和地址推送模型的优化有何关联性吧! + +### 地址推送模型的优化 +#### URL 结构上的优化 +我们在上小节中的类图里看到虽然原来的属性都被移到了 URLAddress 和 URLParam 里,但是 URL 的子类依然多了几个属性,这几个属性自然也是为了优化而新增的,那么这里就讲讲这几个属性的作用。 +**ServiceConfigURL**:这个子类中新增了 attribute 这个属性,这个属性主要是针对 URLParam 的 params 做了冗余,仅仅只是将 value 的类型从 String 改为了 Object,减少了代码中每次获取 parameters 的格式转换消耗。 +**ServiceAddressURL**:这个子类及其对应的其他子类中则新增了 overrideURL 和 consumerURL 属性。其中 consumerURL 是针对 consumer 端的配置信息,overrideURL 则是在 Dubbo Admin 上进行动态配置时写入的值,当我们调用 URL 的 getParameter() 方法时,优先级为 `overrideURL > consumerURL > urlParam`。在 Dubbo 2.7 时,动态配置属性会替换 URL 中的属性,及当你有大量 URL 时消耗也是不可忽视的,而此处的 overrideURL 则避免了这种消耗,因为所有 URL 都会共同使用同一个对象。 + +#### 多级缓存 +缓存是 Dubbo 3.0 在 URL 上做的优化的重点,同时这部分也是直接针对地址推送模型所做的优化,那么接下来我们就开始来介绍一下多级缓存的具体实现。 +首先,多级缓存主要体现在 CacheableFailbackRegistry 这个类之中,它直接继承于 FailbackRegistry,以 Zookeeper 为例,我们看看 Dubbo 2.7 和 Dubbo 3.0 继承结构的区别。 + +![Dubbo3 CacheableFailbackRegistry缓存.png](/imgs/blog/url-perf-tuning-4.png) + +可以看到在 CacheableFailbackRegistry 缓存中,我们新增了 3 个缓存属性 `stringAddress`,`stringParam` 和 `stringUrls`。我们通过下图来描述这 3 个缓存的具体使用场景。 + +![多级缓存.png](/imgs/blog/url-perf-tuning-5.png) + +在该方案下,我们使用了 3 个纬度的缓存数据(URL 字符串缓存、URL 地址缓存、URL 参数缓存),这样一来,在大部分情况下都能有效利用到缓存中的数据,减少了 Zookeeper 重复通知的消耗。 + +#### 延迟通知 +除了上面提到的优化之外,其实另外还有两个小小的优化。 +第一个是解析 URL 时可以直接使用编码后的 URL 字符串字节进行解析,而在 Dubbo 2.7 中,所有编码后的 URL 字符串都需要经过解码才可以正常解析为 URL 对象。该方式也直接减少了 URL 解码过程的开销。 +第二个则是 URL 变更后的通知机制增加了延迟,下图以Zookeeper为例讲解了实现细节。 + +![延迟通知.png](/imgs/blog/url-perf-tuning-6.png) + +在该方案中,当 Consumer 接收 Zookeeper 的变更通知后会主动休眠一段时间,而这段时间内的变更在休眠结束后只会保留最后一次变更,Consumer 便会使用最后一次变更来进行监听实例的更新,以此方法来减少大量 URL 的创建开销。 + +#### 字符串重用 +在旧版本实现中,不同的 URL 中属性相同的字符串会存储在堆内不同的地址中,如 protocol、path 等,当有大量 provider 的情况下,Consumer 端的堆内会存在大量的重复字符串,导致内存利用率低下,所以此处提供了另一个优化方式,即字符串重用。 +而它的实现方式也非常的简单,让我们来看看对应的代码片段。 +```java +public class URLItemCache { + private static final Map PATH_CACHE = new LRUCache<>(10000); + private static final Map PROTOCOL_CACHE = new ConcurrentHashMap<>(); + + // 省略无关代码片段 + + public static String checkProtocol(String _protocol) { + if (_protocol == null) { + return _protocol; + } + String cachedProtocol = PROTOCOL_CACHE.putIfAbsent(_protocol, _protocol); + if (cachedProtocol != null) { + return cachedProtocol; + } + return _protocol; + } + + public static String checkPath(String _path) { + if (_path == null) { + return _path; + } + String cachedPath = PATH_CACHE.putIfAbsent(_path, _path); + if (cachedPath != null) { + return cachedPath; + } + return _path; + } +} +``` +由如上代码片段可以得知,字符串重用即为简单地使用了 Map 来存储对应的缓存值,当你使用了相同的字符串时,便会从 Map 中获取早已存在的对象返回给调用方,由此便可以减少堆内存中重复的字符串数以达到优化的效果。 + +### 优化结果 +这里优化结果我引用了[《Dubbo 3.0 前瞻:服务发现支持百万集群,带来可伸缩微服务架构》](https://zhuanlan.zhihu.com/p/345626851)这篇文章中的两副图来说明,下图模拟了在**220万**个 Provider 接口的情况下,接口数据不断变更导致的 Consumer 端的消耗,我们看到整个 Consumer 端几乎被 Full GC 占满了,严重影响了性能。 + +![Dubbo2 接口级地址模型.png](/imgs/blog/url-perf-tuning-7.png) + +那么我们再来看看 Dubbo 3.0 中对 URL 进行优化后同一个环境下的压测结果,如下图所示。 + +![Dubbo3 接口级地址模型.png](/imgs/blog/url-perf-tuning-8.png) + +我们明显可以看到 Full GC 的频率减少到了只有 3 次,大大提升了性能。当然,该文章中还有其他方面的对比,此处便不一一引用了,感兴趣的读者可以自行去阅读该文章。 diff --git a/content/en/blog/java/codeanalysis/v3-service-discovery.md b/content/en/blog/java/codeanalysis/v3-service-discovery.md new file mode 100644 index 000000000000..e8fcfd57f5c6 --- /dev/null +++ b/content/en/blog/java/codeanalysis/v3-service-discovery.md @@ -0,0 +1,360 @@ +--- +title: "Dubbo3 应用级服务发现" +linkTitle: "应用级服务发现" +date: 2021-06-02 +tags: ["源码解析", "Java"] +description: > + 本文介绍了 Dubbo3 应用级服务发现的实现原理 +--- + +## 1 服务发现(Service Discovery) 概述 + +从 Internet 刚开始兴起,如何动态感知后端服务的地址变化就是一个必须要面对的问题,为此人们定义了 DNS 协议,基于此协议,调用方只需要记住由固定字符串组成的域名,就能轻松完成对后端服务的访问,而不用担心流量最终会访问到哪些机器 IP,因为有代理组件会基于 DNS 地址解析后的地址列表,将流量透明的、均匀的分发到不同的后端机器上。 + +在使用微服务构建复杂的分布式系统时,如何感知 backend 服务实例的动态上下线,也是微服务框架最需要关心并解决的问题之一。业界将这个问题称之为 - 微服务的地址发现(Service Discovery),业界比较有代表性的微服务框架如 SpringCloud、Dubbo 等都抽象了强大的动态地址发现能力,并且为了满足微服务业务场景的需求,绝大多数框架的地址发现都是基于自己设计的一套机制来实现,因此在能力、灵活性上都要比传统 DNS 丰富得多。如 SpringCloud 中常用的 Eureka, Dubbo 中常用的 Zookeeper、Nacos 等,这些注册中心实现不止能够传递地址(IP + Port),还包括一些微服务的 Metadata 信息,如实例序列化类型、实例方法列表、各个方法级的定制化配置等。 + +下图是微服务中 Service Discovery 的基本工作原理图,微服务体系中的实例大概可分为三种角色:服务提供者(Provider)、服务消费者(Consumer)和注册中心(Registry)。而不同框架实现间最主要的区别就体现在注册中心数据的组织:地址如何组织、以什么粒度组织、除地址外还同步哪些数据? + +![img1](/imgs/blog/service-discovery-1.png) + +我们今天这篇文章就是围绕这三个角色展开,重点看下 Dubbo 中对于服务发现方案的设计,包括之前老的服务发现方案的优势和缺点,以及 Dubbo 3.0 中正在设计、开发中的全新的**面向应用粒度的地址发现方案**,我们期待这个新的方案能做到: + +* **支持几十万/上百万级集群实例的地址发现** +* **与不同的微服务体系(如 Spring Cloud)实现在地址发现层面的互通** + + + +## 2 Dubbo 地址发现机制解析 + +我们先以一个 DEMO 应用为例,来快速的看一下 Dubbo “接口粒度”服务发现与“应用粒度”服务发现体现出来的区别。这里我们重点关注 Provider 实例是如何向注册中心注册的,并且,为了体现注册中心数据量变化,我们观察的是两个 Provider 实例的场景。 + + + +**应用 DEMO 提供的服务列表如下:** + +```xml + + +``` + +我们示例注册中心实现采用的是 Zookeeper ,启动 192.168.0.103 和 192.168.0.104 两个实例后,以下是两种模式下注册中心的实际数据 + +**1. “接口粒度” 服务发现** + +192.168.0.103 实例注册的数据 + +```text +dubbo://192.168.0.103:20880/org.apache.dubbo.samples.basic.api.DemoService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.DemoService&methods=testVoid,sayHello&pid=995&release=2.7.7&side=provider×tamp=1596988171266 + +dubbo://192.168.0.103:20880/org.apache.dubbo.samples.basic.api.GreetingService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.GreetingService&methods=greeting&pid=995&release=2.7.7&side=provider×tamp=1596988170816 +``` + +192.168.0.104 实例注册的数据 + +```text +dubbo://192.168.0.104:20880/org.apache.dubbo.samples.basic.api.DemoService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.DemoService&methods=testVoid,sayHello&pid=995&release=2.7.7&side=provider×tamp=1596988171266 + +dubbo://192.168.0.104:20880/org.apache.dubbo.samples.basic.api.GreetingService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.GreetingService&methods=greeting&pid=995&release=2.7.7&side=provider×tamp=1596988170816 +``` + + + +**2. “应用粒度” 服务发现** + +192.168.0.103 与 192.168.0.104 两个实例共享一份注册中心数据,如下: + +```json +{ + "name": "demo-provider", + "id": "192.168.0.103:20880", + "address": "192.168.0.103", + "port": 20880, + "metadata": { + "dubbo.endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]", + "dubbo.metadata.storage-type": "local", + "dubbo.revision": "6785535733750099598" + }, + "time": 1583461240877 +} +``` + +```json +{ + "name": "demo-provider", + "id": "192.168.0.104:20880", + "address": "192.168.0.104", + "port": 20880, + "metadata": { + "dubbo.endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]", + "dubbo.metadata.storage-type": "local", + "dubbo.revision": "7829635812370099387" + }, + "time": 1583461240877 +} +``` + +对比以上两种不同粒度的服务发现模式,从 “接口粒度” 升级到 “应用粒度” 后我们可以总结出最大的区别是:注册中心数据量不再与接口数成正比,不论应用提供有多少接口,注册中心只有一条实例数据。 + +那么接下来我们详细看下这个变化给 Dubbo 带来了哪些好处。 + +## 3 Dubbo 应用级服务发现的意义 +我们先说结论,应用级服务发现给 Dubbo 带来以下优势: + +1. 与业界主流微服务模型对齐,比如 SpringCloud、Kubernetes Native Service等。 +2. 提升性能与可伸缩性。注册中心数据的重新组织(减少),能最大幅度的减轻注册中心的存储、推送压力,进而减少 Dubbo Consumer 侧的地址计算压力;集群规模也开始变得可预测、可评估(与 RPC 接口数量无关,只与实例部署规模相关)。 + +### 3.1 对齐主流微服务模型 +自动、透明的实例地址发现(负载均衡)是所有微服务框架需要解决的事情,这能让后端的部署结构对上游微服务透明,上游服务只需要从收到的地址列表中选取一个,发起调用就可以了。要实现以上目标,涉及两个关键点的自动同步: + +* 实例地址,服务消费方需要知道地址以建立连接 +* RPC 方法定义,服务消费方需要知道 RPC 服务的具体定义,不论服务类型是 rest 或 rmi 等。 + +![img2](/imgs/blog/service-discovery-2.png) + +对于 RPC 实例间借助注册中心的数据同步,REST 定义了一套非常有意思的成熟度模型,感兴趣的朋友可以参考这里的链接 https://www.martinfowler.com/articles/richardsonMaturityModel.html, 按照文章中的 4 级成熟度定义,Dubbo 当前基于接口粒度的模型可以对应到 L4 级别。 + +接下来,我们看看 Dubbo、SpringCloud 以及 Kubernetes 分别是怎么围绕自动化的实例地址发现这个目标设计的。 + +**1. Spring Cloud** + +Spring Cloud 通过注册中心只同步了应用与实例地址,消费方可以基于实例地址与服务提供方建立连接,但是消费方对于如何发起 http 调用(SpringCloud 基于 rest 通信)一无所知,比如对方有哪些 http endpoint,需要传入哪些参数等。 + +RPC 服务这部分信息目前都是通过线下约定或离线的管理系统来协商的。这种架构的优缺点总结如下。 +优势:部署结构清晰、地址推送量小; +缺点:地址订阅需要指定应用名, provider 应用变更(拆分)需消费端感知;RPC 调用无法全自动同步。 + +![img3](/imgs/blog/service-discovery-3.png) + +**2. Dubbo** + +Dubbo 通过注册中心同时同步了实例地址和 RPC 方法,因此其能实现 RPC 过程的自动同步,面向 RPC 编程、面向 RPC 治理,对后端应用的拆分消费端无感知,其缺点则是地址推送数量变大,和 RPC 方法成正比。 + +![img4](/imgs/blog/service-discovery-4.png) + +**3. Dubbo + Kubernetes** + +Dubbo 要支持 Kubernetes native service,相比之前自建注册中心的服务发现体系来说,在工作机制上主要有两点变化: + +* 服务注册由平台接管,provider 不再需要关心服务注册 +* consumer 端服务发现将是 Dubbo 关注的重点,通过对接平台层的 API-Server、DNS 等,Dubbo client 可以通过一个 [Service Name](https://kubernetes.io/docs/concepts/services-networking/service/)(通常对应到 Application Name)查询到一组 Endpoints(一组运行 provider 的 pod),通过将 Endpoints 映射到 Dubbo 内部地址列表,以驱动 Dubbo 内置的负载均衡机制工作。 + +> Kubernetes Service 作为一个抽象概念,怎么映射到 Dubbo 是一个值得讨论的点 +> +> * Service Name - > Application Name,Dubbo 应用和 Kubernetes 服务一一对应,对于微服务运维和建设环节透明,与开发阶段解耦。 +> +> ```yaml +> apiVersion: v1 +> kind: Service +> metadata: +> name: provider-app-name +> spec: +> selector: +> app: provider-app-name +> ports: +> - protocol: TCP +> port: +> targetPort: 9376 +> ``` +> +> +> +> * Service Name - > Dubbo RPC Service,Kubernetes 要维护调度的服务与应用内建 RPC 服务绑定,维护的服务数量变多。 +> +> ```yaml +> --- +> apiVersion: v1 +> kind: Service +> metadata: +> name: rpc-service-1 +> spec: +> selector: +> app: provider-app-name +> ports: ## +> ... +> --- +> apiVersion: v1 +> kind: Service +> metadata: +> name: rpc-service-2 +> spec: +> selector: +> app: provider-app-name +> ports: ## +> ... +> --- +> apiVersion: v1 +> kind: Service +> metadata: +> name: rpc-service-N +> spec: +> selector: +> app: provider-app-name +> ports: ## +> ... +> ``` +> +> + +![img5](/imgs/blog/service-discovery-5.png) + +结合以上几种不同微服务框架模型的分析,我们可以发现,Dubbo 与 SpringCloud、Kubernetes 等不同产品在微服务的抽象定义上还是存在很大不同的。SpringCloud 和 Kubernetes 在微服务的模型抽象上还是比较接近的,两者基本都只关心实例地址的同步,如果我们去关心其他的一些服务框架产品,会发现它们绝大多数也是这么设计的; +> 即 REST 成熟度模型中的 L3 级别。 + +对比起来 Dubbo 则相对是比较特殊的存在,更多的是从 RPC 服务的粒度去设计的。 +> 对应 REST 成熟度模型中的 L4 级别。 + +如我们上面针对每种模型做了详细的分析,每种模型都有其优势和不足。而我们最初决定 Dubbo 要做出改变,往其他的微服务发现模型上的对齐,是我们最早在确定 Dubbo 的云原生方案时,我们发现要让 Dubbo 去支持 Kubernetes Native Service,模型对齐是一个基础条件;另一点是来自用户侧对 Dubbo 场景化的一些工程实践的需求,得益于 Dubbo 对多注册、多协议能力的支持,使得 Dubbo 联通不同的微服务体系成为可能,而服务发现模型的不一致成为其中的一个障碍,这部分的场景描述请参见以下文章:[Dubbo 如何成为连接异构微服务体系的最佳服务开发框架](https://developer.aliyun.com/article/740260) + +### 3.2 更大规模的微服务集群 - 解决性能瓶颈 +这部分涉及到和注册中心、配置中心的交互,关于不同模型下注册中心数据的变化,之前原理部分我们简单分析过。为更直观的对比服务模型变更带来的推送效率提升,我们来通过一个示例看一下不同模型注册中心的对比: + +![img6](/imgs/blog/service-discovery-6.png) + +图中左边是微服务框架的一个典型工作流程,Provider 和 Consumer 通过注册中心实现自动化的地址通知。其中,Provider 实例的信息如图中表格所示: + 应用 DEMO 包含三个接口 DemoService 1 2 3,当前实例的 ip 地址为 10.210.134.30。 + * 对于 Spring Cloud 和 Kubernetes 模型,注册中心只会存储一条 `DEMO - 10.210.134.30+metadata` 的数据; + * 对于老的 Dubbo 模型,注册中心存储了三条接口粒度的数据,分别对应三个接口 DemoService 1 2 3,并且很多的址数据都是重复的; + +可以总结出,基于应用粒度的模型所存储和推送的数据量是和应用、实例数成正比的,只有当我们的应用数增多或应用的实例数增长时,地址推送压力才会上涨。 +而对于基于接口粒度的模型,数据量是和接口数量正相关的,鉴于一个应用通常发布多个接口的现状,这个数量级本身比应用粒度是要乘以倍数的;另外一个关键点在于,接口粒度导致的集群规模评估的不透明,相对于实例、应用增长都通常是在运维侧的规划之中,接口的定义更多的是业务侧的内部行为,往往可以绕过评估给集群带来压力。 + +以 Consumer 端服务订阅举例,根据我对社区部分 Dubbo 中大规模头部用户的粗略统计,根据受统计公司的实际场景,一个 Consumer 应用要消费(订阅)的 Provier 应用数量往往要超过 10 个,而具体到其要消费(订阅)的的接口数量则通常要达到 30 个,平均情况下 Consumer 订阅的 3 个接口来自同一个 Provider 应用,如此计算下来,如果以应用粒度为地址通知和选址基本单位,则平均地址推送和计算量将下降 60% 还要多, +而在极端情况下,也就是当 Consumer 端消费的接口更多的来自同一个应用时,这个地址推送与内存消耗的占用将会进一步得到降低,甚至可以超过 80% 以上。 + +一个典型的极端场景即是 Dubbo 体系中的网关型应用,有些网关应用消费(订阅)达 100+ 应用,而消费(订阅)的服务有 1000+ ,平均有 10 个接口来自同一个应用,如果我们把地址推送和计算的粒度改为应用,则地址推送量从原来的 n * 1000 变为 n * 100,地址数量降低可达近 90%。 + +## 4 应用级服务发现工作原理 + +### 4.1 设计原则 +上面一节我们从**服务模型**及**支撑大规模集群**的角度分别给出了 Dubbo 往应用级服务发现靠拢的好处和原因,但这么做的同时接口粒度的服务治理能力还是要继续保留,这是 Dubbo 框架编程模型易用性、服务治理能力优势的基础。 +以下是我认为我们做服务模型迁移仍要坚持的设计原则 + +* 新的服务发现模型要实现对原有 Dubbo 消费端开发者的无感知迁移,即 Dubbo 继续面向 RPC 服务编程、面向 RPC 服务治理,做到对用户侧完全无感知。 +* 建立 Consumer 与 Provider 间的自动化 RPC 服务元数据协调机制,解决传统微服务模型无法同步 RPC 级接口配置的缺点。 + +### 4.2 基本原理详解 + +应用级服务发现作为一种新的服务发现机制,和以前 Dubbo 基于 RPC 服务粒度的服务发现在核心流程上基本上是一致的:即服务提供者往注册中心注册地址信息,服务消费者从注册中心拉取&订阅地址信息。 + +这里主要的不同有以下两点: + +#### 4.2.1 注册中心数据以“应用 - 实例列表”格式组织,不再包含 RPC 服务信息 + +![img7](/imgs/blog/service-discovery-7.png) + +以下是每个 Instance metadata 的示例数据,总的原则是 metadata 只包含当前 instance 节点相关的信息,不涉及 RPC 服务粒度的信息。 + +总体信息概括如下:实例地址、实例各种环境标、metadata service 元数据、其他少量必要属性。 + +```json +{ + "name": "provider-app-name", + "id": "192.168.0.102:20880", + "address": "192.168.0.102", + "port": 20880, + "sslPort": null, + "payload": { + "id": null, + "name": "provider-app-name", + "metadata": { + "metadataService": "{\"dubbo\":{\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"2.7.5\",\"port\":\"20881\"}}", + "endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]", + "storage-type": "local", + "revision": "6785535733750099598", + } + }, + "registrationTimeUTC": 1583461240877, + "serviceType": "DYNAMIC", + "uriSpec": null +} +``` + +#### 4.2.2 Client – Server 自行协商 RPC 方法信息 + +在注册中心不再同步 RPC 服务信息后,服务自省在服务消费端和提供端之间建立了一条内置的 RPC 服务信息协商机制,这也是“服务自省”这个名字的由来。服务端实例会暴露一个预定义的 MetadataService RPC 服务,消费端通过调用 MetadataService 获取每个实例 RPC 方法相关的配置信息。 + +![img8](/imgs/blog/service-discovery-8.png) + +当前 MetadataService 返回的数据格式如下, + +```json +[ + "dubbo://192.168.0.102:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider×tamp=1583469714314", + "dubbo://192.168.0.102:20880/org.apache.dubbo.demo.HelloService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider×tamp=1583469714314", + "dubbo://192.168.0.102:20880/org.apache.dubbo.demo.WorldService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider×tamp=1583469714314" +] +``` + +> 熟悉 Dubbo 基于 RPC 服务粒度的服务发现模型的开发者应该能看出来,服务自省机制机制将以前注册中心传递的 URL 一拆为二: +> +> * 一部分和实例相关的数据继续保留在注册中心,如 ip、port、机器标识等。 +> * 另一部分和 RPC 方法相关的数据从注册中心移除,转而通过 MetadataService 暴露给消费端。 +> +> **理想情况下是能达到数据按照实例、RPC 服务严格区分开来,但明显可以看到以上实现版本还存在一些数据冗余,有些数据也还未合理划分。尤其是 MetadataService 部分,其返回的数据还只是简单的 URL 列表组装,这些 URL其实是包含了全量的数据。** + +以下是服务自省的一个完整工作流程图,详细描述了服务注册、服务发现、MetadataService、RPC 调用间的协作流程。 + +![img9](/imgs/blog/service-discovery-9.png) + +* 服务提供者启动,首先解析应用定义的“普通服务”并依次注册为 RPC 服务,紧接着注册内建的 MetadataService 服务,最后打开 TCP 监听端口。 +* 启动完成后,将实例信息注册到注册中心(仅限 ip、port 等实例相关数据),提供者启动完成。 +* 服务消费者启动,首先依据其要“消费的 provider 应用名”到注册中心查询地址列表,并完成订阅(以实现后续地址变更自动通知)。 +* 消费端拿到地址列表后,紧接着对 MetadataService 发起调用,返回结果中包含了所有应用定义的“普通服务”及其相关配置信息。 +* 至此,消费者可以接收外部流量,并对提供者发起 Dubbo RPC 调用 + +> 在以上流程中,我们只考虑了一切顺利的情况,但在更详细的设计或编码实现中,我们还需要严格约定一些异常场景下的框架行为。比如,如果消费者 MetadataService 调用失败,则在重试直到成功之前,消费者将不可以接收外部流量。 + +### 4.3 服务自省中的关键机制 +#### 4.3.1 元数据同步机制 + +Client 与 Server 间在收到地址推送后的配置同步是服务自省的关键环节,目前针对元数据同步有两种具体的可选方案,分别是: +* 内建 MetadataService。 +* 独立的元数据中心,通过中心化的元数据集群协调数据。 + +**1. 内建 MetadataService** +MetadataService 通过标准的 Dubbo 协议暴露,根据查询条件,会将内存中符合条件的“普通服务”配置返回给消费者。这一步发生在消费端选址和调用前。 + +**2. 元数据中心** +复用 2.7 版本中引入的元数据中心,provider 实例启动后,会尝试将内部的 RPC 服务组织成元数据的格式同步到元数据中心,而 consumer 则在每次收到注册中心推送更新后,主动查询元数据中心。 + +> 注意 consumer 端查询元数据中心的时机,是等到注册中心的地址更新通知之后。也就是通过注册中心下发的数据,我们能明确的知道何时某个实例的元数据被更新了,此时才需要去查元数据中心。 + +![img10](/imgs/blog/service-discovery-10.png) + +#### 4.3.2 RPC 服务 < - > 应用映射关系 + +回顾上文讲到的注册中心关于“应用 - 实例列表”结构的数据组织形式,这个变动目前对开发者并不是完全透明的,业务开发侧会感知到查询/订阅地址列表的机制的变化。具体来说,相比以往我们基于 RPC 服务来检索地址,现在 consumer 需要通过指定 provider 应用名才能实现地址查询或订阅。 + +老的 Consumer 开发与配置示例: + +```xml + + + + + +``` + +新的 Consumer 开发与配置示例: + +```xml + + + + + +``` + +以上指定 provider 应用名的方式是 Spring Cloud 当前的做法,需要 consumer 端的开发者显示指定其要消费的 provider 应用。 + +以上问题的根源在于注册中心不知道任何 RPC 服务相关的信息,因此只能通过应用名来查询。 + +为了使整个开发流程对老的 Dubbo 用户更透明,同时避免指定 provider 对可扩展性带来的影响(参见下方说明),我们设计了一套 `RPC 服务到应用名`的映射关系,以尝试在 consumer 端自动完成 RPC 服务到 provider 应用名的转换。 + +![img11](/imgs/blog/service-discovery-11.png) + +> Dubbo 之所以选择建立一套“接口-应用”的映射关系,主要是考虑到 service - app 映射关系的不确定性。一个典型的场景即是应用/服务拆分,如上面提到的配置``,PC Service 2 是定义于 provider-app-x 中的一个服务,未来它随时可能会被开发者分拆到另外一个新的应用如 provider-app-x-1 中,这个拆分要被所有的 PC Service 2 消费方感知到,并对应用进行修改升级,如改为``,这样的升级成本不可否认还是挺高的。 +> 到底是 Dubbo 框架帮助开发者透明的解决这个问题,还是交由开发者自己去解决,当然这只是个策略选择问题,并且 Dubbo 2.7.5+ 版本目前是都提供了的。其实我个人更倾向于交由业务开发者通过组织上的约束来做,这样也可进一步降低 Dubbo 框架的复杂度,提升运行态的稳定性。 + +## 5 总结与展望 +应用级服务发现机制是 Dubbo 面向云原生走出的重要一步,它帮 Dubbo 打通了与其他微服务体系之间在地址发现层面的鸿沟,也成为 Dubbo 适配 Kubernetes Native Service 等基础设施的基础。我们期望 Dubbo 在新模型基础上,能继续保留在编程易用性、服务治理能力等方面强大的优势。但是我们也应该看到应用粒度的模型一方面带来了新的复杂性,需要我们继续去优化与增强;另一方面,除了地址存储与推送之外,应用粒度在帮助 Dubbo 选址层面也有进一步挖掘的潜力。 diff --git a/content/en/blog/java/demos/_index.md b/content/en/blog/java/demos/_index.md new file mode 100644 index 000000000000..0512c99a04be --- /dev/null +++ b/content/en/blog/java/demos/_index.md @@ -0,0 +1,8 @@ + +--- +title: "功能演示" +linkTitle: "功能演示" +weight: 10 +--- + + diff --git a/content/en/blog/java/demos/connect-heterogeneous-microservices.md b/content/en/blog/java/demos/connect-heterogeneous-microservices.md new file mode 100644 index 000000000000..acb5945564ad --- /dev/null +++ b/content/en/blog/java/demos/connect-heterogeneous-microservices.md @@ -0,0 +1,298 @@ +--- +title: "使用 Dubbo 连接异构微服务体系" +linkTitle: "使用 Dubbo 连接异构微服务体系" +tags: ["Java"] +date: 2019-06-22 +description: > + 在这篇文章中,我们将探索如何利用 Dubbo 对多协议、多服务发现模型的支持,来实现异构微服务体系间的互联互通 +--- + +从编程开发的角度来说,Dubbo 首先是一款 RPC 服务框架,它最大的优势在于提供了面向接口代理的服务编程模型,对开发者屏蔽了底层的远程通信细节。同时 Dubbo 也是一款服务治理框架,它为分布式部署的微服务提供了服务发现、流量调度等服务治理解决方案。 + +在这篇文章中,我们将以以上基础能力为背景,尝试突破 Dubbo 体系自身,探索如何利用 Dubbo 对多协议、多服务发现模型的支持,来实现异构微服务体系间的互联互通。在实际业务场景中,这可以用来解决异构技术体系共存场景下的通信问题,帮助公司实现在异构技术体系间作平滑迁移,解决大规模跨区域、多集群部署场景的地址发现及流量调度等问题。 + +## 面向接口代理的透明服务开发框架 + +我们还是从 **Dubbo 是一个微服务开发框架** 这个大家熟知的概念开始。就像 Spring 是开发 Java 应用的基础框架一样,我们经常会选用 Dubbo 作为开发微服务业的基础框架。 Dubbo 框架的最大优势我认为就在其面向接口的编程模型,使得开发远程服务调用就像开发本地服务一样(以 Java 语言为例): + +1. 服务定义 + +```java +public interface GreetingsService { + String sayHi(String name); +} +``` + +2. 消费方调用服务 + +```java +// 和调用本地服务一样,完全透明。 +@Reference +private GreetingService greetingService; + +public void doSayHello(String name) { + greetingService.sayHi("Hello world!"); +} +``` + +下图是 Dubbo 的基本工作原理图,服务提供者与服务消费者之间通过注册中心协调地址,通过约定的协议实现数据交换。 + +![Dubbo basic work flow](/imgs/architecture.png) + + +## 同构/异构微服务体系面临的问题 + +关于 Dubbo 协议本身及其服务治理相关功能细节并不是本文的重点,我们今天将从一个更高的层次,来看看公司内部构建微服务体系所面的挑战,以及 Dubbo 能为架构选型和迁移等提供哪些解决思路。 + +一个公司内部的微服务可能都是基于某一个相同的服务框架开发的,比如说 Dubbo,对于这样的架构,我们称之为是**同构的微服务体系**;而有些公司的微服务可能是使用多个不同的服务框架所建设,我们称之为**异构的微服务体系**,多个不同技术栈微服务体系的共存在大型组织内还是非常普遍的,造成这种局面可能有很多原因。比如,可能是遗留系统带来的,也可能是公司正在做技术栈迁移,或者就是不同业务部门为了满足各自特殊需求而做的独立选型(这也意味着异构微服务体系的长期共存)。 + +**1. 异构微服务体系共存** + +我们很容易想到的一个挑战是:**不同的体系间通常是使用不同的 RPC 通信协议、部署独立的注册中心集群,面对这种多协议、多注册中心集群的场景,要如何实现相互之间透明的地址发现和透明的 RPC 调用?** 如果我们什么都不做,那么每个微服务体系就只能感知到自己体系内的服务状态,流量也在各自的体系内封闭。而要做到从体系 A 平滑的迁移到体系 B,或者想长期的保持公司内部多个体系的共存,则解决不同体系间的互联互通,实现流量的透明调度将是非常重要的环节。 + +![2](/imgs/blog/microservices.png) + + +**2. Dubbo 体系内部** + +**多协议、多注册中心集群的问题在同构的微服务体系中也可能存在,尤其是当一个组织内部的微服务规模增长到一定量级的时候。** + +* 我们可能要在不同的服务之间采用不同的通信协议,因为不同的服务面临不同的业务场景,而这也进一步导致了数据传输特点的不同,我们需要分别采用更适合各类业务特点的协议。比如典型的场景:我们可能对于普通的业务服务采用 Dubbo 协议,对于和 FrontEnd 交互的服务需要 HTTP 协议,而对于需要流式数据传输的业务则采用 gRPC 协议等等。 + +* Dubbo 体系内部另一个常出现的问题是,在大规模分布式部署的场景下,微服务系统会做跨区域、跨注册中心的部署,这个时候就会出现多集群间地址同步和流量调度的问题。 + +总结起来,**不论是同构体系还是异构体系,都面临对多协议通信、多注册中心集群地址发现的问题。** Dubbo 目前是支持多协议、多注册中心的,可以说就是为解决我们上面分析的 Dubbo 同构体系内的场景而设计的,因此下面我们从同构体系的多协议、多注册中心场景讲起,先了解 Dubbo 多协议、多注册中心的基本支持情况以及它们是如何工作的。而在后面的一章再进一步探索怎么扩展这个能力来支持异构微服务体系的互联互通。 + +## Dubbo 体系内的多协议、多注册中心机制 + +我们将通过两个场景示例,来分别具体的讲一下 Dubbo 的多协议、多注册中心机制的使用方式和工作原理。 + +### 多协议 + +![multiregistries.png](/imgs/blog/multiregistries.png) + +以上是使用 Dubbo 开发的一套微服务,服务间通信使用到了不同的协议,根据我们的调研发现,公司内部启用多协议其实是非常普遍需求,具体场景在此我们暂不做解释。 + +应用 B 作为服务提供者,发布了 5 个服务,其中: + +* `DemoService1` `DemoService2` 通过 `dubbo` 协议发布 +* `DemoService3` `DemoService4` 通过 `gRPC` 协议发布 +* `DemoService0` 通过 `dubbo` 、`gRPC` 双协议发布 + +应用 A 作为消费者,使用 dubbo 协议消费 `DemoService1` `DemoService2`,使用 gRPC 协议消费 `DemoService0`。 + +应用 B 作为消费者,使用 gRPC 协议消费 `DemoService2` `DemoService4`,使用 dubbo 协议消费 `DemoService0`。 + +以下是具体的代码配置: + +1. 提供端应用 B + +```xml + + + + + + + +``` + +2. 消费端应用 A + +```xml + + + + +``` + +3. 消费端应用 C + +```xml + + + + + +``` + +#### Dubbo 多协议支持现状 + +Dubbo 目前所支持的协议包括 Dubbo、REST、Thrift、gRPC、JsonRPC、Hessian 等,基本涵盖了业界大多数主流的 RPC 通信协议。需要注意的是,这些协议的支持都是以直接集成官方 Release 实现的形式来做的,我认为这是一个很好的选择,既保证了协议解析自身的稳定性,又能使 Dubbo 社区更专注的将更多的精力放在 Dubbo 外围服务治理能力的改善上。试想如果 Dubbo 社区自己为每个协议提供实现,那是要花费多少精力和时间才能使每种协议达到稳定的生产可用。 + +除了以上官方提供支持的协议之外,得益于 Dubbo 灵活的扩展机制,想要为 Dubbo 扩展协议非常容易,开发者可以随时为 Dubbo 增加更多的协议支持,包括自有协议扩展。 + +关于对 gRPC (HTTP/2) 协议的支持,请参阅上期文档 + +![dubbo-screen.png](/imgs/blog/dubbo-screen.png) + +#### 多协议能解决的问题 + +* 将 RPC 框架无缝地接入 Dubbo 的服务治理体系。 + + 通过协议扩展将 RPC 协议纳入 Dubbo 服务开发体系,从而复用 Dubbo 的编程模型和服务发现、流量管控等能力。比如 gRPC,其服务治理体系相对比较弱、编程 API 不够友好,很难直接用于微服务开发。 + +* 满足不同场景的调用需求。 + + 各个服务可能是为了满足不同业务需求而开发,同时外围消费端应用的技术栈也可能多种多样,通过启用不同的通信协议,可以最优化不同场景的通信需求。 + +* 实现协议间的迁移。 + + 通过支持多种协议,借助注册中心的协调,可以快速满足公司内协议迁移的需求。如从自有协议升级到 Dubbo 协议,Dubbo 协议自身升级,从 Dubbo 协议迁移到 gRPC,从 REST 迁移到 Dubbo 协议等。 + + +### 多注册中心 + +当服务集群规模小的时候,一个中心化的集群部署方案能很好的解决我们的业务问题。但是随着应用规模的增长、用户流量的增加,我们就不得不考虑要为业务系统引入跨区域、多集群的部署方案,而此时同业务系统密切相关的注册中心集群也面临部署方案的选型: + +1. 继续维持全局共享的注册中心集群。这种架构方案的优点是简单;缺点是注册中心集群由于要保存全量的地址数据,存储和推送压力会变得很大,另外对于一些注册中心产品(如 Zookeeper 等)在跨集群网络部署的场景下稳定性和性能可能都会面临挑战。 + +2. 每个业务集群部署独立的注册中心集群。多注册中心集群的优点是能解决跨集群网络可用性的问题,同时也能够减轻注册中心的存储和推送压力;缺点则是要求服务框架(如 Dubbo 等)能有同时发布/监听多个注册中心集群的能力。 + +下面我们具体看一下,Dubbo 为多注册中心集群场景提供的解决方案。 + +![multisubscribe.png](/imgs/blog/multisubscribe.png) + +上图有两个业务集群,分别部署在北京和上海,每个业务集群有自己独立的注册中心集群,要解决两个业务集群间服务的透明 RPC 通信问题。 + +1. 服务提供端,双注册中心发布 + +```xml + + + + + + +``` + +2. 服务消费端,根据消费需求做单/双注册中心订阅 + +```xml + + + + + + + + + + + +``` + +#### Dubbo 对异构注册中心集群的支持 + +虽然我们会做多注册中心集群部署,但通常情况下,我们部署的都是相同的注册中心产品,如都是 Zookeeper、Nacos;而对于注册中心迁移的场景,则要求 Dubbo 能提供对更多的注册中心产品的支持,或者最重要的要有很好的扩展能力。Dubbo 官方目前支持的注册中心实现有: + +![dubbo-screen2.png](/imgs/blog/dubbo-screen2.png) + +这里需要特别提到的一点是,当前 Dubbo 的服务注册/发现模型是以接口为粒度的,而从 2.7.5 版本开始,Dubbo 新引入了应用粒度的服务注册/发现模型。这一方面有助于优化 Dubbo 当前服务发现机制、提升服务容量,另一方面对于联通以 SpringCloud 为代表的微服务体系也非常重要(关于这点在下一章中有进一步提及)。更多关于《应用粒度服务发现:服务自省》的介绍,我们将在接下来的文章或文档中予以补充,请持续关注。 + +#### 多订阅带来的流量调度问题 + +在引入多注册中心集群后,Dubbo 在流量选址时的多了一层注册中心集群间的负载均衡: + +![cluster-lb.png](/imgs/blog/cluster-lb.png) + +在 Cluster Invoker 这一级,我们支持的选址策略有(2.7.5+ 版本,具体使用请参见文档): + +* 指定优先级 + + ```xml + + + ``` + +* 同 zone 优先 + + ```xml + + + ``` + +* 权重轮询 + + ```xml + + + + ``` + +* 默认,stick to 任意可用 + +#### 多注册中心适用的场景 + +* 同区域流量优先调度 + + 出于容灾或者服务伸缩性需求,服务/应用往往需要部署在多个独立的机房/区域,在每个区域有独立注册中心集群的场景下,实现同区域的流量优先调度就能很好的解决延迟和可用性问题。 + +* 注册中心迁移 + + 公司的服务一直以来可能是存储在某一个注册中心,如 Zookeeper,但到了某个时间节点,因为各种各样的原因,当我们要迁移到另外的注册中心时,多注册中心模型能够保证平滑的迁移。 + +* 异构系统互通 + + 不同微服务体系开发的服务,都封闭在各自的服务发现体系中,而通过统一的多注册中心模型,可以实现不同体系的服务互相发现。 + +## 借助 Dubbo 联通异构的微服务体系 + +上文我们提到了在组织内存在异构微服务体系的各种合理可能性,现在我们来具体看一下异构微服务体系的实际场景,以及使用 Dubbo 实现互联互通的解决方法。首先我们先通过一张图来看一下,联通异构的微服务体系具体是一个什么样的场景。 + +![heterogeneous.png](/imgs/blog/heterogeneous.png) + +如上图所示,我们有部分微服务可以是基于 SpringCloud、gRPC、K8S 或者是自建体系构建的,他们各自之间默认是相互隔离无法联通的。当我们再构建一套基于 Dubbo 的微服务体系时,则利用 Dubbo 的多协议、多服务发现模型,我们就可以做到和各个微服务体系间的两两之间的互联互通。进一步的,如图中橙色箭头所示,依赖 Dubbo 体系作为桥接层,我们还可以实现两个异构微服务体系间的打通。 + +对于以下几个示例场景,由于在地址发现层面目前没有统一的标准,我们暂且假设地址发现层面不同的体系建是没有障碍的,我们将重点关注迁移的基本流程以及通信协议环节。(关于地址发现部分,我们将在后续《服务自省:基于应用粒度的服务发现》之后再深入探讨) + +### Dubbo 体系内的协议迁移(共存) + +绝大多数开发者对 Dubbo 有这么一个固有认知:使用 Dubbo 开发微服务系统,则就要用 Dubbo 协议来作为服务间的通信协议才是最优方案。实际上,我们完全没有必要只束缚在 Dubbo RPC 协议上。Dubbo 作为微服务开发框架和 Dubbo 作为 RPC 协议这是两个概念,其实是完全可以分开来看待的,比如我们用 Dubbo 框架开发的业务系统,选用 rest、gRPC 通信是完全没有问题的(参加 Dubbo 支持的协议列表),具体用什么协议根据业务特点和技术规划才是最适合的。 + +![grpcrest.png](/imgs/blog/grpcrest.png) + +当前在云原生、Mesh 的大背景下, HTTP1/2、gRPC 协议开始受到越来越多的关注,一方面原因自然是因为它们在标准化方面做的更好,得到的更多的网络设备和基础设施的支持,具备更好的通用性和穿透性。对于很多有云原生迁移意愿的企业来说,往此类协议迁移无疑将对之后的架构升级有更多的帮助。 + +下图演示了在 Dubbo 体系内,从 Dubbo 协议向 gRPC 协议迁移的一个中间状态。 + +![migrate.png](/imgs/blog/migrate.png) + +* 最左边的代表尚未迁移的老应用,这类应用在迁移过程中仍然要消费和提供 Dubbo 协议的服务。 +* 中间的代表处于迁移中的应用,他们中间可能有些是服务提供者,既要为左边的老系统提供提供 Dubbo 协议服务;又要为右边的新系统提供 gRPC 服务;因此他们都是双协议暴露服务。 +* 最右边则代表是新开发的或者已经迁移完成的应用,这个体系内已能完全用 gRPC 协议通信。 +* 最终度过中间态后,我们期望所有的应用都达到最左边应用的状态,实现完全的 gRPC 协议通信。 + +### Spring Cloud 体系迁移到 Dubbo 体系(共存) + +如前文所述,由于 SpringCloud 和 Dubbo 间服务发现模型的问题,要两个体系间的地址互通需要 Dubbo 侧作相应的适配,关于这部分内容将在接下来的 2.7.5 版本《服务自省》部分发布,在此我们暂且认为已经打通。 + +![migrate-final.png](/imgs/blog/migrate-final.png) + +Dubbo 体系内的部分应用作为透明的联通两个体系的关键节点,部分服务提供者应用要双协议发布、部分消费者应用要做到选定协议消费。由于老的 Spring Cloud 体系不允许做任何改动,因此联通两套体系的关键是 REST 协议,对 Dubbo 侧的应用来说: + +* 部分应用可能要以 REST 协议消费 SpringCloud 的服务; +* 部分应用可能要暴露 REST 协议共 SpringCloud 消费; +* Dubbo 自有体系内则通过自己选定的协议通信,这里就比较灵活了,可以是 Dubbo、REST、gRPC 等其中的任一种。而如果选定 REST 协议则对于与 SpringCloud 体系的联通就变得更加自然了,因为两端的协议都是统一的。 + +对于消费 Spring Cloud 服务的应用,要配置服务 : + +```xml + +``` + +对于提供服务给 Spring Cloud 侧消费的应用,则指定服务暴露为 rest 协议,或者双协议暴露(因如果这个服务还要被新体系内的应用调用到): + +```xml + +``` + +作为 Dubbo 的维护者,虽然我们这里有明显的偏向性,讲的是从如何从 SpringCloud 体系迁移到 Dubbo 体系。但是反过来考虑,如果你已经或者即将选型 Dubbo 来开发微服务,则未来从 Dubbo 迁移到 SpringCloud 也是同样的思路,Dubbo 的多协议、多注册模型为双向迁移都提供了同样的灵活性。 + +### 自建体系迁移到 Dubbo 体系(共存) + +这个场景和上一节中讲到的的 SpringCloud 迁移有些类似,最大的区别在于 rest 协议是 Dubbo 官方默认提供支持的,而对于已有的微服务体系内的私有通信协议,则需要先要自己去扩展 Dubbo Protocol 来提供协议层面的支持。 + +## 总结与展望 + +要实现异构微服务体系间的共存或迁移,关键点在打通异构体系间的`协议`与`服务发现`,得益于 Dubbo 自身对多协议、多注册模型的支持,我们可以很容易的使 Dubbo 成为桥接异构微服务体系的中间层。熟悉 Dubbo 多协议实现细节的同学,可能会担心在服务数量较多的场景下,多协议注册会导致地址数量翻倍从而影响地址推送性能;另外在文中《借助 Dubbo 联通异构的微服务体系》一节,关于如何实现异构体系间的透明服务发现部分我们没有做详细的说明。关于涉及服务发现的这部分,我们将在接下来的文章中做具体阐述,看看 Dubbo 2.7.5 版本引入新的服务发现机制是如何解决这个问题的,请持续关注后续文章及 Dubbo 官方文档。 diff --git a/content/en/blog/java/demos/dubbo-101.md b/content/en/blog/java/demos/dubbo-101.md new file mode 100644 index 000000000000..3dae16e356d3 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-101.md @@ -0,0 +1,383 @@ +--- +title: "第一个 Dubbo 应用" +linkTitle: "第一个 Dubbo 应用" +tags: ["Java"] +slug: dubbo-101 +date: 2018-08-07 +description: > + 现代的分布式服务框架的基本概念与 RMI 是类似的,同样是使用 Java 的 Interface 作为服务契约,通过注册中心来完成服务的注册和发现,远程通讯的细节也是通过代理类来屏蔽。 +--- + +## Java RMI 简介 + +Java RMI (Remote Method Invocation)- 远程方法调用,能够让客户端像使用本地调用一样调用服务端 Java 虚拟机中的对象方法。RMI 是面向对象语言领域对 RPC (Remote Procedure Call)的完善,用户无需依靠 IDL 的帮助来完成分布式调用,而是通过依赖接口这种更简单自然的方式。 + +### Java RMI 工作原理 + +一个典型的 RMI 调用如下图所示: + +1. 服务端向 RMI 注册服务绑定自己的地址, +2. 客户端通过 RMI 注册服务获取目标地址, +3. 客户端调用本地的 Stub 对象上的方法,和调用本地对象上的方法一致, +4. 本地存根对象将调用信息打包,通过网络发送到服务端, +5. 服务端的 Skeleton 对象收到网络请求之后,将调用信息解包, +6. 然后找到真正的服务对象发起调用,并将返回结果打包通过网络发送回客户端。 + +![RMI Flow](/imgs/blog/rmi-flow.png) + +(来源:https://www.cs.rutgers.edu/~pxk/417/notes/images/rpc-rmi_flow.png) + +### Java RMI 基本概念 + +Java RMI 是 Java 领域创建分布式应用的技术基石。后续的 EJB 技术,以及现代的分布式服务框架,其中的基本理念依旧是 Java RMI 的延续。在 RMI 调用中,有以下几个核心的概念: + +1. 通过**接口**进行远程调用 + +2. 通过客户端的 **Stub 对象**和服务端的 **Skeleton 对象**的帮助将远程调用伪装成本地调用 +3. 通过 **RMI 注册服务**完成服务的注册和发现 + +对于第一点,客户端需要依赖接口,而服务端需要提供该接口的实现。 + +对于第二点,在 J2SE 1.5 版本之前需要通过 rmic 预先编译好客户端的 Stub 对象和服务端的 Skeleton 对象。在之后的版本中,不再需要事先生成 Stub 和 Skeleton 对象。 + +下面通过示例代码简单的展示 RMI 中的服务注册和发现 + +#### 服务端的服务注册 + +```java +Hello obj = new HelloImpl(); // #1 +Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0); // #2 +Registry registry = LocateRegistry.createRegistry(1099); // #3 +registry.rebind("Hello", stub); // #4 +``` + +说明: + +1. 初始化服务对象实例, +2. 通过 *UnicastRemoteObject.exportObject* 生成可以与服务端通讯的 Stub 对象, +3. 创建一个本地的 RMI 注册服务,监听端口为 1099。该注册服务运行在服务端,也可以单独启动一个注册服务的进程, +4. 将 Stub 对象绑定到注册服务上,这样,客户端可以通过 *Hello* 这个名字查找到该远程对象。 + +#### 客户端的服务发现 + +```java +Registry registry = LocateRegistry.getRegistry(); // #1 +Hello stub = (Hello) registry.lookup("Hello"); // #2 +String response = stub.sayHello(); // #3 +``` + +说明: + +1. 获取注册服务实例,在本例中,由于没有传入任何参数,假定要获取的注册服务实例部署在本机,并监听在 1099 端口上, +2. 从注册服务中查找服务名为 *Hello* 的远程对象, +3. 通过获取的 Stub 对象发起一次 RMI 调用并获得结果。 + +理解 RMI 的工作原理和基本概念,对掌握现代分布式服务框架很有帮助,建议进一步的阅读 RMI 官方教材 [^1]。 + +## Dubbo 基本概念 + +现代的分布式服务框架的基本概念与 RMI 是类似的,同样是使用 Java 的 Interface 作为服务契约,通过注册中心来完成服务的注册和发现,远程通讯的细节也是通过代理类来屏蔽。具体来说,Dubbo 在工作时有以下四个角色参与: + +1. 服务提供者 - 启动时在指定端口上暴露服务,并将服务地址和端口注册到注册中心上 +2. 服务消费者 - 启动时向注册中心订阅自己感兴趣的服务,以便获得服务提供方的地址列表 +3. 注册中心 - 负责服务的注册和发现,负责保存服务提供方上报的地址信息,并向服务消费方推送 +4. 监控中心 - 负责收集服务提供方和消费方的运行状态,比如服务调用次数、延迟等,用于监控 +5. 运行容器 - 负责服务提供方的初始化、加载以及运行的生命周期管理 + +![dubbo-architecture](/imgs/blog/dubbo-architecture.png) + + + +**部署阶段** + +* 服务提供者在指定端口暴露服务,并向注册中心注册服务信息。 +* 服务消费者向注册中心发起服务地址列表的订阅。 + +**运行阶段** + +* 注册中心向服务消费者推送地址列表信息。 +* 服务消费者收到地址列表后,从其中选取一个向目标服务发起调用。 +* 调用过程服务消费者和服务提供者的运行状态上报给监控中心。 + +## 基于 API 的 Dubbo 应用 + +Dubbo 的应用一般都是通过 Spring 来组装的。为了快速获得一个可以工作的 Dubbo 应用,这里的示例摒弃了复杂的配置,而改用面向 Dubbo API 的方式来构建服务提供者和消费者,另外,注册中心和监控中心在本示例中也不需要安装和配置。 + +在生产环境,Dubbo 的服务需要一个分布式的服务注册中心与之配合,比如,ZooKeeper。为了方便开发,Dubbo 提供了直连[^2]以及组播[^3]两种方式,从而避免额外搭建注册中心的工作。在本例中,将使用组播的方式来完成服务的注册和发现。 + +### 定义服务契约 + +```java +public interface GreetingsService { + String sayHi(String name); // #1 +} +``` + +**说明**: + +1. 定义了一个简单的服务契约 *GreetingsService*,其中只有一个方法 *sayHi* 可供调用,入参是 *String* 类型,返回值也是 *String* 类型。 + +### 提供契约的实现 + +```java +public class GreetingsServiceImpl implements GreetingsService { // #1 + @Override + public String sayHi(String name) { + return "hi, " + name; // #2 + } +} +``` + +**说明**: + +1. 服务提供者需要实现服务契约 *GreetingsService* 接口。 +2. 该实现简单的返回一个欢迎信息,如果入参是 *dubbo*,则返回 *hi, dubbo*。 + +### 实现 Dubbo 服务提供方 + +```java +public class Application { + public static void main(String[] args) throws IOException { + ServiceConfig service = new ServiceConfig<>(); // #1 + service.setApplication(new ApplicationConfig("first-dubbo-provider")); // #2 + service.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234")); // #3 + service.setInterface(GreetingsService.class); // #4 + service.setRef(new GreetingsServiceImpl()); // #5 + service.export(); // #6 + System.in.read(); // #7 + } +} +``` + +**说明**: + +1. 创建一个 *ServiceConfig* 的实例,泛型参数信息是服务接口类型,即 *GreetingsService*。 +2. 生成一个 *ApplicationConfig* 的实例,并将其装配进 *ServiceConfig*。 +3. 生成一个 *RegistryConfig* 实例,并将其装配进 *ServiceConfig*,这里使用的是组播方式,参数是 `multicast://224.5.6.7:1234`。合法的组播地址范围为:*224.0.0.0 - 239.255.255.255* +4. 将服务契约 *GreetingsService* 装配进 *ServiceConfig*。 +5. 将服务提供者提供的实现 *GreetingsServiceImpl* 的实例装配进 *ServiceConfig*。 +6. *ServiceConfig* 已经具备足够的信息,开始对外暴露服务,默认监听端口是 *20880*。 +7. 为了防止服务端退出,按任意键或者 *ctrl-c* 退出。 + +### 实现 Dubbo 服务调用方 + +```java +public class Application { + public static void main(String[] args) { + ReferenceConfig reference = new ReferenceConfig<>(); // #1 + reference.setApplication(new ApplicationConfig("first-dubbo-client")); // #2 + reference.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234")); // #3 + reference.setInterface(GreetingsService.class); // #4 + GreetingsService greetingsService = reference.get(); // #5 + String message = greetingsService.sayHi("dubbo"); // #6 + System.out.println(message); // #7 + } +} +``` + +**说明**: + +1. 创建一个 *ReferenceConfig* 的实例,同样,泛型参数信息是服务接口类型,即 *GreetingService*。 +2. 生成一个 *ApplicationConfig* 的实例,并将其装配进 *ReferenceConfig*。 +3. 生成一个 *RegistryConfig* 实例,并将其装配进 *ReferenceConfig*,注意这里的组播地址信息需要与服务提供方的相同。 +4. 将服务契约 *GreetingsService* 装配进 *ReferenceConfig*。 +5. 从 *ReferenceConfig* 中获取到 *GreetingService* 的代理。 +6. 通过 *GreetingService* 的代理发起远程调用,传入的参数为 *dubbo*。 +7. 打印返回结果 *hi, dubbo*。 + +### 运行 + +完整的示例在 https://github.com/apache/dubbo-samples/tree/master/1-basic/dubbo-samples-api 上提供。在完整的示例中,由于配置了 *exec-maven-plugin*,可以很方便的在命令行下通过 maven 的方式执行。当然,您也可以在 IDE 里直接执行,但是需要注意的是,由于使用了组播的方式来发现服务,运行时需要指定 *-Djava.net.preferIPv4Stack=true*。 + +#### 构建示例 + +通过以下的命令来同步示例代码并完成构建: + +1. 同步代码:git clone https://github.com/apache/dubbo-samples.git +2. 构建:mvn clean package + +```bash +$ git clone https://github.com/apache/dubbo-samples.git +$ cd dubbo-samples/java/dubbo-samples-api/ +$ mvn clean package +INFO] Scanning for projects... +[INFO] +[INFO] ------------------------------------------------------------------------ +[INFO] Building dubbo-samples-api 1.0-SNAPSHOT +[INFO] ------------------------------------------------------------------------ +[INFO] +[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ dubbo-samples-api --- +... +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 2.182 s +[INFO] Finished at: 2018-05-28T14:56:08+08:00 +[INFO] Final Memory: 20M/353M +[INFO] ------------------------------------------------------------------------ +``` + +当看到 *BUILD SUCCESS* 的时候表明构建完成,下面就可以开始进入运行阶段了。 + +#### 运行服务端 + +通过运行以下的 maven 命令来启动服务提供者: + +```bash +$ mvn -Djava.net.preferIPv4Stack=true -Dexec.mainClass=com.alibaba.dubbo.samples.server.Application exec:java +[INFO] Scanning for projects... +[INFO] +[INFO] ------------------------------------------------------------------------ +[INFO] Building dubbo-samples-api 1.0-SNAPSHOT +[INFO] ------------------------------------------------------------------------ +[INFO] +[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ dubbo-samples-api --- +log4j:WARN No appenders could be found for logger (com.alibaba.dubbo.common.logger.LoggerFactory). +log4j:WARN Please initialize the log4j system properly. +log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. +first-dubbo-provider is running. +``` + +当 *first-dubbo-provider is running.* 出现时,代表服务提供者已经启动就绪,等待客户端的调用。 + +#### 运行客户端 + +通过运行以下的 maven 命令来调用服务: + +```bash +$ mvn -Djava.net.preferIPv4Stack=true -Dexec.mainClass=com.alibaba.dubbo.samples.client.Application exec:java +[INFO] Scanning for projects... +[INFO] +[INFO] ------------------------------------------------------------------------ +[INFO] Building dubbo-samples-api 1.0-SNAPSHOT +[INFO] ------------------------------------------------------------------------ +[INFO] +[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ dubbo-samples-api --- +log4j:WARN No appenders could be found for logger (com.alibaba.dubbo.common.logger.LoggerFactory). +log4j:WARN Please initialize the log4j system properly. +log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. +hi, dubbo +``` + +可以看到, *hi, dubbo* 是从服务提供者返回的执行结果。 + +## 快速生成 Dubbo 应用 + +Dubbo 还提供了一个公共服务快速搭建基于 Spring Boot 的 Dubbo 应用。访问 http://start.dubbo.io 并按照下图所示来生成示例工程: + +![dubbo initializr](/imgs/blog/dubbo-initializr.png) + +**说明**: + +1. 在 *Group* 中提供 maven groupId,默认值是 *com.example*。 +2. 在 *Artifact* 中提供 maven artifactId,默认值是 *demo*。 +3. 在 *DubboServiceName* 中提供服务名,默认值是 *com.example.HelloService*。 +4. 在 *DubboServiceVersion* 中提供服务的版本,默认值是 *1.0.0*。 +5. 在 *Client/Server* 中选取本次构建的工程是服务提供者 (Server) 还是服务消费者 (Client),默认值是 *server*。 +6. 使用 *embeddedZookeeper* 作为服务注册发现,默认为勾选。 +7. 是否激活 qos 端口,默认为不勾选,如果勾选可以通过 *22222* 端口访问。 +8. 点击 *Generate Project* 即可下载生成好的工程。 + +在本例中展示的是服务提供者,同样的,通过在生成界面选取 *client* 来生成对应的服务消费者。 + +### 运行 + +用 IDE 打开生成好的工程,可以发现应用是一个典型的 Spring Boot 应用。程序的入口如下所示: + +```java +@SpringBootApplication +public class DemoApplication { + public static void main(String[] args) { + new EmbeddedZooKeeper(2181, false).start(); // #1 + SpringApplication.run(DemoApplication.class, args); // #2 + } +} +``` + +**说明**: + +1. 在 *2181* 端口上启动嵌入式 *ZooKeeper*。 +2. 启动 *Spring Boot* 上下文。 + +可以直接在 IDE 中运行,输出结果如下: + +```bash +2018-05-28 16:59:38.072 INFO 59943 --- [ main] a.b.d.c.e.WelcomeLogoApplicationListener : + + ████████▄ ███ █▄ ▀█████████▄ ▀█████████▄ ▄██████▄ + ███ ▀███ ███ ███ ███ ███ ███ ███ ███ ███ + ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ + ███ ███ ███ ███ ▄███▄▄▄██▀ ▄███▄▄▄██▀ ███ ███ + ███ ███ ███ ███ ▀▀███▀▀▀██▄ ▀▀███▀▀▀██▄ ███ ███ + ███ ███ ███ ███ ███ ██▄ ███ ██▄ ███ ███ + ███ ▄███ ███ ███ ███ ███ ███ ███ ███ ███ + ████████▀ ████████▀ ▄█████████▀ ▄█████████▀ ▀██████▀ + + + :: Dubbo Spring Boot (v0.1.0) : https://github.com/dubbo/dubbo-spring-boot-project + :: Dubbo (v2.0.1) : https://github.com/alibaba/dubbo + :: Google group : http://groups.google.com/group/dubbo + +2018-05-28 16:59:38.079 INFO 59943 --- [ main] e.OverrideDubboConfigApplicationListener : Dubbo Config was overridden by externalized configuration {dubbo.application.name=dubbo-demo-server, dubbo.application.qosAcceptForeignIp=false, dubbo.application.qosEnable=true, dubbo.application.qosPort=22222, dubbo.registry.address=zookeeper://localhost:2181?client=curator, dubbo.registry.id=my-registry, dubbo.scan.basePackages=com.example} #1 + +... + +2018-05-28 16:59:39.624 INFO 59943 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 1.746 seconds (JVM running for 2.963) +``` + +**说明**: + +1. 输出中打印的以 *dubbo.* 开头的配置信息,定义在 *main/resources/application.properties* 中。 + +### 通过 Telnet 管理服务 + +生成工程的时候如果选择了激活 *qos* 的话,就可以通过 *telnet* 或者 *nc* 来管理服务、查看服务状态。 + +```bash +$ telnet localhost 22222 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ████████▄ ███ █▄ ▀█████████▄ ▀█████████▄ ▄██████▄ + ███ ▀███ ███ ███ ███ ███ ███ ███ ███ ███ + ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ + ███ ███ ███ ███ ▄███▄▄▄██▀ ▄███▄▄▄██▀ ███ ███ + ███ ███ ███ ███ ▀▀███▀▀▀██▄ ▀▀███▀▀▀██▄ ███ ███ + ███ ███ ███ ███ ███ ██▄ ███ ██▄ ███ ███ + ███ ▄███ ███ ███ ███ ███ ███ ███ ███ ███ + ████████▀ ████████▀ ▄█████████▀ ▄█████████▀ ▀██████▀ + + +dubbo> +dubbo>ls +As Provider side: ++------------------------------+---+ +| Provider Service Name |PUB| ++------------------------------+---+ +|com.example.HelloService:1.0.0| Y | ++------------------------------+---+ +As Consumer side: ++---------------------+---+ +|Consumer Service Name|NUM| ++---------------------+---+ +``` + +目前 *qos* 支持以下几个命令,更详细的信息请查阅官方文档[^4]: + +* *ls*:列出消费者、提供者信息 +* *online*:上线服务 +* *offline*:下线服务 +* *help*:联机帮助 + +## 总结 + +在本文中,从 RMI 开始,介绍了 Java 领域分布式调用的基本概念,也就是基于接口编程、通过代理将远程调用伪装成本地、通过注册中心完成服务的注册和发现。 + +然后为了简单起见,使用简单的组播注册方式和直接面向 Dubbo API 编程的方式介绍了如何开发一个 Dubbo 的完整应用。深入的了解 *ServiceConfig* 和 *ReferenceConfig* 的用法,对于进一步的使用 Spring XML 配置、乃至 Spring Boot 的编程方式有这很大的帮助。 + +最后,简单的介绍了如何通过 Dubbo 团队提供的公共服务 start.dubbo.io 快速搭建基于 Spring Boot 的 Dubbo 应用,并通过 *qos* 来做 Dubbo 服务的简单运维。 + +[^1]: [Getting Started Using JavaTM RMI](https://docs.oracle.com/javase/6/docs/technotes/guides/rmi/hello/hello-world.html) +[^2]: [直连提供者](/en/docsv2.7/user/examples/explicit-target/) +[^3]: [Multicast 注册中心](/en/docsv2.7/user/references/registry/multicast/) +[^4]: [在线运维命令](/en/docsv2.7/user/references/qos/) diff --git a/content/en/blog/java/demos/dubbo-27-features.md b/content/en/blog/java/demos/dubbo-27-features.md new file mode 100644 index 000000000000..56b4089afd1a --- /dev/null +++ b/content/en/blog/java/demos/dubbo-27-features.md @@ -0,0 +1,231 @@ +--- +title: "Dubbo2.7 三大新特性详解" +linkTitle: "Dubbo2.7 三大新特性详解" +tags: ["Java"] +date: 2018-08-15 +description: > + 异步化改造,三大中心改造,服务治理增强 +--- + +## 1 背景介绍 + +自 2017 年 7 月阿里重启 Dubbo 开源,到目前为止 github star 数,contributor 数都有了非常大的提升。2018 年 2 月 9 日阿里决定将 Dubbo 项目贡献给 Apache,经过一周的投票,顺利成为了 Apache 的孵化项目,也就是大家现在看到的 **Incubator Dubbo**。预计在 2019 年 4 月,Dubbo 可以达成毕业,成为 Apache 的顶级项目。 + +## 2 分支介绍 + +![分支](/imgs/blog/270/branches.png) + +Dubbo 目前有如图所示的 5 个分支,其中 2.7.1-release 只是一个临时分支,忽略不计,对其他 4 个分支进行介绍。 + +- 2.5.x 近期已经通过投票,Dubbo 社区即将停止对其的维护。 +- 2.6.x 为长期支持的版本,也是 Dubbo 贡献给 Apache 之前的版本,其包名前缀为:com.alibaba,JDK 版本对应 1.6。 +- 3.x-dev 是前瞻性的版本,对 Dubbo 进行一些高级特性的补充,如支持 rx 特性。 +- master 为长期支持的版本,版本号为 2.7.x,也是 Dubbo 贡献给 Apache 的开发版本,其包名前缀为:org.apache,JDK 版本对应 1.8。 + +> 如果想要研究 Dubbo 的源码,建议直接浏览 master 分支。 + +## 3 Dubbo 2.7 新特性 + +Dubbo 2.7.x 作为 Apache 的孵化版本,除了代码优化之外,还新增了许多重磅的新特性,本文将会介绍其中最典型的三个新特性: + +- 异步化改造 +- 三大中心改造 +- 服务治理增强 + +## 4 异步化改造 + +### 4.1 几种调用方式 + +![调用方式](/imgs/blog/270/invokes.png) + +在远程方法调用中,大致可以分为这 4 种调用方式。oneway 指的是客户端发送消息后,不需要接受响应。对于那些不关心服务端响应的请求,比较适合使用 oneway 通信。 + +> 注意,void hello() 方法在远程方法调用中,不属于 oneway 调用,虽然 void 方法表达了不关心返回值的语义,但在 RPC 层面,仍然需要做通信层的响应。 + +sync 是最常用的通信方式,也是默认的通信方法。 + +future 和 callback 都属于异步调用的范畴,他们的区别是:在接收响应时,future.get() 会导致线程的阻塞;callback 通常会设置一个回调线程,当接收到响应时,自动执行,不会对当前线程造成阻塞。 + +### 4.2 Dubbo 2.6 异步化 + +异步化的优势在于客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小。介绍 2.7 中的异步化改造之前,先回顾一下如何在 2.6 中使用 Dubbo 异步化的能力。 + +1. 将同步接口声明成 `async=true` + ```xml + + ``` + ```java + public interface AsyncService { + String sayHello(String name); + } + ``` +2. 通过上下文类获取 future + ```java + AsyncService.sayHello("Han Meimei"); + Future fooFuture = RpcContext.getContext().getFuture(); + fooFuture.get(); + ``` + +可以看出,这样的使用方式,不太符合异步编程的习惯,竟然需要从一个上下文类中获取到 Future。如果同时进行多个异步调用,使用不当很容易造成上下文污染。而且,Future 并不支持 callback 的调用方式。这些弊端在 Dubbo 2.7 中得到了改进。 + +### 4.3 Dubbo 2.7 异步化 + +1. 无需配置中特殊声明,显式声明异步接口即可 + ```java + public interface AsyncService { + String sayHello(String name); + default CompletableFuture sayHiAsync(String name) { + return CompletableFuture.completedFuture(sayHello(name)); + } + } + ``` +2. 使用 callback 方式处理返回值 + ```java + CompletableFuture future = asyncService.sayHiAsync("Han MeiMei"); + future.whenComplete((retValue, exception) -> { + if (exception == null) { + System.out.println(retValue); + } else { + exception.printStackTrace(); + } + }); + ``` + +Dubbo 2.7 中使用了 JDK1.8 提供的 `CompletableFuture` 原生接口对自身的异步化做了改进。`CompletableFuture` 可以支持 future 和 callback 两种调用方式,用户可以根据自己的喜好和场景选择使用,非常灵活。 + +### 4.4 异步化设计 FAQ + +Q:如果 RPC 接口只定义了同步接口,有办法使用异步调用吗? + +A:2.6 中的异步调用唯一的优势在于,不需要在接口层面做改造,又可以进行异步调用,这种方式仍然在 2.7 中保留;使用 Dubbo 官方提供的 compiler hacker,编译期自动重写同步方法,请[在此](https://github.com/dubbo/dubbo-async-processor#compiler-hacker-processer)讨论和跟进具体进展。 + +--- + +Q:关于异步接口的设计问题,为何不提供编译插件,根据原接口,自动编译出一个 XxxAsync 接口? + +A:Dubbo 2.7 采用过这种设计,但接口的膨胀会导致服务类的增量发布,而且接口名的变化会影响服务治理的一些相关逻辑,改为方法添加 Async 后缀相对影响范围较小。 + +--- + +Q:Dubbo 分为了客户端异步和服务端异步,刚刚你介绍的是客户端异步,为什么不提服务端异步呢? + +A:Dubbo 2.7 新增了服务端异步的支持,但实际上,Dubbo 的业务线程池模型,本身就可以理解为异步调用,个人认为服务端异步的特性较为鸡肋。 + +## 5 三大中心改造 + +三大中心指的:注册中心,元数据中心,配置中心。 + +在 2.7 之前的版本,Dubbo 只配备了注册中心,主流使用的注册中心为 zookeeper。新增加了元数据中心和配置中心,自然是为了解决对应的痛点,下面我们来详细阐释三大中心改造的原因。 + +### 5.1 元数据改造 + +元数据是什么?元数据定义为描述数据的数据,在服务治理中,例如服务接口名,重试次数,版本号等等都可以理解为元数据。在 2.7 之前,元数据一股脑丢在了注册中心之中,这造成了一系列的问题: + +**推送量大 -> 存储数据量大 -> 网络传输量大 -> 延迟严重** + +生产者端注册 30+ 参数,有接近一半是不需要作为注册中心进行传递;消费者端注册 25+ 参数,只有个别需要传递给注册中心。有了以上的理论分析,Dubbo 2.7 进行了大刀阔斧的改动,只将真正属于服务治理的数据发布到注册中心之中,大大降低了注册中心的负荷。 + +同时,将全量的元数据发布到另外的组件中:元数据中心。元数据中心目前支持 redis(推荐),zookeeper。这也为 Dubbo 2.7 全新的 Dubbo Admin 做了准备,关于新版的 Dubbo Admin,我将会后续准备一篇独立的文章进行介绍。 + +示例:使用 zookeeper 作为元数据中心 + +```xml + +``` + +### 5.2 Dubbo 2.6 元数据 + +```shell +dubbo://30.5.120.185:20880/com.alibaba.dubbo.demo.DemoService? +anyhost=true& +application=demo-provider& +interface=com.alibaba.dubbo.demo.DemoService& +methods=sayHello& +bean.name=com.alibaba.dubbo.demo.DemoService& +dubbo=2.0.2& +executes=4500& +generic=false& +owner=kirito& +pid=84228& +retries=7& +side=provider& +timestamp=1552965771067 +``` + +从本地的 zookeeper 中取出一条服务数据,通过解码之后,可以看出,的确有很多参数是不必要。 + +### 5.3 Dubbo 2.7 元数据 + +在 2.7 中,如果不进行额外的配置,zookeeper 中的数据格式仍然会和 Dubbo 2.6 保持一致,这主要是为了保证兼容性,让 Dubbo 2.6 的客户端可以调用 Dubbo 2.7 的服务端。如果整体迁移到 2.7,则可以为注册中心开启简化配置的参数: + +```xml + +``` + +Dubbo 将会只上传那些必要的服务治理数据,一个简化过后的数据如下所示: + +```shell +dubbo://30.5.120.185:20880/org.apache.dubbo.demo.api.DemoService? +application=demo-provider& +dubbo=2.0.2& +release=2.7.0& +timestamp=1552975501873 +``` + +对于那些非必要的服务信息,仍然全量存储在元数据中心之中: + +![元数据](/imgs/blog/270/metadata.png) + +> 元数据中心的数据可以被用于服务测试,服务 MOCK 等功能。目前注册中心配置中 simplified 的默认值为 false,因为考虑到了迁移的兼容问题,在后续迭代中,默认值将会改为 true。 + +### 5.4 配置中心支持 + +衡量配置中心的必要性往往从三个角度出发: + +1. 分布式配置统一管理 + +2. 动态变更推送 + +3. 安全性 + +Spring Cloud Config, Apollo, Nacos 等分布式配置中心组件都对上述功能有不同程度的支持。在 2.7 之前的版本中,在 zookeeper 中设置了部分节点:configurators,routers,用于管理部分配置和路由信息,它们可以理解为 Dubbo 配置中心的雏形。在 2.7 中,Dubbo 正式支持了配置中心,目前支持的几种注册中心 Zookeeper,Apollo,Nacos(2.7.1-release 支持)。 + +在 Dubbo 中,配置中心主要承担了两个作用 + +- 外部化配置。启动配置的集中式存储 + +- 服务治理。服务治理规则的存储与通知 + +示例:使用 Zookeeper 作为配置中心 + +```xml + +``` + +引入配置中心后,需要注意配置项的覆盖问题,优先级如图所示 + +![配置覆盖优先级](/imgs/blog/configuration.jpg) + +## 6 服务治理增强 + +我更倾向于将 Dubbo 当做一个服务治理框架,而不仅仅是一个 RPC 框架。在 2.7 中,Dubbo 对其服务治理能力进行了增强,增加了标签路由的能力,并抽象出了应用路由和服务路由的概念。在最后一个特性介绍中,着重对标签路由 TagRouter 进行探讨。 + +> 在服务治理中,路由层和负载均衡层的对比。区别 1,Router:m 选 n,LoadBalance:n 选 1;区别 2,路由往往是叠加使用的,负载均衡只能配置一种。 + +在很长的一段时间内,Dubbo 社区经常有人提的一个问题是:Dubbo 如何实现流量隔离和灰度发布,直到 2.7 提供了标签路由,用户可以使用这个功能,来实现上述的需求。 + +![标签路由](/imgs/blog/270/tag-route.png) + +标签路由提供了这样一个能力,当调用链路为 A -> B -> C -> D 时,用户给请求打标,最典型的打标方式可以借助 attachment(他可以在分布式调用中传递下去),调用会优先请求那些匹配的服务端,如 A -> B,C -> D,由于集群中未部署 C 节点,则会降级到普通节点。 + +打标方式会受到集成系统差异的影响,从而导致很大的差异,所以 Dubbo 只提供了 `RpcContext.getContext().setAttachment()` 这样的基础接口,用户可以使用 SPI 扩展,或者 server filter 的扩展,对测试流量进行打标,引导进入隔离环境/灰度环境。 + +新版的 Dubbo Admin 提供了标签路由的配置项: + +![标签路由配置](/imgs/blog/270/tag-route-config.png) + +Dubbo 用户可以在自己系统的基础上对标签路由进行二次扩展,或者借鉴标签路由的设计,实现自己系统的流量隔离,灰度发布。 + +## 7 总结 + +本文介绍了 Dubbo 2.7 比较重要的三大新特性:异步化改造,三大中心改造,服务治理增强。Dubbo 2.7 还包含了很多功能优化、特性升级,可以在项目源码的 [CHANGES.md](https://github.com/apache/dubbo/blob/master/CHANGES.md) 中浏览全部的改动点。最后提供一份 Dubbo 2.7 的升级文档:[2.7迁移文档](/en/docsv2.7/user/versions/version-270/),欢迎体验。 diff --git a/content/en/blog/java/demos/dubbo-annotation-driven.md b/content/en/blog/java/demos/dubbo-annotation-driven.md new file mode 100644 index 000000000000..c10702566b43 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-annotation-driven.md @@ -0,0 +1,764 @@ +--- +title: "Dubbo 注解驱动" +linkTitle: "Dubbo 注解驱动" +tags: ["Java"] +date: 2018-08-07 +description: > + 介绍了 Dubbo 中新引入的注解驱动支持 +--- + +## 注解驱动(Annotation-Driven) + +### `@DubboComponentScan` + +#### 起始版本: `2.5.7` + +#### ` `历史遗留问题 + +##### 1. 注解支持不充分 + +在 Dubbo `2.5.7`之前的版本 ,Dubbo 提供了两个核心注解 `@Service` 以及 `@Reference`,分别用于Dubbo 服务提供和 Dubbo 服务引用。 + +其中,`@Service` 作为 XML 元素 ``的替代注解,与 Spring Framework `@org.springframework.stereotype.Service` 类似,用于服务提供方 Dubbo 服务暴露。与之相对应的`@Reference`,则是替代` + + + + + + + +``` + +##### 2. `@Service` Bean 不支持 Spring AOP + +同时,使用 ` ` 方式扫描后的Dubbo `@Service` ,在 Spring 代理方面存在问题,如 GitHub 上的 issue https://github.com/alibaba/dubbo/issues/794: + +> 关于dubbo @Service注解生成ServiceBean时, interface获取成spring 的代理对象的bug +> +> >在项目里, 我使用了 +> > +> >```java +> >@Service +> >@Transactional +> >@com.alibaba.dubbo.config.annotation.Service +> >public class SUserJpushServiceImp +> >``` +> > +> >的形式, 来暴露服务。但是在发布服务的时候, interface class 是通过 +> >`` +> >serviceConfig.setInterface(bean.getClass().getInterfaces()[0]); +> >`` +> >的形式获取, 刚好, 我的service都使用了@Transactional注解, 对象被代理了。所以获取到的interface是Spring的代理接口... + +不少热心的小伙伴不仅发现这个历史遗留问题,而且提出了一些修复方案。同时,为了更好地适配 Spring 生命周期以及将 Dubbo 完全向注解驱动编程模型过渡,因此,引入了全新 Dubbo 组件扫描注解 - `@DubboComponentScan`。 + +> 注: ` ` Spring AOP 问题将在 `2.5.9` 中修复:https://github.com/alibaba/dubbo/issues/1125 + +##### 3. @Reference 不支持字段继承性 + +假设有一个 Spring Bean `AnnotationAction` 直接通过字段`annotationService` 标记 `@Reference` 引用 `AnnotationService` : + +```java +package com.alibaba.dubbo.examples.annotation.action; + +import com.alibaba.dubbo.config.annotation.Reference; +import com.alibaba.dubbo.examples.annotation.api.AnnotationService; +import org.springframework.stereotype.Component; + + +@Component("annotationAction") +public class AnnotationAction { + + @Reference + private AnnotationService annotationService; + + public String doSayHello(String name) { + return annotationService.sayHello(name); + } + +} +``` + +当`AnnotationAction` 被 XML 元素 `` 扫描后: + +```xml + +``` + +字段 `annotationService` 能够引用到 `AnnotationService`,执行 `doSayHello` 方法能够正常返回。 + +如果将字段`annotationService` 抽取到`AnnotationAction` 的父类`BaseAction` 后,`AnnotationService` 无法再被引用,改造如下所示: + +`AnnotationAction.java` + +```java +@Component("annotationAction") +public class AnnotationAction extends BaseAction { + + public String doSayHello(String name) { + return getAnnotationService().sayHello(name); + } + +} +``` + +`BaseAction.java` + +```java +public abstract class BaseAction { + + @Reference + private AnnotationService annotationService; + + protected AnnotationService getAnnotationService() { + return annotationService; + } +} +``` + + + +改造后,再次执行 `doSayHello` 方法,`NullPointerException` 将会被抛出。说明`` 并不支持`@Reference` 字段继承性。 + + + +了解了历史问题,集合整体愿景,下面介绍`@DubboComponentScan` 的设计原则。 + + + + + + + +#### 设计原则 + + + + + +Spring Framework 3.1 引入了新 Annotation - `@ComponentScan` , 完全替代了 XML 元素 ` ` 。同样, `@DubboComponentScan` 作为 Dubbo `2.5.7` 新增的 Annotation,也是XML 元素 `` 的替代方案。 + + + +在命名上(类名以及属性方法),为了简化使用和关联记忆,Dubbo 组件扫描 Annotation `@DubboComponentScan`,借鉴了 Spring Boot 1.3 引入的 `@ServletComponentScan`。定义如下: + +```java +public @interface DubboComponentScan { + + /** + * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation + * declarations e.g.: {@code @DubboComponentScan("org.my.pkg")} instead of + * {@code @DubboComponentScan(basePackages="org.my.pkg")}. + * + * @return the base packages to scan + */ + String[] value() default {}; + + /** + * Base packages to scan for annotated @Service classes. {@link #value()} is an + * alias for (and mutually exclusive with) this attribute. + *

+ * Use {@link #basePackageClasses()} for a type-safe alternative to String-based + * package names. + * + * @return the base packages to scan + */ + String[] basePackages() default {}; + + /** + * Type-safe alternative to {@link #basePackages()} for specifying the packages to + * scan for annotated @Service classes. The package of each class specified will be + * scanned. + * + * @return classes from the base packages to scan + */ + Class[] basePackageClasses() default {}; + +} +``` + + + +> 注意:`basePackages()` 和 `value()` 均能支持占位符(placeholder)指定的包名 + + + +在职责上,`@DubboComponentScan` 相对于 Spring Boot `@ServletComponentScan` 更为繁重,原因在于处理 Dubbo `@Service` 类暴露 Dubbo 服务外,还有帮助 Spring Bean `@Reference`字段或者方法注入 Dubbo 服务代理。 + + + + 在场景上,Spring Framework `@ComponentScan` 组件扫描逻辑更为复杂。而在 `@DubboComponentScan` 只需关注 `@Service` 和 `@Reference` 处理。 + + + +在功能上, `@DubboComponentScan` 不但需要提供完整 Spring AOP 支持的能力,而且还得具备`@Reference ` 字段可继承性的能力。 + + + +了解基本设计原则后,下面通过完整的示例,简介`@DubboComponentScan` 使用方法以及注意事项。 + + + + + + + +#### 使用方法 + + + +后续通过服务提供方(`@Serivce`)以及服务消费方(`@Reference`)两部分来介绍`@DubboComponentScan` 使用方法。 + + + +假设,服务提供方和服务消费分均依赖服务接口`DemoService`: + +```java +package com.alibaba.dubbo.demo; + +public interface DemoService { + + String sayHello(String name); + +} +``` + + + + + +##### 服务提供方(`@Serivce`) + + + +###### 实现 `DemoService` + + + +服务提供方实现`DemoService` - `AnnotationDemoService` ,同时标注 Dubbo `@Service` : + +```java +package com.alibaba.dubbo.demo.provider; + +import com.alibaba.dubbo.config.annotation.Service; +import com.alibaba.dubbo.demo.DemoService; + +/** + * Annotation {@link DemoService} 实现 + * + * @author Mercy + */ +@Service +public class AnnotationDemoService implements DemoService { + + @Override + public String sayHello(String name) { + return "Hello , " + name; + } + +} +``` + + + + + +###### 服务提供方 Annotation 配置 + + + +将 `AnnotationDemoService` 暴露成Dubbo 服务,需要依赖 Spring Bean:`ApplicationConfig`、`ProtocolConfig` 以及 `RegistryConfig` 。这三个 Spring Bean 过去可通过 XML 文件方式组装 Spring Bean: + +```xml + + + + + + + + + + + +``` + + + +以上装配方式不予推荐,推荐使用 Annotation 配置,因此可以换成 Spring `@Configuration` Bean 的形式: + +```java +package com.alibaba.dubbo.demo.config; + +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.ProtocolConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 服务提供方配置 + * + * @author Mercy + */ +@Configuration +@DubboComponentScan("com.alibaba.dubbo.demo.provider") // 扫描 Dubbo 组件 +public class ProviderConfiguration { + + /** + * 当前应用配置 + */ + @Bean("dubbo-annotation-provider") + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("dubbo-annotation-provider"); + return applicationConfig; + } + + /** + * 当前连接注册中心配置 + */ + @Bean("my-registry") + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("N/A"); + return registryConfig; + } + + /** + * 当前连接注册中心配置 + */ + @Bean("dubbo") + public ProtocolConfig protocolConfig() { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.setName("dubbo"); + protocolConfig.setPort(12345); + return protocolConfig; + } +} +``` + + + + + +###### 服务提供方引导类 + + + +```java +package com.alibaba.dubbo.demo.bootstrap; + +import com.alibaba.dubbo.demo.DemoService; +import com.alibaba.dubbo.demo.config.ProviderConfiguration; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * 服务提供方引导类 + * + * @author Mercy + */ +public class ProviderBootstrap { + + public static void main(String[] args) { + // 创建 Annotation 配置上下文 + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + // 注册配置 Bean + context.register(ProviderConfiguration.class); + // 启动上下文 + context.refresh(); + // 获取 DemoService Bean + DemoService demoService = context.getBean(DemoService.class); + // 执行 sayHello 方法 + String message = demoService.sayHello("World"); + // 控制台输出信息 + System.out.println(message); + } + +} +``` + + + +`ProviderBootstrap` 启动并执行后,控制输出与预期一致: + +``` +Hello , World +``` + + + +以上直接结果说明 `@DubboComponentScan("com.alibaba.dubbo.demo.provider")` 扫描后,标注 Dubbo `@Service` 的 `AnnotationDemoService` 被注册成 Spring Bean,可从 Spring ApplicationContext 自由获取。 + + + + + +##### 服务消费方(`@Reference`) + + + +###### 服务 `DemoService` + + + +```java +package com.alibaba.dubbo.demo.consumer; + +import com.alibaba.dubbo.config.annotation.Reference; +import com.alibaba.dubbo.demo.DemoService; + +/** + * Annotation 驱动 {@link DemoService} 消费方 + * + * @author Mercy + */ +public class AnnotationDemoServiceConsumer { + + @Reference(url = "dubbo://127.0.0.1:12345") + private DemoService demoService; + + public String doSayHell(String name) { + return demoService.sayHello(name); + } +} +``` + + + + + +###### 服务消费方 Annotation 配置 + + + +与服务提供方配置类似,服务消费方也许 Dubbo 相关配置 Bean - `ConsumerConfiguration` + +```java +package com.alibaba.dubbo.demo.config; + +import com.alibaba.dubbo.config.ApplicationConfig; +import com.alibaba.dubbo.config.RegistryConfig; +import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan; +import com.alibaba.dubbo.demo.consumer.AnnotationDemoServiceConsumer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 服务消费方配置 + * + * @author Mercy + */ +@Configuration +@DubboComponentScan +public class ConsumerConfiguration { + + /** + * 当前应用配置 + */ + @Bean + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("dubbo-annotation-consumer"); + return applicationConfig; + } + + /** + * 当前连接注册中心配置 + */ + @Bean + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("N/A"); + return registryConfig; + } + + /** + * 注册 AnnotationDemoServiceConsumer,@DubboComponentScan 将处理其中 @Reference 字段。 + * 如果 AnnotationDemoServiceConsumer 非 Spring Bean 的话, + * 即使 @DubboComponentScan 指定 package 也不会进行处理,与 Spring @Autowired 同理 + */ + @Bean + public AnnotationDemoServiceConsumer annotationDemoServiceConsumer() { + return new AnnotationDemoServiceConsumer(); + } + +} +``` + + + +###### 服务消费方引导类 + + + +服务消费方需要先引导服务提供方,下面的实例将会启动两个 Spring 应用上下文,首先引导服务提供方 Spring 应用上下文,同时,需要复用前面Annotation 配置 `ProviderConfiguration`: + +```java + /** + * 启动服务提供方上下文 + */ + private static void startProviderContext() { + // 创建 Annotation 配置上下文 + AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext(); + // 注册配置 Bean + providerContext.register(ProviderConfiguration.class); + // 启动服务提供方上下文 + providerContext.refresh(); + } +``` + + + +然后引导服务消费方Spring 应用上下文: + +```java + /** + * 启动并且返回服务消费方上下文 + * + * @return AnnotationConfigApplicationContext + */ + private static ApplicationContext startConsumerContext() { + // 创建服务消费方 Annotation 配置上下文 + AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); + // 注册服务消费方配置 Bean + consumerContext.register(ConsumerConfiguration.class); + // 启动服务消费方上下文 + consumerContext.refresh(); + // 返回服务消费方 Annotation 配置上下文 + return consumerContext; + } +``` + + + +完整的引导类实现: + +```java +package com.alibaba.dubbo.demo.bootstrap; + +import com.alibaba.dubbo.demo.config.ConsumerConfiguration; +import com.alibaba.dubbo.demo.config.ProviderConfiguration; +import com.alibaba.dubbo.demo.consumer.AnnotationDemoServiceConsumer; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * 服务消费端引导类 + * + * @author Mercy + */ +public class ConsumerBootstrap { + + public static void main(String[] args) { + // 启动服务提供方上下文 + startProviderContext(); + // 启动并且返回服务消费方上下文 + ApplicationContext consumerContext = startConsumerContext(); + // 获取 AnnotationDemoServiceConsumer Bean + AnnotationDemoServiceConsumer consumer = consumerContext.getBean(AnnotationDemoServiceConsumer.class); + // 执行 doSayHello 方法 + String message = consumer.doSayHello("World"); + // 输出执行结果 + System.out.println(message); + } + + /** + * 启动并且返回服务消费方上下文 + * + * @return AnnotationConfigApplicationContext + */ + private static ApplicationContext startConsumerContext() { + // 创建服务消费方 Annotation 配置上下文 + AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); + // 注册服务消费方配置 Bean + consumerContext.register(ConsumerConfiguration.class); + // 启动服务消费方上下文 + consumerContext.refresh(); + // 返回服务消费方 Annotation 配置上下文 + return consumerContext; + } + + /** + * 启动服务提供方上下文 + */ + private static void startProviderContext() { + // 创建 Annotation 配置上下文 + AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext(); + // 注册配置 Bean + providerContext.register(ProviderConfiguration.class); + // 启动服务提供方上下文 + providerContext.refresh(); + } + +} +``` + + + +运行`ConsumerBootstrap`结果,仍然符合期望,`AnnotationDemoServiceConsumer` 输出: + +``` +Hello , World +``` + + + + + + + +#### Spring AOP 支持 + + + +前面提到 ` ` 注册 Dubbo `@Service` 组件后,在 Spring AOP 支持方面存在问题。事务作为 Spring AOP 的功能扩展,自然也会在 ` `中不支持。 + + + +`@DubboComponentScan` 针对以上问题,实现了对 Spring AOP 是完全兼容。将上述服务提供方 Annotation 配置做出一定的调整,标注`@EnableTransactionManagement` 以及自定义实现`PlatformTransactionManager` : + +```java +@Configuration +@DubboComponentScan("com.alibaba.dubbo.demo.provider") // 扫描 Dubbo 组件 +@EnableTransactionManagement // 激活事务管理 +public class ProviderConfiguration { + // 省略其他配置 Bean 定义 + + /** + * 自定义事务管理器 + */ + @Bean + @Primary + public PlatformTransactionManager transactionManager() { + return new PlatformTransactionManager() { + + @Override + public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { + System.out.println("get transaction ..."); + return new SimpleTransactionStatus(); + } + + @Override + public void commit(TransactionStatus status) throws TransactionException { + System.out.println("commit transaction ..."); + } + + @Override + public void rollback(TransactionStatus status) throws TransactionException { + System.out.println("rollback transaction ..."); + } + }; + } +} +``` + + + +同时调整 `AnnotationDemoService` - 增加`@Transactional` 注解: + +```java +@Service +@Transactional +public class AnnotationDemoService implements DemoService { + // 省略实现,保持不变 +} +``` + + + +再次运行`ConsumerBootstrap` , 观察控制台输出内容: + +``` +get transaction ... +commit transaction ... +Hello , World +``` + + + +输入内容中多处了两行,说明自定义 `PlatformTransactionManager` `getTransaction(TransactionDefinition)` 以及 `commit(TransactionStatus) ` 方法被执行,进而说明 `AnnotationDemoService` 的`sayHello(String)` 方法执行时,事务也伴随执行。 + + + + + +#### 注意事项 + + + +`ConsumerConfiguration` 上的 `@DubboComponentScan` 并没有指定 `basePackages` 扫描,这种情况会将`ConsumerConfiguration` 当做 `basePackageClasses` ,即扫描`ConsumerConfiguration` 所属的 package `com.alibaba.dubbo.demo.config` 以及子 package。由于当前示例中,不存在标注 Dubbo `@Service`的类,因此在运行时日志(如果开启的话)会输出警告信息: + +``` +WARN : [DUBBO] No Spring Bean annotating Dubbo's @Service was found in Spring BeanFactory, dubbo version: 2.0.0, current host: 127.0.0.1 +``` + + + +以上信息大可不必担忧,因为 `@DubboComponentScan` 除了扫描 Dubbo `@Service` 组件以外,还将处理 `@Reference`字段注入。然而读者特别关注`@Reference`字段注入的规则。 + + + +以上实现为例,`AnnotationDemoServiceConsumer` 必须申明为 Spring `@Bean` 或者 `@Component`(或者其派生注解),否则 `@DubboComponentScan` 不会主动将标注 `@Reference`字段所在的声明类提成为 Spring Bean,换句话说,如果 `@Reference`字段所在的声明类不是 Spring Bean 的话, `@DubboComponentScan` 不会处理`@Reference`注入,其原理与 Spring `@Autowired` 一致。 + + + +以上使用不当可能会导致相关问题,如 GitHub 上曾有小伙伴提问:https://github.com/alibaba/dubbo/issues/825 + +> **li362692680** 提问: +> +> > @DubboComponentScan注解在消费端扫描包时扫描的是 @Service注解??不是@Reference注解?? +> > 启动时报 +> > DubboComponentScanRegistrar-85]-[main]-[INFO] 0 annotated @Service Components { [] } +> +> 笔者(**mercyblitz**)回复: +> +> > `@Reference` 类似于 `@Autowired` 一样,首先其申明的类必须被 Spring 上下文当做一个Bean,因此,Dubbo 并没有直接将 `@Reference` 字段所在的类提升成 Bean。 +> > +> > 综上所述,这并不是一个问题,而是用法不当! + + + + + +#### 已知问题 + + + +最新发布的 Dubbo `2.5.8` 中,`@DubboComponentScan` 在以下特殊场景下存在 Spring `@Service` 不兼容情况: + +> 假设有两个服务实现类 `A` 和 `B`,同时存放在`com.acme` 包下: +> +> * `A` 标注 Dubbo `@Service` +> * `B` 标注 Dubbo `@Service` 和 Spring `@Service` +> +> 当 Spring `@ComponentScan` 先扫描`com.acme` 包时,`B` 被当做 Spring Bean 的候选类。随后,`@DubboComponentScan` 也扫描相同的包。当应用启动时,`A` 和 `B` 虽然都是 Spring Bean,可仅 `A` 能够暴露 Dubbo 服务,`B` 则丢失。 + + + +问题版本:`2.5.7`、`2.5.8` + +问题详情:https://github.com/alibaba/dubbo/issues/1120 + +修复版本:`2.5.9`(下个版本) + + + + + + + diff --git a/content/en/blog/java/demos/dubbo-annotation.md b/content/en/blog/java/demos/dubbo-annotation.md new file mode 100644 index 000000000000..6c5e9bba215e --- /dev/null +++ b/content/en/blog/java/demos/dubbo-annotation.md @@ -0,0 +1,389 @@ +--- +title: "在 Dubbo 中使用注解" +linkTitle: "在 Dubbo 中使用注解" +tags: ["Java"] +date: 2018-08-07 +description: > + 介绍了如何使用注解方式而非 XML 方式来开发 Dubbo 应用,可以学习到如何使用 @EnableDubbo、@Service、@Reference 的用法。 +--- + +# 在 Dubbo 中使用注解 + +随着微服务架构的广泛地推广和实施。在 Java 生态系统中,以 Spring Boot 和 Spring Cloud 为代表的微服务框架,引入了全新的编程模型,包括: + +* 注解驱动(Annotation-Driven) +* 外部化配置(External Configuration) +* 以及自动装配(Auto-Configure) + +新的编程模型无需 XML 配置、简化部署、提升开发效率。为了更好地实践微服务架构,Dubbo 从 `2.5.8` 版本开始, 分别针对了上述的三个场景,提供了更完善的支持。本文不讨论传统的 XML 配置方式,而是侧重介绍注解这种方式。外部配置、自动装配两种自动装配会在另外的文章中专门介绍。 + +## 注解介绍 +### @EnableDubbo + +`@EnableDubbo` 注解是 `@EnableDubboConfig` 和 `@DubboComponentScan`两者组合的便捷表达方式。与注解驱动相关的是 `@DubboComponentScan`。 + +```java +package org.apache.dubbo.config.spring.context.annotation; + +@EnableDubboConfig +@DubboComponentScan +public @interface EnableDubbo { + /** + * Base packages to scan for annotated @Service classes. + *

+ * Use {@link #scanBasePackageClasses()} for a type-safe alternative to String-based + * package names. + * + * @return the base packages to scan + * @see DubboComponentScan#basePackages() + */ + @AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages") + String[] scanBasePackages() default {}; + + /** + * Type-safe alternative to {@link #scanBasePackages()} for specifying the packages to + * scan for annotated @Service classes. The package of each class specified will be + * scanned. + * + * @return classes from the base packages to scan + * @see DubboComponentScan#basePackageClasses + */ + @AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses") + Class[] scanBasePackageClasses() default {}; +} +``` + +通过 `@EnableDubbo` 可以在指定的包名下(通过 `scanBasePackages`),或者指定的类中(通过 `scanBasePackageClasses`)扫描 Dubbo 的服务提供者(以 `@Service` 标注)以及 Dubbo 的服务消费者(以 `Reference` 标注)。 + +扫描到 Dubbo 的服务提供方和消费者之后,对其做相应的组装并初始化,并最终完成服务暴露或者引用的工作。 + +当然,如果不使用外部化配置(External Configuration)的话,也可以直接使用 `@DubboComponentScan`。 + +### @Service + +`@Service` 用来配置 Dubbo 的服务提供方,比如: + +```java +@Service +public class AnnotatedGreetingService implements GreetingService { + public String sayHello(String name) { + return "hello, " + name; + } +} +``` + +通过 `@Service` 上提供的属性,可以进一步的定制化 Dubbo 的服务提供方: + +```java +package org.apache.dubbo.config.annotation; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) // #1 +@Inherited +public @interface Service { + Class interfaceClass() default void.class; // #2 + String interfaceName() default ""; // #3 + String version() default ""; // #4 + String group() default ""; // #5 + boolean export() default true; // #6 + boolean register() default true; // #7 + + String application() default ""; // #8 + String module() default ""; // #9 + String provider() default ""; // #10 + String[] protocol() default {}; // #11 + String monitor() default ""; // #12 + String[] registry() default {}; // #13 +} +``` + +其中比较重要的有: + +1. @Service 只能定义在一个类上,表示一个服务的具体实现 +1. interfaceClass:指定服务提供方实现的 interface 的类 +1. interfaceName:指定服务提供方实现的 interface 的类名 +1. version:指定服务的版本号 +1. group:指定服务的分组 +1. export:是否暴露服务 +1. registry:是否向注册中心注册服务 +1. application:应用配置 +1. module:模块配置 +1. provider:服务提供方配置 +1. protocol:协议配置 +1. monitor:监控中心配置 +2. registry:注册中心配置 + +另外,需要注意的是,application、module、provider、protocol、monitor、registry(从 8 到 13)需要提供的是对应的 spring bean 的名字,而这些 bean 的组装要么通过传统的 XML 配置方式完成,要么通过现代的 Java Config 来完成。在本文中,将会展示 Java Config 的使用方式。 + +### @Reference + +`@Reference` 用来配置 Dubbo 的服务消费方,比如: + +```java +@Component +public class GreetingServiceConsumer { + @Reference + private GreetingService greetingService; + + public String doSayHello(String name) { + return greetingService.sayHello(name); + } +} +``` + +通过 `@Reference` 上提供的属性,可以进一步的定制化 Dubbo 的服务消费方: + +```java +package org.apache.dubbo.config.annotation; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE}) // #1 +public @interface Reference { + Class interfaceClass() default void.class; // #2 + String interfaceName() default ""; // #3 + String version() default ""; // #4 + String group() default ""; // #5 + String url() default ""; // #6 + + String application() default ""; // #7 + String module() default ""; // #8 + String consumer() default ""; // #9 + String protocol() default ""; // #10 + String monitor() default ""; // #11 + String[] registry() default {}; // #12 +} +``` + +其中比较重要的有: + +1. @Reference 可以定义在类中的一个字段上,也可以定义在一个方法上,甚至可以用来修饰另一个 annotation,表示一个服务的引用。通常 @Reference 定义在一个字段上 +2. interfaceClass:指定服务的 interface 的类 +3. interfaceName:指定服务的 interface 的类名 +4. version:指定服务的版本号 +5. group:指定服务的分组 +6. url:通过指定服务提供方的 URL 地址直接绕过注册中心发起调用 +7. application:应用配置 +8. module:模块配置 +9. consumer:服务消费方配置 +10. protocol:协议配置 +11. monitor:监控中心配置 +12. registry:注册中心配置 + +另外,需要注意的是,application、module、consumer、protocol、monitor、registry(从 7 到 12)需要提供的是对应的 spring bean 的名字,而这些 bean 的组装要么通过传统的 XML 配置方式完成,要么通过现代的 Java Config 来完成。在本文中,将会展示 Java Config 的使用方式。 + +## 示例实战 + +了解了 `@EnableDubbo`, `@Service`,`@Reference` 的作用,下面以一个实际的例子来展示如何使用 annotation 来开发 Dubbo 应用。以下的代码可以在 https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-annotation 中找到。 + +### 1. 接口定义 + +定义一个简单的 `GreetingService` 接口,里面只有一个简单的方法 `sayHello` 向调用者问好。 + +```java +public interface GreetingService { + String sayHello(String name); +} +``` + +### 2. 服务端:服务实现 + +实现 `GreetingService` 接口,并通过 `@Service` 来标注其为 Dubbo 的一个服务。 + +```java +@Service +public class AnnotatedGreetingService implements GreetingService { + public String sayHello(String name) { + return "hello, " + name; + } +} +``` + +### 3. 服务端:组装服务提供方 + +通过 Spring 中 Java Config 的技术(`@Configuration`)和 annotation 扫描(`@EnableDubbo`)来发现、组装、并向外提供 Dubbo 的服务。 + +```java +@Configuration +@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.impl") +static class ProviderConfiguration { + @Bean // #1 + public ProviderConfig providerConfig() { + ProviderConfig providerConfig = new ProviderConfig(); + providerConfig.setTimeout(1000); + return providerConfig; + } + + @Bean // #2 + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("dubbo-annotation-provider"); + return applicationConfig; + } + + @Bean // #3 + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setProtocol("zookeeper"); + registryConfig.setAddress("localhost"); + registryConfig.setPort(2181); + return registryConfig; + } + + @Bean // #4 + public ProtocolConfig protocolConfig() { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.setName("dubbo"); + protocolConfig.setPort(20880); + return protocolConfig; + } +} +``` + +说明: + +* 通过 `@EnableDubbo` 指定在 `com.alibaba.dubbo.samples.impl` 下扫描所有标注有 `@Service` 的类 +* 通过 `@Configuration` 将 ProviderConfiguration 中所有的 `@Bean` 通过 Java Config 的方式组装出来并注入给 Dubbo 服务,也就是标注有 `@Service` 的类。这其中就包括了: + + 1. ProviderConfig:服务提供方配置 + 2. ApplicationConfig:应用配置 + 3. RegistryConfig:注册中心配置 + 4. ProtocolConfig:协议配置 + + +### 4. 服务端:启动服务 + +在 `main` 方法中通过启动一个 Spring Context 来对外提供 Dubbo 服务。 + +```java +public class ProviderBootstrap { + public static void main(String[] args) throws Exception { + new EmbeddedZooKeeper(2181, false).start(); // #1 + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class); // #2 + context.start(); // #3 + System.in.read(); // #4 + } +} +``` + +说明: + +1. 启动一个嵌入式的 zookeeper 在 2181 端口上提供注册中心的服务 +2. 初始化一个 `AnnotationConfigApplicationContext` 的示例,并将 `ProviderConfiguration` 传入以完成 Dubbo 服务的自动发现和装配 +3. 启动 Spring Context,开始提供对外的 Dubbo 服务 +4. 因为是服务端,需要通过阻塞主线程来防止进程退出 + + + +启动服务端的 `main` 方法,将会看到下面的输出,代表服务端启动成功,并在注册中心(ZookeeperRegistry)上注册了 `GreetingService` 这个服务: + +```sh +[01/08/18 02:12:51:051 CST] main INFO transport.AbstractServer: [DUBBO] Start NettyServer bind /0.0.0.0:20880, export /192.168.99.1:20880, dubbo version: 2.6.2, current host: 192.168.99.1 + +[01/08/18 02:12:51:051 CST] main INFO zookeeper.ZookeeperRegistry: [DUBBO] Register: dubbo://192.168.99.1:20880/com.alibaba.dubbo.samples.api.GreetingService?anyhost=true&application=dubbo-annotation-provider&default.timeout=1000&dubbo=2.6.2&generic=false&interface=com.alibaba.dubbo.samples.api +``` + +### 5. 客户端:引用服务 + +通过 `@Reference` 来标记 `GreetingService` 接口的成员变量 greetingService 是一个 Dubbo 服务的引用,也就是说,可以简单的通过该接口向远端的服务提供方发起调用,而客户端并没有实现 `GreetingService` 接口。 + +```java +@Component("annotatedConsumer") +public class GreetingServiceConsumer { + @Reference + private GreetingService greetingService; + + public String doSayHello(String name) { + return greetingService.sayHello(name); + } +} +``` + +### 6. 客户端:组装服务消费者 + +与 **3. 服务端:组装服务提供方** 类似,通过 Spring 中 Java Config 的技术(`@Configuration`)和 annotation 扫描(`@EnableDubbo`)来发现、组装 Dubbo 服务的消费者。 + +```java +@Configuration +@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.action") +@ComponentScan(value = {"com.alibaba.dubbo.samples.action"}) +static class ConsumerConfiguration { + @Bean // #1 + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("dubbo-annotation-consumer"); + return applicationConfig; + } + + @Bean // #2 + public ConsumerConfig consumerConfig() { + ConsumerConfig consumerConfig = new ConsumerConfig(); + consumerConfig.setTimeout(3000); + return consumerConfig; + } + + @Bean // #3 + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setProtocol("zookeeper"); + registryConfig.setAddress("localhost"); + registryConfig.setPort(2181); + return registryConfig; + } +} +``` + +说明: + +- 通过 `@EnableDubbo` 指定在 `com.alibaba.dubbo.samples.impl` 下扫描所有标注有 `@Reference 的类 +- 通过 `@Configuration` 将 ConsumerConfiguration 中所有的 `@Bean` 通过 Java Config 的方式组装出来并注入给 Dubbo 服务消费者,也就是标注有 `@Reference 的类。这其中就包括了: + 1. ApplicationConfig:应用配置 + 2. ConsumerConfig:服务消费者配置 + 3. RegistryConfig:注册中心配置,注意:这里的配置需要与服务提供方启动的 EmbeddedZooKeeper 的配置信息保持一致 + +### 7. 客户端:发起远程调用 + +在 `main` 方法中通过启动一个 Spring Context,从其中查找到组装好的 Dubbo 的服务消费者,并发起一次远程调用。 + +```java +public class ConsumerBootstrap { + public static void main(String[] args) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class); // #1 + context.start(); // #2 + GreetingServiceConsumer greetingServiceConsumer = context.getBean(GreetingServiceConsumer.class); // #3 + String hello = greetingServiceConsumer.doSayHello("annotation"); // #4 + System.out.println("result: " + hello); // #5 + } +} +``` + +说明: + +1. 初始化一个 `AnnotationConfigApplicationContext` 的示例,并将 `ConsumerConfiguration` 传入以完成 Dubbo 服务消费者的自动发现和装配 + +2. 启动 Spring Context + +3. 从 Context 中查找出类型为 `GreetingServiceConsumer` 的 Bean + +4. 调用 `doSayHello` 方法,最终通过 Dubbo 的服务引用(由 `@Reference` 标注)发起一次远程调用 + +5. 打印调用结果 + + + +启动客户端的 `main` 方法,将会看到下面的输出,其中返回结果为 result: hello, annotation: + +```sh +[01/08/18 02:38:40:040 CST] main INFO config.AbstractConfig: [DUBBO] Refer dubbo service com.alibaba.dubbo.samples.api.GreetingService from url zookeeper://localhost:2181/com.alibaba.dubbo.registry.RegistryService?anyhost=true&application=dubbo-annotation-consumer&check=false&default.timeout=3000&dubbo=2.6.2&generic=false&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=33001®ister.ip=192.168.99.1&remote.timestamp=1533105502086&side=consumer×tamp=1533105519216, dubbo version: 2.6.2, current host: 192.168.99.1 +[01/08/18 02:38:40:040 CST] main INFO annotation.ReferenceBeanBuilder: has been built. +result: hello, annotation +``` + + + +## 总结 + +通过本文的学习,读者可以掌握 Dubbo 专属的 annotation `@EnableDubbo`、`@Service`、`@Reference` 的基本概念,并通过一个简单 Dubbo 应用的实战开发掌握其基本的用法。 + +Spring 除了传统的 XML 配置之外,还提供了注解驱动、外部化配置、以及自动装配等更现代的配置方式。本文专注在介绍通过注解方式来开发 Dubbo 应用,可以看到,与 XML 配置相比,注解方式编程更加简洁明快。在今后的博文中,会进一步的介绍在 Dubbo 中使用外部化配置、以及自动装配的方法。 diff --git a/content/en/blog/java/demos/dubbo-api-docs.md b/content/en/blog/java/demos/dubbo-api-docs.md new file mode 100644 index 000000000000..20ba06bace1b --- /dev/null +++ b/content/en/blog/java/demos/dubbo-api-docs.md @@ -0,0 +1,281 @@ +--- +title: "Dubbo-Api-Docs -- Apache Dubbo文档展示&测试工具" +linkTitle: "Dubbo-Api-Docs -- Apache Dubbo文档展示&测试工具" +tags: ["Java"] +date: 2020-12-22 +description: > + 本文将向你介绍Dubbo-Api-Docs +--- +# Dubbo-Api-Docs +## 背景 +Swagger 是一个规范和完整的前端框架,用于生成,描述,调用和可视化 RESTful 风格的 Web 服务. +Swagger 规范也逐渐发展成为了 OpenAPI 规范. + +Springfox 是一个集成了Swagger,基于 Sring MVC/Spring Webflux 实现的一个 Swagger 描述文件生成框架,通过使用它定义的 +一些描述接口的注解自动生成Swagger的描述文件, 使 Swagger 能够展示并调用接口. + +相信很多人都听说和使用过Swagger和Springfox, 这里就不再赘述了. + +Dubbo-Admin中有接口测试功能,但是缺少接口描述的文档,所以该测试功能比较适合接口开发人员用于测试接口.而其他人想要使用该功能就必须 +先通过接口开发者编写的文档或者其他方式了解清楚接口信息才能使用该功能测试接口. +Dubbo这边有没有集合文档展示和测试功能,能不用写文档就能把接口直接给调用方,类似Swagger/Springfox的工具呢? +之前做过一些调研,找到一些类似的工具: +* 有些是基于Springfox做的,直接一个文本域放JSON, 与目前Admin中的测试功能大同小异 +* 有些是直接基于Swagger的Java版OpenApi规范生成工具做的,能把一些基础数据类型的简单参数作为表单项展示 + +它们都有一个共同点: 会把你的提供者变为Web项目. 当然有些提供者是通过web容器加载启动的,甚至也有和web工程在一起的,那就无所谓了. +但也有非web的提供者. 为了文档我得把它变为web项目吗?(还要引入一堆Web框架的依赖?比如Spring MVC)或者说生产环境打包时删除它的引用 +和代码里的相关注解? 有没有简单点的方式呢? + +OpenAPI中没有RPC的规范,Swagger是OpenAPI的实现,所以也不支持RPC相关调用.Springfox是通过Swagger实现的 RESTful API的工具, +而RESTful又是基于Web的,Dubbo没法直接使用.我们最终选择了自己实现: +* 提供一些描述接口信息的简单注解 +* 在提供者启动时解析注解并缓存解析结果 +* 在提供者增加几个Dubbo-Api-Docs使用的获取接口信息的接口 +* 在Dubbo Admin侧通过Dubbo泛化调用实现Http方式调用Dubbo接口的网关 +* 在Dubbo Admin侧实现接口信息展示和调用接口功能 +* 下列情况中的参数直接展示为表单项,其他的展示为JSON: + * 方法参数为基础数据类型的 + * 方法参数为一个Bean,Bena中属性为基础数据类型的 +* 很少的第三方依赖,甚至大部分都是你项目里本身就使用的 +* 可以通过profile决定是否加载, 打包时简单的修改profile就能区分生产和测试,甚至profile你本来就使用了 + +> 今天,我很高兴的宣布: Dubbo 用户也可以享受类似Swagger的体验了 -- Dubbo-Api-Docs发布了. +> +## 简介 +Dubbo-Api-Docs 是一个展示dubbo接口文档,测试接口的工具. + +使用 Dubbo-Api-Docs 分为两个主要步骤: +1. 在dubbo项目引入Dubbo-Api-Docs 相关jar包,并增加类似Swagger的注解. +2. 在 Dubbo-Admin 中查看接口描述并测试. + +通过以上两个步骤即可享受类似Swagger的体验, 并且可以在生产环境中关闭Dubbo-Api-Docs的扫描. + +Dubbo-Api-Docs 目前通过直连服务节点的方式获取该服务的接口列表. 测试接口时可以直连也可以通过注册中心.未来会增加通过注册中心获取服务列表的方式.并根据Dubbo的升级规划增加新的功能支持.也会根据社区的需求增加功能. + +Dubbo-Api-Docs 会在服务提供者启动完毕后扫描docs相关注解并将处理结果缓存.并增加一些Dubbo-Api-Docs相关的Dubbo提供者接口. 缓存的数据在将来可能会放到Dubbo元数据中心中. + +## 当前版本: 2.7.8.1 + +```xml + + org.apache.dubbo + dubbo-api-docs-annotations + ${dubbo-version} + + + + org.apache.dubbo + dubbo-api-docs-core + ${dubbo-version} + +``` + +## 快速入门 +### 1.dubbo提供者项目的方法参数中加上 Dubbo-Api-Docs 注解 +* 如果 dubbo提供者的接口和方法参数在一个单独的jar项目中,则在该项目中引入: dubbo-api-docs-annotations +* dubbo提供者项目引入 dubbo-api-docs-core +* 在提供者项目的项目启动类(标注了@SpringBootApplication的类)或者配制类(标注了@Configuration的类)中增加注解 @EnableDubboApiDocs 以启用Dubbo Api Docs功能 +> 为避免增加生产环境中的资源占用, 建议单独创建一个配制类用于启用Dubbo-Api-Docs, 并配合 @Profile("dev") 注解使用 +> 当然, Dubbo-Api-Docs 仅在项目启动时多消耗了点CPU资源, 并使用了一点点内存用于缓存, 将来会考虑将缓存中的内容放到元数据中心. + +#### 下面以[dubbo-api-docs-examples](https://github.com/apache/dubbo-spi-extensions/tree/2.7.x/dubbo-api-docs/dubbo-api-docs-examples)项目中的部分服务接口为例: +```bash +git clone -b 2.7.x https://github.com/apache/dubbo-spi-extensions.git +``` + +进入 dubbo-spi-extensions/dubbo-api-docs/dubbo-api-docs-examples 目录 + +dubbo-api-docs-examples 中有两个子模块: +* examples-api: 一个jar包项目,其中包含服务的接口和接口参数Bean +* examples-provider: 提供者服务端,包含spring boot启动器和服务的实现 + +下面我们在这两个子模块中增加Dubbo-Api-Docs + +> examples-api: + +maven引入: +```xml + + org.apache.dubbo + dubbo-api-docs-annotations + 2.7.8 + +``` +org.apache.dubbo.apidocs.examples.params 中有两个Bean,我们来为它们添加docs注解 +* QuickStartRequestBean 作为参数Bean, 添加 @RequestParam +```java +public class QuickStartRequestBean { + + @RequestParam(value = "You name", required = true, description = "please enter your full name", example = "Zhang San") + private String name; + + @RequestParam(value = "You age", defaultValue = "18") + private int age; + + @RequestParam("Are you a main?") + private boolean man; + + // getter/setter略... +} +``` +* QuickStartRespBean 作为响应Bean,添加 @ResponseProperty +```java +public class QuickStartRespBean { + + @ResponseProperty(value = "Response code", example = "500") + private int code; + + @ResponseProperty("Response message") + private String msg; + + // getter/setter略... +} +``` +由于我们只挑选了部分接口作为演示,到此这些接口涉及的docs注解添加完毕 +> examples-provider: + +maven引入: +```xml + + org.apache.dubbo + dubbo-api-docs-core + 2.7.8 + +``` +我们挑选一个接口作为演示: + +org.apache.dubbo.apidocs.examples.api.impl.QuickStartDemoImpl 中的 quickStart 方法 + +QuickStartDemoImpl 实现了 api包中的 org.apache.dubbo.apidocs.examples.api.IQuickStartDemo 接口 + +* 在 QuickStartDemoImpl 中: +```java +@DubboService +@ApiModule(value = "quick start demo", apiInterface = IQuickStartDemo.class, version = "v0.1") +public class QuickStartDemoImpl implements IQuickStartDemo { + + @ApiDoc(value = "quick start demo", version = "v0.1", description = "this api is a quick start demo", responseClassDescription="A quick start response bean") + @Override + public QuickStartRespBean quickStart(@RequestParam(value = "strParam", required = true) String strParam, QuickStartRequestBean beanParam) { + return new QuickStartRespBean(200, "hello " + beanParam.getName() + ", " + beanParam.toString()); + } +} +``` +到此docs相关注解已添加完毕,下面我们来开启 Dubbo-Api-Docs. 新增一个配制类,位置任意,只要能被spring boot扫描到就行. + +我们在 org.apache.dubbo.apidocs.examples.cfg 包中新增一个配制类 DubboDocConfig : +```java +@Configuration +@Profile("dev") // 配合 Profile 一起使用, 在 profile 为 dev 时才会加载该配制类 +@EnableDubboApiDocs // 开启 Dubbo-Api-Docs +public class DubboDocConfig { +} +``` +到此 Dubbo-Api-Docs 相关的东西已经添加完毕. +[dubbo-api-docs-examples](https://github.com/apache/dubbo-spi-extensions/tree/2.7.x/dubbo-api-docs/dubbo-api-docs-examples) +中有更多更为详尽的例子.下文中有注解的详细说明.下面我们来看一下增加 Dubbo-Api-Docs 后的效果图. + +![demoApi2](/imgs/blog/api-docs/quickStart.png) + + +### 2.启动提供者项目 +* 示例使用nacos作为注册中心,[下载并启动nacos](https://nacos.io) +* 在上面的例子中,我们启动 examples-provider 项目中的 org.apache.dubbo.apidocs.examples.ExampleApplication. +在examples-provider目录中: +```bash +mvn spring-boot:run +``` + + + +### 3.下载 dubbo-admin +[dubbo-admin仓库](https://github.com/apache/dubbo-admin) + +> dubbo-admin 需要下载 develop 分支源码启动 +> ```bash +> git clone -b develop https://github.com/apache/dubbo-admin.git +> ``` + +### 4.启动访问 dubbo-admin +参考 dubbo-admin 里的说明启动: +```text +1. 在 dubbo-admin-server/src/main/resources/application.properties 中修改注册中心地址 +2. 编译 mvn clean package +3. 启动: +mvn --projects dubbo-admin-server spring-boot:run +或者 +cd dubbo-admin-distribution/target; java -jar dubbo-admin-0.1.jar +4. 浏览器访问: http://localhost:8080 +5. 默认帐号密码都是: root +``` + +### 5.进入"接口文档"模块 +* 在"dubbo提供者IP"和"dubbo提供者端口"中分别输入提供者所在机器IP和端口, 点击右侧 " 加载接口列表" 按钮 +* 左侧接口列表中加载出接口列表,点击任意接口,右边展示出该接口信息及参数表单. +* 填入表单内容后,点击最下方测试按钮 +* 响应部分展示了响应示例及实际响应结果 + +## 源码仓库 +Dubbo-Api-Docs 根据功能拆分,分别在两个仓库中: + +### dubbo-spi-extensions +> [dubbo-spi-extensions仓库地址](https://github.com/apache/dubbo-spi-extensions) + +该仓库存放dubbo的一些非核心功能的扩展, Dubbo-Api-Docs 作为该仓库中的一个子模块,由于该仓库属于Dubbo 3.0中规划的一部分,而Dubbo-Api-Docs是基于Dubbo 2.7.x 开发的,所以在该仓库中增加了[2.7.x分支,Dubbo-Api-Docs就在该分支下](https://github.com/apache/dubbo-spi-extensions/tree/2.7.x/dubbo-api-docs). +该仓库中包含了 Dubbo-Api-Docs 的文档相关注解、注解扫描能力和使用示例: +* dubbo-api-docs-annotations: 文档生成的相关注解.考虑到实际情况中 dubbo api 的接口类和接口参数会规划为一个单独的jar包, 所以注解也独立为一个jar包.本文后面会对注解做详细说明. +* dubbo-api-docs-core: 负责解析注解,生成文档信息并缓存. 前面提到的Dubbo-Api-Docs相关接口也在该包中 +* dubbo-api-docs-examples: 使用示例 + +### Dubbo-Admin +> [Dubbo-Admin仓库地址](https://github.com/KeRan213539/dubbo-admin) + +文档的展示及测试放在了 dubbo admin 项目中 + +## 注解说明 +* @EnableDubboApiDocs: 配制注解, 启用 dubbo api docs 功能 +* @ApiModule: 类注解, dubbo接口模块信息,用于标注一个接口类模块的用途 + * value: 模块名称 + * apiInterface: 提供者实现的接口 + * version: 模块版本 +* @ApiDoc: 方法注解, dubbo 接口信息,用于标注一个接口的用途 + * value: 接口名称 + * description: 接口描述(可使用html标签) + * version: 接口版本 + * responseClassDescription: 响应的数据的描述 +* @RequestParam: 类属性/方法参数注解,标注请求参数 + * value: 参数名 + * required: 是否必传参数 + * description: 参数描述 + * example: 参数示例 + * defaultValue: 参数默认值 + * allowableValues: 允许的值,设置该属性后界面上将对参数生成下拉列表 + * 注:使用该属性后将生成下拉选择框 + * boolean 类型的参数不用设置该属性,将默认生成 true/false 的下拉列表 + * 枚举类型的参数会自动生成下拉列表,如果不想开放全部的枚举值,可以单独设置此属性. +* @ResponseProperty: 类属性注解, 标注响应参数 + * value: 参数名 + * example: 示例 + +## 使用注意 + +* 响应bean(接口的返回类型)支持自定义泛型, 但只支持一个泛型占位符 +* 关于Map的使用:Map的key只能用基本数据类型.如果Map的key不是基础数据类型,生成的 就不是标准json格式,会出异常 +* 接口的同步/异步取自 org.apache.dubbo.config.annotation.Service#async / org.apache.dubbo.config.annotation.DubboService#async + +## 示例说明 +[dubbo-spi-extensions / Dubbo-Api-Docs](https://github.com/apache/dubbo-spi-extensions/tree/2.7.x/dubbo-api-docs) 中的 dubbo-api-docs-examples 目录中为示例工程: +* examples-api: jar包项目,包含服务提供者的接口类及参数Bean +* examples-provider: 使用 dubbo-spring-boot-starter 的提供者项目, 注册中心使用 nacos +* examples-provider-sca: 使用 spring-cloud-starter-dubbo 的提供者项目, 注册中心使用 nacos + +### 示例使用步骤 +1. 示例使用nacos作为注册中心,[下载并启动nacos](https://nacos.io) +2. 任意启动 examples-provider 和 examples-provider-sca 中的任意一个,当然也可以两个都启动. examples-provider 使用 20881端口 examples-provider-sca 使用20882端口.两个项目都是spring boot项目,启动类在 org.apache.dubbo.apidocs.examples 包下. +3. 启动 [Dubbo-Admin](https://github.com/KeRan213539/dubbo-admin), 浏览器访问: http://localhost:8080 +4. 进入 dubbo-admin 中的 "接口文档"模块 +5. 在"dubbo提供者IP"和"dubbo提供者端口"中分别输入提供者所在机器IP和端口, 点击右侧 " 加载接口列表" 按钮 +6. 左侧接口列表中加载出接口列表,点击任意接口,右边展示出该接口信息及参数表单. +7. 填入表单内容后,点击最下方测试按钮 +8. 响应部分展示了响应示例及实际响应结果 diff --git a/content/en/blog/java/demos/dubbo-async-client.md b/content/en/blog/java/demos/dubbo-async-client.md new file mode 100644 index 000000000000..9cf5eed993af --- /dev/null +++ b/content/en/blog/java/demos/dubbo-async-client.md @@ -0,0 +1,89 @@ +--- +title: "Dubbo客户端异步接口的实现背景和实践" +linkTitle: "Dubbo客户端异步接口的实现背景和实践" +tags: ["Java"] +date: 2019-11-01 +description: > + 本文介绍了 Dubbo 客户端异步接口的实现背景和实践 +--- + +## 铺垫 + + +![image | left](/imgs/blog/dubboasyn_client/1.png) + + +先简单介绍下一次完整的Dubbo调用所经历的线程阶段。几个信息这里罗列下 +1. Biz~代表业务线程,即便是业务逻辑处理所处的线程,Biz~线程池可能是业务自己创建维护,大多数的可能是系统框架自身管理的(比如web型的业务系统跑在Tomcat容器下,Biz~线程就是Tomcat维护);IO~代表网络数据处理线程,是IO框架(比如Netty,Grizzly)创建维护,Dubbo Remoting所默认Netty实现是NioEventloopLoopGroup;另外按照Channel与IO线程的绑定关系,也可以直接把IO~看成一个可接受事件消息的Channel。像Biz和IO这样的异步处理阶段在JDK8中有个很精确地抽象描述,叫CompletionStage。 + +2. 大家知道,线程与线程之间做数据通信的方式是共享变量,Biz和IO两个stage之间的数据通信是Queue,具体到Dubbo实现,在客户端一侧的实现(即上图中用1所标注的步骤)中Biz是通过向EventLoop的LinkedBlockingQueue放置一个Task,而EventLoop有对应的Thread会不停的迭代Queue来执行Task中所包含的信息,具体代码可以看SingleThreadEventExecutor(顺便提下,Netty中默认是用无上限的LinkedBlockingQueue,在Biz的速率高于网络速率情况下,似乎好像有Memory Leak的风险)。 + +3. 如上图所示,标准的一次RPC调用经过了图中所示的1,2,3,4的四次消息(事件)传递,分别是客户端业务线程到IO线程的请求发出,服务端IO线程到业务逻辑线程的__请求接受,__服务端处理完成后由业务逻辑线程到IO线程的响应写出,客户端收到结果后从IO线程到业务逻辑的响应处理。除了1与4之间一般需要维护响应和请求的映射对应关系,四次的事件处理都是完全独立的,所以一次RPC调用天然是异步的,而同步是基于异步而来。 + + +## 客户端异步 + +### 实现背景 +在Java语言(其他语言不清楚)下一次本地接口的调用可以透明地通过代理机制转为远程RPC的调用,大多数业务方也比较喜欢这种与本地接口类似的编程方式做远程服务集成,所以虽然RPC内部天然是异步的,但使用Dubbo的用户使用最广泛的还是同步,而异步反而成为小众的使用场景。同步的优点是编程模型更加符合业务方的“传统”习惯,代价是在图中的1代表的请求发出事件后需要阻塞当前的Biz~线程,一直等到4代表的响应处理后才能唤醒。在这个短则微秒级别,长则秒级的1,2,3,4处理过程中都要阻塞Biz~线程,就会消耗线程资源,增加系统资源的开销。 + +所以,客户端异步的出发点是节省线程资源开销,代价是需要了解下异步的使用方式:)。在同步方式下API接口的返回类型是代表着某个业务类,而当异步情况下,响应返回与请求发出是完全独立的两个事件,需要API接口的返回类型变为上述中说的CompletionStage才是最贴合的,这是Dubbo在异步上支持的必然异步。回到最近的Dubbo发布版,是不改变接口的情况下,需要在服务创建时注册一个回调接口来处理响应返回事件。 + +下面以示例来说。 + +### 示例 + +事件通知的示例代码请参考:[https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-notify](https://github.com/dubbo/dubbo-samples/tree/master/2-advanced/dubbo-samples-notify) + +事件通知允许 Consumer 端在调用之前、调用正常返回之后或调用出现异常时,触发 `oninvoke`、`onreturn`、`onthrow` 三个事件。 + +可以通过在配置 Consumer 时,指定事件需要通知的方法,如: + +```xml + + + + + +``` + +其中,NotifyImpl 的代码如下: + +```java +public class NotifyImpl implements Notify{ + + public Map ret = new HashMap(); + + public void onreturn(String name, int id) { + ret.put(id, name); + System.out.println("onreturn: " + name); + } + + public void onthrow(Throwable ex, String name, int id) { + System.out.println("onthrow: " + name); + } +} +``` + +这里要强调一点,自定义 Notify 接口中的三个方法的参数规则如下: + +* `oninvoke` 方法参数与调用方法的参数相同; +* `onreturn`方法第一个参数为调用方法的返回值,其余为调用方法的参数; +* `onthrow`方法第一个参数为调用异常,其余为调用方法的参数。 + +上述配置中,`sayHello`方法为同步调用,因此事件通知方法的执行也是同步执行。可以配置 `async=true`让方法调用为异步,这时事件通知的方法也是异步执行的。特别强调一下,`oninvoke`方法不管是否异步调用,都是同步执行的。 + +### 实践建议 + +*

+
RPC调用后的逻辑非强依赖结果:异步回调是在客户端非强依赖服务端的结果情况下,是适用客户端的异步调用。
+
+ +*
+
rx场景:自从了解到reactive的编程模型后,认为只要编程思维能够拥抱reactive,并且业务模型的状态机设计能做适当的调整,任何场景下都比较适用异步来解决,从而得到更好的终端响应体验。 对于Dubbo来说,当下的异步接口模型是需要像reactive的模型接口做改进,才能使得用户更自然地适用异步接口。
+
+ + +### 小结 + +* 客户端异步的出发点就是请求发出和响应处理本身为两个不同的独立事件,响应如何被处理和在哪个线程中处理等都是不需要和请求发出事件的业务逻辑线程做耦合绑定。 +* 响应事件回调的处理逻辑在哪个线程中做处理是需要根据情况来选择。建议,如果回调逻辑比较简单,建议直接在IO线程中;如果包含了远程访问或者DB访问等IO型的 __同步__ 操作,建议在独立的线程池做处理。 diff --git a/content/en/blog/java/demos/dubbo-async-server.md b/content/en/blog/java/demos/dubbo-async-server.md new file mode 100644 index 000000000000..039a3f3104fd --- /dev/null +++ b/content/en/blog/java/demos/dubbo-async-server.md @@ -0,0 +1,95 @@ +--- +title: "Dubbo服务端异步接口的实现背景和实践" +linkTitle: "Dubbo服务端异步接口的实现背景和实践" +tags: ["Java"] +date: 2019-11-02 +description: > + 本文介绍了 Dubbo 服务端异步接口的实现背景和实践 +--- + +## 铺垫 +建议先对Dubbo的处理过程中涉及的线程阶段先做个了解,具体可参考[Dubbo客户端异步接口的实现背景和使用场景](/en/blog/2019/11/01/dubbo客户端异步接口的实现背景和实践/)。 + +## 实现背景 +有必要比较详细点的介绍下服务端的线程策略来加深用户在选择服务端异步的判断依据,同时有必要引出协程这一在服务端异步中常常会用到的“秘密武器”。 + +### 服务端的线程策略 +Dubbo支持多种NIO框架来做Remoting的协议实现,无论是Netty,Mina或者Grizzly,实现都大同小异,都是基于事件驱动的方式来做网络通道建立,数据流读取的。其中以Grizzly对于[线程策略](https://javaee.github.io/grizzly/iostrategies.html)的介绍为例,通常支持以下四种。Dubbo作为一个RPC框架,默认选择的是第一种策略,原因在于业务服务是CPU密集型还是IO阻塞型,是无法断定的,第一种策略是最保险的策略。当然,对于这几种策略有了了解后,再结合业务场景做针对性的选择是最完美的。 +1. __Worker-thread策略__ + +最常用最普适的策略,其中IO线程将NIO事件处理委托给工作线程。 + + +![workerthread-strategy.png](/imgs/blog/dubboasyn_server/1.png) + + +此策略具有很高的伸缩性。我们可以根据需要更改IO和worker线程池的大小,并且不存在在特定NIO事件处理期间可能发生的,同一Selector各个Channel之间相互干扰的风险。 + +缺点是有线程上下文切换的代价。 + +2. __Same-thread策略__ + +可能是最有效的策略。与第一种不同,同一线程处理当前线程中的NIO事件,避免了昂贵的线程上下文切换。 + + +![samethread-strategy.png](/imgs/blog/dubboasyn_server/2.png) + + +这个策略可以调整IO线程池大小,也是具备可伸缩性;缺点也很明显,它要求业务处理中一定不要有阻塞处理,因为它可能会阻止在同一个IO线程上发生的其他NIO事件的处理。 + +3. __Dynamic策略__ + +如前所述,前两种策略具有明显的优点和缺点。但是,如果策略可以尝试在运行时根据当前条件(负载,收集的统计信息等)巧妙地交换它们,何如? + + +![dynamic-strategy.png](/imgs/blog/dubboasyn_server/3.png) + + +这种策略可能会带来很多好处,能更好地控制资源,前提是不要使条件评估逻辑过载,防止评估判断的复杂性会使这种策略效率低下。 +多说一句,希望大家对这个策略多留意一下,它可能是Dubbo服务端异步方式的最佳搭配。我也多扯个淡,这几天关注了些adaptive XX或者predictive XX,这里看到dynamic真是亲切,Dubbo作为产品级生产级的微服务解决方案,是必须既要adaptive,又要predictive,还要dynamic,哈哈。 + +4. __Leader-follower策略__ + + + +![leaderfollower-strategy.png](/imgs/blog/dubboasyn_server/4.png) + +此策略类似于第一种,但它不是将NIO事件处理传递给worker线程,而是通过将控制传递给Selector给工作线程,并将实际NIO事件处理当前IO线程中。这种策略其实是把worker和IO线程阶段做了混淆,个人不建议。 +### 协程与线程 +在CPU资源的管理上,OS和JVM的最小调度单位都是线程,业务应用通过扩展实现的协程包是可以具备独立的运行单位,事实上也是基于线程来做的,核心应该是遇到IO阻塞,或者锁等待时,保存上下文,然后切换到另一个协程。至于说的协程开销低,能更高效的使用CPU,这些考虑到协程库的用户态实现和上下文设计是支持的,但也建议大家结合实际业务场景做性能测试。 + +__在默认的Dubbo线程策略中,是有worker线程池来执行业务逻辑,但也常常会发生ThreadPool Full的问题,为了尽快释放worker线程,在业务服务的实现中会另起线程。代价是再次增加线程上下文切换,同时需要考虑链路级别的数据传送(比如tracing信息)和流控的出口控制等等。当然,如果Dubbo能够切换到Same-thread策略,再配合协程库的支持,服务端异步是一种值得推荐的使用方式。__ + +## 示例 +通过示例来体验下Dubbo服务端异步接口。Demo代码请访问github之[https://github.com/dubbo/dubbo-samples/tree/master/2-advanced/dubbo-samples-notify](https://github.com/dubbo/dubbo-samples/tree/master/2-advanced/dubbo-samples-notify)。 +```java +public class AsyncServiceImpl implements AsyncService { + + @Override + public String sayHello(String name) { + System.out.println("Main sayHello() method start."); + final AsyncContext asyncContext = RpcContext.startAsync(); + new Thread(() -> { + asyncContext.signalContextSwitch(); + System.out.println("Attachment from consumer: " + RpcContext.getContext().getAttachment("consumer-key1")); + System.out.println(" -- Async start."); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + asyncContext.write("Hello " + name + ", response from provider."); + System.out.println(" -- Async end."); + }).start(); + System.out.println("Main sayHello() method end."); + return "hello, " + name; + } + +``` +## 实践建议 +* 不要迷信服务端异步。 +* 服务端异步在Event-Driven或者Reactive面前基本是伪命题.补充下原因:服务端异步初衷是说Dubbo的服务端业务线程数(默认是200个)不够,但其实在event-driven模式下,200个肯定不需要那么多,只需要cpu核数那样就可以。只要业务实现是非阻塞的纯异步方式的业务逻辑处理,用再多的线程数都是浪费资源。 +* 要用服务端异步,建议服务端的线程策略采用same thread模式+协程包。 + +## 小结 +Dubbo在支持业务应用时,会碰到千奇百怪的需求场景,服务端异步为用户提供了一种解决ThreadPool Full的方案。当发生ThreadPool Full的情况下,如果当前系统瓶颈是CPU,不建议用这种方案;如果系统Load不高,调高worker的线程数目,或者采用服务端异步,都是可以考虑的。 diff --git a/content/en/blog/java/demos/dubbo-basic-usage-dubbo-consumer-configuration.md b/content/en/blog/java/demos/dubbo-basic-usage-dubbo-consumer-configuration.md new file mode 100644 index 000000000000..2204ee0dfb5a --- /dev/null +++ b/content/en/blog/java/demos/dubbo-basic-usage-dubbo-consumer-configuration.md @@ -0,0 +1,202 @@ +--- +title: "Dubbo 基本用法 - Dubbo Consumer 配置" +linkTitle: "Dubbo 基本用法 - Dubbo Consumer 配置" +tags: ["Java"] +date: 2018-08-14 +description: > + XML配置,API调用方式配置,注解方式配置 +--- + +## Dubbo Consumer配置 + +### Consumer配置详解 + +配置Dubbo Consumer有3种方式:XML配置,API调用方式配置,注解方式配置。 + +#### XML配置 + +###### 最简单的配置的样例: + +``` + + + + + + + + +``` + + + +> 支持的配置标签及对应的配置项详解,参考provider中的用法。 + +> 接下来重点讲解下<dubbo:reference/>的配置。 + + + +* <dubbo:reference/>支持的主要属性列表: + +| 属性名 | 说明 | +| -------- | ----- | +| id | 服务引用id,作为java bean id,需要唯一 | +| interface | 接口名,用于查找服务 | +| version | 版本号,与服务提供者的版本一致 | +| timeout | 服务方法调用超时时间(毫秒) | +| retries | 远程服务调用重试次数,不包括第一次调用,不需要重试请设为0 | +| connections | 对每个提供者的最大连接数,rmi、http、hessian等短连接协议表示限制连接数,dubbo等长连接协表示建立的长连接个数 | +| loadbalance | 负载均衡策略,可选值:random,roundrobin,leastactive,分别表示:随机,轮询,最少活跃调用 | +| async | 是否异步执行,不可靠异步,只是忽略返回值,不阻塞执行线程 | +| generic | 泛化调用,可以绕过 | +| check | 启动时检查提供者是否存在,true报错,false忽略 | +| actives | 每服务消费者每服务每方法最大并发调用数 | + + + +其他配置属性请参考xsd:http://dubbo.apache.org/schema/dubbo/dubbo.xsd + + + +* <dubbo:method/>作为<dubbo:reference/>的子元素,它可以针对方法进行配置。比较常用的属性有: + + + +| 属性名 | 说明 | +| -------- | ----- | +| executes | 服务执行的请求上限 | +| retries | 超时重试次数 | +| timeout | 调用超时时间 | +| loadbalance | 负载均衡策略,可选值:random,roundrobin,leastactive,分别表示:随机,轮询,最少活跃调用 | +| async | 是否异步执行,不可靠异步,只是忽略返回值,不阻塞执行线程 | +| actives | 每服务消费者最大并发调用限制 | + +其他属性,可以参考上面的xsd。 + +###### 配置的覆盖关系 + +![undefined](/imgs/blog/2018/08/14/dubbo-usage/1536496436861-1b63bc4e-3e59-4aa3-800e-a32cfe64950d.png) + +
配置的覆盖关系图
+ +其中包含了consumer端和provider的配置,注意区分。 + +#### annotation + + +###### Reference注解远程服务 + +``` + +public class AnnotationConsumeService { + + @com.alibaba.dubbo.config.annotation.Reference + public AnnotateService annotateService; + + // ... + +} + +``` + + + +这种方式的配置和前面用xml配置的方式是一样的效果。 + + + +> 指定dubbo扫描路径的方式,可以参考前一章节中provider的实现。 + + + + + +#### api直接触发 + +``` +import com.alibaba.dubbo.rpc.config.ApplicationConfig; +import com.alibaba.dubbo.rpc.config.RegistryConfig; +import com.alibaba.dubbo.rpc.config.ConsumerConfig; +import com.alibaba.dubbo.rpc.config.ReferenceConfig; +import com.xxx.XxxService; +// 当前应用配置 + +ApplicationConfig application = new ApplicationConfig(); +application.setName("yyy"); +// 连接注册中心配置 +RegistryConfig registry = new RegistryConfig(); +registry.setAddress("10.20.130.230:9090"); +registry.setUsername("aaa"); +registry.setPassword("bbb"); + +// 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接 +// 引用远程服务 +ReferenceConfig reference = new ReferenceConfig(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏 + +reference.setApplication(application); +reference.setRegistry(registry); // 多个注册中心可以用setRegistries() +reference.setInterface(XxxService.class); +reference.setVersion("1.0.0"); + +// 和本地bean一样使用xxxService +XxxService xxxService = reference.get(); +``` + +###### method特殊设置 + +``` + +// 方法级配置 +List methods = new ArrayList(); +MethodConfig method = new MethodConfig(); +method.setName("createXxx"); +method.setTimeout(10000); +method.setRetries(0); +methods.add(method); +// 引用远程服务 +ReferenceConfig reference = new ReferenceConfig(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏 +... +reference.setMethods(methods); // 设置方法级配置 +``` + +### Consumer 调用远程服务 +上面章节更多从配置角度出发,接下来通过一个完整的例子,来讲解下dubbo consumer的完整使用。 + +这个例子中只有一个服务UserReadService,有一个方法 getUserById。 需要将通过Dubbo调用远程的服务。具体的步骤如下: + +1.创建一个工程 +如果本来已经有工程,可以忽略。创建一个spring boot工程,可以通过 https://start.spring.io/ 创建。 +服务的提供方,已经在provider章节中进行了定义。 +2.调用服务 +``` +@RestController +public class UserTestController{ + @Autowired + private UserReadService userReadService; + @RequestMapping("/user/getById") + public String getUserById(Long id){ + // just test + return userReadService.getUserById(id).toString(); + } +} +``` +3.Dubbo配置 +``` + + + + + + + + +``` +Dubbo配置的其他方式可以参考上一章节的相关配置,或者使用集成dubbo spring boot starter方式。 + + diff --git a/content/en/blog/java/demos/dubbo-basic-usage-dubbo-provider-configuration.md b/content/en/blog/java/demos/dubbo-basic-usage-dubbo-provider-configuration.md new file mode 100644 index 000000000000..d8fb087abf0e --- /dev/null +++ b/content/en/blog/java/demos/dubbo-basic-usage-dubbo-provider-configuration.md @@ -0,0 +1,284 @@ +--- +title: "Dubbo 基础用法 - Provider 配置" +linkTitle: "Dubbo 基础用法 - Provider 配置" +tags: ["Java"] +date: 2018-08-14 +description: > + 主要讲述如何配置dubbo,按照配置方式上可以分为:XML配置,properties方式配置,注解方式配置,API调用方式配置。 +--- + +## Dubbo基本用法 + +本章节主要讲述如何配置dubbo,按照配置方式上分,可以分为:XML配置,properties方式配置,注解方式配置,API调用方式配置。 +按照功能角度进行划分,可以分为Dubbo Provider和Dubbo Consumer。接下来章节中,分别对dubbo provider和Dubbo consumer进行讲解。 + +### Dubbo Provider配置 + +#### Provider 配置详解 + +配置Dubbo Provider有4种方式:XML配置,properties方式配置,API调用方式配置,注解方式配置。 + +##### XML配置 + +###### 最简单的配置的样例: +``` + + + + + + + + +``` +上面样例中,注意下dubbo schema的写法: +``` + +``` + +###### 支持的配置标签 + +| 标签 | 用途 | 解释 | +| -------- | ----- | :---- | +| <dubbo:service/> | 服务配置 | 用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心 | +| <dubbo:reference/> | 引用配置 | 用于创建一个远程服务代理,一个引用可以指向多个注册中心 | +| <dubbo:protocol/> | 协议配置 | 用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受 | +| <dubbo:application/> | 应用配置 | 用于配置当前应用信息,不管该应用是提供者还是消费者 | +| <dubbo:module/> | 模块配置 | 用于配置当前模块信息,可选 | +| <dubbo:registry/> | 注册中心配置 | 用于配置连接注册中心相关信息 | +| <dubbo:monitor/> | 监控中心配置 | 用于配置连接监控中心相关信息,可选 | +| <dubbo:provider/> | 提供方配置 | 当 ProtocolConfig 和 ServiceConfig 某属性没有配置时,采用此缺省值,可选 | +| <dubbo:consumer/> | 消费方配置 | 当 ReferenceConfig 某属性没有配置时,采用此缺省值,可选 | +| <dubbo:method/> | 方法配置 | 用于 ServiceConfig 和 ReferenceConfig 指定方法级的配置信息 | +| <dubbo:argument/> | 参数配置 | 用于指定方法参数配置 | + +![配置之间关系图](/imgs/user/dubbo-config.jpg) + +###### 配置项详解 + +* <dubbo:application name="hello-world-app" /> +用于指定应用名,这里需要保证应用名唯一,这个应用名在后续的console admin中可以在列表中显示,方便管理。 + +* <dubbo:registry address="multicast://224.5.6.7:1234" /> +注册中心配置,和服务发现的具体机制有关系。可以是zookeeper地址,也可以eureka地址。上面这个是广播地址,在本地服务调用的测试过程中非常方便。 + +* <dubbo:protocol name="dubbo" port="20880" /> +这里是传输的协议和默认端口,一般不需要更改。 + +> 接下来重点讲解下<dubbo:service/>的配置。 + +* <dubbo:service/>支持的主要属性列表: + +| 属性名 | 说明 | +| -------- | ----- | +| version | 版本号 | +| scope | 服务可见性, 值为:local 或者 remote,默认为remote | +| actives | 最大的激活的请求数 | +| async | 方法调用是否异步,默认为false | +| cache | 服务缓存,可选值:lru/threadlocal/jcache | +| callbacks | callback实例的限制 | +| generic | 泛化调用,可以绕过 | +| class | Service的实现的类名 | +| connections | 这个服务里的连接数 | +| delay | 发布服务延迟的毫秒数 | +| executes | 服务执行的请求上限 | +| retries | 超时重试次数 | +| timeout | 调用超时时间 | + +其他配置属性请参考xsd:http://dubbo.apache.org/schema/dubbo/dubbo.xsd + +* <dubbo:method/>作为<dubbo:service/>的子元素,它可以针对方法进行配置。比较常用的属性有: + +| 属性名 | 说明 | +| -------- | ----- | +| executes | 服务执行的请求上限 | +| retries | 超时重试次数 | +| timeout | 调用超时时间 | + +其他属性,可以参考上面的xsd。 + +###### 配置的覆盖关系 +![配置的覆盖关系图](/imgs/user/dubbo-config-override.jpg) + +这里的覆盖关系包含了Provider和Consumer两端的配置,如果对consumer有疑问,可以参考后一章节的consumer章节之后再来理解。 + +#### dubbo.properties方式配置 + +> 如果公共配置很简单,没有多注册中心,多协议等情况,或者想多个 Spring 容器想共享配置,可以使用 dubbo.properties 作为缺省配置。 + +Dubbo 将自动加载 classpath 根目录下的 dubbo.properties,可以通过JVM启动参数 -Ddubbo.properties.file=xxx.properties 改变缺省配置位置。 + +###### dubbo.properties配置样例 +``` +# 应用名 +dubbo.application.name=dubbodemo-provider +# 注册中心地址 +dubbo.registry.address=zookeeper://localhost:2181 +# 广播的注册中心样例 +#dubbo.registry.address=multicast://224.5.6.7:1234 +# 调用协议地址 +dubbo.protocol.name=dubbo +dubbo.protocol.port=28080 +``` +###### 映射规则 +将 XML 配置的标签名,加属性名,用点分隔,多个属性拆成多行 +* 比如:dubbo.application.name=foo等价于 +* 比如:dubbo.registry.address=10.20.153.10:9090等价于 + +如果 XML 有多行同名标签配置,可用 id 号区分,如果没有 id 号将对所有同名标签生效 +* 比如:dubbo.protocol.rmi.port=1234等价于 +* 比如:dubbo.registry.china.address=10.20.153.10:9090等价于 + +###### 覆盖策略 +![覆盖策略](/imgs/user/dubbo-config.jpg) + +* JVM 启动 -D 参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口。 +* XML 次之,如果在 XML 中有配置,则 dubbo.properties 中的相应配置项无效。 +* Properties 最后,相当于缺省值,只有 XML 没有配置时,dubbo.properties 的相应配置项才会生效,通常用于共享公共配置,比如应用名。 + +> 注意: +1. 如果 classpath 根目录下存在多个 dubbo.properties,比如多个 jar 包中有 dubbo.properties,Dubbo 会任意加载,并打印 Error 日志,后续可能改为抛异常。 ↩ +2. 协议的 id 没配时,缺省使用协议名作为 id + +##### 注解配置 + +###### Service注解暴露服务 +``` +import com.alibaba.dubbo.config.annotation.Service; + +@Service(timeout = 5000) +public class AnnotateServiceImpl implements AnnotateService { + // ... +} +``` +###### javaconfig形式配置公共模块 + +``` +@Configuration +public class DubboConfiguration { + + @Bean + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("provider-test"); + return applicationConfig; + } + + @Bean + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("zookeeper://127.0.0.1:2181"); + registryConfig.setClient("curator"); + return registryConfig; + } +} +``` + +这种方式的配置和前面用xml配置的方式是一样的效果。 + +###### 指定dubbo扫描路径 +``` +@SpringBootApplication +@DubboComponentScan(basePackages = "com.alibaba.dubbo.test.service.impl") +public class ProviderTestApp { + // ... +} +``` +或者使用spring bean xml配置方式: +``` + +``` + +##### 代码配置 + +``` +import com.alibaba.dubbo.rpc.config.ApplicationConfig; +import com.alibaba.dubbo.rpc.config.RegistryConfig; +import com.alibaba.dubbo.rpc.config.ProviderConfig; +import com.alibaba.dubbo.rpc.config.ServiceConfig; +import com.xxx.XxxService; +import com.xxx.XxxServiceImpl; + +// 服务实现 +XxxService xxxService = new XxxServiceImpl(); + +// 当前应用配置 +ApplicationConfig application = new ApplicationConfig(); +application.setName("xxx"); + +// 连接注册中心配置 +RegistryConfig registry = new RegistryConfig(); +registry.setAddress("10.20.130.230:9090"); +registry.setUsername("aaa"); +registry.setPassword("bbb"); + +// 服务提供者协议配置 +ProtocolConfig protocol = new ProtocolConfig(); +protocol.setName("dubbo"); +protocol.setPort(12345); +protocol.setThreads(200); + +// 注意:ServiceConfig为重对象,内部封装了与注册中心的连接,以及开启服务端口 + +// 服务提供者暴露服务配置 +ServiceConfig service = new ServiceConfig(); // 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏 +service.setApplication(application); +service.setRegistry(registry); // 多个注册中心可以用setRegistries() +service.setProtocol(protocol); // 多个协议可以用setProtocols() +service.setInterface(XxxService.class); +service.setRef(xxxService); +service.setVersion("1.0.0"); + +// 暴露及注册服务 +service.export(); +``` + +一般在spring应用中,不推荐使用这种方式。 具体的含义这里不做解释,可以通过github查看源码。 + +### Provider 接口和实现 + +上面章节更多从配置角度出发,接下来通过一个完整的例子,来讲解下dubbo provider的完整使用。 + +这个例子中只有一个服务UserReadService,有一个方法 getUserById。 需要将这个服务通过Dubbo暴露给远程的服务。具体的步骤如下: + +1.创建工程 +如果本来已经有工程,可以忽略。创建一个spring boot工程,可以通过 https://start.spring.io/ 创建。 +2.定义接口 +定义接口:UserReadService +``` +public interface UserReadService{ +public User getUserById(Long userId); +} +``` +这个接口一般来说会放到独立的jar包里,作为client包。 其他应用要消费这个服务的时候,一般来说需要应用引用这个client包。(除了泛化调用) +3.实现接口 +实现UserReadService, 当前实现部署在Provider的应用中。 +``` +public UserReadServiceImpl implements UserReadService{ + public User getUserById(Long userId){ + return xxx; + } +} +``` +4.Dubbo配置 +``` + + + + + + + + +``` +Dubbo配置的其他方式可以参考上一章节的相关配置,或者使用集成dubbo spring boot starter方式。 diff --git a/content/en/blog/java/demos/dubbo-cluster-error-handling.md b/content/en/blog/java/demos/dubbo-cluster-error-handling.md new file mode 100644 index 000000000000..b15b318488d7 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-cluster-error-handling.md @@ -0,0 +1,273 @@ +--- +title: "Dubbo 集群容错" +linkTitle: "Dubbo 集群容错" +tags: ["Java"] +date: 2018-08-22 +description: > + 在分布式系统中,集群某个某些节点出现问题是大概率事件,因此在设计分布式RPC框架的过程中,必须要把失败作为设计的一等公民来对待。一次调用失败之后,应该如何选择对失败的选择策略,这是一个见仁见智的问题,每种策略可能都有自己独特的应用场景。因此,作为框架来说,应当针对不同场景提供多种策略,供用户进行选择。本文介绍了Dubbo框架提供的多种错误处理策略,并通过实例说明如何进行配置。 +--- + + +### Design For failure + +在分布式系统中,集群某个某些节点出现问题是大概率事件,因此在设计分布式RPC框架的过程中,必须要把失败作为设计的一等公民来对待。一次调用失败之后,应该如何选择对失败的选择策略,这是一个见仁见智的问题,每种策略可能都有自己独特的应用场景。因此,作为框架来说,应当针对不同场景提供多种策略,供用户进行选择。 + +在Dubbo设计中,通过Cluster这个接口的抽象,把一组可供调用的Provider信息组合成为一个统一的`Invoker`供调用方进行调用。经过路由规则过滤,负载均衡选址后,选中一个具体地址进行调用,如果调用失败,则会按照集群配置的容错策略进行容错处理。 + +Dubbo默认内置了若干容错策略,如果不能满足用户需求,则可以通过自定义容错策略进行配置。 + +### 内置容错策略 + +Dubbo主要内置了如下几种策略: + +* Failover(失败自动切换) +* Failsafe(失败安全) +* Failfast(快速失败) +* Failback(失败自动恢复) +* Forking(并行调用) +* Broadcast(广播调用) + +这些名称比较相似,概念也比较容易混淆,下面逐一进行解释。 + +#### Failover(失败自动切换) + +`Failover`是高可用系统中的一个常用概念,服务器通常拥有主备两套机器配置,如果主服务器出现故障,则自动切换到备服务器中,从而保证了整体的高可用性。 + +Dubbo也借鉴了这个思想,并且把它作为Dubbo`默认的容错策略`。当调用出现失败的时候,根据配置的重试次数,会自动从其他可用地址中重新选择一个可用的地址进行调用,直到调用成功,或者是达到重试的上限位置。 + +Dubbo里默认配置的重试次数是2,也就是说,算上第一次调用,最多会调用3次。 + + + +其配置方法,容错策略既可以在服务提供方配置,也可以服务调用方进行配置。而重试次数的配置则更为灵活,既可以在服务级别进行配置,也可以在方法级别进行配置。具体优先顺序为: + +``` +服务调用方方法级配置 > 服务调用方服务级配置 > 服务提供方方法级配置 > 服务提供方服务级配置 +``` + +以XML方式为例,具体配置方法如下: + +服务提供方,服务级配置 + +```xml + +``` + +服务提供方,方法级配置 + +```xml + + +
+``` + +服务调用方,服务级配置 + +```xml + +``` + +服务调用方,方法级配置: + +```xml + + + +``` + +Failover可以自动对失败进行重试,对调用者屏蔽了失败的细节,但是Failover策略也会带来一些副作用: + +* 重试会额外增加一下开销,例如增加资源的使用,在高负载系统下,额外的重试可能让系统雪上加霜。 +* 重试会增加调用的响应时间。 +* 某些情况下,重试甚至会造成资源的浪费。考虑一个调用场景,A->B->C,如果A处设置了超时100ms,再B->C的第一次调用完成时已经超过了100ms,但很不幸B->C失败,这时候会进行重试,但其实这时候重试已经没有意义,因此在A看来这次调用已经超时,A可能已经开始执行其他逻辑。 + +#### Failsafe(失败安全) + +失败安全策略的核心是即使失败了也不会影响整个调用流程。通常情况下用于旁路系统或流程中,它的失败不影响核心业务的正确性。在实现上,当出现调用失败时,会忽略此错误,并记录一条日志,同时返回一个空结果,在上游看来调用是成功的。 + +应用场景,可以用于写入审计日志等操作。 + +具体配置方法: + +服务提供方,服务级配置 + +```xml + +``` + +服务调用方,服务级配置 + +```xml + +``` + +其中服务调用方配置优先于服务提供方配置。 + +#### Failfast(快速失败) + +某些业务场景中,某些操作可能是非幂等的,如果重复发起调用,可能会导致出现脏数据等。例如调用某个服务,其中包含一个数据库的写操作,如果写操作完成,但是在发送结果给调用方的过程中出错了,那么在调用发看来这次调用失败了,但其实数据写入已经完成。这种情况下,重试可能并不是一个好策略,这时候就需要使用到`Failfast`策略,调用失败立即报错。让调用方来决定下一步的操作并保证业务的幂等性。 + +具体配置方法: + +服务提供方,服务级配置 + +```xml + +``` + +服务调用方,服务级配置 + +```xml + +``` + +其中服务调用方配置优先于服务提供方配置。 + +#### Failback(失败自动恢复) + +`Failback`通常和`Failover`两个概念联系在一起。在高可用系统中,当主机发生故障,通过`Failover`进行主备切换后,待故障恢复后,系统应该具备自动恢复原始配置的能力。 + +Dubbo中的`Failback`策略中,如果调用失败,则此次失败相当于`Failsafe`,将返回一个空结果。而与`Failsafe`不同的是,Failback策略会将这次调用加入内存中的失败列表中,对于这个列表中的失败调用,会在另一个线程中进行异步重试,重试如果再发生失败,则会忽略,即使重试调用成功,原来的调用方也感知不到了。因此它通常适合于,对于实时性要求不高,且不需要返回值的一些异步操作。 + +具体配置方法: + +服务提供方,服务级配置 + +```xml + +``` + +服务调用方,服务级配置 + +```xml + +``` + +其中服务调用方配置优先于服务提供方配置。 + +按照目前的实现,Failback策略还有一些局限,例如内存中的失败调用列表没有上限,可能导致堆积,异步重试的执行间隔无法调整,默认是5秒。 + +#### Forking(并行调用) + +上述几种策略中,主要都是针对调用失败发生后如何进行弥补的角度去考虑的,而`Forking`策略则跟上述几种策略不同,是一种典型的用成本换时间的思路。即第一次调用的时候就同时发起多个调用,只要其中一个调用成功,就认为成功。在资源充足,且对于失败的容忍度较低的场景下,可以采用此策略。 + +具体配置方法: + +服务提供方,服务级配置 + +```xml + +``` + +服务调用方,服务级配置 + +```xml + +``` + +其中服务调用方配置优先于服务提供方配置。 + +#### Broadcast(广播调用) + +在某些场景下,可能需要对服务的所有提供者进行操作,此时可以使用广播调用策略。此策略会逐个调用所有提供者,只要任意有一个提供者出错,则认为此次调用出错。通常用于通知所有提供者更新缓存或日志等本地资源信息。 + +具体配置方法: + +服务提供方,服务级配置 + +```xml + +``` + +服务调用方,服务级配置 + +```xml + +``` + +其中服务调用方配置优先于服务提供方配置。 + +#### 各种策略对比 + +下表对各种策略做一个简单对比, + +| 策略名称 | 优点 | 缺点 | 主要应用场景 | +| --------- | -------------------------------- | -------------------------------------- | ---------------------------------------------------- | +| Failover | 对调用者屏蔽调用失败的信息 | 增加RT,额外资源开销,资源浪费 | 对调用rt不敏感的场景 | +| Failfast | 业务快速感知失败状态进行自主决策 | 产生较多报错的信息 | 非幂等性操作,需要快速感知失败的场景 | +| Failsafe | 即使失败了也不会影响核心流程 | 对于失败的信息不敏感,需要额外的监控 | 旁路系统,失败不影响核心流程正确性的场景 | +| Failback | 失败自动异步重试 | 重试任务可能堆积 | 对于实时性要求不高,且不需要返回值的一些异步操作 | +| Forking | 并行发起多个调用,降低失败概率 | 消耗额外的机器资源,需要确保操作幂等性 | 资源充足,且对于失败的容忍度较低,实时性要求高的场景 | +| Broadcast | 支持对所有的服务提供者进行操作 | 资源消耗很大 | 通知所有提供者更新缓存或日志等本地资源信息 | + +### 自定义容错策略 + +如果上述内置的容错策略无法满足你的需求,还可以通过扩展的方式来实现自定义容错策略。 + +#### 扩展接口 + +`com.alibaba.dubbo.rpc.cluster.Cluster` + +#### 扩展配置 + +```xml + +``` + +#### 扩展示例 + +下面通过一个例子来展示如何使用自定义的容错策略。 +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxCluster.java (实现Cluster接口) + |-resources + |-META-INF + |-dubbo + |-org.apache.dubbo.rpc.cluster.Cluster (纯文本文件,内容为:xxx=com.xxx.XxxCluster) +``` + +XxxCluster.java: + +```java +package com.xxx; + +import org.apache.dubbo.rpc.cluster.Cluster; +import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker; +import org.apache.dubbo.rpc.cluster.Directory; +import org.apache.dubbo.rpc.cluster.LoadBalance; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Result; +import org.apache.dubbo.rpc.RpcException; + +import java.util.List; + +public class XxxCluster implements Cluster { + + @Override + public Invoker join(Directory directory) throws RpcException { + return new AbstractClusterInvoker() { + @Override + protected Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { + // your custimzed fault tolarence strategy goes here + } + }; + } + +} +``` + +`META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.Cluster`文件的内容为 + +``` +xxx=com.xxx.XxxCluster +``` + + + diff --git a/content/en/blog/java/demos/dubbo-compatible.md b/content/en/blog/java/demos/dubbo-compatible.md new file mode 100644 index 000000000000..5f922093b41e --- /dev/null +++ b/content/en/blog/java/demos/dubbo-compatible.md @@ -0,0 +1,198 @@ +--- +title: "Dubbo 2.7.x repackage 后的兼容实现方案" +linkTitle: "Dubbo 2.7.x repackage 后的兼容实现方案" +tags: ["Java"] +date: 2018-07-22 +description: > + 本文简单描述了2.7.x repackage后对老版本的兼容性实现方案。 +--- + +Dubbo至加入Apache孵化器以来,一个很强的诉求就是需要rename groupId和package name,这两项工作在项目毕业前需要完成。其中rename package相对来说复杂一些,除了要修改所有类的包名为`org.apache.dubbo`外,更多的是需要考虑如何老版本的兼容性。 + +常见的兼容性包括但不限于以下几种情况: + +* 用户API + * 编程API + * Spring注解 +* 扩展SPI + * 扩展Filter + +2.7.x里就是通过增加了一个新的模块`dubbo-compatible`来解决以上兼容性问题。 + +## 编程使用API + +编程使用API是最直接最原始的使用方式,其他方式诸如Spring schema、注解等方式都是基于原始API的;因此非常有必要对API编程形式进行兼容。 + +所有编程相关API的兼容代码均在`com.alibaba.dubbo.config`包下,下面我们看看几个常见API的兼容实现。 + +### ApplicationConfig + +```java +package com.alibaba.dubbo.config; + +@Deprecated +public class ApplicationConfig extends org.apache.dubbo.config.ApplicationConfig { + + public ApplicationConfig() { + super(); + } + + public ApplicationConfig(String name) { + super(name); + } +} +``` + +### ProtocolConfig + +```java +package com.alibaba.dubbo.config; + +@Deprecated +public class ProtocolConfig extends org.apache.dubbo.config.ProtocolConfig { + + public ProtocolConfig() { + } + + public ProtocolConfig(String name) { + super(name); + } + + public ProtocolConfig(String name, int port) { + super(name, port); + } +} +``` + +可以看到: + +1. 兼容类是直接通过继续repacakge后的类,达到最大程度的代码复用; +2. 构造函数也需要保持兼容; + +整个兼容包中,除了上述API以外,包括一些常用的类比如`Constants`、`URL`以及绝大部分的兼容类都是通过简单的继承,让用户基于老的API实现的类能正确运行。 + +## Spring注解 + +Spring注解诸如`@EnableDubbo`、`@Service`以及`@Reference`,由于不能使用继承,故这些注解类是通过代码拷贝来实现的;用于处理这些注解的Spring BeanPostProcessor以及Parser等相关的类,也是通过拷贝来实现; + +这类兼容代码分别位于兼容包的以下几个package中: + +* com.alibaba.dubbo.config.annotation +* com.alibaba.dubbo.config.spring.context.annotation +* org.apache.dubbo.config.spring + +所以这里要特别强调的是,这类代码在2.7.x里存在2份,因此有修改的同时需要同步修改。 + +## 扩展SPI + +Dubbo的SPI扩展机制,可以通过[Dubbo可扩展机制实战](/en/blog/2019/04/25/dubbo可扩展机制实战/)这篇博客详细了解。 + +以Filter扩展为例,简单来说就是: + +1. MyFilter需要实现Filter接口 +2. 在META-INF/dubbo下,增加META-INF/dubbo/com.alibaba.dubbo.rpc.Filter,内容为: + + ``` + myFilter=com.test.MyFilter + ``` + +看似简单的两点,对Dubbo框架来说,需要: + +1. 正确加载配置文件META-INF/dubbo/com.alibaba.dubbo.rpc.Filter +2. 正确加载MyFilter类并执行invoke方法 + +下面分别介绍Dubbo框架怎么实现以上几点。 + +### 正确加载META-INF/dubbo/com.alibaba.dubbo.rpc.Filter + +Dubbo SPI机制在查找配置文件时,是根据扩展点的类名来查找的,以Filter为例,在包名变为org.apache.dubbo后,查询的目录变成: + +* META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter +* META-INF/dubbo/org.apache.dubbo.rpc.Filter +* META-INF/services/org.apache.dubbo.rpc.Filter + +但是用户之前按老的包实现的Filter,其配置是放在类似`META-INF/dubbo/com.alibaba.dubbo.rpc.Filter`的,如果框架不做特殊处理,是不会加载老配置的。 + +因此在`ExtensionLoader`这个类里,做了特殊的处理: + +```java + // synchronized in getExtensionClasses + private Map> loadExtensionClasses() { + final SPI defaultAnnotation = type.getAnnotation(SPI.class); + if (defaultAnnotation != null) { + String value = defaultAnnotation.value(); + if ((value = value.trim()).length() > 0) { + String[] names = NAME_SEPARATOR.split(value); + if (names.length > 1) { + throw new IllegalStateException("more than 1 default extension name on extension " + type.getName() + + ": " + Arrays.toString(names)); + } + if (names.length == 1) cachedDefaultName = names[0]; + } + } + + Map> extensionClasses = new HashMap>(); + loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName()); + loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba")); + loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName()); + loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba")); + loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName()); + loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba")); + return extensionClasses; + } +``` + +可以看到,除了加载新配置外,老配置文件也会进行扫描。 + +### 正确加载MyFilter类 + +`com.alibaba.dubbo.rpc.Filter`接口除了要继承自`org.apache.dubbo.rpc.Filter`以外,其唯一的方法invoke也需要做特殊处理。我们看看它的方法签名: + +`Result invoke(Invoker invoker, Invocation invocation) throws RpcException;` + +这里参数、返回值、异常都会被实现类`MyFilter`用到,因此这些类也需要有兼容类;而参数、返回值不同,对于接口来说是不同的方法,因此: + +* 需要在com.alibaba.dubbo.rpc.Filter里,定义老的invoke方法,MyFilter会覆盖这个方法; +* org.apache.dubbo.rpc.Filter里的invoke方法,需要找一个地方来实现桥接,框架调用Filter链执行到新的invoke方法时,新的参数如何转换成老参数,老返回值如何转换成新的返回值; + +这里就用到了JDK8的新特性:接口default方法。 + +```java +@Deprecated +public interface Filter extends org.apache.dubbo.rpc.Filter { + + Result invoke(Invoker invoker, Invocation invocation) throws RpcException; + + default org.apache.dubbo.rpc.Result invoke(org.apache.dubbo.rpc.Invoker invoker, + org.apache.dubbo.rpc.Invocation invocation) + throws org.apache.dubbo.rpc.RpcException { + Result.CompatibleResult result = (Result.CompatibleResult) invoke(new Invoker.CompatibleInvoker<>(invoker), + new Invocation.CompatibleInvocation(invocation)); + return result.getDelegate(); + } +} +``` + +可以看到,default方法里,对参数进行了包装,然后调用老的invoke方法,并将返回值进行解包后返回给Dubbo框架。这里Result.CompatibleResult、Invocation.CompatibleInvocation以及Invoker.CompatibleInvoker都用到了代理模式。 + +感兴趣的同学可以详细看一下以下几个类: + +* com.alibaba.dubbo.rpc.Invocation +* com.alibaba.dubbo.rpc.Invoker +* com.alibaba.dubbo.rpc.Result + +## 后续todo list + +目前兼容包仅仅是对常见的API及SPI做了支持,列表如下: + +* com.alibaba.dubbo.rpc.Filter / Invocation / Invoker / Result / RpcContext / RpcException +* com.alibaba.dubbo.config.*Config +* com.alibaba.dubbo.config.annotation.Reference / Service +* com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo +* com.alibaba.dubbo.common.Constants / URL +* com.alibaba.dubbo.common.extension.ExtensionFactory +* com.alibaba.dubbo.common.serialize.Serialization / ObjectInput / ObjectOutput +* com.alibaba.dubbo.cache.CacheFactory / Cache +* com.alibaba.dubbo.rpc.service.EchoService / GenericService + +大家如果在试用的过程中发现有任何问题请及时提出;同时如果对其他扩展点有兼容需求,也请大家提出来,也非常欢迎大家自己解决并贡献出来。 diff --git a/content/en/blog/java/demos/dubbo-consistent-hash-implementation.md b/content/en/blog/java/demos/dubbo-consistent-hash-implementation.md new file mode 100644 index 000000000000..f3de4e0e1141 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-consistent-hash-implementation.md @@ -0,0 +1,287 @@ +--- +title: "Dubbo 一致性Hash负载均衡实现剖析" +linkTitle: "Dubbo 一致性Hash负载均衡实现剖析" +tags: ["Java"] +date: 2019-05-01 +description: > + 本文以一般的一致性Hash实现作为引子,详细剖析了Dubbo一致性Hash负载均衡算法的实现 +--- + +需要强调的是,Dubbo的Hash映射模型与大部分网上资料描述的**环形队列Hash映射模型**是存在一些区别的。于我而言,环形队列Hash映射模型,不足以让我对一致性Hash有足够彻底的了解。直到看懂了Dubbo的一致性Hash的实现,才觉得豁然开朗。 + + + +### 一、环形队列Hash映射模型 + +这种方案,其基础还是基于取模运算。对2^32取模,那么,Hash值的区间为[0, 2^32-1]。接下来要做的,就包括两部分: + +#### **a、映射服务** + +将服务地址(ip+端口)按照一定规则构造出特定的识别码(如md5码),再用识别码对2^32取模,确定服务在Hash值区间对应的位置。假设有Node1、Node2、Node3三个服务,其映射关系如下: + +![Init](/imgs/blog/consistenthash/consistent-hash-init-model.jpg) + + + +#### **b、映射请求、定位服务** + +在发起请求时,我们往往会带上参数,而这些参数,就可以被我们用来确定具体调用哪一个服务。假设有请求R1、R2、R3,对它们的参数也经过计算特定识别码、取余的一系列运算之后,有如下映射关系: + +![Request](/imgs/blog/consistenthash/consistent-hash-request-model.jpg) + +从图中,我们可以看到,R1请求映射在0-Node1中间,R2请求映射在Node1-Node2中间,R3请求映射在Node2-Node3中间。我们取**服务Hash值大于等于请求Hash值**的**第一个服务**作为实际的调用服务。也就是说,R1请求将调用Node1服务,R2请求将调用Node2服务,R3请求将调用Node3服务。 + + + +#### **c、新增服务节点** + +假设新增服务Node4,映射在Node3之前,恰巧破坏了原来的一个映射关系: + +![New Node](/imgs/blog/consistenthash/consistent-hash-new-node-model.jpg) + +这样,请求R3将会实际调用服务Node4,但请求R1、R2不受影响。 + + + +#### **d、删除服务节点** + +假设服务Node2宕机,那么R2请求将会映射到Node3: + +![Delete Node](/imgs/blog/consistenthash/consistent-hash-delete-node-model.jpg) + +原本的R1、R3请求不受影响。 + + + +> 可以看出,当新增、删除服务时,受影响的请求是有限的。不至于像简单取模映射一般,服务发生变化时,需要调整全局的映射关系。 + + + +#### **e、平衡性与虚拟节点** + +在我们上面的假设中,我们假设Node1、Node2、Node3三个服务在经过Hash映射后所分布的位置恰巧把环切成了均等的三分,请求的分布也基本是平衡的。但是实际上计算服务Hash值的时候,是很难这么巧的。也许一不小心就映射成了这个样子: + +![Balance](/imgs/blog/consistenthash/consistent-hash-balance-model.jpg) + +这样,就会导致大部分请求都会被映射到Node1上。因此,引出了虚拟节点。 + +所谓虚拟节点,就是除了对服务本身地址进行Hash映射外,还通过在它地址上做些处理(比如Dubbo中,在ip+port的字符串后加上计数符1、2、3......,分别代表虚拟节点1、2、3),以达到同一服务映射多个节点的目的。通过引入虚拟节点,我们可以把上图中映射给Node1的请求进一步拆分: + +![Virtual Node](/imgs/blog/consistenthash/consistent-hash-virtual-node-model.jpg) + +如上图所示,若有请求落在Node3-Node1'区间,该请求应该是调用Node1'服务,但是因为Node1'是Node1的虚拟节点,所以实际调用的是Node1服务。通过引入虚拟节点,请求的分布就会比较平衡了。 + + + +### **二、Dubbo一致性Hash的使用与负载均衡策略的引入阶段** + +#### **a、如何使用一致性Hash作为Dubbo的负载均衡策略?** + +dubbo:service、dubbo:reference、dubbo:provider、dubbo:consumer、dubbo:method这几个配置项都可以配置Dubbo的负载均衡策略,其中一致性Hash的属性值是:**consistenthash**。 + +以dubbo:reference为例: + +**XML配置:** + +> + + + +**Properties配置:** + +> dubbo.reference.loadbalance=consistenthash + + + +**注解:** + +> @Reference(loadbalance = "consistenthash") + + + +#### **b、Dubbo负载均衡策略的引入阶段** + +Dubbo实现的是客户端负载均衡。关于服务接口代理类的实现,这里不做详细描述,可以参考官网: + +> 服务引入:/zh-cn/docs/source_code_guide/refer-service.html + +在接口代理类生成、并且装配好后,服务的调用基本是这样一个流程:proxy -> MockClusterInvoker -> 集群策略(如:FailoverClusterInvoker) -> 初始化负载均衡策略 -> 根据选定的负载均衡策略确定Invoker。 + +**负载均衡策略的初始化**是在AbstractClusterInvoker中的initLoadBalance方法中初始化的: + +```java +protected LoadBalance initLoadBalance(List> invokers, Invocation invocation) { + if (CollectionUtils.isNotEmpty(invokers)) { + return ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl() + .getMethodParameter(RpcUtils.getMethodName(invocation), LOADBALANCE_KEY, DEFAULT_LOADBALANCE)); + } else { + return ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(DEFAULT_LOADBALANCE); + } +} +``` + +这部分代码逻辑分为两部分: + +1、获取调用方法所配置的LOADBALANCE_KEY属性的值,LOADBALANCE_KEY这个常量的实际值为:loadbalance,即为我们的所配置的属性; + +2、利用SPI机制来初始化并加载该值所代表的负载均衡策略。 + + + +所有的负载均衡策略都会继承LoadBalance接口。在各种集群策略中,最终都会调用AbstractClusterInvoker的select方法,而AbstractClusterInvoker会在doSelect中,**调用LoadBalance的select方法,这里即开始了负载均衡策略的执行。** + + + +### 三、Dubbo一致性Hash负载均衡的实现 + +需要说明的一点是,我所说的**负载均衡策略的执行**,即是在所有的Provider中选出一个,作为当前Consumer的远程调用对象。在代码中,Provider被封装成了Invoker实体,所以直接说来,负载均衡策略的执行就是在Invoker列表中选出一个Invoker。 + +所以,对比普通一致性Hash的实现,Dubbo的一致性Hash算法也可以分为两步: + +**1、映射Provider至Hash值区间中(实际中映射的是Invoker);** + +**2、映射请求,然后找到大于等于请求Hash值的第一个Invoker。** + + + +#### **a、映射Invoker** + +Dubbo中所有的负载均衡实现类都继承了AbstractLoadBalance,调用LoadBalance的select方法时,实际上调用的是AbstractLoadBalance的实现: + +```java +@Override +public Invoker select(List> invokers, URL url, Invocation invocation) { + if (CollectionUtils.isEmpty(invokers)) { + return null; + } + if (invokers.size() == 1) { + return invokers.get(0); + } + // doSelect这里进入具体负载均衡算法的执行逻辑 + return doSelect(invokers, url, invocation); +} +``` + +可以看到这里调用了doSelect,Dubbo一致性Hash的具体实现类名字是**ConsistentHashLoadBalance**,让我们来看看它的doSelect方法干了啥: + +```java +@Override +protected Invoker doSelect(List> invokers, URL url, Invocation invocation) { + String methodName = RpcUtils.getMethodName(invocation); + // key格式:接口名.方法名 + String key = invokers.get(0).getUrl().getServiceKey() + "." + methodName; + // identityHashCode 用来识别invokers是否发生过变更 + int identityHashCode = System.identityHashCode(invokers); + ConsistentHashSelector selector = (ConsistentHashSelector) selectors.get(key); + if (selector == null || selector.identityHashCode != identityHashCode) { + // 若不存在"接口.方法名"对应的选择器,或是Invoker列表已经发生了变更,则初始化一个选择器 + selectors.put(key, new ConsistentHashSelector(invokers, methodName, identityHashCode)); + selector = (ConsistentHashSelector) selectors.get(key); + } + return selector.select(invocation); +} +``` + +这里有个很重要的概念:**选择器——selector**。这是Dubbo一致性Hash实现中,承载着整个映射关系的数据结构。它里面主要有这么几个参数: + +```java +/** + * 存储Hash值与节点映射关系的TreeMap + */ +private final TreeMap> virtualInvokers; + +/** + * 节点数目 + */ +private final int replicaNumber; + +/** + * 用来识别Invoker列表是否发生变更的Hash码 + */ +private final int identityHashCode; + +/** + * 请求中用来作Hash映射的参数的索引 + */ +private final int[] argumentIndex; +``` + +在新建ConsistentHashSelector对象的时候,就会遍历所有Invoker对象,然后计算出其地址(ip+port)对应的md5码,并按照配置的节点数目replicaNumber的值来初始化服务节点和所有虚拟节点: + +```java +ConsistentHashSelector(List> invokers, String methodName, int identityHashCode) { + this.virtualInvokers = new TreeMap>(); + this.identityHashCode = identityHashCode; + URL url = invokers.get(0).getUrl(); + // 获取配置的节点数目 + this.replicaNumber = url.getMethodParameter(methodName, HASH_NODES, 160); + // 获取配置的用作Hash映射的参数的索引 + String[] index = COMMA_SPLIT_PATTERN.split(url.getMethodParameter(methodName, HASH_ARGUMENTS, "0")); + argumentIndex = new int[index.length]; + for (int i = 0; i < index.length; i++) { + argumentIndex[i] = Integer.parseInt(index[i]); + } + // 遍历所有Invoker对象 + for (Invoker invoker : invokers) { + // 获取Provider的ip+port + String address = invoker.getUrl().getAddress(); + for (int i = 0; i < replicaNumber / 4; i++) { + byte[] digest = md5(address + i); + for (int h = 0; h < 4; h++) { + long m = hash(digest, h); + virtualInvokers.put(m, invoker); + } + } + } +} +``` + +这里值得注意的是:以replicaNumber取默认值160为例,假设当前遍历到的Invoker地址为127.0.0.1:20880,它会依次获得“127.0.0.1:208800”、“127.0.0.1:208801”、......、“127.0.0.1:2088040”的md5摘要,在每次获得摘要之后,还会对该摘要进行四次数位级别的散列。大致可以猜到其目的应该是为了加强散列效果。(希望有人能告诉我相关的理论依据。) + +代码中 **virtualInvokers.put(m, invoker)** 即是存储当前计算出的Hash值与Invoker的映射关系。 + +这段代码简单说来,就是为每个Invoker都创建replicaNumber个节点,Hash值与Invoker的映射关系即象征着一个节点,这个关系存储在TreeMap中。 + + + +#### **b、映射请求** + +让我们重新回到ConsistentHashLoadBalance的**doSelect**方法,若没有找到selector则会新建selector,找到selector后便会调用selector的select方法: + +```java +public Invoker select(Invocation invocation) { + // 根据invocation的【参数值】来确定key,默认使用第一个参数来做hash计算 + String key = toKey(invocation.getArguments()); + // 获取【参数值】的md5编码 + byte[] digest = md5(key); + return selectForKey(hash(digest, 0)); +} + +// 根据参数索引获取参数,并将所有参数拼接成字符串 +private String toKey(Object[] args) { + StringBuilder buf = new StringBuilder(); + for (int i : argumentIndex) { + if (i >= 0 && i < args.length) { + buf.append(args[i]); + } + } + return buf.toString(); +} + +// 根据参数字符串的md5编码找出Invoker +private Invoker selectForKey(long hash) { + Map.Entry> entry = virtualInvokers.ceilingEntry(hash); + if (entry == null) { + entry = virtualInvokers.firstEntry(); + } + return entry.getValue(); +} +``` + +argumentIndex是在初始化Selector的时候一起赋值的,代表着需要用哪几个请求参数作Hash映射获取Invoker。比如:有方法methodA(Integer a, Integer b, Integer c),如果argumentIndex的值为{0,2},那么即用a和c拼接的字符串来计算Hash值。 + +我们已经知道virtualInvokers是一个TreeMap,TreeMap的底层实现是红黑树。对于TreeMap的方法ceilingEntry(hash),它的作用是用来**获取大于等于传入值的首个元素**。可以看到,这一点与一般的一致性Hash算法的处理逻辑完全是相同的。 + +但这里的回环逻辑有点不同。对于取模运算来讲,大于最大值后,会自动回环从0开始,而这里的逻辑是:当没有比传入ceilingEntry()方法中的值大的元素的时候,virtualInvokers.ceilingEntry(hash)必然会得到null,于是,就用virtualInvokers.firstEntry()来获取整个TreeMap的第一个元素。 + +从selectForKey中获取到Invoker后,负载均衡策略也就算是执行完毕了。后续获取远程调用客户端等调用流程不再赘述。 diff --git a/content/en/blog/java/demos/dubbo-context-information.md b/content/en/blog/java/demos/dubbo-context-information.md new file mode 100644 index 000000000000..e0430a4239e8 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-context-information.md @@ -0,0 +1,61 @@ +--- +title: "Dubbo 上下文信息" +linkTitle: "Dubbo 上下文信息" +tags: ["Java"] +date: 2018-07-12 +description: > + 介绍Dubbo上下文信息的作用、应用场景、使用方式以及注意事项 +--- + +## 简介 +上下文信息是一次 RPC 调用过程中附带的环境信息,如方法名、参数类型、真实参数、本端/对端地址等。这些数据仅属于一次调用,作用于 Consumer 到 Provider 调用的整个流程。 + +提供上下文信息是 RPC 框架很重要的一个功能,使用上下文不仅可以为单次调用指定不同配置,还能在此基础上提供强大的上层功能,如分布式链路追踪。其实现原理就是在上下文中维护一个`span_id`,Consumer 和 Provider 通过传递`span_id`来连接一次RPC调用,分别上报日志后可以在追踪系统中串联并展示完整的调用流程。这样可以更方便地发现异常,定位问题。 + + +## 使用说明 +Dubbo中代表上下文的类是`org.apache.dubbo.rpc.RpcContext`,可通过下述代码来获取上下文信息。 +``` +RpcContext.getContext() +``` +## 使用场景 +### 获取调用信息 +| 方法名 | 用途 | 作用范围 | 说明 | +| :--------------------- | ---------------------------- | -------- | ------------------------------------------------------------ | +| getRequest | 获取 RPC 请求对象 | Consumer | 获取底层 RPC 请求对象,例如 HttpServletRequest,其他情况为 null | +| getResponse | 获取 RPC 请求响应 | Consumer | 获取底层 RPC 响应对象,例如HttpServletResponse,其他情况为 null | +| isProviderSide | 当前是否属于 Provider 上下文 | Both | 服务被调用时为 true,调用其他服务时为false | +| isConsumerSide | 当前是否属于 Consumer 上下文 | Both | 服务被调用时为 false,调用其他服务时为 true | +| getUrls | 获取当前能调用的 Url 列表 | Both | Consumer 端会根据不同的 Failover 策略实时变化 | +| getRemotePort | 获取远端端口 | Both | Consumer 端为最后一次调用的 Provider 端口,Provider 为当前请求的 Consumer 端口 | +| getRemoteHost | 获取远端主机地址 | Both | | +| getRemoteHostName | 获取远端主机名 | Both | | +| getRemoteAddressString | 获取远端地址 | Both | | +| getRemoteAddress | 获取远端地址 | Both | | +| getLocalPort | 获取本端端口 | Both | | +| getLocalHost | 获取本端主机地址 | Both | | +| getLocalHostName | 获取本端主机名 | Both | | +| getLocalAddressString | 获取本端地址 | Both | | +| getLocalAddress | 获取本端地址 | Both | | + + + +### 传递用户参数 + +#### 本端传递 + +调用`get`和`set`方法即可完成参数传递。主要用于本端 Filter 之间的数据共享。 + +#### 对端传递 + +调用`setAttachment`和`getAttachment`即可完成对端数据传递,这些数据会经过 RPC 传递到对端。例如 Consumer 向 Provider 传递`span_id`。 + +- Dubbo已经支持从 Provider 端向 Consumer 端传递参数,读写方式和 Consumer 端调用时的方式一样。 + +### 异步调用 + +在异步调用时,可通过`getCompletableFuture`或`getFuture`获取相关的 Future,异步调用相关文档请参阅:[异步调用](/en/docs/advanced/async-call/) + +## 注意事项 + +Dubbo 内部使用 ThreadLocal 的方式存储每次调用的上下文信息,当接收到请求或发起请求时,当前线程会更新 RpcContext。例如,服务 A 调用服务 B,服务 B 调用服务 C,在 B 调 C 之前,RpcContext 记录的是 A 调 B 的信息,在 B 调 C 之后,RpcContext 记录的是 B 调 C 的信息。 diff --git a/content/en/blog/java/demos/dubbo-contribute-to-opensource.md b/content/en/blog/java/demos/dubbo-contribute-to-opensource.md new file mode 100644 index 000000000000..ddf8ebe6bd27 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-contribute-to-opensource.md @@ -0,0 +1,191 @@ +--- +title: "以 Dubbo 为例,聊聊如何向开源项目做贡献" +linkTitle: "以 Dubbo 为例,聊聊如何向开源项目做贡献" +tags: ["Java"] +date: 2018-06-03 +description: > + 本文将会以 dubbo 项目为例向你阐释,给开源项目做贡献并不是一件难事 +--- + +Github 上有众多优秀的开源项目,大多数 IT 从业者将其当做了予取予求的工具库,遇到什么需求,先去 Github 搜一把,但有没有想过有一天自己也可以给开源事业做一些贡献呢?本文将会以 dubbo 项目为例,向你阐释,给开源项目做贡献并不是一件难事。 + +## 1 为何要给开源贡献力量 + +为开源项目做贡献得到的收益是多方面的,为了让你有足够的信心加入到开源项目中,我在文章最开始列举出它的诸多好处。 + +### 1.1 巩固技能 + +无论你是提交代码,撰写文档,提交 Issue,组织活动,当你切身参与到一个开源项目中,相关的技能都会得到历练,并且在开源项目中找到自己的位置。一方面,日常工作中我们中的大多数人接触到的是业务场景,并没有太多机会接触到基础架构组件,开源项目为我们提供了一个平台,在这里,你可以尽情挑选自己熟悉的项目为它添砖加瓦(以 Dubbo 为例,并不是所有 IT 公司都有能力自研服务治理框架);另一方面,你所提交的代码,会有管理员协助审核,他们会给出专业的建议,更好的代码规范以及更优的编程思路最终都会变成你的经验。 + +### 1.2 结交朋友 + +开源社区为你提供了一个平台,在这里,你可以认识很多纯粹的技术爱好者,开源贡献者是最符合 geek 定义的那群人,你所接触到的往往是某个领域最厉害的那批人。 + +### 1.3 建立口碑 + +这是一个很好的展示个人实力的地方,俗话说:talk is cheap,show me the code. 作为技术人员,没有什么比一个漂亮的 Github 主页更有说服力的了。如果你能够为开源项目做出可观的贡献,你也将收获到业界的知名度,此时开源项目的成就和你是密不可分的。 + +### 1.4 传承开源精神 + +只有源源不断的贡献者给开源项目添砖加瓦,才可以为 Github 一类的开源社区形成良好的开源风气。否则,只有输出没有输入,开源会失去活力。 + +### 1.5 养成习惯 + +相信我,一旦养成了每天提交代码的习惯,就像你不想中断打卡一样,你绝不想中断 commit。不止有英语打卡,健身打卡,还有开源打卡! + + +## 2 贡献代码时的一些疑难杂症 + +如果你是一名开源界的新手,可能会对贡献的流程心生畏惧。比如:我该怎么修改代码并提交?我的代码要是存在bug怎么办?我的代码别人会不会很 low?我该如何寻找合适的开源项目?开源社区那么多的工具和词汇都是什么意思? + +文章的第二部分将从一个**小白**的角度,介绍一下开源中的一些常见问题。 + +### 2.1 git 常规操作 + +一般而言,我们选择使用 git 来作为版本管理的工具,你不一定要非常熟练的使用它,在我看来掌握 clone,add,commit,pull,push 即可,遇到复杂的场景,你还有谷歌。 + +**fork 与 clone** + + +如果你只是想下载源码,查看他的源码实现,使用 Clone or download 按钮即可。 + +如果你想要给开源项目做改动,并且最终请求合并,让开源项目存在你贡献的代码,就应该使用 fork。 + +fork 将会复制一份当前主分支的代码进入到你的仓库中,之后你所有的修改,应当基于自己的仓库进行,在功能开发/bug 修复之后,可以使用你的仓库向源仓库提交 pull request。只有源仓库的管理员才有权利合并你的请求。 + +一些可能对你有帮助的高级指令。 + +```shell +# 设置源仓库 +git remote add upstream https://github.com/apache/dubbo.git +# 拉取源仓库的更新 +git fetch upstream +# 将自己仓库的主分支合并源仓库的更新 +git checkout master +git merge upstream/master +``` + +**pull request** + + +pull request 经常被缩写为 PR,指的是一次向源仓库请求合并的行为,如上是我 fork 了 dubbo 的仓库之后才存在的操作按钮。 + +**源仓库视角的 pull request** + + +管理者会对 pull request 涉及的改动进行 review,以确保你的代码是符合规范的,逻辑有没有偏差,以及符合框架的功能需求。 + +### 2.2 Travis CI + +一些自动化的 CI 流程被植入在每一次 pull request 的构建之中,用于给开源仓库去校验提交者的代码是否符合既定的规范,如:是否有编译问题,单元测试是否通过,覆盖率是否达标,代码风格是否合规等等。 + + +一般情况下,必须通过 CI,你的 pull request 才会被管理 review。 + +### 2.3 Mailing list + +每个开源项目都会有自己的贡献规范,可以参考首页的 Contributing,来获取具体的信息。dubbo 作为一个孵化中的 apache 项目,遵守了 apache 的传统,在 [Contributing](https://github.com/apache/dubbo/blob/master/CONTRIBUTING.md) 中描述道:当你有新特性想要贡献给 Dubbo 时,官方推荐使用 Mailing list 的方式描述一遍你想要做的改动。 + +Mailing list 简单来说,就是一个邮件通知机制,所有的 Dubbo 开发者都会订阅该邮箱:dev@dubbo.apache.org。有任何新特性的改动,或者什么建议想要通知其他开发者,都可以通过向该邮箱发送邮件来达到这个目的,相同地,你也会收到其转发的其他开发者的邮件。 + +或者你是一个 Dubbo 的使用者,你想要得知开发者的改造方向,也可以订阅,这个[指南](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide)可以帮助你订阅 Dubbo 的 Mailing list。 + +> 作为一个 modern developer,你可能觉得 mailing list 的交流方式存在滞后性,这样的沟通方式不是特别的高效,但它作为 apache 项目的推荐交流方式存在其特殊的原因,在此不多赘述。总之遵循一个原则:bug fix或者讨论,可以在 github issue 中进行,影响较大的特性和讨论则推荐在 mailing list 中展开。 + +## 3 其他贡献形式 + +不仅仅只有贡献代码,修复 bug 等行为才算作为开源做贡献,以下这些行为也属于主要形式: + +### 3.1 撰写文档 + + [Dubbo文档](/)是其开源组成成分的重要一环,其内容源文件位于:[https://github.com/apache/dubbo-website](https://github.com/apache/dubbo-website)。同样也是一个 Git 仓库,任何你想要对 dubbo 知识点的补充,都可以在这儿提交 pull request,只需要一些 markdown 的语法知识,和一些可有可无的 npm 语法即可。如果你觉得贡献代码对于现在的自己仍然有点难度,不妨从贡献文档开始接触开源。 + +### 3.2 ISSUE + +无论是 Github 中的 Issue 还是 mailing list 中的讨论,无论是提出问题,汇报 bug,还是回答问题(bugfix 则不仅仅需要 Issue 了),协助管理者 review pull request,都是贡献的一种形式,勿以善小而不为。 + +### 3.3 其他行为 + +任何你能够想到的,可以帮助开源项目变得更好的的行为,都属于开源贡献。例如,给每个 Issue 打上合适的 tag,关闭重复的 Issue,链接相关联的 Issue,线下组织沙龙,回答 Stack Overflow 上相关的问题,以及文档中一个错别字的修改等等。 + +## 4 开源最佳实践 + +### 4.1 有效沟通 + +无论你处于什么样的目的:仅仅是一次性的贡献,亦或是永久性的加入社区,都的和他人进行沟通和交往,这是你要在开源圈发展必须修炼的技能。 + +在你开启一个issue或PR之前,或者是在聊天室问问题之前,请牢记下面所列出的几点建议,会让你的工作更加的高效。 + +**给出上下文** 以便于让其他人能够快速的理解。比方说你运行程序时遇到一个错误,要解释你是如何做的,并描述如何才能再现错误现象。又比方说你是提交一个新的想法,要解释你为什么这么想,对于项目有用处吗(不仅仅是只有你!) + +> 😇 *“当我做 Y 的时候 X 不能工作”* +> +> 😢 *“X 出问题! 请修复它。”* + +**在进一步行动前,做好准备工作。** 不知道没关系,但是要展现你尝试过、努力过。在寻求帮助之前,请确认阅读了项目的 README、文档、问题(开放的和关闭的)、邮件列表,并搜索了网络。当你表现出很强烈的求知欲的时候,人们是非常欣赏这点的,会很乐意的帮助你。 + +> 😇 *“我不确定 X 是如何实现的,我查阅了相关的帮助文档,然而毫无所获。”* +> +> 😢 *“我该怎么做 X ?”* + +**保持请求内容短小而直接。** 正如发送一份邮件,每一次的贡献,无论是多么的简单,都是需要他人去查阅的。很多项目都是请求的人多,提供帮助的人少。相信我,保持简洁,你能得到他人帮助的机会会大大的增加。 + +> 😇 *“我很乐意写 API 教程。”* +> +> 😢 *” 有一天我驾驶汽车行驶在高速公路上,在某个加油站加油的时候,突发奇想,我们应该这么做,不过在我进一步解释之前,我先和大家展示一下。。。”* + +**让所有的沟通都是在公开场合下进行。** 哪怕是很不起眼的小事,也不要去给维护者发私信,除非是你要分享一些敏感信息(诸如安全问题或严重的过失)。你若能够保持谈话是公开的,很多人可以你们交换的意见中学习和受益。 + +> 😇 *(评论) “@维护者 你好!我们该如何处理这个PR?”* +> +> 😢 *(邮件) “你好,非常抱歉给发信,但是我实在很希望你能看一下我提交的PR。”* + +**大胆的提问(但是要谨慎!)。** 每个人参与社区,开始的时候都是新手,哪怕是非常有经验的贡献者也一样,在刚进入一个新的项目的时候,也是新手。出于同样的原因,甚至长期维护人员并不总是熟悉一个项目的每一部分。给他们同样的耐心,你也会得到同样的回报。 + +> 😇 *“感谢查看了这个错误,我按照您的建议做了,这是输出结果。”* +> +> 😢 *“你为什么不修复我的问题?这难道不是你的项目吗?”* + +**尊重社区的决定。** 你的想法可能会和社区的优先级、愿景等有差异,他们可能对于你的想法提供了反馈和最后的决定的理由,这时你应该去积极的讨论,并寻求妥协的办法,维护者必须慎重的考虑你的想法。但是如果你实在是不能同意社区的做法,你可以坚持自己!保持自己的分支,或者另起炉灶。 + +> 😇 *“你不能支持我的用例,我蛮失望,但是你的解释仅仅是对一小部分用户起作用,我理解是为什么。感谢你的耐心倾听。”* +> +> 😢 *“你为什么不支持我的用例?这是不可接受的!”* + +**以上几点,要铭记在心。** 开源是由来自世界各地的人们共同协作实现的。面临的问题是跨语言、跨文化、不同的地理为止、不同的时区,另外,撰写文字的沟通更是难上加难,无法传达语气和情绪。请让这些会话都充满善意吧!在以下情形中请保持礼貌:推动一个想法、请求更多的上下文、进一步澄清你的立场。既然你在互联网找到了自己的所需,那么请尝试让它变得更好! + +### 4.2 创建 issue + +你应该在遇到下列情况下,去创建一个 issue: + +- 报告你自己无法解决的错误 +- 讨论一个高级主题或想法 +- 期望实现某新的特性,或者其它项目的想法 + +在 issue 的沟通中几点实用的技巧: + +- **如果你刚好看到一个开放的issue,恰是你打算解决的,** 添加评论,告诉他人你将对此展开工作,并及时响应。这样的话,可以避免他人重复劳动。 +- **如果说某个issue已经开放很久了,** 这可能是已经有人正在解决中,又或者是早已经解决过了,所以也请添加评论,在打算开始工作之前,最好是确认一下。 +- **如果你创建了一个issue,但是没多久自己解决了,** 也要添加评论,让其他人知道,然后关闭该issue。记录本身就是对社区的贡献。 + +### 4.3 创建 pull request + +在下面的情形时,请你务必使用 PR: + +- 提交补丁 (例如,纠正拼写错误、损坏的链接、或者是其它较明显的错误) +- 开始一项别人请求的任务,或者是过去在issue中早就讨论过的 + +一个 PR 并不代表着工作已经完成。它通常是尽早的开启一个PR,是为了其他人可以观看或者给作者反馈意见。只需要在子标题标记为“WIP”(正在进行中)。作者可以在后面添加很多评论。 + +如果说项目是托管在 GitHub上的,以下是我们总结出的提交RP的建议: + +- **Fork 代码仓库** 并克隆到本地,在本地的仓库配置“上游”为远端仓库。这样你可以在提交你的PR时保持和“上游”同步,会减少很多解决冲突的时间。(更多关于同步的说明,请参考[这里](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork).) +- **创建一个分支** 用于自己编辑。 +- **参考任何相关的issue** 或者在你的RP中支持文档(比如. “Closes #37.”) +- **包含之前和之后的快照** 如果你的改动是包含了不同的 HTML/CSS。在你的PR中拖拉相应的图片。 +- **测试你的改动!** 若测试用例存在的话,跑一遍,以覆盖你的更改,若没有的话,则创建相应的用例。无论测试是否存在,一定要确保你的改动不会破坏掉现有的项目。 +- **和项目现有的风格保持一致** 尽你最大的努力,这也就是意味着在使用缩进、分号、以及注释很可能和你自己的风格大相径庭,但是为了节省维护者的精力,以及未来他人更好的理解和维护,还请你容忍一下。 + +## 5 成为一个开源贡献者 + +如果你有志于参与开源事业,可以尝试从自己最熟悉的项目开始,开源并不是属于高级开发者的专属词汇,它就是由你我这样的人在需求,修复,构建中演进下去的。Let's try it ! diff --git a/content/en/blog/java/demos/dubbo-copywriting-style.md b/content/en/blog/java/demos/dubbo-copywriting-style.md new file mode 100644 index 000000000000..4eaba2e4dd0e --- /dev/null +++ b/content/en/blog/java/demos/dubbo-copywriting-style.md @@ -0,0 +1,253 @@ +--- +title: "Dubbo 博客文档中文排版指南" +linkTitle: "Dubbo 博客文档中文排版指南" +tags: ["Java"] +date: 2018-01-01 +description: > + 统一中文文案、排版的相关用法,降低团队成员之间的沟通成本,增强网站气质。 +--- + +# Dubbo 博客文档中文排版指南 + +[TOC] + +## 空格 + +「有研究显示,打字的时候不喜欢在中文和英文之间加空格的人,感情路都走得很辛苦,有七成的比例会在 34 岁的时候跟自己不爱的人结婚,而其余三成的人最后只能把遗产留给自己的猫。毕竟爱情跟书写都需要适时地留白。与大家共勉之。」—— [vinta/paranoid-auto-spacing](https://github.com/vinta/pangu.js) + +### 中英文之间需要增加空格 + +正确: + +> 在 LeanCloud 上,数据存储是围绕 `AVObject` 进行的。 + +错误: + +> 在LeanCloud上,数据存储是围绕`AVObject`进行的。 + +> 在 LeanCloud上,数据存储是围绕`AVObject` 进行的。 + +完整的正确用法: + +> 在 LeanCloud 上,数据存储是围绕 `AVObject` 进行的。每个 `AVObject` 都包含了与 JSON 兼容的 key-value 对应的数据。数据是 schema-free 的,你不需要在每个 `AVObject` 上提前指定存在哪些键,只要直接设定对应的 key-value 即可。 + +例外:「豆瓣FM」等产品名词,按照官方所定义的格式书写。 + +### 中文与数字之间需要增加空格 + +正确: + +> 今天出去买菜花了 5000 元。 + +错误: + +> 今天出去买菜花了 5000元。 + +> 今天出去买菜花了5000元。 + +### 数字与单位之间需要增加空格 + +正确: + +> 我家的光纤入户宽带有 10 Gbps,SSD 一共有 20 TB。 + +错误: + +> 我家的光纤入户宽带有 10Gbps,SSD 一共有 10TB。 + +例外:度/百分比与数字之间不需要增加空格: + +正确: + +> 今天是 233° 的高温。 + +> 新 MacBook Pro 有 15% 的 CPU 性能提升。 + +错误: + +> 今天是 233 ° 的高温。 + +> 新 MacBook Pro 有 15 % 的 CPU 性能提升。 + +### 全角标点与其他字符之间不加空格 + +正确: + +> 刚刚买了一部 iPhone,好开心! + +错误: + +> 刚刚买了一部 iPhone ,好开心! + +### `-ms-text-autospace` to the rescue? + +Microsoft 有个 [`-ms-text-autospace`](http://msdn.microsoft.com/en-us/library/ie/ms531164(v=vs.85).aspx) 的 CSS 属性可以实现自动为中英文之间增加空白。不过目前并未普及,另外在其他应用场景,例如 OS X、iOS 的用户界面目前并不存在这个特性,所以请继续保持随手加空格的习惯。 + +## 标点符号 + +### 不重复使用标点符号 + +正确: + +> 德国队竟然战胜了巴西队! + +> 她竟然对你说「喵」?! + +错误: + +> 德国队竟然战胜了巴西队!! + +> 德国队竟然战胜了巴西队!!!!!!!! + +> 她竟然对你说「喵」??!! + +> 她竟然对你说「喵」?!?!??!! + +## 全角和半角 + +不明白什么是全角(全形)与半角(半形)符号?请查看维基百科词条『[全角和半角](http://zh.wikipedia.org/wiki/%E5%85%A8%E5%BD%A2%E5%92%8C%E5%8D%8A%E5%BD%A2)』。 + +### 使用全角中文标点 + +正确: + +> 嗨!你知道嘛?今天前台的小妹跟我说「喵」了哎! + +> 核磁共振成像(NMRI)是什么原理都不知道?JFGI! + +错误: + +> 嗨! 你知道嘛? 今天前台的小妹跟我说 “喵” 了哎! + +> 嗨!你知道嘛?今天前台的小妹跟我说”喵”了哎! + +> 核磁共振成像 (NMRI) 是什么原理都不知道? JFGI! + +> 核磁共振成像(NMRI)是什么原理都不知道?JFGI! + +### 数字使用半角字符 + +正确: + +> 这件蛋糕只卖 1000 元。 + +错误: + +> 这件蛋糕只卖 1000 元。 + +例外:在设计稿、宣传海报中如出现极少量数字的情形时,为方便文字对齐,是可以使用全角数字的。 + +### 遇到完整的英文整句、特殊名词,其內容使用半角标点 + +正确: + +> 乔布斯那句话是怎么说的?「Stay hungry, stay foolish.」 + +> 推荐你阅读《Hackers & Painters: Big Ideas from the Computer Age》,非常的有趣。 + +错误: + +> 乔布斯那句话是怎么说的?「Stay hungry,stay foolish。」 + +> 推荐你阅读《Hackers&Painters:Big Ideas from the Computer Age》,非常的有趣。 + +## 名词 + +### 专有名词使用正确的大小写 + +大小写相关用法原属于英文书写范畴,不属于本 wiki 讨论內容,在这里只对部分易错用法进行简述。 + +正确: + +> 使用 GitHub 登录 + +> 我们的客户有 GitHub、Foursquare、Microsoft Corporation、Google、Facebook, Inc.。 + +错误: + +> 使用 github 登录 + +> 使用 GITHUB 登录 + +> 使用 Github 登录 + +> 使用 gitHub 登录 + +> 使用 gイんĤЦ8 登录 + +> 我们的客户有 github、foursquare、microsoft corporation、google、facebook, inc.。 + +> 我们的客户有 GITHUB、FOURSQUARE、MICROSOFT CORPORATION、GOOGLE、FACEBOOK, INC.。 + +> 我们的客户有 Github、FourSquare、MicroSoft Corporation、Google、FaceBook, Inc.。 + +> 我们的客户有 gitHub、fourSquare、microSoft Corporation、google、faceBook, Inc.。 + +> 我们的客户有 gイんĤЦ8、キouЯƧquムгє、๓เςг๏ร๏Ŧt ς๏гק๏гคtเ๏ภn、900913、ƒ4ᄃëв๏๏к, IПᄃ.。 + +注意:当网页中需要配合整体视觉风格而出现全部大写/小写的情形,HTML 中请使用标准的大小写规范进行书写;并通过 `text-transform: uppercase;`/`text-transform: lowercase;` 对表现形式进行定义。 + +### 不要使用不地道的缩写 + +正确: + +> 我们需要一位熟悉 JavaScript、HTML5,至少理解一种框架(如 Backbone.js、AngularJS、React 等)的前端开发者。 + +错误: + +> 我们需要一位熟悉 Js、h5,至少理解一种框架(如 backbone、angular、RJS 等)的 FED。 + +## 争议 + +以下用法略带有个人色彩,即:无论是否遵循下述规则,从语法的角度来讲都是**正确**的。 + +### 链接之间增加空格 + +用法: + +> 请 [提交一个 issue](https://github.com/mzlogin/chinese-copywriting-guidelines) 并分配给相关同事。 + +> 访问我们网站的最新动态,请 [点击这里](https://github.com/mzlogin/chinese-copywriting-guidelines) 进行订阅! + +对比用法: + +> 请[提交一个 issue](https://github.com/mzlogin/chinese-copywriting-guidelines) 并分配给相关同事。 + +> 访问我们网站的最新动态,请[点击这里](https://github.com/mzlogin/chinese-copywriting-guidelines)进行订阅! + +### 简体中文使用直角引号 + +用法: + +> 「老师,『有条不紊』的『紊』是什么意思?」 + +对比用法: + +> “老师,‘有条不紊’的‘紊’是什么意思?” + +## 工具 + +| 仓库 | 语言 | +| ------------------------------------------------------------ | --------------- | +| [vinta/paranoid-auto-spacing](https://github.com/vinta/paranoid-auto-spacing) | JavaScript | +| [huacnlee/auto-correct](https://github.com/huacnlee/auto-correct) | Ruby | +| [sparanoid/space-lover](https://github.com/sparanoid/space-lover) | PHP (WordPress) | +| [nauxliu/auto-correct](https://github.com/NauxLiu/auto-correct) | PHP | +| [ricoa/copywriting-correct](https://github.com/ricoa/copywriting-correct) | PHP | +| [hotoo/pangu.vim](https://github.com/hotoo/pangu.vim) | Vim | +| [sparanoid/grunt-auto-spacing](https://github.com/sparanoid/grunt-auto-spacing) | Node.js (Grunt) | +| [hjiang/scripts/add-space-between-latin-and-cjk](https://github.com/hjiang/scripts/blob/master/add-space-between-latin-and-cjk) | Python | + +## 参考文献 + +- [Guidelines for Using Capital Letters](http://grammar.about.com/od/punctuationandmechanics/a/Guidelines-For-Using-Capital-Letters.htm) +- [Letter case - Wikipedia](http://en.wikipedia.org/wiki/Letter_case) +- [Punctuation - Oxford Dictionaries](http://www.oxforddictionaries.com/words/punctuation) +- [Punctuation - The Purdue OWL](https://owl.english.purdue.edu/owl/section/1/6/) +- [How to Use English Punctuation Corrently - wikiHow](http://www.wikihow.com/Use-English-Punctuation-Correctly) +- [格式 - openSUSE](https://zh.opensuse.org/index.php?title=Help:%E6%A0%BC%E5%BC%8F) +- [全角和半角 - 维基百科](http://zh.wikipedia.org/wiki/%E5%85%A8%E5%BD%A2%E5%92%8C%E5%8D%8A%E5%BD%A2) +- [引号 - 维基百科](http://zh.wikipedia.org/wiki/%E5%BC%95%E8%99%9F) +- [疑问惊叹号 - 维基百科](http://zh.wikipedia.org/wiki/%E7%96%91%E5%95%8F%E9%A9%9A%E5%98%86%E8%99%9F) + +> 统一中文文案、排版的相关用法,降低团队成员之间的沟通成本,增强网站气质。原文出处:https://github.com/mzlogin/chinese-copywriting-guidelines diff --git a/content/en/blog/java/demos/dubbo-echo-test.md b/content/en/blog/java/demos/dubbo-echo-test.md new file mode 100644 index 000000000000..316989ba38da --- /dev/null +++ b/content/en/blog/java/demos/dubbo-echo-test.md @@ -0,0 +1,101 @@ +--- +title: "回声测试" +linkTitle: "回声测试" +tags: ["Java"] +date: 2018-06-26 +description: > + 回声测试用于检测服务是否可用 +--- + +回声测试用于检测服务是否可用。客户端通过 EchoService 来使用回声测试。EchoService 申明如下: + +```Java +public interface EchoService { + + /** + * echo test. + * + * @param message message. + * @return message. + */ + Object $echo(Object message); + +} +``` +用户通过 $echo 方法发起的请求,会按照正常请求的流程执行,能够测试整个调用是否通畅,监控系统可以使用回声测试来检测服务可用性。 + +## 使用范例 + +所有服务引用自动实现 EchoService 接口,用户只需将服务引用强制转型为 EchoService,即可使用。配置和代码范例如下所示。 +Spring 配置: + +``` + +``` +代码: + +```Java +// 远程服务引用 +DemoService demoService= ctx.getBean("demoService"); +// 强制转型为EchoService +EchoService echoService = (EchoService) demoService; +// 回声测试可用性 +String status = echoService.$echo("OK"); +assert(status.equals("OK")); +``` +## 实现原理 + +我们在配置服务引用时,并没有配置 EchoService 这个接口,为什么可以直接把服务引用转型为 EchoService 呢? +用户拿到的服务引用其实是一个 Proxy,Dubbo 在生成 Proxy 的时候,已经默认将 EchoService 这个接口加入到 Proxy 的接口列表中,所以用户拿到的 Proxy 都已经实现了 EchoService。生成代理相关代码如下: + +```Java + public T getProxy(Invoker invoker, boolean generic) throws RpcException { + Class[] interfaces = null; + String config = invoker.getUrl().getParameter(Constants.INTERFACES); + if (config != null && config.length() > 0) { + String[] types = Constants.COMMA_SPLIT_PATTERN.split(config); + if (types != null && types.length > 0) { + interfaces = new Class[types.length + 2]; + interfaces[0] = invoker.getInterface(); + interfaces[1] = EchoService.class; + for (int i = 0; i < types.length; i++) { + // TODO can we load successfully for a different classloader?. + interfaces[i + 2] = ReflectUtils.forName(types[i]); + } + } + } + if (interfaces == null) { + interfaces = new Class[]{invoker.getInterface(), EchoService.class}; + } + + if (!GenericService.class.isAssignableFrom(invoker.getInterface()) && generic) { + int len = interfaces.length; + Class[] temp = interfaces; + interfaces = new Class[len + 1]; + System.arraycopy(temp, 0, interfaces, 0, len); + interfaces[len] = com.alibaba.dubbo.rpc.service.GenericService.class; + } + + return getProxy(invoker, interfaces); + } +``` +通过这种方式,任何服务引用都可以被转型成 EchoService 来使用。 +上面解释了客户端的实现,另外一边,用户在服务端也并没有实现 EchoService,那么客户端 EchoService 发出的调用在服务端是如何处理的呢?框架使用 Filter 机制来处理 EchoService 请求。Filter 实现代码如下: + +```Java +@Activate(group = Constants.PROVIDER, order = -110000) +public class EchoFilter implements Filter { + + @Override + public Result invoke(Invoker invoker, Invocation inv) throws RpcException { + if (inv.getMethodName().equals(Constants.$ECHO) && inv.getArguments() != null && inv.getArguments().length == 1) { + return new RpcResult(inv.getArguments()[0]); + } + return invoker.invoke(inv); + } + +} +``` +请求经过 EchoFilter.invoke 方法时,如果判定为 $echo 调用,则直接返回请求参数,否则继续执行 Filter 链。EchoFilter 默认加入到每一个服务提供者的 Filter 链里 EchoFilter.invoke 方法时,如果判定为 $echo 调用,则直接返回请求参数,否则继续执行 Filter 链。EchoFilter 默认加入到每一个服务提供者的 Filter 链里。这样每一个服务提供者自动具备了响应 EchoService 的能力。 + +通过上述分析,我们了解了框架是如何通过动态代理和 Filter 机制,使得用户可以透明地使用 EchoService 功能。 diff --git a/content/en/blog/java/demos/dubbo-externalized-configuration.md b/content/en/blog/java/demos/dubbo-externalized-configuration.md new file mode 100644 index 000000000000..0b486847888b --- /dev/null +++ b/content/en/blog/java/demos/dubbo-externalized-configuration.md @@ -0,0 +1,696 @@ +--- +title: "Dubbo 外部化配置" +linkTitle: "Dubbo 外部化配置" +tags: ["Java"] +date: 2018-05-21 +description: > +--- + +# Dubbo 外部化配置 + + + + +## 外部化配置 + +在[Dubbo 注解驱动](/en/blog/2018/08/07/dubbo-注解驱动/)例子中,无论是服务提供方,还是服务消费方,均需要转配相关配置Bean: + +```java + @Bean + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("dubbo-annotation-consumer"); + return applicationConfig; + } +``` + + + +虽然实现类似于`ProviderConfiguration` 和 `ConsumerConfiguration` 这样的 Spring `@Configuration` Bean 成本并不高,不过通过 Java Code 的方式定义配置 Bean,或多或少是一种 Hard Code(硬编码)的行为,缺少弹性。 + + + +尽管在 Spring 应用中,可以通过 `@Value` 或者 `Environment` 的方式获取外部配置,其代码简洁性以及类型转换灵活性存在明显的不足。因此,Spring Boot 提出了外部化配置(External Configuration)的感念,即通过程序以外的配置源,动态地绑定指定类型。 + + + +随着 Spring Boot / Spring Cloud 应用的流行,开发人员逐渐地接受并且使用 Spring Boot 外部化配置(External Configuration),即通过 `application.properties` 或者 `bootstrap.properties` 装配配置 Bean。 + + + +下列表格记录了 Dubbo 内置配置类: + +| 配置类 | 标签 | 用途 | 解释 | +| ------------------- | ---------------------- | ------ | ---------------------------------------- | +| `ProtocolConfig` | `` | 协议配置 | 用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受 | +| `ApplicationConfig` | `` | 应用配置 | 用于配置当前应用信息,不管该应用是提供者还是消费者 | +| `ModuleConfig` | `` | 模块配置 | 用于配置当前模块信息,可选 | +| `RegistryConfig` | `` | 注册中心配置 | 用于配置连接注册中心相关信息 | +| `MonitorConfig` | `` | 监控中心配置 | 用于配置连接监控中心相关信息,可选 | +| `ProviderConfig` | `` | 提供方配置 | 当 ProtocolConfig 和 ServiceConfig 某属性没有配置时,采用此缺省值,可选 | +| `ConsumerConfig` | `` | 消费方配置 | 当 ReferenceConfig 某属性没有配置时,采用此缺省值,可选 | +| `MethodConfig` | `` | 方法配置 | 用于 ServiceConfig 和 ReferenceConfig 指定方法级的配置信息 | +| `ArgumentConfig` | `` | 参数配置 | 用于指定方法参数配置 | + + + +通过申明对应的 Spring 扩展标签,在 Spring 应用上下文中将自动生成相应的配置 Bean。 + + + +在 Dubbo 官方用户手册的[“属性配置”](/en/overview/mannual/java-sdk/reference-manual/config/properties/)章节中,`dubbo.properties` 配置属性能够映射到 `ApplicationConfig` 、`ProtocolConfig` 以及 `RegistryConfig` 的字段。从某种意义上来说,`dubbo.properties` 也是 Dubbo 的外部化配置。 + + + +其中,引用“映射规则”的内容: + +>## 映射规则 +> +>将 XML 配置的标签名,加属性名,用点分隔,多个属性拆成多行 +> +>* 比如:`dubbo.application.name=foo`等价于`` +>* 比如:`dubbo.registry.address=10.20.153.10:9090`等价于`` +> +>如果 XML 有多行同名标签配置,可用 id 号区分,如果没有 id 号将对所有同名标签生效 +> +>* 比如:`dubbo.protocol.rmi.port=1234`等价于`` +>* 比如:`dubbo.registry.china.address=10.20.153.10:9090`等价于`` +> +>下面是 dubbo.properties 的一个典型配置: +> +>``` +>dubbo.application.name=foo +>dubbo.application.owner=bar +>dubbo.registry.address=10.20.153.10:9090 +>``` + + + +根据“映射规则”,Dubbo 即支持单配置 Bean 映射,也支持多 Bean 映射。综合以上需求,既要兼容 Dubbo 已有的一个或多个 Bean 字段映射绑定,也支持外部化配置。 + +> 特别提醒:外部化配置(External Configuration)并非 Spring Boot 特有,即使在 Spring Framework 场景下亦能支持。也就是说 Dubbo 外部化配置即可在 Spring Framework 中工作,也能在 Spring Boot 中运行。 + + + +Dubbo 外部化配置(External Configuration) 支持起始版本为:`2.5.8` + + + + + +### `@EnableDubboConfig` + + + +#### 起始版本:`2.5.8` + + + +#### 使用说明 + + + +##### `@EnableDubboConfig` 定义 + +```java +public @interface EnableDubboConfig { + + /** + * It indicates whether binding to multiple Spring Beans. + * + * @return the default value is false + * @revised 2.5.9 + */ + boolean multiple() default false; + +} +``` + + + +* `multiple` : 表示是否支持多Dubbo 配置 Bean 绑定。默认值为 `false` ,即单 Dubbo 配置 Bean 绑定 + + + +##### 单 Dubbo 配置 Bean 绑定 + + + +为了更好地向下兼容,`@EnableDubboConfig` 提供外部化配置属性与 Dubbo 配置类之间的绑定,其中映射关系如下: + +| 配置类 | 外部化配置属性前缀 | 用途 | +| ------------------- | ------------------- | ------ | +| `ProtocolConfig` | `dubbo.protocol` | 协议配置 | +| `ApplicationConfig` | `dubbo.application` | 应用配置 | +| `ModuleConfig` | `dubbo.module` | 模块配置 | +| `RegistryConfig` | `dubbo.registry` | 注册中心配置 | +| `MonitorConfig` | `dubbo.monitor` | 监控中心配置 | +| `ProviderConfig` | `dubbo.provider` | 提供方配置 | +| `ConsumerConfig` | `dubbo.consumer` | 消费方配置 | + + + +当标注 `@EnableDubboConfig` 的类被扫描注册后,同时 Spring(Spring Boot)应用配置(`PropertySources`)中存在`dubbo.application.*` 时,`ApplicationConfig` Bean 将被注册到在 Spring 上下文。否则,不会被注册。如果出现`dubbo.registry.*`的配置,那么,`RegistryConfig` Bean 将会创建,以此类推。即按需装配 Dubbo 配置 Bean。 + + + +如果需要指定配置 Bean的 id,可通过`**.id` 属性设置,以`dubbo.application` 为例: + +```properties +## application +dubbo.application.id = applicationBean +dubbo.application.name = dubbo-demo-application +``` + + + +以上配置等同于以下 Java Config Bean: + +```java + @Bean("applicationBean") + public ApplicationConfig applicationBean() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("dubbo-demo-application"); + return applicationConfig; + } +``` + + + +大致上配置属性与配置类绑定模式 - `dubbo.application.* ` 映射到 `ApplicationConfig` 中的字段。 + +> 注:当配置属性名称无法在配置类中找到字段时,将会忽略绑定 + + + + + +##### 多 Dubbo 配置 Bean 绑定 + + + +Dubbo `@Service` 和 `@Reference` 允许 Dubbo 应用关联`ApplicationConfig` Bean 或者指定多个`RegistryConfig` Bean 等能力。换句话说,Dubbo 应用上下文中可能存在多个`ApplicationConfig` 等 Bean定义。 + + + +为了适应以上需要,因此从Dubbo `2.5.9` 开始,`@EnableDubboConfig` 支持多 Dubbo 配置 Bean 绑定,同时按照业界规约标准,与单 Dubbo 配置 Bean 绑定约定不同,配置属性前缀均为英文复数形式: + +> 详情请参考 :https://github.com/alibaba/dubbo/issues/1141 + + + +* `dubbo.applications` +* `dubbo.modules` +* `dubbo.registries` +* `dubbo.protocols` +* `dubbo.monitors` +* `dubbo.providers` +* `dubbo.consumers` + + + +以`dubbo.applications` 为例,基本的模式如下: + +```properties +dubbo.applications.${bean-name}.property-name = ${property-value} +``` + + + +请读者注意,在单 Dubbo 配置 Bean 绑定时,可以通过指定`id` 属性的方式,定义`ApplicationConfig` Bean 的ID,即`dubbo.application.id`。 + +而在多 Dubbo 配置 Bean 绑定时,Bean ID 则由`dubbo.applications.`与属性字段名称(`.property-name`)之间的字符来表达。 + + + +如下配置: + +```properties +# multiple Bean definition +dubbo.applications.applicationBean.name = dubbo-demo-application +dubbo.applications.applicationBean2.name = dubbo-demo-application2 +dubbo.applications.applicationBean3.name = dubbo-demo-application3 +``` + + + +该配置内容中,绑定了三个`ApplicationConfig` Bean,分别是`applicationBean`、`applicationBean2`以及`applicationBean3` + + + +#### 示例说明 + + + +`@EnableDubboConfig` 的使用方法很简答, 再次强调一点,当规约的外部配置存在时,相应的 Dubbo 配置类 才会提升为 Spring Bean。简言之,按需装配。 + + + + + +##### 单 Dubbo 配置 Bean 绑定 + + + +###### 外部化配置文件 + + + +将以下内容的外部化配置文件物理路径为:`classpath:/META-INF/config.properties`: + +```properties +# 单 Dubbo 配置 Bean 绑定 +## application +dubbo.application.id = applicationBean +dubbo.application.name = dubbo-demo-application + +## module +dubbo.module.id = moduleBean +dubbo.module.name = dubbo-demo-module + +## registry +dubbo.registry.address = zookeeper://192.168.99.100:32770 + +## protocol +dubbo.protocol.name = dubbo +dubbo.protocol.port = 20880 + +## monitor +dubbo.monitor.address = zookeeper://127.0.0.1:32770 + +## provider +dubbo.provider.host = 127.0.0.1 + +## consumer +dubbo.consumer.client = netty +``` + + + +###### `@EnableDubboConfig` 配置 Bean + + + +```java +/** + * Dubbo 配置 Bean + * + * @author Mercy + */ +@EnableDubboConfig +@PropertySource("META-INF/config.properties") +@Configuration +public class DubboConfiguration { + +} +``` + + + +###### 实现引导类 + + + +```java +/** + * Dubbo 配置引导类 + * + * @author Mercy + */ +public class DubboConfigurationBootstrap { + + public static void main(String[] args) { + // 创建配置上下文 + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + // 注册当前配置 Bean + context.register(DubboConfiguration.class); + context.refresh(); + // application + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + System.out.printf("applicationBean.name = %s \n", applicationConfig.getName()); + + // module + ModuleConfig moduleConfig = context.getBean("moduleBean", ModuleConfig.class); + System.out.printf("moduleBean.name = %s \n", moduleConfig.getName()); + + // registry + RegistryConfig registryConfig = context.getBean(RegistryConfig.class); + System.out.printf("registryConfig.name = %s \n", registryConfig.getAddress()); + + // protocol + ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class); + System.out.printf("protocolConfig.name = %s \n", protocolConfig.getName()); + System.out.printf("protocolConfig.port = %s \n", protocolConfig.getPort()); + + // monitor + MonitorConfig monitorConfig = context.getBean(MonitorConfig.class); + System.out.printf("monitorConfig.name = %s \n", monitorConfig.getAddress()); + + // provider + ProviderConfig providerConfig = context.getBean(ProviderConfig.class); + System.out.printf("providerConfig.name = %s \n", providerConfig.getHost()); + + // consumer + ConsumerConfig consumerConfig = context.getBean(ConsumerConfig.class); + System.out.printf("consumerConfig.name = %s \n", consumerConfig.getClient()); + } +} +``` + + + +###### 执行结果 + + + +``` +applicationBean.name = dubbo-demo-application +moduleBean.name = dubbo-demo-module +registryConfig.name = zookeeper://192.168.99.100:32770 +protocolConfig.name = dubbo +protocolConfig.port = 20880 +monitorConfig.name = zookeeper://127.0.0.1:32770 +providerConfig.name = 127.0.0.1 +consumerConfig.name = netty +``` + + + +不难发现,`@EnableDubboConfig` 配置 Bean 配合外部化文件 `classpath:/META-INF/config.properties`,与执行输出内容相同。 + + + + + +##### 多 Dubbo 配置 Bean 绑定 + + + +###### 外部化配置文件 + + + +将以下内容的外部化配置文件物理路径为:`classpath:/META-INF/multiple-config.properties`: + +```properties +# 多 Dubbo 配置 Bean 绑定 +## dubbo.applications +dubbo.applications.applicationBean.name = dubbo-demo-application +dubbo.applications.applicationBean2.name = dubbo-demo-application2 +dubbo.applications.applicationBean3.name = dubbo-demo-application3 +``` + + + +###### `@EnableDubboConfig` 配置 Bean(多) + + + +```java +@EnableDubboConfig(multiple = true) +@PropertySource("META-INF/multiple-config.properties") +private static class DubboMultipleConfiguration { + +} +``` + + + +###### 实现引导类 + + + +```java +/** + * Dubbo 配置引导类 + * + * @author Mercy + */ +public class DubboConfigurationBootstrap { + public static void main(String[] args) { + // 创建配置上下文 + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + // 注册当前配置 Bean + context.register(DubboMultipleConfiguration.class); + context.refresh(); + + // 获取 ApplicationConfig Bean:"applicationBean"、"applicationBean2" 和 "applicationBean3" + ApplicationConfig applicationBean = context.getBean("applicationBean", ApplicationConfig.class); + ApplicationConfig applicationBean2 = context.getBean("applicationBean2", ApplicationConfig.class); + ApplicationConfig applicationBean3 = context.getBean("applicationBean3", ApplicationConfig.class); + + System.out.printf("applicationBean.name = %s \n", applicationBean.getName()); + System.out.printf("applicationBean2.name = %s \n", applicationBean2.getName()); + System.out.printf("applicationBean3.name = %s \n", applicationBean3.getName()); + } +} +``` + + + +###### 执行结果 + + + +``` +applicationBean.name = dubbo-demo-application +applicationBean2.name = dubbo-demo-application2 +applicationBean3.name = dubbo-demo-application3 +``` + + + +`@EnableDubboConfig(multiple = true)` 执行后,运行结果说明`ApplicationConfig` Bean 以及 ID 的定义方式。 + + + + + +### `@EnableDubboConfigBinding` & `@EnableDubboConfigBindings` + + + +`@EnableDubboConfig`适合绝大多数外部化配置场景,然而无论是单 Bean 绑定,还是多 Bean 绑定,其**外部化配置属性前缀**是固化的,如`dubbo.application` 以及 `dubbo.applications` 。 + + + +当应用需要自定义**外部化配置属性前缀**,`@EnableDubboConfigBinding`能提供更大的弹性,支持单个外部化配置属性前缀(`prefix`) 与 Dubbo 配置 Bean 类型(`AbstractConfig` 子类)绑定,如果需要多次绑定时,可使用`@EnableDubboConfigBindings`。 + +> 尽管 Dubbo 推荐使用 Java 8 ,然而实际的情况,运行时的 JDK 的版本可能从 6到8 均有。因此,`@EnableDubboConfigBinding` 没有实现`java.lang.annotation.Repeatable`,即允许实现类不支持重复标注`@EnableDubboConfigBinding`。 + + + +`@EnableDubboConfigBinding` 在支持外部化配置属性与 Dubbo 配置类绑定时,与 Dubbo 过去的映射行为不同,被绑定的 Dubbo 配置类将会提升为 Spring Bean,无需提前装配 Dubbo 配置类。同时,支持多 Dubbo 配置Bean 装配。其 Bean 的绑定规则与`@EnableDubboConfig`一致。 + + + +#### 起始版本: `2.5.8` + + + +#### 使用说明 + + + +##### `@EnableDubboConfigBinding` 定义 + + + +```java +public @interface EnableDubboConfigBinding { + + /** + * The name prefix of the properties that are valid to bind to {@link AbstractConfig Dubbo Config}. + * + * @return the name prefix of the properties to bind + */ + String prefix(); + + /** + * @return The binding type of {@link AbstractConfig Dubbo Config}. + * @see AbstractConfig + * @see ApplicationConfig + * @see ModuleConfig + * @see RegistryConfig + */ + Class type(); + + /** + * It indicates whether {@link #prefix()} binding to multiple Spring Beans. + * + * @return the default value is false + */ + boolean multiple() default false; + +} +``` + + + +* `prefix()` : 指定待绑定 Dubbo 配置类的外部化配置属性的前缀,比如`dubbo.application` 为 `ApplicationConfig` 的外部化配置属性的前缀。`prefix()` 支持占位符(Placeholder), 并且其关联前缀值是否以"." 作为结尾字符是可选的,即`prefix() = "dubbo.application"` 与 `prefix() = "dubbo.application."` 效果相同 +* `type()` : 指定 Dubbo 配置类,所有 `AbstractConfig` 的实现子类即可,如`ApplicationConfig` 、`RegistryConfig` 以及 `ProtocolConfig` 等 +* `multiple()` : 表明是否需要将`prefix()` 作为多个 `type()` 类型的 Spring Bean 外部化配置属性。默认值为`false`,即默认支持单个类型的 Spring 配置 Bean + + + + +假设标注 `@EnableDubboConfigBinding` 的实现类被 Spring 应用上下文扫描并且注册后,其中`prefix()` = `dubbo.app` 、 `type()` = `ApplicationConfig.class` ,且外部配置内容为: + +```properties +dubbo.app.id = applicationBean +dubbo.app.name = dubbo-demo-application +``` + + + +Spring 应用上下文启动后,一个 ID 为 "applicationBean" 的 `ApplicationConfig` Bean 被初始化,其 `name` 字段被设置为 "dubbo-demo-application"。 + + + +##### `EnableDubboConfigBindings` 定义 + + + +```java +public @interface EnableDubboConfigBindings { + + /** + * The value of {@link EnableDubboConfigBindings} + * + * @return non-null + */ + EnableDubboConfigBinding[] value(); + +} +``` + + + +* `value` : 指定多个`EnableDubboConfigBinding`,用于实现外部化配置属性前缀(`prefix`) 与 Dubbo 配置 Bean 类型(`AbstractConfig` 子类)绑定。 + + + +#### 示例说明 + + + +##### 外部化配置文件 + + + +将以下内容的外部化配置文件物理路径为:`classpath:/META-INF/bindings.properties` + +```properties +# classpath:/META-INF/bindings.properties +## 占位符值 : ApplicationConfig 外部配置属性前缀 +applications.prefix = dubbo.apps. + +## 多 ApplicationConfig Bean 绑定 +dubbo.apps.applicationBean.name = dubbo-demo-application +dubbo.apps.applicationBean2.name = dubbo-demo-application2 +dubbo.apps.applicationBean3.name = dubbo-demo-application3 + +## 单 ModuleConfig Bean 绑定 +dubbo.module.id = moduleBean +dubbo.module.name = dubbo-demo-module + +## 单 RegistryConfig Bean 绑定 +dubbo.registry.address = zookeeper://192.168.99.100:32770 +``` + + + + + +##### `EnableDubboConfigBindings` 配置 Bean + + + +`DubboConfiguration` 作为 Dubbo 配置 Bean,除通过 `@EnableDubboConfigBinding` 绑定之外,还需要 `@PropertySource` 指定外部化配置文件(`classpath:/META-INF/bindings.properties`): + +```java +/** + * Dubbo 配置 Bean + * + * @author Mercy + */ +@EnableDubboConfigBindings({ + @EnableDubboConfigBinding(prefix = "${applications.prefix}", + type = ApplicationConfig.class, multiple = true), // 多 ApplicationConfig Bean 绑定 + @EnableDubboConfigBinding(prefix = "dubbo.module", // 不带 "." 后缀 + type = ModuleConfig.class), // 单 ModuleConfig Bean 绑定 + @EnableDubboConfigBinding(prefix = "dubbo.registry.", // 带 "." 后缀 + type = RegistryConfig.class) // 单 RegistryConfig Bean 绑定 +}) +@PropertySource("META-INF/bindings.properties") +@Configuration +public class DubboConfiguration { + +} +``` + + + + + +##### 实现引导类 + + + +通过之前的使用说明,当 `EnableDubboConfigBinding` 将外部配置化文件`classpath:/META-INF/dubbo.properties` 绑定到 `ApplicationConfig`后,其中 Spring Bean "applicationBean" 的 name 字段被设置成 "dubbo-demo-application"。同时, `EnableDubboConfigBinding` 所标注的 `DubboConfiguration` 需要被 Sring 应用上下文注册: + +```java +/** + * Dubbo 配置引导类 + * + * @author Mercy + */ +public class DubboConfigurationBootstrap { + + public static void main(String[] args) { + // 创建配置上下文 + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + // 注册当前配置 Bean + context.register(DubboConfiguration.class); + context.refresh(); + // 获取 ApplicationConfig Bean:"applicationBean"、"applicationBean2" 和 "applicationBean3" + ApplicationConfig applicationBean = context.getBean("applicationBean", ApplicationConfig.class); + ApplicationConfig applicationBean2 = context.getBean("applicationBean2", ApplicationConfig.class); + ApplicationConfig applicationBean3 = context.getBean("applicationBean3", ApplicationConfig.class); + + System.out.printf("applicationBean.name = %s \n", applicationBean.getName()); + System.out.printf("applicationBean2.name = %s \n", applicationBean2.getName()); + System.out.printf("applicationBean3.name = %s \n", applicationBean3.getName()); + + // 获取 ModuleConfig Bean:"moduleBean" + ModuleConfig moduleBean = context.getBean("moduleBean", ModuleConfig.class); + + System.out.printf("moduleBean.name = %s \n", moduleBean.getName()); + + // 获取 RegistryConfig Bean + RegistryConfig registry = context.getBean(RegistryConfig.class); + + System.out.printf("registry.address = %s \n", registry.getAddress()); + } +} +``` + + + +##### 运行结果 + + + +`DubboConfigurationBootstrap` 运行后控制台输出: + +``` +applicationBean.name = dubbo-demo-application +applicationBean2.name = dubbo-demo-application2 +applicationBean3.name = dubbo-demo-application3 +moduleBean.name = dubbo-demo-module +registry.address = zookeeper://192.168.99.100:32770 +``` + + + +输出的内容与`classpath:/META-INF/bindings.properties` 绑定的内容一致,符合期望。 diff --git a/content/en/blog/java/demos/dubbo-generic-invoke.md b/content/en/blog/java/demos/dubbo-generic-invoke.md new file mode 100644 index 000000000000..eff8ec932711 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-generic-invoke.md @@ -0,0 +1,180 @@ +--- +title: "Dubbo的泛化调用" +linkTitle: "Dubbo的泛化调用" +tags: ["Java"] +date: 2018-08-14 +description: > + 本文介绍了 Dubbo 泛化调用的使用场景及相关示例 +--- + + +以下几种场景可以考虑使用泛化调用: + +- 服务测试平台 +- API 服务网关 + +泛化调用主要用于消费端没有 API 接口的情况;不需要引入接口 jar 包,而是直接通过 GenericService 接口来发起服务调用,参数及返回值中的所有 POJO 均用 `Map` 表示。泛化调用对于服务端无需关注,按正常服务进行暴露即可。 + +下面来看看消费端如何使用泛化调用进行服务调用。 + +## 通过 Spring XML 配置进行泛化调用 + +在 Spring 配置申明 `generic="true"`,如: + +```xml + +``` + +需要使用的地方,通过强制类型转化为 GenericService 进行调用: + +```java +GenericService userService = (GenericService) context.getBean("userService"); +// primary param and return value +String name = (String) userService.$invoke("delete", new String[]{int.class.getName()}, new Object[]{1}); +System.out.println(name); +``` + +其中: + +1. GenericService 这个接口只有一个方法,名为 `$invoke`,它接受三个参数,分别为方法名、方法参数类型数组和参数值数组; +2. 对于方法参数类型数组 + 1. 如果是基本类型,如 int 或 long,可以使用 `int.class.getName()`获取其类型; + 2. 如果是基本类型数组,如 int[],则可以使用 `int[].class.getName()`; + 3. 如果是 POJO,则直接使用全类名,如 `com.alibaba.dubbo.samples.generic.api.Params`。 + +## 通过 API 编程进行泛化调用 + +``` +ApplicationConfig application = new ApplicationConfig(); +application.setName("api-generic-consumer"); + +RegistryConfig registry = new RegistryConfig(); +registry.setAddress("zookeeper://127.0.0.1:2181"); + +application.setRegistry(registry); + +ReferenceConfig reference = new ReferenceConfig(); +// 弱类型接口名 +reference.setInterface("com.alibaba.dubbo.samples.generic.api.IUserService"); +// 声明为泛化接口 +reference.setGeneric(true); + +reference.setApplication(application); + +// 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用 +GenericService genericService = reference.get(); + +String name = (String) genericService.$invoke("delete", new String[]{int.class.getName()}, new Object[]{1}); +System.out.println(name); +``` + +通过 API 的方式,不需要像 XML 的方式需要提前将服务配置好,可以动态构建 ReferenceConfig;相对 XML 来说,API 的方式更常见。 + +## 参数或返回值是 POJO 的场景 + +比如方法签名是 `User get(Params params);`其中 User 有 id 和 name 两个属性,Params 有 query 一个属性。 + +以下是消费端的调用代码: + +```java +String[] parameterTypes = new String[]{"com.alibaba.dubbo.samples.generic.api.Params"}; +Map params = new HashMap(); +param.put("class", "com.alibaba.dubbo.samples.generic.api.Params"); +param.put("query", "a=b"); +Object user = userService.$invoke("get", parameterTypes, new Object[]{param}); +System.out.println("sample one result: " + user); +``` + +上述代码的输出结果为: + +```shell +sample one result: {name=charles, id=1, class=com.alibaba.dubbo.samples.generic.api.User} +``` + +这里,Dubbo 框架会自动将 POJO 的返回值转换成 Map。可以看到,返回值 `user` 是一个 HashMap,里面分别存放了 name、id、class 三个 k/v。 + +#### 泛接口实现 + +泛接口实现方式主要用于服务端没有 API 接口的情况,参数及返回值中的所有 POJO 均用 Map 表示,通常用于框架集成,如实现一个通用的远程服务 Mock 框架,可通过实现 GenericService 接口处理所有服务请求。 + +### 服务端实现 GenericService + +```java +public class GenericServiceImpl implements GenericService { + @Override + public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException { + if (method.equals("hi")) { + return "hi, " + args[0]; + } else if (method.equals("hello")) { + return "hello, " + args[0]; + } + + return "welcome"; + } +} +``` + +### 服务端暴露服务 + +```java +ApplicationConfig application = new ApplicationConfig(); +application.setName("api-generic-provider"); + +RegistryConfig registry = new RegistryConfig(); +registry.setAddress("zookeeper://127.0.0.1:2181"); + +application.setRegistry(registry); + +GenericService genericService = new GenericServiceImpl(); + +ServiceConfig service = new ServiceConfig(); +service.setApplication(application); +service.setInterface("com.alibaba.dubbo.samples.generic.api.HelloService"); +service.setRef(genericService); +service.export(); + +ServiceConfig service2 = new ServiceConfig(); +service2.setApplication(application); +service2.setInterface("com.alibaba.dubbo.samples.generic.api.HiService"); +service2.setRef(genericService); +service2.export(); +``` + +同样,也可以使用 XML 配置的方式暴露服务;此时服务端是没有依赖 HiService 和 HelloService 这两个接口的。 + +### 消费端进行服务调用 + +```java +ApplicationConfig application = new ApplicationConfig(); +application.setName("api-generic-consumer"); + +RegistryConfig registry = new RegistryConfig(); +registry.setAddress("zookeeper://127.0.0.1:2181"); + +application.setRegistry(registry); + +ReferenceConfig reference = new ReferenceConfig(); +// 弱类型接口名 +reference.setInterface(HiService.class); +reference.setApplication(application); + +HiService hiService = (HiService) reference.get(); +System.out.println(hiService.hi("dubbo")); + +ReferenceConfig reference2 = new ReferenceConfig(); +// 弱类型接口名 +reference2.setInterface(HelloService.class); +reference2.setApplication(application); + +HelloService helloService = (HelloService) reference2.get(); +System.out.println(helloService.hello("community")); +``` + +同样,消费端也可以使用 XML 配置的方式引用服务,然后进行调用。这里可以看到调用方式为普通的服务调用,并非泛化调用。当然使用泛化调用也是可以的。 + +到这里为止,一个简易的服务 Mock 平台就成功上线了! + +## 其他 + +* 本文介绍的泛化调用和泛接口实现,都是在原生的 `Dubbo` 协议之上的。在 2.6.2 版本之前,其他协议如 http/hessian 等是不支持泛化调用的,2.6.3 版本将会对这两个协议的泛化调用做支持。 +* 本文中提到的相关示例代码可以在 dubbo-samples中找到:https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-generic \ No newline at end of file diff --git a/content/en/blog/java/demos/dubbo-gracefully-shutdown.md b/content/en/blog/java/demos/dubbo-gracefully-shutdown.md new file mode 100644 index 000000000000..19128a2401eb --- /dev/null +++ b/content/en/blog/java/demos/dubbo-gracefully-shutdown.md @@ -0,0 +1,115 @@ +--- +title: "Dubbo 优雅停机" +linkTitle: "Dubbo 优雅停机" +tags: ["Java"] +date: 2018-08-14 +description: > + 本文介绍了Dubbo优雅停机的原理和使用方式 +--- + +## 背景 + +对于任何一个线上应用,如何在服务更新部署过程中保证客户端无感知是开发者必须要解决的问题,即从应用停止到重启恢复服务这个阶段不能影响正常的业务请求。理想条件下,在没有请求的时候再进行更新是最安全可靠的,然而互联网应用必须要保证可用性,因此在技术层面上优化应用更新流程来保证服务在更新时无损是必要的。 + +传统的解决方式是通过将应用更新流程划分为手工摘流量、停应用、更新重启三个步骤,由人工操作实现客户端无对更新感知。这种方式简单而有效,但是限制较多:不仅需要使用借助网关的支持来摘流量,还需要在停应用前人工判断来保证在途请求已经处理完毕。这种需要人工介入的方式运维复杂度较高,只能适用规模较小的应用,无法在大规模系统上使用。 + +因此,如果在容器/框架级别提供某种自动化机制,来自动进行摘流量并确保处理完以到达的请求,不仅能保证业务不受更新影响,还可以极大地提升更新应用时的运维效率。 + +这个机制也就是优雅停机,目前Tomcat/Undertow/Dubbo等容器/框架都有提供相关实现。下面给出正式一些的定义:优雅停机是指在停止应用时,执行的一系列保证应用正常关闭的操作。这些操作往往包括等待已有请求执行完成、关闭线程、关闭连接和释放资源等,优雅停机可以避免非正常关闭程序可能造成数据异常或丢失,应用异常等问题。优雅停机本质上是JVM即将关闭前执行的一些额外的处理代码。 + +## 适用场景 + +- JVM主动关闭(`System.exit(int)`; +- JVM由于资源问题退出(`OOM`); +- 应用程序接受到`SIGTERM`或`SIGINT`信号。 + +## 配置方式 +### 服务的优雅停机 +在Dubbo中,优雅停机是默认开启的,停机等待时间为10000毫秒。可以通过配置`dubbo.service.shutdown.wait`来修改等待时间。 + +例如将等待时间设置为20秒可通过增加以下配置实现: + +```shell +dubbo.service.shutdown.wait=20000 +``` + +### 容器的优雅停机 +当使用`org.apache.dubbo.container.Main`这种容器方式来使用 Dubbo 时,也可以通过配置`dubbo.shutdown.hook`为`true`来开启优雅停机。 + +### 通过QOS优雅上下线 + +基于`ShutdownHook`方式的优雅停机无法确保所有关闭流程一定执行完,所以 Dubbo 推出了多段关闭的方式来保证服务完全无损。 + +多段关闭即将停止应用分为多个步骤,通过运维自动化脚本或手工操作的方式来保证脚本每一阶段都能执行完毕。 + +在关闭应用前,首先通过 QOS 的`offline`指令下线所有服务,然后等待一定时间确保已经到达请求全部处理完毕,由于服务已经在注册中心下线,当前应用不会有新的请求。这时再执行真正的关闭(`SIGTERM` 或` SIGINT`)流程,就能保证服务无损。 + +QOS可通过 telnet 或 HTTP 方式使用,具体方式请见[Dubbo-QOS命令使用说明](/en/docsv2.7/user/references/qos/)。 + +## 流程 + +Provider在接收到停机指令后 + +- 从注册中心上注销所有服务; +- 从配置中心取消监听动态配置; +- 向所有连接的客户端发送只读事件,停止接收新请求; +- 等待一段时间以处理已到达的请求,然后关闭请求处理线程池; +- 断开所有客户端连接。 + +Consumer在接收到停机指令后 + +- 拒绝新到请求,直接返回调用异常; +- 等待当前已发送请求执行完毕,如果响应超时则强制关闭连接。 + +当使用容器方式运行 Dubbo 时,在容器准备退出前,可进行一系列的资源释放和清理工。 + +例如使用 SpringContainer时,Dubbo 的ShutdownHook线程会执行`ApplicationContext`的`stop`和`close`方法,保证 Bean的生命周期完整。 + +## 实现原理 + +1. 在加载类`org.apache.dubbo.config.AbstractConfig`时,通过`org.apache.dubbo.config.DubboShutdownHook`向JVM注册 ShutdownHook。 + + ```java + /** + * Register the ShutdownHook + */ + public void register() { + if (!registered.get() && registered.compareAndSet(false, true)) { + Runtime.getRuntime().addShutdownHook(getDubboShutdownHook()); + } + } + ``` + +2. 每个ShutdownHook都是一个单独的线程,由JVM在退出时触发执行`org.apache.dubbo.config.DubboShutdownHook`。 + + ```java + /** + * Destroy all the resources, including registries and protocols. + */ + public void doDestroy() { + if (!destroyed.compareAndSet(false, true)) { + return; + } + // destroy all the registries + AbstractRegistryFactory.destroyAll(); + // destroy all the protocols + destroyProtocols(); + } + ``` + +3. 首先关闭所有注册中心,这一步包括: + - 从注册中心注销所有已经发布的服务; + - 取消订阅当前应用所有依赖的服务; + - 断开与注册中心的连接。 +4. 执行所有`Protocol`的`destroy()`,主要包括: + - 销毁所有`Invoker`和`Exporter`; + - 关闭Server,向所有已连接Client发送当前Server只读事件; + - 关闭独享/共享Client,断开连接,取消超时和重试任务; + - 释放所有相关资源。 +5. 执行完毕,关闭JVM。 + +## 注意事项 + +- 使用`SIGKILL`关闭应用不会执行优雅停机; +- 优雅停机不保证会等待所有已发送/到达请求结束; +- 配置的优雅停机等待时间`timeout`不是所有步骤等待时间的总和,而是每一个`destroy`执行的最大时间。例如配置等待时间为5秒,则关闭Server、关闭Client等步骤会分别等待5秒。 diff --git a/content/en/blog/java/demos/dubbo-heartbeat-design.md b/content/en/blog/java/demos/dubbo-heartbeat-design.md new file mode 100644 index 000000000000..e2cfff1fe955 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-heartbeat-design.md @@ -0,0 +1,387 @@ +--- +title: "Dubbo 现有心跳方案总结以及改进建议" +linkTitle: "Dubbo 现有心跳方案总结以及改进建议" +tags: ["Java"] +date: 2018-08-19 +description: > + 本文介绍了一种心跳,两种设计 +--- + +### 1 前言 + +设计一个好的心跳机制并不是一件容易的事,就我所熟知的几个 RPC 框架,它们的心跳机制可以说大相径庭,这篇文章我将探讨一下**如何设计一个优雅的心跳机制,主要从 Dubbo 的现有方案以及一个改进方案来做分析**。 + +### 2 预备知识 + +因为后续我们将从源码层面来进行介绍,所以一些服务治理框架的细节还需要提前交代一下,方便大家理解。 + +#### 2.1 客户端如何得知请求失败了? + +高性能的 RPC 框架几乎都会选择使用 Netty 来作为通信层的组件,非阻塞式通信的高效不需要我做过多的介绍。但也由于非阻塞的特性,导致其发送数据和接收数据是一个异步的过程,所以当存在服务端异常、网络问题时,客户端是接收不到响应的,那么我们如何判断一次 RPC 调用是失败的呢? + +误区一:Dubbo 调用不是默认同步的吗? + +Dubbo 在通信层是异步的,呈现给使用者同步的错觉是因为内部做了阻塞等待,实现了异步转同步。 + +误区二: `Channel.writeAndFlush` 会返回一个 `channelFuture`,我只需要判断 `channelFuture.isSuccess` 就可以判断请求是否成功了。 + +注意,writeAndFlush 成功并不代表对端接受到了请求,返回值为 true 只能保证写入网络缓冲区成功,并不代表发送成功。 + +避开上述两个误区,我们再来回到本小节的标题:客户端如何得知请求失败?**正确的逻辑应当是以客户端接收到失败响应为判断依据**。等等,前面不还在说在失败的场景中,服务端是不会返回响应的吗?没错,既然服务端不会返回,那就只能客户端自己造了。 + +一个常见的设计是:客户端发起一个 RPC 请求,会设置一个超时时间 `client_timeout`,发起调用的同时,客户端会开启一个延迟 `client_timeout` 的定时器 + +- 接收到正常响应时,移除该定时器。 +- 定时器倒计时完毕,还没有被移除,则认为请求超时,构造一个失败的响应传递给客户端。 + +Dubbo 中的超时判定逻辑: + +```java +public static DefaultFuture newFuture(Channel channel, Request request, int timeout) { + final DefaultFuture future = new DefaultFuture(channel, request, timeout); + // timeout check + timeoutCheck(future); + return future; +} +private static void timeoutCheck(DefaultFuture future) { + TimeoutCheckTask task = new TimeoutCheckTask(future); + TIME_OUT_TIMER.newTimeout(task, future.getTimeout(), TimeUnit.MILLISECONDS); +} +private static class TimeoutCheckTask implements TimerTask { + private DefaultFuture future; + TimeoutCheckTask(DefaultFuture future) { + this.future = future; + } + @Override + public void run(Timeout timeout) { + if (future == null || future.isDone()) { + return; + } + // create exception response. + Response timeoutResponse = new Response(future.getId()); + // set timeout status. + timeoutResponse.setStatus(future.isSent() ? Response.SERVER_TIMEOUT : Response.CLIENT_TIMEOUT); + timeoutResponse.setErrorMessage(future.getTimeoutMessage(true)); + // handle response. + DefaultFuture.received(future.getChannel(), timeoutResponse); + } +} + +``` + +主要逻辑涉及的类:`DubboInvoker`,`HeaderExchangeChannel`,`DefaultFuture` ,通过上述代码,我们可以得知一个细节,无论是何种调用,都会经过这个定时器的检测,**超时即调用失败,一次 RPC 调用的失败,必须以客户端收到失败响应为准**。 + +#### 2.2 心跳检测需要容错 + +网络通信永远要考虑到最坏的情况,一次心跳失败,不能认定为连接不通,多次心跳失败,才能采取相应的措施。 + +#### 2.3 心跳检测不需要忙检测 + +忙检测的对立面是空闲检测,我们做心跳的初衷,是为了保证连接的可用性,以保证及时采取断连,重连等措施。如果一条通道上有频繁的 RPC 调用正在进行,我们不应该为通道增加负担去发送心跳包。**心跳扮演的角色应当是晴天收伞,雨天送伞。** + +### 3 Dubbo 现有方案 + +> 本文的源码对应 Dubbo 2.7.x 版本,在 apache 孵化的该版本中,心跳机制得到了增强。 + +介绍完了一些基础的概念,我们再来看看 Dubbo 是如何设计应用层心跳的。Dubbo 的心跳是双向心跳,客户端会给服务端发送心跳,反之,服务端也会向客户端发送心跳。 + +#### 3.1 连接建立时创建定时器 + +```java +public class HeaderExchangeClient implements ExchangeClient { + private int heartbeat; + private int heartbeatTimeout; + private HashedWheelTimer heartbeatTimer; + public HeaderExchangeClient(Client client, boolean needHeartbeat) { + this.client = client; + this.channel = new HeaderExchangeChannel(client); + this.heartbeat = client.getUrl().getParameter(Constants.HEARTBEAT_KEY, dubbo != null && dubbo.startsWith("1.0.") ? Constants.DEFAULT_HEARTBEAT : 0); + this.heartbeatTimeout = client.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3); + if (needHeartbeat) { <1> + long tickDuration = calculateLeastDuration(heartbeat); + heartbeatTimer = new HashedWheelTimer(new NamedThreadFactory("dubbo-client-heartbeat", true), tickDuration, + TimeUnit.MILLISECONDS, Constants.TICKS_PER_WHEEL); <2> + startHeartbeatTimer(); + } + } + } +``` + +<1> **默认开启心跳检测的定时器** + +<2> **创建了一个 `HashedWheelTimer ` 开启心跳检测**,这是 Netty 所提供的一个经典的时间轮定时器实现,至于它和 jdk 的实现有何不同,不了解的同学也可以关注下,我就不拓展了。 + +不仅 `HeaderExchangeClient` 客户端开起了定时器,`HeaderExchangeServer` 服务端同样开起了定时器,由于服务端的逻辑和客户端几乎一致,所以后续我并不会重复粘贴服务端的代码。 + +> Dubbo 在早期版本版本中使用的是 schedule 方案,在 2.7.x 中替换成了 HashedWheelTimer。 + +#### 3.2 开启两个定时任务 + +```java +private void startHeartbeatTimer() { + long heartbeatTick = calculateLeastDuration(heartbeat); + long heartbeatTimeoutTick = calculateLeastDuration(heartbeatTimeout); + HeartbeatTimerTask heartBeatTimerTask = new HeartbeatTimerTask(cp, heartbeatTick, heartbeat); <1> + ReconnectTimerTask reconnectTimerTask = new ReconnectTimerTask(cp, heartbeatTimeoutTick, heartbeatTimeout); <2> + + heartbeatTimer.newTimeout(heartBeatTimerTask, heartbeatTick, TimeUnit.MILLISECONDS); + heartbeatTimer.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS); +} +``` + +Dubbo 在 `startHeartbeatTimer` 方法中主要开启了两个定时器: `HeartbeatTimerTask`,`ReconnectTimerTask` + +<1> `HeartbeatTimerTask` 主要用于定时发送心跳请求 + +<2> `ReconnectTimerTask` 主要用于心跳失败之后处理重连,断连的逻辑 + +至于方法中的其他代码,其实也是本文的重要分析内容,先容我卖个关子,后面再来看追溯。 + +#### 3.3 定时任务一:发送心跳请求 + +详细解析下心跳检测定时任务的逻辑 `HeartbeatTimerTask#doTask`: + +```java +protected void doTask(Channel channel) { + Long lastRead = lastRead(channel); + Long lastWrite = lastWrite(channel); + if ((lastRead != null && now() - lastRead > heartbeat) + || (lastWrite != null && now() - lastWrite > heartbeat)) { + Request req = new Request(); + req.setVersion(Version.getProtocolVersion()); + req.setTwoWay(true); + req.setEvent(Request.HEARTBEAT_EVENT); + channel.send(req); + } + } +} +``` + +前面已经介绍过,**Dubbo 采取的是双向心跳设计**,即服务端会向客户端发送心跳,客户端也会向服务端发送心跳,接收的一方更新 lastRead 字段,发送的一方更新 lastWrite 字段,超过心跳间隙的时间,便发送心跳请求给对端。这里的 lastRead/lastWrite 同样会被同一个通道上的普通调用更新,通过更新这两个字段,实现了只在连接空闲时才会真正发送空闲报文的机制,符合我们一开始科普的做法。 + +> 注意:不仅仅心跳请求会更新 lastRead 和 lastWrite,普通请求也会。这对应了我们预备知识中的空闲检测机制。 + +#### 3.4 定时任务二:处理重连和断连 + +继续研究下重连和断连定时器都实现了什么 `ReconnectTimerTask#doTask`。 + +```java +protected void doTask(Channel channel) { + Long lastRead = lastRead(channel); + Long now = now(); + if (lastRead != null && now - lastRead > heartbeatTimeout) { + if (channel instanceof Client) { + ((Client) channel).reconnect(); + } else { + channel.close(); + } + } +} +``` + +第二个定时器则负责根据客户端、服务端类型来对连接做不同的处理,当超过设置的心跳总时间之后,客户端选择的是重新连接,服务端则是选择直接断开连接。这样的考虑是合理的,客户端调用是强依赖可用连接的,而服务端可以等待客户端重新建立连接。 + +> 细心的朋友会发现,这个类被命名为 ReconnectTimerTask 是不太准确的,因为它处理的是重连和断连两个逻辑。 + +#### 3.5 定时不精确的问题 + +在 Dubbo 的 issue 中曾经有人反馈过定时不精确的问题,我们来看看是怎么一回事。 + +Dubbo 中默认的心跳周期是 60s,设想如下的时序: + +- 第 0 秒,心跳检测发现连接活跃 +- 第 1 秒,连接实际断开 +- 第 60 秒,心跳检测发现连接不活跃 + +由于**时间窗口的问题,死链不能够被及时检测出来,最坏情况为一个心跳周期**。 + +为了解决上述问题,我们再倒回去看一下上面的 `startHeartbeatTimer()` 方法 + +```java +long heartbeatTick = calculateLeastDuration(heartbeat); +long heartbeatTimeoutTick = calculateLeastDuration(heartbeatTimeout); +``` + +其中 `calculateLeastDuration` 根据心跳时间和超时时间分别计算出了一个 tick 时间,实际上就是将两个变量除以了 3,使得他们的值缩小,并传入了 `HashedWheelTimer` 的第二个参数之中 + +```java +heartbeatTimer.newTimeout(heartBeatTimerTask, heartbeatTick, TimeUnit.MILLISECONDS); +heartbeatTimer.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS); +``` + +tick 的含义便是定时任务执行的频率。这样,通过减少检测间隔时间,增大了及时发现死链的概率,原先的最坏情况是 60s,如今变成了 20s。这个频率依旧可以加快,但需要考虑资源消耗的问题。 + +> 定时不准确的问题出现在 Dubbo 的两个定时任务之中,所以都做了 tick 操作。事实上,所有的定时检测的逻辑都存在类似的问题。 + +#### 3.6 Dubbo 心跳总结 + +Dubbo 对于建立的每一个连接,同时在客户端和服务端开启了 2 个定时器,一个用于定时发送心跳,一个用于定时重连、断连,执行的频率均为各自检测周期的 1/3。定时发送心跳的任务负责在连接空闲时,向对端发送心跳包。定时重连、断连的任务负责检测 lastRead 是否在超时周期内仍未被更新,如果判定为超时,客户端处理的逻辑是重连,服务端则采取断连的措施。 + +先不急着判断这个方案好不好,再来看看改进方案是怎么设计的。 + +### 4 Dubbo 改进方案 + +实际上我们可以更优雅地实现心跳机制,本小节开始,我将介绍一个新的心跳机制。 + +#### 4.1 IdleStateHandler 介绍 + +Netty 对空闲连接的检测提供了天然的支持,使用 `IdleStateHandler` 可以很方便的实现空闲检测逻辑。 + +```java +public IdleStateHandler( + long readerIdleTime, long writerIdleTime, long allIdleTime, + TimeUnit unit) {} +``` + +- readerIdleTime:读超时时间 +- writerIdleTime:写超时时间 +- allIdleTime:所有类型的超时时间 + +`IdleStateHandler` 这个类会根据设置的超时参数,循环检测 channelRead 和 write 方法多久没有被调用。当在 pipeline 中加入 `IdleSateHandler` 之后,可以在此 pipeline 的任意 Handler 的 `userEventTriggered` 方法之中检测 `IdleStateEvent` 事件, + +```java +@Override +public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + //do something + } + ctx.fireUserEventTriggered(evt); +} +``` + +为什么需要介绍 `IdleStateHandler` 呢?其实提到它的空闲检测 + 定时的时候,大家应该能够想到了,这不天然是给心跳机制服务的吗?很多服务治理框架都选择了借助 `IdleStateHandler` 来实现心跳。 + +> IdleStateHandler 内部使用了 eventLoop.schedule(task) 的方式来实现定时任务,使用 eventLoop 线程的好处是还同时保证了**线程安全**,这里是一个小细节。 + +#### 4.2 客户端和服务端配置 + +首先是将 `IdleStateHandler` 加入 pipeline 中。 + +**客户端:** + +```java +bootstrap.handler(new ChannelInitializer() { + @Override + protected void initChannel(NioSocketChannel ch) throws Exception { + ch.pipeline().addLast("clientIdleHandler", new IdleStateHandler(60, 0, 0)); + } +}); +``` + +**服务端:** + +```java +serverBootstrap.childHandler(new ChannelInitializer() { + @Override + protected void initChannel(NioSocketChannel ch) throws Exception { + ch.pipeline().addLast("serverIdleHandler",new IdleStateHandler(0, 0, 200)); + } +} +``` + +客户端配置了 read 超时为 60s,服务端配置了 write/read 超时为 200s,先在此埋下两个伏笔: + +1. 为什么客户端和服务端配置的超时时间不一致? +2. 为什么客户端检测的是读超时,而服务端检测的是读写超时? + +#### 4.3 空闲超时逻辑 — 客户端 + +对于空闲超时的处理逻辑,客户端和服务端是不同的。首先来看客户端 + +```java +@Override +public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + // send heartbeat + sendHeartBeat(); + } else { + super.userEventTriggered(ctx, evt); + } +} +``` + +检测到空闲超时之后,采取的行为是向服务端发送心跳包,具体是如何发送,以及处理响应的呢?伪代码如下 + +```java +public void sendHeartBeat() { + Invocation invocation = new Invocation(); + invocation.setInvocationType(InvocationType.HEART_BEAT); + channel.writeAndFlush(invocation).addListener(new CallbackFuture() { + @Override + public void callback(Future future) { + RPCResult result = future.get(); + //超时 或者 写失败 + if (result.isError()) { + channel.addFailedHeartBeatTimes(); + if (channel.getFailedHeartBeatTimes() >= channel.getMaxHeartBeatFailedTimes()) { + channel.reconnect(); + } + } else { + channel.clearHeartBeatFailedTimes(); + } + } + }); +} +``` + +行为并不复杂,构造一个心跳包发送到服务端,接受响应结果 + +- 响应成功,清空请求失败标记 +- 响应失败,心跳失败标记+1,如果超过配置的失败次数,则重新连接 + +> 不仅仅是心跳,普通请求返回成功响应时也会清空标记 + +#### 4.4 空闲超时逻辑 — 服务端 + +```java +@Override +public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + channel.close(); + } else { + super.userEventTriggered(ctx, evt); + } +} +``` + +服务端处理空闲连接的方式非常简单粗暴,直接关闭连接。 + +#### 4.5 改进方案心跳总结 + +1. 为什么客户端和服务端配置的超时时间不一致? + + 因为客户端有重试逻辑,不断发送心跳失败 n 次之后,才认为是连接断开;而服务端是直接断开,留给服务端时间得长一点。60 * 3 < 200 还说明了一个问题,双方都拥有断开连接的能力,但连接的创建是由客户端主动发起的,那么客户端也更有权利去主动断开连接。 + +2. 为什么客户端检测的是读超时,而服务端检测的是读写超时? + + 这其实是一个心跳的共识了,仔细思考一下,定时逻辑是由客户端发起的,所以整个链路中不通的情况只有可能是:服务端接收,服务端发送,客户端接收。也就是说,只有客户端的 pong,服务端的 ping,pong 的检测是有意义的。 + +> 主动追求别人的是你,主动说分手的也是你。 + +利用 `IdleStateHandler` 实现心跳机制可以说是十分优雅的,借助 Netty 提供的空闲检测机制,利用客户端维护单向心跳,在收到 3 次心跳失败响应之后,客户端断开连接,交由异步线程重连,本质还是表现为客户端重连。服务端在连接空闲较长时间后,主动断开连接,以避免无谓的资源浪费。 + +### 5 心跳设计方案对比 + +| | Dubbo 现有方案 | Dubbo 改进方案 | +| :------------------: | :----------------------------------------------------------: | :--------------------------------------------------: | +| **主体设计** | 开启两个定时器 | 借助 IdleStateHandler,底层使用 schedule | +| **心跳方向** | 双向 | 单向(客户端 -> 服务端) | +| **心跳失败判定方式** | 心跳成功更新标记,借助定时器定时扫描标记,如果超过心跳超时周期未更新标记,认为心跳失败。 | 通过判断心跳响应是否失败,超过失败次数,认为心跳失败 | +| **扩展性** | Dubbo 存在 mina,grizzy 等其他通信层实现,自定义定时器很容易适配多种扩展 | 多通信层各自实现心跳,不做心跳的抽象 | +| **设计性** | 编码复杂度高,代码量大,方案复杂,不易维护 | 编码量小,可维护性强 | + +私下请教过**美团点评的长连接负责人:俞超(闪电侠)**,美点使用的心跳方案和 Dubbo 改进方案几乎一致,可以说该方案是标准实现了。 + +### 6 Dubbo 实际改动点建议 + +鉴于 Dubbo 存在一些其他通信层的实现,所以可以保留现有的定时发送心跳的逻辑。 + +- **建议改动点一:** + +双向心跳的设计是不必要的,兼容现有的逻辑,可以让客户端在连接空闲时发送单向心跳,服务端定时检测连接可用性。定时时间尽量保证:客户端超时时间 * 3 ≈ 服务端超时时间 + +- **建议改动点二:** + +去除处理重连和断连的定时任务,Dubbo 可以判断心跳请求是否响应失败,可以借鉴改进方案的设计,在连接级别维护一个心跳失败次数的标记,任意响应成功,清除标记;连续心跳失败 n 次,客户端发起重连。这样可以减少一个不必要的定时器,任何轮询的方式,都是不优雅的。 + +最后再聊聊可扩展性这个话题。其实我是建议把定时器交给更加底层的 Netty 去做,也就是完全使用 `IdleStateHandler` ,其他通信层组件各自实现自己的空闲检测逻辑,但是 Dubbo 中 mina,grizzy 的兼容问题囿住了我的拳脚,但试问一下,如今的 2019 年,又有多少人在使用 mina 和 grizzy?因为一些不太可能用的特性,而限制了主流用法的优化,这肯定不是什么好事。抽象,功能,可扩展性并不是越多越好,开源产品的人力资源是有限的,框架使用者的理解能力也是有限的,能解决大多数人问题的设计,才是好的设计。哎,谁让我不会 mina,grizzy,还懒得去学呢[摊手]。 diff --git a/content/en/blog/java/demos/dubbo-invoke.md b/content/en/blog/java/demos/dubbo-invoke.md new file mode 100644 index 000000000000..01da15ae8774 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-invoke.md @@ -0,0 +1,223 @@ +--- +title: "Dubbo 关于同步/异步调用的几种方式" +linkTitle: "Dubbo 关于同步/异步调用的几种方式" +tags: ["Java"] +date: 2018-08-14 +description: > + 本文介绍了Dubbo基于异步通讯机制实现的几种同步和异步调用方式。 +--- + + +我们知道,Dubbo 缺省协议采用单一长连接,底层实现是 Netty 的 NIO 异步通讯机制;基于这种机制,Dubbo 实现了以下几种调用方式: + +* 同步调用 +* 异步调用 +* 参数回调 +* 事件通知 + +## 同步调用 + +同步调用是一种阻塞式的调用方式,即 Consumer 端代码一直阻塞等待,直到 Provider 端返回为止; + +通常,一个典型的同步调用过程如下: + +1. Consumer 业务线程调用远程接口,向 Provider 发送请求,同时当前线程处于`阻塞`状态; +2. Provider 接到 Consumer 的请求后,开始处理请求,将结果返回给 Consumer; +3. Consumer 收到结果后,当前线程继续往后执行。 + +这里有 2 个问题: + +1. Consumer 业务线程是怎么进入`阻塞`状态的? +2. Consumer 收到结果后,如何唤醒业务线程往后执行的? + +其实,Dubbo 的底层 IO 操作都是异步的。Consumer 端发起调用后,得到一个 Future 对象。对于同步调用,业务线程通过`Future#get(timeout)`,阻塞等待 Provider 端将结果返回;`timeout`则是 Consumer 端定义的超时时间。当结果返回后,会设置到此 Future,并唤醒阻塞的业务线程;当超时时间到结果还未返回时,业务线程将会异常返回。 + +## 异步调用 + +基于 Dubbo 底层的异步 NIO 实现异步调用,对于 Provider 响应时间较长的场景是必须的,它能有效利用 Consumer 端的资源,相对于 Consumer 端使用多线程来说开销较小。 + +异步调用,对于 Provider 端不需要做特别的配置。下面的例子中,Provider 端接口定义如下: + +```java +public interface AsyncService { + String goodbye(String name); +} +``` + +### Consumer 配置 + +```xml + + + +``` + +需要异步调用的方法,均需要使用 ``标签进行描述。 + +### Consumer 端发起调用 + +```java +AsyncService service = ...; +String result = service.goodbye("samples");// 这里的返回值为空,请不要使用 +Future future = RpcContext.getContext().getFuture(); +... // 业务线程可以开始做其他事情 +result = future.get(); // 阻塞需要获取异步结果时,也可以使用 get(timeout, unit) 设置超时时间 +``` + +Dubbo Consumer 端发起调用后,同时通过`RpcContext.getContext().getFuture()`获取跟返回结果关联的`Future`对象,然后就可以开始处理其他任务;当需要这次异步调用的结果时,可以在任意时刻通过`future.get(timeout)`来获取。 + +一些特殊场景下,为了尽快调用返回,可以设置是否等待消息发出: + +* `sent="true"` 等待消息发出,消息发送失败将抛出异常; +* `sent="false"` 不等待消息发出,将消息放入 IO 队列,即刻返回。 + +默认为`false`。配置方式如下: + +```xml + +``` + +如果你只是想异步,完全忽略返回值,可以配置 `return="false"`,以减少 Future 对象的创建和管理成本: + +```xml + +``` + +此时,`RpcContext.getContext().getFuture()`将返回`null`。 + +整个异步调用的时序图如下: + +![异步调用](/imgs/blog/dubbo-async.svg) + +此示例代码位于:https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-async + +## 参数回调 + +参数回调有点类似于本地 Callback 机制,但 Callback 并不是 Dubbo 内部的类或接口,而是由 Provider 端自定义的;Dubbo 将基于长连接生成反向代理,从而实现从 Provider 端调用 Consumer 端的逻辑。 + +### Provider 端定义 Service 和 Callback + +```java +public interface CallbackService { + void addListener(String key, CallbackListener listener); +} + +public interface CallbackListener { + void changed(String msg); +} +``` + +#### Provider 端 Service 实现 + +```java +public class CallbackServiceImpl implements CallbackService { + + private final Map listeners = new ConcurrentHashMap(); + + public CallbackServiceImpl() { + Thread t = new Thread(new Runnable() { + public void run() { + while (true) { + try { + for (Map.Entry entry : listeners.entrySet()) { + try { + entry.getValue().changed(getChanged(entry.getKey())); + } catch (Throwable t) { + listeners.remove(entry.getKey()); + } + } + Thread.sleep(5000); // timely trigger change event + } catch (Throwable t) { + t.printStackTrace(); + } + } + } + }); + t.setDaemon(true); + t.start(); + } + + public void addListener(String key, CallbackListener listener) { + listeners.put(key, listener); + listener.changed(getChanged(key)); // send notification for change + } + + private String getChanged(String key) { + return "Changed: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); + } +} +``` + +#### Provider 端暴露服务 + +```xml + + + + + + + + +``` + +这里,Provider 需要在方法中声明哪个参数是 Callback 参数。 + +#### Consumer 端实现 Callback 接口 + +```java +CallbackService callbackService = ...; +callbackService.addListener("foo.bar", new CallbackListener() { + public void changed(String msg) { + System.out.println("callback1:" + msg); + } +}); +``` + +Callback 接口的实现类在 Consumer 端,当方法发生调用时,Consumer 端会自动 export 一个 Callback 服务。而 Provider 端在处理调用时,判断如果参数是 Callback,则生成了一个 proxy,因此服务实现类里在调用 Callback 方法的时候,会被传递到 Consumer 端执行 Callback 实现类的代码。 + +上述示例代码位于:https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-callback + +这种调用方式有点像消息的发布和订阅,但又有区别。比如当 Consumer 端 完成了Callback 服务的 export 后,如果后续重启了,这时 Provider 端就会调不通;同时 Provider 端如何清理掉这个 proxy 也是一个问题。 + +## 事件通知 + +事件通知允许 Consumer 端在调用之前、调用之后或出现异常时,触发 `oninvoke`、`onreturn`、`onthrow` 三个事件。 + +可以通过在配置 Consumer 时,指定事件需要通知的方法,如: + +```xml + + + + + +``` + +其中,NotifyImpl 的代码如下: + +```java +public class NotifyImpl implements Notify{ + + public Map ret = new HashMap(); + + public void onreturn(String name, int id) { + ret.put(id, name); + System.out.println("onreturn: " + name); + } + + public void onthrow(Throwable ex, String name, int id) { + System.out.println("onthrow: " + name); + } +} +``` + +这里要强调一点,自定义 Notify 接口中的三个方法的参数规则如下: + +* `oninvoke` 方法参数与调用方法的参数相同; +* `onreturn`方法第一个参数为调用方法的返回值,其余为调用方法的参数; +* `onthrow`方法第一个参数为调用异常,其余为调用方法的参数。 + +上述配置中,`sayHello`方法为同步调用,因此事件通知方法的执行也是同步执行。可以配置 `async=true`让方法调用为异步,这时事件通知的方法也是异步执行的。特别强调一下,`oninvoke`方法不管是否异步调用,都是同步执行的。 + +事件通知的示例代码请参考:https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-notify \ No newline at end of file diff --git a/content/en/blog/java/demos/dubbo-k8s.md b/content/en/blog/java/demos/dubbo-k8s.md new file mode 100644 index 000000000000..4abc17e035c9 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-k8s.md @@ -0,0 +1,111 @@ +--- +title: "Dubbo与Kubernetes集成" +linkTitle: "Dubbo与Kubernetes集成" +tags: ["Java"] +date: 2018-09-30 +description: > + 本文主要尝试将Dubbo服务注册到Kubernetes,同时无缝融入Kubernetes的多租户安全体系。 +--- + +## 大体目标 + +Dubbo的provider不再关心服务注册的事宜,只需要把其Dubbo服务端口打开,由Kubernetes来进行服务的声明和发布;Dubbo的consumer在服务发现时直接发现kubernetes的对应服务endpoints,从而复用Dubbo已有的微服务通道能力。好处是无需依赖三方的软负载注册中心;同时无缝融入Kubernetes的多租户安全体系。Demo的代码参照: https://github.com/dubbo/dubbo-kubernetes + +## 闲谈 + +Kubernates是建立在扩展性的具备二次开发的功能层次丰富的体系化系统 + +- 首先其最核心的功能是管理容器集群,能管理容器化的集群(包括存储,计算),当然这个是建立在对容器运行时(CRI),网络接口(CNI),存储服务接口(CSI/FV)的基础上; +- 其次是面向应用(包括无状态/有状态,批处理/服务型应用)的部署和路由能力,特别是基于微服务架构的应用管理,具备了其服务定义和服务发现,以及基于configmap的统一配置能力; +- 在基础资源(主要是抽象底层IaaS的资源)和应用层的抽象模型之上是治理层,包含弹性扩容,命名空间/租户,等。当然,基于其原子内核的基础能力,在Kubernetes的核心之上搭建统一的日志中心和全方位监控等服务是水到渠成的,CNCF更是有其认定推荐。 + +来张Kubernetes Architecture的一张图解释下上述描述。在2018年Kubernetes往事实的paas底座的标配迈出质的一步,有人说原因在于基于扩展的二次开发能力,有人说在于其声明式编程和背靠Google和Redhat的强大社区运作,我觉得回归本质是在于下图中的**Layered架构和其问题域的领域建模抽象**。 + +![img](/imgs/blog/k8s/1.png) + +以微服务架构视角,Kubernetes在一定意义上是微服务框架(这时较叫微服务平台或toolkit集更合适),支持微服务的服务发现/注册的基本能力。借用如下图做一个简单描述。 + +![img](/imgs/blog/k8s/2.jpeg) + +话题再展开一下,微服务领域涉及众多问题,大概可以用下图说明。 + +![img](/imgs/blog/k8s/3.jpeg) + +Kubernetes解决得只是少部分,而像动态路由,稳定性控制(断路器,隔水舱等),分布式服务追踪等是个空白,这也就是servicemesh要解决的,是在CNCF的Trail Map占有重要一席;当然Dubbo是基本具备完备的微服务,也就是使得其集成到k8s体系下具有相当的意义。Dubbo在serviemesh中基于sidecar的方案是解决跨语言诉求的通用servicemesh方案,需要新开一个话题来展开说;而引用serviemsh的原始定义: + +> A service mesh is a dedicated infrastructure layer for handling service-to-service communication. It’s responsible for the reliable delivery of requests through the complex topology of services that comprise a modern, cloud native application. + +> 首先服务网格是一个云原生环境下基础设施层,功能在于处理服务间通信,职责是负责实现请求的可靠传递,被使得被监控跟踪,被治理,最终使得微服务架构被赋予高可控的稳定性和快速的问题定位排查能力。 + +可以得出现有Dubbo集成云原生基础设施Kubernetes的基础能力而并解决微服务相关核心问题也算是一种狭义上的servicemesh方案,只是是Java领域的罢了;当玩笑理解也行,哈哈。 + +## 思路/方案 + +Kubernetes是天然可作为微服务的地址注册中心,类似于Zookeeper, 阿里巴巴内部用到的VIPserver,Configserver。 具体来说,Kubernetes中的Pod是对于应用的运行实例,Pod的被调度部署/启停都会调用API-Server的服务来保持其状态到ETCD;Kubernetes中的service是对应微服务的概念,定义如下 + +> A Kubernetes Service is an abstraction layer which defines a logical set of Pods and enables external traffic exposure, load balancing and service discovery for those Pods. + +概括来说Kubernetes service具有如下特点 + +- 每个Service都有一个唯一的名字,及对应IP。IP是kubernetes自动分配的,名字是开发者自己定义的。 +- Service的IP有几种表现形式,分别是ClusterIP,NodePort,LoadBalance,Ingress。 ClusterIP主要用于集群内通信;NodePort,Ingress,LoadBalance用于暴露服务给集群外的访问入口。 + +乍一看,Kubernetes的service都是唯一的IP,在原有的Dubbo/HSF固定思维下:Dubbo/HSF的service是由整个服务集群的IP聚合而成,貌似是有本质区别的,细想下来差别不大,因为Kubernetes下的唯一IP只是一个VIP,背后挂载了多个endpoint,那才是事实上的处理节点。此处只讨论集群内的Dubbo服务在同一个kubernetes集群内访问;至于kubernetes外的consumer访问kubernetes内的provider,涉及到网络地址空间的问题,一般需要GateWay/Loadbalance来做映射转换,不展开讨论。针对Kubernetes内有两种方案可选: : + +1. DNS: 默认Kubernetes的service是靠DNS插件(最新版推荐是coreDNS), Dubbo上有个proposal是关于这个的。我的理解是static resolution的机制是最简单最需要支持的一种service discovery机制,具体也可以参考Envoy在此的观点,由于HSF/Dubbo一直突出其软负载的地址发现能力,反而忽略Static的策略。同时蚂蚁的SOFA一直是支持此种策略,那一个SOFA工程的工程片段做一个解释。这样做有两个好处,1)当软负载中心crash不可用造成无法获取地址列表时,有一定的机制Failover到此策略来处理一定的请求。 2)在LDC/单元化下,蚂蚁的负载中心集群是机房/区域内收敛部署的,首先保证软负载中心的LDC化了进而稳定可控,当单元需要请求中心时,此VIP的地址发现就排上用场了。 + +![img](/imgs/blog/2018/09/30/integrate-dubbo-with-kubernetes/TB1Kj1ktpkoBKNjSZFEXXbrEVXa-985-213.png) + +2. API:DNS是依靠DNS插件进行的,相当于额外的运维开销,所以考虑直接通过kubernetes的client来获取endpoint。事实上,通过访问Kubernetes的API server接口是可以直接获取某个servie背后的endpoint列表,同时可以监听其地址列表的变化。从而实现Dubbo/HSF所推荐的软负载发现策略。具体可以参考代码: + +以上两种思路都需要考虑以下两点: + +1. Kubernetes和Dubbo对于service的名字是映射一致的。Dubbo的服务是由serviename,group,version三个来确定其唯一性,而且servicename一般其服务接口的包名称,比较长。需要映射Kubernetes的servie名与dubbo的服务名。要么是像SOFA那样增加一个属性来进行定义,这是个大的改动,但最合理;要么是通过固定规则来引用部署的环境变量,可用于快速验证。 +2. 端口问题:默认Pod与Pod的网络互通算是解决了,需要验证。 + +## Demo验证 + +下面通过阿里云的容器镜像服务和EDAS中的Kubernetes服务来做一次Demo部署。访问阿里云 -> 容器镜像服务。 + +1. 创建镜像仓库并绑定github代码库。如下图 + +![img](/imgs/blog/2018/09/30/integrate-dubbo-with-kubernetes/TB1m.tEtrorBKNjSZFjXXc_SpXa-1892-870.png) + +2. 点击管理 **进行创建好的仓库**,通过镜像服务下的构建功能,把demo构建成image,并发布到指定仓库。如下图。 + +![img](/imgs/blog/2018/09/30/integrate-dubbo-with-kubernetes/TB1oYqvtcIrBKNjSZK9XXagoVXa-1872-888.png) + +3. 切换到企业级分布式应用服务(EDAS)产品,在资源管理 -> 集群 下创建Kubernetes集群并绑定ECS,如下图. + +![img](/imgs/blog/2018/09/30/integrate-dubbo-with-kubernetes/TB1b1p2trZnBKNjSZFKXXcGOVXa-1858-833.png) + +4. 应用管理 -》创建应用,**类型为kubernetes应用** 并且指定在容器镜像服务中的镜像。如下图。 + +![img](/imgs/blog/2018/09/30/integrate-dubbo-with-kubernetes/TB1b1p2trZnBKNjSZFKXXcGOVXa-1858-833.png) + +![img](/imgs/blog/2018/09/30/integrate-dubbo-with-kubernetes/TB18uzTtdcnBKNjSZR0XXcFqFXa-1820-861.png) + +5. 创建完成后,进行应用部署。如下图 + +![img](/imgs/blog/2018/09/30/integrate-dubbo-with-kubernetes/TB1fEpEtrorBKNjSZFjXXc_SpXa-1846-783.png) + +- 补充应用名不能有大写字母,全部小写,否则有部署失败的问题。 + +- 在创建应用时,选中镜像后,下一步的按钮无法点击,需要点击选择来继续。 + +- EDAS有两套独立的Kubernetes服务,一套是基于阿里云的容器服务,一套是Lark自己搞的。本人体验的是后者。 + +- Docker与IDE集成的开发联调,需要考虑集成IDEA的相关插件。 + +- 部署时总是出错,感觉Kubernetes服务上哪里有问题。需要进一步排查。 + +```json +{ + "kind": "Pod", + "namespace": "lzumwsrddf831iwarhehd14zh2-default", + "name": "dubbo-k8s-demo-610694273-jq238", + "uid": "12892e67-8bc8-11e8-b96a-00163e02c37b", + "apiVersion": "v1", + "resourceVersion": "850282769" +}, "reason": "FailedSync", "message": "Error syncing pod", " +``` diff --git a/content/en/blog/java/demos/dubbo-loadbalance.md b/content/en/blog/java/demos/dubbo-loadbalance.md new file mode 100644 index 000000000000..5854d27e1b98 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-loadbalance.md @@ -0,0 +1,272 @@ +--- +title: "Dubbo的负载均衡" +linkTitle: "Dubbo的负载均衡" +tags: ["Java"] +date: 2018-08-10 +description: > + 本文介绍了负载均衡的相关概念以及 Dubbo 中的负载均衡策略实现。 +--- + +## 背景 + +Dubbo是一个分布式服务框架,能避免单点故障和支持服务的横向扩容。一个服务通常会部署多个实例。如何从多个服务 Provider 组成的集群中挑选出一个进行调用,就涉及到一个负载均衡的策略。 + +## 几个概念 + +在讨论负载均衡之前,我想先解释一下这3个概念。 + +1. 负载均衡 +2. 集群容错 +3. 服务路由 + +这3个概念容易混淆。他们都描述了怎么从多个 Provider 中选择一个来进行调用。那他们到底有什么区别呢?下面我来举一个简单的例子,把这几个概念阐述清楚吧。 + +有一个Dubbo的用户服务,在北京部署了10个,在上海部署了20个。一个杭州的服务消费方发起了一次调用,然后发生了以下的事情: + +1. 根据配置的路由规则,如果杭州发起的调用,会路由到比较近的上海的20个 Provider。 +2. 根据配置的随机负载均衡策略,在20个 Provider 中随机选择了一个来调用,假设随机到了第7个 Provider。 +3. 结果调用第7个 Provider 失败了。 +4. 根据配置的Failover集群容错模式,重试其他服务器。 +5. 重试了第13个 Provider,调用成功。 + +上面的第1,2,4步骤就分别对应了路由,负载均衡和集群容错。 Dubbo中,先通过路由,从多个 Provider 中按照路由规则,选出一个子集。再根据负载均衡从子集中选出一个 Provider 进行本次调用。如果调用失败了,根据集群容错策略,进行重试或定时重发或快速失败等。 可以看到Dubbo中的路由,负载均衡和集群容错发生在一次RPC调用的不同阶段。最先是路由,然后是负载均衡,最后是集群容错。 本文档只讨论负载均衡,路由和集群容错在其他的文档中进行说明。 + +## Dubbo内置负载均衡策略 + +Dubbo内置了4种负载均衡策略: + +1. RandomLoadBalance:随机负载均衡。随机的选择一个。是Dubbo的**默认**负载均衡策略。 +2. RoundRobinLoadBalance:轮询负载均衡。轮询选择一个。 +3. LeastActiveLoadBalance:最少活跃调用数,相同活跃数的随机。活跃数指调用前后计数差。使慢的 Provider 收到更少请求,因为越慢的 Provider 的调用前后计数差会越大。 +4. ConsistentHashLoadBalance:一致性哈希负载均衡。相同参数的请求总是落在同一台机器上。 + +### 1.随机负载均衡 + +顾名思义,随机负载均衡策略就是从多个 Provider 中随机选择一个。但是 Dubbo 中的随机负载均衡有一个权重的概念,即按照权重设置随机概率。比如说,有10个 Provider,并不是说,每个 Provider 的概率都是一样的,而是要结合这10个 Provider 的权重来分配概率。 + +Dubbo中,可以对 Provider 设置权重。比如机器性能好的,可以设置大一点的权重,性能差的,可以设置小一点的权重。权重会对负载均衡产生影响。可以在Dubbo Admin中对 Provider 进行权重的设置。 + +**基于权重的负载均衡算法** + +随机策略会先判断所有的 Invoker 的权重是不是一样的,如果都是一样的,那么处理就比较简单了。使用random.nexInt(length)就可以随机生成一个 Invoker 的序号,根据序号选择对应的 Invoker 。如果没有在Dubbo Admin中对服务 Provider 设置权重,那么所有的 Invoker 的权重就是一样的,默认是100。 如果权重不一样,那就需要结合权重来设置随机概率了。算法大概如下: 假如有4个 Invoker。 + +| invoker | weight | +| ------- | ------ | +| A | 10 | +| B | 20 | +| C | 20 | +| D | 30 | + +A,B,C和D总的权重是10 + 20 + 20 + 30 = 80。将80个数分布在如下的图中: + +``` ++-----------------------------------------------------------------------------------+ +| | | | | ++-----------------------------------------------------------------------------------+ +1 10 30 50 80 + +|-----A----|---------B----------|----------C---------|---------------D--------------| + + +---------------------15 + +-------------------------------------------37 + +-----------------------------------------------------------54 +``` + +上面的图中一共有4块区域,长度分别是A,B,C和D的权重。使用random.nextInt(10 + 20 + 20 + 30),从80个数中随机选择一个。然后再判断该数分布在哪个区域。比如,如果随机到37,37是分布在C区域的,那么就选择 Invoker C。15是在B区域,54是在D区域。 + +**随机负载均衡源码** + +下面是随机负载均衡的源码,为了方便阅读和理解,我把无关部分都去掉了。 + +``` +public class RandomLoadBalance extends AbstractLoadBalance { + + private final Random random = new Random(); + + protected Invoker doSelect(List> invokers, URL url, Invocation invocation) { + int length = invokers.size(); // Invoker 总数 + int totalWeight = 0; // 所有 Invoker 的权重的和 + + // 判断是不是所有的 Invoker 的权重都是一样的 + // 如果权重都一样,就简单了。直接用Random生成索引就可以了。 + boolean sameWeight = true; + for (int i = 0; i < length; i++) { + int weight = getWeight(invokers.get(i), invocation); + totalWeight += weight; // Sum + if (sameWeight && i > 0 && weight != getWeight(invokers.get(i - 1), invocation)) { + sameWeight = false; + } + } + + if (totalWeight > 0 && !sameWeight) { + // 如果不是所有的 Invoker 权重都相同,那么基于权重来随机选择。权重越大的,被选中的概率越大 + int offset = random.nextInt(totalWeight); + for (int i = 0; i < length; i++) { + offset -= getWeight(invokers.get(i), invocation); + if (offset < 0) { + return invokers.get(i); + } + } + } + // 如果所有 Invoker 权重相同 + return invokers.get(random.nextInt(length)); + } +} +``` + +### 2.轮询负载均衡 + +轮询负载均衡,就是依次的调用所有的 Provider。和随机负载均衡策略一样,轮询负载均衡策略也有权重的概念。 轮询负载均衡算法可以让RPC调用严格按照我们设置的比例来分配。不管是少量的调用还是大量的调用。但是轮询负载均衡算法也有不足的地方,存在慢的 Provider 累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上,导致整个系统变慢。 + +### 3.最少活跃调用数负载均衡 + +官方解释: + +> 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差,使慢的机器收到更少。 + +这个解释好像说的不是太明白。目的是让更慢的机器收到更少的请求,但具体怎么实现的还是不太清楚。举个例子:每个服务维护一个活跃数计数器。当A机器开始处理请求,该计数器加1,此时A还未处理完成。若处理完毕则计数器减1。而B机器接受到请求后很快处理完毕。那么A,B的活跃数分别是1,0。当又产生了一个新的请求,则选择B机器去执行(B活跃数最小),这样使慢的机器A收到少的请求。 + +处理一个新的请求时,Consumer 会检查所有 Provider 的活跃数,如果具有最小活跃数的 Invoker 只有一个,直接返回该 Invoker: + +``` +if (leastCount == 1) { + // 如果只有一个最小则直接返回 + return invokers.get(leastIndexs[0]); +} +``` + +如果最小活跃数的 Invoker 有多个,且权重不相等同时总权重大于0,这时随机生成一个权重,范围在 (0,totalWeight) 间内。最后根据随机生成的权重,来选择 Invoker。 + +``` +if (! sameWeight && totalWeight > 0) { + // 如果权重不相同且权重大于0则按总权重数随机 + int offsetWeight = random.nextInt(totalWeight); + // 并确定随机值落在哪个片断上 + for (int i = 0; i < leastCount; i++) { + int leastIndex = leastIndexs[i]; + offsetWeight -= getWeight(invokers.get(leastIndex), invocation); + if (offsetWeight <= 0) + return invokers.get(leastIndex); + } +} +``` + +### 4.一致性Hash算法 + +使用一致性 Hash 算法,让相同参数的请求总是发到同一 Provider。 当某一台 Provider 崩溃时,原本发往该 Provider 的请求,基于虚拟节点,平摊到其它 Provider,不会引起剧烈变动。 算法参见:。 + +缺省只对第一个参数Hash,如果要修改,请配置: + +``` + +``` + +缺省用160份虚拟节点,如果要修改,请配置: + +``` + +``` + +一致性Hash算法可以和缓存机制配合起来使用。比如有一个服务getUserInfo(String userId)。设置了Hash算法后,相同的userId的调用,都会发送到同一个 Provider。这个 Provider 上可以把用户数据在内存中进行缓存,减少访问数据库或分布式缓存的次数。如果业务上允许这部分数据有一段时间的不一致,可以考虑这种做法。减少对数据库,缓存等中间件的依赖和访问次数,同时减少了网络IO操作,提高系统性能。 + +## 负载均衡配置 + +如果不指定负载均衡,默认使用随机负载均衡。我们也可以根据自己的需要,显式指定一个负载均衡。 可以在多个地方类来配置负载均衡,比如 Provider 端,Consumer端,服务级别,方法级别等。 + +### 服务端服务级别 + +``` + +``` + +该服务的所有方法都使用roundrobin负载均衡。 + +### 客户端服务级别 + +``` + +``` + +该服务的所有方法都使用roundrobin负载均衡。 + +### 服务端方法级别 + +``` + + + +``` + +只有该服务的hello方法使用roundrobin负载均衡。 + +### 客户端方法级别 + +``` + + + +``` + +只有该服务的hello方法使用roundrobin负载均衡。 + +和Dubbo其他的配置类似,多个配置是有覆盖关系的: + +1. 方法级优先,接口级次之,全局配置再次之。 +2. 如果级别一样,则消费方优先,提供方次之。 + +所以,上面4种配置的优先级是: + +1. 客户端方法级别配置。 +2. 客户端接口级别配置。 +3. 服务端方法级别配置。 +4. 服务端接口级别配置。 + +## 扩展负载均衡 + +Dubbo的4种负载均衡的实现,大多数情况下能满足要求。有时候,因为业务的需要,我们可能需要实现自己的负载均衡策略。本章只说明如何配置负载均衡算法。关于Dubbo扩展机制的更多内容,请前往[Dubbo可扩展机制实战](/en/blog/2019/04/25/dubbo可扩展机制实战/)。 + +1. 实现LoadBalance接口, 以下是Dubbo的LoadBalance接口: + +``` +@SPI(RandomLoadBalance.NAME) +public interface LoadBalance { + @Adaptive("loadbalance") + Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException; +} +``` + +这是SPI的接口,select方法的参数如下: + +- invokers: 所有的服务 Provider 列表。 +- url: 一些配置信息,比如接口名,是否check,序列化方式。 +- invocation: RPC调用的信息,包括方法名,方法参数类型,方法参数。 下面是我们自己实现的一个LoadBalance,实现很简单,选择第一个 Invoker: + +``` +package com.demo.dubbo; +public class DemoLoadBalance implements LoadBalance { + @Override + public Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException { + System.out.println("[DemoLoadBalance]Select the first invoker..."); + return invokers.get(0); + } +} +``` + +2. 添加资源文件 添加文件:`src/main/resource/META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.LoadBalance`。这是一个简单的文本文件。文件内容如下: + +``` +demo=my=com.demo.dubbo.DemoLoadBalance +``` + +3. 配置使用自定义LoadBalance + +``` + +``` + +在Consumer端的`dubbo:reference`中配置`` + +经过上面的3个步骤,我们编写了一个自定义的LoadBalance,并告诉Dubbo使用它了。启动Dubbo,我们就能看到Dubbo已经使用了自定义的DemoLoadBalance。 diff --git a/content/en/blog/java/demos/dubbo-local-call.md b/content/en/blog/java/demos/dubbo-local-call.md new file mode 100644 index 000000000000..29710e82665f --- /dev/null +++ b/content/en/blog/java/demos/dubbo-local-call.md @@ -0,0 +1,146 @@ +--- +title: "本地调用" +linkTitle: "本地调用" +tags: ["Java"] +date: 2019-08-11 +description: > + 当一个应用既是一个服务的提供者,同时也是这个服务的消费者的时候,可以直接对本机提供的服务发起本地调用 +--- + +### 本地调用介绍 + +当一个应用既是一个服务的提供者,同时也是这个服务的消费者的时候,可以直接对本机提供的服务发起本地调用。从 `2.2.0` 版本开始,Dubbo 默认在本地以 *injvm* 的方式暴露服务,这样的话,在同一个进程里对这个服务的调用会优先走本地调用。 + + + +与本地对象上方法调用不同的是,Dubbo 本地调用会经过 Filter 链,其中包括了 Consumer 端的 Filter 链以及 Provider 端的 Filter 链。通过这样的机制,本地消费者和其他消费者都是统一对待,统一监控,服务统一进行治理。 + + + +![filter-chain](/imgs/blog/dubbo-local-call-filter.png) + + + + + +同时,相比于远程调用来说,Dubbo 本地调用性能较优,省去了请求、响应的编解码及网络传输的过程。 + + + +要使用 Dubbo 本地调用不需做特殊配置,按正常 Dubbo 服务暴露服务即可。任一服务在暴露远程服务的同时,也会同时以 *injvm* 的协议暴露本地服务。*injvm* 是一个伪协议,不会像其他协议那样对外开启端口,只用于本地调用的目的。 + + + +以下面的 XML 配置为例: + + + +```xml + + + + + + + +``` + + + +这里同时配置了同一服务 *DemoService* 的提供者以及消费者。在这种情况下,该应用中的 *DemoService* 的消费方会优先使用 *injvm* 协议进行本地调用。上述的例子可以在 dubbo-samples 工程中找到源码:https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-local + + + +### 细粒度控制本地调用 + +本地调用是可以显示关闭的,通过这种方式,服务提供者可以做到对远端服务消费者和本地消费者一视同仁。具体做法是通过 *scope="remote"* 来关闭 *injvm* 协议的暴露,这样,即使是本地调用者,也需要从注册中心上获取服务地址列表,然后才能发起调用,而这个时候的调用过程,与远端的服务消费者的过程是一致的。 + + + +```xml + + + + +``` + + + +同样的,服务消费者也支持通过 *scope* 来限定发起调用优先走本地,还是只走远程。比如,可以通过以下的方式强制消费端通过**远程调用**的方式来发起 dubbo 调用: + + + +```xml + + +``` + + + +如果同时服务提供方限定了 *scope="local"* 的话, + + + +```xml + + + + +``` + + + +那么该程序中的 dubbo 调用将会失败,原因是服务提供方只暴露了远程服务到注册中心上,并没有暴露 *injvm* 协议的服务,而出于同一个进程中的服务消费者查找不到 *injvm* 协议的服务,也不会去远程的注册中心上订阅服务地址。同样的,当服务提供者限定 *scope="local"* 而服务消费者限定 *scope="remote"* 也会因为相同的原因导致调用失败。出错信息如下: + + + +```sh +[20/03/19 05:03:18:018 CST] main INFO config.AbstractConfig: [DUBBO] Using injvm service org.apache.dubbo.samples.local.api.DemoService, dubbo version: 2.7.1, current host: 169.254.146.168 +Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'demoService': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: Failed to check the status of the service org.apache.dubbo.samples.local.api.DemoService. No provider available for the service org.apache.dubbo.samples.local.api.DemoService from the url injvm://127.0.0.1/org.apache.dubbo.samples.local.api.DemoService?application=demo-provider&default.lazy=false&default.sticky=false&dubbo=2.0.2&interface=org.apache.dubbo.samples.local.api.DemoService&lazy=false&methods=sayHello&pid=76198®ister.ip=169.254.146.168&release=2.7.1-SNAPSHOT&scope=local&side=consumer&sticky=false×tamp=1553072598838 to the consumer 169.254.146.168 use dubbo version 2.7.1 +``` + + + +### 何时无法使用本地调用 + +默认情况下,本地调用是自动开启的,不需要做额外的配置。只有当需要关闭的时候,才需要通过 *scope* 的配置来显式的关闭。 + + + +但是,特别需要指出的是,在下面的几种情况下,本地调用是无法使用的: + +第一,泛化调用的时候无法使用本地调用。 + +第二,消费者明确指定 URL 发起直连调用。当然,如果消费者指定的是 *injvm* 的 URL,最终的调用也是走本地调用的,比如: + + + +```xml + +``` + + + +### 强制打开本地调用 + +除了通过 *scope* 来控制本地调用的行为之外,也可以通过 *injvm* 这个配置来强制打开或者禁用本地调用。 + + + +```xml + + +``` + + + +但是通过 *injvm* 来配置本地调用的方式已经被废弃。通过 *scope* 的方式来控制是官方推荐的。 + + + +### 总结 + +本文介绍了本地调用的概念以及带来的好处,并进一步的揭示了 dubbo 本地调用实际上是在当前进程中暴露了 *injvm* 的协议,而该协议并不会对外暴露端口,然后讨论了如何通过 *scope* 来细粒度的控制本地调用的行为,并强调了通过 *invjm* 来配置的方式已经被废弃,在未来版本中可能会被删除。 + + + diff --git a/content/en/blog/java/demos/dubbo-mesh-in-thinking.md b/content/en/blog/java/demos/dubbo-mesh-in-thinking.md new file mode 100644 index 000000000000..b0987004077d --- /dev/null +++ b/content/en/blog/java/demos/dubbo-mesh-in-thinking.md @@ -0,0 +1,134 @@ +--- +title: "Dubbo 在 Service Mesh 下的思考和方案" +linkTitle: "Dubbo 在 Service Mesh 下的思考和方案" +tags: ["Java"] +date: 2019-11-30 +description: Dubbo 是实现框架,融入 service mesh 理念就是我们今天分享的 +--- + +## 开头 +Service Mesh这个“热”词是2016年9月被“造”出来,而今年2018年更是被称为service Mesh的关键之年,各家大公司都希望能在这个思潮下领先一步。今天我也分享阿里中间件在这方面的观点,思考和实践。考虑到有些人没了解过Dubbo(集团内以HSF为主)和Servicemesh,先简单介绍下这两个词。Dubbo应该是国内最受欢迎的远程服务框架,在Github上有超过2w的star数,也是阿里分布式架构互联互通的核心所在。跟Dubbo一样,servicemesh也是面向服务互联互通这一问题域,是云原生技术栈的核心之一;大家可以简单理解service mesh就是云原生组织定义的微服务架构解决理念。Dubbo是实现框架,融入service mesh理念就是我们今天分享的。 + +## 现状和挑战 + + +![1.png | center | 826x206](/imgs/blog/dubbomesh/1.png) + +当前Dubbo支撑的阿里分布式应用内支撑万级别的应用数,运行在20多万的服务器实例上,每天调用量是万亿级别,这应该是国内最大的分布式应用集群。 + +挑战主要来自三方面 + +* 首先, 数以万计的应用意味着有以十万级的服务,理顺错综复杂的服务拓扑关系,甚至及时诊断某个异常调用链路,需要考虑海量数据的拉取分析,是非常有挑战的,阿里通过EagleEye鹰眼链路系统提供可观察性和治理能力来解决; +* 第二个挑战是机房级别容灾,阿里的机房是分布在天南海北,大家可以想象横跨数千公里的网络延迟会造成服务互通很大的影响,所以在保证一定恢复时间和一定数据容错的情况下做异地多活是有巨大挑战,阿里通过支持异地多活的单元化架构解决。 +* 第三个挑战是阿里业务众多,尤其像阿里生态中的高德,UC,优酷等所使用的开发语言跟淘系Java是不一样的,比如PHP,C,Nodejs,Dart等,要维护多个版本并保证各版本具有同样的功能是成本比较高的;这个挑战在云原生的新一代理念下更具挑战,毕竟。今天主题跟第三个挑战是息息相关,能解决一定的问题。 + +这里讲个大鱼吃小鱼的故事来简单理解下云原生:软件会吃掉这个世界,也就是信息化不可避免,而开源会吃掉软件,最终云原生会吃掉开源。这正代表了云原生理念的颠覆性,从商业软件到开源到云原生,环环相套,以体系化和层次化的方式推荐各个方面的开源方案和标准,这会极大降低企业级架构服务的技术门槛,是企业信息化之路的一大利好,当然也是进化方向。这个故事跟今天的主题--开发者定义软件未来,是非常契合,也就是说这个趋势至少在企业级软件服务领域正在发生。云原生:Cloud Native is Patterns with A complete and trusted tool kit for modern architectures。 + +Service Mesh的典型方案 +## Service Mesh的典型方案 + + +![2.png | center | 826x206](/imgs/blog/dubbomesh/2.png "") + +讲完故事,回到servicemesh。 + +传统形态下SDK代表着一个特定语言的库,由应用和微服务框架共处一进程内,在发布升级中共享生命周期。比较典型的代表是Twitter的finagle,Google的stubby/grpc,阿里巴巴的HSF/Dubbo. + +Serviemesh下推荐是右边Sidecar方案,Sidecar方案没有引入新的功能,只是改变了原有功能的位置,以独立的应用来存在,大家可以暂时以nginx来理解其网络代理能力也可以。 + +在这张图中希望大家关注两个信息, 1)所有的sidecar形成逻辑网络被称为数据面,是业务服务的链路中是强依赖节点,承载了业务数据互联互通的基础;传统的ops管控服务被称为控制面,这部分跟传统是大同小异。 2)在sidecar形态下,网络会增加两跳,即应用与sidecar之间,他们之间的数据互通也是基于协议规范。后面会详细讲。 + +## Sidecar模式的优劣 + + +![3.png | center | 826x206](/imgs/blog/dubbomesh/3.png "") + +接下来从开发和运维两个阶段来分开比较。 + +* 多语言支持方面,既然sidecar是独立应用,用最合适的一种语言开发完成即可,就避免了需要针对不同语言的应用场景做不同的版本开发。当前阿里选择基于C语言的Envoy做二次开发来追求最小的footprint和性能,当然也曾经历一些弯路,比如曾经用Java开发过一个sidecar,但最终由于引入JRE体量大和GC带来的抖动等问题证明不可行。有必要强调的是:这里说的是sidecar自身开发现在避免了多语言多版本的问题,而真要支持任意服务自由采用任意语言实现这一理想,是需要站在从业务到数据面再到业务的整个链路上的数据交互做思考。 +* 性能方面,sidecar情形下由于会增加两跳,这两跳是业务应用与sidecar的两个进程之间的调用,这是本机,即便是经过优化,也是会增加进程切换以及数据转换的开销。经过我们的优化测试,在正常的业务访问下,相比SDK形态下最多增加1毫秒的开销,这在大多数业务情形下是基本无感知无影响。 +* 再看运维阶段的比较,一般SDK形态的服务框架都是只关心开发的诉求,对于如何运维都是不关心,而软件生命周期中运维是最长的,如何从中间件角度解决更多的运维问题是非常有意义的。阿里的中间件经常需要升级,以库的形式升级时就需要业务方应用重新打包,这个推动业务方变更的方式是比较被动,而且周期很长。 +* 当以镜像为基本原子单位进行发布部署时,阿里的中间件SDK体量大概是200兆,需要与业务一起打包,这样在业务应用升级时让分发的包就显得笨重,时效性相比sidecar形态就差一截。 + +稍微总结下,sidecar具有两个明显优势,一个是多语言开发维护成本低 ,另一个是独立升级,当然代价是需要增加一点点的网络延迟。至此大家是不是觉得Sidecar基本完美? 别着急,需要大家再思考一个问题:SDK模式下中间件组件会随应用一起发布,拥有完全一致的生命周期;而在sidecar模式下,如何管理sidecar的生命周期?这里可以拿无线耳机来举个例子,无线耳机是独立了,但必须独立电源的驱动,所以充电是要的。是的,在大规模的集群中这个点会带来不小的复杂性。 + +## 关键点 + + +![4.png | center | 826x206](/imgs/blog/dubbomesh/4.png "") + +下面跟大家分享下我们对servicemesh理解的三个关键技术点。分别是sidecar运维,数据面与控制面的集成,协议。 + +* 先说sidecar的运维,这是个难点,也是为什么sidecar方案以前没有被广泛应用的重要原因。前面说sidecar与应用现在成为两个不同的进程,要考虑多个事宜,一是要考虑如何把sidecar与应用部署在一起,二是考虑业务进程或sidecar进程一方需要升级重启时如何协同来保证请求的正常处理或转发,即优雅上下线的问题。这些事宜考虑清楚并解决后,算是具备servicemesh的前提条件。当然,kubernetes解决了这块的事情,提供了initiator类似插件的机制来对原子性的pod进行注入sidecar,并通过健康检查机制来保证两个进程的协同。简单地也可以这么理解:先把kubernetes容器调度平台的实施是servicemesh的前提条件。 +* 数据面中的sidecar的服务治理能力则是其核心竞争力,包括负载均衡策略,路由,安全,权重等等,这些能力是以规则形式通过控制面来统一下发给数据面。在传统微服务框架下数据面和控制面的集成是紧耦合,也就是数据面和控制面是一体的,举例来说用了Dubbo框架,只能选择Dubbo-Ops。而Envoy作为servicemesh思潮的带领者,提出了一整套的API规范,Istio可以实现其xDS接口,阿里巴巴也可以根据自己的架构设计实现类似的服务平台。 +* 协议 协议 协议, 重要的事说三遍。。。sidecar和Dubbo的内核是网络协议的处理器,而sidecar又是面向多语言场景的,所以自然协议处理能力是要强调的。先说下阿里Dubbo当下向Mesh方向发展时遇到难点。首先我们的服务接口都是通过Java Interface描述,其次涉及的传输模型DTO也是Java POJO定义,最后协议也是私有的。这会导致跨语言比较难,而sidecar形态需要面向多语言,这些问题更是首当其冲。考虑到这里有点稍微偏细节点,希望大家带着如下问题来先思考下:业务应用到sidecar之间的数据交换要考虑什么? Sidecar自身在处理网络字节流时又要考虑什么?是的,首先业务应用最好都不依赖特定协议库,也不依赖特接口定义库;Sidecar自身处理数据时跟nginx很接近,但最好具备协议转换适配的能力,比如把基于HTTP的请求转换为Dubbo请求,就能轻松集成Dubbo遗留系统。 + +## 回看协议 + + +![5.png | center | 826x206](/imgs/blog/dubbomesh/5.png "") + +既然协议在跨语言场景下如此重要,有必要稍微回归下协议的历史轨迹。看历史一般是轻松有趣的过程,最重要的好处是能使我们头脑清晰而不迷茫。 + +我们先从2008年说起,很近也就10年,阿里服务框架诞生这一年。当年各大公司还在炒作SOA思想的时候,阿里在不清楚SOA思想的情况下根据自身业务诉求实践拥抱了SOA的架构。阿里服务框架一直是从三个层面来定义,第一RPC通信 第二是提供丰富强大的治理能力 第三就是基于容器隔离的运维能力,使得中间件可以独立升级。这个理念直到今日都是非常先进,非常的赞。就像前面说的,Dubbo主要是面向Java领域的微服务架构解决方案,在以Java为主导的技术架构下是绝对首选,但因为其协议设计是私有特性,要想成为跨语言的协议标准是有一定难度。 + +事实上,之前已经出现了很多通用的跨语言的服务集成规范。最早是91年的CORBA,是分布式对象访问协议,2000年的SOAP是当年webservice思想下的协议,无论是CORBA还是SOAP都是支持所有平台和语言的一套规范,但是设计地比较复杂笨重,且性能存在一定问题。 + +REST是一种架构风格,相比SOAP的设计,有非常优秀的理念和最佳实践指导,并且万维网作为世界上最大型最成功的的分布式应用是REST最好的证明。但跟SOAP一样,REST跑在1上有性能瓶颈,这个也可能是当年阿里服务框架没有选择REST规范的原因。额外提下,REST思想虽然很早就有,但事实上REST的规范在Java领域JAX-RS API 直到最近两年在2.2版本下才算稳定成形,且越来越接近微服务框架。 + +1996年的1在连接通道不支持多工复用,根本无法发挥TCP/UDP的网络能力;而到了2015年HTTP2则解决这些,能够最大限度的利用TCP层的网络宽带,且支持了streaming,push等交互模式,这些跟很多的私有或专有应用协议干得是一个事,但是标准化的大家都容易接受的事。这里必须提一下,伴随HTTP2而来的是grpc,原先Google早早推出了Protocolbuffer,但一直没把自家stubby开源,我猜测最大的原因是不想grpc跑在一个私有协议上,而是在等HTTP2. + +总结下来,协议技术一直在向着轻量级和标准规范化的方向发展。像SOAP,CORBA这些重量级的不跨平台的协议必然消失在历史车轮里,私有或专有的协议也会向标准协议靠拢。在面向跨语言的场景下,有两种的协议规范是大概率胜出,一种是REST,一种是grpc,两者都是以HTTP为交换通道。 + +## 面向多语言协议的三层面 + + +![6.png | center | 826x206](/imgs/blog/dubbomesh/6.png "") + +展开来讲,在面向多语言的协议需要考虑三个层面。 + +* 先从最右边的会话层,干得事是在tcp字节流的基础上形成交互模式,比如 一对一的标准请求响应模式, 以及onway, 一对多的streaming模式。Dubbo在这一层是有扩展能力的,目前除了支持自定义的Dubbo-Remoting,也支持基于HTTP通道能力,我们觉得未来的趋势是HTTP2,所以也会支持这块.这里在分享一句话跟大家一起思考,HTTP不是RPC,HTTP被翻译成超文本传输协议,但不是传输层。另外提一下,这一层是对于MQ,Streaming Compute,Cache等等都是通用的。 +* 再说展示层,干得事是在真正的服务调用过程中,业务对象以何种形式被格式化,比如HTTP头中的content-type就用于这个展示协议的描述,最常用的JSON,TXT,XML等。这一层对于sidecar来说,可以做透明处理,也就是说sidecar只需要解析出头部信息,前提是要求业务应用把需要在治理时用到的一些字段信息以字符串形式放到头部中。Dubbo当前是默认HEssion,跨语言能力比较弱,所以未来JSON是我们首选。 +* 最后,首先一个服务是干什么的,它的名字,方法,参数都是怎样的,等等基本元信息是需要统一描述的,即便像是REST这样基于URI,也是需要一种协议来定义,以前Dubbo是基于java interface来定义,现在我们在多语言的mesh环境下是考虑向OpenAPI specification方向考虑,支持swagger。 + 我们相信在这几个层面,尤其是会话层和应用层,用不多几年一定会是标准化的,尤其是在云原生的趋势下。 + +### 方案之Kubernetes集成Du + + +![7.png | center | 826x206](/imgs/blog/dubbomesh/7.png "") +bbo Mesh方案之Kubernetes集成 +其实,servicemesh在最近两年流行最大的原因是云原生理念的逐渐深入人心,从广义角度看,能够融入云原生的微服务框架都能称得上servicemesh。谈云原生,肯定绕不开kubernetes,所以我们在Dubbo Mesh的方案的第一个分享是 在kubernetes下的集成,目标是复用Kubernetes的基础服务,从而使得Dubbo能解决kubernetes环境下的微服务集成问题,同时能最大限度的利用dubbo已有的功能。核心思路是两点, + +* Dubbo应用在构建阶段自动生成其deployment和service的声明文件。这个主要是解决Dubbo与kubernetes的服务映射。 +* Dubbo地址注册针对kubernetes的扩展实现,通过Kubernetes的APIServer来拉取并监听某个服务的podIP。这样,在kubernetes集群内,Dubbo服务就能在其podID的虚拟网络内实现服务发现。 + +## 方案之跨语言协议支持 + + +![8.png | center | 826x206](/imgs/blog/dubbomesh/8.png "") + +前面讲了很多关于协议方面的东西,也为我们在Dubbo Mesh的方案的第二点分享是做了铺垫, 第二点的目标是Dubbo 协议的多语言支持。核心思路是 +* 积极兼容开源社区Envoy,这个使得Envoy上兼容支持Dubbo的私有协议。 +* Dubbo支持HTTP/2作为传输通道,这个是为了Dubbo的协议通道能力向更加开放更加标准规范的方向做努力。 + +## ServiceMesh之云原生的指导 + + +![9.png | center | 826x206](/imgs/blog/dubbomesh/9.png "") + +孤立地看待servicemesh其实和传统服务框架,价值还不算大,甚至成本相对更高。这时候,当我们把servicemesh设定到云原生的上下文中,就会发现不一样的意义。 + +servicemesh是云原生理念的路径地图的第五步,如果没有前面的容器化,CICD等四部,真正拥抱servicemesh也只是空中楼阁。阿里在这方面的实践经验是,servicemesh的实施是需要结合软件开发的整个生命周期进行统筹,从软件在本地开发测试,到通过持续集成服务的自动化构建,再到以镜像方式分发到仓库并依托调度云平台的持续部署,最后持续监控。 + +dubbo已经开源好多年,是非常符合云原生这个原则,正向servicemesh方向和云原生理念上努力,为企业信息化做出一点贡献。 + +## 总结 + + +总结一下Dubbo Mesh是Dubbo在cloud native下的一种演进,这个演进是为了更加开放更加靠近标准协议规范的方向做的探索。通过分享希望大家能带走三点思考。 + +1. servicemesh的多语言方案其实是走规范化标准化的协议之路,这样才能覆盖多语言的诉求。 +2. 建议大家根据实际业务场景来慎重权衡sidecar模式下运维复杂性和收益回报。 +3. 一定把servicemesh设定在云原生的上下文中才具意义,离开了Kubernetes谈servicemesh的实践是不建议的大跃进。 + 最后希望大家一起共建共享的Dubbo开源社区,谢谢。 + diff --git a/content/en/blog/java/demos/dubbo-mesh-service-mesh-exploring.md b/content/en/blog/java/demos/dubbo-mesh-service-mesh-exploring.md new file mode 100644 index 000000000000..2f7c9d2dbf02 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-mesh-service-mesh-exploring.md @@ -0,0 +1,158 @@ +--- +title: "Dubbo Mesh | Service Mesh的实践与探索" +linkTitle: "Dubbo Mesh | Service Mesh的实践与探索" +tags: ["Java"] +date: 2018-09-20 +description: 本文介绍了Dubbo在Service Mesh方向的实践与探索 +--- + + +![img](/imgs/blog/meetup-chengdu/all-hands.webp) + +近日,在Aliware Open Source•成都站-Apache Dubbo 开发者沙龙上,阿里巴巴中间件高级技术专家李云(至简)向开发者们分享了阿里巴巴中间件团队在Service Mmesh领域的探索和最新实践。本文是根据至简的现场分享所整理,为大家回顾分享中的精彩内容。 + +## 精彩观点导读 + +* 我们去探索一项技术,并不会仅仅因为其先进性,而是因为我们目前遇到了一些无法解决的问题,而这项技术正好能解决这个问题。 + +* 所有软件最重要的使命不是满足功能要求,而是演进,从而持续成长。 + +* 微服务本质是对服务的拆分,微服务架构符合工程领域常用的“分而治之”范式。 + +## 前言 + +我们去探索一项技术,并不会仅仅因为其先进性,而是因为我们目前遇到了一些无法解决的问题,而这项技术正好能解决这个问题。现在,阿里巴巴整个集团业务的体量很大,在技术上会遇到很多的挑战。而正是因为这些挑战,让我们思考通过哪些新技术可以去解决这些痛点,这也是我们在Service Mesh领域进行探索和实践的出发点。首先,我们先来看看自己遇到了哪些挑战。 + +## 微服务的5大挑战 + +#### 挑战一:微服务框架自身演进困难。 + +任何软件都会有他的生命进化曲线,从最初的萌芽,进入形成期,往上发展,再进入平台期,最后进入衰亡期。当然我们希望我们的软件可以在进入平台期后,能借助某次演进进入新的发展期。从这个维度看,所有软件最重要的使命不是满足功能要求,而是演进,从而持续成长。相反,当某个软件无法演进的时候,就会意味着死亡。但软件的演进并不是一个简单的事情,以微服务框架为例,为了进一步提升双11期间整个中间件平台的稳定性,我们会修改若干个功能,并以SDK的方式去提供给业务方,但业务代码和微服务框架SDK是强耦合的,这时候需要我们推动各个业务方和我们一同去做升级。虽然我们的初衷是实现平台稳定性的提升,帮助业务更好的发展,但这时由于大家的出发点和诉求有所不同,业务方和我们一起去做升级是比较困难的。所以要发展微服务框架,首先遇到的挑战就是演进困难。 +![img](/imgs/blog/meetup-chengdu/challenges.jpg) + +#### 挑战二:微服务框架SDK多语言并行开发与维护成本高。 + +以前我们都是通过对技术栈的统一来提升成本优势和团队效率,大家可以用一种语言去开发和维护,避免多语言时团队的不聚焦。但在软件和开源生态演进的过程中,多语言已经成为一种流行,因为不同语言都有其自身的优势,今天大家能看到的一个现象是云原生的生态中有多种开发语言,使用频率最高的语言已经不是Java了,而是Go,是因为Go的footprint很小。再以 Dubbo为例,除了Java,我们还提供C++,Node.js的SDK,以便让更多的开发者可以加入Dubbo生态,但所有的这些,如果没有社区力量的参与,是很难维持的。 +![img](/imgs/blog/meetup-chengdu/speaker.webp) + +#### 挑战三:异构服务框架难以共存完成渐进式演进。 + +我们结合场景来看看这个挑战。阿里巴巴收购了一些企业,被收购企业的技术栈可能和阿里巴巴不同,比如有些用的是Go语言,有些用的是PHP,这时候为了统一技术栈,我们需要对这类技术平台推倒重来,但这个过程中,我们会面临一系列问题,首当其冲的就是推倒重来会带来巨大的技术风险,其次是可能会面临技术人员大批量流失的风险,这在社会责任的层面也是很难接受。所以我们在寻求一种可能的方案,去解决这类问题。 + +#### 挑战四:是单一的语言限制了人才的多样性。 + +这里,我们不去争论某个编程语言的好与坏,每个语言都有其适用场景,你不能说我手里有个榔头,你面对的都是钉子。以前我们觉得统一技术栈可以集中开发力量,并且带来较高的运维便利性。但伴随着互联网带来的快节奏,以往的团队能力设置已经很难满足这类变化,对工程师个体提出了更高的要求,我们不仅仅需要是某一方面的专家,而且还需要具备多域的工作技能,DevOps和全栈工程师就是这类快节奏变化下最好的注脚。 +![img](/imgs/blog/meetup-chengdu/challenges-continued.jpg) + +#### 挑战五:是点状的服务治理难以做到及时、有效和经济。 + +微服务和架构的核心是拆分,通过拆分,让每个模块可以独立运行,跟上业务的发展速度,持续推动业务的创新。但拆完后新的问题出来了,缺少横向的内容拉通所有独立的烟囱,从而在服务治理上带来极大的挑战。 + +## 分布式应用的发展趋势 + +微服务会成为大规模分布式应用的主流架构。任何复杂的工程问题都会归结为devide and conquer(分而治之),意思就是就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。微服务本质是对服务的拆分,与工程领域惯用的“分而治之”的思路是一致的。 + +微服务架构下应用的开发是多语言的。没有一个语言是一家独大的,每种语言在特定场景下都有其自身的优势,我们希望这种优势能够将技术到产品的周期(time to market)缩短。技术的核心在于创造价值,无论是交付给客户,还是服务于整个社会。因此,微服务是需要不同语言的开发者发挥自身的优势,去进一步完善我们的微服务架构,释放技术价值。 +![img](/imgs/blog/meetup-chengdu/trends.jpg) + +数据安全将成为公有云分布式应用的生命线。云原生时代,业务即便没上云,企业对自身数据的安全都是有诉求的,尤其是在金融行业,如果通过抓包就能获取一些敏感信息,这将会给企业带来巨大的风险。 + +Cloud native成为distributionless(无分布式)的主要探索路径。分布式发展的终极形式是无分布式,在未来我们做开发,所有的代码在web上写好后,通过点击一个按钮,所有部署都会自动实现,所有的code review的工作可以在一个统一的工作台上全部实现。 +![img](/imgs/blog/meetup-chengdu/audience-shapshot.webp) + +以更快的速度,通过构建软件去探索新业务。工程师服务的是客户,通过技术输出来实现技术价值,以互联网的架构帮助赋能传统企业,帮助企业获得差异化竞争力。 + +## 什么是Service Mesh + +Service Mesh是层次化、规范化、体系化、无侵入的分布式服务治理技术平台。 + +#### 层次化 + +分为数据面和控制面两个概念,数据面是指所有数据流动的那个层面,控制面是用来控制这个数据面的,对服务去做处理。对数据面和控制面进行分层,带来的好处是,针对一个复杂的系统进行切分,可以获得更清晰的认识,这和devide and conque是同一个理念。 + +#### 规范化 + +是指通过标准协议完成数据平面和控制平面的连接,同时,sidecar成为所有traffic互联、互通的约束标准。 + +![img](/imgs/blog/meetup-chengdu/what.jpg) + +#### 体系化 + +包含两个维度,一是指observability全局考虑。目前在整个分布式治理过程中的最大挑战是:logging、metrics、tracing这三个observability领域的核心内容缺少体系性的关注。另一个是集中管理的维度,包括服务管理、限流、熔断、安全、灰度在内的服务模块都可以在获得体系化的呈现,每个服务都可以被看到,而非团队a只看限流,团队b只看logging,需要一种技术能力拉通所有的服务模块,这个体系化这个角度看,Service Mesh是一个理想的技术方案。 + +#### 无侵入 + +是指我们希望通过无侵入,当新增一个业务的时候,不需要考虑一个SDK去初始化,而是可以通过sidecar的进程方式来解耦。 + +## Service Mesh的形态 + +我们从三个维度对比的来看 ServiceMesh 的形态。 + +图中左边是传统的微服务形态,调用者和被调用者是通过一个SDK的方式来实现共享服务的,以Dubbo为例,我们会在SDK里提供服务路由、服务发现等功能,虽然我们的开发者在做应用开发的时候并不会太关注SDK的构成,但这些功能是面临不断被变更的可能,有着比较重的逻辑。在右边Service Mesh的形态中,我们首先会对厚重的SDK进行分解,将复杂的逻辑下沉到sidecar,借助sidecar来实现服务的调用。 + +![img](/imgs/blog/meetup-chengdu/forms.jpg) + +虽然在Service Mesh的形态,调用路径要长于传统的形态,路径越长消耗越大,对性能影响越大。但在当前的分布式应用的治理过程中,易用性已经成为一个比性能更重要的话题。当我们给客户部署一套微服务,即便性能很强,但没有处理好易用性问题的话,这将会给技术的推广带来巨大的阻碍,不仅是会影响外部的客户,也会影响内部的用户,如何实现喝着咖啡从容应对双11,必须先解决易用性的问题。在解决易用性问题后,沿着技术的发展路径再去解决性能问题。 + +Service Mesh的形态中的control plan不会导致重复建设,但在shared service是有可能存在重复建设的。 + +## Service Mesh下的应用架构 + +无论是单体应用,还是分布式应用,都可以建立在Service Mesh上,mesh上的sidecar支撑了所有的上层应用,业务开发者无须关心底层构成,可以用Java,也可以用Go等语言完成自己的业务开发。 + +## Service Mesh的价值 +* 为单体应用向微服务架构演进提供了渐进的途径 + +* 为异构(微)服务框架/平台提供了融合发展的可能 + + * 被收购子公司与母公司的业务可以融合发展 + +* 加速(微)服务框架/平台自身的演进 + +* 让业务开发同学聚焦于业务逻辑本身 + +* 业务开发时无需关心安全、灰度、限流、熔断等通用的技术内容 + +* 培育了多语言业务开发的土壤 + + * 助力人才发展中编程语言的多样性 + +* 对(异构)微服务架构应用实现更为有效的全局一体化监管控 + +## Dubbo Mesh的发展思路 + +* 迎合Kubernetes已成orchestrator王者的大势 + +* 开源版本与阿里巴巴集团内版本统一 + +* 与领域主流开源项目形成合力发展,源于开源、反哺开源 + +## Q&A + +#### 阿里巴巴是怎么从微服务过渡到sidecar模式,再过渡到Service Mesh? + +整个过渡是渐进式的,我们会将控制平面的一些组件先下沉到与sidecar部署在一起,这一下沉能很好复用开源软件已有的能力而减少开发工作量。当这一步骤完成后,被下沉的控制面组件会重新拉回到上面的控制面,那时就会面临一定的服务端改造,一旦改造完成就有了一个全新、完整的Service Mesh。 + +#### Service Mesh中的服务注册发现,负载均衡,网关,熔断降级,超时,限流,消息总线,分布式配置,这些都是怎么实现的? + +Dubbo Mesh在控制面会基于Istio去做,而Istio已经具备了Kubernetes下的服务注册与发现能力,我们要做的是扩充Istio的能力,让服务注册与发现能与ZooKeeper、Nacos进行对接去完成。基于开源的Envoy所实现的sidecar已实现了超时处理的功能,相应的内容可以读代码去了解。其他内容我们仍在规划中。 + +#### Dubbo Mesh目前性能怎么样? 增加一层sidecar导致Dubbo的RT有多少? + +在使用iptables的情形下,一跳增加1.5毫秒,如果不采用iptables直接proxy方式的情形下应当性能更好(这一点与Lyft也邮件确认过了),我们接下来会做更多的性能测试,目前的焦点更多在于功能层面。 + +#### Dubbo Mesh是把双刃剑,经过的链路更复杂,运维和开发者问题排查有没有更有效的工具? + +理论上,增加一跳并没有改变服务调用的拓扑结构,但确实会增加复杂度,这个应当通过设计实现去解决。好在因为是一体化的方案,所以解决这类问题时需要更具全局视野。 + +#### Service Mesh中控制面板也用C++吗?我看主流很多实现都是Go, 我相信大佬做过技术调研,有哪些优势? + +控制面是复用Istio的,是Go语言的。我们力争不重复造轮子,而是以开放的心态去共建。 + +#### Client做解码和反序列化是吧,有计划支持HTTP2协议吗? + +Envoy默认就支持了,不需我们开发。这也是借力开源的收益。 + +#### Dubbo Mesh已经支持UNIX Domain Socket了吗? + +目前不支持,这个还处于意向阶段。 diff --git a/content/en/blog/java/demos/dubbo-network-interfaces.md b/content/en/blog/java/demos/dubbo-network-interfaces.md new file mode 100644 index 000000000000..6398cb7bda15 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-network-interfaces.md @@ -0,0 +1,527 @@ +--- +title: "研究 Dubbo 网卡地址注册时的一点思考" +linkTitle: "研究 Dubbo 网卡地址注册时的一点思考" +tags: ["Java"] +date: 2019-10-01 +description: 研究 Dubbo 网卡地址注册时的一点思考 +--- + + +## 1 如何选择合适的网卡地址 + +可能相当一部分人还不知道我这篇文章到底要讲什么,我说个场景,大家应该就明晰了。在分布式服务调用过程中,以 Dubbo 为例,服务提供者往往需要将自身的 IP 地址上报给注册中心,供消费者去发现。在大多数情况下 Dubbo 都可以正常工作,但如果你留意过 Dubbo 的 github issue,其实有不少人反馈:Dubbo Provider 注册了错误的 IP。如果你能立刻联想到:多网卡、内外网地址共存、VPN、虚拟网卡等关键词,那我建议你一定要继续将本文看下去,因为我也想到了这些,它们都是本文所要探讨的东西!那么“如何选择合适的网卡地址”呢,Dubbo 现有的逻辑到底算不算完备?我们不急着回答它,而是带着这些问题一起进行研究,相信到文末,其中答案,各位看官自有评说。 + +## 2 Dubbo 是怎么做的 + +Dubbo 获取网卡地址的逻辑在各个版本中也是千回百转,走过弯路,也做过优化,我们用最新的 2.7.2-SNAPSHOT 版本来介绍,在看以下源码时,大家可以怀着质疑的心态去阅读,在 dubbo github 的 master 分支可以获取源码。获取 localhost 的逻辑位于 `org.apache.dubbo.common.utils.NetUtils#getLocalAddress0()` 之中 + +```java +private static InetAddress getLocalAddress0() { + InetAddress localAddress = null; + // 首先尝试获取 /etc/hosts 中 hostname 对应的 IP + localAddress = InetAddress.getLocalHost(); + Optional addressOp = toValidAddress(localAddress); + if (addressOp.isPresent()) { + return addressOp.get(); + } + + // 没有找到适合注册的 IP,则开始轮询网卡 + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + if (null == interfaces) { + return localAddress; + } + while (interfaces.hasMoreElements()) { + NetworkInterface network = interfaces.nextElement(); + Enumeration addresses = network.getInetAddresses(); + while (addresses.hasMoreElements()) { + // 返回第一个匹配的适合注册的 IP + Optional addressOp = toValidAddress(addresses.nextElement()); + if (addressOp.isPresent()) { + return addressOp.get(); + } + } + } + return localAddress; +} +``` + +Dubbo 这段选取本地地址的逻辑大致分成了两步 + +1. 先去 /etc/hosts 文件中找 hostname 对应的 IP 地址,找到则返回;找不到则转 2 +2. 轮询网卡,寻找合适的 IP 地址,找到则返回;找不到返回 null,在 getLocalAddress0 外侧还有一段逻辑,如果返回 null,则注册 127.0.0.1 这个本地回环地址 + +首先强调下,这段逻辑并没有太大的问题,先别急着挑刺,让我们来分析下其中的一些细节,并进行验证。 + +### 2.1 尝试获取 hostname 映射 IP + +Dubbo 首先选取的是 hostname 对应的 IP,在源码中对应的 `InetAddress.getLocalHost();` 在 `*nix` 系统实际部署 Dubbo 应用时,可以首先使用 `hostname` 命令获取主机名 + +```shell +xujingfengdeMacBook-Pro:~ xujingfeng$ hostname +xujingfengdeMacBook-Pro.local +``` + +紧接着在 `/etc/hosts` 配置 IP 映射,为了验证 Dubbo 的机制,我们随意为 hostname 配置一个 IP 地址 + +``` +127.0.0.1 localhost +1.2.3.4 xujingfengdeMacBook-Pro.local +``` + +接着调用 `NetUtils.getLocalAddress0()` 进行验证,控制台打印如下: + +``` +xujingfengdeMacBook-Pro.local/1.2.3.4 +``` + +### 2.2 判定有效的 IP 地址 + +在 toValidAddress 逻辑中,Dubbo 存在以下逻辑判定一个 IP 地址是否有效 + +```java +private static Optional toValidAddress(InetAddress address) { + if (address instanceof Inet6Address) { + Inet6Address v6Address = (Inet6Address) address; + if (isValidV6Address(v6Address)) { + return Optional.ofNullable(normalizeV6Address(v6Address)); + } + } + if (isValidV4Address(address)) { + return Optional.of(address); + } + return Optional.empty(); +} +``` + +依次校验其符合 Ipv6 或者 Ipv4 的 IP 规范,对于 Ipv6 的地址,见如下代码: + +```java +static boolean isValidV6Address(Inet6Address address) { + boolean preferIpv6 = Boolean.getBoolean("java.net.preferIPv6Addresses"); + if (!preferIpv6) { + return false; + } + try { + return address.isReachable(100); + } catch (IOException e) { + // ignore + } + return false; +} +``` + +首先获取 `java.net.preferIPv6Addresses` 参数,其默认值为 false,鉴于大多数应用并没有使用 Ipv6 地址作为理想的注册 IP,这问题不大,紧接着通过 isReachable 判断网卡的连通性。例如一些网卡可能是 VPN/虚拟网卡的地址,如果没有配置路由表,往往无法连通,可以将之过滤。 + +对于 Ipv4 的地址,见如下代码: + +```java +static boolean isValidV4Address(InetAddress address) { + if (address == null || address.isLoopbackAddress()) { + return false; + } + String name = address.getHostAddress(); + boolean result = (name != null + && IP_PATTERN.matcher(name).matches() + && !Constants.ANYHOST_VALUE.equals(name) + && !Constants.LOCALHOST_VALUE.equals(name)); + return result; +} +``` + +对比 Ipv6 的判断,这里我们已经发现前后不对称的情况了 + +- Ipv4 相比 Ipv6 的逻辑多了 Ipv4 格式的正则校验、本地回环地址校验、ANYHOST 校验 +- Ipv4 相比 Ipv6 的逻辑少了网卡连通性的校验 + +大家都知道,Ipv4 将 127.0.0.1 定为本地回环地址, Ipv6 也存在回环地址:0:0:0:0:0:0:0:1 或者表示为 ::1。改进建议也很明显,我们放到文末统一总结。 + +### 2.3 轮询网卡 + +如果上述地址获取为 null 则进入轮询网卡的逻辑(例如 hosts 未指定 hostname 的映射或者 hostname 配置成了 127.0.0.1 之类的地址便会导致获取到空的网卡地址),轮询网卡对应的源码是 `NetworkInterface.getNetworkInterfaces()` ,这里面涉及的知识点就比较多了,支撑起了我写这篇文章的素材,Dubbo 的逻辑并不复杂,进行简单的校验,返回第一个可用的 IP 即可。 + +性子急的读者可能忍不住了,多网卡!合适的网卡可能不止一个,Dubbo 怎么应对呢?按道理说,我们也替 Dubbo 说句公道话,客官要不你自己指定下?我们首先得对多网卡的场景达成一致看法,才能继续把这篇文章完成下去:我们只能**尽可能**过滤那些“**不对**”的网卡。Dubbo 看样子对所有网卡是一视同仁了,那么是不是可以尝试优化一下其中的逻辑呢? + +许多开源的服务治理框架在 stackoverflow 或者其 issue 中,注册错 IP 相关的问题都十分高频,大多数都是轮询网卡出了问题。既然事情发展到这儿,势必需要了解一些网络、网卡的知识,我们才能过滤掉那些明显不适合 RPC 服务注册的 IP 地址了。 + +## 3 Ifconfig 介绍 + +我并没有想要让大家对后续的内容望而却步,特地选择了这个大家最熟悉的 Linux 命令!对于那些吐槽:“天呐,都 2019 年了,你怎么还在用 net-tools/ifconfig,iproute2/ip 了解一下”的言论,请大家视而不见。无论你使用的是 mac,还是 linux,都可以使用它去 CRUD 你的网卡配置。 + +### 3.1 常用指令 + +**启动关闭指定网卡:** + +``` +ifconfig eth0 up +ifconfig eth0 down +``` + +`ifconfig eth0 up` 为启动网卡 eth0,`ifconfig eth0 down` 为关闭网卡 eth0。ssh 登陆 linux 服务器操作的用户要小心执行这个操作了,千万不要蠢哭自己。不然你下一步就需要去 google:“禁用 eth0 网卡后如何远程连接 Linux 服务器” 了。 + +**为网卡配置和删除IPv6地址:** + +``` +ifconfig eth0 add 33ffe:3240:800:1005::2/64 #为网卡eth0配置IPv6地址 +ifconfig eth0 del 33ffe:3240:800:1005::2/64 #为网卡eth0删除IPv6地址 +``` + +**用 ifconfig 修改 MAC 地址:** + +``` +ifconfig eth0 hw ether 00:AA:BB:CC:dd:EE +``` + +**配置 IP 地址:** + +``` +[root@localhost ~]# ifconfig eth0 192.168.2.10 +[root@localhost ~]# ifconfig eth0 192.168.2.10 netmask 255.255.255.0 +[root@localhost ~]# ifconfig eth0 192.168.2.10 netmask 255.255.255.0 broadcast 192.168.2.255 +``` + +**启用和关闭arp协议:** + +``` +ifconfig eth0 arp #开启网卡eth0 的arp协议 +ifconfig eth0 -arp #关闭网卡eth0 的arp协议 +``` + +**设置最大传输单元:** + +``` +ifconfig eth0 mtu 1500 #设置能通过的最大数据包大小为 1500 bytes +``` + +### 3.2 查看网卡信息 + +在一台 ubuntu 上执行 `ifconfig -a` + +```shell +ubuntu@VM-30-130-ubuntu:~$ ifconfig -a +eth0 Link encap:Ethernet HWaddr 52:54:00:a9:5f:ae + inet addr:10.154.30.130 Bcast:10.154.63.255 Mask:255.255.192.0 + UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 + RX packets:149673 errors:0 dropped:0 overruns:0 frame:0 + TX packets:152271 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:1000 + RX bytes:15205083 (15.2 MB) TX bytes:21386362 (21.3 MB) + +lo Link encap:Local Loopback + inet addr:127.0.0.1 Mask:255.0.0.0 + UP LOOPBACK RUNNING MTU:65536 Metric:1 + RX packets:0 errors:0 dropped:0 overruns:0 frame:0 + TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:1 + RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) + +docker0 Link encap:Ethernet HWaddr 02:42:58:45:c1:15 + inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0 + UP BROADCAST MULTICAST MTU:1500 Metric:1 + RX packets:0 errors:0 dropped:0 overruns:0 frame:0 + TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:0 + RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) + +tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + UP POINTOPOINT NOARP MULTICAST MTU:1500 Metric:1 + RX packets:0 errors:0 dropped:0 overruns:0 frame:0 + TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:100 + RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) +``` + +为了防止黑客对我的 Linux 发起攻击,我还是偷偷对 IP 做了一点“改造”,请不要为难一个趁着打折+组团购买廉价云服务器的小伙子。对于部分网卡的详细解读: + +eth0 表示第一块网卡, 其中 HWaddr 表示网卡的物理地址,可以看到目前这个网卡的物理地址(MAC 地址)是 02:42:38:52:70:54 + +inet addr 用来表示网卡的 IP 地址,此网卡的 IP 地址是 10.154.30.130,广播地址, Bcast: 172.18.255.255,掩码地址 Mask:255.255.0.0 + +lo 是表示主机的回环地址,这个一般是用来测试一个网络程序,但又不想让局域网或外网的用户能够查看,只能在此台主机上运行和查看所用的网络接口。比如把 HTTPD 服务器的指定到回坏地址,在浏览器输入 127.0.0.1 就能看到你所架构的 WEB 网站了。但只有你能看得到,局域网的其它主机或用户则无从知晓。 + +第一行:连接类型:Ethernet(以太网)HWaddr(硬件mac地址) + +第二行:网卡的IP地址、子网、掩码 + +第三行:UP(代表网卡开启状态)RUNNING(代表网卡的网线被接上)MULTICAST(支持组播)MTU:1500(最大传输单元):1500字节(ifconfig 不加 -a 则无法看到 DOWN 的网卡) + +第四、五行:接收、发送数据包情况统计 + +第七行:接收、发送数据字节数统计信息。 + +紧接着的两个网卡 docker0,tun0 是怎么出来的呢?我在我的 ubuntu 上装了 docker 和 openvpn。这两个东西应该是日常干扰我们做服务注册时的罪魁祸首了,当然,也有可能存在 eth1 这样的第二块网卡。ifconfig -a 看到的东西就对应了 JDK 的 api :`NetworkInterface.getNetworkInterfaces()` 。我们简单做个总结,大致有三个干扰因素 + +- 以 docker 网桥为首的虚拟网卡地址,毕竟这东西这么火,怎么也得单独列出来吧? +- 以 TUN/TAP 为代表的虚拟网卡地址,多为 VPN 场景 +- 以 eth1 为代表的多网卡场景,有钱就可以装多网卡了! + +我们后续的篇幅将针对这些场景做分别的介绍,力求让大家没吃过猪肉,起码看下猪怎么跑的。 + +## 4 干扰因素一:Docker 网桥 + +熟悉 docker 的朋友应该知道 docker 会默认创建一个 docker0 的网桥,供容器实例连接。如果嫌默认的网桥不够直观,我们可以使用 bridge 模式自定义创建一个新的网桥: + +```shell +ubuntu@VM-30-130-ubuntu:~$ docker network create kirito-bridge +a38696dbbe58aa916894c674052c4aa6ab32266dcf6d8111fb794b8a344aa0d9 +ubuntu@VM-30-130-ubuntu:~$ ifconfig -a +br-a38696dbbe58 Link encap:Ethernet HWaddr 02:42:6e:aa:fd:0c + inet addr:172.19.0.1 Bcast:172.19.255.255 Mask:255.255.0.0 + UP BROADCAST MULTICAST MTU:1500 Metric:1 + RX packets:0 errors:0 dropped:0 overruns:0 frame:0 + TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:0 + RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) +``` + +使用 docker network 指令创建网桥之后,自动创建了对应的网卡,我只给出了 `ifconfig -a` 的增量返回部分,可以看出多了一个 br-a38696dbbe58 的网卡。 + +我有意区分了“网桥”和“网卡”,可以使用 bridge-utils/brctl 来查看网桥信息: + +```shell +ubuntu@VM-30-130-ubuntu:~$ sudo brctl show +bridge name bridge id STP enabled interfaces +br-a38696dbbe58 8000.02426eaafd0c no +docker0 8000.02425845c215 no +``` + +网桥是一个虚拟设备,这个设备只有 brctl show 能看到,网桥创建之后,会自动创建一个同名的网卡,并将这个网卡加入网桥。 + +## 5 干扰因素二:TUN/TAP 虚拟网络设备 + +平时我们所说的虚拟网卡、虚拟机,大致都跟 TUN/TAP 有关。我的读者大多数是 Java 从业者,相信我下面的内容并没有太超纲,不要被陌生的名词唬住。对于被唬住的读者,也可以直接跳过 5.1~5.3,直接看 5.4 的实战。 + +### 5.1 真实网卡工作原理 + +![1918847-496d0e96c237f25a](/imgs/blog/network/01.png) + +上图中的 **eth0** 表示我们主机已有的真实的网卡接口 (**interface**)。 + +网卡接口 **eth0** 所代表的真实网卡通过网线(**wire**)和外部网络相连,该物理网卡收到的数据包会经由接口 **eth0** 传递给内核的网络协议栈(**Network Stack**)。然后协议栈对这些数据包进行进一步的处理。 + +对于一些错误的数据包,协议栈可以选择丢弃;对于不属于本机的数据包,协议栈可以选择转发;而对于确实是传递给本机的数据包,而且该数据包确实被上层的应用所需要,协议栈会通过 **Socket API** 告知上层正在等待的应用程序。 + +### 5.2 TUN 工作原理 + +![1918847-85ea08bc89d9427e](/imgs/blog/network/02.png) + +我们知道,普通的网卡是通过网线来收发数据包的话,而 **TUN** 设备比较特殊,它通过一个文件收发数据包。 + +如上图所示,**tunX** 和上面的 **eth0** 在逻辑上面是等价的, **tunX** 也代表了一个网络接口,虽然这个接口是系统通过软件所模拟出来的. + +网卡接口 **tunX 所代表的虚拟网卡通过文件 /dev/tunX 与我们的应用程序(App)相连**,应用程序每次使用 **write** 之类的系统调用将数据写入该文件,这些数据会以网络层数据包的形式,通过该虚拟网卡,经由网络接口 **tunX** 传递给网络协议栈,同时该应用程序也可以通过 **read** 之类的系统调用,经由文件 **/dev/tunX** 读取到协议栈向 **tunX** 传递的**所有**数据包。 + +此外,协议栈可以像操纵普通网卡一样来操纵 **tunX** 所代表的虚拟网卡。比如说,给 **tunX** 设定 **IP** 地址,设置路由,总之,在协议栈看来,**tunX** 所代表的网卡和其他普通的网卡区别不大,当然,硬要说区别,那还是有的,那就是 **tunX** 设备不存在 **MAC** 地址,这个很好理解,**tunX** 只模拟到了网络层,要 **MAC**地址没有任何意义。当然,如果是 **tapX** 的话,在协议栈的眼中,**tapX** 和真实网卡没有任何区别。 + +是不是有些懵了?我是谁,为什么我要在这篇文章里面学习 TUN!因为我们常用的 VPN 基本就是基于 TUN/TAP 搭建的,如果我们使用 **TUN** 设备搭建一个基于 **UDP** 的 **VPN** ,那么整个处理过程可能是这幅样子: + +![1918847-ac4155ec7e9489b2](/imgs/blog/network/03.png) + +### 5.3 TAP 工作原理 + +**TAP** 设备与 **TUN** 设备工作方式完全相同,区别在于: + +1. **TUN** 设备是一个三层设备,它只模拟到了 **IP** 层,即网络层 我们可以通过 **/dev/tunX** 文件收发 **IP** 层数据包,它无法与物理网卡做 **bridge**,但是可以通过三层交换(如 **ip_forward**)与物理网卡连通。可以使用`ifconfig`之类的命令给该设备设定 **IP** 地址。 +2. **TAP** 设备是一个二层设备,它比 **TUN** 更加深入,通过 **/dev/tapX** 文件可以收发 **MAC** 层数据包,即数据链路层,拥有 **MAC** 层功能,可以与物理网卡做 **bridge**,支持 **MAC** 层广播。同样的,我们也可以通过`ifconfig`之类的命令给该设备设定 **IP** 地址,你如果愿意,我们可以给它设定 **MAC** 地址。 + +关于文章中出现的二层,三层,我这里说明一下,第一层是物理层,第二层是数据链路层,第三层是网络层,第四层是传输层。 + +### 5.4 openvpn 实战 + +openvpn 是 Linux 上一款开源的 vpn 工具,我们通过它来复现出影响我们做网卡选择的场景。 + +安装 openvpn + +```shell +sudo apt-get install openvpn +``` + +安装一个 TUN 设备: + +```shell +ubuntu@VM-30-130-ubuntu:~$ sudo openvpn --mktun --dev tun0 +Mon Apr 29 22:23:31 2019 TUN/TAP device tun0 opened +Mon Apr 29 22:23:31 2019 Persist state set to: ON +``` + +安装一个 TAP 设备: + +```shell +ubuntu@VM-30-130-ubuntu:~$ sudo openvpn --mktun --dev tap0 +Mon Apr 29 22:24:36 2019 TUN/TAP device tap0 opened +Mon Apr 29 22:24:36 2019 Persist state set to: ON +``` + +执行 `ifconfig -a` 查看网卡,只给出增量的部分: + +```shell +tap0 Link encap:Ethernet HWaddr 7a:a2:a8:f1:6b:df + BROADCAST MULTICAST MTU:1500 Metric:1 + RX packets:0 errors:0 dropped:0 overruns:0 frame:0 + TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:100 + RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) + +tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:10.154.30.131 P-t-P:10.154.30.131 Mask:255.255.255.255 + UP POINTOPOINT NOARP MULTICAST MTU:1500 Metric:1 + RX packets:0 errors:0 dropped:0 overruns:0 frame:0 + TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:100 + RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) +``` + +这样就解释了文章一开始为什么会有 tun0 这样的网卡了。这里读者可能会有疑惑,使用 ifconfig 不是也可以创建 tap 和 tun 网卡吗?当然啦,openvpn 是一个 vpn 工具,只能创建名为 tunX/tapX 的网卡,其遵守着一定的规范,ifconfig 可以随意创建,但没人认那些随意创建的网卡。 + +## 6 干扰因素三:多网卡 + +![image-20190429223515625](/imgs/blog/network/04.png) + +这个没有太多好说的,有多张真实的网卡,从普哥那儿搞到如上的 IP 信息。 + +## 7 MAC 下的差异 + +虽然 ifconfig 等指令是 `*nux` 通用的,但是其展示信息,网卡相关的属性和命名都有较大的差异。例如这是我 MAC 下执行 `ifconfig -a` 的返回: + +```shell +xujingfengdeMacBook-Pro:dubbo-in-action xujingfeng$ ifconfig -a +lo0: flags=8049 mtu 16384 + options=1203 + inet 127.0.0.1 netmask 0xff000000 + inet6 ::1 prefixlen 128 + inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 + nd6 options=201 +gif0: flags=8010 mtu 1280 +stf0: flags=0<> mtu 1280 +XHC0: flags=0<> mtu 0 +XHC20: flags=0<> mtu 0 +en0: flags=8863 mtu 1500 + ether 88:e9:fe:88:a0:76 + inet6 fe80::1cab:f689:60d1:bacb%en0 prefixlen 64 secured scopeid 0x6 + inet 30.130.11.242 netmask 0xffffff80 broadcast 30.130.11.255 + nd6 options=201 + media: autoselect + status: active +p2p0: flags=8843 mtu 2304 + ether 0a:e9:fe:88:a0:76 + media: autoselect + status: inactive +awdl0: flags=8943 mtu 1484 + ether 66:d2:8c:8c:dd:85 + inet6 fe80::64d2:8cff:fe8c:dd85%awdl0 prefixlen 64 scopeid 0x8 + nd6 options=201 + media: autoselect + status: active +en1: flags=8963 mtu 1500 + options=60 + ether aa:00:d0:13:0e:01 + media: autoselect + status: inactive +en2: flags=8963 mtu 1500 + options=60 + ether aa:00:d0:13:0e:00 + media: autoselect + status: inactive +bridge0: flags=8863 mtu 1500 + options=63 + ether aa:00:d0:13:0e:01 + Configuration: + id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0 + maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200 + root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0 + ipfilter disabled flags 0x2 + member: en1 flags=3 + ifmaxaddr 0 port 9 priority 0 path cost 0 + member: en2 flags=3 + ifmaxaddr 0 port 10 priority 0 path cost 0 + nd6 options=201 + media: + status: inactive +utun0: flags=8051 mtu 2000 + inet6 fe80::3fe0:3e8b:384:9968%utun0 prefixlen 64 scopeid 0xc + nd6 options=201 +utun1: flags=8051 mtu 1380 + inet6 fe80::7894:3abc:5abd:457d%utun1 prefixlen 64 scopeid 0xd + nd6 options=201 +``` + +内容很多,我挑几点差异简述下: + +- 内容展示形式不一样,没有 Linux 下的接收、发送数据字节数等统计信息 + +- 真实网卡的命名不一样:eth0 -> en0 +- 虚拟网卡的命名格式不一样:tun/tap -> utun + +对于这些常见网卡命名的解读,我摘抄一部分来自 stackoverflow 的回答: + +> In arbitrary order of my familarity / widespread relevance: +> +> `lo0` is loopback. +> +> `en0` at one point "ethernet", now is WiFi (and I have no idea what extra `en1` or `en2` are used for). +> +> `fw0` is the FireWire network interface. +> +> `stf0` is an [IPv6 to IPv4 tunnel interface](https://www.freebsd.org/cgi/man.cgi?gif(4)) to support [the transition](http://en.wikipedia.org/wiki/6to4) from IPv4 to the IPv6 standard. +> +> `gif0` is a more [generic tunneling interface](https://www.freebsd.org/cgi/man.cgi?gif(4)) [46]-to-[46]. +> +> `awdl0` is [Apple Wireless Direct Link](https://stackoverflow.com/questions/19587701/what-is-awdl-apple-wireless-direct-link-and-how-does-it-work) +> +> `p2p0` is related to AWDL features. Either as an old version, or virtual interface with different semantics than `awdl`. +> +> the "Network" panel in System Preferences to see what network devices "exist" or "can exist" with current configuration. +> +> many VPNs will add additional devices, often "utun#" or "utap#" following [TUN/TAP (L3/L2)](https://en.wikipedia.org/wiki/TUN/TAP)virtual networking devices. +> +> use `netstat -nr` to see how traffic is currently routed via network devices according to destination. +> +> interface naming conventions started in BSD were retained in OS X / macOS, and now there also additions. + +## 8 Dubbo 改进建议 + +我们进行了以上探索,算是对网卡有一点了解了。回过头来看看 Dubbo 获取网卡的逻辑,是否可以做出改进呢? + +**Dubbo Action 1:** + +保持 Ipv4 和 Ipv6 的一致性校验。为 Ipv4 增加连通性校验;为 Ipv6 增加 LoopBack 和 ANYHOST 等校验。 + +**Dubbo Action 2:** + +```java +NetworkInterface network = interfaces.nextElement(); +if (network.isLoopback() || network.isVirtual() || !network.isUp()) { + continue; +} +``` + +JDK 提供了以上的 API,我们可以利用起来,过滤一部分一定不正确的网卡。 + +**Dubbo Action 3:** + +我们本文花了较多的篇幅介绍了 docker 和 TUN/TAP 两种场景导致的虚拟网卡的问题,算是较为常见的一个影响因素,虽然他们的命名具有固定性,如 docker0、tunX、tapX,但我觉得通过网卡名称的判断方式去过滤注册 IP 有一些 hack,所以不建议 dubbo contributor 提出相应的 pr 去增加这些 hack 判断,尽管可能会对判断有所帮助。 + +对于真实多网卡、内外网 IP 共存的场景,不能仅仅是框架侧在做努力,用户也需要做一些事,就像爱情一样,我可以主动一点,但你也得反馈,才能发展出故事。 + +**Dubbo User Action 1:** + +可以配置 `/etc/hosts` 文件,将 hostname 对应的 IP 显式配置进去。 + +**Dubbo User Action 2:** + +可以使用启动参数去显式指定注册的 IP: + +```java +-DDUBBO_IP_TO_REGISTRY=1.2.3.4 +``` + +也可以指定 Dubbo 服务绑定在哪块网卡上: + +```java +-DDUBBO_IP_TO_BIND=1.2.3.4 +``` + +## 9 参考文章 + +[TUN/TAP 设备浅析](https://www.jianshu.com/p/09f9375b7fa7) + +[what-are-en0-en1-p2p-and-so-on-that-are-displayed-after-executing-ifconfig](https://stackoverflow.com/questions/29958143/what-are-en0-en1-p2p-and-so-on-that-are-displayed-after-executing-ifconfig) \ No newline at end of file diff --git a/content/en/blog/java/demos/dubbo-new-async.md b/content/en/blog/java/demos/dubbo-new-async.md new file mode 100644 index 000000000000..4f2d8ce2f39d --- /dev/null +++ b/content/en/blog/java/demos/dubbo-new-async.md @@ -0,0 +1,462 @@ +--- +title: "如何基于Dubbo实现全异步调用链" +linkTitle: "如何基于Dubbo实现全异步调用链" +tags: ["Java"] +date: 2018-09-02 +description: > + 本文回顾了 2.6.x 版本的异步实现,然后引出了 2.7.0 版本基于 CompletableFuture 的异步编程方式。 +--- + +基于Dubbo实现全异步编程,是在2.7.0版本中对现有异步方式增强后新引入的功能。本文先是回顾2.6.x及之前版本对异步的支持情况及存在的问题,引出了2.7.0版本基于CompletableFuture做了哪些针对性的增强,通过几个示例详细阐述了增强后的异步编程的使用方式,最后总结了引入异步模式带来的新问题及Dubbo的解决方法。通过阅读这篇文章,可以很容易的基于Dubbo2.7.0+版本实现一个全异步的远程服务调用链路。 + +从3.0.0版本开始,Dubbo框架提供了对Reactive编程范式的支持,除了编程接口之外,在跨进程的RPC通信中引入了Reactive的语义。如果你所在的环境需要使用Reactive编程范式,或者你的RPC调用需要支持流式传输,Reactive应该会给你带来帮助,具体请参考发布在阿里巴巴中间件公众号上的响应式编程支持相关文章。 +> 注意,你可能并不是总需要Reactive的语义,尤其是在RPC的场景,CompletableFuture本身也能带给你Reactive模式的编程模型,在选择Reactive(RxJava、Reactor之类)而不是理解及使用成本更低的CompletableFuture前,请尝试关注以下问题: +> 1. 你是请求/响应是一次性传输的还是流式传输的,一个明显特征是你定义的数据类型是 `List` 还是 `Stream` +> 2. 你的RPC请求有没有要求是Cold,即在subscribe后触发,因为CompletableFuture总是hot的 +> 3. 你依赖的编程上下文中是否已经在大量使用Reactive的编程接口 +> 4. 你是否需要Rx框架提供的更丰富的Operator,而这点和1又是密切相关的 + + + +## 2.6.x版本之前的异步方式 + +在2.6.x及之前的版本提供了一定的异步编程能力,包括Consumer端[异步调用](/en/docsv2.7/user/examples/async-call/)、[参数回调](/en/docsv2.7/user/examples/callback-parameter/)、[事件通知](/en/docsv2.7/user/examples/events-notify/)等,在上面的文档链接中有关于使用方式的简单介绍和Demo。 + +关于参数回调,其本质上是一种服务端的数据推送能力,这是终端应用很常见的一种需求,关于这部分的重构计划,不在本文讨论范围。 + +但当前的异步方式存在以下问题: + +- Future获取方式不够直接 +- Future接口无法实现自动回调,而自定义ResponseFuture虽支持回调但支持的异步场景有限,如不支持Future间的相互协调或组合等 +- 不支持Provider端异步 + +以Consumer端异步使用方式为例: + +1. 定义一个普通的同步接口并声明支持异步调用 + +```java +public interface FooService { + String findFoo(String name); +} +``` + +```xml + + + +``` + +2. 通过RpcContext获取Future + +```java +// 此调用会立即返回null +fooService.findFoo(fooId); +// 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future +Future fooFuture = RpcContext.getContext().getFuture(); +fooFuture.get(); +``` + +或 + +```java +// 此调用会立即返回null +fooService.findFoo(fooId); +// 拿到Dubbo内置的ResponseFuture并设置回调 +ResponseFuture future = ((FutureAdapter)RpcContext.getContext().getFuture()).getFuture(); +future.setCallback(new ResponseCallback() { + @Override + public void done(Object response) { + System.out.print(response); + } + + @Override + public void caught(Throwable exception) { + exception.printStackTrace(); + } +}); +``` + +从这个简单的示例我们可以体会到一些使用中的不便之处: + +1. findFoo的同步接口,不能直接返回代表异步结果的Future,通过RpcContext进一步获取。 +2. Future只支持阻塞式的get()接口获取结果。 +3. 通过获取内置的ResponseFuture接口,可以设置回调。但获取ResponseFuture的API使用不便,且仅支持设置回调其他异步场景均不支持,如多个Future协同工作的场景等。 + +## 2.7.0基于CompletableFuture的增强 + +了解Java中Future演进历史的同学应该知道,Dubbo 2.6.x及之前版本中使用的Future是在java 5中引入的,所以存在以上一些功能设计上的问题,而在java 8中引入的CompletableFuture进一步丰富了Future接口,很好的解决了这些问题。 + +Dubbo在2.7.0版本已经升级了对Java 8的支持,同时基于CompletableFuture对当前的异步功能进行了增强。 + +1. 支持直接定义返回CompletableFuture的服务接口。通过这种类型的接口,我们可以更自然的实现Consumer、Provider端的异步编程。 + + + + ```java + public interface AsyncService { + CompletableFuture sayHello(String name); + } + ``` + + +2. 如果你不想将接口的返回值定义为Future类型,或者存在定义好的同步类型接口,则可以选择重载原始方法并为新方法定义CompletableFuture类型返回值。 + + + + ```java + public interface GreetingsService { + String sayHi(String name); + } + ``` + + + + ```java + public interface GreetingsService { + String sayHi(String name); + // 为了保证方法级服务治理规则依然有效,建议保持方法名不变: sayHi + // 使用default实现,避免给服务端提供者带来额外实现成本 + // boolean placeHoler只是为了实现重载而增加,只要Java语法规则允许,你可以使用任何方法重载手段 + default CompletableFuture sayHi(String name, boolean placeHolder) { + return CompletableFuture.completedFuture(sayHello(name)); + } + } + ``` + + + + 这样,Provider依然可以只实现sayHi方法;而Consumer通过直接调用新增的sayHi重载方法可以拿到一个Future实例。 + + +3. 如果你的原始接口定义是同步的,这时要实现Provider端异步,则可以使用AsyncContext(类似Servlet 3.0里的AsyncContext的编程接口)。 + +> 注意:在已有CompletabeFuture返回类型的接口上,不建议再使用AsyncContext,请直接利用CompletableFuture带来的异步能力。 + + + ``` + public interface AsyncService { + String sayHello(String name); + } + ``` + + + + ``` + public class AsyncServiceImpl implements AsyncService { + public String sayHello(String name) { + final AsyncContext asyncContext = RpcContext.startAsync(); + new Thread(() -> { + asyncContext.write("Hello " + name + ", response from provider."); + }).start(); + return null; + } + } + ``` + + + + 在方法体的开始`RpcContext.startAsync()`启动异步,并开启新线程异步的执行业务逻辑,在耗时操作完成后通过`asyncContext.write`将结果写回。 + +4. RpcContext直接返回CompletableFuture + + + + ``` + CompletableFuture f = RpcContext.getContext().getCompletableFuture(); + ``` + +以上所有的增强,是在兼容已有异步编程的基础上进行的,因此基于2.6.x版本编写的异步程序不用做任何改造即可顺利编译通过。 + +接下来,我们通过几个示例看一下如何实现一个全异步的Dubbo服务调用链。 + +## 示例1:CompletableFuture类型接口 + +CompletableFuture类型的接口既可以用作同步调用,也可以实现Consumer或Provider的异步调用。本示例实现了Consumer和Provider端异步调用,代码参见[dubbo-samples-async-original-future](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-async/dubbo-samples-async-original-future)。 + +1. 定义接口 + + ```java + public interface AsyncService { + CompletableFuture sayHello(String name); + } + ``` + + 注意接口的返回类型是`CompletableFuture`。 + +2. Provider端 + + - 实现 + + ```java + public class AsyncServiceImpl implements AsyncService { + public CompletableFuture sayHello(String name) { + return CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "async response from provider."; + }); + } + } + ``` + + 可以看到这里通过supplyAsync将业务代码切换到了新的线程执行,因此实现了Provider端异步。 + + - 配置 + + ```xml + + + ``` + + 配置方式和普通接口是一样的。 + +3. Consumer端 + + - 配置 + + ```xml + + ``` + ​ 配置方式和普通接口是一样的。 + + - 调用远程服务 + + ```java + public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/async-consumer.xml"}); + context.start(); + final AsyncService asyncService = (AsyncService) context.getBean("asyncService"); + + CompletableFuture future = asyncService.sayHello("async call request"); + future.whenComplete((v, t) -> { + if (t != null) { + t.printStackTrace(); + } else { + System.out.println("Response: " + v); + } + }); + System.out.println("Executed before response return."); + System.in.read(); + } + ``` + + `CompletableFuture future = asyncService.sayHello("async call request");`很自然的返回了Future示例,这样就实现了Consumer端的异步服务调用。 + +## 示例2:重载同步接口 + +这个示例演示了如何在同步接口的基础上,通过增加重载方法实现消费端的异步调用,具体代码参见地址[dubbo-samples-async-generated-future](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-async/dubbo-samples-async-generated-future) + +1. 定义接口 + + ```java + @DubboAsync + public interface GreetingsService { + String sayHi(String name); + } + ``` + + 修改接口,增加重载方法 + + ```java + public interface GreetingsService { + String sayHi(String name); + + default CompletableFuture sayHi(String name, boolean isAsync) { + return CompletableFuture.completedFuture(sayHello(name)); + } + } + ``` + +2. Provider端 + + + - 配置 + + + ```xml + + + ``` + + + + - 服务实现 + + ```java + public class GreetingsServiceImpl implements GreetingsService { + @Override + public String sayHi(String name) { + return "hi, " + name; + } + } + ``` + +3. Consumer端 + + - 配置 + + ```xml + + ``` + + - 调用服务 + + ```java + public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/async-consumer.xml"}); + context.start(); + + GreetingsService greetingsService = (GreetingsService) context.getBean("greetingsService"); + CompletableFuture future = greetingsService.sayHi("async call reqeust", true); + System.out.println("async call ret :" + future.get()); + + System.in.read(); + } + ``` + + + + 这样,我们就可以直接使用`CompletableFuture future = greetingsService.sayHi("async call reqeust", true);`,直接返回CompletableFuture。 + +## 示例3:使用AsyncContext + +本示例演示了如何在同步接口的基础上,通过AsyncContext实现Provider端异步执行,示例代码参见[dubbo-samples-async-provider](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-async/dubbo-samples-async-provider)。 + +> 之前已经提到过,已经是CompletableFuture签名的接口,要实现Provider端异步没必要再用AsyncContext。 + +1. 定义接口 + + ```java + public interface AsyncService { + String sayHello(String name); + } + ``` + +2. Provider端,和普通provider端配置完全一致 + + - 配置 + + ```xml + + + ``` + + - 异步执行实现 + + ```java + public class AsyncServiceImpl implements AsyncService { + public String sayHello(String name) { + final AsyncContext asyncContext = RpcContext.startAsync(); + new Thread(() -> { + asyncContext.signalContextSwitch(); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + asyncContext.write("Hello " + name + ", response from provider."); + }).start(); + return null; + } + } + ``` + +3. Consumer端 + + - 配置 + + ```xml + + ``` + + - 服务调用 + + ```java + public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/async-consumer.xml"}); + context.start(); + + AsyncService asyncService = (AsyncService) context.getBean("asyncService"); + System.out.println(asyncService.sayHello("async call request")); + + System.in.read(); + } + ``` + +## 异步引入的新问题 + +### Filter链 + +以下是一次普通Dubbo调用的完整Filter链(Filter链路图待补充)。 + +而采用异步调用后,由于异步结果在异步线程中单独执行,所以流经后半段Filter链的Result是空值,当真正的结果返回时已无法被Filter链处理。 + +为了解决这个问题,2.7.0中为Filter增加了回调接口onResponse。 + +以下是一个扩展Filter并支持异步Filter链的例子 + +```java +@Activate(group = {Constants.PROVIDER, Constants.CONSUMER}) +public class AsyncPostprocessFilter implements Filter { + + @Override + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + return invoker.invoke(invoker, invocation); + } + + @Override + public Result onResponse(Result result, Invoker invoker, Invocation invocation) { + System.out.println("Filter get the return value: " + result.getValue()); + return result; + } +} +``` + +### 上下文传递 + +这里的上下文问题主要是指在提供端异步的场景。 + +当前我们考虑的上下文主要是指保存在RpcContext中的数据,大多数场景是需要用户在切换业务线程前自己完成Context的传递。 + +```java +public class AsyncServiceImpl implements AsyncService { + // 保存当前线程的上下文 + RpcContext context = RpcContext.getContext(); + public CompletableFuture sayHello(String name) { + return CompletableFuture.supplyAsync(() -> { + // 设置到新线程中 + RpcContext.setContext(context); + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "async response from provider."; + }); + } +} +``` + +不过AsyncContext也提供了signalContextSwitch()的方法来实现方便的Context切换。 + +```java +public class AsyncServiceImpl implements AsyncService { + public String sayHello(String name) { + final AsyncContext asyncContext = RpcContext.startAsync(); + new Thread(() -> { + asyncContext.signalContextSwitch(); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + asyncContext.write("Hello " + name + ", response from provider."); + }).start(); + return null; + } +} +``` + diff --git a/content/en/blog/java/demos/dubbo-protocol.md b/content/en/blog/java/demos/dubbo-protocol.md new file mode 100644 index 000000000000..66c2219fa3cc --- /dev/null +++ b/content/en/blog/java/demos/dubbo-protocol.md @@ -0,0 +1,207 @@ +--- +title: "Dubbo 协议详解" +linkTitle: "Dubbo 协议详解" +tags: ["Java"] +date: 2018-10-05 +description: 本文介绍了 Dubbo 协议的设计 +--- + +## 协议的概念 + +协议是两个网络实体进行通信的基础,数据在网络上从一个实体传输到另一个实体,以字节流的形式传递到对端。在这个字节流的世界里,如果没有协议,就无法将这个一维的字节流重塑成为二维或者多维的数据结构以及领域对象。 + + + +### 协议是什么 + +协议是双方确定的交流语义,比如:我们设计一个字符串传输的协议,它允许客户端发送一个字符串,服务端接收到对应的字符串。这个协议很简单,首先发送一个4字节的消息总长度,然后再发送1字节的字符集charset长度,接下来就是消息的payload,字符集名称和字符串正文。 + +发送一个`iso-8859-1`的字符串`abc`到对端。经过协议编码,内容是:`18 = 4 + 1 + 10 + 3|10|iso-8859-1|abc`,当这些字节流发往服务端后,当服务端收到字节流后,首先读取4个字节,将其转换为int,在这个例子中是18,接下来继续读14个字节,将首个字节得到字符集名称长度10,将后续内容的前10字节转换为字符串,内容是`iso-8859-1`,使用该字符集将后续的字节数组造型成为字符串`new String(bytes, "iso-8859-1")`。 + +在前面自定义字符串传输协议的例子中,我们已经看到协议在双方传输数据中起到的作用,没有协议就无法完成数据交换,下面是维基百科对于通信协议的定义。 + +> In telecommunication, a communication protocol is a system of rules that allow two or more entities of a communications system to transmit information via any kind of variation of a physical quantity. The protocol defines the rules syntax, semantics and synchronization of communication and possible error recovery methods. Protocols may be implemented by hardware, software, or a combination of both. + +可以看到通信协议需要定义语法、语义以及通信上的同步操作,这里描述的内容实际就是对前面自定义字符串传输协议的形式化描述。 + +### `Codec`的定义 + +`org.apache.dubbo.remoting.Codec2`定义为I/O的 **Codec** 过程,因此主要的方法就是`encode`和`decode`,具体定义如下所示: + +```java +@SPI +public interface Codec2 { + + @Adaptive({Constants.CODEC_KEY}) + void encode(Channel channel, ChannelBuffer buffer, Object message) throws IOException; + + @Adaptive({Constants.CODEC_KEY}) + Object decode(Channel channel, ChannelBuffer buffer) throws IOException; + + + enum DecodeResult { + NEED_MORE_INPUT, SKIP_SOME_INPUT + } + +} +``` + +​ `Codec`工作在一种协议上,`encode`是将通信对象编码到`ByteBufferWrapper`中,`decode`是将从网络上读取的`ChannelBuffer`解码为`Object`,也就是通信对象。 + + + +## 常见的协议模式 + +应用层协议一般的形式有三种:定长协议、特殊结束符和协议头+payload模式,下面介绍一下这些形式的具体内容。 + +从网络上以流的形式进行数据的读取,需要确定的是一次有意义的传输内容在读到何时结束,因为一个一个byte传输过来,需要有一个结束。而且数据在网络上的传输,存在粘包和半包的情况,能够应对这个问题的办法就是协议能够准确的识别,当粘包发生时不会多读,当半包发生时会继续读取。 + + + +### 定长协议 + +定长的协议是指协议内容的长度是固定的,比如协议byte长度是50,当从网络上读取50个byte后,就进行decode解码操作。定长协议在读取或者写入时,效率比较高,因为数据缓存的大小基本都确定了,就好比数组一样,缺陷就是适应性不足,以RPC场景为例,很难估计出定长的长度是多少。 + +> 可以参考Netty的`FixedLengthFrameDecoder` + + + +### 特殊结束符 + +相比定长协议,如果能够定义一个特殊字符作为每个协议单元结束的标示,就能够以变长的方式进行通信,从而在数据传输和高效之间取得平衡,比如用特殊字符`\n`。 + +特殊结束符方式的问题是过于简单的思考了协议传输的过程,对于一个协议单元必须要全部读入才能够进行处理,除此之外必须要防止用户传输的数据不能同结束符相同,否则就会出现紊乱。 + +> 可以参考Netty的`DelimiterBasedFrameDecoder` + + + +### 变长协议(协议头+payload) + +一般是自定义协议,会以定长加不定长的部分组成,其中定长的部分需要描述不定长的内容长度。 + +```sh ++———+ +|定长| ++———+ +|内容| ++———+ +``` + +> 可以参考Netty的`LengthFieldBasedFrameDecoder` + +Dubbo 协议实际上就是一种变长协议,后面的章节会详细介绍。 + +## Dubbo 协议 + +### 协议概览 + +Dubbo 框架定义了私有的RPC协议,其中请求和响应协议的具体内容我们使用表格来展示。 + +![/dev-guide/images/dubbo_protocol_header.jpg](/imgs/dev/dubbo_protocol_header.png) + +### 协议详情 + +- Magic - Magic High & Magic Low (16 bits) + + 标识协议版本号,Dubbo 协议:0xdabb + +- Req/Res (1 bit) + + 标识是请求或响应。请求: 1; 响应: 0。 + +- 2 Way (1 bit) + + 仅在 Req/Res 为1(请求)时才有用,标记是否期望从服务器返回值。如果需要来自服务器的返回值,则设置为1。 + +- Event (1 bit) + + 标识是否是事件消息,例如,心跳事件。如果这是一个事件,则设置为1。 + +- Serialization ID (5 bit) + + 标识序列化类型:比如 fastjson 的值为6。 + +- Status (8 bits) + + 仅在 Req/Res 为0(响应)时有用,用于标识响应的状态。 + + - 20 - OK + - 30 - CLIENT_TIMEOUT + - 31 - SERVER_TIMEOUT + - 40 - BAD_REQUEST + - 50 - BAD_RESPONSE + - 60 - SERVICE_NOT_FOUND + - 70 - SERVICE_ERROR + - 80 - SERVER_ERROR + - 90 - CLIENT_ERROR + - 100 - SERVER_THREADPOOL_EXHAUSTED_ERROR + +- Request ID (64 bits) + + 标识唯一请求。类型为long。 + +- Data Length (32 bits) + + 序列化后的内容长度(可变部分),按字节计数。int类型。 + +- Variable Part + + 被特定的序列化类型(由序列化 ID 标识)序列化后,每个部分都是一个 byte [] 或者 byte + + - 如果是请求包 ( Req/Res = 1),则每个部分依次为: + - Dubbo version + - Service name + - Service version + - Method name + - Method parameter types + - Method arguments + - Attachments + - 如果是响应包(Req/Res = 0),则每个部分依次为: + - 返回值类型(byte),标识从服务器端返回的值类型: + - 返回空值:RESPONSE_NULL_VALUE 2 + - 正常响应值: RESPONSE_VALUE 1 + - 异常:RESPONSE_WITH_EXCEPTION 0 + - 返回值:从服务端返回的响应bytes + +**注意:** 对于(Variable Part)变长部分,当前版本的Dubbo 框架使用json序列化时,在每部分内容间额外增加了换行符作为分隔,请在Variable Part的每个part后额外增加换行符, 如: + +``` +Dubbo version bytes (换行符) +Service name bytes (换行符) +... +``` + +## Dubbo 协议的优缺点 + +### 优点 + +- 协议设计上很紧凑,能用 1 个 bit 表示的,不会用一个 byte 来表示,比如 boolean 类型的标识。 +- 请求、响应的 header 一致,通过序列化器对 content 组装特定的内容,代码实现起来简单。 + +### 可以改进的点 + +- 类似于 http 请求,通过 header 就可以确定要访问的资源,而 Dubbo 需要涉及到用特定序列化协议才可以将服务名、方法、方法签名解析出来,并且这些资源定位符是 string 类型或者 string 数组,很容易转成 bytes,因此可以组装到 header 中。类似于 http2 的 header 压缩,对于 rpc 调用的资源也可以协商出来一个int来标识,从而提升性能,如果在`header`上组装资源定位符的话,该功能则更易实现。 + +- 通过 req/res 是否是请求后,可以精细定制协议,去掉一些不需要的标识和添加一些特定的标识。比如`status`,`twoWay`标识可以严格定制,去掉冗余标识。还有超时时间是作为 Dubbo 的 `attachment` 进行传输的,理论上应该放到请求协议的header中,因为超时是网络请求中必不可少的。提到 `attachment` ,通过实现可以看到 `attachment` 中有一些是跟协议 `content`中已有的字段是重复的,比如 `path`和`version`等字段,这些会增大协议尺寸。 + +- Dubbo 会将服务名`com.alibaba.middleware.hsf.guide.api.param.ModifyOrderPriceParam`,转换为`Lcom/alibaba/middleware/hsf/guide/api/param/ModifyOrderPriceParam;`,理论上是不必要的,最后追加一个`;`即可。 + +- Dubbo 协议没有预留扩展字段,没法新增标识,扩展性不太好,比如新增`响应上下文`的功能,只有改协议版本号的方式,但是这样要求客户端和服务端的版本都进行升级,对于分布式场景很不友好。 + + +## 总结 + +本文主要介绍了协议的概念和常用的协议模式,后面对 Dubbo 协议进行了详细分析,也提到了一些不足的地方,但是相对于其简洁性和易于实现性,以上提出的缺点不足以有动力设计出一个新版本的协议,所以欢迎大家提出对协议优化方面的建议和特性。 + + + + + + + + + + + + diff --git a/content/en/blog/java/demos/dubbo-rest.md b/content/en/blog/java/demos/dubbo-rest.md new file mode 100644 index 000000000000..0728cfd2f26c --- /dev/null +++ b/content/en/blog/java/demos/dubbo-rest.md @@ -0,0 +1,851 @@ +--- +title: "在 Dubbo 中使用 REST" +linkTitle: "在 Dubbo 中使用 REST" +tags: ["Java"] +date: 2019-07-26 +description: 本文介绍了如何在 Dubbo 中发布 RESTful 服务 +--- + +## 什么是 REST + +REST 是 Roy Thomas Fielding [^1] 在 2000 年他的博士论文 [^2] “架构风格以及基于网络的软件架构设计” 中提出来的一个概念。REST 是 **RE**presentational **S**tate **T**ransfer 的缩写,翻译过来就是 “表现层状态转化”。REST 就是 Roy 在这篇论文中提出的面向互联网的软件所应当具备的架构风格。 + + + +按照 REpresentational State Transfer 的字面意思,可以把应用看成是一个虚拟的状态机,软件提供的不是服务而是一系列的**资源**,对这些资源的访问通过**统一的操作**来访问,而返回的结果代表了资源状态的一次跃迁。REST 是一种架构风格,如果一个软件架构符合 REST 风格,就可以称之为 RESTful 架构。这个架构应当具备以下一些设计上的约束:资源具有唯一标示、资源之间有关联关系、使用标准的方式来访问、资源有多种表现形式、无状态交互。 + + + +举例来说,一个简单的静态 HTML 页面的网站就很好的符合了 RESTful 架构风格。访问 `http://example.com/accounts` 返回一个包含所有账号的页面,选取其中一个链接 `http://example.com/accounts/1` 又会返回包含用户 1 的详细信息。爬虫软件在这种场景下工作的很好,当知道了某个网站的首页地址后,可以自举发现这个网站上所有关联的网页。更重要的是,这种访问形式不依赖网站提供的任何客户端,而是仅仅通过 HTTP 标准的访问方式完成的。可以说,HTML 这种超媒体文档的组织形式就是资源的表现层状态迁移的一种形式。 + + + +对于一个提供服务的动态网站来说,可以按照类似的思路将其 RESTful 化: + +- GET `http://example.com/accounts` 返回所有账号信息 + +- POST `http://example.com/accounts` 创建一个新的账号 + +- GET `http://example.com/accounts/1` 返回账号 1 的信息 + +- DELETE `http://example.com/accounts/1` 删除账号 1 + +- PUT `http://example.com/accounts/1` 更新账号 1 信息 + + + +其中的思路是利用 HTTP 协议的标准方法 POST、DELETE、PUT、GET 来表达对于一个资源的增删改查 (CRUD) 操作,利用 URL 来表示一个资源的唯一标识。对资源访问的错误码也复用 HTTP 协议的状态码。返回结果通常由 json 或 XML 来表示,如果其中包括了对关联资源的访问方式 (所谓的表现层状态迁移) ,这种类型的 RESTful 应用可以进一步的称之为 *hypermedia as the engine of application state* (HATEOAS) 应用 [^3]。 + + + +![micro-image](/imgs/blog/rest-sample.png) + +*source: /imgs/blog/2019/07/26/rest/micro-image.png* + + + +这里需要注意的是,按照 Roy 的定义,RESTful 架构风格与 HTTP 协议并没有什么强关联关系。但是,基于 HTTP 的 RESTful 架构风格是实现起来最自然,也是目前使用最广泛的一种实现,我们称之为 RESTful HTTP。同样的,在下文中将会专注在 HTTP 的场景下介绍如何在 Dubbo 框架中将服务暴露成 Restful 架构。 + + + +## 在 Dubbo 中使用 REST + +### 背景 + +随着微服务的流行以及多语言互操作诉求日益增多,在 Dubbo 中暴露 REST 服务变成了一个不容忽视的诉求。为了在 Dubbo 中暴露 REST 服务,通常有两种做法,一种是直接依赖 Spring REST 或者其他 REST 框架来直接暴露,另一种是通过 Dubbo 框架内置的 REST 能力暴露。两种做法各有优缺点,主要体现在前者与微服务体系中的服务发现组件能够更好的工作,而后者可以无缝的享受到 Dubbo 体系中的服务发现以及服务治理的能力。本文关注的是如何使用后者来暴露 REST 服务。 + + + +自 `2.6.0` 开始,Dubbo 合并了当当网捐献的 DubboX [^4] 中的主要特性,其中就包括了基于 RESTeasy `3.0.19.Final` 的 REST 支持,具备 JAXRS 2.0 规范中所有的能力。 + + + +### 基本用法 + +在以下的例子中,展示了如何通过最传统的 Spring XML 配置的方式来快速的暴露和调用一个 REST 服务。其中底层的 server 使用的是 netty,服务注册发现基于 Zookeeper。 + +> 注:本章节讨论的示例可以通过 https://github.com/beiwei30/dubbo-rest-samples/tree/master/basic 来获得 + + + +#### 1. Maven 依赖 + +首先需要在项目中引入 dubbo all-in-one 的依赖以及 RESTEasy 相关的必要依赖。因为在本例中使用 Zookeeper 作为服务发现,还需要引入 Zookeeper client 相关的依赖。为了方便使用,第三方的依赖可以通过框架提供的 BOM 文件 `dubbo-dependencies-bom` 来引入。 + + + +```xml + + 2.6.5 + + + + + + com.alibaba + dubbo-dependencies-bom + ${dubbo.version} + pom + import + + + + + + + com.alibaba + dubbo + ${dubbo.version} + + + + + io.netty + netty-all + + + + org.jboss.resteasy + resteasy-jaxrs + + + + org.jboss.resteasy + resteasy-client + + + + org.jboss.resteasy + resteasy-netty4 + + + + javax.validation + validation-api + + + + org.jboss.resteasy + resteasy-jackson-provider + + + + org.jboss.resteasy + resteasy-jaxb-provider + + + + javax.servlet + javax.servlet-api + + + + + org.apache.curator + curator-framework + + +``` + + + +#### 2. 定义服务接口 + +定义一个服务接口 `UserService`,该接口提供两个功能,一个是获取指定 User 的详细信息,另一个是新注册一个用户。 + +```java +@Path("users") // #1 +@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) // #2 +@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) +public interface UserService { + @GET // #3 + @Path("{id: \\d+}") + User getUser(@PathParam("id") Long id); + + @POST // #4 + @Path("register") + Long registerUser(User user); +} +``` + +通过在接口上用 JaxRS 标准的 annotation 来修饰,我们规定了该服务在 REST 下的访问形式: + +1. `@Path("users")` 定义了 UserService 通过 '/users' 来访问 +2. 在类级别上定义 `@Consumers` 和 `@Produces` 来规定参数以及返回值的类型为 XML 和 JSON。在类级别上定义之后,就可以不用在方法级别上进一步定义了 +3. getUser 方法上通过 `@GET` 定义了接受的 HTTP 方法为 GET,通过 `@Path` 来规定参数是来自于 URL 中的 path。'GET /users/1' 等同于调用 'getUser(1)' +4. registerUser 方法上通过 `@POST` 定义了接受的 HTTP 方法为 POST,通过将 JSON 或 XML 格式的 User 数据 POST 到 '/users/register' 上来创建一个 User + +在 Dubbo 中,将 REST 相关的 annotation 定义在接口或者实现上都是可以的。这个在设计上是个权衡问题。Annotation 定义在实现类上可以保证接口的纯净,否则对于不需要通过 REST 方式调用的 Dubbo 调用方来说将需要强制依赖 JaxRS 的库,但是同时,对于需要通过 REST 方式调用的 Dubbo 调用方来说,就需要自己来处理 REST 调用相关的细节了。Annotation 定义在接口上,框架会自动处理掉 REST 调用相关的细节,并和 Dubbo 的服务发现以及服务治理功能能够很好的结合起来。在本例中采用了在接口上定义 JaxRS annotation 的形式。 + + + +#### 3. 实现服务接口 + +为了简洁,这里给出的接口的实现只是简单的返回了接口需要的类型的示例,在真实的系统中,逻辑可能会比较复杂。 + +```java +public class UserServiceImpl implements UserService { + private final AtomicLong id = new AtomicLong(); + + public User getUser(Long id) { + return new User(id, "username-" + id); + } + + public Long registerUser(User user) { + return id.incrementAndGet(); + } +} +``` + + + +#### 4. 装配服务 + +如上所述,本例展示的是如何通过传统的 Spring XML 的方式来装配并暴露 Dubbo 服务。需要指出的是,这里展示了如何同时暴露两种不同的协议,一种是 REST,另一种是原生的 Dubbo 协议。 + +```xml + + + + + + + + + +``` + +1. 定义了该应用的名字为 `rest-provider` +2. 定义了服务注册通过 Zookeeper,并且 URL 为 "zookeeper://127.0.0.1:2181" +3. 在端口 8080 上以 REST 方式暴露服务,底层的传输使用的是 netty +4. 在默认端口 20880 上以原生 Dubbo 方式暴露服务,底层的传输方式是 netty +5. 将 ‘userService' 的 Spring bean (也就是 UserServiceImpl)暴露为 UserService 服务,支持的协议既包括了 REST 也包括了 Dubbo +6. 将 UserServiceImpl 注册成 'userService' 的 Spring bean + + + +#### 5. 服务提供方的启动类 + +简单的通过 ClassPathXmlApplicationContext 来加载刚刚配置的 Spring XML 配置 'rest-provider.xml' 即可启动 Dubbo 服务端 + +```java +public class RestProvider { + public static void main(String[] args) throws IOException { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/rest-provider.xml"); + context.start(); + System.in.read(); + } +} +``` + + + +#### 6. 启动服务端 + +由于本例依赖 Zookeeper 做服务注册发现,在启动 RestProvider 之前,需要先启动一个 Zookeeper 服务器。之后就可以之间运行 RestProvider 了。通过以下的输出日志,我们可以知道 UserService 以两种方式对外暴露了同一个服务,其中: + +* REST: rest://192.168.2.132:8080/org.apache.dubbo.samples.rest.api.UserService +* Dubbo: dubbo://192.168.2.132:20880/org.apache.dubbo.samples.rest.api.UserServic + +```bash +... +[01/01/19 07:18:56:056 CST] main INFO config.AbstractConfig: [DUBBO] Export dubbo service org.apache.dubbo.samples.rest.api.UserService to url rest://192.168.2.132:8080/org.apache.dubbo.samples.rest.api.UserService?anyhost=true&application=rest-provider&bean.name=org.apache.dubbo.samples.rest.api.UserService&bind.ip=192.168.2.132&bind.port=8080&dubbo=2.0.2&generic=false&interface=org.apache.dubbo.samples.rest.api.UserService&methods=getUser,registerUser&pid=27386&server=netty&side=provider×tamp=1546341536194, dubbo version: 2.6.5, current host: 192.168.2.132 +... +[01/01/19 07:18:57:057 CST] main INFO config.AbstractConfig: [DUBBO] Export dubbo service org.apache.dubbo.samples.rest.api.UserService to url dubbo://192.168.2.132:20880/org.apache.dubbo.samples.rest.api.UserService?anyhost=true&application=rest-provider&bean.name=org.apache.dubbo.samples.rest.api.UserService&bind.ip=192.168.2.132&bind.port=20880&dubbo=2.0.2&generic=false&interface=org.apache.dubbo.samples.rest.api.UserService&methods=getUser,registerUser&pid=27386&server=netty4&side=provider×tamp=1546341537392, dubbo version: 2.6.5, current host: 192.168.2.132 +... +``` + +也可以通过 zkCli 访问 Zookeeper 服务器来验证。'/dubbo/org.apache.dubbo.samples.rest.api.UserService/providers' 路径下返回了一个数组 [dubbo://..., rest:.//...]。数组的第一个元素是 ’dubbo‘ 打头的,而第二个元素是 'rest' 打头的。 + +```bash +[zk: localhost:2181(CONNECTED) 10] ls /dubbo/org.apache.dubbo.samples.rest.api.UserService/providers +[dubbo%3A%2F%2F192.168.2.132%3A20880%2Forg.apache.dubbo.samples.rest.api.UserService%3Fanyhost%3Dtrue%26application%3Drest-provider%26bean.name%3Dorg.apache.dubbo.samples.rest.api.UserService%26dubbo%3D2.0.2%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.samples.rest.api.UserService%26methods%3DgetUser%2CregisterUser%26pid%3D27386%26server%3Dnetty4%26side%3Dprovider%26timestamp%3D1546341537392, rest%3A%2F%2F192.168.2.132%3A8080%2Forg.apache.dubbo.samples.rest.api.UserService%3Fanyhost%3Dtrue%26application%3Drest-provider%26bean.name%3Dorg.apache.dubbo.samples.rest.api.UserService%26dubbo%3D2.0.2%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.samples.rest.api.UserService%26methods%3DgetUser%2CregisterUser%26pid%3D27386%26server%3Dnetty%26side%3Dprovider%26timestamp%3D1546341536194] + +``` + +可以简单的通过 'curl' 在命令行验证刚才暴露出来的 REST 服务: + +```bash +$ curl http://localhost:8080/users/1 +{"id":1,"name":"username-1"} +$ curl -X POST -H "Content-Type: application/json" -d '{"id":1,"name":"Larry Page"}' http://localhost:8080/users/register +1 +``` + + + +#### 7. 装配调用端 + +Dubbo 调用方只需要依赖服务的接口,通过以下方式装配好 Dubbo Consumer,即可发起调用。 + +```xml + + + + + + +``` + +1. 'userService' 配置的 protocol 为 “rest",将通过 REST 协议调用服务端 + +需要特别指出的是,这里显示的指定 protocol="rest" 在通常情况下不是必须的。这里需要显示指定的原因是我们例子中服务端同时暴露了多种协议,这里指定使用 rest 是为了确保调用方走 REST 协议。 + + + +#### 8. 发起调用 + +简单的通过 ClassPathXmlApplicationContext 来加载刚刚配置的 Spring XML 配置 'rest-consumer.xml' 即可发起对 RestProvider 所提供的 UserService 的 REST 服务的调用。 + +```java +public class RestConsumer { + public static void main(String[] args) { + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/rest-consumer.xml"); + context.start(); + + UserService userService = context.getBean("userService", UserService.class); + System.out.println(">>> " + userService.getUser(1L)); + + User user = new User(2L, "Larry Page"); + System.out.println(">>> " + userService.registerUser(user)); + } +} +``` + +这里分别展示了对 'getUser' 和 'registerUser' 的调用,输出结果如下: + +```bash +>>> User{id=1, name='username-1'} +>>> 2 +``` + + + +### 进阶 + + + +#### A. 在 REST 中使用 Annotation + +在 Dubbo 中使用 annotation 而不是 Spring XML 来暴露和引用服务,对于 REST 协议来说并没有什么不同。有关如何使用 annotation 更详细的用法,请参阅《在 Dubbo 中使用注解》章节。这里主要展示一下与上面基于 Spring XML 配置的例子不同之处。 + +> 注:本章节讨论的示例可以通过 https://github.com/beiwei30/dubbo-rest-samples/tree/master/annotation 来获得 + + + +##### 1. 使用 Java Configuration 来配置服务提供方的 protocol、registry、application + +```java + @Configuration + @EnableDubbo(scanBasePackages = "org.apache.dubbo.samples.rest.impl") // #1 + static class ProviderConfiguration { + @Bean // #2 + public ProtocolConfig protocolConfig() { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.setName("rest"); + protocolConfig.setPort(8080); + protocolConfig.setServer("netty"); + return protocolConfig; + } + + @Bean // #3 + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setProtocol("zookeeper"); + registryConfig.setAddress("localhost"); + registryConfig.setPort(2181); + return registryConfig; + } + + @Bean + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("rest-provider"); + return applicationConfig; + } + } +``` + +1. 通过 `@EnableDubbo` 来指定需要扫描 Dubbo 服务的包名,在本例中,UserServiceImpl 在 "org.apache.dubbo.samples.rest.impl" 下 +2. 通过提供一个 ProtocolConfig 的 Spring Bean 来指定服务提供方按照 REST 来暴露服务 +3. 通过提供一个 RegistryConfig 的 Spring Bean 来指定服务提供方所使用的服务注册机制 + + + +##### 2. 使用 @Service 来申明 Dubbo 服务 + +```java +@Service // #1 +public class UserServiceImpl implements UserService { + ... +} +``` + +1. 简单的使用 `@Service` 或者 `@Service(protocol = "rest")` 修饰 "UserServiceImpl" 来申明一个 Dubbo 服务,这里 `protocol = "rest"` 不是必须提供的,原因是通过 Java Configuration 只配置了一个 ProtocolConfig 的示例,在这种情况下,Dubbo 会自动装配该协议到服务中 + + + + +##### 3. 服务提供方启动类 + +通过使用 `ProviderConfiguration` 来初始化一个 `AnnotationConfigApplicationContext` 实例,就可以完全摆脱 Spring XML 的配置文件,完全借助 annotation 来装配好一个 Dubbo 的服务提供方。 + +```java +public class RestProvider { + public static void main(String[] args) throws IOException { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class); + context.start(); + System.in.read(); + } +} +``` + + + +##### 4. 使用 Java Configuration 来配置服务消费方的 registry、application + +```java + @Configuration + @EnableDubbo(scanBasePackages = "org.apache.dubbo.samples.rest.comp") // #1 + @ComponentScan({"org.apache.dubbo.samples.rest.comp"}) // #2 + static class ConsumerConfiguration { + @Bean // #3 + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setProtocol("zookeeper"); + registryConfig.setAddress("localhost"); + registryConfig.setPort(2181); + return registryConfig; + } + + @Bean + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("rest-consumer"); + return applicationConfig; + } + } +``` + +1. 通过 `@EnableDubbo` 来指定需要扫描 Dubbo 服务引用 `@Reference` 的包名。在本例中,UserService 的引用在 "org.apache.dubbo.samples.rest.comp" 下 +2. 通过 `@ComponentScan` 来指定需要扫描的 Spring Bean 的包名。在本例中,包含 UserService 引用的类 UserServiceComponent 本身需要是一个 Spring Bean,以方便调用,所以,这里指定的包名也是 "org.apache.dubbo.samples.rest.comp" +3. 通过提供一个 RegistryConfig 的 Spring Bean 来指定服务消费方所使用的服务发现机制 + + + +这里提到的 UserServiceComponent 的 Spring Bean 定义如下: + +```java +@Component +public class UserServiceComponent implements UserService { // #1 + @Reference + private UserService userService; + + + @Override + public User getUser(Long id) { + return userService.getUser(id); + } + + @Override + public Long registerUser(User user) { + return userService.registerUser(user); + } +} +``` + +1. 这里比较好的实践是让这个 Spring Bean 也继承 `UserService` 接口,这样在调用的时候也可以面向接口编程 + + + + +##### 5. 服务调用方启动类 + +通过使用 `ConsumerConfiguration` 来初始化一个 `AnnotationConfigApplicationContext` 实例,就可以完全摆脱 Spring XML 的配置文件,完全借助 annotation 来装配好一个 Dubbo 的服务消费方。然后就可以通过查找 `UserServiceComponent` 类型的 Spring Bean 来发起远程调用。 + +```java +public class RestConsumer { + public static void main(String[] args) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class); + context.start(); + + UserService userService = context.getBean(UserServiceComponent.class); + System.out.println(">>> " + userService.getUser(1L)); + + User user = new User(2L, "Larry Page"); + System.out.println(">>> " + userService.registerUser(user)); + } +} +``` + + + +#### B. 让协议跑在不同的服务器上 + +目前 REST 协议在 Dubbo 中可以跑在五种不同的 server 上,分别是: + +* "netty": 直接基于 netty 框架的 rest server,通过 `` 来配置 +* "tomcat": 基于嵌入式 tomcat 的 rest server,通过 `` 来配置 +* "jetty": **默认选项**,基于嵌入式 jetty 的 rest server,通过 `` 来配置 +* "sunhttp": 使用 JDK 内置的 Sun HTTP server 作为 rest server,通过 `` 来配置,仅推荐在开发环境中使用 +* "servlet”: 采用外部应用服务器的 servlet 容器来做 rest server,这个时候,除了配置 `` 之外,还需要在 web.xml 中做额外的配置 + + + +由于以上的例子展示了 "netty" 作为 rest server,下面演示一下使用嵌入式 tomcat 的 rest server 的用法。 + +> 注:本章节讨论的示例可以通过 https://github.com/beiwei30/dubbo-rest-samples/tree/master/tomcat 来获得 + + + +##### 1. 增加 Tomcat 相关的依赖 + +```xml + + org.apache.tomcat.embed + tomcat-embed-core + + + org.apache.tomcat.embed + tomcat-embed-logging-juli + +``` + + + +##### 2. 配置 protocol 使用 tomcat 作为 REST server + +```xml + +``` + + + +启动服务提供方之后,在以下的输出将会出现与嵌入式 Tomcat 相关的日志信息: + +```bash +Jan 01, 2019 10:15:12 PM org.apache.catalina.core.StandardContext setPath +WARNING: A context path must either be an empty string or start with a '/' and do not end with a '/'. The path [/] does not meet these criteria and has been changed to [] +Jan 01, 2019 10:15:13 PM org.apache.coyote.AbstractProtocol init +INFO: Initializing ProtocolHandler ["http-nio-8080"] +Jan 01, 2019 10:15:13 PM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector +INFO: Using a shared selector for servlet write/read +Jan 01, 2019 10:15:13 PM org.apache.catalina.core.StandardService startInternal +INFO: Starting service [Tomcat] +Jan 01, 2019 10:15:13 PM org.apache.catalina.core.StandardEngine startInternal +INFO: Starting Servlet Engine: Apache Tomcat/8.5.31 +Jan 01, 2019 10:15:13 PM org.apache.coyote.AbstractProtocol start +INFO: Starting ProtocolHandler ["http-nio-8080"] +``` + + + +#### C. 使用外部的 Servlet 容器 + +进一步的,还可以使用外部的 servlet 容器来启动 Dubbo 的 REST 服务。 + +> 注:本章节讨论的示例可以通过 https://github.com/beiwei30/dubbo-rest-samples/tree/master/servlet 来获得 + + + +##### 1. 修改 pom.xml 改变打包方式 + +因为使用的是外部的 servlet 容器,需要将打包方式修改为 "war" + +```xml + war +``` + + + +##### 2. 修改 rest-provider.xml + +配置 "server" 为 "servlet" 表示将使用外部的 servlet 容器。并配置 "contextpath" 为 "",原因是在使用外部 servlet 容器时,Dubbo 的 REST 支持需要知道被托管的 webapp 的 contextpath 是什么。这里我们计划通过 root context path 来部署应用,所以配置其为 ""。 + +```xml + +``` + + + +##### 3. 配置 WEB-INF/web.xml + +```xml + + + + contextConfigLocation + /WEB-INF/classes/spring/rest-provider.xml + + + + com.alibaba.dubbo.remoting.http.servlet.BootstrapListener + + + + org.springframework.web.context.ContextLoaderListener + + + + dispatcher + com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet + 1 + + + dispatcher + /api/* + + + +``` + +1. 配置 Dubbo 和 Spring 相关的 ContextListener,打开 Dubbo HTTP 支持,以及通过 rest-provider.xml 来装配 Dubbo 服务 +2. 配置 Dubbo HTTP 所需的 DiapatcherServlet + +这样做之后,不再需要 RestProvider 来启动 Dubbo 服务,可以将其从工程中删掉。对应的,现在 Dubbo 的服务将会随着 Servlet 容器的启动而启动。启动完毕之后,可以通过类似 "http://localhost:8080/api/users/1" 来访问暴露出的 REST 服务。需要注意的是,这个例子里假定了服务提供方的 WAR 包部署在 root context path 上,所以当该应用通过 IDE 配置的 tomcat server 启动时,需要指定 Application Context 为 "/"。 + + + +#### D. 增加 Swagger 支持 + +在上面使用外部 Servlet 容器的例子的基础上,讨论如何暴露 Swagger OpenApi 以及如何继承 Swagger UI。 + +> 注:本章节讨论的示例可以通过 https://github.com/beiwei30/dubbo-rest-samples/tree/master/servlet 来获得 + + + +##### 1. 暴露 Swagger OpenApi + +增加 swagger 相关依赖,以便通过 "http://localhost:8080/openapi.json" 来访问 REST 服务的描述 + +```xml + + 2.0.6 + + + + + io.swagger.core.v3 + swagger-jaxrs2 + ${swagger.version} + + + io.swagger.core.v3 + swagger-jaxrs2-servlet-initializer + ${swagger.version} + + +``` + + + +修改 WEB-INF/web.xml,增加 openapi servlet 的配置 + +```xml + + ... + + openapi + io.swagger.v3.jaxrs2.integration.OpenApiServlet + + + openapi + /openapi.json + /openapi.yaml + + +``` + + + +重新启动应用之后,可以通过访问 "http://localhost:8080/openapi.json" 或者 "http://localhost:8080/openapi.yaml" 来访问暴露出的 openapi 的契约,以下是 yaml 格式的表述: + +```yaml +openapi: 3.0.1 +paths: + /api/users/{id}: + get: + operationId: getUser + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + default: + description: default response + content: + application/json: + schema: + $ref: '#/components/schemas/User' + text/xml: + schema: + $ref: '#/components/schemas/User' + /api/users/register: + post: + operationId: registerUser + requestBody: + description: a user to register + content: + application/json: + schema: + $ref: '#/components/schemas/User' + text/xml: + schema: + $ref: '#/components/schemas/User' + responses: + default: + description: default response + content: + application/json: + schema: + type: integer + format: int64 + text/xml: + schema: + type: integer + format: int64 +components: + schemas: + User: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string +``` + + + +##### 2. 集成 Swagger UI + +在 pom.xml 中继续增加 swagger-ui 的依赖,这里使用的是 webjars 的版本,从集成的角度来说更加简洁。webjars 的工作机制可以参阅 webjars 官网 [^6] + +```xml + + 3.20.3 + + + + org.webjars + swagger-ui + ${swagger.webjar.version} + + +``` + + + +在工程的 webapp/WEB-INF 根目录下增加一个 HTML 文件,内容如下。HTML 文件名可以为任何名字,没有硬性要求,如果该文件被命名为 "swagger-ui.html",那么你可以通过访问 “http://localhost:8080/swagger-ui.html" 来访问 swagger UI。本例为了演示方便起见,将其命名为 "index.html",这样当访问 "http://localhost:8080" 时,就可以很方便的得到 swagger UI 的页面。 + +```html + + + + + API UI + + + + + + + +
+ + + + + + + + +``` + + + +再次重启服务器,并访问 "http://localhost:8080" 时,将会看到 swagger UI 页面的展示: + + + +![swagger-ui](/imgs/blog/swagger-ui.png) + + + +通过 Swagger UI 可以很方便的浏览当前服务器提供的 REST 服务的文档信息,甚至可以直接调用来做服务测试。以 '/api/users/{id}' 为例,测试结果如下图所示: + + + +![swagger-ui-execute](/imgs/blog/swagger-ui-execute.png) + + + +## 总结 + +本文主要关注了在 Dubbo 中支持 REST 协议的情况。首先探索了 REST 概念的起源,澄清了 REST 是一种适合互联网的软件架构风格,进一步的说明了 REST 风格的架构可以与 HTTP 协议无关,但是 HTTP 协议的确是 REST 风格架构的最常用甚至是最佳的组合和搭档。然后讨论了如何在 Dubbo 中开发 REST HTTP 的几种典型用法,其中包括了通过不同的配置,如传统的 Spring XML,完全通过 annotation 来配置两种典型的用法,本文中没有涉及到的还有纯 API 编程方式,Spring Boot 配置方式也是完全可以的,因为篇幅原因没有提及;还讨论了如何通过不同的 REST server 来暴露 REST HTTP 服务,包括了 embedded tomcat,netty,以及外置的 servlet 容器等几种用法。最后,在外置的 servlet 容器的基础上,进一步的讨论了如何通过 Swagger 暴露 openAPI 以及集成 Swagger UI 的方法。 + +本文没有涉及的内容包含但不限于国际化支持、Dubbo REST 更高阶的注入扩展的用法、以及 Dubbo REST 支持未来的规划。其中 Dubbo REST 扩展的支持可以参考 https://github.com/beiwei30/dubbo-rest-samples/tree/master/extensions 中的演示。以后有机会会开专门的篇幅来探讨更高级的 Swagger 的支持、以及对未来的展望。 + + + + +[^1]: http://en.wikipedia.org/wiki/Roy_Fielding + +[^2]: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm + +[^3]: https://martinfowler.com/articles/richardsonMaturityModel.html + +[^4]: https://github.com/dangdangdotcom/dubbox +[^5]: http://dubbo.apache.org/zh-cn/blog/dubbo-annotation.html +[^6]: https://www.webjars.org/documentation#servlet3 + + diff --git a/content/en/blog/java/demos/dubbo-stub-mock.md b/content/en/blog/java/demos/dubbo-stub-mock.md new file mode 100644 index 000000000000..006aaf0f8fc9 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-stub-mock.md @@ -0,0 +1,319 @@ +--- +title: "本地存根和本地伪装" +linkTitle: "本地存根和本地伪装" +tags: ["Java"] +date: 2019-10-22 +description: 本文介绍了 Dubbo 中本地存根和本地伪装的用法 +--- + + +## 基本概念 + +典型的 RPC 调用客户端是依赖并且只依赖接口编程来进行远程调用的。在真正发起远程调用之前,用户往往需要做一些预处理的工作,比如提前校验参数。在拿到返回调用结果之后,用户可能需要缓存结果,或者是在调用失败的时候构造容错数据,而不是简单的抛出异常。 + + +这个时候,用户可以编写出类似以下的代码来处理上面提出的这些场景: + +```java +try { + preProcess(); + return service.invoke(...); +} catch (Throwable e) { + return mockValue; +} finally { + postProcess(); +} +``` + + + +类似的,用户也可以通过面向切面编程 *AOP* 的高级技巧来解决上面的诉求,比如通过 *Spring AOP* 的方式可以通过类似下面的这段配置来完成。使用 *AOP* 的技巧相比上面的代码来说,避免了容错处理等与业务无关的代码对业务代码的侵入,使得业务处理主逻辑更简洁。 + +```xml + + + + + + + + + + + + + +``` + + + +为了进一步的方便用户做 Dubbo 开发,框架提出了本地存根 *Stub* 和本地伪装 *Mock* 的概念。通过约定大于配置的理念,进一步的简化了配置,使用起来更加方便,并且不依赖额外的 *AOP* 框架就达到了 *AOP* 的效果。 + + + +本地存根的工作方式与 *AOP* 的 **around** advice 类似,而本地伪装的工作方式等同于 *AOP* 中的 **after-throwing** advice,也就是说,只有当远程调用发生 *exception* 的时候才会执行本地伪装。本地存根和本地伪装的工作流程如下图所示: + +![dubbo-mock-stub-flow](/imgs/blog/dubbo-mock-stub-flow.png) + + +1. 服务消费者发起调用 +2. 如果服务消费者端存在本地存根 *Stub* 的话,会先执行本地存根 +3. 本地存根 Stub 持有远程服务的 *Proxy* 对象,*Stub* 在执行的时候,会先执行自己的逻辑 (*before*),然后通过 *Proxy* 发起远程调用,最后在返回过程之前也会执行自己的逻辑 (*after-returning*) +4. 如果远程服务的 *Proxy* 对象在执行过程中抛出了 *exception*,会执行服务消费端的本地伪装 *Mock* 的逻辑 (*after-throwing*),返回容错数据,从而达到服务降级的目的 + + + +## 开发一个本地存根 Stub + +本地存根 *Stub* 由用户来提供,并在服务消费方部署。完整的示例可以在这里 [^stub-samples] 获得。 + + + +```java +public class DemoServiceStub implements DemoService { // #1 + private static Logger logger = LoggerFactory.getLogger(DemoServiceStub.class); + + private final DemoService demoService; + + public DemoServiceStub(DemoService demoService) { // #2 + this.demoService = demoService; + } + + @Override + public String sayHello(String name) { // #3 + logger.info("before execute remote service, parameter: " + name); // #4 + try { + String result = demoService.sayHello(name); // #5 + logger.info("after execute remote service, result: " + result); // #6 + return result; + } catch (Exception e) { + logger.warn("fail to execute service", e); // #7 + return null; + } + } +} +``` + + + +要和框架在一起工作,本地存根的实现需要遵循一些与框架事先做出的约定: + +1. 首先本地存根 *Stub* 是服务接口的一个实现 +2. 本地存根的实现需要提供一个拷贝构造方法,方便框架将远程调用的 *Proxy* 对象注入进来 +3. 同样的,本地存根需要提供服务接口中所有方法的实现。在本例中,需要实现 *sayHello* 方法 +4. 在真正发起远程调用之前,用户可以在本地执行一些操作。在本例中,在日志中记录传入的参数 +5. 通过框架传入的 *Proxy* 对象真正发起远程调用 +6. 在远程调用结束后,也可以加入本地代码的执行。在本例中,在日志中记录远程调用的返回结果 +7. 如果发生错误的时候,也可以做一些错误恢复的动作。在本例中,在日志中记录异常。当然,如果提供了本地伪装的话,*catch* 中的逻辑是可以省略掉的 + +其中步骤 4、步骤 6、和步骤 7 共同构建了等同于面向切面编程中的概念,分别对应于 **before**、**after-returning**、以及 **after-throwing**。 + + + +*DemoServiceStub* 运行在客户端,要使用本地存根的话,还需要在 *stub-consumer.xml* 中配置属性 *stub*。可以简单的通过指定 *stub="true"* 来告诉 Dubbo 框架使用本地存根,这个时候,本地存根的包名需要和服务接口的包名一致,类名必须在服务接口的类名后加上 **Stub** 的后缀。例如,当服务接口名是 *org.apache.dubbo.samples.stub.api.DemoService* 时,本地存根的全类名应该是 *org.apache.dubbo.samples.stub.api.DemoServiceStub*。 + + + +```xml + +``` + + + +如果不希望使用默认的命名规则,也可以直接通过 *stub* 属性来指定本地存根的全类名。 + + + +```xml + +``` + + + +启动服务端 *StubProvider* 后,再运行客户端 *StubConsumer*,可以通过观察客户端的日志来验证本地存根的运行结果。 + + + +```bash +[09/04/19 11:52:21:021 CST] main INFO api.DemoServiceStub: before execute remote service, parameter: dubbo +[09/04/19 11:52:21:021 CST] main INFO api.DemoServiceStub: after execute remote service, result: greeting dubbo +[09/04/19 11:52:21:021 CST] main INFO stub.StubConsumer: result: greeting dubbo +``` + + + +## 开发一个本地伪装 Mock + +上面说了本地伪装通常用于在远程调用出错的情况下服务降级。完整的示例可以在这里 [^mock-samples] 获得。 + + + +这里通过在服务提供方的代码中睡眠来模拟调用端超时,从而执行本地伪装来做容错处理。 + +```java +public class DemoServiceImpl implements DemoService { + public String sayHello(String name) { + try { + Thread.sleep(5000); // #1 + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "hello " + name; // #2 + } +} +``` + +1. Dubbo 默认的超时时间是 *1000 ms*,这里通过睡眠 *5000ms* 来达到触发超时异常的发生 +2. 由于超时的发生,这个结果并不会被返回给客户端,取而代之的是 *org.apache.dubbo.remoting.TimeoutException* + + + +在客户端提供本地伪装的实现。当远程调用发生错误的时候,返回给调用方的不是服务端的 "hello name",取而代之的是 "mock name"。 + + + +```java +public class DemoServiceMock implements DemoService { + private static Logger logger = LoggerFactory.getLogger(DemoServiceMock.class); + + public String sayHello(String name) { + logger.warn("about to execute mock: " + DemoServiceMock.class.getSimpleName()); + return "mock " + name; + } +} +``` + + + +同样的,要使用本地伪装的话,还需要在 *mock-consumer.xml* 中配置属性 *mock*。可以简单的通过指定 *mock="true"* 来告诉 Dubbo 框架使用本地伪装,这个时候,本地伪装的包名需要和服务接口的包名一致,类名必须在服务接口的类名后加上 **Mock** 的后缀。例如,当服务接口名是 *org.apache.dubbo.samples.stub.api.DemoService* 时,本地存根的全类名应该是 *org.apache.dubbo.samples.stub.api.DemoServiceMock*。 + + + +```xml + +``` + + + +如果不希望使用默认的命名规则,也可以直接通过 *mock* 属性来指定本地伪装的全类名。 + + + +```xml + +``` + + + +通过提供一个本地伪装的类,可以最大限度的控制出错之后的容错逻辑。有的时候,业务上并不需要这样灵活的机制,只有返回一个默认值的诉求,这个时候提供一个完整的本地伪装的实现就显得有点重了。或者线上出错的时候,应用并没有打包本地伪装,需要通过推送规则的方式临时对服务降级。Dubbo 框架为上面的这两种诉求都提供了快捷方式,帮助用户快速配置服务降级。 + + + +启动服务端 *MockProvider* 之后,然后再执行 *MockConsumer* 就可以看到下面的结果: + + + +```bash +Caused by: org.apache.dubbo.remoting.TimeoutException: Waiting server-side response timeout by scan timer. start time: 2019-04-09 14:20:48.061, end time: 2019-04-09 14:20:49.077, client elapsed: 0 ms, server elapsed: 1015 ms, timeout: 1000 ms, request: Request [id=2, version=2.0.2, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=sayHello, parameterTypes=[class java.lang.String], arguments=[world], attachments={path=org.apache.dubbo.samples.mock.api.DemoService, interface=org.apache.dubbo.samples.mock.api.DemoService, version=0.0.0}]], channel: /30.5.125.99:56433 -> /30.5.125.99:20880 + at org.apache.dubbo.remoting.exchange.support.DefaultFuture.returnFromResponse(DefaultFuture.java:295) + at org.apache.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:191) + at org.apache.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:164) + at org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(DubboInvoker.java:108) + at org.apache.dubbo.rpc.protocol.AbstractInvoker.invoke(AbstractInvoker.java:157) + at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:88) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73) + at org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilter.java:49) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73) + at org.apache.dubbo.rpc.filter.ConsumerContextFilter.invoke(ConsumerContextFilter.java:54) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73) + at org.apache.dubbo.rpc.listener.ListenerInvokerWrapper.invoke(ListenerInvokerWrapper.java:78) + at org.apache.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:56) + at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:80) + ... 5 more +[09/04/19 02:20:49:049 CST] main WARN api.DemoServiceMock: about to execute mock: DemoServiceMock +[09/04/19 02:20:49:049 CST] main INFO mock.MockConsumer: result: mock world +``` + + + + + +下面通过规则推送为例展示这种快捷方式的用法,更多的用法请参考 Dubbo 官方用户手册 [^mock]。通过向配置中心推送指定服务的配置,就可以做到动态服务降级的目的。 + + + +```yaml +--- # 1 +configVersion: v2.7 +scope: service + key: org.apache.dubbo.samples.mock.api.DemoService #2 + enabled: true + configs: + - addresses: [0.0.0.0] + side: consumer #3 + parameters: + mock: return configured-mock-value #4 + ... +``` + +1. 以 *Zookeeper* 为例,规则的路径是 /dubbo/config/org.apache.dubbo.samples.mock.api.DemoService/configurators +2. 该规则作用在 *org.apache.dubbo.samples.mock.api.DemoService* 服务上 +3. 该规则作用在客户端 +4. 当错误发送时,对服务的调用返回默认值 *configured-mock-value* + + + +启动服务端 *MockProvider* 之后,再执行例子[^mock-samples]中的 *Configurator* 完成对服务降级规则的配置,然后再执行 *MockConsumer* 就可以看到下面的结果: + + + +```bash +[09/04/19 02:19:01:001 CST] main INFO integration.AbstractConfiguratorListener: [DUBBO] Notification of overriding rule, change type is: MODIFIED, raw config content is: + --- +configVersion: v2.7 +scope: service +key: org.apache.dubbo.samples.mock.api.DemoService +enabled: true +configs: +- addresses: [0.0.0.0] + side: consumer + parameters: + mock: return configured-mock-value +... +, dubbo version: 2.7.1, current host: 30.5.125.99 + +... + +Caused by: org.apache.dubbo.remoting.TimeoutException: Waiting server-side response timeout. start time: 2019-04-09 14:19:03.737, end time: 2019-04-09 14:19:04.741, client elapsed: 1 ms, server elapsed: 1002 ms, timeout: 1000 ms, request: Request [id=2, version=2.0.2, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=sayHello, parameterTypes=[class java.lang.String], arguments=[world], attachments={path=org.apache.dubbo.samples.mock.api.DemoService, interface=org.apache.dubbo.samples.mock.api.DemoService, version=0.0.0}]], channel: /30.5.125.99:56412 -> /30.5.125.99:20880 + at org.apache.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:188) + at org.apache.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:164) + at org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(DubboInvoker.java:108) + at org.apache.dubbo.rpc.protocol.AbstractInvoker.invoke(AbstractInvoker.java:157) + at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:88) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73) + at org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilter.java:49) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73) + at org.apache.dubbo.rpc.filter.ConsumerContextFilter.invoke(ConsumerContextFilter.java:54) + at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73) + at org.apache.dubbo.rpc.listener.ListenerInvokerWrapper.invoke(ListenerInvokerWrapper.java:78) + at org.apache.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:56) + at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:80) + ... 5 more +[09/04/19 02:19:04:004 CST] main INFO mock.MockConsumer: result: configured-mock-value +``` + + + +## 总结 + +本文介绍了 Dubbo 中本地存根和本地伪装的概念和用法。从本质来讲,本地存根和本地伪装等同于面向切面编程中的概念,通过诸如 Spring 框架提供的 *AOP* 编程可以达到同样的目的。通过本文如何开发一个本地存根和本地伪装的示例,读者可以直观的感受到通过框架提供的机制更加方便快捷。同时,对于很多简单的场景和动态配置推送的场景,框架提供了仅通过配置而无需编码的方式来满足,进一步提升了框架使用者的效率。 + + + +[^stub-samples]: https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-stub +[^mock-samples]: https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-mock +[^mock]: https://cn.dubbo.apache.org/zh-cn/docsv2.7/user/examples/local-mock/ + + + diff --git a/content/en/blog/java/demos/dubbo-supporting-grpc-http2-and-protobuf.md b/content/en/blog/java/demos/dubbo-supporting-grpc-http2-and-protobuf.md new file mode 100644 index 000000000000..438e5dcdee91 --- /dev/null +++ b/content/en/blog/java/demos/dubbo-supporting-grpc-http2-and-protobuf.md @@ -0,0 +1,731 @@ +--- +title: "Dubbo 在跨语言和协议穿透性方向上的探索:支持 HTTP/2 gRPC 和 Protobuf" +linkTitle: "支持 HTTP/2 gRPC 和 Protobuf" +tags: ["Java"] +date: 2019-10-28 +description: > + 本文整理自刘军在 Dubbo 成都 meetup 上分享的《Dubbo 在多语言和协议穿透性方向上的探索》。 +--- + +本文总体上可分为基础产品简介、Dubbo 对 gRPC (HTTP/2) 和 Protobuf 的支持及示例演示三部分,在简介部分介绍了 Dubbo、HTTP/2、gRPC、Protobuf 的基本概念和特点;第二部分介绍了 Dubbo 为何要支持 gRPC (HTTP/2) 和 Protobuf,以及这种支持为 gRPC 和 Dubbo 开发带来的好处与不同;第三部分通过两个实例分别演示了 Dubbo gRPC 和 Dubbo Protobuf 的使用方式。 + +## 基本介绍 + +### Dubbo 协议 + +从协议层面展开,以下是当前 2.7 版本支持的 Dubbo 协议 + +![image-20191029103919557](/imgs/blog/grpc/dubbo-ptotocol.png) + +众所周知,Dubbo 协议是直接定义在 TCP 传输层协议之上,由于 TCP 高可靠全双工的特点,为 Dubbo 协议的定义提供了最大的灵活性,但同时也正是因为这样的灵活性,RPC 协议普遍都是定制化的私有协议,Dubbo 同样也面临这个问题。在这里我们着重讲一下 Dubbo 在协议通用性方面值得改进的地方,关于协议详细解析请参见[官网博客](/en/blog/2018/10/05/dubbo-协议详解/) + +* Dubbo 协议体 Body 中有一个可扩展的 attachments 部分,这给 RPC 方法之外额外传递附加属性提供了可能,是一个很好的设计。但是类似的 Header 部分,却缺少类似的可扩展 attachments,这点可参考 HTTP 定义的 Ascii Header 设计,将 Body Attachments 和 Header Attachments 做职责划分。 +* Body 协议体中的一些 RPC 请求定位符如 Service Name、Method Name、Version 等,可以提到 Header 中,和具体的序列化协议解耦,以更好的被网络基础设施识别或用于流量管控。 +* 扩展性不够好,欠缺协议升级方面的设计,如 Header 头中没有预留的状态标识位,或者像 HTTP 有专为协议升级或协商设计的特殊 packet。 +* 在 Java 版本的代码实现上,不够精简和通用。如在链路传输中,存在一些语言绑定的内容;消息体中存在冗余内容,如 Service Name 在 Body 和 Attachments 中都存在。 + +### HTTP/1 + +相比于直接构建与 TPC 传输层的私有 RPC 协议,构建于 HTTP 之上的远程调用解决方案会有更好的通用性,如WebServices 或 REST 架构,使用 HTTP + JSON 可以说是一个事实标准的解决方案。 + +之所以选择构建在 HTTP 之上,我认为有两个最大的优势: + +1. HTTP 的语义和可扩展性能很好的满足 RPC 调用需求。 +2. 通用性,HTTP 协议几乎被网络上的所有设备所支持,具有很好的协议穿透性。 + +![image-20191029113404906](/imgs/blog/grpc/http1.png) + +具体来说,HTTP/1 的优势和限制是: + +* 典型的 Request – Response 模型,一个链路上一次只能有一个等待的 Request 请求 + +* HTTP/1 支持 Keep-Alive 链接,避免了链接重复创建开销 + +* Human Readable Headers,使用更通用、更易于人类阅读的头部传输格式 + +* 无直接 Server Push 支持,需要使用 Polling Long-Polling 等变通模式 + + + +### HTTP/2 + +HTTP/2 保留了 HTTP/1 的所有语义,在保持兼容的同时,在通信模型和传输效率上做了很大的改进。 + +![image-20191029113416731](/imgs/blog/grpc/http2.png) + +* 支持单条链路上的 Multiplexing,相比于 Request - Response 独占链路,基于 Frame 实现更高效利用链路 + +* Request - Stream 语义,原生支持 Server Push 和 Stream 数据传输 + +* Flow Control,单条 Stream 粒度的和整个链路粒度的流量控制 + +* 头部压缩 HPACK + +* Binary Frame + +* 原生 TLS 支持 + + + +### gRPC + +上面提到了在 HTTP 及 TCP 协议之上构建 RPC 协议各自的优缺点,相比于 Dubbo 构建于 TPC 传输层之上,Google 选择将 gRPC 直接定义在 HTTP/2 协议之上,关于 gRPC 的 [基本介绍](https://grpc.io/docs/what-is-grpc/introduction/)和 [设计愿景](https://grpc.io/blog/principles/?spm=ata.13261165.0.0.2be55017XbUhs8) 请参考以上两篇文章,我这里仅摘取 设计愿景 中几个能反映 gRPC 设计目的特性来做简单说明。 + +* Coverage & Simplicity,协议设计和框架实现要足够通用和简单,能运行在任何设备之上,甚至一些资源首先的如 IoT、Mobile 等设备。 + +* Interoperability & Reach,要构建在更通用的协议之上,协议本身要能被网络上几乎所有的基础设施所支持。 + +* General Purpose & Performant,要在场景和性能间做好平衡,首先协议本身要是适用于各种场景的,同时也要尽量有高的性能。 + +* Payload Agnostic,协议上传输的负载要保持语言和平台中立。 + +* Streaming,要支持 Request - Response、Request - Stream、Bi-Steam 等通信模型。 + +* Flow Control,协议自身具备流量感知和限制的能力。 + +* Metadata Exchange,在 RPC 服务定义之外,提供额外附加数据传输的能力。 + +总的来说,在这样的设计理念指导下,gRPC 最终被设计为一个跨语言、跨平台的、通用的、高性能的、基于 HTTP/2 的 RPC 协议和框架。 + + + +### Protobuf + +[Protocol buffers (Protobuf)](https://developers.google.com/protocol-buffers/docs/overview) 是 Google 推出的一个跨平台、语言中立的结构化数据描述和序列化的产品,它定义了一套结构化数据定义的协议,同时也提供了相应的 [Compiler](https://github.com/protocolbuffers/protobuf/releases/tag/v3.10.0) 工具,用来将语言中立的描述转化为相应语言的具体描述。 + +它的一些特性包括: + +* 跨语言 跨平台,语言中立的数据描述格式,默认提供了生成多种语言的 Compiler 工具。 + +* 安全性,由于反序列化的范围和输出内容格式都是 Compiler 在编译时预生成的,因此绕过了类似 Java Deserialization Vulnarability 的问题。 + +* 二进制 高性能 + +* 强类型 + +* 字段变更向后兼容 + +```idl +message Person { + required string name = 1; + required int32 id = 2; + optional string email = 3; + + enum PhoneType { + MOBILE = 0; + HOME = 1; + WORK = 2; + } + + message PhoneNumber { + required string number = 1; + optional PhoneType type = 2 [default = HOME]; + } + + repeated PhoneNumber phone = 4; +} +``` + + + +除了结构化数据描述之外,Protobuf 还支持定义 RPC 服务,它允许我们定义一个 `.proto` 的服务描述文件,进而利用 Protobuf Compiler 工具生成特定语言和 RPC 框架的接口和 stub。后续将要具体讲到的 gRPC + Protobuf、Dubbo-gRPC + Protobuf 以及 Dubbo + Protobuf 都是通过定制 Compiler 类实现的。 + + ```idl +service SearchService { + rpc Search (SearchRequest) returns (SearchResponse); +} + ``` + + + +## Dubbo 所做的支持 + +跨语言的服务开发涉及到多个方面,从服务定义、RPC 协议到序列化协议都要做到语言中立,同时还针对每种语言有对应的 SDK 实现。虽然得益于社区的贡献,现在 Dubbo 在多语言 SDK 实现上逐步有了起色,已经提供了包括 Java, Go, PHP, C#, Python, NodeJs, C 等版本的客户端或全量实现版本,但在以上提到的跨语言友好型方面,以上三点还是有很多可改进之处。 + +* 协议,上面我们已经分析过 Dubbo 协议既有的缺点,如果能在 HTTP/2 之上构建应用层协议,则无疑能避免这些弊端,同时最大可能的提高协议的穿透性,避免网关等协议转换组件的存在,更有利于链路上的流量管控。考虑到 gRPC 是构建在 HTTP/2 之上,并且已经是云原生领域推荐的通信协议,Dubbo 在第一阶段选择了直接支持 gRPC 协议作为当前的 HTTP/2 解决方案。我们也知道 gRPC 框架自身的弊端在于易用性不足以及服务治理能力欠缺(这也是目前绝大多数厂商不会直接裸用 gRPC 框架的原因),通过将其集成进 Dubbo 框架,用户可以方便的使用 Dubbo 编程模型 + Dubbo 服务治理 + gRPC 协议通信的组合。 + +* 服务定义,当前 Dubbo 的服务定义和具体的编程语言绑定,没有提供一种语言中立的服务描述格式,比如 Java 就是定义 Interface 接口,到了其他语言又得重新以另外的格式定义一遍。因此 Dubbo 通过支持 Protobuf 实现了语言中立的服务定义。 +* 序列化,Dubbo 当前支持的序列化包括 Json、Hessian2、Kryo、FST、Java 等,而这其中支持跨语言的只有 Json、Hessian2,通用的 Json 有固有的性能问题,而 Hessian2 无论在效率还是多语言 SDK 方面都有所欠缺。为此,Dubbo 通过支持 Protobuf 序列化来提供更高效、易用的跨语言序列化方案。 + + + +## 示例 + +### 示例 1,使用 Dubbo 开发 gRPC 服务 + +[gRPC](https://grpc.io/) 是 Google 开源的构建在 HTTP/2 之上的一个 PRC 通信协议。Dubbo 依赖其灵活的协议扩展机制,增加了对 gRPC (HTTP/2) 协议的支持。 + +目前的支持限定在 Dubbo Java 语言版本,后续 Go 语言或其他语言版本将会以类似方式提供支持。下面,通过一个[简单的示例](https://github.com/apache/dubbo-samples/tree/925c3d150d9030bc72988564e4f97eca1f6fcb89/3-extensions/protocol/dubbo-samples-grpc)来演示如何在 Dubbo 中使用 gRPC 协议通信。 + +#### 1. 定义服务 IDL + +首先,通过标准的 Protobuf 协议定义服务如下: + +```idl +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.grpc.examples.helloworld"; +option java_outer_classname = "HelloWorldProto"; +option objc_class_prefix = "HLW"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} + +``` + +在此,我们定义了一个只有一个方法 sayHello 的 Greeter 服务,同时定义了方法的入参和出参, + +#### 2. PCompiler 生成 Stub + +1. 定义 Maven Protobuf Compiler 插件工具。这里我们扩展了 Protobuf 的 Compiler 工具,以用来生成 Dubbo 特有的 RPC stub,此当前以 Maven 插件的形式发布。 + +```xml + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.5.1 + + com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier} + + dubbo-grpc-java + org.apache.dubbo:protoc-gen-dubbo-java:1.19.0-SNAPSHOT:exe:${os.detected.classifier} + build/generated/source/proto/main/java + false + grpc + + + + + compile + compile-custom + + + + +``` + +其中, + +pluginArtifact 指定了 Dubbo 定制版本的 Java Protobuf Compiler 插件,通过这个插件来在编译过程中生成 Dubbo 定制版本的 gRPC stub。 + +```xml + org.apache.dubbo:protoc-gen-dubbo-java:1.19.0-SNAPSHOT:exe:${os.detected.classifier} +``` + +由于 `protoc-gen-dubbo-java` 支持 gRPC 和 Dubbo 两种协议,可生成的 stub 类型,默认值是 gRPC,关于 dubbo 协议的使用可参见 [使用 Protobuf 开发 Dubbo 服务](/en/overview/mannual/java-sdk/quick-start/)。 + +```xml +grpc +``` + + + +2. 生成 Java Bean 和 Dubbo-gRPC stub + + ```sh + # 运行以下 maven 命令 + $ mvn clean compile + ``` + + 生成的 Stub 和消息类 如下: + ![image-20191026130516896](/imgs/blog/grpc/compiler-classes.png) + + 重点关注 GreeterGrpc ,包含了所有 gRPC 标准的 stub 类/方法,同时增加了 Dubbo 特定的接口,之后 Provider 端的服务暴露和 Consumer 端的服务调用都将依赖这个接口。 + + ```java + /** + * Code generated for Dubbo + */ + public interface IGreeter { + + default public io.grpc.examples.helloworld.HelloReply sayHello(io.grpc.examples.helloworld.HelloRequest request) { + throw new UnsupportedOperationException("No need to override this method, extend XxxImplBase and override all methods it allows."); + } + + default public com.google.common.util.concurrent.ListenableFuture sayHelloAsync( + io.grpc.examples.helloworld.HelloRequest request) { + throw new UnsupportedOperationException("No need to override this method, extend XxxImplBase and override all methods it allows."); + } + + public void sayHello(io.grpc.examples.helloworld.HelloRequest request, + io.grpc.stub.StreamObserver responseObserver); + + } + ``` + + + +#### 3. 业务逻辑开发 + +继承 `GreeterGrpc.GreeterImplBase` (来自第 2 步),编写业务逻辑,这点和原生 gRPC 是一致的。 + +```java +package org.apache.dubbo.samples.basic.impl; + +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloReply; +import io.grpc.examples.helloworld.HelloRequest; +import io.grpc.stub.StreamObserver; + +public class GrpcGreeterImpl extends GreeterGrpc.GreeterImplBase { + @Override + public void sayHello(HelloRequest request, StreamObserver responseObserver) { + System.out.println("Received request from client."); + System.out.println("Executing thread is " + Thread.currentThread().getName()); + HelloReply reply = HelloReply.newBuilder() + .setMessage("Hello " + request.getName()).build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } +} +``` + + + +#### 4. Provider 端暴露 Dubbo 服务 + +以 Spring XML 为例 + +```xml + + + + + + + + + + + +``` + +```java +public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("spring/dubbo-demo-provider.xml"); + context.start(); + + System.out.println("dubbo service started"); + new CountDownLatch(1).await(); +} +``` + + + +#### 5. 引用 Dubbo 服务 + +```xml + + + + + + +``` + +```java +public static void main(String[] args) throws IOException { + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("spring/dubbo-demo-consumer.xml"); + context.start(); + + GreeterGrpc.IGreeter greeter = (GreeterGrpc.IGreeter) context.getBean("greeter"); + + HelloReply reply = greeter.sayHello(HelloRequest.newBuilder().setName("world!").build()); + System.out.println("Result: " + reply.getMessage()); + + System.in.read(); +} +``` + + + +#### 示例1附:高级用法 + +**一、异步调用** + +再来看一遍 `protoc-gen-dubbo-java` 生成的接口: + +```java +/** + * Code generated for Dubbo + */ +public interface IGreeter { + default public HelloReply sayHello(HelloRequest request) { + // ...... + } + default public ListenableFuture sayHelloAsync(HelloRequest request) { + // ...... + } + public void sayHello(HelloRequest request, StreamObserver responseObserver); +} +``` + +这里为 sayHello 方法生成了三种类型的重载方法,分别用于同步调用、异步调用和流式调用,如果消费端要进行异步调用,直接调用 sayHelloAsync() 即可: + +```java +public static void main(String[] args) throws IOException { + // ... + GreeterGrpc.IGreeter greeter = (GreeterGrpc.IGreeter) context.getBean("greeter"); + ListenableFuture future = + greeter.sayHelloAsync(HelloRequest.newBuilder().setName("world!").build()); + // ... +} +``` + + + +**二、高级配置** + +由于当前实现方式是直接集成了 gRPC-java SDK,因此很多配置还没有和 Dubbo 侧对齐,或者还没有以 Dubbo 的配置形式开放,因此,为了提供最大的灵活性,我们直接把 gRPC-java 的配置接口暴露了出来。 + +绝大多数场景下,你可能并不会用到以下扩展,因为它们更多的是对 gRPC 协议的拦截或者 HTTP/2 层面的配置。同时使用这些扩展点可能需要对 HTTP/2 或 gRPC 有基本的了解。 + +**扩展点** + +目前支持的扩展点如下: + +* org.apache.dubbo.rpc.protocol.grpc.interceptors.ClientInterceptor + +* org.apache.dubbo.rpc.protocol.grpc.interceptors.GrpcConfigurator + +* org.apache.dubbo.rpc.protocol.grpc.interceptors.ServerInterceptor + +* org.apache.dubbo.rpc.protocol.grpc.interceptors.ServerTransportFilter + + + +GrpcConfigurator 是最通用的扩展点,我们以此为例来说明一下,其基本定义如下: + +```java +public interface GrpcConfigurator { + // 用来定制 gRPC NettyServerBuilder + default NettyServerBuilder configureServerBuilder(NettyServerBuilder builder, URL url) { + return builder; + } + // 用来定制 gRPC NettyChannelBuilder + default NettyChannelBuilder configureChannelBuilder(NettyChannelBuilder builder, URL url) { + return builder; + } + // 用来定制 gRPC CallOptions, 定义某个服务在每次请求间传递数据 + default CallOptions configureCallOptions(CallOptions options, URL url) { + return options; + } +} +``` + +以下是一个示例扩展实现: + +```java +public class MyGrpcConfigurator implements GrpcConfigurator { + private final ExecutorService executor = Executors + .newFixedThreadPool(200, new NamedThreadFactory("Customized-grpc", true)); + + @Override + public NettyServerBuilder configureServerBuilder(NettyServerBuilder builder, URL url) { + return builder.executor(executor); + } + + @Override + public NettyChannelBuilder configureChannelBuilder(NettyChannelBuilder builder, URL url) + { + return builder.flowControlWindow(10); + } + + @Override + public CallOptions configureCallOptions(CallOptions options, URL url) { + return options.withOption(CallOptions.Key.create("key"), "value"); + } +} + +``` + +配置为 Dubbo SPI,`resources/META-INF/services 增加配置文件 + +```properties +default=org.apache.dubbo.samples.basic.comtomize.MyGrpcConfigurator +``` + +1. 指定 Provider 端线程池 + + 默认用的是 Dubbo 的线程池,有 fixed (默认)、cached、direct 等类型。以下演示了切换为业务自定义线程池。 + + ```java + private final ExecutorService executor = Executors + .newFixedThreadPool(200, new NamedThreadFactory("Customized-grpc", true)); + + public NettyServerBuilder configureServerBuilder(NettyServerBuilder builder, URL url) + { + return builder.executor(executor); + } + + ``` + + + +2. 指定 Consumer 端限流值 + + 设置 Consumer 限流值为 10 + + ```java + @Override + public NettyChannelBuilder configureChannelBuilder(NettyChannelBuilder builder, URL url) + { + return builder.flowControlWindow(10); + } + + ``` + + + +3. 传递附加参数 + + DemoService 服务调用传递 key + + ```java + @Override + public CallOptions configureCallOptions(CallOptions options, URL url) { + if (url.getServiceInterface().equals("xxx.DemoService")) { + return options.withOption(CallOptions.Key.create("key"), "value"); + } else { + return options; + } + } + + ``` + + + +**三、TLS 配置** + +配置方式和 Dubbo 提供的通用的 [TLS 支持](/en/overview/mannual/java-sdk/reference-manual/protocol/tls/)一致,具体请参见文档 + + + +### 示例 2, 使用 Protobuf 开发 Dubbo 服务 + +下面,我们以一个[具体的示例](https://github.com/apache/dubbo-samples/tree/master/3-extensions/serialization/dubbo-samples-protobuf)来看一下基于 Protobuf 的 Dubbo 服务开发流程。 + + + +#### 1. 定义服务 + +通过标准 Protobuf 定义服务 + +```idl +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.dubbo.demo"; +option java_outer_classname = "DemoServiceProto"; +option objc_class_prefix = "DEMOSRV"; + +package demoservice; + +// The demo service definition. +service DemoService { + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} + +``` + +这里定义了一个 DemoService 服务,服务只包含一个 sayHello 方法,同时定义了方法的入参和出参。 + + + +#### 2. Compiler 编译服务 + +1. 引入 Protobuf Compiler Maven 插件,同时指定 `protoc-gen-dubbo-java` RPC 扩展 + +```xml + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.5.1 + + com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier} + + dubbo-grpc-java + org.apache.dubbo:protoc-gen-dubbo-java:1.19.0-SNAPSHOT:exe:${os.detected.classifier} + build/generated/source/proto/main/java + false + dubbo + + + + + compile + compile-custom + + + + +``` + +注意,这里与 [Dubbo 对 gRPC](https://github.com/apache/dubbo-samples/tree/925c3d150d9030bc72988564e4f97eca1f6fcb89/3-extensions/protocol/dubbo-samples-grpc) 支持部分的区别在于: +` dubbo` + +2. 生成 Dubbo stub + + ```shell + # 运行以下 maven 命令 + $mvn clean compile + ``` + + 生成的 Java 类如下: + + ![image-20191028201240976](/imgs/blog/grpc/compiler-protobuf.png) + + DemoServiceDubbo 为 Dubbo 定制的 stub + + ```java + public final class DemoServiceDubbo { + + private static final AtomicBoolean registered = new AtomicBoolean(); + + private static Class init() { + Class clazz = null; + try { + clazz = Class.forName(DemoServiceDubbo.class.getName()); + if (registered.compareAndSet(false, true)) { + org.apache.dubbo.common.serialize.protobuf.support.ProtobufUtils.marshaller( + org.apache.dubbo.demo.HelloRequest.getDefaultInstance()); + org.apache.dubbo.common.serialize.protobuf.support.ProtobufUtils.marshaller( + org.apache.dubbo.demo.HelloReply.getDefaultInstance()); + } + } catch (ClassNotFoundException e) { + // ignore + } + return clazz; + } + + private DemoServiceDubbo() {} + + public static final String SERVICE_NAME = "demoservice.DemoService"; + + /** + * Code generated for Dubbo + */ + public interface IDemoService { + + static Class clazz = init(); + org.apache.dubbo.demo.HelloReply sayHello(org.apache.dubbo.demo.HelloRequest request); + + java.util.concurrent.CompletableFuture sayHelloAsync( + org.apache.dubbo.demo.HelloRequest request); + + } + + } + ``` + + 最值得注意的是 `IDemoService` 接口,它会作为 Dubbo 服务定义基础接口。 + + + +#### 3. 开发业务逻辑 + +从这一步开始,所有开发流程就和直接定义 Java 接口一样了。实现接口定义业务逻辑。 + +```java +public class DemoServiceImpl implements DemoServiceDubbo.IDemoService { + private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class); + + @Override + public HelloReply sayHello(HelloRequest request) { + logger.info("Hello " + request.getName() + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); + return HelloReply.newBuilder() + .setMessage("Hello " + request.getName() + ", response from provider: " + + RpcContext.getContext().getLocalAddress()) + .build(); + } + + @Override + public CompletableFuture sayHelloAsync(HelloRequest request) { + return CompletableFuture.completedFuture(sayHello(request)); + } +} +``` + + + +#### 4. 配置 Provider + +暴露 Dubbo 服务 + +```xml + + + + + + + + + + +``` + +```java +public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("spring/dubbo-provider.xml"); + context.start(); + System.in.read(); +} +``` + + + +#### 5. 配置 Consumer + +引用 Dubbo 服务 + +```xml + + + + + +``` + +```java +public static void main(String[] args) throws Exception { + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext("spring/dubbo-consumer.xml"); + context.start(); + IDemoService demoService = context.getBean("demoService", IDemoService.class); + HelloRequest request = HelloRequest.newBuilder().setName("Hello").build(); + HelloReply reply = demoService.sayHello(request); + System.out.println("result: " + reply.getMessage()); + System.in.read(); +} +``` + diff --git a/content/en/blog/java/demos/dubbo2.7.14-java17.md b/content/en/blog/java/demos/dubbo2.7.14-java17.md new file mode 100644 index 000000000000..3f9e329352b1 --- /dev/null +++ b/content/en/blog/java/demos/dubbo2.7.14-java17.md @@ -0,0 +1,78 @@ +--- +title: "使用jdk17编译运行dubbo 2.7.14项目" +linkTitle: "使用jdk17编译运行dubbo 2.7.14项目" +tags: ["Java"] +date: 2018-08-07 +description: > + 本文介绍了如何在jdk17环境下编译运行dubbo 2.7.14项目。 +--- +## 概述 +java 17是java目前最新的长期支持(LTS)版本,但是由于其强封装 JDK 的内部 API的新特性,导致dubbo项目无法直接使用jdk17编译运行。通过参考[openjdk的说明](https://openjdk.java.net/jeps/403),可以发现只需要添加相应参数即可绕开java 17的限制 +对于普通的dubbo项目,只需要在运行时添加 +```--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED``` +如上参数即可。如果项目的其它依赖也有类似问题则可能需要加入更多参数,参数的获得方式和详细示例将在下面给出 +本解决方案只能解决由于java 17强封装 JDK 的内部 API的特性造成的问题,其他的兼容性问题请寻找其它方案 +## 参数的获得方法和示例 +我们以dubbo官方仓库中的demo为例 +首先使用java 17作为我们的开发环境,通过 +``` +git clone git@github.com:apache/dubbo.git +git checkout dubbo-2.7.14 +cd dubbo-demo/dubbo-demo-annotation +``` +获得dubbo官方仓库的代码中的demo,然后可以尝试直接使用java 17编译dubbo的demo +确认java版本 +``` +➜ ~ java -version +openjdk version "17.0.1" 2021-10-19 +OpenJDK Runtime Environment Temurin-17.0.1+12 (build 17.0.1+12) +OpenJDK 64-Bit Server VM Temurin-17.0.1+12 (build 17.0.1+12, mixed mode, sharing) +``` +然后运行 +``` +mvn -U clean package --no-transfer-progress -D maven.test.skip=true +``` +启动zookeeper `docker run --name some-zookeepep -p 2181:2181 -it --rm zookeeper` 作为注册中心 +尝试运行provider +``` +java -jar dubbo-demo-annotation-provider/target/dubbo-demo-annotation-provider-2.7.14.jar +``` +可以看到类似的报错: +```Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @8807e25``` +关键词 `module `**java.base**` does not "opens `**java.lang**`" to unnamed module @8807e25`,根据[openjdk的说明](https://openjdk.java.net/jeps/403),我们只需要添加`--add-opens `**java.base**`/`**java.lang**`=ALL-UNNAMED`参数即可解决问题 +对应的报错应该都可以用类似得方法去解决,经过测试,demo中的dubbo项目需要 +``` +--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED +``` +如上参数即可运行 +在两个终端中分别运行provider和consumer: +``` +java --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED -jar dubbo-demo-annotation-provider/target/dubbo-demo-annotation-provider-2.7.14.jar +``` +``` +java --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED -jar dubbo-demo-annotation-consumer/target/dubbo-demo-annotation-consumer-2.7.14.jar +``` +可以发现报出了zookeeper的错误,不难想到,升级依赖的zookeeper的版本大概率可以解决问题... +在provider和consumer的 `pom.xml` 的依赖第一项添加最新版本的zookeeper依赖: +``` + + org.apache.zookeeper + zookeeper + 3.7.0 + + + io.netty + netty + + + +``` +再次运行provider和consumer +可以看到consumer端成功输出了类似的结果 +``` +result :Hello world, response from provider: *.*.*.*/:20880 +``` +provider端也有对应的日志 +``` +Hello world, request from consumer: /*.*.*.*:43346 +``` \ No newline at end of file diff --git a/content/en/blog/java/demos/first-dubbo-filter.md b/content/en/blog/java/demos/first-dubbo-filter.md new file mode 100644 index 000000000000..0fa233ddde98 --- /dev/null +++ b/content/en/blog/java/demos/first-dubbo-filter.md @@ -0,0 +1,202 @@ +--- +title: "第一个 Dubbo Filter" +linkTitle: "第一个 Dubbo Filter" +tags: ["Java"] +date: 2018-07-01 +description: > + 本文介绍了如何开发一个 Dubbo 的 Filter +--- + +### 概述 +在Dubbo的整体设计中,Filter是一个很重要的概念,包括Dubbo本身的大多数功能,都是基于此扩展点实现的,在每次的调用过程中,Filter的拦截都会被执行。 + +#### Dubbo Filter的加载机制 +Dubbo中已经实现的Filter大概有二十几个,它们的入口都是ProtocolFilterWrapper,ProtocolFilterWrapper对Protocol做了Wrapper,会在加载扩展的时候被加载进来,下面我们来看下这个Filter链是如何构造的。 + +```java +//ProtocolFilterWrapper.java +public Invoker refer(Class type, URL url) throws RpcException { + if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { + return protocol.refer(type, url); + } + return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER); + } + + private static Invoker buildInvokerChain(final Invoker invoker, String key, String group) { + Invoker last = invoker; + List filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group); + if (filters.size() > 0) { + for (int i = filters.size() - 1; i >= 0; i --) { + final Filter filter = filters.get(i); + final Invoker next = last; + last = new Invoker() { + + public Class getInterface() { + return invoker.getInterface(); + } + + public URL getUrl() { + return invoker.getUrl(); + } + + public boolean isAvailable() { + return invoker.isAvailable(); + } + + public Result invoke(Invocation invocation) throws RpcException { + return filter.invoke(next, invocation); + } + + public void destroy() { + invoker.destroy(); + } + + @Override + public String toString() { + return invoker.toString(); + } + }; + } + } + return last; + } + +``` + +#### Dubbo Filter的激活机制 +通过上述代码我们可以看到,在`buildInvokerChain`中,先获取所有已经激活的调用链,这里的调用链是已经排好序的。再通过Invoker来构造出一个Filter的调用链,最后构建出的调用链大致可以表示为:Filter1->Filter2->Filter3->......->Invoker,下面我们来看一下,第一步中获取已经激活的调用链的详细流程: + +```java + public List getActivateExtension(URL url, String key, String group) { + String value = url.getParameter(key); + return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group); + } + + public List getActivateExtension(URL url, String[] values, String group) { + List exts = new ArrayList(); + + List names = values == null ? new ArrayList(0) : Arrays.asList(values); + + if (! names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) { + getExtensionClasses(); + for (Map.Entry entry : cachedActivates.entrySet()) { + String name = entry.getKey(); + Activate activate = entry.getValue(); + if (isMatchGroup(group, activate.group())) { + T ext = getExtension(name); + if (! names.contains(name) && ! names.contains(Constants.REMOVE_VALUE_PREFIX + name) + && isActive(activate, url)) { + exts.add(ext); + } + } + } + Collections.sort(exts, ActivateComparator.COMPARATOR); + } + List usrs = new ArrayList(); + for (int i = 0; i < names.size(); i ++) { + String name = names.get(i); + if (! name.startsWith(Constants.REMOVE_VALUE_PREFIX) + && ! names.contains(Constants.REMOVE_VALUE_PREFIX + name)) { + if (Constants.DEFAULT_KEY.equals(name)) { + if (usrs.size() > 0) { + exts.addAll(0, usrs); + usrs.clear(); + } + } else { + T ext = getExtension(name); + usrs.add(ext); + } + } + } + if (usrs.size() > 0) { + exts.addAll(usrs); + } + return exts; + } +``` +通过以上代码可以看到,用户自己配置的Filter中,有些是默认激活,有些是需要通过配置文件来激活。而所有Filter的加载顺序,也是先处理Dubbo的默认Filter,再来处理用户自己定义并且配置的Filter。通过"-"配置,可以替换掉Dubbo的原生Filter,通过这样的设计,可以灵活地替换或者修改Filter的加载顺序。 + +#### Dubbo原生的Filter +Dubbo原生的Filter很多,RpcContext,accesslog等功能都可以通过Dubbo来实现,下面我们来介绍一下Consumer端用于上下文传递的ConsumerContextFilter: + +```java +public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + RpcContext.getContext() + .setInvoker(invoker) + .setInvocation(invocation) + .setLocalAddress(NetUtils.getLocalHost(), 0) + .setRemoteAddress(invoker.getUrl().getHost(), + invoker.getUrl().getPort()); + if (invocation instanceof RpcInvocation) { + ((RpcInvocation)invocation).setInvoker(invoker); + } + try { + return invoker.invoke(invocation); + } finally { + RpcContext.getContext().clearAttachments(); + } + } +``` +此Filter记录了调用过程中的状态信息,并且通过invocation对象将客户端设置的attachments参数传递到服务端。并且在调用完成后清除这些参数,这就是为什么请求状态信息可以按次记录并且进行传递。 + +#### 实现一个Dubbo Filter +得益于Dubbo灵活的设计和良好的可扩展性,我们可以通过实现自己的Dubbo Filter来完成调用链路中的逻辑嵌入,比如,耗时统计,monitor信息统计等,下面我们来实现一个简单的Filter: + +Maven 项目结构: + +``` +src + |-main + |-java + |-com + |-xxx + |-XxxFilter.java (实现Filter接口) + |-resources + |-META-INF + |-dubbo + |-com.alibaba.dubbo.rpc.Filter (纯文本文件,内容为:xxx=com.xxx.XxxFilter) +``` + +XxxFilter.java: + +```java +public class XxxFilter implements Filter { + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + // before filter ... + Result result = invoker.invoke(invocation); + // after filter ... + return result; + } +} +``` + +META-INF/dubbo/com.alibaba.dubbo.rpc.Filter: +``` +xxx=com.xxx.XxxFilter +``` + +在 xml 中配置: + +```xml + + + + + + + + +``` + +或者使用注解: + +```java +@Activate(group = "consumer") +public class XxxFilter implements Filter { + // ... +} +``` + +使用 xml 的配置方式会更加灵活,粒度更细。 + +在before和after中,可以实现自己的业务逻辑来赋予该filter一定的功能。编写和配置完成后,该filter就会被Dubbo框架激活并且在调用链中执行。 diff --git a/content/en/blog/java/demos/hystrix.md b/content/en/blog/java/demos/hystrix.md new file mode 100644 index 000000000000..f5cff6e3d896 --- /dev/null +++ b/content/en/blog/java/demos/hystrix.md @@ -0,0 +1,189 @@ +--- +aliases: + - /en/overview/what/ecosystem/rate-limit/hystrix/ + - /en/overview/tasks/rate-limit/hystrix/ + - /en/overview/tasks/rate-limit/hystrix/ +description: "使用 Hystrix 对 Dubbo 服务进行熔断限流保护" +linkTitle: 待整合-Hystrix 熔断降级 +title: 使用 Hystrix 对 Dubbo 服务进行熔断限流保护 +tags: ["Java", "Hystrix", "限流降级"] +date: 2023-12-14 +--- + +## 背景 + +Hystrix 旨在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以及监控和配置等功能。 + +本文介绍在spring应用里,怎么把 Dubbo 和 Hystrix 结合起来使用。 + +- +- + +## Spring Boot应用 + +Demo 地址: + +### 生成dubbo集成spring boot的应用 + +对于不熟悉dubbo 集成spring boot应用的同学,可以在这里直接生成dubbo + spring boot的工程: + +### 配置spring-cloud-starter-netflix-hystrix + +spring boot官方提供了对hystrix的集成,直接在pom.xml里加入依赖: + +```xml + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + 1.4.4.RELEASE + +``` + +然后在Application类上增加`@EnableHystrix`来启用hystrix starter: + +```java +@SpringBootApplication +@EnableHystrix +public class ProviderApplication { +``` +### 配置Provider端 +在Dubbo的Provider上增加`@HystrixCommand`配置,这样子调用就会经过Hystrix代理。 +```java +@Service(version = "1.0.0") +public class HelloServiceImpl implements HelloService { + @HystrixCommand(commandProperties = { + @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), + @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") }) + @Override + public String sayHello(String name) { + // System.out.println("async provider received: " + name); + // return "annotation: hello, " + name; + throw new RuntimeException("Exception to show hystrix enabled."); + } +} +``` +### 配置Consumer端 +对于Consumer端,则可以增加一层method调用,并在method上配置`@HystrixCommand`。当调用出错时,会走到`fallbackMethod = "reliable"`的调用里。 +```java + @Reference(version = "1.0.0") + private HelloService demoService; + @HystrixCommand(fallbackMethod = "reliable") + public String doSayHello(String name) { + return demoService.sayHello(name); + } + public String reliable(String name) { + return "hystrix fallback value"; + } +``` +通过上面的配置,很简单地就完成了Spring Boot里Dubbo + Hystrix的集成。 +## 传统Spring Annotation应用 +Demo地址: +传统spring annotation应用的配置其实也很简单,和spring boot应用不同的是: +1. 显式配置Spring AOP支持:`@EnableAspectJAutoProxy` +2. 显式通过`@Configuration`配置`HystrixCommandAspect` Bean。 +```java + @Configuration + @EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.annotation.action") + @PropertySource("classpath:/spring/dubbo-consumer.properties") + @ComponentScan(value = {"com.alibaba.dubbo.samples.annotation.action"}) + @EnableAspectJAutoProxy + static public class ConsumerConfiguration { + @Bean + public HystrixCommandAspect hystrixCommandAspect() { + return new HystrixCommandAspect(); + } + } +``` +## Hystrix集成Spring AOP原理 +在上面的例子里可以看到,Hystrix对Spring的集成是通过Spring AOP来实现的。下面简单分析下实现。 +```java +@Aspect +public class HystrixCommandAspect { + @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)") + public void hystrixCommandAnnotationPointcut() { + } + @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)") + public void hystrixCollapserAnnotationPointcut() { + } + @Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()") + public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable { + Method method = getMethodFromTarget(joinPoint); + Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint); + if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) { + throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " + + "annotations at the same time"); + } + MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method)); + MetaHolder metaHolder = metaHolderFactory.create(joinPoint); + HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder); + ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ? + metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType(); + Object result; + try { + if (!metaHolder.isObservable()) { + result = CommandExecutor.execute(invokable, executionType, metaHolder); + } else { + result = executeObservable(invokable, executionType, metaHolder); + } + } catch (HystrixBadRequestException e) { + throw e.getCause() != null ? e.getCause() : e; + } catch (HystrixRuntimeException e) { + throw hystrixRuntimeExceptionToThrowable(metaHolder, e); + } + return result; + } +``` +1. `HystrixCommandAspect`里定义了两个注解的AspectJ Pointcut:`@HystrixCommand`, `@HystrixCollapser`。所有带这两个注解的spring bean都会经过AOP处理 +2. 在`@Around` AOP处理函数里,可以看到Hystrix会创建出`HystrixInvokable`,再通过`CommandExecutor`来执行 +## spring-cloud-starter-netflix-hystrix的代码分析 +1. `@EnableHystrix` 引入了`@EnableCircuitBreaker`,`@EnableCircuitBreaker`引入了`EnableCircuitBreakerImportSelector` + ```java + @EnableCircuitBreaker + public @interface EnableHystrix { + } + + @Import(EnableCircuitBreakerImportSelector.class) + public @interface EnableCircuitBreaker { + } + ``` +2. `EnableCircuitBreakerImportSelector`继承了`SpringFactoryImportSelector`,使spring加载`META-INF/spring.factories`里的`EnableCircuitBreaker`声明的配置 + 在`META-INF/spring.factories`里可以找到下面的配置,也就是引入了`HystrixCircuitBreakerConfiguration`。 + ```properties + org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\ + org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration + ``` +3. 在`HystrixCircuitBreakerConfiguration`里可以发现创建了`HystrixCommandAspect` + ```java + @Configuration + public class HystrixCircuitBreakerConfiguration { + + @Bean + public HystrixCommandAspect hystrixCommandAspect() { + return new HystrixCommandAspect(); + } + ``` +可见`spring-cloud-starter-netflix-hystrix`实际上也是创建了`HystrixCommandAspect`来集成Hystrix。 +另外`spring-cloud-starter-netflix-hystrix`里还有metrics, health, dashboard等集成。 + +## 总结 +- 对于dubbo provider的`@Service`是一个spring bean,直接在上面配置`@HystrixCommand`即可 +- 对于dubbo consumer的`@Reference`,可以通过加一层简单的spring method包装,配置`@HystrixCommand`即可 +- Hystrix本身提供`HystrixCommandAspect`来集成Spring AOP,配置了`@HystrixCommand`和`@HystrixCollapser`的spring method都会被Hystrix处理 + +### Sentinel 与 Hystrix 的比较 + +目前业界常用的熔断降级/隔离的库是 Netflix 的 [Hystrix](https://github.com/Netflix/Hystrix),那么 Sentinel 与 Hystrix 有什么异同呢?Hystrix 的关注点在于以 _隔离_ 和 _熔断_ 为主的容错机制,而 Sentinel 的侧重点在于多样化的流量控制、熔断降级、系统负载保护、实时监控和控制台,可以看到解决的问题还是有比较大的不同的。 + +Hystrix 采用命令模式封装资源调用逻辑,并且资源的定义与隔离规则是强依赖的,即在创建 HystrixCommand 的时候就要指定隔离规则(因其执行模型依赖于隔离模式)。Sentinel 的设计更为简单,不关注资源是如何执行的,资源的定义与规则的配置相分离。用户可以先定义好资源,然后在需要的时候配置规则即可。Sentinel 的原则非常简单:根据对应资源配置的规则来为资源执行相应的限流/降级/负载保护策略,若规则未配置则仅进行统计。从 0.1.1 版本开始,Sentinel 还引入了[注解支持](https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81),可以更方便地定义资源。 + +隔离是 Hystrix 的核心功能。Hystrix 通过线程池或信号量的方式来对依赖(即 Sentinel 中对应的资源)进行隔离,其中最常用的是资源隔离。Hystrix 线程池隔离的好处是比较彻底,但是不足之处在于要开很多线程池,在应用本身线程数目比较多的时候上下文切换的 overhead 会非常大;Hystrix 的信号量隔离模式可以限制调用的并发数而不显式创建线程,这样的方式比较轻量级,但缺点是无法对慢调用自动进行降级,只能等待客户端自己超时,因此仍然可能会出现级联阻塞的情况。Sentinel 可以通过并发线程数模式的流量控制来提供信号量隔离的功能。并且结合基于响应时间的熔断降级模式,可以在不稳定资源的平均响应时间比较高的时候自动降级,防止过多的慢调用占满并发数,影响整个系统。 + +Hystrix 熔断降级功能采用熔断器模式,在某个服务失败比率高时自动进行熔断。Sentinel 的熔断降级功能更为通用,支持平均响应时间与失败比率两个指标。Sentinel 还提供各种调用链路关系和流量控制效果支持,同时还可以根据系统负载去实时地调整流量来保护系统,应用场景更为丰富。同时,Sentinel 还提供了实时的监控 API 和控制台,可以方便用户快速了解目前系统的状态,对服务的稳定性了如指掌。 + +更详细的对比请参见 [Sentinel 与 Hystrix 的对比](https://github.com/alibaba/Sentinel/wiki/Sentinel-%E4%B8%8E-Hystrix-%E7%9A%84%E5%AF%B9%E6%AF%94)。 + +### 链接 +- +- +- +- diff --git a/content/en/blog/java/demos/introduction-to-dubbo-qos.md b/content/en/blog/java/demos/introduction-to-dubbo-qos.md new file mode 100644 index 000000000000..88f6b762b091 --- /dev/null +++ b/content/en/blog/java/demos/introduction-to-dubbo-qos.md @@ -0,0 +1,261 @@ +--- +title: "通过QoS对服务进行动态控制" +linkTitle: "通过QoS对服务进行动态控制" +tags: ["Java"] +date: 2018-08-14 +description: > + 本文介绍了如何使用Dubbo的QoS功能对服务进行动态配置,以及相关的参数及配置方式。 +--- + + +QoS,全称为`Quality of Service`, 是常见于网络设备中的一个术语 ,例如在路由器中,可以通过Qos动态的调整和控制某些端口的权重,从而优先的保障运行在这些端口上的服务质量。 + +在Dubbo中,QoS这个概念被用于动态的对服务进行查询和控制。例如对获取当前提供和消费的所有服务,以及对服务进行动态的上下线,即从注册中心上进行注册和反注册操作。 + +## QoS工作机制 + +从Dubbo 2.5.8开始,默认引入了Qos功能,默认处于启动状态。所有的QoS功能被抽象成一个个的命令,通过执行这些命令,Qos会返回响应的结果。 + +> Qos功能基于Netty4实现,在Dubbo 2.6.x之前的版本中,默认依赖的是Netty3,因此需要显示的添加Netty4的依赖,才能确保Netty4正常工作。如果使用http://start.dubbo.io自动生成的Dubbo应用,则无需添加额外的配置,因为已经默认加上了Netty4的依赖。 + +Qos的工作机制如下图所示: + +![undefined](/imgs/blog/qos-architecture.png) + + + +1. 启动并监听一个端口,默认端口是22222 +2. 识别目标请求的协议是Http或者是Telnet,根据协议不同动态添加对应的处理器 +3. 针对不同的协议进行解码,解析出需要执行的命令 +4. 执行命令并返回结果 + +## QoS命令 + +QoS目前支持的命令包括: + +* help: 帮助命令,列出 +* ls: 列出当前所有的正在提供的服务,以及消费的服务 +* online: 动态将某个或全部服务向注册中心进行注册 +* offline: 动态将某个或全部服务从注册中心摘除(反注册) +* quit: 退出当前telnet会话 + +下面,我们具体来操作一下如何通过用QoS对服务进行动态控制。 + +### 通过Telnet方式访问QoS + +假设我们的Dubbo服务端已经启动,我们通过Telnet方式进行连接: + +``` +$ telnet localhost 22222 +Trying 127.0.0.1... +Connected to localhost. +Escape character is '^]'. + ????????? ??? ?? ??????????? ??????????? ???????? + ??? ???? ??? ??? ??? ??? ??? ??? ??? ??? + ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? + ??? ??? ??? ??? ?????????? ?????????? ??? ??? + ??? ??? ??? ??? ??????????? ??????????? ??? ??? + ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? + ??? ???? ??? ??? ??? ??? ??? ??? ??? ??? + ????????? ????????? ??????????? ??????????? ???????? + + +dubbo> +``` + +连接成功后,会出现`dubbo>`提示符,此时输入`help`命令 + +``` +dubbo>help ++---------+----------------------------------------------------------------------------------+ +| help | help command | ++---------+----------------------------------------------------------------------------------+ +| ls | ls service | ++---------+----------------------------------------------------------------------------------+ +| offline | offline dubbo | ++---------+----------------------------------------------------------------------------------+ +| online | online dubbo | ++---------+----------------------------------------------------------------------------------+ +| quit | quit telnet console | ++---------+----------------------------------------------------------------------------------+ + +dubbo> +``` + +会列出当前所有可用的命令,及相应的说明。 + +也可以对单个命令进行help操作,可以看到该命令对应的示例 + +``` +dubbo>help online ++--------------+----------------------------------------------------------------------------------+ +| COMMAND NAME | online | ++--------------+----------------------------------------------------------------------------------+ +| EXAMPLE | online dubbo | +| | online xx.xx.xxx.service | ++--------------+----------------------------------------------------------------------------------+ +``` + +通过`ls` 查看当前的服务状态 + +``` +dubbo>ls +As Provider side: ++------------------------------------------+---+ +| Provider Service Name |PUB| ++------------------------------------------+---+ +|org.apache.dubbo.demo.provider.DemoService| Y | ++------------------------------------------+---+ +As Consumer side: ++---------------------+---+ +|Consumer Service Name|NUM| ++---------------------+---+ +``` + +可以看到,在服务端可以看到一个服务`org.apache.dubbo.demo.provider.DemoService`,第二列里面的`PUB=Y`代表改服务已经发布到注册中心,可供消费端进行调用。 + +假设我们需要动态的对该服务进行下线操作,可以通过`offline`命令来完成 + +``` +dubbo>offline org.apache.dubbo.demo.provider.DemoService +OK +``` + +可以看到命令返回了OK,我们再通过ls看下当前的状态: + +``` +dubbo>ls +As Provider side: ++------------------------------------------+---+ +| Provider Service Name |PUB| ++------------------------------------------+---+ +|org.apache.dubbo.demo.provider.DemoService| N | ++------------------------------------------+---+ +As Consumer side: ++---------------------+---+ +|Consumer Service Name|NUM| ++---------------------+---+ +``` + +可以看到`org.apache.dubbo.demo.provider.DemoService`的`PUB`已经被设置成了`N`。 + +通过`quit`命令退出当前的telnet会话: + +``` +dubbo>quit +BYE! +Connection closed by foreign host. +``` + + + +### 通过HTTP方式访问QOS + +在上面的例子中,我们已经对`org.apache.dubbo.demo.provider.DemoService`进行了下线操作,下面,我们通过对Http方式对上面的服务进行注册操作: + +``` +$ curl -i http://localhost:22222/online?service=org.apache.dubbo.demo.provider.DemoService +HTTP/1.1 200 OK +Content-Type: text/plain +Content-Length: 2 + +OK% +``` + +> 注意online操作对应的参数,需要以`key=value`的形式提供,但实际上key会被忽略 + +看到操作返回了OK,下面通过ls命令查看下当前的状态 + +``` +$ curl -i http://localhost:22222/ls +HTTP/1.1 200 OK +Content-Type: text/plain +Content-Length: 365 + +As Provider side: ++------------------------------------------+---+ +| Provider Service Name |PUB| ++------------------------------------------+---+ +|org.apache.dubbo.demo.provider.DemoService| Y | ++------------------------------------------+---+ +As Consumer side: ++---------------------+---+ +|Consumer Service Name|NUM| ++---------------------+---+ +``` + +可以看到服务的`PUB`状态已经变成了`Y`。 + + + +## QoS相关参数说明 + +QoS提供了一些启动参数,来对启动进行配置,他们主要包括: + +| 参数 | 说明 | 默认值 | +| ------------------ | ----------------- | ------ | +| qosEnable | 是否启动QoS | true | +| qosPort | 启动QoS绑定的端口 | 22222 | +| qosAcceptForeignIp | 是否允许远程访问 | false | + +> 注意,从2.6.4/2.7.0开始,qosAcceptForeignIp默认配置改为false,如果qosAcceptForeignIp设置为true,有可能带来安全风险,请仔细评估后再打开。 + +QoS参数可以通过如下方式进行配置 + +* 系统属性 +* dubbo.properties +* XML方式 +* Spring-boot自动装配方式 + +其中,上述方式的优先顺序为系统属性 > dubbo.properties > XML/Spring-boot自动装配方式。 + +### 使用系统属性方式进行配置 + +``` +-Ddubbo.application.qos.enable=true +-Ddubbo.application.qos.port=33333 +-Ddubbo.application.qos.accept.foreign.ip=false +``` + +### 使用dubbo.properties文件进行配置 + +在项目的`src/main/resources`目录下添加dubbo.properties文件,内容如下: +``` +dubbo.application.qos.enable=true +dubbo.application.qos.port=33333 +dubbo.application.qos.accept.foreign.ip=false +``` + +### 使用XML方法进行配置 + +如果要通过XML配置响应的QoS相关的参数,可以进行如下配置: + +```xml + + + + + + + + + + + + +``` + +### 使用spring-boot自动装配方式配置 + +如果是spring-boot的应用,可以在`application.properties`或者`application.yml`上配置: + +``` +dubbo.application.qosEnable=true +dubbo.application.qosPort=33333 +dubbo.application.qosAcceptForeignIp=false +``` diff --git a/content/en/blog/java/demos/introduction-to-dubbo-spi-2.md b/content/en/blog/java/demos/introduction-to-dubbo-spi-2.md new file mode 100644 index 000000000000..e768a03a2f02 --- /dev/null +++ b/content/en/blog/java/demos/introduction-to-dubbo-spi-2.md @@ -0,0 +1,408 @@ +--- +title: "Dubbo可扩展机制源码解析" +linkTitle: "Dubbo可扩展机制源码解析" +tags: ["Java"] +date: 2019-05-02 +description: > + 本文介绍了SPI扩展机制的实现原理与细节。 +--- + + +在[Dubbo可扩展机制实战]({{}} "")中,我们了解了Dubbo扩展机制的一些概念,初探了Dubbo中LoadBalance的实现,并自己实现了一个LoadBalance。是不是觉得Dubbo的扩展机制很不错呀,接下来,我们就深入Dubbo的源码,一睹庐山真面目。 + +## ExtensionLoader +ExtensionLoader 是最核心的类,负责扩展点的加载和生命周期管理。我们就以这个类开始吧。 +ExtensionLoader 的方法比较多,比较常用的方法有: +* `public static ExtensionLoader getExtensionLoader(Class type)` +* `public T getExtension(String name)` +* `public T getAdaptiveExtension()` + +比较常见的用法有: +* `LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName)` +* `RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getAdaptiveExtension()` + +说明:在接下来展示的源码中,我会将无关的代码(比如日志,异常捕获等)去掉,方便大家阅读和理解。 + +1. getExtensionLoader方法 + 这是一个静态工厂方法,入参是一个可扩展的接口,返回一个该接口的ExtensionLoader实体类。通过这个实体类,可以根据name获得具体的扩展,也可以获得一个自适应扩展。 + +```java +public static ExtensionLoader getExtensionLoader(Class type) { + // 扩展点必须是接口 + if (!type.isInterface()) { + throw new IllegalArgumentException("Extension type(" + type + ") is not interface!"); + } + // 必须要有@SPI注解 + if (!withExtensionAnnotation(type)) { + throw new IllegalArgumentException("Extension type without @SPI Annotation!"); + } + // 从缓存中根据接口获取对应的ExtensionLoader + // 每个扩展只会被加载一次 + ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get(type); + if (loader == null) { + // 初始化扩展 + EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type)); + loader = (ExtensionLoader) EXTENSION_LOADERS.get(type); + } + return loader; +} + +private ExtensionLoader(Class type) { + this.type = type; + objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); +} +``` + +2. getExtension方法 + +```java +public T getExtension(String name) { + Holder holder = cachedInstances.get(name); + if (holder == null) { + cachedInstances.putIfAbsent(name, new Holder()); + holder = cachedInstances.get(name); + } + Object instance = holder.get(); + // 从缓存中获取,如果不存在就创建 + if (instance == null) { + synchronized (holder) { + instance = holder.get(); + if (instance == null) { + instance = createExtension(name); + holder.set(instance); + } + } + } + return (T) instance; +} +``` +getExtension 方法中做了一些判断和缓存,主要的逻辑在 createExtension 方法中。我们继续看 createExtension 方法。 + +```java +private T createExtension(String name) { + // 根据扩展点名称得到扩展类,比如对于LoadBalance,根据random得到RandomLoadBalance类 + Class clazz = getExtensionClasses().get(name); + + T instance = (T) EXTENSION_INSTANCES.get(clazz); + if (instance == null) { + // 使用反射调用nesInstance来创建扩展类的一个示例 + EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance()); + instance = (T) EXTENSION_INSTANCES.get(clazz); + } + // 对扩展类示例进行依赖注入 + injectExtension(instance); + // 如果有wrapper,添加wrapper + Set> wrapperClasses = cachedWrapperClasses; + if (wrapperClasses != null && !wrapperClasses.isEmpty()) { + for (Class wrapperClass : wrapperClasses) { + instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); + } + } + return instance; +} +``` +createExtension方法做了以下事情: +1. 先根据name来得到对应的扩展类。从ClassPath下`META-INF`文件夹下读取扩展点配置文件。 +2. 使用反射创建一个扩展类的实例 +3. 对扩展类实例的属性进行依赖注入,即IOC。 +4. 如果有wrapper,添加wrapper。即AOP。 + +下面我们来重点看下这4个过程 +1. 根据name获取对应的扩展类 + 先看代码: + +```java +private Map> getExtensionClasses() { + Map> classes = cachedClasses.get(); + if (classes == null) { + synchronized (cachedClasses) { + classes = cachedClasses.get(); + if (classes == null) { + classes = loadExtensionClasses(); + cachedClasses.set(classes); + } + } + } + return classes; +} + +// synchronized in getExtensionClasses +private Map> loadExtensionClasses() { + final SPI defaultAnnotation = type.getAnnotation(SPI.class); + if (defaultAnnotation != null) { + String value = defaultAnnotation.value(); + if (value != null && (value = value.trim()).length() > 0) { + String[] names = NAME_SEPARATOR.split(value); + if (names.length > 1) { + throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()); + } + if (names.length == 1) cachedDefaultName = names[0]; + } + } + + Map> extensionClasses = new HashMap>(); + loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY); + loadFile(extensionClasses, DUBBO_DIRECTORY); + loadFile(extensionClasses, SERVICES_DIRECTORY); + return extensionClasses; +} +``` +过程很简单,先从缓存中获取,如果没有,就从配置文件中加载。配置文件的路径就是之前提到的: +* `META-INF/dubbo/internal` +* `META-INF/dubbo` +* `META-INF/services` + +2. 使用反射创建扩展实例 + 这个过程很简单,使用`clazz.newInstance()`来完成。创建的扩展实例的属性都是空值。 +3. 扩展实例自动装配 + 在实际的场景中,类之间都是有依赖的。扩展实例中也会引用一些依赖,比如简单的Java类,另一个Dubbo的扩展或一个Spring Bean等。依赖的情况很复杂,Dubbo的处理也相对复杂些。我们稍后会有专门的章节对其进行说明,现在,我们只需要知道,Dubbo可以正确的注入扩展点中的普通依赖,Dubbo扩展依赖或Spring依赖等。 +4. 扩展实例自动包装 + 自动包装就是要实现类似于Spring的AOP功能。Dubbo利用它在内部实现一些通用的功能,比如日志,监控等。关于扩展实例自动包装的内容,也会在后面单独讲解。 + +经过上面的4步,Dubbo就创建并初始化了一个扩展实例。这个实例的依赖被注入了,也根据需要被包装了。到此为止,这个扩展实例就可以被使用了。 + +## Dubbo SPI高级用法之自动装配 +自动装配的相关代码在injectExtension方法中: + +```java +private T injectExtension(T instance) { + for (Method method : instance.getClass().getMethods()) { + if (method.getName().startsWith("set") + && method.getParameterTypes().length == 1 + && Modifier.isPublic(method.getModifiers())) { + Class pt = method.getParameterTypes()[0]; + + String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : ""; + Object object = objectFactory.getExtension(pt, property); + if (object != null) { + method.invoke(instance, object); + } + } + } + return instance; +} +``` +要实现对扩展实例的依赖的自动装配,首先需要知道有哪些依赖,这些依赖的类型是什么。Dubbo的方案是查找Java标准的setter方法。即方法名以set开始,只有一个参数。如果扩展类中有这样的set方法,Dubbo会对其进行依赖注入,类似于Spring的set方法注入。 +但是Dubbo中的依赖注入比Spring要复杂,因为Spring注入的都是Spring bean,都是由Spring容器来管理的。而Dubbo的依赖注入中,需要注入的可能是另一个Dubbo的扩展,也可能是一个Spring Bean,或是Google guice的组件,或其他任何一个框架中的组件。Dubbo需要能够从任何一个场景中加载扩展。在injectExtension方法中,是用`Object object = objectFactory.getExtension(pt, property)`来实现的。objectFactory是ExtensionFactory类型的,在创建ExtensionLoader时被初始化: + +```java +private ExtensionLoader(Class type) { + this.type = type; + objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); + } +``` +objectFacory本身也是一个扩展,通过`ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()`来获取。 + + +![Dubbo-ExtensionFactory](/imgs/blog/dubbo-extensionfactory.png "") + +ExtensionFactory 有三个实现: +1. SpiExtensionFactory:Dubbo自己的Spi去加载Extension +2. SpringExtensionFactory:从Spring容器中去加载Extension +3. AdaptiveExtensionFactory: 自适应的AdaptiveExtensionLoader + +这里要注意 AdaptiveExtensionFactory,源码如下: + +```java +@Adaptive +public class AdaptiveExtensionFactory implements ExtensionFactory { + + private final List factories; + + public AdaptiveExtensionFactory() { + ExtensionLoader loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class); + List list = new ArrayList(); + for (String name : loader.getSupportedExtensions()) { + list.add(loader.getExtension(name)); + } + factories = Collections.unmodifiableList(list); + } + + public T getExtension(Class type, String name) { + for (ExtensionFactory factory : factories) { + T extension = factory.getExtension(type, name); + if (extension != null) { + return extension; + } + } + return null; + } +} +``` +AdaptiveExtensionLoader类有@Adaptive注解。前面提到了,Dubbo会为每一个扩展创建一个自适应实例。如果扩展类上有@Adaptive,会使用该类作为自适应类。如果没有,Dubbo会为我们创建一个。所以`ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()`会返回一个AdaptiveExtensionLoader实例,作为自适应扩展实例。 +AdaptiveExtensionLoader会遍历所有的ExtensionFactory实现,尝试着去加载扩展。如果找到了,返回。如果没有,在下一个ExtensionFactory中继续找。Dubbo内置了两个ExtensionFactory,分别从Dubbo自身的扩展机制和Spring容器中去寻找。由于ExtensionFactory本身也是一个扩展点,我们可以实现自己的ExtensionFactory,让Dubbo的自动装配支持我们自定义的组件。比如,我们在项目中使用了Google的guice这个 IOC 容器。我们可以实现自己的GuiceExtensionFactory,让Dubbo支持从guice容器中加载扩展。 + +## Dubbo SPI高级用法之 AOP +在用Spring的时候,我们经常会用到AOP功能。在目标类的方法前后插入其他逻辑。比如通常使用Spring AOP来实现日志,监控和鉴权等功能。 +Dubbo的扩展机制,是否也支持类似的功能呢?答案是yes。在Dubbo中,有一种特殊的类,被称为Wrapper类。通过装饰者模式,使用包装类包装原始的扩展点实例。在原始扩展点实现前后插入其他逻辑,实现AOP功能。 + +### 什么是Wrapper类 +那什么样类的才是Dubbo扩展机制中的Wrapper类呢?Wrapper类是一个有复制构造函数的类,也是典型的装饰者模式。下面就是一个Wrapper类: + +```java +class A{ + private A a; + public A(A a){ + this.a = a; + } +} +``` +类A有一个构造函数`public A(A a)`,构造函数的参数是A本身。这样的类就可以成为Dubbo扩展机制中的一个Wrapper类。Dubbo中这样的Wrapper类有ProtocolFilterWrapper, ProtocolListenerWrapper等, 大家可以查看源码加深理解。 + +### 怎么配置Wrapper类 + +在Dubbo中Wrapper类也是一个扩展点,和其他的扩展点一样,也是在`META-INF`文件夹中配置的。比如前面举例的ProtocolFilterWrapper和ProtocolListenerWrapper就是在路径`dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol`中配置的: +```text +filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper +listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper +mock=org.apache.dubbo.rpc.support.MockProtocol +``` +在Dubbo加载扩展配置文件时,有一段如下的代码: + +```java +try { + clazz.getConstructor(type); + Set> wrappers = cachedWrapperClasses; + if (wrappers == null) { + cachedWrapperClasses = new ConcurrentHashSet>(); + wrappers = cachedWrapperClasses; + } + wrappers.add(clazz); +} catch (NoSuchMethodException e) {} +``` +这段代码的意思是,如果扩展类有复制构造函数,就把该类存起来,供以后使用。有复制构造函数的类就是Wrapper类。通过`clazz.getConstructor(type)`来获取参数是扩展点接口的构造函数。注意构造函数的参数类型是扩展点接口,而不是扩展类。 +以Protocol为例。配置文件`dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol`中定义了`filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper`。 +ProtocolFilterWrapper代码如下: + +```java +public class ProtocolFilterWrapper implements Protocol { + + private final Protocol protocol; + + // 有一个参数是Protocol的复制构造函数 + public ProtocolFilterWrapper(Protocol protocol) { + if (protocol == null) { + throw new IllegalArgumentException("protocol == null"); + } + this.protocol = protocol; + } +} +``` +ProtocolFilterWrapper有一个构造函数`public ProtocolFilterWrapper(Protocol protocol)`,参数是扩展点Protocol,所以它是一个Dubbo扩展机制中的Wrapper类。ExtensionLoader会把它缓存起来,供以后创建Extension实例的时候,使用这些包装类依次包装原始扩展点。 + +## 扩展点自适应 + +前面讲到过,Dubbo需要在运行时根据方法参数来决定该使用哪个扩展,所以有了扩展点自适应实例。其实是一个扩展点的代理,将扩展的选择从Dubbo启动时,延迟到RPC调用时。Dubbo中每一个扩展点都有一个自适应类,如果没有显式提供,Dubbo会自动为我们创建一个,默认使用Javaassist。 +先来看下创建自适应扩展类的代码: + +```java +public T getAdaptiveExtension() { + Object instance = cachedAdaptiveInstance.get(); + if (instance == null) { + synchronized (cachedAdaptiveInstance) { + instance = cachedAdaptiveInstance.get(); + if (instance == null) { + instance = createAdaptiveExtension(); + cachedAdaptiveInstance.set(instance); + } + } + } + + return (T) instance; +} +``` +继续看createAdaptiveExtension方法 + +```java +private T createAdaptiveExtension() { + return injectExtension((T) getAdaptiveExtensionClass().newInstance()); +} +``` +继续看getAdaptiveExtensionClass方法 + +```java +private Class getAdaptiveExtensionClass() { + getExtensionClasses(); + if (cachedAdaptiveClass != null) { + return cachedAdaptiveClass; + } + return cachedAdaptiveClass = createAdaptiveExtensionClass(); + } +``` +继续看createAdaptiveExtensionClass方法,绕了一大圈,终于来到了具体的实现了。看这个createAdaptiveExtensionClass方法,它首先会生成自适应类的Java源码,然后再将源码编译成Java的字节码,加载到JVM中。 + +```java +private Class createAdaptiveExtensionClass() { + String code = createAdaptiveExtensionClassCode(); + ClassLoader classLoader = findClassLoader(); + org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); + return compiler.compile(code, classLoader); + } +``` +Compiler的代码,默认实现是javassist。 + +```java +@SPI("javassist") +public interface Compiler { + Class compile(String code, ClassLoader classLoader); +} +``` +createAdaptiveExtensionClassCode()方法中使用一个StringBuilder来构建自适应类的Java源码。方法实现比较长,这里就不贴代码了。这种生成字节码的方式也挺有意思的,先生成Java源代码,然后编译,加载到jvm中。通过这种方式,可以更好的控制生成的Java类。而且这样也不用care各个字节码生成框架的api等。因为xxx.java文件是Java通用的,也是我们最熟悉的。只是代码的可读性不强,需要一点一点构建xx.java的内容。 +下面是使用createAdaptiveExtensionClassCode方法为Protocol创建的自适应类的Java代码范例: + +```java +package org.apache.dubbo.rpc; + +import org.apache.dubbo.common.extension.ExtensionLoader; + +public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol { + public void destroy() { + throw new UnsupportedOperationException("method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!"); + } + + public int getDefaultPort() { + throw new UnsupportedOperationException("method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!"); + } + + public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException { + if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null"); + if (arg0.getUrl() == null) + throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null"); + org.apache.dubbo.common.URL url = arg0.getUrl(); + String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); + if (extName == null) + throw new IllegalStateException("Fail to get extension(org.apache.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); + org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName); + return extension.export(arg0); + } + + public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException { + if (arg1 == null) throw new IllegalArgumentException("url == null"); + org.apache.dubbo.common.URL url = arg1; + String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); + if (extName == null) + throw new IllegalStateException("Fail to get extension(org.apache.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); + org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName); + return extension.refer(arg0, arg1); + } +} +``` +大致的逻辑和开始说的一样,通过url解析出参数,解析的逻辑由@Adaptive的value参数控制,然后再根据得到的扩展点名获取扩展点实现,然后进行调用。如果大家想知道具体的构建.java代码的逻辑,可以看`createAdaptiveExtensionClassCode`的完整实现。 +在生成的 Protocol$Adaptive 中,发现getDefaultPort和destroy方法都是直接抛出异常的,这是为什么呢?来看看Protocol的源码 + +```java +@SPI("dubbo") +public interface Protocol { + + int getDefaultPort(); + + @Adaptive + Exporter export(Invoker invoker) throws RpcException; + + @Adaptive + Invoker refer(Class type, URL url) throws RpcException; + + void destroy(); +} +``` +可以看到Protocol接口中有4个方法,但只有export和refer两个方法使用了@Adaptive注解。Dubbo自动生成的自适应实例,只有@Adaptive修饰的方法才有具体的实现。所以,Protocol$Adaptive 类中,也只有export和refer这两个方法有具体的实现,其余方法都是抛出异常。 diff --git a/content/en/blog/java/demos/introduction-to-dubbo-spi.md b/content/en/blog/java/demos/introduction-to-dubbo-spi.md new file mode 100644 index 000000000000..be9d4a6f0af4 --- /dev/null +++ b/content/en/blog/java/demos/introduction-to-dubbo-spi.md @@ -0,0 +1,232 @@ +--- +title: "Dubbo可扩展机制实战" +linkTitle: "Dubbo可扩展机制实战" +tags: ["Java"] +date: 2019-04-25 +description: > + description: 本文介绍了Dubbo框架的核心,SPI扩展机制。 +--- + +## 1. Dubbo的扩展机制 +在Dubbo的官网上,Dubbo描述自己是一个高性能的RPC框架。今天我想聊聊Dubbo的另一个很棒的特性, 就是它的可扩展性。 +如同罗马不是一天建成的,任何系统都一定是从小系统不断发展成为大系统的,想要从一开始就把系统设计的足够完善是不可能的,相反的,我们应该关注当下的需求,然后再不断地对系统进行迭代。在代码层面,要求我们适当的对关注点进行抽象和隔离,在软件不断添加功能和特性时,依然能保持良好的结构和可维护性,同时允许第三方开发者对其功能进行扩展。在某些时候,软件设计者对扩展性的追求甚至超过了性能。 + +在谈到软件设计时,可扩展性一直被谈起,那到底什么才是可扩展性,什么样的框架才算有良好的可扩展性呢?它必须要做到以下两点: +1. 作为框架的维护者,在添加一个新功能时,只需要添加一些新代码,而不用大量的修改现有的代码,即符合开闭原则。 +2. 作为框架的使用者,在添加一个新功能时,不需要去修改框架的源码,在自己的工程中添加代码即可。 + +Dubbo很好的做到了上面两点。这要得益于Dubbo的微内核+插件的机制。接下来的章节中我们会慢慢揭开Dubbo扩展机制的神秘面纱。 + +## 2. 可扩展的几种解决方案 +通常可扩展的实现有下面几种: +* Factory模式 +* IoC容器 +* OSGI容器 + +Dubbo作为一个框架,不希望强依赖其他的IoC容器,比如Spring,Guice。OSGI也是一个很重的实现,不适合Dubbo。最终Dubbo的实现参考了Java原生的SPI机制,但对其进行了一些扩展,以满足Dubbo的需求。 + +## 3. Java SPI机制 +既然Dubbo的扩展机制是基于Java原生的SPI机制,那么我们就先来了解下Java SPI吧。了解了Java的SPI,也就是对Dubbo的扩展机制有一个基本的了解。如果对Java SPI比较了解的同学,可以跳过。 + +Java SPI(Service Provider Interface)是JDK内置的一种动态加载扩展点的实现。在ClassPath的`META-INF/services`目录下放置一个与接口同名的文本文件,文件的内容为接口的实现类,多个实现类用换行符分隔。JDK中使用`java.util.ServiceLoader`来加载具体的实现。 +让我们通过一个简单的例子,来看看Java SPI是如何工作的。 + +1. 定义一个接口IRepository用于实现数据储存 +```java +public interface IRepository { + void save(String data); +} +``` + +2. 提供IRepository的实现 + IRepository有两个实现。MysqlRepository和MongoRepository。 + +```java +public class MysqlRepository implements IRepository { + public void save(String data) { + System.out.println("Save " + data + " to Mysql"); + } +} +``` + +```java +public class MongoRepository implements IRepository { + public void save(String data) { + System.out.println("Save " + data + " to Mongo"); + } +} +``` + +3. 添加配置文件 + 在`META-INF/services`目录添加一个文件,文件名和接口全名称相同,所以文件是`META-INF/services/com.demo.IRepository`。文件内容为: + +```text +com.demo.MongoRepository +com.demo.MysqlRepository +``` + +4. 通过ServiceLoader加载IRepository实现 + +```java +ServiceLoader serviceLoader = ServiceLoader.load(IRepository.class); +Iterator it = serviceLoader.iterator(); +while (it != null && it.hasNext()){ + IRepository demoService = it.next(); + System.out.println("class:" + demoService.getClass().getName()); + demoService.save("tom"); +} +``` +在上面的例子中,我们定义了一个扩展点和它的两个实现。在ClassPath中添加了扩展的配置文件,最后使用ServiceLoader来加载所有的扩展点。 +最终的输出结果为: +class:testDubbo.MongoRepository +Save tom to Mongo +class:testDubbo.MysqlRepository +Save tom to Mysql + +## 4. Dubbo的SPI机制 + +Java SPI的使用很简单。也做到了基本的加载扩展点的功能。但Java SPI有以下的不足: +* 需要遍历所有的实现,并实例化,然后我们在循环中才能找到我们需要的实现。 +* 配置文件中只是简单的列出了所有的扩展实现,而没有给他们命名。导致在程序中很难去准确的引用它们。 +* 扩展如果依赖其他的扩展,做不到自动注入和装配 +* 不提供类似于Spring的IOC和AOP功能 +* 扩展很难和其他的框架集成,比如扩展里面依赖了一个Spring bean,原生的Java SPI不支持 + +所以Java SPI应付一些简单的场景是可以的,但对于Dubbo,它的功能还是比较弱的。Dubbo对原生SPI机制进行了一些扩展。接下来,我们就更深入地了解下Dubbo的SPI机制。 + +## 5. Dubbo扩展点机制基本概念 +在深入学习Dubbo的扩展机制之前,我们先明确Dubbo SPI中的一些基本概念。在接下来的内容中,我们会多次用到这些术语。 + +### 5.1 扩展点(Extension Point) +是一个Java的接口。 + +### 5.2 扩展(Extension) +扩展点的实现类。 + +### 5.3 扩展实例(Extension Instance) +扩展点实现类的实例。 + +### 5.4 扩展自适应实例(Extension Adaptive Instance) +第一次接触这个概念时,可能不太好理解(我第一次也是这样的...)。如果称它为扩展代理类,可能更好理解些。扩展的自适应实例其实就是一个Extension的代理,它实现了扩展点接口。在调用扩展点的接口方法时,会根据实际的参数来决定要使用哪个扩展。比如一个IRepository的扩展点,有一个save方法。有两个实现MysqlRepository和MongoRepository。IRepository的自适应实例在调用接口方法的时候,会根据save方法中的参数,来决定要调用哪个IRepository的实现。如果方法参数中有repository=mysql,那么就调用MysqlRepository的save方法。如果repository=mongo,就调用MongoRepository的save方法。和面向对象的延迟绑定很类似。为什么Dubbo会引入扩展自适应实例的概念呢? +* Dubbo中的配置有两种,一种是固定的系统级别的配置,在Dubbo启动之后就不会再改了。还有一种是运行时的配置,可能对于每一次的RPC,这些配置都不同。比如在xml文件中配置了超时时间是10秒钟,这个配置在Dubbo启动之后,就不会改变了。但针对某一次的RPC调用,可以设置它的超时时间是30秒钟,以覆盖系统级别的配置。对于Dubbo而言,每一次的RPC调用的参数都是未知的。只有在运行时,根据这些参数才能做出正确的决定。 +* 很多时候,我们的类都是一个单例的,比如Spring的bean,在Spring bean都实例化时,如果它依赖某个扩展点,但是在bean实例化时,是不知道究竟该使用哪个具体的扩展实现的。这时候就需要一个代理模式了,它实现了扩展点接口,方法内部可以根据运行时参数,动态的选择合适的扩展实现。而这个代理就是自适应实例。 + 自适应扩展实例在Dubbo中的使用非常广泛,Dubbo中,每一个扩展都会有一个自适应类,如果我们没有提供,Dubbo会使用字节码工具为我们自动生成一个。所以我们基本感觉不到自适应类的存在。后面会有例子说明自适应类是怎么工作的。 + +### 5.5 @SPI +@SPI注解作用于扩展点的接口上,表明该接口是一个扩展点。可以被Dubbo的ExtensionLoader加载。如果没有此ExtensionLoader调用会异常。 + +### 5.6 @Adaptive +@Adaptive注解用在扩展接口的方法上。表示该方法是一个自适应方法。Dubbo在为扩展点生成自适应实例时,如果方法有@Adaptive注解,会为该方法生成对应的代码。方法内部会根据方法的参数,来决定使用哪个扩展。 +@Adaptive注解用在类上代表实现一个装饰类,类似于设计模式中的装饰模式,它主要作用是返回指定类,目前在整个系统中AdaptiveCompiler、AdaptiveExtensionFactory这两个类拥有该注解。 + + +### 5.7 ExtensionLoader +类似于Java SPI的ServiceLoader,负责扩展的加载和生命周期维护。 + +### 5.8 扩展别名 +和Java SPI不同,Dubbo中的扩展都有一个别名,用于在应用中引用它们。比如 + +```bash +random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance +roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance +``` +其中的random,roundrobin就是对应扩展的别名。这样我们在配置文件中使用random或roundrobin就可以了。 + +### 5.9 一些路径 +和Java SPI从`/META-INF/services`目录加载扩展配置类似,Dubbo也会从以下路径去加载扩展配置文件: +* `META-INF/dubbo/internal` +* `META-INF/dubbo` +* `META-INF/services` + +## 6. Dubbo的LoadBalance扩展点解读 +在了解了Dubbo的一些基本概念后,让我们一起来看一个Dubbo中实际的扩展点,对这些概念有一个更直观的认识。 + +我们选择的是Dubbo中的LoadBalance扩展点。Dubbo中的一个服务,通常有多个Provider,consumer调用服务时,需要在多个Provider中选择一个。这就是一个LoadBalance。我们一起来看看在Dubbo中,LoadBalance是如何成为一个扩展点的。 + +### 6.1 LoadBalance接口 + +```java +@SPI(RandomLoadBalance.NAME) +public interface LoadBalance { + + @Adaptive("loadbalance") + Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException; +} +``` +LoadBalance接口只有一个select方法。select方法从多个invoker中选择其中一个。上面代码中和Dubbo SPI相关的元素有: +* @SPI(RandomLoadBalance.NAME) + @SPI作用于LoadBalance接口,表示接口LoadBalance是一个扩展点。如果没有@SPI注解,试图去加载扩展时,会抛出异常。@SPI注解有一个参数,该参数表示该扩展点的默认实现的别名。如果没有显示的指定扩展,就使用默认实现。`RandomLoadBalance.NAME`是一个常量,值是"random",是一个随机负载均衡的实现。 + random的定义在配置文件`META-INF/dubbo/internal/com.alibaba.dubbo.rpc.cluster.LoadBalance`中: + +```bash +random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance +roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance +leastactive=com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance +consistenthash=com.alibaba.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance +``` +可以看到文件中定义了4个LoadBalance的扩展实现。由于负载均衡的实现不是本次的内容,这里就不过多说明。只用知道Dubbo提供了4种负载均衡的实现,我们可以通过xml文件,properties文件,JVM参数显式的指定一个实现。如果没有,默认使用随机。 + + +![img](/imgs/blog/dubbo_loadbalance.png) + +* @Adaptive("loadbalance") + @Adaptive注解修饰select方法,表明方法select方法是一个可自适应的方法。Dubbo会自动生成该方法对应的代码。当调用select方法时,会根据具体的方法参数来决定调用哪个扩展实现的select方法。@Adaptive注解的参数`loadbalance`表示方法参数中的loadbalance的值作为实际要调用的扩展实例。 + 但奇怪的是,我们发现select的方法中并没有loadbalance参数,那怎么获取loadbalance的值呢?select方法中还有一个URL类型的参数,Dubbo就是从URL中获取loadbalance的值的。这里涉及到Dubbo的URL总线模式,简单说,URL中包含了RPC调用中的所有参数。URL类中有一个`Map parameters`字段,parameters中就包含了loadbalance。 + +### 6.2 获取LoadBalance扩展 +Dubbo中获取LoadBalance的代码如下: + +```java +LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName); +``` +使用ExtensionLoader.getExtensionLoader(LoadBalance.class)方法获取一个ExtensionLoader的实例,然后调用getExtension,传入一个扩展的别名来获取对应的扩展实例。 + +## 7. 自定义一个LoadBalance扩展 +本节中,我们通过一个简单的例子,来自己实现一个LoadBalance,并把它集成到Dubbo中。我会列出一些关键的步骤和代码,也可以从这个地址([https://github.com/vangoleo/dubbo-spi-demo](https://github.com/vangoleo/dubbo-spi-demo))下载完整的demo。 + +### 7.1 实现LoadBalance接口 +首先,编写一个自己实现的LoadBalance,因为是为了演示Dubbo的扩展机制,而不是LoadBalance的实现,所以这里LoadBalance的实现非常简单,选择第一个invoker,并在控制台输出一条日志。 + +```java +package com.dubbo.spi.demo.consumer; +public class DemoLoadBalance implements LoadBalance { + @Override + public Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException { + System.out.println("DemoLoadBalance: Select the first invoker..."); + return invokers.get(0); + } +} +``` + +### 7.2 添加扩展配置文件 +添加文件:`META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.LoadBalance`。文件内容如下: + +```bash +demo=com.dubbo.spi.demo.consumer.DemoLoadBalance +``` + +### 7.3 配置使用自定义LoadBalance +通过上面的两步,已经添加了一个名字为demo的LoadBalance实现,并在配置文件中进行了相应的配置。接下来,需要显式的告诉Dubbo使用demo的负载均衡实现。如果是通过spring的方式使用Dubbo,可以在xml文件中进行设置。 + +```xml + +``` +在consumer端的[dubbo:reference](dubbo:reference)中配置 + +### 7.4 启动Dubbo +启动Dubbo,调用一次IHelloService,可以看到控制台会输出一条`DemoLoadBalance: Select the first invoker...`日志。说明Dubbo的确是使用了我们自定义的LoadBalance。 + + +## 总结 +到此,我们从Java SPI开始,了解了Dubbo SPI 的基本概念,并结合了Dubbo中的LoadBalance加深了理解。最后,我们还实践了一下,创建了一个自定义LoadBalance,并集成到Dubbo中。相信通过这里理论和实践的结合,大家对Dubbo的可扩展有更深入的理解。 +总结一下,Dubbo SPI有以下的特点: +* 对Dubbo进行扩展,不需要改动Dubbo的源码 +* 自定义的Dubbo的扩展点实现,是一个普通的Java类,Dubbo没有引入任何Dubbo特有的元素,对代码侵入性几乎为零。 +* 将扩展注册到Dubbo中,只需要在ClassPath中添加配置文件。使用简单。而且不会对现有代码造成影响。符合开闭原则。 +* dubbo的扩展机制设计默认值:@SPI("dubbo") 代表默认的spi对象 +* Dubbo的扩展机制支持IoC,AoP等高级功能 +* Dubbo的扩展机制能很好的支持第三方IoC容器,默认支持Spring Bean,可自己扩展来支持其他容器,比如Google的Guice。 +* 切换扩展点的实现,只需要在配置文件中修改具体的实现,不需要改代码。使用方便。 + + +下一篇,我们将会一起深入Dubbo的源码,更深入的了解Dubbo的可扩展机制。 diff --git a/content/en/blog/java/demos/multiple-protocols-registries.md b/content/en/blog/java/demos/multiple-protocols-registries.md new file mode 100644 index 000000000000..399d8aa6af15 --- /dev/null +++ b/content/en/blog/java/demos/multiple-protocols-registries.md @@ -0,0 +1,295 @@ +--- +title: "Dubbo 连接异构微服务体系 - 多协议&多注册中心" +linkTitle: "Dubbo 连接异构微服务体系 - 多协议&多注册中心" +tags: ["Java"] +date: 2023-01-05 +description: > + 本文介绍了 Dubbo 的多协议、多注册中心支持方案,以及如何用它们实现多协议共存、多协议互通、多协议迁移等能力。 +--- + +从编程开发的角度来说,Dubbo 首先是一款 RPC 服务框架,它最大的优势在于提供了面向接口代理的服务编程模型,对开发者屏蔽了底层的远程通信细节。同时 Dubbo 也是一款服务治理框架,它为分布式部署的微服务提供了服务发现、流量调度等服务治理解决方案。 + +在这篇文章中,我们将以以上基础能力为背景,尝试突破 Dubbo 体系自身,探索如何利用 Dubbo 对多协议、多服务发现模型的支持,来实现异构微服务体系间的互联互通。在实际业务场景中,这可以用来解决异构技术体系共存场景下的通信问题,帮助公司实现在异构技术体系间作平滑迁移,解决大规模跨区域、多集群部署场景的地址发现及流量调度等问题。 + +## 面向接口代理的透明服务开发框架 + +我们还是从 **Dubbo 是一个微服务开发框架** 这个大家熟知的概念开始。就像 Spring 是开发 Java 应用的基础框架一样,我们经常会选用 Dubbo 作为开发微服务业的基础框架。 Dubbo 框架的最大优势我认为就在其面向接口的编程模型,使得开发远程服务调用就像开发本地服务一样(以 Java 语言为例): + +1. 服务定义 + +```java +public interface GreetingsService { + String sayHi(String name); +} +``` + +2. 消费方调用服务 + +```java +// 和调用本地服务一样,完全透明。 +@Reference +private GreetingService greetingService; + +public void doSayHello(String name) { + greetingService.sayHi("Hello world!"); +} +``` + +下图是 Dubbo 的基本工作原理图,服务提供者与服务消费者之间通过注册中心协调地址,通过约定的协议实现数据交换。 + +![Dubbo basic work flow](/imgs/blog/2023/01/protocols/img.png) + + +## 同构/异构微服务体系面临的问题 + +关于 Dubbo 协议本身及其服务治理相关功能细节并不是本文的重点,我们今天将从一个更高的层次,来看看公司内部构建微服务体系所面的挑战,以及 Dubbo 能为架构选型和迁移等提供哪些解决思路。 + +一个公司内部的微服务可能都是基于某一个相同的服务框架开发的,比如说 Dubbo,对于这样的架构,我们称之为是**同构的微服务体系**;而有些公司的微服务可能是使用多个不同的服务框架所建设,我们称之为**异构的微服务体系**,多个不同技术栈微服务体系的共存在大型组织内还是非常普遍的,造成这种局面可能有很多原因。比如,可能是遗留系统带来的,也可能是公司正在做技术栈迁移,或者就是不同业务部门为了满足各自特殊需求而做的独立选型(这也意味着异构微服务体系的长期共存)。 + +**1. 异构微服务体系共存** + +我们很容易想到的一个挑战是:**不同的体系间通常是使用不同的 RPC 通信协议、部署独立的注册中心集群,面对这种多协议、多注册中心集群的场景,要如何实现相互之间透明的地址发现和透明的 RPC 调用?**如果我们什么都不做,那么每个微服务体系就只能感知到自己体系内的服务状态,流量也在各自的体系内封闭。而要做到从体系 A 平滑的迁移到体系 B,或者想长期的保持公司内部多个体系的共存,则解决不同体系间的互联互通,实现流量的透明调度将是非常重要的环节。 + +![2](/imgs/blog/2023/01/protocols/img_1.png) + + +**2. Dubbo 体系内部** + +**多协议、多注册中心集群的问题在同构的微服务体系中也可能存在,尤其是当一个组织内部的微服务规模增长到一定量级的时候。** + +* 我们可能要在不同的服务之间采用不同的通信协议,因为不同的服务面临不同的业务场景,而这也进一步导致了数据传输特点的不同,我们需要分别采用更适合各类业务特点的协议。比如典型的场景:我们可能对于普通的业务服务采用 Dubbo 协议,对于和 FrontEnd 交互的服务需要 HTTP 协议,而对于需要流式数据传输的业务则采用 gRPC 协议等等。 + +* Dubbo 体系内部另一个常出现的问题是,在大规模分布式部署的场景下,微服务系统会做跨区域、跨注册中心的部署,这个时候就会出现多集群间地址同步和流量调度的问题。 + +总结起来,**不论是同构体系还是异构体系,都面临对多协议通信、多注册中心集群地址发现的问题。** Dubbo 目前是支持多协议、多注册中心的,可以说就是为解决我们上面分析的 Dubbo 同构体系内的场景而设计的,因此下面我们从同构体系的多协议、多注册中心场景讲起,先了解 Dubbo 多协议、多注册中心的基本支持情况以及它们是如何工作的。而在后面的一章再进一步探索怎么扩展这个能力来支持异构微服务体系的互联互通。 + +## Dubbo 体系内的多协议、多注册中心机制 + +我们将通过两个场景示例,来分别具体的讲一下 Dubbo 的多协议、多注册中心机制的使用方式和工作原理。 + +### 多协议 + +![undefined](/imgs/blog/2023/01/protocols/img_2.png) + +以上是使用 Dubbo 开发的一套微服务,服务间通信使用到了不同的协议,根据我们的调研发现,公司内部启用多协议其实是非常普遍需求,具体场景在此我们暂不做解释。 + +应用 B 作为服务提供者,发布了 5 个服务,其中: + +* `DemoService1` `DemoService2` 通过 `dubbo` 协议发布 +* `DemoService3` `DemoService4` 通过 `gRPC` 协议发布 +* `DemoService0` 通过 `dubbo` 、`gRPC` 双协议发布 + +应用 A 作为消费者,使用 dubbo 协议消费 `DemoService1` `DemoService2`,使用 gRPC 协议消费 `DemoService0`。 + +应用 B 作为消费者,使用 gRPC 协议消费 `DemoService2` `DemoService4`,使用 dubbo 协议消费 `DemoService0`。 + +以下是具体的代码配置: + +1. 提供端应用 B + +```xml + + + + + + + +``` + +2. 消费端应用 A + +```xml + + + + +``` + +3. 消费端应用 C + +```xml + + + + +``` + +#### Dubbo 多协议支持现状 + +Dubbo 目前所支持的协议包括 Dubbo、REST、Thrift、gRPC、JsonRPC、Hessian 等,基本涵盖了业界大多数主流的 RPC 通信协议。需要注意的是,这些协议的支持都是以直接集成官方 Release 实现的形式来做的,我认为这是一个很好的选择,既保证了协议解析自身的稳定性,又能使 Dubbo 社区更专注的将更多的精力放在 Dubbo 外围服务治理能力的改善上。试想如果 Dubbo 社区自己为每个协议提供实现,那是要花费多少精力和时间才能使每种协议达到稳定的生产可用。 + +除了以上官方提供支持的协议之外,得益于 Dubbo 灵活的扩展机制,想要为 Dubbo 扩展协议非常容易,开发者可以随时为 Dubbo 增加更多的协议支持,包括自有协议扩展。 + +关于对 gRPC (HTTP/2) 协议的支持,请参阅上期文档 + +![3](/imgs/blog/2023/01/protocols/img_3.png) + +#### 多协议能解决的问题 + +* 将 RPC 框架无缝地接入 Dubbo 的服务治理体系。 + + 通过协议扩展将 RPC 协议纳入 Dubbo 服务开发体系,从而复用 Dubbo 的编程模型和服务发现、流量管控等能力。比如 gRPC,其服务治理体系相对比较弱、编程 API 不够友好,很难直接用于微服务开发。 + +* 满足不同场景的调用需求。 + + 各个服务可能是为了满足不同业务需求而开发,同时外围消费端应用的技术栈也可能多种多样,通过启用不同的通信协议,可以最优化不同场景的通信需求。 + +* 实现协议间的迁移。 + + 通过支持多种协议,借助注册中心的协调,可以快速满足公司内协议迁移的需求。如从自有协议升级到 Dubbo 协议,Dubbo 协议自身升级,从 Dubbo 协议迁移到 gRPC,从 REST 迁移到 Dubbo 协议等。 + + +### 多注册中心 + +当服务集群规模小的时候,一个中心化的集群部署方案能很好的解决我们的业务问题。但是随着应用规模的增长、用户流量的增加,我们就不得不考虑要为业务系统引入跨区域、多集群的部署方案,而此时同业务系统密切相关的注册中心集群也面临部署方案的选型: + +1. 继续维持全局共享的注册中心集群。这种架构方案的优点是简单;缺点是注册中心集群由于要保存全量的地址数据,存储和推送压力会变得很大,另外对于一些注册中心产品(如 Zookeeper 等)在跨集群网络部署的场景下稳定性和性能可能都会面临挑战。 + +2. 每个业务集群部署独立的注册中心集群。多注册中心集群的优点是能解决跨集群网络可用性的问题,同时也能够减轻注册中心的存储和推送压力;缺点则是要求服务框架(如 Dubbo 等)能有同时发布/监听多个注册中心集群的能力。 + +下面我们具体看一下,Dubbo 为多注册中心集群场景提供的解决方案。 + +![4](/imgs/blog/2023/01/protocols/img_4.png) + +上图有两个业务集群,分别部署在北京和上海,每个业务集群有自己独立的注册中心集群,要解决两个业务集群间服务的透明 RPC 通信问题。 + +1. 服务提供端,双注册中心发布 + +```xml + + + + + +``` + +2. 服务消费端,根据消费需求做单/双注册中心订阅 + +```xml + + + + + + + + + + +``` + +#### Dubbo 对异构注册中心集群的支持 + +虽然我们会做多注册中心集群部署,但通常情况下,我们部署的都是相同的注册中心产品,如都是 Zookeeper、Nacos;而对于注册中心迁移的场景,则要求 Dubbo 能提供对更多的注册中心产品的支持,或者最重要的要有很好的扩展能力。Dubbo 官方目前支持的注册中心实现有: + +![5](/imgs/blog/2023/01/protocols/img_5.png) + +这里需要特别提到的一点是,当前 Dubbo 的服务注册/发现模型是以接口为粒度的,而从 2.7.5 版本开始,Dubbo 新引入了应用粒度的服务注册/发现模型。这一方面有助于优化 Dubbo 当前服务发现机制、提升服务容量,另一方面对于联通以 SpringCloud 为代表的微服务体系也非常重要(关于这点在下一章中有进一步提及)。更多关于《应用粒度服务发现:服务自省》的介绍,我们将在接下来的文章或文档中予以补充,请持续关注。 + +#### 多订阅带来的流量调度问题 + +在引入多注册中心集群后,Dubbo 在流量选址时的多了一层注册中心集群间的负载均衡: + +![6](/imgs/blog/2023/01/protocols/img_6.png) + +在 Cluster Invoker 这一级,我们支持的选址策略有(2.7.5+ 版本,具体使用请参见文档): + +* 指定优先级 + + ```xml + + + ``` + +* 同 zone 优先 + + ```xml + + + ``` + +* 权重轮询 + + ```xml + + + + ``` + +* 默认,stick to 任意可用 + +#### 多注册中心适用的场景 + +* 同区域流量优先调度 + + 出于容灾或者服务伸缩性需求,服务/应用往往需要部署在多个独立的机房/区域,在每个区域有独立注册中心集群的场景下,实现同区域的流量优先调度就能很好的解决延迟和可用性问题。 + +* 注册中心迁移 + + 公司的服务一直以来可能是存储在某一个注册中心,如 Zookeeper,但到了某个时间节点,因为各种各样的原因,当我们要迁移到另外的注册中心时,多注册中心模型能够保证平滑的迁移。 + +* 异构系统互通 + + 不同微服务体系开发的服务,都封闭在各自的服务发现体系中,而通过统一的多注册中心模型,可以实现不同体系的服务互相发现。 + +## 借助 Dubbo 联通异构的微服务体系 + +上文我们提到了在组织内存在异构微服务体系的各种合理可能性,现在我们来具体看一下异构微服务体系的实际场景,以及使用 Dubbo 实现互联互通的解决方法。首先我们先通过一张图来看一下,联通异构的微服务体系具体是一个什么样的场景。 + +![7](/imgs/blog/2023/01/protocols/img_7.png) + +如上图所示,我们有部分微服务可以是基于 SpringCloud、gRPC、K8S 或者是自建体系构建的,他们各自之间默认是相互隔离无法联通的。当我们再构建一套基于 Dubbo 的微服务体系时,则利用 Dubbo 的多协议、多服务发现模型,我们就可以做到和各个微服务体系间的两两之间的互联互通。进一步的,如图中橙色箭头所示,依赖 Dubbo 体系作为桥接层,我们还可以实现两个异构微服务体系间的打通。 + +对于以下几个示例场景,由于在地址发现层面目前没有统一的标准,我们暂且假设地址发现层面不同的体系建是没有障碍的,我们将重点关注迁移的基本流程以及通信协议环节。(关于地址发现部分,我们将在后续《服务自省:基于应用粒度的服务发现》之后再深入探讨) + +### Dubbo 体系内的协议迁移(共存) + +绝大多数开发者对 Dubbo 有这么一个固有认知:使用 Dubbo 开发微服务系统,则就要用 Dubbo 协议来作为服务间的通信协议才是最优方案。实际上,我们完全没有必要只束缚在 Dubbo RPC 协议上。Dubbo 作为微服务开发框架和 Dubbo 作为 RPC 协议这是两个概念,其实是完全可以分开来看待的,比如我们用 Dubbo 框架开发的业务系统,选用 rest、gRPC 通信是完全没有问题的(参加 Dubbo 支持的协议列表),具体用什么协议根据业务特点和技术规划才是最适合的。 + +![8](/imgs/blog/2023/01/protocols/img_8.png) + +当前在云原生、Mesh 的大背景下, HTTP1/2、gRPC 协议开始受到越来越多的关注,一方面原因自然是因为它们在标准化方面做的更好,得到的更多的网络设备和基础设施的支持,具备更好的通用性和穿透性。对于很多有云原生迁移意愿的企业来说,往此类协议迁移无疑将对之后的架构升级有更多的帮助。 + +下图演示了在 Dubbo 体系内,从 Dubbo 协议向 gRPC 协议迁移的一个中间状态。 + +![9](/imgs/blog/2023/01/protocols/img_9.png) + +* 最左边的代表尚未迁移的老应用,这类应用在迁移过程中仍然要消费和提供 Dubbo 协议的服务。 +* 中间的代表处于迁移中的应用,他们中间可能有些是服务提供者,既要为左边的老系统提供提供 Dubbo 协议服务;又要为右边的新系统提供 gRPC 服务;因此他们都是双协议暴露服务。 +* 最右边则代表是新开发的或者已经迁移完成的应用,这个体系内已能完全用 gRPC 协议通信。 +* 最终度过中间态后,我们期望所有的应用都达到最左边应用的状态,实现完全的 gRPC 协议通信。 + +### Spring Cloud 体系迁移到 Dubbo 体系(共存) + +如前文所述,由于 SpringCloud 和 Dubbo 间服务发现模型的问题,要两个体系间的地址互通需要 Dubbo 侧作相应的适配,关于这部分内容将在接下来的 2.7.5 版本《服务自省》部分发布,在此我们暂且认为已经打通。 + +![10](/imgs/blog/2023/01/protocols/img_10.png) + +Dubbo 体系内的部分应用作为透明的联通两个体系的关键节点,部分服务提供者应用要双协议发布、部分消费者应用要做到选定协议消费。由于老的 Spring Cloud 体系不允许做任何改动,因此联通两套体系的关键是 REST 协议,对 Dubbo 侧的应用来说: + +* 部分应用可能要以 REST 协议消费 SpringCloud 的服务; +* 部分应用可能要暴露 REST 协议共 SpringCloud 消费; +* Dubbo 自有体系内则通过自己选定的协议通信,这里就比较灵活了,可以是 Dubbo、REST、gRPC 等其中的任一种。而如果选定 REST 协议则对于与 SpringCloud 体系的联通就变得更加自然了,因为两端的协议都是统一的。 + +对于消费 Spring Cloud 服务的应用,要配置服务 : + +```xml + +``` + +对于提供服务给 Spring Cloud 侧消费的应用,则指定服务暴露为 rest 协议,或者双协议暴露(因如果这个服务还要被新体系内的应用调用到): + +```xml + +``` + +作为 Dubbo 的维护者,虽然我们这里有明显的偏向性,讲的是从如何从 SpringCloud 体系迁移到 Dubbo 体系。但是反过来考虑,如果你已经或者即将选型 Dubbo 来开发微服务,则未来从 Dubbo 迁移到 SpringCloud 也是同样的思路,Dubbo 的多协议、多注册模型为双向迁移都提供了同样的灵活性。 + +### 自建体系迁移到 Dubbo 体系(共存) + +这个场景和上一节中讲到的的 SpringCloud 迁移有些类似,最大的区别在于 rest 协议是 Dubbo 官方默认提供支持的,而对于已有的微服务体系内的私有通信协议,则需要先要自己去扩展 Dubbo Protocol 来提供协议层面的支持。 + +## 总结与展望 + +要实现异构微服务体系间的共存或迁移,关键点在打通异构体系间的`协议`与`服务发现`,得益于 Dubbo 自身对多协议、多注册模型的支持,我们可以很容易的使 Dubbo 成为桥接异构微服务体系的中间层。熟悉 Dubbo 多协议实现细节的同学,可能会担心在服务数量较多的场景下,多协议注册会导致地址数量翻倍从而影响地址推送性能;另外在文中《借助 Dubbo 联通异构的微服务体系》一节,关于如何实现异构体系间的透明服务发现部分我们没有做详细的说明。关于涉及服务发现的这部分,我们将在接下来的文章中做具体阐述,看看 Dubbo 2.7.5 版本引入新的服务发现机制是如何解决这个问题的,请持续关注后续文章及 Dubbo 官方文档。 diff --git a/content/en/blog/java/demos/optimization-branch-prediction.md b/content/en/blog/java/demos/optimization-branch-prediction.md new file mode 100644 index 000000000000..f7e874e2b055 --- /dev/null +++ b/content/en/blog/java/demos/optimization-branch-prediction.md @@ -0,0 +1,143 @@ +--- +title: "提前if判断帮助CPU分支预测" +linkTitle: "提前if判断帮助CPU分支预测" +tags: ["Java"] +date: 2019-02-03 +description: > + 本文介绍了通过提前if判断帮助CPU分支预测的优化技巧 +--- + +## 分支预测 + +在stackoverflow上有一个非常有名的问题:[为什么处理有序数组要比非有序数组快?]( +https://stackoverflow.com/questions/11227809/why-is-it-faster-to-process-a-sorted-array-than-an-unsorted-array),可见分支预测对代码运行效率有非常大的影响。 + +现代CPU都支持分支预测(branch prediction)和指令流水线(instruction pipeline),这两个结合可以极大提高CPU效率。对于像简单的if跳转,CPU是可以比较好地做分支预测的。但是对于switch跳转,CPU则没有太多的办法。switch本质上是据索引,从地址数组里取地址再跳转。 + +要提高代码执行效率,一个重要的原则就是尽量避免CPU把流水线清空,那么提高分支预测的成功率就非常重要。 + +那么对于代码里,如果某个switch分支概率很高,是否可以考虑代码层面帮CPU把判断提前,来提高代码执行效率呢? + +## Dubbo里ChannelEventRunnable的switch判断 + +在`ChannelEventRunnable`里有一个switch来判断channel state,然后做对应的逻辑:[查看]( +https://github.com/hengyunabc/dubbo/blob/dubbo-2.6.1/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/dispatcher/ChannelEventRunnable.java#L54) + +一个channel建立起来之后,超过99.9%情况它的state都是`ChannelState.RECEIVED`,那么可以考虑把这个判断提前。 + +## benchmark验证 + +下面通过jmh来验证下: + +```java +public class TestBenchMarks { + public enum ChannelState { + CONNECTED, DISCONNECTED, SENT, RECEIVED, CAUGHT + } + + @State(Scope.Benchmark) + public static class ExecutionPlan { + @Param({ "1000000" }) + public int size; + public ChannelState[] states = null; + + @Setup + public void setUp() { + ChannelState[] values = ChannelState.values(); + states = new ChannelState[size]; + Random random = new Random(new Date().getTime()); + for (int i = 0; i < size; i++) { + int nextInt = random.nextInt(1000000); + if (nextInt > 100) { + states[i] = ChannelState.RECEIVED; + } else { + states[i] = values[nextInt % values.length]; + } + } + } + } + + @Fork(value = 5) + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void benchSiwtch(ExecutionPlan plan, Blackhole bh) { + int result = 0; + for (int i = 0; i < plan.size; ++i) { + switch (plan.states[i]) { + case CONNECTED: + result += ChannelState.CONNECTED.ordinal(); + break; + case DISCONNECTED: + result += ChannelState.DISCONNECTED.ordinal(); + break; + case SENT: + result += ChannelState.SENT.ordinal(); + break; + case RECEIVED: + result += ChannelState.RECEIVED.ordinal(); + break; + case CAUGHT: + result += ChannelState.CAUGHT.ordinal(); + break; + } + } + bh.consume(result); + } + + @Fork(value = 5) + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void benchIfAndSwitch(ExecutionPlan plan, Blackhole bh) { + int result = 0; + for (int i = 0; i < plan.size; ++i) { + ChannelState state = plan.states[i]; + if (state == ChannelState.RECEIVED) { + result += ChannelState.RECEIVED.ordinal(); + } else { + switch (state) { + case CONNECTED: + result += ChannelState.CONNECTED.ordinal(); + break; + case SENT: + result += ChannelState.SENT.ordinal(); + break; + case DISCONNECTED: + result += ChannelState.DISCONNECTED.ordinal(); + break; + case CAUGHT: + result += ChannelState.CAUGHT.ordinal(); + break; + } + } + } + bh.consume(result); + } +} +``` +* benchSiwtch里是纯switch判断 +* benchIfAndSwitch 里用一个if提前判断state是否`ChannelState.RECEIVED` + +benchmark结果是: + +``` +Result "io.github.hengyunabc.jmh.TestBenchMarks.benchSiwtch": + 576.745 ±(99.9%) 6.806 ops/s [Average] + (min, avg, max) = (490.348, 576.745, 618.360), stdev = 20.066 + CI (99.9%): [569.939, 583.550] (assumes normal distribution) + + +# Run complete. Total time: 00:06:48 + +Benchmark (size) Mode Cnt Score Error Units +TestBenchMarks.benchIfAndSwitch 1000000 thrpt 100 1535.867 ± 61.212 ops/s +TestBenchMarks.benchSiwtch 1000000 thrpt 100 576.745 ± 6.806 ops/s +``` + +可以看到提前if判断的确提高了代码效率,这种技巧可以放在性能要求严格的地方。 + +Benchmark代码:https://github.com/hengyunabc/jmh-demo + +## 总结 + +* switch对于CPU来说难以做分支预测 +* 某些switch条件如果概率比较高,可以考虑单独提前if判断,充分利用CPU的分支预测机制 diff --git a/content/en/blog/java/demos/proxyless-guide.md b/content/en/blog/java/demos/proxyless-guide.md new file mode 100644 index 000000000000..261fe50534b8 --- /dev/null +++ b/content/en/blog/java/demos/proxyless-guide.md @@ -0,0 +1,509 @@ +--- +title: "Proxyless Mesh在Dubbo中的实践" +linkTitle: "Proxyless Mesh在Dubbo中的实践" +tags: ["Java"] +date: 2022-09-05 +description: > + Proxyless 模式是指 Dubbo 直接与 Istiod 通信,通过 xDS 协议实现服务发现和服务治理等能力。本文将带领大家熟悉 Dubbo Proxyless Mesh。 +--- + +## 背景 + +随着 Dubbo 3.1 的 release,Dubbo 在云原生的路上又迈出了重要的一步。在这个版本中添加了 Proxyless Mesh 的新特性,Dubbo Proxyless Mesh 直接实现 xDS 协议解析, +实现 Dubbo 与 Control Plane 的直接通信,进而实现控制面对流量管控、服务治理、可观测性、安全等的统一管控,规避 Sidecar 模式带来的性能损耗与部署架构复杂性。 + +## 什么是Service Mesh + +Service Mesh 又译作 “服务网格”,作为服务间通信的基础设施层。Buoyant 公司的 CEO Willian Morgan 在他的这篇文章 [WHAT’S A Service Mesh? AND WHY DO I NEED ONE? ](https://linkerd.io/2017/04/25/whats-a-service-mesh-and-why-do-i-need-one/) +中解释了什么是 Service Mesh,为什么云原生应用需要 Service Mesh。 + +**下面是 Willian Morgan 对 Service Mesh 的解释。** + +``` +A Service Mesh is a dedicated infrastructure layer for handling service-to-service communication. +It’s responsible for the reliable delivery of requests through the complex topology of services +that comprise a modern, cloud native application. In practice, the Service Mesh is typically implemented +as an array of lightweight network proxies that are deployed alongside application code, without the +application needing to be aware. +``` + +**翻译成中文** + +``` +服务网格(Service Mesh)是处理服务间通信的基础设施层。它负责构成现代云原生应用程序的复杂服务拓扑来可靠地交付请求。 +在实践中,Service Mesh 通常以轻量级网络代理阵列的形式实现,这些代理与应用程序代码部署在一起,对应用程序来说无需感知代理的存在。 +``` + +说到 Service Mesh 一定离不开 Sidecar 经典架构模式。它通过在业务 Pod 中注入 Sidecar 容器,接管业务容器的通信流量,同时 Sidecar 容器与网格平台的控制平面对接, +基于控制平面下发的策略,对代理流量实施治理和管控,将原有服务框架的治理能力下层到 Sidecar 容器中,从而实现了基础框架能力的下沉,与业务系统解耦。 + +![Service Mesh](/imgs/blog/20220905/1.png) + +经典的 Sidecar Mesh 部署架构有很多优势,如平滑升级、多语言、业务侵入小等,但也带来了一些额外的问题,比如: + +* Proxy 带来的性能损耗,在复杂拓扑的网络调用中将变得尤其明显 +* 流量拦截带来的架构复杂性 +* Sidecar 生命周期管理 +* 部署环境受限,并不是所有环境都满足 Sidecar 流量拦截条件 + +针对 Sidecar Mesh 模型的问题,Dubbo 社区自很早之前就做了 Dubbo 直接对接到控制面的设想与思考,并在国内开源社区率先提出了 Proxyless Mesh 的概念,当然就 Proxyless 概念的说法而言,最开始是谷歌提出来的。 + +## Dubbo Proxyless Mesh + +Dubbo Proxyless 模式是指 Dubbo 直接与 Istiod通信,通过 xDS协议实现服务发现和服务治理等能力。 + +![Proxyless](/imgs/blog/20220905/2.png) + +Proxyless 模式使得微服务又回到了 2.x 时代的部署架构,同 Dubbo 经典服务治理模式非常相似,所以说这个模式并不新鲜, Dubbo 从最开始就是这样的设计模式。 +这样做可以极大的提升应用性能,降低网络延迟。有人说这种做法又回到了原始的基于 SDK 的微服务模式,其实非也,它依然使用了 Envoy 的 xDS API, +但是因为不再需要向应用程序中注入 Sidecar 代理,因此可以减少应用程序性能的损耗。 + +但相比于 Mesh 架构,Dubbo 经典服务治理模式并没有强调控制面的统一管控,而这点恰好是 Service Mesh 所强调的,强调对流量、可观测性、证书等的标准化管控与治理,也是 Mesh 理念先进的地方。 + +在 Dubbo Proxyless 架构模式下,Dubbo 进程将直接与控制面通信,Dubbo 进程之间也继续保持直连通信模式,我们可以看出 Proxyless 架构的优势: + +* 没有额外的 Proxy 中转损耗,因此更适用于性能敏感应用 +* 更有利于遗留系统的平滑迁移 +* 架构简单,容易运维部署 +* 适用于几乎所有的部署环境 + +## 服务发现 + +xDS 接入以注册中心的模式对接,节点发现同其他注册中心的服务自省模型一样,对于 xDS 的负载均衡和路由配置通过 ServiceInstance 的动态运行时配置传出, +在构建 Invoker 的时候将配置参数传入配置地址。 + +![服务发现](/imgs/blog/20220905/3.png) + +## 证书管理 + +零信任架构下,需要严格区分工作负载的识别和信任,而签发 X.509 证书是推荐的一种认证方式。在 Kubernetes 集群中,服务间是通过 DNS 名称互相访问的,而网络流量可能被 DNS 欺骗、BGP/路由劫持、ARP 欺骗等手段劫持,为了将服务名称(DNS 名称)与服务身份强关联起来,Istio 使用置于 X.509 证书中的安全命名机制。SPIFFE是 Istio 所采用的安全命名的规范,它也是云原生定义的一种标准化的、可移植的工作负载身份规范。 + +Secure Production Identity Framework For Everyone (SPIFFE) 是一套服务之间相互进行身份识别的标准,主要包含以下内容: + +* SPIFFE ID 标准,SPIFFE ID 是服务的唯一标识,具体实现使用 URI 资源标识符 +* SPIFFE Verifiable Identity Document (SVID) 标准,将 SPIFFE ID 编码到一个加密的可验证的数据格式中 +* 颁发与撤销 SVID 的 API 标准(SVID 是 SPIFFE ID 的识别凭证) + +SPIFFE ID 规定了形如 ```spiffe:///``` 的 URI 格式,作为工作负载(Workload)的唯一标识。 +而 Istio 在自身的生态中只使用到了 SPIFFE ID 作为安全命名,其数据格式由自己实现,通信格式采用 CNCF 支持的 xDS 协议规范(证书认证通信更具体来说是 xDS 的 SDS)。 + +Istio 使用形如 ```spiffe:///ns//sa/``` 格式的 SPIFFE ID 作为安全命名,注入到 X.509 证书的 subjectAltName 扩展中。 +其中"trust_domain"参数通过 Istiod 环境变量TRUST_DOMAIN 注入,用于在多集群环境中交互。 + +以下是 Dubbo Proxyless Mesh 证书颁发的过程 + +![证书颁发](/imgs/blog/20220905/4.png) + +* 创建 RSA 私钥(Istio 还不支持 ECDSA 私钥) +* 构建 CSR(Certificate signing request)模板 +* 自签名 CSR 生成证书 +* 创建 Kubernetes Secret 资源储存 CA 证书和私钥(CA Service处理) + +## 案例实践 + +接下来我将带领大家通过一个例子使已有的项目快速跑在 Proxyless Mesh 模式下。 + +## 环境准备 + +### 安装docker + +[https://www.docker.com/](https://www.docker.com/) + +### 安装minikube + +墙裂推荐:[https://kubernetes.io/zh-cn/docs/tutorials/hello-minikube/](https://kubernetes.io/zh-cn/docs/tutorials/hello-minikube/) + +### 安装istio + +[https://istio.io/latest/docs/setup/getting-started/](https://istio.io/latest/docs/setup/getting-started/) + +❗❗❗ 安装 Istio 的时候需要开启 first-party-jwt 支持(使用 istioctl 工具安装的时候加上 --set values.global.jwtPolicy=first-party-jwt 参数),否则将导致客户端认证失败的问题。 +参考命令如下: + +```bash +curl -L https://istio.io/downloadIstio | sh - +cd istio-1.xx.x +export PATH=$PWD/bin:$PATH +istioctl install --set profile=demo --set values.global.jwtPolicy=first-party-jwt -y +``` + +## 代码准备 + +### xds-provider + +#### 定义一个接口 + +```java +public interface GreetingService { + + String sayHello(String name); +} +``` + +#### 实现对应的接口 + +```java +@DubboService(version = "1.0.0") +public class AnnotatedGreetingService implements GreetingService { + + @Override + public String sayHello(String name) { + System.out.println("greeting service received: " + name); + return "hello, " + name + "! from host: " + NetUtils.getLocalHost(); + } +} +``` + +#### 编写启动类 + +```java +public class ProviderBootstrap { + + public static void main(String[] args) throws Exception { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class); + context.start(); + System.out.println("dubbo service started"); + new CountDownLatch(1).await(); + } + + @Configuration + @EnableDubbo(scanBasePackages = "org.apache.dubbo.samples.impl") + @PropertySource("classpath:/spring/dubbo-provider.properties") + static class ProviderConfiguration { + } +} +``` + +#### 编写配置信息 + +``` +dubbo.application.name=dubbo-samples-xds-provider +# 由于 Dubbo 3 应用级服务发现的元数据无法从 istio 中获取,需要走服务自省模式。 +# 这要求了 Dubbo MetadataService 的端口在全集群的是统一的。 +dubbo.application.metadataServicePort=20885 +# 走xds协议 +dubbo.registry.address=xds://istiod.istio-system.svc:15012 +dubbo.protocol.name=tri +dubbo.protocol.port=50051 +# 对齐k8s pod生命周期,由于 Kubernetes probe 探活机制的工作原理限制, +# 探活请求的发起方不是 localhost,所以需要配置 qosAcceptForeignIp 参数开启允许全局访问 +dubbo.application.qosEnable=true +dubbo.application.qosAcceptForeignIp=true +``` + +#### 编写Deployment.yml和Service.yml + +``` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dubbo-samples-xds-provider + namespace: dubbo-demo +spec: + replicas: 3 + selector: + matchLabels: + app: dubbo-samples-xds-provider + template: + metadata: + labels: + app: dubbo-samples-xds-provider + spec: + containers: + - name: server + image: apache/dubbo-demo:dubbo-samples-xds-provider_0.0.1 + livenessProbe: + httpGet: + path: /live + port: 22222 + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + httpGet: + path: /ready + port: 22222 + initialDelaySeconds: 5 + periodSeconds: 5 + startupProbe: + httpGet: + path: /startup + port: 22222 + failureThreshold: 30 + periodSeconds: 10 +``` + +``` +apiVersion: v1 +kind: Service +metadata: + name: dubbo-samples-xds-provider + namespace: dubbo-demo +spec: + clusterIP: None + selector: + app: dubbo-samples-xds-provider + ports: + - name: grpc + protocol: TCP + port: 50051 + targetPort: 50051 +``` + +#### 编写Dockerfile + +``` +FROM openjdk:8-jdk +ADD ./target/dubbo-samples-xds-provider-1.0-SNAPSHOT.jar dubbo-samples-xds-provider-1.0-SNAPSHOT.jar +CMD java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=31000 /dubbo-samples-xds-provider-1.0-SNAPSHOT.jar +``` + +### xds-consumer + +#### 定义一个接口 + +``` +public interface GreetingService { + + String sayHello(String name); +} +``` + +#### 实现对应的接口 + +``` +@Component("annotatedConsumer") +public class GreetingServiceConsumer { + // 这里特别注意的是、由于当前 Dubbo 版本受限于 istio 的通信模型无法获取接口所对应的应用名, + // 因此需要配置 providedBy 参数来标记此服务来自哪个应用。 + @DubboReference(version = "1.0.0", providedBy = "dubbo-samples-xds-provider") + private GreetingService greetingService; + + public String doSayHello(String name) { + return greetingService.sayHello(name); + } +} +``` + +#### 编写启动类 + +``` +public class ConsumerBootstrap { + + public static void main(String[] args) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class); + context.start(); + GreetingServiceConsumer greetingServiceConsumer = context.getBean(GreetingServiceConsumer.class); + while (true) { + try { + String hello = greetingServiceConsumer.doSayHello("xDS Consumer"); + System.out.println("result: " + hello); + Thread.sleep(100); + } catch (Throwable t) { + t.printStackTrace(); + } + } + } + + @Configuration + @EnableDubbo(scanBasePackages = "org.apache.dubbo.samples.action") + @PropertySource("classpath:/spring/dubbo-consumer.properties") + @ComponentScan(value = {"org.apache.dubbo.samples.action"}) + static class ConsumerConfiguration { + + } +} +``` + +#### 编写配置信息 + +``` +dubbo.application.name=dubbo-samples-xds-consumer +dubbo.application.metadataServicePort=20885 +dubbo.registry.address=xds://istiod.istio-system.svc:15012 +dubbo.consumer.timeout=3000 +dubbo.consumer.check=false +dubbo.application.qosEnable=true +dubbo.application.qosAcceptForeignIp=true +``` + +#### 编写Deployment.yml和Service.yml + +``` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dubbo-samples-xds-consumer + namespace: dubbo-demo +spec: + replicas: 2 + selector: + matchLabels: + app: dubbo-samples-xds-consumer + template: + metadata: + labels: + app: dubbo-samples-xds-consumer + spec: + containers: + - name: server + image: apache/dubbo-demo:dubbo-samples-xds-consumer_0.0.1 + livenessProbe: + httpGet: + path: /live + port: 22222 + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + httpGet: + path: /ready + port: 22222 + initialDelaySeconds: 5 + periodSeconds: 5 + startupProbe: + httpGet: + path: /startup + port: 22222 + failureThreshold: 30 + periodSeconds: 10 +``` + +``` +apiVersion: v1 +kind: Service +metadata: + name: dubbo-samples-xds-consumer + namespace: dubbo-demo +spec: + clusterIP: None + selector: + app: dubbo-samples-xds-consumer + ports: + - name: grpc + protocol: TCP + port: 50051 + targetPort: 50051 +``` + +#### 编写Dockerfile + +``` +FROM openjdk:8-jdk +ADD ./target/dubbo-samples-xds-consumer-1.0-SNAPSHOT.jar dubbo-samples-xds-consumer-1.0-SNAPSHOT.jar +CMD java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=31000 /dubbo-samples-xds-consumer-1.0-SNAPSHOT.jar +``` + +✅ 到目前为止我们的环境和代码就全都准备完毕了! + +## 构建镜像 + +### 1、启动docker + +![启动docker](/imgs/blog/20220905/5.png) + +### 2、启动minikube +因为minikube是一个本地的k8s,他启动需要一个虚拟引擎,这里我们用docker来管理。我们通过如下命令启动 + +`minikube start` + +![启动minikube](/imgs/blog/20220905/6.png) + +我们可以在docker里看到minikube + +![minikube](/imgs/blog/20220905/7.png) + +### 3、检查istio的状态 + +![istio的状态](/imgs/blog/20220905/8.png) + +### 4、构建镜像 + +在本地找到代码所在位置、依次执行以下命令 + +``` +# 找到provider所在路径 +cd ./dubbo-samples-xds-provider/ +# 构建provider的镜像 +docker build -t apache/dubbo-demo:dubbo-samples-xds-provider_0.0.1 . +``` + +![构建provider](/imgs/blog/20220905/9.png) + +``` +# 找到consumer所在路径 +cd ../dubbo-samples-xds-consumer/ +# 构建consumer的镜像 +docker build -t apache/dubbo-demo:dubbo-samples-xds-consumer_0.0.1 . +``` + +![构建consumer](/imgs/blog/20220905/10.png) + +### 5、检查本地镜像 + +![检查本地镜像](/imgs/blog/20220905/11.png) + +### 6、创建namespace + +``` +# 初始化命名空间 +kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-xds/deploy/Namespace.yml + +# 切换命名空间 +kubens dubbo-demo +``` + +如果不创建namespace,那么会看到如下错误 + +![错误](/imgs/blog/20220905/12.png) + +## 部署容器 + +``` +# 找到provider所在路径 +cd ./dubbo-samples-xds-provider/src/main/resources/k8s +# dubbo-samples-xds/dubbo-samples-xds-provider/src/main/resources/k8s/Deployment.yml +# dubbo-samples-xds/dubbo-samples-xds-provider/src/main/resources/k8s/Service.yml + +# 部署provider的Deployment和Service +kubectl apply -f Deployment.yml +kubectl apply -f Service.yml +``` + +![部署provider](/imgs/blog/20220905/13.png) + +``` +# 找到consumer所在路径 +cd ../../../../../dubbo-samples-xds-consumer/src/main/resources/k8s +# dubbo-samples-xds/dubbo-samples-xds-consumer/src/main/resources/k8s/Deployment.yml + +# 部署consumer的Deployment +kubectl apply -f Deployment.yml +``` + +![部署provider](/imgs/blog/20220905/14.png) + +在minikube dashboard看到我们已经部署的pod + +![部署provider](/imgs/blog/20220905/15.png) + +## 观察consumer效果 + +``` +kubectl logs xxx + +result: hello, xDS Consumer! from host: 172.17.0.5 +result: hello, xDS Consumer! from host: 172.17.0.5 +result: hello, xDS Consumer! from host: 172.17.0.6 +result: hello, xDS Consumer! from host: 172.17.0.6 +``` + +## 总结&展望 + +本文主要剖析了 Dubbo Proxyless Mesh 的架构、服务发现以及证书管理等核心流程,最后通过示例给大家演示了如何使用 Dubbo Proxyless。 + +![部署provider](/imgs/blog/20220905/16.png) + +随着 Dubbo 3.1 的 release,Dubbo 在云原生的路上又迈出了重要的一步。在今年年底,Dubbo Mesh 将发布具有服务发现能力的版本, +届时将面向所有 Dubbo 用户提供从低版本平滑迁移到 Mesh 架构的能力;在明年年初春季的时候将发布带有治理能力的版本;在明年年底前发布带热插件更新能力的版本, +希望有兴趣见证 Dubbo 云原生之路的同学可以积极参与社区贡献! + +更多关于 Dubbo Mesh 的动态可以关注 Apache Dubbo 社区官方公众号(ApacheDubbo),及时获取最新消息。 \ No newline at end of file diff --git a/content/en/blog/java/demos/resilience4j.md b/content/en/blog/java/demos/resilience4j.md new file mode 100644 index 000000000000..6cf00b7ea833 --- /dev/null +++ b/content/en/blog/java/demos/resilience4j.md @@ -0,0 +1,14 @@ +--- +aliases: + - /en/overview/tasks/rate-limit/resilience4j/ + - /en/overview/tasks/rate-limit/resilience4j/ +description: "使用 Resilience4j 断路器、限流器、重试、隔离机制保护 Dubbo 应用" +linkTitle: Resilience4j +title: 使用 Resilience4j 断路器、限流器、重试、隔离机制保护 Dubbo 应用 +tags: ["Java", "Resilience4j", "限流降级"] +date: 2023-12-14 +--- + +Resilience4j 提供了一组高阶函数(装饰器),包括断路器,限流器,重试,隔离,可以对任何的函数式接口,lambda表达式,或方法的引用进行增强,并且这些装饰器可以进行叠加。这样做的好处是,你可以根据需要选择特定的装饰器进行组合。 + +关于 Resilience4j 与 Dubbo 集成的使用示例请参见 [dubbo-samples-resilience4j](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-resilience4j) diff --git a/content/en/blog/java/demos/rpc-introduction.md b/content/en/blog/java/demos/rpc-introduction.md new file mode 100644 index 000000000000..37a0f2c9d8fa --- /dev/null +++ b/content/en/blog/java/demos/rpc-introduction.md @@ -0,0 +1,135 @@ +--- +title: "浅谈 RPC" +linkTitle: "浅谈 RPC" +tags: ["Java"] +date: 2019-01-07 +description: > + RPC-远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。 +--- + +近几年随着微服务化项目的崛起,逐渐成为许多公司中大型分布式系统架构的主流方式,而今天所说的 RPC 在这其中扮演着至关重要的角色。随着这段日子公司项目微服务化的演进,发现在日常开发中都在隐式或显式的使用 RPC,一些刚刚接触 RPC 的小伙伴会感觉无所适从,而一些入行多年的老手虽然使用 RPC 经验丰富,但有些对其原理也一知半解,缺乏对原理的深入理解,往往也会造成开发中的一些误用。 + +## 什么是RPC? + +RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。 + +RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。现在业界有很多开源的优秀 RPC 框架,例如 Spring Cloud、Dubbo、Thrift 等。 + +## RPC 起源 + +RPC 这个概念术语在上世纪 80 年代由 **Bruce Jay Nelson** 提出。这里我们追溯下当初开发 RPC 的原动机是什么?在 Nelson 的论文 "Implementing Remote Procedure Calls" 中他提到了几点: +* 简单:RPC 概念的语义十分清晰和简单,这样建立分布式计算就更容易。 +* 高效:过程调用看起来十分简单而且高效。 +* 通用:在单机计算中过程往往是不同算法部分间最重要的通信机制。 + +通俗一点说,就是一般程序员对于本地的过程调用很熟悉,那么我们把 RPC 作成和本地调用完全类似,那么就更容易被接受,使用起来毫无障碍。Nelson 的论文发表于 30 年前,其观点今天看来确实高瞻远瞩,今天我们使用的 RPC 框架基本就是按这个目标来实现的。 + +## RPC 结构 + +Nelson 的论文中指出实现 RPC 的程序包括 5 个部分: +1. User +2. User-stub +3. RPCRuntime +4. Server-stub +5. Server + +![RPC结构](/imgs/blog/rpc/rpc-structure-1.png) + +这里 user 就是 client 端,当 user 想发起一个远程调用时,它实际是通过本地调用 user-stub。user-stub 负责将调用的接口、方法和参数通过约定的协议规范进行编码并通过本地的 RPCRuntime 实例传输到远端的实例。远端 RPCRuntime 实例收到请求后交给 server-stub 进行解码后发起本地端调用,调用结果再返回给 user 端。 + +以上是粗粒度的 RPC 实现概念结构,接下来我们进一步细化它应该由哪些组件构成,如下图所示。 + +![RPC 结构拆解](/imgs/blog/rpc/rpc-structure-2.png) + +RPC 服务方通过 RpcServer 去导出(export)远程接口方法,而客户方通过 RpcClient 去引入(import)远程接口方法。客户方像调用本地方法一样去调用远程接口方法,RPC 框架提供接口的代理实现,实际的调用将委托给代理RpcProxy 。代理封装调用信息并将调用转交给RpcInvoker 去实际执行。在客户端的RpcInvoker 通过连接器RpcConnector 去维持与服务端的通道RpcChannel,并使用RpcProtocol 执行协议编码(encode)并将编码后的请求消息通过通道发送给服务方。 + +RPC 服务端接收器 RpcAcceptor 接收客户端的调用请求,同样使用RpcProtocol 执行协议解码(decode)。解码后的调用信息传递给RpcProcessor 去控制处理调用过程,最后再委托调用给RpcInvoker 去实际执行并返回调用结果。如下是各个部分的详细职责: + +``` +1. RpcServer + + 负责导出(export)远程接口 + +2. RpcClient + + 负责导入(import)远程接口的代理实现 + +3. RpcProxy + + 远程接口的代理实现 + +4. RpcInvoker + + 客户方实现:负责编码调用信息和发送调用请求到服务方并等待调用结果返回 + + 服务方实现:负责调用服务端接口的具体实现并返回调用结果 + +5. RpcProtocol + + 负责协议编/解码 + +6. RpcConnector + + 负责维持客户方和服务方的连接通道和发送数据到服务方 + +7. RpcAcceptor + + 负责接收客户方请求并返回请求结果 + +8. RpcProcessor + + 负责在服务方控制调用过程,包括管理调用线程池、超时时间等 + +9. RpcChannel + + 数据传输通道 +``` + +## RPC 工作原理 + +RPC的设计由Client,Client stub,Network ,Server stub,Server构成。 其中Client就是用来调用服务的,Cient stub是用来把调用的方法和参数序列化的(因为要在网络中传输,必须要把对象转变成字节),Network用来传输这些信息到Server stub, Server stub用来把这些信息反序列化的,Server就是服务的提供者,最终调用的就是Server提供的方法。 + +![RPC工作原理](/imgs/blog/rpc/rpc-work-principle.png) + +1. Client像调用本地服务似的调用远程服务; + +2. Client stub接收到调用后,将方法、参数序列化 + +3. 客户端通过sockets将消息发送到服务端 + +4. Server stub 收到消息后进行解码(将消息对象反序列化) + +5. Server stub 根据解码结果调用本地的服务 + +6. 本地服务执行(对于服务端来说是本地执行)并将结果返回给Server stub + +7. Server stub将返回结果打包成消息(将结果消息对象序列化) + +8. 服务端通过sockets将消息发送到客户端 + +9. Client stub接收到结果消息,并进行解码(将结果消息反序列化) + +10. 客户端得到最终结果。 + +RPC 调用分以下两种: + +1. 同步调用:客户方等待调用执行完成并返回结果。 + +2. 异步调用:客户方调用后不用等待执行结果返回,但依然可以通过回调通知等方式获取返回结果。若客户方不关心调用返回结果,则变成单向异步调用,单向调用不用返回结果。 + +异步和同步的区分在于是否等待服务端执行完成并返回结果。 + +## RPC 能干什么? + +RPC 的主要功能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。为实现该目标,RPC 框架需提供一种透明调用机制,让使用者不必显式的区分本地调用和远程调用,在之前给出的一种实现结构,基于 stub 的结构来实现。下面我们将具体细化 stub 结构的实现。 + +* 可以做到分布式,现代化的微服务 +* 部署灵活 +* 解耦服务 +* 扩展性强 + +RPC的目的是让你在本地调用远程的方法,而对你来说这个调用是透明的,你并不知道这个调用的方法是部署哪里。通过RPC能解耦服务,这才是使用RPC的真正目的。 + +## 总结 + +这篇文章介绍了 RPC 的一些基本原理,相信到这里您已经对 RPC 有了一定理解。其实发现实现一个 RPC 不算难,难的是实现一个高性能高可靠的RPC框架。比如,既然是分布式了,那么一个服务可能有多个实例,你在调用时,要如何获取这些实例的地址呢?这时候就需要一个服务注册中心,比如在Dubbo中,就可以使用Zookeeper作为注册中心,在调用时,从Zookeeper获取服务的实例列表,再从中选择一个进行调用。那么选哪个调用好呢?这时候就需要负载均衡了,于是你又得考虑如何实现复杂均衡,比如Dubbo就提供了好几种负载均衡策略。所以请继续关注我的另外两篇文章**RPC与服务化的关系**和**注册中心,配置中心, 服务发现浅谈**,相信会帮助对RPC设计和实现有更多的理解。 diff --git a/content/en/blog/java/demos/service-and-version.md b/content/en/blog/java/demos/service-and-version.md new file mode 100644 index 000000000000..0c769f5d5627 --- /dev/null +++ b/content/en/blog/java/demos/service-and-version.md @@ -0,0 +1,242 @@ +--- +title: "Dubbo服务分组和版本聚合" +linkTitle: "Dubbo服务分组和版本聚合" +tags: ["Java"] +date: 2018-10-27 +description: > + 本文主要介绍了 Dubbo 中服务分组和版本聚合的概念和用法 +--- + +我们在调用Dubbo服务的时候,一般只需要将Consumer端的`dubbo:reference`指定成服务端中`dubbo:service`暴露的服务,就可以找到服务端,完成调用,也就是说,Dubbo只需要服务接口信息就可以找到服务提供者。 +其实除了服务提供者以外,Dubbo也有服务分组和版本的概念,在客户端去寻找“匹配”的服务端的时候,需要服务接口,版本号,组别这三个信息都匹配,才算是一个有效的服务端: + +```java + public static boolean isMatch(URL consumerUrl, URL providerUrl) { + String consumerInterface = consumerUrl.getServiceInterface(); + String providerInterface = providerUrl.getServiceInterface(); + if (!(Constants.ANY_VALUE.equals(consumerInterface) || StringUtils.isEquals(consumerInterface, providerInterface))) + return false; + + if (!isMatchCategory(providerUrl.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY), + consumerUrl.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY))) { + return false; + } + if (!providerUrl.getParameter(Constants.ENABLED_KEY, true) + && !Constants.ANY_VALUE.equals(consumerUrl.getParameter(Constants.ENABLED_KEY))) { + return false; + } + + String consumerGroup = consumerUrl.getParameter(Constants.GROUP_KEY); + String consumerVersion = consumerUrl.getParameter(Constants.VERSION_KEY); + String consumerClassifier = consumerUrl.getParameter(Constants.CLASSIFIER_KEY, Constants.ANY_VALUE); + + String providerGroup = providerUrl.getParameter(Constants.GROUP_KEY); + String providerVersion = providerUrl.getParameter(Constants.VERSION_KEY); + String providerClassifier = providerUrl.getParameter(Constants.CLASSIFIER_KEY, Constants.ANY_VALUE); + return (Constants.ANY_VALUE.equals(consumerGroup) || StringUtils.isEquals(consumerGroup, providerGroup) || StringUtils.isContains(consumerGroup, providerGroup)) + && (Constants.ANY_VALUE.equals(consumerVersion) || StringUtils.isEquals(consumerVersion, providerVersion)) + && (consumerClassifier == null || Constants.ANY_VALUE.equals(consumerClassifier) || StringUtils.isEquals(consumerClassifier, providerClassifier)); + } +``` +如果没有配置组别和版本号,默认值为空。服务端和消费端都没有配,只有服务接口,其他两个信息都为空,也是可以“找到”对方的,那服务名和版本号可以如何使用呢?下面我们来看一下具体的场景: +### 服务分组 +当一个接口有多种实现时,可以用 group 区分。 + +服务 + +```xml + + +``` +引用 + +```xml + + +``` + +任意组 + +```xml + +``` + +### 多版本 +当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。 + +可以按照以下的步骤进行版本迁移: + +1. 在低压力时间段,先升级一半提供者为新版本 +1. 再将所有消费者升级为新版本 +1. 然后将剩下的一半提供者升级为新版本 + +老版本服务提供者配置: + +```xml + +``` + +新版本服务提供者配置: + +```xml + +``` + +老版本服务消费者配置: + +```xml + +``` + +新版本服务消费者配置: + +```xml + +``` + +如果不需要区分版本,可以按照以下的方式配置: + +```xml + +``` + + +### 分组聚合 + +按组合并返回结果,比如菜单服务,接口一样,但有多种实现,用group区分,现在消费方需从每种group中调用一次返回结果,合并结果返回,这样就可以实现聚合菜单项。 + +#### 配置 +搜索所有分组 + +```xml + +``` + +合并指定分组 + +```xml + +``` + +指定方法合并结果,其它未指定的方法,将只调用一个 Group + +```xml + + + + +``` + +某个方法不合并结果,其它都合并结果 + +```xml + + + + +``` + +指定合并策略,缺省根据返回值类型自动匹配,如果同一类型有两个合并器时,需指定合并器的名称 + +```xml + + + +``` +指定合并方法,将调用返回结果的指定方法进行合并,合并方法的参数类型必须是返回结果类型本身 + +```xml + + + +``` + +#### 实现原理 +如果配置了merge,Dubbo会分别调用多个组别的服务提供者,然后把结果聚合,返回给消费端,具体的实现在`MergeableClusterInvoker.java`里: + +```java + public Result invoke(final Invocation invocation) throws RpcException { + List> invokers = directory.list(invocation); + + String merger = getUrl().getMethodParameter(invocation.getMethodName(), Constants.MERGER_KEY); + if (ConfigUtils.isEmpty(merger)) { // If a method doesn't have a merger, only invoke one Group + for (final Invoker invoker : invokers) { + if (invoker.isAvailable()) { + return invoker.invoke(invocation); + } + } + return invokers.iterator().next().invoke(invocation); + } + + Class returnType; + try { + returnType = getInterface().getMethod( + invocation.getMethodName(), invocation.getParameterTypes()).getReturnType(); + } catch (NoSuchMethodException e) { + returnType = null; + } + + Map> results = new HashMap>(); + for (final Invoker invoker : invokers) { + Future future = executor.submit(new Callable() { + @Override + public Result call() throws Exception { + return invoker.invoke(new RpcInvocation(invocation, invoker)); + } + }); + results.put(invoker.getUrl().getServiceKey(), future); + } + + Object result = null; + + List resultList = new ArrayList(results.size()); + + int timeout = getUrl().getMethodParameter(invocation.getMethodName(), Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); + for (Map.Entry> entry : results.entrySet()) { + Future future = entry.getValue(); + try { + Result r = future.get(timeout, TimeUnit.MILLISECONDS); + if (r.hasException()) { + log.error("Invoke " + getGroupDescFromServiceKey(entry.getKey()) + + " failed: " + r.getException().getMessage(), + r.getException()); + } else { + resultList.add(r); + } + } catch (Exception e) { + throw new RpcException("Failed to invoke service " + entry.getKey() + ": " + e.getMessage(), e); + } + } + + if (resultList.isEmpty()) { + return new RpcResult((Object) null); + } else if (resultList.size() == 1) { + return resultList.iterator().next(); + } + + if (returnType == void.class) { + return new RpcResult((Object) null); + } +``` +如果配置了merger,会依次调用,结果都放在results里面,其中value都是future类型,等调用完成之后,再遍历results,通过future.get拿到真正的结果,到此为止,所有调用的结果都放在resultList里面了,接下来要做的是把结果进行聚合: + +```java + Merger resultMerger; + if (ConfigUtils.isDefault(merger)) { + resultMerger = MergerFactory.getMerger(returnType); + } else { + resultMerger = ExtensionLoader.getExtensionLoader(Merger.class).getExtension(merger); + } + if (resultMerger != null) { + List rets = new ArrayList(resultList.size()); + for (Result r : resultList) { + rets.add(r.getValue()); + } + result = resultMerger.merge( + rets.toArray((Object[]) Array.newInstance(returnType, 0))); + } else { + throw new RpcException("There is no merger to merge result.") + } + return new RpcResult(result); +``` +这里会根据返回值的类型,获取到对应的resultMerger,除了Dubbo默认实现的类型外,也可以自己指定merger类型并且添加相应的扩展,通过实现`merge`方法类进行结果聚合。 \ No newline at end of file diff --git a/content/en/blog/java/demos/service-test.md b/content/en/blog/java/demos/service-test.md new file mode 100644 index 000000000000..b4041e186c3b --- /dev/null +++ b/content/en/blog/java/demos/service-test.md @@ -0,0 +1,166 @@ +--- +title: "Dubbo Admin服务测试功能" +linkTitle: "Dubbo Admin服务测试功能" +tags: ["Java"] +date: 2019-08-26 +slug: service-test +description: > + 可以通过泛化调用,在控制台上调用真实的服务提供者 +--- + +基于Dubbo2.7的元数据,Dubbo Admin实现了服务测试功能,可以通过泛化调用,在控制台上调用真实的服务提供者 + +## 使用方式 +* 部署服务提供者: 可以在[这里](https://github.com/nzomkxia/dubbo-demo)下载demo,此工程基于spring boot,方便在IDE或者命令行启动,对于服务测试来说,只需要启动`dubbo-basic-provider`即可。 +* 服务查询: 完成服务端部署后,可以到Dubbo Admin的`服务测试`页面上查询对应的服务: +![testSearch](/imgs/blog/admin/testSearch.jpg) +这里的信息和元数据类似,包含方法名,参数类型和返回值信息,点击右边的标签就可以进入服务测试页面 +* 服务测试: +![testSuccess](/imgs/blog/admin/testSuccess.jpg) +服务测试页面包含了两个json编辑器,参数类型的信息都是以json格式保存,这里需要填入对应的参数值(本例中数类型时`String`),填写完成后点击`执行`即可对服务端发起调用,调用结果展示在右边的编辑器中,如果调用失败,会显示详细的失败原因,下面来看一下调用失败的例子: +![testFail](/imgs/blog/admin/testFail.jpg) +本例中,先关掉Dubbo服务提供者的进程,再执行服务测试,可以看到返回的结果是`找不到服务提供者`的异常。和普通调用一样,业务和框架的异常都会返回在结果中,方便业务排查。 +* 复合类型参数 +考虑`UserService`中的以下方法和类型: +```java +//org.apache.dubbo.demo.api.UserService +Result getUser(String name, UserInfoDO userInfoDO); +``` +```java +public class UserInfoDO { + private int id; + private LocationDO locationDO; + private DepartmentDO departmentDO; + + @Override + public String toString() { + return "UserInfoDO{" + + "id=" + id + + ", locationDO=" + locationDO.toString() + + ", departmentDO=" + departmentDO.toString() + + '}'; + } +} +``` + +```java +public class DepartmentDO { + + private String departName; + private LocationDO departLocation; + + @Override + public String toString() { + return "DepartmentDO{" + + "departName='" + departName + '\'' + + ", departLocation=" + departLocation.toString() + + '}'; + } +} +``` + +```java +public class LocationDO { + private String address; + private int postNum; + + @Override + public String toString() { + return "LocationDO{" + + "address='" + address + '\'' + + ", postNum=" + postNum + + '}'; + } +} +``` +参数是比较复杂的符合类型参数,服务测试的时候,会逐层展开填写每一个field的值,如下图所示: +![complex](/imgs/blog/admin/complex.jpg) +同样可以调用成功并且返回结果 + +## 原理:数据来源 +服务测试中,最重要的就是完整的方法签名信息,和参数的类型信息,有了这些信息才能够一步步填入每个参数的值,拼装出完整的服务消费者。在Dubbo2.7中,新增了元数据中心,Dubbo Admin的方法签名和参数类型信息就是从这里来的: +![medatada](/imgs/blog/admin/metadata.png) +如图所示,服务端在运行的时候会将服务的元数据信息注册到元数据中心,格式如下: +```json +{ + ... + "methods": [ + { + "name": "sayHello", + "parameterTypes": [ + "org.apache.dubbo.demo.model.User" + ], + "returnType": "org.apache.dubbo.demo.model.Result" + }, + ... + ], + "types": [ + { + "type": "char" + }, + { + "type": "long" + }, + { + "type": "org.apache.dubbo.demo.model.Result", + "properties": { + "msg": { + "type": "java.lang.String", + "properties": { + "value": { + "type": "char[]" + }, + "hash": { + "type": "int" + } + } + }, + "userName": { + "type": "java.lang.String", + "properties": { + "value": { + "type": "char[]" + }, + "hash": { + "type": "int" + } + } + } + } + }, + { + "type": "org.apache.dubbo.demo.model.User", + "properties": { + "id": { + "type": "java.lang.Long", + "properties": { + "value": { + "type": "long" + } + } + }, + "username": { + "type": "java.lang.Sring", + "properties": { + "value": { + "type": "char[]" + }, + "hash": { + "type": "int" + } + } + } + } + }, + ... + ] +} +``` +与服务测试相关的就是`methods`和`types`所包含的方法和类型信息,Dubbo Admin根据这些信息,将参数渲染到服务测试页面的Json Editor中,由用户来输入每个参数,每个成员变量的值。 + + +## 原理: 泛化调用 +有了参数类型,下一个问题就是怎么能够调用到服务端,在传统的Dubbo RPC调用中,客户端需要依赖服务端的API jar包(参考前文demo中的[dubbo-basic-consumer](https://github.com/nzomkxia/dubbo-demo/tree/master/dubbo-basic-consumer)),这对于Dubbo Admin来说不太可能,因为服务的上下线是动态的,Dubbo Admin无法动态增加jar包依赖,因此需要用到Dubbo中的**泛化调用**,指的是在没有服务端API接口的情况下,客户端直接通过 `GenericService` 接口来发起服务调用,返回值中的数据对象都用Map来表示。泛化调用在服务端不需要做特殊处理,只需要客户端发起即可。 + +## 总结和展望 +本文简单介绍了服务测试的用法和原理,后续会进一步针对该功能进行增强,比如处理抽象类的参数类型,支持从json文件导入参数值,支持对参数值的保存等等,方便对服务接口进行回归测试。 \ No newline at end of file diff --git a/content/en/blog/java/demos/spring-boot-dubbo-start-stop-analysis.md b/content/en/blog/java/demos/spring-boot-dubbo-start-stop-analysis.md new file mode 100644 index 000000000000..d8b3225d69d1 --- /dev/null +++ b/content/en/blog/java/demos/spring-boot-dubbo-start-stop-analysis.md @@ -0,0 +1,235 @@ +--- +title: "Spring Boot Dubbo应用启停源码分析" +linkTitle: "Spring Boot Dubbo应用启停源码分析" +tags: ["Java"] +date: 2018-08-14 +description: > + 本文分析 `dubbo-spring-boot-project` 中 Dubbo 启停源码的实现原理。 +--- + +## 背景介绍 + +[Dubbo Spring Boot](https://github.com/apache/dubbo-spring-boot-project) 工程致力于简化 Dubbo RPC 框架在Spring Boot应用场景的开发。同时也整合了 Spring Boot 特性: + +- [自动装配](https://github.com/apache/dubbo-spring-boot-project/blob/master/dubbo-spring-boot-autoconfigure) (比如: 注解驱动, 自动装配等). +- [Production-Ready](https://github.com/apache/dubbo-spring-boot-project/blob/master/dubbo-spring-boot-actuator) (比如: 安全, 健康检查, 外部化配置等). + +## DubboConsumer启动分析 + +你有没有想过一个问题?`dubbo-spring-boot-project`中的`DubboConsumerDemo`应用就一行代码,`main`方法执行完之后,为什么不会直接退出呢? + +```java +@SpringBootApplication(scanBasePackages = "com.alibaba.boot.dubbo.demo.consumer.controller") +public class DubboConsumerDemo { + + public static void main(String[] args) { + SpringApplication.run(DubboConsumerDemo.class,args); + } + +} +``` + +其实要回答这样一个问题,我们首先需要把这个问题进行一个抽象,即一个JVM进程,在什么情况下会退出? + +以Java 8为例,通过查阅JVM语言规范[1],在12.8章节中有清晰的描述: + +A program terminates all its activity and *exits* when one of two things happens: + +- All the threads that are not daemon threads terminate. +- Some thread invokes the `exit` method of class `Runtime` or class `System`, and the `exit` operation is not forbidden by the security manager. + +也就是说,导致JVM的退出只有2种情况: + +1. 所有的非daemon进程完全终止 +2. 某个线程调用了`System.exit()`或`Runtime.exit()` + +因此针对上面的情况,我们判断,一定是有某个非daemon线程没有退出导致。我们知道,通过jstack可以看到所有的线程信息,包括他们是否是daemon线程,可以通过jstack找出那些是非deamon的线程。 + +```sh +➜ jstack 57785 | grep tid | grep -v "daemon" +"container-0" #37 prio=5 os_prio=31 tid=0x00007fbe312f5800 nid=0x7103 waiting on condition [0x0000700010144000] +"container-1" #49 prio=5 os_prio=31 tid=0x00007fbe3117f800 nid=0x7b03 waiting on condition [0x0000700010859000] +"DestroyJavaVM" #83 prio=5 os_prio=31 tid=0x00007fbe30011000 nid=0x2703 waiting on condition [0x0000000000000000] +"VM Thread" os_prio=31 tid=0x00007fbe3005e800 nid=0x3703 runnable +"GC Thread#0" os_prio=31 tid=0x00007fbe30013800 nid=0x5403 runnable +"GC Thread#1" os_prio=31 tid=0x00007fbe30021000 nid=0x5303 runnable +"GC Thread#2" os_prio=31 tid=0x00007fbe30021800 nid=0x2d03 runnable +"GC Thread#3" os_prio=31 tid=0x00007fbe30022000 nid=0x2f03 runnable +"G1 Main Marker" os_prio=31 tid=0x00007fbe30040800 nid=0x5203 runnable +"G1 Conc#0" os_prio=31 tid=0x00007fbe30041000 nid=0x4f03 runnable +"G1 Refine#0" os_prio=31 tid=0x00007fbe31044800 nid=0x4e03 runnable +"G1 Refine#1" os_prio=31 tid=0x00007fbe31045800 nid=0x4d03 runnable +"G1 Refine#2" os_prio=31 tid=0x00007fbe31046000 nid=0x4c03 runnable +"G1 Refine#3" os_prio=31 tid=0x00007fbe31047000 nid=0x4b03 runnable +"G1 Young RemSet Sampling" os_prio=31 tid=0x00007fbe31047800 nid=0x3603 runnable +"VM Periodic Task Thread" os_prio=31 tid=0x00007fbe31129000 nid=0x6703 waiting on condition + +``` + +> 此处通过grep tid 找出所有的线程摘要,通过grep -v找出不包含daemon关键字的行 + +通过上面的结果,我们发现了一些信息: + +* 有两个线程`container-0`, `container-1`非常可疑,他们是非daemon线程,处于wait状态 +* 有一些GC相关的线程,和VM打头的线程,也是非daemon线程,但他们很有可能是JVM自己的线程,在此暂时忽略。 + +综上,我们可以推断,很可能是因为`container-0`和`container-1`导致JVM没有退出。现在我们通过源码,搜索一下到底是谁创建的这两个线程。 + +通过对spring-boot的源码分析,我们在`org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer`的`startDaemonAwaitThread`找到了如下代码 + +```java + private void startDaemonAwaitThread() { + Thread awaitThread = new Thread("container-" + (containerCounter.get())) { + + @Override + public void run() { + TomcatEmbeddedServletContainer.this.tomcat.getServer().await(); + } + + }; + awaitThread.setContextClassLoader(getClass().getClassLoader()); + awaitThread.setDaemon(false); + awaitThread.start(); + } +``` + +在这个方法加个断点,看下调用堆栈: + +``` +initialize:115, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat) +:84, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat) +getTomcatEmbeddedServletContainer:554, TomcatEmbeddedServletContainerFactory (org.springframework.boot.context.embedded.tomcat) +getEmbeddedServletContainer:179, TomcatEmbeddedServletContainerFactory (org.springframework.boot.context.embedded.tomcat) +createEmbeddedServletContainer:164, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded) +onRefresh:134, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded) +refresh:537, AbstractApplicationContext (org.springframework.context.support) +refresh:122, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded) +refresh:693, SpringApplication (org.springframework.boot) +refreshContext:360, SpringApplication (org.springframework.boot) +run:303, SpringApplication (org.springframework.boot) +run:1118, SpringApplication (org.springframework.boot) +run:1107, SpringApplication (org.springframework.boot) +main:35, DubboConsumerDemo (com.alibaba.boot.dubbo.demo.consumer.bootstrap) +``` + +可以看到,spring-boot应用在启动的过程中,由于默认启动了Tomcat暴露HTTP服务,所以执行到了上述方法,而Tomcat启动的所有的线程,默认都是daemon线程,例如监听请求的Acceptor,工作线程池等等,如果这里不加控制的话,启动完成之后JVM也会退出。因此需要显式地启动一个线程,在某个条件下进行持续等待,从而避免线程退出。 + +下面我们在深挖一下,在Tomcat的`this.tomcat.getServer().await()`这个方法中,线程是如何实现不退出的。这里为了阅读方便,去掉了不相关的代码。 + +```java +public void await() { + // ... + if( port==-1 ) { + try { + awaitThread = Thread.currentThread(); + while(!stopAwait) { + try { + Thread.sleep( 10000 ); + } catch( InterruptedException ex ) { + // continue and check the flag + } + } + } finally { + awaitThread = null; + } + return; + } + // ... + } +``` + +在await方法中,实际上当前线程在一个while循环中每10秒检查一次 `stopAwait`这个变量,它是一个`volatile`类型变量,用于确保被另一个线程修改后,当前线程能够立即看到这个变化。如果没有变化,就会一直处于while循环中。这就是该线程不退出的原因,也就是整个spring-boot应用不退出的原因。 + +因为Springboot应用同时启动了8080和8081(management port)两个端口,实际是启动了两个Tomcat,因此会有两个线程`container-0`和`container-1`。 + +接下来,我们再看看,这个Spring-boot应用又是如何退出的呢? + +## DubboConsumer退出分析 + +在前面的描述中提到,有一个线程持续的在检查`stopAwait`这个变量,那么我们自然想到,在Stop的时候,应该会有一个线程去修改`stopAwait`,打破这个while循环,那又是谁在修改这个变量呢? + +通过对源码分析,可以看到只有一个方法修改了`stopAwait`,即`org.apache.catalina.core.StandardServer#stopAwait`,我们在此处加个断点,看看是谁在调用。 + +> 注意,当我们在Intellij IDEA的Debug模式,加上一个断点后,需要在命令行下使用`kill -s INT $PID`或者`kill -s TERM $PID`才能触发断点,点击IDE上的Stop按钮,不会触发断点。这是IDEA的bug + +可以看到有一个名为`Thread-3`的线程调用了该方法: + +```java +stopAwait:390, StandardServer (org.apache.catalina.core) +stopInternal:819, StandardServer (org.apache.catalina.core) +stop:226, LifecycleBase (org.apache.catalina.util) +stop:377, Tomcat (org.apache.catalina.startup) +stopTomcat:241, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat) +stop:295, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat) +stopAndReleaseEmbeddedServletContainer:306, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded) +onClose:155, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded) +doClose:1014, AbstractApplicationContext (org.springframework.context.support) +run:929, AbstractApplicationContext$2 (org.springframework.context.support) +``` + +通过源码分析,原来是通过Spring注册的`ShutdownHook`来执行的 + +```java + @Override + public void registerShutdownHook() { + if (this.shutdownHook == null) { + // No shutdown hook registered yet. + this.shutdownHook = new Thread() { + @Override + public void run() { + synchronized (startupShutdownMonitor) { + doClose(); + } + } + }; + Runtime.getRuntime().addShutdownHook(this.shutdownHook); + } + } +``` + +通过查阅Java的API文档[2], 我们可以知道ShutdownHook将在下面两种情况下执行 + +> The Java virtual machine *shuts down* in response to two kinds of events: +> +> - The program *exits* normally, when the last non-daemon thread exits or when the `exit` (equivalently, [`System.exit`](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#exit-int-)) method is invoked, or +> - The virtual machine is *terminated* in response to a user interrupt, such as typing `^C`, or a system-wide event, such as user logoff or system shutdown. + +1. 调用了System.exit()方法 +2. 响应外部的信号,例如Ctrl+C(其实发送的是SIGINT信号),或者是`SIGTERM`信号(默认`kill $PID`发送的是`SIGTERM`信号) + +因此,正常的应用在停止过程中(`kill -9 $PID`除外),都会执行上述ShutdownHook,它的作用不仅仅是关闭tomcat,还有进行其他的清理工作,在此不再赘述。 + +## 总结 + +1. 在`DubboConsumer`启动的过程中,通过启动一个独立的非daemon线程循环检查变量的状态,确保进程不退出 +2. 在`DubboConsumer`停止的过程中,通过执行spring容器的shutdownhook,修改了变量的状态,使得程序正常退出 + +## 问题 + +在DubboProvider的例子中,我们看到Provider并没有启动Tomcat提供HTTP服务,那又是如何实现不退出的呢?我们将在下一篇文章中回答这个问题。 + +### 彩蛋 + +在`Intellij IDEA`中运行了如下的单元测试,创建一个线程执行睡眠1000秒的操作,我们惊奇的发现,代码并没有线程执行完就退出了,这又是为什么呢?(被创建的线程是非daemon线程) + +```java + @Test + public void test() { + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }).start(); + } +``` + + + +[1] https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.8 + +[2] https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#addShutdownHook diff --git a/content/en/blog/java/demos/test-verification.md b/content/en/blog/java/demos/test-verification.md new file mode 100644 index 000000000000..d53993877313 --- /dev/null +++ b/content/en/blog/java/demos/test-verification.md @@ -0,0 +1,99 @@ +--- +title: "Dubbo测试验证" +linkTitle: "Dubbo测试验证" +tags: ["Java"] +date: 2019-12-02 +description: > + 对正在开发的功能进行验证测试,或者单独调用某台机器的服务 +--- + +除了线上常规的使用场景以外,我们在日常使用中还需要一些特定的使用方式,比如对正在开发的功能进行验证测试,比如单独调用某台机器的服务,这篇文章就来介绍一下这些场景下的使用方式。 + +### 只订阅 +为方便开发测试,经常会在线下共用一个所有服务可用的注册中心,这时,如果一个正在开发中的服务提供者注册,可能会影响消费者不能正常运行。 + +可以让服务提供者开发方,只订阅服务(开发的服务可能依赖其它服务),而不注册正在开发的服务,通过直连测试正在开发的服务。 +![subscribe-only](/imgs/blog/subscribe-only.jpg) +禁用注册配置 + + +或者 + + + +### 指定IP调用 +在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,点对点直联方式,将以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点对点,不影响 B 接口从注册中心获取列表 +![subscribe-only](/imgs/blog/dubbo-directly.jpg) + +可以通过以下几种配置来指定IP调用 + +* XML 配置: 如果是线上需求需要点对点,可在 中配置 url 指向提供者,将绕过注册中心,多个地址用分号隔开,配置如下: + `` +* 通过-D参数指定: 在 JVM 启动参数中加入-D参数映射服务地址,如:`java -Dcom.alibaba.xxx.XxxService=dubbo://localhost:20890` +* 通过文件映射: 如果服务比较多,也可以用文件映射,用 -Ddubbo.resolve.file 指定映射文件路径,此配置优先级高于 中的配置,如: +`java -Ddubbo.resolve.file=xxx.properties` +然后在映射文件 xxx.properties 中加入配置,其中 key 为服务名,value 为服务提供者 URL:`com.alibaba.xxx.XxxService=dubbo://localhost:20890` + +### 回声测试 +#### 使用方式 +回声测试用于检测服务是否可用,回声测试按照正常请求流程执行,能够测试整个调用是否通畅,可用于监控。 + +所有服务自动实现 EchoService 接口,只需将任意服务引用强制转型为 EchoService,即可使用。 + +Spring 配置: + + +代码: + +``` +// 远程服务引用 +MemberService memberService = ctx.getBean("memberService"); + +EchoService echoService = (EchoService) memberService; // 强制转型为EchoService + +// 回声测试可用性 +String status = echoService.$echo("OK"); + +assert(status.equals("OK")); +``` +#### 实现原理 +我们在实现,注册服务的时候,并没有配置EchoService这个接口,为什么可以直接使用呢?原来是Dubbo在生成proxy的时候,已经实现了`EchoService这个接口` + +```java + @Override + public T getProxy(Invoker invoker) throws RpcException { + Class[] interfaces = null; + String config = invoker.getUrl().getParameter("interfaces"); + if (config != null && config.length() > 0) { + String[] types = Constants.COMMA_SPLIT_PATTERN.split(config); + if (types != null && types.length > 0) { + interfaces = new Class[types.length + 2]; + interfaces[0] = invoker.getInterface(); + interfaces[1] = EchoService.class; + for (int i = 0; i < types.length; i++) { + interfaces[i + 1] = ReflectUtils.forName(types[i]); + } + } + } + if (interfaces == null) { + interfaces = new Class[]{invoker.getInterface(), EchoService.class}; + } + return getProxy(invoker, interfaces); + } +``` +通过这种方式,任何bean都可以被转换成EchoService的实例,但是并没有实现`$echo`这个方法,这里,Dubbo使用filter机制做了处理: + +```java +public class EchoFilter implements Filter { + + @Override + public Result invoke(Invoker invoker, Invocation inv) throws RpcException { + if (inv.getMethodName().equals(Constants.$ECHO) && inv.getArguments() != null && inv.getArguments().length == 1) + return new RpcResult(inv.getArguments()[0]); + return invoker.invoke(inv); + } + +} +``` +在经过EchoFilter.invoke方法时,如果调用的是`$echo`,会中断当前的调用过程,直接返回`$echo`的入参,否则会继续执行Filter链。 +通过动态代理和EchoFilter机制,使得回声测试的整个过程对用户透明,不需要做任何额外的配置,直接调用即可。 diff --git a/content/en/blog/java/demos/v3.2_rest_protocol_design.md b/content/en/blog/java/demos/v3.2_rest_protocol_design.md new file mode 100644 index 000000000000..6463c64ad35a --- /dev/null +++ b/content/en/blog/java/demos/v3.2_rest_protocol_design.md @@ -0,0 +1,660 @@ +--- +aliases: + - /en/docs3-v2/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ + - /en/docs3-v2/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ + - /en/overview/mannual/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ + - /en/overview/mannual/java-sdk/reference-manual/protocol/v3.2_rest_protocol_design/ +description: 本文将介绍 Dubbo 2.x 版本中的 Rest 协议及其未来的重构方向。 +linkTitle: 2.7 版本 Rest 协议实现重构设想 +title: Rest 协议 +tags: ["Java"] +date: 2022-07-26 +--- + + + + +# Dubbo RestProtocol 设计文档 + +## 原版本dubbo rest + +consumer + +restClient支持 依赖resteasy 不支持spring mvc  + +provider(较重) + +依赖web container   (tomcat,jetty,)servlet 模式,jaxrs netty server + +### 改版dubbo rest  + +方向: + +更加轻量,具有dubbo风格的rest,微服务体系互通(Springcloud Alibaba) + +1.注解解析 + +2.报文编解码 + +3.restClient + +4.restServer(netty) + +支持程度: + +content-type   text json xml form(后续会扩展) + +注解 + +param,header,body,pathvariable (spring mvc & resteasy) + +## Http 协议报文 + + POST /test/path? HTTP/1.1 + Host: localhost:8080 + Connection: keep-alive + Content-type: application/json + + + {"name":"dubbo","age":10,"address":"hangzhou"} + + + +### dubbo http(header) + + // service key header + path: com.demo.TestInterface + group: demo + port: 80 + version: 1.0.0 + + // 保证长连接 + Keep-Alive,Connection: keep-alive + Keep-alive: 60 + + // RPCContext Attachment + userId: 123456 + + +## 目前支持粒度: + +| 数据位置 | content-type | spring注解 | resteasy注解 | +| --- | --- | --- | --- | +| body | 无要求 | ReuqestBody |  无注解即为body | +| querystring(?test=demo) | 无要求 | RequestParam | QueryParam | +| header | 无要求 | RequestHeader | PathParam | +| form | application/x-www-form-urlencoded | RequestParam ReuqestBody | FormParam | +| path | 无要求 | PathVariable | PathParam | +| method | 无要求 | PostMapping GetMapping | GET POST | +| url | | PostMapping GetMapping path属性 | Path | +| content-type | | PostMapping GetMapping consumers属性 | Consumers | +| Accept | | PostMapping GetMapping produces属性 | Produces | + +## rest注解解析(ServiceRestMetadataResolver) + + JAXRSServiceRestMetadataResolver + + SpringMvcServiceRestMetadataResolver + +ServiceRestMetadata + + public class ServiceRestMetadata implements Serializable { + + private String serviceInterface; // com.demo.TestInterface + + private String version;// 1.0.0 + + private String group;// demo + + private Set meta;// method 元信息 + + private int port;// 端口 for provider service key + + private boolean consumer;// consumer 标志 + + /** + * make a distinction between mvc & resteasy + */ + private Class codeStyle;// + + /** + * for provider + */ + private Map pathToServiceMap; + + /** + * for consumer + */ + private Map> methodToServiceMa + +RestMethodMetadata + + public class RestMethodMetadata implements Serializable { + + private MethodDefinition method; // method 定义信息(name ,pramType,returnType) + + private RequestMetadata request;// 请求元信息 + + private Integer urlIndex; + + private Integer bodyIndex; + + private Integer headerMapIndex; + + private String bodyType; + + private Map> indexToName; + + private List formParams; + + private Map indexToEncoded; + + private ServiceRestMetadata serviceRestMetadata; + + private List argInfos; + + private Method reflectMethod; + + /** + * make a distinction between mvc & resteasy + */ + private Class codeStyle; + + +ArgInfo + + public class ArgInfo { + /** + * method arg index 0,1,2,3 + */ + private int index; + /** + * method annotation name or name + */ + private String annotationNameAttribute; + + /** + * param annotation type + */ + private Class paramAnnotationType; + + /** + * param Type + */ + private Class paramType; + + /** + * param name + */ + private String paramName; + + /** + * url split("/") String[n] index + */ + private int urlSplitIndex; + + private Object defaultValue; + + private boolean formContentType; + +RequestMeatadata + + public class RequestMetadata implements Serializable { + + private static final long serialVersionUID = -240099840085329958L; + + private String method;// 请求method + + private String path;// 请求url + + + private Map> params // param参数?拼接 + + private Map> headers// header; + + private Set consumes // content-type; + + private Set produces // Accept; + +### Consumer 代码: + +refer: + + @Override + protected Invoker protocolBindingRefer(final Class type, final URL url) throws RpcException { + + // restClient spi创建 + ReferenceCountedClient refClient = + clients.computeIfAbsent(url.getAddress(), key -> createReferenceCountedClient(url, clients)); + + refClient.retain(); + + // resolve metadata + Map> metadataMap = MetadataResolver.resolveConsumerServiceMetadata(type, url); + + ReferenceCountedClient finalRefClient = refClient; + Invoker invoker = new AbstractInvoker(type, url, new String[]{INTERFACE_KEY, GROUP_KEY, TOKEN_KEY}) { + @Override + protected Result doInvoke(Invocation invocation) { + try { + // 获取 method的元信息 + RestMethodMetadata restMethodMetadata = metadataMap.get(invocation.getMethodName()).get(ParameterTypesComparator.getInstance(invocation.getParameterTypes())); + + RequestTemplate requestTemplate = new RequestTemplate(invocation, restMethodMetadata.getRequest().getMethod(), url.getAddress(), getContextPath(url)); + + HttpConnectionCreateContext httpConnectionCreateContext = new HttpConnectionCreateContext(); + // TODO dynamic load config + httpConnectionCreateContext.setConnectionConfig(new HttpConnectionConfig()); + httpConnectionCreateContext.setRequestTemplate(requestTemplate); + httpConnectionCreateContext.setRestMethodMetadata(restMethodMetadata); + httpConnectionCreateContext.setInvocation(invocation); + httpConnectionCreateContext.setUrl(url); + + // http 信息构建拦截器 + for (HttpConnectionPreBuildIntercept intercept : httpConnectionPreBuildIntercepts) { + intercept.intercept(httpConnectionCreateContext); + } + + + CompletableFuture future = finalRefClient.getClient().send(requestTemplate); + CompletableFuture responseFuture = new CompletableFuture<>(); + AsyncRpcResult asyncRpcResult = new AsyncRpcResult(responseFuture, invocation); + // response 处理 + future.whenComplete((r, t) -> { + if (t != null) { + responseFuture.completeExceptionally(t); + } else { + AppResponse appResponse = new AppResponse(); + try { + int responseCode = r.getResponseCode(); + MediaType mediaType = MediaType.TEXT_PLAIN; + + if (400 < responseCode && responseCode < 500) { + throw new HttpClientException(r.getMessage()); + } else if (responseCode >= 500) { + throw new RemoteServerInternalException(r.getMessage()); + } else if (responseCode < 400) { + mediaType = MediaTypeUtil.convertMediaType(r.getContentType()); + } + + + Object value = HttpMessageCodecManager.httpMessageDecode(r.getBody(), + restMethodMetadata.getReflectMethod().getReturnType(), mediaType); + appResponse.setValue(value); + Map headers = r.headers() + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0))); + appResponse.setAttachments(headers); + responseFuture.complete(appResponse); + } catch (Exception e) { + responseFuture.completeExceptionally(e); + } + } + }); + return asyncRpcResult; + } catch (RpcException e) { + if (e.getCode() == RpcException.UNKNOWN_EXCEPTION) { + e.setCode(getErrorCode(e.getCause())); + } + throw e; + } + } + + @Override + public void destroy() { + super.destroy(); + invokers.remove(this); + destroyInternal(url); + } + }; + invokers.add(invoker); + return invoker; + +### provider 代码: + +export: + + public Exporter export(final Invoker invoker) throws RpcException { + URL url = invoker.getUrl(); + final String uri = serviceKey(url); + Exporter exporter = (Exporter) exporterMap.get(uri); + if (exporter != null) { + // When modifying the configuration through override, you need to re-expose the newly modified service. + if (Objects.equals(exporter.getInvoker().getUrl(), invoker.getUrl())) { + return exporter; + } + } + + + // TODO addAll metadataMap to RPCInvocationBuilder metadataMap + Map metadataMap = MetadataResolver.resolveProviderServiceMetadata(url.getServiceModel().getProxyObject().getClass(),url); + + PathAndInvokerMapper.addPathAndInvoker(metadataMap, invoker); + + + final Runnable runnable = doExport(proxyFactory.getProxy(invoker, true), invoker.getInterface(), invoker.getUrl()); + exporter = new AbstractExporter(invoker) { + @Override + public void afterUnExport() { + exporterMap.remove(uri); + if (runnable != null) { + try { + runnable.run(); + } catch (Throwable t) { + logger.warn(PROTOCOL_UNSUPPORTED, "", "", t.getMessage(), t); + } + } + } + }; + exporterMap.put(uri, exporter); + return exporter; + } + +RestHandler + + private class RestHandler implements HttpHandler { + + @Override + public void handle(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException, ServletException { + // 有servlet reuqest 和nettyRequest + RequestFacade request = RequestFacadeFactory.createRequestFacade(servletRequest); + RpcContext.getServiceContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort()); + // dispatcher.service(request, servletResponse); + + Pair build = null; + try { + // 根据请求信息创建 RPCInvocation + build = RPCInvocationBuilder.build(request, servletRequest, servletResponse); + } catch (PathNoFoundException e) { + servletResponse.setStatus(404); + } + + Invoker invoker = build.getSecond(); + + Result invoke = invoker.invoke(build.getFirst()); + + // TODO handling exceptions + if (invoke.hasException()) { + servletResponse.setStatus(500); + } else { + + try { + Object value = invoke.getValue(); + String accept = request.getHeader(RestConstant.ACCEPT); + MediaType mediaType = MediaTypeUtil.convertMediaType(accept); + // TODO write response + HttpMessageCodecManager.httpMessageEncode(servletResponse.getOutputStream(), value, invoker.getUrl(), mediaType); + servletResponse.setStatus(200); + } catch (Exception e) { + servletResponse.setStatus(500); + } + + + } + + // TODO add Attachment header + + + } + } + +RPCInvocationBuilder + + { + + + private static final ParamParserManager paramParser = new ParamParserManager(); + + + public static Pair build(RequestFacade request, Object servletRequest, Object servletResponse) { + + // 获取invoker + Pair invokerRestMethodMetadataPair = getRestMethodMetadata(request); + + RpcInvocation rpcInvocation = createBaseRpcInvocation(request, invokerRestMethodMetadataPair.getSecond()); + + ProviderParseContext parseContext = createParseContext(request, servletRequest, servletResponse, invokerRestMethodMetadataPair.getSecond()); + // 参数构建 + Object[] args = paramParser.providerParamParse(parseContext); + + rpcInvocation.setArguments(args); + + return Pair.make(rpcInvocation, invokerRestMethodMetadataPair.getFirst()); + + } + + private static ProviderParseContext createParseContext(RequestFacade request, Object servletRequest, Object servletResponse, RestMethodMetadata restMethodMetadata) { + ProviderParseContext parseContext = new ProviderParseContext(request); + parseContext.setResponse(servletResponse); + parseContext.setRequest(servletRequest); + + Object[] objects = new Object[restMethodMetadata.getArgInfos().size()]; + parseContext.setArgs(Arrays.asList(objects)); + parseContext.setArgInfos(restMethodMetadata.getArgInfos()); + + + return parseContext; + } + + private static RpcInvocation createBaseRpcInvocation(RequestFacade request, RestMethodMetadata restMethodMetadata) { + RpcInvocation rpcInvocation = new RpcInvocation(); + + + int localPort = request.getLocalPort(); + String localAddr = request.getLocalAddr(); + int remotePort = request.getRemotePort(); + String remoteAddr = request.getRemoteAddr(); + + String HOST = request.getHeader(RestConstant.HOST); + String GROUP = request.getHeader(RestConstant.GROUP); + + String PATH = request.getHeader(RestConstant.PATH); + String VERSION = request.getHeader(RestConstant.VERSION); + + String METHOD = restMethodMetadata.getMethod().getName(); + String[] PARAMETER_TYPES_DESC = restMethodMetadata.getMethod().getParameterTypes(); + + rpcInvocation.setParameterTypes(restMethodMetadata.getReflectMethod().getParameterTypes()); + + + rpcInvocation.setMethodName(METHOD); + rpcInvocation.setAttachment(RestConstant.GROUP, GROUP); + rpcInvocation.setAttachment(RestConstant.METHOD, METHOD); + rpcInvocation.setAttachment(RestConstant.PARAMETER_TYPES_DESC, PARAMETER_TYPES_DESC); + rpcInvocation.setAttachment(RestConstant.PATH, PATH); + rpcInvocation.setAttachment(RestConstant.VERSION, VERSION); + rpcInvocation.setAttachment(RestConstant.HOST, HOST); + rpcInvocation.setAttachment(RestConstant.REMOTE_ADDR, remoteAddr); + rpcInvocation.setAttachment(RestConstant.LOCAL_ADDR, localAddr); + rpcInvocation.setAttachment(RestConstant.REMOTE_PORT, remotePort); + rpcInvocation.setAttachment(RestConstant.LOCAL_PORT, localPort); + + Enumeration attachments = request.getHeaders(RestConstant.DUBBO_ATTACHMENT_HEADER); + + while (attachments != null && attachments.hasMoreElements()) { + String s = attachments.nextElement(); + + String[] split = s.split("="); + + rpcInvocation.setAttachment(split[0], split[1]); + } + + + // TODO set path,version,group and so on + return rpcInvocation; + } + + + private static Pair getRestMethodMetadata(RequestFacade request) { + String path = request.getRequestURI(); + String version = request.getHeader(RestConstant.VERSION); + String group = request.getHeader(RestConstant.GROUP); + int port = request.getIntHeader(RestConstant.REST_PORT); + + return PathAndInvokerMapper.getRestMethodMetadata(path, version, group, port); + } + + + } + +## 编码示例 + +API + +mvc: + + @RestController() + @RequestMapping("/demoService") + public interface DemoService { + @RequestMapping(value = "/hello", method = RequestMethod.GET) + Integer hello(@RequestParam Integer a, @RequestParam Integer b); + + @RequestMapping(value = "/error", method = RequestMethod.GET) + String error(); + + @RequestMapping(value = "/say", method = RequestMethod.POST, consumes = MediaType.TEXT_PLAIN_VALUE) + String sayHello(@RequestBody String name); + } + +resteasy: + + @Path("/demoService") + public interface RestDemoService { + @GET + @Path("/hello") + Integer hello(@QueryParam("a")Integer a,@QueryParam("b") Integer b); + + @GET + @Path("/error") + String error(); + + @POST + @Path("/say") + @Consumes({MediaType.TEXT_PLAIN}) + String sayHello(String name); + + boolean isCalled(); + } + +impl(service) + + @DubboService() + public class RestDemoServiceImpl implements RestDemoService { + private static Map context; + private boolean called; + + + @Override + public String sayHello(String name) { + called = true; + return "Hello, " + name; + } + + + public boolean isCalled() { + return called; + } + + @Override + public Integer hello(Integer a, Integer b) { + context = RpcContext.getServerAttachment().getObjectAttachments(); + return a + b; + } + + + @Override + public String error() { + throw new RuntimeException(); + } + + public static Map getAttachments() { + return context; + } + } + +## 流程图 + +**Consumer**   + +![image](https://static.dingtalk.com/media/lQLPJxLOtqTxs9TNA5rNBQCwci8F2QYiGAYD5sSyd4BVAA_1280_922.png) + +**Provider(RestServer)** + +![image](https://static.dingtalk.com/media/lQLPJxZcNUm4M9TNA1_NBMuwZUu6IC3FeYAD5sSydYADAA_1227_863.png) + +## 场景 : + +**非dubbo体系互通(Springcloud alibaba  互通)** + +互通条件: + +| | 协议 | Dubbo | SpringCloud Alibaba | 互通 | +| --- | --- | --- | --- | --- | +| 通信协议 | rest | spring web/resteasy  编码风格 | 集成feignclient,ribbon (spring web 编码风格) | 是 | +| | triple | | | | +| | dubbo | | | | +| | grpc | | | | +| | hessian | | | | +| 注册中心 | zookeeper | | | | +| | nacos | 支持 | 支持 | 应用级别注册 | + +### 2.dubbo 双注册  + + 完成应用级别注册,(dubo2-dubbo3 过度),dubbo版本升级 + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/0ceca951-f467-4ab3-9b71-8e7d52e5e7d1.png) + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/6bcc7aed-1d22-470f-b185-efbab32df1e5.png) + +### 3.多协议发布 + +配置: + + + +### 4.跨语言 + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/1bdf8f91-9666-4c20-9aea-8396c745f554.png) + +### 5.多协议交互 + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/af72e3df-05d5-42a2-a333-618be7ec6cb8.png) + +### 6.协议迁移 + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/36d30183-8d5f-494c-8ebb-b57403c88661.png) + +rest编码风格 + +Http协议更通用跨语言调用 + +dubbo rest 对其他http服务 进行调用 + +其他httpclient 对dubbo rest进行调用 + +dubbo restServer 可以与其他web服务,浏览器等客户端直接进行http交互 + +## consumer TODOLIST(功能已经初步实现,可以调通解析response) + +1. org/apache/dubbo/rpc/protocol/rest/RestProtocol.java:157  dynamic load config + +2.org/apache/dubbo/remoting/http/factory/AbstractHttpClientFactory.java:50 load config  HttpClientConfig + +3.org/apache/dubbo/rpc/protocol/rest/annotation/metadata/MetadataResolver.java:52  support Dubbo style service + +4.org/apache/dubbo/remoting/http/restclient/HttpClientRestClient.java:120  TODO config + +5.org/apache/dubbo/remoting/http/restclient/HttpClientRestClient.java:140 TODO close judge + +6.org/apache/dubbo/rpc/protocol/rest/message/decode/MultiValueCodec.java:35  TODO java bean  get set convert + +## provider TODOLIST(待实现) + +基于netty实现支持http协议的NettyServer + +无注解协议定义 + +官网场景补充 + +## Rest使用说明文档及demo: diff --git a/content/en/blog/java/proposals/_index.md b/content/en/blog/java/proposals/_index.md new file mode 100644 index 000000000000..cfafe94c7d75 --- /dev/null +++ b/content/en/blog/java/proposals/_index.md @@ -0,0 +1,7 @@ +--- +title: "方案设计" +linkTitle: "方案设计" +weight: 30 +--- + + diff --git a/content/en/blog/java/proposals/service-discovery-migration.md b/content/en/blog/java/proposals/service-discovery-migration.md new file mode 100644 index 000000000000..29ff4c81e197 --- /dev/null +++ b/content/en/blog/java/proposals/service-discovery-migration.md @@ -0,0 +1,401 @@ +--- +aliases: + - /en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery/ +title: "如果从接口级服务发现平滑迁移到应用级服务发现" +linkTitle: "Dubbo3 服务发现平滑迁移步骤与原理" +tags: ["Java","服务发现"] +date: 2024-05-13 +description: > + "Dubbo3 应用级服务发现迁移详情,如果从接口级服务发现平滑迁移到应用级服务发现,迁移规则详情与工作原理。" +--- + +总体上来说,在地址注册与发现环节,`3.x` 是完全兼容 `2.x` 版本的,这意味着,用户可以选择将集群内任意数量的应用或机器升级到 `3.x`,同时在这个过程中保持与 `2.x` 版本的互操作性。 + +> 如关心迁移背后工作原理,请参考 [迁移规则详情与工作原理](../service-discovery-rule) + +## 1 快速升级步骤 + +简单的修改 pom.xml 到最新版本就可以完成升级,如果要迁移到应用级地址,只需要调整开关控制 3.x 版本的默认行为。 + +1. 升级 Provider 应用到最新 3.x 版本依赖,配置双注册开关`dubbo.application.register-mode=all`(建议通过全局配置中心设置,默认已自动开启),完成应用发布。 +2. 升级 Consumer 应用到最新 3.x 版本依赖,配置双订阅开关`dubbo.application.service-discovery.migration=APPLICATION_FIRST`(建议通过全局配置中心设置,默认已自动开启),完成应用发布。 +3. 在确认 Provider 的上有 Consumer 全部完成应用级地址迁移后,Provider 切到应用级地址单注册。完成升级 + + + +以下是关于迁移流程的详细描述。 + +## 2 Provider 端升级过程详解 + +在不改变任何 Dubbo 配置的情况下,可以将一个应用或实例升级到 3.x 版本,升级后的 Dubbo 实例会默保保证与 2.x 版本的兼容性,即会正常注册 2.x 格式的地址到注册中心,因此升级后的实例仍会对整个集群仍保持可见状态。 + +同时新的地址发现模型(注册应用级别的地址)也将会自动注册。 + +![//imgs/v3/migration/provider-registration.png](/imgs/v3/migration/provider-registration.png) + +1. 全局开关 + +应用配置(可以通过配置文件或者 -D 指定)`dubbo.application.register-mode` 为 instance(只注册应用级)、all(接口级+应用级均注册)开启全局的注册开关,配置此开关后,默认会向所有的注册中心中注册应用级的地址,供消费端服务发现使用。 + +``` +# 双注册 +dubbo.application.register-mode=all +``` +``` +# 仅应用级注册 +dubbo.application.register-mode=instance +``` +通过 -D 参数,可以指定 provider 启动时的注册行为 + +```text +-Ddubbo.application.register-mode=all +# 可选值 interface、instance、all,默认是 all,即接口级地址、应用级地址都注册 +``` + +另外,可以在配置中心修改全局默认行为,来控制所有 3.x 实例注册行为。其中,全局性开关的优先级低于 -D 参数。 + +2. 注册中心地址参数配置 + +注册中心的地址上可以配置 `registry-type=service` 来显示指定该注册中心为应用级服务发现的注册中心,带上此配置的注册中心将只进行应用级服务发现。 +> [参考示例](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-demo-servicediscovery-xml/servicediscovery-provider/src/main/resources/spring/dubbo-provider.xml) + +```xml + +``` + +为了保证平滑迁移,即升级到 3.x 的实例能同时被 2.x 与 3.x 的消费者实例发现,3.x 实例需要开启双注册;当所有上游的消费端都迁移到 3.x 的地址模型后,提供端就可以切换到 instance 模式(只注册应用级地址)。对于如何升级消费端到 3.x 请参见下一小节。 + +### 2.1 双注册带来的资源消耗 + +双注册不可避免的会带来额外的注册中心存储压力,但考虑到应用级地址发现模型的数据量在存储方面的极大优势,即使对于一些超大规模集群的用户而言,新增的数据量也并不会带来存储问题。总体来说,对于一个普通集群而言,数据增长可控制在之前数据总量的 1/100 ~ 1/1000 + +以一个中等规模的集群实例来说: 2000 实例、50个应用(500 个 Dubbo 接口,平均每个应用 10 个接口)。 + +​ 假设每个接口级 URL 地址平均大小为 5kb,每个应用级 URL 平均大小为 0.5kb + +​ 老的接口级地址量:2000 * 500 * 5kb ≈ 4.8G + +​ 新的应用级地址量:2000 * 50 * 0.5kb ≈ 48M + +​ 双注册后仅仅增加了 48M 的数据量。 + + + +## 3 Consumer 端升级过程 + +对于 2.x 的消费者实例,它们看到的自然都是 2.x 版本的提供者地址列表; + +对于 3.x 的消费者,它具备同时发现 2.x 与 3.x 提供者地址列表的能力。在默认情况下,如果集群中存在可以消费的 3.x 的地址,将自动消费 3.x 的地址,如果不存在新地址则自动消费 2.x 的地址。Dubbo3 提供了开关来控制这个行为: + +```text +dubbo.application.service-discovery.migration=APPLICATION_FIRST +# 可选值 +# FORCE_INTERFACE,只消费接口级地址,如无地址则报错,单订阅 2.x 地址 +# APPLICATION_FIRST,智能决策接口级/应用级地址,双订阅 +# FORCE_APPLICATION,只消费应用级地址,如无地址则报错,单订阅 3.x 地址 +``` + +![//imgs/v3/migration/consumer-subscription.png](/imgs/v3/migration/consumer-subscription.png) + +1. 默认配置(不需要配置) + +升级到 Dubbo 3.0 后默认行为为接口级+应用级多订阅,如果应用级能订阅到地址就使用应用级的订阅,如果订阅不到地址则使用接口级的订阅,以此保证最大的兼容性。 + +2. 订阅参数配置 + +应用配置(可以通过配置文件或者 -D 指定)`dubbo.application.service-discovery.migration` 为 `APPLICATION_FIRST` 可以开启多订阅模式,配置为 `FORCE_APPLICATION` 可以强制为仅应用级订阅模式。 +具体接口订阅可以在 `ReferenceConfig` 中的 `parameters` 中配置 Key 为 `migration.step`,Value 为 `APPLICATION_FIRST` 或 `FORCE_APPLICATION` 的键值对来对单一订阅进行配置。 + +`dubbo.application.service-discovery.migration ` 支持通过 `-D` 以及 `全局配置中心` 两种方式进行配置。 + +> [参考示例](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-consumer/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConfigIT.java) + +```java +System.setProperty("dubbo.application.service-discovery.migration", "APPLICATION_FIRST"); +``` +```java +ReferenceConfig referenceConfig = new ReferenceConfig<>(applicationModel.newModule()); +referenceConfig.setInterface(DemoService.class); +referenceConfig.setParameters(new HashMap<>()); +referenceConfig.getParameters().put("migration.step", mode); +return referenceConfig.get(); +``` + +3. 动态配置(优先级最高,可以在运行时修改配置) + +此配置需要基于配置中心进行推送,Key 为应用名 + `.migration` (如 `demo-application.migraion`),Group 为 `DUBBO_SERVICEDISCOVERY_MIGRATION`。规则体配置详见[接口级服务发现迁移至应用级服务发现指南](../migration-service-discovery/)。 +> [参考示例](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-consumer/src/main/java/org/apache/dubbo/demo/consumer/UpgradeUtil.java) + +```java +step: FORCE_INTERFACE +``` + + +接下来,我们就具体看一下,如何通过双订阅模式(APPLICATION_FIRST)让升级到 3.x 的消费端迁移到应用级别的地址。在具体展开之前,先明确一条消费端的选址行为:**对于双订阅的场景,消费端虽然可同时持有 2.x 地址与 3.x 地址,但选址过程中两份地址是完全隔离的:要么用 2.x 地址,要么用 3.x 地址,不存在两份地址混合调用的情况,这个决策过程是在收到第一次地址通知后就完成了的。** + + + +下面,我们看一个`APPLICATION_FIRST`策略的具体操作过程。 + +首先,提前在全局配置中心 Nacos 配置一条配置项(所有消费端都将默认执行这个选址策略): + +![//imgs/v3/migration/nacos-migration-item.png](/imgs/v3/migration/nacos-migration-item.png) + + + +紧接着,升级消费端到 3.x 版本并启动,这时消费端读取到`APPLICATION_FIRST`配置后,执行双订阅逻辑(订阅 2.x 接口级地址与 3.x 应用级地址) + + + +至此,升级操作就完成了,剩下的就是框架内部的执行了。在调用发生前,框架在消费端会有一个“选址过程”,注意这里的选址和之前 2.x 版本是有区别的,选址过程包含了两层筛选: + +* 先进行地址列表(ClusterInvoker)筛选(接口级地址 or 应用级地址) +* 再进行实际的 provider 地址(Invoker)筛选。 + +![//imgs/v3/migration/migration-cluster-item.png](/imgs/v3/migration/migration-cluster-invoker.png) + +ClusterInvoker 筛选的依据,可以通过 MigrationAddressComparator SPI 自行定义,目前官方提供了一个简单的地址数量比对策略,即当 `应用级地址数量 == 接口级地址数量` 满足时则进行迁移。 + +> 其实 FORCE_INTERFACE、APPLICATION_FIRST、FORCE_APPLICATION 控制的都是这里的 ClusterInvoker 类型的筛选策略 + + + +### 3.1 双订阅带来的资源消耗 + +双订阅不可避免的会增加消费端的内存消耗,但由于应用级地址发现在地址总量方面的优势,这个过程通常是可接受的,我们从两个方面进行分析: + +1. 双订阅带来的地址推送数据量增长。这点我们在 ”双注册资源消耗“ 一节中做过介绍,应用级服务发现带来的注册中心数据量增长非常有限。 +2. 双订阅带来的消费端内存增长。要注意双订阅只存在于启动瞬态,在ClusterInvoker选址决策之后其中一份地址就会被完全销毁;对单个服务来说,启动阶段双订阅带来的内存增长大概能控制在原内存量的 30% ~ 40%,随后就会下降到单订阅水平,如果切到应用级地址,能实现内存 50% 的下降。 + + + +### 3.2 消费端更细粒度的控制 + +除了全局的迁移策略之外,Dubbo 在消费端提供了更细粒度的迁移策略支持。控制单位可以是某一个消费者应用,它消费的服务A、服务B可以有各自独立的迁移策略,具体是用方式是在消费端配置迁移规则: + + +```yaml +key: demo-consumer +step: APPLICATION_FIRST +applications: + - name: demo-provider + step: FORCE_APPLICATION +services: + - serviceKey: org.apache.dubbo.config.api.DemoService:1.0.0 + step: FORCE_INTERFACE +``` + +使用这种方式能做到比较精细迁移控制,但是当下及后续的改造成本会比较高,除了一些特别场景,我们不太推荐启用这种配置方式。 +[迁移指南](../service-discovery-rule/)官方推荐使用的全局的开关式的迁移策略,让消费端实例在启动阶段自行决策使用哪份可用的地址列表。 + + + +## 4 迁移状态的收敛 + +为了同时兼容 2.x 版本,升级到 3.x 版本的应用在一段时间内要么处在双注册状态,要么处在双订阅状态。 + +解决这个问题,我们还是从 Provider 视角来看,当所有的 Provider 都切换到应用级地址注册之后,也就不存在双订阅的问题了。 + +### 4.1 不同的升级策略影响很大 + +毫无疑问越早越彻底的升级,就能尽快摆脱这个局面。设想,如果可以将组织内所有的应用都升级到 3.x 版本,则版本收敛就变的非常简单:升级过程中 Provider 始终保持双注册,当所有的应用都升级到 3.x 之后,就可以调整全局默认行为,让 Provider 都变成应用级地址单注册了,这个过程并不会给 Consumer 应用带来困扰,因为它们已经是可以识别应用级地址的 3.x 版本了。 + +如果没有办法做到应用的全量升级,甚至在相当长的时间内只能升级一部分应用,则不可避免的迁移状态要持续比较长的时间。 +在这种情况下,我们追求的只能是尽量保持已升级应用的上下游实现版本及功能收敛。推动某些 Provider 的上游消费者都升级到 Dubbo3,这样就可以解除这部分 Provider 的双注册,要做到这一点,可能需要一些辅助统计工具的支持。 + +1. 要能分析出应用间的依赖关系,比如一个 Provdier 应用被哪些消费端应用消费,这可以通过 Dubbo 提供的服务元数据上报能力来实现。 +2. 要能知道每个应用当前使用的 dubbo 版本,可以通过扫描或者主动上报手段。 + +## 5. 迁移状态模型 + +在 Dubbo 3 之前地址注册模型是以接口级粒度注册到注册中心的,而 Dubbo 3 全新的应用级注册模型注册到注册中心的粒度是应用级的。从注册中心的实现上来说是几乎不一样的,这导致了对于从接口级注册模型获取到的 invokers 是无法与从应用级注册模型获取到的 invokers 进行合并的。为了帮助用户从接口级往应用级迁移,Dubbo 3 设计了 Migration 机制,基于三个状态的切换实现实际调用中地址模型的切换。 + +![//imgs/v3/migration/migration-1.png](/imgs/v3/migration/migration-1.png) + +当前共存在三种状态,FORCE_INTERFACE(强制接口级),APPLICATION_FIRST(应用级优先)、FORCE_APPLICATION(强制应用级)。 + + +FORCE_INTERFACE:只启用兼容模式下接口级服务发现的注册中心逻辑,调用流量 100% 走原有流程 +APPLICATION_FIRST:开启接口级、应用级双订阅,运行时根据阈值和灰度流量比例动态决定调用流量走向 +FORCE_APPLICATION:只启用新模式下应用级服务发现的注册中心逻辑,调用流量 100% 走应用级订阅的地址 + + +### 5.1 规则体说明 + + +规则采用 yaml 格式配置,具体配置下参考如下: +```yaml +key: 消费者应用名(必填) +step: 状态名(必填) +threshold: 决策阈值(默认1.0) +proportion: 灰度比例(默认100) +delay: 延迟决策时间(默认0) +force: 强制切换(默认 false) +interfaces: 接口粒度配置(可选) + - serviceKey: 接口名(接口 + : + 版本号)(必填) + threshold: 决策阈值 + proportion: 灰度比例 + delay: 延迟决策时间 + force: 强制切换 + step: 状态名(必填) + - serviceKey: 接口名(接口 + : + 版本号) + step: 状态名 +applications: 应用粒度配置(可选) + - serviceKey: 应用名(消费的上游应用名)(必填) + threshold: 决策阈值 + proportion: 灰度比例 + delay: 延迟决策时间 + force: 强制切换 + step: 状态名(必填) +``` + + +- key: 消费者应用名 +- step: 状态名(FORCE_INTERFACE、APPLICATION_FIRST、FORCE_APPLICATION) +- threshold: 决策阈值(浮点数,具体含义参考后文) +- proportion: 灰度比例(0~100,决定调用次数比例) +- delay: 延迟决策时间(延迟决策的时间,实际等待时间为 1~2 倍 delay 时间,取决于注册中心第一次通知的时间,对于目前 Dubbo 的注册中心实现次配置项保留 0 即可) +- force: 强制切换(对于 FORCE_INTERFACE、FORCE_APPLICATION 是否不考虑决策直接切换,可能导致无地址调用失败问题) +- interfaces: 接口粒度配置 + + + +参考配置示例如下: +```yaml +key: demo-consumer +step: APPLICATION_FIRST +threshold: 1.0 +proportion: 60 +delay: 0 +force: false +interfaces: + - serviceKey: DemoService:1.0.0 + threshold: 0.5 + proportion: 30 + delay: 0 + force: true + step: APPLICATION_FIRST + - serviceKey: GreetingService:1.0.0 + step: FORCE_APPLICATION +``` + + +### 5.1 配置方式说明 +#### 1. 配置中心配置文件下发(推荐) + + +- Key: 消费者应用名 + ".migration" +- Group: DUBBO_SERVICEDISCOVERY_MIGRATION + + +配置项内容参考上一节 + + +程序启动时会拉取此配置作为最高优先级启动项,当配置项为启动项时不执行检查操作,直接按状态信息达到终态。 +程序运行过程中收到新配置项将执行迁移操作,过程中根据配置信息进行检查,如果检查失败将回滚为迁移前状态。迁移是按接口粒度执行的,也即是如果一个应用有 10 个接口,其中 8 个迁移成功,2 个失败,那终态 8 个迁移成功的接口将执行新的行为,2 个失败的仍为旧状态。如果需要重新触发迁移可以通过重新下发规则达到。 + + +注:如果程序在迁移时由于检查失败回滚了,由于程序无回写配置项行为,所以如果此时程序重启了,那么程序会直接按照新的行为不检查直接初始化。 + + +#### 2. 启动参数配置 + + +- 配置项名:dubbo.application.service-discovery.migration +- 允许值范围:FORCE_INTERFACE、APPLICATION_FIRST、FORCE_APPLICATION + + + +此配置项可以通过环境变量或者配置中心传入,启动时优先级比配置文件低,也即是当配置中心的配置文件不存在时读取此配置项作为启动状态。 + + +#### 3. 本地文件配置 + + + +| 配置项名 | 默认值 | 说明 | +| --- | --- | --- | +| dubbo.migration.file | dubbo-migration.yaml | 本地配置文件路径 | +| dubbo.application.migration.delay | 60000 | 配置文件延迟生效时间(毫秒) | + +配置文件中格式与前文提到的规则一致 + + +本地文件配置方式本质上是一个延时配置通知的方式,本地文件不会影响默认启动方式,当达到延时时间后触发推送一条内容和本地文件一致的通知。这里的延时时间与规则体中的 delay 字段无关联。 +本地文件配置方式可以保证启动以默认行为初始化,当达到延时时触发迁移操作,执行对应的检查,避免启动时就以终态方式启动。 + + +### 5.2 决策说明 +##### 1. 阈值探测 + + +阈值机制旨在进行流量切换前的地址数检查,如果应用级的可使用地址数与接口级的可用地址数对比后没达到阈值将检查失败。 + + +核心代码如下: +```java +if (((float) newAddressSize / (float) oldAddressSize) >= threshold) { + return true; +} +return false; +``` + + +同时 MigrationAddressComparator 也是一个 SPI 拓展点,用户可以自行拓展,所有检查的结果取交集。 + + +##### 2. 灰度比例 + + +灰度比例功能仅在应用级优先状态下生效。此功能可以让用户自行决定调用往新模式应用级注册中心地址的调用数比例。灰度生效的前提是满足了阈值探测,在应用级优先状态下,如果阈值探测通过,`currentAvailableInvoker` 将被切换为对应应用级地址的 invoker;如果探测失败 `currentAvailableInvoker` 仍为原有接口级地址的 invoker。 + + +流程图如下: +探测阶段 +![//imgs/v3/migration/migration-2.png](/imgs/v3/migration/migration-2.png) +调用阶段 +![//imgs/v3/migration/migration-3.png](/imgs/v3/migration/migration-3.png) + + +核心代码如下: +```java +// currentAvailableInvoker is based on MigrationAddressComparator's result +if (currentAvailableInvoker != null) { + if (step == APPLICATION_FIRST) { + // call ratio calculation based on random value + if (ThreadLocalRandom.current().nextDouble(100) > promotion) { + return invoker.invoke(invocation); + } + } + return currentAvailableInvoker.invoke(invocation); +} + +``` + + +### 5.3 切换过程说明 + + +地址迁移过程中涉及到了三种状态的切换,为了保证平滑迁移,共有 6 条切换路径需要支持,可以总结为从强制接口级、强制应用级往应用级优先切换;应用级优先往强制接口级、强制应用级切换;还有强制接口级和强制应用级互相切换。 +对于同一接口切换的过程总是同步的,如果前一个规则还未处理完就收到新规则则回进行等待。 + + +###### 1. 切换到应用级优先 + + +从强制接口级、强制应用级往应用级优先切换本质上是从某一单订阅往双订阅切换,保留原有的订阅并创建另外一种订阅的过程。这个切换模式下规则体中配置的 delay 配置不会生效,也即是创建完订阅后马上进行阈值探测并决策选择某一组订阅进行实际优先调用。由于应用级优先模式是支持运行时动态进行阈值探测,所以对于部分注册中心无法启动时即获取全量地址的场景在全部地址通知完也会重新计算阈值并切换。 +应用级优先模式下的动态切换是基于服务目录(Directory)的地址监听器实现的。 +![//imgs/v3/migration/migration-4.png](/imgs/v3/migration/migration-4.png) + + +###### 2. 应用级优先切换到强制 + + +应用级优先往强制接口级、强制应用级切换的过程是对双订阅的地址进行检查,如果满足则对另外一份订阅进行销毁,如果不满足则回滚保留原来的应用级优先状态。 +如果用户希望这个切换过程不经过检查直接切换可以通过配置 force 参数实现。 +![//imgs/v3/migration/migration-5.png](/imgs/v3/migration/migration-5.png) +###### 3. 强制接口级和强制应用级互相切换 + + +强制接口级和强制应用级互相切换需要临时创建一份新的订阅,判断新的订阅(即阈值计算时使用新订阅的地址数去除旧订阅的地址数)是否达标,如果达标则进行切换,如果不达标会销毁这份新的订阅并且回滚到之前的状态。 +![//imgs/v3/migration/migration-6.png](/imgs/v3/migration/migration-6.png) diff --git a/content/en/blog/java/proposals/service-discovery-rule.md b/content/en/blog/java/proposals/service-discovery-rule.md new file mode 100644 index 0000000000000000000000000000000000000000..e657721ff29d06cc2584d3ebf93fa65faa5463db GIT binary patch literal 9455 zcmd5?eN$6c8sER~r?|DVQ<>cWYU}LSac8XB4!dpbsN0#HPDdj|n>8d%66m^XX95~X zfRL!Xg93^`t0YhmLlWS_^qzZf{_-pA?>W!8HGeUCjInQ}sf6vR&=ksa) zP|zO>#Lj3setddMAl%XsX^)-q^_*<^o4?2Ji*?*?>F&A}^>+kfK7Y8w*Bz49d!#22J>ZEi+8qkC{4Wn6MtXvQ?^`6AOzBI=NMDn$<^T;l2nv)|&sb9>liN^_huh&{G+j|4n%8*f9HFox_(G_d@ zzP)^3q^7Xm*jq4r3vVjJcy6X%i)_ItKR4&M%}m}N_({B8ug)gS^*)iG7OAajqEF;f z{G5m|aY^czM4uK4hHqaD#zTQKx+sm(L8WDLHX{ZXMD~F-vbK*Uxl4=xTgzEEE$+V+ zJEMPd>`!oxW4}MuB6T8BRl22Qq~{Lt6>k?+JQ%?BUjpZDL_t-&ob(QB?Oh$lmM zC}vmm3*9$vMD$a-u{|Wx8D`SlSP}ihyv&@GIvIH`vd4#@lA{3UoM7Ku5~h2UwU_!C>?yIjpZ##ePYTKnRuYKBf`N~yV=!BS2 znH0$s7XFgxWqO|FE=6~_Tu4$joINeFKZ#rc>JiC`$ZwNwDp{jA7 z6CWY#%I>o9>t%Ng#Zr*3N!No307xzpD{#{^eo`G6fFbld{?3qY&R1ZFYBFQ(yc zdj1OQh-{yoxF?qS@EKBQ*RNlvUE1xy9pr|sl)braCz33O$YsbQ_L5@Z1sp+(#RFYu z6e!lei+>jl#J-D!IsoVW8`kPLYa9Ek@Rm>}#}o!E32%4Ihr(RNB8G7LC;-39the<&89LxbUXAbQi^j=P}x+)R=EHxrwkA>x}`tS5J_-Cb4$fP3s8oO|0O-WRj9HIb2!4BKkLwki9v=dij#7l9vnB#I!Z{d>?sPl~^-*BuiC2(Q8>CadE{-oHk1w ztS)RDdylQLDZNz}nGM7{%XUCSkyMhr-e|mrgh{oI$St9O0;t+k4;ZPenN7k9Sxu07 zvjzL!4wqCYj8tJOD+{r>Zf`!XPUNdkCz+$SV-*}wVvuGd?4~B0wGQsiLU_{D+oL*U}=J+-esLHVKBkP`M z*7*(lma}TWC~wJ(ib5u3j;z?39NCaCLgo(0(3nt>I*v8FW#Tcc{VW>kMq0h_mrp*q zbnVK;%U`#hzj&eT%K1xQU%dR+YhSc|c3GBkn)VxwPlhv#{v=8+_5`3P;=~@LDh&mb zC}mL_Q9(1YWmKlkA)vyzxw@z%*qKEnnzM=Oi%Bj8(WLNtkR@l`dE}mgmF_E|R?L{` zWvZy2CCs_!=A(?UGm9*q7LoOjQtZIRuk5=OS8+%zyxB*0Ri`DB*Aa(IEJn0aEBry&oM1#B>{;7lEao@F@g zEe@CszzS#@+jBq-igigG>PFkZc?*Rq>Q)`!c{6d4gsN8cKhQ%(J(UxKb9i-Qb7I*Qi#bI&S1B_yoAnLDL{7a z09NRg-?AffHOaQ)?gpSr#jccFdDrZUl4@eh8eJ#Umj0lW&6+OtgGYYLy9oGZo{0V_ z*VL{kW;%f}g0kD{B0P<^fHAlq8aP&!v7O@Q@ame&C6~R5As3a*I1v0;EDwp{ah8Q* z`DC-sK8@f(qGN7k%({%pYHzxO8vSN}t>|fP7#-E(7-1}uy>`Bc2E!h{CuUHmPB-R{ z2Jkv4`GXnFjaQ0wkFBhcf_QpQWGB%snW=G9>M9cCM8T-ci{x`?izSo*K;0fqRtlrM z5|shL*3Jl))!f<%dImT+)V{^V47Z~oXcx*}IH9~M5rt25y$>RgvQIVBxCsf5Pi3Mc z-(3Z$Bwj9~34b_~inVo|#c0ho;a3i@sHV5BXpjR3bL6S{ zipGcB5%UPjoLIqpN2M+~h)}~PWG1KOr#jqWhtZK!4viJD2CyIpv}!aphQVHKO2-Rm zIKzXhu{DSY5P)6HpBLEPY94|F0#zo#}ThD^rGdQ~^tRzap`tx;M&6*weL-Dy`)B7|LU$ z07c+BuV+`b^J=KcoO$~&j5d+jc(CM>-Phqr!@|yLUgb1xIEC5cL&*_7F_QUAYExVeRb!+0vpPVhKGM({JFytV752`wM3}-4H_`#B@Y( zcPK7n`!HJXoz=tLp^y{21OwDk>1WUC4V8_vh&nl9&mRiuatKc!+q*+Nk9S#%;-)Ur zsrUFps@tP|bih^275yEbN3iR%T+^($JKoeB4*WfSA<_-MJB~pH5QfGboe`QYdXFbk z3R%=0MKk|BPJei!)%3B%BU<`{{KUW2wnG$hAekSuT0hDD&%KK~v1K>q61vvbY@tmX zL{Wg~^iKULe4RN0;)vdI`rF6$_)9!_SNx&gwZXW8O(k$ueW_O@iUN^%%|9ooZW0fXGE_?w4xo}b)4jqq1?7o%j7x`gicefSg z1-S1-yTbXI$5;#|Y8=2E!CZAZK&1XBO5IoI;m&O?2c|`4jPC--6wd92V}xNIYcUd% z7UbOruFphjMwCk;yCfFJK?K)G?u7zt3i8-{Q`C-14Z2qt-YSiYFOXHW8h_`ClG6(m zT%*5iji-ZW)pE)?U-jOKNcDSDE8kw$YQM~ey68-H%Qw2(%cn%^m zA#)WBpMqLYcdOPrzhLDjRJ}#Ep?gN@&rX=JoURd|a&;xe#(_)A3roIMqQU3R7=}(4 zg3&-bN}xOFI%o@*1Tzmr?xmPo;Tb5N(@F2TrTp*+*+{OTY~(c3`?;?Lg@ggDt1}ci z@X-(gOsjZ?M [参考示例](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-provider1/src/main/resources/application.yml) + +``` +# 双注册 +dubbo: + registry: + register-mode: all +``` +``` +# 仅应用级注册 +dubbo: + registry: + register-mode: instance +``` + +2. 注册中心地址参数配置 + +注册中心的地址上可以配置 `registry-type=service` 来显示指定该注册中心为应用级服务发现的注册中心,带上此配置的注册中心将只进行应用级服务发现。 + +```xml + +``` +### 消费端订阅模式 +FORCE_INTERFACE:仅接口级订阅,行为和 Dubbo 2.7 及以前版本一致。 +APPLICATION_FIRST:接口级 + 应用级多订阅,如果应用级能订阅到地址就使用应用级的订阅,如果订阅不到地址则使用接口级的订阅,以此保证迁移过程中最大的兼容性。(注:由于存在同时进行订阅的行为,此模式下内存占用会有一定的增长,因此在所有服务端都升级到 Dubbo 3.0 以后建议迁移到 FORCE_APPLICATION 模式降低内存占用) +FORCE_APPLICATION:仅应用级订阅,将只采用全新的服务发现模型。 +### 消费端配置 + +1. 默认配置(不需要配置) + +升级到 Dubbo 3.0 后默认行为为接口级+应用级多订阅,如果应用级能订阅到地址就使用应用级的订阅,如果订阅不到地址则使用接口级的订阅,以此保证最大的兼容性。 + +2. 订阅参数配置 + +应用配置(可以通过配置文件或者 -D 指定)`dubbo.application.service-discovery.migration` 为 `APPLICATION_FIRST` 可以开启多订阅模式,配置为 `FORCE_APPLICATION` 可以强制为仅应用级订阅模式。 +具体接口订阅可以在 `ReferenceConfig` 中的 `parameters` 中配置 Key 为 `migration.step`,Value 为 `APPLICATION_FIRST` 或 `FORCE_APPLICATION` 的键值对来对单一订阅进行配置。 +> [参考示例](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-consumer/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConfigIT.java) + +```java +System.setProperty("dubbo.application.service-discovery.migration", "APPLICATION_FIRST"); +``` +```java +ReferenceConfig referenceConfig = new ReferenceConfig<>(applicationModel.newModule()); +referenceConfig.setInterface(DemoService.class); +referenceConfig.setParameters(new HashMap<>()); +referenceConfig.getParameters().put("migration.step", mode); +return referenceConfig.get(); +``` + +3. 动态配置(优先级最高,可以在运行时修改配置) + +此配置需要基于配置中心进行推送,Key 为应用名 + `.migration` (如 `demo-application.migraion`),Group 为 `DUBBO_SERVICEDISCOVERY_MIGRATION`。规则体配置详见[接口级服务发现迁移至应用级服务发现指南](../migration-service-discovery/)。 +> [参考示例](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-consumer/src/main/java/org/apache/dubbo/demo/consumer/UpgradeUtil.java) + +```java +step: FORCE_INTERFACE +``` diff --git a/content/en/blog/news/2022-review-2023-roadmap.md b/content/en/blog/news/2022-review-2023-roadmap.md new file mode 100644 index 000000000000..de588792ea43 --- /dev/null +++ b/content/en/blog/news/2022-review-2023-roadmap.md @@ -0,0 +1,43 @@ +--- +title: "2022 年度总结与 2023 新年规划" +linkTitle: "2022 年度总结与 2023 新年规划" +date: 2023-02-23 +description: > + Apache Dubbo 社区 2022 年度总结,与 2023 年规划暨 Roadmap 发布。 +--- + +![dubbo-introduction](/imgs/blog/2023/2/roadmap/2023-roadmap.jpg) + +## 2022 年度总结 + +### 1 Dubbo 开源 12 周年 +50k+ star,30k fork,1000+ Contributor +### 2 Dubbo3 里程碑 +### 实现规模化生产检验 +阿里巴巴核心微服务集群实现从 HSF 到 Dubbo3 的全面升级,顺利支撑双十一、双十二万亿级服务调用 +### 发力多语言生态 +#### 具备生产可用条件 +Java、Go +#### 从孵化走向成熟 +Rust、Node.js、Python +### 3 核心技术 +应用级服务发现 +HTTP/2 协议 +流量管控升级 +可观测性 +自适应负载均衡 +Proxyless Mesh +Spring Boot3 & Spring6 +### 4 新晋 Committers&PMC +本年度社区共发展 Committer 13 位,PMC 4 位 + +## 2023 新年规划 +* 官网与文档体验全面提升 +* Go、Node.js、Rust 等多语言体系建设 +* 全面提升整体可观测性 +* Dubbo Admin 一站式服务运维管控平台 +* Dubbo Mesh 走向成熟 +* 提升 HTTP 开发体验,补全 Web 互通 +* 打造 gRPC over Dubbo 最佳实践 +* 完善的认证鉴权体系 + diff --git a/content/en/blog/news/20230130-release.md b/content/en/blog/news/20230130-release.md new file mode 100644 index 000000000000..3d59e526d735 --- /dev/null +++ b/content/en/blog/news/20230130-release.md @@ -0,0 +1,142 @@ +--- +title: "Dubbo 3.1.5、3.2.0-beta.4 正式发布" +linkTitle: "Dubbo 3.1.5、3.2.0-beta.4 正式发布" +date: 2023-01-30 +description: > + 在 1 月 27 日,新年伊始,Dubbo 3.1.5 和 3.2.0-beta.4 正式通过投票发布。本文将介绍发布的变化一览。 +--- + +Dubbo 3.1.5 版本是目前 Dubbo 3 的最新稳定版本,我们建议所有的用户都升级到最新的稳定版本。Dubbo 3.2.0-beta.4 版本是目前 Dubbo 3 的最新特性版本,包括了如 Spring Boot 3、JDK 17、服务粒度的线程池隔离等新特性的支持,欢迎大家尝鲜使用。 + +# Dubbo 3.1.5 + +![image.png](/imgs/blog/release/3-1-5.png) + +### 新特性 + +- Dubbo QoS 支持记录请求的记录,便于进行审计 +- 支持在服务映射失败以后定时进行重试,降低由于元数据中心抖动带来的影响 +- 支持在初始化 Nacos Client 的时候进行健康检查,如果失败则在一定次数限制下进行重试,降低由于 Nacos 性能问题带来的稳定性影响 +- 支持序列化类检查机制,默认开启日志告警模式 + +### Bugfix + +- 修复资源加载器的日志级别 +- 修复 Dubbo 配置类对 Scope Model 进行懒加载,避免触发非预期的默认模块初始化 +- 修复 ReferenceConfig 中获取 ClassLoader 的逻辑 +- 修复 Metadata Service 在获取订阅服务列表时出现 NPE 的问题 +- 修复对接 Spring Cloud Rest 模式的时候 Metadata 配置覆盖的问题 +- 修复 Spring 懒加载时可能出现死锁的问题 +- 修复端口重复的无效日志 +- 修复 Active Limit Filter 不生效的问题 +- 修复服务映射时 Nacos CAS 检查写入无效的问题 +- 修复 Zookeeper 注册中心对接的应用级服务发现在服务发布的时候出现单节点服务找不到的问题 +- 修复服务映射在冲突以后未等待导致的冲突率高的问题 +- 修复应用级服务发现下节点更新失败的问题 +- 修复应用级配置覆盖不生效的问题 +- 修复在应用级地址刷新之后原 Revision 的元数据无法获取的问题 +- 修复 Zookeeper 注册中心在应用级服务发现下退订阅后无法重订阅的问题 +- 兼容 Nacos 在频繁刷新时最终一致性错误的问题 +- 关闭 Nacos 本地缓存获取的开关 +- 修复 Triple 传递大写 Attachment 无效的问题 +- 修复 Triple 处理特定类反序列化错误的问题 +- 修复 Protobuf 依赖不存在时抛出非预期异常的问题 +- 修复 CountDown 功能无效的问题 +- 修复 Triple 在反序列化时类加载器未切换的问题 + +### FAQ + +本次发布中有 5 个提交涉及异常日志 FAQ 的完善。关于错误码机制请参考官网[错误码机制介绍](/en/overview/java-sdk/reference-manual/faq/intro/)一文。 + +### 代码优化 + +本次发布中有 4 个提交涉及代码质量的优化。 + +### 依赖升级 + +- 升级 protobuf-java: 3.16.3 -> 3.18.3 +- 升级 fastjson2: 2.0.21 -> 2.0.23 + +### 贡献者 + +Dubbo 感谢以下贡献者对本次发布的贡献:@win120a, @wuwen5, @AlbumenJ, @CrazyHZM, @EarthChen, @xieshouyu, @wxbty + +### 新贡献者 + +- @xieshouyu 在 PR #11177 提交了第一个贡献 + +# Dubbo 3.2.0-beta.4 + +![image.png](/imgs/blog/release/3-2-0-beta-4.png) + +**注:Dubbo 3.2.0-beta.4 的代码基础和 Dubbo 3.1.5 完全一致,因此在 Dubbo 3.1.5 中包括的所有修改内容,在 Dubbo 3.2.0-beta.4 中也同样存在,后续说明中对于重复的内容讲不再赘述。** + +### 新特性 + +- 支持 bytebuddy 作为动态代理的生成平台 +- 支持采集超时指标进行上报 +- 完善 Metrics 上报应用名 +- 完善 Metrics 上报指标的前缀 +- 支持上报请求失败的指标 +- 完善 xDS 的监听逻辑 +- 完善 xDS 对接路由规则的能力 + +### Bugfix + +- 修复 Token 请求在 Rest 协议下不生效的问题 +- 修复 GraalVM Native Image 的配置 +- 修复配置类无法进行序列化的问题 +- 修复 IPv6 地址段检查无效的问题 +- 修复路由链切换时地址可能存在异常的情况 +- 修复缓存文件锁被异常删除的问题 +- 修复 Deployer Listener 并发修改的问题 + +### 性能优化 + +- 优化 ConcurrentHashMap 的使用方式,避免在 JDK 1.8 下出现性能衰减 + +### 代码优化 + +本次发布中有 8 个提交涉及代码质量的优化。 + +### 依赖升级 + +- 升级 protobuf-java: 3.18.3 -> 3.19.6 +- 升级 cglib-nodep: 2.2 -> 2.2.2 +- 升级 byte-buddy: 1.12.19 -> 1.12.22 +- 升级 bouncycastle-bcprov_version: 1.69 -> 1.70 +- 升级 javax.ws.rs-api: 2.0 -> 2.1.1 +- 升级 curator_version: 4.2.0 -> 4.3.0 +- 升级 maven-plugin-plugin: 3.6.0 -> 3.7.1 +- 升级 javax.el: 3.0.1-b08 -> 3.0.1-b12 +- 升级 slf4j-api: 1.7.25 -> 1.7.36 +- 升级 spring-boot-dependencies: 2.3.1.RELEASE -> 2.7.7 +- 升级 maven-enforcer-plugin: 3.0.0-M3 -> 3.1.0 +- 升级 javassist: 3.28.0-GA -> 3.29.2-GA +- 升级 spring-boot-maven-plugin: 2.1.4.RELEASE -> 2.7.7 +- 升级 javax.el-api: 2.2.4 -> 2.2.5 +- 升级 eureka.version: 1.9.12 -> 1.10.18 +- 升级 jetty-maven-plugin: 9.4.38.v20210224 -> 9.4.50.v20221201 +- 升级 jetty_version: 9.4.43.v20210629 -> 9.4.50.v20221201 +- 升级 resteasy_version: 3.0.20.Final -> 3.15.3.Final + +### 贡献者 + +Dubbo 感谢以下贡献者对本次发布的贡献:@aamingaa, @AlbumenJ, @CrazyHZM, @fomeiherz, @HHoflittlefish777, @icodening, @jojocodeX, @LXPWing, @MentosL, @mxsm, @schneiderlin, @sconvent, @ShenFeng312, @songxiaosheng, @TigerTurbo, @yuluo-yx, @zeusbee + +### 新贡献者 + +- @LXPWing 在 PR #11258 提交了第一个贡献 +- @HHoflittlefish777 在 PR #11266 提交了第一个贡献 +- @sconvent 在 PR #11260 提交了第一个贡献 +- @yuluo-yx 在 PR #11291 提交了第一个贡献 +- @fomeiherz 在 PR #11295 提交了第一个贡献 +- @schneiderlin 在 PR #11324 提交了第一个贡献 +- @mxsm 在 PR #11326 提交了第一个贡献 + + +# 未来版本规划 + +![image.png](/imgs/blog/release/release-roadmap.png) + +Dubbo 版本的发布规划以及在《[聚焦稳定性,Dubbo 发版规划公布](https://mp.weixin.qq.com/s?__biz=MzIwODYwNTA4MA==&mid=2247484424&idx=1&sn=2f5ff4846f7dafad325f78fd8cf4d1fc&chksm=9701deffa07657e9a46eb97bb859770b4856599566b992724013a848a730f394702938e72404&token=1547029975&lang=zh_CN#rd)》一文中正式发布,欢迎查看。 diff --git a/content/en/blog/news/Dubbo-proxyless.md b/content/en/blog/news/Dubbo-proxyless.md new file mode 100644 index 000000000000..9a07234ba7ac --- /dev/null +++ b/content/en/blog/news/Dubbo-proxyless.md @@ -0,0 +1,186 @@ +--- +title: "Dubbo 在 Proxyless Mesh 模式下的探索与改进" +linkTitle: "Dubbo 在 Proxyless Mesh 模式下的探索与改进" +date: 2023-02-02 +--- + +## 一、背景 +随着 Docker 和 Kubernetes 的出现,一个庞大的单体应用可以被拆分成多个独立部署的微服务,并被打包运行于对应的容器中。不同应用之间相互通信,以共同完成某一功能模块。微服务架构与容器化部署带来的好处是显而易见的,它降低了服务间的耦合性,利于开发和维护,能更有效地利用计算资源。当然,微服务架构也存在相应的缺点: + +- 强依赖于 SDK,业务模块与治理模块耦合较为严重。 除了相关依赖,往往还需要在业务代码中嵌入SDK代码或配置。 +- 统一治理难。每次框架升级都需要修改 SDK 版本,并重新进行回归测试,确认功能正常后再对每一台机器重新部署上线。不同服务引用的 SDK 版本不统一、能力参差不齐,增大了统一治理的难度。 +- 缺少一套统一解决方案。目前市场不存在一整套功能完善、无死角的微服务治理与解决方案。在实际生产环境往往还需要引入多个治理组件来完成像灰度发布、故障注入等功能。 + +为解决这些痛点,Service Mesh诞生了。以经典的 Sidecar 模式为例,它通过在业务 Pod 中注入 Sidecar 容器,对代理流量实施治理和管控,将框架的治理能力下层到 Sidecar 容器中,与业务系统解耦,从而轻松实现多语言、多协议的统一流量管控、监控等需求。通过剥离SDK能力并拆解为独立进程,从而解决了强依赖于SDK的问题,从而使开发人员可以更加专注于业务本身,实现了基础框架能力的下沉,如下图所示(源自dubbo官网): +![image.png](/imgs/blog/2023/2/2/1.png) + +经典的 Sidecar Mesh 部署架构有很多优势,如减少SDK耦合、业务侵入小等,但增加了一层代理,也带来了一些额外的问题,比如: + +- Sidecar 代理会损耗一部分性能,当网络结构层级比较复杂时尤其明显,对性能要求很高的业务造成了一定的困扰。 +- 架构更加复杂,对运维人员要求高。 +- 对部署环境有一定的要求,需要其能支持 Sidecar 代理的运行。 + +为解决这些痛点,Proxyless Service Mesh 模式诞生了。传统服务网格通过代理的方式拦截所有的业务网络流量,代理需要感知到控制平面下发的配置资源,从而按照要求控制网络流量的走向。以istio为例,Proxyless 模式是指应用直接与负责控制平面的 istiod 进程通信,istiod 进程通过监听并获取 Kubernetes 的资源,例如 Service、Endpoint 等,并将这些资源统一通过 xDS 协议下发到不同的 RPC 框架,由 RPC 框架进行请求转发,从而实现服务发现和服务治理等能力。 +Dubbo 社区是国内最早开始对 Proxyless Service Mesh 模式进行探索的社区,这是由于相比于 Service Mesh,Proxyless 模式落地成本较低,对于中小企业来说是一个较好的选择。Dubbo 在 3.1 版本中通过对 xDS 协议进行解析,新增了对 Proxyless 的支持。xDS 是一类发现服务的总称,应用通过 xDS API 可以动态获取 Listener(监听器)、Route(路由)、Cluster(集群)、Endpoint(集群成员) 以及 Secret(证书)配置。 + +![image.png](/imgs/blog/2023/2/2/2.jpeg) + +通过 Proxyless 模式,Dubbo 与 Control Plane 直接建立通信,进而实现控制面对流量管控、服务治理、可观测性、安全等的统一管控,从而规避 Sidecar 模式带来的性能损耗与部署架构复杂性。 + +## 二、Dubbo xDS 推送机制详解 + +从整体上看,istio control plane 和 dubbo 的交互时序图如上。Dubbo 里 xDS 处理的主要逻辑在 PilotExchanger 和各个 DS (LDS、RDS、CDS、EDS) 的对应协议的具体实现里。PilotExchanger 统一负责串联逻辑,主要有三大逻辑: + +- 获取授信证书。 +- 调用不同 protocol 的 getResource 获取资源。 +- 调用不同 protocol 得 observeResource 方法监听资源变更。 + +例如对于 lds 和 rds,PilotExchanger 会调用 lds 的 getResource 方法与 istio 建立通信连接,发送数据并解析来自 istio 的响应,解析完成后的 resource 资源会作 为rds 调用 getResource 方法的入参,并由 rds 发送数据给 istio。当 lds 发生变更时,则由 lds 的 observeResource 方法去触发自身与 rds 的变更。上述关系对于 rds 和 eds 同样如此。现有交互如下,上述过程对应图里红线的流程: + +![image.png](/imgs/blog/2023/2/2/3.jpeg) + +在第一次成功获取资源之后,各个DS会通过定时任务去不断发送请求给 istio,并解析响应结果和保持与 istio 之间的交互,进而实现控制面对流量管控、服务治理、可观测性方面的管控,其流程对应上图蓝线部分。 + +## 三、当前Dubbo Proxyless实现存在的不足 + +Dubbo Proxyless 模式经过验证之后,已经证明了其可靠性。现有 Dubbo proxyless 的实现方案存在以下问题: + +- 目前与 istio 交互的逻辑是推送模式。getResource 和 observeResource 是两条不同的 stream 流,每次发送新请求都需要重新建立连接。但我们建立的 stream 流是双向流动的,istio 在监听到资源变化后由主动推送即可,LDS、RDS、EDS 分别只需要维护一条 stream 流。 +- Stream 流模式改为建立持久化连接之后,需要设计一个本地的缓存池,去存储已经存在的资源。当 istio 主动推送更新后,需要去刷新缓存池的数据。 +- 现有observeResource 逻辑是通过定时任务去轮询istio。现在 observeResource 不再需要定时去轮询,只需要将需要监听的资源加入到缓存池,等 istio 自动推送即可,且 istio 推送回来的数据需要按照 app 切分好,实现多点监听,后续 dubbo 支持其他 DS 模式,也可复用相应的逻辑。 +- 目前由 istio 托管的 dubbo 应用在 istio 掉线后会抛出异常,断线后无法重新连接,只能重新部署应用,增加了运维和管理的复杂度。我们需增加断线重连的功能,等 istio 恢复正常后无需重新部署即可重连。 + +改造完成后的交互逻辑: + +![image.png](/imgs/blog/2023/2/2/4.jpeg) + +## 四、Xds 监听模式实现方案 + +### 4.1 资源缓存池 + +目前 Dubbo 的资源类型有LDS,RDS,EDS。对于同一个进程,三种资源监听的所有资源都与 istio 对该进程所缓存的资源监听列表一一对应。因此针对这三种资源,我们应该设计分别对应的本地的资源缓存池,dubbo 尝试资源的时候先去缓存池查询,若有结果则直接返回;否则将本地缓存池的资源列表与想要发送的资源聚合后,发送给 istio 让其更新自身的监听列表。缓存池如下,其中 key 代表单个资源,T 为不同 DS 的返回结果: + +```java + protected Map resourcesMap = new ConcurrentHashMap<>(); +``` + +有了缓存池我们必须有一个监听缓存池的结构或者容器,在这里我们设计为 Map 的形式,如下: + +```java +protected Map, List>>> consumerObserveMap = new ConcurrentHashMap<>(); +``` + +其中key为想要监听的资源,value 为一个 List, 之所以设计为 List 是为了可以支持重复订阅。 List 存储的 item 为 jdk8 中的 Consumer 类型,它可以用于传递一个函数或者行为,其入参为 Map,其 key 对应所要监听的单个资源,便于从缓存池中获取。如上文所述,PilotExchanger 负责串联整个流程,不同 DS 之间的更新关系可以用 Consumer 进行传递。以监听 LDS observeResource 为例, 大致代码如下: + +```java +// 监听 +void observeResource(Set resourceNames, Consumer> consumer, boolean isReConnect); + +// Observe LDS updated +ldsProtocol.observeResource(ldsResourcesName, (newListener) -> { + // LDS数据不一致 + if (!newListener.equals(listenerResult)) { + //更新LDS数据 + this.listenerResult = newListener; + // 触发RDS监听 + if (isRdsObserve.get()) { + createRouteObserve(); + } + } +}, false); +``` + +Stream流模式改为建立持久化连接之后,我们也需要把这个 Consumer 的行为存储在本地的缓存池中。Istio 收到来自 dubbo 的推送请求后,刷新自身缓存的资源列表并返回响应。此时 istio 返回的响应内容是聚合后的结果,Dubbo 收到响应后,将响应资源拆分为更小的资源粒度,再推送给对应的 Dubbo应用通知其进行变更。 + +踩坑点: + +- istio推送的数据可能为空字符串,此时缓存池子无需存储,直接跳过即可。否则dubbo会绕过缓冲池,不断向istio发送请求。 +- 考虑以下场景,dubbo应用同时订阅了两个接口,分别由app1和app2提供。为避免监听之间的相互覆盖,因此向istio发送数据时,需要聚合所有监听的资源名一次性发起。 + +### 4.2 多点独立监听 + +在第一次向istio发送请求时会调用getResource方法先去cache查询,缺失了再聚合数据去istio请求数据,istio再返回相应的结果给dubbo。我们处理istio的响应有两种实现方案: +1. 由用户在getResource方案中new 一个completeFuture,由cache分析是否是需要的数据,若确认是新数据则由该future回调传递结果。 +2. getResource建立资源的监听器consumerObserveMap,定义一个consumer并把取到的数据同步到原来的线程,cache 收到来自istio的推送后会做两件事:将数据推送所有监听器和将数据发送给该资源的监听器。 +以上两种方案都能实现,但最大的区别就是用户调用onNext发送数据给istio的时候需不需要感知getResource 的存在。综上,最终选择方案2进行实现。具体实现逻辑是让dubbo与istio建立连接后,istio会推送自身监听到资源列表给dubbo,dubbo解析响应,并根据监听的不同app切分数据,并刷新本地缓存池的数据,并发送ACK响应给istio,大致流程如下: + +![image.png](/imgs/blog/2023/2/2/5.svg) + +```java +public class ResponseObserver implements XXX { + ... + public void onNext(DiscoveryResponse value) { + //接受来自istio的数据并切分 + Map newResult = decodeDiscoveryResponse(value); + //本地缓存池数据 + Map oldResource = resourcesMap; + //刷新缓存池数据 + discoveryResponseListener(oldResource, newResult); + resourcesMap = newResult; + // for ACK + requestObserver.onNext(buildDiscoveryRequest(Collections.emptySet(), value)); + } + ... + public void discoveryResponseListener(Map oldResult, + Map newResult) { + .... + } +} +//具体实现交由LDS、RDS、EDS自身 +protected abstract Map decodeDiscoveryResponse(DiscoveryResponse response){ + //比对新数据和缓存池的资源,并将不同时存在于两种池子的资源取出 + ... + for (Map.Entry, List>>> entry : consumerObserveMap.entrySet()) { + // 本地缓存池不存在则跳过 + ... + //聚合资源 + Map dsResultMap = entry.getKey() + .stream() + .collect(Collectors.toMap(k -> k, v -> newResult.get(v))); + //刷新缓存池数据 + entry.getValue().forEach(o -> o.accept(dsResultMap)); + } +} + +``` +踩坑点: + +- 原本多个stream流的情况下,会用递增的requestId来复用stream流,改成持久化连接之后,一种resource会有多个requestid,可能会相互覆盖,因此必须去掉这个机制。 +- 初始实现方案并没有对资源进行切分,而是一把梭,考虑到后续对其他DS的支持,对istio返回的数据进行切分,也导致consumerObserveMap有点奇形怪状。 +- 三种DS在发送数据时可以共享同一channel,但监听所用到的必须是同一channel,否则数据变更时istio不会进行推送。 +- 建立双向stream流之后,初始方案future为全局共享。但可能有这样的场景:相同的ds两次相邻时间的onNext事件,记为A事件和B事件,可能是A事件先发送,B随后;但可能是B事件的结果先返回,不确定istio推送的时间,因此future必须是局部变量而不是全局共享。 + +### 4.3 采用读写锁避免并发冲突 + +监听器consumerObserveMap和缓存池resourcesMap均可能产生并发冲突。对于resourcemap,由于put操作都集中在getResource方法,因此可以采用悲观锁就能锁住相应的资源,避免资源的并发监听。对于consumerObserveMap,同时存在put、remove和遍历操作,从时序上,采用读写锁可规避冲突,对于遍历操作加读锁,对于put和remove操作加写锁,即可避免并发冲突。综上,resourcesMap加悲观锁即可,consumerObserveMap涉及的操作场景如下: + +- 远程请求istio时候会往consumerObserveMap 新增数据,加写锁。 +- CompleteFuture跨线程返回数据后,去掉监听future,加写锁。 +- 监听缓存池时会往consumerObserveMap新增监听,加写锁。 +- 断线重连时会往consumerObserveMap新增监听,加写锁。 +- 解析istio返回的数据,遍历缓存池并刷新数据,加读锁。 + +踩坑点: + +- 由于dubbo和istio建立的是是双向stream流,相同的ds两次相邻时间的onNext事件,记为A事件和B事件,可能是A事件先发送,B随后;但可能是B事件的结果先返回,不确定istio推送的时间。因此需要加锁。 + +### 4.4 断线重连 + +断线重连只需要用定时任务去定时与istio交互,尝试获取授信证书,证书获取成功即可视为istio成功重新上线,dubbo会聚合本地的资源去istio请求数据,并解析响应和刷新本地缓存池数据,最后再关闭定时任务。 +踩坑点: + +- 采用全局共享的定时任务池,不能进行关闭,否则会影响其他业务。 +- +## 五、感想与总结 +在这次功能的改造中,笔者着实掉了一波头发,怎么找bug也找不到的情形不在少数。除了上述提到的坑点之外,其他的坑点包括但不局限于: + +- dubbo在某一次迭代里更改了获取k8s证书的方式,授权失败。 +- 原本的功能没问题,merge了下master代码,grpc版本与envoy版本不兼容,各种报错,最后靠降低版本成功解决。 +- 原本的功能没问题,merge了下master代码,最新分支代码里metadataservice发成了triple,然而在Proxyless模式下只支持dubbo协议,debug了三四天,最后发现需要增加配置。 + + ...... +但不得不承认,Proxyless Service Mesh确实有它自身的优势和广阔的市场前景。自dubbo3.1.0 release版本之后,dubbo已经实现了Proxyless Service Mesh能力,未来dubbo社区将深度联动业务,解决更多实际生产环境中的痛点,更好地完善service mesh能力。 + + + + diff --git a/content/en/blog/news/apache-33-release.md b/content/en/blog/news/apache-33-release.md new file mode 100644 index 000000000000..7b83c54c6161 --- /dev/null +++ b/content/en/blog/news/apache-33-release.md @@ -0,0 +1,192 @@ +--- +title: "Apache Dubbo 3.3 全新发布:Triple X 领衔,开启微服务通信新时代" +linkTitle: "Apache Dubbo 3.3 全新发布" +date: 2024-09-11 +tags: ["新闻动态"] +description: > + 在 Apache Dubbo 突破 4w Star 之际,Apache Dubbo 团队正式宣布,Dubbo 3.3 正式发布!作为全球领先的开源微服务框架,Dubbo 一直致力于为开发者提供高性能、可扩展且灵活的分布式服务解决方案。此次发布的 Dubbo 3.3,通过 Triple X 的全新升级,突破了以往局限,实现了对南北向与东西向流量的全面支持,并提升了对云原生架构的友好性。 +--- + +在 Apache Dubbo 突破 4w Star 之际,Apache Dubbo 团队正式宣布,Dubbo 3.3 正式发布!作为全球领先的开源微服务框架,Dubbo 一直致力于为开发者提供高性能、可扩展且灵活的分布式服务解决方案。此次发布的 Dubbo 3.3,通过 Triple X 的全新升级,突破了以往局限,实现了对南北向与东西向流量的全面支持,并提升了对云原生架构的友好性。 + +## Dubbo 的基础介绍 + +**Apache Dubbo** 是一个高性能、轻量级的微服务框架,最初由 Java 开发,但现在已扩展支持 **Go、Rust、Python** 等多种语言,为全球企业构建跨语言、跨平台的分布式系统提供了强有力的支持。Dubbo 提供了丰富的服务治理能力,包括服务注册与发现、负载均衡、容错机制和调用链追踪,帮助开发者构建高效、灵活的微服务架构。 + +随着 Dubbo 逐渐演进,其通信性能、服务治理能力和跨语言兼容性得到了大幅提升,成为支持现代微服务架构的理想工具。 + +## Triple X 全新升级背景 + +在 Dubbo 的早期应用中,虽然其在数据中心内部的服务互通中展现了卓越的性能,但随着技术演进和应用场景的扩展,原有架构逐渐暴露出了一些瓶颈。这些瓶颈在跨区域、跨云的环境中尤为明显,尤其是在 Web 框架与 RPC 框架之间的频繁切换中,开发复杂性和系统性能都受到了影响。 + +**传统架构的痛点主要体现在:** + +1. **局限于数据中心内的应用场景**:在跨地域或跨云应用中,Dubbo 的传统架构缺乏对广域环境的原生支持,导致开发者需要在多种协议和框架中切换,增加了复杂性。 + +2. **南北向与东西向流量的双重挑战**:在现代微服务架构下,传统的 RPC 框架往往更侧重南北向流量优化,而服务间(东西向)通信的性能要求日益增加,对传统 Dubbo 架构提出了新的挑战。 + +3. **云原生与跨语言互操作性要求**:随着云原生技术的普及,系统需要对 HTTP 协议有更深层次的支持,并具备跨语言的通信能力,然而传统 Dubbo 在这一点上并未原生优化。 + + +**Triple X 的变革和突破:** Triple X 的诞生,直接回应了这些痛点,它不仅延续了 Dubbo 一贯的高性能通信能力,还实现了与 gRPC 协议的全面兼容,通过支持 HTTP/1、HTTP/2、HTTP/3 等协议,为跨云、跨区域的广泛应用场景提供了更具灵活性和高效性的解决方案。 + +![image.png](/imgs/blog/33-release/ee5812e0-a90b-4a02-abab-b658cdddefc1.png) + +## Triple X 核心能力概述 + +* **全面支持南北向与东西向流量**:Triple X 无缝支持从客户端到服务器的南北向流量及服务间通信的东西向流量,并确保灵活转换,提升通信链路的整体效率。 + +* **遵循 gRPC 协议标准**:Triple X 遵循了 gRPC 协议标准,支持通过 Protobuf 进行通信,与 gRPC 服务无缝交互,扩展了 Dubbo 的跨语言、跨平台通信能力。 + +* **基于 HTTP 协议,原生支持云原生架构**:Triple X 构建于 HTTP/1、HTTP/2 和 HTTP/3 协议栈之上,全面优化了网络通信性能,并与现代云原生基础设施无缝集成,支持各种网关和服务网格。 + +* **高性能优化**:Triple X 提供了极致的性能提升,尤其在高并发和弱网环境下表现卓越,极大提高了系统吞吐量与响应速度。 + +* **平滑迁移与框架兼容**:支持从现有的 Spring Web 项目无缝迁移,开发者无需更改现有代码即可切换至 Triple X,提升性能,并保留对 Spring MVC 等框架的支持。 + +* **高扩展性**:Triple X 新引入 20+ SPI 扩展点,支持自定义核心行为,包括路由映射、参数解析、序列化及异常处理等。显著提升框架的灵活性和可定制性,使开发者能够根据特定业务需求和场景自定义行为,提高开发效率并降低定制化成本。 + + +## Triple X 使用场景 + +**Triple X** 在 Dubbo 3.3 中为微服务架构提供了灵活的接入方式,能够适应不同场景下的系统需求。根据系统架构的不同,Triple X 提供了 **中心化接入方式** 和 **去中心化接入方式**,适用于多种应用场景。 + +### 1. 中心化接入方式 + +在 **中心化接入方式** 中,外部流量通过一个统一的服务网关进入 Dubbo 后端服务。网关负责处理 HTTP 流量的解析、转发,并将请求路由到合适的后端服务中。这种方式适用于对流量统一管理、流量控制、权限校验等有较高要求的系统,能够集中式地控制流量的进入点。 + +![lQLPJxkYhOcUzFfNA3bNC0Sw5rRkqBkcwQ4GwaypwVc_AA_2884_886.png](/imgs/blog/33-release/78d6744b-928a-41d4-857c-ff91ad69c896.png) + +* **使用场景**:当系统需要集中管理外部请求、对流量进行监控和限流等操作时,Triple X 能够通过服务网关处理 HTTP/1、HTTP/2 和 HTTP/3 的流量,并高效地转发给 Dubbo 服务进行处理。 + +* **优势**:集中化控制、易于管理,适合大规模系统中的统一流量治理。 + + +### 2. 去中心化接入方式 + +在 **去中心化接入方式** 中,外部客户端可以直接通过 HTTP 协议访问后端 Dubbo 服务,而不需要依赖中间的网关层。这种方式适合对性能和低延迟有较高要求的系统,通过减少网关的转发,直接将流量路由到服务节点,从而降低通信开销,提升系统响应速度。网关节点的消除,能避免网关故障造成的系统不可用,简化部署架构,提升系统稳定性。 + +![lQLPJw7B47rI7FfNAzjNCYiwStDS2ladC3oGwaypwZe9AA_2440_824.png](/imgs/blog/33-release/68b69954-9df2-48b2-bd63-fe07ba8cb25b.png) + +* **使用场景**:当系统希望通过直接的 HTTP 流量接入 Dubbo 服务,减少中间环节,提高系统的响应速度时,Triple X 提供了直接暴露 REST API 的能力,无需借助网关即可完成服务导出。 + +* **优势**:去除中间环节,提升性能和响应速度,简化了架构,适合对低延迟有需求的应用场景。 + + +## Triple X 核心能力拆解说明 + +### 1. 支持全面的流量管理与高效通信 + +在复杂的微服务架构中,南北向流量(客户端到服务器)和东西向流量(服务间通信)需要采用不同的技术进行处理,系统往往面临性能瓶颈与复杂的开发和运维问题。 + +Triple X 协议通过统一的通信协议,同时支持南北向与东西向流量。无需在 Web 框架与 RPC 框架之间切换,简化了开发流程,提升了系统的整体性能和可维护性。 + +开发者可以通过 Triple X 实现全方位的流量支持,无论是用户发起的请求,还是服务间的通信,均可通过 Triple X 实现高效传输。 + +```java +package org.apache.test; + +@DubboService +public class UserServiceImpl implements UserService { + // 处理东西向请求 +} + +// Triple X 也支持南北向流量处理 +@DubboService +public class OrderService { + @GetMapping("/order/{orderId}") + public Order getOrderById(@PathVariable("orderId") String orderId) {} +} +``` + +调用方式: + +1. Dubbo Client 直接发起 RPC 调用 + +2. 前端使用 HTTP 直接请求,目标路径为 `http://server:50051/order/{orderId}` + +3. 使用 Dubbo 默认发布的路径进行请求,目标路径为 `http://server:50051/org.apache.test.OrderService/getOrderById?orderId=xxx` + + +### 2. 遵循 gRPC 协议标准 + +跨语言服务之间的通信经常成为分布式系统中的难题,gRPC 是常用的解决方案之一,但传统 Dubbo 需要借助额外工具实现与 gRPC 的互操作性。 + +Triple X 遵循 **gRPC 协议标准**,通过 Protobuf 实现与 gRPC 的无缝交互,简化了开发流程,增强了跨语言和跨平台通信能力。 + +使用 Triple X 的服务可直接与基于 gRPC 的服务进行互通,无需额外适配,系统之间即可高效互访。 + +### 3. 基于 HTTP 协议,原生支持云原生架构 + +在云原生环境下,服务需要与各种网络设施(如 API 网关、服务网格)进行高效集成,同时支持多种 HTTP 协议以优化网络性能。 + +Triple X 同时支持 **HTTP/1、HTTP/2 和 HTTP/3** 协议,开发者无需进行额外配置即可利用这些协议的优势,包括长连接、多路复用和头部压缩,从而实现高效的网络通信。使用 **HTTP/3** 还能彻底解决队头阻塞问题,同时基于 UDP 的通讯方式,在弱网下能够维持较高的连接质量和服务性能,同等环境 TCP 在高丢包率下可能已不可用。 + +Triple X 支持复用 Spring Boot 现有 **Servlet** 端口接入 HTTP 流量,无需新增 Netty 监听端口。网络架构的简化,可以降低使用和维护成本,提升安全性,流量易于通过企业防火墙和网关。 + +![image.png](/imgs/blog/33-release/0e6b75c3-3340-4bed-a566-88c46a03ada6.png) + +### 4. 高性能优化,提升 5 倍 QPS + +在高并发场景中,传统通信协议并未做深度优化,容易造成瓶颈,影响系统的整体响应时间和吞吐量。 + +Triple X 通过 **Radix Tree** 和 **Zero Copy** 等技术降低了 CPU 使用和内存用量,显著提升了系统性能,尤其在高并发和弱网环境下表现突出: + +* **高效路由**:采用 Radix Tree 前缀树结构进行路由匹配,优化 key hash 算法并支持动态更新,减少内存占用,提高匹配效率。 + +* **内存使用优化**:结合 Zero Copy 技术和对象复用技术,减少数据复制和对象创建开销,降低垃圾回收压力,提升吞吐量。 + +* **HTTP/3 支持**:引入基于 QUIC 的 HTTP/3 协议,显著提升弱网环境下的性能表现,解决队头阻塞问题,减少延迟并提高连接可靠性。 + +* **多协议压测优化**:Dubbo 团队对各种协议进行了全面压测,基于测试结果进行了多轮性能优化,确保在不同场景下都能达到最佳表现。 + + +经过压测,简单 Rest 服务相较于传统 Spring Boot REST 服务,Triple X 服务的平均响应时间降低至 1/3,高压力下 QPS 提升 5 倍,同时内存分配量减少 50%,显著提升了系统整体性能和资源利用效率。 + +![image.png](/imgs/blog/33-release/c7d4f983-f619-4d39-94b6-5d62fd5a430e.png) + +![image.png](/imgs/blog/33-release/53a6f3c7-20ad-49f6-abc0-4e2d80a9597d.png) + +![image.png](/imgs/blog/33-release/7e4f3ced-9932-472f-bb8f-272ec97a7fbe.png) + +![image.png](/imgs/blog/33-release/5f8ebef5-08f3-463a-bb86-14b32a09ebb2.png) + +### 5. 平滑迁移与框架兼容 + +此外,Triple X 还支持对于已有 Spring Web 的项目,在不大幅修改代码的前提下提升性能,向微服务架构迁移。 + +Triple X 支持零侵入式的迁移方案,开发者无需更改现有代码即可将现有的 Spring Web 项目迁移至 Triple X,同时保留对 Spring MVC 等框架的支持。 + +```java +@DubboService // 仅需添加服务发布配置 +@RestController +public class DemoController { + + @GetMapping("/spring-test") + public String sayHello(@RequestParam("name") String name) { + return "Hello " + name; + } +} +``` + +## 此次版本升级其他的能力优化概述 + +### 1. Native Image AOT 支持 + +Dubbo 3.3 引入了对 **Native Image AOT(Ahead-of-Time 编译)** 的支持,开发者可以将 Dubbo 应用编译为原生二进制文件,极大缩短启动时间,降低内存占用,特别适合无服务器(Serverless)场景。 + +### 2. Project Loom 支持 + +Dubbo 3.3 提供了对 **Project Loom** 的支持,通过虚拟线程优化了高并发场景下的线程管理,简化了异步编程模型,提升了并发处理能力。 + +### 3. 全新路由规则 + +在路由机制上,Dubbo 3.3 引入了全新的路由规则,支持更加灵活的流量控制和服务治理,增强了微服务系统在大规模部署中的适应性。 + +## 总结 + +**Apache Dubbo 3.3** 的发布标志着微服务通信技术迈向新高度。通过 **Triple X**,Dubbo 不仅实现了对南北向与东西向流量的全面支持,还通过与 gRPC 的无缝集成、基于 HTTP 协议的云原生支持以及高性能优化,为开发者提供了更强大、灵活的工具,帮助他们构建现代分布式系统。 + +无论是提升服务间通信的高效性、实现跨语言兼容,还是优化云原生环境下的通信性能,Dubbo 3.3 都是开发者应对现代分布式系统挑战的理想选择。立即升级至 Dubbo 3.3,体验 **Triple X** 带来的变革,开启微服务通信的新时代! + +更多升级指南和兼容性说明,请参考[Dubbo 3.2 升级 3.3 指南](/en/overview/mannual/java-sdk/reference-manual/upgrades-and-compatibility/version/3.2-to-3.3-compatibility-guide/)。 diff --git a/content/en/blog/news/apache-dubbo-2019-2020.md b/content/en/blog/news/apache-dubbo-2019-2020.md new file mode 100644 index 000000000000..92bdd5d8809b --- /dev/null +++ b/content/en/blog/news/apache-dubbo-2019-2020.md @@ -0,0 +1,320 @@ +--- +title: "从 2019 到 2020,Apache Dubbo 年度回顾与总结" +linkTitle: "从 2019 到 2020,Apache Dubbo 年度回顾与总结" +date: 2020-05-11 +tags: ["新闻动态"] +description: > + 通过这篇文章我们将:总结过去一年 Dubbo 社区取得的成绩 +--- + +非常感谢大家对 Dubbo 社区的关注,通过这篇文章我们将:总结过去一年 Dubbo 社区取得的成绩,包括社区和框架演进两个方面;展望未来 Dubbo 社区和框架的新的规划(roadmap)。社区建设是推动 Dubbo 健康持续发展的一个非常重要的环节,我们需要与社区保持良性的互动、有活跃的贡献者、有积极的富有建设性的讨论,而整个 Dubbo 社区过去一年在这方面都做的不错;在框架演进上,我们主要发布了 2.7.0 - 2.7.5 共 6 个特性版本,功能层面涵盖编程模型、协议、服务治理、性能优化等多个方面;除了已经发布的功能外,我们在 Dubbo 3.0 协议、服务自省和云原生等方向上也做了深入的探索,对这些方向的支持将是 Dubbo 接下来的重要工作方向,希望能通过这篇文章将其中更详细的思考和计划同步给大家。 + + +## 社区回顾 + +回顾 Dubbo 社区过去一年的发展,其中一个重要的节点就是 2019 年 5 月从 Apache 孵化毕业。成为第二个由 Alibaba 捐献后从 Apache 毕业的项目,我有幸参与到了从重启开源、进入 Apache 孵化到毕业的整个过程,社区在此过程中做了大量的工作,包括邮件列表建设、代码规范检查、文档和代码国际化、issue/pr 处理等,这些一方面是 Apache 社区要求的工作,同时也为推动 Dubbo 的发展起到了正面的作用。 + +在从 Apache 毕业之后,Dubbo 相关的项目也进行了迁移,都迁移到了 [Apache](https://github.com/apache?utf8=✓&q=dubbo&type=&language=) 组织之下: + +Dubbo 社区的项目总共有 24 个之多,维护如此多的项目,并不是单纯靠几个活跃的开发者就能做到的,而是靠整个社区努力的结果。我总结了过去一年提名的所有 Committer/PMC,总过有 27 人获得提名(23 名 committer、4 名 PMC),通过下方的饼状图可以看出,只有不到 20% 的贡献者是来自于 Alibaba,而 80% 以上是来自各个不同组织的开发者或爱好者。这样的 Committer 分布,是加入 Apache 带给 Dubbo 社区的一个最重要的变化之一:Dubbo 项目是属于整个社区的,反映的是不同组织不同开发者的共同诉求,它的发展不是由一个公司控制或决定的,而是由社区共同讨论后决定的。如果你对参与到 Dubbo 社区感兴趣,都可以参与到 Dubbo 发展的讨论、决策和 coding 中来,也非常期待各位能成为下一个 Committer。 + +![community distribution](/imgs/blog/community-distribution.png) + + +过去一年 Dubbo 社区组织了超过 10 场的线下 meetup 活动,覆盖了国内基本所有的开发者聚集的城市,与广大 Dubbo 开发者和使用者保持了密切交流。通过这些线下或线上的直播活动,分享了超过 100 个 topic 的演讲,深度讲解了 Dubbo 社区最新动态、功能模块开发和近期规划等。并且在所有的这些主题演讲中,绝大多数都是通过社区采集的方式,最终由 Dubbo 的深度企业分享的实践主题,其中典型的代表包括携程、工商银行、考拉、信用算力等。 + +![community meetup](/imgs/blog/community-meetup.png) + +从 Github 上来看,Dubbo 在过去一年也受到了非常高的关注度,一个重要的里程碑是 Star 数突破 3w,相比重启开源时增长了近 5 倍;贡献者由最初的几十个增长到现在的 282 个,而这其中有六七十个已经被提名为 committer,不论是贡献者数量还是 committer 比例都得到很大的提升;另一个数据是发布的版本,总共发布了 64 个版本,大家如果要了解每个版本的具体信息,也可以从这里点进去查看。 + +![community github](/imgs/blog/community-github.png) + +当前社区维护的大版本主要有 3 个,分别是 2.5.x 2.6.x 和 2.7.x。 + +其中,2.7.x 是我们的主要开发版本,在过去的一年共发布了 6 个版本(2.7.0 - 2.7.5),每个版本都带来了一些值得关注的特性或功能升级,涵盖从编程模型、服务治理、性能到协议的多个方面的增强。 + +2.6.x 版本则定位为 bugfix 版本,过去一年共发布了 3 个版本,主要以修复问题和安全漏洞为主,并没有增加什么新 feature,因此这一系列的版本在稳定性上是得到保证的。 + +2.5.x 版本当前从去年初开始已宣布 EOF,只做安全修复;而到了下半年已经完全停止了维护。还在使用这个版本的用户建议尽快升级到 2.6 或 2.7 版本。 + +关于 2.6 和 2.7 版本的用户分布情况,目前并没有官方的统计数据,但是根据我们从 issue 分布及一些深度用户的跟踪情况来看,这两个版本的使用分布大概是 40% - 60% 的状态。同时我们还观察到一个趋势,即很大一部分 2.6 的用户都已经开始调研升级到 2.7 版本或在升级的过程中,毕竟一个框架是否能很好的满足业务开发诉求,一个重要的因素是其是否不断的有功能的加入,是否能跟进新的技术趋势,2.6 版本已很难满足这些诉求。 + +对于很多开发者来说,要升级到 2.7 版本,当前最大的顾虑即是其稳定性。因为 2.7 每个版本都会增加很多新内容且迭代速度较快,要保证每个发布版本的稳定性对社区来说也是一个充满挑战的事情。为了方便用户更好的完成升级评估,我们近期在 github 上列出了单独列了一个 issue 来统计现在包括未来版本的稳定性:[Dubbo 各版本总结与升级建议 #5669](https://github.com/apache/dubbo/issues/5669) + +| | **版本** | **重要功能** | **升级建议** | +| -------- | ------------ | ------------------------------------------------------------ | ------------------------------- | +| 1 | 2.7.5 | 服务自省 HTTP/2(gRPC) Protobuf TLS 性能优化 https://github.com/apache/dubbo/releases/tag/dubbo-2.7.5 | 不建议大规模生产使用 | +| 2 | 2.7.4.1 | [bugfixes and enhancements of 2.7.3](https://github.com/apache/dubbo/releases/tag/dubbo-2.7.4.1) | **推荐生产使用** | +| 3 | 2.7.3 | [bigfixes of and enhancements of 2.7.2](https://github.com/apache/dubbo/releases/tag/dubbo-2.7.3) | **推荐生产使用** | +| 4 | 2.7.2 | [bigfixes of and enhancements of 2.7.1](https://github.com/apache/dubbo/releases/tag/dubbo-2.7.2) | 不建议大规模生产使用 | +| 5 | 2.7.1 | [bigfixes of and enhancements of 2.7.0](https://github.com/apache/dubbo/releases/tag/dubbo-2.7.1) | 不建议大规模生产使用 | +| 6 | 2.7.0 | 异步编程模型 - 消费端/提供端异步 服务治理规则增强 简化的注册模型 配置中心、元数据中心 package 重构 https://github.com/apache/dubbo/releases/tag/dubbo-2.7.0 | beta 版本,2.6.x 重构后首个版本 | + +其中 2.7.5 版本预计将在接下来的 1-2 个版本之后逐步达到稳定状态。 + +对于后续的版本是否通过标识性的后缀如 -beta、RC 等来区分不同阶段的发布版本,社区也有过类似的讨论,后续我们将视未来发展情况而定。 + +## 重点功能回顾 + +接下来针对 2.7 版本中发布的新功能,从编程模型、性能优化、服务治理、传输协议、生态发展等几个角度来做具体的讲解。 + +### 编程模型 + +Dubbo 中涉及编程模型相关的改动主要是以下几点: + +* CompletableFuture 异步方法签名的服务 +* 服务端异步支持 API +* IDL 跨语言服务定义 +* Reactive-style 方法签名的服务 + +首先,我们先来看一下异步化相关的增强。 +Dubbo Java 版本的典型服务定义如下: + +```java +public interface HelloService { + // Synchronous style + String sayHello(String name); +} +``` + +如果要实现消费端的异步服务调用,则需要单独配置异步标识,并通过 RpcContext API 配合使用 + +```java +String result = helloService.sayHello("world"); // result is always null +Future future = RpcContext.getContext().getFuture(); +``` + +在 2.7 版本之后,我们可以直接定义如下方法接口,以更直观的实现消费端/提供端异步: + +```java +public interface HelloService { + // Asynchronous style + CompletableFuture sayHello(String name); +} + +CompletableFuture future = helloService.sayHello("world"); +``` + +以上示例都是基于 Java Interface 来描述 Dubbo 服务的,如果要和多语言异构的微服务实现互调,则服务又需要用相应语言的方式重新定义一遍,无法实现跨语言的服务复用;另外跨语言的序列化也是需要注意的一个问题。 + +为此 2.7.5 版本引入了对 IDL + Protobuf 的支持,以解决跨语言的服务定义问题,具体可参见示例: + +[dubbo-samples-protobuf](https://github.com/apache/dubbo-samples/tree/master/3-extensions/serialization/dubbo-samples-protobuf) + +![service idl](/imgs/blog/service-idl.png) + +对 Reactive-style API 的支持则和上面 CompletableFuture 有些类似,允许用户定义 RxJava、Reactor API 的服务接口 + +![idl dubbo compiler](/imgs/blog/idl-dubbo-compiler.png) + +但是需要注意的一定是,由于外围的 Reactive API 需要有底层传输协议的支持才有意义,因此,目前 Reactive API 只能在使用 gRPC 协议时才有意义,具体请参见示例以及下面关于 ”[Dubbo 对 gRPC 的支持](https://github.com/apache/dubbo-samples/tree/925c3d150d9030bc72988564e4f97eca1f6fcb89/3-extensions/protocol/dubbo-samples-grpc/dubbo-samples-rxjava)” 一节的讲解。 + +### 性能优化 + +2.7 版本在性能优化方面也做了很多的工作,对 Dubbo 业务系统的吞吐量、调用链路响应速度、服务治理链路性能等都有明显提升。 + +1. 系统吞吐量 + + 和提升系统吞吐量相关的增强主要有框架的全异步化改造、消费端线程模型优化、引入 Stream 语义协议等。 + + 全异步化改造,很关键的一点是 Filter 链路的异步化,之前的 Filter 只有一个同步的 invoke 方法,现在为了支持异步回调,增加了 Listener 回调监听器,从而可以实现对异步调用结果的监听与拦截。 + +![filter](/imgs/blog/filter.png) + + 关于消费端线程模型的优化,对于网关类应用,需要消费大量服务的应用,都会在系统稳定性和性能表现上有很大提升,其优化后的总体工作原理图所下所示,具体解析可以参见之前发布的文章:[《消费端线程池模型》](/en/docsv2.7/user/examples/consumer-threadpool/) + + + 老线程模型工作原理: + + ![consumer threadpool](/imgs/blog/consumer-threadpool0.png) + + 新线程模型工作原理: + + ![consumer threadpool new](/imgs/blog/consumer-threadpool1.png) + + +2. RPC 调用链路 + + 从 2.7.0 到 2.7.5,从我们的测试数据来看,通过一系列的优化调用链路性能提升在 30% 以上。总体来说,优化的目标是减少调用过程中的内存分配和 cpu 计算,主要有两个方面的改造: + + * 服务元数据静态化,在启动阶段尽可能多的计算并缓存,以减少调用过程中的计算成本,加快响应速度 + * 减少调用过程中的 URL 操作产生的内存分配 + +3. 服务治理链路 + + 服务治理链路上主要有以下几点值得关注:地址推送、服务治理规则推送、服务治理规则计算、路由选址等,尤其是在大规模服务集群的场景下,以上每个点都可能成为性能或稳定性瓶颈。在 2.7 版本中,目前着重对 “地址推送” 相关计算路径做了优化,简单概括起来主要是以下几点: + + * 地址推送事件合并,避免短时间重复计算 + * 全量地址推送时,避免 URL 重新分配 + * 在 URL 合并链路上,引入 URL 可变状态,避免 URL 拷贝造成的开销 + +### 服务治理 + +服务治理也是 2.7 版本中着重增强的一个模块。总体上可以分为三部分 + +* 普通路由规则相关的优化和增强 +* 增强对跨区域、跨机房部署的路由支持 +* 元数据中心、配置中心 + +我们针对这三部分逐步展开讲解。以下是 2.7 版本路由规则的几个例子。 + +![route app](/imgs/blog/route-app.png) + +![route service](/imgs/blog/route-service.png) + +其中,最明显的一个变化是路由规则都以 YAML 进行了重写,并且后续所有的路由规则都计划以 YAML 为基本描述语言;相比于之前路由规则直接存储于注册中心,在 2.7 版本中增加了配置中心后,新版本的路由规则默认将存储在于独立的配置中心,配置格式推送机制都得到了优化;另外,2.7 版本中还增加了应用粒度的路由规则,方便从整个应用的角度去设置流量规则。 + +新增加的跨注册中心的路由机制,可以实现调用流量在多个注册中心间的负载均衡,对于需要做异地容灾、同机房优先或者注册中心迁移的场景比较有用处。 + +![cluster load balance](/imgs/blog/cluster-lb.png) + +当前支持的注册中心集群负载均衡策略有: + +- 同区域优先 +- 权重轮询 +- 指定优先级 +- 任意可用 + +元数据中心存储了 Dubbo 服务方法定义的描述,目前主要的用途是服务测试,将来也可用作服务 API 管理、网关参数映射等。 + +新增的配置中心主要有两个用途:存储/推送配置规则、应用配置托管,接下来着重讲解应用配置托管相关功能,看其对 Dubbo 的开发与运维配置的影响。Dubbo 当前支持 JVM 动态参数、配置中心、API、本地配置文件等几种配置源,他们之间按照优先级从高到低的顺序实现配置覆盖,如下图所示: + +![config](/imgs/blog/config.png) + +配置中心相当于是共享版本的 `dubbo.properties` 的远程托管,其中,key 值有特定的命名规范: + +```properties +# 应⽤用级别 +dubbo.{config-type}[.{config-id}].{config-item} {config-item-value} +# 服务级别 +dubbo.service.{interface-name}[.{method-name}].{config-item} {config-item-value} +dubbo.reference.{interface-name}[.{method-name}].{config-item} {config-item-value} +# 多配置项 +dubbo.{config-type}s.{config-id}.{config-item} {config-item-value} +``` + +### 传输协议 + +2.7 版本在 RPC 协议层和序列化层进行了扩展,RPC 协议层增加了对 gRPC 协议的支持,序列化层增加了对 Protobuf 协议的支持。 + +支持 gRPC 其中一个重要原因是其基于 HTTP/2 协议构建,HTTP/2 协议作为 HTTP 标准协议,在各个层次的网络设备及网关代理上都得到了很好的支持,因此具有更好的穿透性和通用性。通过支持 gRPC 协议,对于期望使用 HTTP/2 的 Dubbo 用户提供了一种传输协议选择。 + +gRPC 在 HTTP/2 上构建了 Stream 的 RPC 语义,支持 Request - Response、Stream - Response、Request - Stream、Bi-Stream 等多种语义,能满足不同的业务调用场景。 + +![service idl2](/imgs/blog/service-idl2.png) + +在 Dubbo 的设计中,所有的 RPC 协议都处于一个平等的地位,无论是自有的 Dubbo 协议,还是扩展的其他三方协议如 Thrift、Hessian、gRPC 等,得益于这样的设计,我们可以扩展任何新协议支持。关于如何扩展 RPC 协议及其应用场景,请参见之前发布的[《使用 Dubbo 连接异构微服务体系》](https://mp.weixin.qq.com/s/-fvDeGlCLjz0n60naZJnQg)文章。 + +Protobuf 序列化协议支持更多的是考虑其在跨语言、安全性和性能方面。 + +## Roadmap + +未来社区将会持续推动 Dubbo 的发展,重点来说有以下几个方向: + +* 继续增强服务治理相关能力,以更好的满足微服务开发和运维的需求; +* 协议层面,着手研发下一代的 RPC 协议,新协议将提供更丰富的如 Stream、Flow Control 等内置语义,同时将具有更好的扩展性、网关的友好性等; +* 基于应用粒度的服务发现机制, +* 云原生带来了底层基础设施的变化,同时在此基础上衍生出了如 ServiceMesh 的微服务解决方案,我们需要继续探索 Dubbo ; + +### 微服务功能 + +目前正在开发或规划中的微服务功能有服务鉴权、熔断、路由规则增强等,预计将在接下来的 2.7.6 等版本中陆续发布。后续也将会根据社区中的诉求,陆续增加其他的微服务功能支持。 + +以当前正在开发的服务鉴权功能为例,这是社区中很多 Dubbo 使用者在实际使用中遇到的需求:虽然 Dubbo 服务主要是在内部运转,但有些服务仍期望只对部分场景或用户开放,比如某些涉及到敏感数据操作的服务,这就需要有鉴权能力的支持。 + +[Dubbo调用鉴权认证方案 #5461](https://github.com/apache/dubbo/issues/5461) 中有关于 Dubbo 当前正在开发中的鉴权功能的详细讨论,总体来说 Dubbo 提供的鉴权功能约束了 Dubbo 侧鉴权的基本流程,这是一套通用鉴权的方案,在 token 计算、校验等环节都被设计为可扩展的,因此可以方便的对接到各种认证及权限管理系统。 + +非常感谢社区的活跃开发者,现就职于爱奇艺的 [CodingSinger](https://github.com/CodingSinger),其是鉴权模块的发起者和主要开发贡献者。 + + +### 协议 - 3.0 + +以下是 Dubbo 2.0 协议,我们之前已经在多个场合做过详细的讲解 + +![Dubbo Protocol 2.0](/imgs/blog/grpc/dubbo-ptotocol.png) + +Dubbo 2.0 协议在云原生、mesh 等场景下暴露出一些问题,如: + +* 协议缺少扩展性 +* RPC 协议层和 payload 耦合在一起 +* 基于 TCP 构建的二进制私有协议 +* 缺少 Stream 语义的支持 + +所以,针对以上问题,新一代的 Dubbo 协议将突出以下特点: + +**Reactive Stream** +Reactive Stream 引入 RPC,带来更丰富的通信语义和 API 编程模型支持,如 Request-Stream、Bi-Stream 等 + +**协议升级** +协议内置应⽤层协议协商机制,包括自建协议升级机制、ALPN 等,以方面将来协议升级或兼容老版本协议的迁移 + +**HTTP/2** +微服务云原⽣生场景下,基于 HTTP/2 构建的通信协议具有更更好的通⽤用性和穿透性 + +**可扩展** +协议可扩展,区分协议头 Metadata 与 RPC 方法的参数 + +**多语⾔支持** +如通过支持 Protobuf 提供了更完善的 跨语言服务定义 与 序列化传输 的支持 + +**Mesh** +协议对 Mesh 更友好,方便完成与 Mesh 的协作,包括流量控制机制、应用层配置协商等 + +**流量控制** +协议内置流控机制,支持类似 Reqctive Stream 的 Request (n) 流控机制 + +**协议通用性** +兼顾通用性与性能,支持协议能在各种设备上运行 + +### 服务自省 - 应用粒度的服务注册 + +Dubbo 最大的优势之一在于其易用性,其面向接口(RPC 方法)的编程模型。同时,面向接口的治理也带来了一些问题: + +* 地址数量成倍增长,给地址推送带来很大压力 +* 和主流微服务体系模型不匹配,如 SpringCloud、Kubernetes 等 + +为此,我们计划引入应用粒度的服务注册机制,主要有以下几个重点: + +* 注册中心按 “应用 - 实例IP” 组织,不再关心 RPC 接口同步 +* 引入独立的元数据服务完成 RPC 接口同步工作 + +以下是应用粒度服务注册(服务自省)的基本工作原理,请持续关注后续对这部分的具体解析和开发进展。 + +![service discovery new](/imgs/blog/servicediscovery-new.png) + +### 云原生 + +云原生带来了底层基础设施,应用开发、部署和运维等全方位的变化: + +**基础设施** + +* 基础设施调度机制变化,带来运维(生命周期)、服务治理等方面的变化。 +* 服务发现能力下沉, Kubernetes 抽象了 Native Service Discovery。 + +**Service Mesh - 云原生微服务解决方案** + +* Mesh 为跨语言、sdk 升级等提供了解决方案,Dubbo sdk 要与 Mesh 协作,做到功能、协议、服务治理等多方便的适配。 +* Mesh 尚未大规模铺开,且其更适合对流量管控更关注的应用,传统 SDK 的性能优势仍旧存在,两者混部迁移场景可能会长期存在。 + +从应用场景上,Dubbo 可能的部署环境包括: + +1. 不使用 Kubernetes Native Service,Kubernetes 只作为容器编排调度设施,继续使用 Dubbo 自建的服务注册、发现机制。 +2. 复用 Kubernetes Native Service,Dubbo 不再关心服务注册,Dubbo Client 负责服务发现与流量分配。 +3. Dubbo sdk 往 Mesh 迁移,一方面要做到适应 Mesh 架构,成为 Mesh 体系下的 RPC 编程和通信方案;另一方面要做到 Dubbo 与 Mesh 架构长期共存,互相打通服务发现和治理体系。 +4. Kubernetes 上与云下混合部署的平滑迁移支持,包括服务发现的统一与网络通信方案的打通。 + +从 Dubbo 功能划分上,将着重从以下方面提供对云原生基础设施的支持: + +**生命周期:** Dubbo 与 Kubernetes 调度机制绑定,保持服务生命周期与 Pod 容器等生命周期的自动对齐 +**治理规则:** 服务治理规则在规则体、规则格式方面进行优化,如规则体以 YAML 描述、取消过滤规则对 IP 的直接依赖,定义规则特有的 CRD 资源等。 +**服务发现:** 支持 K8S Native Service 的服务发现,包括 DNS、API-Server,支持 xDS 的服务发现 +**Mesh 架构协作:** 构建下一代的基于 HTTP/2 的通信协议,支持 xDS 的标准化的数据下发 + + + + + + + + + diff --git a/content/en/blog/news/apachecon-2023.md b/content/en/blog/news/apachecon-2023.md new file mode 100644 index 000000000000..ca44b09bdcba --- /dev/null +++ b/content/en/blog/news/apachecon-2023.md @@ -0,0 +1,16 @@ +--- +title: "Dubbo 微服务专题论坛 - 8月19日北京ApacheCon大会不见不散" +linkTitle: "Dubbo 微服务专题论坛 - 8月19日北京ApacheCon大会不见不散" +date: 2023-08-07 +tags: ["新闻动态"] +description: > + Dubbo 微服务专题论坛 - 8月19日北京ApacheCon大会不见不散! +--- + +Dubbo 微服务专题论坛将于8月19日下午在北京丽亭华苑酒店举行,作为本次 CommunityOverCode Asia 2023(原 ApacheCon Asia)大会上的重磅议题,我们将以 Apache Dubbo 为中心展开,给大家带来开源微服务技术方向发展、云原生微服务选型、企业实践分享等精彩内容! + +打开 [官网购票链接](https://www.bagevent.com/event/cocasia-2023),输入 cocasia 优惠码可八折购票! + +![apachecon-rpc-schedule](/imgs/blog/2023/8/apachecon/apachecon-rpc-schedule.png) + +作为 Apache 软件基金会(ASF)的官方全球系列大会,每年的 CommunityOverCode Asia 都吸引着来自全球各个层次的参与者、社区共同探索 "明天的技术"。8 月 18 日至 20 日,即将强势来袭的 CommunityOverCode Asia 2023 上,大家可以近距离感受来自 Apache 项目的最新发展和新兴创新。 diff --git a/content/en/blog/news/apachecon-asia-2023-summary.md b/content/en/blog/news/apachecon-asia-2023-summary.md new file mode 100644 index 000000000000..2e584dd553e5 --- /dev/null +++ b/content/en/blog/news/apachecon-asia-2023-summary.md @@ -0,0 +1,57 @@ +--- +title: "CoC Asia 2023 大会精彩回顾" +linkTitle: "" +date: 2023-08-25 +description: > + Community over Code Asia 首次下线大会在北京召开,Dubbo 微服务专题论坛带来了 8 大精彩主题演讲,让我们一起回顾一些大会的一些精彩瞬间吧。 +--- + +以下包含本期演讲的完成文字稿内容与现场精彩瞬间,更多 ppt、视频录像可关注 "apachedubbo" 微信公众号获取。 +* [基于 Triple 协议实现 Web、移动端、后端微服务全面打通](/en/blog/2023/10/07/基于-triple-实现-web-移动端后端全面打通/) +* [手把手教你部署 Dubbo 应用到 Kubernetes - Apache Dubbo & Kubernetes最佳实践](/en/blog/2023/10/07/手把手教你部署dubbo应用到kubernetes-apache-dubbo-kubernetes-最佳实践/) +* [Apache Dubbo 云原生可观测性的探索与实践](/en/blog/2023/10/07/apache-dubbo-云原生可观测性的探索与实践/) +* [Opensergo & Dubbo 微服务治理最佳实践](/en/blog/2023/10/07/opensergo-dubbo-微服务治理最佳实践/) +* [Seata 微服务架构下的一站式分布式事务解决方案](/en/blog/2023/10/07/seata-微服务架构下的一站式分布式事务解决方案/) +* [启动速度提升 10 倍:Apache Dubbo-静态化 GraalVM Native Image 深度解析](/en/blog/2023/10/07/启动速度提升10倍apache-dubbo-静态化-graalvm-native-image-深度解析/) +* [政采云基于 Dubbo 的混合云数据跨网实践](/en/blog/2023/10/07/政采云基于dubbo的混合云数据跨网实践/) +* 工商银行分布式建设及转型实践 + +![dubbo-members-justin](/imgs/blog/2023/8/apachecon-summary/dubbo-members-justin.jpg) + +Apache Dubbo 社区骨干成员及 Apache Board Member, Justin Mclean 合影 + +![dubbo-members-apache-members](/imgs/blog/2023/8/apachecon-summary/dubbo-members-apache-members.jpg) + +Apache Dubbo 社区骨干与 Apache Member 交流合影 + +![huazhongming](/imgs/blog/2023/8/apachecon-summary/huazhongming.jpg) + +华钟明,Apache Dubbo PMC Member,杭州有赞科技有限公司中间件技术专家,《Apache Dubbo 静态化 GraalVM Native Image 解决方案与实践》 + +![songxiaosheng](/imgs/blog/2023/8/apachecon-summary/songxiaosheng.jpg) + +宋小生,Apache Dubbo Committer,平安壹钱包中间件资深工程师,《Apache Dubbo 云原生可观测性探索与实践》 + +![chenyouwei](/imgs/blog/2023/8/apachecon-summary/chenyouwei.jpg) + +陈有为,Apache Dubbo PMC Member,陌陌研发工程师,《基于 Triple 协议实现WEB、移动端、后端服务全面打通》 + +![jiangheqing](/imgs/blog/2023/8/apachecon-summary/jiangheqing.jpg) + +江河清,Apache Dubbo PMC Member,阿里云研发工程师,《精进云原生 - Dubbo Kubernetes 最佳实践》 + +![wangxiaobin](/imgs/blog/2023/8/apachecon-summary/wangxiaobin.jpg) + +王晓彬,Apache Dubbo Committer,政采云资深开发工程师,《政采云基于 Dubbo 的混合云跨网方案实践》 + +![hejiahuan](/imgs/blog/2023/8/apachecon-summary/hejiahuan.jpg) + +何家欢,Sentinel Maintainer,阿里云研发工程师,《OPENSERGO & DUBBO 微服务治理最佳实践》 + +![dingxingzhong](/imgs/blog/2023/8/apachecon-summary/dingxingzhong.jpg) + +丁兴中,中国工商银行软件研发中心云计算实验室架构师,《工商银行分布式建设及转型实践》 + +![jimin](/imgs/blog/2023/8/apachecon-summary/jimin.jpg) + +季敏,Seata 开源项目创始人,阿里云分布式事务产品负责人,《SEATA:微服务架构下的一站式分布式事务解决方案》 diff --git a/content/en/blog/news/apachecon2023/dubbo-on-kubernetes.md b/content/en/blog/news/apachecon2023/dubbo-on-kubernetes.md new file mode 100644 index 000000000000..774b6938d516 --- /dev/null +++ b/content/en/blog/news/apachecon2023/dubbo-on-kubernetes.md @@ -0,0 +1,181 @@ +--- +title: "手把手教你部署Dubbo应用到Kubernetes – Apache Dubbo Kubernetes 最佳实践" +linkTitle: "手把手教你部署Dubbo应用到Kubernetes – Apache Dubbo Kubernetes 最佳实践" +tags: ["apachecon2023", "observability", "metrics", "tracing"] +date: 2023-10-07 +authors: ["江河清"] +description: 手把手教你部署Dubbo应用到Kubernetes – Apache Dubbo Kubernetes 最佳实践 +--- + +精进云原生 – Dubbo Kubernetes 最佳实践 + +摘要:本文整理自阿里云研发工程师、Apache Dubbo PMC江河清的分享。本篇内容主要分为六个部分: + +- 一、使用 Dubbo Starter 初始化项目 +- 二、开发微服务之协议选型 +- 三、基于 Kubernetes 快速初始化环境 +- 四、快速部署应用到 Kubernetes 集群中 +- 五、云原生微服务可观测最佳实践 +- 六、在 Kubernetes 中管理微服务应用 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img.png) + +上图是从 Istio 借鉴的一个demo,它包含了四个组件,分别是Product Page、Reviews、Details、Ratings,它就是一个全链路的串联,实现了整体的微服务架构,它的功能可以实现我们简单的调用。 + +## 一、使用 Dubbo Starter 初始化项目 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_1.png) + +首先介绍一下Starter的功能。对于很多开发来说,在Java体系下创建出新的应用,无外乎就是用IDE创建一个新的项目,或者用maven的artifact,或者基于Spring的Initializer。 + +上图使我们基于Spring的Initializer建立了我们自己的初始化项目的工程。我们点击最上面的网址就能直接看到这个页面了,你需要输入对应的group和artifact。然后选择你希望用到的组件,比如Nacos、Prometheus的组件等等。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_2.png) + +除此之外,我们在IDE里提供了一个Dubbo的插件。这个插件可以通过上图的方式进行安装,或者如果你的仓库里已经用到了Dubbo的配置,它会提示你可以直接安装。安装完成后在右边就会有一个对应的初始化的项目了。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_3.png) + +上图是一个示例,它在这里建立了一个Dubbo的项目,然后你需要在这里选中所需要的组件信息,最后点击创建,之后它就会帮你在本地直接创建出一个全新的项目,然后你就可以在这个模版上开发了。 + +## 二、开发微服务之协议选型 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_4.png) + +我们会用到最新的Triple协议,它整体支持兼容gRPC、HTTP/1、HTTP/2。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_5.png) + +这里主要想和大家分享的点是,我们基于curl访问的能力,比如POSTMAN、HttpClient都是支持的。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_6.png) + +下面来看一下我们的项目,这是刚才建立的一个项目,我现在把应用启动起来,配置一些注册中心的地址,这就是一个标准的Spring的启动的流程。这里定义了一个接口,这个接口返回了一个"hello"的内容信息。然后我用一个简单的命令,就可以直接返回我的hello world的结果了。这样对我们本身的测试来说有很大的帮助,也就是本地启动之后,就可以直接测试接口。 + +## 三、基于 Kubernetes 快速初始化环境 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_7.png) + +假设我们已经把前面四个应用的代码全部开发完成了,接下来我要把它部署到K8s环境上。部署之前有一个非常重要的步骤,需要先初始化环境。比如Nacos、ZK、Skywalking、Zipkin、Prometheus等组件,我们都需要将它们安装上去,因为它们是应用前置依赖的各种组件。这些组件的安装流程都很复杂,那么我们如何简化这个流程呢? + +Dubbo提供了一个命令,这个命令可以一键帮你在K8s体系下拉起上图左边的所有组件。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_8.png) + +这里有一个简单的例子,拉起来之后,它会把所有的组件都会帮你拉起来。这里埋一个点,这里的Prometheus我们后面还会继续使用。整个Nacos的地址,Zookeeper的地址都会直接提供给你。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_9.png) + +这也是一个的例子。执行一个简单的命令,然后本地会把kubectl的配置都准备好,它就会自动的帮你把组件都创建起来。也就是我们一键就可以获取到所有service的部署。 + +## 四、快速部署应用到 Kubernetes 集群中 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_10.png) + +部署应用有三个重要的点,分别是应用容器化、无状态部署、生命周期对齐。 + +首先介绍一下应用容器化。想要将应用容器化,首先需要建一个dockerfile,引入一个jdk的包,把启动命令和启动脚本拉进去。然后还要写一个Java的编译的脚本,把Java编译的jar包结果拉进去。这个过程非常复杂,所以我们可以用一下Jib的插件。这个插件是maven的一个plugin,我只需要把这些配进去,指定成我的Image就足够了。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_11.png) + +可以看到,我只需要把我的pom里添加一个对应的配置项依赖,通过一键maven的编译模式,它就可以在maven打包的过程中帮你构建完镜像,然后直接推送到远端仓库。这一切都只需要这一个命令就可以完成,而且一次性配置之后,未来你所有的镜像更新都可以自动化的去做,不需要再去写繁琐的dockerfile。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_12.png) + +其次介绍一下无状态部署。刚才我们把镜像打出来了,这只是第一步,紧接着我们要让镜像run起来。我们可以基于K8s的deployment的模式,它是从K8s的官网上直接拉下来的。拉下来之后我们可以指定对应的应用名、镜像信息等等,这是K8s无法绕过去的,相对于说它需要配置这样的一个demo,当然也会有云厂商平台提供一个可视化的界面给你,它的底层配置的就是这样的一个yarml。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_13.png) + +这是一个简单的例子,把deployment配置完之后,指定了刚才的镜像。同时我声明了一个service,这个service非常重要,它后面会作为from_end应用入口的配置,但它是一个Ingress网关。可以看到apply镜像之后,我们就可以在K8s体系上把这个环境run起来了。 + +这里做一个简单的测试,我引入一个curl的容器,同样我们可以用刚才curl的命令访问我新部署好的容器节点,可以看到它返回了hello world的数据信息。 + +综上,我们通过deployment的部署,可以在K8s上把容器run起来,同时它还可以对外提供服务,对外提供的服务我可以通过下面curl的命令进行调用。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_14.png) + +最后介绍一下生命周期对齐。整体部署上了之后,大家都会进行多Pod部署,所以就会涉及到分批的行为。如果现在分了两批,且我希望我的业务中间是不中断的,这个时候就需要让K8s帮我们进行分批处理。因为K8s只知道进程起来了,所以我们需要让K8s感知到这个应用当前的状态是否startup了。然后还需要让K8s知道是否ready,以及是否存活。这是K8s提供的流程,那么怎么和Dubbo的流程相匹配呢? + +上图右侧有一些Dubbo原生提供的ports信息,我们会对外发布这样的Dubbo的状态信息,可以让你和K8s的生命周期完整的对齐。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_15.png) + +上图是一个例子。在整个应用启动的时候,这里sleep了20秒,然后配置了对应的Pro信息。 + +我们简单推测一下,我在前面设置了等待20秒,那么我的应用肯定要超过20秒才能起来。因为修改了代码,所以这里需要重新编译一下,用一键maven的编译模式直接推上去。接下来要把deployment apply进去,进去之后Pod的状态全都是not ready的,都是零的状态。 + +因为前面sleep了20秒的时候,Dubbo还没启动完,所以都是not ready的状态。我们等sleep的阶段过了,它就会变成ready的状态,然后再进行分批这就是生命周期对齐的过程。 + +所以K8s知道应用什么时候启动成功了,什么时候启动失败了,才能进行更好的调度。 + +## 五、云原生微服务可观测最佳实践 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_16.png) + +部署上去之后,我们还会涉及到整个应用的可观测。因为我们的应用可能部署了非常多节点,我需要感知应用的状态。 + +可观测体系包括Metrics体系和Tracing体系。Metrics体系包括几个指标,比如谷歌的四个环境指标,延迟、流量等等。对应到Dubbo,会提供QPS、RT等等指标,它都是在这样体系下的Metrics的最佳实践。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_17.png) + +前面在部署初始化环境的时候,提了Prometheus的服务,现在就有用了。当我把Prometheus环境部署完之后,我们只需配置几行简单的Metrics采集信息。然后Prometheus就会帮你在你的节点上面采集很多的Metrics信息,然后得到右边的panel信息,这个panel也是Dubbo官方提供的,可以直接看到Dubbo的状态信息。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_18.png) + +上面是一个演示的例子。我们在前面的deployment的例子上加上Metrics的采集信息,然后把它apply进去之后,我们就可以用整个Grafana导出过来。跑了一段时间之后,就会有对应的流量信息,比如QPS信息、RT信息、成功率等等。 + +得到这些指标后,我们还可以做一个告警。比如QPS从100突然跌到了0,或者成功率突然跌了很多,这种情况我们需要做一个警示,让大家知道当前发生的问题。我们可以基于Prometheus采集,做一个主动的推送,这就是告警的过程。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_19.png) + +Tracing包括内置的Tracing、agent注入的方案。目前主流的Go语言和其他语言大多都会用sdk依赖一个open去做一个Tracing。因为Go构体系下的agent注入也不太完善,Dubbo本身也提供了默认Tracing的能力支持。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_20.png) + +大家可以看到,在这里你只需要依赖dependency里面加上Dubbo的starter,配置项里把Tracing能力打开,开启一个指标的上报,9411是我们Zipkin的一个后端。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_21.png) + +这也是一个例子,我只需要配置这些配置,它的数据就会报到Zipkin上去,这里的dependency直接加上。 + +同样的,用刚才的命令进行打包,把镜像推送上去,然后我们等待一下。推送的过程中可以看一下Zipkin这个组件,它也是在最前面我们在K8s初始化环境的时候一起拉起的,所以这一切你只需要在前面一次性部署的时候就可以拥有了。 + +然后我们简单的执行一个curl命令,因为我需要让我的环境有流量。部署完之后,用curl命令还是执行一下我们的获取,这个其实已经把后端开发完了,它返回了真实的结果。 + +接下来我们去Zipkin上看看能不能找到这条Tracing。首先把9411映射过来,我们可以看到curry一下,这里就会有对应的指标信息。整个全链路的调用信息这里都可以看到,这就是全链路的接入的流程。相当于你只需要把前面的dependency加上,把上报的配置加上,之后的一切我都会帮你在后面完成以及上报。你看到对应的结果,就可以知道全链路上发生了什么事情。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_22.png) + +除此之外,还可以基于agent的方式。如果我们基于K8s部署,我们接入一个agent也是非常方便的。你可以基于一个initContainer把整个Java的配置项信息直接注入进去,这样在skywalking上就可以看到一个对应的全链路的信息。因为和前面是类似的,这里就不再赘述它的demo的工程了。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_23.png) + +对于整个可观测来说,我们可以通过Metrics看到QPS、RT等信息,通过Tracing看到全链路的访问信息。这里提供给我们一个很好的方案,就是我们要先去做服务的观测,基于服务的观测更好的排查整体的问题,第一时间知道应用挂没挂。比如半夜两点,它的可用率跌到零了。这个时候可以通过一系列的自动化机制告诉你应用出了问题,快速的进行恢复。这里的快速恢复可以使用回滚,将流量隔离的方案他都可以快速的执行。 + +基于这样快速的从观测到排查,再到快速恢复的链条,可以构建整个生产环境下的安全稳定的体系。所以我们观测完之后的目标就是保证整个应用的稳定。 + +## 六、在 Kubernetes 中管理微服务应用 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_24.png) + +K8s给我们带来的收益包括快速扩缩容,即我可以很快的基于K8s从一个Pod变成多个Pod。因为K8s是基于整个Image的部署的流程,当镜像打包出来后,你的环境就是固定的,只需要去横向的扩容即可。 + +横向的快速扩容也会涉及到几个瓶颈的点,如果我需要让我的应用能够快速扩容,比如我的应用提起来就要几十分钟,这种情况即使快速扩容了,等扩容完之后你的业务峰值也过去了,这里就会引入到Native Image。 + +基于Native Image,我们可以很好的实现整个Serverless的横向的扩容。如果可以实现毫秒级的启动,我可以在流量来的波峰,直接让我的Pod横向扩容好几倍,当它的流量下去的时候就直接下掉,这样就实现了成本的压缩。 + +另外还有一个问题是怎么知道什么时候要扩容?这就需要基于Metrics的观测,基于一些历史数据的分析,知道在某个时间点会有多少的流量,然后提前扩容,或者做一个自动化的扩容。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_25.png) + +这里我举一个简单的例子,比如我的rating上出了一些问题,我需要把它的故障摘除掉,返回一个磨合的结果。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_26.png) + +这个时候你只需要在上面去配置一个上图的规则,它就会返回。这就是Admin的使用流程,这里就不再展开了,还有刚刚提到的我们在做Go版本的重构能力,后面也都会有更好的建设。 + +![dubbo-kubernetes-最佳实践](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_27.png) + +除此之外,基于 istio的Service Mesh治理,我们前面协议选型的时候选了Triple协议,它完全是based on HTTP标准的。因此我们使用istio的整个体系之后,你只需要挂上subcard它就会帮你去做流量治理。这一切的前提是你的协议一定是istio可见的。 + +比如你原来用是Dubbo 2的Dubbo的协议,它是一个私有的tcp协议,对于istio来说它很难分辨你的协议内容。如果你用了Triple协议,我们可以基于HTTP标准,你就可以知道你的header里有什么东西,可以去做一个流量的转发。所以它完全拥抱Mesh的体系,可以支持我们所有istio的治理能力。 diff --git a/content/en/blog/news/apachecon2023/ecosystem-opensergo.md b/content/en/blog/news/apachecon2023/ecosystem-opensergo.md new file mode 100644 index 000000000000..c722e1dd1927 --- /dev/null +++ b/content/en/blog/news/apachecon2023/ecosystem-opensergo.md @@ -0,0 +1,200 @@ +--- +title: "OpenSergo & Dubbo 微服务治理最佳实践" +linkTitle: "OpenSergo & Dubbo 微服务治理最佳实践" +tags: ["apachecon2023", "opensergo", "ecosystem"] +date: 2023-10-07 +authors: ["何家欢"] +description: OpenSergo & Dubbo 微服务治理最佳实践 +--- + +摘要:本文整理自阿里云 MSE 研发工程师何家欢的分享。本篇内容主要分为四个部分: + +* 一、Why 微服务治理? +* 二、OpenSergo:服务治理控制面与标准规范 +* 三、OpenSergo & Dubbo 最佳实践 +* 四、OpenSergo 的未来之路 + +## 一、Why 微服务治理? + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img.png) + +现代的微服务架构里,我们通过将系统分解成一系列的服务并通过远程过程调用联接在一起,在带来一些优势的同时也为我们带来了一些挑战。 + +如上图所示,可以看到一个词云,这些都是目前微服务架构在生产上所遇到的挑战。比如,最常见的流量激增的场景,近一年内AIGC突然爆火,相关网站/服务都存在过因为激增流量导致服务不可用的情况,可能会让我们错过一个最佳的增长窗口。 + +再比如缺乏容错机制,某视频网站的某个服务异常,随调用链扩散,导致全站入口不可用,影响千万用户,产生实质性的经济损失。这些生产故障频频发生,也是在提醒我们稳定性是用好微服务的重大挑战之一。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_1.png) + +为了保障微服务的稳定性,我们就需要做一些架构的演进。 + +我们先看一下左侧的微服务3大件,这个大家已经很熟悉了,通过这三者的配合,我们的应用就能够正常使用了,但是距离生产可用其实还有很大一段距离,各个企业和社区为了消除这其中的gap都有一些探索和实践,比如Dubbo社区在Dubbo3中引入一系列诸如流量管理、高可用性的能力来保障微服务的稳定性,这些措施可以统称为微服务治理。 + +所以其实大家已经意识到,从把微服务跑起来到真的生产可用,微服务治理是必不可少的一环。但微服务治理要做些什么,如何去做其实都还比较模糊。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_2.png) + +从软件生命周期的角度,我们可以把微服务治理分成三个域,开发态与测试态、变更态、运行态。 + +在这三个域中都面临着很多挑战,对于这些挑战大家也有着一些探索和实践,比如对于发布有损的问题,我们可以通过无损上下线来解决,变更的影响面通过灰度来控制,对于不确定流量使用流控、热点防护,不稳定调用使用熔断与隔离。 + +可以看到在各个域中都有一些成熟的方案和效果很好的实践。但是不管是阿里还是其他公司,在体系化落地微服务治理时都会遇到很多问题。 + +## 二、OpenSergo:服务治理控制面与标准规范 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_3.png) + +首先我们涉及的组件有很多,在微服务架构中,往往会涉及很多组件,它们需要有Dubbo这样的调用框架,nacos这样注册中心,snetinel、hystrix这样的稳定性中间件等等,因此也没办法进行统一治理,管控成本就非常高。 + +其次时概念不统一,比如在envoy中的隔离与 sentinel中的隔离完全不是一个意思,envoy的隔离是摘除不健康实例,sentinel的隔离是并发控制,这就会使开发者理解成本很高。 + +同时各个企业社区都有自己的最佳实践,这也就导致大家能力上是不对齐的,没有统一的标准。 + +还有配置不统一的问题相信大家都很有体感,比如sentinel、hystrix、istio都有熔断的能力,但是配置却各有差别,需要开发者分别学习,还要注意不混淆,不利于理解,也不利于统一管控。 + +可以发现由于这些问题,我们在落地体系化微服务治理时会有很大的阻力,我们需要的是一个统一的治理界面来让我们更好地做微服务治理,因此我们提出了OpenSergo这个项目。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_4.png) + +而OpenSergo期望提出一套开放通用的、面向云原生架构的微服务治理解决方案及标准规范,来助力保障微服务高可用,上图的四个部分就是OpenSergo社区的愿景。 + +OpenSergo社区会基于业界微服务治理场景与实践抽象成规范,通过这种方式去解决前面提到的概念、配置、能力不统一的问题,并用统一的管控面去承载,降低使用和维护成本。 + +同时在纵向上,我们针对链路上的每一环进行抽象,覆盖完整的场景,在横向上,无论是Java生态,Go生态或是其他语言,无论是传统微服务还是Mesh架构,都会纳入到这套统一的体系中。 + +但是OpenSergo作为一个开放标准,仅凭借阿里是不够的,所以我们联合了多家公司以及社区比如bilibili、中国移动、字节跳动的cloudwego社区等,共同建设这套开放标准,希望能够真正解决微服务稳定性的风险。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_5.png) + +接下来简单介绍一下OpenSergo的架构体系,前面也介绍了OpenSergo社区会基于场景抽象出OpenSergo的Spec,但这只是第一步,为了承载这些标准规范我们就需要一个控制面,社区在一开始的演进中选择从0开始开发一个控制面来做治理规则的管控、监听与下发。 + +但是随着社区的演进,我们发现基于Istion去扩展,成本更低,也能够复用更多的能力,因此在后续的演进中我们会选择结合Istio扩展控制面与决策中心实现治理规则统一管控、治理策略预计算。 + +在有了控制面后我们还需要数据面来进行具体治理能力的实现,它可以是像sentinel这样的中间件,也可以是框架本身。控制面与数据面之间的通讯在初始的架构中是基于grpc构建的链路,但在确定了后续演进方向会基于istio扩展后,社区选择拥抱xds,尽可能服用它的链路,对于一些无法承载的我们再使用自身的grpc链路。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_6.png) + +前面也提到社区控制面的后续演进是基于Istio扩展的,Istio本身也有一些流量治能力,并有着一定的普及度。但是Istio主要关注流量管理,让流量到达该去的地方而不是微服务治理治理,所以在微服务稳定性的场景下,Istio所提供的这些能力是不足以满足我们的需求的。 + +因此我们在Istio的基础上,基于微服务稳定性的一些场景,比如前面提到的变更态稳定性、运行时稳定性去抽象、制定了满足需求的规范标准,希望能够更加贴合微服务场景。所以整体上我们在微服务治理领域会是Istio的超集,而不是互斥关系。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_7.png) + +接下来我们一起看一下OpenSergo的标准规范是如何解决前面所提到的这些场景。 + +首先我们聊一下流量路由,它的主要作用是将符合一定特征的流量路由到指定的workload上,一般大家会用这种能力来实现灰度、同AZ路由等方案。 + +基于 Istio VirtualService/DestinationRule 的格式社区定义了流量路由spec,但我们在调研以及实践的过程中发现,它并不能很好的满足微服务场景下的需求。所以为了更贴近微服务的场景去扩展去做了扩展。比如我们增加了路由失败后的处理逻辑,这在微服务架构中是很常见的需求。 + +又由于Istio主要关注的是HTTP请求,它的CRD不能够很好地承载像Dubbo这样的RPC调用,所以我们为此增加了更多RPC模型的支持。后续我们也会探索与社区标准结合的方案,使我们的Spec更加通用与标准。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_8.png) + +前面所提到的灰度,在阿里集团内部数年的安全生产实践中,与可监控、可回滚一起被定义为安全变更的三板斧,其中灰度是控制变更影响面,保障变更稳定性的必不可少的能力。 + +为了实现灰度,我们通常有几种方案,第一种是物理隔离,我们通过部署两套一样的环境来实现灰度,但是这种方案的部署和维护成本都很高。 + +为了提高资源利用率,便产生了第二种方案,流量灰度。我们不部署独立的环境,而是在流量的每一跳进行流量的特征匹配,并且由此决定去往灰度实例还是base实例,这种方案相较与前者更加灵活高效,可以通过前面提到的流量路由能力来实现。但是需要我们在每一跳都配置路由规则,相对比较繁琐。 + +并且由于有些信息在后续链路是获取不到的,比如uid,导致这个方案的实施有一定的困难。于是便产生了第三种方案,全链路灰度,我们通过在流量入口处进行流量匹配并打上标签,标签会自动沿着调用链路透传,后续链路根据标签来进行路由。通过这种方式,我们就能够更简洁地去定义灰度。Opensergo针对这种场景抽象了对应的CRD。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_9.png) + +我们将这个CRD称之为TrafficLane也就是泳道,我觉得还是比较形象的,大家看一下上边的图片,橙色的是正常的流量走向,灰色的是灰度流量的走向,就像是将一个池子分成了多个泳道。 + +泳道的CRD有三个部分组成,也比较好理解,首先我们需要去匹配灰度流量,所以就要去定义匹配的条件,然后定义为这些流量打上什么标签,最后再定义这个标签以什么方式去透传。 + +通过这样的CRD我们就定义了一条灰度泳道。但是如果只是定义是不足以实现全路灰度的,我们还需要借助OpenSergo体系全链路全方位框架的一个支持,才能让标签在这些框架中自动的透传,这些框架也能通过标签进行路由。其中流量染色和标签透传会借助标准的trcae体系去实现,比如OT。 + +上图右侧是一个CRD的例子,大家可以简单看一下。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_10.png) + +接下来我们一起看一下运行态稳定性的场景。 + +我们主要提两个场景,第一个是流量激增的场景,比如双十一的秒杀活动,一开始流量是稳定的情况下,系统也处于稳态。但是当流量激增的时候,系统就会开始往不稳定的方向发展,异常调用也会激增,最后就会变成不可用的状态。对于这类场景,我们可以用流量控制的能力拒绝超出容量的请求,或是通过流量平滑的能力削峰填谷,让流量处于比较平稳的状态,避免服务的不可用。 + +第二个是不稳定调用导致服务不可用的场景,比如我们调用一些第三方服务经常会出现不稳定的情况,这里的不稳定主要指异常或是慢调用。以dubbo为例,当服务提供方出现慢调用的时候,会导致服务消费方的线程堆积,影响到其他的正常调用甚至是整个服务的稳定性,并且这种风险会沿着调用链反向传递、扩散最终影响整个系统的稳定性。这时我们可以通过并发控制或是熔断保护来限制慢调用对资源的占用,保障系统的整体稳定性。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_11.png) + +针对前面提到的这些场景,OpenSergo也制定了相关的CRD。在业界的实践中sentinel是一个成熟的流量防护方案,在阿里内部积累了大量的流量防护相关的场景和实践,2018年开源依赖在业界进一步丰富了这些积累,我们从这些积累中抽象出了一套流量防护的规范标准。 + +那么一条流量防护的规则应该包含哪些内容,大家可以简单想一下。 + +首先我们要确定的是要针对怎样的流量,我们可以按接口去划,也可以按请求中的特征去划。确定了目标之后,我们就需要定义要采取怎样的治理策略。这里的策略包括了刚才提到的这些策略,以及更高阶的比如自身过载保护等策略。 + +最后由于限流本身是有损的,但是我们不希望这种有损传递到用户侧,因此我们需要为不同的规则配置不同行为,从而使得在用户侧的表现是比较友好的,比如最基本的对于抢购场景的限流,我们可以返回一个排队中,请稍后的提示。 + +上图右侧是一个CRD的示例,流量目标为接口名为/foo的请求,策略为阈值为10的全局限流,fallback为特定的返回体。 + +通过这样的CRD配置,不管是Dubbo框架还是其他框架,我们都能很方便的使用流量防护的能力。 + +## 三、OpenSergo & Dubbo 最佳实践 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_12.png) + +对于框架开发者来说想要接入到OpenSergo的体系中其实有两种方式 + +一种是通过对接OpenSergo体系的数据面来接入,框架开发者只需要实现对接Sentinel的适配模块就可以完成对接工作。而对于有特殊要求或是更贴近特定场景的框架,也可以自行对接OpenSergo的标准,来接入OpenSergo体系。 + +对于用户来说,不管是哪一种方式,都只需要简单地引入一些依赖,就可以无感地获取OpenSergo定义的微服务治理能力,并能在统一的控制面管控这些框架的微服务治理能力,大大提高使用微服务治理的体验与效率。讲完了接入的方式,我们再一起来看下实现的效果。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_13.png) + +第一个实践是全链路灰度控制消除变更态稳定性风险。这是一个简单的demo,我们只需要部署这样的一个CRD,定义/A/dubbo的请求,当它的参数里出现xiaoing的时候,我们就把它导向灰度的环境。可以看到现在的请求走向是符合我们预期的,有灰度环境的就是灰度环境了。对于不符合要求的流量,就还是走基线环境,我们只需要简单的CRD就可以实现。 + +但我们的生产环境会比demo复杂的多,会涉及各种框架,比如RokcetMQ、spring cloud alibabab。但只要这些框架对接了Opensergo的体系,就可以用这一个CRD来做到全链路,全框架的灰度。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_14.png) + +第二个实践是流量防护与容错保障运行时稳定性——不稳定调用场景。这里使用一个简单的Demo,应用A通过Dubbo调用应用B。右侧是一个正常接口和慢调用接口的流量图,蓝色的是总流量,黄色的是拒绝流量,橙色的异常流量。在一开始慢调用还没有发生,系统处于稳态,没有异常流量。 + +在第一个时间点,我手动调整了慢调用接口的RT,慢调用发生,异常流量出现,同时由于慢调用大量地占用了Dubbo的线程资源,导致正常调用的资源受到挤占,同样出现大量的异常流量,Dubbo侧也出现了线程池耗尽的异常。 + +大家可以想一下,这种场景下我们应该配置什么规则来解决这个问题,其实这个时候很多人会想要流量控制来做限流希望能解决这个问题,我们一起看下它的一个效果。 + +在第二个时间我配置了一条限流规则,可以看到情况虽然有所缓解,但是依旧有大量报错,这是因为在慢调用场景下,请求已经出现堆积,仅仅通过QPS限流还是会导致请求涌入进一步堆积。 + +所以我们真正需要的并发控制,在第三个时间点我配置并发控制规则来限制慢调用接口的并发数,也就是正在处理的请求数。可以看到通过这种限制,即便慢调用仍然存在,但是它所能占用的线程资源被限制,正常接口得以正常调用,从而避免稳定性风险的扩展,保障应用的稳定性。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_15.png) + +第三个实践是流量防护与容错保障运行时稳定性——自适应过载保护。可以看到我们的demo在持续的高负载下,异常流量开始逐渐上升,系统的稳态被破坏,这时我们可以通过配置自适应过载保护规则,来自适应地调节限流行为,达到消除异常请求,帮助系统重新回到稳态的效果。 + +目前的策略我们在开源已经支持了BBR,在内部的实践中我们也有用PID。这些策略我就不在这里详细介绍了,大家感兴趣可以去我们的开源社区一起参与讨论。 + +从这三个例子可以看到Dubbo通过对接Sentinel接入OpenSergo体系后就无感地具备了OpenSergo所定义的通用的治理能力,并且能够通过统一的控制平面来管控。 + +而对于其他框架也是一样,可以设想一下如果我们生产上所涉及的所有框架都对接了OpenSergo体系,那我们就可以在一个控制面上管控所有服务,所有框架的微服务治理能力,更好地保障系统的稳定性。 + +## 四、OpenSergo 的未来之路 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_16.png) + +这是多语言服务治理的生态大图。在生态上,我们希望OpenSergo是全链路多语言异构化的,我们会主要关注Java/Go + Gateway + Mesh 生态,在生态上不断去覆盖更多的框架。 + +在能力上我们会不断抽象并落地更多的通用的微服务治理能力。包括流量防护、自愈、服务容错、健全、发现等等。 + +目前我们已经和很多社区建立了联系和合作,比如Dubbo、ShenYu、APISIX、Higress、RocketMQ、MOSN等等,其中也有不少已经有了一些实质性的进展。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_17.png) + +接下来分享一下我们近期的规划。 + +- 控制面方面,我们会逐步推动控制面的生产可用,在明年3月份发布GA版本,让大家能够在生产上去验证微服务治理体系。 +- Spec方面,我们会去支持微服务安全治理、离群实例摘除,并持续地与社区标准集成。 +- 治理能力的演进上,我们会重点完成Sentinel 2.0 流量治理的升级,并在安全和自适应方向上进行探索。 +- 在社区合作上,我们会继续推进与社区间的交流与合作,推进各个微服务治理领域的生态落地,统一控制面、Spec 共建。 + +![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_18.png) + +虽然阿里在集团以及云上积累了大量的经验和场景,但稳定性的问题是复杂的,场景是多样的,仅凭一方不足以覆盖所有稳定性的场景,也不足以成为标准,所以微服务治理技术、生态与标准化的演进还需要各个企业和社区的共同参与。 + +大家可以从以下三个方面入手来参与社区。 + +- 微服务治理的spec,各个社区和企业都是各自领域中引领者,大家能从各自的场景和最佳实践出发,一起制定与完善标准规范。 +- 微服务统一控制面的演进,这一块其实有很多的可能性,作为控制面其实它处在一个决策者的位置,一定程度上具备整个系统的上帝视角,在AI技术火爆的当下大有可为。 +- 治理能力与社区生态的贡献,大家可以参与到服务治理能力的演进中,也可以贡献各个社区和OpenSergo体系的对接。 + +最后我想说,微服务治理其实是一个很广阔的平台,参与其中,你可以接触到各个领域的技术与场景,而不是被限制在单点技术范围内摸爬滚打。欢迎企业与社区同学加入开源贡献小组,一起主导下一代微服务技术体系的演进! \ No newline at end of file diff --git a/content/en/blog/news/apachecon2023/ecosystem-seata.md b/content/en/blog/news/apachecon2023/ecosystem-seata.md new file mode 100644 index 000000000000..fb9577272db3 --- /dev/null +++ b/content/en/blog/news/apachecon2023/ecosystem-seata.md @@ -0,0 +1,160 @@ +--- +title: "Seata 微服务架构下的一站式分布式事务解决方案" +linkTitle: "Seata 微服务架构下的一站式分布式事务解决方案" +tags: ["apachecon2023", "seata", "ecosystem"] +date: 2023-10-07 +authors: ["季敏"] +description: Seata 微服务架构下的一站式分布式事务解决方案 +--- + +摘要:本文整理自阿里云分布式事务产品负责人、Seata 开源项目创始人、微服务开源治理负责人季敏的分享。本篇内容主要分为三个部分: + +* 一、微服务架构下数据一致性的挑战 +* 二、分布式事务Seata的架构演进 +* 三、如何基于Seata扩展RPC和数据库 + +## 一、微服务架构下数据一致性的挑战 + +![dubbo-seata-分布式事务最佳实践](/imgs/blog/2023/8/apachecon-scripts/seata/img.png) + +在2019年,我们基于Dubbo Ecosystem Meetup,收集了2000多份关于"在微服务架构,哪些核心问题是开发者最关注的?"的调研问卷。最终分布式事务占比最大,有54%。 + +但在Seata出现之前,大家都说分布式事务能避就避,因为消息最终一致性去解释了问题。但Seata开源之后,这些问题都迎刃而解。比如无损上下限,到底是说服务的可用性还是其他的。对于我来说,我觉得它最终关注的是数据的问题。因为无论前端的业务怎么去交互,最终都会沉淀到数据。如果业务的数据不一致,前面是什么架构,都意义不太大,所以我认为数据是企业的核心资产。 + +![dubbo-seata-分布式事务最佳实践](/imgs/blog/2023/8/apachecon-scripts/seata/img_1.png) + +那么到底哪些场景会遇到分布式事务的问题呢? + +第一个场景,在拆分成微服务架构之后,不同的服务可能由不同的团队负责上下游的协调联动。比如C服务发布的时候,并不会通知A服务和B服务,这个时候就会遇到上下线带来的数据一致性的问题。 + +第二个场景,不可靠、不稳定的基础设施,会导致网络或者个别主机的宕机。 + +第三个场景,timeup是分布式架构里比较难解的状态,因为一旦出现服务调用的timeup,这个服务的业务逻辑到底是执行了,还是没有执行timeup的服务怎么实现数据的密度,都是比较尖锐的问题。 + +第四个场景,业务里除了会涉及到数据库,还会涉及第三方的组件。比如缓存、Redis,我们的库存会先经过Redis这样的组件,那么如何实现它的一致性也是个问题。 + +第五个场景,我们在上下游做业务的时候,你传给我一些参数,但这些参数本身可能是非法的。那么我就需要把你的下服务也回关掉,而不是只有我这一个服务去做拒绝。 + +所以分布式事务的场景主要包括了跨库、跨服务、资源的多样性。异常上主要包括业务异常、系统异常。 + +那么分布式事务是不是微服务架构独有的问题呢?其实不是,它在单体应用里也有类似的问题,只不过在微服务架构里它的问题更凸显。 + +在单体架构下存在哪些分布事务的场景呢?比如一个单体应用要去修改多个数据库或者多模块的,整体而言,单体数据库它完成的是ServerSission下边的一个本地事务。只要跨了这个本地事务,其他的都是分布式事务,即使微服务都去修改同一个数据库。这样其实你的数据库的本身也不是能反序列化传递到另外一个服务的,这些问题都会涉及到分布式事物的问题。 + +整体看起来,分布式事物涉及到了分布式架构和单体架构中非常广泛的应用。 + +![dubbo-seata-分布式事务最佳实践](/imgs/blog/2023/8/apachecon-scripts/seata/img_2.png) + +市面上的分布式事务方案有以下六类: + +- XA模式,它的问题是吞吐量和性能要差一点,在一致性上是最高水准。 +- TCC模式和SAGA模式,可以归结为是一个业务层面的分布式事务,因为他不会拦截数据。比如TCC模式可能有cc接口,至于这个接口怎么回滚,怎么正向的,在框架层面完全不用管。这可能是你里边逻辑本身不是对等的,也不是框架已经参与的,所以更多的是把接口暴露给了业务实现。 +- 消息最终一致性,它最大的优点是实现异步化的解耦,结合消息的削峰填补的特点。但它本身存在着一些问题,对消息来说,他更多的是做一个单项的通知。这个通知可能对于一些消息消费来说,即使业务失败了,它也没法去回滚。 + +比如现金红包的业务,我首先要将红包转到我的账户,然后再从我的账户转到我的银行卡。可能消息消费的时候我这个账户已经注销掉了,那么你的消息消费就会一直处在失败的状态。对于这类问题,不可能再把上游消息的发送给关掉,所以它更多的是单项通知的场景。 + +- 定时任务补偿,它的学习成本低,但实践成本高。尤其是微服务的链路有多翘的节点,需要业务逻辑写的非常周全。 +- AT模式,它综合了一致性性能,主要的特点是简单无侵入,强一致,学习成本低。缺点是需要遵守一定的开发规约,并且它不是对所有的SQL类型都支持,它有一定限制。从业务场景上来说适应的是一个通用的场景,但它并不适应于热点数据类型的高并发场景,比如SKU的库存的部件。因为在这个模式它有一个应用层的分支锁,需要对相同的数据做一个排队的等待。 + +## 二、分布式事务Seata的架构演进 + +![dubbo-seata-分布式事务最佳实践](/imgs/blog/2023/8/apachecon-scripts/seata/img_3.png) + +Seata在阿里内部的代号叫TXC,在蚂蚁叫DTX。它起源于集团的五彩石项目,五彩石的项目是当初集团内在做去IOE,从单体架构引进到分布式架构。在分布式架构必然会涉及到很多的中间价,TXC承担的主要的角色做服务一致性的保证。 + +我们和集团内的三大件都做了深度的集成,包括服务调用框架HSF,也就是对外开源的Dubbo;数据库有分库分表的TDDL组件;异步消息的MetaQ组件。在集团内也有广泛的使用,日均百亿级别调用,标准3节点集群吞吐达近10w TPS。 + +我们的SLA会分为几个SLA,一个是可用性的SLA服务,另外一个是性能的SLA服务。因为对于分配事物来说,除了要保证一致性,也要保证性能的吞吐量。所以我们规定比如每一次的RT额外的开销不能超过XX。目前能达到毫秒级的事务处理,能保证在稳定性上全年无故障。 + +![dubbo-seata-分布式事务最佳实践](/imgs/blog/2023/8/apachecon-scripts/seata/img_4.png) + +最开始我们在做分布式事务实现的时候,我们也去考虑我们的分布式事务应该是在哪层面去实现? + +从应用架构的视角,分为这么几层,一个是最上层的应用开发框架,可能每一套公司都有自己的开发框架,比如像ddt的开发框架或者club的体系等等。再下一层是服务调用框架,类似于Apache Dubbo主要承担,也在国内使用的非常广泛。再下一层是数据中间件,这层主要包括ORM框架、事务、同步、对账。再下一层是跟数据库连接,这一层类似于JDBC、Java去连数据库。 + +我们去做了一个简单的对比,到底是在哪层实现分布式事务,是在DB层、数据中间件层还是应用框架层? + +在应用框架层,它去实现一致性相对来说比较弱,因为你会掺杂很多复杂的、不可控的因素,会把服务调用的因素给牵扯进去。比如服务调用的超时,这就是为什么我们现在有的像TCC模式它会有一些密等、放悬挂那些问题。都是因为融入了RPC的因素,持续的不确性导致的一些问题。 + +在数据中间件层,它的一致性比应用框架要好一些,它主要的问题是他不是在DB层实现的,所以我是有办法绕过中间件直接去修改DB的,这时候就会存在事物并发时序的问题。最好的一致性是在DB层去实现数据一致性,但这一层数据一致性主要是数据库的厂商,但是也是参差不齐。比如Msever,他在5.7.7版本才把差异完善起来,在之前的版本它对差异回滚一直是有问题的。 + +但它只能局限在数据库的scope,如果我要去更大的scope,从应用架构层可能要跨服务,跨服务这一层它就管不了,只能管我自己数据库。所以他最终还是需要有一个第三方的去协调跨服务的数据一致性。最终我们把这一层AT差异模式是把它做到了数据库中间件这层,JDBC server这层我们做到了应用开发框架这层。 + +所以它不仅实现了一整套的集团生产体系,还包括了我们对分布式事务编程模型的定义,运维安全。因为要涉及到数据,会有数据的敏感以及性能和观测高可用等等。 + +在理论模型上我们当时还是比较匮乏的,我们做了一些对差异以及Spring事物模型的延展。我们延展了已有的模型,而不是新造一条。这于开发者来说,学习成本会更低。 + +此外,我们还做了一些定义,包括怎么定义一致性,是定义多节点的一致性,还是业务应用架构数据的一致性,以及这套架构里的角色模型设计的事物动作和隔离。 + +![dubbo-seata-分布式事务最佳实践](/imgs/blog/2023/8/apachecon-scripts/seata/img_5.png) + +什么是分布式事务的模型定义?举个例子,我去做银行转账的时候,我给你转100块钱,恰好这个时候出现了网络超时,那么这100块钱到底有没有扣。如果不确定就可能出现资损的问题,甚至可能影响企业的商誉。 + +我们都在谈分布式架构,但从整个应用的视角,并不是所有东西都是分布式的。比如我们从一个应用的架构的层面去看数据库,包括今天称之为分布数据库。从整个应用层面,它我们看它是一个集成式的数据的存储。它的内部实现可能是分布式的,包括分布式的链路数据。 + +因为在分布式的应用架构里,每个业务的节点都只掌握了部分的信息。如果做一些问题的排查,必然需要一个集成式的东西。对于分布式事务它的核心工作是做分布式协调,所以他要掌握全局的信息。 + +这就是为什么我们有了Transaction Coordinator。对他来说,他要有一个上帝视角,充当第三方的协调器。而真正做事的是Resource Manager,你可以认为它是数据库的灵魂,我们需要把它作为Pro。 + +真正随着业务应用去做事务的动作是Transaction Manager,它会随着业务的执行链路进行,到底直接事务的边界是怎么样的,以及分布式事务的动作是怎么样的。 + +![dubbo-seata-分布式事务最佳实践](/imgs/blog/2023/8/apachecon-scripts/seata/img_6.png) + +2019年1月Seata开始开源了,我们主打的特点特色是AT 模式,因为是组装,我们从0.1版本就把AT模式给开源出去了。0.4版本我们纳入了TCC的模式,因为AT模式它需要适配不同的数据库。而在现有阶段我们不能满足对所有数据库的支持以及缓存资源,这就需要应用TCC模式去做补充。你可以用TCC模式做一些我们没实现的数据库以及缓存的结构。 + +在0.9版本,我们纳入Saga的事务模式,它主要解决长事务方解决方案。比如一个事务非常长,且还有微服务的编排工作。在1.1版本,我们纳入了XA的事务模式,因为有的客户已经应用了Seata的AT模式,但他还有一些老的特别事务。他希望应用Seata统一的一套解决方案,解决不同业务常用的分支事务,所以我们把XA的事务模式也纳入进来了。 + +最终从整个架构上来说,我们是打造了一站式的分布式事务的解决方案。针对不同的业务场景,Seata都能做事务。如上图所示,目前市面上没有一只分布事务的模式,能解决不同业务场景的问题。主要强调几个问题,分布式事务可能有同步的分布式事物,有异步的分布式事务,以及对分布式事务的一致性的要求也不高。有强一致性,最终一致性,弱一致性。 + +另外,对于事物执行时间的长短也有要求。比如有长事务、短事务以及性能吞吐量等等。所以我们纳入了现在的四种事务模式,它们从改造成本、性能隔离性上各有所长,这里就不展开介绍了。 + +## 三、如何基于Seata扩展RPC和数据库 + +![dubbo-seata-分布式事务最佳实践](/imgs/blog/2023/8/apachecon-scripts/seata/img_7.png) + +首先看一下Seata开源社区这几年的发展。目前Seata已经具备了AT、TCC、Saga、XA四种事务模式,而且对于市面上主流的关系数据库,RPC框架做了广泛的支持,同时被许多第三方社区做了主动和被动集成。已经和三十多个社区做了集成,这些集成都放在我们的扩展机制里边。 + +目前多语言体系也做起来了,除了最开始的Java,Go语言支持的也非常成熟,欢迎大家去使用我们的Go版本,给我们提更多宝贵的建议。另外,我们还建建设了多语言版本,包括PHP、Python等等。 + +目前 Seata 开源产品已被上千家企业在业务系统中应用,金融企业纷纷试点。我们都知道金融类的业务对分布式事务是强需求,而且它的业务场景非常严苛。像中信银行、光大银行、农行我们也做了一些社区上的合作,改造一些他们的核心账务系统,用Seata保证他们账务体系的数据一致性。 + +目前Seata社区的Star数已经到达了24k,contributor有300+。并且Seata社区是非常开放的,现在整个Seata的框架代码有70%来自创始团队之外的外部贡献者,所以欢迎大家积极的参与到我们Seata社区里。 + +![dubbo-seata-分布式事务最佳实践](/imgs/blog/2023/8/apachecon-scripts/seata/img_8.png) + +接下来介绍一些Seata比较典型的企业案例。 + +第一个案例,中航信航旅纵横项目。中航信是Seata 最早的天使用户,用的是Seata 0.2版本。如果大家出差比较频繁,应该会用到它们的APP,航旅纵横。它解决机票和优惠券业务的数据一致性问题。虽然在早期的版本中陪我们踩了不少坑,但最终还是应用起来。 + +第二个案例,滴滴出行二轮车事业部。它在Seata 0.6.1版本就将 Seata 引入到了二轮车事业部的各个业务中,包括市面上大家看到青桔单车,还有他们内部的资产管理。 + +第三个案例,美团基础架构。美团基础架构团队基于开源 Seata 项目封装了内部分布式事务 Swan 项目,作为美团内部各业务解决分布式事务问题的组件。 + +第四个案例,盒马小镇。盒马小镇游戏互动中通过 Seata 控制偷花的流程,开发周期从20天下降至5天,大幅度减少了开发的成本。 + +综上可以发现分布式事务的两个价值。 + +- 业务的正确性,因为只有数据一致了谈架构才有意义。 +- Seata大幅度提高了开发迭代的效率。 + +![dubbo-seata-分布式事务最佳实践](/imgs/blog/2023/8/apachecon-scripts/seata/img_9.png) + +上图是Seata生态的扩展点。最上层我们定义了API这一层,中间这一层包括注册、配置中心等等,下边是群的模式,包括基于关系数据库DB的,Redis的以及现在2.x里正在推广的rough模式,负载均衡也有各种模式,以及对于分布式锁扩展也是基于各种各样的模式。目前我们对于关系型数据库也支持的挺多的。 + +![dubbo-seata-分布式事务最佳实践](/imgs/blog/2023/8/apachecon-scripts/seata/img_10.png) + +我们在做Seata机制的时候参考了Dubbo的机制,对我们的学习成长以及社区的成长还是非常有帮助意义的。我们把扩展点充分发挥到了极致,分为server侧的扩展点以及客户端的扩展点。客户端扩展点大概有30+个,server侧的扩展点包括锁的扩展、存储的扩展以及事务模式的处理。 + +从今天来看如果你去支持数据库、国产达梦、人大金仓,成本都比较低。只要按照我们的文档,按照API的扩展点去做简单的实践,就能把整个流程跑起来。另外,我们server不同的锁的存储,事务筛选的存储都是可以扩展的。这里我们也是借鉴了Dubbo去做了一些对开发者非常友好的扩展,让开发者更容易的扩展市面上的RPC框架以及数据库。 + +![dubbo-seata-分布式事务最佳实践](/imgs/blog/2023/8/apachecon-scripts/seata/img_11.png) + +目前我们支持了11中RPC框架,Dubbo是我们核心要支持的。我们类似于Dubbo,基于一般RPC都有fell或者ins。我们核心要做的是把Seata事物上下文通过服务调用链路给传递下去。并且把事物链路还原到服务里边去做事物的绑定、解除、清除等等,这个核心我们扩展起来还是比较容易的。 + +核心的话右边我们实现了一些接口,目前我们对Dubbo生态,包括老的阿里巴巴Dubbo以及Apache我们都做了充分的支持。欢迎大家在Dubbo的生态去适应一下Seata分布式事物去体验一下。 + +![dubbo-seata-分布式事务最佳实践](/imgs/blog/2023/8/apachecon-scripts/seata/img_12.png) + +目前Seata数据库支持MySQL、OceanBase、Oracle等等数据库,其中有一些PR还没有合并,比如达梦、IBMDB2。就像我刚才说的,我们只要基于当前的扩展点,我们就能做充分的扩展。 + +最近我们也是做仓库的编程之下,也是让我们眼前的同学感觉一下,它也做了一些PolarDB的支持,后边我们会对数据库的生态top 20完整的支持起来。 \ No newline at end of file diff --git a/content/en/blog/news/apachecon2023/graalvm-native-image.md b/content/en/blog/news/apachecon2023/graalvm-native-image.md new file mode 100644 index 000000000000..a656e7ec8c1f --- /dev/null +++ b/content/en/blog/news/apachecon2023/graalvm-native-image.md @@ -0,0 +1,225 @@ +--- +title: "启动速度提升10倍:Apache Dubbo 静态化 GraalVM Native Image 深度解析" +linkTitle: "启动速度提升10倍:Apache Dubbo 静态化 GraalVM Native Image 深度解析" +tags: ["apachecon2023", "native image", "dubbo aot"] +date: 2023-10-07 +authors: ["华钟明"] +description: 启动速度提升10倍:Apache Dubbo 静态化 GraalVM Native Image 深度解析 +--- + +摘要:本文整理自杭州有赞科技有限公司中间件技术专家、Apache Dubbo PMC华钟明在 Community Over Code 2023 大会上的分享。本篇内容主要分为五个部分: + +- 一、GraalVM 直面Java应用在云时代的挑战 +- 二、Dubbo 享受 AOT 带来的技术红利 +- 三、Dubbo Native Image 的实践和示例 +- 四、Dubbo 集成 Native Image 的原理和思考 +- 五、Dubbo 在 Native Image 技术的未来规划 + +## 一、GraalVM 直面Java应用在云时代的挑战 +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img.png) + +云计算时代比较显著的特点包括: + +- 基于云计算的基础设施,Java应用能够在云计算的基础设施上快速、轻松、高效的做到弹性。 +- 基于容器化技术,系统资源切分的更加细,资源的利用率也更高了。 +- 基于云计算的开发平台,让应用部署的更加容易,更加敏捷。 + +那么在云计算时代,Java应用存在哪些问题呢? + +- 冷启动速度较慢。 +- 应用预热时间过长,无法立即达到性能峰值。 +- 内存、CPU等系统资源占用高。 +- Java构建的应用程序繁重,执行还需要具备JDK环境。 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_1.png) + +在Serverless场景上,Java的问题会尤为突出,因为Serverless不仅能简化开发场景和开发体验,还能做到极致的弹性,甚至是秒级的弹性。 + +上图是Datalog统计的Fast和AWS两个产品。Java语言虽然更流行,但相较于Python和Node.JS,它的占比还是比较低的。Java本身在Serverless层面,比如在做容器的调度、镜像的下载的时候,启动时间、冷启动的时间、预热时间等等,都会影响Serverless场景下它弹性扩容的时间。 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_2.png) + +下面介绍一下GraalVM,它是可以把Java应用提前编译到独立的二进制包内,这些二进制包相对于跑在JVM上它可以更小,更快的启动,不需要预热就能够达到极限的峰值,还可以减少内存和CPU的占比。 + +可以看到它的介绍和Java语言的应用所涉及到的问题都一一对应。GraalVM应该算是JDK的"超集",除了包含完整的JDK发行版本外,还有GraalVM Compiler、Native image、Truffle等,甚至还涉及到多语言汇编的能力。 + +总结一下,GraalVM本身涉及两部分,JIT和AOT。 + +- JIT,是在编译后的class文件、字节码文件,它会在运行时把它翻译成机器码。 +- AOT, 它和JIT的区别是,它在编译期就能把字节码直接转化为机器码,无需在运行时再去处理。所以它的CPU和内存会相对更低。 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_3.png) + +上图左侧是一张Java生命周期的全景图。可以看到,它从JVM的启动,再到Java的main函数的启动,再到Java的应用预热,再到它的稳定期,最后到达效果,这是Java完整的生命周期的呈现。 + +而AOT的区别在于,它没有红色的VM。另外,JIT相对于AOT而言是没有的,也没有浅绿色的解释器。所以AOT对于JIT来说,只有内加载,GC以及它能够瞬间达到应用的稳定期。 + +根据右侧的图可以看出: + +- AOT的启动耗时相对较低,内存损耗和它打出来的二进制包相对较小。 +- JIT因为有及时编译的效果,所以现在极限的分值比AOT要好,比如它的极限吞吐量比AOT好。 + +## 二、Dubbo 享受 AOT 带来的技术红利 + +1. 多产物形态 + +![dubbo-graalvm-native-image.png](/imgs/blog/2023/8/apachecon-scripts/native/img_4.png) + +我们在编码之后,Soft Code的产物形态新增了。 + +第一种是我们传统认知上的Jar包形态,比如mvn、clean、package。第二种是Docker Image,它能轻松的帮我们直接打到镜像里面去,不用写dockerfile等文件。第三种是我们集成GraalVM后新产生的一种Native可执行文件的形态。这种形态无需JDK的环境就能启动,它能像GO一样把二进制文件直接启动。 + +2. 启动耗时大幅降低 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_5.png) + +上图的跑分都是基于4c16g的micro24的系统上跑出来的。左边和右边的区别是,左边的Provider端提供了一个Dubbo服务跑出来的,右边是提供了一个调用者的身份跑分出来的。从左边这张图可以看到,Native的可视性文件比Jar包方式的启动耗时降低了12倍+,在客户端应用,它的启动耗时降低了11倍+。所以在刚刚提到的Serverless场景上,它能提供一个非常好的启动速度。在扩容的时候能够达到秒级,甚至达到毫秒级。 + +3. 启动后立即达到性能峰值 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_6.png) + +上图也是跑分跑出来的数据,可以看到Consumer和Provider端通过静态化执行文件执行后,比都为Jar包的情况,第一次调用的耗时降低6倍。这第一次调用代表的是预热的时长,以及第一次需要解析的类,包括资源的情况等等。这让我们在Serverless场景下能够瞬间达到性能峰值。 + +4. 内存损耗大幅降低 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_7.png) + +上面有左右两张图,在Dubbo应用的基础上,它的内存损耗也降低大概3.5倍。Native静态化执行文件可以做到60M的内存占比,在客户端它的内存损耗也大概降低了4倍。 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_8.png) + +这是Dubbo在Native Image技术场景中做的努力: + +- 易用性增强:在注解和XML方式中自动识别服务接口,生成Reachability Metadata。 +- 可维护性增强:自动生成Source code,减轻了Dubbo开发者维护Adaptive的维护成本。自动扫描生成Dubbo core 所需的Reachability Metadata。 +- 多平台的支持:Linux、MacOS、Windows。 +- 多功能的覆盖:Dubbo、Triple协议。 + +## 三、Dubbo Native Image 的实践和示例 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_9.png) + +首先需要安装Dubbo Native Image,这里就不过多介绍了,大家可以根据官方的文档进行下载。 + +然后安装插件,可以看到上图中有三个插件需要安装,但和Dubbo相关的只有一个,是Dubbo Maven Plugin。除此之外,还有Spring Boot 的Maven Plugin,它提供的是Spring的AOT的能力。如果是API的接入方式我们无需加这个插件,如果是XML和注解就还需要加这个插件。第三个是GraalVM提供的插件,可以看到这里加了一个reachabilitu-metadata的执行,这个后面会介绍到。 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_10.png) + +然后配置依赖,现在Dubbo关于可达性元数据的扫描、执行,以及配置文件和Source code的生成都在Dubbo Native的依赖下面,我们需要引入这个依赖。 + +另外,注解和XML的还是需要接入一个Spring6的兼容的包。因为Dubbo现在还兼容JDK 8的版本,而Spring6发布后支持的最低版本是JDK 17,所以我们还是需要有这么一个模块做一下兼容。 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_11.png) + +最后还需要加一个插件和依赖,然后就能轻松的把应用转化成Native Image的形式。 + +最下面是完整的代码示例,大家感兴趣的话,可以尝试一下编译打包,看一下执行的效果。 + +## 四、Dubbo 集成 Native Image 的原理和思考 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_12.png) + +首先看一下Dubbo集成GraalVM Native Image技术的发展历程。2021年6月我们发布了Dubbo 3.0版本,初步探索了Native Image技术,提供了一个实验性的版本和Demo,涉及到的问题包括以下三个。 + +- 维护繁重的Adaptive源码、维护Dubbo所需的全量Reachability Metadata。可能涉及到的问题是,比如要新增一个功能,我们需要考虑coding以及code review的时候是否要添加可达性的元数据,这也会造成维护成本非常高。 +- 仅支持API方式,不支持注解和XML方式。 +- dubbo-native-plugin的插件,在后面3.1版本的时候,Native Image的发展并不多。 + +2022年11月Spring6+Spring Boot3正式发布了,它把Native Image技术作为发布的亮点展现给大家。但Dubbo社区认为我们应该对Native Image技术有一个新的跨越,所以在2023年4月发布了Dubbo 3.2版本,将Native Image技术进行了思考和重构。支持以下四个方面: + +- 编译阶段自动生成Adaptive源码,已经不需要开发者维护了。 +- 支持编译阶段自动生成Dubbo所需的Reachability Metadata。减小了打在业务启动的可执行文件里包的大小。因为在之前的版本里,它是把Dubbo所涉及的全量的可达性的元数据都打在二进制包里。比如业务用jka作为注册中心,我们把nacos也打在那里面,这就会导致它的二进制包非常大。现在这个版本如果用到jka,我们在box上解析不到nacos相关的依赖。所以我们就不会再把相关的内容打进去了,而且现在都是自动识别的。 +- 新增dubbo-maven-plugin,用于替代dubbo-native-plugin。因为dubbo-native-plugin的能力和内容是比较聚焦的,我们把它重新归名为dubbo-maven-plugin后,涉及到的是我们能够降低业务接入的心智负担。后面Dubbo相关的maven插件,都通过它来做就行了。 +- 兼容了Spring6+Spring Boot3,这就是我们在下个版本把XML和注解支持上去的技术的基础。 + +2023年12月将会发布Dubbo 3.3x版本。它基于Spring6,完成对XML和注解方式的支持,还移除了dubbo-native-plugin。 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_13.png) + +刚刚提到了非常多次Reachability Metadata可达性的元数据,到底是什么呢? + +我们先来聊一聊AOT的局限性,它本身就有局限,它遵循封闭世界的一个假设。比如它只关注能看到的所有字节码的信息,这就会带来一个问题,Java动态语言的功能就不再支持了。也及时说JNI、Java反射、动态代理、ClassPath资源的获取等都不再支持。 + +我们知道,在组件/业务开发/使用产品上涉及到的这些功能是非常多的,既然GraalVM出了这个功能,当然也考虑到了这个问题,所以它利用Reachability Metadata的能力解决了这些问题。 + +右边的这张图分为了五类,它涉及到了JNI、反射、序列化、resource、proxy相关的元数据的配置信息。它可以让开发者在编译前就提供好这些元数据信息,提前打包到可执行的二进制文件中。还有第六种分类,是预定义的类型,他需要提供完整的字节码Hash值,所以就没列出来,它可能需要和Tracing的agent联合起来使用。 + +下面我们主要介绍一下这五类。 + +第一,GraalVM 提供了Tracing Agent来辅助应用采集Reachability Metadata,也就是说在运行期间它会去采集你的行为,比如你要用到反射,他会把反射的元素自动生成出来,然后生成出一个配置文件提供给你。但是并无法确保把所有都采集完整。 + +第二,GraalVM提供了Reachability Metadata Repository,用于管理三方组件的Reachability Metadata。我们在Java反射、动态代理这种纯业务的场景,用的相对较少,在运用到组件中相对多一点。举个例子,比如Native里用到反射,我们可以在仓库中直接找到Native反射的metadata。然后通过刚刚提到三个插件中的Native自身提供的插件,它会把仓库里的元数据直接打在二进制包里,我们也就不需要关心这些公共组件的元数据信息了。 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_14.png) + +和Dubbo相关的元数据信息包括以下五类: + +第一,反射的元数据。 + +- 内外部的service。我们知道Dubbo是rpc框架,所以定义服务接口是最通用的一种能力。内部提供的服务包括metric service、metadata service,用户服务就是业务定义的服务接口。 +- SPI扩展。Dubbo的扩展能力得益于自己建的一套SPI机制。 +- 多实例。 +- 配置相关的内容。 +- 业务上自己用到的反射的行为。 + +第二,resource的元数据。如果业务上要做扩展,配置文件,resource的元数据主要涉及的就是META-INF下的三个路径。此外,还有一个是在Dubbo 3里支持对安全性的增强,序列化的黑白名单的resources的配置。 + +第三,序列化的元数据。作为rpc调用的框架,它的接口定义、方法定义、内外部分的服务、parameter、请求参数、返回类型等都需要用到序列化的接口。 + +第四,动态代理的元数据。在传统的rpc框架里动态代理是用的比较多的产品。内外部分服务的引用就是代理的元数据。 + +第五,JNI的元数据,暂时没有用到。 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_15.png) + +这是Dubbo 相关的 Reachability Metadata 总结和处理策略,我们把它分为了四类。 + +- 规律性的内容,是刚刚提到的Adaptive Source Code的生成。 +- 确定性资源和行为,是Dubbo内部的扩展以及资源的配置。 +- 不确定性的资源和行为,是业务自定义的扩展实现以及定义的服务。 +- 集成和依赖的组件,比如刚刚提到jka是其他社区的生态,它涉及到注解的元数据信息,我们会提供官方的支持,还会提供内部的适配逻辑。 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_16.png) + +这是AOT的执行流程。可以看到它的源码在编译之后,它的区别是它会从main函数开始启动Java应用进程,然后去找所有的source code和Bean的元数据信息。 + +下面是Spring Server自动生成的一个source code,它会把它生成一个Bean定义的获取的类。 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_17.png) + +而Dubbo并不是从main函数启动的,它启动了一个扫描的进程,把确定性的、不确定性的元素以及规律性的内容扫描进来,自动帮大家生成元数据信息。 + +下面是用Dubbo service生成后的一些信息。 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_18.png) + +上图是Spring本身提供的一个产物的内容以及Dubbo的AOT产物的内容。可以看到Dubbo下面是Adaptive的一些source code。最后Native在执行的时候会读取到这里所有的配置。 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_19.png) + +这是Dubbo和AOT之间的边界,可以看到API的接入方式和注解、XML的接入方式是有所区别的。注解和XML借用了Spring AOT的能力,包括ServiceBean、ReferenceBean等等,而Dubbo AOT的能力主要是自身的元数据的生产。 + +## 五、Dubbo 在 Native Image 技术的未来规划 + +1. 提升开发者体验&开发效率 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_20.png) + +Dubbo在3.0之后提供了CTL、脚手架、IDEA插件,Dubbo Native Image目前还在建设中,之后也会加进去。此外,还有一些文档的建设。 + +2. 性能优化与提升 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_21.png) + +刚刚已经分享了很多内容,但还是有很多可以做的事情。在GraalVM提供的能力上,我们还可以把一些类相关的可达性的配置加上去,产生作用之后能让最后打出来的二进制包更小,编译时间更短。 + +3. 覆盖更多的组件 + +![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_22.png) + +因为目前很多组件都还不支持,所以我们现在的主要思路是把Dubbo主仓库的扩展性支持完成,然后再往wpi的扩展上做相应的支持。 + +另外,内核所需要的可达性的元数据,我们会把它推到program的可达性的元数据的仓库上面去,让业务开发能够正常使用大陆内核里的元数据信息。 + +最后我们的思路还是优先考虑GraalVM官方的支持。 diff --git a/content/en/blog/news/apachecon2023/observability.md b/content/en/blog/news/apachecon2023/observability.md new file mode 100644 index 000000000000..b5e043f17d91 --- /dev/null +++ b/content/en/blog/news/apachecon2023/observability.md @@ -0,0 +1,164 @@ +--- +title: "Apache Dubbo 云原生可观测性的探索与实践" +linkTitle: "Apache Dubbo 云原生可观测性的探索与实践" +tags: ["apachecon2023", "observability", "metrics", "tracing"] +date: 2023-10-07 +authors: ["宋小生"] +description: Apache Dubbo 云原生可观测性的探索与实践 +--- + +摘要:本文整理自平安壹钱包中间件资深工程师、Apache Dubbo committer宋小生在 Community Over Code 2023 大会上的分享。本篇内容主要分为五个部分: + +- 一、可观测性建设 +- 二、多维指标体系 +- 三、链路追踪门面 +- 四、日志管理分析 +- 五、稳定性的实践 + +## 一、可观测性建设 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img.png) + +首先介绍一下云原生升级的挑战。目前大部分公司里基本上都有CICD、OPS来帮助开发、测试、运维提升开发的效率与质量,也会有容器化来帮助提升产线运维的效率与质量。但在云原生时代,大规模容器的频繁变更会带来很多稳定性的问题。这些稳定性问题,包含了很多我们可以提前规避掉的已知的异常,也包含了很多我们无法避免的异常,比如网络故障、机器宕机等系统无法提前测出来的问题。 + +如果我们能提前发现这些问题,其实是可以规避掉很多风险的。所以我们通过可观测系统及时的感知到了这些问题,高效的分析异常,快速的恢复系统。因此可以判定,在云原生时代,可观测系统的建设是非常重要的。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_1.png) + +Dubbo作为微服务RPG的框架,直接建设一个大而全的可观测性系统或者平台是不现实的,而且它的定位也不是很符合。可观测性系统更强调关联性,通过单维度或者多维度进行系统的观测与问题的诊断。 + +首先看一下可度量系统的健康状态的指标。Dubbo通过采集系统内部的Dubbo指标的同时,把指标内部的数据暴露给外部的监控系统。这些监控指标中间包含了很多的应用信息、主机信息、Dubbo服务标签信息等等。当我们发现问题的时候,可以通过这些标签信息关联到全链路系统。之后全链路系统可以做到请求级或者应用级的系统性能分析或者系统异常诊断。 + +Dubbo侧通过适配各大厂商门面的形式,只需进行非常简易的依赖就引入或者配置就可以直接把数据导出到各大全链路平台。无论企业使用哪个流行平台,在后期升级Dubbo后都可以直接把链路导出去。 + +另外,链路系统还包含全链路的Traceid或者局部的磁盘ID。通过全链路的ID,我们可以在链路系统直接跳转到日志平台。在日志平台里包含非常详细的日志上下文,这些日志上下文可以提供非常精确的异常问题诊断。 + +Dubbo也提供了非常详细的错误码机制和专家建议的形式,在官网上通过日志的形式可以直接通过错误码的形式直接导航到官网上的帮助文档。 + +## 二、多维指标体系 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_2.png) + +Dubbo在多维度指标体系实践的时候,我们主要从两个维度来看它。 + +第一个是纵向的维度。Dubbo指标在采集的时候有一个接入导出的流程。Dubbo为用户和开发者提供了简单易用的接入门面。接入后服务在运行过程中通过指标器进行指标的采集。Dubbo中提供了非常多的指标采集器,包括聚合和非聚合的指标采集等等。 + +然后采集的指标会通过变量值临时存储在内存里,之后会有部分指标(QPS等带有滑动窗口的最小值、最大值的聚合指标)进行聚合计算,最后这些指标会导出到外部系统。我们支持在Dubbo QPS服务质量中进行指标导出,或者把指标导出到Prometheus,或者http直接访问也可以进行指标的查询。 + +第二个是横向的维度。Dubbo指标采集覆盖了非常容易出现异常的地方。比如Dubbo 3提供了三大中心,包括注册中心、元数据中心、配置中心,存在外部网络交互的地方是非常容易出现问题的。 + +另外一个比较关键的是RPC电路上的采集,比如请求相应的时间、异常、nity网络、IO的指标等等。此外还有一些关于Dubbo线程池的指标采集。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_3.png) + +前面说的是比较大面上的指标采集,具体Dubbo的采集需要哪些指标我们也调研了很多比较流行的方法论。 + +- 图中第一张图是谷歌SRE书的四大黄金指标。它是谷歌总结大规模的分布式服务监控总结出来的,它可以进行请求级别的服务质量的衡量,主要包含延迟、流量、错误以及饱和度。 +- 图中第二张图是RED 方法。它更侧重于请求,从外部视角来查看服务的健康状态,主要包含速率、错误与持续时间。 +- 图中第三张图是USE 方法。它更侧重于系统内部的资源使用情况,包含利用率、饱和度与错误。 + +可以看到,以上三个指标的方法论中都包含的指标是错误,错误也是每个开发者比较关注的。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_4.png) + +然后我们进行了指标的系统完善。在Dubbo 3.2版本中,多维度指标体系已经完成,而且也在快速持续的版本迭代中。在这个版本中我们只需要引入一个快速集成的Spring Boot中的Starter包就可以实现指标的自动采集。之后我们通过Dubbo的QPS服务质量端口可以直接访问到。如果是本机可以通过浏览器,如果是服务器可以通过科尔命令访问52端口,后面加一个Metric路径,这样就可以看到非常详细的默认指标的导出。 + +可以看到这些指标有Dubbo前缀,类型是Dubbo的不同模块,比如消费者提供的请求级别,三大注册中心一起线程。 + +下面是Dubbo当前指标的行为,比如响应时间最后会加一些单位,这个格式参考的是Prometheus的官方格式。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_5.png) + +多维度指标体系有些人可能会直接复用Spring Boot默认的manager管理端口,Dubbo也适配了一下Spring Boot Actuator的扩展。 + +操作和刚刚一样,只是引入Spring Boot Starter包。后面也无需做任何其他的配置,就可以在Spring端口里看到详细的指标了。包括Spring Boot内置的jvm指标、Dubbo指标等等。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_6.png) + +指标体系接入之后,我们如果直接通过命令行访问只能看到一些瞬时的数据,但在监控指标体系我们其实更关注的是多维度的向量数据。如果我们把这些数据看作是一个点其实是比较难看出问题的,所以我们需要把这些数据存储起来,看作是一个实际化的向量数据。 + +Dubbo默认提供对Prometheus采集的介入。Prometheus作为指标存储与监控一体的监控系统,提供了很多的服务发现模型。比如我们直接把服务部署在K8s上,可以直接基于K8s标签的服务发现机制进行指标采集。如果公司有自建的cmdb系统,可以自己扩展http接口进行指标采集。此外,文件或者静态的服务发现机制只要能发现Dubbo服务的IP和服务接口,也可以进行指标采集。采集到的指标会自动存储在Prometheus的实际数据库里。 + +上图是我们通过Prometheus的查询框查询出来的响应时间的最新指标。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_7.png) + +Prometheus的指标更侧重于存储与报警,如果我们想更直观的体现还需要接入Grafana。Grafana的目标是为企业提供简易接入的监控面板,上图是一个简易的全局大盘。 + +我们通过应用级别的筛选/机器IP维度的查询/服务接口的维度,查询服务的健康状态。可以看到,这些指标基本上都是基于前面总结的方法论实现的。比如QPS、请求数量、成功率、失败率、请求的时延等等。 + +此外,还有一些应用信息的指标,比如升级Dubbo 3时,想看到哪些应用已经升级到新的版本,就可以看到新的应用的版本号,也会有应用信息的实例IP分布,还有一些现成资源。 + +## 三、链路追踪门面 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_8.png) + +刚才说的指标比较抽象,它更利于帮助我们发现问题,接下来进行一些简单问题的诊断。微服务系统往往是多个系统之间有关联关系,所以服务之间的诊断更依赖于全链路系统。 + +全链路系统Dubbo,当时考虑使用Agent的方式,这种方式对于用户接入是非常方便的,在代理层直接注入一些指标采集的方式即可。如果用这种方式在企业里做全链路的覆盖是非常方便的,但如果Dubbo只做Dubbo的指标采集,风险会比较大。因为Agent接入后会进行字节码修改等不兼容的问题,有些时候很难在前期发现。 + +另外,Dubbo也调研了一些开源的链路追踪门面。Dubbo选择通过原生内置门面的形式,让专业的事情交给专业人做。Dubbo通过适配各大厂商的全链路追踪系统,快速适配接入的用户,只需增加少量的配置就可以实现链路数据的导出。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_9.png) + +在链路追踪门面的选型方面,我们参考了业界比较流行的几个链路,从中挑选了两个进行选型,分别是OpenTelemetry和Micrometer。 + +OpenTelemetry,大家应该非常熟悉,它支持多语言,规范标准统一的API,支持大部分流行的第三方厂商的全链路追踪系统,是CNCF孵化的项目之一,很多中间件应用都已经接入了这种规范。 + +Micrometer,大家可能对的印象是指标采集的接入。它的缺点是只能支持Java,但它在语言方面,它是Spring Boot 3默认的指标采集,链路采集默认支持micrometer-tracing的功能。此外,Micrometer它还可以通过桥接包直接转化为open的协议,间接也支持各种第三方的采集。并且Micrometer自身也通过调节机制调节了很多的全链路厂商。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_10.png) + +我们为了和前面使用到的指标采集进行统一,使用Micrometer后无需额外引入第三方的依赖,只需使用Micrometer Tracing的桥接包,就可以快速的接入。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_11.png) + +上图是链路追踪系统的简单结构。Dubbo的边路采集主要采集rpc请求的链路。在消费者发起请求的时候,如果存在链路ID就直接复用,没有的话会产生链路ID,然后把她们上报给采集器。同样消费者也会通过rpc的上下文把链路数据透传给提供端。提供端拿到这个链路数据后,会对它进行父子关系的关联。最后把这些链路数据上报采集器。 + +采集器在前面的时候主要是内存级别的操作,对系统的损耗比较小。后面将进行异步的导出,和前面指标体系是一样的。内存级的同步采集,异步的把数据导出到第三方的链路系统。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_12.png) + +链路系统接入也比较简单,主要是引入Spring Boot Starter的依赖包,进行一些比较简单的配置,包括不同厂商的导出地址等等。 + +链路系统可以帮助大家分析性能与异常,但一些系统问题原因的排查可能需要更详细的日志上下文来进行关联。这个时候这个链路系统会把数据放到mdc日志系统的上下文里面,然后在日志上下文里把链路系统编入的内容取出来,展示到日志的文件里。 + +日志文件可能也会接触到第三方的日志平台,如果你有二次开发能力,可以在这种系统平台里加上链接,让这些Traceid自动跳转,即全链路系统自动跳转到日志平台,日志平台也可以自动跳转到全链路系统,查询问题会非常高效。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_13.png) + +上图是接入Zipkin的展示页面。可以看到它可以进行应用级的性能分析和接口级的性能分析。还可以看到一些Dubbo元数据,它的标签可以和指标大盘指标体系进行关联关系。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_14.png) + +这是Skywalking的格式,包括列表形式、表格形式等等。它通过Traceid搜到全链路的请求链路,也可以进行性能和异常的诊断。 + +## 四、日志管理分析 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_15.png) + +Dubbo通过日志里面的形式适配了各大日志组件。因为我们的日志组件在后期发展的体系是非常多的,可能是历史原因,Dubbo已经通过门面的形式适配了各大日志组件。 + +系统运行过程中,非常容易出现问题的地方包括,服务的注册与发现,注册服务发现模型,服务提供端的注册,服务消费端的订阅与通知,服务rpc请求链路。 + +当出现这些问题的时候,系统会出现异常。如果我们直接查看异常/网上检索/通过源码形式分析的话,不仅比较困难而且非常耗时。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_16.png) + +基于此,Dubbo做了一个专家建议帮助的文档手册。升级到Dubbo 3版本后,可以看到日志里有一个帮助文档的sq链接的形式。这个帮助手册套里提供了一些问题可能出现的原因和排查问题的解决思路。 + +对排查问题比较感兴趣的同学,可以直接打开官网看一下。里面包含了非常多资深专家提供的问题诊断的思路,希望社区里的用户和开发者和我们一起共同建设。 + +## 五、稳定性的实践 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_17.png) + +最后我们结合指标、链路、日志进行稳定性实践的介绍。主要分为两个部分:观测系统的异常和快速的恢复。 + +观测系统的异常,在整体全链路系统建设之后,我们有运营人员主动的盯监控大盘发现告警,也有通过邮件、短信、钉钉的形式被动的收到告警。无论通过哪种形式,收到告警之后可以尝试使用可观测的思维,通过一些常见的、和异常相关的指标进行排查。 + +通过这个方法,你可能会发现一些问题,但不一定是病因。这个时候你可以通过指标发生问题的地方找到全链路系统,之后分析哪个系统的哪一段有问题。如果排查不到问题,再通过链路系统的全链路ID关联到日志,通过日志里排查详细原因。如果日志也排查不到问题,可能就需要你在系统流量摘掉之后,通过工具进行详细的根因分析。 + +![dubbo-可观测性-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_18.png) + +快速的恢复,有了前面的原因定位后,基本上就可以知道哪里有问题了。这个时候可以根据你的原因进行流量的治理。比如切换机房流量,对流量进行限流,或者你的系统有异常的时候进行系统的回滚。 diff --git a/content/en/blog/news/apachecon2023/triple-to-connect-frontend-and-backend.md b/content/en/blog/news/apachecon2023/triple-to-connect-frontend-and-backend.md new file mode 100644 index 000000000000..48d8881148a1 --- /dev/null +++ b/content/en/blog/news/apachecon2023/triple-to-connect-frontend-and-backend.md @@ -0,0 +1,127 @@ +--- +title: "基于 Triple 实现 Web 移动端后端全面打通" +linkTitle: "基于 Triple 实现 Web 移动端后端全面打通" +tags: ["apachecon2023", "triple", "protocol"] +date: 2023-10-07 +authors: ["陈有为"] +description: 基于 Triple 实现 Web 移动端后端全面打通 +--- + +摘要:本文整理自陌陌研发工程师、Apache Dubbo PMC陈有为在 Community Over Code 2023 大会上的分享,本篇内容主要分为四个部分: + +- 一、RPC 协议开发微服务 +- 二、全新升级的 Triple 协议 +- 三、Triple 协议开发微服务 +- 四、Dubbo 为 Triple 协议带来治理能力 + +## 一、RPC 协议开发微服务 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img.png) + +在我们正常开发微服务的时候,传统RPC服务可能在最底层。上层可能是浏览器、移动端、外界的服务器、自己的测试、curl等等。我们可能会通过Tomcat这种外部服务器去组装我们的RPC层,也就是BFF。或者我们没有BFF,我们的RPC就是对外提供服务。但因为浏览器要访问,所以我们需要有一个网关,比如说Apisix或者ShenYu等HTTP网关。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_1.png) + +上图展示的是我们的流程,但是存在一些问题。 + +如果我们的服务是非常轻的,我们只需要一个转发层,我们是不是很麻烦。无论是配网关还是起一个webserver去转发,肯定都很麻烦。 + +此外,RPC服务大部分都是基于二进制的,而二进制正常在本地是没法测试的。因此我们的公司内都可能就会开发一种后台或者中间的Process让我们去测试。但这个的前提是你至少得把它部署到测试环境,所以还是没法在本地测试。 + +总体来说,这两个问题的易用性比较低,且开发成本相对较高,因为要做一些重复劳动。 + +## 二、全新升级的 Triple 协议 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_2.png) + +基于上边的两个问题,我们来介绍一下Triple协议。 + +先来说一下上一代协议,它产出的原因是什么。我们应该都知道Dubbo原来是Dubbo协议,它是基于tcp的,它有一个包。因为它的包的设计,导致了网关无法做一些特殊规则判断、过滤等操作。但也不是绝对的,如果你愿意牺牲性能把包完全解出来,组装回去再透传还是可以做到的,但一般大家都不太能接受。 + +所以我们就在想能不能把原数据和真正的包分开。现在我们有现成的HTTP,又有一个业界主流的gRPC,所以我们的目标就是兼容gRPC。因为gRPC目前都是用IDL,而IDL有一个问题,尤其在Java侧。因为大家都是写一些接口,定义一些包去实现,这样就会非常麻烦。Go侧就还好,因为大家已经习惯了这种开发模式。 + +所以我们开发了Triple协议,首先它兼容了gRPC,所以我们能实现和gRPC的完全互通。其次,我们兼容了自己定义接口的方法。虽然会损失一定的性能,但提升了一些易用性。而且RPC一般不是业务的瓶颈,大多数瓶颈还是在DB。 + +但还有个问题,虽然我们兼容了gRPC,但gRPC是基于TPC的,所以如果前端或者其他第三方系统只有HTTP,它还是接受不了我们的系统。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_3.png) + +基于此,我们想推出一个全新的Triple协议。为了解决上述的所有问题,我们参考了gRPC、gRPC Web、通用HTTP等多种协议,做到浏览器访问,支持Streaming,还支持同时运行在 HTTP/1、HTTP/2 协议上。因为目前HTTP/3还没有大规模推广,未来也会支持HTTP/3。 + +最终的设计实现是完全基于HTTP的,且对人类、开发调试友好。我们可以通过简单的浏览器访问或者curl访问,尤其是对unary RPC。此外,我们和gRPC是完全互通的,用HTTP的业务不用担心兼容性的问题,也不用担心签协议的问题。为了稳定性,我们只会采用业界流行的网络库,比如Java的netty、Go的基础的net包。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_4.png) + +虽然Triple协议和gRPC协议都基于HTTP,但gRPC是基于HTTP/2的,而Triple是基于HTTP/1和HTTP/2的。 + +我们在进入gRPC的同时,我们为了易用性扩展了一些功能。比如请求里我们支持application Json,curl访问,此外上一版的协议,为了支持传统定义接口的方式,我们有一个二次序列化的过程。我们想在这里通过一个特殊的tag来决定我们的body的结构,解决二次序列化的问题。同时这个东西是可以扩展的,理论上HTTP的所有future我们在Triple协议上都可以实现,也可以拓展。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_5.png) + +用了Triple协议之后,我们的开发流程也发生了改变。如果你不需要进行组装,或者没有外层的代理,可能你的接入流程就是从外部的请求浏览器、对方的服务器、curl、自己测试等直接到了server。 + +和其他的gRPC的通信也是没有问题的,流程就相当于少了一层。对于大多数用户,如果你不需要这个场景,其实是有很大的好处。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_6.png) + +Triple协议因为最开始兼容gRPC,那个时候只基于HTTP/2,HTTP/2有Streaming的能力,所以它天然支持Streaming。但这里比较特殊的是,我们新版的协议在HTTP/1也支持了Stream,但仅支持了Server Stream。也就是客户端发一个,服务端发好几个回去,这个HTTP/1的Server Push实现的。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_7.png) + +Client Stream和Bi Stream就没什么可说的了。但有一个特别的是,在Java侧没有Bi Stream,从编码上就没有,但从实现上是有的。 + +## 三、Triple 协议开发微服务 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_8.png) + +目前Triple协议比较灵活的支持两种定义方式,分别是IDL定义和直接定义。直接定义支持同步、异步、手写。还有比较极端一点的,比如在自己定义接口的时候用IDL生成probuff的类,我们不定义它的service,只用它的接口也是没问题的,它会自动识别接口使用pb还是不使用pb。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_9.png) + +Server就是把它的务实现一下。上图是一个例子,我就直接拿了API的组装方式,真正的业务上可能是注解或者XML的方式。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_10.png) + +因为我们支持了HTTP这个标准的协议,理论上我们的测试就会变得很简单。 + +因为我们支持gRPC,所以我们可以用gRPC curl去调用我们的服务。但前提是你得有反射服务,然后手动开启一下,它不是默认开启的。然后它就可以通过反射拿到接口的源数据,通过Json转成pb格式发过去。或者我们直接用Application Json的方式直接调过去。这里有一点比较特别的是在HTTP/1下我们也可以用Sream。 + +另外,因为我们支持HTTP,理论上所有第三方的HTTP客户端都是可以调用的。然后我们的admin也可以进行测试,前提是你得把它注册上。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_11.png) + +调用端不管是POJO还是IDL,它们都没有本质的区别。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_12.png) + +现在我们有了Triple协议,但如果这个协议没有承载方也是行不通的。因此我们还得有一个框架,有一些服务治理才是我们的微服务。所以服务治理也是微服务中不可或缺的一部分。 + +## 四、Dubbo 为 Triple 协议带来治理能力 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_13.png) + +Triple的定位只是Dubbo里的其中一个协议,当然你也可以为了兼容性,用原来的Dubbo协议或者其他的协议。而且我们支持在同一个端口上开多个协议,可以按需选择。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_14.png) + +同时Dubbo 为 Triple 提供了多语言的实现。目前会在Rust、Go、Java、JS、node、Python这几部分实现官方的实现。这样用户就不用自己根据实验协议的spec去实现了。如果你有一些定制需求,比如内部的一些框架,你根据spec实现也是可以的。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_15.png) + +Dubbo和服务框架集成的很好,理论上在开发流程中,尤其是在Java侧服务定义、服务治理、服务注册发现等都不用客户来操心,是开箱即用的。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_16.png) + +Dubbo 提供了丰富的生态,第三方的生态包括Nacos、Zookeeper等等,我们不用创新,直接引入相应的包即可。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_17.png) + +这是我们使用Triple协议服务注册的例子。上面你可以选Nacos、Zookeeper、K8s,左边是一个Client和一个Server,这么调用。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_18.png) + +我们在admin上看一下实现。这里提一句,我们的admin也在新版重构,是用Go实现的,大家可以期待一下。 + +![dubbo-triple-协议](/imgs/blog/2023/8/apachecon-scripts/triple/img_19.png) + +我们经常会遇到灰度发布或者流量染色的需求。我们可以从admin上发一个tag下去,把一些实例打上tag,然后这个流量从入口就会挨个下去。 diff --git a/content/en/blog/news/apachecon2023/usecase-zhengcaiyun.md b/content/en/blog/news/apachecon2023/usecase-zhengcaiyun.md new file mode 100644 index 000000000000..06df7105c5d1 --- /dev/null +++ b/content/en/blog/news/apachecon2023/usecase-zhengcaiyun.md @@ -0,0 +1,202 @@ +--- +title: "政采云基于Dubbo的混合云数据跨网实践" +linkTitle: "政采云基于Dubbo的混合云数据跨网实践" +tags: ["apachecon2023", "用户案例", "政采云"] +date: 2023-10-07 +authors: ["王晓彬"] +description: 政采云基于Dubbo的混合云数据跨网实践 +--- + +摘要:本文整理自政采云资深开发工程师王晓彬的分享。本篇内容主要分为四个部分: + +* 一、项目背景 +* 二、为什么叫高速公路 +* 三、修路实践 +* 四、未来规划 + +## 一、项目背景 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img.png) + +我们有一个云岛业务叫政采云,它是政府的购物网站,类似于淘宝。政府采购会在政采云上做企业采购、政府采购的业务。 + +云岛中的"云"是指我们的云平台,云平台是我们公司自己部署的一套购物网站,它对应的是一套微服务框架。而"岛"是指,比如安徽或者山西它们都有自己的局域网,如果我们在它们那里也部署一套这个框架,就叫"岛"。我们的云主要是给浙江省和相关的区划用的。 + +我们的云和岛之间存在数据传输的问题,举个例子,比如我现在收到一个政府的公告,而这个公告肯定是全国性的。所以我可能会在云平台的管理平台上去录公告,再把它推送出去,这个时候云和岛之间就存在了一些数据的跨网。 + +1. 云岛网络 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_1.png) + +对我们云平台来说,这个局域网是我们公司内部完全可控的。比如你要开个端口,很快就能开起来。导端它可能是局域网或者是私有网络,比如我们之前做了一个浙商银行的项目,它是完全隔离的一个岛。他们的安全策略和开端口的东西都是他们自己定义的,这就是我们云岛的业务结构。 + +2. 混合云岛网络 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_2.png) + +上图是大概的数据链路图。云平台下面有分支机构、分公司,它们会对应一套业务的系统。政务云是我刚才说的省级(安徽省)或者市级(无锡市)对应的区块,隔离的政务云。私有部署是银行、国企、军队、政企等典型的混合云的网络架构。 + +3. 混合云岛网络的特点 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_3.png) + +我们混合云网络架构的特点包括: + +- 平台的一致性。我们部署在公有云、云平台、政务云、私有云上的那一套的代码是一样的。我们把一套代码部署在不同的地方就变成了多个平台。 +- 网络连接与能力复用。我们会依赖一些第三方的能力,比如短信,但私有云上它的网络管控比较严,所以和第三方互通端口或者网络的流程就会比较复杂。这个时候我们希望去复用我们云平台的能力,这个时候他们之间又有一些数据的交互。 +- 跨域访问迁移。 +- 统一的平台管理。像我刚才举的例子,如果要发公告,我们希望可以在一个平台上就可以管理起来。而不是浙江发一条,安徽发一条,那样维护的成本也会比较高。 + +4. 政企网络痛点 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_4.png) + +很多公司都会和政府打交道,政企网络有以下几个特点: + +网络复杂。比如银行的网络,它们的安全性和内部的东西很复杂,流程的开通也比较多,需要你要经常去跑,跑完了之后发现有新的问题,又要去跑。 + +安全要求高。比如在开通端口的时候,我们需要去传数据,如果里面的那些序列化的协议不符合它们的规范,它们就会拿掉。这个时候给我们的业务其实是超时的,或者是那种通用的异常。而我们并不知道发生了什么,这就会带来未知的风险。 + +业务驱动运维。我们有了业务才会去部署,才会去做事情。我们就会多次、重复的投入,这就会导致人力、时间成本会比较高,私有部署的时候会更多。 + +5. 现有方案 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_5.png) + +基于以上的痛点,我们做了两个方案。 + +第一个方案,基于Dubbo Filter的单向方案。这个方案的历史比较久一些,它有两个特点。 + +第一个特点,单向传输。它是从"岛"到"云"只有一个方向,它基于Dubbo Filter的原因是,我们公司内部的微服务都是通过Dubbo来调用的,所以我们是强依赖的来Dubbo的。所以做数据跨网的方案肯定会基于Dubbo的特性来做。 + +第二个特点,在本地部署业务的provider过滤器是运维上的负担。当导端需要把数据同步给云端的时候,也就是从岛端的业务Web传输到云端的业务provider。这个时候我必须在导端也部署一套业务的provider才可以。部署它的原因是它要拦截这个请求,然后把这个请求转发给部署在云平台的Dubbo网关。 + +但这个时候就会给我们带来负担。如果导端本来就有数据的入库就还好,因为provider本来就存在,但一些业务只是做跨网用的,没有本地的入库,那么这个时候业务的provider就是多余的了。 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_6.png) + +第二个方案,网状点对点方案。因为岛和岛之间需要网络互通,所以就会单独开通这个点和你需要传输的点之间的端口。开通之后我们就可以调用了,调用的形式可以用Dubbo。 + +这个方案有一个很明显的缺陷,线特别多,所以点和点之间开通的复杂度也很高,对后面的扩展可能也非常不利。 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_7.png) + +以上方案存在的问题包括单向传输、白名单开通成本高、平台维护成本高、公共功能的缺失。 + +基于以上的问题,我们做了一个新的方案,叫高速公路。 + +## 二、为什么叫高速公路 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_8.png) + +为什么叫告诉公路呢?主要因为我们想要达到的效果是: + +只建一次,可复用。比如北京到上海的高速公路,它只要够宽,一条就够了。如果你是从上海到北京或者从杭州到北京,是可以复用的,不用单独再修建一条。 + +隧道机制。因为高速公路修建的地方不一定都在平原,可能会在河、海、山等等附近。如果我们在高速公路下面搭建一条隧道,这个时候对于司机来说就是无感的。我们的目的是一样的,如果你觉得政企网络很复杂,那么我们就帮你把它屏蔽掉,这样你也是无感的了。 + +考虑传输性能。如果每个业务部门都自己搭建一套传输链路,那么传输性能只要能承载自己的业务就够了,因为不一定要给别人用,或者给别人用了也是小范围的。但如果搭建的是一条可复用的链路,就必须考虑传输的性能了。 + +## 三、修路实践 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_9.png) + +接下来介绍一下我们在修建高速公路的时候遇到的一些问题以及具体的做法。我们在客户端接入上遇到了以下问题: + +第一个问题,强依赖Dubbo。 + +第二个问题,透明传输,不改变使用Dubbo的方式。也就是我不需要自己写一些注解代替Dubbo,或者写一些API调用Dubbo。因为写了之后,一些新人可能并不能理解或者不能习惯,也不知道里面有什么坑。所以我们用原始的Dubbo来做可能会对用户更加无感。 + +第三个问题,接入灵活,支持多种形态。虽然我们强依赖Dubbo必须支持Dubbo,但我们也需要支持其他的形式,比如HTTP。但在接入之前,我们需要考虑接入灵活性的问题。 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_10.png) + +下面我们先介绍一下Dubbo的方式。Dubbo的客观接入主要有以下三种方式: + +第一种,注解方式。使用@DubboReference提供的通用parameters参数,设置路由目标,可以达到方法粒度的路由。路由信息写在中间parameters那里,parameters是Dubbo给我们提供的通用参数的传递。 + +如果是正常的,我写了这个信息,Dubbo是不做任何处理的,因为这个东西对它来说没有含义。但因为你引入了高速公路的SDK,所以在你写了这个东西之后,我们就会去解析,拦截Dubbo的请求,把parameters里的参数抓起来做一些路由处理,这种形式其实没有改变Dubbo的使用方式。 + +第二种,配置中心指定。比如我们用的是阿波罗的配置中心,它完全可以把接入方式替换掉,parameters的信息在配置中心配置也可以,只要SDK可以支持就好。这种方式其实代码是完全侵入的,就是跟跨网之前和跨网之后没有任何区别。但最后发现我们的业务并不喜欢这种方式,首先因为阿波罗大家不喜欢用,其次不好理解。如果是一个新人看这个代码,他就会认为是在调本地的接口。 + +第三种,线程指定。当你在线程里指定了路由信息,下面再去调用的时候,这次调用就会走你的路由。如果再调用一次,它就会调回本地。因为基于线程的形式,在Dubbo的扩展里,它会在调用完成之后把线程信息清理掉。所以需要注意一下,如果你想多次调用,就需要写多次。如果不想写多次,你可以用上面这种方式,你只要在当前的been里,都是路由到上海。 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_11.png) + +接下来介绍一下高速公路的架构,刚才介绍点对点的方式,它的缺点是开通白名单比较复杂。现在我们的高速公路架构是一个新型的架构,所以它开通白名单的复杂度会低一点。 + +如上图所示,比如最左边的节点是上海,最上边的节点是安徽,我想从安徽到上海,这个时候中心网关就需要开通一个白名单。开完之后,这条链路就可以直接过去了。可以看到一共就六条线,所以它的复杂度也就下来了。 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_12.png) + +18:30上图是高速公路里最核心的架构图。 + +比如山西集群的APP1调APP2的时候,我想去调上海APP2,如果你什么都不做,它默认调的就是山西集群的APP2。如果你在APP调用的时候加了一些路由信息,放在山西集群APP1里的SDK就会把它的流量切走,切到山西集群的Dubbo网关。 + +之后Dubbo网关会通过HTTP的协议走统一网关,再通过HTTP的协议到上海集群的Dubbo网关。在这里会把路由信息拿到,包括调用的Service、方法、版本号、参数等等。然后通过泛化的形式调上海集群的APP1,最后返回,完成这次跨网的调用。 + +那么为什么要有Dubbo Proxy这个角色呢?为什么不直接从APP1切到统一网关?少一个步骤不好么?涉及到的原因有以下三点: + +虽然这个图上只画了一个APP1,但实际上山西集群里的调用非常多。如果几百个应用都直接到统一网关,网关就需要建立很多的长链接,而统一网关的资源是有限的。 + +因为安全性的问题,可能每次调用都要走一下白名单来保证安全。这个时候如果加了一个Dubbo Proxy,就可以去收敛IP。岛内不用和Dubbo Proxy交互,因为它们是同一个环境,不用考虑安全的问题。当Dubbo Proxy请求到网关之后,因为网关和统一网关之间只有一条链接,所以IP是收敛的。 + +还有一个是功能的收敛,当后面要做升级的时候,如果更新SDK,就需要每个应用都升级,这就需要推动业务做升级,做起来会比较痛苦。所以我们希望把升级功能全放在一个应用里,对业务功能无感,连升级SDK都不需要。当然因为SDK就做了一件事情,就是切换路由,基本不需要更新。 + +所以对于业务来说,它也解放了。我把它理解成是一个功能上的收益。这个模式叫分布式运行时,在现在也比较流行。我们可以把它理解成Dapper,把一些比较麻烦的操作放到公共的服务里,留给业务的SDK是很纯粹的。 + +另外,为什么要用HTTP协议呢?它也并不是很高效的协议。而Dubbo协议中的Dubbo2其实也是比较惊艳的,除了一些模糊全部都是数据。这样的话其实我们后面是可以考虑把HTTP升级掉,让它的性能更快一点。 + +现在用HTTP协议的原因是,它是一个标准的协议,中间可能会通过很多设备,虽然我们这里只画了一个。HTTP协议是没有任何障碍的,如果用Dubbo协议,还需要一个个打通。 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_13.png) + +为了实现这个架构,Dubbo本身并不能直接用。因为Dubbo没有提供跨网的特性,所以我们需要从Dubbo层面解决我们碰到的问题。 + +在动态IP切换方面,其实Dubbo是支持的,但因为这个特性比较新,所以也会出现一些问题。它的支持程度是部分支持,比如在最开始的时候Dubbo2不支持,Dubbo3支持。此外,还会有一些bug。 + +在404扩展方面,对于HTTP来说,你要调一个接口,但这个接口不存在,就会返回给前端一个404的报错。比如当我们把流量从APP1切到Dubbo Proxy的时候,Dubbo Proxy其实是Dubbo的一个应用,它引入了一个Dubbo的jar包,它是Dubbo的一个空应用。这个流量到Dubbo的网关后,它不能识别,它的功能是要把它转发出去。这个时候我们就需要加入这个扩展。 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_14.png) + +下面介绍一下隧道的机制。隧道机制的作用是屏蔽网络的复杂性,屏蔽中间的协议转换,给用户一个统一、透明的调用方式。 + +中间的HTTP协议里面的body带了一个原始的bodv。倒装之后再把它拆包拆出来,再通过泛化去调。这个时候隧道是可以匹配掉这些差异的。 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_15.png) + +另外,隧道机制对Dubbo协议的支持力度更高。比如APP1和本地的APP 3,最终调到APP2的时候,它看到了二进制流是一样的。因为我并没有去做什么,我只是把它分装起来,最后拆包。中间除了一点路由信息之外其他都一模一样。 + +这个机制的好处是,基本上Dubbo的所有特性都能支持。但也有一些个例,比如token和网络相关的机制。 + +## 四、未来规划 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_16.png) + +借用网络分层的架构对高速公路做了一些规划: + +第一层,物理网络层打通。它其实跟我们关系不大,因为我理解的是开通端口,你开通了那么多事,可以总结一些经验或者方法论去加快这个事情。 + +第二层,通讯协议层加速。中间的HTTP协议转发,我们是可以加速的。比如Tripple协议也是基于HTTP2对网络设备进行了识别,然后把问题解决了。所以我们也可以考虑去调研,在通讯协议层去做优化。 + +第三层,语言层编译加速。GraalVM之前我们也调研过,而且也真正的去试过。虽然没有落地,但编译加速是可以的。特别是网关层,它的特点是流量大,但是每个流量又特别小,对语言本身的性能要求比较高。如果把它用Go来实现,其实也是一个比较好的加速。 + +第四层,框架层功能升级。中间件层我们也做了很多事情。 + +第五层,通用任务调度与编排。调用其实会经过很多节点,比如a到b到c到d到e,随着业务越来越复杂,我们可能会有更多的路由。比如a到c,c和d汇合起来再到d,未来也将会规划进去。 + +第六层: 定制任务调度与编排。 + +第七层: 监控 & 告警 & 可观测性。 + +第八层: 规范 & 流程& 安全。 + +![dubbo企业实践-政采云](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_17.png) + +最后做一个总结。 + +为什么要做这个项目?之前的方案比较多,成本也比较高。所以我们需要有一个统一的方案考虑更多公共的测试把这个东西给推广起来。目前我们已经接入了非常多的应用,它已经成为了政法人员数据跨网的统一的标准方案。 + +我们要达到的效果,项目架构,未来规划刚才都介绍过了,就不再重复了。 + +重点说一下我们的开源与社区的合作。刚才的方案其实是我们公司内部使用的,也对Dubbo做了深度的定制。一般我们会选择私有版本进行开发,但因为想要开源,所以在最开始的时候,我们就和Dubbo社区沟通,看能不能在开源层实施掉。一方面社区可以帮我们review这些特性,做一些安全上的把控。另一方面我们也能把自己做的一些事情,特别是把公共的东西抽出来反馈给社区。 diff --git a/content/en/blog/news/build-new-docker-image-in-dockerhub.md b/content/en/blog/news/build-new-docker-image-in-dockerhub.md new file mode 100644 index 000000000000..ed70a70a65b2 --- /dev/null +++ b/content/en/blog/news/build-new-docker-image-in-dockerhub.md @@ -0,0 +1,59 @@ +--- +title: "在DockerHub发布Dubbo Admin镜像" +linkTitle: "在DockerHub发布Dubbo Admin镜像" +date: 2018-04-23 +tags: ["新闻动态"] +description: > + 本文将介绍如何在Dockerhub上发布Dubbo Admin镜像。 +--- + +Dubbo Admin是Dubbo的服务治理中心,提供了大量日常运维所需的服务治理、配置管理等功能。 + +Dubbo Admin同时包含了前端代码和后端代码,如果用户需要自己下载源码并编译打包,需要花费一定时间。 +特别是对于一些希望快速调研和试用Dubbo Admin的用户,这种流程的体验并不是很好。 + +Docker是一个开源的应用容器引擎,让开发者可以打包应用以及依赖包到一个可移植的镜像中,社区对于提供Dubbo Admin镜像的呼声较高。 +Docker官方维护了一个公共仓库DockerHub,该仓库还有很多国内镜像,访问速度快,将Dubbo Admin镜像发布到DockerHub是一个较好的选择。 + + +## DockerHub账号申请 +要在DockerHub上发布镜像,自然需要对应的账号。 +而DockerHub有两种常见账号,一种是面向个人的,一种是面向组织的。Apache在DockerHub上有一个组织账号[^apache-repo]。 +自然我们首选是发布在组织账号下。 + +DockerHub对于组织账号的管理是基于组的,也就是一个组织账号下有多个组,每个组有不同的成员,而一个组可以管理一个或者多个镜像。 + +所以要做的第一步就是申请权限,这个需要提一个issue给Apache Infrastructure团队,申请DockerHub的镜像仓库和组权限。 +目前镜像和组已经申请好了,只需要申请组的权限就行了,可以参考之前的申请[^request-ticket]。 + +申请完权限以后使用Apache账号登陆应该就可以看到对应的镜像和配置选项了。 + +## 添加新的构建规则 +发布镜像到DockerHub有两种办法,一种是本地构建好镜像以后远程push到DockerHub,另外一种是提供Dockerfile并借助DockerHub提供的构建功能直接在DockerHub构建。 +后者明显操作性和便捷性要好很多,目前Dubbo Admin的镜像也是这样构建发布的。 + +当Dubbo Admin有新版本发布以后,需要在项目的docker目录新增一个Dockerfile文件,可以参考目前0.1.0版本的Dockerfile[^docker-file],其中的配置根据具体的版本可能有细微差别,但是大致上是一致的。 + +在添加了Dockerfile之后,进入DockerHub对应的管理界面新增Build Rules + +![dockerhub-build-rules.png](/imgs/blog/dockerhub-build-rules.png) + + +根据实际情况填写即可。这里需要注意两点: ++ latest 版本要和最新的版本配置一致 ++ 不要勾选Autobuild + +勾选Autobuild会导致每次git提交都会触发自动构建,但是由于Dubbo Admin不提供snapshot的Docker镜像,所以只有发布新版本的时候才需要构建发布。 + +修改以后点Save,然后手动触发构建即可。 + +## 总结 +总的来说DockerHub上发布镜像的步骤并不复杂,如果已经申请过权限的话,操作起来是很流畅的。 + +另外DockerHub的构建是需要排队的,有时候会遇到长时间没有开始构建的情况,需要耐心等待。 + + + +[^apache-repo]: https://hub.docker.com/r/apache +[^request-ticket]: https://issues.apache.org/jira/browse/INFRA-18167 +[^docker-file]: https://github.com/apache/dubbo-admin/blob/develop/docker/0.1.0/Dockerfile diff --git a/content/en/blog/news/dubbo-10years.md b/content/en/blog/news/dubbo-10years.md new file mode 100644 index 000000000000..2b46aae53eb3 --- /dev/null +++ b/content/en/blog/news/dubbo-10years.md @@ -0,0 +1,193 @@ +--- +title: "都已经十岁的 Apache Dubbo,还能再乘风破浪吗?" +linkTitle: "都已经十岁的 Apache Dubbo,还能再乘风破浪吗?" +date: 2021-01-14 +tags: ["新闻动态"] +description: > + 在云原生时代,Apache Dubbo 将如何延续当前光芒? +--- + +![img](/imgs/blog/dubbo-go/10years/dubbo-home.png) + +纵观中国开源历史,你真的没法找到第二个像 Dubbo 一样自带争议和讨论热度的开源项目。 + +一方面,2011 年,它的开源填补了当时生产环境使用的 RPC 框架的空白,一发布就被广泛采用;另一方面,它经历了停止维护、重启维护后捐献给 Apache 基金会、接着又以顶级项目的身份毕业。 + +面对多疑的开发者,在云原生时代,Apache Dubbo 将如何延续当前光芒? + +今年是 Dubbo 从 Apache 基金会毕业的一周年,同时也是推进 Dubbo 3.0,即全面拥抱云原生的重要一年。开源中国与 Apaceh Dubbo 共同策划**【Dubbo 云原生之路】**系列文章,和大家一起回顾 Apache Dubbo 社区的发展。系列文章主要涵盖 Dubbo 技术解读、社区、应用案例解析三大部分,之后每周都会和大家见面。 + +**在【阿里巴巴云原生公众号】留言说出与 Apache Dubbo 的故事**,点赞排名前十的同学可领取 Dubbo 送出的专属奖品杯子一只;另外由Apache Dubbo PMC @Chickenlj 随机抽取一名幸运读者,赠送价值 260 元护眼灯一台。下周三开奖。 + +**作者简介** + +**刘军**,花名陆龟,GitHub 账号 Chickenlj,Apache Dubbo PMC,项目核心开发,见证了 Dubbo 重启开源,到从 Apache 基金会毕业的整个过程。现任职阿里云云原生应用平台团队,参与服务框架、微服务相关工作,目前主要在推动 Dubbo 3.0 - Dubbo 云原生。 + +# 系列开篇:3.0 全面铺开、ASF 毕业一周年 + +从 2019 年到现在,在 Dubbo 毕业的这一年时间里,Dubbo 社区和产品都取得长足进步,同时 Dubbo 云原生版本 - Dubbo 3.0 的开发工作也已经全面铺开。 + +社区方面。需要重点提及的有两点:一个是落地与贡献的企业用户进一步增加,主动与社区取得联系的中、大规模公司达 200 多家,如携程、工商银行、瓜子二手车、网联清算、中通等;另一个是[**以 Dubbo-go 为代表的子社区**](http://mp.weixin.qq.com/s?__biz=MjM5NzM0MjcyMQ==&mid=2650091639&idx=1&sn=9733d57fd9babe53826bc93c2a466adf&chksm=bedaeb1989ad620f99abfee5902d69dc6c7544d1d70803d854f20ea7a1a44c1d0c4ba82f8d3a&scene=21#wechat_redirect)蓬勃发展。 + +产品技术演进方面。Dubbo Java 版发布 10 个版本,在多语言、协议、性能、服务治理模型等方面都有深度探索。Dubbo go 发布超过 8 个版本,在功能基本对齐 Java 版本的基础上,一些方向上也已经走在了 Java 版本前面。 + +值得一提的是,阿里巴巴内部也正在积极推动 Dubbo 社区版本在内部的落地,从今年开始逐步实现**以 Dubbo 升级其内部的 HSF 框架**。这一方面有利于阿里将其在 HSF 上的丰富服务治理经验回馈输出到社区,另一方面阿里官方的落地也将直接加速 Dubbo 云原生的发展。 + +在云原生大潮下,**3.0 已被正式列为今年 Dubbo 产品建设的核心目标**,涉及下一代 RPC 协议、服务治理模型、云原生基础设施适配等多方面的内容。其中,很多方面已经在当前的 2.7 版本中做了前置性探索,如近期发布的基于 HTTP/2 的协议支持、应用级服务发现等,后续工作将以此为基础展开。系列文章也会有对 Dubbo 3.0 Roadmap 及技术方案的详细解析。 + +## Dubbo 毕业一周年回顾 + +2017 年 7 月,Dubbo 开源项目被重新激活,2018 年捐献到 Apache 基金会,2019 年 5 月,Dubbo 正式从 Apache 基金会孵化毕业,成为 Apache 顶级项目。接下来,文章分别从社区、子社区、产品三方面介绍 Dubbo 过去一年的成绩。 + +### 社区一年发布 24 个版本,贡献者已超 300 + +如果说最开始重新激活是以阿里巴巴为主导的项目维护投入,那自 Dubbo 加入 Apache 起,它就已经开始成为一个社区主导、社区贡献为主的完全开放的基金会项目。 + +到今天,这一趋势正变得更明显。包括阿里巴巴、携程、工商银行、瓜子二手车、网联清算、中通等在内的互联网、传统企业公司,在 Dubbo 的使用与社区代码贡献上都有投入。Dubbo 社区正变得非常活跃和多样化。 + +过去一年,Dubbo 社区项目总共发布 24 个版本,发展 Committer/PMC 27 人,其中有 20% 的贡献者是来自于阿里巴巴,80% 以上来自不同组织的开发者或爱好者。 + +Dubbo 社区组织了超过 10 场线下 meetup 活动,基本覆盖了国内开发者聚集的城市。通过线下或线上直播活动,分享超过 100 个 topic 的演讲,深度讲解 Dubbo 社区最新动态、功能模块开发和近期规划等。主题演讲大多是社区采集方式,由 Dubbo 的深度企业分享实践经验,其中典型的代表包括携程、工商银行、考拉、信用算力等。 + +从 GitHub 统计数据来看,Dubbo Star 数取得新的里程碑,已超过 3 万,相比重启开源时增长了近 5 倍;贡献者由最初的几十个增长到现在的 300 多个,而这其中有 60 多人已经被提名为 committer,不论是贡献者数量还是 committer 比例都得到很大的提升;Dubbo Java 发布的有 65 个。 + +上述主要是对 Dubbo Java 项目社区发展的总结,下面将介绍 Dubbo Java 产品方面的进展。 + +### Dubbo Java 迭代,目前主要维护 3 个大版本 + +当前社区维护的 Dubbo Java 大版本主要有 3 个,分别是 2.5.x、2.6.x 和 2.7.x。 + +- 2.7.x 是社区的主要开发版本,在过去的一年共发布了 8 个版本(2.7.0 - 2.7.7),每个版本都有一些值得关注的特性或功能升级,涵盖从编程模型、服务治理、性能到协议的多个方面的增强; +- 2.6.x 版本则定位为 bugfix 版本,过去一年共发布了 3 个版本,主要以修复问题和安全漏洞为主,并没有增加太多新的 feature; +- 2.5.x 版本从 2019 年初开始已宣布 EOF,只做安全修复;而到了下半年已经完全停止了维护。 + +下面通过一个简要分层模块图,回顾过去一段时间 Dubbo 的技术架构演进,从编程模型、服务治理、传输协议、性能优化等角度切入: + +![img](/imgs/blog/dubbo-go/10years/dubbo-layer.png) + + +以上很多功能都已被各大厂商落地,用于解决具体的业务问题。我们也期待,接下来这些厂商带来更多关于 Dubbo 实践经验的深度总结。 + +### Dubbo-go 发展的第五年,正与 Dubbo 齐头并进 + +除 Dubbo Java 之外,Dubbo 周边也发展出了很多优秀的子项目(子社区),其中包括 Dubbo-spring-boot-project、Dubbo-go 等,这里先着重介绍 Dubbo-go 子社区。 + +Dubbo-go 项目最早由于雨在 2016 年 5 月构建,同年 9 月发布并开源,如下时间轴图清晰记录了 Dubbo-go 的前世今生。 + +![img](/imgs/blog/dubbo-go/10years/dubbo-go-events.png) + +秉承 "bridge the gap between Java and Go" 天然使命的 Dubbo-go,已经进入第五个年头,也走出了自己独特的发展路径: + +- 当前的 v1.4.0 版本已对齐 2.6.x 版本,即将发布的版本将与 v2.7.x【对标 v2.7.5】对齐,而后将会发布对标 Dubbo 3.x 的 v1.6.0版本; +- 独立维护从底层的 hessian2 协议库 Dubbo-go-hessian2、网络库 getty 到上层对标 Dubbo 的 Dubbo-go 的全套实现; +- 独立的 TCP + Protobuf 和 gRPC + JSON 通信方案也已开发完成【将包含着在版本 v1.5.0 中】; +- 已与 Dubbo/gRPC/[Spring Boot](https://mp.weixin.qq.com/s?__biz=MzA4ODg0NDkzOA==&mid=2247487916&idx=1&sn=894316507590793285d0e15734db0bde&scene=21#wechat_redirect) 实现互联互通; +- 通过接入 [Opentracing](https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247488596&idx=2&sn=4d554d32fdd167b6b74fc792c78fb341&scene=21#wechat_redirect) 和 Promethus,Dubbo-go 在可观测性等微服务方向的进行了自己独特的探索; +- 已实现了基于 HTTPS 的[可信 RPC 调用](https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247489539&idx=3&sn=379514cac71b91d57643e6f3d2701cdf&scene=21#wechat_redirect); +- 已经实现了自己独特的[把 Kubernetes 作为注册中心的微服务方案](https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247489465&idx=3&sn=514144ef1a217a50b9f5a640ca122ac8&scene=21#wechat_redirect); + +Dubbo-go 从最开始 Dubbo 的 Go 语言实现,已发展成为目前 Dubbo 多语言版本中功能最强大者,它的发展离不开背后强大的 Dubbo-go 社区。除了上述 Dubbo-go 的自身特性外,通过跨社区合作,取得了如下成绩: + +- 通过与 MOSN 社区合作,已经实现 Dubbo/Dubbo-go 应用可以零成本接入基于 MOSN 实现 Dubbo Mesh,实现微服务和云原生共存的 **“双模微服务”**; +- 与 sentinel 社区合作,在 Dubbo/Dubbo-go 完整接入 sentinel 的降级和限流方案; +- 与 Apollo 社区合作,在 Dubbo-go 中实现远程配置下发; +- 与 Nacos 社区合作,实现基于 Nacos 的服务发现; + +Dubbo-go 社区 2020 年 Q2 主要目标有: + +- 发布完全对齐 Dubbo 2.7.x 的 v1.5.0 版本; +- 发布对标 Dubbo 3.0 的 v1.6.0版本; +- 在云原生方面继续自己的探索; +- 继续与兄弟社区保持合作共进态势,扩大自身使用范围; +- 生产实践上推进在阿里集团,以及更多厂家的落地。 + +项目(包括子项目)目前已先后在携程、涂鸦智能和蚂蚁金服等公司生产落地。 + +今年阿里集团完成 HSF 和 Dubbo 的融合后,项目也将在阿里集团双十一战场经受考验。 + +## 云原生 Dubbo - Dubbo 3.0 + +3.0 是下一代 Dubbo 架构的代号。一年前,最开始探索 Reactive Stream 之时,社区也曾有过对 Dubbo 3.0的广泛讨论。而这一次,在云原生大背景下,3.0 代表了更全面的 Dubbo 架构升级,涉及到下一代 RPC 协议、全新的服务治理模型和云原生基础设施适配等。 + +阿里巴巴是参与 Dubbo 3.0 开发建设的主要力量之一,这款始于阿里的开源项目正重新回归阿里内部落地。 + +去年开始,阿里巴巴就已经在逐步推动以 Dubbo 替换其内部的 HSF 框架的工作,通过将 Dubbo 与 HSF 两个框架融为一体,并在此基础上发展出适应云原生架构的 Dubbo 版本。Dubbo 重回阿里巴巴的落地是拥抱社区、拥抱云原生、拥抱标准化的一次很好的实践。 + +阿里巴巴内部 Dubbo 3.0 的落地,对社区也是一个重大利好,这一方面有利于阿里巴巴将其在 HSF 上的丰富服务治理经验回馈输出到社区,另一方面也将直接推动 Dubbo 云原生架构的快速演进。除了阿里巴巴之外,包括斗鱼、工商银行、爱奇艺等厂商也都在参与下一代 Dubbo 3.0 的建设。 + +下面列出了 Dubbo 3.0 中的三个重要方向,具体的 Roadmap 将在接下来文章中单独说明: + +- 下一代 RPC 协议。新协议将提供更丰富的如 Stream、Flow Control 等内置语义,同时将具有更好的扩展性、网关的友好性等; +- 基于应用粒度的服务发现机制。在兼顾 Dubbo 面向接口的易用性与功能性的基础上,解决与 Kubernetes Native Service 适配问题,解决大规模集群下的地址推送性能瓶颈问题; +- 适配云原生基础设施的解决方案。这涉及到 Dubbo 服务与基础设施生命周期对接、Kubernetes Native Service 适配、适应基础设施调度的服务治理规则、适配 Service Mesh 架构的解决方案等; + +接下来沿着这三个方面简要展开。 + +### 下一代 RPC 协议 + +专注在协议自身来说,下一代的协议主要聚焦在 HTTP/2、Reactive Stream、Flow Control 等方面: + +- **Reactive Stream:** Reactive Stream 引入 RPC,带来更丰富的通信语义和 API 编程模型支持,如 Request-Stream、Bi-Stream 等; +- **HTTP/2:** 微服务云原生场景下,基于 HTTP/2 构建的通信协议具有更好的通用性和穿透性; +- **Flow Control:** 协议内置流控机制,支持类似 Reqctive Stream 的 Request (n) 流控机制。 + +从解决的业务场景问题上来说,基于新的协议 Dubbo 在框架层面要支持智能决策的负载均衡算法、对 Mesh 和网关更友好、更容易提供多语言实现与互通等。 + +- **Mesh:** 协议对穿透 Mesh 更友好,区分协议头 Metadata 与 RPC Payload,方便完成与 Mesh 的协作,包括流量控制机制、应用层配置协商等; +- **协议通用性:** 兼顾通用性与性能,支持协议能在各种设备上运行; +- **多语言支持:** 如通过支持 Protobuf 提供了更完善的 跨语言服务定义 与 序列化传输的支持。 + +### 应用级服务治理 + +面向接口一直以来都是 Dubbo 框架的优势。一方面它的易用性,为开发者屏蔽了远程调用的存在;另一方面面向接口的地址发现、服务治理带来了更强大的能力,使得整个 Dubbo 治理体系非常强大与灵活。 + +既然面向接口有如此多的好处,那为什么我们还要探索面向应用的服务治理模式呢? + +听起来似乎有些矛盾。其实到底是面向接口,还是面向应用,只是从不同的角度看 Dubbo。我们所聊的“面向接口 -> 面向应用”的改造,主要体现在服务注册、发现层面: + +![img](/imgs/blog/dubbo-go/10years/dubbo-triangle.png) + +而我们说的面向应用的新模型,主要对第 2 点,即注册中心的数据组织转变为 “面向应用/实例” 粒度。这为我们解决两个问题: + +- 在服务发现层面与 Kubernetes Service 等微服务模型对齐; +- 服务发现的数据量将有一个量级的下降,从 “接口数 * 实例数 ”下降到 “应用数 * 实例数”。 + +具体可以参见文章《[Dubbo 迈出云原生重要一步 - 应用级服务发现解析](https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247489653&idx=1&sn=445692c491f68aed3f649730d3d9ba96&scene=21#wechat_redirect)》,本系列文章后续也会有对这部分机制和实现的更深度解析。 + +### 云原生基础设施 + +云原生带来了底层基础设施,应用开发、部署和运维等全方位的变化: + +**基础设施** + +- 基础设施调度机制变化,带来运维(生命周期)、服务治理等方面的变化; +- 服务发现能力下沉, Kubernetes 抽象了 Native Service Discovery。 + +**Service Mesh - 云原生微服务解决方案** + +- Mesh 为跨语言、sdk 升级等提供了解决方案,Dubbo sdk 要与 Mesh 协作,做到功能、协议、服务治理等多方便的适配; +- Mesh 尚未大规模铺开,且其更适合对流量管控更关注的应用,传统 SDK 的性能优势仍旧存在,两者混部迁移场景可能会长期存在。 + +从应用场景上,Dubbo 可能的部署环境包括: + +1. 不使用 Kubernetes Native Service,Kubernetes 只作为容器编排调度设施,继续使用 Dubbo 自建的服务注册、发现机制; +2. 复用 Kubernetes Native Service,Dubbo 不再关心服务注册,Dubbo Client 负责服务发现与流量分配; +3. Dubbo sdk 往 Mesh 迁移,一方面要做到适应 Mesh 架构,成为 Mesh 体系下的 RPC 编程和通信方案;另一方面要做到 Dubbo 与 Mesh 架构长期共存,互相打通服务发现和治理体系; +4. Kubernetes 上与云下混合部署的平滑迁移支持,包括服务发现的统一与网络通信方案的打通。 + +从 Dubbo 功能划分上,将着重从以下方面提供对云原生基础设施的支持: + +- **生命周期**:Dubbo 与 Kubernetes 调度机制绑定,保持服务生命周期与 Pod 容器等生命周期的自动对齐; +- **治理规则**:服务治理规则在规则体、规则格式方面进行优化,如规则体以 YAML 描述、取消过滤规则对 IP 的直接依赖,定义规则特有的 CRD 资源等; +- **服务发现**:支持 K8S Native Service 的服务发现,包括 DNS、API-Server,支持 xDS 的服务发现; +- **Mesh 架构协作**:构建下一代的基于 HTTP/2的通信协议,支持 xDS 的标准化的数据下发。 + +新一代的 RPC 协议和应用级服务发现模型将会是这一部分的前置基础。 + +# 总结与展望 + +作为系列文章开篇,我们在这里对 Dubbo 过去一年的成绩做了简要的总结与回顾,包括 Dubbo 社区、产品迭代的发展。接下来我们会看到更多来自深度 Dubbo 用户的落地经验分享,Dubbo-go 子社区的发展故事等。更重要的,我们也对下一代云原生 Dubbo - Dubbo 3.0 做了展望,后续关于 Dubbo 3.0 Roadmap、方案设计与进展解析等也将在此系列中发布。 + + + + diff --git a/content/en/blog/news/dubbo-history-gochina.md b/content/en/blog/news/dubbo-history-gochina.md new file mode 100644 index 000000000000..2688e2752069 --- /dev/null +++ b/content/en/blog/news/dubbo-history-gochina.md @@ -0,0 +1,214 @@ +--- +title: "Dubbo Go 回顾与展望" +linkTitle: "Dubbo Go 回顾与展望" +date: 2021-01-11 +tags: ["新闻动态"] +description: 本文记录了发表在 gochina 上的 Dubbo Go 的回顾与展望 +--- + +Dubbo 是阿里于 2011 年开源的一款高性能 RPC 框架,在 Java 生态中具有不小的影响力。2019年5月21日,Dubbo 从 Apache 软件基金会毕业,成为 Apache 顶级项目。目前,毕业后的 Dubbo 项目的生态中已经正式官宣引入了 Go 语言,发布了 Dubbogo 项目。本文即是对 Dubbogo 这一项目的完整回顾与真实展望。由蚂蚁金服中间件技术专家于雨和携程基础中台研发部工程师方银城合作完成。 + +## 一 Dubbogo 整体框架 + +先介绍一下 dubbogo 的缘起,先看下面这幅图: + +![img](/imgs/blog/dubbo-go/gochina/p1.jpeg) + +最右边的 service0 和 service1 是 Dubbo 的服务端,左边的 gateway 是网关,HTTP 请求从网关进来,必须转化成 Dubbo 的协议才能到后面的服务,所以中间加了一层proxy 完成相关功能。基本上每个 service 都需要一个 proxy 去转化协议和请求,所以这个时候 dubbogo 的项目需求就出来了。最初的实现就是以 Dubbo 的 Go 版本作为目标,实现与 Java 版本 Dubbo 的互调。 + +### Dubbogo 目标 + +![img](/imgs/blog/dubbo-go/gochina/p2.jpeg) + +然后这个图是 dubbogo 的现在达到的目标:用一份 Go 客户端的代码能够在没有任何代理和其他中间件的情况下直接调用其他语言端,主要是Java 服务端的服务和 Go 服务端的服务,而 Go 作为服务端的时候,Java 客户端也可以直接调用 Go 服务端的服务。 + +### Dubbogo 发展历程 + +![img](/imgs/blog/dubbo-go/gochina/p3.jpeg) + +下面介绍 dubbogo 的整个发展历程,在2016年8月份的时候是于雨构建了 dubbogo 项目,那个时候的 dubbogo 只支持通过 jsonrpc 2.0 协议 进行 HTTP 通信,到 2018 年2 月份支持 hessian2 协议进行 TCP 通信,到 2018 年 5 月项目被 dubbo 官方关注后开始从零重构,于雨 2018 年 8 月份初步重构出一个 0.1 版本。由于我们携程这边的一些需求,2019 年初我和我的同事何鑫铭也开始参与了 dubbogo 项目的重构,同时和于雨一起开始组建社区,在 2019 年 6 月份的时候 dubbogo1.0 版本上线,这个版本的重构是参照了 Dubbo 的整体设计,主体功能都在这个版本里面有呈现,同期该项目进入了 Apache 组织。今年 8 月份由社区同学望哥负责的 Dubbo-go-hessian2 的项目也进了 Apache 组织。到目前为止我们社区有些工作已经和 dubbo 齐头并进,例如对 grpc 和 k8s 的支持,相关代码正在 review 中,年底发布的 v1.3 版本会包含 grpc 支持。预计到2020年,也是明年的目标,希望项目能以全新姿态融入云原生时代。 + +### Dubbogo 整体设计 + +![img](/imgs/blog/dubbo-go/gochina/p4.jpeg) + +这个图大家是不是看着很熟悉,是 Dubbo 的整个分层设计图,但是少了 Dubbo 里面的很多东西,因为我们是借鉴了 Dubbo 的分层设计和易拓展性的思想,但是由于 Go 语言和 Java 语言的本质差别决定了我们项目设计不可能完全照搬它,有一些东西就给它简化了,特别是协议层这一块。比如说 Dubbo 里面 SPI 的拓展,在 Go 里面我们是借用了 Go 的非侵入式接口的方式去实现的,由于 Go 禁止 package 循环引用,所以 dubbogo 在代码的分包分层上面也是有严格的规定,这正好跟它的易拓展性的特性结合了起来。 + +关于代理部分,因为 Java 有动态代理,Go 的反射就没有 Java 的反射那么强大,所以我们这边代理的实现方式也跟它是不一样的。 + +### Dubbogo 能力大图 + +![img](/imgs/blog/dubbo-go/gochina/p5.jpeg) + +上面的图是我们当前 dubbogo 项目实现的能力大图,最上层是当前实现的一些注册中心有 zk、etcd、nacos、consul,现在与 k8s 关联的功能正在开发中。配置中心目前是支持 Apollo 和 zookeeper。左边是消费端,消费端这边实现的是有 cluster 的,策略上基本上实现了 dubbo 支持的所有策略。然后还有负载均衡策略,fillter 主要是有一个 tps 的限流还有泛化调用,这两个后面会讲到。编码层现在就是 jsonrpc 2.0 和 hessian2,protobuf v3 正在加紧 review 中。目前社区正在开发中的支持,包括 trace、grpc、k8s注册中心,以及对 restful 的支持。 + +### 关键项目 + +![img](/imgs/blog/dubbo-go/gochina/p6.jpeg) + +目前 dubbogo 项目整体由 4 个组成部分。第一个是 getty,一个异步网络 IO 库,是实现 tcp 通信协议最坚实的基础;第二个是 dubbo-go-hessian2,这个是与当前 java hessian2 高度兼容的项目;第三个是 gost,是 dubbogo 的 基础库;最后是 dubbogo 的示例库,目前已经迁移到 https://github.com/apache/dubbo-samples,和 Java 示例合并了。这些都是当前 dubbogo 主要的组成项目。 + +## 二 协议实现 + +![img](/imgs/blog/dubbo-go/gochina/p7.jpeg) + +接下来讲一些具体的实现和部分的功能,上图是 dubbo-go-hessian2 实现,列出来是一些主要的功能列表,第一个是 Java 的 JDK Exceptions 的实现,里面实现了 40 多种的 Java JDK 主要的异常,可以与 Java 的 hessian2 版本互相解编码的支持,支持自动扩展自己实现 exceptions,或者是不常见的 Exceptions;第二个是支持字段名的联名,Go 可序列化的字段是大写字母开头,但是 Java 默认是小写开头的,所以有编码的字段名不一致的问题,这就有别名识别和支持自定义命名。 + +go-hessian2 还支持 Java 的 bigdecimal、Date、Time、基本类型的包装类型、Generic Invocation、Dubbo Attachements,甚至支持 emoji 表情。 + +go-hessian2 里面如果要解码和编码用户自定义类型,用户需要自己把它注册进去,前提是支持 go-hessian2 的 POJO interface,才能跟 JAVA 对应类互相解编码。 + +![img](/imgs/blog/dubbo-go/gochina/p8.jpeg) + +上面是 go-hessian2 的类型对应表,需要特别点出的是 int,go 这边的 int 类型在不同字长系统下是有不同的大小,可能是 32 位也可能 64位的,而 Java 的 int 是 32 位的,所以我们以 go 语言的 int32 类型对应 Java int 类型。 + +刚才提到了 Java 的 Class 和 go struct 的对应。上图有一个 go-hessian2 的 POJO 接口定义,每个 Java class 对应到 go struct,则 struct 需要给出 Java ClassName。 + +![img](/imgs/blog/dubbo-go/gochina/p9.jpeg) + +你也可以加 hessian 标签,解析的时候会把这个字段名用别名写进去,实现自定义 fieldName。默认情况下,go-hessian2 中会自动把 struct field 首字母变成小写作为其 fieldName。 + +![img](/imgs/blog/dubbo-go/gochina/p10.jpeg) + + +泛化引用,是 dubbogo 里面比较重要的功能。社区一位同学需要基于 dubbogo 实现网关,收集外部的请求,然后通过泛化引用的形式调用其他 Dubbo 服务,最后自己动手把它实现了。使用时,首先需要在项目里内置一个 GenericService 服务,调用Load,然后就像正常的调用服务一样直接调用,跟 Java 是类似的,Go 客户端可以不知道 Java 的接口定义和类定义,把方法名、参数类型、参数数组以一个 map 的形式传输到 Java 服务端,Java 服务端收到请求后进行识别,把它转换成 POJO 类。 + +以上是 go-hessian2 一些细节。上文讲到的泛化引用,是把网关作为整个内网 Dubbo 服务的公共消费端,使用的时候只需要知道请求的方法、参数类别,然后就能够调用 Dubbo 的服务。后面主要分享三部分内容:首先是网络引擎、底层网络库这块;其次是服务治理方面的内容,其中包含以 k8s 作为注册中心的一个初步的解决方案;第三部分是互联互通,主要是和 grpc 打通。最后给出一个展望,包含 dubbogo 社区明年的工作内容。 + +## 三 网络引擎 + +dubbogo 的网络引擎里面分为三层, 如下图所示: + +![img](/imgs/blog/dubbo-go/gochina/p11.jpeg) + +最底层 streaming 处理二进制流,第二层 codec层,进行协议的序列化和反序列化,第三层是 Eventlistener,提供应用使用接口。streaming 层能支持 websocket、TCP、UDP 三种网络通讯协议,这层具有一定的灵活性,今年年初上海有一个同学今年把 KCP 也加进去了,当时说要开源贡献出来,我还在期待中。codec 层可以适用不同协议,用户自定义即可。 + +![img](/imgs/blog/dubbo-go/gochina/p12.jpeg) + +EventListener 对上层暴露了 4 个回调接口。第一个是 OnOpen,网络连接初建成功时被调用,应用层如果判定其为正常连接,则可以把连接 session 存储下来,如果用户判断当前连接过多则返回一个非空的 error,则这个连接会被 dubbogo 关闭。其次是 OnError 事件,当网络连接出错,就会回调到这个接口,在 dubbogo 关闭这个连接之前允许用户做相应处理,如把网络连接 session 从应用层的 session 池中删除。第三个是 OnCron,处理定时任务,如心跳,dubbogo 针对 websocket 协议在底层直接把心跳热任务处理了,针对 tcp 和 udp 协议需要用户在这个回调函数中自己实现。第四个接口是 OnMessage,用作处理一个完整的网络包。可以看到整个回调接口风格跟 websocket 的接口很像。 + +![img](/imgs/blog/dubbo-go/gochina/p13.jpeg) + +### 协程池 + +dubbogo 的 goroutine pool 里有 worker channel 【数量为 M】和逻辑处理 goroutine 【数量为 N】和网络任务【网络包】三种角色,网络解包后把把包按照某种规则放入某个 worker pool,然后逻辑处理 goroutine 从 channel 中读取数据包并执行逻辑处理,其目的是是为了把网络 I/O 与逻辑处理分开。不同的 goroutine pool 设计中,有的 N 大小会变化,有的不变,分别可称之为可伸缩 goroutine pool 和不可伸缩 goroutine pool,可伸缩 goroutine pool 可以对机器资源的使用不可预计。dubbogo 采用了不可伸缩 goroutine pool,其考量是限定其网络资源使用的上限。 + +另外,dubbogo 的 goroutine pool 不考虑收包后的处理顺序。譬如,dubbogo 服务端收到了 A 和 B 两个网络包,dubbogo 有可能先处理网络包 B,后处理网络包 A。如果客户端的每次请求都是独立的,没有前后顺序关系,则带有不考虑网络包处理顺序是没有问题的。如果有强顺序要求,譬如上层用户关注 A 和 B 请求处理的前后顺序,则可以把 A 和 B 两个请求合并为一个请求,或者把 dubbogo 的 goroutine pool 特性关闭。 + +一般情况下,不建议大家自己写 goroutine pool,因为 Go 语言对 goroutine 资源的管理已经非常先进,比如释放一个协程,Go 不会马上销毁掉相关的资源,一旦有创建 goroutine 的需要,马上就可复用这个成本是很低的。什么情况下使用 Goroutine Pool 呢?个人觉得像网络库逻辑处理这类场景下执行同样类型任务场景下确定 goroutine 会被迅速重复使用时可以尝试使用,但是怎么用好还是需要仔细考量,即需要仔细考量 M 与 N 的比例关系。 + +假设处理某种网络任务请求,有的请求1秒就处理完了,有的可能10毫秒处理完了,设置 M 与 N 比例为 1:1,这样 1 对 1 造成的后果可能是饥饿,就是有一些队列处理的很快,有的处理很慢,整体负载不均衡,这种情况下就不推荐你用协成池了。 + +还有一个比例模型是是1:N的,一写多读,比如说所有的请求都交给一个队列,所有逻辑处理 goroutine pool 都消费这个队列,造成的结果是什么呢?因为你只有一个生产者,那你就只有一个队列,多个消费者消费这一个队列,造成的结果是什么呢?因为 go channel 的低效率【整体使用一个 mutex lock】造成消费者 goroutine hang 在锁竞争上,当然其网络包处理顺序更无从保证。 + +比较均衡的效果就是 M 和 N 都大于 1,dubbogo 的的 goroutine pool 模型中 M 和 N 的取值可以自行配置,其效果是每个 channel 被 N/M 个 goroutine 消费,这种模型类似于 kafka 的 consumer group,其优点是兼顾处理效率和锁压力平衡,可以做到总体层面的任务处理均衡。 + +### 优化改进 + +优化改进主要从三个方面入手, 如下图所示: + +![img](/imgs/blog/dubbo-go/gochina/p14.jpeg) + +1. 内存池。goroutine pool 是管理对 CPU 资源的分配,内存池就是管理内存资源的分配。我个人反对纯粹为了炫技没有目的地写内存池,其实 Go 的内存管理这块目前优化的很好了。Go 语言初始版本的内存管理使用了谷歌自家的 tcmalloc 库,这个库把应用释放的内存自己先缓存住,待失效期后才释放,那这样造成的结果是什么呢?就是早期的 Go 程序的内存成本很高。假设程序一个 sidecar 程序的资源限制是内存2G,CPU 核数是 2 核,用这样一个内存管理库,内存用完不释放给操作系统,那么没人敢用这个项目,当然最新的 Go 内存管理器是经过完全重构的,虽然也区分不同大小 span 的内存在 P 级别和全局级别进行缓存,但是基本上不用考虑这种内存膨胀不可控的问题了。那么什么情况下使用内存池呢?你确定你的业务有一些对象是频繁的复用则可以尝试使用。 目前大部分内存池技术底层依赖的底座都是 sync.Pool,自己写一个也不难。而且 Go 1.13 之后的 sync.Pool 已经可以做到跨 GC span 不释放缓存对象,非常之好。 +2. 定时器。Go 语言早期定时器因为整体使用一把大锁的缘故效率极差,当然最新的就相当好了,通过每个 CPU 核下一个定时器的方法【类似于分片锁】分散了竞争压力,但是很多情况下还是有竞争压力,如果对时间精度要求不高个人建议在自己的应用中自己写一个简单的时间轮实现一个定时器,释放 CPU 压力。 +3. 网络写 buffer 合并。写 buffer 合并一般采用 writev,但是 Go 语言的 writev 有内存泄露问题,我这边一个负责 MOSN 开发的同事元总发现的。他先给 Go 语言官方提交了 PR,然后在 MOSN 中把 writev 扔掉自己写了一个简单好用的写 buffer 合并发送实现:通过 for 循环 10 次从发送 channel 中把网络包读取出来然后合并发送,当然循环中间网络发送 channel 没有足够的网络包就通过 `select-default` 分支立即退出循环。 + +### channel 使用 + +Go 语言是一个适合处理 IO 密集型任务的语言,不擅长处理 CPU 密集型任务,其内存通信的基础就是 channel。channel 整体的内存基础是一个 ring buffer 数组和一个 lock,外加其他一些读写通知队列等,也是因为一把大锁的缘故,则 buffer 型 channel 如果使用不当则效率不会很高,如每个 channel element 的内存使用过大。channel 还有一个 closed 字段,用于判定 channel 的写是否被关闭掉,Go 语言对其操作是以原子锁方式进行的,很多人以这个字段为基础进行信号通知,如果使用不当很可能造成 for 循环 CPU 100% 的问题,所以在 for-select 循环中特别要谨慎使用,dubbogo 在这方面踩过坑。 + +## 四 服务治理 + +下面为大家讲一下服务治理,说到服务治理,其实最重要的还是服务发现和服务注册,这块逻辑跟 Dubbo 类似,这次不作展开。下面主要包含两方面的内容,分别是限流算法和优雅退出。 + +### 限流算法 + +限流算法首先需要考虑限流的对象,dubbogo 需要考虑 interface 和 method。其次是限流方法,首先需要考虑的是单机限流还是集群限流,单机限流算法很多,譬如常用的固定窗口算法和滑动窗口算法,以及更进一步的自适应限流。限流时一个重要问题就是限流参数是很难配的,譬如线上服务到底需要使用多少机器资源合理,限流窗口的时间窗口时长应该多长合适,其 qps 值设置多少合适呢?这都是 dubbogo 需要解决的问题。先进如谷歌的 BBR 算法,可以在当前的网络环境恶化前不断尝试改进相关参数,直到尝试出一段时间内的最佳参数。还有一些业务形态下的限流,如针对会员和非会员分别设计不同的限流链路。 + +Dubbo 的限流接口源码如下: + +![img](/imgs/blog/dubbo-go/gochina/p15.png) + +这个接口抽象是非常漂亮的,第一个是限流 url,第二个服务调用。下面是 Dubbo 的固定窗口限流源码: + +![img](/imgs/blog/dubbo-go/gochina/p16.png) + +上面的代码很明显,"private final" 决定了 Dubbo 使用者只能使用期给定的固定窗口限流限算法,无法扩展。 + +以下是 dubbogo 的限流接口: + +![img](/imgs/blog/dubbo-go/gochina/p17.jpeg) + +TpsLimiter 是限流对象,TpsLimitStrategy 是限流算法,RejectedExecutionHandle 是限流动作。 + +接下来是一个固定窗口算法实现: + +![img](/imgs/blog/dubbo-go/gochina/p18.jpeg) + +上图是 dubbogo 的固定窗口算法实现,其非线程安全,大家看一下代码就可以了,不推荐大家用。下图是 dubbogo 的滑动窗口算法实现: + +![img](/imgs/blog/dubbo-go/gochina/p19.jpeg) + +其基本原理是用一个队列存储一段时间内的请求,然后根据队列长度判定即可。 + +不管是固定窗口还是滑动窗口,其判定算法简单,麻烦的是其参数设置,如下图: + +![img](/imgs/blog/dubbo-go/gochina/p20.png) + +固定窗口时长精度很难控制。比如说限流一秒 QPS 值 1000,前 100 毫秒来了一千个请求,然后判定算法把请求放过了,而其后 900 毫秒 任何请求都无法处理。一般的处理方法是把时间粒度更精细一些,dubbogo 的时间窗口最小单位是一毫秒,则用户可以把时间窗口设定为 100 毫秒,总体来说一段时间内是很平稳的。下面这个图是我们社区的 commiter 邓明写完博客发出来,行业大佬微信评论如下: + +![img](/imgs/blog/dubbo-go/gochina/p21.png) + +图中第一个问题是 qps 和 tps 每个请求成本不同,这个问题怎么处理呢?个人觉得这是一个分级限流问题,在同一个服务下针对不同的请求做不同的分级处理。第二个问题 ”配置了 qps 1000,但是请求过来是10万你还是死“,这个就需要更上层的运维能力进行应对,譬如判定为恶意流量攻击就应该在网关层拦截掉,如果是服务能力不行就扩容。 + +针对分级限流,dubbogo 目前尚无法在同一个进程内完成,这需要 dubbogo 的配置中心更完善以后进行处理,用户可以通过搭建不同的服务链路处理之。譬如会员/非会员分级,同一个服务针对不同的会员等级搭建相应的链路,在网关层就判定一个 userID 是否是会员,然后发送不同的链路。 + +dubbogo 的单机熔断是基于 hystrix-go 实现的,其判定参数有最大并发请求数、超时时间、错误率;其次是保护窗口,是熔断时长,熔断多久后进行服务恢复;第三个是保护性动作,就是在保护时间窗口之内执行什么样的动作,具体实现用户自定义。 + +![img](/imgs/blog/dubbo-go/gochina/p22.jpeg) + +### 优雅退出 + +优雅退出也是邓明同学的大作,可以在网络上搜到相关博客。实现优雅退出的步骤有: + +1. 告知注册中心,服务即将关闭,此时等待并处理请求; +2. 注册中心通知别的客户端,别的客户端停止发送新请求,等待已发请求的响应; +3. 节点处理完所有接收到的请求并且返回响应后,释放作为服务端相关的组件和资源; +4. 节点释放作为客户端的组件和资源。 + +![img](/imgs/blog/dubbo-go/gochina/p23.jpeg) + +所以每一步基本上都要给程序一定的时间进行等待,所以等的时间窗口是多少呢?dubbogo 默认每个步骤大概花2秒,总体一个时间窗口是10秒。 + +![img](/imgs/blog/dubbo-go/gochina/p24.png) + +基本上在别的 RPC 框架里面,可能不太常见到这种处理。 + +## 五 Dubbogo 上云 + +dubbogo 作为微服务框架如何适配 k8s,如何部署?dubbogo 本身是一个 RPC 框架,但是其又有了服务治理能力,这部分能力与 k8s 的部分能力有些重合,不可能为了适配 k8s 就彻底抛弃。目前 Dubbo 官方也没有很好的解决方案供我们参考,所以这里我们 dubbogo 先给出一个简单的常识性的实践方案。下面先分析下 dubbogo 的 interface/service 和 k8s service 两者直接的差别。 + +![img](/imgs/blog/dubbo-go/gochina/p25.jpeg) + +k8s service 是许多具有相同服务能力 pod 资源的聚合,它自己的负载均衡算法以及健康检查等功能。而 Dubbo 里面的 interface/service 仅仅是服务 provider 集合,服务治理能力依赖 dubbo 的 directory、router 和 loadbalace 等额外的功能模块。并且Dubbo 服务区分 group/version,还有 provider、consumer 角色等等。Dubbo interface/service 无法与 k8s service 对标,Dubbo interface/service 和其整体服务治理能力才能对标成 k8s service。二者差异这么大,如何将 dubbo 集成到 k8s 中呢? + +k8s 提供了 pod/endpoint/service 三层维度的资源。简单的做法,可以通过监听pod/endpoint/service 三层维度资源的事件,作出合理的处理以达到服务治理的目的。目前我们社区成员王翔提交了一个基于监听 pod 事件来实现服务治理的 pr,优点就是不需要引入额外组件,通过监听 k8s 中最细粒度资源 pod 的事件,通过 k8s apiserver 获取 pod 列表,只是通过 apiserver 使用 etcd 的服务注册和服务通知能力,其他继续使用 Dubbo 的服务治理能力。其优点是模型简单,不需要实现额外的模块,几乎不需要对 Dubbo 作出改动,缺点就是其实无法使用 k8s 自己的健康检查能力,需要自己监听很细粒度的 pod 事件来综合处理服务健康、服务上下线等情况,而且还存在没有使用 k8s service 的事件监听能力,每个 consumer 冗余监听一些不必要监听的事件,加大 apiserver 的网络压力。所以其实现目前来看可能还不是最优解,与 k8s 建议的operator 方式也有一定的背离。社区目前还在讨论新方案,寻求 k8s 最优解,大部分人倾向于采用 k8s 社区推荐的 operator 方案,但是其开发和线上维护成本就上升了。后面两种方式会共存,使用者见仁见智。 + +## 六 互融互通 + +关于互融互通,Dubbo 明年有个三个重要目标,其中一个目标是与外面的微服务生态进行互联互通,比如说跟 grpc 互通。目前 dubbo 的 grpc 的解决方案已经开放出来,dubbogo 与 grpc 互通的开发工作也几近完成。 + +下面左边 dubbogo 的代码生成器工具根据 grpc 的 pb 服务定义文件自动生成的适配 dubbogo 的代码,右边是对应的使用示例。不同于 k8s service 的复杂性,grpc 整体仅仅具有 rpc 能力,没有服务治理能力,所以原始的 grpc 就可以很好的嵌入到 dubbogo 里面,grpc server 的 methodhandler 对我们 dubbogo 来说就是 dubbo invoker,grpc 的一些相关的接口直接跟我们的接口嵌套起来,两个生态就对接起来了。 + +![img](/imgs/blog/dubbo-go/gochina/p26.jpeg) + + +## 七 展望未来 + +最后就是展望未来,也就是明年的规划。 + +明年我们将会很快实现 dubbo router。社区在 8月份已经实现了 router 功能需要的底层的算法模块,但是当时配置中心下发相关的参数的能力还不是很强,所以没有最终完成。最近服务治理配置刚刚支持了 zookeeper 和 apollo,预计很快就可以将 router 的参数通过配置中心下发的形式支持掉。另外,还有 tracing,我们将会引入社区主流的 tracing 方案,以 opentracing 为标准,去集成 opentracing 开源生态的相关能力。第三个是 kubernetes operator,这个就是刚才说的 K8s 的服务调用,我们会基于 operator 的方案做一版新的基于 k8s 的注册中心实现。最后就是云原生生态的融入,即与 istio 的集成,dubbogo 将会成为 dubbo 在 service mesh 生态中的重要角色。 + +目前 dubbogo 项目,今年是能 run 起来,质量方面还有很多工作要做,功能基本上到明年可与 dubbo 2.7 补齐,目前已经基本够用。目前落地实践的是 3 个比较典型的公司,一个是携程,还有一个是涂鸦智能。 + +dubbogo 本身是一个 go 语言项目,也期待与其他 go 社区的指正或者需求,一起成长。 diff --git a/content/en/blog/news/dubbo-initializer.md b/content/en/blog/news/dubbo-initializer.md new file mode 100644 index 000000000000..e1e41766746a --- /dev/null +++ b/content/en/blog/news/dubbo-initializer.md @@ -0,0 +1,64 @@ +--- +aliases: + - /en/overview/tasks/develop/template/ + - /en/overview/tasks/develop/template/ + - /en/overview/mannual/java-sdk/tasks/develop/template/ +title: "通过模板生成项目脚手架" +linkTitle: "通过模板生成项目脚手架" +date: 2023-12-31 +tags: ["新闻动态"] +description: > + 本文介绍 dubbo initializer 的基本使用,使用 start.dubbo.apache.org 快速生成 Dubbo 项目(应用)。 +--- + +Dubbo Initializer 可用来快速生成 Java 项目脚手架,帮助简化微服务项目搭建、基本配置、组件依赖管理等。 + +> Initializer 仍在持续更新中,更多 Dubbo Feature 的支持将会陆续发布。 + +## 选择 Dubbo 版本 +Initializer 将使用 `dubbo-spring-boot-starter` 创建 Spring Boot 项目,因此我们首先需要选择 Dubbo 与 Spring Boot 的版本。 + +![initializer-choose-version](/imgs/v3/tasks/develop/initializer-choose-version.png) + +## 录入项目基本信息 +接下来,填入项目基本信息,包括项目坐标、项目名称、包名、JDK 版本等。 + +![initializer-project-info](/imgs/v3/tasks/develop/initializer-project-info.png) + +## 选择项目结构 +有两种项目结构可共选择,分别是 `单模块` 和 `多模块`,在这个示例中我们选择 `单模块`。 + +![initializer-project-architecture](/imgs/v3/tasks/develop/initializer-project-architecture.png) + +* 单模块,所有组件代码存放在一个 module 中,特点是结构简单。 +* 多模块,生成的项目有 `API`、`Service` 两个模块,其中 `API` 用于存放 Dubbo 服务定义,`Service` 用于存放服务实现或调用逻辑。通常多模块更有利于服务定义的单独管理与发布。 + +## 选择依赖组件 +我们为模板默认选择如下几个依赖组件: +* Dubbo 组件 + * Java Interface + * 注册中心,zookeeper + * 协议 TCP +* 常用微服务组件 + * Web + * Mybatis + * 模版引擎 + +![initializer-dependencies](/imgs/v3/tasks/develop/initializer-dependencies.png) + +基于以上选项,生成的项目将以 Zookeeper 为注册中心,以高性能 Dubbo2 TCP 协议为 RPC 通信协议,并且增加了 Web、Mybatis 等组件依赖和示例。 + +> 注意:上面选中的 Dubbo 组件也都是默认选项,即在不手动添加任何依赖的情况下,打开页面后直接点击代码生成,生成的代码即包含以上 Dubbo 组件。 +> +> 如手动添加依赖组件,请注意 Dubbo 各个依赖组件之间的隐含组合关系限制,比如 +> * 如果选择了【Dubbo Service API】-【IDL】,则目前仅支持选择 【Dubbo Protocol】中的 【HTTP/2】或 【gRPC】 协议。 +> * 同一个依赖分组下,相同类型的依赖只能选择一个,比如 【Dubbo Registry&Config&Metadata】分组下,从注册中心视角【Zookeeper】、【Nacos】只能选一个,如果要设置多注册中心,请在生成的代码中手动修改配置。但注册中心、配置中心可以分别选一个,比如 Zookeeper 和 Apollo 可同时选中。 + +## 生成项目模板 +* 点击 “浏览代码” 可在线浏览项目结构与代码 +* 点击 “获取代码” 生成项目下载地址 + +![initializer-preview](/imgs/v3/tasks/develop/initializer-preview.png) + +项目下载到本地后,解压并导入 IDE 后即可根据需要开发定制 Dubbo 应用。 + diff --git a/content/en/blog/news/dubbo-introduction.md b/content/en/blog/news/dubbo-introduction.md new file mode 100644 index 000000000000..b4eeef36634b --- /dev/null +++ b/content/en/blog/news/dubbo-introduction.md @@ -0,0 +1,116 @@ +--- +title: "一文帮你快速了解 Dubbo 核心能力" +linkTitle: "一文帮你快速了解 Dubbo 核心能力" +date: 2023-02-23 +description: > + Apache Dubbo 是一款微服务开发框架,它帮助解决微服务开发中的通信问题,同时为构建企业级微服务的提供服务治理能力,Dubbo 不绑定编程语言,我们的目标是为所有主流语言提供对等的微服务开发体验 。 +--- + +## Dubbo 简介 + +### 一句话定义 +Apache Dubbo 是一款微服务开发框架,它帮助解决微服务开发中的通信问题,同时为构建企业级微服务的提供服务治理能力,Dubbo 不绑定编程语言,我们的目标是为所有主流语言提供对等的微服务开发体验。 +![overview](/imgs/blog/2023/2/introduction/1-overview.jpg) + +### 基本架构 + +![overview](/imgs/blog/2023/2/introduction/2-arc.jpg) + +Dubbo 从架构图上分为数据面和控制面。在数据面,使用 Dubbo 开发的微服务进程间基于 RPC 协议通信。DubboAdmin 控制面作为服务治理的抽象入口,由一系列可选的服务治理组件构成,负责 Dubbo集群的服务发现、流量管控策略、可视化监测。 + +### 行业应用 + +![overview](/imgs/blog/2023/2/introduction/3-usecase.jpg) + +Dubbo 设计用于解决阿里巴巴内部大规模 微服务集群实践难题,当前已被广泛应用于几乎所有行业的微服务实践中。 + +![overview](/imgs/blog/2023/2/introduction/4-usecase-alibaba.jpg) + +以阿里巴巴为例,在 2021 年,阿里巴巴基于内部多年 HSF 框架实践积累,面向云原生架构设计了下一代微服务框架 Dubbo3,用于解决性能、治理升级、服务网格等一系列问题;截止目前,阿里巴巴已全面完成从 HSF到 Dubbo3 的迁移,核心业务都跑在开源 Dubbo3 之上。 + +## Dubbo 到底提供了哪些核心能力? + +### 提供微服务抽象与框架 + +![overview](/imgs/blog/2023/2/introduction/5-framework.jpg) + +首先,Dubbo 作为服务开发框架解决了业务应用中微服务定义、暴露、通信与治理的问题,为业务应用开发定义了一套微服务编程范式。 +具体来说,Dubbo 为业务应用提供了微服务开发API、RPC 协议、服务治理三大核心能力,让开发者真正的专注业务逻辑开发。 + +![overview](/imgs/blog/2023/2/introduction/6-extensibility.jpg) + +Dubbo 不是应用框架的替代者,它可以很好的工作在每种语言的主流编程框架之上,以 Java 为例,Dubbo 可以很好的与 Spring 协作,并在此基础上提供服务定义、微服务编程、服务发现、负载均衡、流量管控等能力。 + +### 提供灵活的通信协议切换能力 + + +在通信方面,Dubbo 区别于其他 RPC 框架的是它不绑定特定协议,你可以在底层选用 HTTP./2、TCP、gRPC、REST、Hessian 等任意通信协议,同时享受统一的 API、以及对等的服务治理能力。 + +### 一切皆可扩展 +![overview](/imgs/blog/2023/2/introduction/8-extensibility.jpg) + +Dubbo 的另一个优势在于其可扩展性设计,从流量管控、协议编码、诊断调优、再到服务治理,你都可以去扩展,满足企业级微服务开发与运维的所有诉求。 + +### 丰富的生态 +![overview](/imgs/blog/2023/2/introduction/9-ecosystem.jpg) + +基于扩展能力 Dubbo 官方提供了丰富的生态适配,涵盖了所有主流的开源微服务组件。 + +### 服务网格 +![overview](/imgs/blog/2023/2/introduction/10-mesh.jpg) + +对于服务网格架构,Dubbo也可以轻松接入原生 Istio 体系; +在数据面支持与 Envoy 部署的 Proxy 模式,也支持无 Envoy 的 Proxyless 模式,提供更灵活的数据面选择。 + +## 构建企业级Dubbo 微服务有多简单?你只需要 4 步 +我们以 Java 微服务开发为例。 + +### 第一步 +![overview](/imgs/blog/2023/2/introduction/11-initializer.png) + +使用 [官方脚手架](https://start.dubbo.apache.org/bootstrap.html) 快速创建项目模板,只需要选择依赖的版本、组件,点击 “获取代码” 即可 + +### 第二步 +将模板项目导入 IDE 开发环境。 +定义 Java 接口作为 Dubbo 服务。 +![overview](/imgs/blog/2023/2/introduction/12-interface.jpg) + +开发 Dubbo 服务端,实现接口并完成业务逻辑编码,通过一条简单的注解配置完成服务发布。 +![overview](/imgs/blog/2023/2/introduction/13-impl.jpg) + +开发Dubbo 客户端,通过注解声明 Dubbo 服务,然后就可以发起远程方法调用了。至此,开发工作完成。 +![overview](/imgs/blog/2023/2/introduction/14-reference.jpg) + + +### 第三步 +进入部署环节,我们选择 Kubernetes 作为部署环境。 + +首先,通过一条命令安装 dubbo-admin 等服务治理组件,安装成功之后,我们查看部署状态。接下来,开始部署业务应用,随后查看确认直到应用已经正常启动 +![overview](/imgs/blog/2023/2/introduction/15-deploy.jpg) + +然后,我们就可以打开 Admin 控制台查看服务部署与调用情况了。这里是 Dubbo Admin 控制台的页面显示效果,可以看到刚才启动的 Dubbo 服务部署状态;除此之外,Admin 还提供了更详细的流量监控监测,点击服务统计,可进入监控页面 + +![overview](/imgs/blog/2023/2/introduction/16-admin.jpg) + +你可以在此了解Dubbo 集群的详细运行状态,包括每个应用对外服务和调用服务的情况,QpS、成功率等,还可以查看每个实例的资源健康状况。 + +![overview](/imgs/blog/2023/2/introduction/17-grafana1.png) + +### 第四步 +进行流量管控。当应用已经平稳运行后,进一步控制流量的访问行为,包括实现金丝雀发布、全链路灰度、动态调整超时时间、调整权重、按比例流量分发、参数路由等。控制台提供了可视化的流量治理规则操作入口,在这里可以直接下发流量规则。 + +![overview](/imgs/blog/2023/2/introduction/19-gray.jpg) + +以一个线上环境的灰度隔离示例,通过 Dubbo 流量管控机制,我们可以给每个应用的一部分机器打上 gray 标签,接下来,对于入口为 gray 的流量,就可以控制确保它只在有 gray 标记的 Dubbo 实例内流转,实现了全链路的逻辑隔离效果, +对于隔离多套开发环境、线上灰度测试等场景都非常有用。 + +![overview](/imgs/blog/2023/2/introduction/20-region.jpg) + +对于同区域优先调用的场景,这里有两个应用做了多区域部署,紫色是杭州区域、蓝色是北京区域,部署在橙色区域的应用会优先访问同区域的应用,以此降低访问延迟,蓝色区域部署的服务亦是如此。 + +![overview](/imgs/blog/2023/2/introduction/21-region.jpg) + +当应用在同区域区域部署的实例不可用时,调用会自动跨区域切换到其他可用区,确保整体可用性。 + +## 总结 +接下来,请开始你的Dubbo 之旅吧。 diff --git a/content/en/blog/news/glcc-project-announcement.md b/content/en/blog/news/glcc-project-announcement.md new file mode 100644 index 000000000000..60ca81fd8b40 --- /dev/null +++ b/content/en/blog/news/glcc-project-announcement.md @@ -0,0 +1,20 @@ +--- +title: "GLCC x Apache Dubbo编程夏令营报名启动" +linkTitle: "GLCC x Apache Dubbo编程夏令营报名启动" +date: 2023-07-05 +tags: ["新闻动态"] +description: > + "GitLink编程夏令营(GLCC)Apache Dubbo 无奖金项目报名正式启动后!" +--- + +## 背景介绍 +GitLink编程夏令营(GLCC),是在CCF中国计算机学会指导下,由CCF开源发展委员会(CCF ODC)举办的面向全国高校学生的暑期编程活动。活动将覆盖近千所高校,并联合各大开源基金会、开源企业、开源社区、开源专家,旨在鼓励青年学生通过参加真实的开源软件开发,提升自身技术能力,为开源社区输送优秀人才。为青年学生提供开放友好的交流平台,希望进一步推动国内开源社区的繁荣发展。 + +## 报名方式 +此次报名仅限 GLCC “无奖金项目”。具体请在此查看 **项目详情与报名方式**。 + +**Apache Dubbo 项目报名截止日期:2023-07-30** + +如有更多问题,请扫描官方公众号咨询: + +![wechat-account](/imgs/contacts/wechat-account.jpg) diff --git a/content/en/blog/news/how-to-involve-dubbo-community.md b/content/en/blog/news/how-to-involve-dubbo-community.md new file mode 100644 index 000000000000..5ad585b9aea6 --- /dev/null +++ b/content/en/blog/news/how-to-involve-dubbo-community.md @@ -0,0 +1,114 @@ +--- +title: "如何参与贡献Dubbo社区" +linkTitle: "如何参与贡献Dubbo社区" +date: 2018-03-11 +tags: ["新闻动态"] +description: > + 本文介绍了如何以Apache Way的方式参与Dubbo社区并做贡献 +--- + + +![img](/imgs/blog/involve-dubbo/head.jpg) + +## 前言 + +本文首次分享是在Apache Dubbo成都meetup上,这个话题是第一次在meetup上讲,不是我们没有更好的话题,相反,我们认为这个话题非常重要,甚至建议这个话题以后每次meetup都要讲。 + +Dubbo的发展历史大家应该并不陌生了,这里我还是简单回顾一下。Dubbo于2011年在github开源,后面几年由于一些原因停止了维护,直接去年7月份阿里重启维护,并于2018年2月16日捐献给Apache。 + +为什么会选择捐献给Apache,主要是为了打消社区对Dubbo未来发展的顾虑,给Dubbo用户足够的信心;Apache认为`社区大于代码`,非常注重多样性,强调一个项目需要有多个公司和个人贡献者参与,现在Dubbo的发展完全是按`The Apache Way`社区化的方式来运作的。 + + +## Apache的诞生 + +说到Apache,大家都非常熟悉了,它是全球目前最大的软件基金;Apache的很多项目我们都用过,比如Maven、Log4j、Tomcat等,但有一个项目要特别强调的,那就是 Apache httpd server,这是Apache的第一个项目。 + +Apache软件基金会正式创建于1999年,主要是为公众提供有用的免费软件,并为软件开发者社区提供支持和服务;它的创建者是一个自称为`Apache组织`的群体; + +早在1995年,这个组织就存在了,他们聚集在一起,在美国伊利诺伊大学超级计算机应用程序国家中心开发的NCSA HTTPd服务器的基础上开发与维护了一个叫Apache的HTTP服务器。 + +最早NCSA HTTPd服务器是一个叫Rob McCool的人开发的,但是后来慢慢失去了兴趣,导致这个功能强大又好用的服务器没人维护;于是一些爱好者和用户就自发开始维护起来,并不断改善功能、发布版本;为了更好进行沟通,一哥们就创建了一个邮件组,并把维护工作高效组织起来,且自称是`Apache组织`,并把这个软件叫`Apache 服务器`。 + +这也是为什么Apache的所有的项目到今天为止依然以邮件列表作为沟通的主要方式。 + +关于Apache的命名来源,从北美当地的一支叫`Apache`的印第安部落名称而来,这支部落以高超的军事素养和超人的忍耐力著称,19世纪后半期对侵占他们领土的入侵者进行了反抗;为了对这支部落表示敬仰,就取了这个名字;但这里还流传着一个小故事,说是在NCSA HTTPd基础上,大家都通过打补丁不断在修改这个软件,被戏称为`A Patchy Server`,和`Apache Server`读音很像。 + +![img](/imgs/blog/involve-dubbo/apache-history.png) + +随着后来商业需求扩大,围绕Apache HTTP服务器的项目越来越多,后来越来越多的项目启动,也有很多外部组织捐献项目;为了让这些外部项目能顺利进入到Apache基金会,2002年创建了Incubator(孵化)项目。可以看到,经过10多年的发展,到2010年,75个顶级项目,30个孵化项目,每天2697封讨论邮件;2018年这个数据进一步增长,194个顶级项目,54个孵化项目,3255个committers;其中中国人主导的项目,有RocketMQ,WeeX,ECharts,Skywalking等。 + +Dubbo正在成为Apache顶级项目的路上——Apache孵化项目中。 + +回顾一下Apache这些历史和数据,我们不难发现几个关键词:兴趣、参与、邮件;这些就是我们后面要重点介绍的`The Apache Way`。 + +## ASF组织架构 + +![img](/imgs/blog/involve-dubbo/apache-org.png) + +我们知道每个组织都有它自己的架构,ASF同样也不例外;那Apache的组织架构是什么样的呢?它有什么独特的地方吗?这里特别要强调的是Project Management Committees,即 PMC,每个项目从孵化阶段开始就会有PMC,主要负责保证开源项目的社区活动都能运转良好,这里运转的机制就是`The Apache Way`。 + +图中,Board就是负责整个基金会符合章程的运作。Board我们一般很少能接触到,接触更多的是PMC以及下面的这几层。 + +参与Apache项目社区活动的人,一般分为以下几类: + +* 直接用户:在座的都是Dubbo的用户,可能部分现在还不是,但将来肯定会是 + +* 贡献者:部分用户在使用Dubbo过程中,遇到问题,自己通过分析调试找到解决方案,并提交给Dubbo官方,最终被接受,这些用户就是Dubbo的贡献者 + +* 提交者:贡献多了,经过PMC的提议和投票,就会成为Committer;Committer即意味着正式加入Apache,拥有个人Apache帐号以及相应项目的写权限 + +* PMC:Committer再往上走就是PMC,这个必须由现有PMC成员提名 + +个人在社区的成长,就像我们在公司晋升一样,一步一步往上走。 + +本文的目的就是告诉大家,从User到Contributor没有大家想像的那么难,从Contributor到Committer也不是不可能;只要大家拥有一颗开源的心,找到自己感兴趣的项目,并持续投入,付出肯定会有回报。 + +## The Apache Way + +就像你加入一家公司需要了解这家公司的文化一样,参与Apache开源项目之前,同样我们需要需要了解ASF的文化,这个文化就称为`The Apache Way`。 + +![img](/imgs/blog/involve-dubbo/apache-way.png) + +这里想特别强调以下几点: + +* 社区胜于代码:把项目构建出来这不是开源,去构建社区才是真正的开源;对社区而言,一切都是围绕代码而生,无代码则社区不复存在;在代码之上,则是如何做事、如何待人、如何决策的理念体现;一个健康的社区远比优秀的代码重要——如果代码奇烂无比,社区可以重写,但社区有了毛病,代码最终也会付之东流; +* 公开透明与共识决策:`If it doesn't happen on email, it doesn't happen.` 所有的决定,不管是技术feature、发展方向,还是版本发布等,都应该被公开讨论,而形式就是邮件列表,这些讨论过程和结论都会被永久存档;而讨论的过程,就是大家自由发表意见的过程,但最终大家要投票,比较民主的做法; +* 任人唯贤:`Those that have proven they can do, get to do more.` 特别强调一点,贡献绝不仅仅是代码,贡献可以是很多方面,接下来我们结合Dubbo来讲,大家如何参与并贡献; + +## 参与Dubbo社区 + +![img](/imgs/blog/involve-dubbo/dubbo-community.png) + +要参与Dubbo社区,就要先大概了解一下目前社区的工作方式。总结一句话就是4个角色、3个途径以及2个代码组; + +1. 4个角色前面也提到过了,分别是User、Contributor、Committer、PMC;这里特别要强调用的是,角色之间不是孤立的,比如提功能建议的也可以是Committer或Contributor等;PMC有投票权,但其他人一样也可以投票,这本身就是一种参与、一种贡献; +2. 3个途径,分别是Dubbo官网、github、dev邮件列表;目前比较活跃的是github issue/PR;我们鼓励按`The Apache Way`的方式,使用邮件列表交流,让导师看到我们的贡献; +3. 2个代码组,一个是 `github.com/apache/dubbo*` ,这里是dubbo孵化的项目,目前主要包含dubbo-rpc、dubbo-spring-boot-start、dubbo-ops三个部分;另外一个就是 `github.com/dubbo`,这个是dubbo作为微服务解决方案的所有相关的生态部分,包括dubbo-rpc的扩展、dubbo与其他产品集成、dubbo多语言客户端实现以及一些工具和套件等; + +![img](/imgs/blog/involve-dubbo/dubbo-project.png) + +所以,对于想参与Dubbo社区、想为Dubbo这个微服务解决方案自己一份力量的人来说,以下就是你们现在就可以开始做的: + +1. 开发邮件组可以订阅起来,可以参考这里:https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide +2. github.com/apache/dubbo star起来,fork起来 +3. 学习中英文文档,进行修正或优化,提PR;有疑问的地方,可以email到邮件组或提issue;官方开发者的回复总比google或stackoverflow里找到的答案要强的多吧? +4. 如果你正在使用dubbo,可以将经验总结出来,写篇blog,分享给社区;真实的案例总是最具有说服力; +5. 如果你有时间,可以参与issue和PR的解决,回条用户的问题、PR的review;`Good first issue`以及`Help wanted`的issue,总有一个是适合你的; +6. 如果你想深入学习dubbo-rpc框架,UT是一个非常好的开始,完善和补充现有的UT,一边学习一边贡献,何乐而不为? +7. 发现了bug,报issue;通过自己的努力最终解决了,提一个issue,`first-contributor`并不是那么难;哦,对了,拼写错误也算哦; +8. 如果你发现一个可以帮助用户更方便地使用dubbo,开发、测试、调试、mock、工具等;都可以贡献到Dubbo生态中来; +9. 最后我们非常欢迎大家通过邮件提想法,也欢迎大家多讨论;你会发现,技术变牛的同时,英文也变的66的了; + +## 加入Apache孵化 + +如果大家有好的项目希望捐献给Apache,这个流程可以参考一下; + +![img](/imgs/blog/involve-dubbo/get-into-apache.png) + +进入 Apache 分为三个阶段,准备阶段、孵化阶段和毕业阶段。准备阶段需要做的事情要找到愿意帮助孵化的导师,向Apache 提交进入孵化的申请,经过导师们讨论并投票,如果通过的话就可以进入孵化。孵化阶段分为两大环节,第一个环节是公司和个人签署协议向Apache 移交代码和知识产权,之后就是在导师的指导下按照Apache的规范做版本迭代、社区运营、发展更多的Committer;如果最终通过了成熟度评估,就可以顺利毕业成为Apache的顶级项目。 + +## 结语 + +希望越来越多的公司团队和个人能够贡献到国际化的开源社区里去,一起打造我们中国的开源品牌!也希望大家都能愉快去贡献,罗马非一日建成,但付出一定会有回报。 + +这里透露一个小福利,所有Apache Committer可以免费使用IntelliJ的全套付费产品,包括全宇宙最好用的IDEA。 diff --git a/content/en/blog/news/meet-dubbo.md b/content/en/blog/news/meet-dubbo.md new file mode 100644 index 000000000000..2dcef366f349 --- /dev/null +++ b/content/en/blog/news/meet-dubbo.md @@ -0,0 +1,65 @@ +--- +title: "遇见Dubbo" +linkTitle: "遇见Dubbo" +date: 2019-01-26 +tags: ["新闻动态"] +description: > + 本文记录了一个小白成长为Dubbo committer的过程。 +--- + +我是一个有Dubbo情节的程序员。 + +Dubbo以不同方式,陪伴了我时间不长的整个代码生涯。不久前,通过社区投票,我被选举为`Committer`。当时我在朋友圈发了一句话,也是贯穿我从开始使用Dubbo、研究Dubbo、贡献Dubbo到最后成为`Committer`的全过程,一直为我提供内心无与伦比愉悦的源泉:成长这种事,能看见脚印特别幸福。 + +今天来个回忆杀,把我和Dubbo的那些事拿出来说说。 + +## 小白 + +我知道Dubbo,是在我大三翘课出去实习的时候,那个时候是无知的,我眼里最牛的人就是能熟练使用各种配置,精通SSH框架的人。就是在那种情况下,我外出实习,遇到了一群影响我至今的人。当时也是机缘巧合,我们进行了两个非常小的模块的服务化改造。那时的团队除了我们老大,全是一群新兵蛋子,老大指哪我们打哪。老大说,就用Dubbo吧,从那时候开始,我才知道,哦!原来还有一种东西叫做RPC,还有个阿里巴巴的RPC框架叫Dubbo。 + +苦于当时非常有限的水平和高强度的工作,我和Dubbo的缘分也就停留在一面之缘的程度——要说认识谈不上,说不认识也牵强。 + +## Contributor + +我在二维火任职的一年算是我Dubbo生涯里承上启下的一年。二维火当时自己维护了一个Dubbo的分支,有一群对Dubbo非常了解的人。那时候,工作结束搞Dubbo,周六加班研究Dubbo。看源码,看不懂就debug一下,debug也不明白就问,问人,问google,里外折腾了个遍。 + +后来毕业加入网易云音乐。大概是今年五月份的时候,我发现了一个Dubbo的小bug,并且给Dubbo提交了pull request。在第一次被merge之后,非常受鼓舞,这才有了后续的故事。后来,回看这第一次提交,真的算是我和Dubbo的一个拐点,拐弯之后,我才逐渐走上一条成为`Committer`的路。 + +可能很多人看到这里要望而却步了,这也是做开源给很多人留下的固有的印象——是不是没发现BUG就不能提交pull request,不能做贡献?其实完全不是的,这里给大家敲黑板划重点:其实很多贡献者的第一次贡献,贡献的并非代码,而是文档修改或者单元测试。相比于BUG或者新的Feature,单测和文档上的修复门槛就比较低了。 + +我自己的方法论就是:**先尝试增加单元测试,写单测的时候顺手debug+看代码。或者多看文档,了解框架的同时,发现错别字、语意不明或者文档上的链接干脆点不开的情况,直接提交PR到对应的仓库**。 + +万事开头难。第一次被merge代码,你就可以成为一个`Contributor`了。`Contributor`很多,但是`Committer`很少,下面继续说怎么从一个`Contributor`成长为独当一面的`Committer`。 + +## Committer + +做开源和写代码一样,都不是一朝一夕的事情,而是量变促成质变的过程。这是一个没捷径可走的过程,欲带皇冠必承其重。身后的Dubbo功底自不必多说,这个部分主要是想跟大家说一下除了钻研和热爱之外,其他需要注意的地方。 + +首先是多提交高质量PR。任何一个PR都会被review,代码中的问题,思路上的偏差,都会被指正。提交PR是一个反复琢磨的过程。PR的质量不能简单的归结于新增了多少行代码,高质量的PR一定是经过缜密思考的,为什么删除代码,新增的代码有什么意义,修改之后有什么效果等等。希望大家更加重视质量而非数量,眼光放长远,相信你的收获一定会非常大! + +第二个就是,我们需要培养一种思维方式——Apache Way。一句话概括就是**社区重于代码**。Apache是一个注重社区的的开源组织,其行为方式相比于目前我们的开发方式,还是有所不同,这里我举一个Apache Way的例子,用以说明传统方式相较于Apache Way的区别在哪里,这里假设我想为Dubbo开发一个功能A。 + +**Old Way**: + +1. 功能设计:做一个设计文档(根据功能大小而定),大概划定需要修改或新增的类,大体设计接口等。 +2. 开发代码。 +3. 提交PR。 +4. Review & Merge + +可以看到,我们整个过程中,真正与社区交互的只有最后一步。 + +**Apache Way**: + +1. 功能设计:发送邮件至mailing list并且提交ISSUE,与社区成员共同探讨,产出一个设计文档(根据功能大小而定),大概划定需要修改或新增的类,大体设计接口等。然后再次发送邮件并且回复ISSUE,通知社区设计文档定稿或者方案确定。 +2. 开发代码:发送邮件至社区,通知社区成员我即将投入开发功能A,如需帮助,可以同时说明需要协助。 +3. 提交PR:发送邮件并且回复ISSUE,提醒社区开发结束,贴上PR地址以通知社区review代码。 +4. Review + Merge后,发送邮件并且关闭ISSUE,通知社区功能A的开发功能告一段落。 + +可以看到,Apache Way就是在整个开发过程中,不断地与社区交互,最大发挥社区的功能,汲取众人之力,这才是所谓**社区**以及所谓**开源**的含义。 + +## 结尾 + +Dubbo目前还在孵化阶段,整个Dubbo社区还不完善,我们也在跟着Dubbo一起成长,我们非常希望更多的Dubbo爱好者深度参与到Dubbo中,为你的代码生涯树一个里程碑。 + +相信过程,收获结果;天道酬勤,功不唐捐! + diff --git a/content/en/blog/news/openatom-opensopurce-competition-2024.md b/content/en/blog/news/openatom-opensopurce-competition-2024.md new file mode 100644 index 000000000000..bd2ae10fa996 --- /dev/null +++ b/content/en/blog/news/openatom-opensopurce-competition-2024.md @@ -0,0 +1,238 @@ +--- +title: "Apache Dubbo 下一代云原生微服务挑战赛启动报名!五大赛题50万奖金池等你来战" +linkTitle: "Apache Dubbo 下一代云原生微服务挑战赛启动报名!五大赛题50万奖金池等你来战" +date: 2024-01-18 +tags: ["新闻动态"] +description: > + 中国开源开放原子基金会主办,Apache Dubbo 下一代云原生微服务挑战赛启动报名!五大赛题50万奖金池等你来战 +--- + +本文带来本赛题详细解读,开放原子开源基金会官方报名渠道 及更多详情请查看文章最后链接与二维码。 + +## 赛题解读 +我们期待参赛团队在高性能 Triple(HTTP/3) 协议设计、完善的 Benchmark 验收体系、零信任解决方案、Service Mesh架构 等方向持续探索,共同定义下一代云原生微服务体系,为开源社区和企业用户在性能、安全等方面带来收益。 + +本赛事一共包含五道赛题: +* 基于 HTTP/3 的高性能传输协议(Java) +* 自动化的 Dubbo 框架与协议性能基准 Benchmark 机制与平台(语言不限) +* 设计并实现一套零信任安全机制(含 Java/Golang SDK 适配与证书管理) +* 面向云原生的下一代微服务集群监测机制,涵盖Kubernetes、Nacos 等(Golang) +* 一种跨集群Kubernetes、传统VM微服务集群的互通方案与实现(Golang) + +### 1 基于HTTP/3 的高性能传输协议(Java) + +#### 1.1 赛题背景与目标 +本赛题的主要目标是将 Dubbo 中的 triple 协议适配到 HTTP/3 之上,兑现 triple 协议规范中的所有核心能力。 + +关于 Dubbo3 triple 协议使用的相关示例请参考(请注意阅读 README 中链接指向的其他相关示例):[https://github.com/apache/dubbo-samples/tree/master/1-basic](https://github.com/apache/dubbo-samples/tree/master/1-basic),通过运行示例,可以了解当前 triple 协议的功能。 + +以下是 Triple 协议规范:[https://cn.dubbo.apache.org/zh-cn/overview/reference/protocols/triple-spec/](https://cn.dubbo.apache.org/zh-cn/overview/reference/protocols/triple-spec/) + +#### 1.2 赛题说明 + +请基于 Apache Dubbo Java 实现的 3.3 分支进行开发,代码仓库链接如下: +[https://github.com/apache/dubbo/tree/3.3](https://github.com/apache/dubbo/tree/3.3) + +triple 协议相关实现源码: + +- [https://github.com/apache/dubbo/tree/3.2/dubbo-rpc/dubbo-rpc-triple](https://github.com/apache/dubbo/tree/3.2/dubbo-rpc/dubbo-rpc-triple) +- [https://github.com/apache/dubbo/tree/3.3/dubbo-remoting/dubbo-remoting-http12](https://github.com/apache/dubbo/tree/3.3/dubbo-remoting/dubbo-remoting-http12) + +开发者可根据自己的理解修改 Dubbo源码实现,比如在 remoting 层做 http3 适配,赛题实现不受限制,可以依赖如 Netty 等任意网络库或框架。 + +#### 1.3 参考链接 + +- [https://github.com/grpc/proposal/blob/master/G2-http3-protocol.md](https://github.com/grpc/proposal/blob/master/G2-http3-protocol.md) +- [https://devblogs.microsoft.com/dotnet/http-3-support-in-dotnet-6/](https://devblogs.microsoft.com/dotnet/http-3-support-in-dotnet-6/) +- [https://github.com/netty/netty-incubator-codec-http3](https://github.com/netty/netty-incubator-codec-http3) +- [https://webtide.com/jetty-http-3-support/](https://webtide.com/jetty-http-3-support/) + +### 2 自动化的 Dubbo 框架与协议性能基准 Benchmark 机制与平台(语言不限) + +#### 2.1 赛题背景与目标 +作为一款 RPC 框架,Apache Dubbo 内置了两款高性能通信协议: + +- triple 协议,基于 TCP 的高性能通信协议。 +- dubbo 协议,基于 HTTP 的高性能通信协议,支持 Streaming 通信模型。 + +本赛题计划建设的 benchmark 平台理论需具备持任意协议测试的能力,实际产出可以 dubbo、triple 协议为主。 + +#### 2.2 赛题说明 + +- 建设一套支持 dubbo benchmark 验收的机制与流程,如当前有支持 java 语言的 [https://github.com/apache/dubbo-](https://github.com/apache/dubbo-samples)benchmark 可供参考 +- 给出 dubbo、triple 协议的性能指标,以直观可视化的方式展示 +- 找出性能瓶颈点、给出优化建议或实现 + +#### 2.3 参考资料 + +- [https://github.com/benchmark-action/github-action-benchmark](https://github.com/benchmark-action/github-action-benchmark) +- [https://grpc.io/docs/guides/benchmarking/](https://grpc.io/docs/guides/benchmarking/) +- triple协议规范 [https://cn.dubbo.apache.org/zh-cn/overview/reference/protocols/triple-spec/](https://cn.dubbo.apache.org/zh-cn/overview/reference/protocols/triple-spec/) +- dubbo协议规范 [https://cn.dubbo.apache.org/zh-cn/overview/reference/protocols/tcp/](https://cn.dubbo.apache.org/zh-cn/overview/reference/protocols/tcp/) +- 了解 dubbo 的基本使用方式 [https://github.com/apache/dubbo-samples](https://github.com/apache/dubbo-samples) + + +### 3 设计并实现一套零信任安全机制(含Java/Golang SDK 适配与证书管理) +#### 3.1 赛题背景与目标 +本赛题的直接目标是为 Dubbo RPC 数据通信提供 TLS/mTLS 支持,但仅有相应的 API 与底层 tcp 链路是不够的,为了打造一套微服务整体解决方案,我们期望建立如下的一套零信任安全体系: + +![openatom-2024](/imgs/blog/2024/01/openatom/security.png) + +赛题涉及到控制面到数据面(Dubbo SDK)的数据推送,如证书更新、认证规则、鉴权规则等,我们计划在这个推送链路使用 xDS 协议。 + +针对架构设计中的几个核心组件,其主要职责是: + +1. 控制面组件 + 1. 作为 CA 机构负责证书签发与轮转,负责认证/鉴权规则的转换,提供 xDS Server 将证书与规则下发到数据面 + 2. 接收认证/鉴权规则,一套定义良好的认证与鉴权规则,支持控制 TLS/mTLS 行为,如什么场景下启用mTLS等;支持配置符合匹配条件下的认证/鉴权,可通过下文参考链接了解更多内容 + 3. xDS 协议,提供 xDS Server 负责证书与规则的推送。 + +2. 数据面组件(Dubbo SDK) + 1. Dubbo 框架适配 xDS 通道,接收证书与规则 + +#### 3.2 赛题说明 +本赛题是取自 Dubbo 体系的微服务零信任总体方案,以上架构图描述的内容为该总体方案核心目标。 + +本赛题选手可以参与开发的内容分为两部分: + +1. 数据面(Dubbo SDK),此部分为必做内容,即为 Dubbo SDK(Java/Go) 提供 xDS 的安全机制适配支持。如果选手决定不做控制面部分开发,则可以使用任意控制面 xDS Server 如 Istio 等辅助开发,流程与规则亦可直接使用 Istio 等,最终跑通 SDK 整体流程即可。 +2. 控制面,此部分为选做内容,即通过定制 Dubbo 社区提供的控制面实现,实现一整套定制化零信任解决方案。 + +##### 3.2.1 数据面(Dubbo SDK)开发指南: + +- 社区 Dubbo SDK 适配 xDS 的基本代码已经由官方提供,选手可直接在此之上关注安全相关 xDS 内容的进一步解析,并将接收到的证书、规则等适配到 Dubbo 框架内不 +- 选手可以考虑 Dubbo 框架认证鉴权能力的可扩展性。比如为 Dubbo 提供一套通用的认证、鉴权 API,本赛题来自 xDS 控制面的安全源成为其中的一个扩展实现;未来可以扩展其他的如非 xDS 通道的证书来源等。 + +相关源码仓库: + +- Dubbo Java 源码:[https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-xds](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-xds) +- Dubbo Go 源码:[https://github.com/apache/dubbo-go/tree/main/xds](https://github.com/apache/dubbo-go/tree/main/xds) + +##### 3.2.2 控制面开发指南: +控制面的 xDS Server 将由官方社区提供基础实现,选手们可关注安全相关部分的设计与实现。 + +控制面源码仓库:[https://github.com/apache/dubbo-kubernetes](https://github.com/apache/dubbo-kubernetes) + +#### 3.3 参考资料 +总的来说,本赛题要建设的是一套通用的零信任体系,提供以下业界实现作为参考: + +- [https://istio.io/latest/docs/concepts/security/](https://istio.io/latest/docs/concepts/security/) +- [https://github.com/grpc/proposal/blob/master/A29-xds-tls-security.md](https://github.com/grpc/proposal/blob/master/A29-xds-tls-security.md) +- [https://kuma.io/docs/2.5.x/policies/mutual-tls/](https://kuma.io/docs/2.5.x/policies/mutual-tls/) +- [https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol#xds-protocol-delta](https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol#xds-protocol-delta) + + +### 4 面向云原生的下一代微服务集群监测机制,涵盖Kubernetes、Nacos (Golang) + +#### 4.1 赛题背景与目标 +微服务的整体可视化管控一直依赖都是一个非常重要的议题,本赛题的大背景是 Apache Dubbo 社区正在推进的 Dubbo 整体可视化项目,我们计划实现一个可以同时兼容 Zookeeper/Nacos 等传统注册中心、Kubernetes Service、Service Mesh 架构的统一的可视化控制台: + +- 微服务集群数据可视化。包括集群内的应用、服务、示例等基本信息展示。 +- 监控相关。借助 Dubbo SDK 上报到 Prometheus 的 Metrics 数据,控制台通过查询 Prometheus 展示相关监控指标,绘制调用链路图与依赖关系图等。 +- 流量管控。支持流量管控规则,支持规则可视化编辑、预览、下发。 + +##### 4.1.1 总体目标 +相比之前老版本的 Dubbo Admin 实现,我们期望新版本的控制台在部署架构、功能丰富度上都实现全面升级。 + +因此参赛选手可重点关注以下几个方向: + +- 提供一个通用的微服务适配层抽象(如包含 Application、Servcice、Instance 等概念),作为新版控制台的统一数据源,屏蔽底层 Nacos、Kubernetes、Service Mesh 架构的差异。目前官方仓库提供了一个基本参考设计与实现。 +- 设计控制台功能并提供完整实现。目前官方提供了参考交互效果图。 + +从用户 GUI 视角看,如可做菜单设计如下: + +- 首页大盘 +- 资源详情 + - 应用 + - 服务 + - 实例 +- 流量管控 + +#### 4.2 赛题说明 +本赛题官方已经提供了后端适配层的参考实现,同时给出了部分前端交互设计初稿。选手完全可以此为基础进行开发设计,具体评分标准参见官方报名渠道说明。 + +1. 后端: [https://github.com/apache/dubbo-kubernetes/tree/master/pkg/admin](https://github.com/apache/dubbo-kubernetes/tree/master/pkg/admin) + +2. 前端代码框架:https://github.com/apache/dubbo-kubernetes/tree/master/ui-vue3 + +#### 4.3 参考资料 + +- [https://github.com/kiali/kiali](https://github.com/kiali/kiali) +- [https://github.com/codecentric/spring-boot-admin](https://github.com/codecentric/spring-boot-admin) +- [https://github.com/apache/dubbo-admin](https://github.com/apache/dubbo-admin) +- [https://github.com/istio/istio](https://github.com/istio/istio) + +### 5 一种跨集群Kubernetes、传统VM微服务集群的互通方案与实现(Golang) + +#### 5.1 赛题背景与目标 + +在 Apache Dubbo 最新规划中,我们计划完整的支持以下部署架构: + +##### 5.1.1 传统注册中心模式 + +![5-1-vm](/imgs/blog/2024/01/openatom/5-1-vm.png) + +##### 5.1.2 基于 Kubernetes 调度的注册中心模式 + +![5-2-kubernetes](/imgs/blog/2024/01/openatom/5-2-kubernetes.png) + +##### 5.1.3 基于 Kubernetes Service 的 Proxyless Service Mesh 模式 + +![5-3-kubernetes-service](/imgs/blog/2024/01/openatom/5-3-kubernetes-service.png) + +其中,控制面由 Dubbo 社区建设,仓库地址位于:[https://github.com/apache/dubbo-kubernetes](https://github.com/apache/dubbo-kubernetes) + +#### 5.2 赛题解读 +由于网络模型、注册中心等多个层面的原因,以上三种部署架构在很多情况下是相互隔离的,要实现这几个架构间的通信变的非常困难。 + +为了实现多集群地址、路由规则等互通,我们提供了一个跨集群部署的示例架构图,如下所示 + +![5-4-kubernetes-service](/imgs/blog/2024/01/openatom/5-4-multiple-cluster.png) + +其中,红色部分即为跨集群的数据流向,其中红色实现部分为控制面数据流,红色虚线部分为数据面数据流。 + +##### 5.2.1 为什么要跨集群通信那? + +有以下场景可能会用到: + +1. Kubernetes 迁移,之前用的是 Zookeeper 传统注册中心架构,期望迁移到 Kubernetes 集群部署,或者期望使用 kubernetes Service 服务模型 +2. Kubernetes 多集群部署,跨多个 Kubernetes 集群 Dubbo 微服务通信 +3. 混合部署,传统注册中心集群、Kubernetes 集群、Kubernetes Service(Service Mesh)架构混合部署 + +##### 5.2.2 期待交付用户的使用体验 + +1. Kubernetes Service:`dubboctl install --mode=kubernetes --ingress-enabled` +2. Kubernetes:`dubboctl instaqll --mode=universal --ingress-enabled` +3. 传统 VM: + * `dubbo-cp run --registry-address=nacos://xxx`` + * `dubbo-dp run --control-plane=xxx` +4. 跨集群则需要额外部署 global 集群,使用方式与以上类似 + +##### 5.2.1 主要交付内容 +以上图示例架构为例,参赛选手应主要关注: + +1. 控制面、Ingress 的开发与建设(Dubbo SDK 侧无须关注,包括 SDK 与控制面的 xDS 通信,此部分可假设整体已经就绪),包括提供新方案中对于跨集群通信必要的组件支持等。 +2. 跨集群的 global 控制面能力建设 + +Dubbo 官方目前提供了基础控制面实现,包括基于 xds server 的服务发现等内容,可在此基础上继续扩展跨集群方案实现。项目源码:[https://github.com/apache/dubbo-kubernetes](https://github.com/apache/dubbo-kubernetes) + +#### 5.3 参考资料 + +1. [https://istio.io/](https://istio.io/) +2. [https://kuma.io/docs/2.5.x/production/deployment/multi-zone/](https://kuma.io/docs/2.5.x/production/deployment/multi-zone/) + +## 报名方式 + +### 报名链接 + +[开放原子开源基金会官方报名渠道](https://competition.atomgit.com/competitionInfo?id=be48a38bb1daf499bd5c98ac8a3108fd) + +### 答疑群 + +有任何赛题疑问扫码加入以下钉钉群: + +![5-4-kubernetes-service](/imgs/blog/2024/01/openatom/dingding-group.png) + +### 赛题详情海报 + +![openatom-2024](/imgs/blog/2024/01/openatom/openatom-2024.png) \ No newline at end of file diff --git a/content/en/blog/news/ospp-2023-announcement.md b/content/en/blog/news/ospp-2023-announcement.md new file mode 100644 index 000000000000..3f9b4bdb43d1 --- /dev/null +++ b/content/en/blog/news/ospp-2023-announcement.md @@ -0,0 +1,90 @@ +--- +title: "Apache Dubbo 开源之夏 2023,贡献社区赢取 12000 奖金" +linkTitle: "Apache Dubbo开源之夏2023,贡献社区赢取12000奖金" +date: 2023-05-15 +tags: ["新闻动态"] +authors: Dubbo 社区 +description: > + Apache Dubbo开源之夏2023,贡献社区赢取12000奖金。 +--- + +欢迎在校同学们参与Apache Dubbo开源之夏,社区导师手把手让**你的代码被社会广泛复用,来赚取最高12000奖金,可**推荐入职/实习你心意公司,**又拿钱又成长又有价值**,你还等什么呢?报名马上截止,快来参与Apache Dubbo开源之夏。 + +## OSPP 开源之夏是什么? + +开源之夏是由“开源软件供应链点亮计划”发起并长期支持的一项暑期开源活动,旨在鼓励**在校学生**积极参与开源软件的开发维护,促进优秀开源软件社区的蓬勃发展,培养和发掘更多优秀的开发者。 +活动联合国内外各大开源社区,针对重要开源软件的开发与维护提供项目任务,并面向全球高校学生开放报名。 +学生可在本活动中自主选择感兴趣的项目任务进行申请,并在中选后获得该开源项目资深维护者(社区导师)亲自指导的机会,完成项目并贡献给社区后,参与学生还将获得开源之夏**活动奖金**和**结项证书**。 + +# Apache Dubbo 项目简介 + +Apache Dubbo 是国内最具影响力的开源软件项目之一,由阿里巴巴贡献开源,是支撑阿里双十一百万集群、万亿次服务调用的核心框架,目前 Dubbo 已捐献给享誉世界的 Apache 软件基金会 (ASF)。 + +## 参与Apache Dubbo开源之夏条件 + +- 本活动面向年满 18 周岁在校学生。 +- 暑期即将毕业的学生,只要在申请时学生证处在有效期内,就可以提交申请。 +- 海外学生可提供录取通知书、学生卡、在读证明等文件用于证明学生身份。 + +## 参与Apache Dubbo开源之夏,你能获得什么? + +1. **【你的代码被社会广泛复用】**你的代码可能会运行在上万家企业核心业务逻辑中,帮助企业解决问题。 +2. **【赢得最高12000奖金】**奖金总额根据项目难度分为进阶 12000 元、基础 8000 元(注:奖金数额为税前人民币金额) +3. **【社区核心人员辅导快速成长】**只要你报名被选中,每个题目的导师会精心手把手教你融入社区,帮助你完成题目的设计以及最终的落地。 +4. **【推荐入职/实习】**在本次编程之夏项目中表现优秀同学,可推荐入职/实习 你心意的公司工作。 +5. **【额外获得社区礼包】**所有参与本次编程之夏项目的同学,均可获得Apache Dubbo社区大礼包。 + +**百分百有奖品拿哦**,现在唯一的问题是时间不多了,赶紧上车报名,截止报名时间是6月4日,6个核心题目,快点来报名参与Apache Dubbo编程之夏吧。 + +## 课题&报名方式 + +点开Apache Dubbo开源之夏的[链接](https://summer-ospp.ac.cn/org/orgdetail/ab188e59-fab8-468f-bc89-bdc2bd8b5e64?lang=zh) 选择你喜欢的题目: + +- [IDL 管理平台](https://summer-ospp.ac.cn/org/prodetail/23a7f0282?list=org&navpage=org) +- [API 管理平台](https://summer-ospp.ac.cn/org/prodetail/23a7f0286?list=org&navpage=org) +- [基于 Kubernetes 的集成测试体系建设](https://summer-ospp.ac.cn/org/prodetail/23a7f0284?list=org&navpage=org) +- [服务 JSON 序列化兼容性校验](https://summer-ospp.ac.cn/org/prodetail/23a7f0287?list=org&navpage=org) +- [将 Dubbo 工程结构重构为 Gradle 项目](https://summer-ospp.ac.cn/org/prodetail/23a7f0289?list=org&navpage=org) +- [自动化性能测试方案](https://summer-ospp.ac.cn/org/prodetail/23a7f0292?list=org&navpage=org) +- [移除对 jprotoc 的依赖](https://summer-ospp.ac.cn/org/prodetail/23a7f0294?list=org&navpage=org) +- [Node.js HTTP/2 协议实现](https://summer-ospp.ac.cn/org/prodetail/23a7f0520?list=org&navpage=org) +- [实现 Dubbo Rust 的路由模块](https://summer-ospp.ac.cn/org/prodetail/23a7f0553?list=org&navpage=org) + +具体流程请参考 [学生指南](https://summer-ospp.ac.cn/help/student/)。 + +请注意找导师沟通截止流程时间,优先更导师沟通,能帮助你更好的了解题目。 + +为了方便大家报名,我们有以下咨询通道开放,如果对报名、题目、如何撰写 Proposal 有任何疑问,都可以前往咨询: + +1. 扫码关注回复 "Apache Dubbo" 官网微信公众号,回复 “编程之夏” 加入微信沟通群 + + ![qrcode_for_gh_a84d4cf4c871_258 (1).jpg](/imgs/blog/news/ospp-2023-announcement/1684119089728-eae2eb7d-4098-430e-a69e-a3939265e22b.jpeg) + +2. 钉钉群:22895027434(Dubbo 2023 编程之夏群),搜索并加入咨询问题 +3. 发送邮件到 Apache Dubbo 邮件组:dev@dubbo.apache.org + +# 参考资料 + +- Apache Dubbo Github 仓库: + - [Java](http://github.com/apache/dubbo) + - [Go](http://github.com/apache/dubbo-go) + - [Node.js](http://github.com/apache/dubbo-js) + - [Rust](http://github.com/apache/dubbo-rust) + - [Admin](http://github.com/apache/dubbo-admin) + - [更多生态](http://github.com/dubbo/) +- [Apache Dubbo 官网](https://dubbo.apache.org/) +- [开源之夏官网](https://summer-ospp.ac.cn/org/orgdetail/a7f6e2ad-4acc-47f8-9471-4e54b9a166a6?lang=zh) + +为了让同学们更好地了解Apache Dubbo,我们还在观望提供了电子书供大家阅读学习。 + +- [Apache Dubbo 微服务开发从入门到精通](https://cn.dubbo.apache.org/zh-cn/contact/books/) +- [Apache Dubbo3 源码深度解析](https://cn.dubbo.apache.org/zh-cn/contact/books/) + +同时如果同学们对其他领域项目感兴趣,也可以尝试申请,例如: + +- 对于**微服务注册发现和配置管理**有兴趣的同学,可以尝试填报 [Nacos 开源之夏](https://summer-ospp.ac.cn/org/orgdetail/ab188e59-fab8-468f-bc89-bdc2bd8b5e64?lang=zh); +- 对于**微服务分布式事务**有兴趣的同学,可以尝试填报[Seata](https://summer-ospp.ac.cn/org/orgdetail/064c15df-705c-483a-8fc8-02831370db14?lang=zh)开源之夏; +- 对于**微服务框架和RPC框架**有兴趣的同学,可以尝试填报[Spring Cloud Alibaba](https://summer-ospp.ac.cn/org/orgdetail/41d68399-ed48-4d6d-9d4d-3ff4128dc132?lang=zh) 和 [Dubbo](https://summer-ospp.ac.cn/org/orgdetail/a7f6e2ad-4acc-47f8-9471-4e54b9a166a6?lang=zh) 开源之夏; +- 对于**云原生网关**有兴趣的同学,可以尝试填报[Higress](https://higress.io/zh-cn/blog/ospp-2023) 开源之夏; +- 对于**分布式高可用防护**有兴趣的同学,可以尝试填报[Sentinel](https://summer-ospp.ac.cn/org/orgdetail/5e879522-bd90-4a8b-bf8b-b11aea48626b?lang=zh) 开源之夏; +- 对于**微服务治理**有兴趣的同学,可以尝试填报[OpenSergo](https://summer-ospp.ac.cn/org/orgdetail/aaff4eec-11b1-4375-997d-5eea8f51762b?lang=zh) 开源之夏。 diff --git a/content/en/blog/news/release-roadmap.md b/content/en/blog/news/release-roadmap.md new file mode 100644 index 000000000000..8d1bd6db7c35 --- /dev/null +++ b/content/en/blog/news/release-roadmap.md @@ -0,0 +1,69 @@ +--- +title: "聚焦稳定性,Dubbo Java 发版规划公布" +linkTitle: "Dubbo Java 发版规划" +date: 2022-10-22 +tags: ["新闻动态"] +weight: 10 +description: > + 聚焦稳定性,Dubbo 发版规划公布 +--- + +## Dubbo 简介 +Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。 + +## 我应该如何选择版本? +对于这个问题,一直以来 Dubbo 都没有很好地去回答。究其原因保证所有版本的稳定性是一件非常有挑战的事情。比如在 Dubbo 2.7 的一些版本中,出现了一些前后不兼容的问题,给一些用户升级带来了困扰。为此,很多用户从保障稳定性的视角出发,选择了更保守的策略,即生产环境采用被采用最多的版本,此后就不再更新,避免升级过程中出现意外。 + +但是这种方式无疑是有问题的,一方面这将导致永远无法用上社区新的功能,得到技术演进的红利;另一方面,对于安全漏洞和带来不稳定因素的 bug 等已知问题如果不升级永远会存在,久而久之将给应用带来巨大的风险,很有可能导致严重的安全生产事故。 + +因此,为了更好地回答这个问题,Dubbo 制定了未来的版本迭代规划,明确版本的稳定性维护机制,提升开发者使用 Dubbo 的信心。 + +## 现状 +在此前,Dubbo 总共维护了 2.6.x、2.7.x 以及 3.x 三个大版本,其中 2.7.x 为捐献进入 Apache 基金会之后的版本。 + +2.6.x 在去年已经宣布生命周期结束(EOL)了,而 2.7.x 累计维护了四年的时间了。这四年的时间里,2.7.x 版本经历了多次大的修改,如 2.7.3 版本中对 Nacos 的注册方式进行了修改、2.7.6 版本中添加了应用级服务发现、2.7.9 版本中对应用级服务发现进行大的重构等。 + +这些修改都对 2.7.x 版本的稳定性带来了巨大的风险隐患,导致 2.7.x 中很多版本或多或少存在不同的问题,用户无法选择一个最稳定的版本进行使用。 + +因此,我们希望在 3.x 版本中将这种不稳定的情况通过发版机制给收敛掉,提高 Dubbo 版本的稳定性。 + +## 未来总体规划 +在接下来,Dubbo 将以每 6 个月为一个周期,对每个版本包括了新功能合入、稳定性维护以及安全漏洞修复三个大方向的内容。 + +新功能合入是指将 Dubbo 开发过程中所有新的特性、性能优化、破坏性修改都会被合入的行为。由于新功能是需要一段时间迭代稳定的,所以新功能的合入会给对应版本带来不稳定因素,因此只能在每个版本最开始的时候进行。 + +稳定性维护是指修复**已有**功能的非预期行为,进一步提升版本的稳定性。特别的,对于一些大的问题修复,如功能需要整体重构的,或者回带来破坏性影响的提交将被视为新功能提交,执行新功能合入的流程。避免因为修复一个问题而来带更多问题的严重后果。 + +安全维护是指修复使用中的安全风险问题,这一块主要是解决来自白帽子提交的漏洞问题。 + +新功能合入在每个版本中会持续 **6** 个月,稳定性维护在每个版本中会持续 **12** 个月,安全维护在每个版本中会持续 **18** 个月。 + +因此,从整体迭代规划来看,每 6 个月 Dubbo 会开始一个新的版本迭代,与之同时的,也会有一个版本宣布生命周期结束(EOL)。 + +## 逐版本维护规划 + +![image.png](/imgs/blog/release/release-roadmap.png) + +上图为具体到每个版本在每个时间点的维护状态图。 + +对于 Dubbo 2.7 以及 3.0 版本,目前已经进入了安全维护阶段,将在 2023 年 3 月宣布版本维护周期结束。 + +对于 Dubbo 3.1 版本,目前已经是稳定性维护阶段,如前一小节所述,目前只会继续合入和稳定性修改的修改。处于稳定性维护阶段的版本也是社区推荐生产使用的最新版本。稳定性维护工作将持续到 2023 年 3 月,在此之后会有持续 6 个月的安全维护阶段,最终在 2023 年 9 月结束其版本的生命周期。 + +对于 Dubbo 3.2 版本,目前仍处在新功能合入的阶段,发布的是 beta 版本。此阶段适合一些尝鲜使用,版本稳定性相较于已经进入仅稳定性维护阶段的版本稍欠。在 2023 年 3 月,Dubbo 3.2 将结束新功能合入周期,进行充分的稳定性验证,并正式发布生产可用的 GA 版本。此后在 2023 年 9 月之前会进行稳定性的维护,在 2024 年 3 月结束版本的生命周期。 + +对于 Dubbo 3.3 版本,将在 2023 年 3 月紧随着 3.2 版本结束新功能合入阶段后正式开始开发。因此,Dubbo 3.3 版本的第一个 beta release 也将会在 2023 年 3 月发布。同样的,经过 6 个月的新功能合入阶段之后,Dubbo 3.3 版本将会在 2023 年 9 月正式发布生产可用 GA 版本,同时进入稳定性维护阶段。之后在 2024 年 3 月进入安全维护阶段,在 2024 年 9 月结束版本的生命周期。 + +## 总结 + +对于绝大多数的生产用户,我们建议使用**当前处于仅稳定性维护阶段的版本的最新小版本**。如在 2022 年 9 月至 2023 年 3 月这段时间,Dubbo 3.1 是处于仅稳定性维护阶段的,因此首选 Dubbo 3.1 版本。而对于如 3.1.0、3.1.1、3.1.2 等的 Dubbo 3.1.x 的多个小版本,我们建议直接使用最新的小版本。由于各个小版本之间仅包含稳定性修复,所以越往后的版本是越稳定的。 + +对于愿意尝鲜、体验新功能的用户,可以直接基于最新的开发版本进行测试。即使是开发版本,Dubbo 也有一整套的质量保障机制,如果使用过程中遇到问题,欢迎向社区提交反馈。 + +目前,阿里巴巴集团已经基于 Dubbo 3.0 的稳定版本完美支撑了整个核心电商今年双十一的所有调用,现在也正在升级到 Dubbo 3.1 这个最新的稳定版本上来。我们欢迎更多的用户一起升级到 Dubbo 3.1 版本上,在升级过程中可以参考官网给出的升级指南,遇到任何问题也可以通过 issue、微信群、钉钉群及时反馈社区,我们将尽全力协助。 + +## 更多 + +在版本规划的方向上,除了本次发布的迭代线路图,Dubbo 还将通过一系列的机制保障用户的使用体验是连续的、稳定的。在大版本升级方面,Dubbo 将建设**完善的版本升级指南**,如 Dubbo 3.1 版本升级到 Dubbo 3.2 版本中的重大修改点,让用户在升级的时候能够清晰的了解其中的风险点,更好的规划升级节奏。 + +此外,对于目前人在大范围使用的 Dubbo 2.7 版本,在近期 Dubbo 社区也将推出**针对 Dubbo 2.7 版本的升级的指南与工具**,通过工程化的方式让所有的 Dubbo 2.7 用户都可以提前查出所有的版本差异点,平滑升级到 Dubbo 3 上来。 diff --git a/content/en/blog/news/releases/2.7.14.md b/content/en/blog/news/releases/2.7.14.md new file mode 100644 index 000000000000..963fa8f73490 --- /dev/null +++ b/content/en/blog/news/releases/2.7.14.md @@ -0,0 +1,36 @@ +--- +title: "Dubbo Java 2.7.14 发版公告" +linkTitle: "dubbo-java 2.7.14" +weight: 50 +tags: ["Release Notes"] +date: 2020-05-18 +description: > + Apache Dubbo 2.7.14 发版公告 +--- + +## 变动项 + +- 为 ServiceDiscovery 增加动态配置中心的覆盖规则。(#8389) +- 修复当 mock 参数中包含 ':' 或者 '=' 符号时无法正常使用的问题。(#8379) +- 修复 zone 参数对 ZoneAwareClusterInvoker 配置无法生效的问题。(#8521) +- 为序列化白名单检查增加开关,默认为 true。(#8537) +- 修复当请求超时时序列化检查的空指针异常。(#8587) +- 修复 NetUtils.ignoreNetworkInterface 无法处理网卡中包含 '(' 符号的问题。(#8629) +- 统一获取本地地址的方式。(#8679) +- 修复当重试参数为0,依旧会重试1次的问题。(#8743) +- 当清除未使用的 invoker 时,立即关闭客户端。(#8756) +- 修复 destroy 方法以及 doOverrideIfNecessary 中的异常。(#8683) +- DefaultFuture.closeChannel 根据日志级别选择是否打印请求的详细数据。(#8778) +- 使用 MapUtils 替换 AttachmentsAdapter(#8772) + +## Maven依赖变化 + +- netty4: 4.1.51.Final -> 4.1.66.Final +- netty4_ssl: 2.0.39.Final -> 2.0.40.Final +- http_client: 4.5.3 -> 4.5.13 +- jetty: 9.4.11.v20180605 -> 9.4.43.v20210629 +- apollo_client: 1.1.1 -> 1.8.0 +- tomcat_embed: 8.5.31-> 9.0.48 +- commons_io: 2.6 -> 2.7 +- curator: 5.0.0 -> 5.1.0 +- hessian_lite: 3.2.8 -> 3.2.11 \ No newline at end of file diff --git a/content/en/blog/news/releases/2.7.5.md b/content/en/blog/news/releases/2.7.5.md new file mode 100644 index 000000000000..aa30ea61480e --- /dev/null +++ b/content/en/blog/news/releases/2.7.5.md @@ -0,0 +1,282 @@ +--- +title: "Dubbo Java 2.7.5 功能解析" +linkTitle: "dubbo-java 2.7.5" +date: 2020-05-18 +tags: ["Release Notes"] +description: > + 2.7.5 发布,及其功能解析 +--- + + +近日,备受瞩目的 Dubbo 2.7.5 版本正式发布,在 2.7.5 版本中,Dubbo 引入了很多新的特性、对现有的很多功能做了增强、同时在性能上也有了非常大的提升,这个版本无论对 Dubbo 社区亦或是开发者来说,都将是一个里程碑式的版本。 + +* 应用粒度服务注册【beta】 +* HTTP/2 (gRPC) 协议支持 +* Protobuf 支持 +* 性能优化,调用链路性能提升 30% +* 支持 TLS 安全传输链路 +* 优化的消费端线程模型 +* 新增更适应多集群部署场景的负载均衡策略 +* 全新的应用开发 API (兼容老版本应用)【beta】 +* 其他一些功能增强与 bugfix + +首先,从服务发现上,新版本突破以往基于接口粒度的模型,引入了全新的基于应用粒度的服务发现机制 - 服务自省,虽然该机制当前仍处于 beta 阶段,但对于 Dubbo 向整个微服务云原生体系靠齐,都打下了非常好的基础;得益于紧凑的协议设计和代码实现上的优化,Dubbo 一直以来都具有较好的性能表现,在 2.7.5 版本中,性能上有了进一步的提升,根据来自官方维护团队的压测,新版本在调用链路上性能提升达到 30%;云原生微服务时代,多语言需求变得越来越普遍,协议的通用性和穿透性对于构建打通前后端的整套微服务体系也变得非常关键,Dubbo 通过实现 gRPC 协议实现了对 HTTP/2 协议的支持,同时增加了与 Protobuf 的结合。 + +## 1. 应用粒度服务注册【beta】 + +从 Java 实现版本的角度来说,Dubbo 是一个面向接口代理的服务开发框架,服务定义、服务发布以及服务引用都是基于接口,服务治理层面包括服务发现、各种规则定义也都是基于接口定义的,基于接口可以说是 Dubbo 的一大优势,比如向开发者屏蔽了远程调用细节、治理粒度更精细等。但基于接口的服务定义同时也存在一些问题,如服务,与业界通用的微服务体系等。 + +![servicediscovery-old.png](/imgs/blog/servicediscovery-old.png) + +针对以上问题,2.7.5 版本引入了一种新的服务定义/治理机制:**服务自省**,简单来说这是一种基于应用粒度的服务治理方案。一个实例只向注册中心注册一条记录,彻底解决服务推送性能瓶颈,同时由于这样的模型与主流微服务体系如 SpringCloud、K8S 等天然是对等的,因此为 Dubbo 解决和此类异构体系间的互联互通清除了障碍。有兴趣进一步了解 Dubbo 服务自省机制如何解决异构微服务体系互联互通问题的,可具体参考我们之前的文章解析《Dubbo 如何成为联通异构微服务体系的最佳服务开发框架》。 + +以下是服务自省机制的基本工作原理图。 + +![servicediscovery-new.png](/imgs/blog/servicediscovery-new.png) + +要了解更多关于服务自省工作原理的细节,请参与官方文档及后续文章。 + +服务自省与当前已有的机制之间可以说是互补的关系,Dubbo 框架会继续保持接口粒度的服务治理的优势,实现接口和应用两个粒度互为补充的局面,兼顾性能、灵活性和通用性,力争使 Dubbo 成为微服务开发的最佳框架。 + +## 2. HTTP/2 (gRPC) 协议支持 + +Dubbo RPC 协议是构建在 TCP 之上,这有很多优势也有一些缺点,缺点比如通用性、协议穿透性不强,对多语言实现不够友好等。HTTP/2 由于其标准 HTTP 协议的属性,无疑将具有更好的通用性,现在或将来在各层网络设备上肯定都会得到很好的支持,gRPC 之所以选在 HTTP/2 作为传输层载体很大程度上也是因为这个因素。当前 gRPC 在云原生、Mesh 等体系下的认可度和采用度逐步提升,俨然有成为 RPC 协议传输标准的趋势,Dubbo 和 gRPC 在协议层面是对等竞争的,但是在框架实现上却各有侧重,Dubbo 无疑有更丰富的服务开发和治理体验 。 + +Dubbo 支持 gRPC 协议带来的直观好处有: + +* 正式支持基于 HTTP/2 的远程通信,在协议通用性和穿透性上进一步提升。 +* 支持跨进程的 Stream 流式通信,支持 Reactive 风格的 RPC 编程。 +* 解决了 gRPC 框架难以直接用于微服务开发的问题,将其纳入 Dubbo 的服务治理体系。 +* 为联通组织内部已有的 gRPC 或多语言体系提供支持。 + +2.7.5 版本开始,gRPC (HTTP/2) 成为 Dubbo 协议体系中的一等公民,对于有需求的开发者完全可以在 Dubbo 开发的微服务体系中启用 gRPC 协议,而不必束缚在 Dubbo 协议自身上,关于这点我们在《Dubbo 如何成为联通异构微服务体系的最佳服务开发框架》一文中也有类似的观点表述。 + +关于 Dubbo 中如何开发 grpc (HTTP/2) 服务的细节,请参考文章《Dubbo 在跨语言与协议穿透性等方面的探索》,关于如何开启 TLS 和使用 Reactive RPC 编程,请参见示例。另外,Dubbo 的 go 版本目前同样也提供了对 gRPC 协议对等的支持,具体请关注 dubbogo 社区的发版计划。 + +## 3. Protobuf 支持 + +支持 Protobuf 更多的是从解决 Dubbo 跨语言易用性的角度考虑的。 + +跨语言的服务开发涉及到多个方面,从服务定义、RPC 协议到序列化协议都要做到语言中立,同时还针对每种语言有对应的 SDK 实现。虽然得益于社区的贡献,现在 Dubbo 在多语言 SDK 实现上逐步有了起色,已经提供了包括 Java, Go, PHP, C#, Python, NodeJs, C 等版本的客户端或全量实现版本,但在以上提到的跨语言友好性方面,以上三点还是有很多可改进之处。 + + 协议上 2.7.5 版本支持了 gRPC,而关于服务定义与序列化,Protobuf 则提供了很好的解决方案。 + +* 服务定义。当前 Dubbo 的服务定义和具体的编程语言绑定,没有提供一种语言中立的服务描述格式,比如 Java 就是定义 Interface 接口,到了其他语言又得重新以另外的格式定义一遍。因此 Dubbo 通过支持 Protobuf 实现了语言中立的服务定义。 +* 序列化。Dubbo 当前支持的序列化包括 Json、Hessian2、Kryo、FST、Java 等,而这其中支持跨语言的只有 Json、Hessian2,通用的 Json 有固有的性能问题,而 Hessian2 无论在效率还是多语言 SDK 方面都有所欠缺。为此,Dubbo 通过支持 Protobuf 序列化来提供更高效、易用的跨语言序列化方案。 + +日后,不论我们使用什么语言版本来开发 Dubbo 服务,都可以直接使用 IDL 定义如下服务,具体请参见示例 + +```idl +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.dubbo.demo"; +option java_outer_classname = "DemoServiceProto"; +option objc_class_prefix = "DEMOSRV"; + +package demoservice; + +// The demo service definition. +service DemoService { + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} +``` + +## 4. 性能优化 + +### 4.1 调用链路优化 + +2.7.5 版本对整个调用链路做了全面的优化,根据压测结果显示,总体 QPS 性能提升将近 30%,同时也减少了调用过程中的内存分配开销。其中一个值得提及的设计点是 2.7.5 引入了 Servicerepository 的概念,在服务注册阶段提前生成 ServiceDescriptor 和 MethodDescriptor,以减少 RPC 调用阶段计算 Service 元信息带来的资源消耗。 + +### 4.2 消费端线程池模型优化 + +对 2.7.5 版本之前的 Dubbo 应用,尤其是一些消费端应用,当面临需要消费大量服务且并发数比较大的大流量场景时(典型如网关类场景),经常会出现消费端线程数分配过多的问题,具体问题讨论可参见以下 issue : + +https://github.com/apache/dubbo/issues/2013 + +改进后的消费端线程池模型,通过复用业务端被阻塞的线程,很好的解决了这个问题。 + +**老的线程池模型** + +![消费端线程池.png](/imgs/blog/consumer-threadpool0.png) + +我们重点关注 Consumer 部分: + +1. 业务线程发出请求,拿到一个 Future 实例。 +2. 业务线程紧接着调用 future.get 阻塞等待业务结果返回。 +3. 当业务数据返回后,交由独立的 Consumer 端线程池进行反序列化等处理,并调用 future.set 将反序列化后的业务结果置回。 +4. 业务线程拿到结果直接返回 + + + +**2.7.5 版本引入的线程池模型** + +![消费端线程池新.png](/imgs/blog/consumer-threadpool1.png) + +1. 业务线程发出请求,拿到一个 Future 实例。 +2. 在调用 future.get() 之前,先调用 ThreadlessExecutor.wait(),wait 会使业务线程在一个阻塞队列上等待,直到队列中被加入元素。 +3. 当业务数据返回后,生成一个 Runnable Task 并放入 ThreadlessExecutor 队列 +4. 业务线程将 Task 取出并在本线程中执行:反序列化业务数据并 set 到 Future。 +5. 业务线程拿到结果直接返回 + +这样,相比于老的线程池模型,由业务线程自己负责监测并解析返回结果,免去了额外的消费端线程池开销。 + +关于性能优化,在接下来的版本中将会持续推进,主要从以下两个方面入手: + +1. RPC 调用链路。目前能看到的点包括:进一步减少执行链路的内存分配、在保证协议兼容性的前提下提高协议传输效率、提高 Filter、Router 等计算效率。 +2. 服务治理链路。进一步减少地址推送、服务治理规则推送等造成的内存、cpu 资源消耗。 + +## 5. TLS 安全传输链路 + +2.7.5 版本在传输链路的安全性上做了很多工作,对于内置的 Dubbo Netty Server 和新引入的 gRPC 协议都提供了基于 TLS 的安全链路传输机制。 + +TLS 的配置都有统一的入口,如下所示: + +**Provider 端** + +```java +SslConfig sslConfig = new SslConfig(); +sslConfig.setServerKeyCertChainPath("path to cert"); +sslConfig.setServerPrivateKeyPath(args[1]); +// 如果开启双向 cert 认证 +if (mutualTls) { + sslConfig.setServerTrustCertCollectionPath(args[2]); +} + +ProtocolConfig protocolConfig = new ProtocolConfig("dubbo/grpc"); +protocolConfig.setSslEnabled(true); +``` + + + +**Consumer 端** + +```java +if (!mutualTls) {} + sslConfig.setClientTrustCertCollectionPath(args[0]); +} else { + sslConfig.setClientTrustCertCollectionPath(args[0]); + sslConfig.setClientKeyCertChainPath(args[1]); + sslConfig.setClientPrivateKeyPath(args[2]); +} +``` + +为尽可能保证应用启动的灵活性,TLS Cert 的指定还能通过 -D 参数或环境变量等方式来在启动阶段根据部署环境动态指定,具体请参见 Dubbo 配置读取规则与 TLS 示例 + +Dubbo 配置读取规则:/zh-cn/docs/user/configuration/configuration-load-process.html + +TLS 示例:https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-ssl + +> 如果要使用的是 gRPC 协议,在开启 TLS 时会使用到协议协商机制,因此必须使用支持 ALPN 机制的 Provider,推荐使用的是 netty-tcnative,具体可参见 gRPC Java 社区的总结: https://github.com/grpc/grpc-java/blob/master/SECURITY.md + +在服务调用的安全性上,Dubbo 在后续的版本中会持续投入,其中服务发现/调用的鉴权机制预计在接下来的版本中就会和大家见面。 + +## 6. Bootstrap API【beta】 + +在上面讲《服务自省》时,我们提到了 Dubbo 面向接口的设计,面向接口编程、面向接口做服务发现和服务治理。在引入应用粒度服务发现的同时,2.7.5 版本对编程入口也做了优化,在兼容老版本 API 的同时,新增了新的面向应用的编程接口 - DubboBootstrap。 + +以面向 Dubbo API 编程为例,以前我们要这么写: + +```java +ServiceConfig service1 = new ServiceConfig<>(); +service1.setApplication(new ApplicationConfig("first-dubbo-provider")); +service1.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181")); +service1.export(); + +ServiceConfig service2 = new ServiceConfig<>(); +service2.setApplication(new ApplicationConfig("first-dubbo-provider")); +service2.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181")); +service2.export(); + +...... +``` + +ApplicationConfig、RegistryConfig、ProtocolConfig 等全局性的配置要在每个服务上去配置;并且从 Dubbo 框架的角度,由于缺少一个统一的 Server 入口,一些实例级别的配置如 ShutdownHook、ApplicationListener、应用级服务治理组件等都缺少一个加载驱动点。 + +在引入 DubboBootstrap 后,新的编程模型变得更简单,并且也为解决了缺少实例级启动入口的问题 + +```java +ProtocolConfig protocolConfig = new ProtocolConfig("grpc"); +protocolConfig.setSslEnabled(true); + +SslConfig sslConfig = new SslConfig(); +sslConfig.setXxxCert(...); + +DubboBootstrap bootstrap = DubboBootstrap.getInstance(); +bootstrap.application(new ApplicationConfig("ssl-provider")) + .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) + .protocol(protocolConfig) + .ssl(sslConfig); + +ServiceConfig service1 = new ServiceConfig<>(); +ServiceConfig service2 = new ServiceConfig<>(); + +bootstrap.service(service1).service(service2); +bootstrap.start(); +``` + +## 7. 多注册中心集群负载均衡 + +对于多注册中心订阅的场景,选址时的多了一层注册中心集群间的负载均衡: + +![cluster-lb.png](/imgs/blog/cluster-lb.png) + +在 Cluster Invoker 这一级,我们支持的选址策略有(2.7.5+ 版本,具体使用请参见文档): + +* 指定优先级 + + ```xml + + + ``` + +* 同 zone 优先 + + ```xml + + + ``` + +* 权重轮询 + + ```xml + + + + ``` + +* 默认,stick to 任意可用 + +>关于多注册中心订阅模型,Dubbo 同时也提供了 Multi-Registry 合并的解决思路,欢迎参与到以下 PR 的讨论中: https://github.com/apache/dubbo/issues/5399 + +## 8. 其他功能增强 + +* 新增地址变更事件通知接口,方便业务侧感知地址变化 + +* 新增外围配置加载入口,方便开发者在启动阶段定制服务启动参数 + +* config 模块重构 + +* parameters 扩展配置增强 +* 其他一些 Bugfix + +从 Dubbo 框架自身的角度来说,2.7.5 版本也做了很多的重构与优化(比如说 config 模块的重构),这些改动对于使用者来说并无感知的,但是从优化整个 Dubbo 代码内部结构的角度来说,这些改动对后续的功能开发与新机制的引入是一个很好的铺垫。 + +## 9. 总结与展望 + +在后续的版本中,Dubbo 会持续快速的优化与迭代,主要从以下几个方面发力: + +* 继续探索服务自省成为 Dubbo 主推的服务治理模型。 +* 对于企业用户关心的微服务解决方案场景,会持续推进框架的演进,包括当前正在开发的配置、服务鉴权机制、熔断等功能。后续还会尝试联合社区推动周边配套设施如网关、治理平台 Admin 等的建设,非常期待社区能踊跃参与到此部分的建设中。 +* 性能优化上。主要从两个方面着手,一是调用链路的持续优化,同时继续探索新的更通用的 RPC 协议;另一方面是在服务治理推送机制上的优化,以进一步提高 Dubbo 在大规模服务地址推送场景下的表现。 +* 云原生方向。接下来的版本将重点探索,1. 如何更好的支持 Dubbo 在 Kubernetes 上的部署和服务治理;2. 对于混合部署的场景,如传统 VM 和 K8S 体系混合部署、SDK Dubbo 与 Mesh 混合部署的场景,如何提供更好的支持以实现混部场景的长期共存或迁移。 diff --git a/content/en/blog/news/releases/3.0.1.md b/content/en/blog/news/releases/3.0.1.md new file mode 100644 index 000000000000..c4d0ddb4e2f6 --- /dev/null +++ b/content/en/blog/news/releases/3.0.1.md @@ -0,0 +1,39 @@ +--- +title: "Dubbo Java 3.0.1 发版公告" +linkTitle: "dubbo-ava 3.0.1" +date: 2021-07-02 +tags: ["Release Notes"] +description: > + Apache Dubbo 3.0.1 发版公告 +--- + +## 优化 +- 重构服务自省映射关系,支持地址迁移时直接配置上游应用名 +- 为 Spring 扫描添加缓存 +- 优化配置覆盖逻辑 +- 支持 Servlet 环境下控制 Dubbo 生命周期 +- 添加 ServiceListener 用于监听 ServiceConfig +- 优化方法回调参数设置 + +## Bug 修复 +- 启用强制校验 +- 更正多注册中心情况下,一个注册中心启动时无地址就销毁的逻辑 +- 移除冗余的日志输出 +- 忽略无效的 MetadataReportConfig +- 修复消费端启动时 NPE 的情况 +- 修复若干和低版本兼容问题 +- 修复若干应用级服务发现逻辑存在的问题 +- 优化地址迁移规则,支持应用级地址重订阅 +- 修复 MetadataInfo 存在 NPE 的情况 +- 修复应用级注册到注册中心的实例信息被错误覆盖的问题 + +## 代码质量提升 + +感谢以下提高 Apache Dubbo 的稳定性的贡献。 + +[#8043](https://github.com/apache/dubbo/pull/8043), +[#8044](https://github.com/apache/dubbo/pull/8044), +[#8048](https://github.com/apache/dubbo/pull/8048), +[#8071](https://github.com/apache/dubbo/pull/8071), +[#8119](https://github.com/apache/dubbo/pull/8119), +[#8132](https://github.com/apache/dubbo/pull/8132) \ No newline at end of file diff --git a/content/en/blog/news/releases/3.0.2.1.md b/content/en/blog/news/releases/3.0.2.1.md new file mode 100644 index 000000000000..401cc7954758 --- /dev/null +++ b/content/en/blog/news/releases/3.0.2.1.md @@ -0,0 +1,17 @@ +--- +title: "Dubbo Java 3.0.2.1 发版公告" +linkTitle: "dubbo-java 3.0.2.1" +date: 2021-08-23 +tags: ["Release Notes"] +description: > + Apache Dubbo 3.0.2.1 发版公告 +--- + +这是 3.0.2 的错误修正版本。 +除了以下更改外,与版本 3.0.2 完全相同。 + +## Bug 修复 + +- 修复 nacos group 在消费者端不生效的问题 (#8533) +- 修复请求超时时序列化检查的 NPE (#8547) +- 兼容使用 dubbo-all 时未导入 farbic-io 包的问题 (#8546) diff --git a/content/en/blog/news/releases/3.0.2.md b/content/en/blog/news/releases/3.0.2.md new file mode 100644 index 000000000000..d1a59c164237 --- /dev/null +++ b/content/en/blog/news/releases/3.0.2.md @@ -0,0 +1,134 @@ +--- +title: "Dubbo Java 3.0.2 发版公告" +linkTitle: "dubbo-java 3.0.2" +weight: 10 +date: 2021-07-18 +tags: ["Release Notes"] +description: > + Apache Dubbo 3.0.2 发版公告 +--- + +## 新特性 +- 支持通过 @DubboService 注解暴露泛化服务 +- 元数据中心xml格式的配置支持 protocol 和 port 属性 +- 兼容 curator5 以上的版本 +- 点对点调用支持*通配符进行匹配, 一个提供者地址可对应多个接口 +- 为应用级别的服务发现增加动态配置去进行规则覆盖 +- 对提供者测的动态配置覆盖规则提供开关,可以使提供者无视动态配置,不重新暴露 +- 支持 native image +- 提供取消执行 shutdown hook 的开关 +- 支持 Kubernetes Mesh 的服务治理规则 +- Netty 连接支持 SSL 配置 + +## Bug 修复 +- DubboBootStrap start 重复调用后,动态配置被覆盖 +- 动态配置规则被删除后,依然生效 +- triple 协议在暴露时会抛出空指针异常 +- ConfigCenterConfig.setAddress 方法会覆盖掉 username 属性 +- DefaultFuture.closeChannel 会销毁掉消费端测的线程池 +- TripleClientHandler.writeRequest 抛出空指针异常 +- 解析3.0迁移规则异常时会抛出空指针异常 +- Activated Extensions 的顺序性问题 +- URLAddress.parse 方法在解析 ipv6 地址时存在问题 +- 用户自定义的参数在 properties 配置中不生效 +- 同时使用 API 模式和 Spring 模式配置时属性,Config Id 存在覆盖问题 +- 应用级别服务发现在启动时不生效 +- Nacos 注册中心无法动态感知提供者的数量变化 +- ${dubbo.application} 在 xml 文件中无法被 spring 的 placeholder 规则给解析替换 +- 获取实例参数的顺序问题,先去获取了实例级别参数,再去获取接口级别参数 +- 当 DubboConfigBeanInitializer 不存在时,注册应用启动监听器会抛出异常 +- Mock 时 参数中包含 ':' 或者 '=' 字符时,不生效 +- 删除 Mesh 规则时空指针异常 + +## 优化 +- 抓住 RemovalTask 的异常,保证信号量能够释放 +- 通过 唯一 service name 检查 ReferenceConfig/ServiceConfig 是否重复 +- 优化生成随机数的性能 +- 如果用户使用接口级别去做服务发现,不发布应用与接口的映射数据到元数据中心 +- 使用 StringBuilder#append(Char) 提升性能 +- 保证 GRPC 编译的类文件中接口的顺序 +- 优化 reference bean 的占位符解析 +- MergeableClusterInvoker 中使用 CompletableFuture#get(long, TimeUnit) 去提升性能 +- 内置服务 MetadataService 不延迟暴露 +- 优化 ConfigBean 和 Bootstrap 的启动逻辑 +- 优化 Config 检查是否重复的逻辑 +- 使用 Ring 数据结构去进行注册通知 +- 优化动态配置的初始化逻辑 +- ConfigManager 使用 ConcurrentHashMap 去移除锁逻辑,提升 equals 和 toString 性能 +- 优化 MetadataInfo equals 方法 以及 Instance Listener +- 优化异步 export/refer 逻辑 +- 使用 TreeSet 数据结构保证应用级别服务发现时应用名称的顺序一致 +- RegistryNotifier 的第一个十次通知不延迟 +- dubbo-compile 编译使用新的格式生成 stub +- Mesh 服务治理规则在动态配置中心的分组和其他规则分组统一,由 DEFAULT_GROUP 改成 dubbo +- 使用 nacos 用作注册中心时,可以在注册中心地址中使用参数来改变在 nacos 中的分组 +- 计算 ServiceInfo 的 reversion 时,移除运行时参数,避免生成多个 reversion +- Nacos 注册中心抛出异常时,将异常封装称 RpcException 抛出 +- 禁止动态配置中心对一些权限参数进行动态修改 +- 优化 Config Bean 的初始化流程,并兼容 spring 3.x/4.1.x +- Bootstrap.start 方法可重入,暴露或引用新的服务 +- 将 org.apache.dubbo 包中的类默认添加到白名单中 +- 保证生成的 Config 的 Id 唯一,并检查 Config 是否之前存在 +- Javaassist 兼容改变 override 声明字段 +- 重构解码时的检查逻辑,当找不到 path, version 对应的提供者是,抛出异常 +- 当 ApplicationModel 为 null 时,兼容 adaptive extensions + +## 代码质量提升 + +感谢以下提高 Apache Dubbo 的稳定性的贡献。 + +[#8111](https://github.com/apache/dubbo/pull/8111), +[#8147](https://github.com/apache/dubbo/pull/8147), +[#8164](https://github.com/apache/dubbo/pull/8164), +[#8177](https://github.com/apache/dubbo/pull/8177), +[#8180](https://github.com/apache/dubbo/pull/8180), +[#8161](https://github.com/apache/dubbo/pull/8161), +[#8183](https://github.com/apache/dubbo/pull/8183), +[#8205](https://github.com/apache/dubbo/pull/8205), +[#8173](https://github.com/apache/dubbo/pull/8173), +[#8219](https://github.com/apache/dubbo/pull/8219), +[#8228](https://github.com/apache/dubbo/pull/8228), +[#8232](https://github.com/apache/dubbo/pull/8232), +[#8230](https://github.com/apache/dubbo/pull/8230), +[#8236](https://github.com/apache/dubbo/pull/8236), +[#8260](https://github.com/apache/dubbo/pull/8260), +[#8262](https://github.com/apache/dubbo/pull/8262), +[#8252](https://github.com/apache/dubbo/pull/8252), +[#8246](https://github.com/apache/dubbo/pull/8246), +[#8208](https://github.com/apache/dubbo/pull/8208), +[#8278](https://github.com/apache/dubbo/pull/8278), +[#8267](https://github.com/apache/dubbo/pull/8267), +[#8277](https://github.com/apache/dubbo/pull/8277), +[#8291](https://github.com/apache/dubbo/pull/8291), +[#8296](https://github.com/apache/dubbo/pull/8296), +[#8302](https://github.com/apache/dubbo/pull/8302), +[#8175](https://github.com/apache/dubbo/pull/8175), +[#8319](https://github.com/apache/dubbo/pull/8319), +[#8309](https://github.com/apache/dubbo/pull/8309), +[#8336](https://github.com/apache/dubbo/pull/8336), +[#8332](https://github.com/apache/dubbo/pull/8332), +[#8328](https://github.com/apache/dubbo/pull/8328), +[#8355](https://github.com/apache/dubbo/pull/8355), +[#8396](https://github.com/apache/dubbo/pull/8396), +[#8401](https://github.com/apache/dubbo/pull/8401), +[#8395](https://github.com/apache/dubbo/pull/8395), +[#8415](https://github.com/apache/dubbo/pull/8415), +[#8406](https://github.com/apache/dubbo/pull/8406), +[#8411](https://github.com/apache/dubbo/pull/8411), +[#8418](https://github.com/apache/dubbo/pull/8418), +[#8439](https://github.com/apache/dubbo/pull/8439), +[#8404](https://github.com/apache/dubbo/pull/8404), +[#8443](https://github.com/apache/dubbo/pull/8443) + + +## Maven依赖变化 +- 移除依赖: org.eclipse.collections:eclipse-collections +- 移除依赖: com.google.guava:guava +- jetty: 9.4.11.v20180605 -> 9.4.43.v20210629 +- apollo client: 1.1.1 -> 1.8.0 +- snakeyaml: 1.20 -> 1.29 +- tomcat embed: 8.5.31 -> 8.5.69 +- nacos client: 2.0.0 -> 2.0.2 +- swagger: 1.5.19 -> 1.5.24 +- hessian_lite: 3.2.8 -> 3.2.11 + diff --git a/content/en/blog/news/releases/3.1.3.md b/content/en/blog/news/releases/3.1.3.md new file mode 100644 index 000000000000..f2b8dd2b3887 --- /dev/null +++ b/content/en/blog/news/releases/3.1.3.md @@ -0,0 +1,43 @@ +--- +title: "Dubbo Java 3.1.3 正式发布" +linkTitle: "dubbo-java 3.1.3" +date: 2022-07-18 +tags: ["Release Notes"] +weight: 20 +description: > + 在 11 月 28 日,Dubbo 3.1.3 正式通过投票发布。本文将介绍本次发布的变化一览。 +--- + +## Dubbo 3.1.3 + +![image.png](/imgs/blog/release/3-1-3.png) + +### 修改内容 + +- 修复本地调用的过程中 Filter 顺序异常的问题 +- 支持导入协议配置项到 MetadataService +- 支持在发布 MetadataService 时自动选择可用端口 +- 完善错误码内容 +- 泛化调用下支持一致性哈希负载均衡 +- 修复泛化调用时反序列化异常的问题 +- 修复由于 JVM Methods 顺序不一致导致的应用级元数据无法复用的问题 +- 默认关闭端口复用能力,修复 remoting 组建找不到 SPI 的问题 +- 修复由于引用计数异常导致的 safe gard 问题 +- 删除 Nacos 注册中心组建中使用的 guava 依赖 +- 修复接口级使用 Nacos 注册中心时由于地址聚合导致的无法下线的问题 +- 多个代码质量优化提交 + +### 新贡献者 + +- [@zhangzq7](https://github.com/zhangzq7) 在 [#10847](https://github.com/apache/dubbo/pull/10847) 中提交了第一个贡献 +- [@akaakking](https://github.com/akaakking) 在 [#10799](https://github.com/apache/dubbo/pull/10799) 中提交了第一个贡献 +- [@wxbty](https://github.com/wxbty) 在 [#10921](https://github.com/apache/dubbo/pull/10921) 中提交了第一个贡献 +- [@haoxz11](https://github.com/haoxz11) 在 [#10937](https://github.com/apache/dubbo/pull/10937) 中提交了第一个贡献 + +### 新贡献者 + +- [@weixsun](https://github.com/weixsun) 在 [#10941](https://github.com/apache/dubbo/pull/10941) 中提交了第一个贡献 + +## 未来的版本规划 + +3.0、3.1、3.2 有什么区别?未来会怎么发展?发版周期是怎么样的?更多的版本迭代规划也将在近期推出,欢迎关注 Apache Dubbo 官方公众号获取最新的信息。 diff --git a/content/en/blog/news/releases/3.1.4.md b/content/en/blog/news/releases/3.1.4.md new file mode 100644 index 000000000000..94164461c6f7 --- /dev/null +++ b/content/en/blog/news/releases/3.1.4.md @@ -0,0 +1,68 @@ +--- +title: "Dubbo Java 3.1.4 正式发布" +linkTitle: "dubbo-java 3.1.4" +date: 2022-12-01 +tags: ["Release Notes"] +weight: 10 +description: > + 在 12 月 22 日,Dubbo 3.1.4 版本发布,本文将介绍发布的变化一览。 +--- + +Dubbo 3.1.4 版本是目前 Dubbo 3 的最新稳定版本,我们建议所有的用户都升级到最新的稳定版本。 + +# Dubbo 3.1.4 + +![image.png](/imgs/blog/release/3-1-4.png) + +### 新特性 + +- Dubbo QoS 支持指定白名单 IP 列表访问所有命令 + +### Bugfix + +- 修复在泛化调用时 Dubbo Metrics 采集方法名错误 +- 修复使用 Zookeeper 作为元数据中心时,上报接口映射可能存在相互覆盖的问题 +- 修复 timeout countdown 在 Triple 协议的支持 +- 修复 timeout countdown 存在透传的问题 +- 修复多注册中心请求时,由于没有可用的地址导致的 NPE 问题 +- 修复 Mesh 模式下 Triple 获取 remoteApplicationName 为空的问题 +- 修复 GraalVM Native Image 的支持 +- 修复端口复用时无 SSL 连接导致的 NPE 异常 +- 完善 JDK 编译器报错日志的输出格式 +- 修复 MetadataReportConfig 部分配置时应用无法启动的问题 +- 修复 dubbo.reference 作为默认参数在 3.x 版本中不生效的问题 +- 完善 Zookeeper 连接失败的日志 +- 修复 ReferenceConfig 中配置的 ClassLoader 可能被覆盖的问题 +- 修复部分属性在应用级服务发现时被缓存在实例级的地址中导致方法级配置失效的问题 +- 修复 Triple 协议 onError 异常的问题 + +### FAQ + +本次发布中有 3 个提交涉及异常日志 FAQ 的完善。关于错误码机制请参考官网错误码机制介绍一文。(https://cn.dubbo.apache.org/zh-cn/overview/java-sdk/reference-manual/faq/intro/) + +### 代码优化 + +本次发布中有 11 个提交涉及代码质量的优化。 + +### 依赖升级 + +- 升级 fastjson2: 2.0.14 -> 2.0.21 +- 升级 resteasy-jaxrs: 3.0.19.Final -> 3.0.20.Final + +### 贡献者 + +Dubbo 感谢以下贡献者对本次发布的贡献:@cnjxzhao, @CrazyHZM, @EarthChen, @gold-fisher, @IncrementalRefinement, @Koooooo-7, @ShenFeng312, @tonycody, @twz007, @win120a, @wlazjr + +### 新贡献者 + +- @twz007 在 PR #11012 提交了第一个贡献 +- @IncrementalRefinement 在 PR #11046 提交了第一个贡献 +- @gold-fisher 在 PR #11058 提交了第一个贡献 +- @wlazjr 在 PR #11084 提交了第一个贡献 +- @ShenFeng312 在 PR #11102 提交了第一个贡献 + +# 未来版本规划 + +![image.png](/imgs/blog/release/release-roadmap.png) + +Dubbo 版本的发布规划以及在《[聚焦稳定性,Dubbo 发版规划公布](https://mp.weixin.qq.com/s?__biz=MzIwODYwNTA4MA==&mid=2247484424&idx=1&sn=2f5ff4846f7dafad325f78fd8cf4d1fc&chksm=9701deffa07657e9a46eb97bb859770b4856599566b992724013a848a730f394702938e72404&token=1547029975&lang=zh_CN#rd)》一文中正式发布,欢迎查看。 diff --git a/content/en/blog/news/releases/3.2.0-beta.2.md b/content/en/blog/news/releases/3.2.0-beta.2.md new file mode 100644 index 000000000000..901d04485374 --- /dev/null +++ b/content/en/blog/news/releases/3.2.0-beta.2.md @@ -0,0 +1,38 @@ +--- +title: "Dubbo 3.2.0-beta.2 正式发布" +linkTitle: "dubbo-java 3.2.0-beta.2" +date: 2022-11-18 +weight: 40 +tags: ["Release Notes"] +description: > + 在 11 月 28 日,Dubbo 3.2.0-beta.2 正式通过投票发布。本文将介绍本次发布的变化一览。 +--- + +## Dubbo 3.2.0-beta.2 +![image.png](/imgs/blog/release/3-2-0-beta-2.png) +### 修改内容 + +- 切换到在用户线程序列化,提升协议性能 +- 支持 Netty3 的端口复用 +- 修复存在多个用户配置的 providedBy 时不生效的问题 +- 支持 istio 的 first-party-jwt 能力 +- 删除 fastjson 和 gson 的传递依赖 +- 支持可选 appResponse 不透传的能力 +- 切换到 Fastjson2 为默认序列化依赖 +- 完善注册中心推送的日志 +- 修复路由刷新时机早于服务目录刷新时机的问题 +- 关闭地址推空保护 +- 更新支持 GraalVM Native 的 SPI 生成代码 +- 支持使用 plain text 模式传输 xds 通道 +- 支持 Nacos 批量注册,修复多注册覆盖的问题 +- 支持 Spring Framework 6 and Spring Boot 3 +- 多个代码质量优化提交 +- 前述 Dubbo 3.1.3 的所有修改内容 + +### 新贡献者 + +- [@weixsun](https://github.com/weixsun) 在 [#10941](https://github.com/apache/dubbo/pull/10941) 中提交了第一个贡献 + +## 未来的版本规划 + +3.0、3.1、3.2 有什么区别?未来会怎么发展?发版周期是怎么样的?更多的版本迭代规划也将在近期推出,欢迎关注 Apache Dubbo 官方公众号获取最新的信息。 diff --git a/content/en/blog/news/releases/3.2.0-beta.3.md b/content/en/blog/news/releases/3.2.0-beta.3.md new file mode 100644 index 000000000000..7ac158b80acc --- /dev/null +++ b/content/en/blog/news/releases/3.2.0-beta.3.md @@ -0,0 +1,63 @@ +--- +title: "Dubbo Java 3.2.0-beta.3 正式发布" +linkTitle: "dubbo-java 3.2.0-beta.3" +date: 2022-12-18 +tags: ["Release Notes"] +weight: 30 +description: > + 在 12 月 22 日,3.2.0-beta.3 正式通过投票发布。本文将介绍发布的变化一览。 +--- + +Dubbo 3.2.0-beta.3 版本是目前 Dubbo 3 的最新特性版本,包括了如 Spring Boot 3、JDK 17、服务粒度的线程池隔离等新特性的支持,欢迎大家尝鲜使用。 + +# Dubbo 3.2.0-beta.3 + +![image.png](/imgs/blog/release/3-2-0-beta-3.png) + +**注:Dubbo 3.2.0-beta.3 的代码基础和 Dubbo 3.1.4 完全一致,因此在 Dubbo 3.1.4 中包括的所有修改内容,在 Dubbo 3.2.0-beta.3 中也同样存在,后续说明中对于重复的内容讲不再赘述。** + +### 新特性 + +- 支持使用 jackson 作为Dubbo 内部的 JSON 序列化方式 +- 优化 Dubbo Logger 的选择逻辑,在存在多种日志框架的情况下会尝试读取其配置,选择一个有效的日志框架,解决在 SpringBoot 等场景下 Dubbo 日志不输出的问题。 +- Triple 协议支持客户端流控 +- 支持发布 Dubbo Metrics 数据到 Spring Boot 的 Endpoints 上 +- 支持可选关闭线程池满时的线程 Dump 以及支持配置 Dump 的结果输出路径 +- xDS 实现支持路由规则的解析 +- 支持 Dubbo QoS 命令安全性分级,默认对外暴露存活检测的端口,支持 Kubernetes 的原生接入 +- 支持基于 P2C 的自适应负载均衡 + +### Bugfix + +- 修复默认 Metadata 缓存未开启的问题 +- 修复 Metrics 指标资源路径错误的问题 +- 完善线程池隔离的配置,默认采用共享线程池,避免创建过多的线程 +- 完善 prefer-serialization 的选择逻辑,提供向前兼容的能力 +- 修复 Triple 协议传输时未携带版本号导致版本调用错误的问题 +- 完善 GraalVM Native Image 的支持 + +### 性能优化 + +- 优化在连接数高时由于获取 channels 数量导致的资源占用问题 + +### 代码优化 + +本次发布中有 5 个提交涉及代码质量的优化。 + +### 贡献者 + +Dubbo 感谢以下贡献者对本次发布的贡献:@AlbumenJ, @asa3311, @conghuhu, @CrazyHZM, @gitchenjh, @haoyann, @JavaHello, @Koooooo-7, @nannanfighting, @ningboliu, @shanuo0312, @songxiaosheng, @tonycody, @XDanwar + +### 新贡献者 + +- @JavaHello 在 PR #10970 提交了第一个贡献 +- @songxiaosheng 在 PR #10997提交了第一个贡献 +- @Koooooo-7 在 PR #11051 提交了第一个贡献 +- @ningboliu 在 PR #10745 提交了第一个贡献 +- @XDanwar 在 PR #11063 提交了第一个贡献 + +# 未来版本规划 + +![image.png](/imgs/blog/release/release-roadmap.png) + +Dubbo 版本的发布规划以及在《[聚焦稳定性,Dubbo 发版规划公布](https://mp.weixin.qq.com/s?__biz=MzIwODYwNTA4MA==&mid=2247484424&idx=1&sn=2f5ff4846f7dafad325f78fd8cf4d1fc&chksm=9701deffa07657e9a46eb97bb859770b4856599566b992724013a848a730f394702938e72404&token=1547029975&lang=zh_CN#rd)》一文中正式发布,欢迎查看。 diff --git a/content/en/blog/news/releases/dubbo-go-1.4.md b/content/en/blog/news/releases/dubbo-go-1.4.md new file mode 100644 index 000000000000..031cac102d26 --- /dev/null +++ b/content/en/blog/news/releases/dubbo-go-1.4.md @@ -0,0 +1,153 @@ +--- +title: "Dubbo Go 1.4.0" +linkTitle: "dubbo-go 1.4.0" +date: 2021-01-12 +tags: ["Release Notes"] +description: > + dubbo-go 1.4.0 版本发布,支持 K8s 注册中心、rest 协议 +--- + +得益于社区活跃的支持,2020 年 3 月 25 日 我们发布了一个让人兴奋的版本——dubbo-go v1.4.0。除了继续支持已有的 Dubbo 的一些特性外, dubbo-go 开始了一些自己的创新尝试。 + +这个版本,最大的意义在于,做了一些支持云原生的准备工作。比如说,社区在探讨了很久的 k8s 落地之后,终于拿出来了使用 k8s 作为注册中心的解决方案。 + +其次一个比较大的改进是--我们在可观测性上也迈出了重要的一步。在这之前,dubbo-go只提供了日志这么一个单一手段,内部的信息比较不透明,这个版本将有很大的改善。 + +最后一个令人心动的改进是,我们支持了 REST 协议。 + +## 1. K8s 注册中心 + +dubbo-go 注册中心的本质为K/V型的数据存储。当前版本实现了以 Endpoint 为维度在 k8s API Server 进行服务注册和发现的方案【下文简称 Endpoint 方案】,架构图如下。 + +![img](/imgs/blog/dubbo-go/1.4/k8s.png) + +Endpoint 方案,首先将每个 dubbo-go 进程自身服务信息序列化后,通过 Kubernetes 提供的 Patch 的接口写入在自身 Pod 对象的 Annotation 中。其次,通过 Kubernetes 的 Watch 接口观察集群中本 Namespace 内带有某些固定lable [见上图] Pod 的Annotation 信息的更新,处理服务健康检查、服务上下线等情况并实时更新本地缓存。整体流程仅使用 Kubernetes 原生 API 完成将 Kubernetes 作为注册中心的功能特性。 + +这个方案非常简洁,不需要实现额外的第三方模块,也不需要对 Dubbo 业务作出改动,仅仅把 k8s 当做部署平台,依赖其容器管理能力,没有使用其 label selector 和 service 等服务治理特性。如果站在 k8s Operator 的角度来看,Operator 方案的优点即 Endpoint 方案的缺点,Endpoint 方案无法使用 k8s 的健康检查能力,亦没有使用 k8s service 的事件监听能力,每个 consumer 冗余监听一些不必要监听的事件,当 Endpoint 过多时会加大 API Server 的网络压力。 + +目前 dubbo-go 社区其实已经有了 operator 版本注册中心的技术方案, 后续版本【计划版本是 v1.6】的 dubbo-go 会给出其实现。相比当前实现,operator 方案开发和线上维护成本当然上升很多。二者如同硬币的两面,社区会让两种方式会共存,以满足不同 level 的使用者。 + +注意: 因 Pod 被调度而 IP 发生变化时,当前版本的 configuration 以及 router config 模块暂时无法动态更新。这有待于我们进一步解决。 + +参考范例[^1]. + +## 2. tracing 和 metric + +可观测性是微服务重要的一环,也是我们1.4版本着力支持的部分。在1.4版本中,我们主要在 tracing 和 metric 两个方向提供了支持。 + +为了支持 tracing 和 metric,关键的一点是支持context在整个调用过程中传递。为此我们解决了context跨端传递的问题。目前用户可以在接口中声明 context 并且设置值,dubbo-go 在底层完成 context 内容从 client 传递到 server 的任务。 + +![img](/imgs/blog/dubbo-go/1.4/context.png) + +在 metric 方面,dubbo-go 开始支持 Prometheus 采集数据了。目前支持 Prometheus中 的 Histogram 和 Summary。用户也可以通过扩展 Reporter 接口来自定义数据采集。 + +在 tracing 方面,目前 dubbo-go 的设计是采用 opentracing 作为统一的 API,在该 API 的基础上,通过在 client 和 server 之中传递 context,从而将整个链路串起来。用户可以采用任何支持 opentracing API 的监控框架来作为实现,例如 zipkin,jaeger 等。 + +## 3. rest协议支持 + +Dubbo 生态的应用与其他生态的应用互联互通,一直是 dubbo-go 社区追求的目标。dubbo-go v1.3 版本已经实现了 dubbo-go 与 grpc 生态应用的互联互通,若想与其他生态如 Spring 生态互联互通,借助 rest 协议无疑是一个很好的技术手段。 + +Rest 协议是一个很强大并且社区呼声很高的特性,它能够有效解决 open API,前端通信,异构系统通信等问题。比如,如果你的公司里面有一些陈年代码是通过 http 接口来提供服务的,那么使用我们的 rest 协议就可以无缝集成了。 + +通过在 dubbo-go 中发布 RESTful 的接口的应用可以调用任意的 RESTful 的接口,也可以被任何客户端以 http 的形式调用,框架图如下: + +![img](/imgs/blog/dubbo-go/1.4/rest.png) + +在设计过程中,考虑到不同的公司内部使用的 web 框架并不相同,所以我们允许用户扩展自己 rest server ( web 框架在 dubbo-go的封装)的实现,当然,与 rest server 相关的,诸如 filter 等,都可以在自己的 rest server 实现内部扩展。 + +## 4. 路由功能增强 + +路由规则在发起一次 RPC 调用前起到过滤目标服务器地址的作用,过滤后的地址列表,将作为消费端最终发起 RPC 调用的备选地址。v1.4 版本的 dubbo-go 实现了 Condition Router 和 Health Instance First Router,将在后面版本中陆续给出诸如 Tag Router 等剩余 Router 的实现。 + +### 4.1 条件路由 + +条件路由,是 dubbo-go 中第一个支持的路由规则,允许用户通过配置文件及远端配置中心管理路由规则。 + +与之相似的一个概念是 dubbo-go 里面的 group 概念,但是条件路由提供了更加细粒度的控制手段和更加丰富的表达语义。比较典型的使用场景是黑白名单设置,灰度以及测试等。 + +参考范例[^2]。 + +### 4.2 健康实例优先路由 + +在 RPC 调用中,我们希望尽可能地将请求命中到那些处理能力快、处于健康状态的实例,该路由的功能就是通过某种策略断定某个实例不健康,并将其排除在候选调用列表,优先调用那些健康的实例。这里的"健康"可以是我们自己定义的状态,默认实现即当错误比例到达某一个阈值时或者请求活跃数大于上限则认为其不健康,允许用户扩展健康检测策略。 + +在我们服务治理里面,核心的问题其实就在于如何判断一个实例是否可用。无论是负载均衡、 + +熔断还是限流,都是对这个问题的解答。所以,这个 feature 是一个很好的尝试。因为我们接下来计划提供的特性,基于规则的限流以及动态限流,都是要解决“如何断定一个实例是否可用”这么一个问题。 + +所以欢迎大家使用这个特性,并向社区反馈各自设定的健康指标。这对我们接下来的工作会有很大的帮助。 + +## 5. hessian 协议增强 + +相较于 dubbo 的 Java 语言以及其他多语言版本,dubbo-go 社区比较自豪的地方之一就是:无论底层网络引擎还是原生使用的 hessian2 协议,以及整体服务治理框架,都由 dubbo-go 社区从零开发并维护。v1.4 版本的 dubbo-go 对 hessian2 协议又带来了诸多新 feature。 + +### 5.1 支持 dubbo 协议的 attachments + +在 dubbo-go中,attachments 机制用于传递业务参数之外的附加信息,是在客户端和服务端之间传递非业务参数信息的重要方式。 + +hessian 编码协议将之编码在 body 内容的后面进行传输,dubbo-go-hessian2 之前并不支持读/写 attachments,在多个使用方【如蚂蚁金服】的要求下,dubbo-go-hessian2 以兼容已有的使用方式为前提,支持了 attachments 的读/写。 + +Request 和 Response 的 struct 中定义了 attachments 的 map,当需要使用 attachments,需要由使用方构造这两种类型的参数或者返回对象。否则,将无法在hessian的传输流中获取和写入attachments。 + +另外,利用 dubbo-go 调用链中传输 context 的功能,用户已经可以在服务方法中通过 context 添加 attachments了。 + +### 5.2 支持忽略非注册 pojo 的解析方式 + +由于 hessian 编码协议与 Java 的类型高度耦合,在 golang 的实现中会相对比较麻烦,需要有指明的对应类型。dubbo-go-hessian2 的实现方式是:定义 POJO 接口,要求实现 JavaClassName 方法来供程序获取 Java 对应的类名。这导致了接收到包含未注册类的请求时,将会无法解析而报错,这个问题以前是无法解决的。 + +但是,有一些使用场景如网关或者 service mesh 的 sidecar,需要在不关心 Java 类的具体定义的情况下,像 http读取 header 信息一样仅仅读取 dubbo 请求的附加信息,将 dubbo/dubbo-go 请求转发。通过该 feature,网关/sidecar 并不关注请求的具体内容,可以在解析请求的数据流时跳过无法解析的具体类型,直接读取 attachments 的内容。 + +该实现通过在 Decoder 中添加的 skip 字段,对每一个 object 做出特殊处理。 + +### 5.3 支持 java.math.BigInteger 和 java.math.BigDecimal + +在 Java 服务中,java.math.BigInteger 和 java.math.BigDecimal 是被频繁使用的数字类型,hessian 库将它们映射为 github.com/dubbogo/gost/math/big 下的对应类型。 + +### 5.4 支持 ‘继承’ 和忽略冗余字段 + +由于 go 没有继承的概念,所以在之前的版本,Java 父类的字段不被 dubbo-go-hessian2 所支持。新版本中,dubbo-go-hessian2 将Java来自父类的字段用匿名结构体对应,如: + +```go +type Dog struct { + Animal + Gender string + DogName string `hessian:"-"` +} +``` + +同时,就像 json 编码中通过 `immediately` 可以在序列化中忽略该字段,同理,通过 `hessian:"-"` 用户也可以让冗余字段不参与 hessian 序列化。 + +目前,上述四个特性已被某 Go 版本的 sidecar 集成到其商业版本中提供商业服务。 + +## 6. Nacos 配置中心 + +配置中心是现代微服务架构里面的核心组件,现在 dubbo-go 提供了对配置中心的支持。 + +![img](/imgs/blog/dubbo-go/1.4/config-center.png) + +Nacos 作为一个易于构建云原生应用的动态服务发现、配置管理和服务管理平台,在该版本终于作为配置中心而得到了支持。 + +参考范例[^3]. + +## 7. 接口级签名认证 + +Dubbo 鉴权认证是为了避免敏感接口被匿名用户调用而在 SDK 层面提供的额外保障。用户可以在接口级别进行定义是否允许匿名调用,并对调用方进行验签操作,对于验签不通过的消费端,禁止调用。 + +![img](/imgs/blog/dubbo-go/1.4/acl.png) + +如上图,总体实现基于 AK/SK 机制,应用通过 HTTPS 通信,启动时向鉴权服务拉取,定期更新。且允许用户自定义获取 AK/SK 的源,在 RPC 层面保障安全性。 + +## 8. 回顾与展望 + +目前 dubbo-go 已经到了一个比较稳定成熟的状态。在接下来的版本里面,我们将集中精力在云原生上。下一个版本,我们将首先实现应用维度的服务注册,这是一个和现有注册模型完全不同的新的注册模型。也是我们朝着云原生努力的一个关键版本。 + +在可观测性上,我们计划在整个 dubbo-go 的框架内,引入更多的埋点,收集更加多的内部状态。这需要实际生产环境用户的使用反馈,从而知道该如何埋点,收集何种数据。 + +在限流和熔断上,可以进一步扩展。当下的限流算法,是一种静态的算法--限流参数并没有实时根据当前服务器的状态来推断是否应该限流,它可能仅仅是用户的经验值。其缺点在于,用户难以把握应该如何配置,例如 TPS 究竟应该设置在多大。所以计划引入一种基于规则的限流和熔断。这种基于规则的限流和熔断,将允许用户设置一些系统状态的状态,如 CPU 使用率,磁盘 IO,网络 IO 等。当系统状态符合用户规则时,将触发熔断。 + +目前这些规划的 任务清单[^4],都已经放入在 dubbo-go 项目的 issue 里面,欢迎感兴趣的朋友认领参与开发。dubbo-go 社区在 **钉钉群 23331795** 欢迎你的加入。 + +[^1]: https://github.com/apache/dubbo-go-samples/tree/1.5/registry/kubernetes +[^2]: https://github.com/dubbogo/dubbo-samples/tree/master/golang/router/condition +[^3]: https://github.com/dubbogo/dubbo-samples/tree/master/golang/configcenter/nacos +[^4]: https://github.com/apache/dubbo-go/milestone/1 diff --git a/content/en/blog/news/releases/dubbo-go-1.5.1.md b/content/en/blog/news/releases/dubbo-go-1.5.1.md new file mode 100644 index 000000000000..a18398e24090 --- /dev/null +++ b/content/en/blog/news/releases/dubbo-go-1.5.1.md @@ -0,0 +1,180 @@ +--- +title: "Dubbo Go 1.5.1" +linkTitle: "dubbo-go 1.5.1" +date: 2021-6-12 +weight: 60 +description: > + Dubbo-go 团队近期发布了 Dubbo-go v1.5.1,Dubbo-go 是 Apache Dubbo 项目的 Go 实现。 +--- + +近期我们发布了 dubbo-go v1.5.1,虽然是 v1.5 的一个子版本,但相比于 v1.5.0, 社区还是投入了很大人力添加了如下重大改进。 + +## 1 应用维度注册模型 + +在新模型 release 后,我们发现 Provider 每个 URL 发布元数据都会注册 ServiceInstance,影响性能需要优化。 + +我们的优化方案是: + +去除 ServiceDiscoveryRegistry 中注册 ServiceInstance 的代码,在 config_loader 中的loadProviderConfig 方法的最后注册 ServiceInstance + +具体步骤: +1. 获取所有注册的 Registry,过滤出 ServiceDiscoveryRegistry,拿取所有 ServiceDiscovery。 +2. 创建 ServiceInstance。 +3. 每个 ServiceDiscovery 注册 ServiceInstance。 + +保证 Provider 在注册成功之后,才暴露元数据信息。 + +## 2 支持基于 Seata 的事务 + +基于 Seata 扩展实现。通过增加过滤器,在服务端接收 xid 并结合 [seata-golang](https://github.com/seata-golang/seata-golang) 达到支持分布式事务的目的。 从而使 Dubbo-go 在分布式场景下,让用户有更多的选择,能适应更多的个性化场景。 + +我们在 dubbo-samples 中给出了 [事务测试用例](https://github.com/apache/dubbo-go-samples/tree/1.5/seata) 。 + +## 3 多注册中心集群负载均衡 + +对于多注册中心订阅的场景,选址时的多了一层注册中心集群间的负载均衡: + +在 Cluster Invoker 这一级,我们支持的选址策略有: + +- 指定优先级 +- 同 zone 优先 +- 权重轮询 + +## 4 传输链路安全性 + +该版本在传输链路的安全性上做了尝试,对于内置的 Dubbo getty Server 提供了基于 TLS 的安全链路传输机制。 + +为尽可能保证应用启动的灵活性,TLS Cert 的指定通过配置文件方式,具体请参见 Dubbo-go 配置读取规则与 TLS 示例: + +## 5 路由功能增强 + +本次路由功能重点支持了 动态标签路由 和 应用/服务级条件路由。 + +### 5.1 动态标签路由 + +标签路由通过将某一个或多个服务的提供者划分到同一个分组,约束流量只在指定分组中流转,从而实现流量隔离的目的,可以作为蓝绿发布、灰度发布等场景的能力基础。 + +标签主要是指对 Provider 端应用实例的分组,目前有两种方式可以完成实例分组,分别是`动态规则打标`和`静态规则打标`,其中动态规则相较于静态规则优先级更高,而当两种规则同时存在且出现冲突时,将以动态规则为准。 + +#### 5.1.1 动态规则打标 + +可随时在[服务治理控制台](/en/docsv2.7/user/examples/routing-rule/)下发标签归组规则 + +```yaml +# governance-tagrouter-provider应用增加了两个标签分组tag1和tag2 +# tag1包含一个实例 127.0.0.1:20880 +# tag2包含一个实例 127.0.0.1:20881 +--- + force: false + runtime: true + enabled: true + key: governance-tagrouter-provider + tags: + - name: tag1 + addresses: ["127.0.0.1:20880"] + - name: tag2 + addresses: ["127.0.0.1:20881"] + ... +``` + +#### 5.1.2 静态规则打标 + +可以在 server 配置文件的 tag 字段里设置 + +```yaml +services: + "UserProvider": + registry: "hangzhouzk" + protocol : "dubbo" + interface : "com.ikurento.user.UserProvider" + loadbalance: "random" + warmup: "100" + tag: "beijing" + cluster: "failover" + methods: + - name: "GetUser" + retries: 1 + loadbalance: "random" +``` + +consumer 添加 tag 至 attachment 即可 + +```go +ctx := context.Background() +attachment := make(map[string]string) +attachment["dubbo.tag"] = "beijing" +ctx = context.WithValue(ctx, constant.AttachmentKey, attachment) +err := userProvider.GetUser(ctx, []interface{}{"A001"}, user) +``` + +请求标签的作用域为每一次 invocation,使用 attachment 来传递请求标签,注意保存在 attachment 中的值将会在一次完整的远程调用中持续传递,得益于这样的特性,我们只需要在起始调用时,通过一行代码的设置,达到标签的持续传递。 + +#### 5.1.3 规则详解 + +##### 格式 + +- `Key`明确规则体作用到哪个应用。**必填**。 +- `enabled=true` 当前路由规则是否生效,可不填,缺省生效。 +- `force=false` 当路由结果为空时,是否强制执行,如果不强制执行,路由结果为空的路由规则将自动失效,可不填,缺省为 `false`。 +- `runtime=false` 是否在每次调用时执行路由规则,否则只在提供者地址列表变更时预先执行并缓存结果,调用时直接从缓存中获取路由结果。如果用了参数路由,必须设为 `true`,需要注意设置会影响调用的性能,可不填,缺省为 `false`。 +- `priority=1` 路由规则的优先级,用于排序,优先级越大越靠前执行,可不填,缺省为 `0`。 +- `tags` 定义具体的标签分组内容,可定义任意n(n>=1)个标签并为每个标签指定实例列表。**必填** +- - name, 标签名称 +- addresses, 当前标签包含的实例列表 + +##### 降级约定 + +1. `dubbo.tag=tag1` 时优先选择 标记了 `tag=tag1` 的 provider。若集群中不存在与请求标记对应的服务,默认将降级请求 tag 为空的 provider;如果要改变这种默认行为,即找不到匹配 tag1 的 provider 返回异常,需设置`dubbo.force.tag=true`。 +2. `dubbo.tag` 未设置时,只会匹配 tag 为空的 provider。即使集群中存在可用的服务,若 tag 不匹配也就无法调用,这与约定 1 不同,携带标签的请求可以降级访问到无标签的服务,但不携带标签/携带其他种类标签的请求永远无法访问到其他标签的服务。 + +### 5.2 应用/服务级条件路由 + +您可以在路由规则配置中配置多个条件路由及其粒度 + +Sample: + +```yaml +# dubbo router yaml configure file +routerRules: + - scope: application + key: BDTService + priority: 1 + enable: false + force: true + conditions : ["host = 192.168.199.208 => host = 192.168.199.208 "] + - scope: service + key: com.ikurento.user.UserProvider + priority: 1 + force: true + conditions : ["host = 192.168.199.208 => host = 192.168.199.208 "] +``` + +#### 5.2.1 规则详解 + +##### 各字段含义 + +- scope表示路由规则的作用粒度,scope的取值会决定key的取值。必填。 +- - service 服务粒度 +- application 应用粒度 +- Key明确规则体作用在哪个服务或应用。必填。 +- - scope=service时,key取值为[{group}/]{service}[:{version}]的组合 +- scope=application时,key取值为application名称 +- enabled=true 当前路由规则是否生效,可不填,缺省生效。 +- force=false 当路由结果为空时,是否强制执行,如果不强制执行,路由结果为空的路由规则将自动失效,可不填,缺省为 false。 +- runtime=false 是否在每次调用时执行路由规则,否则只在提供者地址列表变更时预先执行并缓存结果,调用时直接从缓存中获取路由结果。如果用了参数路由,必须设为 true,需要注意设置会影响调用的性能,可不填,缺省为 false。 +- priority=1 路由规则的优先级,用于排序,优先级越大越靠前执行,可不填,缺省为 0。 +- conditions 定义具体的路由规则内容。必填。 + +## 6 回顾与展望 + +Dubbo-go 处于一个比较稳定成熟的状态。目前新版本正处于往云原生方向的尝试,应用服务维度注册是首先推出的功能,这是一个和之前模型完全不一样的新注册模型。该版本是我们朝云原生迈进新一步的关键版本。除此之外,包含在该版本也有一些之前提到的优化。 + +下一个版本 v1.5.2,本次的关注重点以通信模型改进为主,除此之外,与 2.7.x 的兼容性、易用性及质量保证也是本次关注的信息。 + +在**服务发现**,会支持更加多的方式,如:文件、Consul。 从而使 Dubbo-go 在服务发现场景下,让用户有更多的选择,能适应更多的个性化场景。 + +另外 **易用性及质量保证**,主要关注的是 samples 与自动化构建部分。可降低用户上手 Dubbo-go 的难度,提高代码质量。 + +目前下一个版本正在紧锣密鼓的开发中,具体规划及任务清单[^1] ,都已经在 Github 上体现。 + +[^1]: https://github.com/apache/dubbo-go/projects/10 diff --git a/content/en/blog/news/releases/dubbo-go-1.5.md b/content/en/blog/news/releases/dubbo-go-1.5.md new file mode 100644 index 000000000000..1de16aa20a89 --- /dev/null +++ b/content/en/blog/news/releases/dubbo-go-1.5.md @@ -0,0 +1,99 @@ +--- +title: "Dubbo Go 1.5.0" +linkTitle: "dubbo-go 1.5.0" +date: 2021-01-14 +description: > + Dubbo-go 发布 1.5 版,朝云原生迈出关键一步 +--- + +## 引语 + +计算机技术浪潮每 10 年都有一次技术颠覆,相关知识体系最迟每 5 年都会革新一次,大概每两年贬值一半,在应用服务通信框架领域亦然。凡是有长期生命的通信框架,大概有 5 年的成长期和 5 年的稳定成熟期。每个时代都有其匹配的应用通信框架,在 20 年前的 2G 时代,强跨语言跨平台而弱性能的 gRPC 是不会被采用的。 + +每个通信框架,不同的人从不同角度看出不同的结论:初学者看重易用易学,性能测评者注重性能,应用架构师考虑其维护成本,老板则考虑则综合成本。一个应用通信框架的性能固然重要,其稳定性和进化能力更重要,得到有效维护的框架可在长时间单位内降低其综合成本:学习成本、维护成本、升级成本和更换成本。 + +什么是 Dubbo-go?第一,它是 Dubbo 的 Go 语言版本,全面兼容 Dubbo 是其第一要义。第二,它是一个 Go 语言应用通信框架,会充分利用作为云原生时代第一语言---Go 语言的优势,扩展 dubbo 的能力。 + +2008 年诞生的 Dubbo 已有十多年历史,依靠阿里和其社区,历久弥新。2016 年发布的 Dubbo-go 也已进入第五个年头,如今全面兼容 Dubbo v2.7.x 的 Dubbo-go v1.5 终于发布了。 + +回首过往,Dubbo-go 已经具备如下能力: + +- 互联互通:打通了 gRPC 和 Spring Cloud 生态; +- 可观测性:基于 OpenTracing 和 Prometheus,使得其在 Logging、Tracing 和 Metrics 方面有了长足进步; +- 云原生:Dubbo-go 实现了基于 Kubernetes API Server 为注册中心的通信能力,做到了升级成本最低。 + +毋庸讳言,相较于现有成绩,发展阶段的 Dubbo-go 对未来有更多的期待之处: + +- 易用性:Dubbo-go 的入门成本并不低,把很多感兴趣者挡在了门外。但好消息是,随着 Dubbo-go 在阿里内部的逐步推开,阿里中间件团队对其进行了进一步的封装,经生产环境检验后会开放给社区使用。 +- 云原生:目前的 Dubbo-go 的基于 kubernetes 的方案,从技术分层角度来看, Kubernetes API Server 终究是系统的运维态组件,不应该暴露给应用层,否则会造成 APIServer 自身通信压力过大,且系统整体风险很高:应用层使用不当,或者框架自身的流量方面的 bug,可能会把 APIServer 打垮,后果就是造成整体后端服务能力的瘫痪!所以应用层需要感知的是 kubernetes 提供给应用层的 Operator,不断进化的 Dubbo-go 计划在 v1.6 版本中发布 Dubbo-go Operator。 + +雄关漫道真如铁,而今迈步从头越。Dubbo-go 社区【钉钉群 23331795】与 Dubbo-go 同在。 + +## 应用维度注册模型 + +经过一段时间的努力之后,我们终于完成了应用维度的服务注册与发现。和原本已有的接口维度的注册模型比起来,新的注册模型有两个突出特点: + +1. 和主流的注册模型保持一致。目前的主流做法都是按照应用为基本单位来进行注册的,如Spring Cloud。在支持应用维度注册之后,对于接下来的云原生支持,奠定了基础; +2. 大幅度减轻对注册中心的压力。在该模型之下,从注册中心的视角看过去,集群规模只和实例数量成正比,而不是现有的和服务数量成正比; + +当然,我们在设计的时候就考虑到了用户的迁移成本。要迁移到新的注册模型,只需要将现有使用的注册中心换成新的 `ServiceDiscoveryRegistry` 就可以。 + +`ServiceDiscoveryRegistry` 是支持多种实现的。目前来说,我们支持: + +1. nacos; +2. etcd; +3. zookeeper; + +我们提倡新上线的业务尽量使用 nacos 和 etcd 这种更可靠稳定的注册中心。 + + +## Metadata Report 元数据中心 + +v1.5 版本在支持应用维度注册模型时,有很重要的一个问题需要解决,即接口维度的元数据存储。服务维度的注册模型和应用维度的注册模型,本质的区别是往注册中心注册的数据维度的不一致。虽然我们在应用维度注册模型中,将接口维度的数据从注册中心中剔除了,但是在rpc的框架中,一个 consumer 要想真正找到想要调用的服务地址,就必须得到 provider 端开放的服务信息。这部分数据,在 v1.5 版本中,我们将它们存储到了元数据中心中。 + +元数据中心,是一个接口定义。泛指一块存储区域,可以对接口级别的元数据进行存储、读取,provider 端调用存储,consumer 端调用读取。元数据中心中的数据需要保持准确性、实时性。 + +目前元数据中心,有两个父类(Go 中没有继承,此处说的父子类,单纯指子类对父类的组合关系)实现,一个是 local 实现,一个是 remote 实现。local 实现是将 provider 的内存作为虚拟元数据中心,remote 实现是指依赖 ZooKeeper、etcd、nacos 等注册中心作为元数据中心。目前 remote 有 zookeeper、nacos、etcd 和 consul 的子类实现。即用户可以将元数据信息,通过以上的第三方注册中心进行数据存储和分发。 + +## Invocation 接口支持 attribute 属性 + +invocation 结构中新增 attribute 属性支持,用于流程内部的属性存储。和 attachment 不同点在于,attachment会从 consumer 传递到 provider,但 attribute 属性不会。 + +## k8s注册中心 + +在 v1.5 版本之前,k8s 注册中心的实现是通过直接使用 [k8s client](https://github.com/kubernetes/client-go) 中Pod对象的 List&&Watch 接口。在本次迭代中引入了 k8s informer。这样做的原因在于两点,首先一定的程度上来讲 dubbo-go 的 k8s 注册中心也是一个 k8s controller,使用 informer 的模式更加 k8s native。更重要的是社区计划后续向 CRD+Operator 的模式演进,informer 模式是对后续的演进的探索。除了这个铺垫之外,本次迭代还对跨 namespace 的服务发现做了支持。再有就是为了减少对 kube-apiserver List&&Watch 的压力,对 provider 和 consumer 的行为进行了区分,provider 不再进行 Watch 而仅对 kube-apiserver 进行写操作。 + +# 优化路由模型 + +在 1.5 版本之前,Router 模型中属性是包含:优先级与路由属性,Router Chain 只包含路由属性。从中能识别出其实 Router Chain 也是一种特殊 Router。1.5 版本之后,使 Router 更抽象,分离出其优先级属性,新增 Priority Router、Chain 继承 Router 使其变为特殊的 Router,使关系上看起来更加清晰。如下图: + +![img](/imgs/blog/dubbo-go/1.5/router.png) + +# 回顾与展望 + +Dubbo-go 处于一个比较稳定成熟的状态。目前新版本正处于往云原生方向的尝试,应用服务维度注册是首先推出的功能,这是一个和之前模型完全不一样的新注册模型。该版本是我们朝云原生迈进新一步的关键版本。除此之外,包含在该版本也有一些之前提到的优化。 + +下一个版本 v1.5.1,虽然仍是以兼容 Dubbo 2.7.x 为主要任务,但在分布式能力的增强上,也是我们关注的重点。 + +在**分布式事务**方面,有一个重要的基于 Seata 扩展实现。通过增加过滤器,在服务端接收 xid 并结合 seata-golang[^2] 达到支持分布式事务的目的。 从而使 Dubbo-go 在分布式场景下,让用户有更多的选择,能适应更多的个性化场景。 + +与此同时,在**传输链路安全性**上,TLS 安全传输链路是该版本重要功能之一。通过提供统一入口,未来能引入更多的与传输链路安全性相关的功能,适应用户不一样的使用场景。 + +**注册中心模型**上,支持多注册中心集群负载均衡。业务部署假设是双注册中心(图 1 ),从原来双注册中心中所有 Provider 一起选址。优化成选址时的多了一层注册中心集群间的负载均衡(图 2 )。 + +![img](/imgs/blog/dubbo-go/1.5/multi-registry.png) + + +(图 1 ) + +![img](/imgs/blog/dubbo-go/1.5/loadbalance.png) + +(图 2 ) + +以前的 dubbo-go RPC 层直接复用了 getty 框架 的 RPC[[^3](https://github.com/AlexStocks/getty/tree/feature/rpc)],未能实现协议和应用通信地址的隔离。阿里中间件展图同学重构了 dubbo-go RPC 层,实现了连接复用:可以实现 consumer 与 provider 端的同一个 TCP 连接上进行多协议通信。相关 PR 业已合并,会在 dubbo-go v1.5.1 中发布。 + +目前下一个版本正在紧锣密鼓的开发中,具体规划及任务清单[^1] ,都已经在 Github 上体现。 + +[^1]: https://github.com/apache/dubbo-go/projects/8 +[^2]: https://github.com/seata-golang/seata-golang +[^3]: https://github.com/AlexStocks/getty/tree/feature/rpc diff --git a/content/en/blog/news/releases/dubbo-go-hessian2-1.6.md b/content/en/blog/news/releases/dubbo-go-hessian2-1.6.md new file mode 100644 index 000000000000..873223716672 --- /dev/null +++ b/content/en/blog/news/releases/dubbo-go-hessian2-1.6.md @@ -0,0 +1,62 @@ +--- +title: "Dubbo Go Hessian2 v1.6.0" +linkTitle: "dubbo-go-hessian2 v1.6.0" +date: 2021-01-14 +description: > + What's new in Dubbo-go-hessian2 v1.6.0 +--- + +## 1. 增加缓存优化 + +dubbo-go-hessian2 在解析数据的数据大量使用到了 struct 的结构信息,这部分信息可以缓存起来反复利用,使得性能提升了一倍。优化过程记录可以详细阅读[《记一次对 dubbo-go-hessian2 的性能优化》](https://mp.weixin.qq.com/s/ouVxldQAt0_4BET7srjJ6Q). + +对应 pr [#179](https://github.com/apache/dubbo-go-hessian2/pull/179),作者 [micln](https://github.com/micln)。 + +## 2. string 解析性能优化 + +由于 hessian ( dubbo 序列化协议,下称:hessian )对 string 的定义是16 bit 的 unicode 的 UTF-8 表示形式,字符长度表示是16 bit 的字符数。这是仅针对 java 制定的规范,java 中一个字符是16 bit,对应到 UTF-16. hessian 库也是对每一个字符进行转码序列化。但 golang 里面字符是和 UTF-8 对应的,dubbo-go-hessian2 里面的 rune 是 32bit,和 unicode一一映射。对于 U+10000 ~ U+10FFFF 的字符,需按照 UTF16 的规范,将字符转换为 2 个字节的代理字符,再做转换,才能和 java 的序列化方式对应起来。 + +原来不管是编码还是解析都是一个字符一个字符处理,特别是解析的时候,从流里面一个字节一个字节读取并组装成 rune,然后再转换为 string,这样效率特别低。我们的优化方案是,批次读取字节流到 buffer 中,对 buffer 进行解析转为 UTF-8 数组,并统计字符数量。其中需要对代理对字符将其转换为标准 UTF-8 子节数组。如果统计的字符数量不足,再进一步读取流种的数据进行解析。通过此方式提升一倍的解析效率。 + +对应 pr [#188](https://github.com/apache/dubbo-go-hessian2/pull/188),作者 [zonghaishang](https://github.com/zonghaishang)。 + +## 3. 解析忽略不存在的字段 + +hessian 库在解析数据的时候,对于一个 class 字段,如果不存在,则直接忽略掉。但 v1.6.0 版本之前 dubbo-go-hessian2 解析数据,如果遇到不存在的字段,会返回 error。从 v1.6.0 开始,与 hessian 一样,忽略不存在的字段。**因为这是一个特性的变更,所以升级的同学一定要注意了。** + +对应 pr [#201](https://github.com/apache/dubbo-go-hessian2/pull/201),作者 [micln](https://github.com/micln) & [fangyincheng](https://github.com/fangyincheng)。 + +## 4. 解决浮点数精度丢失问题 + +在对 float32 类型进行序列化时,我们一律强制转换为 float64 再进行序列化操作。由于浮点数的精度问题,在这个转换过程中可能出现小数点后出现多余的尾数,例如 (float32)99.8-->(float64)99.80000305175781。 + +1.6.0 版本对 float32 的序列化进行了优化: + +- 如果小数尾数小于 3 位,根据 hessian2 协议序列化为 double 32-bit 格式 +- 否则先转换为 string 类型,再转换为 float64 类型,这样做可以避免由于浮点数精度问题产生多余的尾数,最后对 float64 进行序列化。 + +虽然对 float32 类型进行了优化,但是依然建议使用浮点数的时候优先使用 float64 类型。 + +对应 pr [#196](https://github.com/apache/dubbo-go-hessian2/pull/196),作者 [willson-chen](https://github.com/willson-chen)。 + +## 5. 解决 attachment 空值丢失问题 + +dubbo 请求中包含 attachment 信息,之前如果 attachment 里面含有如 `"key1":""`,这种 value 为空的情况,解析出来的结果会直接丢失这个属性 key1 ,v1.6.0 修复了此问题,现在解析出来的 attachment 会正确解析出空 value 的属性。 + +对应 pr [#191](https://github.com/apache/dubbo-go-hessian2/pull/191),作者 [champly](https://github.com/champly)。 + +## 6. 支持 ‘继承’ 和忽略冗余字段 + +由于 go 没有继承的概念,所以在之前的版本,Java 父类的字段不被 dubbo-go-hessian2 所支持。新版本中,dubbo-go-hessian2 将Java来自父类的字段用匿名结构体对应,如: + +```go +type Dog struct { + Animal + Gender string + DogName string `hessian:"-"` +} +``` + +同时,就像 json 编码中通过 immediately 可以在序列化中忽略该字段,同理,通过 hessian:"-" 用户也可以让冗余字段不参与 hessian 序列化。 + +对应pr [#154](https://github.com/apache/dubbo-go-hessian2/pull/154),作者 [micln](https://github.com/micln) \ No newline at end of file diff --git a/content/en/blog/news/releases/dubbo-go-hessian2-1.7.md b/content/en/blog/news/releases/dubbo-go-hessian2-1.7.md new file mode 100644 index 000000000000..a51e6457e1b1 --- /dev/null +++ b/content/en/blog/news/releases/dubbo-go-hessian2-1.7.md @@ -0,0 +1,247 @@ +--- +title: "Dubbo Go Hessian2 v1.7.0" +linkTitle: "dubbo-go-hessian2 v1.7.0" +date: 2021-6-12 +weight: 70 +description: > + What's new in Dubbo-go-hessian2 v1.7.0 +--- + +Dubbo-go-hessian2 v1.7.0已发布,详见 https://github.com/apache/dubbo-go-hessian2/releases/tag/v1.7.0, 以下对这次更新内容进行详细整理。 + +另外v1.6.3 将 attachment 类型由 map[string]stiring 改为map[string]interface{} 导致版本不兼容问题,这部分已还原,后续的计划是将dubbo协议的request/response对象整体迁移到dubbogo项目中进行迭代修改, hessian2中将不再改动到request/response对象。 + +## 1. New Features + +### 1.1 add GetStackTrace method into Throwabler and its implements. [#207](https://github.com/apache/dubbo-go-hessian2/pull/207) + +go语言client请求java语言服务时,如果java语言抛出了异常,异常对应的堆栈信息是被保存在StackTraceElement中。 + +这个异常信息在日志中最好能被打印出来,以方便客户端排查问题,所以在Throwabler和对应子类中增加了StackTraceElement的获取。 + +注:其实还有一种更好的方法,所有的具体的异常类型都包含java_exception/exception.go的Throwable struct。这样只需要在Throwable中增加GetStackTrace方法就可以了。但是这种方式需要更多的测试验证,改动的逻辑相对会复杂一些。但是代码会更整洁。 这里先不用这种方法。 + +### 1.2 catch user defined exceptions. [#208](https://github.com/apache/dubbo-go-hessian2/pull/208) + +golang中增加一个java中Exception对象的序列化输出方法: + +```go +func JavaException() []byte { + e := hessian.NewEncoder() + exception := java_exception.NewException("java_exception") + e.Encode(exception) + return e.Buffer() +} +``` + +在output/output.go 提供调用入口:添加如下函数初始化声明 + +```go +func init() { + funcMap["JavaException"] = testfuncs.JavaException +} +``` + +java代码中增加调用go方法序列化结果: + +**说明**: Assert.assertEquals 不能直接比较Exception对象是否相等 + +```java + /** + * test java java.lang.Exception object and go java_exception Exception struct + */ + @Test + public void testException() { + Exception exception = new Exception("java_exception"); + Object javaException = GoTestUtil.readGoObject("JavaException"); + if (javaException instanceof Exception) { + Assert.assertEquals(exception.getMessage(), ((Exception) javaException).getMessage()); + } + } +``` + +### 1.3 support java8 time object. [#212](https://github.com/apache/dubbo-go-hessian2/pull/212), [#221](https://github.com/apache/dubbo-go-hessian2/pull/221) + +golang中增加一个java8对象的序列化输出方法: + +```go +// test java8 java.time.Year +func Java8TimeYear() []byte { + e := hessian.NewEncoder() + year := java8_time.Year{Year: 2020} + e.Encode(year) + return e.Buffer() +} +// test java8 java.time.LocalDate +func Java8LocalDate() []byte { + e := hessian.NewEncoder() + date := java8_time.LocalDate{Year: 2020, Month: 9, Day: 12} + e.Encode(date) + return e.Buffer() +} +``` + +在output/output.go 提供调用入口:添加函数初始化声明 + +```go +func init() { + funcMap["Java8TimeYear"] = testfuncs.Java8TimeYear + funcMap["Java8LocalDate"] = testfuncs.Java8LocalDate +} +``` + +java代码中增加调用go方法序列化结果: + +```java +/** + * test java8 java.time.* object and go java8_time/* struct + */ +@Test +public void testJava8Year() { + Year year = Year.of(2020); + Assert.assertEquals(year + , GoTestUtil.readGoObject("Java8TimeYear")); + LocalDate localDate = LocalDate.of(2020, 9, 12); + Assert.assertEquals(localDate, GoTestUtil.readGoObject("Java8LocalDate")); +} +``` + +### 1.4 support test golang encoding data in java. [#213](https://github.com/apache/dubbo-go-hessian2/pull/213) + +为了更好的测试验证hessian库,原来已经支持在golang中测试java的序列化数据,现在增加在java中测试golang的序列化数据,实现双向测试验证。 + +golang中增加序列化输出方法: + +```go +func HelloWorldString() []byte { + e := hessian.NewEncoder() + e.Encode("hello world") + return e.Buffer() +} +``` + +将该方法注册到output/output.go中 + +```go + // add all output func here + func init() { + funcMap["HelloWorldString"] = testfuncs.HelloWorldString +} +``` + +output/output.go 提供调用入口: + +```go +func main() { + flag.Parse() + if *funcName == "" { + _, _ = fmt.Fprintln(os.Stderr, "func name required") + os.Exit(1) + } + f, exist := funcMap[*funcName] + if !exist { + _, _ = fmt.Fprintln(os.Stderr, "func name not exist: ", *funcName) + os.Exit(1) + } + defer func() { + if err := recover(); err != nil { + _, _ = fmt.Fprintln(os.Stderr, "error: ", err) + os.Exit(1) + } + }() + if _, err := os.Stdout.Write(f()); err != nil { + _, _ = fmt.Fprintln(os.Stderr, "call error: ", err) + os.Exit(1) + } + os.Exit(0) +} +``` + +java代码中增加调用go方法序列化结果: + +```java +public class GoTestUtil { + public static Object readGoObject(String func) { + System.out.println("read go data: " + func); + try { + Process process = Runtime.getRuntime() + .exec("go run output/output.go -func_name=" + func, + null, + new File("..")); + int exitValue = process.waitFor(); + if (exitValue != 0) { + Assert.fail(readString(process.getErrorStream())); + return null; + } + InputStream is = process.getInputStream(); + Hessian2Input input = new Hessian2Input(is); + return input.readObject(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + private static String readString(InputStream in) throws IOException { + StringBuilder out = new StringBuilder(); + InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8); + char[] buffer = new char[4096]; + int bytesRead; + while ((bytesRead = reader.read(buffer)) != -1) { + out.append(buffer, 0, bytesRead); + } + return out.toString(); + } +} +``` + +增加java测试代码: + +```java +@Test +public void testHelloWordString() { + Assert.assertEquals("hello world" + , GoTestUtil.readGoObject("HelloWorldString")); +} +``` + +### 1.5 support java.sql.Time & java.sql.Date. [#219](https://github.com/apache/dubbo-go-hessian2/pull/219) + +增加了 java 类 java.sql.Time, java.sql.Date 支持,分别对应到hessian.Time 和 hessian.Date, 详见 https://github.com/apache/dubbo-go-hessian2/pull/219/files。 + +## 2. Enhancement + +### 2.1 Export function EncNull. [#225](https://github.com/apache/dubbo-go-hessian2/pull/225) + +开放 hessian.EncNull 方法,以便用户特定情况下使用。 + +## 3. Bugfixes + +### 3.1 fix enum encode error in request. [#203](https://github.com/apache/dubbo-go-hessian2/pull/203) + +原来在 dubbo request 对象中没有判断 enum 类型的情况,此pr增加了判断是不是POJOEnum类型。详见 https://github.com/apache/dubbo-go-hessian2/pull/203/files + +### 3.2 fix []byte field decoding issue. [#216](https://github.com/apache/dubbo-go-hessian2/pull/216) + +v1.7.0 之前如果 struct中包含[]byte字段时无法反序列化, 报错“error list tag: 0x29”,主要原因是被当做list进行处理,对于这种情况应该按照binary数据进行处理即可。 + +```go +type Circular struct { + Num int + Previous *Circular + Next *Circular + ResponseDataBytes []byte // <---- +} +func (Circular) JavaClassName() string { + return "com.company.Circular" +} +``` + +### 3.3 fix decoding error for map in map. [#229](https://github.com/apache/dubbo-go-hessian2/pull/229) + +v1.7.0 之前嵌套map无法正确解析,主要原因是对应的map对象被当做一个数据类型却未被自动加到类引用列表中,而嵌套map类信息是同一类型的引用,去类引用列表找,找不到就报错了。 解决这个问题的方法就是遇到map类对象,也将其加入到类引用列表中即可。 问题详细参考 [#119](https://github.com/apache/dubbo-go-hessian2/issues/119). + +### 3.4 fix fields name mismatch in Duration class. [#234](https://github.com/apache/dubbo-go-hessian2/pull/234) + +这个 PR 解决了Duration对象中字段错误定义,原来是"second/nano", 应该是"seconds/nanos"。 + +同时改善了测试验证数据。之前使用0作为int字段的测试数据,这是不准确的,因为int类型默认值就是0. \ No newline at end of file diff --git a/content/en/blog/nodejs/_index.md b/content/en/blog/nodejs/_index.md new file mode 100644 index 000000000000..a19aad2ce1ec --- /dev/null +++ b/content/en/blog/nodejs/_index.md @@ -0,0 +1,9 @@ + +--- +title: "Node.js" +linkTitle: "Node.js" +weight: 11 +description: "使用 Node.js 开发 Dubbo 应用与微服务" +--- + + diff --git a/content/en/blog/nodejs/first-nodejs-release-announcement.md b/content/en/blog/nodejs/first-nodejs-release-announcement.md new file mode 100644 index 000000000000..91a969f68d6d --- /dev/null +++ b/content/en/blog/nodejs/first-nodejs-release-announcement.md @@ -0,0 +1,201 @@ +--- +title: "Apache Dubbo 首个 Node.js 3.0-alpha 版本正式发布" +linkTitle: "Apache Dubbo 首个 Node.js 3.0-alpha 版本正式发布" +tags: ["node.js", "dubbo-js"] +authors: ["蔡建怿"] +date: 2023-10-07 +description: "本文分享了 Dubbo3 Node.js 首个正式版本,演示基于 Triple 协议的 RPC 通信模式,包括代码生成、服务发布和服务访问等过程。" +--- +# 关于 Apache Dubbo3 +Apache Dubbo 是一款易用、高性能的 WEB 和 RPC 框架,同时为构建企业级微服务提供服务发现、流量治理、可观测、认证鉴权等能力、工具与最佳实践。经过近几年发展,Dubbo3 已在阿里巴巴集团各条业务线实现全面推广,成功取代运行多年的 HSF 框架;同时 Dubbo3 的多语言体系也有了快速发展,目前涵盖的多语言体系有: + +- [apache/dubbo](https://github.com/apache/dubbo) (java) +- [apache/dubbo-go](https://github.com/apache/dubbo-go) +- [apache/dubbo-js](https://github.com/apache/dubbo-js) (web、node.js) +- [apache/dubbo-rust](https://github.com/apache/dubbo-rust) + +基于 Dubbo3 定义的 **Triple** 协议,你可以轻松编写浏览器、移动端、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。Dubbo Node.js SDK 支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 API 来发布或调用这些服务。 + +![image.png](/imgs/blog/2023/9/nodejs/img.png) + +# 关于 Dubbo3 Node.js 首个发布版 +Dubbo-js 项目于 9 月份刚刚发布了支持 Dubbo3 协议的首个 alpha 版本,该项目是 Dubbo3 的 Typescript 版本实现,提供了 Web、Node.js 两种发布包。其中,Web 框架能让开发者直接在浏览器页面访问后端服务,Node.js 则进一步丰富了后端微服务技术栈的选择。当前 Node.js 版本主要是实现了 Triple 协议的完整支持,接下来的版本中,社区将继续完善地址发现、负载均衡等服务治理能力。目前 dubbo-js 项目快速发展中,对参与 apache/dubbo-js 项目感兴趣的开发者,欢迎搜索钉钉群:**29775027779** 加入开发者群组。 + +# Node.js 微服务开发完整示例 + +本示例基于最新发布的 Node.js 版本,演示了基于 Triple 协议的 RPC 通信模式,示例使用 Protocol Buffer 定义 RPC 服务,并演示了代码生成、服务发布和服务访问等过程。 +## 前置条件 + +因为使用 Protocol Buffer 的原因,我们首先需要安装相关的代码生成工具,这包括 `@bufbuild/protoc-gen-es`、`@bufbuild/protobuf`、`@apachedubbo/protoc-gen-apache-dubbo-es`、`@apachedubbo/dubbo`。 + +```shell +npm install @bufbuild/protoc-gen-es @bufbuild/protobuf @apachedubbo/protoc-gen-apache-dubbo-es @apachedubbo/dubbo +``` + +## 定义服务 + +现在,使用 Protocol Buffer (IDL) 来定义一个 Dubbo 服务。 + +创建目录,并生成文件 + +```shell +mkdir -p proto && touch proto/example.proto +``` + +写入内容 + +```protobuf +syntax = "proto3"; + +package apache.dubbo.demo.example.v1; + +message SayRequest { + string sentence = 1; +} + +message SayResponse { + string sentence = 1; +} + +service ExampleService { + rpc Say(SayRequest) returns (SayResponse) {} +} +``` + +这个文件声明了一个叫做 `ExampleService` 的服务,为这个服务定义了 `Say` 方法以及它的请求参数 `SayRequest` 和返回值 `SayResponse`。 + +## 生成代码 + +创建 gen 目录,做为生成文件放置的目标目录 + +``` +mkdir -p gen +``` + +运行以下命令,在 gen 目录下生成代码文件 + +```shell +PATH=$PATH:$(pwd)/node_modules/.bin \ + protoc -I proto \ + --es_out gen \ + --es_opt target=ts \ + --apache-dubbo-es_out gen \ + --apache-dubbo-es_opt target=ts \ + example.proto +``` + +运行命令后,应该可以在目标目录中看到以下生成的文件: + +``` +├── gen +│ ├── example_dubbo.ts +│ └── example_pb.ts +├── proto +│ └── example.proto +``` + +## 实现服务 + +接下来我们就需要添加业务逻辑了,实现 ExampleService ,并将其注册到 DubboRouter 中。 + +创建 dubbo.ts 文件 + +```typescript +import { DubboRouter } from "@apachedubbo/dubbo"; +import { ExampleService } from "./gen/example_dubbo"; + +export default (router: DubboRouter) => + // registers apache.dubbo.demo.example.v1 + router.service(ExampleService, { + // implements rpc Say + async say(req) { + return { + sentence: `You said: ${req.sentence}`, + }; + }, + }, { serviceGroup: 'dubbo', serviceVersion: '1.0.0' }); +``` + +## 启动 Server + +Dubbo 服务可以嵌入到普通的 Node.js 服务器、Next.js、Express 或 Fastify 中。 +在这里我们将使用 Fastify,所以让我们安装 Fastify 以及我们为 Fastify 准备的插件。 + +```shell +npm install fastify @apachedubbo/dubbo-fastify +``` + +创建 server.ts 文件,新建一个 Server,把上一步中实现的 `ExampleService` 注册给它。 +接下来就可以直接初始化和启动 Server 了,它将在指定的端口接收请求。 + +```typescript +import { fastify } from "fastify"; +import { fastifyDubboPlugin } from "@apachedubbo/dubbo-fastify"; +import routes from "./dubbo"; + +async function main() { + const server = fastify(); + await server.register(fastifyDubboPlugin, { + routes, + }); + server.get("/", (_, reply) => { + reply.type("text/plain"); + reply.send("Hello World!"); + }); + await server.listen({ host: "localhost", port: 8080 }); + console.log("server is listening at", server.addresses()); +} + +void main(); +``` + +最后,运行代码启动服务 + +```shell +npx tsx server.ts +``` + +## 访问服务 + +最简单方式是使用 HTTP/1.1 POST 请求访问服务,参数则作以标准 JSON 格式作为 HTTP 负载传递。如下是使用 cURL 命令的访问示例: + +```shell +curl \ + --header 'Content-Type: application/json' \ + --header 'TRI-Service-Version: 1.0.0' \ + --header 'TRI-Service-group: dubbo' \ + --data '{"sentence": "Hello World"}' \ + http://localhost:8080/apache.dubbo.demo.example.v1.ExampleService/Say +``` + +也可以使用标准的 Dubbo client 请求服务,我们首先需要从生成代码即 dubbo-node 包中获取服务代理,为它指定 server 地址并初始化,之后就可以发起起 RPC 调用了。 + +创建 client.ts 文件。 + +```typescript +import { createPromiseClient } from "@apachedubbo/dubbo"; +import { ExampleService } from "./gen/example_dubbo"; +import { createDubboTransport } from "@apachedubbo/dubbo-node"; + +const transport = createDubboTransport({ + baseUrl: "http://localhost:8080", + httpVersion: "1.1", +}); + +async function main() { + const client = createPromiseClient(ExampleService, transport, { serviceVersion: '1.0.0', serviceGroup: 'dubbo' }); + const res = await client.say({ sentence: "Hello World" }); + console.log(res); +} +void main(); +``` + +运行客户端 + +```shell +npx tsx client.ts +``` + +# 总结 +当前 Node.js 版本主要是实现了 Triple 协议的完整支持,接下来的版本中,社区将继续完善地址发现、负载均衡等服务治理能力。目前 dubbo-js 项目快速发展中,对参与 apache/dubbo-js 项目感兴趣的开发者,欢迎搜索钉钉群:**29775027779** 加入开发者群组。 + diff --git a/content/en/blog/pixiu/_index.md b/content/en/blog/pixiu/_index.md new file mode 100644 index 000000000000..3257f3c1a4f6 --- /dev/null +++ b/content/en/blog/pixiu/_index.md @@ -0,0 +1,8 @@ + +--- +title: "Pixiu" +linkTitle: "Pixiu" +weight: 35 +date: 2022-02-19 +--- + diff --git a/content/en/blog/pixiu/dubbo-go-pixiu-animal.md b/content/en/blog/pixiu/dubbo-go-pixiu-animal.md new file mode 100644 index 000000000000..3a44c8723bc3 --- /dev/null +++ b/content/en/blog/pixiu/dubbo-go-pixiu-animal.md @@ -0,0 +1,266 @@ +--- +title: Dubbo 跨语言调用神兽:dubbo-go-pixiu +keywords: Pixiu 介绍 +description: dubbo-go-pixiu 项目是一个基于 dubbo-go 发展起来的项目,目前接口协议层支持的是七层的 HTTP 请求调用 +author: 冯振宇,于雨 +tags: ["Go", "Pixiu", "网关"] +date: 2021-08-25 +--- + +## Pixiu 是什么 + + +在回答 Pixiu 是什么之前,我们简单解释一下 Dubbo 是什么。Dubbo 是一个开源的高性能 RPC 框架,有着丰富的服务治理能力以及优秀的扩展能力。Dubbo 更扩展出 Dubbo-go【1】,为用户提供了 Golang 的 Dubbo 解决方案,打通了两种语言之间的隔阂,使 Dubbo 更加贴近云原生。 + + + +Dubbo-go 作为 Golang 服务,实现与 Dubbo 服务之间的相互调用。然而,在日常使用场景中,用户往往有把 Dubbo 服务以 RESTful 风格向外暴露的需求同时也要兼顾内部 Dubbo 调用。为了解决这种场景,作为 Dubbo API 网关的 Pixiu【2】 (中文: 貔貅, 曾用名 dubbo-go-proxy) 便应运而生。之所以采用 Pixiu 这个名称,是因为 Java 同类产品 Zuul 的意象是一个西方怪兽,Pixiu 作为一个国产产品,就用了我们中国的一个类似的神兽貔貅作为项目名称。也同时表达了 Dubbo 社区希望扩展出一整套云原生生态链的决心。 + + + +目前 Dubbo 多语言生态,发展最好的自然是 Java,其次是 Golang,其他语言都差强人意。dubbo-go-pixiu 项目是一个基于 dubbo-go 发展起来的项目,目前接口协议层支持的是七层的 HTTP 请求调用,计划在未来的 0.5 版本中支持 gRPC 请求调用,其另外一个使命是作为一种新的 dubbo 多语言解决方案。 + +## 为什么使用 Pixiu +Pixiu 是基于 Dubbogo 的云原生、高性能、可扩展的微服务 API 网关。作为一款网关产品,Pixiu 帮助用户轻松创建、发布、维护、监控和保护任意规模的 API ,接受和处理成千上万个并发 API 调用,包括流量管理、 CORS 支持、授权和访问控制、限制、监控,以及 API 版本管理。除此以外,作为 Dubbo 的衍生产品,Pixiu 可以帮助 Dubbo 用户进行协议转换,实现跨系统、跨协议的服务能力互通。 + + + +Pixiu 的整体设计遵守以下原则: + +- High performance: 高吞吐量以及毫秒级的延时。 +- 可扩展: 通过 go-plugin,用户可以根据自己的需求延展 Pixiu 的功能。 +- 简单可用: 用户通过少量配置,即可上线。 + +## Pixiu 的特性及核心功能 + + +- 为 RESTful API 和 Dubbo API 提供支持 + + + +非 RESTful 风格的 API 和 Dubbo 协议的服务往往需要修改才可以以 RESTful API 风格对外开放。Pixiu 提供协议转换功能,通过 Pixiu,开发者可以将自己的 HTTP API 或 Dubbo API 通过配置,以 RESTful API 风格对外开放。v0.2.1 版本已支持基于泛化调用的 HTTP 至 Dubbo 的协议转换以及 HTTP 协议的转发。在后续的版本,社区将会增加对 gRPC 和 http2 协议的支持。 + + + +- 面向用户的配置方式 + + + +一般的网关的配置往往繁琐且复杂。Pixiu,目标作为一款易用的网关产品,在设计上拥有三层配置层级,Gateway 层全局配置, API resource 层配置以及 HTTP verbs 方法层配置。通过三个不同层级的配置,既可以实现深度的定制,亦支持统一的默认配置;同时,支持本地的配置文件,亦可使用统一配置服务器。另外,还提供控制台模块,通过控制台模块,支持配置的热更新。Pixiu 配套配套的控制台界面也在同步开发中。 + + + +- 通用功能的集成 + + + +重试、熔断、流量控制、访问控制等通用功能不再需要在每个后端服务上重复实现。使用 Pixiu,通过配置 filter ,开发者可以进行全局的控制,亦可以根据 API 配置各自的规则。因此开发者可以专注于业务逻辑和服务,而不是将时间用在维护基础设施上。 + +- 可扩展 + +不同的使用场景有着各自独特的需求。为满足不同用户的定制化需求,Pixiu 使用了插件模式。开发者可以通过编写 go plugin,将自身特有的业务逻辑以 filter 形式内嵌至 Pixiu 网关中,实现诸如企业登录鉴权等功能。 + +![img](/imgs/blog/1/01/01/dubbo-go-pixiu/fd38da297d095e4c3af1c89b18804ef1.webp) + +图 1: Pixiu 核心功能列表 + + +## Pixiu 的架构设计 + + +![img](/imgs/blog/1/01/01/dubbo-go-pixiu/2b2fd6ea1cc0375392919d9e0c181f2b.webp) + +图 2: Pixiu 架构 + + +貔貅: 即 dubbo-go-pixiu,由四个主要模块:Listener、Router、Filters 和 Clients 组成; + +- Dubbo Cluster: Dubbo 服务所在集群,包含一个或多个 Dubbo Services; +- Other Cluster: Dubbo 以外的服务所在集群,现支持 HTTP 服务,未来将拓展支持 gRPC 等其他服务; +- Registry Center: 注册中心,维护每个业务服务的调用地址信息; +- Metadata Center: 元数据中心,维护每个业务服务的配置信息以及存储 Pixiu 本身的配置信息。 + + +作为 Dubbo 所衍生的 API 网关,Pixiu 使用 Golang 搭建,主要因为: 1. Golang 的 G-M-P,net poller 等特性使 Golang 非常适合构建 IO 密集型应用;2. 使用 Golang 可以直接引入 Dubbo-go 中的一些组建,简化开发。 + + +整个 Pixiu 大致可以拆分为四个主要模块:Listener、Router、Filters 和 Client。 + + +### 1、Listener + +在 Pixiu 中,Listener 代表外部可以访问 Pixiu 的方式。通过配置指定协议类型,地址,端口等属性,暴露 Gateway。现阶段暂支持 HTTP 协议,未来将会加入 gRPC。 + +``` +listeners: + + - name: "net/http" + + address: + + socket_address: + + protocol_type: "HTTP" + + address: "0.0.0.0" + + port: 8888 + + config: + + idle_timeout: 5s + + read_timeout: 5s + + write_timeout: 5s +``` + +### 2、Router + + +Router 是 Pixiu 的路由组件。根据配置文件,Pixiu 将对外暴露的 URLs 以树的形势存储于内存中,当请求到了 router 组件时,即会根据 URL 及 HTTP 方法查找到对应的后端服务及其 API 配置,并将信息封装于请求中,为后续 filter,及 client 的调用提供足够的内容。 + + +现阶段,Router 提供以下功能: + + +- 支持请求一对一转发路由配置或 wildcard 路由配置。 +- 支持 HTTP 请求的转发到后端 HTTP 服务。 +- 支持 HTTP 请求转化为 dubbo 泛化调用请求。 + + +### 3、Filters + + +Filter 是 Pixiu 实现额外功能及其扩展性的主要组件。其实现类似于 Dubbo-go 中的 filter,根据配置中 filter 的指定,生成调用链,从而在调用后端服务前,将各 filter 中的逻辑运行一遍,实现节流,日志等功能。 + + +用户如果需要客制化的 filter,可通过编写 go-plugin 实现。在配置中,可通过类似如下配置,加载 .so 文件,并在 API config 中指定使用的 plugin group,plugin name 实现。 + +``` +pluginFilePath: "" +pluginsGroup: + - groupName: "group1" + plugins: + - name: "rate limit" + version: "0.0.1" + priority: 1000 + externalLookupName: "ExternalPluginRateLimit" + - name: "access" + version: "0.0.1" + priority: 1000 + externalLookupName: "ExternalPluginAccess" + - groupName: "group2" + plugins: + - name: "blacklist" + version: "0.0.1" + priority: 1000 + externalLookupName: "ExternalPluginBlackList" +``` + + +### 4、Client + + +Client 负责调用具体服务。现阶段,Pixiu 支持 HTTP 与 Dubbo 的后端服务。社区将逐渐增加 gRPC 等其他 Client 以满足不同的协议。 + +HTTP client 的实现相对简单,根据 Router 中获取的后端服务信息,通过 Golang 官方包 net/http 生成请求并调用。 + +Dubbo client 的实现对比 HTTP client 会稍微复杂,其基础为 Dubbo 服务的泛化调用。泛化调用技术是 Dubbo 提供的一个很基础的功能只需要知道调用的方法名、参数类型和返回值类型,即可发起服务调用。客户端对服务端的泛化调用既可以通过注册中心发现服务,也可以直连服务端,实现对服务的动态调用。 + +如下面代码所示,Pixiu 通过动态配置 referenceConfig,然后通过 GetRPCService 生成 Dubbo 的 Generic Client(泛化调用客户端)进行下一步的调用。 + +``` +referenceConfig := dg.NewReferenceConfig(irequest.Interface, context.TODO()) + referenceConfig.InterfaceName = irequest.Interface + referenceConfig.Cluster = constant.DEFAULT_CLUSTER + var registers []string + for k := range dgCfg.Registries { + registers = append(registers, k) + } + referenceConfig.Registry = strings.Join(registers, ",") + + if len(irequest.DubboBackendConfig.Protocol) == 0 { + referenceConfig.Protocol = dubbo.DUBBO + } else { + referenceConfig.Protocol = irequest.DubboBackendConfig.Protocol + } + + referenceConfig.Version = irequest.DubboBackendConfig.Version + referenceConfig.Group = irequest.Group + referenceConfig.Generic = true + if len(irequest.DubboBackendConfig.Retries) == 0 { + referenceConfig.Retries = "3" + } else { + referenceConfig.Retries = irequest.DubboBackendConfig.Retries + } + dc.lock.Lock() + defer dc.lock.Unlock() + referenceConfig.GenericLoad(key) + clientService := referenceConfig.GetRPCService().(*dg.GenericService) +``` + + +实际上,在泛化调用的客户端中,实际执行泛化调用的关键步骤是 Dubbo-go 中的 generic_filter (如下代码片段)。在调用 generic_filter 的 Invoke 时,约定 invocation 参数列表第一个为方法名,第二个为参数类型列表,第三个为参数值列表。generic_filter 将用户请求的参数值列表转化为统一格式的 map(代码中的 struct2MapAll ),将类( golang 中为 struct )的正反序列化操作变成 map 的正反序列化操作。这使得无需 POJO 描述通过硬编码注入 hessain 库,从而完成 Dubbo 服务的泛化调用。 + + +``` +func (ef *GenericFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { + if invocation.MethodName() == constant.GENERIC && len(invocation.Arguments()) == 3 { + oldArguments := invocation.Arguments() + if oldParams, ok := oldArguments[2].([]interface{}); ok { + newParams := make([]hessian.Object, 0, len(oldParams)) + for i := range oldParams { + newParams = append(newParams, hessian.Object(struct2MapAll(oldParams[i]))) + } + newArguments := []interface{}{ + oldArguments[0], + oldArguments[1], + newParams, + } + newInvocation := invocation2.NewRPCInvocation(invocation.MethodName(), newArguments, invocation.Attachments()) + newInvocation.SetReply(invocation.Reply()) + return invoker.Invoke(ctx, newInvocation) + } + } + return invoker.Invoke(ctx, invocation) +} + +``` + +## 总结 + + +通过上面的四个模块以及注册中心的简单介绍不难发现,当请求通过 listener 被 Pixiu 接收后,请求被传入 router 中。router 根据接口的配置,从原请求中找到目标后端服务连同相关 API 配置下发到 filter 组件。filter 组件根据原请求、 API 配置等信息顺序执行,最终请求到达 client, 通过 client 调用后端服务。 + +### Pixiu 的未来 + +![img](/imgs/blog/1/01/01/dubbo-go-pixiu/e57050f224f658b96cd6bd917050b259.webp) +图 3: Pixiu 迭代里程碑 + + + +Pixiu 作为网关产品外,其衍生项目也会在我们的未来计划中,主要目的是提供更好的可用性。例如,由于 Golang 语言缺乏原生的注解, 因此 Dubbo-go 需要通过配置文件方式生成服务的元数据写入注册中心。开课啦教育公司相关同学写了一个扫描代码的工具 https://github.com/jack15083/dubbo-go-proxy-tool,在每个 RPC 服务方法前加上对应的注释,从而在服务启动前通过扫描注释生成元数据。Pixiu 也计划在未来的版本上通过提供 package,允许服务通过注释借助 https://github.com/MarcGrol/golangAnnotations 生成 API 配置并注册到 Pixiu 上。 + + + +Pixiu 目前的定位是一个七层协议网关,其最初版本是被定义成一个 Dubbo 的服务网关。作为云时代的产品,Pixiu 的发展方向必然是面向云原生的。现在的版本为 0.2.1, 已经实现基本的 Dubbo/Http 服务代理和部分的网关通用功能。目前正在开发中的 0.4 及其后续版本支持 gRPC 和 Spring Cloud 服务调用, 后续还将提供 MQ 服务支持。另外,社区将继续优化配置方式,降低用户的使用难度,继续优化官方的 filter,使 Pixiu 可以在官方层面实现更多的网关通用功能。 + + +![img](/imgs/blog/1/01/01/dubbo-go-pixiu/0c1afe00699eb3e5cc022e48966ef5a6.webp) + +在未来的一年内,社区计划支持 xDS API,将 Pixiu 演化为 Dubbo mesh 的 sidecar。其最终目的就是:在现有的 dubbo mesh 形态中演化出 Proxy Service Mesh 形态。基于这个形态,Js、Python、PHP、Ruby 和 Perl 等脚本语言程序除了收获 dubbo mesh 原有的技术红利之外,大概率还能收获性能上的提升。 + + + +Pixiu 在 Dubbo Mesh 中的终极目的是:把东西向和南北向数据面流量逐步统一 Pixiu 中的同时,让它逐步具备 Application Runtime 的能力,作为 Dubbo 多语言生态的关键解决方案。 + + +相关链接: + +【1】Dubbo-go:https://github.com/apache/dubbo-go + +【2】Pixiu:https://github.com/apache/dubbo-go-pixiu + + +冯振宇,Apache Dubbo Committer,目前负责管理香港一家消费品公司的 IT 部门整个团队。2020 年夏天 偶然看到了介绍 dubbogo 的文章后加入了 dubbogo 社区,目前在主导 Pixiu 0.4.0 版本的开发。 diff --git a/content/en/blog/pixiu/filter-intro.md b/content/en/blog/pixiu/filter-intro.md new file mode 100644 index 000000000000..3c7b448caf96 --- /dev/null +++ b/content/en/blog/pixiu/filter-intro.md @@ -0,0 +1,218 @@ +--- +title: 谈谈Pixiu的Filter +keywords: Pixiu 介绍 +description: Filter通常是网关最重要的一部分,那Pixiu的过滤器链是如何运行的呢 +tags: ["Go", "Pixiu"] +author: mark4z +date: 2022-02-19 +--- + +## **Filter的生命周期** + +Pixiu作为一个面向云原生的gateway,通过简单的配置即可代理Http to Dubbo 2、Tripe甚至是Spring Cloud的请求。那Filter是怎样运行的呢? + +首先**Filter Plugin**向**Filter Manager**注册自己**,**然后**Filter Manager**根据配置创建好**Filter Factory**并持有它们,等待请求来临时,**Manager**创建一个一次性的用于此次请求的Filter Chain,然后利用**Factory**创建好**Decode/Encode Filter**并把它们加入链中,然后按照顺序去运行Decode Filter,然后去请求**Upstream**,拿到Response再反向运行Encode Filter,让Filter可以访问到Response。 + +几个关键的概念: + +**Filter Manager** + +> Filter的Manger。。。 + +```go +// FilterManager manage filters +type FilterManager struct { + filters map[string]HttpFilterFactory + filtersArray []*HttpFilterFactory +} +``` + +**Filter Plugin**:定义了Filter的(唯一的)名字和描述如何去创建一个Filter Factory。 + +> 其实结合Filter Factory的定义,可以认为Plugin是Filter Factory的Factory + +```go +// HttpFilterPlugin describe plugin +HttpFilterPlugin interface { + // Kind returns the unique kind name to represent itself. + Kind() string + + // CreateFilterFactory return the filter factory + CreateFilterFactory() (HttpFilterFactory, error) +} +``` + +**Filter Factory**:定义了Filter自身的配置,并且在请求来临时创建真实的Filter并把它添加到FilterChain中 + +> - Config() 的目的是能让Filter Manager能够有机会把配置交给Factory(此时golang泛型还没有落地) +> - Apply() 在配置被注入到Factory后,有机会对config做一些检查和提前做一些初始化的工作 +> - PrepareFilterChain() 创建Filter并加入Filter Chain + +```go +// HttpFilterFactory describe http filter +HttpFilterFactory interface { + // Config Expose the config so that Filter Manger can inject it, so it must be a pointer + Config() interface{} + + // Apply After the config is injected, check it or make it to default + Apply() error + + // PrepareFilterChain create filter and append it to FilterChain + // + // Be Careful !!! Do not pass the Factory's config pointer to the Filter instance, + // Factory's config may be updated by FilterManager + PrepareFilterChain(ctx *http.HttpContext, chain FilterChain) error +} +``` + +**Decode/Encode Filter:**Filter分为两个部分,**Decode**在实际请求**Upstream**之前,所以可以做一些鉴权、限流,把请求在gateway层拦截掉。**Eecode**则运行在获得**Upstream**的Response之后,所以可以对返回Log甚至修改Response。 + +> 一个Filter可以即是Decode Filter,又是Encode Filter,没有限制! +> +> 假设有A、B、C三个Filter,都是Decode/Encode Filter,如果配置的顺序是A、B、C,那么运行将会是下面这样 +> +> 在Decode阶段 A->B->C,而在Encode阶段,顺序将会反过来!C->B->A + + + +```go +// decode filters will be invoked in the config order: A、B、C, and decode filters will be +// invoked in the reverse order: C、B、A +HttpDecodeFilter interface { + Decode(ctx *http.HttpContext) FilterStatus +} + +// HttpEncodeFilter after invoke upstream, +// decode filters will be invoked in the reverse order +HttpEncodeFilter interface { + Encode(ctx *http.HttpContext) FilterStatus +} +``` + +更详细的,每个Decode/Encode Filter可以返回一个FilterStatus来决定继续还是就在这里停下!比如JWT鉴权,token无效时就要及时把401返回给Downstream。当然Decode Filter发出的停止命令只会终止Decode阶段,至于为什么?想想如何做一个Access Log Filter,能在请求失败时也把失败的结果记录下吧来! + + + +## **怎样编写一个自定义Filter** + +我们来尝试写一个简单的Filter,这个Filter将会有简单的配置,在Decode阶段把请求的Body Log出来,并翻转后作为Mock的返回值。最后在Encode阶段根据配置把返回值Log出来。 + +1.首先创建一个Filter + +```go +type DemoFilter struct { + logPrefix string +} + +func (f *DemoFilter) Decode(ctx *contexthttp.HttpContext) filter.FilterStatus { + body, _ := ioutil.ReadAll(ctx.Request.Body) + logger.Infof("request body: %s", body) + + //reverse res str + runes := []rune(string(body)) + for i := 0; i < len(runes)/2; i += 1 { + runes[i], runes[len(runes)-1-i] = runes[len(runes)-1-i], runes[i] + } + reverse := string(runes) + + //mock response + ctx.SendLocalReply(200, []byte(reverse)) + return filter.Stop +} + +func (f *DemoFilter) Encode(ctx *contexthttp.HttpContext) filter.FilterStatus { + res := ctx.SourceResp.(string) + logger.Infof("%s: %s", f.logPrefix, res) + return filter.Continue +} +``` + +2.创建Filter Factory + +```go +type ( + DemoFilterFactory struct { + conf *Config + } + // Config describe the config of Filter + Config struct { + LogPrefix string `yaml:"logPrefix,omitempty"` + } +) + +func (f *DemoFilterFactory) PrepareFilterChain(ctx *contexthttp.HttpContext, chain filter.FilterChain) error { + demo := &DemoFilter{logPrefix: f.conf.LogPrefix} + + chain.AppendDecodeFilters(demo) + chain.AppendEncodeFilters(demo) + return nil +} + +func (f *DemoFilterFactory) Config() interface{} { + return f.conf +} + +func (f *DemoFilterFactory) Apply() error { + return nil +} +``` + +3.创建Filter Plugin,并注册自己 + +```go +//important +func init() { + filter.RegisterHttpFilter(&Plugin{}) +} + +type Plugin struct { +} + +func (p *Plugin) Kind() string { + return "dgp.filters.demo" +} + +func (p *Plugin) CreateFilterFactory() (filter.HttpFilterFactory, error) { + return &DemoFilterFactory{conf: &Config{}}, nil +} +``` + +4.配置文件中配置此Filter,并启动Pixiu + +```yaml +static_resources: + listeners: + - name: "net/http" + protocol_type: "HTTP" + address: + socket_address: + address: "0.0.0.0" + port: 8888 + filter_chains: + filters: + - name: dgp.filter.httpconnectionmanager + config: + route_config: + routes: + - match: + prefix: "/" + http_filters: + - name: dgp.filters.demo + config: +``` + +5.访问并查看日志与结果 + +```shell +curl localhost:8888/demo -d "eiv al tse’c" + +c’est la vie% +``` + +日志 + +``` +2022-02-19T20:20:11.900+0800 INFO demo/demo.go:62 request body: eiv al tse’c +2022-02-19T20:20:11.900+0800 INFO demo/demo.go:71 : eiv al tse’c +``` + diff --git a/content/en/blog/proposals/google-service-weaver-paper-2023.md b/content/en/blog/proposals/google-service-weaver-paper-2023.md new file mode 100644 index 000000000000..aa798f092185 --- /dev/null +++ b/content/en/blog/proposals/google-service-weaver-paper-2023.md @@ -0,0 +1,346 @@ +--- +title: "[Google Paper] 面向云时代的应用开发新模式" +linkTitle: "面向云时代的应用开发新模式" +date: 2023-05-26 +author: Google +description: "面向云时代的应用开发新模式:谷歌发布的关于单体&微服务开发与部署的论文,文中原型实现为 Service Weaver" +--- +> 本文翻译自发表在以下地址的论文:https://serviceweaver.dev/assets/docs/hotos23_vision_paper.pdf + +> 原文作者(Authors): Sanjay Ghemawat, Robert Grandl, Srdjan Petrovic, Michael Whittaker, Parveen Patel, Ivan Posva, Amin Vahdat +> +> 转载或发布请遵循原文许可: +> Permission to make digital or hard copies of part or all of this work for +> personal or classroom use is granted without fee provided that copies are +> not made or distributed for profit or commercial advantage and that copies +> bear this notice and the full citation on the first page. Copyrights for thirdparty components of this work must be honored. For all other uses, contact +> the owner/author(s). +> HOTOS ’23, June 22–24, 2023, Providence, RI, USA +> © 2023 Copyright held by the owner/author(s). +> ACM ISBN 979-8-4007-0195-5/23/06. +> https://doi.org/10.1145/3593856.3595909 + +## 摘要 +在编写分布式应用程序时,传统的明智做法是将您的应用程序拆分为可以分别拉起的独立服务。这种方式的用意是好的,但像这样基于微服务的架构经常会适得其反,带来的挑战抵消了架构试图实现的好处。从根本上说,这是因为微服务将逻辑边界(代码的编写方式)与物理边界(代码的部署方式)混为一谈。在本文中,我们提出了一种不同的编程方法,将两者(代码编写与部署方式)分离以解决这些挑战。通过我们的方法,开发人员将他们的应用程序编写为逻辑上的单体,将有关如何分发和运行应用程序的决策放到一套自动化运行时 (runtime),并以原子方式部署应用程序。与当前的微服务开发模式相比,我们的原型应用最多可减少延迟 15 倍、成本最多减少了 9 倍。 + +ACM 参考格式: +Sanjay Ghemawat, Robert Grandl, Srdjan Petrovic, Michael Whit-taker, Parveen Patel, Ivan Posva, Amin Vahdat. 2023. Towards Mod-ern Development of Cloud Applications. In Workshop on Hot Topics in Operating Systems (HOTOS ’23), June 22–24, 2023, Providence, RI, USA. ACM, New York, NY, USA, 8 pages. https://doi.org/10.1145/3593856.3595909 + +## 1 介绍 +近年来,云计算出现了前所未有的增长。编写和部署可扩展到数百万用户的分布式应用程序从未如此简单,这在很大程度上归功于 Kubernetes [25] 等框架,[7, 18, 31, 33, 40, 60] 等消息传递解决方案,以及数据格式如 [5,6, 23, 30]。使用这些技术时,普遍的做法是手动将您的应用程序拆分为可以独立部署的独立微服务。 +通过对各种基础设施团队的内部调查,我们发现大多数开发人员出于以下原因之一将他们的应用程序拆分为多个二进制包:(1) 提升性能。单独的二进制包可以独立扩展,从而提高资源利用率。 (2) 提升容错能力。一个微服务的崩溃不会导致其他微服务崩溃,从而限制了错误的传播范围。 (3) 改进抽象边界。微服务需要清晰明确的 API,并且代码纠缠的可能性会大大降低。 (4) 允许灵活的滚动发布。不同的二进制包可以以不同的速率发布,从而导致更敏捷的代码升级。 +然而,将应用程序拆分为可独立部署的微服务并非没有挑战,其中一些直接与收益相矛盾。 + +- C1:影响性能。序列化数据并通过网络发送数据的开销越来越成为瓶颈 [72]。当开发人员过度拆分他们的应用程序时,这些开销也会增加 [55]。 +- C2:损害正确性。推断每个微服务的每个已部署版本之间的交互是极具挑战性的。在对八个广泛使用的系统的 100 多个灾难性故障进行的案例研究中,三分之二的故障是由系统的多个版本之间的交互引起的 [78]。 +- C3:很难管理。开发人员必须按照自己的发布计划管理不同的二进制包,而不是使用一个二进制文件来构建、测试和部署。如果在本地运行一个应用程序,同时需要执行端到端的集成测试,那可是一个不小的工程。 +- C4:API 冻结。一旦微服务建立了 API,就很难在不破坏使用该 API 的其他服务的情况下进行更改。遗留的 API 不得不长期存在,只能不停的在上面打补丁。 +- C5:降低应用程序的开发速度。当开发活动影响多个微服务的更改时,开发人员无法以原子方式实施和部署更改。 + +开发人员必须仔细计划规划发布时间表,已决定在何时跨微服务引入更改。根据我们的经验,我们发现许多开发人员将上述挑战视为开展业务的必要部分,并且这个比例是压倒性的。许多云原生公司实际上正在开发旨在缓解上述一些挑战的内部框架和流程,但这不会从根本上改变或完全消除它们。例如, + +持续部署框架 [12, 22, 37] 简化了单个二进制包的构建、推送到生产环境的方式,但它们没有解决版本控制问题;如果它有提供这个能力的话,情况可能会更糟,因为代码将以更快的速度被发布并投入生产。各种编程库 [13、27] 使创建和发现网络端点变得更加容易,但对简化应用程序管理没有任何帮助。像 gRPC [18] 这样的网络协议和像 Protocol Buffers [30]这样的数据格式在不断改进,但仍然占据了应用程序执行成本的主要部分。 + +这些基于微服务的解决方案无法解决上述 C1-C5 的原因有两个。第一个原因是他们都假设开发人员手动将他们的应用程序拆分为多个二进制包。这意味着应用程序的网络布局由应用程序开发人员预先确定。此外,一旦确定,网络布局就会通过将网络代码添加到应用程序中而变得更加坚固(例如,网络端点、客户端/服务器存根、网络优化数据结构,如 [30] )。这意味着撤消或修改拆分变得更加困难,即使这样做是有意义的。这隐含地促成了上述挑战 C1、C2 和 C4。 + +第二个原因是假设应用程序二进制包是单独(在某些情况下是连续的)发布到生产环境中。这使得对跨二进制协议进行更改变得更加困难。此外,它还引入了版本控制问题并强制使用更低效的数据格式,如[23、30]。这反过来又会导致上面列出的挑战 C1-C5。 + +在本文中,我们提出了一种不同的编写和部署分布式应用程序的方法,一种解决 C1-C5 问题的方法。我们的编程方法包括三个核心原则: +- (1) 以模块化的方式编写逻辑上划分为多个组件的单体应用程序。 +- (2) 利用运行时根据执行特征动态自动地将逻辑组件分配给物理进程。 +- (3) 以原子方式部署应用程序,防止应用程序的不同版本交互。 + +其他解决方案(例如 actor 系统)也尝试提高抽象度。但是,它们无法解决其中一项或多项挑战(第 7 节)。尽管这些挑战和我们的提案是在服务型应用 (serving application) 的背景下讨论的,但我们相信我们的观察和解决方案具有广泛的用途。 + +## 2 提出的解决方案 +我们提案的两个主要部分是 (1) 具有抽象的编程模型(programing model),允许开发人员编写仅关注业务逻辑的单一二进制模块化应用程序,(2) 用于构建、部署和优化这些应用程序的运行时(runtime)。 + +编程模型使开发人员能够将分布式应用程序编写为单个程序,其中代码被拆分为称为组件的模块化单元(第 3 节)。这类似于将应用程序拆分为微服务,除了微服务将逻辑和物理边界混为一谈。相反,我们的解决方案将两者分离:组件以基于应用程序业务逻辑的逻辑边界为中心,而运行时以基于应用程序性能的物理边界为中心(例如,两个组件应位于同一位置以提高性能)。这种解耦——连同边界可以自动更改的事实——解决了 C4。 + +通过将所有执行责任委托给运行时,我们的解决方案能够提供与微服务相同的优势,但性能更高,成本更低(解决 C1)。例如,运行时决定如何运行、放置、复制和缩放组件(第 4 节)。由于应用程序是原子部署的,因此运行时可以鸟瞰应用程序的执行情况,从而实现进一步的优化。例如,运行时可以使用自定义序列化和传输协议,利用所有参与者都以相同版本执行的事实。 + +将应用程序编写为单个二进制文件并以原子方式部署它还可以更轻松地推断其正确性(解决 C2)并使应用程序更易于管理(解决 C3)。我们的提案为开发人员提供了一个编程模型,使他们能够专注于应用程序业务逻辑,将部署复杂性委托给运行时(解决 C5)。最后,我们的提案支持未来的创新,例如分布式应用程序的自动化测试(第 5 节)。 + +## 3 编程模型 +### 3.1 组件 + +我们提案的关键抽象是组件 (component)。组件是一种长期存在的、可复制的计算代理,类似于 actor [2]。每个组件都实现一个接口(interface),与组件交互的唯一方法是调用其接口上的方法。组件可能由不同的操作系统进程托管(可能跨越多台机器)。组件方法调用在必要时变成远程过程调用,但如果调用者和被调用者组件在同一个进程中,则仍然是本地过程调用。 + +组件如 图-1 所示。示例应用程序包含三个组件:A、B 和 C。当部署应用程序时,运行时决定如何共同定位和复制组件。在此示例中,组件 A 和组件 B 位于同一个操作系统进程中,因此它们之间的方法调用作为常规方法调用执行。组件 C 不与任何其他组件位于同一位置,同时组件 C 被部署到了两台不同机器上,组件 C 之间的方法调用是通过跨网络 RPC 完成的。 + +![pic1-arch.png](/imgs/blog/2023/5/pic1-arch.png) + +图-1:说明如何编写和部署组件。应用程序被编写为一组组件(左)并跨机器部署(右)。请注意,组件可以复制和放置在同一位置。 + +组件通常是长期存在的,但运行时可能会根据负载随时间增加或减少组件的副本数量。同样,组件副本可能会失败并重新启动。运行时还可以四处移动组件副本,例如,将两个交互非常多的组件放在同一个操作系统进程中,以便组件之间的通信在本地而不是通过网络完成。 + +### 3.2 接口 + +为了具体起见,我们在 Go 中提供了一个组件 API,尽管我们的想法与语言无关。图-2 给出了一个“Hello, World!” 应用程序。组件接口表示为 Go 接口,组件实现表示为实现这些接口的 Go 结构。在图-2 中, `hello` 结构嵌入了 **Implements[ Hello] **结构来表示它是 `Hello` 组件的实现。 + +**Init **初始化应用程序。**Get[Hello] **将客户端返回给具有接口 `Hello` 的组件,必要时创建它。对 `hello.Greet` 的调用看起来像是常规方法调用,开发人员不需要关心任何序列化和远程过程调用相关内容。 + +![image.png](/imgs/blog/2023/5/pic2-hello-world.png) + +图-2: “Hello, World!” 应用 + +## 4 运行时 + +### 4.1 概述 + +在编程模型之下是一个负责分发(distributing)和执行(executing)组件的运行时。运行时做出关于如何运行组件的所有高级决策。例如,它决定将哪些组件放在一起并进行多副本部署。运行时还负责底层细节,例如将组件运行到物理资源以及在组件失败时重新启动组件。最后,运行时负责执行原子滚动更新,确保一个应用程序版本中的组件永远不会与不同版本中的组件进行通信。 + +有许多方法可以实现运行时。本文的目的不是规定任何特定的实现。不过,重要的是要认识到运行时并没有什么神奇魔法。在本节的其余部分,我们将概述运行时的关键部分并揭开其内部工作原理的神秘面纱。 + +### 4.2 代码生成 + +运行时的首要职责是代码生成。通过检查一个项目中使用 **Implements[T] **的相关源码调用,代码生成器即可计算出所有组件接口和实现的集合。然后它生成代码来编码和解码组件方法的参数。它还生成代码以将这些方法作为远程过程调用来执行。生成的代码将与开发人员的代码一起编译成一个二进制文件。 + +### 4.3 应用-运行时交互 + +根据我们的提案,应用程序不需要包含任何特定于其部署环境的代码,但由于它们最终必须运行并集成到特定环境中(例如在本地集群中跨机器或在公共云中跨区域运行),为了支持这种集成,我们引入了一个 API(在表-1 中进行了部分概述),它将应用程序逻辑与部署环境的细节隔离开来。 + +![table1.png](/imgs/blog/2023/5/table1.png) + +表-1:应用程序和运行时之间的示例 API。 + +API 的调用者是一个 `proclet`。每个应用程序二进制文件都会运行一个小型的、与环境无关的守护进程,称为 `proclet`,它在编译期间链接到二进制文件中。 proclet 管理正在运行的二进制文件中的组件:运行、启动、停止、在失败时重新启动这些组件等等。 +API 的实现者是运行时,它负责所有控制平面操作。运行时决定 `proclet` 应该如何运行以及在何处运行。例如,多进程运行时可以运行子进程中的每个 `proclet`; SSH 运行时可以通过 SSH 运行 `proclet`;云运行时可以将 `proclet` 作为 Kubernetes pod [25、28] 运行。 + +具体而言,`proclet` 通过 Unix Pipeline 与运行时交互。例如,当构造一个 `proclet` 时,它会通过管道发送一条 `RegisterReplica` 消息,以将自己标记为活动和就绪。它定期发出 `ComponentsToHost` 请求以了解它应该运行哪些组件。如果组件调用不同组件的方法,`proclet` 会发出 `StartComponent` 请求以确保它已启动。 + +运行时以对部署环境有意义的方式实现这些 API。我们希望大多数运行时实现包含以下两部分: +- (1) 一组通过 UNIX 管道与 proclet 直接通信的信封(Envelope)进程,以及 +- (2) 协调 proclet 执行的全局管理器(Global Manager)(参见图-3)。 + +![image.png](/imgs/blog/2023/5/pic3-runtime.png) + +图-3:提案中的 Deployer 架构 + +信封(Envelope)作为 proclet 的父进程运行,并将 API 调用中继到管理器。管理器跨可用资源集(例如服务器、VM)启动信封和(间接)proclet。在应用程序的整个生命周期中,管理器与信封交互以收集运行组件的健康和负载信息;聚合组件导出的指标、日志和跟踪;并处理启动新组件的请求。管理器还发布特定于环境的 API(例如,谷歌云[16]、AWS [4])更新流量分配并根据负载、健康状况和性能约束扩展和缩减组件。请注意,运行时实现控制平面(Golbal Manager)而不是数据平面,Proclet 直接相互通信。 + +### 4.4 原子滚动更新(Rollout) + +开发人员不可避免地必须发布其应用程序的新版本。一种广泛使用的方法是执行滚动更新,其中部署中的机器一台一台地从旧版本更新到新版本。在滚动更新期间,运行不同版本代码的机器必须相互通信,这可能会导致失败。 [78]表明大多数更新失败是由这些跨版本交互引起的。 +为了解决这些复杂性,我们提出了一种不同的方法。运行时确保应用程序版本以原子方式推出,这意味着所有组件通信都发生在应用程序的单个版本中。运行时逐渐将流量从旧版本转移到新版本,但是一旦用户请求转发到特定版本,它就会完全在该版本内处理。原子部署的一种流行实现是使用蓝/绿部署[9]。 + +## 5 启用创新 +### 5.1 传输(Transport)、放置(Placement)和缩容(Scaling) +运行时可以鸟瞰应用程序执行,这为性能优化开辟了新途径。例如,我们的框架可以在组件之间构建一个细粒度的调用图,并用它来识别关键的路径路径、瓶颈组件、频繁交互型组件等。使用这些信息,运行时可以做出更智能的扩缩容、独立部署和组合部署决策。此外,由于序列化和传输机制对开发者透明(Code Generate 机制自动实现),运行时可以自由地优化它们。例如,对于网络瓶颈应用程序,运行时可能决定压缩网络上的消息,对于某些部署,传输可能会利用 RDMA [32] 等技术。 + +### 5.2 路由(Routing) +当请求以亲和力(affinity)路由时,某些组件的性能会大大提高。例如,考虑由基于磁盘的底层存储系统支持的内存缓存组件。当对相同键的请求被路由到相同的缓存副本时,缓存命中率和整体性能会提高。 Slicer [44]表明,许多应用程序可以从这种基于亲和力的路由中受益,并且当路由嵌入到应用程序本身时,路由效率最高[43]。我们的编程框架可以自然地扩展为包含路由 API。运行时还可以了解哪些方法从路由中获益最多并自动路由它们。 + +### 5.3 自动化测试(Automated Testing) +微服务架构被吹捧的好处之一是容错。这个想法是,如果应用中的一个服务组件失败,应用的部分功能可用性会降低,但整个应用仍然可用。这在理论上很棒,但在实践中它依赖于开发人员确保他们的应用对故障具有弹性,更重要的是,测试他们的故障处理逻辑是否正确。由于构建和运行不同的微服务、系统地失败和恢复它们以及检查正确行为的开销,测试尤其具有挑战性。结果,只有一小部分基于微服务的系统针对这种类型的容错进行了测试。根据我们的建议,运行端到端测试能带来的帮助是微不足道的。因为应用程序是用单一编程语言编写的单个二进制文件,所以端到端测试变成了简单的单元测试。这为自动化容错测试打开了大门,类似于混沌测试[47]、Jepsen 测试[14]和模型检查[62]。 + +### 5.4 有状态应用滚动更新(Rollout) +我们的建议确保一个应用程序版本中的组件永远不会与不同版本中的组件通信。这使开发人员更容易推理正确性。但是,如果应用程序更新持久存储系统(如数据库)中的状态,则应用程序的不同版本将通过它们读取和写入的数据间接影响彼此。这些跨版本交互是不可避免的——持久状态,根据定义,跨版本持续存在 —— 但一个悬而未决的问题是如何测试这些交互并及早发现错误以避免在推出期间出现灾难性故障。 + +### 5.5 讨论 +请注意,本节讨论的领域中的创新并不是我们提案所独有的。对传输协议[63、64]、路由[44、65]、测试[45、75]、资源管理[57、67、71]、故障排除[54、56]等。然而,我们的编程模型的独特功能支持新的创新,并使现有的创新更容易实现实施。 + +例如,通过在我们的提议中利用原子部署,我们可以设计高效的序列化协议,可以安全地假设所有参与者都使用相同的模式。此外,我们的编程模型可以轻松地将路由逻辑直接嵌入到用户的应用程序中,从而提供一系列好处[43]。同样,我们的提案提供应用程序鸟瞰图的能力允许 +研究人员专注于开发用于调整应用程序和降低部署成本的新解决方案。 + +## 6 原型实现 +我们的原型实现是用 Go [38]编写的,包括图2 中描述的组件 API、第4.2节中描述的代码生成器以及第 4.3 节中描述的 proclet 架构。该实现使用自定义序列化格式和直接构建在 TCP 之上的自定义传输协议。该原型还带有一个谷歌 Kubernetes 引擎 (GKE) 部署器,它通过渐进的蓝/绿部署实现多区域部署。它使用 Horizontal Pod Autoscalers [20]根据负载动态调整容器副本的数量,并遵循类似于图3中的架构。我们的实现可在github.com/ServiceWeaver 获得。 + +### 6.1 评价 +为了评估我们的原型,我们使用了一个流行的 Web 应用程序[41],它代表了开发人员编写的各种微服务应用程序。该应用程序有 11 个微服务,并使用 gRPC [18]和 Kubernetes [25]部署在云端。该应用程序是用各种编程语言编写的,因此为了公平比较,我们将应用程序移植为完全用 Go 编写。然后我们将应用程序移植到我们的原型中,每个微服务都被重写为一个组件。我们使用 Locust [26],一种工作负载生成器,在有和没有我们的原型的情况下对应用程序进行负载测试。 + +工作负载生成器向应用程序发送稳定速率的 HTTP 请求。两个应用程序版本都配置为自动缩放容器副本的数量以响应负载。我们测量了应用程序版本在稳定状态下使用的 CPU 内核数量,以及它们的端到端延迟。表-2 显示了我们的结果。 + +![table2.png](/imgs/blog/2023/5/table2.png) + +表-2 + +我们原型的大部分性能优势来自它使用专为非版本化数据交换设计的自定义序列化格式,以及它使用直接构建在 TCP 之上的流线型传输协议。例如,使用的序列化格式不需要对字段编号或类型信息进行任何编码。这是因为所有编码器和解码器都以完全相同的版本运行,并且预先就字段集以及它们的编码和解码顺序达成一致。 + +为了与基线进行同类比较,我们没有将任何组件放在一起。当我们共同定位所有将 11 个组件集成到单个操作系统进程中,内核数量下降到 9,中值延迟下降到 0.38 毫秒,均比基线低一个数量级。这反映了行业经验[34、39]。 + +## 7 相关工作 +演员系统。最接近我们建议的解决方案是 Orleans [74]和 Akka [3]。这些框架还使用抽象来解耦应用程序和运行时。 Ray [70]是另一个基于角色的框架,但专注于 ML 应用程序。这些系统都不支持原子部署,而原子部署是完全应对 C2-C5 挑战的必要组成部分。其他流行的基于 actor 的框架,如 Er-lang [61]、E [52]、Thorn [48]和 C++ Actor Framework [10],给开发人员带来了处理系统和有关部署和执行的低级细节的负担,因此它们未能分离应用程序和运行时之间的关注点,因此没有完全解决 C1-C5。 CORBA、DCOM 和 Java RMI 等分布式对象框架使用与我们类似的编程模型,但存在许多技术和组织问题[58],并且也没有完全解决 C1-C5。 + +基于微服务的系统。 Kubernetes [25]广泛用于在云中部署基于容器的应用程序。但是,它的重点与我们的提案正交,不涉及 C1-C5 中的任何一个。 Docker Compose [15]、Acorn [1]、Helm [19]、Skaffold [35]和 Istio [21]抽象出了一些微服务挑战(例如,配置生成)。然而,与将应用程序拆分为微服务、版本化推出和测试相关的挑战仍然留给了用户。因此,它们不满足 C1-C5。 + +其他系统。还有许多其他解决方案可以让开发人员更轻松地编写分布式应用程序,包括数据流系统[51、59、77]、ML 推理服务系统[8、17、42、50、73]、无服务器解决方案[11, 24、36]、数据库[29、49]和 Web 应用程序[66]。最近,服务网格[46、69]提出了网络抽象以分解出常见的通信功能。我们的提案体现了这些相同的想法,但在通用服务系统和分布式应用程序的新领域中。在这种情况下,出现了新的挑战(例如,原子推出)。 + +## 8 讨论 +### 8.1 多个应用程序二进制文件 +我们认为应用程序应该作为单个二进制文件来编写和构建,但我们承认这可能并不总是可行的。例如,应用程序的大小可能超出单个团队的能力,或者不同的应用程序服务可能出于组织原因需要不同的发布周期。在所有这些情况下,应用程序可能需要包含多个二进制文件。 + +虽然本文没有解决需要使用多个二进制文件的情况,但我们相信我们的提议允许开发人员编写更少的二进制文件(即尽可能将多个服务分组为单个二进制文件),实现更好的性能,并推迟做出艰难的决定与如何划分应用程序有关。我们正在探索如何容纳以多种语言编写并编译成单独的二进制文件的应用程序。 + +### 8.2 与外部服务集成 +应用程序通常需要与外部服务(例如,Postgres 数据库[29])进行交互。我们的编程模型允许应用程序像任何应用程序一样与这些服务交互。什么都不是,一切都必须是一个组件。但是,当外部服务在应用程序内部和跨应用程序广泛使用时,定义相应的组件可能会提供更好的代码重用。 + +### 8.3 分布式系统挑战 +虽然我们的编程模型允许开发人员专注于他们的业务逻辑并推迟将他们的应用程序部署到运行时的大量复杂性,但我们的提议并没有解决分布式系统的基本挑战 [53, 68, 76]。应用程序开发人员仍然需要意识到组件可能会失败或经历高延迟。 + +### 8.4 编程指导 +没有关于如何编写分布式应用程序的官方指南,因此关于将应用程序编写为单体应用程序还是微服务是更好的选择,一直存在着长期而激烈的争论。但是,每种方法都有其优点和缺点。我们认为开发人员应该使用我们的建议将他们的应用程序编写为单个二进制文件,然后再决定他们是否真的需要迁移到基于微服务的架构。通过推迟决定如何准确地拆分成不同的微服务,它允许他们编写更少但更好的微服务。 + +## 9 结论 +编写分布式应用程序时的现状涉及将应用程序拆分为可独立部署的服务。这种架构有很多好处,但也有很多缺点。在本文中,我们提出了一种不同的编程范式来回避这些缺点。我们的提议鼓励开发人员 (1) 编写划分为逻辑组件的单体应用程序,(2) 将物理分布和执行模块化单体的挑战推迟到运行时,以及 (3) 原子部署应用程序。这三个指导原则带来了许多好处,并为未来的创新打开了大门。与现状相比,我们的原型实施将应用程序延迟最多减少了 15 倍,并将成本最多减少了 9 倍。 + + +[1] Acorn. [https://www.acorn.io/.](https://www.acorn.io/) + +[2] Actor model. [https://en.wikipedia.org/wiki/Actor_model.](https://en.wikipedia.org/wiki/Actor_model) + +[3] Akka. [https://akka.io.](https://akka.io) + +[4] Amazon Web Services. [https://aws.amazon.com/.](https://aws.amazon.com/) + +[5] Apache avro. [https://avro.apache.org/docs/1.2.0/.](https://avro.apache.org/docs/1.2.0/) + +[6] Apache thrift. [https://thrift.apache.org/.](https://thrift.apache.org/) + +[7] AWS Cloud Map. [https://aws.amazon.com/cloud-map/.](https://aws.amazon.com/cloud-map/) + +[8] Azure Machine Learning. [https://docs.microsoft.com/en-us/azure/](https://docs.microsoft.com/en-us/azure/machine-learning)[machine-learning.](https://docs.microsoft.com/en-us/azure/machine-learning) + +[9] Blue/green deployments. [https://tinyurl.com/3bk64ch2.](https://tinyurl.com/3bk64ch2) + +[10] The c++ actor framework. [https://www.actor-framework.org/.](https://www.actor-framework.org/) + +[11] Cloudflare Workers. [https://workers.cloudflare.com/.](https://workers.cloudflare.com/) + +[12] Continuous integration and delivery - circleci. [https://circleci.com/.](https://circleci.com/) + +[13] Dapr - distributed application runtime. [https://dapr.io/.](https://dapr.io/) + +[14] Distributed systems safety research. `https://jespen.io.` + +[15] Docker compose. [https://docs.docker.com/compose/.](https://docs.docker.com/compose/) + +[16] Google Cloud. [https://cloud.google.com/.](https://cloud.google.com/) + +[17] Google Cloud AI Platform. [https://cloud.google.com/ai-platform.](https://cloud.google.com/ai-platform) + +[18] grpc. [https://grpc.io/.](https://grpc.io/) + +[19] Helm. [http://helm.sh.](http://helm.sh) + +[20] Horizontal Pod Autoscaling. [https://kubernetes.io/docs/tasks/run-](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/)[application/horizontal-pod-autoscale/.](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) + +[21] Istio. [https://istio.io/.](https://istio.io/) + +[22] Jenkins. [https://www.jenkins.io/.](https://www.jenkins.io/) + +[23] Json. [https://www.json.org/json-en.html.](https://www.json.org/json-en.html) + +[24] Kalix. [https://www.kalix.io/.](https://www.kalix.io/) + +[25] Kubernetes. [https://kubernetes.io/.](https://kubernetes.io/) + +[26] Locust. [https://locust.io/.](https://locust.io/) + +[27] Micro | powering the future of cloud. [https://micro.dev/.](https://micro.dev/) + +[28] Pods. [https://kubernetes.io/docs/concepts/workloads/pods/.](https://kubernetes.io/docs/concepts/workloads/pods/) + +[29] Postgresql. [https://www.postgresql.org/.](https://www.postgresql.org/) + +[30] Protocol buffers. [https://developers.google.com/protocol-buffers.](https://developers.google.com/protocol-buffers) + +[31] RabbitMQ. [https://www.rabbitmq.com/.](https://www.rabbitmq.com/) + +[32] Remote direct memory access. [https://en.wikipedia.org/wiki/Remote_](https://en.wikipedia.org/wiki/Remote_direct_memory_access)[direct_memory_access.](https://en.wikipedia.org/wiki/Remote_direct_memory_access) + +[33] REST API. [https://restfulapi.net/.](https://restfulapi.net/) + +[34] Scaling up the Prime Video audio/video monitoring service and reduc-ing costs by 90%. [https://tinyurl.com/yt6nxt63.](https://tinyurl.com/yt6nxt63) + +[35] Skaffold. [https://skaffold.dev/.](https://skaffold.dev/) + +[36] Temporal. [https://temporal.io/.](https://temporal.io/) + +[37] Terraform. [https://www.terraform.io/.](https://www.terraform.io/) + +[38] The Go programming language. [https://go.dev/.](https://go.dev/) + +[39] To Microservices and Back Again - Why Segment Went Back to a Monolith. [https://tinyurl.com/5932ce5n.](https://tinyurl.com/5932ce5n) + +[40] WebSocket. [https://en.wikipedia.org/wiki/WebSocket.](https://en.wikipedia.org/wiki/WebSocket) + +[41] Online boutique. [https://github.com/GoogleCloudPlatform/](https://github.com/GoogleCloudPlatform/microservices-demo)[microservices-demo,](https://github.com/GoogleCloudPlatform/microservices-demo)2023. + +[42] M. Abadi, P. Barham, J. Chen, Z. Chen, A. Davis, J. Dean, M. Devin, +S.Ghemawat, G. Irving, M. Isard, M. Kudlur, J. Levenberg, R. Monga, +S.Moore, D. G. Murray, B. Steiner, P. Tucker, V. Vasudevan, P. Warden, +M.Wicke, Y. Yu, and X. Zheng. Tensorflow: A system for large-scale machine learning. In OSDI, 2016. + +[43] A. Adya, R. Grandl, D. Myers, and H. Qin. Fast key-value stores: An idea whose time has come and gone. In HotOS, 2019. + +[44] A. Adya, D. Myers, J. Howell, J. Elson, C. Meek, V. Khemani, S. Fulger, +P.Gu, L. Bhuvanagiri, J. Hunter, R. Peon, L. Kai, A. Shraer, A. Merchant, and K. Lev-Ari. Slicer: Auto-sharding for datacenter applications. In OSDI, 2016. + +[45] D. Ardelean, A. Diwan, and C. Erdman. Performance analysis of cloud applications. In NSDI, 2018. + +[46] S. Ashok, P. B. Godfrey, and R. Mittal. Leveraging service meshes as a new network layer. In HotNets, 2021. + +[47] A. Basiri, N. Behnam, R. De Rooij, L. Hochstein, L. Kosewski, J.Reynolds, and C. Rosenthal. Chaos engineering. In IEEE Software, 2016. + +[48] B. Bloom, J. Field, N. Nystrom, J. Östlund, G. Richards, R. Strniša, J.Vitek, and T. Wrigstad. Thorn: Robust, concurrent, extensible script-ing on the jvm. In OOPSLA, 2009. + +[49] J. C. Corbett, J. Dean, M. Epstein, A. Fikes, C. Frost, J. J. Furman, S. Ghe-mawat, A. Gubarev, C. Heiser, P. Hochschild, W. Hsieh, S. Kanthak, E.Kogan, H. Li, A. Lloyd, S. Melnik, D. Mwaura, D. Nagle, S. Quin-lan, R. Rao, L. Rolig, Y. Saito, M. Szymaniak, C. Taylor, R. Wang, and D.Woodford. Spanner: Google’s globally-distributed database. In OSDI, 2012. + +[50] D. Crankshaw, X. Wang, G. Zhou, M. J. Franklin, J. E. Gonzalez, and I.Stoica. Clipper: A low-latency online prediction serving system. In NSDI, 2017. + +[51] J. Dean and S. Ghemawat. Mapreduce: Simplified data processing on large clusters. In OSDI, 2004. +[52] J. Eker, J. Janneck, E. Lee, J. Liu, X. Liu, J. Ludvig, S. Neuendorffer, S.Sachs, and Y. Xiong. Taming heterogeneity - the ptolemy approach. In Proceedings of the IEEE, 2003. + +[53] M. J. Fischer, N. A. Lynch, and M. S. Paterson. Impossibility of dis-tributed consensus with one faulty process. In ACM Journal, 1985. + +[54] Y. Gan, M. Liang, S. Dev, D. Lo, and C. Delimitrou. Sage: Practical and Scalable ML-Driven Performance Debugging in Microservices. In ASPLOS, 2021. + +[55] Y. Gan, Y. Zhang, D. Cheng, A. Shetty, P. Rathi, N. Katarki, A. Bruno, J.Hu, B. Ritchken, B. Jackson, et al. An open-source benchmark suite for microservices and their hardware-software implications for cloud & edge systems. In ASPLOS, 2019. + +[56] Y. Gan, Y. Zhang, K. Hu, Y. He, M. Pancholi, D. Cheng, and C. De-limitrou. Seer: Leveraging Big Data to Navigate the Complexity of Performance Debugging in Cloud Microservices. In ASPLOS, 2019. + +[57] R. Grandl, G. Ananthanarayanan, S. Kandula, S. Rao, and A. Akella. Multi-resource packing for cluster schedulers. In SIGCOMM, 2014. + +[58] M. Henning. The rise and fall of corba: There’s a lot we can learn from corba’s mistakes. In Queue, 2006. + +[59] M. Isard, M. Budiu, Y. Yu, A. Birrell, and D. Fetterly. Dryad: Distributed data-parallel programs from sequential building blocks. In Eurosys, 2007. + +[60] K. Jay, N. Neha, and R. Jun. Kafka : a distributed messaging system for log processing. In NetDB, 2011. + +[61] A. Joe. Erlang. In Communications of the ACM, 2010. + +[62] L. Lamport. The temporal logic of actions. In ACM TOPLS, 1994. + +[63] A. Langley, A. Riddoch, A. Wilk, A. Vicente, C. Krasic, D. Zhang, F.Yang, F. Kouranov, I. Swett, J. Iyengar, J. Bailey, J. Dorfman, J. Roskind, J.Kulik, P. Westin, R. Tenneti, R. Shade, R. Hamilton, V. Vasiliev, W.-T. Chang, and Z. Shi. The quic transport protocol: Design and internet-scale deployment. In SIGCOMM, 2017. + +[64] N. Lazarev, N. Adit, S. Xiang, Z. Zhang, and C. Delimitrou. Dagger: Towards Efficient RPCs in Cloud Microservices with Near-Memory Reconfigurable NICs. In ASPLOS, 2021. + +[65] S. Lee, Z. Guo, O. Sunercan, J. Ying, T. Kooburat, S. Biswal, J. Chen, K.Huang, Y. Cheung, Y. Zhou, K. Veeraraghavan, B. Damani, P. M. Ruiz, V.Mehta, and C. Tang. Shard manager: A generic shard management framework for geo-distributed applications. In SOSP, 2021. + +[66] B. Livshits and E. Kiciman. Doloto: Code splitting for network-bound web 2.0 applications. In FSE, 2008. + +[67] S. Luo, H. Xu, C. Lu, K. Ye, G. Xu, L. Zhang, Y. Ding, J. He, and C. Xu. Characterizing microservice dependency and performance: Alibaba trace analysis. In SOCC, 2021. + +[68] N. A. Lynch. Distributed algorithms. In Morgan Kaufmann Publishers Inc., 1996. + +[69] S. McClure, S. Ratnasamy, D. Bansal, and J. Padhye. Rethinking net-working abstractions for cloud tenants. In HotOS, 2021. + +[70] P. Moritz, R. Nishihara, S. Wang, A. Tumanov, R. Liaw, E. Liang, M. Eli-bol, Z. Yang, W. Paul, M. I. Jordan, and I. Stoica. Ray: A distributed framework for emerging ai applications. In OSDI, 2018. + +[71] H. Qiu, S. S. Banerjee, S. Jha, Z. T. Kalbarczyk, and R. K. Iyer. FIRM: An intelligent fine-grained resource management framework for SLO-Oriented microservices. In OSDI, 2020. + +[72] D. Raghavan, P. Levis, M. Zaharia, and I. Zhang. Breakfast of champi-ons: towards zero-copy serialization with nic scatter-gather. In HotOS, 2021. + +[73] F. Romero, Q. Li, N. J. Yadwadkar, and C. Kozyrakis. Infaas: Automated model-less inference serving. In ATC, 2021. + +[74] B. Sergey, G. Allan, K. Gabriel, L. James, P. Ravi, and T. Jorgen. Orleans: Cloud computing for everyong. In SOCC, 2011. + +[75] M. Waseem, P. Liang, G. Márquez, and A. D. Salle. Testing microser-vices architecture-based applications: A systematic mapping study. In APSEC, 2020. + +[76] Wikipedia contributors. Fallacies of distributed computing. + +[77] M. Zaharia, M. Chowdhury, T. Das, A. Dave, J. Ma, M. McCauly, M. J. Franklin, S. Shenker, and I. Stoica. Resilient distributed datasets: A fault-tolerant abstraction for in-memory cluster computing. In NSDI, 2012. + +[78] Y. Zhang, J. Yang, Z. Jin, U. Sethi, K. Rodrigues, S. Lu, and D. Yuan. Understanding and detecting software upgrade failures in distributed systems. In SOSP, 2021. + diff --git a/content/en/blog/proposals/heuristic-flow-control.md b/content/en/blog/proposals/heuristic-flow-control.md new file mode 100644 index 000000000000..b6a42df68a67 --- /dev/null +++ b/content/en/blog/proposals/heuristic-flow-control.md @@ -0,0 +1,221 @@ +--- +title: "启发式流控制" +linkTitle: "启发式流控制" +date: 2023-01-30 +author: Quanlu Liu +description: > +--- + +# 整体介绍 +本文所说的柔性服务主要是指**consumer端的负载均衡**和**provider端的限流**两个功能。在之前的dubbo版本中, +* 负载均衡部分更多的考虑的是公平性原则,即consumer端尽可能平等的从provider中作出选择,在某些情况下表现并不够理想。 +* 限流部分只提供了静态的限流方案,需要用户对provider端设置静态的最大并发值,然而该值的合理选取对用户来讲并不容易。 + +我们针对这些存在的问题进行了改进。 + +## 负载均衡 +### 使用介绍 +在原本的dubbo版本中,有五种负载均衡的方案供选择,他们分别是 `Random`、`ShortestResponse`、`RoundRobin`、`LeastActive` 和 `ConsistentHash`。其中除 `ShortestResponse` 和 `LeastActive` 外,其他的几种方案主要是考虑选择时的公平性和稳定性。 + +对于 `ShortestResponse` 来说,其设计目的是从所有备选的 provider 中选择 response 时间最短的以提高系统整体的吞吐量。然而存在两个问题: +1. 在大多数的场景下,不同provider的response时长没有非常明显的区别,此时该算法会退化为随机选择。 +2. response的时间长短有时也并不能代表机器的吞吐能力。对于 `LeastActive` 来说,其认为应该将流量尽可能分配到当前并发处理任务较少的机器上。但是其同样存在和 `ShortestResponse` 类似的问题,即这并不能单独代表机器的吞吐能力。 + +基于以上分析,我们提出了两种新的负载均衡算法。一种是同样基于公平性考虑的单纯 `P2C` 算法,另一种是基于自适应的方法 `adaptive`,其试图自适应的衡量 provider 端机器的吞吐能力,然后将流量尽可能分配到吞吐能力高的机器上,以提高系统整体的性能。 + +#### 总体效果 +对于负载均衡部分的有效性实验在两个不同的情况下进行的,分别是提供端机器配置比较均衡和提供端机器配置差距较大的情况。 + +![image.png](/imgs/blog/proposals/heuristic-flow-control/1675265258687-c3df68a8-80e0-4311-816c-63480494850c.png) + +![image.png](/imgs/blog/proposals/heuristic-flow-control/1675265271198-5b045ced-8524-42a2-8b34-d7edbbd1f232.png) + +#### 使用方法 +使用方法与原本的负载均衡方法相同。只需要在consumer端将"loadbalance"设置为"p2c"或者"adaptive"即可。 + +#### 代码结构 +负载均衡部分的算法实现只需要在原本负载均衡框架内继承 LoadBalance接口即可。 + +### 原理介绍 + +#### P2C算法 + +Power of Two Choice算法简单但是经典,主要思路如下: + +1. 对于每次调用,从可用的provider列表中做两次随机选择,选出两个节点providerA和providerB。 +2. 比较providerA和providerB两个节点,选择其“当前正在处理的连接数”较小的那个节点。 + +#### adaptive算法 + +[代码的github地址](https://github.com/apache/dubbo/pull/10745) + +##### 相关指标 +1. cpuLoad +![img](/imgs/blog/proposals/heuristic-flow-control/26808016bc7f1ee83ab425e308074f17.svg)。该指标在provider端机器获得,并通过invocation的attachment传递给consumer端。 + +2. rt +rt为一次rpc调用所用的时间,单位为毫秒。 + +3. timeout +timeout为本次rpc调用超时剩余的时间,单位为毫秒。 + +4. weight +weight是设置的服务权重。 + +5. currentProviderTime +provider端在计算cpuLoad时的时间,单位是毫秒 + +6. currentTime +currentTime为最后一次计算load时的时间,初始化为currentProviderTime,单位是毫秒。 +7. multiple +![img](/imgs/blog/proposals/heuristic-flow-control/b60f036bd026b92129df8a6476922cc8.svg) + +8. lastLatency +![img](/imgs/blog/proposals/heuristic-flow-control/f2abbc771049cf4f3e492e93a258d699.svg)![img](/imgs/blog/proposals/heuristic-flow-control/8fb1af970b995232ebed2764a5706aab.svg) + +9. beta +平滑参数,默认为0.5 + +10. ewma +lastLatency的平滑值![img](/imgs/blog/proposals/heuristic-flow-control/c26fdbae56f3a06c46434ae91185a3d6.svg) + +11. inflight +inflight为consumer端还未返回的请求的数量。 +![img](/imgs/blog/proposals/heuristic-flow-control/f429c4726dec484e70ee73e6a37c88dd.svg) + +12. load +对于备选后端机器x来说,若距离上次被调用的时间大于2*timeout,则其load值为0。 +否则, + +![img](/imgs/blog/proposals/heuristic-flow-control/0f56746b3643dc3ed0e019c24ad5f377.svg) + +##### 算法实现 +依然是基于P2C算法。 + +1. 从备选列表中做两次随机选择,得到providerA和providerB +2. 比较providerA和providerB的load值,选择较小的那个。 + +## 自适应限流 +与负载均衡运行在consumer端不同的是,限流功能运行在provider端。其作用是限制provider端处理并发任务时的最大数量。从理论上讲,服务端机器的处理能力是存在上限的,对于一台服务端机器,当短时间内出现大量的请求调用时,会导致处理不及时的请求积压,使机器过载。在这种情况下可能导致两个问题:1.由于请求积压,最终所有的请求都必须等待较长时间才能被处理,从而使整个服务瘫痪。2.服务端机器长时间的过载可能有宕机的风险。因此,在可能存在过载风险时,拒绝掉一部分请求反而是更好的选择。在之前的dubbo版本中,限流是通过在provider端设置静态的最大并发值实现的。但是在服务数量多,拓扑复杂且处理能力会动态变化的局面下,该值难以通过计算静态设置。 +基于以上原因,我们需要一种自适应的算法,其可以动态调整服务端机器的最大并发值,使其可以在保证机器不过载的前提下,尽可能多的处理接收到的请求。因此,我们参考brpc等其他框架的基础上,在dubbo的框架内实现了两种自适应限流算法,分别是基于启发式平滑的"HeuristicSmoothingFlowControl"和基于窗口的"AutoConcurrencyLimier"。 + +[代码的github地址](https://github.com/apache/dubbo/pull/10642) + +### 使用介绍 +#### 总体效果 + +自适应限流部分的有效性实验我们在提供端机器配置尽可能大的情况下进行,并且为了凸显效果,在实验中我们将单次请求的复杂度提高,将超时时间尽可能设置的大,并且开启消费端的重试功能。 +![image.png](/imgs/blog/proposals/heuristic-flow-control/1675267798831-3da99681-577f-4e5a-b122-b87c8aba7299.png) + +#### 使用方法 +要确保服务端存在多个节点,并且消费端开启重试策略的前提下,限流功能才能更好的发挥作用。 + +设置方法与静态的最大并发值设置类似,只需在provider端将"flowcontrol"设置为"autoConcurrencyLimier"或者"heuristicSmoothingFlowControl"即可。 + +#### 代码结构 +1. FlowControlFilter:在provider端的filter负责根据限流算法的结果来对provider端进行限流功能。 +2. FlowControl:根据dubbo的spi实现的限流算法的接口。限流的具体实现算法需要继承自该接口并可以通过dubbo的spi方式使用。 +3. CpuUsage:周期性获取cpu的相关指标 +4. HardwareMetricsCollector:获取硬件指标的相关方法 +5. ServerMetricsCollector:基于滑动窗口的获取限流需要的指标的相关方法。比如qps等。 +6. AutoConcurrencyLimier:自适应限流的具体实现算法。 +7. HeuristicSmoothingFlowControl:自适应限流的具体实现方法。 + +### 原理介绍 +#### HeuristicSmoothingFlowControl +##### 相关指标 +1. alpha +alpha为可接受的延时的上升幅度,默认为0.3 + +2. minLatency +在一个时间窗口内的最小的Latency值。 + +3. noLoadLatency +noLoadLatency是单纯处理任务的延时,不包括排队时间。这是服务端机器的固有属性,但是并不是一成不变的。在HeuristicSmoothingFlowControl算法中,我们根据机器CPU的使用率来确定机器当前的noLoadLatency。当机器的CPU使用率较低时,我们认为minLatency便是noLoadLatency。当CPU使用率适中时,我们平滑的用minLatency来更新noLoadLatency的值。当CPU使用率较高时,noLoadLatency的值不再改变。 + +4. maxQPS +一个时间窗口周期内的QPS的最大值。 + +5. avgLatency +一个时间窗口周期内的Latency的平均值,单位为毫秒。 + +6. maxConcurrency +计算得到的当前服务提供端的最大并发值。 +![img](/imgs/blog/proposals/heuristic-flow-control/f40e48ebdb49648cf942714609808c52.svg) + +##### 算法实现 +当服务端收到一个请求时,首先判断CPU的使用率是否超过50%。如果没有超过50%,则接受这个请求进行处理。如果超过50%,说明当前的负载较高,便从HeuristicSmoothingFlowControl算法中获得当前的maxConcurrency值。如果当前正在处理的请求数量超过了maxConcurrency,则拒绝该请求。 + +#### AutoConcurrencyLimier +##### 相关指标 +1. MaxExploreRatio +默认设置为0.3 +2. MinExploreRatio +默认设置为0.06 +3. SampleWindowSizeMs +采样窗口的时长。默认为1000毫秒。 +4. MinSampleCount +采样窗口的最小请求数量。默认为40。 +5. MaxSampleCount +采样窗口的最大请求数量。默认为500。 +6. emaFactor +平滑处理参数。默认为0.1。 +7. exploreRatio +探索率。初始设置为MaxExploreRatio。 +若avgLatency<=noLoadLatency*(1.0 + MinExploreRatio)或者qps>=maxQPS*(1.0 + MinExploreRatio) +则exploreRatio=min(MaxExploreRatio,exploreRatio+0.02) +否则 +exploreRatio=max(MinExploreRatio,exploreRatio-0.02) + +8. maxQPS +窗口周期内QPS的最大值。 +![img](/imgs/blog/proposals/heuristic-flow-control/d5cf045bc17267befc176f3d76273267.svg) +9. noLoadLatency +![img](/imgs/blog/proposals/heuristic-flow-control/8c700211f5c7a13403e3088df9cd9f43.svg) +10. halfSampleIntervalMs +半采样区间。默认为25000毫秒。 +11. resetLatencyUs +下一次重置所有值的时间戳,这里的重置包括窗口内值和noLoadLatency。单位是微秒。初始为0. +![img](/imgs/blog/proposals/heuristic-flow-control/1af4a6134ede96985302ee8a27f93df7.svg) +12. remeasureStartUs +下一次重置窗口的开始时间。 +![img](/imgs/blog/proposals/heuristic-flow-control/c7da904b9a4c890456499b09d01938d3.svg) +13. startSampleTimeUs +开始采样的时间。单位为微秒。 +14. sampleCount +当前采样窗口内请求的数量。 +15. totalSampleUs +采样窗口内所有请求的latency的和。单位为微秒。 +16. totalReqCount +采样窗口时间内所有请求的数量和。注意区别sampleCount。 +17. samplingTimeUs +采样当前请求的时间戳。单位为微秒。 +18. latency +当前请求的latency。 +19. qps +在该时间窗口内的qps值。 +![img](/imgs/blog/proposals/heuristic-flow-control/c0e8b30fc1ecf9438bc2d574fb3da8b6.svg) +20. avgLatency +窗口内的平均latency。 +![img](/imgs/blog/proposals/heuristic-flow-control/3a3acfdb05be7d3985835d43e492d3b9.svg) +21. maxConcurrency +上一个窗口计算得到当前周期的最大并发值。 +22. nextMaxConcurrency +当前窗口计算出的下一个周期的最大并发值。 +![img](/imgs/blog/proposals/heuristic-flow-control/09852cc0ef125b43a37719796cb8baae.svg) + +##### Little's Law +* 当服务处于稳定状态时:concurrency=latency*qps。这是自适应限流理论的基础。 +* 当请求没有导致机器超载时,latency基本稳定,qps和concurrency处于线性关系。 +* 当短时间内请求数量过多,导致服务超载的时候,concurrency会和latency一起上升,qps则会趋于稳定。 + +##### 算法实现 +AutoConcurrencyLimier的算法使用过程和HeuristicSmoothingFlowControl类似。与HeuristicSmoothingFlowControl的最大区别是: + +AutoConcurrencyLimier是基于窗口的。每当窗口内积累了一定量的采样数据时,才利用窗口内的数据来更新得到maxConcurrency。 +其次,利用exploreRatio来对剩余的容量进行探索。 + +另外,每隔一段时间都会自动缩小max_concurrency并持续一段时间,以处理noLoadLatency上涨的情况。因为估计noLoadLatency时必须先让服务处于低负载的状态,因此对maxConcurrency的缩小是难以避免的。 + +由于 max_concurrency < concurrency 时,服务会拒绝掉所有的请求,限流算法将 "排空所有的经历过排队的等待请求的时间" 设置为 2*latency,以确保 minLatency 的样本绝大部分时没有经过排队等待的。 + diff --git a/content/en/blog/proposals/metrics.md b/content/en/blog/proposals/metrics.md new file mode 100644 index 000000000000..fcad31a9f673 --- /dev/null +++ b/content/en/blog/proposals/metrics.md @@ -0,0 +1,523 @@ +--- +title: "指标埋点" +linkTitle: "指标埋点" +date: 2023-02-20 +author: Song Xiaosheng +description: "" +--- + +# 概述 + +## 1. 指标接入说明 + +## 2. 指标体系设计 + +Dubbo的指标体系,总共涉及三块,指标收集、本地聚合、指标推送 +* 指标收集:将Dubbo内部需要监控的指标推送至统一的Collector中进行存储 +* 本地聚合:指标收集获取的均为基础指标,而一些分位数指标则需通过本地聚合计算得出 +* 指标推送:收集和聚合后的指标通过一定的方式推送至第三方服务器,目前只涉及Prometheus + +## 3. 结构设计 +- 移除原来与 Metrics 相关的类 +- 创建新模块 dubbo-metrics/dubbo-metrics-api、dubbo-metrics/dubbo-metrics-prometheus,MetricsConfig 作为该模块的配置类 +- 使用micrometer,在Collector中使用基本类型代表指标,如Long、Double等,并在dubbo-metrics-api中引入micrometer,由micrometer对内部指标进行转换 +## 4. 数据流转 + ![img.png](/imgs/docs3-v2/java-sdk/observability/dataflow.png) + + +## 5. 目标 + 指标接口将提供一个 MetricsService,该 Service 不仅提供柔性服务所的接口级数据,也提供所有指标的查询方式,其中方法级指标的查询的接口可按如下方式声明 + +```java +public interface MetricsService { + + /** + * Default {@link MetricsService} extension name. + */ + String DEFAULT_EXTENSION_NAME = "default"; + + /** + * The contract version of {@link MetricsService}, the future update must make sure compatible. + */ + String VERSION = "1.0.0"; + + /** + * Get metrics by prefixes + * + * @param categories categories + * @return metrics - key=MetricCategory value=MetricsEntityList + */ + Map> getMetricsByCategories(List categories); + + /** + * Get metrics by interface and prefixes + * + * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) + * @param categories categories + * @return metrics - key=MetricCategory value=MetricsEntityList + */ + Map> getMetricsByCategories(String serviceUniqueName, List categories); + + /** + * Get metrics by interface、method and prefixes + * + * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) + * @param methodName methodName + * @param parameterTypes method parameter types + * @param categories categories + * @return metrics - key=MetricCategory value=MetricsEntityList + */ + Map> getMetricsByCategories(String serviceUniqueName, String methodName, Class[] parameterTypes, List categories); +} +``` + +其中 MetricsCategory 设计如下: +```java +public enum MetricsCategory { + RT, + QPS, + REQUESTS, +} +``` + +MetricsEntity 设计如下 +```java +public class MetricsEntity { + private String name; + private Map tags; + private MetricsCategory category; + private Object value; +} +``` + +# 指标收集 +## 1. 嵌入位置 + Dubbo 架构图如下 + ![img.png](/imgs/docs3-v2/java-sdk/observability/dubbo.png) + +在 provider 中添加一层 MetricsFilter 重写 invoke 方法嵌入调用链路用于收集指标,用 try-catch-finally 处理,核心代码如下 + +```java +@Activate(group = PROVIDER, order = -1) +public class MetricsFilter implements Filter, ScopeModelAware { + @Override + public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { + collector.increaseTotalRequests(interfaceName, methodName, group, version); + collector.increaseProcessingRequests(interfaceName, methodName, group, version); + Long startTime = System.currentTimeMillis(); + try { + Result invoke = invoker.invoke(invocation); + collector.increaseSucceedRequests(interfaceName, methodName, group, version); + return invoke; + } catch (RpcException e) { + collector.increaseFailedRequests(interfaceName, methodName, group, version); + throw e; + } finally { + Long endTime = System.currentTimeMillis(); + Long rt = endTime - startTime; + collector.addRT(interfaceName, methodName, group, version, rt); + collector.decreaseProcessingRequests(interfaceName, methodName, group, version); + } + } +} + +``` + + +## 2. 指标标识 + 用以下五个属性作为隔离级别区分标识不同方法,也是各个 ConcurrentHashMap 的 key +```java +public class MethodMetric { + private String applicationName; + private String interfaceName; + private String methodName; + private String group; + private String version; +} +``` + +## 3. 基础指标 + 指标通过 common 模块下的 MetricsCollector 存储所有指标数据 + +```java +public class DefaultMetricsCollector implements MetricsCollector { + private Boolean collectEnabled = false; + private final List listeners = new ArrayList<>(); + private final ApplicationModel applicationModel; + private final String applicationName; + + private final Map totalRequests = new ConcurrentHashMap<>(); + private final Map succeedRequests = new ConcurrentHashMap<>(); + private final Map failedRequests = new ConcurrentHashMap<>(); + private final Map processingRequests = new ConcurrentHashMap<>(); + + private final Map lastRT = new ConcurrentHashMap<>(); + private final Map minRT = new ConcurrentHashMap<>(); + private final Map maxRT = new ConcurrentHashMap<>(); + private final Map avgRT = new ConcurrentHashMap<>(); + private final Map totalRT = new ConcurrentHashMap<>(); + private final Map rtCount = new ConcurrentHashMap<>(); + } +``` + +# 本地聚合 +本地聚合指将一些简单的指标通过计算获取各分位数指标的过程 +## 1. 参数设计 + 收集指标时,默认只收集基础指标,而一些单机聚合指标则需要开启服务柔性或者本地聚合后另起线程计算。此处若开启服务柔性,则本地聚合默认开启 + +### 1.1 本地聚合开启方式 +```xml + + + +``` + +### 1.2 指标聚合参数 +```xml + + + +``` + +## 2. 具体指标 + +Dubbo的指标模块帮助用户从外部观察正在运行的系统的内部服务状况 ,Dubbo参考 ["四大黄金信号"](https://sre.google/sre-book/monitoring-distributed-systems/)、*RED方法*、*USE方法*等理论并结合实际企业应用场景从不同维度统计了丰富的关键指标,关注这些核心指标对于提供可用性的服务是至关重要的。 + +Dubbo的关键指标包含:**延迟(Latency)**、**流量(Traffic)**、 **错误(Errors)** 和 **饱和度(Saturation)** 等内容 。同时,为了更好的监测服务运行状态,Dubbo 还提供了对核心组件状态的监控,如Dubbo应用信息、线程池信息、三大中心交互的指标数据等。 + +在Dubbo中主要包含如下监控指标: + +| | 基础设施 | 业务监控 | +| :------- | :----------------------------------------------------------- |:-----------------------------| +| 延迟类 | IO 等待; 网络延迟; | 接口、服务的平均耗时、TP90、TP99、TP999 等 | +| 流量类 | 网络和磁盘 IO; | 服务层面的 QPS、 | +| 错误类 | 宕机; 磁盘(坏盘或文件系统错误); 进程或端口挂掉; 网络丢包; | 错误日志;业务状态码、错误码走势; | +| 饱和度类 | 系统资源利用率: CPU、内存、磁盘、网络等; 饱和度:等待线程数,队列积压长度; | 这里主要包含JVM、线程池等| + +- qps: 基于滑动窗口获取动态qps +- rt: 基于滑动窗口获取动态rt +- 失败请求数: 基于滑动窗口获取最近时间内的失败请求数 +- 成功请求数: 基于滑动窗口获取最近时间内的成功请求数 +- 处理中请求数: 前后增加Filter简单统计 +- 具体指标依赖滑动窗口,额外使用 AggregateMetricsCollector 收集 + +输出到普罗米修斯的相关指标可以参考的内容如下: +``` +# HELP jvm_gc_live_data_size_bytes Size of long-lived heap memory pool after reclamation +# TYPE jvm_gc_live_data_size_bytes gauge +jvm_gc_live_data_size_bytes 1.6086528E7 +# HELP requests_succeed_aggregate Aggregated Succeed Requests +# TYPE requests_succeed_aggregate gauge +requests_succeed_aggregate{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 39.0 +# HELP jvm_buffer_memory_used_bytes An estimate of the memory that the Java virtual machine is using for this buffer pool +# TYPE jvm_buffer_memory_used_bytes gauge +jvm_buffer_memory_used_bytes{id="direct",} 1.679975E7 +jvm_buffer_memory_used_bytes{id="mapped",} 0.0 +# HELP jvm_gc_memory_allocated_bytes_total Incremented for an increase in the size of the (young) heap memory pool after one GC to before the next +# TYPE jvm_gc_memory_allocated_bytes_total counter +jvm_gc_memory_allocated_bytes_total 2.9884416E9 +# HELP requests_total_aggregate Aggregated Total Requests +# TYPE requests_total_aggregate gauge +requests_total_aggregate{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 39.0 +# HELP system_load_average_1m The sum of the number of runnable entities queued to available processors and the number of runnable entities running on the available processors averaged over a period of time +# TYPE system_load_average_1m gauge +system_load_average_1m 0.0 +# HELP system_cpu_usage The "recent cpu usage" for the whole system +# TYPE system_cpu_usage gauge +system_cpu_usage 0.015802269043760128 +# HELP jvm_threads_peak_threads The peak live thread count since the Java virtual machine started or peak was reset +# TYPE jvm_threads_peak_threads gauge +jvm_threads_peak_threads 40.0 +# HELP requests_processing Processing Requests +# TYPE requests_processing gauge +requests_processing{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 +# HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management +# TYPE jvm_memory_max_bytes gauge +jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'profiled nmethods'",} 1.22912768E8 +jvm_memory_max_bytes{area="heap",id="G1 Survivor Space",} -1.0 +jvm_memory_max_bytes{area="heap",id="G1 Old Gen",} 9.52107008E8 +jvm_memory_max_bytes{area="nonheap",id="Metaspace",} -1.0 +jvm_memory_max_bytes{area="heap",id="G1 Eden Space",} -1.0 +jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 5828608.0 +jvm_memory_max_bytes{area="nonheap",id="Compressed Class Space",} 1.073741824E9 +jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 1.22916864E8 +# HELP jvm_threads_states_threads The current number of threads having BLOCKED state +# TYPE jvm_threads_states_threads gauge +jvm_threads_states_threads{state="blocked",} 0.0 +jvm_threads_states_threads{state="runnable",} 10.0 +jvm_threads_states_threads{state="waiting",} 16.0 +jvm_threads_states_threads{state="timed-waiting",} 13.0 +jvm_threads_states_threads{state="new",} 0.0 +jvm_threads_states_threads{state="terminated",} 0.0 +# HELP jvm_buffer_total_capacity_bytes An estimate of the total capacity of the buffers in this pool +# TYPE jvm_buffer_total_capacity_bytes gauge +jvm_buffer_total_capacity_bytes{id="direct",} 1.6799749E7 +jvm_buffer_total_capacity_bytes{id="mapped",} 0.0 +# HELP rt_p99 Response Time P99 +# TYPE rt_p99 gauge +rt_p99{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 1.0 +# HELP jvm_memory_used_bytes The amount of used memory +# TYPE jvm_memory_used_bytes gauge +jvm_memory_used_bytes{area="heap",id="G1 Survivor Space",} 1048576.0 +jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'profiled nmethods'",} 1.462464E7 +jvm_memory_used_bytes{area="heap",id="G1 Old Gen",} 1.6098728E7 +jvm_memory_used_bytes{area="nonheap",id="Metaspace",} 4.0126952E7 +jvm_memory_used_bytes{area="heap",id="G1 Eden Space",} 8.2837504E7 +jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 1372032.0 +jvm_memory_used_bytes{area="nonheap",id="Compressed Class Space",} 4519248.0 +jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 5697408.0 +# HELP qps Query Per Seconds +# TYPE qps gauge +qps{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.3333333333333333 +# HELP rt_min Min Response Time +# TYPE rt_min gauge +rt_min{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 +# HELP jvm_buffer_count_buffers An estimate of the number of buffers in the pool +# TYPE jvm_buffer_count_buffers gauge +jvm_buffer_count_buffers{id="mapped",} 0.0 +jvm_buffer_count_buffers{id="direct",} 10.0 +# HELP system_cpu_count The number of processors available to the Java virtual machine +# TYPE system_cpu_count gauge +system_cpu_count 2.0 +# HELP jvm_classes_loaded_classes The number of classes that are currently loaded in the Java virtual machine +# TYPE jvm_classes_loaded_classes gauge +jvm_classes_loaded_classes 7325.0 +# HELP rt_total Total Response Time +# TYPE rt_total gauge +rt_total{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 2783.0 +# HELP rt_last Last Response Time +# TYPE rt_last gauge +rt_last{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 +# HELP jvm_gc_memory_promoted_bytes_total Count of positive increases in the size of the old generation memory pool before GC to after GC +# TYPE jvm_gc_memory_promoted_bytes_total counter +jvm_gc_memory_promoted_bytes_total 1.4450952E7 +# HELP jvm_gc_pause_seconds Time spent in GC pause +# TYPE jvm_gc_pause_seconds summary +jvm_gc_pause_seconds_count{action="end of minor GC",cause="Metadata GC Threshold",} 2.0 +jvm_gc_pause_seconds_sum{action="end of minor GC",cause="Metadata GC Threshold",} 0.026 +jvm_gc_pause_seconds_count{action="end of minor GC",cause="G1 Evacuation Pause",} 37.0 +jvm_gc_pause_seconds_sum{action="end of minor GC",cause="G1 Evacuation Pause",} 0.156 +# HELP jvm_gc_pause_seconds_max Time spent in GC pause +# TYPE jvm_gc_pause_seconds_max gauge +jvm_gc_pause_seconds_max{action="end of minor GC",cause="Metadata GC Threshold",} 0.0 +jvm_gc_pause_seconds_max{action="end of minor GC",cause="G1 Evacuation Pause",} 0.0 +# HELP rt_p95 Response Time P95 +# TYPE rt_p95 gauge +rt_p95{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 +# HELP requests_total Total Requests +# TYPE requests_total gauge +requests_total{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 27738.0 +# HELP process_cpu_usage The "recent cpu usage" for the Java Virtual Machine process +# TYPE process_cpu_usage gauge +process_cpu_usage 8.103727714748784E-4 +# HELP rt_max Max Response Time +# TYPE rt_max gauge +rt_max{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 4.0 +# HELP jvm_gc_max_data_size_bytes Max size of long-lived heap memory pool +# TYPE jvm_gc_max_data_size_bytes gauge +jvm_gc_max_data_size_bytes 9.52107008E8 +# HELP jvm_threads_live_threads The current number of live threads including both daemon and non-daemon threads +# TYPE jvm_threads_live_threads gauge +jvm_threads_live_threads 39.0 +# HELP jvm_threads_daemon_threads The current number of live daemon threads +# TYPE jvm_threads_daemon_threads gauge +jvm_threads_daemon_threads 36.0 +# HELP jvm_classes_unloaded_classes_total The total number of classes unloaded since the Java virtual machine has started execution +# TYPE jvm_classes_unloaded_classes_total counter +jvm_classes_unloaded_classes_total 0.0 +# HELP jvm_memory_committed_bytes The amount of memory in bytes that is committed for the Java virtual machine to use +# TYPE jvm_memory_committed_bytes gauge +jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'profiled nmethods'",} 1.4680064E7 +jvm_memory_committed_bytes{area="heap",id="G1 Survivor Space",} 1048576.0 +jvm_memory_committed_bytes{area="heap",id="G1 Old Gen",} 5.24288E7 +jvm_memory_committed_bytes{area="nonheap",id="Metaspace",} 4.1623552E7 +jvm_memory_committed_bytes{area="heap",id="G1 Eden Space",} 9.0177536E7 +jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 2555904.0 +jvm_memory_committed_bytes{area="nonheap",id="Compressed Class Space",} 5111808.0 +jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 5701632.0 +# HELP requests_succeed Succeed Requests +# TYPE requests_succeed gauge +requests_succeed{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 27738.0 +# HELP rt_avg Average Response Time +# TYPE rt_avg gauge +rt_avg{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 +``` + +## 聚合收集器 +```java +public class AggregateMetricsCollector implements MetricsCollector, MetricsListener { + private int bucketNum; + private int timeWindowSeconds; + + private final Map totalRequests = new ConcurrentHashMap<>(); + private final Map succeedRequests = new ConcurrentHashMap<>(); + private final Map failedRequests = new ConcurrentHashMap<>(); + private final Map qps = new ConcurrentHashMap<>(); + private final Map rt = new ConcurrentHashMap<>(); + + private final ApplicationModel applicationModel; + + private static final Integer DEFAULT_COMPRESSION = 100; + private static final Integer DEFAULT_BUCKET_NUM = 10; + private static final Integer DEFAULT_TIME_WINDOW_SECONDS = 120; + +//在构造函数中解析配置信息 + + public AggregateMetricsCollector(ApplicationModel applicationModel) { + this.applicationModel = applicationModel; + ConfigManager configManager = applicationModel.getApplicationConfigManager(); + MetricsConfig config = configManager.getMetrics().orElse(null); + if (config != null && config.getAggregation() != null && Boolean.TRUE.equals(config.getAggregation().getEnabled())) { + // only registered when aggregation is enabled. + registerListener(); + + AggregationConfig aggregation = config.getAggregation(); + this.bucketNum = aggregation.getBucketNum() == null ? DEFAULT_BUCKET_NUM : aggregation.getBucketNum(); + this.timeWindowSeconds = aggregation.getTimeWindowSeconds() == null ? DEFAULT_TIME_WINDOW_SECONDS : aggregation.getTimeWindowSeconds(); + } + } +} +``` + +如果开启了本地聚合,则通过 spring 的 BeanFactory 添加监听,将 AggregateMetricsCollector 与 DefaultMetricsCollector 绑定,实现一种生产者消费者的模式,DefaultMetricsCollector 中使用监听器列表,方便扩展 + +```java +private void registerListener() { + applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).addListener(this); +} +``` + +## 3. 指标聚合 +滑动窗口 +假设我们初始有6个bucket,每个窗口时间设置为2分钟 +每次写入指标数据时,会将数据分别写入6个bucket内,每隔两分钟移动一个bucket并且清除原来bucket内的数据 +读取指标时,读取当前current指向的bucket,以达到滑动窗口的效果 +具体如下图所示,实现了当前 bucket 内存储了配置中设置的 bucket 生命周期内的数据,即近期数据 +![img_1.png](/imgs/docs3-v2/java-sdk/observability/aggre.png) + +在每个bucket内,使用**TDigest 算法**计算分位数指标 + +> **TDigest 算法**(极端分位精确度高,如p1 p99,中间分位精确度低,如p50),相关资料如下 +> +> - https://op8867555.github.io/posts/2018-04-09-tdigest.html +> - https://blog.csdn.net/csdnnews/article/details/116246540 +> - 开源实现:https://github.com/tdunning/t-digest + +代码实现如下,除了 TimeWindowQuantile 用来计算分位数指标外,另外提供了 TimeWindowCounter 来收集时间区间内的指标数量 +```java +public class TimeWindowQuantile { + private final double compression; + private final TDigest[] ringBuffer; + private int currentBucket; + private long lastRotateTimestampMillis; + private final long durationBetweenRotatesMillis; + + public TimeWindowQuantile(double compression, int bucketNum, int timeWindowSeconds) { + this.compression = compression; + this.ringBuffer = new TDigest[bucketNum]; + for (int i = 0; i < bucketNum; i++) { + this.ringBuffer[i] = TDigest.createDigest(compression); + } + + this.currentBucket = 0; + this.lastRotateTimestampMillis = System.currentTimeMillis(); + this.durationBetweenRotatesMillis = TimeUnit.SECONDS.toMillis(timeWindowSeconds) / bucketNum; + } + + public synchronized double quantile(double q) { + TDigest currentBucket = rotate(); + return currentBucket.quantile(q); + } + + public synchronized void add(double value) { + rotate(); + for (TDigest bucket : ringBuffer) { + bucket.add(value); + } + } + + private TDigest rotate() { + long timeSinceLastRotateMillis = System.currentTimeMillis() - lastRotateTimestampMillis; + while (timeSinceLastRotateMillis > durationBetweenRotatesMillis) { + ringBuffer[currentBucket] = TDigest.createDigest(compression); + if (++currentBucket >= ringBuffer.length) { + currentBucket = 0; + } + timeSinceLastRotateMillis -= durationBetweenRotatesMillis; + lastRotateTimestampMillis += durationBetweenRotatesMillis; + } + return ringBuffer[currentBucket]; + } +} +``` + +# 指标推送 +指标推送只有用户在设置了配置且配置protocol参数后才开启,若只开启指标聚合,则默认不推送指标。 +## 1. Promehteus Pull ServiceDiscovery + 使用dubbo-admin等类似的中间层,启动时根据配置将本机 IP、Port、MetricsURL 推送地址信息至dubbo-admin(或任意中间层)的方式,暴露HTTP ServiceDiscovery供prometheus读取,配置方式如,其中在pull模式下address为可选参数,若不填则需用户手动在Prometheus配置文件中配置地址 + +```java +private void exportHttpServer() { + boolean exporterEnabled = url.getParameter(PROMETHEUS_EXPORTER_ENABLED_KEY, false); + if (exporterEnabled) { + int port = url.getParameter(PROMETHEUS_EXPORTER_METRICS_PORT_KEY, PROMETHEUS_DEFAULT_METRICS_PORT); + String path = url.getParameter(PROMETHEUS_EXPORTER_METRICS_PATH_KEY, PROMETHEUS_DEFAULT_METRICS_PATH); + if (!path.startsWith("/")) { + path = "/" + path; + } + + try { + prometheusExporterHttpServer = HttpServer.create(new InetSocketAddress(port), 0); + prometheusExporterHttpServer.createContext(path, httpExchange -> { + String response = prometheusRegistry.scrape(); + httpExchange.sendResponseHeaders(200, response.getBytes().length); + try (OutputStream os = httpExchange.getResponseBody()) { + os.write(response.getBytes()); + } + }); + + httpServerThread = new Thread(prometheusExporterHttpServer::start); + httpServerThread.start(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} +``` + +## 2. Prometheus Push Pushgateway +用户直接在Dubbo配置文件中配置Prometheus Pushgateway的地址即可,如,其中interval代表推送间隔 + +```java + +private void schedulePushJob() { + boolean pushEnabled = url.getParameter(PROMETHEUS_PUSHGATEWAY_ENABLED_KEY, false); + if (pushEnabled) { + String baseUrl = url.getParameter(PROMETHEUS_PUSHGATEWAY_BASE_URL_KEY); + String job = url.getParameter(PROMETHEUS_PUSHGATEWAY_JOB_KEY, PROMETHEUS_DEFAULT_JOB_NAME); + int pushInterval = url.getParameter(PROMETHEUS_PUSHGATEWAY_PUSH_INTERVAL_KEY, PROMETHEUS_DEFAULT_PUSH_INTERVAL); + String username = url.getParameter(PROMETHEUS_PUSHGATEWAY_USERNAME_KEY); + String password = url.getParameter(PROMETHEUS_PUSHGATEWAY_PASSWORD_KEY); + + NamedThreadFactory threadFactory = new NamedThreadFactory("prometheus-push-job", true); + pushJobExecutor = Executors.newScheduledThreadPool(1, threadFactory); + PushGateway pushGateway = new PushGateway(baseUrl); + if (!StringUtils.isBlank(username)) { + pushGateway.setConnectionFactory(new BasicAuthHttpConnectionFactory(username, password)); + } + + pushJobExecutor.scheduleWithFixedDelay(() -> push(pushGateway, job), pushInterval, pushInterval, TimeUnit.SECONDS); + } +} + +protected void push(PushGateway pushGateway, String job) { + try { + pushGateway.pushAdd(prometheusRegistry.getPrometheusRegistry(), job); + } catch (IOException e) { + logger.error("Error occurred when pushing metrics to prometheus: ", e); + } +} +``` + +## 可视化展示 +目前推荐使用 Prometheus 来进行服务监控,Grafana 来展示指标数据。可以通过案例来快速入门 [Dubbo 可视化监控](/en/overview/tasks/observability/grafana/)。 diff --git a/content/en/blog/rust/_index.md b/content/en/blog/rust/_index.md new file mode 100644 index 000000000000..600d73423ed1 --- /dev/null +++ b/content/en/blog/rust/_index.md @@ -0,0 +1,7 @@ + +--- +title: "Rust" +linkTitle: "Rust" +weight: 31 +--- + diff --git a/content/en/blog/rust/first-release.md b/content/en/blog/rust/first-release.md new file mode 100644 index 0000000000000000000000000000000000000000..8c0a2c16a89e971f8ed217c56e1d1ef56700fc8a GIT binary patch literal 9493 zcmb7K>vI!VmY>i4SKKjGvo?cdY}nn2GsD&v+0A5UGRp$rD2m8-W3%j~a|bJbCxJCa$TfCqK7a78l*I?FPe&b!FPbjRqp$ za85K_H4|nmV~W3|EHl$^)98#@;J5XBYip$Ce5Cb)(P?Hn((xWEo=UcfOTrNNBW|V# z?8=B+8MVv(S}esepU=E9-{Ri+XlwMmaAzMo%O!dINDeP~j}GONf_-@GKHG4n_aWC$ z2L%>GQE^v~WTEWLzi}4Uy!FR&@Cla7@jkmW#>;=q^%)W9*9dKr#aa7s)Gn1ju4bHH z9T@dq_p&N*pff&UAI(+2pK)^Q;ONI(uQT%$9N~=|-*Se&lkcXmOI*EjSvV{G&f+dM z$%%sVe7BmL^^OOeu{D`r)5m>nX6^{KC=<3z+j6TwV$YAt;T7kHiaXIyk`K>;eXYY% z1ss8Axw&fqlJcYdQf zFaT}UdFt$Ad60vTdbvDoWgkGaS+eoqUUeq#ZB@u_XU>S0u!wFk2f4K+?ZbJpppF;F zT^*RT4`!YDoU>E$_8yTsXU3eFrK(bly*~mq1ZJ`Kmz@g^VlNCpF3|~ddFkf z1-_i}ggh#0YXtV3-(aglH!ytQ4bZWDyh1(^vYxv+1plipymaP=+=X0qVNsS!FdgXI z2QzZ`I4}+icmey_LzQ>XcI9(Wyj`A@V@vL{B{@DK*AAIOXbx(tKH6{(e{eQd5EoDw zIsN7;`yJ>rJz8H6BamGlJ(q*qAkOYUSn+O(SeiP9J?+XG!igEcc8DPUD|Rmi7Qaj- zV#zLHmsZ{NQO2AgNGKk$3M!+ibXW7u#-DxE6i^`|s8%}j@hHV3P-sOjvX~${L zQEwQrlvL!Ap9CtH7#z8CC1>lI0suhNblB*DLn_>s+x_xrP`mTscPG%nS?u)&b^@@K z#UYvB0I)j+tM%vNKu)Hb4)YZit2XZDgjO4(1qyI4pp_$jAs*<@WG6L{%434ZWly-SLjJ`X&|m zyO~bG4hVO^{fVQ&8Tmi4r9e+(?Z7yppTecEW?-yqJ?S_?{c<9e?ZipS6F?m3<*w(5 z)p{MXP>gfXw6{{giIG01q> z!YjR`UZOh0m{wB=6H8krdfeY z?dwQ4f;ZZe>}oO$_@iAK_KvqvpMVgw0sdHaIoOY6ijb0nyGU9TYE#>APrL`#!<&$4 zumBPM?5~frmB@k8?h3^X0+%a>pukg>VVkgVxpDwIA&v=z=62l5loo>%06nPn`Y=0Mod=jd%!O}1-@8~JjdtiQgz*%{PJ$7XbfQSSjM+X!` z463wG6~U?;>XUQJs69^boZq83evQIpgdrLs9@sa9AV;Uhp&dttdB1-i3CS(YO^xEQf>gE!uSj4S>e&sb*COk?HcR5EFH zSSfn{pYepHzElEsq!R2IUnTFQ?wVNepTv#TZ%hjz5*$Q?bDaY2}@njhaL%Na^U<{0+M$s1|<#Eg&*03ln z=|>PyffJUonz>40M<-uy75|fscia`%tXSGIE(zjdYDZu8a5-ICbLU6IkGTmI1zbu0 zn41)lOZ26}jB8)~NpQI10a5-3mGKNgQ~pQ{H1G=pEx~+VVaept5g*$bh+JJtG+=_g6UeKxJOfKKv1aY5K*9Ov_=Jb zB}lqqdZ-$_57U5az7rZ3q5@Tqw>3%ojf+t~URB_!2OL{aK4K!P;P zQQS;gh>D7LG->>ERCvb|z*|lJqx>m;1WRUo^UXIsI+E+&H#duDvwG6pl{QU;L{xn; zG7pkg>~G=^qCtJW(D1ooq*TvE{4dJ8Tiw}&MF4Z_c06Hbu+B29pc6u2z; z_ohyDiOR&fu{>&}<5*?j-0SE*X+RJt9x}A6BZX7rNva1eJkDm!^gm@pGS+QI4S&s- z%;!~x7xAqD)SwNt3VgJDZafUpXYBd81C-3zoH_dw?UFh+7y({r@Y2yopP=)80f&tWvcErsLx^JpKSlggJM_{Mh@vaaZ<3@Wnp6HBxWOGD439Svpt&0kQlEGQtr>lxe zGbchpd%lhf1u;50NFP*;8fR`;sk`x1TU$3==%x{a3wMayNkJbQn_x_86sFBCN(kv& zWI{9T8-oMwE4Zj$M{7xs=#={EgPL!#uQfKEQ^X#^eCiF%uUKkpOPco^o1zMq@EW@x zi(8+oCE@4l3pycsAKigltj$JdkiMqBglUO1w01R>vXHo-ZcUuY@gf1?td2V(9ZjTS zoq>@4Lwf!1yNyi0N&Mjw1sEtX_u*Clkxn<>GSg|bs3(?;cl^4s0iWB%w{8FS5N%oY z@SK34LGr#I%ZSc&s>kdMLOuHU7vB@54RQi=s7jT?~{(k{S ze%zh4L`NbHZ`Ry0AwODF5MNbTk6^@P9j<>L!9n#dS>8e92cJZ4O6& zh#?)Z#9b}oVOEMO6@K)lMv)@Z4@^!Wq9(fzPI}He9@gYtsG3GF8mkIVmxJ5yxR&Bd6&)qI zE~w@PY9gK5xI*Nzk!wl6G*nls3qZbDXLqazP2jQc+$B6<@t1Hjg_{d@X^8p=GrLX^ zlL^%-!}Ut$2dQA@UN?92YeN*|8onO!wTc#Qt}+E(O{Ona ztGiXvGqg1-)ABfvAq%BAVuD5k%OzcH)?7iRKoFp&yHu zB@eU0GH9m#J{p&=;DuWY#FUzUaoLXs2lnFf!j+@9o5yg8)*SSqAojK&p$f)FGpRq@?U zGg;pQs=k<@uF#87=z(~yZ~9;hd>G!#O>o?m(5;0XU^tAaI9@??^Lhqz10& zjB){DhShlTFn{EMzBcvSFbY%i7al@6kC$YA$J>2{UAhH~1!`8tqfMNP+a+m0S=Q@) zhUqZRJK4nS17uADZ@IH*AFU&5(9H=e;irQ^xVqmaAJSZx3x1pq2JXzr5v&Aj-g>{c z{)F1+aIPWW2nuiXeI4Z{N6CCFIH*5s1!;KBGqzs(A-&gPJ*sZ ztI(W56OVFBd5+rq3X`gsvcBuX_zrInsX^$|fcbTwhIh_C!SGRQcYmb%dh8G3LR@gr{_zZY$cyR)~^I=SeNg>EzreYi>h6wP2(Bw% zUnVYcOLF)-?INrRY(#=bX=9hm&fJ2`V-WEg=hl6%h7$7doqUQh0nH-d-_@Dp>Oev6 z?cg8afQ@LEp5oUXPy%HIjDj(LDX$`T!tpUiB5~C3H<-Adb*!VeIEEpD`qj&6_XROd z4M8tn4lHAQuLd|1^X|?|nhGczR-X*vAN-2GQRG-gIbM*H8_Ym$&G;VX-WMlkLZ+vL-AE6lQji?1>z}h;STkuCh+PWgjUr50WPlt(f|Me literal 0 HcmV?d00001 diff --git a/content/en/blog/users/_index.md b/content/en/blog/users/_index.md new file mode 100644 index 000000000000..a6b79fae363b --- /dev/null +++ b/content/en/blog/users/_index.md @@ -0,0 +1,6 @@ +--- +title: "用户案例" +linkTitle: "用户案例" +weight: 10 +--- + diff --git a/content/en/blog/users/alibaba.md b/content/en/blog/users/alibaba.md new file mode 100644 index 000000000000..9874159a0a51 --- /dev/null +++ b/content/en/blog/users/alibaba.md @@ -0,0 +1,57 @@ +--- +title: "阿里巴巴升级 Dubbo3 全面取代 HSF2" +linkTitle: "阿里巴巴" +tags: ["用户案例"] +date: 2023-01-16 +weight: 1 +--- + +继业务全面上云后,2022 双十一,阿里巴巴微服务技术栈全面迁移到以 Dubbo3 为代表的云上开源标准中间件体系。在业务上,基于 Dubbo3 首次实现了关键业务不停推、不降级的全面用户体验提升,从技术上,大幅提高研发与运维效率的同时地址推送等关键资源利用率提升超 40%,基于三位一体的 Dubbo3 开源中间件体系打造了阿里在云上的单元化最佳实践和统一标准,同时将规模化实践经验与技术创新贡献开源社区,成为微服务开源技术与标准发展的核心源泉与推动力。 +## 1 阿里电商 +![image.png](/imgs/blog/users/tmall.png) ![image.png](/imgs/blog/users/taobao.png) ![image.png](/imgs/blog/users/kaola.png) ...... + +整个电商体系的所有核心应用,包括交易相关、导购相关都都升级到了 Dubbo3 体系,用来升级原有的 HSF 框架,阿里电商是对 Dubbo3 实践最广泛、需求最强烈的体系,基于 Dubbo3 实现了以下关键目标。 +2022 618大促、双11 大促期间 超 2000+ 应用、40w 节点均跑在 Dubbo3 之上。 + +- 应用级服务发现,解决了大促期间地址推送降级的问题,部分关键链路提升单机资源利用率 40%,大促期间地址推送SLA保障、资源利用率。 +- Triple协议,解决跨网关高效互通的问题,同时部分业务线升级了 Streaming 编程和通信模式。 +- 统一的流量治理规则,阿里电商场景的路由规则非常复杂,基于实现了云原生体系的结合。 +- Service Mesh 解决方案,Thin SDK + Proxyless 的解决方案 +- 服务柔性,目前正在落地和探索自适应负载均衡、自适应限流等策略。 + +## 2 蚂蚁金服 +![image.png](/imgs/blog/users/antpay.png) ![image.png](/imgs/blog/users/feizhu.png) ![image.png](/imgs/blog/users/1688.png)![image.png](/imgs/blog/users/taobao.png) + +阿里集团内与蚂蚁体系的互通,目前都跑在 Dubbo3 Triple 互通链路上,与原有基于 HSF 的互通方案对比,Triple 协议链路的 RT 降低了 50%。集团与蚂蚁东西向流量的核心链路,飞猪、手淘、口碑、饿了么、1688、部分导购应用、商品库、评价等业务都采用此方案。 + +## 3 本地生活 +![image.png](/imgs/blog/users/eleme.png) ![image.png](/imgs/blog/users/amap.png) + +截止 2022 年初,Dubbo3 实现了在饿了么全量业务的生产上线,取代了之前自建的微服务体系,在过去的近一年时间内,饿了么线上有 2000 应用、15w 实例节点平稳跑在 Dubbo3 之上。 + +饿了么成功升级 Dubbo3 及应用级服务发现模型,实现了和阿里电商系统互通、单元化体系互通架构的升级,实现了去 proxy 架构的目标,在饿了么关心的服务发现数据链路上: + +- 数据注册与订阅的传输量下降 90% +- 注册中心数据存储的总体资源占用下降 90% +- 消费端服务框架自身的常驻内存消耗下降达 50% + +集群总体的稳定性、性能都得到明显提升,也为未来容量扩展做好准备。 +## 4 钉钉 +![image.png](/imgs/blog/users/alibaba/1670649135935-0d6804cc-00ca-4acb-a7b3-842377d1a6b0.png) + +钉钉核心业务在 2021 年实现了 Dubbo3 升级,基于 Triple 协议解决了云上、云下混合部署环境的互通问题。 + + +## 5 阿里云 +![image.png](/imgs/blog/users/alibaba/1670649159068-ed9ba59b-9e3d-4268-be7e-c327227baa7b.png) + +阿里云公有云、转有云核心底座目前正全面迁移到 Dubbo3 体系,取代老版本的 Dubbo2 体系,预计本财年结束就能全部跑在 Dubbo3 之上。 +除此之外,阿里云平台上的大部分对外售卖产品,目前都基于 Dubbo3 提供服务或提供 Dubbo3 支持,如微服务引擎MSE、达摩院店小蜜、教育平台、视频云业务等。 + +## 6 菜鸟 +![image.png](/imgs/blog/users/alibaba/1670650418063-31eee85d-9e6a-474c-ade7-4a45fc956ae4.png) + +2022 年中下旬,菜鸟网络部分核心业务开始推进 Dubbo3 的全面升级,目前生产数据正在采集中。 + + + diff --git a/content/en/blog/users/dianxiaomi.md b/content/en/blog/users/dianxiaomi.md new file mode 100644 index 000000000000..d88fced777e8 --- /dev/null +++ b/content/en/blog/users/dianxiaomi.md @@ -0,0 +1,119 @@ +--- +title: "店小蜜升级 Triple 协议" +linkTitle: "达摩院云小蜜" +tags: ["用户案例"] +date: 2023-01-15 +weight: 4 +--- + +# 前言 +阿里云-达摩院-云小蜜对话机器人产品基于深度机器学习技术、自然语言理解技术和对话管理技术,为企业提供多引擎、多渠道、多模态的对话机器人服务。17年云小蜜对话机器人在公共云开始公测,同期在混合云场景也不断拓展。为了同时保证公共云、混合云发版效率和稳定性,权衡再三我们采用了1-2个月一个大版本迭代。 +经过几年发展,为了更好支撑业务发展,架构升级、重构总是一个绕不过去的坎,为了保证稳定性每次公共云发版研发同学都要做两件事: + + 1. 梳理各个模块相较线上版本接口依赖变化情况,决定十几个应用的上线顺序、每批次发布比例; + 2. 模拟演练上述1产出的发布顺序,保证后端服务平滑升级,客户无感知; + +上述 1、2 动作每次都需要 2-3 周左右的时间梳理、集中演练,但是也只能保证开放的PaaS API平滑更新; + +控制台服务因为需要前端、API、后端保持版本一致才能做到体验无损(如果每次迭代统一升级API版本开发、协同成本又会非常大),权衡之下之前都是流量低谷期上线,尽量缩短发布时间,避免部分控制台模块偶发报错带来业务问题。针对上面问题,很早之前就考虑过用蓝绿发布、灰度等手段解决,但是无奈之前对话机器人在阿里云内部业务区域,该不再允许普通云产品扩容,没有冗余的机器,流量治理完全没法做。 + +# 迁移阿里云云上 + +带着上面的问题,终于迎来的 2021 年 9 月份,云小蜜将业务迁移至阿里云云上。 + +## Dubbo3 的实践 + +“当时印象最深的就是这张图,虽然当时不知道中间件团队具体要做什么事情,但是记住了两个关键词:三位一体、红利。没想到在2021年底,真真切切享受到了这个红利。” + +![image1](/imgs/v3/users/yunxiaomi-1.png) + +云小蜜使用的是集团内部的HSF服务框架,需要迁移至阿里云云上,并且存在阿里云云上与阿里内部业务域的互通、互相治理的诉求。云小蜜的公共服务部署在公有云VPC,部分依赖的数据服务部署在内部,内部与云上服务存在RPC互调的诉求,其实属于混合云的典型场景。 +简单整理了下他们的核心诉求,概括起来有以下三点吧:希望尽可能采用开源方案,方便后续业务推广;在网络通信层面需要保障安全性;对于业务升级改造来说需要做到低成本。 + +![image2](/imgs/v3/users/yunxiaomi-2.png) + +在此场景下,经过许多讨论与探索,方案也敲定了下来 + +- 全链路升级至开源 Dubbo3.0,云原生网关默认支持Dubbo3.0,实现透明转发,网关转发RT小于1ms +- 利用 Dubbo3.0 支持HTTP2特性,云原生网关之间采用 mTLS 保障安全 +- 利用云原生网关默认支持多种注册中心的能力,实现跨域服务发现对用户透明,业务侧无需做任何额外改动 +- 业务侧升级SDK到支持 Dubbo3.0,配置发布 Triple 服务即可,无需额外改动 + +**解决了互通、服务注册发现的问题之后,就是开始看如何进行服务治理方案了** + +# 阿里云云上流量治理 + +迁移至阿里云云上之后,流量控制方案有非常多,比如集团内部的全链路方案、集团内单元化方案等等。 + +## 设计目标和原则 + +1. 要引入一套流量隔离方案,上线过程中,新、旧两个版本服务同时存在时,流量能保证在同一个版本的“集群”里流转,这样就能解决重构带来的内部接口不兼容问题。 +2. 要解决上线过程中控制台的平滑性问题,避免前端、后端、API更新不一致带来的问题。 +3. 无上线需求的应用,可以不参与上线。 +4. 资源消耗要尽量少,毕竟做产品最终还是要考虑成本和利润。 + +## 方案选型 + +1. 集团内部的全链路方案:目前不支持阿里云云上 +2. 集团内单元化方案:主要解决业务规模、容灾等问题,和我们碰到的问题不一样 +3. 搭建独立集群,版本迭代时切集群:成本太大 +4. 自建:在同一个集群隔离新、老服务,保证同一个用户的流量只在同版本服务内流转 + +以RPC为例: + +* 方案一:通过开发保证,当接口不兼容升级时,强制要求升级HSF version,并行提供两个版本的服务; 缺点是一个服务变更,关联使用方都要变更,协同成本特别大,并且为了保持平滑,新老接口要同时提供服务,维护成本也比较高 +* 方案二:给服务(机器)按版本打标,通过RPC框架的路由规则,保证流量优先在同版本内流转 + +## 全链路灰度方案 + +就当1、2、3、4都觉得不完美,一边调研一边准备自建方案5的时候,兜兜绕绕拿到了阿里云 MSE 微服务治理团队[《20分钟获得同款企业级全链路灰度能力》](https://yuque.antfin.com/docs/share/a8df43ac-3a3b-4af4-a443-472828884a5d?#),方案中思路和准备自建的思路完全一致,也是利用了RPC框架的路由策略实现的流量治理,并且实现了产品化(微服务引擎-微服务治理中心),同时,聊了两次后得到几个“支持”,以及几个“后续可以支持”后,好像很多事情变得简单了... + +![image3](/imgs/v3/users/yunxiaomi-3.png) + +从上图可以看到,各个应用均需要搭建基线(base)环境和灰度(gray)环境,除了流量入口-业务网关以外,下游各个业务模块按需部署灰度(gray)环境,如果某次上线某模块没有变更则无需部署。 + +### 各个中间件的治理方案 + +1. Mysql、ElasticSearch:持久化或半持久化数据,由业务模块自身保证数据结构兼容升级; +2. Redis:由于对话产品会有多轮问答场景,问答上下文是在Redis里,如果不兼容则上线会导致会话过程中的C端用户受影响,因此目前Redis由业务模块自身保证数据结构兼容升级; +3. 配置中心:基线(base)环境、灰度(gray)环境维护两套全量配置会带来较大工作量,为了避免人工保证数据一致性成本,基线(base)环境监听dataId,灰度(gray)环境监听gray.dataId如果未配置gray.dataId则自动监听dataId;(云小蜜因为在18年做混合云项目为了保证混合云、公共云使用一套业务代码,建立了中间件适配层,本能力是在适配层实现) +4. RPC服务:使用阿里云 one agent 基于Java Agent技术利用Dubbo框架的路由规则实现,无需修改业务代码; + +应用只需要加一点配置: + +* 1)linux环境变量 +alicloud.service.tag=gray标识灰度,基线无需打标 +profiler.micro.service.tag.trace.enable=true标识经过该机器的流量,如果没有标签则自动染上和机器相同的标签,并向后透传 +* 2)JVM参数,标识开启MSE微服务流量治理能力** SERVICE_OPTS=**"$**{SERVICE_OPTS}** -Dmse.enable=true"** + +### 流量管理方案 + +流量的分发模块决定流量治理的粒度和管理的灵活程度。 + +对话机器人产品需要灰度发布、蓝绿发布目前分别用下面两种方案实现: + +1. 灰度发布: +部分应用单独更新,使用POP的灰度引流机制,该机制支持按百分比、UID的策略引流到灰度环境 +2. 蓝绿发布: + * 1)部署灰度(gray)集群并测试:测试账号流量在灰度(gray)集群,其他账号流量在基线(base)集群 + * 2)线上版本更新:所有账号流量在灰度(gray)集群 + * 3)部署基线(base)集群并测试:测试账号流量在基线(base)集群,其他账号流量在灰度(gray)集群 + * 4)流量回切到基线(base)集群并缩容灰度(gray)环境:所有账号流量在基线(base)集群 + +## 全链路落地效果 + +上线后第一次发布的效果:“目前各个模块新版本的代码已经完成上线,含发布、功能回归一共大约花费2.5小时,相较之前每次上线到凌晨有很大提升。” +MSE 微服务治理全链路灰度方案满足了云小蜜业务在高速发展情况下快速迭代和小心验证的诉求,通过JavaAgent技术帮助云小蜜快速落地了企业级全链路灰度能力。 +流量治理随着业务发展会有更多的需求,下一步,我们也会不断和微服务治理产品团队,扩充此解决方案的能力和使用场景,比如:rocketmq、schedulerx的灰度治理能力。 + +## 更多的微服务治理能力 + +使用 MSE 服务治理后,发现还有更多开箱即用的治理能力,能够大大提升研发的效率。包含服务查询、服务契约、服务测试等等。这里要特别提一下就是云上的服务测试,服务测试即为用户提供一个云上私网 Postman ,让我们这边能够轻松调用自己的服务。我们可以忽略感知云上复杂的网络拓扑结构,无需关系服务的协议,无需自建测试工具,只需要通过控制台即可实现服务调用。支持 Dubbo 3.0 框架,以及 Dubbo 3.0 主流的 Triple 协议。 + +![image4](/imgs/v3/users/yunxiaomi-4.png) + +# 结束语 + +最终云小蜜对话机器人团队成功落地了全链路灰度功能,解决了困扰团队许久的发布效率问题。在这个过程中我们做了将部分业务迁移至阿里云云上、服务框架升级至Dubbo3.0、选择MSE微服务治理能力等等一次次新的选择与尝试。“世上本没有路,走的人多了便成了路”。经过我们工程师一次又一次的探索与实践,能够为更多的同学沉淀出一个个最佳实践。我相信这些最佳实践将会如大海中璀璨的明珠般,经过生产实践与时间的打磨将会变得更加熠熠生辉。 + + diff --git a/content/en/blog/users/eleme.md b/content/en/blog/users/eleme.md new file mode 100644 index 000000000000..2829d87df4eb --- /dev/null +++ b/content/en/blog/users/eleme.md @@ -0,0 +1,57 @@ +--- +title: "饿了么全站成功升级 Dubbo3 " +linkTitle: "饿了么" +date: 2023-01-15 +tags: ["用户案例"] +weight: 3 +--- +### 升级目标 +![elem-arc](/imgs/user/eleme/elem-arc.png) + +这里是饿了么的的基本部署架构图。 + +在升级之前,饿了么的微服务框架采用的是 HSF2,跨单元的 RPC 调用是通过 proxy 中转代理,在这个过程中 proxy 所承载的机器数和流量迅速增长,比较突出的一点是 proxy 在订阅所有的地址数据后资源消耗和稳定性都收到严峻挑战。 + +通过全站升级 Dubbo3,业务线期望达到两个目标: +* 将地址模型切换到应用级服务发现大幅减轻中心化节点和消费端节点的资源消耗压力。 +* 以应用级服务发现架构下的全局共享注册中心取代 proxy 模式,实现跨单元节点通信直连。 + + +### 升级过程 +![eleme-upgrade1](/imgs/user/eleme/elem-upgrade1.png) + +不论是针对 Dubbo2 还是 HSF2,我们都做了全面的 API 兼容,因此 Dubbo3 基本可以做到零改造升级,并且每个应用都是独立透明升级,不需要关心它的上下游应用的升级状态,因为 Dubbo3 升级之后不论是从地址发现模型还是协议的默认行为都保持与 2.0 版本兼容,用户可以在任意时间点对任意应用按需切换 Dubbo3 行为。 +如右图所示,我们模拟展示了饿了么集群 Dubbo3 升级过程的一个中间状态,其中灰色标记的是老版本 HSF2 应用,橙色和绿色标记的是已经升级 Dubbo3 的应用,橙色部分的应用及其调用链路代表不但已经升级到 Dubbo3,同时也完成了 Dubbo3 行为的切换,在这里是指已经切换到了应用级地址模型。这里的升级过程主要为了说明 Dubbo3 框架升级的兼容性和独立性。 + +接下来,我们详细分析一下橙色部分节点往 Dubbo3 应用级发现迁移的具体过程。 + +![elem-upgrade-provider](/imgs/user/eleme/elem-upgrade-provider.png) + +首先看 Provider 侧,服务提供者在升级 Dubbo3 后会默认保持双注册行为,即同时注册接口级地址和应用级地址到注册中心,一方面保持兼容,另一方面为未来消费端迁移做好准备。双注册的开关可通过 -Ddubbo.application.register-mode=al/interface/interface控制,我们推荐保持双注册的默认行为以减少后续迁移成本。 + +大家可能担心双注册给注册中心带来的存储压力,实际上在应用级服务发现模型下这并不是一个问题,因为大家如果回想前面我们对应用级服务发现工作原理的分析,注册地址已经被大幅精简,根据我们实际推算,每多注册一条应用级服务发现 URL 地址,只会增加 0.1% ~ 1% 的额外开销。 + +![elem-upgrade-consumer](/imgs/user/eleme/elem-upgrade-consumer.png) + +与提供端类似,要实现平滑迁移消费端也要经历双订阅的过程,流程上就不再赘述。消费端的双订阅行为也可通过规则或开关进行动态调整,控制消费端的消费的某个服务、应用迁移到应用级地址模型;除此之外,Dubbo3 还内置了自动决策机制,在发现应用级地址可用的情况下即会自动完成切换,并且这个行为是默认的。 + +以下是消费端双订阅时的选址流程: + +![elem-upgrade-consumer1](/imgs/user/eleme/elem-upgrade-consumer1.png) + +### 升级效果 + +![elem-result](/imgs/user/eleme/elem-result.png) + +饿了么成功升级 Dubbo3 及应用级服务发现模型,实现了去 proxy 架构的目标,在我们关心的服务发现数据链路上: +* 数据注册与订阅的传输量下降 90% +* 注册中心数据存储的总体资源占用下降 90% +* 消费端服务框架自身的常驻内存消耗下降达 50% +集群总体的稳定性、性能都得到明显提升,也为未来容量扩展做好准备。 + + + + + + + diff --git a/content/en/blog/users/guazi.md b/content/en/blog/users/guazi.md new file mode 100644 index 000000000000..2eeac96b238f --- /dev/null +++ b/content/en/blog/users/guazi.md @@ -0,0 +1,175 @@ +--- +title: "瓜子二手车 Dubbo 实践" +linkTitle: "瓜子二手车" +tags: ["用户案例"] +date: 2023-01-15 +weight: 4 +--- + +## 前言 + +  随着瓜子业务的不断发展,系统规模在逐渐扩大,目前在瓜子的私有云上已经运行着数百个dubbo应用,上千个dubbo实例。瓜子各部门业务迅速发展,版本没有来得及统一,各个部门都有自己的用法。随着第二机房的建设,dubbo版本统一的需求变得越发迫切。几个月前,公司发生了一次与dubbo相关的生产事故,成为了公司dubbo版本升级的诱因。 + +  接下来,我会从这次事故开始,讲讲我们这段时间所做的dubbo版本升级的历程以及dubbo后续多机房的方案。 + +## 一、Ephermal节点未及时删除导致provider不能恢复注册的问题修复 + +### 事故背景 + +  在生产环境,瓜子内部各业务线共用一套zookeeper集群作为dubbo的注册中心。2019年9月份,机房的一台交换机发生故障,导致zookeeper集群出现了几分钟的网络波动。在zookeeper集群恢复后,正常情况下dubbo的provider应该会很快重新注册到zookeeper上,但有一小部分的provider很长一段时间没有重新注册到zookeeper上,直到手动重启应用后才恢复注册。 + +### 排查过程 + +  首先,我们统计了出现这种现象的dubbo服务的版本分布情况,发现在大多数的dubbo版本中都存在这种问题,且发生问题的服务比例相对较低,在github中我们也未找到相关问题的issues。因此,推断这是一个尚未修复的且在网络波动情况的场景下偶现的问题。 + +  接着,我们便将出现问题的应用日志、zookeeper日志与dubbo代码逻辑进行相互印证。在应用日志中,应用重连zookeeper成功后provider立刻进行了重新注册,之后便没有任何日志打印。而在zookeeper日志中,注册节点被删除后,并没有重新创建注册节点。对应到dubbo的代码中,只有在`FailbackRegistry.register(url)`的`doRegister(url)`执行成功或线程被挂起的情况下,才能与日志中的情况相吻合。 + +```java + public void register(URL url) { + super.register(url); + failedRegistered.remove(url); + failedUnregistered.remove(url); + try { + // Sending a registration request to the server side + doRegister(url); + } catch (Exception e) { + Throwable t = e; + + // If the startup detection is opened, the Exception is thrown directly. + boolean check = getUrl().getParameter(Constants.CHECK_KEY, true) + && url.getParameter(Constants.CHECK_KEY, true) + && !Constants.CONSUMER_PROTOCOL.equals(url.getProtocol()); + boolean skipFailback = t instanceof SkipFailbackWrapperException; + if (check || skipFailback) { + if (skipFailback) { + t = t.getCause(); + } + throw new IllegalStateException("Failed to register " + url + " to registry " + getUrl().getAddress() + ", cause: " + t.getMessage(), t); + } else { + logger.error("Failed to register " + url + ", waiting for retry, cause: " + t.getMessage(), t); + } + + // Record a failed registration request to a failed list, retry regularly + failedRegistered.add(url); + } + } +``` +  在继续排查问题前,我们先普及下这些概念:dubbo默认使用curator作为zookeeper的客户端,curator与zookeeper是通过session维持连接的。当curator重连zookeeper时,若session未过期,则继续使用原session进行连接;若session已过期,则创建新session重新连接。而ephemeral节点与session是绑定的关系,在session过期后,会删除此session下的ephemeral节点。 + +  继续对`doRegister(url)`的代码进行进一步排查,我们发现在`CuratorZookeeperClient.createEphemeral(path)`方法中有这么一段逻辑:在`createEphemeral(path)`捕获了`NodeExistsException`,创建ephemeral节点时,若此节点已存在,则认为ephemeral节点创建成功。这段逻辑初看起来并没有什么问题,且在以下两种常见的场景下表现正常: + +1. Session未过期,创建Ephemeral节点时原节点仍存在,不需要重新创建 +1. Session已过期,创建Ephemeral节点时原节点已被zookeeper删除,创建成功 + +```java + public void createEphemeral(String path) { + try { + client.create().withMode(CreateMode.EPHEMERAL).forPath(path); + } catch (NodeExistsException e) { + } catch (Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } +``` +  但是实际上还有一种极端场景,**zookeeper的Session过期与删除Ephemeral节点不是原子性的**,也就是说客户端在得到Session过期的消息时,Session对应的Ephemeral节点可能还未被zookeeper删除。此时dubbo去创建Ephemeral节点,发现原节点仍存在,故不重新创建。待Ephemeral节点被zookeeper删除后,便会出现dubbo认为重新注册成功,但实际未成功的情况,也就是我们在生产环境遇到的问题。 + +  此时,问题的根源已被定位。定位问题之后,我们与dubbo社区交流,发现考拉的同学也遇到过同样的问题,更确定了这个原因。 + +### 问题的复现与修复 + +  定位到问题之后,我们便开始尝试本地复现。由于zookeeper的Session过期但Ephemeral节点未被删除的场景直接模拟比较困难,我们通过修改zookeeper源码,在Session过期与删除Ephemeral节点的逻辑中增加了一段休眠时间,间接模拟出这种极端场景,并在本地复现了此问题。 + +  在排查问题的过程中,我们发现kafka的旧版本在使用zookeeper时也遇到过类似的问题,并参考kafka关于此问题的修复方案,确定了dubbo的修复方案。在创建Ephemeral节点捕获到`NodeExistsException`时进行判断,若Ephemeral节点的SessionId与当前客户端的SessionId不同,则删除并重建Ephemeral节点。在内部修复并验证通过后,我们向社区提交了issues及pr。 + +  kafka类似问题issues:https://issues.apache.org/jira/browse/KAFKA-1387 + +  dubbo注册恢复问题issues:https://github.com/apache/dubbo/issues/5125 + +## 二、瓜子的dubbo升级历程 + +  上文中的问题修复方案已经确定,但我们显然不可能在每一个dubbo版本上都进行修复。在咨询了社区dubbo的推荐版本后,我们决定在dubbo2.7.3版本的基础上,开发内部版本修复来这个问题。并借这个机会,开始推动公司dubbo版本的统一升级工作。 + +### 为什么要统一dubbo版本 +1. 统一dubbo版本后,我们可以在此版本上内部紧急修复一些dubbo问题(如上文的dubbo注册故障恢复失效问题)。 +2. 瓜子目前正在进行第二机房的建设,部分dubbo服务也在逐渐往第二机房迁移。统一dubbo版本,也是为dubbo的多机房做铺垫。 +3. 有利于我们后续对dubbo服务的统一管控。 +4. dubbo社区目前的发展方向与我们公司现阶段对dubbo的一些诉求相吻合,如支持gRPC、云原生等。 + +### 为什么选择dubbo2.7.3 +1. 在我们之前,携程与dubbo社区合作进行了携程dubbo内部版本的升级,并在社区2.7.3版本上修复了很多兼容性问题。感谢携程的同学帮我们踩坑~ +2. dubbo2.7.3版本在当时虽然是最新的版本,但已经发布了2个月的时间,从社区issues反馈来看,dubbo2.7.3相对dubbo2.7之前的几个版本,在兼容性方面要好很多。 +3. 我们也咨询了dubbo社区的同学,推荐升级版本为2.7.3。 + +### 内部版本定位 + +  基于社区dubbo2.7.3版本开发的dubbo内部版本属于过渡性质的版本,目的是为了修复线上provider不能恢复注册的问题,以及一些社区dubbo2.7.3的兼容性问题。瓜子的dubbo最终还是要跟随社区的版本,而不是开发自已的内部功能。因此我们在dubbo内部版本中修复的所有问题均与社区保持了同步,以保证后续可以兼容升级到社区dubbo的更高版本。 + +### 兼容性验证与升级过程 + +  我们在向dubbo社区的同学咨询了版本升级方面的相关经验后,于9月下旬开始了dubbo版本的升级工作。 +1. **初步兼容性验证** +首先,我们梳理了一些需要验证的兼容性case,针对公司内部使用较多的dubbo版本,与dubbo2.7.3一一进行了兼容性验证。经验证,除dubboX外,dubbo2.7.3与其他dubbo版本均兼容。dubboX由于对dubbo协议进行了更改,与dubbo2.7.3不兼容。 +1. **生产环境兼容性验证** +在初步验证兼容性通过后,我们与业务线合作,挑选了一些重要程度较低的项目,在生产环境对dubbo2.7.3与其他版本的兼容性进行了进一步验证。并在内部版本修复了一些兼容性问题。 +1. **推动公司dubbo版本升级** +在10月初,完成了dubbo兼容性验证后,我们开始在各个业务线推动dubbo的升级工作。截止到12月初,已经有30%的dubbo服务的完成了版本升级。按照排期,预计于2020年3月底前完成公司dubbo版本的统一升级。 + +### 兼容性问题汇总 + +  在推动升级dubbo2.7.3版本的过程整体上比较顺利,当然也遇到了一些兼容性问题: +* **创建zookeeper节点时提示没有权限** + dubbo配置文件中已经配置了zookeeper的用户名密码,但在创建zookeeper节点时却抛出`KeeperErrorCode = NoAuth`的异常,这种情况分别对应两个兼容性问题: + * issues:https://github.com/apache/dubbo/issues/5076 + dubbo在未配置配置中心时,默认使用注册中心作为配置中心。通过注册中心的配置信息初始化配置中心配置时,由于遗漏了用户名密码,导致此问题。 + * issues:https://github.com/apache/dubbo/issues/4991 + dubbo在建立与zookeeper的连接时会根据zookeeper的address复用之前已建立的连接。当多个注册中心使用同一个address,但权限不同时,就会出现`NoAuth`的问题。 + 参考社区的pr,我们在内部版本进行了修复。 + +* **curator版本兼容性问题** + * dubbo2.7.3与低版本的curator不兼容,因此我们默认将curator版本升级至4.2.0 + ```xml + + org.apache.curator + curator-framework + 4.2.0 + + + org.apache.curator + curator-recipes + 4.2.0 + + ``` + * 分布式调度框架elastic-job-lite强依赖低版本的curator,与dubbo2.7.3使用的curator版本不兼容,这给dubbo版本升级工作带来了一定阻塞。考虑到elastic-job-lite已经很久没有人进行维护,目前一些业务线计划将elastic-job-lite替换为其他的调度框架。 +* **openFeign与dubbo兼容性问题** + issues: https://github.com/apache/dubbo/issues/3990 + dubbo的ServiceBean监听spring的ContextRefreshedEvent,进行服务暴露。openFeign提前触发了ContextRefreshedEvent,此时ServiceBean还未完成初始化,于是就导致了应用启动异常。 + 参考社区的pr,我们在内部版本修复了此问题。 +* **RpcException兼容性问题** + dubbo低版本consumer不能识别dubbo2.7版本provider抛出的`org.apache.dubbo.rpc.RpcException`。因此,在consumer全部升级到2.7之前,不建议将provider的`com.alibaba.dubbo.rpc.RpcException`改为`org.apache.dubbo.rpc.RpcException` +* **qos端口占用** + dubbo2.7.3默认开启qos功能,导致一些混部在物理机的dubbo服务升级时出现qos端口占用问题。关闭qos功能后恢复。 +* **自定义扩展兼容性问题** + 业务线对于dubbo的自定义扩展比较少,因此在自定义扩展的兼容性方面暂时还没有遇到比较难处理的问题,基本上都是变更package导致的问题,由业务线自行修复。 +* **skywalking agent兼容性问题** + 我们项目中一般使用skywalking进行链路追踪,由于skywalking agent6.0的plugin不支持dubbo2.7,因此统一升级skywalking agent到6.1。 + +## 三、dubbo多机房方案 + +  瓜子目前正在进行第二机房的建设工作,dubbo多机房是第二机房建设中比较重要的一个话题。在dubbo版本统一的前提下,我们就能够更顺利的开展dubbo多机房相关的调研与开发工作。 + +### 初步方案 + +  我们咨询了dubbo社区的建议,并结合瓜子云平台的现状,初步确定了dubbo多机房的方案。 +1. 在每个机房内,部署一套独立的zookeeper集群。集群间信息不同步。这样就没有了zookeeper集群跨机房延迟与数据不同步的问题。 +1. dubbo服务注册时,仅注册到本机房的zookeeper集群;订阅时,同时订阅两个机房的zookeeper集群。 +1. 实现同机房优先调用的路由逻辑。以减少跨机房调用导致的不必要网络延迟。 + +### 同机房优先调用 + +  dubbo同机房优先调用的实现比较简单,相关逻辑如下: +1. 瓜子云平台默认将机房的标志信息注入容器的环境变量中。 +1. provider暴露服务时,读取环境变量中的机房标志信息,追加到待暴露服务的url中。 +1. consumer调用provider时,读取环境变量中的机房标志信息,根据路由策略优先调用具有相同标志信息的provider。 + +  针对以上逻辑,我们简单实现了dubbo通过环境变量进行路由的功能,并向社区提交了pr。 +  dubbo通过环境变量路由pr: https://github.com/apache/dubbo/pull/5348 diff --git a/content/en/blog/users/icbc.md b/content/en/blog/users/icbc.md new file mode 100644 index 000000000000..49d1772530ea --- /dev/null +++ b/content/en/blog/users/icbc.md @@ -0,0 +1,28 @@ +--- +date: 2023-01-15 +title: "工商银行 Dubbo3 应用级服务发现实践" +linkTitle: "工商银行" +tags: ["用户案例"] +weight: 2 +--- + +### 问题分析 +以下是经典的 Dubbo 的工作原理图,服务提供者和消费者通过注册中心协调实现地址的自动发现。 + +![icbc-analyze](/imgs/user/icbc/icbc-analyze.png) + +工商银行面临的主要瓶颈是在注册中心与服务消费端,接口级别地址的数量已经是亿级规模,一方面存储容量达到瓶颈、另一方面推送效率明显下降;而在消费端这一侧,Dubbo2 框架常驻内存已超 40%,每次地址推送带来的 cpu 等资源消耗率也非常高,影响正常的业务调用。 + +这是 Dubbo2 接口级服务发现架构在大规模集群场景下的固有问题(具体原因请查看应用级服务发现原理解析),通过常规的性能优化无法从根本上解决问题。因此工商银行采用了 Dubbo3 中提出的应用级服务发现模型,经过实测,新的服务发现模型能实现节点到注册中心间数据传输量 90% 的下降,这就使得注册中心的压力极大降低,同时消费端的框架常驻内存也实现超 50% 下降。 + +### 压测数据 +下面是工商银行联合 Dubbo 社区给出的一组基于真实服务特点给出的模拟压测数据。 + +![icbc-data1](/imgs/user/icbc/icbc-data1.png) + +上图是对使用了应用级服务发现的消费端进程采样的内存对比数据。其中横轴是不同的 Dubbo 版本,纵轴是实际采样到的内存表现,可以看到 Dubbo 2.6、2.7 版本表现几乎一致,而升级到 3.0 版本后,即使不升级应用级服务发现,内存也降低接近 40%,而当切换到应用级服务发现之后,内存占用下降到只有原来的 30%。 + +![icbc-data2](/imgs/user/icbc/icbc-data2.png) + +上图是消费端的 GC 情况统计,同样的,横轴是不同的 Dubbo 版本,纵轴是实际采样到的 GC 表现。这里的压测数据,是通过模拟注册中心不停的往消费端进程推送地址列表的场景得到的。可以看到 Dubbo 2.6、2.7 版本表现几乎一致,而在 3.0 版本中切换到应用级服务发现之后,GC 已经趋近于零次。 + diff --git a/content/en/blog/users/pingan.md b/content/en/blog/users/pingan.md new file mode 100644 index 000000000000..5a636fb87ac2 --- /dev/null +++ b/content/en/blog/users/pingan.md @@ -0,0 +1,228 @@ +--- +date: 2023-01-15 +title: "平安健康的 Dubbo3 迁移历程" +linkTitle: "平安健康" +tags: ["用户案例"] +weight: 5 +--- +# 1 背景 + +我们公司从15年开始就使⽤dubbo作为微服务框架,当社区推出dubbo3时,我们也⽴刻跟进并做了深⼊调研,发现dubbo3 的应⽤/实例级服务注册和发现模式能够在一定程度上解决我们当前注册中⼼⾯临的压⼒,解决稳定性和安全性问题。同时dubbo3在服务治理上也做了升级,契合云原⽣架构,⽽且dubbo3能够向下兼容dubbo2,这也将降低升级的成本和⻛险。 + +升级项目有了阶段性的进展,目前仍然在进行中。通过本⽂,我们对公司内部的Dubbo3 升级过程及收益等做了深⼊总结。 + +# 2 Dubbo3 核⼼功能介绍 + +dubbo社区关于dubbo3的文档和资料越来越完善,以下是我们从社区引用的一些内容。 + +## 2.1 下一代云原生服务框架 + +![pingan](/imgs/v3/users/pingan-2.png) + +Dubbo3被社区寄予厚望,将其视为下一代云原生服务框架打造,Dubbo3 提供的核心特性列表,主要包括四部分。 + +- **全新服务发现模型** 。应用粒度服务发现,面向云原生设计,适配基础设施与异构系统;性能与集群伸缩性大幅提升。 +- **下一代 **** RPC ****协议** **Triple** 。基于 HTTP/2 的 Triple 协议,兼容 gRPC;网关穿透性强、多语言友好、支持 Reactive Stream。 +- **统一流量治理模型** 。面向云原生流量治理,SDK、Mesh、VM、Container 等统一治理规则;能够支持更丰富的流量治理场景。 +- **Service Mesh** 。在最新的3.1.0的版本中支持Sidecar Mesh 与 Proxyless Mesh,提供更多架构选择,降低迁移、落地成本。 + +![pingan](/imgs/v3/users/pingan-3.png) + +首先是性能、资源利用率的提升。社区资料显示,升级 Dubbo3 的应用预期能实现单机内存 50% 的下降,对于越大规模的集群效果将越明显,Dubbo3 从架构上支持百万实例级别的集群横向扩展,同时依赖应用级服务发现、Triple协议等可以大大提供应用的服务治理效率和吞吐量。 + +其次, Dubbo3 让业务架构升级变得更容易、更合理,尤其是RPC协议,在 2.x 版本中,web、移动端与后端的通信都要经过网关代理,完成协议转换、类型映射等工作,dubbo3的Triple 协议让这些变得更容易与自然;并通过流式通信模型满足更多的使用场景。 + +最后,得益于 Dubbo3 的完善云原生解决方案,Dubbo3的mesh架构可以帮助业务屏蔽底层云原生基础设施细节,让业务更专注于业务,这也是mesh的最根本的优势。 + +## 2.2 应用级服务发现核心原理 + +![pingan](/imgs/v3/users/pingan-4.png) + +我们从 Dubbo 最经典的工作原理图说起,Dubbo 从设计之初就内置了服务地址发现的能力,Provider 注册地址到注册中心,Consumer 通过订阅实时获取注册中心的地址更新,在收到地址列表后,consumer 基于特定的负载均衡策略发起对 provider 的 RPC 调用。 在这个过程中 + + - 每个 Provider 通过特定的 key 向注册中心注册本机可访问地址; + - 注册中心通过这个 key 对 provider 实例地址进行聚合; + - Consumer 通过同样的 key 从注册中心订阅,以便及时收到聚合后的地址列表; + +![pingan](/imgs/v3/users/pingan-5.png) + +再来看一下Provider向注册中心注册的 URL 地址的详细格式,这里把 URL 地址数据划分成了几份: + +- 首先是实例可访问地址,主要信息包含 ip port,是消费端将基于这条数据生成 tcp 网络链接,作为后续 RPC 数据的传输载体。 +- 其次是 RPC 元数据,元数据用于定义和描述一次 RPC 请求,表明这条地址数据是与某条具体的 RPC 服务有关的,它的版本号、分组以及方法相关信息。 +- 下一部分是 RPC 配置数据,部分配置用于控制 RPC 调用的行为,还有一部分配置用于同步 Provider 进程实例的状态,典型的如超时时间、数据编码的序列化方式等。 +- 最后一部分是自定义的元数据,这部分内容区别于以上框架预定义的各项配置,给了用户更大的灵活性,用户可任意扩展并添加自定义元数据,以进一步丰富实例状态。 + +结合以上对于 Dubbo2 接口级地址模型的分析,以及最开始的 Dubbo 基本原理图,可以得出这么几条结论: + +- 第一,地址发现聚合的 key 就是 RPC 粒度的服务。 +- 第二,注册中心同步的数据不止包含地址,还包含了各种元数据以及配置。 +- 得益于 1 与 2,Dubbo 实现了支持应用、RPC 服务、方法粒度的服务治理能力。 + +这就是一直以来 Dubbo2 在易用性、服务治理功能性、可扩展性上强于很多服务框架的真正原因。 + +面对这样的地址数量级放大的问题,在 Dubbo3 架构下,社区认真思考了两个问题: + +- 如何在保留易用性、功能性的同时,重新组织 URL 地址数据,避免冗余数据的出现,让 Dubbo3 能支撑更大规模集群水平扩容? +- 如何在地址发现层面与其他的微服务体系如 Kubernetes、Spring Cloud 打通? + +![pingan](/imgs/v3/users/pingan-6.png) + +最终,社区给出的方案也是非常巧妙和经典。Dubbo3 的应用级服务发现方案设计的基本思路是:地址发现链路上的聚合元素也就是之前提到的 Key 由服务调整为应用,这也是其名称叫做应用级服务发现的由来,与kubernetes和spring cloud的服务注册发现处于同一粒度,能够平滑打通;另外,通过注册中心同步的数据内容上做了大幅精简,只保留最核心的 ip、port 地址数据。 经过上述调整,应用级别服务发现在保持接口级地址模型易用性的同时,实现了地址单条数据大小和总数量的下降。 + +元数据、配置数据以及自定义数据等通过元数据中心或者MetadataService进行同步,且将所有的数据生成一个metadata revision, metadata revision相同则认为元数据等信息相同,通过这种方式来降低元数据中心或MetadataService的访问频次。 + +# 3 前期调研 + +了解了 Dubbo3 的核心功能以及应用级服务发现的工作原理后,我们开始进入前期工作阶段。 + +## 3.1 性能压测 + +从社区的资料来看,dubbo3各方面都非常不错,但是我们还得自己检验一次,所以我们使用当前在用的dubbo2内部定制版和dubbo3的性能压测,压测的主要场景在于同步调用,异步场景只做了dubbo3的压测, **以下压测数据和结论仅供参考** 。结果表明dubbo3在性能上面确实做了很多的优化,在相同cpu使用率的情况下,dubbo3的tps是要高于dubbo2的;tps相当的情况下,dubbo3的cpu使用率要低于dubbo2。尤其是dubbo2的接口级与dubbo3的实例级,在tps相当的情况下,dubbo3的cpu使用率要较定制版的dubbo2低20%左右。 + +压测环境: + +| 类别 | 版本 | 机器配置 | +| --- | --- | --- | +| Provider | dubbo 3.0.4 | 4C8G | +| Consumer | dubbo 3.0.4 | 4C8G | +| Provider | dubbo 2.5.3.22(基于2.5.3版本定制) | 4C8G | +| Consumer | dubbo 2.5.3.222(基于2.5.3版本定制) | 4C8G | + +测试场景: + +使用的是Dubbo协议,接口没有其它逻辑,直接将输入返回给消费者, 接口数据包大小500B,每个场景压30分钟。 + +测试数据 (仅供参考): + +![pingan](/imgs/v3/users/pingan-7.png) + +## 3.2 升级前调研 + +做了压测得到dubbo2和dubbo3的压测数据后,我们开始计划将 Dubbo3 引入公司进行试点,此时,我们需要考虑dubbo3与dubbo2的兼容和迁移重构问题,升级目标,以及dubbo3提供有哪些能力支持升级和迁移。 + +### 3.2.1 升级的兼容和迁移重构问题 + +考虑到公司的系统规模,要将dubbo2升级到dubbo3却不是一个简单的过程,尤其是公司的dubbo2版本在原开源版本基础之上做了不少优化和扩展,涵盖了ops服务治理、monitor数据指标监控、服务注册和发现、RPC灰度路由、链路分析、序列化编解码、作为其他基础框架的底层支持等多个方面,同时dubbo3社区也处于活跃的状态,我们也希望能够持续享受dubbo社区的技术红利,在这样的背景下不得不考虑三个问题: + +1. 需要解决公司版本的dubbo2与dubbo3的兼容问题; +2. 原有功能的迁移重构问题; +3. 不在dubbo3的源码上做改动,保持和社区版本一致。 + +得益于dubbo 良好的扩展能力,我们可以通过dubbo 的SPI和IoC模块在dubbo3的基础之上优雅的兼容公司版本的dubbo2,不用改动dubbo3源码,只要研发dubbo3扩展包跟随dubbo3版本的API升级即可,这个升级改动的成本和从社区获取红利相比是比较小的。 + +### 3.2.2 升级目标 + +既然历史包袱的解决方案已经有了,那么就要思考升级的目标了。首先确定的是,最终我们将会采用实例级的服务注册和服务发现,其次我们目前使用的注册中心是zookeeper,而dubbo社区更推荐使用的注册中心是nacos,而且我们在验证阶段时也暴露过几个在zookeeper上出现而在nacos上没有出现的问题,这也使得我们开始考虑将来是否将注册中心最终也迁移到nacos上。 + +同时,我们也希望整个迁移过程是平滑、可控的,我们整体方案也要将风险把控作为核心要点考虑,尽可能的做到失败降级、实时可控。 + +综上,我们将升级的目标归纳为下面几点: + +1)平滑的从dubbo2升级到dubbo3。 + +2)将接口级服务注册和发现模式平滑的迁移到应用级服务注册和发现模式。 + +3)为后面平滑迁移注册中心做好准备。 + +4)迁移过程可监控、可观测。 + +5)迁移过程要可灰度、可实时管控。 + +6)统一dubbo3的通用配置规范,尽量适配原dubbo2的export和refer方式。 + +### 3.2.3 dubbo3对于迁移的支撑能力 + +前面介绍的是我们的目标,但是如何把dubbo3的原生设计理念融入到现实情况中呢?以下是我们的相关思考,并在验证过程中。 + +首先dubbo3能够支持在registryUrl上通过参数管理provider和consumer以不同的模式进行服务注册和服务发现,其中核心参数名有: registry-type, registry-protocol-type, register-mode。 + +其次,dubbo3可以支持使用多个注册中心,不同的注册中心通过上面的registryUrl参数控制注册中心的服务注册模式和服务发现模式。而且还可以通过ProviderConfig和ConsumerConfig这两个这两个Config类分别管理provider侧和consumer侧使用的注册中心。在consumer侧,如果有使用多个注册中心,默认会使用ZoneAwareCluster创建的ZoneAwareClusterInvoker来进行负载均衡,从类名上可以看出,该ClusterInvoker是有提供区域感知的能力,查看源码时发现它还提供了preferred的功能,只在相应的registryUrl中添加了preferred=true,这个registryUrl创建的ClusterInvoker就会被优先调用。 + +在同一注册中心进行接口级迁移到实例级的场景中,dubbo3的MigrationInvoker也提供了相应的支持,MigrationInvoker可以根据MigrationRule来控制实例级的RPC流量,并且根据MigrationRuleListener能够实时监听到指定应用的MigrationRule的变更。 + +关于RPC 的监控在dubbo中一直由MonitorFilter和DubboMonitor提供RPC监控数据的收集和上报,收集的数据有消费者的ip端口、提供者的ip端口、应用名称、DubboService、Method、以及成功数、失败数、输入字节数、输出字节数、耗时、并发数等, + +这些能力能够满足基本的迁移工作,结合我们的现状来看,相对升级目标要求的平滑迁移,迁移流量可观测、可灰度、可管控还有一些距离,不过在梳理dubbo3这块能力的时候,也找到了相对简单的扩展方案。到此,对于整体的迁移方案也有了一个大致的雏形。 + +# 4 升级&迁移方案设计 + +方案的设计重点放在"平滑、可控"两点,根据dubbo3的新架构,目前正在验证中的迁移方案示意图如下: + +![pingan](/imgs/v3/users/pingan-8.png) + +从上图可以看出,在整个升级迁移的过程中,应用域中会存在多个dubbo版本,dubbo3是能够兼容社区的dubbo2版本,而我们公司内部的dubbo2版本是基于dubbo2.5.3开源版本深度定制过的,在ops服务治理、monitor数据指标监控、服务注册和发现、RPC灰度路由、序列化编解码等方面都做了扩展定制,我们的思路是由dubbo3基于dubbo的SPI采用扩展的方式或者ExtensionLoader的Wrapper模式去兼容定制版的dubbo2。 + +除了应用外,在dubbo3的架构基础上划分了3个逻辑域,分别是注册域、配置管控域和监控域。注册域主要服务于服务的注册和发现,例如provider在DubboService暴露时,将服务信息和元数据信息上报到注册域的注册中心和元数据中心,consumer通过注册中心和元数据中心来发现服务。配置管控域主要是管理应用配置和迁移流量管控,dubbo3提供的配置中心支持自身能力的配置,所以流量规则的配置由dubbo3的配置中心进行维护,dubbo3的DynamicConfigration提供了很多关于动态配置的方法可以直接使用。监控域除了原RPC流量的监控外,还细分了迁移流量的监控,在迁移过程中,可以通过监控直观的看到迁移流量的现状,出现问题时,也可以及时报警通知相关人员介入。 + +整个升级过程分为3个阶段: + +第一阶段:将dubbo2升级到dubbo3的接口级,验证功能、兼容性、性能和稳定性 + +第二阶段:接口级和应用级双注册,通过MigrationRule和RegistryMigrationRule管理RPC流量 + +第三阶段:全面切换到应用级,撤掉MigrationRule和RegistryMigrationRule + +## 4.1 dubbo3扩展兼容dubbo2定制版本 + +考虑到dubbo3社区版本的迭代情况,最终决定dubbo3兼容dubbo2定制版本的插件以SDK的方式单独维护,实现兼容的扩展功能主要有如下内容: + +1. RPC 正向透递与反向透传 + +在consumer侧和provider侧扩展Filter接口实现类,为正向与反向透传数据实现其发送和接收的功能。Dubbo2定制版是在序列化编解码层面对RpcResult进行了修改,要兼容这一逻辑也只能在序列化编解码层面去支持,采用Wrapper模式对Codec2这个SPI进行增强,与其它扩展类一并实现该兼容功能。 + +2. RPC 灰度路由 + +扩展Dubbo 的Router、 Cluster和ConfiguratorFactory等SPI,与内部的eunomia灰度管控平台集成实现RPC灰度路由,替换并兼容掉原dubbo2定制版在其源码层面修改实现的灰度路由功能。 + +3. monitor数据指标监控 + +扩展Protocol、MonitorFilter、Monitor等SPI,与内部的监控中心完成对接,与dubbo2定制版的监控逻辑保持一致。 + +4. ops 支持实例级 + +在ops层面,除了要兼容原接口级的服务管控外,还要添加实例级的服务管控。 + +5. 其它中间件兼容 + +除了dubbo本身的兼容外,内部还有部分自研的中间件也是有依赖dubbo或者跟dubbo有关联的,还要对这些中间件进行改造升级。 + +## 4.2 迁移扩展 + +在dubbo3原有能力基础上,也要另外进行扩展以提供平滑迁移的能力,我们构想的设计方案如下: + +1. 扩展支持注册中心的迁移可灰度、可管控 + +在dubbo3中,当consumer侧应用了多个注册中心时,默认会通过ZoneAwareCluster创建ZoneAwareClusterInvoker来进行负载均衡,参考其实现可以扩展一个Cluster实现类和一个ClusterInvoker实现类将ZoneAwareCluster替换掉,注册中心迁移的流量管理、灰度、降级等能力都在扩展的ClusterInvoker中去实现 + +2. 扩展支持接口级到实例级迁移规则的全局配置管理 + +MigrationRule由MigrationRuleListener通过DynamicConfiguration监听指定的应用的迁移规则,如果一个系统拥有成百上千个微服务应用时,由这种方式去管理,维护成本将会变高,我们借鉴这个方法实现了全局级别的MigrationRule管理能力。 + +3. 扩展迁移流量可观测、可报警 + +dubbo RPC的流量监控已经有MonitorFilter和DubboMonitor实现了,只是MonitorFilter不能识别本次RPC请求的Invoker对象是通过哪个注册中心进行服务发现的,以及该Invoke对象的服务发现模式是接口级还是实例级的;,我们在consumer侧新增一个ClusterFilter接口和Filter接口去实现这个识别逻辑。 + +4. 迁移组件开关 + +在扩展的最后,要考虑迁移组件下线的问题,即使要下线也不可能再次调整业务工程将迁移组件全部从依赖中删除掉,所以需要通过开关控制迁移组件的功能下线。 + +## 4.3 配置统一管理 + +在升级和迁移过程中,我们可能会随时调整注册中心和迁移规则的配置参数,为减少出错的风险以及业务工程升级改动的工作量,这些公共的配置需要统一管理维护起来,dubbo3的配置中心正常能够把这个任务较好的承接下来。 + +最终我们又扩展了一个配置加载的组件,通过我们公司内部的配置中心管理维护迁移组件的开关和配置中心的连接地址与超时等配置参数。有了这个组件后,新的应用可以不用担心dubbo3和迁移的公共配置,老的应用也减少了这部分公共配置的调整工作量。 + +## 4.4 风险预案 + +dubbo作为一个提供底层支撑能力的微服务框架,我们始终把稳定性的要求放在首位,升级过程中任何一点意外,都可能导致线上问题,所以我们整个方案都是在面向失败、面向风险设计的。除了在扩展的迁移组件中实现了主动降级外,也着重考虑了一些极端情况,同时为这些极端情况提供风险预案。线上环境可能会出现各种意想不到的情况,在迁移过程中需要预先思考各种风险,准备完善的应对处理预案,保证系统快速恢复。 + +## 4.5 小结 + +dubbo2是一个优秀的微服务框架,提供的SPI以及Extension机制能够非常方便的让用户去扩展实现想要功能。dubbo3在其基础之上,丰富了不少新的SPI,我们花了很长的时间去设计迁移方案,真正花在迁移组件上的开发时间较短。 + +dubbo3整体架构升级调整对于过去的服务注册压力也得到了解决。性能上也做了优化,架构升级后的dubbo3也更适应目前云原生的架构,dubbo 3.1.x 版本支持sidecar和proxyless的mesh方案,而且社区也在准备开源java agent 方式的proxyless,这样就能较好的将微服务架框的framework与数据面解耦,降低微服务框架的维护成本和升级成本。 + +# 5 社区协作 + +目前该项目仍然在持续升级中,我们跟社区保持着紧密的联系,期间碰到不少问题,都得到了社区开发同学耐⼼解答并最终给予解决。对于要升级 Dubbo3 的⽤户,可以在社区的Github User Issue(https://github.com/apache/dubbo/issues/9436) 进⾏登记,想参与社区的同学们也可以关注 Dubbo 官⽅公众号(搜索 Apache Dubbo)了解更多关于dubbo社区的进展。 \ No newline at end of file diff --git a/content/en/blog/users/xiaomi.md b/content/en/blog/users/xiaomi.md new file mode 100644 index 000000000000..3353cf60adf9 --- /dev/null +++ b/content/en/blog/users/xiaomi.md @@ -0,0 +1,78 @@ +--- +date: 2023-01-15 +title: "小米与 Dubbo 社区的合作" +linkTitle: "小米" +tags: ["用户案例"] +weight: 4 +--- + +小米一直在积极拥抱开源社区并提交贡献,参与Dubbo3建设发布以来,在内部业务也积极推进升级工作,目前实例数已经升级到了一定的比例 。升级过程总体平稳,稳定性指标正常,性能提升明显,率先升级完成的应用更早拥有了mesh化的条件。从升级后的数据表现来看,Dubbo3改变以往接口粒度的注册发现方式为应用粒度的注册发现方式,这样带来了注册中心存储和运行的更稳定,降低运维成本;使用protobuf协议进行序列化与反序列化,性能和字节大小均提升数量级;完全兼容gprc,给小米这样多言语并存的服务环境带来了极大便利。 + +Xiaomi is devoted to making continuous contribution to the open source community. Since the introduction of Dubbo3, internal projects are rapidly upgrading to the latest version of Dubbo. Currently, At present the numbers of instances has been upgrade to a certain proportion. Not only performance improvements have been seen, but services are also running smoothly with improvements in availability. Statistics provide proof that Dubbo’s switch from api-level discovery to application-level discovery has improved the availability and reliability of service discovery, which leads to lower operations cost. In addition, using ProtoBuf for serialization and deserialization has reduced data exchange size. Lastly, full compatibility with grpc provides convenience to Xiaomi’s multi-language development environment. + +Dubbo3 基于 Dubbo2 演进而来,Dubbo3 在云原生基础设施适配、服务注册发现、面向下一代协议设计等几大方向上进行了全面升级。并且往 3.0 版本的升级过程将会是完全透明的,用户无需做任何业务改造,就可以直接升级到 Dubbo 3.0。 +下面从云原生适配、全新服务发现模型、通信协议、升级兼容四个方面详细介绍。 + +Having evolved from Dubbo2, Dubbo3 is a major upgrade in several areas including, Cloud Native adaptation, service discovery, communication protocols. Furthermore, upgrading to version 3.0 requires no changes in application code. The following is a detailed introduction to Dubbo3’s features. + +### 云原生适配 Cloud Native Adaptation +Dubbo3从理念到设计再到实现最大的变革之一在于全面遵循云原生环境,做到了面向未来,为了达到这个目标dubbo本身做了相当重要的取舍。 +在“取”这个层面,Dubbo3众多核心组件已经面向云原生升级,支持 Kubernetes 平台调度,实现了服务生命周期与容器生命周期的对齐,Serverless、Native Image等机制都在计划之中。 + +在“舍”这个层面,Dubbo3割舍了以往要求开发人员遵守并熟知的Dubbo启动、销毁、注册等生命周期事件,Dubbo3自身设配了Kubernetes基础设施定义的生命周期事件(probe),并且将服务的定义与注册下沉到了Kubernetes Service,重新划定了dubbo和k8s基础设施的边界。 + +To be future proof, the design and development of Dubbo3 has fully adapted Cloud Native. To meet this goal, Dubbo has made some trade-offs.Several core components of Dubbo3 support Kubernetes. In particular, Dubbo3 implements Kubernetes service and container life-cycle. Serverless and native image support will be release in the future. + +To support Kubernetes, Dubbo3 places service registration and discovery down to the Kubernetes Service layer, thus reestablishing the boundary between Dubbo and Kubernetes. However, this requires deprecating Dubbo’s own service discovery events. + +### 全新服务发现模型 New Service Discovery Model +Dubbo以往版本与Spring Cloud、gRPC等同属主流的服务框架进行服务发现的粒度不一致,Dubbo选择了基于更细粒度的接口来进行服务发现,Dubbo3.x进行了服务发现机制的对齐,即以应用粒度来进行服务发现,应用粒度的机制也带来了几点好处: + +1. 打通与其他异构微服务体系的地址互发现障碍,这一点对于小米这样的多语种多框架并存的技术组织非常重要。 +2. 提升了 Dubbo3 在大规模集群实践中的性能与稳定性。新模型可大幅提高系统资源利用率,降低 Dubbo 地址的单机内存消耗近一半,降低注册中心集群的存储与推送压力一半以上, Dubbo 可支持集群规模步入百万实例层次。 + +Previous versions of Dubbo differs from other mainstream service discovery middle-ware such as Spring Cloud and gRPC in its service discovery granularity. In the past Dubbo discovers services at the API level. Dubbo3, however, utilizes application level service discovery. This provides the following benefits. + +1. Eliminates incompatibility issues with other service discovery platforms, which is crucial since Xiaomi has diverse languages and development frameworks. +2. The new service discovery model improves resource utilization, lowers Dubbo address’s single machine memory usage, lowers service discover cluster’s load. + +### 全新RPC 通信协议 New RPC Communication Protocal +定义了全新的 RPC 通信协议 – Triple,它是基于 HTTP/2 上构建的 RPC 协议。 使用 Triple 协议,用户将获得以下能力: + +1. 完全兼容gRPC,能够更友好的支持跨语言跨框架的微服务进行互通。 +2. 支持Protobuf进行序列化与反序列化,性能和字节大小均提升数量级。 + +Introduction of a new RPC communication protocol based on HTTP/2 called Triple. Using Triple has the following benefits. + +1. Complete compatibility with gRPC. +2. Protobuf support for serialization and deserialization. + +### 升级与兼容性 Upgrade and Backwards Compatibility +对业务而言,在保证兼容以往版本的前提下进行升级是最核心的问题,在 3.0 版本的设计与开发之初,就定下了兼容老版本 Dubbo 用户(2.5、2.6、2.7)的目标。因此,往 3.0 版本的升级过程将会是完全透明的,用户无需做任何业务改造,升级 3.x 后的框架行为将保持与 2.x 版本完全一致。 + +但也要注意,透明升级仅仅是通往 3.0 的第一步,因为 “框架行为保持一致” 也就意味着用户将无法体验到 3.0 的新特性。如果要启用 3.0 带来的新特性,用户则需要进行一定的改造,这个过程称为迁移,这是一个按需开启的过程。 +因此,对老用户而言,有两条不同的迁移路径: + +1. 分两步走,先以兼容模式推动业务升级到 3.0 版本(无需改造),之后在某些时机按需启用新特性(按需改造); +2. 升级与迁移同步完成,在业务升级到 3.0 版本的同时,完成改造并启用新特性; + +第一种方式更安全,第二种方式更彻底,业务可根据自身的情况来进行评判选择。 + +For production systems, upgrading a dependency while maintaining backward compatibility is challenging. Supporting users of older versions of Dubbo (2.5, 2.6, 2,7) is a goal of Dubbo3’s design and development. Thus, upgrading to Dubbo3 is painless. No changes are required to be made to existing production systems. However to use Dubbo3’s new features, additional changes are needed to existing code. Thus, there are two suggested upgrade paths. + +1. Upgrade to Dubbo3 but do not use Dubbo3’s new features. This path requires no code changes. +2. Upgrade to Dubbo3 while making additional changes to support the new features. + +### 建议 +1. dubbo3已经和云原生做了深度适配,建议后续能够和istio等service mesh框架进行更多的衔接打通,方便dubbo用户更简单的走向mesh化之路; +2. 建议在调用方和服务方调用链路上增加更多的可选可观测点; + +Suggestions +1. Since Dubbo3 is closely compatible with Cloud Native, further work can be done to enhance Dubbo’s support of istio and other service mesh frameworks to speed up Dubbo users’ adaption of service mesh. +2. Add more performance metrics to monitor Dubbo consumers and providers. + +### 作者 +* 张志勇 +* 张平 +* 许铮 + diff --git a/content/en/blog/users/zhengcaiyun.md b/content/en/blog/users/zhengcaiyun.md new file mode 100644 index 000000000000..3d84fffe40c7 --- /dev/null +++ b/content/en/blog/users/zhengcaiyun.md @@ -0,0 +1,312 @@ +--- +date: 2023-03-22 +title: "全国首个政企采购云平台:政采云的混合云跨网方案实践" +linkTitle: "政采云" +tags: ["用户案例"] +weight: 10 +--- + + +对云岛业务结构的公司来说,云平台属于公司内部、完全可控的局域网,而岛端则是有自己安全网络策略的独立内部网络。需要云岛通信时,会基于需求,按客户要求走流程开通一些端口,这个过程需要一定的成本且不完全可控。业务上,如果这种跨网需求增多,则会逐渐变成痛点。如果可以搭建一个透明的跨网传输网络,配合良好的顶层设计,就可以在业务支撑、安全管控和运维成本中寻求较好的平衡。 + +本文将介绍政采云基于 Dubbo 的跨网方案落地过程中面临的技术挑战、社区合作以及更深层次抽象的一些思考。在政采云这种政企业务场景中的数据跨网,与业界公有云、自建私有云的公司相比,既有共性又有自己的特点,希望能为大家提供新的思路或者启发。 + +## 前言 + +稳定、高效、可靠的基础设施是互联网企业应对业务高峰流量的底层基石。作为政采云的基础技术平台,基础平台部一直致力于通过业内前沿技术的落地,保障公司内部所有业务在线生产系统所依赖的基础技术平台能稳定、安全、低成本、可持续地运行与发展。 + +由于公司对 Dubbo 框架的重度使用,**跨网数据传输系统**一般基于 Dubbo 特性开发,在政采云内部就有多个版本的实现。 + +早在几年前,政采云就上线了基于 Dubbo Filter 转发的方案,它解决了岛到云的单向数据传输,安全认证等问题。另外,业务部门也有按照自己的需求,推出网状点对点的方案,实现了一定程度的透明传输。 + +结合前两年的探索实践以及业界相关领域技术的成熟度,2022年下半年,我们对各跨岛方案,进行了整合升级,也就是现在的**高速公路**方案,保障跨岛标准化同时,解决了之前方案实践过程中面临的很多业务痛点,包括: + +- **单向传输**:因为架构原因,如需双向需要对等重新部署一套,成本较大。 + +- **白名单开通成本高**:点对点的网状架构,需要两两开通白名单,因为政企网络特殊性,开通流程复杂且慢。 + +- **平台维护成本高**:业务各自一套数据传输平台,重复建设且运维成本高。 + +- **公共功能的缺失**:核心功能,业务可以按需开发,但是数据审计、链路追踪、可观测性等公共特性,往往没有足够投入。 + + +## 1. 跨网数据传输系统演进 + +### 1.1 历史架构 + +![img](/imgs/v3/users/zcy-1.png) + +​ + +自左向右、自下而上进行模块介绍: + +- **业务Web**:业务 Web 作为数据发送方,调本地 集群 Provider 时,携带跨岛信息过去(Dubbo 上下文)。 + +- **岛业务Center**:本地虚拟Provider,通过Filter拦截跨岛请求,通过http传送到云平台 Dubbo 网关,返回数据后反序列化返回岛业务 web。 + +- **Dubbo网关**:接收 Http 请求,通过泛化调用云端 Provider,处理数据后返回业务 Center。 + +- **云业务Center**:普通 Dubbo Provider。 + + +### 1.2 高速公路架构 + +![img](/imgs/v3/users/zcy-2.png) + +​ + +**1.2.1 隧道机制** + +隧道技术是一种通过使用**互联网络**的**基础设施**在网络之间传递数据的方式。使用隧道传递的**数据**(或负载)可以是不同协议的数据帧或包。 + +高速公路架构中,使用了隧道这个概念。两端(业务层)是 Dubbo 私有协议,跨网传输过程中,则使用了 http 协议,http 协议可以更好的被中间设备、网关识别转发。这个机制的最大便利在于对业务的低侵入性。对于业务集群的应用完全不需要修改。 +![img](/imgs/v3/users/zcy-3.png) + + +除了路由标记,出口/入口 Dubbo 协议字节流没有任何业务外信息,所以可以路由任何 Dubbo 请求。 + +![img](/imgs/v3/users/zcy-4.png) + + + +**1.2.2 主要节点** + +**客户端 Sdk**:不改变用户使用 Dubbo 的方式,多种形式提供Dubbo的路由。 + +**Dubbo 出口网关:**代理 Dubbo 流量出口。 + +**Dubbo 入口网关:**代理 Dubbo 流量入口。 + +**统一网关:**基于 Apisix,代理跨网间所有流量,可以扩展鉴权、审计、限流等特性 + + + +## 2. 挑战与应对之策 + +如前言中所述,已有的几个方案设计上存在了一些问题,落地后也限制了使用了场景。在架构上,我们提出了高速公路方案,选择了全双工的对等网络传输框架。角色上,云平台定位一个特殊的岛端应用,遵循P2P实施原则。而对用户而言,高速公路是一个通往岛端的隧道,遵循对用户透明原则。我们可以先来看下在搭建平台的过程中面临的一些挑战以及解法。 + +### 2.1 技术挑战 + +结合当下跨网数据传输系统面临的处境,并对业界 Dubbo 跨网方案做过一番调研后,在平台搭建上确定了如下三期目标: + +- **一期目标**:网络能力建设,简单来说是搭建基于 Dubbo 的传输通道,上层功能先维持不变。 +- **二期目标**:业务上,找业务先行试点,基于反馈,小步快跑,快速迭代;技术上,寻求 Dubbo 社区协作,增强对Dubbo相关技术风险的把控,同时抽离通用特性,反馈社区。 +- **三期目标**:抽象出更通用的网络框架,从而使语言层,传输协议层、及中间件层独立扩展,一键切换。 + +在上述三期目标基本落地后,高速公路系统不仅可以跑起来,同时拥有非常强大的扩展性,更好的承接业务需求及共建。在这过程中,我们需要解决不少技术问题。 + +**2.1.1 客户端路由** + +如前面历史方案所述,其场景被限制为岛到云的单向数据传输,特点如下: + +- **客户端无路由能力**:Consumer 端只能指定是否路由到云平台,而不能指定其他岛端。 + +- **基于filter的扩展**:Dubbo的 Filter 并不是为路由设计的,在此基础上较难扩展。 + +- **需要本地Provider角色**:Consumer 端发出的请求,必须由一个注册在 Zookeeper 下的 Provider 兜住,然后 Filter 根据上下文决定是否转发,这就限制了业务方必须部署一个本地 Provider 应用(哪怕是空应用),才能做到跨网访问。 + + +我们要解决的问题之一,就是打破单向传输瓶颈,客户端可以更自由的路由到目标云/岛。我们设计了以下几种路由方式: + +- **注解方式**:使用@DubboReference提供的通用 parameters 参数,设置路由目标,可以达到方法粒度的路由。 + + ```java + @DubboReference(check = false, parameters = {"ENV_SHANGHAI", "ALL"}) //all表示所有方法,可以单独指定 + private DemoService demoService; + ``` + +- **配置中心指定**:把以上parameters = {"ENV_SHANGHAI", "ALL"} 信息,在配置中心配置,达到同样的效果,这种方式对代码完全无侵入。 + +- **线程指定**:这种方式最灵活。 + + ```java + AddressZoneSpecify.setAddress(Enviroment.SHANGHAI); + demoService.play(); + ``` + +无论哪种路由方式,基于“用户透明“的原则,都不改变用户使用 dubbo 的方式。 + + + +**2.1.2 Dubbo请求地址切换** + +客户端路由最小限度地侵入业务代码,达到了透明调用远程服务的目标。但是,用户仍旧需要部署一套虚拟 Provider 应用,接收请求后按规则进行路由。 + +为了避免部署多余的应用,我们需要有一定的机制,直接把dubbo流量切换到远程。 + +![img](/imgs/v3/users/zcy-5.png) + +​ + +解决了切换问题后,本地的 APP2 不再需要,甚至zk也可以移除。当然,如果业务同时有本地和远程的调用需要,也可以继续存在。 + +![img](/imgs/v3/users/zcy-6.png) + +​ + +原先,我们准备通过Dubbo的Route自定义扩展,去实现动态切换地址的能力。查阅资料后,发现Dubbo已经提供了类似能力。 + +https://cn.dubbo.apache.org/zh-cn/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip/ + +该特性放在Dubbo的子工程dubbo-spi-extensions中,同样以Route扩展形式实现。 + +但在实际使用过程中,我们遇到如下问题: + +- **不支持 Dubbo2**:使用 Dubbo2 时,直接以异常的形式提醒暂不支持。 +- **NPE异常:** 某些场景下调用出现了NPE异常。 +- **丢失部分信息:** Router下构建新 Invocation 时,丢失了 version、group等信息。 +- **重试异常:** 远程 Provider 如果发生了异常,客户端在重试的时候,选择了本地集群 Provider 调用,造成错误. + +作为一个尝鲜新特性,我们理解功能存在不稳定的情况。但这个功能作为我们跨网方案的技术要点,又必须解决。所以,我们通过PR的形式,把相应补丁提交到Dubbo社区。这个过程中,我们联系到了Dubbo PMC 远云大佬,一起讨论和完善PR,直到解决所有已知问题。 + + + +**2.1.3 出口网关的实现** + +在上图中,通过切换地址,我们似乎可以直接访问远程应用,并且架构非常简单。但是遗憾的是,存在几个难以解决的问题: + +- **网关组件的限制**:在云岛/岛岛间,存在一系列网关组件,来提供转发、负载均衡的功能,比如SLB、NGINX、WAF。这些组件并不能识别私有的 Dubbo 流量并转发 +- **ip白名单开通成本高:** 类似 P2P 方案,需要点对点开通 IP 白名单,成本巨大。 +- **升级维护复杂:** 客户端通过集成 SDK 的形式转发,后续如需要劫持流量进行扩展,需要同时对每个接入应用进行升级。 + +![img](/imgs/v3/users/zcy-7.png) + + +​ + +针对以上问题,我们的设计中,需要加入 Dubbo 网关的角色,来实现以下目标。 + +① **两端ip收敛** + +- 显著减少网关长连接数量 +- 弱化服务注册发现流程(每个环境只有一个 Dubbo 网关,直接配置即可互相发现) +- 简化鉴权、认证流程。一条链路可以使用白名单,一群则只能配置较复杂的鉴权 + +② **两端功能收敛** + +- 客户端的 SDK 专注路由功能,基本不用升级 +- 扩展功能放在 Dubbo-Proxy,统一升级,业务端无感知 + +Dubbo-Proxy 作为业务网关,可以减轻对业务端的侵入,起到类似分布式运行时(Dapr)作用。但是,在引入之前,需要解决一些现实的技术问题。其中,最重要的问题是如何接收陌生的 Dubbo 流量,然后进行转发。做了一些相关调研后,有两个方案可用: + +- **通用Provider**:直接在 Dubbo-Proxy 注册一个普通的通用 Service,客户端的 SDK 利用 Filter,劫持流量,直接调用通用 Service 后处理数据返回。 + +- **注册虚拟节点:**该方案来源于远云。客户端在本地zk订阅远程节点时,通知 Proxy,Proxy 获取订阅的信息后(预先订阅所有 zk 变更),主动注册相应虚拟 Service(对 zk 来说,注册一个节点的参数只是字符串)到zk上。这样,可以把客户端的远程流量“骗”到 Proxy ,Proxy 再使用服务端泛化,接收请求并转发。 + +以上两种方案,都可以实现出口网关。但是,在设计上,角色间需要多次交互,才能达到目的。那么,是否有更简洁的方式,直接支持这种接收和转发呢? + +首先,我们对 Dubbo 源码进行了调研,看 Provider 接收到陌生流量(无相应Service)后会如何处理,是否有扩展点可以拦截。发现在 Byte 流解析阶段,Dubbo 即对 Service 进行了检查,不存在直接抛异常返回。 + +![img](/imgs/v3/users/zcy-8.png) +​ + +在 Provider 处理的生命周期中,Decode 出于非常早期的阶段,几乎没有什么扩展点可以拦截处理。因为快速失败的理念,早期的检测确实可以避免后面无谓的代码执行消耗。但是,对比 Spring ,Dubbo 在扩展性上是有不足的,即对于一个通用的异常,却没有相应的扩展机制。 + +我们决定在 decode 的基础上,加上对这个异常的扩展。主要思路是,在 decode 被调用处,catch 住这块异常,通过 SPI 的形式,获取扩展实现,可以定制异常信息,也可以控制 decode 流程重试。这块修改难度并不大,私有版本上顺利通过测试,同时提交 PR 到社区。这个过程中,远云大佬帮忙发现了一个并发安全的 bug,并给了不少减少风险的建议。 + +```java +//解码结束后,无论是否异常,都将进入这个方法 + void handleRequest(final ExchangeChannel channel, Request req) throws RemotingException { + if (req.error != null) { + // Give ExceptionProcessors a chance to retry request handle or custom exception information. + String exPs = System.getProperty(EXCEPTION_PROCESSOR_KEY); + if (StringUtils.isNotBlank(exPs)) { + ExtensionLoader extensionLoader = channel.getUrl().getOrDefaultFrameworkModel().getExtensionLoader(ExceptionProcessor.class); + ExceptionProcessor expProcessor = extensionLoader.getOrDefaultExtension(exPs); + boolean handleError = expProcessor.shouldHandleError(error); + if (handleError) { + //获取异常扩展,执行wrapAndHandleException操作,需要重试的场景可以抛出retry异常 + msg = Optional.ofNullable(expProcessor.wrapAndHandleException(channel, req)).orElse(msg); + } + } + } + + res.setErrorMessage("Fail to decode request due to: " + msg); + res.setStatus(Response.BAD_REQUEST); + + channel.send(res); + } + + + //handleRequest过程中的retry控制 + public void received(Channel channel, Object message) throws RemotingException { + //解码 + decode(message); + try { + handler.handleRequest(channel, message); + } catch (RetryHandleException e) { + if (message instanceof Request) { + ErrorData errorData = (ErrorData) ((Request) message).getData(); + //有定制,进行重试 + retry(errorData.getData()); + } else { + // Retry only once, and only Request will throw an RetryHandleException + throw new RemotingException(channel, "Unknown error encountered when retry handle: " + e.getMessage()); + } + handler.received(channel, message); + } + } +``` + +关于ExceptionProcessor扩展,我们在官方扩展包Dubbo-Spi-Extensions中,提供了一个默认实现,允许控制重试解码,并自定义异常处理。 + + + +**2.1.4 中心网关** + +最新架构,已经非常接近最终实现了,但是缺了一个中心网关角色。引入这个网关(基于 Apisix )的原因: + +- 白名单问题:虽然 Dubbo 网关收敛了终端 IP,但是要实现岛岛互通,还是得两两互开白名单。引入中心网关(云平台)后,每个岛单独和云平台互开即可。白名单开通复杂度从O(n*n) 变为O(n)。 +- 统一网关的好处:作为公司级网关,可以统一对所有应用进行限流、鉴权、审计、可观测性等功能拓展。 + +## 3. 更多思考 + +无论公司内外,能选择的跨网方案非常多,我们会去选择一个能解决痛点的,而不是完美的方案。落地方案一般比较保守,但是对于架构的思考,一定是需要更超前的。 + +**http协议导致的性能损失** + +前面说到,在 Dubbo 网关和中心网关间,我们使用了 Http 协议。对比 Dubbo 等精简协议,Http 协议显然更臃肿。但是,也许这是现阶段最合适的方案。除了避免私有协议在网络设备中的“艰难前行”,Http 协议开发成本更低,相应落地风险也更小。一些新技术,也许是我们后续发展的方向。比如 Higress,支持 Triple 协议(基于 Http2)交换信息,在获得更高性能的同时,也解决了设备识别问题。但是选择 Higress,需要面对学习认知成本、新开源 BUG 多等问题,同时它可能更适合内部网络(即使跨公网也能搭建 VPN),而不是我们各私有岛端(客户自定义安全策略)的网络互通。 + +**扩展性不足** + +高速公路是一个基于 Dubbo 的跨网方案,在协议与框架层,与 Dubbo 的绑定比较深,但是它应该能做的更多。也许很快,会接入 Http、Mq 等应用协议的流量,或者 Python、Go 等语言的客户端,甚至是 Mysql 的数据互通。这个时候,要么对架构大改,要么各种兼容,这都不是我们想看到的。参考网络分层协议,我们也粗略地做了一个分层抽象规划。 + +![img](/imgs/v3/users/zcy-9.png) +​ + +- 物理层打通:主要解决网络异构问题,即约定不同安全策略的子域如何通信。 +- 通讯协议层加速:前面讲到的应用层协议,需要做到允许独立扩展及切换。 +- 语言层编译加速:业务网关可能更适合使用 Golang,然后 Java 节点是否可以用 Native 优化性能? +- 框架层功能升级:比如当前对 Dubbo 的定制开发,使用的 Apisix 中心网关是否可以扩展 dubbo 转 dubbo? +- 任务编排:业务的跨网调度,不一定是A->B->C->D,会不会是A、B同时完成后才能->C->D? +- 更上层的控制面/治理面/运维面 + + + + +## 4. 未来规划 + +随着高速公路方案在政采云的逐渐落地,我们未来会从稳定性、功能增强、新技术探索三个方面去做深、做广: + +(1)**稳定性**:基础服务的稳定性是一切的基石,而这往往是不少研发同学容易忽视的一点,研发同学需“在晴天时修屋顶”。 + +- **系统自身的健壮性**:资源池化隔离、QoS 保障能力建设。 +- **节点实例的稳定性**:加固发现能力,持续完善异常检测工具(除了常规的健康检测,会从观测指标的不同纬度综合决策),自动进行异常实例的替换;加强数据运营,提升反馈能力。 + +(2)**功能增强** + +- **协议增强**:当前只能对 Dubbo 流量转发,计划增加对 Http/Grpc等协议等支持,从而支持更多的场景(已有业务提此类需求)。 +- **安全性增强**:在中心网关 Apisix 开发鉴权、审计等插件,更好的控制跨网的调用与被调。 +- **易用性增强**:开发自动工单系统,对需要配置的事项,由业务测提工单,相应人员审核后自动配置,解放劳动力同时减少出错概率。 + +(3)**新技术探索** + +​ 网关场景,通常有个两个比较明显的特点: + +- 并发量高: 多个应用复用同一个网关 + +- 行为轻量: 一般只有转发、权限校验等轻量操作 + +基于这两个特点,语言层性能开销在总性能开销中的占比,往往会业务应用更大,这个时候, Golang 等语言会比 Java更有优势。当前也在对 Dubbo-Go 调研,未来替换基于 Java 版 Dubbo 的网关应用。 + +另外,Higress 方案看起来不错,必定会有许多值得我们学习的东西。 \ No newline at end of file diff --git a/content/en/blog/users/zhonglunwangluo.md b/content/en/blog/users/zhonglunwangluo.md new file mode 100644 index 000000000000..5b054378fd2c --- /dev/null +++ b/content/en/blog/users/zhonglunwangluo.md @@ -0,0 +1,61 @@ +--- +date: 2023-01-15 +title: "中伦网络 Dubbo3 升级实践" +linkTitle: "中伦网络" +tags: ["用户案例"] +weight: 4 +--- + +中伦网络在 2022 年完成了服务框架从 Dubbo2 到 Dubbo3 的全站升级,深度使用了应用级服务发现、Kubernetes 原生服务部署、服务治理等核心能力。来自中仑网络的技术负责人来彬彬对整个 Dubbo3 的选型、升级过程及收益等做了深入总结。 + +值得一提的是近期 [Dubbo3 官网文档](/en/) 整体有了本质的提升,并且社区承诺短期内文档还会投入大量精力完善文档,这点对于 Dubbo3 的使用和用户信心提升非常重要。 + +### 一、公司业务与技术架构简介 + +[苏州中仑网络科技有限公司](https://www.zhonglunnet.com/guanyu.html)是一家“专注零售门店增收服务”的公司,一直以“解决中小零售门店经营难的问题”为初心,致力于为零售商户提供门店运营一体化解决方案,帮助零售门店实现增收。中仑网络以零售技术为核心,为零售商户打造出集收银系统、中仑掌柜、微商城、汇邻生活平台、大数据平台、移动支付、智慧农贸、汇邻门店运营服务等为一体的新零售生态体系,实现线上线下全方位融合,为零售商家赋能增收。技术团队在构建之初选取Dubbo 2.5.3+Zookeeper版本构建公司微服务基座支撑公司业务发展,后期同阿里云深度合作整体迁移使用阿里云,使用云原生基础设施ACK(Kubernetes)+MSE(Zookeeper)+Dubbo+PolarDB等构建,实现可动态缩扩容的服务能力。 +伴随合作商扩展3000+,市场遍及300+城市,零售商户30万+,服务覆盖餐饮、茶饮、服装、母婴、烘焙、生鲜、商超、美业、美妆、宠物等多个行业。伴随着领域拓宽、商户量快速增长上升,系统数量和部署节点也迎来了暴增,随之在系统可用性上受到较大挑战:微服务治理能力、微服务地址注册发现,Kubernetes平台服务的无损上下线顺滑度上问题与挑战越来越多。架构图见图一。 + +![image1](/imgs/v3/users/zhonglunwangluo-1.png) + +图一 + +### 二、Dubbo3 升级总结 + +在升级微服务组件技术选型上主要考虑解决以前的痛点:服务治理能力、云原生友好性、服务注册发现,这几个制约业务发展的紧要问题。比较下来Dubbo3架构设计理念与我们较为契合,能较好的满足我们业务发展要求。 + +### 1、服务治理能力 + +Dubbo 3提供丰富的服务治理能力,可实现诸如服务发现、负载均衡、流量调度等服务治理诉求。在使用上我们有两种选择:一、使用Dubbo管理控制台管理配置、二、集成相关API能力到系统。同时Dubbo 扩展性较好,可以在很多功能点(见图二)去定制自己的实现,以改变框架的默认行为来满足自己的业务需求。Dubbo SPI ( Service Provider Interface)将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。基于此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能,如我们在此基础上实现了基于生产和消费者过滤器Filter实现全链路自定义的链路监控;基于路由扩展标签路由方式进行测试环境的隔离方便快速多版本服务测试验证。实操上我们基于生产者注册服务时打标,如原系统A V1版本部署在fat环境上,现在为了测试V2版本,我们将V2版本打标tag=fat-v2;使用端在消费时指定Invocation Attachment 参数,inv.setAttachment(TAG_KEY, routeTag);基于此我们可以方便自测试,同时生产上我们也可以做简单的生产灰度运用。 + +![image2](/imgs/v3/users/zhonglunwangluo-2.png) +图二 + +### 2、云原生友好性 + +Dubbo 在设计上遵循云原生微服务开发理念,微服务支持 Kubernetes平台调度,实现服务生命周期与容器生命周期的对齐,包括 Dubbo 的启动、销毁、服务注册等生命周期事件。中仑网络微服务管理使用的是MSE(Zookeeper),因而我们服务暴露使用需与之对齐。具体操作上我们自定义Startup 启动探针、 Liveness 存活探针、Readiness 就绪探针。项目的正常切换需要保障无损的上下线,在实施中无损上线相对于下线来说会更麻烦点,项目的发布上线过程大体会遵从如下流程:大致分成三个阶段,第一阶段升级少量(如 20% )的实例,并切换少量流量到新版本,完成这个阶段后先暂停升级。经过人工确认之后继续第二个阶段,升级更大比例(如 90% )的实例和流量,再次暂停等待人工确认。最后阶段将全量升级到新版本并验证完毕,从而完成整个发布过程。如果升级期间发现包括业务指标在内的任何异常,例如 CPU 或 memory 异常使用率升高或请求 500 日志过多等情况,可以快速回滚。因为我们使用的是MSE(Zookeeper)服务,dubbo服务自注册在应用启动过程暴露不受Kubernetes 生命周期的控制,出现项目未完全就绪部分服务可被提前可被访问问题。 + +![image3](/imgs/v3/users/zhonglunwangluo-3.png) +图三 + +实施处理上我们主要利用Dubbo Qos指令,初始使用服务不暴露,在应用就绪后调用Qos online指令进行服务上线替换老节点,每次替换的节点数量基于发布策略来制定;下线过程针对需下线节点我们会先使用Qos指令进行下线offline操作等待应用执行完服务,从而进行优雅停机,从实践的效果来看能满足我们的生产需求。 + +### 3、实例级别升级切换 + +相比于 2.x 版本中的基于接口粒度的服务发现机制,3.x 引入了全新的基于应用粒度的服务发现机制,进一步提升了 Dubbo3 在大规模集群实践中的性能与稳定性。此次升级过程中我们也同步引入了配置中心与原数据中心,即将图四置灰部分启用 + +![image4](/imgs/v3/users/zhonglunwangluo-4.png) +图四 + +采用实例级别注册管理,一个应用N个服务,接口级时N服务需监听推送,应用级只关注单实例相关信息。同时引入元数据中心后极大降低接口配置数据信息,减少接口数据传输大小,相关职责配置也更加清晰。根据测试新模型大幅提高系统资源利用率,降低 Dubbo 地址的单机内存消耗,大幅降低注册中心集群的存储与推送压力,上线后稳定性有较大的提升。 + +### 三、总结与展望 + +在中仑网络Dubbo 2升级Dubbo 3的过程中我们也有过一些迟疑,如把接口级换成应用级还是混合注册;Dubbo 3.0新特性新技术在项目中引入的时机与范围。对公司来说大的升级意味风险和不可预知的问题,但同时也能为之带来资源利用率提升、基础功能的扩展与增强,作为技术人员我们需要反复谨慎评估与论证。现在我们已经完成切换所有的业务领域。 + +### 四、Dubbo 社区合作 + +在这里再次感谢Dubbo社区人员的专业、高效,以及对中仑网络架构升级的大力支持,同时很荣幸能够成为一名社区的贡献者,感兴趣的同学可以**加入贡献者钉钉群:31982034**。 + +Dubbo 社区近期筹办了每周一次的微服务纯技术分享,讲解 Dubbo 使用、源码,同时涵盖众多云原生微服务知识,感兴趣的同学可扫码关注。 + + diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/_index.md b/content/en/overview/mannual/java-sdk/tasks/framework/_index.md index 041f348d7aa8..a666310fc6af 100755 --- a/content/en/overview/mannual/java-sdk/tasks/framework/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/_index.md @@ -6,4 +6,3 @@ type: docs weight: 6 --- -{{% docs/section_list %}} \ No newline at end of file diff --git a/content/en/overview/mannual/java-sdk/tasks/framework/more/_index.md b/content/en/overview/mannual/java-sdk/tasks/framework/more/_index.md index 79d44c4720f4..0231a9c955d3 100755 --- a/content/en/overview/mannual/java-sdk/tasks/framework/more/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/framework/more/_index.md @@ -5,5 +5,3 @@ title: Dubbo 作为轻量 RPC 框架解决组件通信问题 type: docs weight: 100 --- - -{{% docs/section_list %}} \ No newline at end of file diff --git a/content/en/overview/reference/pixiu/user/appendix/_index.md b/content/en/overview/reference/pixiu/user/appendix/_index.md index e61568a62108..30ec7e90427e 100755 --- a/content/en/overview/reference/pixiu/user/appendix/_index.md +++ b/content/en/overview/reference/pixiu/user/appendix/_index.md @@ -9,4 +9,4 @@ linkTitle: Appendix title: Appendix type: docs weight: 90 -### +--- diff --git a/content/en/overview/reference/pixiu/user/httpfilter/_index.md b/content/en/overview/reference/pixiu/user/httpfilter/_index.md index 82b520b227a6..abd9754b72b4 100755 --- a/content/en/overview/reference/pixiu/user/httpfilter/_index.md +++ b/content/en/overview/reference/pixiu/user/httpfilter/_index.md @@ -8,5 +8,4 @@ linkTitle: Introduction to Http Filter title: Introduction to Http Filter type: docs weight: 60 -### - +--- diff --git a/content/en/overview/reference/pixiu/user/listener/_index.md b/content/en/overview/reference/pixiu/user/listener/_index.md index ea8c255c9d1c..205243221b92 100755 --- a/content/en/overview/reference/pixiu/user/listener/_index.md +++ b/content/en/overview/reference/pixiu/user/listener/_index.md @@ -8,4 +8,4 @@ linkTitle: Introduction to Listener title: Introduction to Listener type: docs weight: 40 -### +--- diff --git a/content/en/overview/reference/setup/_index.md b/content/en/overview/reference/setup/_index.md index c793526a1e40..c6ba98a0b791 100755 --- a/content/en/overview/reference/setup/_index.md +++ b/content/en/overview/reference/setup/_index.md @@ -8,5 +8,5 @@ title: Installation toc_hide: true type: docs weight: 50 -### +--- From e1841f5152ff63d694c4d3fce367fe5d945498f2 Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Mon, 30 Sep 2024 14:21:28 +0800 Subject: [PATCH 05/23] Update netlify --- netlify.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/netlify.toml b/netlify.toml index 8975918d1311..85d6dd2e40ee 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,8 +1,8 @@ [build.environment] - HUGO_VERSION = "0.111.3" + HUGO_VERSION = "0.134.2" [context.deploy-preview.environment] -HUGO_VERSION = "0.111.3" +HUGO_VERSION = "0.134.2" [context.branch-deploy.environment] -HUGO_VERSION = "0.111.3" +HUGO_VERSION = "0.134.2" From ce9468332633de153f336f62b912bd9066baca2f Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Mon, 30 Sep 2024 14:25:26 +0800 Subject: [PATCH 06/23] Translate --- content/en/overview/_index.md | 6 +++--- content/en/overview/home/_index.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/content/en/overview/_index.md b/content/en/overview/_index.md index 65294327bc4a..be1d13f0f802 100755 --- a/content/en/overview/_index.md +++ b/content/en/overview/_index.md @@ -1,8 +1,8 @@ --- aliases: - /en/overview/ -description: Dubbo 文档 -linkTitle: 文档 -title: Dubbo 文档 +description: Dubbo Documentation +linkTitle: Documentation +title: Dubbo Documentation type: docs --- diff --git a/content/en/overview/home/_index.md b/content/en/overview/home/_index.md index cde46c541070..4008d2e2f11b 100644 --- a/content/en/overview/home/_index.md +++ b/content/en/overview/home/_index.md @@ -56,7 +56,7 @@ main_menu: true toc_hide: true menu: main: - name: Documentation + name: DOCUMENTATION weight: 1 no_list: true noedit: true From 7498923da535c8608eee512b42baa0868d449745 Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Mon, 30 Sep 2024 14:58:14 +0800 Subject: [PATCH 07/23] Translate --- content/en/overview/reference/_index.md | 11 +- .../overview/reference/integrations/_index.md | 5 +- .../reference/integrations/grafana.md | 37 +-- .../reference/integrations/higress.md | 25 +- .../overview/reference/integrations/nacos.md | 25 +- .../reference/integrations/prometheus.md | 26 +- .../reference/integrations/skywalking.md | 9 +- .../overview/reference/integrations/zipkin.md | 9 +- .../reference/integrations/zookeeper.md | 49 ++-- content/en/overview/reference/pixiu/_index.md | 5 +- .../en/overview/reference/pixiu/dev/_index.md | 7 +- .../reference/pixiu/dev/dubbo-pilot.md | 97 +++---- .../reference/pixiu/dev/filter-extension.md | 29 ++- .../en/overview/reference/pixiu/dev/trie.md | 121 ++++----- .../reference/pixiu/overview/_index.md | 7 +- .../overview/reference/pixiu/overview/faq.md | 19 +- .../reference/pixiu/overview/terminology.md | 31 +-- .../reference/pixiu/overview/what-is-pixiu.md | 34 +-- .../overview/reference/pixiu/user/_index.md | 9 +- .../reference/pixiu/user/adapter/_index.md | 7 +- .../reference/pixiu/user/adapter/dubbo.md | 9 +- .../pixiu/user/adapter/springcloud.md | 9 +- .../reference/pixiu/user/configurations.md | 50 ++-- .../reference/pixiu/user/deployment.md | 68 ++--- .../pixiu/user/networkfilter/_index.md | 7 +- .../pixiu/user/networkfilter/dubbo.md | 9 +- .../pixiu/user/networkfilter/grpc.md | 29 ++- .../pixiu/user/networkfilter/http.md | 9 +- .../reference/pixiu/user/quality/_index.md | 7 +- .../reference/pixiu/user/quickstart.md | 66 +++-- .../reference/pixiu/user/samples/_index.md | 7 +- .../pixiu/user/samples/http_proxy.md | 33 +-- .../pixiu/user/samples/http_to_dubbo.md | 9 +- .../reference/pixiu/user/samples/https.md | 9 +- .../en/overview/reference/proposals/_index.md | 7 +- .../en/overview/reference/proposals/admin.md | 92 +++---- .../proposals/heuristic-flow-control.md | 219 ++++++++-------- .../reference/proposals/protocol-http.md | 215 +++++++-------- .../proposals/registry-config-meta.md | 97 ++++--- .../reference/proposals/service-discovery.md | 81 +++--- .../proposals/support-more-content-types.md | 57 ++-- .../en/overview/reference/protocols/_index.md | 7 +- .../en/overview/reference/protocols/http.md | 244 +++++++----------- .../en/overview/reference/protocols/tcp.md | 65 +++-- .../en/overview/reference/protocols/triple.md | 99 ++++--- 45 files changed, 1001 insertions(+), 1065 deletions(-) diff --git a/content/en/overview/reference/_index.md b/content/en/overview/reference/_index.md index 8203868d7c66..4ccea3e14aaf 100755 --- a/content/en/overview/reference/_index.md +++ b/content/en/overview/reference/_index.md @@ -2,9 +2,9 @@ aliases: - /en/overview/reference/ description: "" -linkTitle: 其他 +linkTitle: Others no_list: true -title: 其他 +title: Others type: docs weight: 7 --- @@ -19,7 +19,7 @@ weight: 7

Dubbo Metrics

-

Dubbo Metrics 监控指标

+

Monitoring metrics for Dubbo

@@ -29,7 +29,7 @@ weight: 7

Dubbo Integrations

-

Dubbo Integrations 使用指南

+

User guide for Dubbo Integrations

@@ -39,7 +39,7 @@ weight: 7

Dubbo Proposals

-

Dubbo 提案

+

Dubbo proposals

@@ -49,3 +49,4 @@ weight: 7 {{< /blocks/section >}} + diff --git a/content/en/overview/reference/integrations/_index.md b/content/en/overview/reference/integrations/_index.md index 9ae61b587eac..0f6c13a1b521 100644 --- a/content/en/overview/reference/integrations/_index.md +++ b/content/en/overview/reference/integrations/_index.md @@ -2,8 +2,9 @@ aliases: - /en/overview/reference/integrations/ description: "" -linkTitle: 集成适配 -title: 集成适配 +linkTitle: Integration Adaptation +title: Integration Adaptation type: docs weight: 3 --- + diff --git a/content/en/overview/reference/integrations/grafana.md b/content/en/overview/reference/integrations/grafana.md index 6d15d7ce05a3..ef10e3780440 100644 --- a/content/en/overview/reference/integrations/grafana.md +++ b/content/en/overview/reference/integrations/grafana.md @@ -1,44 +1,44 @@ --- aliases: - /en/overview/reference/integrations/grafana/ -description: 配置 Grafana 与 Dubbo 一起工作 +description: Configuring Grafana to Work with Dubbo linkTitle: Grafana title: Grafana type: docs weight: 2 --- -Grafana 是一种开源的监控解决方案,可用于为 Dubbo 配置可视化仪表板,您可以使用 Grafana 来监控 Dubbo 集群的运行状况。 +Grafana is an open-source monitoring solution that can be used to configure visual dashboards for Dubbo, allowing you to monitor the health of your Dubbo cluster. -## 配置可视化控制面板 +## Configuring Visual Dashboards -以下是 Dubbo 社区提供的默认指标面板,您配置好数据源并直接导入使用即可。如果默认面板不能满足要求,您还可以自定义 Grafana 面板。 +Here are the default metrics dashboards provided by the Dubbo community. You can quickly use them after configuring the data source and importing directly. If the default dashboards do not meet your requirements, you can customize your Grafana dashboards. -* [**Apache Dubbo Observability Dashboard:**](https://grafana.com/grafana/dashboards/18469) -* [**JVM (Micrometer) Dashboard:**](https://grafana.com/grafana/dashboards/4701) +* [**Apache Dubbo Observability Dashboard:**](https://grafana.com/grafana/dashboards/18469) +* [**JVM (Micrometer) Dashboard:**](https://grafana.com/grafana/dashboards/4701) -您可以通过以下几种方式快速的导入 Grafana 监控面板。 +You can quickly import Grafana monitoring dashboards in the following ways. -### 方式一:Kubernetes 安装 +### Method 1: Kubernetes Installation -你可以使用 Dubbo 社区提供的示例配置快速安装 Grafana,安装后的 Grafana 提供了社区默认指标面板视图。 +You can quickly install Grafana using the sample configuration provided by the Dubbo community, which comes with the default community metrics dashboards. ```bash kubectl create -f https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/deploy/kubernetes/grafana.yaml ``` -你可能需要端口映射获得访问地址 `$ kubectl port-forward service/grafana 3000:3000`,打开浏览器访问页面 `http://localhost:3000`。 +You may need to port-forward to access it: `$ kubectl port-forward service/grafana 3000:3000`, then open the browser and visit `http://localhost:3000`. -> 获取登录信息 +> Retrieve login information > ```bash > kubectl get secrets grafana -o jsonpath="{.data.admin-user}" | base64 --decode ; echo && kubectl get secrets grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo > ``` -### 方式二:向已经安装好的集群导入 dashboard +### Method 2: Importing Dashboard into an Already Installed Cluster -如果你已经有安装好的 Grafana 服务了,则还可以通过 [Grafana 控制台的导入菜单](https://grafana.com/docs/grafana/v8.4/dashboards/export-import/#importing-a-dashboard) 导入 dashboard。根据 Grafana 的要求,导入 dashboard 的过程中需要同时指定 Prometheus 数据源地址。 +If you already have Grafana installed, you can import the dashboard via the [import menu in the Grafana console](https://grafana.com/docs/grafana/v8.4/dashboards/export-import/#importing-a-dashboard). The Prometheus data source address must also be specified during the import process. -你也可以选择使用以下脚本快速导入。 +You can also use the following script for quick importing. ```sh $ # Address of Grafana @@ -66,7 +66,8 @@ $ echo -e "\nDone\n" $ done ``` -### 方式三:自定义 -Grafana 可以通过其他方法进行安装和配置,可以参阅有关安装方法的文档了解如何制作和导入 Dubbo 检测面板 -* [Grafana provisioning 官方文档](https://grafana.com/docs/grafana/latest/administration/provisioning/#dashboards) -* [为 `stable/grafana` Helm chart 导入面板](https://github.com/helm/charts/tree/master/stable/grafana#import-dashboards) +### Method 3: Customization +Grafana can be installed and configured through other methods; refer to the documentation on installation methods to learn how to create and import Dubbo monitoring dashboards. +* [Grafana provisioning official documentation](https://grafana.com/docs/grafana/latest/administration/provisioning/#dashboards) +* [Importing dashboards for `stable/grafana` Helm chart](https://github.com/helm/charts/tree/master/stable/grafana#import-dashboards) + diff --git a/content/en/overview/reference/integrations/higress.md b/content/en/overview/reference/integrations/higress.md index 7890eb43e77e..060d60fc81d0 100644 --- a/content/en/overview/reference/integrations/higress.md +++ b/content/en/overview/reference/integrations/higress.md @@ -1,48 +1,47 @@ --- aliases: - /en/overview/reference/integrations/skywalking/ -description: "如何安装与配置 Higress,涵盖本地、docker、kubernetes 等环境。" +description: "How to install and configure Higress, covering local, docker, kubernetes, and other environments." linkTitle: Higress title: Higress type: docs weight: 6 --- -本文档讲解如何安装与配置 Higress,涵盖本地、docker、kubernetes 等环境。以下仅为快速示例安装指南,如想搭建生产可用集群请参考 Higress 官方文档。 +This document explains how to install and configure Higress, covering local, docker, kubernetes, and other environments. Below is a quick sample installation guide; for setting up a production-ready cluster, please refer to the official Higress documentation. ## docker -使用 docker 启动 Higress,请首先确保您已经在本地机器正确 下载页面 安装 docker。 +To start Higress using docker, please ensure you have correctly installed docker on your local machine. -使用以下命令安装 Higress: +Use the following command to install Higress: ```shell curl -fsSL https://higress.io/standalone/get-higress.sh | bash -s -- -a -c nacos://192.168.0.1:8848 --nacos-username=nacos --nacos-password=nacos ``` -请将 `192.168.0.1` 替换为 Nacos 服务器的 IP(如果 Nacos 部署在本机,请不要使用如 `localhost` 或 `127.0.0.1` 的 Loopback 地址)。按需调整 --nacos-username 和 --nacos-password 的取值,如果 Nacos 服务未开启认证功能,则可以移除这两个参数。 +Please replace `192.168.0.1` with the IP of the Nacos server (if Nacos is deployed locally, do not use loopback addresses such as `localhost` or `127.0.0.1`). Adjust the values of --nacos-username and --nacos-password as needed; if Nacos service does not have authentication enabled, these two parameters can be removed. -{{% alert title="注意" color="info" %}} -* 如果您还没有安装 nacos,请 [参考文档完成安装](../nacos/)。 -* 如果您使用 Zookeeper 做服务发现,请修改对应的集群地址为 zookeeper 集群地址。 +{{% alert title="Note" color="info" %}} +* If you haven't installed nacos, please [refer to the documentation for installation](../nacos/) . +* If you are using Zookeeper for service discovery, please modify the corresponding cluster address to the zookeeper cluster address. {{% /alert %}} -在浏览器中输入 `http://127.0.0.1:8080` 进入 Higress 控制台。 +Enter `http://127.0.0.1:8080` in your browser to access the Higress console. ## kubernetes -通过以下命令安装 Higress: +Install Higress with the following command: ```shell helm repo add higress.io https://higress.io/helm-charts helm install higress -n higress-system higress.io/higress --create-namespace --render-subchart-notes --set global.local=true --set higress-console.o11y.enabled=false ``` -通过以下端口映射命令,对本机访问开放端口: +Use the following port forwarding command to open ports for local access: ```shell kubectl port-forward service/higress-gateway -n higress-system 80:80 443:443 8080:8080 ``` -在浏览器中输入 `http://127.0.0.1:8080` 进入 Higress 控制台。 - +Enter `http://127.0.0.1:8080` in your browser to access the Higress console. diff --git a/content/en/overview/reference/integrations/nacos.md b/content/en/overview/reference/integrations/nacos.md index a2a9c6b0cb3b..9b3b034cc2c6 100644 --- a/content/en/overview/reference/integrations/nacos.md +++ b/content/en/overview/reference/integrations/nacos.md @@ -1,20 +1,20 @@ --- aliases: - /en/overview/reference/integrations/skywalking/ -description: "如何安装与配置 Nacos,涵盖本地、docker、kubernetes等环境。" +description: "How to install and configure Nacos, covering local, docker, kubernetes, and other environments." linkTitle: Nacos title: Nacos type: docs weight: 5 --- -本文档讲解如何安装与配置 Nacos,涵盖本地、docker、kubernetes 等环境。以下仅为快速示例安装指南,如想搭建生产可用集群请参考 Nacos 官方文档。 +This document explains how to install and configure Nacos, covering local, docker, and kubernetes environments. The following is just a quick example installation guide; for setting up a production-ready cluster, please refer to the official Nacos documentation. -## 本地下载 +## Local Download -Nacos 依赖 Java 环境 来运行,目前支持 Linux、MacOS、Windows 等环境。 +Nacos depends on the Java environment to run, currently supporting environments such as Linux, MacOS, and Windows. -您可以 下载最新稳定版本 Nacos,解压缩二进制包: +You can download the latest stable version of Nacos and extract the binary package: ```shell unzip nacos-server-$version.zip @@ -22,7 +22,7 @@ cd nacos/bin #tar -xvf nacos-server-$version.tar.gz ``` -#### 启动命令 +#### Startup Command ```shell # Linux/Unix/Mac sh startup.sh -m standalone @@ -34,17 +34,18 @@ bash startup.sh -m standalone startup.cmd -m standalone ``` -#### 验证 nacos 正常启动 +#### Verify Nacos Started Normally -通过浏览器访问以下链接打开控制台:http://127.0.0.1:8848/nacos/ +Access the console via the browser at the following link: http://127.0.0.1:8848/nacos/ -## docker -使用 docker 启动 nacos,请首先确保您已经在本地机器正确 下载页面 安装 docker。 +## Docker +To start Nacos using Docker, please ensure you have properly installed Docker on your local machine. ```shell docker run --name nacos-quick -e MODE=standalone -p 8849:8848 -d nacos/nacos-server:2.3.1 ``` -## kubernetes +## Kubernetes + +Please refer to nacos-operator for details on deploying Nacos to a Kubernetes cluster. -请参考 nacos-operator 了解如何部署 Nacos 到 Kubernetes 集群。 diff --git a/content/en/overview/reference/integrations/prometheus.md b/content/en/overview/reference/integrations/prometheus.md index 5abd96dfddf6..e5728ecde637 100644 --- a/content/en/overview/reference/integrations/prometheus.md +++ b/content/en/overview/reference/integrations/prometheus.md @@ -1,35 +1,35 @@ --- aliases: - /en/overview/reference/integrations/prometheus/ -description: 配置 Prometheus 与 Dubbo 一起工作 +description: Configure Prometheus to work with Dubbo linkTitle: Prometheus title: Prometheus type: docs weight: 1 --- -## 安装 +## Installation -你可以使用 Dubbo 社区提供的示例配置快速安装 Prometheus。 +You can quickly install Prometheus using the example configuration provided by the Dubbo community. ```bash kubectl create -f https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/deploy/kubernetes/prometheus.yaml ``` -> 本安装仅适用于测试或体验使用,生产级别的安装请参考 Prometheus 官方安装文档。 +> This installation is only suitable for testing or experience purposes. For production-grade installation, please refer to the official Prometheus installation documentation. -执行端口映射 `kubectl -n dubbo-system port-forward svc/prometheus-server 9090:9090`,访问页面 `http://localhost:9090`,切换到 graph 视图。 +Execute the port mapping `kubectl -n dubbo-system port-forward svc/prometheus-server 9090:9090`, and access the page at `http://localhost:9090`, then switch to the graph view. ![Prometheus](/imgs/v3/reference/integrations/prometheus.jpg) -## Scrape 配置 +## Scrape Configuration -Dubbo 的每个实例都会暴露一个 http 端口用于 Metrics 采集,Prometheus 通过 scraping 每个实例的 http 接口来采集统计数据。具体的 scraping 路径可以通过 Prometheus 配置文件进行调整,该文件控制 scraping 实例的端口、路径、TLS 设置等。 +Each instance of Dubbo exposes an HTTP port for Metrics collection, and Prometheus collects statistics by scraping the HTTP interface of each instance. The specific scraping path can be adjusted via the Prometheus configuration file, which controls the port, path, TLS settings, etc., for scraping instances. -### Kubernetes 注解约定 +### Kubernetes Annotation Convention -在 Kubernetes 部署模式下,使用官方社区维护的 [Helm Charts 安装 Prometheus](https://github.com/prometheus-community/helm-charts),Prometheus 服务可以自动识别包含 `prometheus.io` 注解的 Dubbo Pod 实例,并将它们列入 Scraping 实例列表。 +In the Kubernetes deployment mode, install Prometheus using the [Helm Charts maintained by the official community](https://github.com/prometheus-community/helm-charts), and the Prometheus service can automatically identify Dubbo Pod instances with the `prometheus.io` annotation and include them in the scraping instance list. -Dubbo 官网给出的示例即是基于 `prometheus.io` 注解实现了 scraping target 地址的自动发现,具体注解配置可参见示例中的 [Deployment 资源定义](https://github.com/apache/dubbo-samples/blob/master/4-governance/dubbo-samples-metrics-spring-boot/Deployment.yml)。 +The example provided by the Dubbo official website implements automatic discovery of the scraping target address based on the `prometheus.io` annotation. The specific annotation configuration can be found in the [Deployment resource definition](https://github.com/apache/dubbo-samples/blob/master/4-governance/dubbo-samples-metrics-spring-boot/Deployment.yml). ```yaml annotations: @@ -38,11 +38,11 @@ annotations: prometheus.io/port: "22222" ``` -在此模式下,Dubbo 实例默认提供的 Prometheus Metrics 采集路径是:`/management/prometheus`。 +In this mode, the Prometheus Metrics collection path provided by default for Dubbo instances is: `/management/prometheus`. -### 自定义配置 +### Custom Configuration -对于已经安装好的 Prometheus 服务,可以通过 Dubbo Admin 提供的 Prometheus http_sd 服务发现接口来配置 Dubbo Metrics 采集的目标实例。可以参考 Admin 安装相关文档,安装完成后 Prometheus 侧需要调整的配置如下: +For an already installed Prometheus service, you can configure the target instances for Dubbo Metrics collection using the Prometheus http_sd service discovery interface provided by Dubbo Admin. After the installation is complete, the configurations that need to be adjusted on the Prometheus side are as follows: ```yaml - job_name: 'dubbo' diff --git a/content/en/overview/reference/integrations/skywalking.md b/content/en/overview/reference/integrations/skywalking.md index 0d16206f154f..3f04dde4ecf5 100644 --- a/content/en/overview/reference/integrations/skywalking.md +++ b/content/en/overview/reference/integrations/skywalking.md @@ -1,18 +1,19 @@ --- aliases: - /en/overview/reference/integrations/skywalking/ -description: 配置 Skywalking 与 Dubbo 一起工作 +description: Configure Skywalking to work with Dubbo linkTitle: Skywalking title: Skywalking type: docs weight: 3 --- -## 安装 +## Installation -你可以使用 Dubbo 社区提供的示例配置快速安装 Skywalking。 +You can quickly install Skywalking using the example configuration provided by the Dubbo community. ```bash kubectl create -f https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/deploy/kubernetes/skywalking.yaml ``` -> 本安装仅适用于测试或体验使用,生产级别的安装请参考 Skywalking 官方安装文档。 +> This installation is only suitable for testing or experimental use; for production-level installation, please refer to the official Skywalking installation documentation. + diff --git a/content/en/overview/reference/integrations/zipkin.md b/content/en/overview/reference/integrations/zipkin.md index 4db9f1032820..44e732233075 100644 --- a/content/en/overview/reference/integrations/zipkin.md +++ b/content/en/overview/reference/integrations/zipkin.md @@ -1,18 +1,19 @@ --- aliases: - /en/overview/reference/integrations/zipkin/ -description: 配置 Zipkin 与 Dubbo 一起工作 +description: Configuring Zipkin to work with Dubbo linkTitle: Zipkin title: Zipkin type: docs weight: 4 --- -## 安装 +## Installation -你可以使用 Dubbo 社区提供的示例配置快速安装 Zipkin。 +You can quickly install Zipkin using the example configuration provided by the Dubbo community. ```bash kubectl create -f https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/deploy/kubernetes/zipkin.yaml ``` -> 本安装仅适用于测试或体验使用,生产级别的安装请参考 Zipkin 官方安装文档。 +> This installation is only suitable for testing or demonstration purposes. For production-level installations, please refer to the official Zipkin installation documentation. + diff --git a/content/en/overview/reference/integrations/zookeeper.md b/content/en/overview/reference/integrations/zookeeper.md index cc2c71891875..dfe8c8fc167c 100644 --- a/content/en/overview/reference/integrations/zookeeper.md +++ b/content/en/overview/reference/integrations/zookeeper.md @@ -1,30 +1,30 @@ --- aliases: - /en/overview/reference/integrations/skywalking/ -description: "如何安装与配置 Zookeeper,涵盖本地、docker、kubernetes等环境。" +description: "How to install and configure Zookeeper, covering local, docker, kubernetes, and other environments." linkTitle: Zookeeper title: Zookeeper type: docs weight: 6 --- -这篇文章讲解如何安装与配置 Zookeeper,涵盖本地、docker、kubernetes 等环境。以下仅为快速示例安装指南,如想搭建生产可用集群请参考 Zookeeper 官方文档。 +This article explains how to install and configure Zookeeper, covering local, docker, kubernetes, and other environments. The following is just a quick example installation guide; for setting up a production-ready cluster, please refer to the Zookeeper official documentation. -## 本地下载 +## Local Download -#### 下载Zookeeper -请到 Apache Zookeeper 下载页面 下载最新版本的 zookeeper 发行包。 +#### Download Zookeeper +Please go to the Apache Zookeeper download page to download the latest version of the Zookeeper release package. -解压下载的 zookeeper 包: +Unpack the downloaded Zookeeper package: ```shell tar -zxvf apache-zookeeper-3.8.3.tar.gz cd apache-zookeeper-3.8.3 ``` -#### 启动 Zookeeper +#### Start Zookeeper -在启动 zookeeper 之前,首先需要在根目录以下位置创建文件 `conf/zoo.cfg`: +Before starting Zookeeper, you need to create the file `conf/zoo.cfg` in the root directory: ``` tickTime=2000 @@ -32,26 +32,26 @@ clientPort=2181 admin.enableServer=false ``` -以下是一些参数的详细解释: -* tickTime : Zookeeper 用到的基本时间设置,tickTime 为心跳检测间隔, 2*tickTime 是最大 session 超时时间等(单位是毫秒 ms)。 -* clientPort : 监听端口,客户端可通过这个端口方案 zookeeper server -* admin.enableServer:运维端口,默认为 8080,建议关闭防止和 Spring Web 应用程序冲突 +Here are detailed explanations of some parameters: +* tickTime: The basic time setting used by Zookeeper, tickTime is the heartbeat detection interval, 2*tickTime is the maximum session timeout (in milliseconds). +* clientPort: The listening port, clients can connect to the Zookeeper server through this port. +* admin.enableServer: The maintenance port, default is 8080, recommended to turn off to prevent conflicts with Spring web applications. -接下来,可以以 standalone 模式启动 Zookeeper 了: +Next, you can start Zookeeper in standalone mode: ```shell bin/zkServer.sh start ``` -#### 测试连接到 ZooKeeper +#### Test Connection to ZooKeeper -运行以下命令,连接到刚刚启动的 zookeeper server: +Run the following command to connect to the just started Zookeeper server: ```shell $ bin/zkCli.sh -server 127.0.0.1:2181 ``` -连接成功后,可看到以下输出: +Once connected successfully, you will see the following output: ```shell Connecting to localhost:2181 @@ -61,32 +61,33 @@ JLine support is enabled [zkshell: 0] ``` -执行以下命令查看根节点内容: +Execute the following command to view the root node contents: ```shell [zkshell: 8] ls / [zookeeper] ``` -## docker +## Docker -使用 docker 启动 zookeeper,请首先确保您已经在本地机器正确 下载页面 安装 docker。 +To start Zookeeper using Docker, please ensure you have correctly installed Docker on your local machine. -运行以下命令启动 zookeeper server: +Run the following command to start the Zookeeper server: ```shell docker run --name some-zookeeper -p 2181:2181 -e JVMFLAGS="-Dzookeeper.admin.enableServer=false" --restart always -d zookeeper:3.8.3 ``` -如果你要指定 `/conf` 配置文件,可通过 mount 本地文件到 docker 容器: +If you want to specify the `/conf` configuration file, you can mount the local file to the Docker container: ```shell -$ docker run --name some-zookeeper --restart always -e JVMFLAGS="-Dzookeeper.admin.enableServer=false" -d -v $(pwd)/zoo.cfg:/conf/zoo.cfg +$ docker run --name some-zookeeper --restart always -e JVMFLAGS="-Dzookeeper.admin.enableServer=false" -d -v $(pwd)/zoo.cfg:/conf/zoo.cfg ``` -## kubernetes +## Kubernetes -您可以使用 Dubbo 社区提供的示例配置快速安装 Zookeeper 到 Kubernetes 集群。 +You can quickly install Zookeeper to a Kubernetes cluster using the example configuration provided by the Dubbo community. ```shell kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/deploy/kubernetes/zookeeper.yaml ``` + diff --git a/content/en/overview/reference/pixiu/_index.md b/content/en/overview/reference/pixiu/_index.md index f5fc015b6334..9b2bcc91fd05 100755 --- a/content/en/overview/reference/pixiu/_index.md +++ b/content/en/overview/reference/pixiu/_index.md @@ -4,9 +4,10 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/ - /en/overview/mannual/dubbo-go-pixiu/ - /en/overview/reference/pixiu/ -description: Dubbo Go Pixiu 简介 +description: Introduction to Dubbo Go Pixiu linkTitle: Pixiu gateway -title: Dubbo Go Pixiu 简介 +title: Introduction to Dubbo Go Pixiu type: docs weight: 15 --- + diff --git a/content/en/overview/reference/pixiu/dev/_index.md b/content/en/overview/reference/pixiu/dev/_index.md index 422cbb61fecb..285e0c468d38 100755 --- a/content/en/overview/reference/pixiu/dev/_index.md +++ b/content/en/overview/reference/pixiu/dev/_index.md @@ -2,9 +2,10 @@ aliases: - /en/overview/mannual/dubbo-go-pixiu/dev/ - /en/overview/reference/pixiu/dev/ -description: 开发者指南 -linkTitle: 开发者指南 -title: 开发者指南 +description: Developer Guide +linkTitle: Developer Guide +title: Developer Guide type: docs weight: 30 --- + diff --git a/content/en/overview/reference/pixiu/dev/dubbo-pilot.md b/content/en/overview/reference/pixiu/dev/dubbo-pilot.md index 0b0a58fda877..5f931f6168e0 100644 --- a/content/en/overview/reference/pixiu/dev/dubbo-pilot.md +++ b/content/en/overview/reference/pixiu/dev/dubbo-pilot.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/dev/dubbo-pilot/ - /en/overview/reference/pixiu/dev/dubbo-pilot/ - /en/overview/mannual/dubbo-go-pixiu/dev/dubbo-pilot/ -description: dubbo-pilot Control Plane 部署 -linkTitle: dubbo-pilot Control Plane 部署 -title: dubbo-pilot Control Plane 部署 +description: dubbo-pilot Control Plane Deployment +linkTitle: dubbo-pilot Control Plane Deployment +title: dubbo-pilot Control Plane Deployment type: docs weight: 2 --- @@ -16,33 +16,33 @@ weight: 2 -* [1.总体目标](#target) -* [2.基本流程](#basic) -* [3.详细步骤](#detail) - + [3.1 环境要求](#env) - + [3.2 istio 本地部署](#native_deploy) - - [3.2.1 编译](#nbuild) - - [3.2.2 部署 & debug](#ndeploy) - + [3.3 istio 容器部署](#docker_deploy) - - [3.3.1 编译](#dbuild) - - [3.3.2 部署 & debug](#ddeploy) -

1 总体目标

+* [1. Overall Goals](#target) +* [2. Basic Process](#basic) +* [3. Detailed Steps](#detail) + + [3.1 Environment Requirements](#env) + + [3.2 Local Deployment of Istio](#native_deploy) + - [3.2.1 Compilation](#nbuild) + - [3.2.2 Deployment & Debugging](#ndeploy) + + [3.3 Container Deployment of Istio](#docker_deploy) + - [3.3.1 Image Building](#dbuild) + - [3.3.2 Deployment](#ddeploy) +

1 Overall Goals

-* 控制面编译和镜像构建 -* 使用 istioctl 在 kubernetes 环境部署 -* 如何对控制面程序 debug +* Compile the control plane and build images +* Deploy using istioctl in a Kubernetes environment +* How to debug the control plane program -

2 基本流程

-这个例子将演示如何在编译 dubbo-pilot 控制平面并在 kubernetes 环境下如何使用 istioctl 进行部署 +

2 Basic Process

+This example will demonstrate how to compile the dubbo-pilot control plane and how to deploy it using istioctl in a Kubernetes environment. -1. 本地启动控制平面,对 dubbo-pilot 进行启动和 debug -2. 使用 istioctl 在 k8s 环境启动和 debug +1. Start the control plane locally, and debug dubbo-pilot. +2. Use istioctl for starting and debugging in the k8s environment. -

3 详细步骤

-

3.1 环境要求

+

3 Detailed Steps

+

3.1 Environment Requirements

* Golang * Docker @@ -51,10 +51,10 @@ weight: 2 * Dlv -

3.2 本地部署

-

3.2.1 编译

+

3.2 Local Deployment

+

3.2.1 Compilation

-1. 编译 docker-builder +1. Compile the docker-builder ``` cd dubbo-go-pixiu/tools/docker-builder && go install @@ -84,31 +84,31 @@ Flags: --version show build version ``` -2. 使用 docker-builder 自动编译 && 构建镜像 +2. Use docker-builder to automatically compile and build the image -编译 istioctl +Compile istioctl ``` docker-builder --targets istioctl -编译完成: +Compilation completed: ls out/linux_amd64/ istioctl logs pilot-agent pilot-discovery ``` -编译 dubbo-pilot 并推送到私有镜像仓库 +Compile dubbo-pilot and push to private image repository ``` tools/docker-builder/docker-builder --targets pilot --hub docker.io/bobtthp --push ``` -

3.2.2 本地部署

+

3.2.2 Local Deployment

-本地启动方式: +Local start method: ``` ./out/linux_amd64/pilot-discovery -启动日志: +Startup log: 2022-09-24T15:31:56.751245Z info FLAG: --caCertFile="" 2022-09-24T15:31:56.751277Z info FLAG: --clusterAliases="[]" 2022-09-24T15:31:56.751280Z info FLAG: --clusterID="Kubernetes" @@ -121,13 +121,13 @@ tools/docker-builder/docker-builder --targets pilot --hub docker.io/bobtthp --pu 2022-09-24T15:31:56.753814Z info initializing mesh configuration ./etc/istio/config/mesh ``` -

3.3 容器部署

+

3.3 Container Deployment

-

3.3.1 镜像构建

+

3.3.1 Image Building

-构建远程 debug 镜像 +Build remote debug image -1. 下载 dlv +1. Download dlv ``` git clone https://github.com/go-delve/delve.git make install @@ -136,22 +136,22 @@ which dlv /root/go/bin/dlv ``` -2. Dockerfile 增加dlv dubbo-go-pixiu/pilot/docker/Dockerfile.pilot: +2. Add dlv to Dockerfile in dubbo-go-pixiu/pilot/docker/Dockerfile.pilot: ``` COPY ${TARGETARCH:-amd64}/dlv /usr/local/bin/dlv ``` -3. 拷贝 dlv 至镜像挂载目录中: +3. Copy dlv to the image mount directory: ``` cp /root/go/bin/dlv out/linux_amd64/dockerx_build/build.docker.pilot/amd64/ ``` -4. debug 镜像构建并推送: +4. Build and push the debug image: ``` docker-builder --targets pilot --hub docker.io/bobtthp --push --tag debug ``` -5. 本地也可以查看镜像构建情况: +5. You can also check the image build status locally: ``` [root~master-1] /tmp/dubbo-go-pixiu/tools/docker-builder> docker images @@ -161,14 +161,14 @@ bobtthp/pilot latest -

3.3.2 部署

+

3.3.2 Deployment

-1. 使用刚构建的镜像部署: +1. Deploy using the newly built image: ``` out/linux_amd64/istioctl --set .values.pilot.image=bobtthp/pilot:debug install ``` -2. 查看部署情况: +2. Check the deployment status: ``` [root~master] /tmp/dubbo-go-pixiu/tools/docker-builder> kubectl get po -n istio-system NAME READY STATUS RESTARTS AGE @@ -176,13 +176,13 @@ istiod-fd5d9f77-2ncjq 1/1 Running 0 18m ``` -3. 进入容器远程 debug: +3. Enter the container for remote debugging: ``` [root~master-1] /tmp/dubbo-go-pixiu> kubectl exec -it -n istio-system istiod-fd5d9f77-2ncjq bash kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. ``` -4. 启动 dlv: +4. Start dlv: ``` istio-proxy@istiod-fd5d9f77-2ncjq:/$ dlv --listen=:8015 --headless=true --api-version=2 --log attach `ps -ef |grep pilot-discovery| awk '{print $2}'` 2022-11-04T15:43:14Z error layer=debugger could not create config directory: mkdir /home/istio-proxy/.config: read-only file system @@ -192,7 +192,7 @@ API server listening at: [::]:8015 ``` -5. 对外暴露端口: +5. Expose ports: ``` [root~master-1] /tmp> kubectl port-forward -n istio-system istiod-fd5d9f77-2ncjq 8015:8015 @@ -200,4 +200,5 @@ Forwarding from 127.0.0.1:8015 -> 8015 Forwarding from [::1]:8015 -> 8015 ``` -6. 可以进行远程调试 +6. Remote debugging is now possible. + diff --git a/content/en/overview/reference/pixiu/dev/filter-extension.md b/content/en/overview/reference/pixiu/dev/filter-extension.md index e6cb752f2fb6..2e5fe21eb365 100644 --- a/content/en/overview/reference/pixiu/dev/filter-extension.md +++ b/content/en/overview/reference/pixiu/dev/filter-extension.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/dev/filter-extension/ - /en/overview/reference/pixiu/dev/filter-extension/ - /en/overview/mannual/dubbo-go-pixiu/dev/filter-extension/ -description: Pixiu Filter体系介绍 -linkTitle: Pixiu Filter体系介绍 -title: Pixiu Filter体系介绍 +description: Introduction to the Pixiu Filter System +linkTitle: Introduction to the Pixiu Filter System +title: Introduction to the Pixiu Filter System type: docs weight: 1 --- @@ -16,19 +16,19 @@ weight: 1 -## **怎样编写一个Filter** -`更详细的信息,请移步Blog《谈谈Pixiu的Filter》` +## **How to Write a Filter** +`For more detailed information, please refer to the Blog "Talking About Pixiu's Filter"` -我们来尝试写一个简单的Filter,这个Filter将会有简单的配置,在Decode阶段把请求的Body Log出来,并翻转后作为Mock的返回值。最后在Encode阶段根据配置把返回值Log出来。 +Let's try writing a simple Filter that will have a basic configuration, log the request Body during the Decode phase, and return the reversed string as a Mock response. Finally, in the Encode phase, it will log the return value based on the configuration. -1.首先创建一个Filter +1. First, create a Filter ```go type DemoFilter struct { logPrefix string } -// Decode阶段,发生在调用Upstream之前 +// Decode phase, occurs before calling Upstream func (f *DemoFilter) Decode(ctx *contexthttp.HttpContext) filter.FilterStatus { body, _ := ioutil.ReadAll(ctx.Request.Body) logger.Infof("request body: %s", body) @@ -45,7 +45,7 @@ func (f *DemoFilter) Decode(ctx *contexthttp.HttpContext) filter.FilterStatus { return filter.Stop } -// Encode阶段,此时可以获取到Upstream的Response +// Encode phase, at this point the Upstream Response can be accessed func (f *DemoFilter) Encode(ctx *contexthttp.HttpContext) filter.FilterStatus { res := ctx.SourceResp.(string) logger.Infof("%s: %s", f.logPrefix, res) @@ -53,7 +53,7 @@ func (f *DemoFilter) Encode(ctx *contexthttp.HttpContext) filter.FilterStatus { } ``` -2.创建Filter Factory +2. Create a Filter Factory ```go type ( @@ -83,7 +83,7 @@ func (f *DemoFilterFactory) Apply() error { } ``` -3.创建Filter Plugin,并注册自己 +3. Create a Filter Plugin and register it ```go //important @@ -103,7 +103,7 @@ func (p *Plugin) CreateFilterFactory() (filter.HttpFilterFactory, error) { } ``` -4.配置文件中配置此Filter,并启动Pixiu +4. Configure this Filter in the configuration file and start Pixiu ```yaml static_resources: @@ -127,7 +127,7 @@ static_resources: config: ``` -5.访问并查看日志与结果 +5. Access and check the logs and results ```shell curl localhost:8888/demo -d "eiv al tse’c" @@ -135,9 +135,10 @@ curl localhost:8888/demo -d "eiv al tse’c" c’est la vie% ``` -日志 +Logs ``` 2022-02-19T20:20:11.900+0800 INFO demo/demo.go:62 request body: eiv al tse’c 2022-02-19T20:20:11.900+0800 INFO demo/demo.go:71 : eiv al tse’c ``` + diff --git a/content/en/overview/reference/pixiu/dev/trie.md b/content/en/overview/reference/pixiu/dev/trie.md index 449ecd33e42e..ebfe772cc4d9 100644 --- a/content/en/overview/reference/pixiu/dev/trie.md +++ b/content/en/overview/reference/pixiu/dev/trie.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/dev/trie/ - /en/overview/reference/pixiu/dev/trie/ - /en/overview/mannual/dubbo-go-pixiu/dev/trie/ -description: Trie 前缀树介绍 -linkTitle: Trie 前缀树介绍 -title: Trie 前缀树介绍 +description: Introduction to Trie Prefix Tree +linkTitle: Introduction to Trie Prefix Tree +title: Introduction to Trie Prefix Tree type: docs weight: 2 --- @@ -15,18 +15,18 @@ weight: 2 -# 简介 +# Introduction -![image.png](/imgs/pixiu/trie-1.png)
网关的核心之一是路由逻辑,决定一个请求需要经过怎样的加工,被转发到哪个下行服务。
其中 80% 的路由需求表达都以 URL 为基础。需要描述清楚具有某个特征的 URL 或者 URL 集合对应怎样的一系列下游处理策略。 +![image.png](/imgs/pixiu/trie-1.png)
One of the cores of the gateway is the routing logic, which determines how a request needs to be processed and which downstream service it should be forwarded to.
About 80% of routing requirements are URL-based. It is necessary to clearly describe how URLs or sets of URLs with certain characteristics correspond to a series of downstream processing strategies. -例如,'/test/**' 开头的 URL 路由到测试环境集群,'/release/user/**' 开头的 URL 会被路由到正式环境的 user 服务集群。 +For example, URLs starting with '/test/**' route to the testing environment cluster, while URLs starting with '/release/user/**' route to the production environment's user services cluster. -同时网关作为所有请求的入口,每一毫秒的延时都会做用在全量的业务下,在 mesh 场景下,延时还会随着调用链路的加深,被倍数放大。按照生产环境业务相应 <=7 毫秒的标准来看,规则匹配的性能要求也是十分苛刻的。一定不能随着规则数目的增加而性能退化。 +Additionally, as the entry point for all requests, every millisecond of delay accumulates across the entire business in a mesh scenario, where delays can further magnify with the depth of the call chain. According to the standard for production environments, response times of <=7 milliseconds set a very demanding performance requirement for rule matching. Performance must not degrade as the number of rules increases. -# 使用介绍 +# Usage Introduction -仅从使用方的角度阐述 pixiu 的配置文件如何描述 URL 相关的路由规则。(下面,我们介绍一下如何配置 URL 路由规则)
如下是一份 pixiu 的 api 配置文件,这份配置文件会被解析后生成一份对应的内存模型,作为 pixiu 路由相关配置的初始状态。之后由 RDS 协议修改解析后得到的内存模型,实现路由逻辑动态生效的效果。RDS 协议(RDS:xDS 协议下描述路由规则的部分)相关内容是后话不详细阐述。我们把注意力聚焦到resource部分。
resource 下 path 部分就是上文阐述的,URL 相关的路由描述。意思是满足 path 描述特征的 URL 会被成功匹配。 +This section describes how Pixiu's configuration file delineates URL-related routing rules from the user's perspective. (Next, we will explain how to configure URL routing rules.)
Below is a sample Pixiu API configuration file, which will be parsed to create a corresponding memory model as the initial state for Pixiu's routing configuration. Subsequently, the memory model obtained by parsing will be modified by the RDS protocol to achieve dynamic routing logic. The content related to the RDS protocol (RDS: the part of the xDS protocol that describes routing rules) will not be detailed here. Let’s focus on the resource section.
The path part under resource represents the URL-related routing description discussed above. This means that URLs that match the path description will be successfully matched. ```json name: server @@ -60,88 +60,89 @@ resources: ``` -被匹配后的请求会被转化成 dubbo 协议转发到 test_dubbo 集群调用 com.dubbogo.server.UserService 下的 GetUserByName 服务。
我们继续聚焦到如下范围: +Matched requests will be converted into the Dubbo protocol and forwarded to the test_dubbo cluster to call the GetUserByName service under com.dubbogo.server.UserService.
Let’s further focus on the following scope: ```json path: '/api/v1/test-dubbo/user/name/:name' ``` -为了描述清楚一个 URL 或者一组 URL,路由引擎需要拥有以下能力: +To describe a URL or a group of URLs clearly, the routing engine needs to have the following capabilities: -1. URL 可以包含变量,'/api/v1/test-dubbo/user/name/:name' 代表 URL 用“/”分割后,第六个部分的值作为变量 name 的值,向下游 filter 传递供filter使用。 -1. 需要有通配符 - 1. * 代表一个层级任意字符的通配 '/api/*/test-dubbo/user/name/:name' 这样的一个 path 描述代表了可能并不关心具体的版本,不论什么版本下的 URL 只要匹配都使用相同的逻辑加工数据并转发。 - 1. ** 代表多个层级的通配,从这个层级以后,子层级也可以是任意字符,**只可能存在于 URL 的末尾,不然会有二义性。'/api/v1/**' 这样的 path 表达了所有 V1 版本下的 URL 都采用相同的逻辑。 +1. URLs can include variables; '/api/v1/test-dubbo/user/name/:name' indicates that the value of the sixth segment separated by "/" is used as the value of the variable name, which is passed to the downstream filter for usage. +1. Wildcards are required. + 1. * represents a wildcard for any single character at one level; a path description like '/api/*/test-dubbo/user/name/:name' indicates that the specific version is not essential, and any URL that matches, regardless of the version, will be processed and forwarded using the same logic. + 1. ** represents wildcards for multiple levels; it can only exist at the end of the URL to avoid ambiguity. A path like '/api/v1/**' indicates that all V1 version URLs will adopt the same logic. -为了正确的使用 pixiu 您可能还需要了解如下内容。 +To use Pixiu correctly, you may need to understand the following content. -## 优先级 +## Priority -并非是独创的,类似 java 下的 spring 以及其他框架统一具有的优先级逻辑: +This is not a novel concept; it is a priority logic commonly possessed by frameworks like Spring in Java: -1. 通配的优先级低于特指 。 '/api/v1/**' 低于 '/api/v1/test-dubbo/user/name/:name' 的优先级,假设有两个 resource 分别采用了如上两个path 配置,request 为 '/api/v1/test-dubbo/user/name/yqxu' 的请求到达pixiu 后应该生效哪个 resource?按照通配低于特指的原则,'/api/v1/test-dubbo/user/name/:name' 这条规则会生效。 -1. 深度更深的,优先级更高 。 '/api/v1/**' 对比 /api/v1/test-dubbo/**' ,如果请求同时满足如上两个描述, '/api/v1/test-dubbo/**' 深度更深,会生效。 -1. 通配符之间 '/*' 优先级高于 '/**' -1. 变量等同于通配。 +1. Wildcard priorities are lower than specific ones. The priority of '/api/v1/**' is lower than that of '/api/v1/test-dubbo/user/name/:name'. If two resources adopt the aforementioned path configurations, which resource should take effect upon receiving a request for '/api/v1/test-dubbo/user/name/yqxu' ? According to the principle that wildcards are lower than specifics, the rule '/api/v1/test-dubbo/user/name/:name' will take effect. +1. Deeper levels have higher priorities. The comparison between '/api/v1/**' and '/api/v1/test-dubbo/**'; if both descriptions are satisfied, '/api/v1/test-dubbo/**' will take effect due to its deeper level. +1. Wildcard '/*' has a higher priority than '/**'. +1. Variables are equivalent to wildcards. -## 冲突处理 +## Conflict Handling -优先级规则只是冲突解决策略的一种,才同时匹配多个url描述时,优先级更高的那一种将会生效,然而优先级策略并不能涵盖所有的情况。
如果强行配置两条 resource path 完全相同,但是转发到不同的下游服务,这时候就会冲突。pixiu 下应对冲突的方案是 failfast,在 pixiu 初始化阶段,发现配置文件中有冲突的两项规则,则启动失败,让开发者今早发现问题并处理。 +The priority rule is just one way to resolve conflicts. When multiple URL descriptions match simultaneously, the one with the higher priority will take effect. However, the priority strategy cannot cover all cases.
If two resource paths are configured to be exactly the same but forwarded to different downstream services, a conflict will occur. Pixiu's strategy for handling conflicts is to fail fast; if conflicting rules are found during the initialization phase of Pixiu, the startup will fail, allowing developers to detect and address the issue early. -# 原理介绍 +# Principle Introduction -技术选型之初,以及确定使用pixiu后为了处理一些突发情况,以及应付一些pixiu自身可能存在的bug,开发者需要对pixiu 的路由原理有更深刻的了解。
下面,我们将详细介绍路由引擎的相关原理和实现,供感兴趣的同学了解。
相信阅读这部分内容的同学一定会有人下意识联想到字典树这个结构。使用字典树这个结构能实现存量规则数无关的匹配性能优化。 +Upon selecting the technology and determining the use of Pixiu to handle unforeseen situations and potential bugs, developers need to have a deeper understanding of the routing principles of Pixiu.
Next, we will detail the relevant principles and implementations of the routing engine for those interested.
Those who read this part are likely to subconsciously think of the structure of a trie. Utilizing a trie structure can achieve performance optimization in matching irrespective of the number of existing rules. -一个存放字符串作为node的字典树,具有表达url 的能力。
![img](/imgs/pixiu/trie-2.png)
如上图描述等价于URL集合 '/api/v1' ,'/api/v2' ,'/web' +A trie that stores strings as nodes can express URLs.
![img](/imgs/pixiu/trie-2.png)
This depiction is equivalent to the URL set '/api/v1', '/api/v2', '/web'. -维护一个标准字典树有几个关键的操作 +Maintaining a standard trie involves several key operations: -1. 字典树指定节点的查找(find): 从root 开始遍历字典书,'/api/v2' 称之为路径,在当前层级寻找指定路径,如果存在就继续在子树下完成剩下的路径匹配。'/api/v2' 先从 logic root 找到 '/api' ,并在 '/api' 的子树下继续查找剩下的路径 '/v2' 。 -1. 字典树节点的添加(add): 尝试查找指定节点,如果指定节点不存在则新建一个节点。假设一个空树状态下添加 '/api/v1' ,因为是空树那么logic root 下查找 '/api' 一定不存在,则在 root 下创建 '/api' ,继续在创建的 '/api' 节点下查找 '/v1' 因为 '/api' 是新建的 v1 一定也不存在,则继续创建v1 -1. 字典树url匹配(match):在这个最简单的版本下,匹配逻辑与指定节点的查找逻辑没有区别。 +1. Trie Node Lookup (find): Starting from the root, traverse the trie; '/api/v2' is called a path that searches for the specified path in the current level. If it exists, continue matching the remaining path in the subtree. For '/api/v2', the search begins at the logic root for '/api', continuing under '/api' for the remainder '/v2'. +1. Adding to Trie Nodes (add): Attempt to find the specified node; if it does not exist, create a new node. Assuming an empty tree state while adding '/api/v1', the logic root will not find '/api', creating it before searching under '/api' for '/v1', which also does not exist, leading to its creation. +1. URL Matching in Trie (match): In this simplest version, the matching logic is identical to the specified node lookup logic. -还有一些不涉及递归或者复用上面逻辑递归操作的简单操作 +Some simple operations that do not involve recursion or reuse the above logic: -4. 修改字典树节点(modify):通过 find 逻辑找到指定节点,调用 set 方法或者直接赋值的方式修改节点内容。 -4. 删除字典树节点(delete): 通过 modify 逻辑修改 isdeleted 标为 true,并把节点内容 modify 为空。节点本身的内存不释放。 -4. 重建字典树(rebuild):遍历所有节点,添加到新树,如果 isdeleted为 true 则不添加到新树,通过rebuild 操作创建副本。 +4. Modifying a Trie Node (modify): Find the specified node using the find logic and modify the node content through the set method or direct assignment. +4. Deleting a Trie Node (delete): Using the modify logic, change isDeleted to true and modify the node content to empty. The node's memory is not released. +4. Rebuilding the Trie (rebuild): Traverse all nodes and add them to a new tree. If isDeleted is true, it is not added to the new tree, creating a copy via the rebuild operation. -由上可知,标准字典树结构距离通用的路由引擎底层数据结构能力还有一定差距,缺乏统配描述能力,缺乏变量表达的能力,下面我们来看一下如何进行改进。 +As noted, a standard trie structure still has gaps in its capabilities for a general routing engine, lacking generalized representation and variable expression abilities. Let’s look at how to improve this. -添加 描述统配逻辑的子树,作为子树中默认存在的一部分
![img](/imgs/pixiu/trie-3.png)
现在我们的变种字典树多了变量表达能力
'/web/:appname/test/*' 这样的url 在图中应该怎么表达?
没错就是这个路径
+Adding subordinate trees that describe generalized logic to form a default component of the subtree.
![img](/imgs/pixiu/trie-3.png)
Now our variant trie gains variable expression capability.
How should a URL like '/web/:appname/test/*' be represented in the diagram?
Correct, it should be this path.
![img](/imgs/pixiu/trie-4.png) -继续分析字典树几个关键的操作是否需要做变化? +Continuing to analyze whether any key operations in the trie need changes: -1. 字典树指定节点的查找 : - 1. 如果不改动使用前一版本逻辑在 '/*' 节点处理之前都不会有问题: 从root 开始遍历字典书,'/api/v2/*' 称之为路径,在当前层级寻找指定路径,如果存在就继续在子树下完成剩下的路径匹配。 /api/v2 先从 logic root 找到 '/api' ,并在 '/api' 的子树下继续查找剩下的路径 '/v2' 。 - 1. 这版本我们加上对 '/*' 节点的处理:'/v2' 后是 '/*' ,'/*' 对应单级通配节点,继续递归查找 '/v2' 节点下一级通配节点是否为空。如果 path 是 '/api/v2/*/test2' 这样的路径则继续在统配子树下完成递归过程。 -2. 字典树节点的添加 : - 1. 在添加 '/*' 节点之前,所有逻辑上一版本就足够处理:尝试查找指定节点,如果指定节点不存在则新建一个节点。假设一个空树状态下添加 '/api/v1/*' ,因为是空树那么 logic root 下查找 '/api' 一定不存在,则在 root 下创建 '/api' ,继续在创建的 '/api' 节点下查找 '/v1' 因为 '/api' 是新建的 v1 一定也不存在,则继续创建 v1。 - 1. 这版本加上 '/*' 的特殊处理 :'/v1' 新建后,查看通配子树,通配子树不存在,则为V1 节点添加内容为空的单级通配子树并在子树中继续递归。 -3. 字典树url匹配:在这个版本下,对比查找逻辑需要增加回朔逻辑。 - 1. 在遇到通配节点前逻辑与find 依旧相同 : 从root 开始遍历字典书,'/api/v2/*' 称之为路径,在当前层级寻找指定路径,如果存在就继续在子树下完成剩下的路径匹配。 '/api/v2' 先从 logic root 找到 '/api' ,并在 '/api' 的子树下继续查找剩下的路径 '/v2' 。 - 1. 在处理统配节点的时候会与 find 逻辑有所不同:'/v2' 下普通子树无匹配节点,回朔到通配子树,查看是否能匹配,这个例子中 '/v2' 下无通配子树,查询不到节点 。值得注意的是回朔逻辑的先后顺序,是先找普通子树再回朔到通配子树还是先查找通配子树再回朔到普通子树是取决于优先级规则的,按照需求必须是先查找普通子树。 +1. Lookup for a Specific Trie Node: + 1. If the previous version logic is not modified before processing the '/*' node, there should not be any issues: Starting from the root, traverse the trie; '/api/v2/*' serves as the path. It finds the specified path in the current level. If it exists, continue matching in the subtree. For example, '/api/v2' first finds '/api' and continues searching for '/v2' in its subtree. + 1. In this version, handling of the '/*' node is added: After '/v2' is '/*', which corresponds to a single-level wildcard node. Continue to recursively check whether the wildcard node is empty beneath '/v2'. If path is '/api/v2/*/test2', continue the recursive process in the generalized subtree. +2. Adding a Trie Node: + 1. Before adding a '/*' node, the previous logic is adequate: attempt to locate the specified node; if it does not exist, create a new node. Given an empty tree state while adding '/api/v1/*', the logic root will not find '/api', leading to its creation before checking for '/v1', again leading to its creation if it doesn't exist. + 1. This version adds special handling for '/*': After creating '/v1', check for the wildcard subtree. If nonexistent, a single-level wildcard subtree representing V1 will be added, continuing the recursion. +3. URL Matching in the Trie: In this version, the comparison for fetch logic needs to enhance backtracking. + 1. When encountering a wildcard node, the logic prior to it remains unchanged: Starting from the root, traverse the trie; '/api/v2/*' is a designated path that searches for the specified path. If it exists, continue matching in the subtree. '/api/v2' will first find '/api' then continue with '/v2' in its subtree. + 1. There’s a deviation in handling wildcard nodes versus the find logic: If '/v2' hosts no matching nodes in its ordinary subtree, backtrack to the wildcard subtree to check for matches. In this case, as '/v2' leads to no matches, it should be mentioned that the order in backtracking is critical — whether to search the ordinary subtree first before backtracking to the wildcard subtree depends on the priority rules, and it must search the ordinary subtree first. -但是我们目前还是缺乏 '/**' 这种通配的表达能力代表了多级通配,可以分析需求得到结论,这种通配符,一定不存在子树,是一种特殊的叶子结点,仅用于 match 逻辑回朔时做特殊判断。继续加点特殊 node 后演化为:
![img](/imgs/pixiu/trie-5.png)
好了至此,需求都能满足了。
'/api/**' 等价路径为:
![img](/imgs/docs3-v2/dubbo-go-pixiu/dev/trie/1642993180981-51a0df19-bb03-49c8-9128-a6e95dbabfcd.png)
其他逻辑大同小异,match 逻辑回朔再多一级判断,如果一级通配子树也匹配不到结果,则再看一下多级通配子树是否为空(其实留一个标位就可以,为了统一模型好理解,还是用一个子树去描述) +However, we currently still lack the expressiveness of multi-level wildcards represented by '/**'. Analyzing requirement conclusions indicates these wildcards should not have subtrees; they are specialized leaf nodes used for special judgments during match logic backtracking. Continuing to introduce some special nodes evolves this into:
![img](/imgs/pixiu/trie-5.png)
Now, all requirements are sufficed.
Equivalent paths for '/api/**':
![img](/imgs/docs3-v2/dubbo-go-pixiu/dev/trie/1642993180981-51a0df19-bb03-49c8-9128-a6e95dbabfcd.png)
Other logic is largely the same; match logic now has one more level of judgment. If the single-level wildcard subtree still finds no results, check if the multi-level wildcard subtree is empty (one flag would suffice, but a subtree is used here for model uniformity and clarity). -到目前这个版本所有上文提到的能力已经都能有效支撑,回头分析一下时间复杂读。
url 被 '/' 分割出一个一个的段,容易理解在匹配一个url 过程中复杂度是 O(n) n= url 段数。与树中存有的规则数量无关。再分析 n 的范围,n 其实不是一个可以无限大的数字,一部分浏览器甚至约束 url 长度必须小于 2000,按照一个单词长度为 5 来计算,可以大概估计段数最多会在 400 左右,n 如果可以被视为一个常数,那么复杂读可以看作是 O(1)。 +At this point, all capabilities previously discussed can effectively support the relevant operations. Analyzing the complexity, URLs are divided into segments by '/', making matching complexity O(n), where n = number of URL segments. This complex analysis remains indifferent to the quantity of rules stored in the tree. Further analyzing scope of n reveals it is not an unlimited number; some browsers even constrain the URL length to below 2000 characters. Assuming an average segment length of 5, segments would generally be capped at around 400. If n could be considered a constant, the complexity can thus be viewed as O(1). -稍微解释一下find 和 match 有什么不同,为什么需要两种查找节点的方法。看下这个例子 :假设树中已经add 了 '/api/v1/:name/add' 这个 path,那么
find("/api/v1/:name/add"),find("/api/v1/*/add")两个调用应该能够拿到结果,在add 的过程中用于冲突判断。
假设有请求进来url 为 '/api/v1/:name/add' 那么match("/api/v1/:name/list")也应该能 match 到结果且变量name 为 :name。
再假设有请求进来 url 为 '/api/v1/yq/add' 那么match("/api/v1/yq/list")也应该能 match 到结果且变量name 为 yq 。find("/api/v1/yq/add" ) 则不会匹配到结果。 -# 后续改进 +In brief, explain the difference between find and match, and why both node retrieval methods are necessary. Consider this example: if the tree has already added the path '/api/v1/:name/add', then
find("/api/v1/:name/add") and find("/api/v1/*/add") should yield results during the add process for conflict checking.
Assuming a request comes in with URL '/api/v1/:name/add', match("/api/v1/:name/list") should also yield results, setting the variable name to :name.
If a request with the URL '/api/v1/yq/add' comes in, match("/api/v1/yq/list") should produce results with name being yq, while find("/api/v1/yq/add") will yield no result. +# Future Improvements -目前实现在读树和写树之前,竞争一把全局锁,竞争失败后自旋直到竞争成功,然后完成读写。
解释一下为什么读都需要上锁,因为代码中大量运用了go 的 map 结构。这个结构只要并发读写直接会报如下错误:concurrent map read and map write
目前实现如下
![img](/imgs/pixiu/trie-6.png)
引入 command 队列,所有对 trie 的用户写操作先入列,同时做读写分离,分为读树和写树,维护一个线程负责追 log 把 command 写入到写树,读树因为只读,没有写入线程操作读树所以可以不加锁。写树因为只有一条线程向树内写入,没有竞争问题,也可以不加锁。(写入操作并不会很频繁单线程完全能负荷)
定义一个配置延迟生效的时间,比如3s
每3秒,读树和写树角色切换,每个 trie 分别维护一个 command 队列的游标,游标代表当前这个 trie,追 log 追到了哪条记录,写入线程每3s 切换写游标引用。
+Currently, a global lock is acquired before reading or writing to the tree. On failure, it will spin until success before proceeding with read or write.
This is done because extensive use of Go's map structure is present in the code. Concurrent read-write accesses lead to this error: concurrent map read and map write.
The current implementation is as follows:
![img](/imgs/pixiu/trie-6.png)
A command queue is introduced, where all user write operations go in first, while separating read and write from each other. One thread is maintained to capture logs and write to the write tree. The read tree, which is purely read, does not require a write thread; hence, no locks are necessary. The write tree, written by only one thread, incurs no competition issues and, therefore, can also operate without locks (write operations are not frequent and are manageable via a single thread).
A configuration defining an effective delay time, say 3s, is set.
Every 3 seconds, the roles of the read and write trees switch. Each trie maintains a cursor for its command queue, indicating which record has been traced in the log where this trie is at, while the writing thread switches references of the writing cursor every 3 seconds.
![img](/imgs/pixiu/trie-7.png) -如上图,最上面部分是一个先进先出的 command 队列,追 log 线程从这个队列中读取用户写操作,这个队列维护了两个游标 index1,index2,index1 代表了trie1 追 log 追到了 index1 的位置,index2 代表了 trie2 追 log 追到了 index2 的位置。追 log 线程同一时间内只会使用一个引用进行写操作,每次写完树对应的 index 游标下移一格,另一个 trie 引用将被用于读操作,一切读请求将从读引用对应的树中读取。因为追的是同一份 log ,最终一致性是能保证的。 +In the above image, the top part represents a first-in-first-out command queue; the logging thread reads from this queue for user write operations. It maintains two cursor indices, index1 and index2; index1 indicates that trie1 has traced its logs to index1 position, while index2 shows trie2 has traced to index2. At any one moment, the logging thread will operate on one reference for write operations, shifting the corresponding index cursor down one space after completing each write. The other trie reference will be used for read operations; all read requests will come from the tree represented by the read reference. Since they are tracing the same log, eventual consistency is guaranteed. -切换逻辑: +Switching logic: -1. 先使追 log 线程空转(不挂起,避免上下文切换,因为马上要恢复) -1. 保证两个树都没有写入线程操作 -1. 切换读引用到另一个树 -1. 切换写引用到另一个树 -1. 恢复追 log 线程 +1. First, ensure that the logging thread does empty runs (not suspended, avoiding context switching as it will resume shortly). +1. Ensure both trees are not undergoing write operations. +1. Switch the read reference to another tree. +1. Switch the write reference to another tree. +1. Resume the logging thread. + +pr:
[https://github.com/apache/dubbo-go-pixiu/pull/262](https://github.com/apache/dubbo-go-pixiu/pull/262)
pkg/common/router/trie/trie.go:26 -pr:
[https://github.com/apache/dubbo-go-pixiu/pull/262](https://github.com/apache/dubbo-go-pixiu/pull/262)
pkg/common/router/trie/trie.go:26 diff --git a/content/en/overview/reference/pixiu/overview/_index.md b/content/en/overview/reference/pixiu/overview/_index.md index 7f331e30b769..e119ef273715 100755 --- a/content/en/overview/reference/pixiu/overview/_index.md +++ b/content/en/overview/reference/pixiu/overview/_index.md @@ -4,9 +4,10 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/overview/ - /en/overview/reference/pixiu/overview/ - /en/overview/mannual/dubbo-go-pixiu/overview/ -description: 入门概述 -linkTitle: 入门概述 -title: 入门概述 +description: Getting Started Overview +linkTitle: Getting Started Overview +title: Getting Started Overview type: docs weight: 10 --- + diff --git a/content/en/overview/reference/pixiu/overview/faq.md b/content/en/overview/reference/pixiu/overview/faq.md index 6730744f66f0..7060f007d8ec 100755 --- a/content/en/overview/reference/pixiu/overview/faq.md +++ b/content/en/overview/reference/pixiu/overview/faq.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/overview/faq/ - /en/overview/reference/pixiu/overview/faq/ - /en/overview/mannual/dubbo-go-pixiu/overview/faq/ -description: Pixiu 常见问题 -linkTitle: Pixiu 常见问题 -title: Pixiu 常见问题 +description: Pixiu Frequently Asked Questions +linkTitle: Pixiu Frequently Asked Questions +title: Pixiu Frequently Asked Questions type: docs weight: 3 --- @@ -17,14 +17,15 @@ weight: 3 -### 常见问题 Q1 -**Pixiu 目前可以用于生产环境吗?** +### Frequently Asked Questions Q1 +**Can Pixiu currently be used in production environments?** **A:** - 0.4.0版本之后就可以上生产环境,欢迎已经在使用的企业参与此 issue: [who's using Pixiu](https://github.com/apache/dubbo-go-pixiu/issues/64) + Since version 0.4.0, it can be used in production environments. We welcome enterprises that are already using it to participate in this issue: [who's using Pixiu](https://github.com/apache/dubbo-go-pixiu/issues/64) -### 常见问题 Q2 -**Pixiu 目前支持高可用吗?** +### Frequently Asked Questions Q2 +**Does Pixiu currently support high availability?** **A:** - 目前 Pixiu 仅支持单实例部署,可以和 Nginx 组成无状态多实例集群。 + Currently, Pixiu only supports single-instance deployment and can form a stateless multi-instance cluster with Nginx. + diff --git a/content/en/overview/reference/pixiu/overview/terminology.md b/content/en/overview/reference/pixiu/overview/terminology.md index d781e34b88eb..f1ef68d36bef 100755 --- a/content/en/overview/reference/pixiu/overview/terminology.md +++ b/content/en/overview/reference/pixiu/overview/terminology.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/overview/terminology/ - /en/overview/reference/pixiu/overview/terminology/ - /en/overview/mannual/dubbo-go-pixiu/overview/terminology/ -description: Pixiu 术语 -linkTitle: Pixiu 术语 -title: Pixiu 术语 +description: Pixiu Terminology +linkTitle: Pixiu Terminology +title: Pixiu Terminology type: docs weight: 2 --- @@ -19,26 +19,27 @@ weight: 2 ![img](/imgs/pixiu/overview/terminology.png) -### Listener 监听器 +### Listener -Lisnter 代表网络端口监听的能力,可以配置监听的协议类型,地址,端口。目前支持 TCP、HTTP、HTTP2 和 TRIPLE 协议。 +Listener represents the ability to listen on a network port and can be configured with the protocol type, address, and port. It currently supports TCP, HTTP, HTTP2, and TRIPLE protocols. -### Network Filter 网络过滤器 +### Network Filter -NetworkFilter 直接和 Listener 进行对接,代表对基础网络请求的处理,包括原始协议解析,路由解析等功能。 +NetworkFilter interfaces directly with Listener and represents the handling of basic network requests, including raw protocol parsing and routing parsing. -### Http Filter & Dubbo Filter HTTP & Dubbo 过滤器 +### Http Filter & Dubbo Filter -Http Filter 和 Dubbo Filter 可以看做二级 Filter,提供诸如协议转换,限流,身份认证等通用功能。 +Http Filter and Dubbo Filter can be viewed as secondary filters, providing common functions such as protocol conversion, traffic limiting, and authentication. -### Route 路由 +### Route -Route 代表请求的路由规则 +Route represents the routing rules for requests. -### Cluster 集群 +### Cluster -Cluter 代表相同服务的集群,Endpoint 则代表服务集群中的单一服务实例。 +Cluster represents a cluster of the same service, while Endpoint represents a single service instance within the service cluster. -### Adapter 适配器 +### Adapter + +Adapter represents the capability of Pixiu to obtain metadata from external sources. It can dynamically acquire routing and cluster information based on the service metadata in the service. Currently, Pixiu supports two types of adapters, which retrieve information from Dubbo clusters and Spring Cloud clusters. -Adapter 则代表 Pixiu 和外界进行元数据获取的能力。能够根据服务中的服务元数据,进行路由和集群信息的动态获取。目前 Pixiu 支持两宽 Adapter,分别是从 Dubbo 集群和 Springcloud 集群获取信息。 diff --git a/content/en/overview/reference/pixiu/overview/what-is-pixiu.md b/content/en/overview/reference/pixiu/overview/what-is-pixiu.md index 3a60dc823cc4..307754decb1f 100755 --- a/content/en/overview/reference/pixiu/overview/what-is-pixiu.md +++ b/content/en/overview/reference/pixiu/overview/what-is-pixiu.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/overview/what-is-pixiu/ - /en/overview/reference/pixiu/overview/what-is-pixiu/ - /en/overview/mannual/dubbo-go-pixiu/overview/what-is-pixiu/ -description: Pixiu 是一款开源的 Dubbo 生态的 API 网关和 接入 dubbo 集群的语言解决方案。作为 API 网关形态。 -linkTitle: Pixiu 是什么 -title: Pixiu 是什么 +description: Pixiu is an open-source API gateway for the Dubbo ecosystem and a language solution for accessing the Dubbo cluster. As an API gateway, it can receive external network requests, convert them into Dubbo and other protocol requests, and forward them to the backend cluster. +linkTitle: What is Pixiu +title: What is Pixiu type: docs weight: 1 --- @@ -16,10 +16,10 @@ weight: 1 -### Pixiu 说明 +### Pixiu Overview -Pixiu 是一款开源的 Dubbo 生态的 API 网关和 接入 dubbo 集群的语言解决方案。作为 API 网关形态, Pixiu 能接收外界的网络请求,将其转换为 dubbo 等协议请求,转发给背后集群;作为 Sidecar,Pixiu 期望可以代替代理服务注册到 Dubbo 集群,让多语言服务接入 Dubbo 集群提供更快捷的解决方案。 +Pixiu is an open-source API gateway for the Dubbo ecosystem and a language solution for accessing the Dubbo cluster. As an API gateway, Pixiu can receive external network requests, convert them into Dubbo and other protocol requests, and forward them to the backend cluster. As a Sidecar, Pixiu aims to replace proxy services registered to the Dubbo cluster, providing a faster solution for multi-language services to connect to the Dubbo cluster. ![image](/imgs/pixiu/overview/pixiu-overview.png) @@ -27,22 +27,22 @@ Pixiu 是一款开源的 Dubbo 生态的 API 网关和 接入 dubbo 集群的语 -### API 网关 +### API Gateway -作为一款网关产品,Pixiu 帮助用户轻松创建、发布、维护、监控和保护任意规模的 API ,接受和处理成千上万个并发 API 调用,包括流量管理、 CORS 支持、授权和访问控制、限制、监控,以及 API 版本管理。除此以外,作为 Dubbo 的衍生产品,Pixiu 可以帮助 Dubbo 用户进行协议转换,实现跨系统、跨协议的服务能力互通。 -Pixiu 的整体设计遵守以下原则: -- High performance: 高吞吐量以及毫秒级的延时。 -- 可扩展: 通过 go-plugin,用户可以根据自己的需求延展 Pixiu 的功能。 -- 简单可用: 用户通过少量配置,即可上线。 +As a gateway product, Pixiu helps users easily create, publish, maintain, monitor, and protect APIs of any scale, handling thousands of concurrent API calls. This includes traffic management, CORS support, authorization and access control, limits, monitoring, and API version management. Additionally, as a derived product of Dubbo, Pixiu can help Dubbo users with protocol conversion for cross-system and cross-protocol service interoperability. +The overall design of Pixiu adheres to the following principles: +- High performance: High throughput and millisecond-level latency. +- Scalable: Users can extend Pixiu's functionality via go-plugin according to their needs. +- Easy to use: Users can go live with minimal configuration. +### Sidecar Mode -### Sidecar 模式 +Currently, the main way to access the Dubbo cluster is to integrate with the corresponding language's SDK, as shown on the left side of the diagram. However, Dubbo's multi-language support is insufficient; only the Java and Go versions are mature, while the JS and Python versions are catching up. Moreover, there are general issues with using SDKs, such as high code coupling, difficulty in version upgrades, and challenges in service discovery, routing, and load balancing. -目前最为主流的接入 dubbo 集群的方式当然是集成语言对应的 sdk,但是如图的左侧部分。但是对于dubbo来讲,它的多语言支持能力不足,目前较为成熟的只有 java 版本和 go 版本,当然 js 版本 和 python 版本也在努力追赶中.其次,就是使用sdk的通用问题,比如代码耦合度高,版本升级困难,服务发现,服务路由和负载均衡策略不易整体调控等。 - -所以 mesh 话或者 sidecar 的方案,也就是 service mesh 在16年时被提出。将服务发现,服务路由和负载均衡等逻辑放在 sidecar,服务使用轻量级 sdk 与之进行交互。 +Thus, the concept of a service mesh or sidecar was proposed in 2016. By placing service discovery, routing, and load balancing logic in the sidecar, services can interact with it using lightweight SDKs. ![img](/imgs/pixiu/overview/pixiu-sidecar.png) -对于接入 dubbo 的多语言解决方案。首推的当然是 pixiu 作为 sidecar 和 服务进行同时部署。pixiu提供 服务发现,流量治理,路由能力,协议转换能力和通讯能力。如图的左侧部分,使用sidecar的服务可以和原生使用 dubbo 框架的服务组成集群,无感的进行相互调用。 -另外一种方案是 pixiu 只单单作为代理,将服务注册到dubbo集群中,如图右侧部分,这种方案部署和运维较为简单,比如适合中小规模的集群。 +For multi-language solutions accessing Dubbo, Pixiu is recommended as a Sidecar deployed alongside services. Pixiu provides service discovery, traffic governance, routing capability, protocol conversion, and communication capabilities. As shown on the left side of the diagram, services using the sidecar can form clusters with services natively using the Dubbo framework, allowing for seamless interactions. +Another option is for Pixiu to serve solely as a proxy, registering services to the Dubbo cluster, as illustrated on the right side of the diagram. This solution is simpler for deployment and operation, suitable for small to medium-sized clusters. + diff --git a/content/en/overview/reference/pixiu/user/_index.md b/content/en/overview/reference/pixiu/user/_index.md index 01359302bbe7..b013ae8007e4 100755 --- a/content/en/overview/reference/pixiu/user/_index.md +++ b/content/en/overview/reference/pixiu/user/_index.md @@ -3,10 +3,11 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/ - /en/docs3-v2/dubbo-go-pixiu/user/ - /en/overview/reference/pixiu/user/ - - /en/overview/mannual/dubbo-go-pixiu/user/ -description: 用户文档 -linkTitle: 用户文档 -title: 用户文档 + - /en/overview/manual/dubbo-go-pixiu/user/ +description: User Documentation +linkTitle: User Documentation +title: User Documentation type: docs weight: 20 --- + diff --git a/content/en/overview/reference/pixiu/user/adapter/_index.md b/content/en/overview/reference/pixiu/user/adapter/_index.md index ba72b9457d3e..6526b6c02d63 100755 --- a/content/en/overview/reference/pixiu/user/adapter/_index.md +++ b/content/en/overview/reference/pixiu/user/adapter/_index.md @@ -4,9 +4,10 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/adapter/ - /en/overview/reference/pixiu/user/adapter/ - /en/overview/mannual/dubbo-go-pixiu/user/adapter/ -description: Adapter 介绍 -linkTitle: Adapter 介绍 -title: Adapter 介绍 +description: Introduction to Adapter +linkTitle: Introduction to Adapter +title: Introduction to Adapter type: docs weight: 60 --- + diff --git a/content/en/overview/reference/pixiu/user/adapter/dubbo.md b/content/en/overview/reference/pixiu/user/adapter/dubbo.md index 6dd714f1fe90..7a7684307aa6 100644 --- a/content/en/overview/reference/pixiu/user/adapter/dubbo.md +++ b/content/en/overview/reference/pixiu/user/adapter/dubbo.md @@ -3,10 +3,11 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/adapter/dubbo/ - /en/docs3-v2/dubbo-go-pixiu/user/adapter/dubbo/ - /en/overview/reference/pixiu/user/adapter/dubbo/ - - /en/overview/mannual/dubbo-go-pixiu/user/adapter/dubbo/ -description: Dubbo 集群中心 Adapter -linkTitle: Dubbo 集群中心 Adapter -title: Dubbo 集群中心 Adapter + - /en/overview/manual/dubbo-go-pixiu/user/adapter/dubbo/ +description: Dubbo Cluster Center Adapter +linkTitle: Dubbo Cluster Center Adapter +title: Dubbo Cluster Center Adapter type: docs weight: 10 --- + diff --git a/content/en/overview/reference/pixiu/user/adapter/springcloud.md b/content/en/overview/reference/pixiu/user/adapter/springcloud.md index e423820399e8..df68e3382e45 100644 --- a/content/en/overview/reference/pixiu/user/adapter/springcloud.md +++ b/content/en/overview/reference/pixiu/user/adapter/springcloud.md @@ -3,10 +3,11 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/adapter/springcloud/ - /en/docs3-v2/dubbo-go-pixiu/user/adapter/springcloud/ - /en/overview/reference/pixiu/user/adapter/springcloud/ - - /en/overview/mannual/dubbo-go-pixiu/user/adapter/springcloud/ -description: Spring Cloud 集群中心 Adapter -linkTitle: Spring Cloud 集群中心 Adapter -title: Spring Cloud 集群中心 Adapter + - /en/overview/manual/dubbo-go-pixiu/user/adapter/springcloud/ +description: Spring Cloud Cluster Center Adapter +linkTitle: Spring Cloud Cluster Center Adapter +title: Spring Cloud Cluster Center Adapter type: docs weight: 20 --- + diff --git a/content/en/overview/reference/pixiu/user/configurations.md b/content/en/overview/reference/pixiu/user/configurations.md index d50e75935ca7..ac4a5500c598 100755 --- a/content/en/overview/reference/pixiu/user/configurations.md +++ b/content/en/overview/reference/pixiu/user/configurations.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/configurations/ - /en/overview/reference/pixiu/user/configurations/ - /en/overview/mannual/dubbo-go-pixiu/user/configurations/ -description: 启动和配置 -linkTitle: 启动和配置 -title: 启动和配置 +description: Start and configuration +linkTitle: Start and configuration +title: Start and configuration type: docs weight: 20 --- @@ -16,17 +16,17 @@ weight: 20 -### Pixiu 启动命令 +### Pixiu Startup Command -Pixiu 分为两个形态 Gateway 和 Sidecar,目前 Pixiu 可执行程序的命令如下所示,其中 pixiu 是可执行文件名称。注意,-c 后是本地配置文件的绝对路径。 +Pixiu has two forms: Gateway and Sidecar. The command for the Pixiu executable is as follows, where pixiu is the name of the executable file. Note that the path after -c is the absolute path of the local configuration file. ``` pixiu gateway start -c /config/conf.yaml ``` -### 配置详解 +### Configuration Detailed Explanation -Pixiu 接受 yaml 格式的文件作为其主配置文件,其中对 Pixiu 的各类组件进行配置。我们以快速开始中的配置文件为例,详细讲解其中的组成部分,并且列出可能的扩展。 +Pixiu accepts YAML formatted files as its main configuration file for configuring various components of Pixiu. Taking the configuration file from Quick Start as an example, we will explain its components in detail and list possible extensions. ``` static_resources: @@ -59,11 +59,11 @@ static_resources: password: "" ``` -首先,类似 `envoy`的配置,`static_resources` 表示如下都是静态配置。在静态配置中包括 Listener,NetworkFilter,Route,HttpFilter等组件,它们之间并不是完全独立的。 +First, similar to the `envoy` configuration, `static_resources` indicates that all the following configurations are static. This includes components such as Listener, NetworkFilter, Route, and HttpFilter, which are not completely independent of each other. #### Listener -比如说上述配置就声明了一个监听本地 8883 端口的 HTTP 类型的 Listener,更多 Listener 的配置可以查看 [Listener](../listener/http/)。 +For example, the above configuration declares an HTTP type Listener listening on port 8883. More Listener configurations can be found in [Listener](../listener/http/). ``` listeners: @@ -75,11 +75,11 @@ static_resources: port: 8883 filter_chains: ``` -listeners 的配置有 `protocol_type` 表示是 HTTP 类型的 Listener,`address` 则配置了监听的地址和端口,`filter_chains` 则指定了该 Listener 接收到请求要交由哪些 NetworkFilter 处理。 +The configuration of listeners has `protocol_type`, indicating that it is an HTTP type Listener, and `address`, which configures the listening address and port, while `filter_chains` specifies which NetworkFilters should handle requests received by this Listener. #### NetworkFilter -NetworkFilter 是 Pixiu 的关键组件之一,它可以有 Route 和 HttpFilter 一起组成,负责接收 Listener 传递而来的请求并进行处理。 +NetworkFilter is one of Pixiu's key components, composed of Route and HttpFilter, responsible for receiving requests passed from Listener and processing them. ``` filters: @@ -89,13 +89,11 @@ filters: http_filters: ``` -上述配置指明了使用 `dgp.filter.httpconnectionmanager` 这款 NetworkFilter,它能够接收 Http 请求的 `Request` 和 `Response` 进行处理,并且可以配置 Route 路由信息和使用 HttpFilter 对请求进行链式处理。更多的 NetworkFilter 可以查看 [NetworkfFilter文档](../networkfilter/http/) +The above configuration specifies using the `dgp.filter.httpconnectionmanager` NetworkFilter, which can process HTTP `Request` and `Response` and configure route information and use HttpFilters for chained processing of requests. More NetworkFilters can be found in the [NetworkFilter documentation](../networkfilter/http/). +#### Route and Cluster - -#### Route 路由 和 Cluster 集群 - -route 可以用于对请求进行路由分发,以下面配置为例。具体配置文件可以查看 `/samples/http/simple` 案例的配置文件 +Route can be used for routing requests, as exemplified by the following configuration. For detailed configuration files, please see the configuration files in `/samples/http/simple`. ``` - name: dgp.filter.httpconnectionmanager @@ -108,9 +106,9 @@ route 可以用于对请求进行路由分发,以下面配置为例。具体 cluster: "user" ``` -上述配置指定了对于 Path 的前缀为 `/user` 的 HTTP 请求,转发给名称为 user 的 cluster 服务集群中。 +The above configuration specifies that for HTTP requests with a path prefix of `/user`, they will be forwarded to a cluster service group named user. -而具体 cluster 集群的定义如下所示: +The specific definition of the cluster is shown below: ``` clusters: @@ -123,13 +121,13 @@ route 可以用于对请求进行路由分发,以下面配置为例。具体 port: 1314 ``` -上述配置定义了名为 user 的 cluster 集群信息,它的负载均衡策略是 RoundRobin,然后它包含一个 endpoint 实例,其地址是 127.0.0.1。 +The above configuration defines a cluster named user with a load balancing policy of RoundRobin, which includes one endpoint instance with the address 127.0.0.1. -目前,在转发 HTTP 请求或者 Grpc 请求的场景下需要使用 Route 和 Cluster,而涉及到转发 Dubbo 相关请求的场景下暂时不需要二者。 +Currently, forwarding HTTP or gRPC requests requires using Route and Cluster. However, there is no need for both in scenarios involving forwarding Dubbo-related requests. #### HttpFilter -当 NetworkFilter 接收到 Listener 传来的请求后,需要对其进行系列操作,例如限流、鉴权等,最后还需要将这个请求转发给具体上游服务。这些工作都交给 NetworkFilter 所持有的 HttpFilter 链进行处理。 +When a NetworkFilter receives a request from a Listener, it needs to perform a series of operations, such as rate limiting and authorization, and finally forward the request to specific upstream services. These tasks are handled by the HttpFilter chain associated with the NetworkFilter. ``` - name: dgp.filter.httpconnectionmanager @@ -148,13 +146,13 @@ route 可以用于对请求进行路由分发,以下面配置为例。具体 password: "" ``` -如上配置所示,`httpconnectionmanager` 这个 NetworkFilter 下有一个 HttpFilter chain。其中包括 `dgp.filter.http.dubboproxy` 这一款 HttpFilter。 -它负责将 HTTP 请求转换为 Dubbo 请求,并转发出去。它需要配置一个 Dubbo 集群注册中心的地址信息,指定其为 zookeeper 中间件。其中 `auto_resolve` 则指定使用 HTTP to Dubbo 默认转换协议来进行相关数据转换,具体可以参考[《默认转换协议》](../appendix/http-to-dubbo-default-stragety/)。 +As shown in the configuration above, the `httpconnectionmanager` NetworkFilter has an HttpFilter chain, which includes the `dgp.filter.http.dubboproxy` HttpFilter. It is responsible for converting HTTP requests into Dubbo requests and forwarding them. It requires configuration of the address of a Dubbo cluster registration center, specified as middleware in Zookeeper. The `auto_resolve` specifies using the default HTTP to Dubbo conversion protocol for related data conversions, which can be referenced in [Default Conversion Protocol](../appendix/http-to-dubbo-default-stragety/). -更多的 HttpFilter 可以查看 [HttpFilter文档](../httpfilter/dubbo/)。 +More HttpFilters can be found in the [HttpFilter documentation](../httpfilter/dubbo/). #### Adapter -Adapter 代表 Pixiu 和外界元数据中心交互的能力。目前有两款,分别是 `dgp.adapter.dubboregistrycenter` 和 `dgp.adapter.springcloud`,分别代表从 Dubbo 集群注册中心和 Spring Cloud 集群注册中心获取服务实例信息,构建 Pixiu 转发 Http 请求路由规则的。 +Adapter represents the capability of Pixiu to interact with external metadata centers. Currently, there are two: `dgp.adapter.dubboregistrycenter` and `dgp.adapter.springcloud`, representing retrieval of service instance information from Dubbo cluster registration centers and Spring Cloud cluster registration centers respectively to build Pixiu forwarding HTTP request routing rules. + +More Adapters can be found in the [Adapter documentation](../adapter/dubbo/)。 -更多的 Adapter 可以查看 [Adapter文档](../adapter/dubbo/)。 diff --git a/content/en/overview/reference/pixiu/user/deployment.md b/content/en/overview/reference/pixiu/user/deployment.md index c5a84da9e4b2..1103a0c125a7 100644 --- a/content/en/overview/reference/pixiu/user/deployment.md +++ b/content/en/overview/reference/pixiu/user/deployment.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/deployment/ - /en/overview/reference/pixiu/user/deployment/ - /en/overview/mannual/dubbo-go-pixiu/user/deployment/ -description: 部署操作 -linkTitle: 部署操作 -title: 部署操作 +description: Deployment operations +linkTitle: Deployment operations +title: Deployment operations type: docs weight: 30 --- @@ -16,29 +16,29 @@ weight: 30 -## 一、Docker镜像部署 +## 1. Docker Image Deployment -注:首先确认本机已经安装好docker并且启动 +Note: First confirm that Docker is installed and running on your machine. -### 1、从docker hub 拉取 pixiu 镜像 +### 1. Pull the Pixiu image from Docker Hub `docker pull phial3/dubbo-go-pixiu:latest` -### 2、按照需求准备pixiu配置 -#### [pixiu配置参数详解](../configurations/) +### 2. Prepare Pixiu Configuration as Needed +#### [Detailed Explanation of Pixiu Configuration Parameters](../configurations/) -准备 `log.yml` 和 `conf.yaml` 配置文件,将这两个配置文件在pixiu启动的时候挂在到本地 +Prepare the `log.yml` and `conf.yaml` configuration files, and mount these two configuration files to the local directory when starting Pixiu. -### 3、启动 pixiu +### 3. Start Pixiu -**前台启动**:,可方便查看服务信息运行是否正常 +**Foreground Start**: Convenient to check if the service information is running normally. ```shell docker run --name dubbo-go-pixiu -p 8883:8883 \ -v /yourpath/conf.yaml:/etc/pixiu/conf.yaml \ -v /yourpath/log.yml:/etc/pixiu/log.yml \ apache/dubbo-go-pixiu:latest ``` -**后台启动**: +**Background Start**: ```shell docker run -itd --name dubbo-go-pixiu -p 8883:8883 \ -v /yourpath/conf.yaml:/etc/pixiu/conf.yaml \ @@ -46,45 +46,45 @@ docker run -itd --name dubbo-go-pixiu -p 8883:8883 \ apache/dubbo-go-pixiu:latest ``` -> 注: +> Note: > -> (1) `--name`命令后面的dubbo-go-pixiu为你的pixiu实例的名称,可自行修改 +> (1) The `dubbo-go-pixiu` after the `--name` command is the name of your Pixiu instance, which can be modified as you like. > -> (2)命令中的`/yourpath/**`路径为你本地存放pixiu配置文件的绝对路径 +> (2) The path `/yourpath/**` in the command is the absolute path where you store the Pixiu configuration files locally. -### 4、查看 pixiu 实例 +### 4. View Pixiu Instance -`docker ps | grep dubbo-go-pixiu` 正在运行的pixiu实例 +`docker ps | grep dubbo-go-pixiu` Running Pixiu instance. -`docker exec -it dubbo-go-pixiu /bin/bash` 进入pixiu +`docker exec -it dubbo-go-pixiu /bin/bash` Enter Pixiu. -### 5、停止pixiu +### 5. Stop Pixiu -`docker stop dubbo-go-pixiu` 停止pixiu +`docker stop dubbo-go-pixiu` Stop Pixiu. -`docker restart dubbo-go-pixiu` 重启pixiu +`docker restart dubbo-go-pixiu` Restart Pixiu. -## 二、源码构建部署 +## 2. Source Code Build and Deployment -注:首先确认本机已经安装好 golang 1.15+ 开发环境,启用`go mod` +Note: First confirm that Golang 1.15+ development environment is installed on your machine and that `go mod` is enabled. -### 1、下载 pixiu 源码到本地 +### 1. Download Pixiu Source Code Locally `git clone git@github.com:apache/dubbo-go-pixiu.git` -### 2、配置pixiu +### 2. Configure Pixiu -#### [pixiu配置参数详解](../configurations/) +#### [Detailed Explanation of Pixiu Configuration Parameters](../configurations/) -进入到pixiu的源码目录`cd dubbo-go-pixiu/`,在`dubbo-go-pixiu/configs/`目录下 -修改配置文件`conf.yaml`和`log.yml` +Enter the Pixiu source code directory `cd dubbo-go-pixiu/`, and modify the `conf.yaml` and `log.yml` configuration files in the `dubbo-go-pixiu/configs/` directory. -### 3、编译构建 -在pixiu的源码目录`dubbo-go-pixiu/`下执行`make build` -: 构建完成会在当前目录下生成名为`dubbo-go-pixiu`的可执行文件 +### 3. Compile and Build +Execute `make build` in the Pixiu source code directory `dubbo-go-pixiu/`. +: After the build is complete, an executable file named `dubbo-go-pixiu` will be generated in the current directory. -### 4、启动服务与运行示例 +### 4. Start Service and Run Examples -在当前目录下`make run` 可根据你当前的配置直接启动pixiu服务 +Run `make run` in the current directory to start the Pixiu service directly based on your current configuration. + +[Run Example Reference](../quickstart/) -[运行示例参考](../quickstart/) diff --git a/content/en/overview/reference/pixiu/user/networkfilter/_index.md b/content/en/overview/reference/pixiu/user/networkfilter/_index.md index 05d911605244..41907752330b 100755 --- a/content/en/overview/reference/pixiu/user/networkfilter/_index.md +++ b/content/en/overview/reference/pixiu/user/networkfilter/_index.md @@ -4,9 +4,10 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/networkfilter/ - /en/overview/reference/pixiu/user/networkfilter/ - /en/overview/mannual/dubbo-go-pixiu/user/networkfilter/ -description: Network Filter 介绍 -linkTitle: Network Filter 介绍 -title: Network Filter 介绍 +description: Introduction to Network Filter +linkTitle: Introduction to Network Filter +title: Introduction to Network Filter type: docs weight: 50 --- + diff --git a/content/en/overview/reference/pixiu/user/networkfilter/dubbo.md b/content/en/overview/reference/pixiu/user/networkfilter/dubbo.md index 657b7202693e..51dff81492a9 100644 --- a/content/en/overview/reference/pixiu/user/networkfilter/dubbo.md +++ b/content/en/overview/reference/pixiu/user/networkfilter/dubbo.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/networkfilter/dubbo/ - /en/overview/reference/pixiu/user/networkfilter/dubbo/ - /en/overview/mannual/dubbo-go-pixiu/user/networkfilter/dubbo/ -description: Dubbo NetWorkFilter 介绍 -linkTitle: Dubbo NetWorkFilter 介绍 -title: Dubbo NetWorkFilter 介绍 +description: Introduction to Dubbo NetWorkFilter +linkTitle: Introduction to Dubbo NetWorkFilter +title: Introduction to Dubbo NetWorkFilter type: docs weight: 30 --- @@ -16,4 +16,5 @@ weight: 30 -欢迎认领补充此文档。 +Welcome to contribute to this document. + diff --git a/content/en/overview/reference/pixiu/user/networkfilter/grpc.md b/content/en/overview/reference/pixiu/user/networkfilter/grpc.md index 9c0c26943408..ba11a3986e69 100644 --- a/content/en/overview/reference/pixiu/user/networkfilter/grpc.md +++ b/content/en/overview/reference/pixiu/user/networkfilter/grpc.md @@ -2,18 +2,18 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/networkfilter/grpc/ - /en/docs3-v2/dubbo-go-pixiu/user/networkfilter/grpc/ -description: Grpc NetWorkFilter 介绍 -linkTitle: Grpc NetWorkFilter 介绍 -title: Grpc NetWorkFilter 介绍 +description: Introduction to Grpc NetWorkFilter +linkTitle: Introduction to Grpc NetWorkFilter +title: Introduction to Grpc NetWorkFilter type: docs weight: 20 --- -# 使用 grpc 调用服务提供程序 +# Using grpc to Call Service Providers -> [下面的文档符合代码](https://github.com/apache/dubbo-go-pixiu-samples/blob/main/http/grpc/pixiu/conf.yaml) +> [The following documentation conforms to the code](https://github.com/apache/dubbo-go-pixiu-samples/blob/main/http/grpc/pixiu/conf.yaml) -## 定义Pixiu配置文件 +## Define Pixiu Configuration File ```yaml static_resources: @@ -64,11 +64,11 @@ static_resources: reject_policy: "immediacy" ``` -> Grpc 服务器在“集群”中定义 +> The Grpc server is defined in the “cluster” -> 目前 http 请求仅支持 json body 解析参数 +> Currently, HTTP requests only support JSON body parsing parameters. -## 准备服务器 +## Prepare the Server [generate pb files under with command:](https://github.com/apache/dubbo-go-pixiu-samples/tree/main/http/grpc/proto) @@ -76,7 +76,7 @@ static_resources: protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative hello_grpc.proto ``` -## 启动 Server +## Start the Server [Run](https://github.com/apache/dubbo-go-pixiu-samples/blob/main/http/grpc/server/app/server.go) @@ -84,15 +84,15 @@ protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=p go run server.go ``` -## 启动 Pixiu +## Start Pixiu ```shell ./dubbo-go-pixiu gateway start --config {CURRENT_PATH}/samples/http/grpc/pixiu/conf.yaml ``` -## 使用 curl 进行测试 +## Test Using Curl -使用以下命令运行命令 curl: +Run the curl command with the following: ```shell curl http://127.0.0.1:8881/api/v1/provider.UserProvider/GetUser @@ -102,4 +102,5 @@ curl http://127.0.0.1:8881/api/v1/provider.UserProvider/GetUser curl http://127.0.0.1:8881/api/v1/provider.UserProvider/GetUser -X POST -d '{"userId":1}' ``` -> 如果响应正文是 json,则`Content-Type`的标头将设置为`application/json`。如果它只是一个纯文本,则`Content-Type`的标题是`text/plain`。 +> If the response body is JSON, the `Content-Type` header will be set to `application/json`. If it is just plain text, the `Content-Type` header is `text/plain`. + diff --git a/content/en/overview/reference/pixiu/user/networkfilter/http.md b/content/en/overview/reference/pixiu/user/networkfilter/http.md index 6451a5ddc27a..e5fb958775e7 100644 --- a/content/en/overview/reference/pixiu/user/networkfilter/http.md +++ b/content/en/overview/reference/pixiu/user/networkfilter/http.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/networkfilter/http/ - /en/overview/reference/pixiu/user/networkfilter/http/ - /en/overview/mannual/dubbo-go-pixiu/user/networkfilter/http/ -description: Http NetWorkFilter 介绍 -linkTitle: Http NetWorkFilter 介绍 -title: Http NetWorkFilter 介绍 +description: Introduction to Http NetWorkFilter +linkTitle: Introduction to Http NetWorkFilter +title: Introduction to Http NetWorkFilter type: docs weight: 10 --- @@ -14,6 +14,5 @@ weight: 10 +Http NetWorkFilter is used to handle HTTP requests. It can receive HTTP requests passed from the HTTP Listener, then process them through the HTTP Filter chain it maintains, and finally return the response to the caller. - -Http NetWorkFilter 用来处理 HTTP 请求,它能接收来自 HTTP Listener 传递的 HTTP 请求,然后将其交给自身维护的 HTTP Filter 链进行处理,最后将响应返回给调用方。 diff --git a/content/en/overview/reference/pixiu/user/quality/_index.md b/content/en/overview/reference/pixiu/user/quality/_index.md index 498f40c3b8ef..bcde44da30af 100755 --- a/content/en/overview/reference/pixiu/user/quality/_index.md +++ b/content/en/overview/reference/pixiu/user/quality/_index.md @@ -4,9 +4,10 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/quality/ - /en/overview/reference/pixiu/user/quality/ - /en/overview/mannual/dubbo-go-pixiu/user/quality/ -description: 质量指标 -linkTitle: 质量指标 -title: 质量指标 +description: Quality Indicators +linkTitle: Quality Indicators +title: Quality Indicators type: docs weight: 80 --- + diff --git a/content/en/overview/reference/pixiu/user/quickstart.md b/content/en/overview/reference/pixiu/user/quickstart.md index 8c6bfcc976d1..4e33ccf45396 100755 --- a/content/en/overview/reference/pixiu/user/quickstart.md +++ b/content/en/overview/reference/pixiu/user/quickstart.md @@ -4,34 +4,33 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/quickstart/ - /en/overview/reference/pixiu/user/quickstart/ - /en/overview/mannual/dubbo-go-pixiu/user/quickstart/ -description: 快速开始 -linkTitle: 快速开始 -title: 快速开始 +description: Quick Start +linkTitle: Quick Start +title: Quick Start type: docs weight: 10 --- -让我们从将 HTTP 请求转换为 Dubbo2 请求的案例来快速展示 Pixiu 的能力。 +Let's quickly demonstrate Pixiu's capabilities by converting an HTTP request to a Dubbo2 request. -## 用例 +## Use Case -Pixiu 将 Client 的 HTTP 请求转换为 Dubbo2 请求,然后转发给背后的 Dubbo Server,然后将 Dubbo Server 的响应转换为 HTTP -响应,最后返回给 Client。 +Pixiu converts the Client's HTTP request into a Dubbo2 request, which is then forwarded to the Dubbo Server. It then converts the Dubbo Server's response back into an HTTP response, finally returning it to the Client. -### 架构图 +### Architecture Diagram ![Architecture](/imgs/pixiu/user/quick_start_architecture.png) -### 案例 +### Example -案例路径请查看 `/samples/dubbogo/simple/resolve` +The example path can be found at `/samples/dubbogo/simple/resolve`. -#### Dubbo Server 实现和启动 +#### Dubbo Server Implementation and Startup -Dubbo Server 提供用户增删改查的相关接口,其具体的代码实现见案例路径下的 `server` +The Dubbo Server provides interfaces for adding, deleting, modifying, and querying users. The specific code implementations can be found in the `server` directory under the example path. -Dubbo Server 的配置如下所示,注册了 Dubbo2 协议的 interface `com.dubbogo.pixiu.UserService`。 +The configuration of the Dubbo Server is as follows, registering the Dubbo2 protocol interface `com.dubbogo.pixiu.UserService`. ```yaml dubbo: @@ -55,13 +54,11 @@ dubbo: interface: com.dubbogo.pixiu.UserService ``` -#### Pixiu 配置和启动 +#### Pixiu Configuration and Startup -为了用例的场景,Pixiu 需要启动对应的 HTTP Listener 进行 HTTP 请求的监听,所以就会使用到 `httpconnectionmanager`。 -然后因为要将 HTTP 请求转换为 Dubbo请求,所以需要使用 `dgp.filter.http.dubboproxy`,这里我们将其`auto_resolve` 设置为true,表示开启 -HTTP to Dubbo 默认转换协议(具体定义请看[附录](../appendix/http-to-dubbo-default-stragety))。 +For the scenario of the use case, Pixiu needs to start the corresponding HTTP Listener to monitor HTTP requests, which will utilize `httpconnectionmanager`. Then, as it needs to convert HTTP requests into Dubbo requests, it requires `dgp.filter.http.dubboproxy`, where we set `auto_resolve` to true to enable the default HTTP to Dubbo conversion protocol (specific definitions can be found in the [Appendix](../appendix/http-to-dubbo-default-stragety)). -Pixiu 的具体配置如下所示 +The specific configuration for Pixiu is as follows: ``` static_resources: @@ -94,10 +91,9 @@ static_resources: password: "" ``` -#### Client 实现 +#### Client Implementation -Client 就是简单的 HTTP Client 实现,但是需要按照前文提及的 HTTP to Dubbo 默认转换协议在 HTTP 请求的 Path 和 Header -中填入对应的数据,具体如下所示。 +The Client is a simple HTTP Client implementation but needs to populate corresponding data in the HTTP request's Path and Header according to the aforementioned HTTP to Dubbo default conversion protocol, as shown below. ``` url := "http://localhost:8883/UserService/com.dubbogo.pixiu.UserService/GetUserByName" @@ -114,37 +110,37 @@ Client 就是简单的 HTTP Client 实现,但是需要按照前文提及的 HT resp, err := client.Do(req) ``` -#### 案例启动 +#### Example Start -项目提供了快速启动脚本,需要本地先安装有 Go 语言开发环境。 +The project provides a quick start script, and the Go development environment should be installed locally. ``` -# cd 到案例总目录 +# cd to the main example directory cd samples/dubbogo/simple/ -# 进行环境准备,启动 zk 和准备对应配置文件 +# Prepare the environment, start zk, and prepare the corresponding configuration files ./start.sh prepare resolve -# 启动 dubbo server +# Start the dubbo server ./start.sh startServer resolve -# 启动 pixiu +# Start Pixiu ./start.sh startPixiu resolve -# 启动 Client 测试用例 +# Start Client test case ./start.sh startTest resolve -# 或者使用 curl +# Or use curl curl -X POST 'http://localhost:8883/UserService/com.dubbogo.pixiu.UserService/GetUserByName' -d '{"types":"string","values":"tc"}' -H 'Content-Type: application/json' -H 'x-dubbo-http1.1-dubbo-version: 1.0.0' -H 'x-dubbo-service-protocol: dubbo' -H 'x-dubbo-service-version: 1.0.0' -H 'x-dubbo-service-group: test' -# 返回值 {"age":15,"code":1,"iD":"0001","name":"tc","time":"2021-08-01T18:08:41+08:00"} +# Response {"age":15,"code":1,"iD":"0001","name":"tc","time":"2021-08-01T18:08:41+08:00"} ``` -#### docker示例 +#### Docker Example ```shell docker pull phial3/dubbo-go-pixiu:latest @@ -154,17 +150,17 @@ docker run --name pixiuname -p 8883:8883 \ -v /yourpath/log.yml:/etc/pixiu/log.yml \ apache/dubbo-go-pixiu:latest -# http请求调用dubbo服务转换,首先启动provider,这里使用zookeeper作为注册中心 +# Start provider that uses zookeeper as the registration center first cd samples/dubbogo/simple/resolve/server -# 添加需要的环境变量,指定provider的配置文件位置 +# Add required environment variables, specifying the location of the provider's configuration file export DUBBO_GO_CONFIG_PATH="../profiles/dev/server.yml" export APP_LOG_CONF_FILE="../profiles/dev/log.yml" -# 启动provider +# Start provider go run server.go user.go -# 进入到test目录下,启动test示例 +# Go to the test directory and start the test example cd samples/dubbogo/simple/resolve/test go test pixiu_test.go diff --git a/content/en/overview/reference/pixiu/user/samples/_index.md b/content/en/overview/reference/pixiu/user/samples/_index.md index 817903731d69..874225b40120 100755 --- a/content/en/overview/reference/pixiu/user/samples/_index.md +++ b/content/en/overview/reference/pixiu/user/samples/_index.md @@ -4,9 +4,10 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/samples/ - /en/overview/reference/pixiu/user/samples/ - /en/overview/mannual/dubbo-go-pixiu/user/samples/ -description: 案例介绍 -linkTitle: 案例介绍 -title: 案例介绍 +description: Case Introduction +linkTitle: Case Introduction +title: Case Introduction type: docs weight: 70 --- + diff --git a/content/en/overview/reference/pixiu/user/samples/http_proxy.md b/content/en/overview/reference/pixiu/user/samples/http_proxy.md index d25dafa438c6..767346042dea 100644 --- a/content/en/overview/reference/pixiu/user/samples/http_proxy.md +++ b/content/en/overview/reference/pixiu/user/samples/http_proxy.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/samples/http_proxy/ - /en/overview/reference/pixiu/user/samples/http_proxy/ - /en/overview/mannual/dubbo-go-pixiu/user/samples/http_proxy/ -description: Http Proxy 案例介绍 -linkTitle: Http Proxy 案例介绍 -title: Http Proxy 案例介绍 +description: Introduction to Http Proxy Case +linkTitle: Introduction to Http Proxy Case +title: Introduction to Http Proxy Case type: docs weight: 10 --- @@ -16,49 +16,49 @@ weight: 10 -### HTTP 代理 +### HTTP Proxy -HTTP 代理案例展示了 Pixiu 接收外界 HTTP 请求然后转发给背后的 HTTP Server 的功能。 +The HTTP Proxy case demonstrates Pixiu's ability to receive external HTTP requests and forward them to the underlying HTTP Server. ![img](/imgs/pixiu/user/samples/http_proxy.png) -案例代码具体查看 `/samples/http/simple`。案例中的目录结构和作用如下所示: +For the case code, please refer to `/samples/http/simple`. The directory structure and purpose in the case are as follows: ``` -- pixiu # pixiu 配置文件 +- pixiu # Pixiu configuration file - server # http server - test # client or unit test ``` -我们来具体看一下有关 pixiu 的具体配置文件。 +Let's take a closer look at the specific configuration file for pixiu. ``` static_resources: listeners: - name: "net/http" - protocol_type: "HTTP" # 使用 HTTP Listener + protocol_type: "HTTP" # Use HTTP Listener address: socket_address: - address: "0.0.0.0" # 监听地址设置为 0.0.0.0 - port: 8888 # 端口设置为 8888 + address: "0.0.0.0" # Set the listening address to 0.0.0.0 + port: 8888 # Set port to 8888 filter_chains: filters: - - name: dgp.filter.httpconnectionmanager # NetworkFilter 设置为 httpconnectionmanager + - name: dgp.filter.httpconnectionmanager # Set NetworkFilter to httpconnectionmanager config: route_config: routes: - match: - prefix: "/user" # 设置路由规则,将 /user 前缀的请求转发给名称为 user 的 cluster 集群 + prefix: "/user" # Set routing rules to forward requests with /user prefix to the cluster named user route: cluster: "user" cluster_not_found_response_code: 505 http_filters: - - name: dgp.filter.http.httpproxy # 使用 dgp.filter.http.httpproxy 这个 HttpFilter 来进行转发 + - name: dgp.filter.http.httpproxy # Use dgp.filter.http.httpproxy for forwarding config: clusters: - - name: "user" # 配置一个名称为 user 的 集群,其中有一个实例,地址是 127.0.0.1:1314 + - name: "user" # Configure a cluster named user with one instance at address 127.0.0.1:1314 lb_policy: "random" endpoints: - id: 1 @@ -68,8 +68,9 @@ static_resources: ``` -可以先启动 `Server` 文件夹下的 Http Server,然后再使用如下命令启动 `Pixiu`,最后执行 test 文件夹下的单元测试。注意,-c 后是本地配置文件的绝对路径。 +First, start the Http Server in the `Server` folder and then use the following command to start `Pixiu`. Finally, execute the unit tests in the test folder. Note that -c should be followed by the absolute path of the local configuration file. ``` pixiu gateway start -c /pixiu/conf.yaml ``` + diff --git a/content/en/overview/reference/pixiu/user/samples/http_to_dubbo.md b/content/en/overview/reference/pixiu/user/samples/http_to_dubbo.md index 000b35bc5023..9ae3febfbdd2 100644 --- a/content/en/overview/reference/pixiu/user/samples/http_to_dubbo.md +++ b/content/en/overview/reference/pixiu/user/samples/http_to_dubbo.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/samples/http_to_dubbo/ - /en/overview/reference/pixiu/user/samples/http_to_dubbo/ - /en/overview/mannual/dubbo-go-pixiu/user/samples/http_to_dubbo/ -description: Http to Dubbo 案例介绍 -linkTitle: Http to Dubbo 案例介绍 -title: Http to Dubbo 案例介绍 +description: Introduction to the Http to Dubbo case +linkTitle: Introduction to the Http to Dubbo case +title: Introduction to the Http to Dubbo case type: docs weight: 20 --- @@ -16,4 +16,5 @@ weight: 20 -欢迎认领补充此文档。 +We welcome you to claim and contribute to this document. + diff --git a/content/en/overview/reference/pixiu/user/samples/https.md b/content/en/overview/reference/pixiu/user/samples/https.md index 73a92e6b1de7..bc38ceb01a52 100644 --- a/content/en/overview/reference/pixiu/user/samples/https.md +++ b/content/en/overview/reference/pixiu/user/samples/https.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/dubbo-go-pixiu/user/samples/https/ - /en/overview/reference/pixiu/user/samples/https/ - /en/overview/mannual/dubbo-go-pixiu/user/samples/https/ -description: Https 案例介绍 -linkTitle: Https 案例介绍 -title: Https 案例介绍 +description: Https Case Introduction +linkTitle: Https Case Introduction +title: Https Case Introduction type: docs weight: 30 --- @@ -16,4 +16,5 @@ weight: 30 -欢迎认领补充此文档。 +Welcome to contribute to this document. + diff --git a/content/en/overview/reference/proposals/_index.md b/content/en/overview/reference/proposals/_index.md index f00db1b0edcd..e8646a201f10 100644 --- a/content/en/overview/reference/proposals/_index.md +++ b/content/en/overview/reference/proposals/_index.md @@ -1,9 +1,10 @@ --- aliases: - /en/overview/reference/proposals/ -description: "Dubbo 框架核心功能设计方案" -linkTitle: 提案 -title: 提案 +description: "Design proposal for the core functionalities of the Dubbo framework" +linkTitle: Proposals +title: Proposals type: docs weight: 4 --- + diff --git a/content/en/overview/reference/proposals/admin.md b/content/en/overview/reference/proposals/admin.md index 4d4637631b53..44c45feb48d2 100644 --- a/content/en/overview/reference/proposals/admin.md +++ b/content/en/overview/reference/proposals/admin.md @@ -4,85 +4,85 @@ aliases: author: Jun Liu date: 2023-02-28T00:00:00Z description: | - 本文描述了 Dubbo Admin 作为控制面的总体架构设计与抽象。 -linkTitle: Admin 架构设计 -title: Dubbo Admin 控制面总体架构设计 + This article describes the overall architectural design and abstraction of Dubbo Admin as a control plane. +linkTitle: Admin Architecture Design +title: Overall Architecture Design of Dubbo Admin Control Plane type: docs weight: 3 working_in_progress: true --- -## 1 Dubbo 整体架构 -![DubboAdmin架构图.png](/imgs/v3/reference/admin/architecture.png) +## 1 Overall Architecture of Dubbo +![DubboAdmin Architecture Diagram.png](/imgs/v3/reference/admin/architecture.png) -架构上分为:**服务治理抽象控制面** 和 **Dubbo 数据面** 。 +The architecture is divided into: **Service Governance Abstract Control Plane** and **Dubbo Data Plane**. -- **服务治理控制面**。控制面包含注册中心、流量管控策略、Admin 控制台、Istio、OpenSergo 等组件。 -- **Dubbo 数据面**。数据面代表集群部署的所有 Dubbo 进程,进程之间通过 RPC 协议实现数据交换,并与控制面进行治理策略交互。 +- **Service Governance Control Plane.** The control plane includes components such as the registry, traffic management strategies, Admin console, Istio, OpenSergo, etc. +- **Dubbo Data Plane.** The data plane represents all Dubbo processes in cluster deployment, which exchange data via RPC protocol and interact with governance strategies from the control plane. -**进一步解释:**https://cn.dubbo.apache.org/zh-cn/overview/what/overview/ +**Further explanation:** https://cn.dubbo.apache.org/zh-cn/overview/what/overview/ -## Dubbo Admin 的整体定位与解释 +## Overall Positioning and Explanation of Dubbo Admin -**Dubbo Admin 是对微服务治理体系的统一定义与抽象,通过自定义核心组件与一系列配套工具,为不同部署架构和基础设施环境下部署的微服务集群带来统一的开发与运维差异。** +**Dubbo Admin is a unified definition and abstraction of the microservice governance system, providing uniform development and operation differences for microservice clusters deployed under different deployment architectures and infrastructure environments through custom core components and a series of supporting tools.** -## 2 面向用户的开发步骤 -### 第一步:安装 Dubbo Stack/Admin -> 核心思路是,屏蔽架构差异,通过统一入口将治理组件的安装和配置纳入成为 Dubbo 体系中的前置步骤 +## 2 User-Oriented Development Steps +### Step 1: Install Dubbo Stack/Admin +> The core idea is to eliminate architectural differences by incorporating the installation and configuration of governance components into a prerequisite step in the Dubbo system through a unified entry point. ```shell dubboctl install dubbo-stack ``` -安装请参见: [Dubbo Admin 安装指南](../../setup/install/) +For installation, see: [Dubbo Admin Installation Guide](../../setup/install/) -### 第二步:服务框架开发 +### Step 2: Service Framework Development - [Java](https://cn.dubbo.apache.org/zh-cn/overview/quickstart/java/) - [Go](https://cn.dubbo.apache.org/zh-cn/overview/quickstart/go/) - [Node.js](https://github.com/apache/dubbo-js) - [Rust](https://cn.dubbo.apache.org/zh-cn/overview/quickstart/rust/) -## 3 控制面方案 -![Dubbo架构草图.jpeg](/imgs/v3/reference/admin/architecture-draft.png) -### 3.1 确定 Dubbo 微服务治理体系的核心能力 +## 3 Control Plane Solutions +![Dubbo Architecture Draft.jpeg](/imgs/v3/reference/admin/architecture-draft.png) +### 3.1 Identify Core Capabilities of the Dubbo Microservice Governance System -- 服务发现 -- 配置管理 -- 流量治理规则 -- 安全基础设施 -- 可视化控制台 +- Service Discovery +- Configuration Management +- Traffic Governance Rules +- Security Infrastructure +- Visualization Console -### 3.2 统一服务治理层接入方式 +### 3.2 Unified Access Method for Service Governance Layer ![address-discovery.png](/imgs/v3/reference/admin/address-discovery.png) -**对于任何微服务部署模式,Dubbo 数据面统一面向 **`**dubbo://hopst:ip**`**抽象服务治理控制面编程。** +**For any microservice deployment model, the Dubbo data plane uniformly targets **`**dubbo://hopst:ip**`** for programming the abstract service governance control plane.** -具体工作流程: +Specific workflow: -1. 数据面通过配置先与 admin 组件进行交互,admin 返回当前部署架构下的实际注册中心、配置中心等组件地址,如图中的 `nacos://host:port`。 -2. 数据面组件接收到新的组件地址后,直接与 Nacos 建立通信,此后依赖 Nacos 完成服务发现等功能。 +1. The data plane interacts with the admin component through configuration, and the admin returns the addresses of the actual registry, configuration center, and other components under the current deployment architecture, such as `nacos://host:port`. +2. After receiving the new component addresses, the data plane component directly establishes communication with Nacos, relying on Nacos to complete service discovery and other functions. -### 3.3 在不同场景下如何兑现这些核心能力? -#### 场景一:传统微服务体系 (VM & Kubernetes) +### 3.3 How to Realize These Core Capabilities in Different Scenarios? +#### Scenario 1: Traditional Microservice System (VM & Kubernetes) -- 控制面治理体系一键安装 (Admin & Nacos) -- 传统 Nacos 服务发现与治理模式 -- 控制面可按需拉起更多的的组件,如 prometheus 等 +- One-click installation of control plane governance system (Admin & Nacos) +- Traditional Nacos service discovery and governance model +- The control plane can pull up more components as needed, such as Prometheus, etc. ![traditional.png](/imgs/v3/reference/admin/traditional.png) -#### 场景二:Kubernetes Service +#### Scenario 2: Kubernetes Service -1. **Istio 模式** +1. **Istio Mode** ![kubernetes-service.png](/imgs/v3/reference/admin/kubernetes-service.png) -2. **其他对等模式 Nacos/OpenSergo** -#### 场景三:Migration or Multi-cluster -集群处于隔离的子网络空间 +2. **Other Peer Modes Nacos/OpenSergo** +#### Scenario 3: Migration or Multi-cluster +Clusters in isolated sub-network space - 1 - 2 @@ -90,21 +90,21 @@ dubboctl install dubbo-stack ![multi-cluster-ingress.png](/imgs/v3/reference/admin/multi-cluster-ingress.png) -集群处于同一网络空间 +Clusters in the same network space ![multi-cluster.png](/imgs/v3/reference/admin/multi-cluster.png) -### 3.4 Admin 控制面 +### 3.4 Admin Control Plane -![admin-core-components -.png](/imgs/v3/reference/admin/admin-core-components.png) +![admin-core-components.png](/imgs/v3/reference/admin/admin-core-components.png) -### 3.5 其他配套基础设施与工具 +### 3.5 Other Supporting Infrastructures and Tools -#### 用户控制台 Console +#### User Console -交互地址:[https://qedzyx.axshare.com/#id=2pqh0k&p=admin__&g=1](https://qedzyx.axshare.com/#id=2pqh0k&p=admin__&g=1) +Interactive address: [https://qedzyx.axshare.com/#id=2pqh0k&p=admin__&g=1](https://qedzyx.axshare.com/#id=2pqh0k&p=admin__&g=1) ![console-ui.png](/imgs/v3/reference/admin/console-ui.png) #### Dubboctl & Helm + diff --git a/content/en/overview/reference/proposals/heuristic-flow-control.md b/content/en/overview/reference/proposals/heuristic-flow-control.md index 36d062c8c82e..95ebcd16aa5e 100644 --- a/content/en/overview/reference/proposals/heuristic-flow-control.md +++ b/content/en/overview/reference/proposals/heuristic-flow-control.md @@ -3,76 +3,76 @@ aliases: - /en/overview/reference/proposals/heuristic-flow-control/ author: Quanlu Liu date: 2023-01-30T00:00:00Z -description: 本文所说的柔性服务主要是指**consumer端的负载均衡**和**provider端的限流**两个功能。在之前的dubbo版本中,负载均衡部分更多的考虑的是公平性原则,即consumer端尽可能平等的从provider中作出选择,在某些情况下表现并不够理想。而限流部分只提供了静态的限流方案,需要用户对provider端设置静态的最大并发值,然而该值的合理选取对用户来讲并不容易。我们针对这些存在的问题进行了改进。 -linkTitle: 服务柔性 -title: 自适应负载均衡与限流 +description: The flexible services discussed in this article mainly refer to the functions of **load balancing on the consumer side** and **traffic limiting on the provider side**. In previous versions of Dubbo, the load balancing focused more on fairness, meaning that the consumer would choose equally from the providers, which didn’t perform ideally in some cases. The traffic limiting only provided static schemes, requiring users to set a static maximum concurrency value on the provider, which was not easy for users to determine. We made improvements to address these issues. +linkTitle: Flexible Services +title: Adaptive Load Balancing and Flow Control type: docs weight: 5 working_in_progress: true --- -# 整体介绍 -本文所说的柔性服务主要是指**consumer端的负载均衡**和**provider端的限流**两个功能。在之前的dubbo版本中, -* 负载均衡部分更多的考虑的是公平性原则,即consumer端尽可能平等的从provider中作出选择,在某些情况下表现并不够理想。 -* 限流部分只提供了静态的限流方案,需要用户对provider端设置静态的最大并发值,然而该值的合理选取对用户来讲并不容易。 +# Overview +The flexible services discussed in this article mainly refer to the functions of **load balancing on the consumer side** and **traffic limiting on the provider side**. In previous versions of Dubbo, +* The load balancing focused more on fairness, meaning the consumer chooses equally from the provider, which didn’t perform ideally in some cases. +* The traffic limiting only provided static schemes, requiring users to set a static maximum concurrency value on the provider, which was not easy for users to determine. -我们针对这些存在的问题进行了改进。 +We made improvements to address these issues. -## 负载均衡 -### 使用介绍 -在原本的dubbo版本中,有五种负载均衡的方案供选择,他们分别是 `Random`、`ShortestResponse`、`RoundRobin`、`LeastActive` 和 `ConsistentHash`。其中除 `ShortestResponse` 和 `LeastActive` 外,其他的几种方案主要是考虑选择时的公平性和稳定性。 +## Load Balancing +### Usage Introduction +In the original Dubbo versions, there were five loading balancing schemes available: `Random`, `ShortestResponse`, `RoundRobin`, `LeastActive`, and `ConsistentHash`. Except for `ShortestResponse` and `LeastActive`, the others mainly considered fairness and stability. -对于 `ShortestResponse` 来说,其设计目的是从所有备选的 provider 中选择 response 时间最短的以提高系统整体的吞吐量。然而存在两个问题: -1. 在大多数的场景下,不同provider的response时长没有非常明显的区别,此时该算法会退化为随机选择。 -2. response的时间长短有时也并不能代表机器的吞吐能力。对于 `LeastActive` 来说,其认为应该将流量尽可能分配到当前并发处理任务较少的机器上。但是其同样存在和 `ShortestResponse` 类似的问题,即这并不能单独代表机器的吞吐能力。 +For `ShortestResponse`, its design aims to select the provider with the shortest response time to improve overall system throughput. However, two issues arise: +1. In most scenarios, the response times of different providers do not show significant differences, making this algorithm degrade to random selection. +2. The response time does not always represent the machine’s throughput capacity. For `LeastActive`, it believes traffic should be allocated to machines with fewer active connections, but it similarly fails to reflect the machine's throughput capacity. -基于以上分析,我们提出了两种新的负载均衡算法。一种是同样基于公平性考虑的单纯 `P2C` 算法,另一种是基于自适应的方法 `adaptive`,其试图自适应的衡量 provider 端机器的吞吐能力,然后将流量尽可能分配到吞吐能力高的机器上,以提高系统整体的性能。 +Based on this analysis, we propose two new load balancing algorithms. One is a simple `P2C` algorithm based on fairness, while the other is an `adaptive` method that attempts to dynamically assess the throughput capacity of the provider machines and allocate traffic accordingly to improve overall system performance. -#### 总体效果 -对于负载均衡部分的有效性实验在两个不同的情况下进行的,分别是提供端机器配置比较均衡和提供端机器配置差距较大的情况。 +#### Overall Effect +The effectiveness experiments for load balancing were conducted under two different conditions: balanced provider machine configurations and configurations with large discrepancies. ![image.png](/imgs/overview/reference/proposals/heuristic-flow-control/1675265258687-c3df68a8-80e0-4311-816c-63480494850c.png) ![image.png](/imgs/overview/reference/proposals/heuristic-flow-control/1675265271198-5b045ced-8524-42a2-8b34-d7edbbd1f232.png) -#### 使用方法 -[Dubbo Java 实现的使用方法](/en/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance) 与原本的负载均衡方法相同。只需要在consumer端将"loadbalance"设置为"p2c"或者"adaptive"即可。 +#### Usage Method +[Usage method of Dubbo Java implementation](/en/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance) is the same as the original load balancing method. Just set "loadbalance" to "p2c" or "adaptive" on the consumer side. -#### 代码结构 -负载均衡部分的算法实现只需要在原本负载均衡框架内继承 LoadBalance接口即可。 +#### Code Structure +The algorithm implementation of load balancing only needs to inherit from the LoadBalance interface in the existing load balancing framework. -### 原理介绍 +### Principle Introduction -#### P2C算法 +#### P2C Algorithm -Power of Two Choice 算法简单但是经典,主要思路如下: +The Power of Two Choice algorithm is simple yet classic, mainly as follows: -1. 对于每次调用,从可用的provider列表中做两次随机选择,选出两个节点providerA和providerB。 -2. 比较providerA和providerB两个节点,选择其“当前正在处理的连接数”较小的那个节点。 +1. For each call, make two random selections from the available provider list, selecting two nodes, providerA and providerB. +2. Compare providerA and providerB, choosing the one with the smaller "current active connection count". -#### adaptive算法 +#### Adaptive Algorithm -[代码的github地址](https://github.com/apache/dubbo/pull/10745) +[Code's GitHub address](https://github.com/apache/dubbo/pull/10745) -##### 相关指标 +##### Related Metrics 1. cpuLoad -![img](/imgs/overview/reference/proposals/heuristic-flow-control/26808016bc7f1ee83ab425e308074f17.svg)。该指标在provider端机器获得,并通过invocation的attachment传递给consumer端。 +![img](/imgs/overview/reference/proposals/heuristic-flow-control/26808016bc7f1ee83ab425e308074f17.svg). This metric is obtained from the provider machine and passed to the consumer via the invocation's attachment. 2. rt -rt为一次rpc调用所用的时间,单位为毫秒。 +rt is the time taken for an RPC call, measured in milliseconds. 3. timeout -timeout为本次rpc调用超时剩余的时间,单位为毫秒。 +timeout is the remaining timeout for this RPC call, measured in milliseconds. 4. weight -weight是设置的服务权重。 +weight is the service weight set. 5. currentProviderTime -provider端在计算cpuLoad时的时间,单位是毫秒 +The time on the provider side when calculating cpuLoad, measured in milliseconds. 6. currentTime -currentTime为最后一次计算load时的时间,初始化为currentProviderTime,单位是毫秒。 +currentTime is the last calculated load time, initialized to currentProviderTime, measured in milliseconds. 7. multiple ![img](/imgs/overview/reference/proposals/heuristic-flow-control/b60f036bd026b92129df8a6476922cc8.svg) @@ -80,155 +80,152 @@ currentTime为最后一次计算load时的时间,初始化为currentProviderTi ![img](/imgs/overview/reference/proposals/heuristic-flow-control/f2abbc771049cf4f3e492e93a258d699.svg)![img](/imgs/overview/reference/proposals/heuristic-flow-control/8fb1af970b995232ebed2764a5706aab.svg) 9. beta -平滑参数,默认为0.5 +Smoothing parameter, defaulting to 0.5. 10. ewma -lastLatency的平滑值![img](/imgs/overview/reference/proposals/heuristic-flow-control/c26fdbae56f3a06c46434ae91185a3d6.svg) +Smooth value of lastLatency![img](/imgs/overview/reference/proposals/heuristic-flow-control/c26fdbae56f3a06c46434ae91185a3d6.svg) 11. inflight -inflight为consumer端还未返回的请求的数量。 +inflight is the number of requests not yet returned on the consumer side. ![img](/imgs/overview/reference/proposals/heuristic-flow-control/f429c4726dec484e70ee73e6a37c88dd.svg) 12. load -对于备选后端机器x来说,若距离上次被调用的时间大于2*timeout,则其load值为0。 -否则, +For a candidate backend machine x, if the time since the last call is greater than 2 * timeout, its load value is 0. Otherwise, ![img](/imgs/overview/reference/proposals/heuristic-flow-control/0f56746b3643dc3ed0e019c24ad5f377.svg) -##### 算法实现 -依然是基于P2C算法。 +##### Algorithm Implementation +Still based on the P2C algorithm. -1. 从备选列表中做两次随机选择,得到providerA和providerB -2. 比较providerA和providerB的load值,选择较小的那个。 +1. Make two random selections from the candidate list to get providerA and providerB. +2. Compare the load values of providerA and providerB, selecting the smaller one. -## 自适应限流 +## Adaptive Traffic Limiting -与负载均衡运行在consumer端不同的是,限流功能运行在provider端。其作用是限制provider端处理并发任务时的最大数量。从理论上讲,服务端机器的处理能力是存在上限的,对于一台服务端机器,当短时间内出现大量的请求调用时,会导致处理不及时的请求积压,使机器过载。在这种情况下可能导致两个问题: +Unlike load balancing running on the consumer side, traffic limiting operates on the provider side. Its purpose is to limit the maximum number of concurrent tasks processed by the provider. The processing capacity of a server machine theoretically has an upper limit, and when a large number of requests occur in a short period, it can lead to undelivered requests and overload the machine. This scenario can lead to two issues: -1. 由于请求积压,最终所有的请求都必须等待较长时间才能被处理,从而使整个服务瘫痪。 -2. 服务端机器长时间的过载可能有宕机的风险。 +1. Due to backlogged requests, all requests may have to wait a long time to be processed, leading to service paralysis. +2. Prolonged server overload poses a risk of downtime. -因此,在可能存在过载风险时,拒绝掉一部分请求反而是更好的选择。在之前的 Dubbo 版本中,限流是通过在 provider 端设置静态的最大并发值实现的。但是在服务数量多,拓扑复杂且处理能力会动态变化的局面下,该值难以通过计算静态设置。 +Therefore, when overload risks are present, it is better to reject some requests. In previous versions of Dubbo, traffic limiting was achieved by setting a static maximum concurrency value on the provider side. However, in scenarios with many services, complex topology, and dynamically changing processing capabilities, calculating a static value is difficult. -基于以上原因,我们需要一种自适应的算法,其可以动态调整服务端机器的最大并发值,使其可以在保证机器不过载的前提下,尽可能多的处理接收到的请求。因此,我们参考相关理论与算法实践基础上,在 Dubbo 框架内实现了两种自适应限流算法,分别是基于启发式平滑的`HeuristicSmoothingFlowControl` 和基于窗口的 `AutoConcurrencyLimier`。 +Based on these reasons, we require an adaptive algorithm that can dynamically adjust the maximum concurrency value of server machines to process as many received requests as possible while ensuring the machine does not overload. Therefore, we implemented two adaptive traffic limiting algorithms in the Dubbo framework: `HeuristicSmoothingFlowControl` based on heuristic smoothing and `AutoConcurrencyLimier` based on a window. -[代码的github地址](https://github.com/apache/dubbo/pull/10642) +[Code's GitHub address](https://github.com/apache/dubbo/pull/10642) -### 使用介绍 -#### 总体效果 +### Usage Introduction +#### Overall Effect -自适应限流部分的有效性实验我们在提供端机器配置尽可能大的情况下进行,并且为了凸显效果,在实验中我们将单次请求的复杂度提高,将超时时间尽可能设置的大,并且开启消费端的重试功能。 +The effectiveness experiments for adaptive traffic limiting were conducted under conditions of large provider machine configurations, and to highlight the effects, we increased the complexity of individual requests, set the timeout as large as possible, and enabled the retry functionality on the consumer side. ![image.png](/imgs/overview/reference/proposals/heuristic-flow-control/1675267798831-3da99681-577f-4e5a-b122-b87c8aba7299.png) -#### 使用方法 -要确保服务端存在多个节点,并且消费端开启重试策略的前提下,限流功能才能更好的发挥作用。 +#### Usage Method +To ensure the presence of multiple nodes on the server side and the enabling of retry strategies on the consumer side, the traffic limiting function can perform better. -[Dubbo Java 实现的自适应限流开启方法](/en/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance) 与静态的最大并发值设置类似,只需在provider端将"flowcontrol"设置为"autoConcurrencyLimier"或者"heuristicSmoothingFlowControl"即可。 +[Method to enable adaptive traffic limiting in Dubbo Java implementation](/en/overview/mannual/java-sdk/advanced-features-and-usage/performance/loadbalance) is similar to setting a static maximum concurrency value, simply set "flowcontrol" to "autoConcurrencyLimier" or "heuristicSmoothingFlowControl" on the provider side. -#### 代码结构 -1. FlowControlFilter:在provider端的filter负责根据限流算法的结果来对provider端进行限流功能。 -2. FlowControl:根据dubbo的spi实现的限流算法的接口。限流的具体实现算法需要继承自该接口并可以通过dubbo的spi方式使用。 -3. CpuUsage:周期性获取cpu的相关指标 -4. HardwareMetricsCollector:获取硬件指标的相关方法 -5. ServerMetricsCollector:基于滑动窗口的获取限流需要的指标的相关方法。比如qps等。 -6. AutoConcurrencyLimier:自适应限流的具体实现算法。 -7. HeuristicSmoothingFlowControl:自适应限流的具体实现方法。 +#### Code Structure +1. FlowControlFilter: the filter on the provider side responsible for implementing traffic control based on the results of the limiting algorithm. +2. FlowControl: the interface for limiting algorithms implemented based on Dubbo's SPI. Specific implementation algorithms for traffic limiting need to inherit from this interface and be usable via Dubbo's SPI. +3. CpuUsage: periodically retrieves relevant CPU metrics. +4. HardwareMetricsCollector: methods for obtaining hardware-related metrics. +5. ServerMetricsCollector: methods for obtaining metrics required for traffic limiting based on sliding windows. For example, QPS, etc. +6. AutoConcurrencyLimier: specific implementation algorithm for adaptive traffic limiting. +7. HeuristicSmoothingFlowControl: specific implementation method for adaptive traffic limiting. -### 原理介绍 +### Principle Introduction #### HeuristicSmoothingFlowControl -##### 相关指标 +##### Related Metrics 1. alpha -alpha为可接受的延时的上升幅度,默认为0.3 +alpha is the acceptable delay increase, defaulting to 0.3. 2. minLatency -在一个时间窗口内的最小的Latency值。 +The minimum latency value in a time window. 3. noLoadLatency -noLoadLatency是单纯处理任务的延时,不包括排队时间。这是服务端机器的固有属性,但是并不是一成不变的。在HeuristicSmoothingFlowControl算法中,我们根据机器CPU的使用率来确定机器当前的noLoadLatency。当机器的CPU使用率较低时,我们认为minLatency便是noLoadLatency。当CPU使用率适中时,我们平滑的用minLatency来更新noLoadLatency的值。当CPU使用率较高时,noLoadLatency的值不再改变。 +noLoadLatency is the delay without any queue time. This is an inherent property of server machines but is not constant. In the HeuristicSmoothingFlowControl algorithm, we determine the current noLoadLatency based on the CPU usage. When CPU usage is low, we consider minLatency as noLoadLatency. When CPU usage is moderate, we use a smooth update of noLoadLatency's value with minLatency. When CPU usage is high, noLoadLatency’s value remains unchanged. 4. maxQPS -一个时间窗口周期内的QPS的最大值。 +The maximum QPS within a time window. 5. avgLatency -一个时间窗口周期内的Latency的平均值,单位为毫秒。 +The average latency over a time window, measured in milliseconds. 6. maxConcurrency -计算得到的当前服务提供端的最大并发值。 +The calculated maximum concurrency value for the current service provider. ![img](/imgs/overview/reference/proposals/heuristic-flow-control/f40e48ebdb49648cf942714609808c52.svg) -##### 算法实现 -当服务端收到一个请求时,首先判断CPU的使用率是否超过50%。如果没有超过50%,则接受这个请求进行处理。如果超过50%,说明当前的负载较高,便从HeuristicSmoothingFlowControl算法中获得当前的maxConcurrency值。如果当前正在处理的请求数量超过了maxConcurrency,则拒绝该请求。 +##### Algorithm Implementation +When the server receives a request, it first checks whether the CPU usage exceeds 50%. If not, the request is accepted for processing. If it does exceed 50%, the current maxConcurrency value is obtained from the HeuristicSmoothingFlowControl algorithm. If the currently processed request count exceeds maxConcurrency, the request is rejected. #### AutoConcurrencyLimier -##### 相关指标 +##### Related Metrics 1. MaxExploreRatio -默认设置为0.3 +Default set to 0.3. 2. MinExploreRatio -默认设置为0.06 +Default set to 0.06. 3. SampleWindowSizeMs -采样窗口的时长。默认为1000毫秒。 +The duration of the sampling window, defaulting to 1000 milliseconds. 4. MinSampleCount -采样窗口的最小请求数量。默认为40。 +The minimum request count for the sampling window, defaulting to 40. 5. MaxSampleCount -采样窗口的最大请求数量。默认为500。 +The maximum request count for the sampling window, defaulting to 500. 6. emaFactor -平滑处理参数。默认为0.1。 +Smoothing processing parameter, defaulting to 0.1. 7. exploreRatio -探索率。初始设置为MaxExploreRatio。 -若avgLatency<=noLoadLatency*(1.0 + MinExploreRatio)或者qps>=maxQPS*(1.0 + MinExploreRatio) -则exploreRatio=min(MaxExploreRatio,exploreRatio+0.02) -否则 -exploreRatio=max(MinExploreRatio,exploreRatio-0.02) +Exploration rate, initially set to MaxExploreRatio. +If avgLatency <= noLoadLatency * (1.0 + MinExploreRatio) or qps >= maxQPS * (1.0 + MinExploreRatio), +then exploreRatio = min(MaxExploreRatio, exploreRatio + 0.02); +Otherwise, +exploreRatio = max(MinExploreRatio, exploreRatio - 0.02). 8. maxQPS -窗口周期内QPS的最大值。 +The maximum QPS within the window period. ![img](/imgs/overview/reference/proposals/heuristic-flow-control/d5cf045bc17267befc176f3d76273267.svg) 9. noLoadLatency ![img](/imgs/overview/reference/proposals/heuristic-flow-control/8c700211f5c7a13403e3088df9cd9f43.svg) 10. halfSampleIntervalMs -半采样区间。默认为25000毫秒。 +Half sampling interval, defaulting to 25000 milliseconds. 11. resetLatencyUs -下一次重置所有值的时间戳,这里的重置包括窗口内值和noLoadLatency。单位是微秒。初始为0. +The timestamp for resetting all values next time, including the values within the window and noLoadLatency. Measured in microseconds and initialized to 0. ![img](/imgs/overview/reference/proposals/heuristic-flow-control/1af4a6134ede96985302ee8a27f93df7.svg) 12. remeasureStartUs -下一次重置窗口的开始时间。 +The starting time for resetting the window next time. ![img](/imgs/overview/reference/proposals/heuristic-flow-control/c7da904b9a4c890456499b09d01938d3.svg) 13. startSampleTimeUs -开始采样的时间。单位为微秒。 +The starting time for sampling, measured in microseconds. 14. sampleCount -当前采样窗口内请求的数量。 +The number of requests within the current sampling window. 15. totalSampleUs -采样窗口内所有请求的latency的和。单位为微秒。 +The sum of latencies for all requests within the sampling window, measured in microseconds. 16. totalReqCount -采样窗口时间内所有请求的数量和。注意区别sampleCount。 +The total number of requests within the sampling window, differing from sampleCount. 17. samplingTimeUs -采样当前请求的时间戳。单位为微秒。 +The timestamp of the current request's sampling, measured in microseconds. 18. latency -当前请求的latency。 +The latency of the current request. 19. qps -在该时间窗口内的qps值。 +The QPS value within this time window. ![img](/imgs/overview/reference/proposals/heuristic-flow-control/c0e8b30fc1ecf9438bc2d574fb3da8b6.svg) 20. avgLatency -窗口内的平均latency。 +The average latency within the window. ![img](/imgs/overview/reference/proposals/heuristic-flow-control/3a3acfdb05be7d3985835d43e492d3b9.svg) 21. maxConcurrency -上一个窗口计算得到当前周期的最大并发值。 +The maximum concurrency value calculated in the previous window for the current period. 22. nextMaxConcurrency -当前窗口计算出的下一个周期的最大并发值。 +The next maximum concurrency value calculated for the current window. ![img](/imgs/overview/reference/proposals/heuristic-flow-control/09852cc0ef125b43a37719796cb8baae.svg) ##### Little's Law -* 当服务处于稳定状态时:concurrency=latency*qps。这是自适应限流理论的基础。 -* 当请求没有导致机器超载时,latency基本稳定,qps和concurrency处于线性关系。 -* 当短时间内请求数量过多,导致服务超载的时候,concurrency会和latency一起上升,qps则会趋于稳定。 +* When the service is in a stable state: concurrency = latency * qps. This is the foundation of the adaptive traffic limiting theory. +* When requests do not overload the machine, latency remains stable, and qps and concurrency are linearly related. +* When an excessive number of requests occur in a short time, leading to service overload, concurrency will increase with latency, while qps will tend to stabilize. -##### 算法实现 -AutoConcurrencyLimier的算法使用过程和HeuristicSmoothingFlowControl类似。与HeuristicSmoothingFlowControl的最大区别是: +##### Algorithm Implementation +The algorithm execution process of AutoConcurrencyLimier is similar to HeuristicSmoothingFlowControl. The main difference is: -AutoConcurrencyLimier是基于窗口的。每当窗口内积累了一定量的采样数据时,才利用窗口内的数据来更新得到maxConcurrency。 -其次,利用exploreRatio来对剩余的容量进行探索。 +AutoConcurrencyLimier is window-based. Only when a certain amount of sample data accumulates within the window will the maxConcurrency value be updated using the window data. Additionally, it uses the exploreRatio to explore the remaining capacity. -另外,每隔一段时间都会自动缩小max_concurrency并持续一段时间,以处理noLoadLatency上涨的情况。因为估计noLoadLatency时必须先让服务处于低负载的状态,因此对maxConcurrency的缩小是难以避免的。 - -由于 max_concurrency < concurrency 时,服务会拒绝掉所有的请求,限流算法将 "排空所有的经历过排队的等待请求的时间" 设置为 2*latency,以确保 minLatency 的样本绝大部分时没有经过排队等待的。 +Moreover, every so often, max_concurrency will be automatically reduced for a period to handle the rise in noLoadLatency, as estimating noLoadLatency requires the service to be in a low-load state, making the reduction of maxConcurrency unavoidable. +Since max_concurrency < concurrency, the service will reject all requests, and the traffic limiting algorithm sets "emptying all the time spent waiting for queued requests" to 2 * latency, ensuring that the majority of samples for minLatency were not waiting in line. diff --git a/content/en/overview/reference/proposals/protocol-http.md b/content/en/overview/reference/proposals/protocol-http.md index bf139cfe4f2e..8ea0fc77afce 100644 --- a/content/en/overview/reference/proposals/protocol-http.md +++ b/content/en/overview/reference/proposals/protocol-http.md @@ -1,59 +1,56 @@ --- aliases: - /en/overview/reference/proposals/protocol-http/ -description: 本文将介绍 Dubbo 的 REST/HTTP 协议设计。 -linkTitle: Rest 协议 -title: Rest 协议 +description: This article will introduce the REST/HTTP protocol design of Dubbo. +linkTitle: Rest Protocol +title: Rest Protocol type: docs weight: 1 --- -本文将介绍 Dubbo 的 REST/HTTP 协议设计。 +This article will introduce the REST/HTTP protocol design of Dubbo. -## RestProtocol 设计 +## RestProtocol Design -### 原版本dubbo rest +### Original Version Dubbo Rest **consumer** -restClient支持 依赖resteasy 不支持spring mvc  +restClient supports relying on resteasy and does not support spring mvc. -**provider(较重)** +**provider (heavier)** -依赖web container   (tomcat,jetty,)servlet 模式,jaxrs netty server +Depends on web container (tomcat, jetty), servlet mode, jaxrs netty server. -### 新版本dubbo rest  +### New Version Dubbo Rest -更加轻量,具有dubbo风格的rest,微服务体系互通(Springcloud Alibaba) +Lighter, with a Dubbo-style REST that is interoperable in a microservices system (Springcloud Alibaba). -**1.注解解析** +**1. Annotation Parsing** -**2.报文编解码** +**2. Message Codec** -**3.restClient** +**3. RestClient** -**4.restServer(netty)** +**4. RestServer (netty)** -支持程度: +Support Levels: -content-type   text json xml form(后续会扩展) +content-type: text, json, xml, form (will be extended later) -注解 +Annotations: -param,header,body,pathvaribale (spring mvc & resteasy) +param, header, body, pathvariable (spring mvc & resteasy) -## Http 协议报文 +## Http Protocol Message POST /test/path? HTTP/1.1 Host: localhost:8080 Connection: keep-alive Content-type: application/json - {"name":"dubbo","age":10,"address":"hangzhou"} - - -### dubbo http(header) +### Dubbo Http (header) // service key header path: com.demo.TestInterface @@ -61,29 +58,28 @@ param,header,body,pathvaribale (spring mvc & resteasy) port: 80 version: 1.0.0 - // 保证长连接 + // ensure keep-alive Keep-Alive,Connection: keep-alive Keep-alive: 60 // RPCContext Attachment userId: 123456 +## Support Granularity -## 支持粒度 - -| 数据位置 | content-type | spring注解 | resteasy注解 | +| Data Location | content-type | spring annotations | resteasy annotations | | --- | --- | --- | --- | -| body | 无要求 | ReuqestBody |  无注解即为body | -| querystring(?test=demo) | 无要求 | RequestParam | QueryParam | -| header | 无要求 | RequestHeader | PathParam | -| form | application/x-www-form-urlencoded | RequestParam ReuqestBody | FormParam | -| path | 无要求 | PathVariable | PathParam | -| method | 无要求 | PostMapping GetMapping | GET POST | -| url | | PostMapping GetMapping path属性 | Path | -| content-type | | PostMapping GetMapping consumers属性 | Consumers | -| Accept | | PostMapping GetMapping produces属性 | Produces | - -## rest注解解析 +| body | No requirements | RequestBody | No annotations means body | +| querystring(?test=demo) | No requirements | RequestParam | QueryParam | +| header | No requirements | RequestHeader | PathParam | +| form | application/x-www-form-urlencoded | RequestParam RequestBody | FormParam | +| path | No requirements | PathVariable | PathParam | +| method | No requirements | PostMapping GetMapping | GET POST | +| url | | PostMapping GetMapping path attribute | Path | +| content-type | | PostMapping GetMapping consumers attribute | Consumers | +| Accept | | PostMapping GetMapping produces attribute | Produces | + +## Rest Annotation Parsing ServiceRestMetadataResolver JAXRSServiceRestMetadataResolver @@ -100,11 +96,11 @@ ServiceRestMetadata private String group;// demo - private Set meta;// method 元信息 + private Set meta;// method meta information - private int port;// 端口 for provider service key + private int port;// port for provider service key - private boolean consumer;// consumer 标志 + private boolean consumer;// consumer flag /** * make a distinction between mvc & resteasy @@ -119,15 +115,15 @@ ServiceRestMetadata /** * for consumer */ - private Map> methodToServiceMa + private Map> methodToServiceMap; RestMethodMetadata public class RestMethodMetadata implements Serializable { - private MethodDefinition method; // method 定义信息(name ,pramType,returnType) + private MethodDefinition method; // method definition info (name, paramType, returnType) - private RequestMetadata request;// 请求元信息 + private RequestMetadata request;// request meta info private Integer urlIndex; @@ -191,18 +187,17 @@ ArgInfo private boolean formContentType; -RequestMeatadata +RequestMetadata public class RequestMetadata implements Serializable { private static final long serialVersionUID = -240099840085329958L; - private String method;// 请求method - - private String path;// 请求url + private String method;// request method + private String path;// request url - private Map> params // param参数?拼接 + private Map> params // param parameters? concatenated private Map> headers// header; @@ -210,14 +205,14 @@ RequestMeatadata private Set produces // Accept; -### Consumer 代码 +### Consumer Code refer @Override protected Invoker protocolBindingRefer(final Class type, final URL url) throws RpcException { - // restClient spi创建 + // restClient spi creation ReferenceCountedClient refClient = clients.computeIfAbsent(url.getAddress(), key -> createReferenceCountedClient(url, clients)); @@ -231,7 +226,7 @@ refer @Override protected Result doInvoke(Invocation invocation) { try { - // 获取 method的元信息 + // get method meta info RestMethodMetadata restMethodMetadata = metadataMap.get(invocation.getMethodName()).get(ParameterTypesComparator.getInstance(invocation.getParameterTypes())); RequestTemplate requestTemplate = new RequestTemplate(invocation, restMethodMetadata.getRequest().getMethod(), url.getAddress(), getContextPath(url)); @@ -244,7 +239,7 @@ refer httpConnectionCreateContext.setInvocation(invocation); httpConnectionCreateContext.setUrl(url); - // http 信息构建拦截器 + // http info build interceptor for (HttpConnectionPreBuildIntercept intercept : httpConnectionPreBuildIntercepts) { intercept.intercept(httpConnectionCreateContext); } @@ -253,7 +248,7 @@ refer CompletableFuture future = finalRefClient.getClient().send(requestTemplate); CompletableFuture responseFuture = new CompletableFuture<>(); AsyncRpcResult asyncRpcResult = new AsyncRpcResult(responseFuture, invocation); - // response 处理 + // response handling future.whenComplete((r, t) -> { if (t != null) { responseFuture.completeExceptionally(t); @@ -305,7 +300,7 @@ refer invokers.add(invoker); return invoker; -### provider 代码 +### Provider Code export @@ -320,13 +315,11 @@ export } } - // TODO addAll metadataMap to RPCInvocationBuilder metadataMap Map metadataMap = MetadataResolver.resolveProviderServiceMetadata(url.getServiceModel().getProxyObject().getClass(),url); PathAndInvokerMapper.addPathAndInvoker(metadataMap, invoker); - final Runnable runnable = doExport(proxyFactory.getProxy(invoker, true), invoker.getInterface(), invoker.getUrl()); exporter = new AbstractExporter(invoker) { @Override @@ -351,14 +344,14 @@ RestHandler @Override public void handle(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException, ServletException { - // 有servlet reuqest 和nettyRequest + // has servlet request and nettyRequest RequestFacade request = RequestFacadeFactory.createRequestFacade(servletRequest); RpcContext.getServiceContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort()); // dispatcher.service(request, servletResponse); Pair build = null; try { - // 根据请求信息创建 RPCInvocation + // create RPCInvocation based on request info build = RPCInvocationBuilder.build(request, servletRequest, servletResponse); } catch (PathNoFoundException e) { servletResponse.setStatus(404); @@ -368,7 +361,7 @@ RestHandler Result invoke = invoker.invoke(build.getFirst()); - // TODO handling exceptions + // TODO handling exceptions if (invoke.hasException()) { servletResponse.setStatus(500); } else { @@ -384,12 +377,10 @@ RestHandler servletResponse.setStatus(500); } - } // TODO add Attachment header - } } @@ -397,25 +388,21 @@ RPCInvocationBuilder { - private static final ParamParserManager paramParser = new ParamParserManager(); - public static Pair build(RequestFacade request, Object servletRequest, Object servletResponse) { - - // 获取invoker + // get invoker Pair invokerRestMethodMetadataPair = getRestMethodMetadata(request); RpcInvocation rpcInvocation = createBaseRpcInvocation(request, invokerRestMethodMetadataPair.getSecond()); ProviderParseContext parseContext = createParseContext(request, servletRequest, servletResponse, invokerRestMethodMetadataPair.getSecond()); - // 参数构建 + // parameter construction Object[] args = paramParser.providerParamParse(parseContext); rpcInvocation.setArguments(args); return Pair.make(rpcInvocation, invokerRestMethodMetadataPair.getFirst()); - } private static ProviderParseContext createParseContext(RequestFacade request, Object servletRequest, Object servletResponse, RestMethodMetadata restMethodMetadata) { @@ -427,14 +414,12 @@ RPCInvocationBuilder parseContext.setArgs(Arrays.asList(objects)); parseContext.setArgInfos(restMethodMetadata.getArgInfos()); - return parseContext; } private static RpcInvocation createBaseRpcInvocation(RequestFacade request, RestMethodMetadata restMethodMetadata) { RpcInvocation rpcInvocation = new RpcInvocation(); - int localPort = request.getLocalPort(); String localAddr = request.getLocalAddr(); int remotePort = request.getRemotePort(); @@ -451,7 +436,6 @@ RPCInvocationBuilder rpcInvocation.setParameterTypes(restMethodMetadata.getReflectMethod().getParameterTypes()); - rpcInvocation.setMethodName(METHOD); rpcInvocation.setAttachment(RestConstant.GROUP, GROUP); rpcInvocation.setAttachment(RestConstant.METHOD, METHOD); @@ -474,12 +458,10 @@ RPCInvocationBuilder rpcInvocation.setAttachment(split[0], split[1]); } - // TODO set path,version,group and so on return rpcInvocation; } - private static Pair getRestMethodMetadata(RequestFacade request) { String path = request.getRequestURI(); String version = request.getHeader(RestConstant.VERSION); @@ -488,11 +470,9 @@ RPCInvocationBuilder return PathAndInvokerMapper.getRestMethodMetadata(path, version, group, port); } - - } -## 编码示例 +## Coding Examples **API** @@ -538,14 +518,12 @@ impl(service) private static Map context; private boolean called; - @Override public String sayHello(String name) { called = true; return "Hello, " + name; } - public boolean isCalled() { return called; } @@ -556,7 +534,6 @@ impl(service) return a + b; } - @Override public String error() { throw new RuntimeException(); @@ -567,9 +544,9 @@ impl(service) } } -## 流程图 +## Flow Chart -**Consumer**   +**Consumer** ![image](https://static.dingtalk.com/media/lQLPJxLOtqTxs9TNA5rNBQCwci8F2QYiGAYD5sSyd4BVAA_1280_922.png) @@ -577,82 +554,82 @@ impl(service) ![image](https://static.dingtalk.com/media/lQLPJxZcNUm4M9TNA1_NBMuwZUu6IC3FeYAD5sSydYADAA_1227_863.png) -## 场景  +## Scenarios -### 1.体系互通 +### 1. Interoperability of Systems -**非dubbo体系互通(Springcloud alibaba  互通)** +**Non-Dubbo System Interoperability (Springcloud Alibaba Interoperability)** -互通条件: +Interoperability Conditions: -| | 协议 | Dubbo | SpringCloud Alibaba | 互通 | +| | Protocol | Dubbo | SpringCloud Alibaba | Interoperation | | --- | --- | --- | --- | --- | -| 通信协议 | rest | spring web/resteasy  编码风格 | 集成feignclient,ribbon (spring web 编码风格) | 是 | +| Communication Protocol | rest | spring web/resteasy encoding style | integrates feignclient, ribbon (spring web encoding style) | Yes | | | triple | | | | | | dubbo | | | | | | grpc | | | | | | hessian | | | | -| 注册中心 | zookeeper | | | | -| | nacos | 支持 | 支持 | 应用级别注册 | +| Registration Center | zookeeper | | | | +| | nacos | supported | supported | application-level registration | -### 2.dubbo 双注册  +### 2. Dubbo Dual Registration - 完成应用级别注册,(dubo2-dubbo3 过度),dubbo版本升级 +Complete application-level registration (from dubbo2 to dubbo3 migration), dubbo version upgrade ![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/0ceca951-f467-4ab3-9b71-8e7d52e5e7d1.png) ![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/6bcc7aed-1d22-470f-b185-efbab32df1e5.png) -### 3.多协议发布 +### 3. Multi-Protocol Publishing -配置: +Configuration: - + -### 4.跨语言 +### 4. Cross-Language ![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/1bdf8f91-9666-4c20-9aea-8396c745f554.png) -### 5.多协议交互 +### 5. Multi-Protocol Interaction ![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/af72e3df-05d5-42a2-a333-618be7ec6cb8.png) -### 6.协议迁移 +### 6. Protocol Migration + +![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/36d30183-8d5-494c-8ebb-b57403c88661.png) -![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/36d30183-8d5f-494c-8ebb-b57403c88661.png) +Rest encoding style -rest编码风格 +HTTP protocol is more universally applicable for cross-language calls. -Http协议更通用跨语言调用 +Dubbo Rest calls other HTTP services. -dubbo rest 对其他http服务 进行调用 +Other HttpClient calls Dubbo Rest. -其他httpclient 对dubbo rest进行调用 +Dubbo RestServer can directly interact with other web services, browsers, and clients via HTTP. -dubbo restServer 可以与其他web服务,浏览器等客户端直接进行http交互 +## Consumer TODO LIST +> Features have been initially implemented and can parse responses. -## consumer TODOLIST -> 功能已经初步实现,可以调通解析response +1. org/apache/dubbo/rpc/protocol/rest/RestProtocol.java:157 dynamic load config -1. org/apache/dubbo/rpc/protocol/rest/RestProtocol.java:157  dynamic load config +2. org/apache/dubbo/remoting/http/factory/AbstractHttpClientFactory.java:50 load config HttpClientConfig -2.org/apache/dubbo/remoting/http/factory/AbstractHttpClientFactory.java:50 load config  HttpClientConfig +3. org/apache/dubbo/rpc/protocol/rest/annotation/metadata/MetadataResolver.java:52 support Dubbo style service -3.org/apache/dubbo/rpc/protocol/rest/annotation/metadata/MetadataResolver.java:52  support Dubbo style service +4. org/apache/dubbo/remoting/http/restclient/HttpClientRestClient.java:120 TODO config -4.org/apache/dubbo/remoting/http/restclient/HttpClientRestClient.java:120  TODO config +5. org/apache/dubbo/remoting/http/restclient/HttpClientRestClient.java:140 TODO close judgment -5.org/apache/dubbo/remoting/http/restclient/HttpClientRestClient.java:140 TODO close judge +6. org/apache/dubbo/rpc/protocol/rest/message/decode/MultiValueCodec.java:35 TODO java bean get set convert -6.org/apache/dubbo/rpc/protocol/rest/message/decode/MultiValueCodec.java:35  TODO java bean  get set convert +## Provider TODO LIST +> To be implemented -## provider TODOLIST -> 待实现 - -基于netty实现支持http协议的NettyServer +Netty implementation supporting HTTP protocol for NettyServer. -无注解协议定义 +No annotation protocol definition. -官网场景补充 +Website scenario supplements. -## Rest使用说明文档及demo +## Rest User Documentation and Demo diff --git a/content/en/overview/reference/proposals/registry-config-meta.md b/content/en/overview/reference/proposals/registry-config-meta.md index 7ed9adc6ffee..b0de6f8263cf 100644 --- a/content/en/overview/reference/proposals/registry-config-meta.md +++ b/content/en/overview/reference/proposals/registry-config-meta.md @@ -1,93 +1,90 @@ --- aliases: - /en/overview/reference/proposals/registry-config-meta/ -description: 本文介绍三中心架构设计 -linkTitle: 注册&配置&元数据中心 -title: 注册中心、配置中心和元数据中心 +description: This article introduces the design of a three-center architecture +linkTitle: Registry & Configuration & Metadata Center +title: Registry Center, Configuration Center, and Metadata Center type: docs weight: 2 --- -## 三中心逻辑架构 -> 本节侧重描述传统模式下的 Dubbo 部署架构,在云原生背景下的部署架构会有些变化,主要体现在基础设施(Kubernetes、Service Mesh等)会承担更多的职责, -> 中心化组件如注册中心、元数据中心、配置中心等的职责被集成、运维变得更加简单,但通过强调这些中心化的组件能让我们更容易理解 Dubbo 的工作原理。 +## Three Center Logical Architecture +> This section focuses on describing the traditional deployment architecture of Dubbo. The deployment architecture in a cloud-native context may vary, mainly in that the infrastructure (Kubernetes, Service Mesh, etc.) takes on more responsibilities. +> Centralized components such as registry centers, metadata centers, and configuration centers have their duties integrated, making operation and maintenance simpler. However, emphasizing these centralized components helps us better understand how Dubbo works. -作为一个微服务框架,Dubbo sdk 跟随着微服务组件被部署在分布式集群各个位置,为了在分布式环境下实现各个微服务组件间的协作, -Dubbo 定义了一些中心化组件,这包括: -* 注册中心。协调 Consumer 与 Provider 之间的地址注册与发现 -* 配置中心。 - * 存储 Dubbo 启动阶段的全局配置,保证配置的跨环境共享与全局一致性 - * 负责服务治理规则(路由规则、动态配置等)的存储与推送。 -* 元数据中心。 - * 接收 Provider 上报的服务接口元数据,为 Admin 等控制台提供运维能力(如服务测试、接口文档等) - * 作为服务发现机制的补充,提供额外的接口/方法级别配置信息的同步能力,相当于注册中心的额外扩展 +As a microservice framework, Dubbo SDK is deployed across distributed clusters along with microservice components. To achieve collaboration between various microservice components in a distributed environment, Dubbo defines several centralized components, including: +* Registry Center. Coordinates address registration and discovery between Consumer and Provider. +* Configuration Center. + * Stores global configurations during the Dubbo startup phase to ensure cross-environment sharing and global consistency. + * Responsible for storing and pushing service governance rules (routing rules, dynamic configurations, etc.). +* Metadata Center. + * Receives service interface metadata reported by Providers and provides operation and maintenance capabilities for consoles like Admin (e.g., service testing, interface documentation). + * Acts as a supplement to the service discovery mechanism, providing synchronization capabilities for additional interface/method-level configuration information, equivalent to extra extensions of the registry center. ![threecenters](/imgs/v3/concepts/threecenters.png) -上图完整的描述了 Dubbo 微服务组件与各个中心的交互过程。 +The above figure fully describes the interaction process between Dubbo microservice components and each center. -以上三个中心并不是运行 Dubbo 的必要条件,用户完全可以根据自身业务情况决定只启用其中一个或多个,以达到简化部署的目的。通常情况下,所有用户都会以独立的注册中心 -以开始 Dubbo 服务开发,而配置中心、元数据中心则会在微服务演进的过程中逐步的按需被引入进来。 +The three centers mentioned above are not necessary for running Dubbo; users can decide to enable only one or more of them based on their business needs to simplify deployment. Generally, all users will start Dubbo service development with an independent registry center, while the configuration and metadata centers will be gradually introduced as needed during the evolution of microservices. -### 注册中心 +### Registry Center -注册中心扮演着非常重要的角色,它承载着服务注册和服务发现的职责。目前Dubbo支持以下两种粒度的服务发现和服务注册,分别是接口级别和应用级别,注册中心可以按需进行部署: +The registry center plays a very important role, shouldering the responsibilities of service registration and service discovery. Currently, Dubbo supports two granularities of service discovery and registration: interface-level and application-level, and the registry center can be deployed as needed: -- 在传统的Dubbo SDK使用姿势中,如果仅仅提供直连模式的RPC服务,不需要部署注册中心。 -- 无论是接口级别还是应用级别,如果需要Dubbo SDK自身来做服务注册和服务发现,则可以选择部署注册中心,在Dubbo中集成对应的注册中心。 +- In the traditional usage of the Dubbo SDK, if only direct connection mode RPC services are provided, it is not necessary to deploy a registry center. +- Whether at the interface or application level, if the Dubbo SDK needs to handle service registration and discovery, a registry center can be deployed to integrate the corresponding registry. +- In Dubbo + Mesh scenarios, as the service registration capabilities of Dubbo weaken, the registry center is no longer mandatory, and its responsibilities begin to be replaced by the control plane. If the Dubbo + Mesh deployment method is adopted, neither the ThinSDK's mesh method nor the Proxyless mesh method requires an independent registry center. -- 在Dubbo + Mesh 的场景下,随着 Dubbo 服务注册能力的弱化,Dubbo内的注册中心也不再是必选项,其职责开始被控制面取代,如果采用了Dubbo + Mesh的部署方式,无论是ThinSDK的mesh方式还是Proxyless的mesh方式,都不再需要独立部署注册中心。 - -而注册中心并不依赖于配置中心和元数据中心,如下图所示: +The registry center does not depend on the configuration center and the metadata center, as shown in the diagram below: ![centers-registry](/imgs/v3/concepts/centers-registry.png) -该图中没有部署配置中心和元数据中心,在Dubbo中会默认将注册中心的实例同时作为配置中心和元数据中心,这是Dubbo的默认行为,如果确实不需要配置中心或者元数据中心的能力,可在配置中关闭,在注册中心的配置中有两个配置分别为use-as-config-center和use-as-metadata-center,将配置置为false即可。 +This diagram shows that the configuration center and metadata center are not deployed, meaning that Dubbo will default the instance of the registry center to also serve as the configuration center and metadata center. This is the default behavior of Dubbo. If the functionalities of the configuration center or metadata center are indeed not needed, they can be disabled in the configuration. In the registry center's configuration, the two settings 'use-as-config-center' and 'use-as-metadata-center' can be set to false. -### 元数据中心 +### Metadata Center -元数据中心在2.7.x版本开始支持,随着应用级别的服务注册和服务发现在Dubbo中落地,元数据中心也变的越来越重要。在以下几种情况下会需要部署元数据中心: +The metadata center started to be supported from version 2.7.x. As application-level service registration and discovery are implemented in Dubbo, the metadata center becomes increasingly important. The following scenarios may require the deployment of a metadata center: -1. 对于一个原先采用老版本Dubbo搭建的应用服务,在迁移到Dubbo 3时,Dubbo 3 会需要一个元数据中心来维护RPC服务与应用的映射关系(即接口与应用的映射关系),因为如果采用了应用级别的服务发现和服务注册,在注册中心中将采用“应用 —— 实例列表”结构的数据组织形式,不再是以往的“接口 —— 实例列表”结构的数据组织形式,而以往用接口级别的服务注册和服务发现的应用服务在迁移到应用级别时,得不到接口与应用之间的对应关系,从而无法从注册中心得到实例列表信息,所以Dubbo为了兼容这种场景,在Provider端启动时,会往元数据中心存储接口与应用的映射关系。 -2. 为了让注册中心更加聚焦于地址的发现和推送能力,减轻注册中心的负担,元数据中心承载了所有的服务元数据、大量接口/方法级别配置信息等,无论是接口粒度还是应用粒度的服务发现和注册,元数据中心都起到了重要的作用。 +1. For an application service originally built with an old version of Dubbo, migrating to Dubbo 3 requires a metadata center to maintain the mapping relationship between RPC services and applications (i.e., the mapping between interfaces and applications). If application-level service discovery and registration are adopted, the registry will use an "application - instance list" structure for organizing data, rather than the previous "interface - instance list" structure, making it impossible to obtain the corresponding relationship between interfaces and applications during the migration process. To accommodate this scenario, Dubbo will store the mapping relationship between interfaces and applications in the metadata center during the Provider startup. +2. To allow the registry center to focus more on address discovery and push capabilities, reducing its burden, the metadata center bears all service metadata and extensive interface/method-level configuration information. Regardless of whether service discovery and registration are at the interface granularity or application granularity, the metadata center plays an important role. -如果有以上两种需求,都可以选择部署元数据中心,并通过Dubbo的配置来集成该元数据中心。 +If the above two needs exist, deploying a metadata center and integrating it through Dubbo's configuration is feasible. -元数据中心并不依赖于注册中心和配置中心,用户可以自由选择是否集成和部署元数据中心,如下图所示: +The metadata center does not depend on the registry center and configuration center, allowing users to freely choose whether to integrate and deploy the metadata center, as shown in the diagram below: ![centers-metadata](/imgs/v3/concepts/centers-metadata.png) -该图中不配备配置中心,意味着可以不需要全局管理配置的能力。该图中不配备注册中心,意味着可能采用了Dubbo mesh的方案,也可能不需要进行服务注册,仅仅接收直连模式的服务调用。 +The absence of a configuration center in this diagram means that global configuration management capabilities are not necessary. The absence of a registry center means that Dubbo's mesh solution may be employed, or there may be no need for service registration, only direct calls are received. -### 配置中心 +### Configuration Center -配置中心与其他两大中心不同,它无关于接口级还是应用级,它与接口并没有对应关系,它仅仅与配置数据有关,即使没有部署注册中心和元数据中心,配置中心也能直接被接入到Dubbo应用服务中。在整个部署架构中,整个集群内的实例(无论是Provider还是Consumer)都将会共享该配置中心集群中的配置,如下图所示: +The configuration center differs from the other two centers in that it is unrelated to interface or application levels; it does not correspond to interfaces but only to configuration data. Even without deploying a registry center and metadata center, the configuration center can be directly integrated into Dubbo application services. In the overall deployment architecture, instances across the cluster (whether Providers or Consumers) will share configurations from the configuration center cluster, as shown in the diagram below: ![centers-config](/imgs/v3/concepts/centers-config.png) -该图中不配备注册中心,意味着可能采用了Dubbo mesh的方案,也可能不需要进行服务注册,仅仅接收直连模式的服务调用。 - -该图中不配备元数据中心,意味着Consumer可以从Provider暴露的MetadataService获取服务元数据,从而实现RPC调用 +The absence of a registry center in this diagram indicates the potential use of a Dubbo mesh solution, and service registration may not be required, only direct service calls are handled. -### 保证三大中心高可用的部署架构 +The absence of a metadata center in this diagram means that Consumers can obtain service metadata from the MetadataService exposed by Providers to facilitate RPC calls. -虽然三大中心已不再是Dubbo应用服务所必须的,但是在真实的生产环境中,一旦已经集成并且部署了该三大中心,三大中心还是会面临可用性问题,Dubbo需要支持三大中心的高可用方案。在Dubbo中就支持多注册中心、多元数据中心、多配置中心,来满足同城多活、两地三中心、异地多活等部署架构模式的需求。 +### Ensure Highly Available Deployment Architecture of the Three Centers -Dubbo SDK对三大中心都支持了Multiple模式。 +While the three centers are no longer mandatory for Dubbo application services, once they are integrated and deployed in a production environment, they still face availability issues. Dubbo needs to support high availability solutions for the three centers. Dubbo supports multiple registry centers, multiple metadata centers, and multiple configuration centers to meet deployment architecture models such as multi-active in the same city, two-location three centers, and cross-geography multi-active. -- 多注册中心:Dubbo 支持多注册中心,即一个接口或者一个应用可以被注册到多个注册中心中,比如可以注册到ZK集群和Nacos集群中,Consumer也能够从多个注册中心中进行订阅相关服务的地址信息,从而进行服务发现。通过支持多注册中心的方式来保证其中一个注册中心集群出现不可用时能够切换到另一个注册中心集群,保证能够正常提供服务以及发起服务调用。这也能够满足注册中心在部署上适应各类高可用的部署架构模式。 -- 多配置中心:Dubbo支持多配置中心,来保证其中一个配置中心集群出现不可用时能够切换到另一个配置中心集群,保证能够正常从配置中心获取全局的配置、路由规则等信息。这也能够满足配置中心在部署上适应各类高可用的部署架构模式。 +Dubbo SDK supports Multiple mode for all three centers. -- 多元数据中心:Dubbo 支持多元数据中心:用于应对容灾等情况导致某个元数据中心集群不可用,此时可以切换到另一个元数据中心集群,保证元数据中心能够正常提供有关服务元数据的管理能力。 +- Multiple Registry Centers: Dubbo supports multiple registry centers, meaning an interface or application can be registered to multiple registry centers, such as both a ZK cluster and a Nacos cluster. Consumers can also subscribe to related service address information from multiple registry centers for service discovery. This support for multiple registry centers ensures that if one registry center cluster becomes unavailable, it can switch to another, ensuring continuous service provision and invocation. This also meets various high-availability deployment architecture models for the registry center. +- Multiple Configuration Centers: Dubbo supports multiple configuration centers to ensure that if one configuration center cluster becomes unavailable, it can switch to another, ensuring that global configurations, routing rules, and other information can still be obtained from the configuration center. This also meets various high-availability deployment architecture models for the configuration center. +- Multiple Metadata Centers: Dubbo supports multiple metadata centers to respond to situations where a metadata center cluster becomes unavailable due to disaster recovery or similar circumstances, allowing a switch to another metadata center cluster to maintain management capabilities for service metadata. -拿注册中心举例,下面是一个多活场景的部署架构示意图: +Taking the registry center as an example, below is a schematic diagram of a multi-active deployment architecture: ![multiple-registry-deployment-architecture](/imgs/v3/concepts/multiple-registry-deployment-architecture.png) -## 三中心物理部署架构 +## Physical Deployment Architecture of the Three Centers + +![Same cluster, undertaking the responsibilities of the three centers](#) -![同一集群,承担三个中心职责](#) +## Recommended Usage in Different Scenarios +* Configure only the registry, defaulting to serve as the metadata and config-center. +* Use different clusters or even different extension implementations for the registry, metadata, and config-center, requiring independent configuration for metadata or config-center. -## 不同场景下的推荐使用方式 -* 只配置 registry,默认作为 metadata、config-center -* registry、metadata、config-center 使用不同的集群甚至是不同的扩展实现,此时需要独立配置 metadata 或 config-center diff --git a/content/en/overview/reference/proposals/service-discovery.md b/content/en/overview/reference/proposals/service-discovery.md index 499e40ba6d2b..42f3eb1bfddb 100644 --- a/content/en/overview/reference/proposals/service-discovery.md +++ b/content/en/overview/reference/proposals/service-discovery.md @@ -3,9 +3,9 @@ aliases: - /en/overview/reference/proposals/service-discovery/ author: Jun Liu date: 2023-01-30T00:00:00Z -description: 应用级服务发现设计 -linkTitle: 应用级服务发现 -title: Dubbo3 应用级服务发现设计 +description: Application-level service discovery design +linkTitle: Application-level service discovery +title: Dubbo3 Application-level Service Discovery Design type: docs weight: 6 --- @@ -13,78 +13,79 @@ weight: 6 ## Objective -* 显著降低服务发现过程的资源消耗,包括提升注册中心容量上限、降低消费端地址解析资源占用等,使得 Dubbo3 框架能够支持更大规模集群的服务治理,实现无限水平扩容。 -* 适配底层基础设施服务发现模型,如 Kubernetes、Service Mesh 等。 +* Significantly reduce the resource consumption during the service discovery process, including improving the capacity limits of the registry center and reducing the resource consumption of address resolution on the consumer side, enabling the Dubbo3 framework to support service governance for larger cluster scales and achieving infinite horizontal scaling. +* Adapt to lower-level infrastructure service discovery models, such as Kubernetes and Service Mesh. ## Background ![interface-arc](/imgs/blog/proposals/discovery/arc.png) -我们从 Dubbo 最经典的工作原理图说起,Dubbo 从设计之初就内置了服务地址发现的能力,Provider 注册地址到注册中心,Consumer 通过订阅实时获取注册中心的地址更新,在收到地址列表后,consumer 基于特定的负载均衡策略发起对 provider 的 RPC 调用。 +Let's start with the classic working principle diagram of Dubbo. Since its inception, Dubbo has built-in capabilities for service address discovery. The provider registers its address to the registry center, and the consumer subscribes to receive real-time address updates from the registry center. Upon receiving the address list, the consumer initiates RPC calls to the provider based on specific load balancing strategies. -在这个过程中: -* 每个 Provider 通过特定的 key 向注册中心注册本机可访问地址; -* 注册中心通过这个 key 对 provider 实例地址进行聚合; -* Consumer 通过同样的 key 从注册中心订阅,以便及时收到聚合后的地址列表; +In this process: +* Each provider registers its accessible addresses with the registry using specific keys; +* The registry aggregates the provider instance addresses using this key; +* The consumer subscribes from the registry using the same key to receive the aggregated address list in a timely manner; ![interface-data1](/imgs/blog/proposals/discovery/interface-data1.png) -这里,我们对接口级地址发现的内部数据结构进行详细分析。 +Here, we conduct a detailed analysis of the internal data structure of interface-level address discovery. -首先,看右下角 provider 实例内部的数据与行为。Provider 部署的应用中通常会有多个 Service,也就是 Dubbo2 中的服务,每个 service 都可能会有其独有的配置,我们所讲的 service 服务发布的过程,其实就是基于这个服务配置生成地址 URL 的过程,生成的地址数据如图所示;同样的,其他服务也都会生成地址。 +First, let's look at the data and behavior of provider instances in the lower right corner. Typically, an application deployed as a provider will have multiple services, which are equivalent to services in Dubbo2. Each service may have its unique configurations. The process we discuss about service publishing is essentially the process of generating address URLs based on these service configurations, as depicted in the generated address data. Similarly, other services will also generate addresses. -然后,看一下注册中心的地址数据存储结构,注册中心以 service 服务名为数据划分依据,将一个服务下的所有地址数据都作为子节点进行聚合,子节点的内容就是实际可访问的ip地址,也就是我们 Dubbo 中 URL,格式就是刚才 provider 实例生成的。 +Next, let's examine the address data storage structure of the registry. The registry uses the service name for data partitioning, aggregating all address data under a service as child nodes, where the contents of the child nodes are the actual accessible IP addresses, which are the URLs in Dubbo, formatted as generated by the provider instance. ![interface-data2](/imgs/blog/proposals/discovery/interface-data2.png) -这里把 URL 地址数据划分成了几份: -* 首先是实例可访问地址,主要信息包含 ip port,是消费端将基于这条数据生成 tcp 网络链接,作为后续 RPC 数据的传输载体 -* 其次是 RPC 元数据,元数据用于定义和描述一次 RPC 请求,一方面表明这条地址数据是与某条具体的 RPC 服务有关的,它的版本号、分组以及方法相关信息,另一方面表明 -* 下一部分是 RPC 配置数据,部分配置用于控制 RPC 调用的行为,还有一部分配置用于同步 Provider 进程实例的状态,典型的如超时时间、数据编码的序列化方式等。 -* 最后一部分是自定义的元数据,这部分内容区别于以上框架预定义的各项配置,给了用户更大的灵活性,用户可任意扩展并添加自定义元数据,以进一步丰富实例状态。 +Here, the URL address data is divided into several parts: +* First, the instance accessible address, which mainly contains the IP and port information and is used by the consumer to generate TCP network connections for further RPC data transmission. +* Second, the RPC metadata, which is used to define and describe a single RPC request, indicating that this address data is related to a specific RPC service, its version number, group, and method-related information. +* The third part is RPC configuration data, where some configurations control the behavior of RPC calls, and others synchronize the state of the provider process instance, such as timeout and data encoding serialization method. +* The last part is custom metadata, which differs from the predefined configurations and allows users to expand and add custom metadata freely to enrich instance states further. -结合以上两页对于 Dubbo2 接口级地址模型的分析,以及最开始的 Dubbo 基本原理图,我们可以得出这么几条结论: -* 第一,地址发现聚合的 key 就是 RPC 粒度的服务 -* 第二,注册中心同步的数据不止包含地址,还包含了各种元数据以及配置 -* 得益于 1 与 2,Dubbo 实现了支持应用、RPC 服务、方法粒度的服务治理能力 +Combining the analysis above of Dubbo2's interface-level address model with the initial basic principle diagram of Dubbo, we can draw several conclusions: +* First, the key for address discovery aggregation is the RPC granularity of the service. +* Second, the data synchronized by the registry center contains not only addresses but also various metadata and configurations. +* Thanks to 1 and 2, Dubbo achieves service governance capabilities at the application, RPC service, and method granularity. -这就是一直以来 Dubbo2 在易用性、服务治理功能性、可扩展性上强于很多服务框架的真正原因。 +This is the true reason why Dubbo2 has always been superior to many service frameworks in usability, service governance functionality, and scalability. ![interface-defect](/imgs/blog/proposals/discovery/interface-defect.png) -一个事物总是有其两面性,Dubbo2 地址模型带来易用性和强大功能的同时,也给整个架构的水平可扩展性带来了一些限制。这个问题在普通规模的微服务集群下是完全感知不到的,而随着集群规模的增长,当整个集群内应用、机器达到一定数量时,整个集群内的各个组件才开始遇到规模瓶颈。在总结包括阿里巴巴、工商银行等多个典型的用户在生产环境特点后,我们总结出以下两点突出问题(如图中红色所示): -* 首先,注册中心集群容量达到上限阈值。由于所有的 URL 地址数据都被发送到注册中心,注册中心的存储容量达到上限,推送效率也随之下降。 -* 而在消费端这一侧,Dubbo2 框架常驻内存已超 40%,每次地址推送带来的 cpu 等资源消耗率也非常高,影响正常的业务调用。 +Every entity has its duality. While Dubbo2's address model brings usability and powerful functionality, it also imposes some limitations on the horizontal scalability of the entire architecture. This issue is not perceivable under a typical-scale microservice cluster. However, as the cluster scales up and the total number of applications and machines reaches a certain level, each component within the cluster starts to encounter scaling bottlenecks. After summarizing the characteristics of multiple typical users such as Alibaba and ICBC in the production environment, we identified the following two prominent problems (highlighted in red in the diagram): +* First, the cluster capacity of the registry center reaches its upper limit. As all URL address data is sent to the registry center, its storage capacity reaches a limit, and the push efficiency declines as well. +* On the consumer side, the Dubbo2 framework's memory resident usage has exceeded 40%, and the CPU and other resource consumption rates brought by each address push are also very high, affecting normal business calls. -为什么会出现这个问题?我们以一个具体 provider 示例进行展开,来尝试说明为何应用在接口级地址模型下容易遇到容量问题。 -青蓝色部分,假设这里有一个普通的 Dubbo Provider 应用,该应用内部定义有 10 个 RPC Service,应用被部署在 100 个机器实例上。这个应用在集群中产生的数据量将会是 “Service 数 * 机器实例数”,也就是 10 * 100 = 1000 条。数据被从两个维度放大: -* 从地址角度。100 条唯一的实例地址,被放大 10 倍 -* 从服务角度。10 条唯一的服务元数据,被放大 100 倍 +Why does this issue arise? Let's explore a specific provider example to illustrate why applications under the interface-level address model are prone to capacity issues. +In the cyan area, let's assume there is a typical Dubbo provider application with 10 RPC services defined internally and deployed on 100 machine instances. This application will generate data in the cluster totaling "number of services * number of machine instances," which is 10 * 100 = 1000 entries. Data is magnified from two dimensions: +* From the address perspective. 100 unique instance addresses magnified by 10 times. +* From the service perspective. 10 unique service metadata entries magnified by 100 times. ## Proposal ![app-principle](/imgs/blog/proposals/discovery/app-principle.png) -面对这个问题,在 Dubbo3 架构下,我们不得不重新思考两个问题: -* 如何在保留易用性、功能性的同时,重新组织 URL 地址数据,避免冗余数据的出现,让 Dubbo3 能支撑更大规模集群水平扩容? -* 如何在地址发现层面与其他的微服务体系如 Kubernetes、Spring Cloud 打通? +In response to this issue, under the Dubbo3 architecture, we must rethink two questions: +* How can we reorganize URL address data while retaining usability and functionality to avoid data redundancy, enabling Dubbo3 to support larger scale cluster horizontal expansion? +* How can we integrate service discovery with other microservice systems like Kubernetes and Spring Cloud? ![app-data1](/imgs/blog/proposals/discovery/app-data1.png) -Dubbo3 的应用级服务发现方案设计本质上就是围绕以上两个问题展开。其基本思路是:地址发现链路上的聚合元素也就是我们之前提到的 Key 由服务调整为应用,这也是其名称叫做应用级服务发现的由来;另外,通过注册中心同步的数据内容上做了大幅精简,只保留最核心的 ip、port 地址数据。 +The design of Dubbo3's application-level service discovery solution fundamentally revolves around these two questions. The basic idea is: the aggregation elements in the address discovery link, which we previously mentioned as keys, are adjusted from service to application, hence the name application-level service discovery; additionally, the data content synchronized from the registry has been substantially simplified, keeping only the core IP and port address data. ![app-data2](/imgs/blog/proposals/discovery/app-data2.png) -这是升级之后应用级地址发现的内部数据结构进行详细分析。 -对比之前接口级的地址发现模型,我们主要关注橙色部分的变化。首先,在 provider 实例这一侧,相比于之前每个 RPC Service 注册一条地址数据,一个 provider 实例只会注册一条地址到注册中心;而在注册中心这一侧,地址以应用名为粒度做聚合,应用名节点下是精简过后的 provider 实例地址; +This is a detailed analysis of the internal data structure of the upgraded application-level address discovery. +Comparing with the previous interface-level address discovery model, we primarily focus on the changes in the orange part. First, on the provider instance side, compared to registering one address data for each RPC service previously, a provider instance will only register one address with the registry center; on the registry center side, addresses are aggregated based on application names, with streamlined provider instance addresses under the application name node; ![app-metadataservice](/imgs/blog/proposals/discovery/app-metadataservice.png) -应用级服务发现的上述调整,同时实现了地址单条数据大小和总数量的下降,但同时也带来了新的挑战:我们之前 Dubbo2 强调的易用性和功能性的基础损失了,因为元数据的传输被精简掉了,如何精细的控制单个服务的行为变得无法实现。 +The above adjustments in application-level service discovery achieved a reduction in both the size of individual address data and the total number of entries while also introducing new challenges: we previously emphasized usability and functionality in Dubbo2 have been lost because metadata transmission has been streamlined. How to finely control the behavior of a single service becomes unachievable. -针对这个问题,Dubbo3 的解法是引入一个内置的 MetadataService 元数据服务,由中心化推送转为 Consumer 到 Provider 的点对点拉取,在这个模式下,元数据传输的数据量将不在是一个问题,因此可以在元数据中扩展出更多的参数、暴露更多的治理数据。 +To address this issue, Dubbo3's solution is to introduce a built-in MetadataService for metadata management, shifting from centralized push to point-to-point pull from the consumer to the provider. In this mode, the amount of metadata transmitted will no longer be an issue, thus allowing for more parameters to be extended and more governance data to be exposed within the metadata. ![app-metadataservice](/imgs/blog/proposals/discovery/app-workflow.png) -这里我们个重点看消费端 Consumer 的地址订阅行为,消费端从分两步读取地址数据,首先是从注册中心收到精简后的地址,随后通过调用 MetadataService 元数据服务,读取对端的元数据信息。在收到这两部分数据之后,消费端会完成地址数据的聚合,最终在运行态还原出类似 Dubbo2 的 URL 地址格式。因此从最终结果而言,应用级地址模型同时兼顾了地址传输层面的性能与运行层面的功能性。 +Here we focus on the address subscription behavior of the consumer. The consumer reads address data in two steps: first receiving the streamlined address from the registry center, and then calling the MetadataService to read the metadata information from the opposite end. After receiving these two data parts, the consumer will complete address data aggregation, ultimately restoring it to a URL address format similar to Dubbo2 in runtime. Therefore, from the final result, the application-level address model balances performance at the address transmission layer with functionality at the runtime layer. + +This concludes the content regarding the background and working principles of application-level service discovery. Next, we will look into the process of Ele.me upgrading to Dubbo3, especially the transition to application-level service discovery. -以上就是的应用级服务发现背景、工作原理部分的所有内容,接下来我们看一下饿了么升级到 Dubbo3 尤其是应用级服务发现的过程。 diff --git a/content/en/overview/reference/proposals/support-more-content-types.md b/content/en/overview/reference/proposals/support-more-content-types.md index c396c33c4307..0595db150194 100644 --- a/content/en/overview/reference/proposals/support-more-content-types.md +++ b/content/en/overview/reference/proposals/support-more-content-types.md @@ -1,35 +1,33 @@ --- aliases: - /en/overview/reference/proposals/support-more-content-type/ -author: 武钰皓 +author: Wu Yuhao description: | - 本文主要介绍Triple对更多Http标准Content-Type的支持方式,以及服务该如何接收这些请求。 -title: Triple协议Http标准能力增强-多Content-Type支持 + This article mainly introduces how Triple supports more standard HTTP Content-Types and how services should handle these requests. +title: Enhanced HTTP Standard Capabilities of Triple - Multi Content-Type Support type: docs working_in_progress: true --- -### **Triple协议Http标准能力增强-多Content-Type支持** -> 本文主要介绍Triple对更多HTTP标准Content-Type的支持方式,以及服务该如何接收这些请求。 -#### **概述** +### **Enhanced HTTP Standard Capabilities of Triple - Multi Content-Type Support** +> This article mainly introduces how Triple supports more standard HTTP Content-Types and how services should handle these requests. +#### **Overview** -Triple目前支持两种序列化方式:Json和protobuf,对应的ContentType: +Triple currently supports two serialization methods: Json and protobuf, corresponding to the ContentTypes: * application/json * application/grpc+proto -这在消费者和提供者都是后端服务时没有问题。但对于浏览器客户端,其可能发送更多类型的ContentType,需要服务端支持解码,如: +This poses no problem when both consumers and providers are backend services. However, for browser clients, they may send more types of ContentTypes that the server needs to support for decoding, such as: * multipart/formdata * text/plain * application/x-www-form-urlencoded * application/xml -Rest已基本实现上述解码能力,使Triple实现这些能力是让Triple服务端与浏览器客户端完全互通的重要一步。 +Rest has basically implemented the above decoding capabilities, making it an important step for Triple to achieve complete interoperability between Triple servers and browser clients. - - -#### **用法** +#### **Usage** ##### **multipart/formdata** @@ -59,7 +57,7 @@ Content-Type: image/jpeg --example-part-boundary-- ``` -接收: +Receiving: ```java @Override @@ -74,11 +72,9 @@ Content-Type: image/jpeg } ``` -* 每一个 part 根据其 Content-Type 解码 -* 若方法参数是 byte[] 或 Byte[],对应字段不会解码 -* 响应使用 application/json 编码 - - +* Each part is decoded based on its Content-Type. +* If the method parameter is byte[] or Byte[], the corresponding field will not be decoded. +* The response is encoded using application/json. ##### application/x-www-form-urlencoded @@ -91,7 +87,7 @@ Accept: application/json Hello=World&Apache=Dubbo&id=10086 ``` -两种接收方式: +Two receiving methods: ```java public ServerResponse greetUrlForm(String hello,String apache,long id){ @@ -111,11 +107,9 @@ Hello=World&Apache=Dubbo&id=10086 } ``` -* 若参数为Map,则解码为Map传入 -* 若参数均为String或数值类型,按照参数列表逐个解码传入 -* 响应使用 application/json 编码 - - +* If the parameter is a Map, it is decoded as Map. +* If the parameters are all String or numeric types, they are decoded one by one according to the parameter list. +* The response is encoded using application/json. ##### text/plain @@ -128,7 +122,7 @@ Accept: application/json World! ``` -接收: +Receiving: ```java public ServerResponse greetUrlForm(String world){ @@ -137,10 +131,8 @@ World! } ``` -* charset支持ASCII、UTF-8、UTF-16等,默认UTF-8 -* 响应使用 application/json 编码 - - +* Charset supports ASCII, UTF-8, UTF-16, etc., defaulting to UTF-8. +* The response is encoded using application/json. ##### application/xml @@ -157,7 +149,7 @@ Accept: application/xml ``` -接收: +Receiving: ```java @Override @@ -168,5 +160,6 @@ Accept: application/xml } ``` -* 该实现与Rest的XMLCodec相同 -* 响应使用 application/xml 编码 +* This implementation is the same as Rest's XMLCodec. +* The response is encoded using application/xml. + diff --git a/content/en/overview/reference/protocols/_index.md b/content/en/overview/reference/protocols/_index.md index f0eb66eff061..fd0043a722f6 100644 --- a/content/en/overview/reference/protocols/_index.md +++ b/content/en/overview/reference/protocols/_index.md @@ -1,7 +1,8 @@ --- -description: "Dubbo 内置协议设计思路与协议规范" -linkTitle: 协议规范 -title: 协议规范 +description: "Design concepts and protocol specifications of Dubbo's built-in protocols" +linkTitle: Protocol Specifications +title: Protocol Specifications type: docs weight: 4 --- + diff --git a/content/en/overview/reference/protocols/http.md b/content/en/overview/reference/protocols/http.md index 2c1c5b24b78d..d8a537831e0e 100644 --- a/content/en/overview/reference/protocols/http.md +++ b/content/en/overview/reference/protocols/http.md @@ -1,35 +1,31 @@ --- -description: "HTTP Json 协议规范" -linkTitle: HTTP 协议规范 -title: HTTP 协议规范 +description: "HTTP Json Protocol Specification" +linkTitle: HTTP Protocol Specification +title: HTTP Protocol Specification type: docs weight: 3 working_in_progress: true --- -{{% alert title="注意" color="warning" %}} -从 Dubbo 3.3 版本开始,Rest 协议已移至 Extensions 库,由 Triple 协议来对 Rest 提供更全面的支持,具体参见 [Triple Rest用户手册](../../../mannual/java-sdk/reference-manual/protocol/tripe-rest-manual/), -如需继续使用原 Rest 协议,可引入对应 [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) 库依赖 +{{% alert title="Note" color="warning" %}} +Starting from Dubbo version 3.3, the Rest protocol has been moved to the Extensions library, with the Triple protocol providing more comprehensive support for Rest. For details, refer to the [Triple Rest User Manual](../../../mannual/java-sdk/reference-manual/protocol/tripe-rest-manual/). If you wish to continue using the original Rest protocol, you can import the corresponding [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) library dependency. {{% /alert %}} -## 什么是 Dubbo Http -基于 spring web 和 resteasy 注解编码风格,通过http协议进行服务间调用互通,dubbo protocol扩展实现的协议 +## What is Dubbo Http +A protocol implemented through the Dubbo protocol extension, based on the coding style of Spring Web and Resteasy, enabling inter-service calls via the HTTP protocol. -## 为什么选择Dubbo Http -- dubbo http 可以实现微服务与dubbo之间的互通 -- 多协议发布服务,可以实现服务协议的平滑迁移 -- http的通用性,解决跨语言互通 -- 最新版本的http 无需添加其他组件,更轻量 -- resteasy以及spring web的编码风格,上手更快 +## Why Choose Dubbo Http +- Enables interoperability between microservices and Dubbo. +- Multi-protocol service publishing allows for smooth migration of service protocols. +- The universality of HTTP addresses cross-language interoperability. +- The latest version of HTTP does not require additional components, making it lighter. +- Resteasy and Spring Web coding styles allow for quicker onboarding. -## 协议规范 +## Protocol Specification - Request -相对于原生的http协议dubbo http 请求增加version和group两个header用于确定服务的唯一, -如果provider一端没有声明group和version,http请求时就不需要传递这连个header,反之必须要传递目标 -服务的group和version, 如果使用dubbo http的RestClient这两个header将会默认通过attachment传递 -为区别于其他的header,attachment将会增加rest-service-前缀,因此通过其他形式的http client调用 -dubbo http服务需要传递 rest-service-version 和 rest-service-group 两个header +Compared to the native HTTP protocol, the Dubbo Http request adds two headers, version and group, to determine the service's uniqueness. If the provider does not declare the group and version, these headers do not need to be passed during the HTTP request; otherwise, they must be passed. When using the Dubbo Http's RestClient, these headers will be passed by default via attachment with the prefix rest-service-. Therefore, other HTTP clients need to pass rest-service-version and rest-service-group headers. + ```` POST /test/path HTTP/1.1 Host: localhost:8080 @@ -39,9 +35,8 @@ rest-service-version: 1.0.0 rest-service-group: dubbo {"name":"dubbo","age":10,"address":"hangzhou"} - - ```` + - Response ```` HTTP/1.1 200 @@ -51,27 +46,24 @@ Date: Fri, 28 Apr 2023 14:16:42 GMT "success" ```` -- content-type支持 +- Supported content-types - application/json - application/x-www-form-urlencoded - text/plain - text/xml -目前支持以上media,后面还会对type进行扩展 +Currently, the above media types are supported, and further extensions will be made. -## 快速入门 -详细的依赖以及spring配置,可以参见dubbo 项目的dubbo-demo-xml模块 -https://github.com/apache/dubbo/tree/3.2/dubbo-demo/dubbo-demo-xml +## Quick Start +For detailed dependencies and Spring configurations, refer to the Dubbo project's dubbo-demo-xml module: https://github.com/apache/dubbo/tree/3.2/dubbo-demo/dubbo-demo-xml -- spring web 编码 -在使用dubbo http的spring web编码时,类注解我们要求必须出现@RequestMapping或者@Controller,以此来判断用户使用的编码风格,决定使用对应的SpringMvcServiceRestMetadataResolver -注解解析器进行元注解解析,Provider一侧我们允许用户使用实现类作为Dubbo Service(相比之前dubbo service export时service必须是接口的要求) +- Spring Web Coding +When using Dubbo Http with Spring Web coding, class annotations must include @RequestMapping or @Controller to determine the user's coding style, which decides which SpringMvcServiceRestMetadataResolver annotation parser should be used for meta-annotation parsing. On the provider side, users are allowed to use implementation classes as Dubbo Services, unlike the previous requirement that the service must be an interface. API ````java @RequestMapping("/spring/demo/service") public interface SpringRestDemoService { - @RequestMapping(method = RequestMethod.GET, value = "/hello") Integer hello(@RequestParam("a") Integer a, @RequestParam("b") Integer b); @@ -87,7 +79,6 @@ public interface SpringRestDemoService { @RequestMapping(method = RequestMethod.POST, value = "/testJavaBeanBody", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) User testJavaBeanBody(@RequestBody User user); - @RequestMapping(method = RequestMethod.GET, value = "/primitive") int primitiveInt(@RequestParam("a") int a, @RequestParam("b") int b); @@ -97,11 +88,9 @@ public interface SpringRestDemoService { @RequestMapping(method = RequestMethod.GET, value = "/primitiveByte") long primitiveByte(@RequestParam("a") byte a, @RequestParam("b") Long b); - @RequestMapping(method = RequestMethod.POST, value = "/primitiveShort") long primitiveShort(@RequestParam("a") short a, @RequestParam("b") Long b, @RequestBody int c); - @RequestMapping(method = RequestMethod.GET, value = "/testMapParam") String testMapParam(@RequestParam Map params); @@ -111,92 +100,82 @@ public interface SpringRestDemoService { @RequestMapping(method = RequestMethod.POST, value = "/testMapForm", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) List testMapForm(MultiValueMap params); - @RequestMapping(method = RequestMethod.GET, value = "/headerInt") int headerInt(@RequestHeader("header") int header); - - } ```` Provider - ````java - @DubboService(interfaceClass = SpringRestDemoService.class ,protocol = "rest") +@DubboService(interfaceClass = SpringRestDemoService.class ,protocol = "rest") public class SpringRestDemoServiceImpl implements SpringRestDemoService { + @Override + public String sayHello(String name) { + return "Hello, " + name; + } - @Override - public String sayHello(String name) { - return "Hello, " + name; - } - - @Override - public Long testFormBody(Long number) { - return number; - } - - @Override - public User testJavaBeanBody(User user) { - return user; - } - - - @Override - public int primitiveInt(int a, int b) { - return a + b; - } - - @Override - public long primitiveLong(long a, Long b) { - return a + b; - } - - @Override - public long primitiveByte(byte a, Long b) { - return a + b; - } - - @Override - public long primitiveShort(short a, Long b, int c) { - return a + b; - } + @Override + public Long testFormBody(Long number) { + return number; + } + @Override + public User testJavaBeanBody(User user) { + return user; + } - @Override - public String testMapParam(Map params) { - return params.get("param"); - } + @Override + public int primitiveInt(int a, int b) { + return a + b; + } - @Override - public String testMapHeader(Map headers) { - return headers.get("header"); - } + @Override + public long primitiveLong(long a, Long b) { + return a + b; + } - @Override - public List testMapForm(MultiValueMap params) { - return params.get("form"); - } + @Override + public long primitiveByte(byte a, Long b) { + return a + b; + } + @Override + public long primitiveShort(short a, Long b, int c) { + return a + b; + } - @Override - public int headerInt(int header) { - return header; - } + @Override + public String testMapParam(Map params) { + return params.get("param"); + } + @Override + public String testMapHeader(Map headers) { + return headers.get("header"); + } - @Override - public Integer hello(Integer a, Integer b) { - return a + b; - } + @Override + public List testMapForm(MultiValueMap params) { + return params.get("form"); + } + @Override + public int headerInt(int header) { + return header; + } - @Override - public String error() { - throw new RuntimeException("test error"); - } + @Override + public Integer hello(Integer a, Integer b) { + return a + b; + } + @Override + public String error() { + throw new RuntimeException("test error"); + } } ```` + Consumer ````java @Component @@ -235,15 +214,11 @@ public class SpringRestDemoServiceConsumer { throw new RuntimeException(); } } - - } - ```` -- JaxRs 编码 - JaxRs注解使用的时候我们要求service 类上必须使用@Path注解,来确定使用JAXRSServiceRestMetadataResolver - 注解解析器来解析注解元信息 +- JaxRs Coding +When using JaxRs annotations, it's required that the service class must have the @Path annotation to determine the use of JAXRSServiceRestMetadataResolver for annotation parsing. API ````java @@ -261,10 +236,6 @@ public interface JaxRsRestDemoService { @Path("/say") String sayHello(String name); - - - - @POST @Path("/testFormBody") Long testFormBody(@FormParam("number") Long number); @@ -274,8 +245,6 @@ public interface JaxRsRestDemoService { @Consumes({MediaType.APPLICATION_JSON}) User testJavaBeanBody(User user); - - @GET @Path("/primitive") int primitiveInt(@QueryParam("a") int a, @QueryParam("b") int b); @@ -319,8 +288,6 @@ public interface JaxRsRestDemoService { @Path("/headerInt") @Consumes({MediaType.TEXT_PLAIN}) int headerInt(@HeaderParam("header") int header); - - } ```` @@ -328,7 +295,6 @@ Provider ````java @DubboService(interfaceClass =JaxRsRestDemoService.class ,protocol = "rest",version = "1.0.0",group = "test") public class JaxRsRestDemoServiceImpl implements JaxRsRestDemoService { - @Override public String sayHello(String name) { return "Hello, " + name; @@ -344,7 +310,6 @@ public class JaxRsRestDemoServiceImpl implements JaxRsRestDemoService { return user; } - @Override public int primitiveInt(int a, int b) { return a + b; @@ -365,8 +330,6 @@ public class JaxRsRestDemoServiceImpl implements JaxRsRestDemoService { return a + b; } - - @Override public String testMapParam(Map params) { return params.get("param"); @@ -392,20 +355,18 @@ public class JaxRsRestDemoServiceImpl implements JaxRsRestDemoService { return header; } - @Override public Integer hello(Integer a, Integer b) { return a + b; } - @Override public String error() { throw new RuntimeException("test error"); } - } ```` + Consumer ````java @Component @@ -435,15 +396,12 @@ public class JaxRsRestDemoService { assertEquals(Arrays.asList("F1"), jaxRsRestDemoService.testMapForm(forms)); assertEquals(User.getInstance(), jaxRsRestDemoService.testJavaBeanBody(User.getInstance())); } - } ```` + +## Use Cases - -## 使用场景 - - 因为dubbo http consumer一端实现http 调用的RestClient 实现有三种形式:httpclient,okhttp,URLConnection(jdk内置) - 默认请情况下采用okhttp,因此在使用dubbo http 去调用其他http服务时,需要添加引入的依赖有 +As the Dubbo Http consumer implements the RestClient in three forms: httpclient, okhttp, URLConnection (jdk built-in), okhttp is the default option. When using Dubbo Http to call other HTTP services, the required dependencies to include are: ````xml @@ -457,7 +415,7 @@ public class JaxRsRestDemoService { mockwebserver ${okhttp_version} - 或 + or org.apache.httpcomponents httpclient @@ -465,7 +423,7 @@ public class JaxRsRestDemoService { ```` -- 微服务服务调用dubbo http +- Microservices invoking Dubbo Http ````java @@ -484,7 +442,7 @@ public class JaxRsRestDemoService { } ```` -- 跨语言调用 +- Cross-language invocation python ```` @@ -522,30 +480,26 @@ public class JaxRsRestDemoService { } defer resp.Body.Close() +```` - -- 多协议发布 - - dubbo 协议的代码使用http 进行数据请求测试 - - 服务协议迁移 +- Multi-protocol publishing + - Testing code requests using HTTP for the Dubbo protocol + - Service protocol migration ````java @DubboService(interfaceClass = HttpService.class, protocol = "rest,dubbo", version = "1.0.0", group = "test") public class HttpServiceImpl implements HttpService { - - @Override public String http(String invokeType) { - return "Rest http request test success! by invokeType: " + invokeType; + return "Rest http request test success! by invokeType: " + invokeType; } } ```` - - http client组件调用dubbo http(可以不引入 service api) + - HTTP client component invoking Dubbo Http (service API can be excluded) ````java public class HttpClientInvoke { - - private final String versionHeader = RestHeaderEnum.VERSION.getHeader(); private final String groupHeader = RestHeaderEnum.GROUP.getHeader(); /** @@ -553,7 +507,6 @@ public class HttpClientInvoke { */ private final String url = "http://localhost:8888/services/http"; - public void httpServiceHttpClientInvoke() throws IOException { CloseableHttpClient httpClient = createHttpClient(); HttpRequestBase httpUriRequest = new HttpGet(url); @@ -606,7 +559,6 @@ public class HttpClientInvoke { }; } - private CloseableHttpClient createHttpClient() { PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); return HttpClients.custom().setConnectionManager(connectionManager).build(); @@ -614,12 +566,12 @@ public class HttpClientInvoke { } ```` -## 3.2 与 3.0 HTTP 实现对比 +## Comparison of HTTP Implementations between 3.2 and 3.0 -因为 Dubbo Java 3.2 内部移除了原本 Resteasy 的实现,因此在对 Resteasy 内置的 Response,extend,ExceptionMapper 支持上将会有所变化 -ExceptionMapper 转换成了org.apache.dubbo.rpc.protocol.rest.exception.mapper.ExceptionHandler,Response后面也会做适配处理 +Due to the removal of the original Resteasy implementation in Dubbo Java 3.2, there will be changes in support for Resteasy's built-in Response, extend, and ExceptionMapper. ExceptionMapper has been transformed into org.apache.dubbo.rpc.protocol.rest.exception.mapper.ExceptionHandler, and Response will undergo adaptations later. -| 版本 | JaxRs| j2ee | web容器(tomcat/jetty)|spring web| http client\(okhttp/httpclient/jdk URLConnnection ) +| Version | JaxRs| j2ee | Web container (tomcat/jetty)| Spring Web| HTTP client (okhttp/httpclient/jdk URLConnection) | | ---- | ---- |--- |--- |--- |---| -| 3.0 | 依赖与resteasy的client和server |遵循j2ee规范|依赖常见web容器|不依赖|不依赖 -| 3.2 | 不依赖(仅需要JaxRs注解包) |不遵循|netty实现的http服务器|仅依赖spring web注解|内部实现RestClient依赖http client(默认为okhttp) +| 3.0 | Depends on Resteasy Client and Server | Follows j2ee specifications| Relies on common web containers| No dependence| No dependence| +| 3.2 | No dependence (only requires JaxRs annotation package) | Not followed| HTTP server implemented with Netty| Only depends on Spring Web annotations| Internal implementation of RestClient relies on HTTP client (default is okhttp)| + diff --git a/content/en/overview/reference/protocols/tcp.md b/content/en/overview/reference/protocols/tcp.md index 8a19320ac51f..1246c62c287b 100644 --- a/content/en/overview/reference/protocols/tcp.md +++ b/content/en/overview/reference/protocols/tcp.md @@ -1,38 +1,38 @@ --- -description: "TCP (Dubbo2) 协议规范" -linkTitle: Dubbo2 协议规范 -title: Dubbo2 协议规范 +description: "TCP (Dubbo2) Protocol Specification" +linkTitle: Dubbo2 Protocol Specification +title: Dubbo2 Protocol Specification type: docs weight: 2 --- ![/dev-guide/images/dubbo_protocol_header.jpg](/imgs/dev/dubbo_protocol_header.png) -## 协议规范 Specification +## Protocol Specification - Magic - Magic High & Magic Low (16 bits) - 标识协议版本号,Dubbo 协议:0xdabb + Identifies the protocol version number, Dubbo Protocol: 0xdabb - Req/Res (1 bit) - 标识是请求或响应。请求: 1; 响应: 0。 + Indicates whether it is a request or response. Request: 1; Response: 0. - 2 Way (1 bit) - 仅在 Req/Res 为1(请求)时才有用,标记是否期望从服务器返回值。如果需要来自服务器的返回值,则设置为1。 + Only useful when Req/Res is 1 (request), marks whether a return value is expected from the server. Set to 1 if a return value from the server is needed. - Event (1 bit) - 标识是否是事件消息,例如,心跳事件。如果这是一个事件,则设置为1。 + Indicates whether it is an event message, such as a heartbeat event. Set to 1 if this is an event. - Serialization ID (5 bit) - 标识序列化类型:比如 fastjson 的值为6。 + Identifies the serialization type: for example, the value for fastjson is 6. - Status (8 bits) - 仅在 Req/Res 为0(响应)时有用,用于标识响应的状态。 + Only useful when Req/Res is 0 (response), used to identify the response status. - 20 - OK - 30 - CLIENT_TIMEOUT @@ -47,17 +47,17 @@ weight: 2 - Request ID (64 bits) - 标识唯一请求。类型为long。 + Identifies a unique request. Type is long. - Data Length (32 bits) - 序列化后的内容长度(可变部分),按字节计数。int类型。 + Length of the serialized content (variable part), counted in bytes. Type is int. - Variable Part - 被特定的序列化类型(由序列化 ID 标识)序列化后,每个部分都是一个 byte [] 或者 byte + Each part serialized by a specific serialization type (identified by Serialization ID) is a byte[] or byte. - - 如果是请求包 ( Req/Res = 1),则每个部分依次为: + - If it is a request package (Req/Res = 1), each part is in order: - Dubbo version - Service name - Service version @@ -65,36 +65,35 @@ weight: 2 - Method parameter types - Method arguments - Attachments - - 如果是响应包(Req/Res = 0),则每个部分依次为: - - 返回值类型(byte),标识从服务器端返回的值类型: - - 返回空值:RESPONSE_NULL_VALUE 2 - - 正常响应值: RESPONSE_VALUE 1 - - 异常:RESPONSE_WITH_EXCEPTION 0 - - 返回值:从服务端返回的响应bytes + - If it is a response package (Req/Res = 0), each part is in order: + - Return value type (byte), identifying the type of value returned from the server: + - Return null: RESPONSE_NULL_VALUE 2 + - Normal response value: RESPONSE_VALUE 1 + - Exception: RESPONSE_WITH_EXCEPTION 0 + - Return value: response bytes returned from the server. -**注意:** 对于(Variable Part)变长部分,当前版本的Dubbo 框架使用json序列化时,在每部分内容间额外增加了换行符作为分隔,请在Variable Part的每个part后额外增加换行符, 如: +**Note:** For the (Variable Part), the current version of the Dubbo framework adds additional newline characters as separators between each content part when using JSON serialization, please add an extra newline after each part of the Variable Part, for example: ``` -Dubbo version bytes (换行符) -Service name bytes (换行符) +Dubbo version bytes (newline) +Service name bytes (newline) ... ``` -## 协议特点分析 +## Protocol Characteristics Analysis -### 优点 +### Advantages -- 协议设计上很紧凑,能用 1 个 bit 表示的,不会用一个 byte 来表示,比如 boolean 类型的标识。 -- 请求、响应的 header 一致,通过序列化器对 content 组装特定的内容,代码实现起来简单。 +- The protocol is compactly designed; if it can be represented by 1 bit, it will not use a byte, for example, identifiers of boolean types. +- The headers for requests and responses are consistent, making it simple to implement with specific content assembled by the serializer. -### 可以改进的点 +### Points for Improvement -- 对于网关代理类组件不友好。http 请求而言,通过 header 就可以确定要访问的资源,而 Dubbo 需要涉及到用特定序列化协议才可以将服务名、方法、方法签名解析出来,并且这些资源定位符是 string 类型或者 string 数组,很容易转成 bytes,因此可以组装到 header 中。类似于 http2 的 header 压缩,对于 rpc 调用的资源也可以协商出来一个int来标识,从而提升性能,如果在`header`上组装资源定位符的话,该功能则更易实现。 +- Unfriendly for gateway proxy components. For HTTP requests, the resource to be accessed can be determined through headers, while Dubbo requires specific serialization protocols to resolve service names, methods, and method signatures. These locators are string types or string arrays, easily convertible to bytes and could be assembled into headers. Similar to HTTP/2 header compression, an int could be negotiated to identify RPC call resources, improving performance; if resource locators were assembled in the `header`, this functionality would be easier to implement. -- 通过 req/res 是否是请求后,可以精细定制协议,去掉一些不需要的标识和添加一些特定的标识。比如`status`,`twoWay`标识可以严格定制,去掉冗余标识。还有超时时间是作为 Dubbo 的 `attachment` 进行传输的,理论上应该放到请求协议的header中,因为超时是网络请求中必不可少的。提到 `attachment` ,通过实现可以看到 `attachment` 中有一些是跟协议 `content`中已有的字段是重复的,比如 `path`和`version`等字段,这些会增大协议尺寸。 +- Using req/res to determine if it is a request, the protocol can be fine-tuned, removing unnecessary identifiers and adding specific identifiers. For instance, `status` and `twoWay` identifiers can be strictly customized, removing redundant identifiers. Additionally, timeout is transmitted as a Dubbo `attachment`, theoretically it should be placed in the request protocol's header since timeout is essential in network requests. Noting `attachment`, it can be seen that some fields in `attachment` duplicate existing fields in the protocol `content`, such as `path` and `version`, which increases protocol size. -- Dubbo 会将服务名`com.alibaba.middleware.hsf.guide.api.param.ModifyOrderPriceParam`,转换为`Lcom/alibaba/middleware/hsf/guide/api/param/ModifyOrderPriceParam;`,理论上是不必要的,最后追加一个`;`即可。 - -- Dubbo 协议没有预留扩展字段,没法新增标识,扩展性不太好,比如新增`响应上下文`的功能,只有改协议版本号的方式,但是这样要求客户端和服务端的版本都进行升级,对于分布式场景很不友好。 +- Dubbo converts the service name `com.alibaba.middleware.hsf.guide.api.param.ModifyOrderPriceParam` to `Lcom/alibaba/middleware/hsf/guide/api/param/ModifyOrderPriceParam;`, which is unnecessary, adding only a `;` would suffice. +- The Dubbo protocol does not reserve extension fields, making it difficult to add new identifiers, thus affecting extensibility. For example, adding `response context` functionality can only be done by updating the protocol version number, which requires both the client and server versions to be upgraded, making it unfriendly for distributed scenarios. diff --git a/content/en/overview/reference/protocols/triple.md b/content/en/overview/reference/protocols/triple.md index 41177421832d..f3a9cd4109ad 100644 --- a/content/en/overview/reference/protocols/triple.md +++ b/content/en/overview/reference/protocols/triple.md @@ -1,64 +1,64 @@ --- -description: "Triple 协议优势与目标:Triple 协议是 Dubbo3 设计的基于 HTTP 的 RPC 通信协议规范,它完全兼容 gRPC 协议并可同时运行在 HTTP/1 和 HTTP/2 之上。" -linkTitle: Triple 协议优势与目标 -title: Triple 协议优势与目标 +description: "Advantages and Goals of the Triple Protocol: The Triple protocol is an HTTP-based RPC communication protocol specification designed for Dubbo3, which is fully compatible with the gRPC protocol and can run simultaneously over HTTP/1 and HTTP/2." +linkTitle: Advantages and Goals of the Triple Protocol +title: Advantages and Goals of the Triple Protocol type: docs weight: 1 working_in_progress: true --- -## 简介 -Triple 协议是 Dubbo3 设计的基于 HTTP 的 RPC 通信协议规范,它完全兼容 gRPC 协议,支持 Request-Response、Streaming 流式等通信模型,可同时运行在 HTTP/1 和 HTTP/2 之上。 +## Introduction +The Triple protocol is an HTTP-based RPC communication protocol specification designed for Dubbo3, fully compatible with the gRPC protocol, supporting communication models like Request-Response and Streaming, and can run on both HTTP/1 and HTTP/2. -Dubbo 框架提供了 Triple 协议的多种语言实现,它们可以帮助你构建浏览器、gRPC 兼容的 HTTP API 接口:你只需要定义一个标准的 Protocol Buffer 格式的服务并实现业务逻辑,Dubbo 负责帮助生成语言相关的 Server Stub、Client Stub,并将整个调用流程无缝接入如路由、服务发现等 Dubbo 体系。Go、Java 等语言的 Triple 协议实现原生支持 HTTP/1 传输层通信,相比于 gRPC 官方实现,Dubbo 框架提供的协议实现更简单、更稳定,帮助你更容易的开发和治理微服务应用。 +The Dubbo framework provides various language implementations of the Triple protocol, helping you build browser- and gRPC-compatible HTTP API interfaces: you only need to define a standard Protocol Buffer format service and implement business logic. Dubbo takes care of generating language-related Server Stub, Client Stub, and seamlessly integrates the entire invocation process with routing, service discovery, and other Dubbo systems. The Triple protocol implementations in languages like Go and Java natively support HTTP/1 transport layer communication. Compared to the official gRPC implementation, Dubbo's protocol implementation is simpler and more stable, making it easier for you to develop and manage microservice applications. -针对某些语言版本,Dubbo 框架还提供了更贴合语言特性的编程模式,即不绑定 IDL 的服务定义与开发模式,比如在 Dubbo Java 中,你可以选择使用 Java Interface 和 Pojo 类定义 Dubbo 服务,并将其发布为基于 Triple 协议通信的微服务。 +For certain language versions, the Dubbo framework also provides programming modes that are more aligned with language features, such as service definition and development modes that do not bind to IDL. For example, in Dubbo Java, you can choose to define Dubbo services using Java Interfaces and Pojo classes and publish them as microservices based on Triple protocol communication. -## 协议规范(Specification) -基于 Triple 协议,你可以实现以下目标: +## Protocol Specification +With the Triple protocol, you can achieve the following goals: -### 当 Dubbo 作为 Client 时 -Dubbo Client 可以访问 Dubbo 服务端 (Server) 发布的 Triple 协议服务,同时还可以访问标准的 gRPC 服务端。 -* 调用标准 gRPC 服务端,发送 Content-type 为标准 gRPC 类型的请求:application/grpc, application/grpc+proto, and application/grpc+json -* 调用 Dubbo 服务端,发送 Content-type 为 Triple 类型的请求:application/json, application/proto, application/triple+wrapper +### When Dubbo is Used as a Client +The Dubbo Client can access Triple protocol services published by the Dubbo server and standard gRPC servers. +* Call standard gRPC servers and send requests with Content-type as standard gRPC types: application/grpc, application/grpc+proto, and application/grpc+json. +* Call Dubbo servers and send requests with Content-type as Triple types: application/json, application/proto, application/triple+wrapper. -### 当 Dubbo 作为 Server 时 -Dubbo Server 默认将同时发布对 Triple、gRPC 协议的支持,并且 Triple 协议可以同时工作在 HTTP/1、HTTP/2 之上。因此,Dubbo Server 可以处理 Dubbo 客户端发过来的 Triple 协议请求,可以处理标准的 gRPC 协议请求,还能处理 cURL、浏览器发送过来的 HTTP 请求。以 Content-type 区分就是: -* 处理 gRPC 客户端发送的 Content-type 为标准 gRPC 类型的请求:application/grpc、application/grpc+proto、application/grpc+json -* 处理 Dubbo 客户端发送的 Content-type 为 Triple 类型的请求:application/json、application/proto、application/grpc+wrapper -* 处理 cURL、浏览器等发送的 Content-type 为 Triple 类型的请求:application/json、application/proto、application/grpc+wrapper +### When Dubbo is Used as a Server +The Dubbo Server by default publishes support for both Triple and gRPC protocols simultaneously, and the Triple protocol can work over HTTP/1 and HTTP/2. Therefore, Dubbo Server can handle Triple protocol requests from Dubbo clients, standard gRPC protocol requests, as well as HTTP requests sent by cURL and browsers. The distinction based on Content-type is: +* Handling requests sent by gRPC clients with Content-type as standard gRPC types: application/grpc, application/grpc+proto, application/grpc+json. +* Handling requests sent by Dubbo clients with Content-type as Triple types: application/json, application/proto, application/grpc+wrapper. +* Handling requests sent by cURL, browsers, etc., with Content-type as Triple types: application/json, application/proto, application/grpc+wrapper. -详细在此查看详细的 [Triple Specification](../triple-spec)。 +For details, refer to the detailed [Triple Specification](../triple-spec). -## 与 gRPC 协议的关系 -上面提到 Triple 完全兼容 gRPC 协议,那既然 gRPC 官方已经提供了多语言的框架实现,为什么 Dubbo 还要通过 Triple 重新实现一遍呢?核心目标主要有以下两点: +## Relationship with the gRPC Protocol +As mentioned above, Triple is fully compatible with the gRPC protocol. Given that gRPC has already provided multi-language framework implementations, why does Dubbo need to reimplement it through Triple? The core goals primarily include two points: -* 首先,在协议设计上,Dubbo 参考 gRPC 与 gRPC-Web 两个协议设计了自定义的 Triple 协议:Triple 是一个基于 HTTP 传输层协议的 RPC 协议,它完全兼容 gRPC 的同时可运行在 HTTP/1、HTTP/2 之上。 -* 其次,Dubbo 框架在每个语言的实现过程中遵循了符合框架自身定位的设计理念,相比于 grpc-java、grpc-go 等框架库,Dubbo 协议实现更简单、更纯粹,尝试在实现上规避 gRPC 官方库中存在的一系列问题。 +* First, in protocol design, Dubbo refers to both gRPC and gRPC-Web to design the custom Triple protocol: Triple is an RPC protocol based on HTTP transport layer that is fully compatible with gRPC while running on HTTP/1 and HTTP/2. +* Second, the Dubbo framework follows a design philosophy that aligns with its framework positioning during the implementation for each language, making the Dubbo protocol implementation simpler and purer compared to frameworks like grpc-java and grpc-go, attempting to avoid a series of issues present in the official gRPC library. -gRPC 本身作为 RPC 协议规范非常优秀,但我们发现原生的 gRPC 库实现在实际使用存在一系列问题,包括实现复杂、绑定 IDL、难以调试等,Dubbo 在协议设计与实现上从实践出发,很好的规避了这些问题: +gRPC itself as an RPC protocol specification is excellent, but we found that the native gRPC library implementation has several issues in practical use, including complexity, IDL binding, and debugging difficulties. Dubbo, starting from practical implementation, effectively avoids these problems: -* 原生的 gRPC 实现受限于 HTTP/2 交互规范,无法为浏览器、HTTP API 提供交互方式,你需要额外的代理组件如 grpc-web、grpc-gateway 等才能实现。在 Dubbo 中,你可以直接用 curl、浏览器访问 Dubbo HTTP/2 服务. -* gRPC 官方库强制绑定 Proto Buffer,唯一的开发选择就是使用 IDL 定义和管理服务,这对于一些多语言诉求不强的用户是一个非常大的使用负担。Dubbo 则在支持 IDL 的同时,为 Java、Go 等提供了语言特有的服务定义与开发方式。 -* 在开发阶段,以 gRPC 协议发布的服务非常难以调试,你只能使用 gRPC 特定的工具来进行,很多工具都比较简陋 & 不成熟。而从 Dubbo3 开始,你可以直接使用 curl | jq 或者 Chrome 开发者工具来调试你的服务,直接传入 JSON 结构体就能调用服务。 -* 首先,gRPC 协议库有超过 10 万行代码的规模,但 Dubbo (Go、Java、Rust、Node.js 等) 关于协议实现部分仅有几千行代码,这让代码维护和问题排查变得更简单。 -* 谷歌提供的 gRPC 实现库没有使用主流的第三方或语言官方协议库,而是选择自己维护了一套实现,让整个维护与生态扩展变得更加复杂。比如 grpc-go 自己维护了一套 HTTP/2 库而不是使用的 go 官方库。Dubbo 使用了官方库的同时,相比 gRPC 自行维护的 http 协议库维持了同一性能水准。 -* gRPC 库仅仅提供了 RPC 协议实现,需要你做很多额外工作为其引入服务治理能力。而 Dubbo 本身是不绑定协议的微服务开发框架,内置 HTTP/2 协议实现可以与 Dubbo 服务治理能力更好的衔接在一起。 +* The native gRPC implementation is limited by HTTP/2 interaction standards, making it unable to provide interaction methods for browsers and HTTP APIs, requiring additional proxy components like grpc-web and grpc-gateway for functionality. In Dubbo, you can directly access Dubbo HTTP/2 services using cURL and browsers. +* The official gRPC library enforces Proto Buffer binding, with the only development choice being to define and manage services using IDL, which is a significant burden for users with limited multi-language demands. Dubbo, while supporting IDL, also offers language-specific service definitions and development methods for Java, Go, etc. +* During the development phase, services published with the gRPC protocol are challenging to debug, requiring the use of gRPC-specific tools, many of which are rudimentary and immature. With Dubbo3, you can debug your services using cURL | jq or Chrome Developer Tools directly, simply passing in JSON structures to invoke services. +* The gRPC protocol library has over 100,000 lines of code, while the Dubbo (Go, Java, Rust, Node.js, etc.) protocol implementation only has a few thousand lines of code, simplifying code maintenance and troubleshooting. +* The gRPC implementation library provided by Google does not use mainstream third-party or language-official protocol libraries but chooses to maintain its own implementation, complicating maintenance and ecosystem expansion. For instance, grpc-go maintains its own HTTP/2 library instead of using Go's official library. Dubbo, while using official libraries, maintains a performance level comparable to gRPC's self-maintained HTTP protocol library. +* The gRPC library only provides RPC protocol implementations and requires additional work to introduce service governance capabilities, whereas Dubbo is a microservices development framework that is not bound to protocols, with built-in HTTP/2 protocol implementations that integrate better with Dubbo's service governance capabilities. -### 实现简单 -Dubbo 框架实现专注在 Triple 协议自身,而对于底层的网络通信、HTTP/2 协议解析等选择依赖那些经过长期检验的网络库。比如 Dubbo Java 基于 Netty 构建,而 Dubbo Go 则是直接使用的 Go 官方 HTTP 库。 +### Simple Implementation +The Dubbo framework focuses on the Triple protocol itself while relying on well-tested network libraries for underlying network communication, HTTP/2 protocol parsing, etc. For example, Dubbo Java is built on Netty, while Dubbo Go directly uses Go's official HTTP library. -Dubbo 提供的 Triple 协议实现非常简单,对应 Dubbo 中的 Protocol 组件实现,你可以仅仅花一下午时间就搞清楚 Dubbo 协议的代码实现。 +The Triple protocol implementation provided by Dubbo is very simple, corresponding to the Protocol component implementation in Dubbo, and you can grasp Dubbo protocol code implementation in just one afternoon. -### 大规模生产环境检验 -自 Dubbo3 发布以来,Triple 协议已被广泛应用于阿里巴巴以及众多社区标杆企业,尤其是一些代理、网关互通场景。一方面 Triple 通过大规模生产实践被证实可靠稳定,另一方面 Triple 的简单、易于调试、不绑定 IDL 的设计也是其得到广泛应用的重要因素。 +### Large-Scale Production Environment Verification +Since the release of Dubbo3, the Triple protocol has been widely used in Alibaba and many community benchmark enterprises, especially in scenarios involving proxy and gateway interoperability. On one hand, Triple has been proven reliable and stable through large-scale production practice; on the other hand, the simplicity, ease of debugging, and non-IDL binding design of Triple are also important factors for its widespread adoption. -### 原生多协议支持 -当以 Dubbo 框架为服务端对外发布服务时,可以做到在同一端口原生支持 Triple、gRPC 和 HTTP/1 协议,这意味着你可以用多种形式访问 Dubbo 服务端发布的服务,所有请求形式最终都会被转发到相同的业务逻辑实现,这给你提供了更大的灵活性。 +### Native Multi-Protocol Support +When launching services externally using the Dubbo framework as a server, it can natively support Triple, gRPC, and HTTP/1 protocols on the same port. This means you can access the services published by Dubbo server in various forms, with all request forms ultimately being forwarded to the same business logic implementation, providing greater flexibility. -Dubbo 完全兼容 gRPC 协议及相关特性包括 streaming、trailers、error details 等,你选择直接在 Dubbo 框架中使用 Triple 协议(另外,你也可以选择使用原生的 gRPC 协议),然后你就可以直接使用 Dubbo 客户端、curl、浏览器等访问你发布的服务。在与 gRPC 生态互操作性方面,任何标准的 gRPC 客户端,都可以正常访问 Dubbo 服务;Dubbo 客户端也可以调用任何标准的 gRPC 服务,这里有提供的 [互操作性示例](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/interop) +Dubbo is fully compatible with gRPC protocols and related features, including streaming, trailers, and error details. You can choose to directly use the Triple protocol in the Dubbo framework (or you can opt to use the native gRPC protocol), and then directly access your published services with the Dubbo client, cURL, browsers, etc. In terms of interoperability with the gRPC ecosystem, any standard gRPC client can normally access Dubbo services; Dubbo clients can also call any standard gRPC services. Here is a provided [interoperability example](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/interop). -以下是使用 cURL 客户端访问 Dubbo 服务端 Triple 协议服务的示例: +Here is an example of using cURL client to access Dubbo server Triple protocol service: ```sh curl \ @@ -67,20 +67,19 @@ curl \ https://host:port/org.apache.dubbo.sample.GreetService/sayHello ``` -### 一站式服务治理接入 -我们都知道 Dubbo 有丰富的微服务治理能力,比如服务发现、负载均衡、流量管控等,这也是我们使用 Dubbo 框架开发应用的优势所在。要想在 Dubbo 体系下使用 gRPC 协议通信,有两种方式可以实现,一种是直接在 Dubbo 框架中引入 gRPC 官方发布的二进制包,另一种是在 Dubbo 内原生提供 gRPC 协议兼容的源码实现。 +### One-Stop Service Governance Integration +We all know that Dubbo has rich microservices governance capabilities, such as service discovery, load balancing, traffic control, etc. This is also one of the advantages of developing applications using the Dubbo framework. To use gRPC protocol communication in the Dubbo system, there are two ways to achieve it: one is to directly introduce the gRPC official published binary package into the Dubbo framework, and the other is to provide a natively compatible source implementation of the gRPC protocol within Dubbo. -相比于第一种引入二进制依赖的方式,Dubbo 框架通过内置 Triple 协议实现的方式,原生支持了 gRPC 协议,这种方式的优势在于源码完全由自己掌控,因此协议的实现与 Dubbo 框架结合更为紧密,能够更灵活的接入 Dubbo 的服务治理体系。 +Compared to the first method of introducing binary dependencies, the Dubbo framework natively supports the gRPC protocol through built-in Triple protocol implementation. The advantage of this approach is that the source code is entirely under your control, allowing for a closer integration of the protocol implementation with the Dubbo framework, enabling more flexible access to Dubbo's service governance system. -### Java 语言 -在 Dubbo Java 库实现中,除了 IDL 方式外,你可以使用 Java Interface 方式定义服务,这对于众多熟悉 Dubbo 体系的 Java 用户来说,可以大大降低使用 gRPC 协议的成本。 +### Java Language +In the Dubbo Java library implementation, you can define services using Java Interfaces in addition to IDL approaches, which can significantly reduce the cost of using the gRPC protocol for many Java users familiar with the Dubbo system. -另外,Java 版本的协议实现在性能上与 grpc-java 库基本持平,甚至某些场景下比 grpc-java 性能表现还要出色。而这一切还是建立在 Dubbo 版本协议的实现复杂度远小于 gRPC 版本的情况下,因为 grpc-java 维护了一套定制版本的 netty 协议实现。 +Additionally, the protocol implementation in the Java version performs on par with the grpc-java library in performance, with even better performance in certain scenarios. All of this is built upon the fact that the implementation complexity of the Dubbo version protocol is much lower than that of the gRPC version, as grpc-java maintains a customized version of the netty protocol implementation. -### Go 语言实现 -Dubbo Go 推荐 IDL 开发模式,通过 Dubbo 配套的 protoc 插件生成 stub 代码,你只需要提供对应的业务逻辑实现即可,你可以通过 curl、浏览器访问 Dubbo Go 发布的 gRPC 服务。 - -## 后续规划 -当前我们已经提供了 Triple 协议的 Java、Go 语言版本,接下来我们计划陆续提供 Rust、Python、Node.js 等语言的对应实现。 +### Go Language Implementation +Dubbo Go recommends the IDL development model, generating stub code through Dubbo's accompanying protoc plugin. You only need to provide the corresponding business logic implementation, and you can access the gRPC services published by Dubbo Go through cURL and browsers. +## Future Plans +Currently, we have provided Java and Go versions of the Triple protocol, and we plan to successively provide corresponding implementations in Rust, Python, Node.js, and other languages. From 1615ab40574e8610b6b6efa75fe2d0a4b6ba9077 Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Mon, 30 Sep 2024 15:01:23 +0800 Subject: [PATCH 08/23] Translate --- .../overview/reference/proposals/metrics.md | 147 +++++++++--------- .../reference/protocols/triple-spec.md | 134 ++++++++-------- 2 files changed, 141 insertions(+), 140 deletions(-) diff --git a/content/en/overview/reference/proposals/metrics.md b/content/en/overview/reference/proposals/metrics.md index abe2a53d89fb..6cc9122d7779 100644 --- a/content/en/overview/reference/proposals/metrics.md +++ b/content/en/overview/reference/proposals/metrics.md @@ -3,36 +3,36 @@ aliases: - /en/overview/reference/proposals/metrics/ author: Song Xiaosheng date: 2023-02-20T00:00:00Z -description: 指标埋点 -linkTitle: 指标埋点 -title: 指标埋点 +description: Metrics tracking +linkTitle: Metrics tracking +title: Metrics tracking type: docs weight: 4 --- -# 概述 +# Overview -## 1. 指标接入说明 +## 1. Metrics Access Instructions -## 2. 指标体系设计 +## 2. Metrics System Design -Dubbo的指标体系,总共涉及三块,指标收集、本地聚合、指标推送 -* 指标收集:将Dubbo内部需要监控的指标推送至统一的Collector中进行存储 -* 本地聚合:指标收集获取的均为基础指标,而一些分位数指标则需通过本地聚合计算得出 -* 指标推送:收集和聚合后的指标通过一定的方式推送至第三方服务器,目前只涉及Prometheus +The metrics system of Dubbo involves three aspects: metrics collection, local aggregation, and metrics pushing. +* Metrics Collection: Push metrics that need to be monitored internally in Dubbo to a unified Collector for storage. +* Local Aggregation: Basic metrics are obtained from metrics collection, while some quantile metrics need to be calculated through local aggregation. +* Metrics Pushing: Collected and aggregated metrics are pushed to a third-party server in a specific manner, currently only involving Prometheus. -## 3. 结构设计 -- 移除原来与 Metrics 相关的类 -- 创建新模块 dubbo-metrics/dubbo-metrics-api、dubbo-metrics/dubbo-metrics-prometheus,MetricsConfig 作为该模块的配置类 -- 使用micrometer,在Collector中使用基本类型代表指标,如Long、Double等,并在dubbo-metrics-api中引入micrometer,由micrometer对内部指标进行转换 -## 4. 数据流转 +## 3. Structural Design +- Remove the original classes related to Metrics +- Create new modules dubbo-metrics/dubbo-metrics-api, dubbo-metrics/dubbo-metrics-prometheus, with MetricsConfig as the configuration class for these modules +- Use micrometer, and in the Collector, use basic types to represent metrics, such as Long, Double, etc., and introduce micrometer in dubbo-metrics-api to convert internal metrics. +## 4. Data Flow ![img.png](/imgs/docs3-v2/java-sdk/observability/dataflow.png) -## 5. 目标 - 指标接口将提供一个 MetricsService,该 Service 不仅提供柔性服务所的接口级数据,也提供所有指标的查询方式,其中方法级指标的查询的接口可按如下方式声明 +## 5. Objectives + The metrics interface will provide a MetricsService, which not only provides interface-level data for flexible services but also offers ways to query all metrics. The method-level metrics query interface can be declared as follows: ```java public interface MetricsService { @@ -43,7 +43,8 @@ public interface MetricsService { String DEFAULT_EXTENSION_NAME = "default"; /** - * The contract version of {@link MetricsService}, the future update must make sure compatible. + * The contract version of {@link MetricsService}, future updates +must ensure compatibility. */ String VERSION = "1.0.0"; @@ -65,7 +66,7 @@ public interface MetricsService { Map> getMetricsByCategories(String serviceUniqueName, List categories); /** - * Get metrics by interface、method and prefixes + * Get metrics by interface, method, and prefixes * * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) * @param methodName methodName @@ -77,7 +78,7 @@ public interface MetricsService { } ``` -其中 MetricsCategory 设计如下: +Where MetricsCategory is designed as follows: ```java public enum MetricsCategory { RT, @@ -86,7 +87,7 @@ public enum MetricsCategory { } ``` -MetricsEntity 设计如下 +MetricsEntity is designed as follows: ```java public class MetricsEntity { private String name; @@ -96,12 +97,12 @@ public class MetricsEntity { } ``` -# 指标收集 -## 1. 嵌入位置 - Dubbo 架构图如下 +# Metrics Collection +## 1. Insertion Location + The architecture diagram of Dubbo is as follows: ![img.png](/imgs/docs3-v2/java-sdk/observability/dubbo.png) -在 provider 中添加一层 MetricsFilter 重写 invoke 方法嵌入调用链路用于收集指标,用 try-catch-finally 处理,核心代码如下 +Add a layer of MetricsFilter in the provider to overwrite the invoke method and embed the call chain for metrics collection, handled using try-catch-finally. The core code is as follows: ```java @Activate(group = PROVIDER, order = -1) @@ -129,9 +130,8 @@ public class MetricsFilter implements Filter, ScopeModelAware { ``` - -## 2. 指标标识 - 用以下五个属性作为隔离级别区分标识不同方法,也是各个 ConcurrentHashMap 的 key +## 2. Metric Identification + Use the following five attributes as isolation levels to distinguish different methods, which are also the keys of various ConcurrentHashMap. ```java public class MethodMetric { private String applicationName; @@ -142,8 +142,8 @@ public class MethodMetric { } ``` -## 3. 基础指标 - 指标通过 common 模块下的 MetricsCollector 存储所有指标数据 +## 3. Basic Metrics + Metrics are stored in the MetricsCollector under the common module. ```java public class DefaultMetricsCollector implements MetricsCollector { @@ -166,48 +166,48 @@ public class DefaultMetricsCollector implements MetricsCollector { } ``` -# 本地聚合 -本地聚合指将一些简单的指标通过计算获取各分位数指标的过程 -## 1. 参数设计 - 收集指标时,默认只收集基础指标,而一些单机聚合指标则需要开启服务柔性或者本地聚合后另起线程计算。此处若开启服务柔性,则本地聚合默认开启 +# Local Aggregation +Local aggregation refers to the process of obtaining quantile metrics through calculations based on some simple metrics. +## 1. Parameter Design + When collecting metrics, only basic metrics are collected by default, while some single-machine aggregation metrics need to enable service flexibility or local aggregation to compute in a separate thread. If service flexibility is enabled here, local aggregation is enabled by default. -### 1.1 本地聚合开启方式 +### 1.1 Local Aggregation Enablement ```xml ``` -### 1.2 指标聚合参数 +### 1.2 Metrics Aggregation Parameters ```xml ``` -## 2. 具体指标 +## 2. Specific Metrics -Dubbo的指标模块帮助用户从外部观察正在运行的系统的内部服务状况 ,Dubbo参考 ["四大黄金信号"](https://sre.google/sre-book/monitoring-distributed-systems/)、*RED方法*、*USE方法*等理论并结合实际企业应用场景从不同维度统计了丰富的关键指标,关注这些核心指标对于提供可用性的服务是至关重要的。 +The metrics module of Dubbo helps users observe the internal service status of the running system from the outside. Dubbo refers to the "Four Golden Signals", *RED Method*, *USE Method*, and other theories combined with practical enterprise application scenarios to provide a rich set of key metrics from different dimensions. Focusing on these core metrics is crucial for providing usable services. -Dubbo的关键指标包含:**延迟(Latency)**、**流量(Traffic)**、 **错误(Errors)** 和 **饱和度(Saturation)** 等内容 。同时,为了更好的监测服务运行状态,Dubbo 还提供了对核心组件状态的监控,如Dubbo应用信息、线程池信息、三大中心交互的指标数据等。 +Key metrics of Dubbo include: **Latency**, **Traffic**, **Errors**, and **Saturation**. To better monitor service operation status, Dubbo also provides monitoring for core component states, such as Dubbo application information, thread pool information, and metrics data for interaction with the three major centers. -在Dubbo中主要包含如下监控指标: +Key monitoring metrics in Dubbo mainly include: -| | 基础设施 | 业务监控 | -| :------- | :----------------------------------------------------------- |:-----------------------------| -| 延迟类 | IO 等待; 网络延迟; | 接口、服务的平均耗时、TP90、TP99、TP999 等 | -| 流量类 | 网络和磁盘 IO; | 服务层面的 QPS、 | -| 错误类 | 宕机; 磁盘(坏盘或文件系统错误); 进程或端口挂掉; 网络丢包; | 错误日志;业务状态码、错误码走势; | -| 饱和度类 | 系统资源利用率: CPU、内存、磁盘、网络等; 饱和度:等待线程数,队列积压长度; | 这里主要包含JVM、线程池等| +| | Infrastructure | Business Monitoring | +| :------- | :----------------------------------------------------------- |:------------------------------------- | +| Latency | IO wait; Network latency; | Average time consumed by interfaces and services, TP90, TP99, TP999, etc. | +| Traffic | Network and disk IO; | QPS at the service level, | +| Errors | Downtime; Disk (bad disk or file system error); Process or port crash; Network packet loss; | Error logs; Business status codes, trends of error codes; | +| Saturation| System resource utilization: CPU, memory, disk, network; Saturation: number of waiting threads, queue backlog length; | This mainly includes JVM, thread pools, etc.| -- qps: 基于滑动窗口获取动态qps -- rt: 基于滑动窗口获取动态rt -- 失败请求数: 基于滑动窗口获取最近时间内的失败请求数 -- 成功请求数: 基于滑动窗口获取最近时间内的成功请求数 -- 处理中请求数: 前后增加Filter简单统计 -- 具体指标依赖滑动窗口,额外使用 AggregateMetricsCollector 收集 +- qps: dynamically obtained qps based on a sliding window +- rt: dynamically obtained rt based on a sliding window +- Number of failed requests: dynamically obtained number of failed requests in recent time based on a sliding window +- Number of successful requests: dynamically obtained number of successful requests in recent time based on a sliding window +- Number of requests being processed: simple statistics using pre-and post-Filters +- Specific metrics rely on a sliding window, with additional use of AggregateMetricsCollector for collection -输出到普罗米修斯的相关指标可以参考的内容如下: +Metrics output to Prometheus can be referenced as follows: ``` # HELP jvm_gc_live_data_size_bytes Size of long-lived heap memory pool after reclamation # TYPE jvm_gc_live_data_size_bytes gauge @@ -349,7 +349,7 @@ requests_succeed{application_name="metrics-provider",group="",hostname="iZ8lgm9i rt_avg{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 ``` -## 聚合收集器 +## Aggregation Collector ```java public class AggregateMetricsCollector implements MetricsCollector, MetricsListener { private int bucketNum; @@ -367,7 +367,7 @@ public class AggregateMetricsCollector implements MetricsCollector, MetricsListe private static final Integer DEFAULT_BUCKET_NUM = 10; private static final Integer DEFAULT_TIME_WINDOW_SECONDS = 120; -//在构造函数中解析配置信息 +// In the constructor, parse the configuration information public AggregateMetricsCollector(ApplicationModel applicationModel) { this.applicationModel = applicationModel; @@ -385,7 +385,7 @@ public class AggregateMetricsCollector implements MetricsCollector, MetricsListe } ``` -如果开启了本地聚合,则通过 spring 的 BeanFactory 添加监听,将 AggregateMetricsCollector 与 DefaultMetricsCollector 绑定,实现一种生存者消费者的模式,DefaultMetricsCollector 中使用监听器列表,方便扩展 +If local aggregation is enabled, listeners are added through the Spring BeanFactory, binding AggregateMetricsCollector with DefaultMetricsCollector, implementing a producer-consumer model. The DefaultMetricsCollector uses a list of listeners for easy expansion. ```java private void registerListener() { @@ -393,23 +393,23 @@ private void registerListener() { } ``` -## 3. 指标聚合 -滑动窗口 -假设我们初始有6个bucket,每个窗口时间设置为2分钟 -每次写入指标数据时,会将数据分别写入6个bucket内,每隔两分钟移动一个bucket并且清除原来bucket内的数据 -读取指标时,读取当前current指向的bucket,以达到滑动窗口的效果 -具体如下图所示,实现了当前 bucket 内存储了配置中设置的 bucket 生命周期内的数据,即近期数据 +## 3. Metrics Aggregation +Sliding Window +Assuming we initially have 6 buckets, each with a window time set to 2 minutes. +Each time metrics data is written, it will be written into 6 buckets. Every two minutes, a bucket will be moved, and the data in the original bucket will be cleared. +When reading metrics, the current bucket pointed to by current will be read to achieve the sliding window effect. +As shown in the figure below, it implements that the current bucket stores data within the lifecycle of the bucket as configured, i.e., recent data. ![img_1.png](/imgs/docs3-v2/java-sdk/observability/aggre.png) -在每个bucket内,使用**TDigest 算法**计算分位数指标 +In each bucket, the **TDigest algorithm** is used to calculate quantile metrics. -> **TDigest 算法**(极端分位精确度高,如p1 p99,中间分位精确度低,如p50),相关资料如下 +> **TDigest Algorithm** (high accuracy for extreme quantiles, such as p1 p99, low accuracy for central quantiles, such as p50). Related materials are as follows: > > - https://op8867555.github.io/posts/2018-04-09-tdigest.html > - https://blog.csdn.net/csdnnews/article/details/116246540 -> - 开源实现:https://github.com/tdunning/t-digest +> - Open Source Implementation: https://github.com/tdunning/t-digest -代码实现如下,除了 TimeWindowQuantile 用来计算分位数指标外,另外提供了 TimeWindowCounter 来收集时间区间内的指标数量 +The code implementation is as follows. In addition to TimeWindowQuantile for calculating quantile metrics, TimeWindowCounter is provided to collect the count of metrics within the time interval. ```java public class TimeWindowQuantile { private final double compression; @@ -457,10 +457,10 @@ public class TimeWindowQuantile { } ``` -# 指标推送 -指标推送只有用户在设置了配置且配置protocol参数后才开启,若只开启指标聚合,则默认不推送指标。 -## 1. Promehteus Pull ServiceDiscovery - 使用dubbo-admin等类似的中间层,启动时根据配置将本机 IP、Port、MetricsURL 推送地址信息至dubbo-admin(或任意中间层)的方式,暴露HTTP ServiceDiscovery供prometheus读取,配置方式如,其中在pull模式下address为可选参数,若不填则需用户手动在Prometheus配置文件中配置地址 +# Metrics Push +Metrics pushing is only enabled when the user has set the configuration and set the protocol parameter. If only metrics aggregation is enabled, no metrics will be pushed by default. +## 1. Prometheus Pull ServiceDiscovery + Using intermediate layers such as dubbo-admin, at startup, the local IP, Port, and MetricsURL push address information are pushed to dubbo-admin (or any intermediate layer) based on the configuration, exposing HTTP ServiceDiscovery for Prometheus to read, with the configuration like . In pull mode, address is an optional parameter; if not filled, the user must manually configure the address in the Prometheus configuration file. ```java private void exportHttpServer() { @@ -492,7 +492,7 @@ private void exportHttpServer() { ``` ## 2. Prometheus Push Pushgateway -用户直接在Dubbo配置文件中配置Prometheus Pushgateway的地址即可,如,其中interval代表推送间隔 +Users can directly configure the address of the Prometheus Pushgateway in the Dubbo configuration file, e.g. , where the interval represents the push interval. ```java @@ -525,5 +525,6 @@ protected void push(PushGateway pushGateway, String job) { } ``` -## 可视化展示 -目前推荐使用 Prometheus 来进行服务监控,Grafana 来展示指标数据。可以通过案例来快速入门 [Dubbo 可视化监控](../../../tasks/observability/grafana/)。 +## Visualization +Currently, it is recommended to use Prometheus for service monitoring and Grafana to display metrics data. You can quickly get started with a case of [Dubbo Visualization Monitoring](../../../tasks/observability/grafana/) . + diff --git a/content/en/overview/reference/protocols/triple-spec.md b/content/en/overview/reference/protocols/triple-spec.md index 3ce482305022..b27a23c165cf 100644 --- a/content/en/overview/reference/protocols/triple-spec.md +++ b/content/en/overview/reference/protocols/triple-spec.md @@ -1,26 +1,26 @@ --- -description: "Triple 协议规范" -linkTitle: Triple 协议规范 -title: Triple 协议设计理念与规范 +description: "Triple Protocol Specification" +linkTitle: Triple Protocol Specification +title: Triple Protocol Design Philosophy and Specification type: docs weight: 1 working_in_progress: true --- -## 1 协议设计理念 -Triple 协议的设计参考了 gRPC、gRPC-Web、通用 HTTP 等多种协议模式,吸取每个协议各自的特性和优点,最终设计成为一个易于浏览器访问、完全兼容 gRPC 且支持 Streaming 通信的协议,Triple 支持同时运行在 HTTP/1、HTTP/2 协议之上。 +## 1 Protocol Design Philosophy +The design of the Triple protocol references various protocol patterns such as gRPC, gRPC-Web, and general HTTP, absorbing the characteristics and advantages of each, ultimately designing a protocol that is easy to access via browsers, fully compatible with gRPC, and supports Streaming communication. Triple can run simultaneously over HTTP/1 and HTTP/2 protocols. -Triple 协议的设计目标如下: -* Triple 设计为对人类、开发调试友好的一款基于 HTTP 的协议,尤其是对 unary 类型的 RPC 请求。 -* 完全兼容基于 HTTP/2 的 gRPC 协议,因此 Dubbo Triple 协议实现可以 100% 与 gRPC 体系互调互通。 -* 仅依赖标准的、被广泛使用的 HTTP 特性,以便在实现层面可以直接依赖官方的标准 HTTP 网络库。 +The design goals of the Triple protocol are as follows: +* Triple is designed to be a human and development-friendly HTTP-based protocol, especially for unary RPC requests. +* Fully compatible with HTTP/2-based gRPC protocol, so the Dubbo Triple protocol implementation can 100% interact with the gRPC ecosystem. +* Only relies on standard, widely used HTTP features, enabling direct reliance on official standard HTTP network libraries in the implementation layer. -当与 Protocol Buffers 一起使用时(即使用 IDL 定义服务),Triple 协议可支持 unary、client-streaming、server-streaming 和 bi-streaming RPC 通信模式,支持二进制 Protobuf、JSON 两种数据格式 payload。 Triple 实现并不绑定 Protocol Buffers,比如你可以使用 Java 接口定义服务,Triple 协议有对这种模式的扩展 Content-type 支持。 +When used with Protocol Buffers (i.e., using IDL to define services), the Triple protocol supports unary, client-streaming, server-streaming, and bi-streaming RPC communication modes, supporting both binary Protobuf and JSON data format payloads. The Triple implementation does not bind to Protocol Buffers; for instance, you can use Java interface to define services, and the Triple protocol has extended Content-Type support for this model. -## 2 示例 -### 2.1 Unary 请求 +## 2 Examples +### 2.1 Unary Request -以 HTTP/1 请求为例,目前 HTTP/1 协议仅支持 Unary RPC,支持使用 application/proto 和 application/json 编码类型,使用方式与 REST 风格请求保持一致,同时响应也包含常规的 HTTP 响应编码(如 200 OK)。 +Taking HTTP/1 request as an example, the current HTTP/1 protocol only supports Unary RPC, supporting application/proto and application/json encoding types, maintaining a usage style consistent with REST-style requests, while the response also includes standard HTTP response encoding (such as 200 OK). ```text > POST /org.apache.dubbo.demo.GreetService/Greet HTTP/1.1 @@ -35,7 +35,7 @@ Triple 协议的设计目标如下: < {"greeting": "Hello, Dubbo!"} ``` -一个包含指定超时时间的调用请求。 +A call request with a specified timeout. ```text > POST /org.apache.dubbo.demo.GreetService/Greet HTTP/1.1 @@ -51,11 +51,11 @@ Triple 协议的设计目标如下: < {"greeting": "Hello, Buf!"} ``` -> 目前仅支持 POST 请求类型,我们将考虑在未来支持 GET 请求类型,GET 请求可能适用于具有幂等属性的一些服务调用。 +> Currently only POST request type is supported; we will consider supporting GET request types in the future, which may apply to certain service calls with idempotent properties. -### 2.2 Streaming 调用请求 +### 2.2 Streaming Call Request -Triple 仅支持在 HTTP/2 上支持 Streaming RPC。并且为了与 gRPC 协议保持兼容,Triple 在 HTTP/2 协议实现上(包含 Streaming RPC)保持与标准 gRPC 协议完全一致。 +Triple only supports Streaming RPC on HTTP/2. To maintain compatibility with gRPC, the Triple implementation on HTTP/2 (including Streaming RPC) is entirely consistent with the standard gRPC protocol. Request @@ -90,19 +90,19 @@ grpc-status = 0 # OK trace-proto-bin = jher831yy13JHy3hc ``` -## 3 规范详情 +## 3 Specification Details -Triple 协议支持同时运行在 HTTP/1 和 HTTP/2 协议之上,其包含以下两部分内容: -1. 一套自定义的精简 HTTP RPC 子协议,支持 HTTP/1 和 HTTP/2 作为传输层实现,仅支持 Request-Response 类型的 Unary RPC。 -2. 一套基于 gRPC 协议的扩展子协议(仍保持和 gRPC 的 100% 兼容),仅支持 HTTP/2 实现,支持 Unary RPC 和 Streaming RPC。 +The Triple protocol supports running simultaneously over both HTTP/1 and HTTP/2, comprising the following two parts: +1. A custom, streamlined HTTP RPC sub-protocol that supports HTTP/1 and HTTP/2 as transport layers and supports only Request-Response type Unary RPC. +2. An extended sub-protocol based on the gRPC protocol (still 100% compatible with gRPC), supporting only HTTP/2 implementation, and supports Unary RPC and Streaming RPC. -### 3.1 Triple 之 HTTP RPC 协议 +### 3.1 HTTP RPC Protocol of Triple -大部分的 RPC 调用都是 unary (request-response) 模式的,Triple HTTP RPC 协议 unary 模式能很好的满足后端服务间的数据传输需求。同时解决了gRPC协议的痛点,让浏览器、cURL 以及其他一些 HTTP 工具更容易的访问后端服务,即不需要借助代理和gRPC-web,使用标准的 HTTP 协议直接发起调用。 +Most RPC calls are unary (request-response), and the Triple HTTP RPC protocol's unary mode meets the data transmission needs among backend services well. It also addresses the pain points of the gRPC protocol, making it easier for browsers, cURL, and other HTTP tools to access backend services without relying on proxies and gRPC-web, using standard HTTP protocol to initiate calls directly. -Triple HTTP RPC 同时支持 HTTP/1、HTTP/2 作为底层传输层协议,在实现上对应支持的 content-type 类型为 application/json、application/proto +Triple HTTP RPC supports both HTTP/1 and HTTP/2 as underlying transport layer protocols, corresponding to supported content-type types as application/json, application/proto. -#### 3.1.1 请求 Request +#### 3.1.1 Request - Request → Request-Headers Bare-Message - Request-Headers → Call-Specification *Leading-Metadata @@ -113,7 +113,7 @@ Content-Encoding Accept-Encoding Accept Content-Length - Http-Method → POST - Path → /Service-Name/Method-Name; case-sensitive - Service-Name → service interface full classname -- Method-Name → service interface declared method`s name +- Method-Name → service interface declared method's name - Http-Host → Target-IP:Target-Port - Target-IP → target server ip or domain - Target-Port → target server process port @@ -138,28 +138,28 @@ Content-Encoding Accept-Encoding Accept Content-Length - ASCII-Value → 1*( %x20-%x7E ) ; space & printable ASCII - Bare-Message → data that encoded by json or custom and Content-Encoding -Triple 协议请求的仅支持 POST 请求,请求 path 为 interfaceName/methodName,为了实现调用超时机制,需要添加 tri-service-timeout (单位 ms), +The Triple protocol request only supports POST requests, with the request path being interfaceName/methodName. To implement a call timeout mechanism, tri-service-timeout (in ms) needs to be added, -Dubbo 框架支持基于 **分组(group)** 和 **版本(version)** 的服务隔离机制,因此 Triple 协议中引入了 tri-service-group、tri-service-version 支持。 +The Dubbo framework supports service isolation mechanisms based on **group** and **version**, thus the Triple protocol introduces tri-service-group and tri-service-version support. -**Request-Headers** 以标准的 HTTP header 的形式发送,如果收到的 headers 数量过多,server 可返回相应错误信息。 +**Request-Headers** are sent in the form of standard HTTP headers. If too many headers are received, the server can return the corresponding error message. -**TRI-Protocol-Version** 头用来区分具有相同 Content-Type 的 triple 协议请求和其他协议请求,因为 application/json 格式的 Content-Type 非常普遍。所有的 Dubbo 原生客户端实现都应该在请求中携带 TRI-Protocol-Version,Dubbo 服务端或代理可以选择拒绝没有 TRI-Protocol-Version 的请求并返回 Http-Status 400 错误。 +**TRI-Protocol-Version** header is used to distinguish between Triple protocol requests with the same Content-Type and other protocol requests because the application/json format Content-Type is very common. All Dubbo native client implementations should carry TRI-Protocol-Version in the request, and the Dubbo server or proxy can choose to reject requests without TRI-Protocol-Version and return Http-Status 400 error. -如果 Server 不支持 **Message-Codec** 指定的编码格式,则必须返回标准 HTTP 415 编码表明 Unsupported Media Type 异常。 +If the Server does not support the specified encoding format of **Message-Codec**, it must return standard HTTP 415 encoding to indicate Unsupported Media Type exception. -**Bare-Message** 即请求 payload 的编码格式取决于 Message-Codec 设置: -* Message-Codec: json 的场景下,payload 采用有序的数组编码形式,即将 rpc 方法的参数按顺序组装进 Array 后进行 json 序列化,方法参数的位置与数组下标保持一致,当 Triple server 接收到请求体时,根据每个参数的类型进行反序列化成对应的参数数组。对于使用 Protocol Buffer 的情形,payload 则是只有一个 json 对象的数组。 -* Message-Codec: proto 的场景下,Protobuf 生成的 Request 类包含了编码格式,因此将直接使用 Request 对象中的内置编码方式。 -* Message-Codec 支持更多自定义扩展值,请确保框架实现遵循相应的编码与解码约定。 +**Bare-Message** is the encoding format of the request payload that depends on the Message-Codec setting: +* When Message-Codec: json, the payload adopts an ordered array encoding format, i.e., the rpc method parameters are assembled into an Array in order for json serialization; the position of method parameters corresponds to the array index. When the Triple server receives the request body, it deserializes according to the type of each parameter into the corresponding parameter array. For situations using Protocol Buffer, the payload is an array of a single json object. +* When Message-Codec: proto, the Protobuf generated Request class contains the encoding format, so it directly uses the built-in encoding method in the Request object. +* Message-Codec supports more customized extension values; ensure the framework implementation follows the corresponding encoding and decoding conventions. -如果 Content-Encoding 指定了相应值,则 payload 是被压缩过的,应该首先进行解压缩后再解析编码数据,Bare-Message 将作为 HTTP Body 在链路上传输。 +If Content-Encoding specifies the corresponding value, the payload is compressed and should be decompressed before parsing the encoded data. Bare-Message will be transmitted as the HTTP Body in the link. -##### Request 报文示例 +##### Request Message Example -- 请求行 +- Request line - POST /org.apache.dubbo.demo.GreetService/greeting HTTP/1.1 -- 请求头 +- Request headers - Host: 127.0.0.1:30551 - Content-Type: application/json - Accept: application/json @@ -169,7 +169,7 @@ Dubbo 框架支持基于 **分组(group)** 和 **版本(version)** 的 - tri-service-version: 1.0.0 - tri-service-group: dubbo - tri-service-timeout: 3000 -- 请求体 +- Request body - [{"world"}] ```latex @@ -188,19 +188,19 @@ tri-service-timeout: 3000 ``` -#### 3.1.2 响应 Response +#### 3.1.2 Response - Response → Response-Headers *Bare-Message - Response-Headers → HTTP-Status Content-Type [Content-Encoding] [Accept-Encoding] *Leading-Metadata *Prefixed-Trailing-Metadata - HTTP-Status → 200 /{error code translated to HTTP} - Bare-Message → data that encoded by Content-Type and Content-Encoding -对于成功 Response 响应 **HTTP-Status** 是 200,在这种场景下,响应体的 Content-Type 将保持和请求体的 Content-Type 保持一致。**Bare-Message** 就是 RPC 响应的 Payload,以 Content-Type 指定的方式进行编码并且以 Content-Encoding 来压缩(如果指定了 Content-Encoding 的话)。Bare-Message 作为 HTTP response body 发送。 +For a successful Response, the **HTTP-Status** is 200. In this case, the Content-Type of the response body will match the Content-Type of the request body. **Bare-Message** is the Payload of the RPC response encoded by the method specified by Content-Type and compressed by Content-Encoding (if specified). Bare-Message is sent as the HTTP response body. -异常 Response 响应的 HTTP-Status 是 non-200,并且都是标准的 HTTP status code,在这个场景下,**Content-Type** 必须是 "application/json"。**Bare-Message** 可以是空的,如果 Bare-Message 有值的话则是一个标准 JSON 格式数据,如果 **Content-Encoding** 有指定的话则是一个压缩过的数据,Bare-Message 作为标准的 HTTP response body 发送回调用方。客户端可以根据以下表格,查询 HTTP-Status 与 RPC status 之间的映射关系,以了解具体的 RPC 错误情况。 +For an exception Response, the HTTP-Status is non-200, and they are all standard HTTP status codes. In this case, **Content-Type** must be "application/json". **Bare-Message** can be empty, and if Bare-Message has a value, it must be in standard JSON format data, and if **Content-Encoding** is specified, it is compressed data, sent back to the caller as the standard HTTP response body. The client can refer to the following table to query the mapping relationship between HTTP-Status and RPC status to understand the specific RPC error situation. -##### Response 报文格式 -** 成功响应 ** +##### Response Message Format +** Successful Response ** ```latex HTTP/1.1 200 OK @@ -210,7 +210,7 @@ Content-Length: 11 hello world ``` -** 失败响应 ** +** Failed Response ** ```latex HTTP/1.1 400 Bad Request @@ -221,7 +221,7 @@ Content-Length: 46 #### 3.1.3 Error Codes -Dubbo 的错误码参考 +Dubbo Error Codes Reference ``` status http-status message @@ -238,7 +238,7 @@ Dubbo 的错误码参考 90 500 internal client error ``` -> Connect 的 HTTP to Error Code 参考 +> Connect's HTTP to Error Code Reference > > | HTTP Status | Inferred Code | > | --- | --- | @@ -259,27 +259,27 @@ Dubbo 的错误码参考 > | _all others_ | unknown | -### 3.2 Triple 之扩展版 gRPC 协议 +### 3.2 Extended gRPC Protocol of Triple -Triple 协议的 Streaming 请求处理完全遵循 gRPC 协议规范,且仅支持 HTTP/2 作为传输层协议。并且后端服务间的 Unary 请求默认采用扩展版 gPRC 协议。 +The Streaming request processing of the Triple protocol fully follows the gRPC protocol specification and only supports HTTP/2 as the transport protocol. Additionally, Unary requests between backend services default to use the extended gRPC protocol. -Triple 支持的 content-type 类型为标准的 gRPC 类型,包括 application/grpc、application/grpc+proto、application/grpc+json,除此之外,Triple 在实现上还扩展了 application/triple+wrapper 编码格式。 +The content-type types supported by Triple are standard gRPC types, including application/grpc, application/grpc+proto, application/grpc+json. Furthermore, the implementation of Triple has also extended the application/triple+wrapper encoding format. #### 3.2.1 Outline -The following is the general sequence of message atoms in a GRPC request & response message stream +The following is the general sequence of message atoms in a gRPC request & response message stream -* Request → Request-Headers \*Length-Prefixed-Message EOS -* Response → (Response-Headers \*Length-Prefixed-Message Trailers) / Trailers-Only +* Request → Request-Headers *Length-Prefixed-Message EOS +* Response → (Response-Headers *Length-Prefixed-Message Trailers) / Trailers-Only #### 3.2.2 Requests -* Request → Request-Headers \*Length-Prefixed-Message EOS +* Request → Request-Headers *Length-Prefixed-Message EOS Request-Headers are delivered as HTTP2 headers in HEADERS + CONTINUATION frames. -* **Request-Headers** → Call-Definition \*Custom-Metadata +* **Request-Headers** → Call-Definition *Custom-Metadata * **Call-Definition** → Method Scheme Path TE [Authority] [Timeout] Content-Type [Message-Type] [Message-Encoding] [Message-Accept-Encoding] [User-Agent] Service-Version Service-Group Tracing-ID Tracing-Span-ID Cluster-Info * **Method** → ":method POST" * **Scheme** → ":scheme " ("http" / "https") @@ -299,31 +299,31 @@ Request-Headers are delivered as HTTP2 headers in HEADERS + CONTINUATION frames. * **Content-Type** → "content-type" "application/grpc" [("+proto" / "+json" / {_custom_})] * **Content-Coding** → "identity" / "gzip" / "deflate" / "snappy" / {_custom_} * **Message-Encoding** → "grpc-encoding" Content-Coding -* **Message-Accept-Encoding** → "grpc-accept-encoding" Content-Coding \*("," Content-Coding) +* **Message-Accept-Encoding** → "grpc-accept-encoding" Content-Coding *("," Content-Coding) * **User-Agent** → "user-agent" {_structured user-agent string_} * **Message-Type** → "grpc-message-type" {_type name for message schema_} * **Custom-Metadata** → Binary-Header / ASCII-Header * **Binary-Header** → {Header-Name "-bin" } {_base64 encoded value_} * **ASCII-Header** → Header-Name ASCII-Value -* **Header-Name** → 1\*( %x30-39 / %x61-7A / "\_" / "-" / ".") ; 0-9 a-z \_ - . -* **ASCII-Value** → 1\*( %x20-%x7E ) ; space and printable ASCII +* **Header-Name** → 1*( %x30-39 / %x61-7A / "\_" / "-" / ".") ; 0-9 a-z \_ - . +* **ASCII-Value** → 1*( %x20-%x7E ) ; space and printable ASCII * Service-Version → "tri-service-version" {Dubbo service version} * Service-Group → "tri-service-group" {Dubbo service group} * Tracing-ID → "tri-trace-traceid" {tracing id} * Tracing-RPC-ID → "tri-trace-rpcid" {_span id _} -* Cluster-Info → "tri-unit-info" {cluster infomation} +* Cluster-Info → "tri-unit-info" {cluster information} #### 3.2.3 Responses -* **Response** → (Response-Headers \*Length-Prefixed-Message Trailers) / Trailers-Only -* **Response-Headers** → HTTP-Status [Message-Encoding] [Message-Accept-Encoding] Content-Type \*Custom-Metadata +* **Response** → (Response-Headers *Length-Prefixed-Message Trailers) / Trailers-Only +* **Response-Headers** → HTTP-Status [Message-Encoding] [Message-Accept-Encoding] Content-Type *Custom-Metadata * **Trailers-Only** → HTTP-Status Content-Type Trailers -* **Trailers** → Status [Status-Message] \*Custom-Metadata +* **Trailers** → Status [Status-Message] *Custom-Metadata * **HTTP-Status** → ":status 200" -* **Status** → "grpc-status" 1\*DIGIT ; 0-9 +* **Status** → "grpc-status" 1*DIGIT ; 0-9 * **Status-Message** → "grpc-message" Percent-Encoded -* **Percent-Encoded** → 1\*(Percent-Byte-Unencoded / Percent-Byte-Encoded) -* **Percent-Byte-Unencoded** → 1\*( %x20-%x24 / %x26-%x7E ) ; space and VCHAR, except % +* **Percent-Encoded** → 1*(Percent-Byte-Unencoded / Percent-Byte-Encoded) +* **Percent-Byte-Unencoded** → 1*( %x20-%x24 / %x26-%x7E ) ; space and VCHAR, except % * **Percent-Byte-Encoded** → "%" 2HEXDIGIT ; 0-9 A-F -以上即为 Triple 扩展版本的 gRPC 协议,更多详细规范说明请参照 gRPC 协议规范。 +This is the extended version of the gRPC protocol for Triple. For more detailed specifications, please refer to gRPC Protocol Specification. From f1a65027bcd5528023766494c8870e8ff290f654 Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Mon, 30 Sep 2024 15:04:14 +0800 Subject: [PATCH 09/23] Translate --- .../overview/mannual/control-plane/_index.md | 5 +- .../mannual/control-plane/architecture.md | 88 +++++------ .../mannual/control-plane/documentation.md | 5 +- .../en/overview/mannual/control-plane/mock.md | 145 +++++++++--------- .../overview/mannual/control-plane/search.md | 39 +++-- .../en/overview/mannual/control-plane/test.md | 54 +++---- 6 files changed, 166 insertions(+), 170 deletions(-) diff --git a/content/en/overview/mannual/control-plane/_index.md b/content/en/overview/mannual/control-plane/_index.md index 6093af9b0178..9f3d9ef3326f 100644 --- a/content/en/overview/mannual/control-plane/_index.md +++ b/content/en/overview/mannual/control-plane/_index.md @@ -3,8 +3,9 @@ aliases: - /en/overview/reference/admin/ - /en/overview/reference/admin/ description: "" -linkTitle: 控制面 -title: Admin 控制台操作手册 +linkTitle: Control Panel +title: Admin Console User Guide type: docs weight: 20 --- + diff --git a/content/en/overview/mannual/control-plane/architecture.md b/content/en/overview/mannual/control-plane/architecture.md index 2a326211ec9f..a14943399741 100644 --- a/content/en/overview/mannual/control-plane/architecture.md +++ b/content/en/overview/mannual/control-plane/architecture.md @@ -3,45 +3,45 @@ aliases: - /en/overview/reference/admin/architecture/ - /en/overview/reference/admin/architecture/ description: "" -linkTitle: 架构与安装 +linkTitle: Architecture and Installation no_list: true -title: Admin 整体架构与安装步骤 +title: Admin Overall Architecture and Installation Steps type: docs weight: 1 working_in_progress: true --- -回顾 [Dubbo 服务治理体系的总体架构](../../../what/overview/),Admin 是服务治理控制面中的一个核心组件,负责微服务集群的服务治理、可视化展示等。 +Reviewing the [overall architecture of the Dubbo service governance system](../../../what/overview/), Admin is a core component in the service governance control plane, responsible for service governance and visualization display for microservice clusters. -## Admin 部署架构 +## Admin Deployment Architecture ![admin-core-components.png](/imgs/v3/reference/admin/admin-core-components.png) -总体上来说,Admin 部署架构分为以下几个部分: -* Admin 主进程,包括服务发现元数据管理、可视化控制台、安全认证策略管控、其他定制化服务治理能力等组件。 -* 强依赖组件,包括 Mysql 数据库、注册/配置/元数据中心(可以是 Kubernetes、Nacos、Zookeeper 等) -* 可选依赖组件,包括 Prometheus、Grafana、Zipkin 等 +Overall, the Admin deployment architecture is divided into the following parts: +* The Admin main process, including service discovery metadata management, a visualization console, security authentication policy control, and other customized service governance capabilities. +* Strong dependency components, including Mysql database, registration/configuration/metadata centers (which can be Kubernetes, Nacos, Zookeeper, etc.) +* Optional dependency components, including Prometheus, Grafana, Zipkin, etc. -## 安装 Admin +## Install Admin -### Dubboctl 安装 +### Dubboctl Installation #### Download -当前Dubboctl未正式发行,可按以下方式进行尝试。 -拉取Dubbo Admin并编译Dubboctl +Currently, Dubboctl is not formally released and can be tried as follows. +Pull Dubbo Admin and compile Dubboctl ```shell git clone https://github.com/apache/dubbo-admin.git cd dubbo-admin/cmd/dubboctl go build -o dubboctl . ``` -将 dubboctl 放入可执行路径 +Place dubboctl in an executable path ```shell ln -s dubbo-admin/cmd/dubboctl/dubboctl /usr/local/bin/dubboctl ``` #### Install -安装过程会依次: +The installation process will sequentially: -1. 将用户自定义的配置profile以及set参数覆盖于默认profile,得到最终的profile +1. Overlay the user-defined configuration profile and setting parameters onto the default profile to obtain the final profile ```yaml # default profile apiVersion: dubbo.apache.org/v1alpha1 @@ -77,7 +77,7 @@ spec: repoURL: https://openzipkin.github.io/zipkin version: 0.3.0 ``` -建议使用自定义profile进行配置,在componentsMeta中开启或关闭组件,在components下配置各组件。其中components下各组件的配置值都是helm chart的values,各组件的具体配置请参考: +It is recommended to use a custom profile for configuration, enabling or disabling components in componentsMeta and configuring each component under components. The configuration values of each component are the values of helm charts. For specific component configurations, please refer to: Grafana: https://github.com/grafana/helm-charts/blob/main/charts/grafana/README.md Zookeeper: https://github.com/bitnami/charts/tree/main/bitnami/zookeeper/#installing-the-chart Prometheus: https://github.com/prometheus-community/helm-charts/tree/main/charts @@ -107,10 +107,10 @@ spec: testFramework: enabled: false ``` -2. 根据profile拉取所需组件并生成manifest,目前Admin,Nacos已在本地,无需拉取;Grafana,Zookeeper,Prometheus,Skywalking,Zipkin将从官方chart库拉取,具体地址和版本可见上方default profile -3. 将manifest应用于k8s集群 +2. Pull the required components based on the profile and generate the manifest. Currently, Admin and Nacos are local, no need to pull; Grafana, Zookeeper, Prometheus, Skywalking, Zipkin will pull from the official chart repository, specific addresses and versions can be seen in the above default profile +3. Apply the manifest to the k8s cluster ```shell -dubboctl manifest install # 使用默认 manifests 安装 +dubboctl manifest install # Install using default manifests # or @@ -118,34 +118,34 @@ dubboctl manifest generate | kubectl apply -f - ``` ```shell -dubboctl install --set spec.components.admin.replicas=2 # 设置组件的配置 +dubboctl install --set spec.components.admin.replicas=2 # Set component configuration ``` ```shell dubboctl install --set spec.componentsMeta.admin.enabled=true, spec.componentsMeta.grafana.enabled=false -# 开启或关闭组件 +# Enable or disable components ``` ```shell dubboctl install --set spec.componentsMeta.grafana.repoURL=https://grafana.github.io/helm-charts, spec.componentsMeta.grafana.version=6.31.0 -# 设置需远程拉取组件的仓库地址与版本 +# Set repository address and version for remotely pulled components ``` -检查安装效果 +Check installation effect ```shell kubectl get pod -n dubbo-system ``` -#### 打开 Admin 控制台 +#### Open Admin Console ```shell kubectl port-forward svc/dubbo-admin -n dubbo-system 38080:38080 ``` -打开浏览器,访问: `http://127.0.0.1:38080/` +Open the browser and visit: `http://127.0.0.1:38080/` -### Helm 安装 +### Helm Installation -获取图表 +Get the charts ``` helm repo add https://charts.bitnami.com/bitnami helm repo add https://prometheus-community.github.io/helm-charts @@ -153,45 +153,45 @@ helm repo add https://grafana.github.io/helm-charts helm repo add https://apache.jfrog.io/artifactory/skywalking-helm helm repo add https://openzipkin.github.io/zipkin ``` -安装 zookeeper +Install zookeeper ```bash helm install zookeeper bitnami/zookeeper -n dubbo-system ``` -安装 prometheus +Install prometheus ```bash helm install prometheus prometheus-community/prometheus -n dubbo-system ``` -安装 grafana +Install grafana ```bash helm install grafana grafana/grafana -n dubbo-system ``` -安装 skywalking +Install skywalking ```bash helm install skywalking skywalking/skywalking -n dubbo-system ``` -安装 zipkin +Install zipkin ``` helm install zipkin openzipkin/zipkin -n dubbo-system ``` -检查安装状态 +Check installation status ```shell -helm ls -n dubbo-system ;kubectl get pods -n dubbo-system --output wide +helm ls -n dubbo-system ; kubectl get pods -n dubbo-system --output wide ``` -### VM 安装 +### VM Installation #### Download -下载 Dubbo Admin 发行版本 +Download the Dubbo Admin release version ```shell curl -L https://dubbo.apache.org/installer.sh | VERSION=0.1.0 sh - -# Admin 要组织好发行版本 +# Admin needs to organize the release version ``` -将 dubboctl 放入可执行路径 +Place dubboctl in an executable path ```shell ln -s dubbo-admin-0.1.0/bin/dubbo-admin /usr/local/bin/dubbo-admin ``` @@ -199,9 +199,8 @@ ln -s dubbo-admin-0.1.0/bin/dubbo-admin /usr/local/bin/dubbo-admin ```shell dubbo-admin run -f override-configuration.yml ``` -## 配置手册 (Configuration) -配置用于控制 dubbo-admin 的行为 - +## Configuration Manual (Configuration) +Configuration used to control the behavior of dubbo-admin ```yaml # Environment type. Available values are: "kubernetes" or "universal" @@ -289,8 +288,9 @@ external-services: # Public facing URL of Grafana url: 'http://my-ingress-host/grafana' -# 更多配置 +# More configurations ``` -#### 打开 Admin 控制台 +#### Open Admin Console + +Open the browser and visit: `http://127.0.0.1:38080/` -打开浏览器,访问: `http://127.0.0.1:38080/` diff --git a/content/en/overview/mannual/control-plane/documentation.md b/content/en/overview/mannual/control-plane/documentation.md index 7685636f6eef..50f6572b8791 100644 --- a/content/en/overview/mannual/control-plane/documentation.md +++ b/content/en/overview/mannual/control-plane/documentation.md @@ -3,10 +3,10 @@ aliases: - /en/overview/reference/admin/documentation/ - /en/overview/reference/admin/documentation/ description: "" -linkTitle: 文档管理 +linkTitle: Documentation Management no_list: true toc_hide: true -title: Admin 文档管理功能介绍 +title: Introduction to Admin Documentation Management Features type: docs weight: 6 working_in_progress: true @@ -14,4 +14,3 @@ working_in_progress: true // TBD - diff --git a/content/en/overview/mannual/control-plane/mock.md b/content/en/overview/mannual/control-plane/mock.md index abe0f3034ef1..3b3ee56a39fc 100644 --- a/content/en/overview/mannual/control-plane/mock.md +++ b/content/en/overview/mannual/control-plane/mock.md @@ -3,56 +3,56 @@ aliases: - /en/overview/reference/admin/mock/ - /en/overview/reference/admin/mock/ description: "" -linkTitle: 服务Mock +linkTitle: Service Mock no_list: true -title: Admin 服务 Mock 功能简介 +title: Introduction to Admin Service Mock Functionality type: docs weight: 4 working_in_progress: true --- -Mock 功能是设计用来提升微服务研发与测试效率的,它可以短路 Consumer 侧发起的远程调用,提前返回预先设定好的 Mock 值,这样即使在没有 Provider 可用的情况下,消费端也能正常的推进开发、测试进程。除此之外,mock 也可用于快速模拟负责返回值的测试数据、模拟服务端异常等场景 +The mock functionality is designed to enhance the efficiency of microservices development and testing. It can short circuit remote calls initiated by the consumer side and return pre-set mock values in advance, allowing the consumer to continue development and testing even when no provider is available. Additionally, mocking can be used for quickly simulating test data responsible for return values and simulating server exceptions. -需要注意的是,Mock 能力仅限用于测试环境,应避免将其用于生产环境。 +It is important to note that the mock capability is limited to the testing environment and should be avoided in the production environment. -# 设计背景 -在跨团队或是多应用开发时,在前期开发中往往会出现依赖的服务还未开发完成的情况,这样就会导致流程的阻塞,影响研发效率。基于这种情况,Dubbo Admin 提供了 mock 能力来解耦 Consumer 与 Provider 之间的依赖,以确保在 Provider 未就绪的情况下 Consumer 仍能正常开展测试,提高研发效率。 +# Design Background +During cross-team or multi-application development, there are often situations where dependent services have not yet been finished, leading to process blockage and impacting development efficiency. To address this, Dubbo Admin provides mock capabilities to decouple dependencies between consumer and provider, ensuring that the consumer can continue testing even when the provider is not ready, thereby enhancing development efficiency. -Dubbo 框架本身设计有服务降级(有时也称为 mock)能力,通过配置 `org.apache.dubbo.config.ReferenceConfig` 的 mock 字段(可设置为true或是对应接口的Mock实现)或动态配置规则,此时就可以启动服务降级能力。这种服务降级能力是为生产环境的限流降级准备的,虽然也可以用于本地开发测试场景,但灵活度并不高,基于提升开发效率的根本诉求,我们设计了基于 Admin 的服务降级能力。 +The Dubbo framework itself has service degradation (sometimes referred to as mock) capabilities, which can be activated by configuring the `mock` field of `org.apache.dubbo.config.ReferenceConfig`, allowing it to be set to true or an implementation of the corresponding interface. This service degradation capability is primarily designed for production environments to manage traffic and degradation, although it can also be used in local development scenarios, its flexibility is limited. To fundamentally enhance development efficiency, we have designed a service degradation capability based on Admin. -Dubbo Admin 服务 mock 是一种更为轻量和便捷实现方式,主要用于开发测试阶段的,目标是提升微服务场景下的整体研发效率。需求详见:[Dubbo Admin Mock需求](https://github.com/apache/dubbo-admin/issues/757)。 +The Dubbo Admin service mock is a lighter and more convenient implementation primarily used during the development and testing phases, aiming to enhance overall development efficiency in microservice scenarios. For details on requirements, see: [Dubbo Admin Mock Requirements](https://github.com/apache/dubbo-admin/issues/757). -## 架构设计 +## Architecture Design ![admin-mock-architecture.png](/imgs/v3/reference/admin/console/mock-architecture.png) -**实现 Mock 能力,Dubbo 框架与 Admin 侧要支持的能力** +**Capabilities to Implement Mock in Dubbo Framework and Admin Side** * Dubbo Admin - * 规则管理 - * 规则新增 - * 规则查询 - * 规则修改 - * 规则删除 - * 请求历史记录 - * Mock 请求数据查询 + * Rule Management + * Add Rule + * Query Rule + * Modify Rule + * Delete Rule + * Request History + * Query Mock Request Data * MockService Provider - * 根据规则生成 Mock 数据 - * 响应 Consumer Mock 请求 - * 保存请求和返回数据 + * Generate Mock Data According to Rules + * Respond to Consumer Mock Requests + * Save Requests and Returned Data * Dubbo - * 根据 mock 开关配置,转发请求到 Admin 注册的 MockService - * 处理 mock 返回值并转换为匹配方法签名的强类型数据 + * Forward Requests to Admin Registered MockService Based on Mock Switch Configuration + * Process Mock Return Values and Convert Them to Strongly Typed Data Matching Method Signatures -**Mock 请求原理时序图** +**Mock Request Principle Sequence Diagram** ![admin-mock-workflow.png](/imgs/v3/reference/admin/console/mock-workflow.png) -## 使用方式 +## Usage -1. 在 Consumer 应用中添加依赖 +1. Add dependencies in the Consumer application - 开启 Mock 前,请确保在消费端应用中引入以下依赖: + Before enabling Mock, make sure to include the following dependency in the consumer application: ```xml @@ -62,27 +62,27 @@ Dubbo Admin 服务 mock 是一种更为轻量和便捷实现方式,主要用 ``` - > 查看 [dubbo-mock-admin 的可用版本](/en/download/spi-extensions/) + > Check [available versions of dubbo-mock-admin](/en/download/spi-extensions/) -2. 配置 `-Denable.dubbo.admin.mock=true` 参数开启 Mock 并重启进程 -3. 打开 Admin 配置 Mock 规则 +2. Enable Mock by configuring `-Denable.dubbo.admin.mock=true` and restarting the process. +3. Open Admin to configure Mock rules - 用户可以通过在控制台上指定需要被 mock 的消费端IP、服务名和方法和具体的 mock 行为,实现对调用结果的 mock。 + Users can specify the consumer IP, service name, method, and specific mock behavior that needs to be mocked via the console to achieve mocked calling results. ![admin-mock](/imgs/v3/reference/admin/console/mock-rule-screenshot.png) - 一些支持的规则类型与示例 + Some Supported Rule Types and Examples ``` - 数字类型:123 + Numeric Type: 123 - 字符串:"hello, world!" + String: "hello, world!" - 数组、列表:[1, 2, 3] + Array, List: [1, 2, 3] - 枚举:"ENUM_TYPE" + Enum: "ENUM_TYPE" - Map、对象: + Map, Object: { "prop1": "value1", "prop2": ["a", "b", "c"] @@ -91,32 +91,32 @@ Dubbo Admin 服务 mock 是一种更为轻量和便捷实现方式,主要用 null: null ``` -4. 此时,消费端再次发起远程调用,就会得到预期 Mock 返回值。 +4. At this point, when the consumer initiates a remote call again, it will receive the expected Mock return value. - > 注意事项 - > 1. Mock 仅限用于测试开发环境,因此为了确保核心依赖的稳定性,社区没有将 mock 组件打包在核心框架包中,用户可以自行决策是否将其作为应用的默认依赖在公司内推广 - > 2. 即使添加了 mock 二进制依赖,mock 功能也不会默认开启,需要设置 `-Denable.dubbo.admin.mock=true` 后才能开启。 + > Notes + > 1. Mock is restricted to test and development environments, therefore to ensure the stability of core dependencies, the community has not packaged the mock component in the core framework package. Users can decide whether to promote it as a default dependency within their company. + > 2. Even if the mock binary dependency is added, the mock function will not be enabled by default; it must be configured with `-Denable.dubbo.admin.mock=true` to be activated. -## 实现原理 +## Implementation Principles -Consumer 调用发起的调用会被本地的 MockServiceFilter 拦截,如果 mock 开关开启,则 MockServiceFilter 将请求转发到 MockService (由 Dubbo Admin 发布的服务),MockService 根据请求的服务、方法等查询用户预先配置的 mock 规则,如果查询到则返回规则中的 mock 值,Consumer 收到 mock 值后调用成功返回。 +Calls initiated by the consumer will be intercepted by the local MockServiceFilter. If the mock switch is enabled, the MockServiceFilter will forward the request to the MockService (provided by Dubbo Admin). The MockService will look up the user's preconfigured mock rules based on the requested service and method; if found, it will return the mock value from the rules, and the consumer will receive the mock value and return successfully. -### Mock 返回值如何定义? +### How are Mock Return Values Defined? -当前 Admin 支持录入 JSON 或者基本类型数据,如: +Currently, Admin supports inputting JSON or basic type data, such as: -* 返回数字值 (当方法签名返回值是数字类型) +* Returning numeric values (when the method signature returns a numeric type) ``` 123 ``` -* 返回字符串 (当方法签名返回值是字符串类型) +* Returning strings (when the method signature returns a string type) ``` "hello, world!" ``` -* 返回 JSON (当方法签名返回值是 Map 或对象类型) +* Returning JSON (when the method signature returns a Map or object type) ``` { "prop1": "value1", @@ -124,53 +124,50 @@ Consumer 调用发起的调用会被本地的 MockServiceFilter 拦截,如果 } ``` -* 返回数组 (当方法签名返回值是数组或列表) +* Returning arrays (when the method signature returns an array or list) ``` [1, 2, 3] ``` -### 消费端如何发起 MockService 调用? +### How does the Consumer Initiate MockService Calls? -`dubbo-mock-admin` 将为消费端引入 MockServiceFilter 请求拦截器,如果用户打开 mock 开关,那么 Filter 会将请求转发到 Admin MockService 服务。 +`dubbo-mock-admin` will introduce the MockServiceFilter request interceptor for the consumer. If the user opens the mock switch, the Filter will forward the request to the Admin MockService. -### Mock 值如何转换为原始类型值? +### How are Mock Values Converted to Primitive Type Values? -MockService 支持返回标准 JSON 格式或者基本类型数据,消费端会基于 Dubbo 内置类型转换器将 JSON 等值转为原始对象类型。 +MockService supports returning standard JSON format or basic type data. The consumer will use Dubbo's built-in type converter to convert JSON values to primitive object types. -### 未来优化点 -* 保存 Mock 开关到配置中心,用户可以通过 Admin 动态控制开关。 -* 开启 Mysql 数据库链接池 +### Future Optimization Points +* Save the Mock switch to the configuration center, allowing users to dynamically control the switch through Admin. +* Enable MySQL database connection pooling. -### 表结构设计 -Admin 依赖 Mysql 数据库存储用户配置的 mock 规则,具体的表结构设计如下。 +### Table Structure Design +Admin relies on MySQL database to store user-configured mock rules. The specific table structure design is as follows. #### Mock Rule ```sql CREATE TABLE `mock_rule` ( - `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', - `service_name` varchar(255) DEFAULT NULL COMMENT '服务名', - `method_name` varchar(255) DEFAULT NULL COMMENT '方法名', - `rule` text NULL DEFAULT COMMENT '规则', - `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key', + `service_name` varchar(255) DEFAULT NULL COMMENT 'Service Name', + `method_name` varchar(255) DEFAULT NULL COMMENT 'Method Name', + `rule` text NULL DEFAULT COMMENT 'Rule', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Time', + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update Time', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='服务mock方法表'; +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Service Mock Method Table'; ``` #### Mock Log ```sql CREATE TABLE `mock_log` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id', - `method_id` int(11) DEFAULT NULL COMMENT '规则id', - `request` text COMMENT '请求数据', - `response` text COMMENT '返回值', - `created_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Primary Key ID', + `method_id` int(11) DEFAULT NULL COMMENT 'Rule ID', + `request` text COMMENT 'Request Data', + `response` text COMMENT 'Return Value', + `created_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Time', + `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update Time', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='mock请求记录表'; +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Mock Request Record Table'; ``` - - - diff --git a/content/en/overview/mannual/control-plane/search.md b/content/en/overview/mannual/control-plane/search.md index c8e411164c54..7ee8f6aba1dc 100644 --- a/content/en/overview/mannual/control-plane/search.md +++ b/content/en/overview/mannual/control-plane/search.md @@ -3,53 +3,50 @@ aliases: - /en/overview/reference/admin/search/ - /en/overview/reference/admin/search/ description: "" -linkTitle: 文档查询 -title: Admin 服务查询 +linkTitle: Document Query +title: Admin Service Query type: docs weight: 2 working_in_progress: true --- -Admin 支持可视化的展示 Dubbo 微服务集群的状态,方便用户从全局掌握集群的应用、服务和实例分布,Admin 还可以通过查询的方式了解某一个服务更详细的信息: -* 首页集群大盘,展示集群应用、服务、示例的总体分布,集群总体流量情况等 -* 支持根据应用名、服务名(可包含版本&分组)、实例 IP 查询详细信息 -* 支持服务名/应用名的自动补全 -* 支持查看单条服务实例的详情 +The Admin supports a visual display of the status of the Dubbo microservice cluster, making it easy for users to globally grasp the distribution of applications, services, and instances in the cluster. Admin can also obtain more detailed information about a specific service through queries: +* Home page cluster dashboard, displaying the overall distribution of cluster applications, services, instances, and overall traffic conditions. +* Supports querying detailed information based on application name, service name (can include version & group), instance IP. +* Supports automatic completion of service name/application name. +* Supports viewing the details of a single service instance. -## 首页大盘 +## Home Dashboard ![admin-dashboard](/imgs/v3/reference/admin/console/dashboard.png) -## 根据 Dubbo 服务名查询 +## Query by Dubbo Service Name -精确输入`接口名:版本` 查询服务 +Enter `interface name:version` for precise service query. ![admin-search-service](/imgs/v3/reference/admin/console/admin-search-service.png) -通过 `*` 通配符模糊查询服务 +Use the `*` wildcard for fuzzy service queries. ![admin-search-service2](/imgs/v3/reference/admin/console/admin-search-service.png) -## 根据应用名查询 +## Query by Application Name -输入应用名查询某应用关联的所有服务(包含提供和消费的服务) +Enter the application name to query all services associated with the application (including provided and consumed services). ![admin-search-application](/imgs/v3/reference/admin/console/admin-search-application.png) -## 根据实例 IP 名查询 +## Query by Instance IP Name -输入实例 IP 查询某实例关联的所有服务(包含提供和消费的服务) +Enter the instance IP to query all services associated with the instance (including provided and consumed services). ![admin-search-ip](/imgs/v3/reference/admin/console/admin-search-ip.png) -> 支持基于端口过滤服务 +> Supports filtering services based on port. -## 查看服务实例详情 +## View Service Instance Details -在服务列表点击 `详情` 查看服务详细情况 +Click `Details` in the service list to view the service details. ![admin-search-service-detail](/imgs/v3/reference/admin/console/admin-search-service-detail.png) - - - diff --git a/content/en/overview/mannual/control-plane/test.md b/content/en/overview/mannual/control-plane/test.md index bddd6849a8b0..3991d3d88f32 100644 --- a/content/en/overview/mannual/control-plane/test.md +++ b/content/en/overview/mannual/control-plane/test.md @@ -3,48 +3,48 @@ aliases: - /en/overview/reference/admin/test/ - /en/overview/reference/admin/test/ description: "" -linkTitle: 服务测试 +linkTitle: Service Testing no_list: true -title: Admin 服务测试功能简介 +title: Overview of Admin Service Testing Features type: docs weight: 3 working_in_progress: true --- -服务测试功能通常提供给 Dubbo 服务的开发者使用,用来对自己发布的服务进行自测。通过在 Admin 控制台上模拟真实的消费端进程,对服务提供者发起调用,并验证调用结果是否符合预期。 +The service testing feature is usually provided for developers of Dubbo services to perform self-testing on their published services. By simulating a real consumer process on the Admin console, calls can be made to the service provider, and the results can be verified to meet expectations. -## 使用方式 +## Usage -### 准备用例 -1. 启动用例 +### Prepare Test Cases +1. Start the test case - 可以参考 [快速开始](../../../quickstart/java/) 启动一个简单的 Dubbo 服务,对于服务测试来说,只需要启动 provider 即可。 + You can refer to [Quick Start](../../../quickstart/java/) to start a simple Dubbo service. For service testing, you only need to start the provider. -2. 查询服务 +2. Query Services - 完成服务端部署后,可以到 Admin 的 `服务测试` 页面查询对应的服务: + After deploying the server, you can go to the Admin's `Service Testing` page to query the corresponding service: ![testSearch](/imgs/blog/admin/testSearch.jpg) - 这里的信息和元数据类似,包含方法名,参数类型和返回值信息,点击右边的标签就可以进入服务测试页面 + The information here is similar to metadata and includes method names, parameter types, and return value information. Click the tag on the right to enter the service testing page. -### 执行服务测试 +### Execute Service Test -服务测试页面包含了两个 json 编辑器,参数类型的信息都是以 json 格式保存。 +The service testing page has two JSON editors, where the parameter type information is stored in JSON format. -如以下示例所示,在左侧编辑器中填入对应的参数值(本例中数类型是 `String` ),填写完成后点击 `执行` 即可对服务端发起调用,调用结果展示在右边的编辑器中。 +As shown in the example below, fill in the corresponding parameter values in the left editor (in this example, the data type is `String`), and after filling, click `Execute` to call the server, with results displayed in the right editor. ![testSuccess](/imgs/blog/admin/testSuccess.jpg) -如果调用失败,会显示详细的失败原因,下面来看一下调用失败的例子: +If the call fails, the detailed failure reason will be displayed; below is an example of a failed call: ![testFail](/imgs/blog/admin/testFail.jpg) -本例中,先关掉 Dubbo 服务提供者的进程,再执行服务测试,可以看到返回的结果是`找不到服务提供者`的异常。和普通调用一样,业务和框架的异常都会返回在结果中,方便业务排查。 +In this example, the Dubbo service provider's process is first shut down, and then the service test is executed, resulting in an exception indicating that the `service provider cannot be found`. Similar to ordinary calls, both business and framework exceptions are returned in the results for easier troubleshooting. -### 复合类型参数的填写 +### Filling Complex Type Parameters -考虑 `UserService` 中的以下方法和类型: +Consider the following method and types in `UserService`: ```java //org.apache.dubbo.demo.api.UserService @@ -97,19 +97,20 @@ public class LocationDO { } } ``` -参数是比较复杂的符合类型参数,服务测试的时候,会逐层展开填写每一个field的值,如下图所示: + +The parameters are relatively complex composite type parameters. During service testing, each field's value is filled in layer by layer, as shown in the following image: ![complex](/imgs/blog/admin/complex.jpg) -同样可以调用成功并且返回结果 +It can also be successfully called and return results. -## 原理 +## Principle -### 数据来源 +### Data Source -服务测试中,最重要的就是完整的方法签名信息,和参数的类型信息,有了这些信息才能够一步步填入每个参数的值,拼装出完整的服务消费者。因此,使用服务测试的前提是在 Dubbo 中开启元数据中心(默认开启,Zookeeper、Nacos、Redis 等默认以注册中心做为元数据中心),Dubbo Admin 的方法签名和参数类型信息就是元数据中心来的: +In service testing, the most important aspects are the complete method signature information and parameter type information. With this information, each parameter's value can be filled step by step to assemble a complete service consumer. Therefore, a prerequisite for using service testing is to enable the metadata center in Dubbo (enabled by default, with Zookeeper, Nacos, Redis, etc. defaulting to the registry as the metadata center). The method signature and parameter type information in Dubbo Admin come from the metadata center: ![medatada](/imgs/blog/admin/metadata.png) -如图所示,服务端在运行的时候会将服务的元数据信息注册到元数据中心,格式如下: +As shown in the image, when the server is running, it registers the service's metadata to the metadata center in the following format: ```json { @@ -186,8 +187,9 @@ public class LocationDO { ] } ``` -与服务测试相关的就是`methods`和`types`所包含的方法和类型信息,Dubbo Admin根据这些信息,将参数渲染到服务测试页面的Json Editor中,由用户来输入每个参数,每个成员变量的值。 +The `methods` and `types` containing the method and type information related to service testing are used by Dubbo Admin to render the parameters in the JSON Editor on the service testing page for users to input each parameter's values. + +### Generic Invocation -### 泛化调用 +With the parameter types defined, the next issue is how to invoke the service on the server. In traditional Dubbo RPC calls, clients rely on the server's API jar package (refer to the consumer example in [Quick Start](https://github.com/apache/dubbo-samples/tree/master/1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-consumer)). However, this is not really feasible for Dubbo Admin, as the service's online and offline status is dynamic, and Dubbo Admin cannot dynamically add jar dependencies. Therefore, the [**generic invocation**](../../../mannual/java-sdk/advanced-features-and-usage/service/generic-reference/) feature in Dubbo is utilized, which allows the client to invoke services directly through the `GenericService` interface without needing the server's API interface. The data objects in the return value are represented using Map. No special processing on the server side is needed for generic invocation; it only needs to be initiated by the client. -有了参数类型,下一个问题就是怎么能够调用到服务端,在传统的Dubbo RPC调用中,客户端需要依赖服务端的API jar包 (参考 [Quick Start](https://github.com/apache/dubbo-samples/tree/master/1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-consumer) 中的消费端示例,这对于 Dubbo Admin 来说不太可能,因为服务的上下线是动态的,Dubbo Admin 无法动态增加 jar 包依赖,因此需要用到 Dubbo 中的[**泛化调用**](../../../mannual/java-sdk/advanced-features-and-usage/service/generic-reference/),指的是在没有服务端API接口的情况下,客户端直接通过 `GenericService` 接口来发起服务调用,返回值中的数据对象都用Map来表示。泛化调用在服务端不需要做特殊处理,只需要客户端发起即可。 From 86e2f6e5241222c18d487287efced35445e43a62 Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Mon, 30 Sep 2024 15:10:33 +0800 Subject: [PATCH 10/23] Translate --- content/en/overview/mannual/_index.md | 25 ++-- .../en/overview/mannual/nodejs-sdk/_index.md | 5 +- .../mannual/nodejs-sdk/quick-start.md | 59 ++++---- .../en/overview/mannual/rust-sdk/_index.md | 5 +- .../mannual/rust-sdk/java-interoperability.md | 45 +++--- .../overview/mannual/rust-sdk/quick-start.md | 62 ++++----- .../mannual/rust-sdk/router-module.md | 110 +++++++-------- .../mannual/rust-sdk/service-discovery.md | 131 +++++++++--------- .../en/overview/mannual/rust-sdk/streaming.md | 50 +++---- .../mannual/rust-sdk/unix-transport.md | 37 ++--- content/en/overview/mannual/web-sdk/_index.md | 5 +- .../overview/mannual/web-sdk/quick-start.md | 68 ++++----- 12 files changed, 298 insertions(+), 304 deletions(-) diff --git a/content/en/overview/mannual/_index.md b/content/en/overview/mannual/_index.md index caf922698dcc..2d55af4ee32d 100755 --- a/content/en/overview/mannual/_index.md +++ b/content/en/overview/mannual/_index.md @@ -4,21 +4,21 @@ aliases: - /en/docs3-v2/ - /en/docs3-v2/ always_unfold: true -description: Dubbo SDK 用户手册 +description: Dubbo SDK User Manual feature: description: | - 提供 Java、Golang、Rust、Node.js、Python 等多语言 SDK 实现,支持基于 IDL 的跨语言服务定义和基于 Protobuf、Json 的数据编码 - title: 多语言 SDK -linkTitle: 用户手册 + Provides multi-language SDK implementations such as Java, Golang, Rust, Node.js, Python, etc., supporting language-agnostic service definitions based on IDL and data encoding based on Protobuf and JSON. + title: Multi-language SDK +linkTitle: User Manual no_list: true -title: Dubbo SDK 用户手册 +title: Dubbo SDK User Manual type: docs weight: 6 --- -> 本文档基于 Dubbo3 编写,由于 Dubbo3 完全兼容 2.7 版本用法,因此文档中的通用功能(除 3.x 版本特有功能外)同样适用于 2.7 版本用户。 +> This document is based on Dubbo3. Since Dubbo3 is fully compatible with 2.7 version usage, the general features in this document (except those specific to 3.x version) are also applicable to 2.7 version users. > -> 点此可查看 老版本文档 +> Click here to view the old version documentation > @@ -32,7 +32,7 @@ weight: 6

Java SDK

-

Dubbo Java SDK 手册

+

Dubbo Java SDK Manual

@@ -42,7 +42,7 @@ weight: 6

Go SDK

-

Dubbo Golang SDK 手册

+

Dubbo Golang SDK Manual

@@ -52,7 +52,7 @@ weight: 6

Node.js

-

Dubbo Node.js SDK 手册

+

Dubbo Node.js SDK Manual

@@ -62,7 +62,7 @@ weight: 6

Web SDK

-

Dubbo Web SDK 手册

+

Dubbo Web SDK Manual

@@ -72,7 +72,7 @@ weight: 6

Rust SDK

-

Dubbo Rust SDK 手册

+

Dubbo Rust SDK Manual

@@ -81,3 +81,4 @@ weight: 6 {{< /blocks/section >}} + diff --git a/content/en/overview/mannual/nodejs-sdk/_index.md b/content/en/overview/mannual/nodejs-sdk/_index.md index 294410b450f9..d58dba8cd7ee 100755 --- a/content/en/overview/mannual/nodejs-sdk/_index.md +++ b/content/en/overview/mannual/nodejs-sdk/_index.md @@ -1,7 +1,8 @@ --- -description: Node.js SDK 使用手册 +description: Node.js SDK User Manual linkTitle: Node.js SDK -title: Node.js SDK 手册 +title: Node.js SDK Manual type: docs weight: 3 --- + diff --git a/content/en/overview/mannual/nodejs-sdk/quick-start.md b/content/en/overview/mannual/nodejs-sdk/quick-start.md index e895f01fcd7c..55d2e6e0c700 100644 --- a/content/en/overview/mannual/nodejs-sdk/quick-start.md +++ b/content/en/overview/mannual/nodejs-sdk/quick-start.md @@ -2,36 +2,36 @@ aliases: - /en/overview/quickstart/nodejs/ - /en/overview/quickstart/nodejs/ -description: 使用 Node.js 开发后端微服务 -linkTitle: 快速开始 -title: 快速开始 +description: Develop backend microservices using Node.js +linkTitle: Quick Start +title: Quick Start type: docs weight: 1 --- -基于 Dubbo 定义的 Triple 协议,你可以轻松编写浏览器、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。Dubbo Node.js SDK 支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 API 来发布或调用这些服务。 +Based on the Triple protocol defined by Dubbo, you can easily write browser and gRPC compatible RPC services that run simultaneously on HTTP/1 and HTTP/2. The Dubbo Node.js SDK supports defining services using IDL or language-specific methods and provides a lightweight API for publishing or invoking these services. -本示例演示了基于 Triple 协议的 RPC 通信模式,示例使用 Protocol Buffer 定义 RPC 服务,并演示了代码生成、服务发布和服务访问等过程。 +This example demonstrates the RPC communication model based on the Triple protocol, using Protocol Buffers to define RPC services, and illustrating processes such as code generation, service publishing, and service access. -## 前置条件 +## Preconditions -因为使用 Protocol Buffer 的原因,我们首先需要安装相关的代码生成工具,这包括 `@bufbuild/protoc-gen-es`、`@bufbuild/protobuf`、`@apachedubbo/protoc-gen-apache-dubbo-es`、`@apachedubbo/dubbo`。 +Due to the use of Protocol Buffers, we first need to install the relevant code generation tools, including `@bufbuild/protoc-gen-es`, `@bufbuild/protobuf`, `@apachedubbo/protoc-gen-apache-dubbo-es`, `@apachedubbo/dubbo`. ```Shell npm install @bufbuild/protoc-gen-es @bufbuild/protobuf @apachedubbo/protoc-gen-apache-dubbo-es @apachedubbo/dubbo ``` -## 定义服务 +## Define Service -现在,使用 Protocol Buffer (IDL) 来定义一个 Dubbo 服务。 +Now, use Protocol Buffers (IDL) to define a Dubbo service. -创建目录,并生成文件 +Create a directory and generate a file. ```Shell mkdir -p proto && touch proto/example.proto ``` -写入内容 +Write the content. ```Protobuf syntax = "proto3"; @@ -51,17 +51,17 @@ service ExampleService { } ``` -这个文件声明了一个叫做 `ExampleService` 的服务,为这个服务定义了 `Say` 方法以及它的请求参数 `SayRequest` 和返回值 `SayResponse`。 +This file declares a service called `ExampleService`, defining a `Say` method along with its request parameter `SayRequest` and return value `SayResponse`. -## 生成代码 +## Generate Code -创建 gen 目录,做为生成文件放置的目标目录 +Create a gen directory as the target directory for generated files. ``` mkdir -p gen ``` -运行以下命令,在 gen 目录下生成代码文件 +Run the following command to generate code files in the gen directory. ```Shell PATH=$PATH:$(pwd)/node_modules/.bin \ @@ -73,7 +73,7 @@ PATH=$PATH:$(pwd)/node_modules/.bin \ example.proto ``` -运行命令后,应该可以在目标目录中看到以下生成的文件: +After running the command, you should see the following generated files in the target directory: ```Plain Text ├── gen @@ -83,11 +83,11 @@ PATH=$PATH:$(pwd)/node_modules/.bin \ │ └── example.proto ``` -## 实现服务 +## Implement Service -接下来我们就需要添加业务逻辑了,实现 ExampleService ,并将其注册到 DubboRouter 中。 +Next, we'll need to add business logic to implement ExampleService and register it with DubboRouter. -创建 dubbo.ts 文件 +Create a dubbo.ts file. ```typescript import { DubboRouter } from "@apachedubbo/dubbo"; @@ -105,17 +105,15 @@ export default (router: DubboRouter) => }, { serviceGroup: 'dubbo', serviceVersion: '1.0.0' }); ``` -## 启动 Server +## Start Server -Dubbo 服务可以嵌入到普通的 Node.js 服务器、Next.js、Express 或 Fastify 中。 -在这里我们将使用 Fastify,所以让我们安装 Fastify 以及我们为 Fastify 准备的插件。 +Dubbo services can be embedded into a regular Node.js server, Next.js, Express, or Fastify. Here we will use Fastify, so let's install Fastify and the plugin we prepared for Fastify. ```Shell npm install fastify @apachedubbo/dubbo-fastify ``` -创建 server.ts 文件,新建一个 Server,把上一步中实现的 `ExampleService` 注册给它。 -接下来就可以直接初始化和启动 Server 了,它将在指定的端口接收请求。 +Create a server.ts file, create a Server, and register the implemented `ExampleService` from the previous step. Then initialize and start the Server, which will receive requests on the specified port. ```typescript import { fastify } from "fastify"; @@ -138,15 +136,15 @@ async function main() { void main(); ``` -最后,运行代码启动服务 +Finally, run the code to start the service. ```Shell npx tsx server.ts ``` -## 访问服务 +## Access Service -最简单方式是使用 HTTP/1.1 POST 请求访问服务,参数则作以标准 JSON 格式作为 HTTP 负载传递。如下是使用 cURL 命令的访问示例: +The simplest way to access the service is to use an HTTP/1.1 POST request, passing parameters in standard JSON format as the HTTP payload. Below is an example using the cURL command: ```Shell curl \ @@ -157,9 +155,9 @@ curl \ http://localhost:8080/apache.dubbo.demo.example.v1.ExampleService/Say ``` -也可以使用标准的 Dubbo client 请求服务,我们首先需要从生成代码即 dubbo-node 包中获取服务代理,为它指定 server 地址并初始化,之后就可以发起起 RPC 调用了。 +You can also use a standard Dubbo client to request the service. We first need to get the service proxy from the generated code, i.e., the dubbo-node package, specify the server address for it, and initialize it before we can make the RPC call. -创建 client.ts 文件。 +Create a client.ts file. ```typescript import { createPromiseClient } from "@apachedubbo/dubbo"; @@ -179,8 +177,9 @@ async function main() { void main(); ``` -运行客户端 +Run the client. ```Shell npx tsx client.ts ``` + diff --git a/content/en/overview/mannual/rust-sdk/_index.md b/content/en/overview/mannual/rust-sdk/_index.md index 3bd8c9ccfb3f..5a62fe5d4b33 100755 --- a/content/en/overview/mannual/rust-sdk/_index.md +++ b/content/en/overview/mannual/rust-sdk/_index.md @@ -2,9 +2,10 @@ aliases: - /en/docs3-v2/rust-sdk/ - /en/docs3-v2/rust-sdk/ -description: Rust SDK 使用手册 +description: Rust SDK User Manual linkTitle: Rust SDK -title: Rust SDK 手册 +title: Rust SDK Manual type: docs weight: 5 --- + diff --git a/content/en/overview/mannual/rust-sdk/java-interoperability.md b/content/en/overview/mannual/rust-sdk/java-interoperability.md index afc3e5d1cf23..93f4441cd5bf 100644 --- a/content/en/overview/mannual/rust-sdk/java-interoperability.md +++ b/content/en/overview/mannual/rust-sdk/java-interoperability.md @@ -2,9 +2,9 @@ aliases: - /en/docs3-v2/rust-sdk/java-interoperability/ - /en/docs3-v2/rust-sdk/java-interoperability/ -description: 使用 Rust 调用 Java 开发的 Dubbo 服务。 -linkTitle: Rust和Java互相调用 -title: Rust和Java互相调用 +description: Call Dubbo services developed in Java using Rust. +linkTitle: Interoperability between Rust and Java +title: Interoperability between Rust and Java type: docs weight: 2 --- @@ -14,48 +14,48 @@ weight: 2 -## 1 前置条件 -- 安装 [Rust](https://rustup.rs/) 开发环境 -- 安装 [protoc](https://grpc.io/docs/protoc-installation/) 工具 -- 安装 Java 开发环境 +## 1 Prerequisites +- Install the [Rust](https://rustup.rs/) development environment +- Install the [protoc](https://grpc.io/docs/protoc-installation/) tool +- Install the Java development environment -## 2 运行示例 Java 版本的 Dubbo provider +## 2 Run the Example Java Version of Dubbo Provider -Java 版本的 Dubbo provider 示例源码见。 +The source code for the Java version of the Dubbo provider can be found at . -Clone 源代码、编译构建,并运行 provider: +Clone the source code, compile, and run the provider: ```sh -$ # clone 源代码 +$ # clone the source code $ git clone https://github.com/apache/dubbo-samples.git $ cd dubbo-samples/dubbo-samples-triple/ -$ # 构建 +$ # build $ mvn clean compile package -DskipTests -$ # 运行 provider +$ # run the provider $ java -Dprovider.port=8888 -jar ./target/dubbo-samples-triple-1.0-SNAPSHOT.jar -# ……省略部分日志 +# … omitted part of the logs Dubbo triple stub server started, port=8888 ``` -[Java 侧的接口定义](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/proto/greeter.proto) +[Interface definition on the Java side](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/proto/greeter.proto) -## 3 运行 Rust 版本的 Dubbo consumer +## 3 Run the Rust Version of Dubbo Consumer -Rust 版本的 Dubbo consumer 示例源码见。 +The source code for the Rust version of the Dubbo consumer can be found at . -Clone 源代码、编译构建,并运行 consumer: +Clone the source code, compile, and run the consumer: ```sh -$ # clone 源代码 +$ # clone the source code $ git clone https://github.com/apache/dubbo-rust.git $ cd dubbo-rust/examples/greeter/ -$ # 构建 +$ # build $ cargo build -$ # 运行 consumer,调用provider +$ # run the consumer, call the provider $ ../../target/debug/greeter-client # unary call Response: GreeterReply { message: "hello, dubbo-rust" } @@ -75,4 +75,5 @@ reply: GreeterReply { message: "msg3 from server" } trailer: Some(Metadata { inner: {"content-type": "application/grpc", "grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity", "grpc-status": "0"} }) ``` -[Rust侧的接口定义](https://github.com/apache/dubbo-rust/blob/main/examples/greeter/proto/greeter.proto) +[Interface definition on the Rust side](https://github.com/apache/dubbo-rust/blob/main/examples/greeter/proto/greeter.proto) + diff --git a/content/en/overview/mannual/rust-sdk/quick-start.md b/content/en/overview/mannual/rust-sdk/quick-start.md index 567603a79436..3fbba902bb25 100644 --- a/content/en/overview/mannual/rust-sdk/quick-start.md +++ b/content/en/overview/mannual/rust-sdk/quick-start.md @@ -4,9 +4,9 @@ aliases: - /en/docs3-v2/rust-sdk/quick-start/ - /en/overview/quickstart/rust/ - /en/overview/quickstart/rust/ -description: 使用 Rust 快速开发 Dubbo 服务。 -linkTitle: 快速开始 -title: 快速开始 +description: Quickly develop Dubbo services using Rust. +linkTitle: Quick Start +title: Quick Start type: docs weight: 1 --- @@ -16,15 +16,15 @@ weight: 1 -请在此查看完整 [示例](https://github.com/apache/dubbo-rust/tree/main/examples/greeter)。 +View the complete [example](https://github.com/apache/dubbo-rust/tree/main/examples/greeter) here. -## 1 前置条件 -- 安装 [Rust](https://rustup.rs/) 开发环境 -- 安装 [protoc](https://grpc.io/docs/protoc-installation/) 工具 +## 1 Prerequisites +- Install the [Rust](https://rustup.rs/) development environment +- Install the [protoc](https://grpc.io/docs/protoc-installation/) tool -## 2 使用 IDL 定义 Dubbo 服务 +## 2 Define Dubbo Services Using IDL -Greeter 服务定义如下,包含一个 Unary(request-response) 模型的 Dubbo 服务。 +The Greeter service is defined as follows, including a Dubbo service with a Unary (request-response) model. ```protobuf // ./proto/greeter.proto @@ -51,7 +51,7 @@ service Greeter{ } ``` -## 3 添加 Dubbo-rust 及相关依赖到项目 +## 3 Add Dubbo-rust and Related Dependencies to the Project ```toml # ./Cargo.toml [package] @@ -84,9 +84,9 @@ dubbo-config = "0.1.0" dubbo-build = "0.1.0" ``` -## 4 配置 dubbo-build 编译 IDL +## 4 Configure dubbo-build to Compile IDL -在项目根目录创建 (not /src),创建 `build.rs` 文件并添加以下内容: +Create a `build.rs` file in the project root directory (not /src) and add the following content: ```rust // ./build.rs @@ -96,11 +96,11 @@ fn main() { .unwrap(); } ``` -这样配置之后,编译项目就可以生成 Dubbo Stub 相关代码,路径一般在`./target/debug/build/example-greeter-/out/org.apache.dubbo.sample.tri.rs`。 +After this configuration, compiling the project will generate related Dubbo Stub code, usually located at `./target/debug/build/example-greeter-/out/org.apache.dubbo.sample.tri.rs`. -## 5 编写 Dubbo 业务代码 +## 5 Write Dubbo Business Code -### 5.1 编写 Dubbo Server +### 5.1 Write Dubbo Server ```rust // ./src/greeter/server.rs @@ -147,9 +147,9 @@ impl Greeter for GreeterServerImpl { } ``` -### 5.2 配置dubbo.yaml +### 5.2 Configure dubbo.yaml -dubbo.yaml指示server端的配置,包括暴露的服务列表、协议配置、监听配置等。 +The dubbo.yaml file specifies the server-side configuration, including the exposed service list, protocol configuration, listening configuration, etc. ```yaml # ./dubbo.yaml @@ -173,7 +173,7 @@ protocols: name: triple ``` -### 5.3 编写 Dubbo Client +### 5.3 Write Dubbo Client ```rust // ./src/greeter/client.rs @@ -198,32 +198,31 @@ async fn main() { } ``` -## 6 运行并总结 +## 6 Run and Summarize -1. 编译 +1. Compile -执行`cargo build`来编译server和client。 +Run `cargo build` to compile the server and client. -2. 运行server +2. Run the server -执行`./target/debug/greeter-server`来运行server,如上文dubbo.yaml所配置,server会监听8888端口,并以triple协议提供RPC服务: +Run `./target/debug/greeter-server` to start the server, which will listen on port 8888 and provide RPC services using the triple protocol as configured in dubbo.yaml: ```sh $ ./target/debug/greeter-server 2022-09-28T23:33:28.104577Z INFO dubbo::framework: url: Some(Url { uri: "triple://0.0.0.0:8888/org.apache.dubbo.sample.tri.Greeter", protocol: "triple", location: "0.0.0.0:8888", ip: "0.0.0.0", port: "8888", service_key: ["org.apache.dubbo.sample.tri.Greeter"], params: {} }) ``` -3. 运行client,验证调用是否成功 - -执行`./target/debug/greeter-client`来运行client,调用`triple://127.0.0.1:8888/org.apache.dubbo.sample.tri.Greeter`下的各种方法: +3. Run the client to verify successful invocation +Run `./target/debug/greeter-client` to execute the client and call various methods under `triple://127.0.0.1:8888/org.apache.dubbo.sample.tri.Greeter`: ```sh $ ./target/debug/greeter-client Response: GreeterReply { message: "hello, dubbo-rust" } ``` -## 7 更多示例 +## 7 More Examples {{< blocks/section color="white" height="auto">}}
@@ -233,9 +232,9 @@ Response: GreeterReply { message: "hello, dubbo-rust" }

- Streaming 通信模式 + Streaming Communication Mode

-

使用 Dubbo Rust 实现 Streaming 通信模型。

+

Implement Streaming communication model using Dubbo Rust.

@@ -243,9 +242,9 @@ Response: GreeterReply { message: "hello, dubbo-rust" }

- 与 Dubbo Java 互通 + Interoperability with Dubbo Java

-

实现与其他 Dubbo 多语言服务的互通

+

Implement interoperability with other Dubbo multi-language services.

@@ -254,3 +253,4 @@ Response: GreeterReply { message: "hello, dubbo-rust" } {{< /blocks/section >}} + diff --git a/content/en/overview/mannual/rust-sdk/router-module.md b/content/en/overview/mannual/rust-sdk/router-module.md index d4ce0da00900..aa3b0c597f29 100644 --- a/content/en/overview/mannual/rust-sdk/router-module.md +++ b/content/en/overview/mannual/rust-sdk/router-module.md @@ -2,18 +2,17 @@ aliases: - /en/docs3-v2/rust-sdk/router-module/ - /en/docs3-v2/rust-sdk/router-module/ -description: "服务路由" -linkTitle: 服务路由 -title: 服务路由规则 +description: "Service Routing" +linkTitle: Service Routing +title: Service Routing Rules type: docs weight: 2 --- -## 条件路由 -使用模式与 [条件路由文档](/en/overview/core-features/traffic/condition-rule/) 中的模式类似,但配置格式略有不同,以下是条件路由规则示例。 +## Conditional Routing +The usage pattern is similar to the [Conditional Routing Documentation](/en/overview/core-features/traffic/condition-rule/), but the configuration format is slightly different. Below is an example of conditional routing rules. -基于以下示例规则,所有 `org.apache.dubbo.sample.tri.Greeter` 服务 `greet` -方法的调用都将被转发到有 `port=8888` 标记的地址子集 +Based on the following example rule, all calls to the `greet` method of the `org.apache.dubbo.sample.tri.Greeter` service will be forwarded to a subset of addresses marked with `port=8888`. ```yaml configVersion: v1.0 @@ -24,11 +23,11 @@ key: "org.apache.dubbo.sample.tri.Greeter" conditions: - method=greet => port=8888 ``` -注:
-dubbo rust目前还没有实现对于**应用粒度**的区分,无法区分服务来自哪个应用
-因此对于标签路由和条件路由,都仅能配置一条应用级别的配置
-对于应用级别的配置,默认key指定为application,此配置将对全部服务生效
-例如: +Note:
+The Dubbo Rust currently does not distinguish at the **application level**, and cannot differentiate the origin of the service.
+Therefore, for tag routing and conditional routing, only one application-level configuration can be specified.
+For application-level configuration, the default key is set to application, and this configuration will affect all services.
+For example: ```yaml configVersion: v1.0 scope: "application" @@ -39,28 +38,28 @@ conditions: - ip=127.0.0.1 => port=8000~8888 ``` -#### 匹配/过滤条件 +#### Match/Filter Conditions -**参数支持** +**Parameter Support** -* 服务调用上下文,如:service_name, method等 -* URL 本身的字段,如:location, ip, port等 -* URL params中存储的字段信息 +* Service call context, such as: service_name, method, etc. +* URL fields, such as: location, ip, port, etc. +* Field information stored in URL params. -**条件支持** +**Condition Support** -* 等号 = 表示 "匹配",如:method = getComment -* 不等号 != 表示 "不匹配",如:method != getComment +* Equal sign = indicates "match", e.g.: method = getComment +* Not equal != indicates "no match", e.g.: method != getComment -**值支持** +**Value Support** -* 以逗号 , 分隔多个值,如:ip != 10.20.153.10,10.20.153.11 -* 以星号 * 结尾,表示通配,如:ip != 10.20.* -* 整数值范围,如:port = 80~8080 +* Multiple values separated by comma, e.g.: ip != 10.20.153.10,10.20.153.11 +* Asterisk * at the end indicates a wildcard, e.g.: ip != 10.20.* +* Integer value range, e.g.: port = 80~8080 -## 标签路由 -使用模式与 [标签路由文档](/en/overview/core-features/traffic/tag-rule/)中的模式类似,但配置格式略有不同,以下是标签路由规则示例 +## Tag Routing +The usage pattern is similar to the [Tag Routing Documentation](/en/overview/core-features/traffic/tag-rule/), but the configuration format is slightly different. Below is an example of tag routing rules. ```yaml configVersion: v1.0 force: false @@ -72,12 +71,12 @@ tags: - key: ip value: 127.0.0.1 ``` -在此配置中,所有ip=127.0.0.1的服务提供者/消费者均会被打上local的标签 +In this configuration, all service providers/consumers with ip=127.0.0.1 will be tagged with local. -## 动态配置 -### 动态下发配置 简介 -动态下发配置使用 Nacos 作为配置中心实现,需要在项目的 application.yaml 配置文件中对 Nacos 进行配置,若不进行配置则使用本地路由配置。 -### 使用方式: +## Dynamic Configuration +### Overview of Dynamic Configuration +Dynamic configuration uses Nacos as the configuration center. It needs to be configured in the project's application.yaml file; if not configured, local routing configuration will be used. +### Usage: ```yaml nacos: addr: "127.0.0.1:8848" @@ -87,38 +86,38 @@ nacos: auth_username: username auth_password: password ``` -app:路由配置项在Nacos中所处的app -namespace:配置信息在Nacos所处的namespace -addr:Nacos服务地址 -enable_auth:可选配置项,若启用了Nacos的认证功能,则需要配置此项,auth_username对应帐号,auth_password对应密钥 +app: the app where routing configurations are placed in Nacos. +namespace: the namespace where configuration information is located in Nacos. +addr: the Nacos service address. +enable_auth: optional configuration; if Nacos's authentication feature is enabled, this must be specified. auth_username corresponds to the account, auth_password to the key. -#### 配置条件路由 +#### Configuring Conditional Routing -在nacos中创建条件路由配置项时, -app和namespace为配置nacos时所填写的信息; -group:固定为condition; -name:需要和 服务名称 保持一致; +When creating conditional routing configurations in Nacos, +app and namespace are the information input during Nacos configuration; +group: fixed as condition; +name: must match the service name; -#### 配置标签路由 -在nacos中创建标签路由配置项时, +#### Configuring Tag Routing +When creating tag routing configurations in Nacos, -app:配置nacos时所填写的app; -namespace:配置nacos时所填写的namespace; -group:固定为tag; -name:固定为application; +app: the app filled in during Nacos configuration; +namespace: the namespace filled in during Nacos configuration; +group: fixed as tag; +name: fixed as application; -#### 注意事项 -dubbo rust目前还没有实现对于**应用**的区分,无法区分服务来自哪个应用; -故对于应用级别的配置项,默认对所有服务生效 -因此对于标签路由和条件路由,都仅能配置一条应用级别的配置,配置名称(name)指定为application +#### Notes +Dubbo Rust does not currently differentiate at the **application** level and cannot identify the source of a service; +therefore, application-level configurations will apply to all services by default. +Thus, for tag routing and conditional routing, only one application-level configuration can be specified with the name designated as application. -#### 例: +#### Example: ![nacos-example.png](/imgs/rust/router-example/nacos-example.png) -#### 对应的配置项: +#### Corresponding Configuration Items: -*服务级别的条件路由配置:* +*Service Level Conditional Routing Configuration:* ```yaml configVersion: v1.0 scope: "service" @@ -128,7 +127,7 @@ key: "org.apache.dubbo.sample.tri.Greeter" conditions: - method=greet => ip=127.* ``` -*标签路由配置:* +*Tag Routing Configuration:* ```yaml configVersion: v1.0 force: true @@ -141,7 +140,7 @@ tags: value: 127.0.0.1 ``` -*应用级别的条件路由配置:* +*Application Level Conditional Routing Configuration:* ```yaml configVersion: v1.0 scope: "application" @@ -151,3 +150,4 @@ key: application conditions: - ip=127.0.0.1 => port=8000~8888 ``` + diff --git a/content/en/overview/mannual/rust-sdk/service-discovery.md b/content/en/overview/mannual/rust-sdk/service-discovery.md index d1fcaaea38c5..edfc1b5b34a2 100644 --- a/content/en/overview/mannual/rust-sdk/service-discovery.md +++ b/content/en/overview/mannual/rust-sdk/service-discovery.md @@ -2,99 +2,100 @@ aliases: - /en/docs3-v2/rust-sdk/service-discovery/ - /en/docs3-v2/rust-sdk/service-discovery/ -description: 服务发现 -linkTitle: 服务发现 -title: 服务发现 +description: Service Discovery +linkTitle: Service Discovery +title: Service Discovery type: docs weight: 2 --- -## Dubbo Rust服务发现简介 -Dubbo Rust提供的是一种 Client-Based 的服务发现机制,依赖第三方注册中心组件来协调服务发现过程,支持的注册中心: Nacos、Zookeeper +## Introduction to Dubbo Rust Service Discovery +Dubbo Rust provides a client-based service discovery mechanism that relies on third-party registry components to coordinate the service discovery process. Supported registries: Nacos, Zookeeper. -以下是 Dubbo Rust服务发现机制的基本工作原理图: +The following is a basic working principle diagram of the Dubbo Rust service discovery mechanism: ![service-discovery](/imgs/rust/dubbo-rust-service-discovery.png) -服务发现包含提供者、消费者和注册中心三个参与角色,其中,Dubbo 提供者实例注册 URL 地址到注册中心,注册中心负责对数据进行聚合,Dubbo 消费者从注册中心读取地址列表并订阅变更,每当地址列表发生变化,注册中心将最新的列表通知到所有订阅的消费者实例。 +Service discovery involves three participant roles: provider, consumer, and registry. The Dubbo provider instance registers its URL with the registry, which is responsible for aggregating the data. The Dubbo consumer reads the address list from the registry and subscribes to changes. Whenever the address list changes, the registry notifies all subscribed consumer instances with the latest list. -* Dubbo Rust注册中心以服务粒度聚合实例数据,消费者按消费需求精准订阅。 +* Dubbo Rust aggregates instance data at the service granularity, allowing consumers to accurately subscribe based on their consumption needs. -Dubbo Rust服务发现的一个示例:[example](https://github.com/apache/dubbo-rust/tree/feat/cluster/examples/greeter) +An example of Dubbo Rust service discovery: [example](https://github.com/apache/dubbo-rust/tree/feat/cluster/examples/greeter) -## 高效地址推送实现 +## Efficient Address Push Implementation -从注册中心视角来看,它负责以服务名 (例如:org.apache.dubbo.sample.tri.Greeter) 对整个集群的实例地址进行聚合,每个对外提供服务的实例将自身的实例ip:port 地址信息 (例如:127.0.0.1:8848) 注册到注册中心。 +From the perspective of the registry, it aggregates the instance addresses of the entire cluster by service name (e.g., org.apache.dubbo.sample.tri.Greeter). Each service-providing instance registers its IP:port address information (e.g., 127.0.0.1:8848) with the registry. -## 配置方式 -Dubbo Rust服务发现支持两种注册中心组件,既Nacos、Zookeeper,可以通过以下方式创建不同的注册中心,并将其绑定到Dubbo Rust框架。 +## Configuration Methods +Dubbo Rust service discovery supports two types of registry components: Nacos and Zookeeper. Different registries can be created and bound to the Dubbo Rust framework as follows. -配置方式: -假设有服务:Greeter,对应的服务实现为GreeterServerImpl +Configuration method: +Assuming there is a service: Greeter, the corresponding service implementation is GreeterServerImpl. -服务端: +Server: ``` - //注册服务 - register_server(GreeterServerImpl { - name: "greeter".to_string(), - }); - - //创建注册中心 - let zkr = ZookeeperRegistry::default(); - - let r = RootConfig::new(); - let r = match r.load() { - Ok(config) => config, - Err(_err) => panic!("err: {:?}", _err), // response was droped - }; - - //启动Dubbo框架 - let mut f = Dubbo::new() - .with_config(r) - //将创建出的注册中心绑定Dubbo框架 - .add_registry("zookeeper", Box::new(zkr)); - f.start().await; +// Register service +register_server(GreeterServerImpl { + name: "greeter".to_string(), +}); + +// Create registry +let zkr = ZookeeperRegistry::default(); + +let r = RootConfig::new(); +let r = match r.load() { + Ok(config) => config, + Err(_err) => panic!("err: {:?}", _err), // response was dropped +}; + +// Start Dubbo framework +let mut f = Dubbo::new() + .with_config(r) + // Bind the created registry to the Dubbo framework + .add_registry("zookeeper", Box::new(zkr)); +f.start().await; ``` -对于上述过程,可以通过修改创建注册中心的步骤来更改所使用的注册中心 +For the above process, the registry used can be changed by modifying the steps to create the registry. -客户端: +Client: ``` - let mut builder = ClientBuilder::new(); - - //通过env获取注册中心地址 - if let Ok(zk_servers) = env::var("ZOOKEEPER_SERVERS") { - //创建注册中心 - let zkr = ZookeeperRegistry::new(&zk_servers); - //绑定注册中心 - let directory = RegistryDirectory::new(Box::new(zkr)); - builder = builder.with_directory(Box::new(directory)); - } else if let Ok(nacos_url_str) = env::var("NACOS_URL") { - // NACOS_URL=nacos://mse-96efa264-p.nacos-ans.mse.aliyuncs.com - //创建注册中心 - let nacos_url = Url::from_url(&nacos_url_str).unwrap(); - let registry = NacosRegistry::new(nacos_url); - //绑定注册中心 - let directory = RegistryDirectory::new(Box::new(registry)); - builder = builder.with_directory(Box::new(directory)); - } else { - builder = builder.with_host("http://127.0.0.1:8888"); - } - - let mut cli = GreeterClient::new(builder); +let mut builder = ClientBuilder::new(); + +// Get registry address via env +if let Ok(zk_servers) = env::var("ZOOKEEPER_SERVERS") { + // Create registry + let zkr = ZookeeperRegistry::new(&zk_servers); + // Bind registry + let directory = RegistryDirectory::new(Box::new(zkr)); + builder = builder.with_directory(Box::new(directory)); +} else if let Ok(nacos_url_str) = env::var("NACOS_URL") { + // NACOS_URL=nacos://mse-96efa264-p.nacos-ans.mse.aliyuncs.com + // Create registry + let nacos_url = Url::from_url(&nacos_url_str).unwrap(); + let registry = NacosRegistry::new(nacos_url); + // Bind registry + let directory = RegistryDirectory::new(Box::new(registry)); + builder = builder.with_directory(Box::new(directory)); +} else { + builder = builder.with_host("http://127.0.0.1:8888"); +} + +let mut cli = GreeterClient::new(builder); ``` -创建Nacos注册中心: +Create Nacos registry: ``` -//通过Url创建注册中心实例 +// Create registry instance through Url let nacos_url = Url::from_url("127.0.0.1:1221").unwrap(); let registry = NacosRegistry::new(nacos_url); ``` -创建Zookeeper注册中心: +Create Zookeeper registry: ``` -//直接创建Zookeeper注册中心 +// Directly create Zookeeper registry let zkr = ZookeeperRegistry::new("127.0.0.1:1221"); ``` ``` -//使用default方法创建Zookeeper注册中心会默认使用环境变量中的值ZOOKEEPER_SERVERS +// Using the default method to create Zookeeper registry will use the value of ZOOKEEPER_SERVERS in the environment variables by default let zkr = ZookeeperRegistry::default(); ``` + diff --git a/content/en/overview/mannual/rust-sdk/streaming.md b/content/en/overview/mannual/rust-sdk/streaming.md index ad93bc4e3d2d..907bca2b9134 100644 --- a/content/en/overview/mannual/rust-sdk/streaming.md +++ b/content/en/overview/mannual/rust-sdk/streaming.md @@ -2,9 +2,9 @@ aliases: - /en/docs3-v2/rust-sdk/streaming/ - /en/docs3-v2/rust-sdk/streaming/ -description: 介绍使用 Dubbo Rust 快速开发 Client streaming、Server streaming、Bidirectional streaming 模型的服务。 -linkTitle: Streaming通信模型 -title: Streaming 通信模型 +description: Introduction to using Dubbo Rust to quickly develop services for Client streaming, Server streaming, and Bidirectional streaming models. +linkTitle: Streaming Communication Model +title: Streaming Communication Model type: docs weight: 3 --- @@ -14,11 +14,11 @@ weight: 3 -本文重点讲解 Dubbo Rust Streaming 通信模式,请先查看 [Quick Start](../quick-start) 了解 Dubbo Rust 基本使用,在此查看本文的[完整示例](https://github.com/apache/dubbo-rust/tree/main/examples/greeter)。 +This article focuses on the Dubbo Rust Streaming communication pattern. Please refer to the [Quick Start](../quick-start) to understand the basic usage of Dubbo Rust and view the [complete example](https://github.com/apache/dubbo-rust/tree/main/examples/greeter) for this article. -## 1 IDL 中增加 Streaming 模型定义 +## 1 Adding Streaming Model Definitions in IDL -完整 Greeter 服务定义如下,包含一个 Unary、Client stream、Server stream、Bidirectional stream 模型的 Dubbo 服务。 +The complete Greeter service definition is as follows, which includes a Unary, Client stream, Server stream, and Bidirectional stream model for Dubbo services. ```protobuf // ./proto/greeter.proto @@ -56,9 +56,9 @@ service Greeter{ } ``` -## 2 使用 Streaming 模型定义编写逻辑 +## 2 Writing Logic with Streaming Model Definitions -### 2.1 编写 Streaming Server +### 2.1 Writing the Streaming Server ```rust // ./src/greeter/server.rs @@ -97,7 +97,7 @@ async fn main() { let r = RootConfig::new(); match r.load() { Ok(config) => config, - Err(_err) => panic!("err: {:?}", _err), // response was droped + Err(_err) => panic!("err: {:?}", _err), // response was dropped } }) .start() @@ -178,19 +178,10 @@ impl Greeter for GreeterServerImpl { let mut in_stream = request.into_inner(); let (tx, rx) = mpsc::channel(128); - // this spawn here is required if you want to handle connection error. - // If we just map `in_stream` and write it back as `out_stream` the `out_stream` - // will be drooped when connection error occurs and error will never be propagated - // to mapped version of `in_stream`. tokio::spawn(async move { while let Some(result) = in_stream.next().await { match result { Ok(v) => { - // if v.name.starts_with("msg2") { - // tx.send(Err(dubbo::status::Status::internal(format!("err: args is invalid, {:?}", v.name)) - // )).await.expect("working rx"); - // continue; - // } tx.send(Ok(GreeterReply { message: format!("server reply: {:?}", v.name), })) @@ -200,8 +191,6 @@ impl Greeter for GreeterServerImpl { Err(err) => { if let Some(io_err) = match_for_io_error(&err) { if io_err.kind() == ErrorKind::BrokenPipe { - // here you can handle special case when client - // disconnected in unexpected way eprintln!("\tclient disconnected: broken pipe"); break; } @@ -209,7 +198,7 @@ impl Greeter for GreeterServerImpl { match tx.send(Err(err)).await { Ok(_) => (), - Err(_err) => break, // response was droped + Err(_err) => break, } } } @@ -217,7 +206,6 @@ impl Greeter for GreeterServerImpl { println!("\tstream ended"); }); - // echo just write the same data that was received let out_stream = ReceiverStream::new(rx); Ok(Response::new( @@ -242,7 +230,7 @@ fn match_for_io_error(err_status: &dubbo::status::Status) -> Option<&std::io::Er } ``` -### 2.2 编写 Streaming Client +### 2.2 Writing the Streaming Client ```rust // ./src/greeter/client.rs @@ -348,25 +336,24 @@ async fn main() { } ``` -## 3 运行示例 +## 3 Running the Example -1. 编译 +1. Build -执行`cargo build`来编译server和client。 +Run `cargo build` to compile the server and client. -2. 运行server +2. Run the server -执行`./target/debug/greeter-server`来运行server,如上文dubbo.yaml所配置,server会监听8888端口,并以triple协议提供RPC服务: +Run `./target/debug/greeter-server` to start the server. As configured in the above dubbo.yaml, the server will listen on port 8888 and provide RPC services via the triple protocol: ```sh $ ./target/debug/greeter-server 2022-09-28T23:33:28.104577Z INFO dubbo::framework: url: Some(Url { uri: "triple://0.0.0.0:8888/org.apache.dubbo.sample.tri.Greeter", protocol: "triple", location: "0.0.0.0:8888", ip: "0.0.0.0", port: "8888", service_key: ["org.apache.dubbo.sample.tri.Greeter"], params: {} }) ``` -3. 运行client,可以看到 Streaming 通信效果 - -执行`./target/debug/greeter-client`来运行client,调用`triple://127.0.0.1:8888/org.apache.dubbo.sample.tri.Greeter`下的各种方法: +3. Run the client to see the Streaming communication effects +Run `./target/debug/greeter-client` to execute the client, calling various methods under `triple://127.0.0.1:8888/org.apache.dubbo.sample.tri.Greeter`: ```sh $ ./target/debug/greeter-client @@ -387,3 +374,4 @@ reply: GreeterReply { message: "msg2 from server" } reply: GreeterReply { message: "msg3 from server" } trailer: Some(Metadata { inner: {"content-type": "application/grpc", "grpc-status": "0", "grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity"} }) ``` + diff --git a/content/en/overview/mannual/rust-sdk/unix-transport.md b/content/en/overview/mannual/rust-sdk/unix-transport.md index 8334061730fe..be58b79e733c 100644 --- a/content/en/overview/mannual/rust-sdk/unix-transport.md +++ b/content/en/overview/mannual/rust-sdk/unix-transport.md @@ -2,9 +2,9 @@ aliases: - /en/docs3-v2/rust-sdk/unix-transport/ - /en/docs3-v2/rust-sdk/unix-transport/ -description: 介绍使用 Dubbo Rust Triple 协议使用 Unix 套接字连接器实现通信。 -linkTitle: 使用Unix套接字连接器通信 -title: 使用Unix套接字连接器通信 +description: Introduction to using the Dubbo Rust Triple protocol to implement communication via the Unix socket connector. +linkTitle: Communication using Unix Socket Connector +title: Communication using Unix Socket Connector type: docs weight: 3 --- @@ -14,27 +14,27 @@ weight: 3 -本文重点讲解 Dubbo Rust Triple 协议使用Unix 套接,请先查看 [Quick Start](../quick-start) 了解 Dubbo Rust 基本使用,在此查看本文的[完整示例](https://github.com/apache/dubbo-rust/tree/main/examples/greeter)。 +This article focuses on using the Dubbo Rust Triple protocol with Unix sockets. Please refer to the [Quick Start](../quick-start) for basic usage of Dubbo Rust, and you can see the [complete example](https://github.com/apache/dubbo-rust/tree/main/examples/greeter) here. -## 1 使用 Unix 套接字连接器 说明 -> #[cfg(any(target_os = "macos", target_os="unix"))] 当操作系统符合cfg配置时,unix 模块会被编译使用,否则无法使用 +## 1 Explanation of Using Unix Socket Connector +> #[cfg(any(target_os = "macos", target_os="unix"))] The unix module will be compiled for use when the operating system meets the cfg configuration, otherwise it cannot be used. -## 2 使用 client/connection 使用 Unix 套接字连接器编写逻辑 +## 2 Logic for Using Unix Socket Connector with client/connection -### 2.1 编写 Client 端 +### 2.1 Writing the Client Side ```rust // examples/echo/src/echo/client.rs -// 使用 ClientBuilder 初始化 Client +// Initialize Client using ClientBuilder let builder = ClientBuilder::new().with_connector("unix").with_host("unix://127.0.0.1:8888"); let mut cli = EchoClient::build(builder); ``` -### 2.2 编写 Server 端 +### 2.2 Writing the Server Side ```rust // examples/echo/src/echo/server.rs -// 通过 serverbuilder 来初始化 Server +// Initialize Server using serverbuilder let builder = ServerBuilder::new() .with_listener("unix".to_string()) .with_service_names(vec!["grpc.examples.echo.Echo".to_string()]) @@ -43,24 +43,24 @@ builder.build().serve().await.unwrap(); ``` -## 3 运行示例 +## 3 Running Example -1. 编译 +1. Compile -执行`cargo build`来编译server和client。 +Run `cargo build` to compile the server and client. -2. 运行server +2. Run the server -执行`cargo run --bin echo-server`来运行server,如上文dubbo.yaml所配置,server会监听8888端口,并以triple协议提供RPC服务: +Run `cargo run --bin echo-server` to start the server. As configured in the dubbo.yaml above, the server will listen on port 8888 and provide RPC services using the triple protocol: ```sh $ cargo run --bin echo-server 2023-01-19T08:36:25.663138Z INFO dubbo::triple::server::builder: server starting. addr: Some(127.0.0.1:8888) ``` -3. 运行client,可以看到 Unix 通信效果 +3. Run the client to see Unix communication in action -执行`cargo run --bin echo-client`来运行client,调用`triple://127.0.0.1:8888/org.apache.dubbo.sample.tri.Greeter`下的各种方法: +Run `cargo run --bin echo-client` to start the client, calling various methods under `triple://127.0.0.1:8888/org.apache.dubbo.sample.tri.Greeter`: ```sh @@ -82,3 +82,4 @@ reply: EchoResponse { message: "msg2 from server" } reply: EchoResponse { message: "msg3 from server" } trailer: Some(Metadata { inner: {"grpc-status": "0", "content-type": "application/grpc", "grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity"} }) ``` + diff --git a/content/en/overview/mannual/web-sdk/_index.md b/content/en/overview/mannual/web-sdk/_index.md index 0c16b02ac2d5..93c565a8669c 100755 --- a/content/en/overview/mannual/web-sdk/_index.md +++ b/content/en/overview/mannual/web-sdk/_index.md @@ -1,7 +1,8 @@ --- -description: Web SDK 使用手册 +description: Web SDK User Guide linkTitle: Web SDK -title: Web SDK 手册 +title: Web SDK Manual type: docs weight: 4 --- + diff --git a/content/en/overview/mannual/web-sdk/quick-start.md b/content/en/overview/mannual/web-sdk/quick-start.md index aa080a983324..ddf4bfd54bfe 100644 --- a/content/en/overview/mannual/web-sdk/quick-start.md +++ b/content/en/overview/mannual/web-sdk/quick-start.md @@ -2,30 +2,30 @@ aliases: - /en/docs3-v2/rust-sdk/quick-start/ - /en/docs3-v2/rust-sdk/quick-start/ -description: 使用 dubbo-js 开发运行在浏览器页面的微服务。 -linkTitle: Web浏览器访问Dubbo服务 -title: Web 浏览器访问 Dubbo 服务 +description: Develop microservices running on browser pages using dubbo-js. +linkTitle: Access Dubbo Services via Web Browser +title: Access Dubbo Services via Web Browser type: docs weight: 1 --- -基于 Dubbo3 定义的 Triple 协议,你可以轻松编写浏览器、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。[Dubbo TypeScript SDK](https://github.com/apache/dubbo-js/) 支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 API 来发布或调用这些服务。 +Based on the Triple protocol defined by Dubbo3, you can easily write browser and gRPC compatible RPC services that run on both HTTP/1 and HTTP/2. The [Dubbo TypeScript SDK](https://github.com/apache/dubbo-js/) supports defining services using IDL or language-specific methods, and provides a lightweight API set to publish or invoke these services. -Dubbo-js 已于 9 月份发布支持 Dubbo3 协议的首个 alpha 版本,它的发布将有机会彻底改变微服务前后端的架构与通信模式,让你能直接在浏览器页面或web服务器中访问后端 Dubbo RPC 服务。 +Dubbo-js released its first alpha version supporting the Dubbo3 protocol in September, which can fundamentally change the architecture and communication patterns of microservices' front and back end, allowing you to directly access backend Dubbo RPC services from a browser page or web server. ![dubbo-web.png](/imgs/v3/web/web-1.png) -# 浏览器 Web 应用示例 +# Browser Web Application Example -本示例演示了如何使用 dubbo-js 开发运行在浏览器上的 web 应用程序,web 页面将调用 dubbo node.js 开发的后端服务并生成页面内容。本示例演示基于 IDL 和非 IDL 两种编码模式。 +This example demonstrates how to use dubbo-js to develop a web application running in a browser, where the web page will call backend services developed in dubbo node.js to generate page content. This example shows both IDL and non-IDL coding modes. ![dubbo-web.png](/imgs/v3/web/web-2.png) -## IDL 模式 +## IDL Mode -### 前置条件 +### Prerequisites -首先,我们将使用 Vite 来生成我们的前端项目模板,它内置了我们稍后需要的所有功能支持。 +First, we will use Vite to generate our frontend project template, which has all the features we need later. ```shell npm create vite@latest -- dubbo-web-example --template react-ts @@ -33,23 +33,23 @@ cd dubbo-web-example npm install ``` -因为使用 Protocol Buffer 的原因,我们首先需要安装相关的代码生成工具,这包括 `@bufbuild/protoc-gen-es`、`@bufbuild/protobuf`、`@apachedubbo/protoc-gen-apache-dubbo-es`、`@apachedubbo/dubbo`。 +Because we are using Protocol Buffer, we need to install related code generation tools: `@bufbuild/protoc-gen-es`, `@bufbuild/protobuf`, `@apachedubbo/protoc-gen-apache-dubbo-es`, `@apachedubbo/dubbo`. ```shell npm install @bufbuild/protoc-gen-es @bufbuild/protobuf @apachedubbo/protoc-gen-apache-dubbo-es @apachedubbo/dubbo ``` -### 使用 Proto 定义服务 +### Defining Service with Proto -现在,使用 Protocol Buffer (IDL) 来定义一个 Dubbo 服务。 +Now, use Protocol Buffer (IDL) to define a Dubbo service. -src 下创建 util/proto 目录,并生成文件 +Create the util/proto directory under src and generate the file ```shell mkdir -p src/util/proto && touch src/util/proto/example.proto ``` -写入内容 +Write the content ```protobuf syntax = "proto3"; @@ -69,17 +69,17 @@ service ExampleService { } ``` -这个文件声明了一个叫做 `ExampleService` 的服务,为这个服务定义了 `Say` 方法以及它的请求参数 `SayRequest` 和返回值 `SayResponse`。 +This file declares a service called `ExampleService`, defining the `Say` method with its request parameter `SayRequest` and return value `SayResponse`. -### 生成代码 +### Generate Code -创建 gen 目录,作为生成文件放置的目标目录 +Create the gen directory as the target directory for generated files ```shell mkdir -p src/util/gen ``` -运行以下命令,利用 `protoc-gen-es`、`protoc-gen-apache-dubbo-es` 等插件在 gen 目录下生成代码文件 +Run the following command to generate code files in the gen directory using `protoc-gen-es`, `protoc-gen-apache-dubbo-es`, and other plugins ```shell PATH=$PATH:$(pwd)/node_modules/.bin \ @@ -91,7 +91,7 @@ PATH=$PATH:$(pwd)/node_modules/.bin \ example.proto ``` -运行命令后,应该可以在目标目录中看到以下生成的文件: +After running the command, you should see the following generated files in the target directory: ``` ├── src @@ -103,15 +103,15 @@ PATH=$PATH:$(pwd)/node_modules/.bin \ │ │ └── example.proto ``` -### 创建 App +### Create App -需要先下载 `@apachedubbo/dubbo-web` +First, download `@apachedubbo/dubbo-web` ```shell npm install @apachedubbo/dubbo-web ``` -现在我们可以从包中导入服务并设置一个客户端。在 App.tsx 中添加以下内容: +Now we can import the service from the package and set a client. Add the following content in App.tsx: ```typescript import { useState } from "react"; @@ -184,23 +184,23 @@ function App() { export default App; ``` -执行以下命令,即可得到样例页面 +Run the following command to get the sample page: ```shell npm run dev ``` -### 启动 Server +### Start Server -接下来我们需要启动 Server,可以使用 Java、Go、Node.js 等 Dubbo 支持的任一语言开发 Server。这里我们采用 Dubbo 服务嵌入的 Node.js 服务器,具体可参考 [Node.js 开发 Dubbo 后端服务](https://github.com/apache/dubbo-js/tree/dubbo3/example/dubbo-node-example) 中的操作步骤。 +Next, we need to start the Server, which can be developed in any language that Dubbo supports, such as Java, Go, or Node.js. Here, we take the Node.js server embedded with Dubbo service; see [Developing Dubbo Backend Service with Node.js](https://github.com/apache/dubbo-js/tree/dubbo3/example/dubbo-node-example) for specific steps. -不过需要注意,我们额外需要修改 Node.js 示例:引入 @fastify/cors 来解决前端请求的跨域问题 +Please note that we need to additionally modify the Node.js example: introduce `@fastify/cors` to solve the front-end request cross-origin issues ```shell npm install @fastify/cors ``` -需要在 server.ts 文件下修改 +We need to modify the server.ts file ```typescript ... @@ -221,23 +221,23 @@ async function main() { void main(); ``` -最后,运行代码启动服务 +Finally, run the code to start the service ```shell npx tsx server.ts ``` -## 无 IDL 模式 +## Non-IDL Mode -在接下来的版本中,我们将继续提供无 IDL 模式的通信支持,这样就可以更方便的访问无 IDL 的后端服务。在这里,我们先快速的看一下无 IDL 模式的使用方式。 +In upcoming versions, we will continue to provide support for communication without IDL mode, making it easier to access backend services without IDL. Here, we will quickly look at how to use the non-IDL mode. -同样需要先安装 `@apachedubbo/dubbo`、`@apachedubbo/dubbo-web` +You also need to install `@apachedubbo/dubbo` and `@apachedubbo/dubbo-web` first. ```shell npm install @apachedubbo/dubbo @apachedubbo/dubbo-web ``` -现在就可以一个启动一个客户端,并发起调用了。App.tsx 中的代码与 IDL 模式基本一致,区别点在于以下内容: +Now, you can start a client and initiate a call. The code in App.tsx is basically the same as in IDL mode, with the difference in the following content: ```typescript // ... @@ -260,7 +260,7 @@ function App() { } ``` -执行以下命令,即可得到样例页面 +Run the following command to get the sample page: ```shell npm run dev From 4433c834018c2b381558461e30617eac72e2b4dd Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Mon, 30 Sep 2024 15:21:08 +0800 Subject: [PATCH 11/23] Translate --- .../mannual/java-sdk/tasks/develop/_index.md | 7 +- .../mannual/java-sdk/tasks/develop/api.md | 142 +++---- .../java-sdk/tasks/develop/springboot.md | 89 ++--- .../mannual/java-sdk/tasks/mesh/_index.md | 15 +- .../tasks/mesh/bookinfo-proxyless/_index.md | 9 +- .../bookinfo-proxyless/security/_index.md | 7 +- .../mesh/bookinfo-proxyless/traffic/_index.md | 7 +- .../tasks/mesh/bookinfo-sidecar/_index.md | 9 +- .../mesh/bookinfo-sidecar/security/_index.md | 7 +- .../mesh/bookinfo-sidecar/traffic/_index.md | 11 +- .../java-sdk/tasks/mesh/migration/_index.md | 15 +- .../tasks/mesh/migration/deploy-on-k8s.md | 108 +++-- .../tasks/mesh/migration/proxyless.md | 122 +++--- .../tasks/troubleshoot/no-provider.md | 372 +++++++++--------- .../tasks/troubleshoot/request-failed.md | 129 +++--- 15 files changed, 518 insertions(+), 531 deletions(-) diff --git a/content/en/overview/mannual/java-sdk/tasks/develop/_index.md b/content/en/overview/mannual/java-sdk/tasks/develop/_index.md index fc5f2a405f0a..eccf997aadee 100755 --- a/content/en/overview/mannual/java-sdk/tasks/develop/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/develop/_index.md @@ -2,9 +2,10 @@ aliases: - /en/overview/tasks/develop/ - /en/overview/tasks/develop/ -description: 演示 Dubbo 框架提供的微服务开发 API 与编程模式 -linkTitle: 快速创建应用 -title: 快速创建应用 +description: Demonstrates the microservice development APIs and programming model provided by the Dubbo framework +linkTitle: Quickly Create Applications +title: Quickly Create Applications type: docs weight: 1 --- + diff --git a/content/en/overview/mannual/java-sdk/tasks/develop/api.md b/content/en/overview/mannual/java-sdk/tasks/develop/api.md index 0f3512d98c67..4461f6aeca54 100644 --- a/content/en/overview/mannual/java-sdk/tasks/develop/api.md +++ b/content/en/overview/mannual/java-sdk/tasks/develop/api.md @@ -1,16 +1,16 @@ --- -description: 作为一款 RPC 框架,Dubbo 定义了一套完善的 API 接口,我们可以基于原生 API 开发 RPC 服务和微服务应用 -linkTitle: 纯 API 开发模式 -title: 使用原生 API 开发 Dubbo 应用 +description: As an RPC framework, Dubbo defines a comprehensive set of API interfaces, allowing us to develop RPC services and microservice applications based on the native API. +linkTitle: Pure API Development Model +title: Developing Dubbo Applications Using Native APIs type: docs weight: 2 --- -你可能已经注意到了,文档中大部分的功能、示例都是基于 Spring Boot 模式编写的,但 Spring Boot 或 Spring 仅仅是 Dubbo 适配的一种应用或者微服务开发模式。**作为一款 RPC 框架,Dubbo 定义了一套完善的 API 接口,我们可以基于原生 API 开发 Dubbo 应用**,纯 API 可以实现的业务场景包括: -* **轻量 RPC Server & Client**,通常用于一些应用内、基础组件、中间件等内的简单远程调用场景 -* **微服务应用**,不依赖 Spring 的情况下,直接用 API 开发微服务 +You may have noticed that most of the functions and examples in the documentation are based on the Spring Boot model, but Spring Boot or Spring is merely one application or microservice development model adapted by Dubbo. **As an RPC framework, Dubbo defines a comprehensive set of API interfaces, enabling us to develop Dubbo applications based on the native APIs**. Business scenarios that can be achieved with pure APIs include: +* **Lightweight RPC Server & Client**, typically used for simple remote call scenarios within applications, foundational components, middleware, etc. +* **Microservices Applications**, without relying on Spring, directly using APIs to develop microservices. -## API 概览 +## API Overview ```java public class Application { public static void main(String[] args) { @@ -23,36 +23,36 @@ public class Application { } ``` -以上是启动 Dubbo RPC Server 的一段代码示例,`DubboBootstrap` 实例代表一个 Dubbo 应用,是整个 Dubbo 应用的启动入口。在 DubboBootstrap 基础上,我们可以设置 `protocol`、`service`、`registry`、`metrics` 等来注册服务、连接注册中心等,这和我们在 Spring Boot 中调整 application.yml 或者 application.properties 文件是对等的作用。 +The above is a code example of starting a Dubbo RPC Server. The `DubboBootstrap` instance represents a Dubbo application and serves as the entry point for starting the entire Dubbo application. Based on DubboBootstrap, we can set `protocol`, `service`, `registry`, `metrics`, etc., to register services, connect to the registry, etc., similar to adjusting application.yml or application.properties files in Spring Boot. -官方推荐使用 `DubboBootstrap.start()` 作为应用的集中启动入口,但为了方便在进程启动后,在运行态单独发布一些服务,Dubbo 框架也允许直接调用 `ServiceConfig.export()` 或 `ReferenceConfig.refer()` 方法发布单个服务,这时 Service/Reference 会注册到默认的 DubboBootstrap 实例中,效果同调用 `DubboBootstrap.service(...).start()` 类似。 +The official recommendation is to use `DubboBootstrap.start()` as the centralized entry for application startup, but to facilitate the separate publication of some services after the process starts, the Dubbo framework also allows directly calling `ServiceConfig.export()` or `ReferenceConfig.refer()` methods to publish individual services. In this case, Service/Reference will register with the default DubboBootstrap instance, similar to calling `DubboBootstrap.service(...).start()`. -以下是开发中会常用到的一些组件,完整组件定义及详细参数说明请参见 [参考手册 - 配置项手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/#配置项手册): +Below are some components commonly used in development. For a complete component definition and detailed parameter description, please refer to the [Reference Manual - Configuration Items Manual](/en/overview/mannual/java-sdk/reference-manual/config/properties/#配置项手册): -| API 组件 | 全局唯一 | 核心方法或属性 | 说明 | +| API Component | Globally Unique | Core Methods or Properties | Description | | --- | --- | --- | --- | -| DubboBootstrap | 是(多应用场景除外) | start()、stop() | DubboBootstrap 实例代表一个 Dubbo 应用,是整个 Dubbo 应用的启动入口。 | -| ApplicationConfig | 是 | name | 应用名及应用级别的一些全局配置 | -| MetricsConfig | 是 | protocol、prometheus、tracing | Metrics、tracing 采集相关配置 | -| ProtocolConfig | 否。多协议场景服务通过 id 关联 | id、name、port、serialization、threadpool | RPC 协议端口、序列化协议、运行时行为配置 | -| RegistrtyConfig | 否。多注册中心场景服务通过 id 关联 | id、address、protocol、group | 注册中心实现、地址、订阅等配置 | -| ConfigCenterConfig | 否。多配置中心场景服务通过 id 关联 | id、address、protocol、group、namespace | 配置中心实现、地址、分组隔离等配置 | -| MetadataReportConfig | 否。多元数据中心场景服务通过 id 关联 | id、address、protocol、group、namespace | 元数据中心实现、地址、分组隔离等配置 | -| ProviderConfig | 否 | 参考 ServiceConfig | 作为多个ServiceConfig的默认值 | -| ConsumerConfig | 否 | 参考 ReferenceConfig | 作为多个ReferenceConfig的默认值 | -| ServiceConfig | 否 | - 方法:export()
- 属性: interfaceClass、ref、group、version、timeout、retry | 一个 ServiceConfig 实例代表一个 RPC 服务 | -| ReferenceConfig | 否 | - 方法:refer()
- 属性:interfaceClass、group、version、timeout、retry、cluster、loadbalance | 一个 ReferenceConfig 实例代表一个 RPC 服务 | -| MethodConfig | 否 | name、oninvoke、onreturn、onthrow | ServiceConfig/ReferenceConfig 内嵌的方法级别配置 | -| ArgumentConfig | 否 | index、type、callback | MethodConfig 内嵌的参数级别配置 | - -## 轻量 RPC 示例 -本示例演示如何使用轻量 Dubbo SDK 开发 RPC Server 与 Client,示例使用 Java Interface 方式定义、发布和访问 RPC 服务,底层使用 Triple 协议通信。本示例完整代码请参见 dubbo-samples。 - -基于 Dubbo 定义的 Triple 协议,你可以轻松编写浏览器、gRPC 兼容的 RPC 服务,并让这些服务同时运行在 HTTP/1 和 HTTP/2 上。Dubbo Java SDK 支持使用 IDL 或编程语言特有的方式定义服务,并提供一套轻量的 API 来发布或调用这些服务。 - -### Maven 依赖 - -在基于 Dubbo RPC 编码之前,您只需要在项目添加一个非常轻量的 `dubbo`依赖包即可,以 Maven 为例: +| DubboBootstrap | Yes (except for multi-application scenarios) | start(), stop() | The DubboBootstrap instance represents a Dubbo application and serves as the entry point for starting the entire Dubbo application. | +| ApplicationConfig | Yes | name | Application name and some global configurations at the application level | +| MetricsConfig | Yes | protocol, prometheus, tracing | Configurations related to Metrics and tracing collection | +| ProtocolConfig | No. Services in multi-protocol scenarios are associated by id | id, name, port, serialization, threadpool | RPC protocol port, serialization protocol, runtime behavior configuration | +| RegistrtyConfig | No. Services in multi-registry scenarios are associated by id | id, address, protocol, group | Registry implementation, address, subscription, etc. configurations | +| ConfigCenterConfig | No. Services in multi-configuration center scenarios are associated by id | id, address, protocol, group, namespace | Configuration center implementation, address, group isolation, etc. configurations | +| MetadataReportConfig | No. Services in multi-metadata center scenarios are associated by id | id, address, protocol, group, namespace | Metadata center implementation, address, group isolation, etc. configurations | +| ProviderConfig | No | Reference ServiceConfig | Default values for multiple ServiceConfig | +| ConsumerConfig | No | Reference ReferenceConfig | Default values for multiple ReferenceConfig | +| ServiceConfig | No | - Method: export()
- Properties: interfaceClass, ref, group, version, timeout, retry | A ServiceConfig instance represents an RPC service | +| ReferenceConfig | No | - Method: refer()
- Properties: interfaceClass, group, version, timeout, retry, cluster, loadbalance | A ReferenceConfig instance represents an RPC service | +| MethodConfig | No | name, oninvoke, onreturn, onthrow | Method-level configuration embedded in ServiceConfig/ReferenceConfig | +| ArgumentConfig | No | index, type, callback | Parameter-level configuration embedded in MethodConfig | + +## Lightweight RPC Example +This example demonstrates how to use the lightweight Dubbo SDK to develop RPC Server and Client. The example defines, publishes, and accesses RPC services using Java Interface, with Triple protocol communications. For complete code, please see dubbo-samples. + +Based on the Triple protocol defined by Dubbo, you can easily write browser and gRPC compatible RPC services and run them simultaneously on HTTP/1 and HTTP/2. The Dubbo Java SDK supports defining services using IDL or language-specific methods and provides a lightweight API for publishing or calling these services. + +### Maven Dependency + +Before coding with Dubbo RPC, you only need to add a lightweight `dubbo` dependency package to your project. For Maven, it looks like this: ```xml org.apache.dubbo @@ -61,9 +61,9 @@ public class Application { ``` -### 定义服务 +### Define Service -定义一个名为 `DemoService`的标准 Java 接口作为 Dubbo 服务(Dubbo 还支持[基于 IDL 的服务定义模式](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/))。 +Define a standard Java interface named `DemoService` as a Dubbo service (Dubbo also supports [IDL-based service definition patterns](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/)). ```java public interface DemoService { @@ -71,7 +71,7 @@ public interface DemoService { } ``` -实现 `DemoService` 接口并编写业务逻辑代码。 +Implement the `DemoService` interface and write the business logic code. ```java public class DemoServiceImpl implements DemoService { @@ -82,12 +82,12 @@ public class DemoServiceImpl implements DemoService { } ``` -### 注册服务并启动 Server +### Register Service and Start Server -启动 server 并在指定端口监听 RPC 请求,在此之前,我们向 server 注册了以下信息: +Start the server and listen for RPC requests on the specified port. Before this, we registered the following information with the server: -- 使用 `Triple` 作为通信 RPC 协议与并监听端口 `50051` -- 注册 Dubbo 服务到 `DemoService` server +- Using `Triple` as the communication RPC protocol and listening on port `50051` +- Registering the Dubbo service to `DemoService` server ```java public class Application { @@ -101,9 +101,9 @@ public class Application { } ``` -### 访问服务 +### Access Service -最简单方式是使用 HTTP/1.1 POST 请求访问服务,参数则以标准 JSON 格式作为 HTTP 负载传递。如下是使用 cURL 命令的访问示例: +The simplest way is to use an HTTP/1.1 POST request to access the service, with parameters passed as standard JSON format in the HTTP payload. Here is an example using the cURL command: ```shell curl \ @@ -112,9 +112,9 @@ curl \ http://localhost:50051/org.apache.dubbo.demo.DemoService/sayHello ``` -> 参数必须以数组格式进行传递,如果有多个参数,则格式类似 `["param1", {"param2-field": "param2-value"}, ...]`,具体请参见 triple 协议规范。 +> Parameters must be passed in array format. If there are multiple parameters, the format should be like `["param1", {"param2-field": "param2-value"}, ...]`, please refer to the triple protocol specification for specifics. -接下来,您也可以使用标准的 Dubbo client 请求服务,指定 server 地址即可发起 RPC 调用,其格式为 `protocol://ip:host` +Next, you can also use a standard Dubbo client to request the service, specifying the server address to initiate an RPC call. The format is `protocol://ip:host`. ```java public class Application { @@ -132,14 +132,13 @@ public class Application { } ``` -恭喜您, 以上即是 Dubbo Java RPC 通信的基本使用方式! 🎉 +Congratulations! The above is the basic usage of Dubbo Java RPC communication! 🎉 +### More Examples +Besides the simple usage scenarios above, developers can also publish multiple services, directly call ServiceConfig/ReferenceConfig to publish/subscribe individual services, etc. -### 更多示例 -除了以上简单使用场景之外,开发者还可以发布多个服务、直接调用 ServiceConfig/ReferenceConfig 发布/订阅单个服务等。 - -#### 发布多个服务 -以下示例注册并发布任意多个服务 FooService、BarService,这些服务都将使用 providerConfig 中配置的默认超时时间,省去多个服务重复配置的烦恼。 +#### Publish Multiple Services +The following example registers and publishes any number of services FooService, BarService. These services will all use the default timeout configured in providerConfig, avoiding the hassle of repeated configurations for multiple services. ```java public static void main(String[] args) { @@ -158,10 +157,10 @@ public static void main(String[] args) { } ``` -#### 发布单个服务 -直接调用 ServiceConfig.export() 发布服务,适用于运行态动态发布或订阅一个服务,对于 ReferenceConfig 同理。对于正常的应用启动流程,推荐使用 DubboBootstrap 而非直接调用 ServiceConfig.export() 发布单个服务。 +#### Publish Individual Services +Directly call ServiceConfig.export() to publish services suitable for dynamic publication or subscription of a single service in runtime; it is similar for ReferenceConfig. For routine application startup processes, it is recommended to use DubboBootstrap instead of directly calling ServiceConfig.export() to publish individual services. -1. 通过 ServiceConfig 发布服务 +1. Publishing a service through ServiceConfig ```java public static void main(String[] args) { ServiceConfig demoServiceConfig = new ServiceConfig<>(); @@ -173,7 +172,7 @@ public static void main(String[] args) { } ``` -2. 通过 ReferenceConfig 订阅服务 +2. Subscribing to services through ReferenceConfig ```java private DemoService referService() { @@ -189,10 +188,10 @@ private DemoService referService() { } ``` -由于 ReferenceConfig.get() 创建的代理对象持有连接、地址等大量资源,因此建议缓存复用,Dubbo 官方提供了 SimpleReferenceCache 实现参考实现。关于 SimpleReferenceCache 更多内容,请参考 [RPC 框架](/en/overview/mannual/java-sdk/tasks/framework/more/reference-config-cache/)。 +Because the proxy object created by ReferenceConfig.get() holds a lot of resources such as connections and addresses, it is recommended to cache and reuse it. Dubbo officially provides a SimpleReferenceCache implementation for reference. For more content on SimpleReferenceCache, please refer to [RPC Framework](/en/overview/mannual/java-sdk/tasks/framework/more/reference-config-cache/). -#### 获得引用代理 -使用 DubboBootstrap 作为启动入口,订阅服务并获得代理对象。 +#### Getting Reference Proxy +Use DubboBootstrap as the startup entry, subscribe to services, and obtain proxy objects. ```java public static void main(String[] args) { @@ -205,9 +204,9 @@ public static void main(String[] args) { } ``` -## 微服务示例 -### 注册中心和应用名 -相比于 RPC server、RPC client,基于 API 的微服务应用开发需要配置应用名、注册中心。 +## Microservices Example +### Registry Center and Application Name +Compared to RPC server and RPC client, developing microservice applications based on APIs requires configurations for the application name and registry center. ```java public static void main(String[] args) { @@ -222,8 +221,8 @@ public static void main(String[] args) { } ``` -### 多个注册中心 -多个注册中心可指定不同的 id,服务通过 id 关联注册中心实例。如下示例中,GreetingsService 发布到 bjRegistry,DemoService 发布到 hzRegistry。 +### Multiple Registry Centers +Multiple registry centers can specify different ids, and services are associated with the registry center instances by id. In the following example, GreetingsService is published to bjRegistry, while DemoService is published to hzRegistry. ```java public static void main(String[] args) { @@ -245,14 +244,14 @@ public static void main(String[] args) { } ``` -### 发布单个服务 -直接调用 ServiceConfig.export() 发布服务,适用于运行态动态发布或订阅一个服务,对于 ReferenceConfig 同理。对于正常的应用启动流程,推荐使用 DubboBootstrap 而非直接调用 ServiceConfig.export() 发布单个服务。 +### Publish Individual Services +Directly call ServiceConfig.export() to publish services, suitable for dynamically publishing or subscribing to a single service in runtime; it is similar for ReferenceConfig. For routine application startup processes, it is recommended to use DubboBootstrap instead of directly calling ServiceConfig.export() to publish individual services. -{{% alert title="注意" color="primary" %}} +{{% alert title="Note" color="primary" %}} {{% /alert %}} -1. 通过 ServiceConfig 发布服务 +1. Publishing a service through ServiceConfig ```java public static void main(String[] args) { RegistryConfig hzRegistry = new RegistryConfig(); @@ -270,7 +269,7 @@ public static void main(String[] args) { } ``` -2. 通过 ReferenceConfig 订阅服务 +2. Subscribing to services through ReferenceConfig ```java private DemoService referService() { @@ -292,8 +291,9 @@ private DemoService referService() { } ``` -## 更多内容 +## More Content + +- The Triple protocol is fully compatible with gRPC, you can refer to here to learn how to [write gRPC compatible services using IDL](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/), or [use other communication protocols](/en/overview/mannual/java-sdk/tasks/protocols/) +- As an RPC framework, Dubbo supports asynchronous calls, connection management, context, etc., please refer to [Core Functions of RPC Framework](/en/overview/mannual/java-sdk/tasks/framework/) +- Use [Dubbo Spring Boot to develop microservice applications](/en/overview/mannual/java-sdk/tasks/develop/springboot/) -- Triple 协议完全兼容 gRPC,您可以参考这里了解如何 [使用 IDL 编写 gRPC 兼容的服务](/en/overview/mannual/java-sdk/tasks/protocols/triple/idl/),或者 [使用其他通信协议](/en/overview/mannual/java-sdk/tasks/protocols/) -- 作为 RPC 框架,Dubbo 支持异步调用、连接管理、context上下文等,请参考 [RPC 框架核心功能](/en/overview/mannual/java-sdk/tasks/framework/) -- 使用 [Dubbo Spring Boot 开发微服务应用](/en/overview/mannual/java-sdk/tasks/develop/springboot/) diff --git a/content/en/overview/mannual/java-sdk/tasks/develop/springboot.md b/content/en/overview/mannual/java-sdk/tasks/develop/springboot.md index fe924f55dd4f..96e49350f80e 100644 --- a/content/en/overview/mannual/java-sdk/tasks/develop/springboot.md +++ b/content/en/overview/mannual/java-sdk/tasks/develop/springboot.md @@ -1,26 +1,26 @@ --- -description: Dubbo 提供了对 Spring 框架的完整支持,我们推荐使用官方提供的丰富的 `dubbo-spring-boot-starter` 高效开发 Dubbo 微服务应用。 +description: Dubbo provides full support for the Spring framework, and we recommend using the officially provided rich `dubbo-spring-boot-starter` for efficient development of Dubbo microservice applications. linkTitle: Spring Boot Starter title: Spring Boot type: docs weight: 1 --- -Dubbo 提供了对 Spring 框架的完整支持,我们推荐使用官方提供的 `dubbo-spring-boot-starter` 高效开发 Dubbo 微服务应用。 +Dubbo provides full support for the Spring framework, and we recommend using the official `dubbo-spring-boot-starter` for efficient development of Dubbo microservice applications. -## 创建项目 -创建 Dubbo 应用最快捷的方式就是使用官方项目脚手架工具 - start.dubbo.apache.org 在线服务。它可以帮助开发者创建 Spring Boot 结构应用,自动管理 `dubbo-spring-boot-starter` 等依赖和必要配置。 +## Creating a Project +The fastest way to create a Dubbo application is to use the official project scaffold tool - start.dubbo.apache.org online service. It helps developers create Spring Boot structured applications and automatically manage dependencies like `dubbo-spring-boot-starter` along with necessary configurations. -另外,Jetbrain 官方也提供了 Apache Dubbo 项目插件,可用于快速创建 Dubbo Spring Boot 项目,能力与 start.dubbo.apache.org 对等,具体安装使用请查看 [博客文章](/en/blog/2023/10/23/intellij-idea%EF%B8%8Fapache-dubboidea官方插件正式发布/) +Additionally, Jetbrain also provides an Apache Dubbo project plugin for quickly creating Dubbo Spring Boot projects, which is on par with start.dubbo.apache.org. For specific installation and usage, please refer to the [blog post](/en/blog/2023/10/23/intellij-idea%EF%B8%8Fapache-dubboidea官方插件正式发布/). ## dubbo-spring-boot-starter -在 [快速开始](/en/overview/mannual/java-sdk/quick-start/) 中,我们已经详细介绍了典型的 Dubbo Spring Boot 工程源码及其项目结构,不熟悉的开发者可以前往查看。 +In the [Quick Start](/en/overview/mannual/java-sdk/quick-start/), we have detailed typical Dubbo Spring Boot project source code and its project structure. Developers who are unfamiliar can refer there. -`dubbo-spring-boot-starter` 可为项目引入 dubbo 核心依赖,自动扫描 dubbo 相关配置与注解。 +`dubbo-spring-boot-starter` can introduce Dubbo core dependencies into the project and automatically scan Dubbo-related configurations and annotations. -### Maven 依赖 +### Maven Dependencies -使用 Dubbo Spring Boot Starter,首先引入以下 Maven 依赖 +To use the Dubbo Spring Boot Starter, first include the following Maven dependency: ```xml @@ -36,7 +36,7 @@ Dubbo 提供了对 Spring 框架的完整支持,我们推荐使用官方提供 ``` -然后,在相应模块的 pom 中增加必要的 starter 依赖: +Then, add the necessary starter dependencies in the respective module's pom: ```xml @@ -50,10 +50,10 @@ Dubbo 提供了对 Spring 框架的完整支持,我们推荐使用官方提供 ``` -`dubbo-spring-boot-starter` 和 `dubbo-zookeeper-spring-boot-starter` 是官方提供的 starter,提供了 Spring Boot 的集成适配,它们的版本号与 Dubbbo 主框架版本号完全一致。 +`dubbo-spring-boot-starter` and `dubbo-zookeeper-spring-boot-starter` are official starters that provide integration adaptations for Spring Boot, and their version numbers are fully consistent with the Dubbo main framework version. -### application.yml 配置文件 -以下是一个示例文件配置 +### application.yml Configuration File +Here is an example configuration file: ```yaml dubbo: @@ -67,9 +67,9 @@ dubbo: address: zookeeper://127.0.0.1:2181 ``` -除 service、reference 之外的组件都可以在 application.yml 文件中设置,具体可参考 [配置列表](/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#applicationyaml)。 +Other components besides service and reference can be set in the application.yml file, and for specifics, please refer to the [configuration list](/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot/#applicationyaml). -service、reference 组件也可以通过 `id` 与 application 中的全局组件做关联,以下面配置为例。如果要扩展 service 或 reference 的注解配置,则需要增加 `dubbo.properties` 配置文件或使用其他非注解如 Java Config 方式,具体请看下文 [扩展注解的配置](#扩展注解配置)。 +Service and reference components can also be associated with global components in the application by using `id`, as in the following configuration. To extend the annotation configuration of service or reference, you need to add the `dubbo.properties` configuration file or use other non-annotation methods like Java Config; please see the section on [Extending Annotation Configuration](#扩展注解配置) for details. ```yaml dubbo: @@ -83,13 +83,13 @@ dubbo: address: zookeeper://127.0.0.1:2181 ``` -通过注解将 service 关联到上文定义的特定注册中心(通过id关联) +Associate the service with the specific registry defined above (linked by id) using annotations: ```java @DubboService(registry="zk-registry") public class DemoServiceImpl implements DemoService {} ``` -通过 Java Config 配置进行关联也是同样道理 +Using Java Config for association works similarly: ```java @Configuration public class ProviderConfiguration { @@ -102,30 +102,30 @@ public class ProviderConfiguration { } ``` -### Dubbo 注解 -* `application.properties` 或 `application.yml` 配置文件。 -* `@DubboService`、`@DubboReference` 与 `EnableDubbo` 注解。其中 `@DubboService` 与 `@DubboReference` 用于标记 Dubbo 服务,`EnableDubbo` 启动 Dubbo 相关配置并指定 Spring Boot 扫描包路径。 +### Dubbo Annotations +* `application.properties` or `application.yml` configuration files. +* `@DubboService`, `@DubboReference`, and `EnableDubbo` annotations. Among them, `@DubboService` and `@DubboReference` are used to mark Dubbo services, while `EnableDubbo` starts Dubbo-related configurations and specifies the package path for Spring Boot scanning. -#### @DubboService 注解 +#### @DubboService Annotation -> `@Service` 注解从 3.0 版本开始就已经废弃,改用 `@DubboService`,以区别于 Spring 的 `@Service` 注解 +> The `@Service` annotation has been deprecated since version 3.0, replaced by `@DubboService` to differentiate it from the Spring `@Service` annotation. -定义好 Dubbo 服务接口后,提供服务接口的实现逻辑,并用 `@DubboService` 注解标记,就可以实现 Dubbo 的服务暴露 +Once the Dubbo service interface is defined, implement the service interface logic and mark it with the `@DubboService` annotation to expose the Dubbo service: ```java @DubboService public class DemoServiceImpl implements DemoService {} ``` -如果要设置服务参数,`@DubboService` 也提供了常用参数的设置方式。如果有更复杂的参数设置需求,则可以考虑使用其他设置方式 +If you need to set service parameters, `@DubboService` also provides a way to set common parameters. For more complex parameter settings, consider using other configuration methods: ```java @DubboService(version = "1.0.0", group = "dev", timeout = 5000) public class DemoServiceImpl implements DemoService {} ``` -#### @DubboReference 注解 +#### @DubboReference Annotation -> `@Reference` 注解从 3.0 版本开始就已经废弃,改用 `@DubboReference`,以区别于 Spring 的 `@Reference` 注解 +> The `@Reference` annotation has been deprecated since version 3.0, replaced by `@DubboReference` to differentiate it from the Spring `@Reference` annotation. ```java @Component @@ -135,10 +135,10 @@ public class DemoClient { } ``` -`@DubboReference` 注解将自动注入为 Dubbo 服务代理实例,使用 demoService 即可发起远程服务调用 +The `@DubboReference` annotation will automatically inject a Dubbo service proxy instance, allowing remote service calls via demoService. -#### @EnableDubbo 注解 -`@EnableDubbo` 注解必须配置,否则将无法加载 Dubbo 注解定义的服务,`@EnableDubbo` 可以定义在主类上 +#### @EnableDubbo Annotation +The `@EnableDubbo` annotation must be configured; otherwise, services defined by Dubbo annotations will not load. `@EnableDubbo` can be defined on the main class: ```java @SpringBootApplication @@ -150,19 +150,19 @@ public class ProviderApplication { } ``` -Spring Boot 注解默认只会扫描 main 类所在的 package,如果服务定义在其它 package 中,需要增加配置 `EnableDubbo(scanBasePackages = {"org.apache.dubbo.springboot.demo.provider"})` +Spring Boot annotations will only scan the package where the main class is located by default. If services are defined in other packages, you need to add the configuration `EnableDubbo(scanBasePackages = {"org.apache.dubbo.springboot.demo.provider"})`. -#### 扩展注解配置 -虽然可以通过 `@DubboService` 和 `DubboReference` 调整配置参数(如下代码片段所示),但总体来说注解是为易用性设计的,其提供的仅仅是 80% 场景下常用的配置项。在这种情况下,如果有更复杂的参数设置需求,可以使用 `Java Config` 或 `dubbo.properties` 两种方式。 +#### Extending Annotation Configuration +While it is possible to adjust configuration parameters through `@DubboService` and `DubboReference` (as shown in the code snippet below), overall, annotations are designed for ease of use and provide only 80% of commonly used configuration items for scenarios. In such cases, if there are more complex parameter setting needs, you can use either Java Config or `dubbo.properties`. ```java @DubboService(version = "1.0.0", group = "dev", timeout = 5000) @DubboReference(version = "1.0.0", group = "dev", timeout = 5000) ``` -#### 使用 Java Config 代替注解 +#### Using Java Config in Place of Annotations -注意,Java Config 是 `DubboService` 或 `DubboReference` 的替代方式,对于有复杂配置需求的服务建议使用这种方式。 +Note that Java Config is an alternative to `DubboService` or `DubboReference`. For services with complex configuration needs, this approach is recommended. ```java @Configuration @@ -181,9 +181,8 @@ public class ProviderConfiguration { } ``` - -#### 通过 dubbo.properties 补充配置 -对于使用 `DubboService` 或 `DubboReference` 的场景,可以通过在项目 resources 目录下增加 dubbo.properties 文件作为配置补充,[具体格式](../principle/#1-配置格式)这里有更详细解释。 +#### Supplementing Configuration Through dubbo.properties +For scenarios using `DubboService` or `DubboReference`, additional configuration can be provided by adding a dubbo.properties file under the project's resources directory. [Specific format](../principle/#1-配置格式) has more detailed explanations here. ```properties dubbo.service.org.apache.dubbo.springboot.demo.DemoService.timeout=5000 @@ -191,17 +190,15 @@ dubbo.service.org.apache.dubbo.springboot.demo.DemoService.parameters=[{myKey:my dubbo.reference.org.apache.dubbo.springboot.demo.DemoService.timeout=6000 ``` -> properties 格式配置目前结构性不太强,比如体现在 key 字段冗余较多,后续会考虑提供对于 yaml 格式的支持。 +> The properties format currently has limited structural strength, such as excessive redundancy in key fields, and support for YAML format will be considered in the future. -## 更多微服务开发模式 -* [纯 API 开发模式](../api/) -* 其他 Spring 开发模式 +## More Microservice Development Patterns +* [Pure API Development Pattern](../api/) +* Other Spring Development Patterns * [Spring XML](/en/overview/mannual/java-sdk/reference-manual/config/spring/xml/) -## Dubbo 与 Spring Cloud 的关系 -Dubbo 与 Spring Cloud 是两套平行的微服务开发与解决方案,两者都提供了微服务定义、发布、治理的相关能力,对于微服务开发者来说,我们建议在开发之初就确定好 Apache Dubbo 与 Spring Cloud 之间的选型,尽量避免两个不同体系在同一集群中出现,以降低集群维护复杂度。而对于一些确需两套体系共存的场景,为了解决相互之间的通信问题,我们提供了 [Dubbo 与 Spring Cloud 异构微服务体系互通最佳实践](/en/blog/2023/10/07/微服务最佳实践零改造实现-spring-cloud-apache-dubbo-互通/) 解决方案。 - - Dubbo 与 Spring Boot 是互补的关系,Dubbo 在 Spring Boot 体系之上提供了完整的微服务开发、治理能力,关于这一点我们在另一篇文章中有更详尽的说明:[Dubbo、Spring Cloud 与 Istio](/en/overview/what/xyz-difference/)。 - +## Relationship Between Dubbo and Spring Cloud +Dubbo and Spring Cloud are two parallel microservice development and solution frameworks. Both provide the capability for defining, publishing, and governing microservices. For microservice developers, we recommend making a clear choice between Apache Dubbo and Spring Cloud at the beginning of development to minimize the complexity of maintaining different systems within the same cluster. For scenarios that require both systems to coexist, we provide a solution for communication issues between them in [Best Practices for Intercommunication between Dubbo and Spring Cloud Heterogeneous Microservice Systems](/en/blog/2023/10/07/微服务最佳实践零改造实现-spring-cloud-apache-dubbo-互通/). +Dubbo and Spring Boot have a complementary relationship, where Dubbo provides complete microservice development and governance capabilities atop the Spring Boot framework. More detailed explanations on this can be found in another article: [Dubbo, Spring Cloud, and Istio](/en/overview/what/xyz-difference/). diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/_index.md index 2c8887cae02d..85c916c04ad1 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/_index.md @@ -2,10 +2,10 @@ aliases: - /en/overview/tasks/mesh/ - /en/overview/tasks/mesh/ -description: '演示多种部署形态的 Dubbo Mesh 解决方案,以及 Dubbo Mesh 如何帮助用户实现架构的平滑迁移。 ' -linkTitle: 服务网格 +description: 'Demonstrates multiple deployment models of the Dubbo Mesh solution and how Dubbo Mesh helps users achieve a smooth migration of architecture.' +linkTitle: Service Mesh no_list: true -title: 服务网格 +title: Service Mesh toc_hide: true type: docs weight: 70 @@ -21,9 +21,9 @@ weight: 70

- Istio & Envoy 示例 + Istio & Envoy Example

-

演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系。

+

Demonstrates the Dubbo service access based on the Envoy proxy in the Istio service mesh framework.

@@ -31,9 +31,9 @@ weight: 70

- Istio & Proxyless 示例 + Istio & Proxyless Example

-

演示 Dubbo Proxyless 接入 Istio 服务网格体系。

+

Demonstrates Dubbo Proxyless access to the Istio service mesh framework.

@@ -42,3 +42,4 @@ weight: 70 {{< /blocks/section >}} + diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/_index.md index ccfdc24f7732..0e9da8bf84f0 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/_index.md @@ -2,17 +2,17 @@ aliases: - /en/overview/tasks/mesh/bookinfo-proxyless/ - /en/overview/tasks/mesh/bookinfo-proxyless/ -description: 通过完整的 Bookinfo 示例操作演示 Dubbo Proxyless 接入 Istio 服务网格体系。 +description: Demonstrates the Dubbo Proxyless integration with Istio service mesh through a complete Bookinfo example. linkTitle: Proxyless Bookinfo no_list: true -title: Proxyless Bookinfo 示例 +title: Proxyless Bookinfo Example type: docs weight: 70 --- -通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系。 +Demonstrates the integration of Dubbo services into the Istio service mesh system based on Envoy proxy through a complete Bookinfo example. {{< blocks/section color="white" height="auto">}} {{< /blocks/section >}} @@ -27,7 +27,7 @@ weight: 70

Traffic Management

-

Tasks that demonstrates how to use Istio's traffic routing features.

+

Tasks that demonstrate how to use Istio's traffic routing features.

@@ -46,3 +46,4 @@ weight: 70 {{< /blocks/section >}} + diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/_index.md index 1be4feb3ad39..8c86f4b0ce6d 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/security/_index.md @@ -2,17 +2,17 @@ aliases: - /en/overview/tasks/mesh/bookinfo-proxyless/security/ - /en/overview/tasks/mesh/bookinfo-proxyless/security/ -description: Envoy Security Bookinfo 示例。 +description: Envoy Security Bookinfo Example. linkTitle: security no_list: true -title: Envoy Bookinfo 认证鉴权示例 +title: Envoy Bookinfo Authentication and Authorization Example type: docs weight: 20 --- -通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系,如何配置认证鉴权体系。 +Through the complete Bookinfo example, this operation demonstrates how to integrate Dubbo services into the Istio service mesh system based on the Envoy proxy, as well as how to configure the authentication and authorization system. {{< blocks/section color="white" height="auto">}} {{< /blocks/section >}} @@ -90,3 +90,4 @@ weight: 20 {{< /blocks/section >}} + diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/_index.md index e7eb3bc5a260..9e8c53fcddda 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-proxyless/traffic/_index.md @@ -2,17 +2,17 @@ aliases: - /en/overview/tasks/mesh/bookinfo-proxyless/traffic/ - /en/overview/tasks/mesh/bookinfo-proxyless/traffic/ -description: Envoy Traffic Management Bookinfo 示例。 +description: Envoy Traffic Management Bookinfo example. linkTitle: Traffic Management no_list: true -title: Envoy Bookinfo 流量管控示例 +title: Envoy Bookinfo Traffic Management Example type: docs weight: 10 --- -通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系,如何进行流量管理。 +Demonstrates traffic management in the Envoy proxy-based Istio service mesh architecture through a complete Bookinfo example with Dubbo service access. {{< blocks/section color="white" height="auto">}} {{< /blocks/section >}} @@ -90,3 +90,4 @@ weight: 10 {{< /blocks/section >}} + diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/_index.md index 7c849d94c10e..9cd2d74b5dd6 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/_index.md @@ -2,17 +2,17 @@ aliases: - /en/overview/tasks/mesh/bookinfo-sidecar/ - /en/overview/tasks/mesh/bookinfo-sidecar/ -description: 通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系。 +description: Demonstrates the access of Dubbo services into an Istio service mesh system based on Envoy proxy through the complete Bookinfo sample. linkTitle: Envoy Bookinfo no_list: true -title: Envoy Bookinfo 示例 +title: Envoy Bookinfo Example type: docs weight: 70 --- -通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系。 +Demonstrates the access of Dubbo services into an Istio service mesh system based on Envoy proxy through the complete Bookinfo sample. {{< blocks/section color="white" height="auto">}} {{< /blocks/section >}} @@ -27,7 +27,7 @@ weight: 70

Traffic Management

-

Tasks that demonstrates how to use Istio's traffic routing features.

+

Tasks that demonstrate how to use Istio's traffic routing features.

@@ -46,3 +46,4 @@ weight: 70 {{< /blocks/section >}} + diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/_index.md index 1cd99c7a9699..c7dd9d91c060 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/security/_index.md @@ -2,17 +2,17 @@ aliases: - /en/overview/tasks/mesh/bookinfo-sidecar/security/ - /en/overview/tasks/mesh/bookinfo-sidecar/security/ -description: Envoy Security Bookinfo 示例。 +description: Envoy Security Bookinfo example. linkTitle: security no_list: true -title: Envoy Bookinfo 认证鉴权示例 +title: Envoy Bookinfo Authentication and Authorization Example type: docs weight: 20 --- -通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系,如何配置认证鉴权体系。 +The complete Bookinfo example demonstrates how to access Dubbo services within the Istio service mesh framework based on the Envoy proxy, and how to configure the authentication and authorization system. {{< blocks/section color="white" height="auto">}} {{< /blocks/section >}} @@ -90,3 +90,4 @@ weight: 20 {{< /blocks/section >}} + diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/_index.md index 8a3a001d052b..bbfaef0376ad 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/bookinfo-sidecar/traffic/_index.md @@ -2,17 +2,17 @@ aliases: - /en/overview/tasks/mesh/bookinfo-sidecar/traffic/ - /en/overview/tasks/mesh/bookinfo-sidecar/traffic/ -description: Envoy Traffic Management Bookinfo 示例。 +description: Envoy Traffic Management Bookinfo example. linkTitle: Traffic Management no_list: true -title: Envoy Bookinfo 流量管控示例 +title: Envoy Bookinfo Traffic Control Example type: docs weight: 10 --- -通过完整的 Bookinfo 示例操作演示 Dubbo 服务接入基于 Envoy 代理的 Istio 服务网格体系,如何进行流量管理。 +This demonstration showcases how to perform traffic management in the Dubbo service access based on the Envoy proxy within the Istio service mesh, using the complete Bookinfo example. {{< blocks/section color="white" height="auto">}} {{< /blocks/section >}} @@ -37,7 +37,7 @@ weight: 10

Traffic Shifting

-

Shows you how to migrate traffic from an old to new version of a service.

+

Shows you how to migrate traffic from an old to a new version of a service.

@@ -46,7 +46,7 @@ weight: 10

TCP Traffic Shifting -

Shows you how to migrate TCP traffic from an old to new version of a TCP service.

+

Shows you how to migrate TCP traffic from an old to a new version of a TCP service.

@@ -90,3 +90,4 @@ weight: 10 {{< /blocks/section >}} + diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/_index.md b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/_index.md index e0e9adbc57d2..c66a411f81ce 100755 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/_index.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/_index.md @@ -2,10 +2,10 @@ aliases: - /en/overview/tasks/mesh/migration/ - /en/overview/tasks/mesh/migration/ -description: 演示 Dubbo Mesh 如何帮助用户实现架构的平滑迁移。 -linkTitle: Dubbo2 平滑迁移 +description: Demonstrate how Dubbo Mesh helps users achieve a smooth architecture migration. +linkTitle: Smooth Migration of Dubbo2 no_list: true -title: 传统 Dubbo 微服务集群如何平滑迁移到 Istio 服务网格体系 +title: How Traditional Dubbo Microservice Clusters Smoothly Migrate to the Istio Service Mesh System type: docs weight: 70 --- @@ -20,9 +20,9 @@ weight: 70

- 地址同步问题 + Address Synchronization Issues

-

如何解决地址同步问题?

+

How to solve address synchronization issues?

@@ -30,9 +30,9 @@ weight: 70

- 协议识别问题 + Protocol Recognition Issues

-

如何解决 Dubbo2+hessian2 协议问题?

+

How to solve the Dubbo2 + hessian2 protocol issues?

@@ -41,3 +41,4 @@ weight: 70 {{< /blocks/section >}} + diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/deploy-on-k8s.md b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/deploy-on-k8s.md index 9109795884c0..9107e8cb6539 100644 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/deploy-on-k8s.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/deploy-on-k8s.md @@ -2,129 +2,126 @@ aliases: - /en/overview/tasks/mesh/migration/deploy-on-k8s/ - /en/overview/tasks/mesh/migration/deploy-on-k8s/ -description: 该示例演示了直接以 API-SERVER 为注册中心,将 Dubbo 应用部署到 Kubernetes 并复用 Kubernetes Native Service 的使用示例。 此示例的局限在于需要授予每个 Dubbo 应用访问 API-SERVER 特定资源的权限,同时直接访问和监听 API-SERVER 对中小集群来说并没有什么问题, 但对于较大规模集群而言可能给 API-SERVER 的稳定性带来一定的考验。除此之外,可以考虑配合 Dubbo 控制面将 Dubbo 应用部署到 Kuberntes 的方案, 该方案无需授予 Dubbo 应用访问 API-SERVER 的权限,也无需为 API-SERVER 引连接过多数据面造成的稳定性而担心。 -linkTitle: 协议识别 -title: 协议识别 +description: This example demonstrates the deployment of a Dubbo application to Kubernetes using API-SERVER as the registry center and reusing Kubernetes Native Service. The limitation of this example is that each Dubbo application must be granted permissions to access specific resources on API-SERVER. Direct access and monitoring of API-SERVER is not an issue for small to medium clusters, but it may challenge the stability of API-SERVER in larger clusters. Additionally, consider deploying Dubbo applications to Kubernetes with a Dubbo control plane, which does not require granting access to API-SERVER and alleviates concerns about stability caused by excessive data connections. +linkTitle: Protocol Recognition +title: Protocol Recognition type: docs weight: 2 --- -可以按照下文步骤,将 Dubbo 服务轻松部署到 Kubernetes 集群,此查看文章用到的 [完整代码示例地址](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-kubernetes) +You can easily deploy Dubbo services to a Kubernetes cluster by following the steps below, with the [full code example available here](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-kubernetes). -## 1 总体目标 +## 1 Overall Goals -* 部署 Dubbo 应用到 Kubernetes -* 基于 Kubernetes 内置 Service 实现服务发现 -* 将 Dubbo 应用对接到 Kubernetes 生命周期 +* Deploy Dubbo applications to Kubernetes +* Implement service discovery based on Kubernetes built-in Service +* Integrate Dubbo applications with Kubernetes lifecycle -## 2 基本流程 +## 2 Basic Workflow -1. 创建一个 Dubbo - 应用( [dubbo-samples-kubernetes](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-kubernetes) ) -2. 构建容器镜像并推送到镜像仓库( [dubbo-demo 示例例镜像](https://hub.docker.com/r/apache/dubbo-demo) ) -3. 分别部署 Dubbo Provider 与 Dubbo Consumer 到 Kubernetes -4. 验证服务发现与调用正常 +1. Create a Dubbo application ([dubbo-samples-kubernetes](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-kubernetes)) +2. Build container images and push to the image repository ([dubbo-demo example image](https://hub.docker.com/r/apache/dubbo-demo)) +3. Deploy Dubbo Provider and Dubbo Consumer to Kubernetes +4. Verify service discovery and calls are normal -## 3 详细步骤 +## 3 Detailed Steps -### 3.1 环境要求 +### 3.1 Environment Requirements -请确保本地安装如下环境,以提供容器运行时、Kubernetes集群及访问工具 +Ensure that the following environment is installed locally to provide container runtime, Kubernetes cluster, and access tools. * [Docker](https://www.docker.com/get-started/) * [Minikube](https://minikube.sigs.k8s.io/docs/start/) * [Kubectl](https://kubernetes.io/docs/tasks/tools/) -* [Kubens(optional)](https://github.com/ahmetb/kubectx) +* [Kubens (optional)](https://github.com/ahmetb/kubectx) -通过以下命令启动本地 Kubernetes 集群 +Start the local Kubernetes cluster using the following command: ```shell minikube start ``` -通过 kubectl 检查集群正常运行,且 kubectl 绑定到默认本地集群 +Check if the cluster is running normally and if kubectl is bound to the default local cluster: ```shell kubectl cluster-info ``` -### 3.2 前置条件 +### 3.2 Prerequisites -由于示例 Dubbo 项目均部署在 Pod 中且与 API-SERVER 有交互,因此有相应的权限要求,我们这里创建独立 ServiceAccount 并绑定必须的 Roles,后面所有的 Dubbo Kubernetes -资源都将使用这里新建的 ServiceAccount。 +As the example Dubbo project is deployed in Pods and interacts with API-SERVER, there are corresponding permission requirements. Here we create an independent ServiceAccount and bind the necessary Roles. All later Dubbo Kubernetes resources will use the newly created ServiceAccount. -通过以下命令我们创建了独立的 Namespace `dubbo-demo` 与 ServiceAccount `dubbo-sa`。 +With the following command, we created an independent Namespace `dubbo-demo` and ServiceAccount `dubbo-sa`. ```shell -# 初始化命名空间和账号 +# Initialize the namespace and account kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-kubernetes/dubbo-samples-apiserver-provider/src/main/resources/k8s/ServiceAccount.yml -# 切换命名空间 +# Switch namespace kubens dubbo-demo ``` -### 3.3 部署到 Kubernetes +### 3.3 Deploying to Kubernetes -#### 3.3.1 部署 Provider +#### 3.3.1 Deploy Provider ```shell -# 部署 Service +# Deploy Service kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-kubernetes/dubbo-samples-apiserver-provider/src/main/resources/k8s/Service.yml -# 部署 Deployment +# Deploy Deployment kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-kubernetes/dubbo-samples-apiserver-provider/src/main/resources/k8s/Deployment.yml ``` -以上命令创建了一个名为 `dubbo-samples-apiserver-provider` 的 Service,注意这里的 service name 与项目中的 dubbo 应用名是一样的。 +The above commands create a Service named `dubbo-samples-apiserver-provider`. Note that the service name here is the same as the Dubbo application name. -接着 Deployment 部署了一个 3 副本的 pod 实例,至此 Provider 启动完成。 -可以通过如下命令检查启动日志。 +The Deployment then deploys a pod instance with 3 replicas, thus completing the Provider startup. +You can check the startup logs with the following commands. ```shell -# 查看 pod 列表 +# Check the pod list kubectl get pods -l app=dubbo-samples-apiserver-provider -# 查看 pod 部署日志 +# Check pod deployment logs kubectl logs your-pod-id ``` -#### 3.3.2 部署 Consumer +#### 3.3.2 Deploy Consumer ```shell -# 部署 Service +# Deploy Service kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-kubernetes/dubbo-samples-apiserver-consumer/src/main/resources/k8s/Service.yml -# 部署 Deployment +# Deploy Deployment kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-kubernetes/dubbo-samples-apiserver-consumer/src/main/resources/k8s/Deployment.yml ``` -部署 consumer 与 provider 是一样的,这里也保持了 K8S Service 与 Dubbo consumer 名字一致: dubbo-samples-apiserver-consumer。 +Deploying the consumer is the same as the provider. Here, the K8S Service and Dubbo consumer names are kept consistent: dubbo-samples-apiserver-consumer. -检查启动日志,consumer 完成对 provider 服务的消费。 +Check the startup logs, and the consumer completes the consumption of the provider service. ```shell -# 查看 pod 列表 +# Check the pod list kubectl get pods -l app=dubbo-samples-apiserver-consumer -# 查看 pod 部署日志 +# Check pod deployment logs kubectl logs your-pod-id ``` -可以看到日志输出如下: +The logs output as follows: ```java [22/04/22 01:10:24:024UTC]main INFO deploy.DefaultApplicationDeployer:[DUBBO]Dubbo Application[1.1](dubbo-samples-apiserver-consumer)is ready.,dubbo version:3.0.7,current host:172.17.0.6 result:hello,Kubernetes Api Server ``` -### 3.4 修改项目并打包(可跳过) +### 3.4 Modify Project and Package (Optional) -示例项目及相关镜像均已就绪,此小节仅面向需要修改示例并查看部署效果的用户。在此查看[完整代码示例地址](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-kubernetes) +The example project and related images are ready. This section is for users who need to modify the example and check the deployment effect. You can view the [full code example here](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-kubernetes). -设置 Dubbo 项目使用 Kubernetes 作为注册中心,这里通过 DEFAULT_MASTER_HOST指定使用默认 API-SERVER 集群地址 kubernetes.default.srv,同时还指定了 -namespace、trustCerts 两个参数 +Configure the Dubbo project to use Kubernetes as the registry, specifying the default API-SERVER cluster address `kubernetes.default.srv` through `DEFAULT_MASTER_HOST`, along with two additional parameters: `namespace` and `trustCerts`. ```properties dubbo.application.name=dubbo-samples-apiserver-provider @@ -137,25 +134,25 @@ dubbo.application.qosAcceptForeignIp=true dubbo.provider.token=true ``` -如果要在本地打包镜像,可通过 jib-maven-plugin 插件打包镜像 +To package the image locally, you can use the `jib-maven-plugin` to package the image. ```shell -# 打包并推送镜像 +# Package and push the image mvn compile jib:build ``` -> Jib 插件会自动打包并发布镜像。注意,本地开发需将 jib 插件配置中的 docker registry 组织 apache/dubbo-demo 改为自己有权限的组织(包括其他 kubernetes manifests 中的 dubboteam 也要修改,以确保 kubernetes 部署的是自己定制后的镜像),如遇到 jib 插件认证问题,请参考[相应链接](https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md#what-should-i-do-when-the-registry-responds-with-unauthorized)配置 docker registry 认证信息。 -> 可以通过直接在命令行指定 `mvn compile jib:build -Djib.to.auth.username=x -Djib.to.auth.password=x -Djib.from.auth.username=x -Djib.from.auth.username=x`,或者使用 docker-credential-helper. +> The Jib plugin automatically packages and publishes the image. Note that for local development, you must change the Docker registry organization in the jib plugin configuration from apache/dubbo-demo to an organization you have permission for (ensure to modify others in the Kubernetes manifests, as well, to deploy your custom image). If you encounter authentication issues with the jib plugin, refer to [the relevant link](https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md#what-should-i-do-when-the-registry-responds-with-unauthorized) for configuring Docker registry authentication information. +> You can specify directly in the command line `mvn compile jib:build -Djib.to.auth.username=x -Djib.to.auth.password=x -Djib.from.auth.username=x -Djib.from.auth.username=x`, or use docker-credential-helper. -## 4 最佳实践 +## 4 Best Practices TBD -* rediness probe +* readiness probe * liveness probe -* ci/cd 接入 Skalfold +* CI/CD access with Skalfold -## 5 附录 k8s manifests +## 5 Appendix k8s manifests ServiceAccount.yml @@ -321,3 +318,4 @@ spec: failureThreshold: 30 periodSeconds: 10 ``` + diff --git a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/proxyless.md b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/proxyless.md index 595d1f907ff6..070204633c2e 100644 --- a/content/en/overview/mannual/java-sdk/tasks/mesh/migration/proxyless.md +++ b/content/en/overview/mannual/java-sdk/tasks/mesh/migration/proxyless.md @@ -3,26 +3,25 @@ aliases: - /en/overview/tasks/mesh/migration/proxyless/ - /en/overview/tasks/mesh/migration/proxyless/ description: "" -linkTitle: 其他问题? -title: 其他问题? +linkTitle: Other Issues? +title: Other Issues? type: docs weight: 3 --- -Proxyless 模式是指 Dubbo 直接与 Istiod 通信,通过 xDS 协议实现服务发现和服务治理等能力。 -本示例中将通过一个简单的示例来演示如何使用 Proxyless 模式。 +Proxyless mode refers to Dubbo communicating directly with Istiod, utilizing the xDS protocol to achieve capabilities such as service discovery and service governance. This example will demonstrate how to use Proxyless mode through a simple demonstration. -[示例地址](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-xds) +[Example Address](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-xds) -## 代码架构 +## Code Architecture -本小节中主要介绍本文所使用的示例的代码架构,通过模仿本示例中的相关配置改造已有的项目代码可以使已有的项目快速跑在 Proxyless Mesh 模式下。 +This section primarily introduces the code architecture of the example used in this article. By mimicking the relevant configurations in this example, existing project code can be quickly adapted to run in Proxyless Mesh mode. -### 1. 接口定义 +### 1. Interface Definition -为了示例足够简单,这里使用了一个简单的接口定义,仅对参数做拼接进行返回。 +To keep the example simple, a straightforward interface definition is used, returning a concatenated result of parameters. ```java public interface GreetingService { @@ -30,7 +29,7 @@ public interface GreetingService { } ``` -### 2. 接口实现 +### 2. Interface Implementation ```java @DubboService(version = "1.0.0") @@ -43,11 +42,11 @@ public class AnnotatedGreetingService implements GreetingService { } ``` -### 3. 客户端订阅方式 +### 3. Client Subscription Method -**由于原生 xDS 协议无法支持获取从接口到应用名的映射,因此需要配置 `providedBy` 参数来标记此服务来自哪个应用。** +**Since the native xDS protocol does not support obtaining the mapping from the interface to the application name, the `providedBy` parameter needs to be configured to indicate which application this service comes from.** -未来我们将基于 Dubbo Mesh 的控制面实现自动的[服务映射](/en/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/)关系获取,届时将不需要独立配置参数即可将 Dubbo 运行在 Mesh 体系下,敬请期待。 +In the future, we will implement automatic [service mapping](/en/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/) relationship retrieval based on Dubbo Mesh's control panel, eliminating the need for independent parameter configurations. ```java @Component("annotatedConsumer") @@ -60,13 +59,13 @@ public class GreetingServiceConsumer { } ``` -### 4. 服务端配置 +### 4. Server Configuration -服务端配置注册中心为 istio 的地址,协议为 xds。 +The server configuration registers the Istio address as the registration center, and the protocol is xds. -我们建议将 `protocol` 配置为 tri 协议(全面兼容 grpc 协议),以获得在 istio 体系下更好的体验。 +We recommend setting the `protocol` to tri (fully compatible with grpc) for a better experience within the Istio environment. -为了使 Kubernetes 感知到应用的状态,需要配置 `qosAcceptForeignIp` 参数,以便 Kubernetes 可以获得正确的应用状态,[对齐生命周期](/en/overview/mannual/java-sdk/advanced-features-and-usage/others/dubbo-kubernetes-probe/)。 +To allow Kubernetes to be aware of the application's status, the `qosAcceptForeignIp` parameter needs to be configured for Kubernetes to obtain the correct application status, [aligning the lifecycle](/en/overview/mannual/java-sdk/advanced-features-and-usage/others/dubbo-kubernetes-probe/). ```properties dubbo.application.name=dubbo-samples-xds-provider @@ -77,9 +76,9 @@ dubbo.protocol.port=50052 dubbo.application.qosAcceptForeignIp=true ``` -### 5. 客户端配置 +### 5. Client Configuration -客户端配置注册中心为 istio 的地址,协议为 xds。 +The client configuration registers the Istio address as the registration center, and the protocol is xds. ```properties dubbo.application.name=dubbo-samples-xds-consumer @@ -88,13 +87,13 @@ dubbo.registry.address=xds://istiod.istio-system.svc:15012 dubbo.application.qosAcceptForeignIp=true ``` -## 快速开始 +## Quick Start -### Step 1: 搭建 Kubernetes 环境 +### Step 1: Set Up Kubernetes Environment -目前 Dubbo 仅支持在 Kubernetes 环境下的 Mesh 部署,所以在运行启动本示例前需要先搭建 Kubernetes 环境。 +Currently, Dubbo only supports Mesh deployment in Kubernetes environments, so you need to set up a Kubernetes environment before running this example. -搭建参考文档: +Reference Documentation: > [minikube(https://kubernetes.io/zh-cn/docs/tutorials/hello-minikube/)](https://kubernetes.io/zh-cn/docs/tutorials/hello-minikube/) > @@ -102,15 +101,15 @@ dubbo.application.qosAcceptForeignIp=true > > [k3s(https://k3s.io/)](https://k3s.io/) -### Step 2: 搭建 Istio 环境 +### Step 2: Set Up Istio Environment -搭建 Istio 环境参考文档: +Reference Documentation for Istio Installation: -[Istio 安装文档(https://istio.io/latest/docs/setup/getting-started/)](https://istio.io/latest/docs/setup/getting-started/) +[Istio Installation Documentation(https://istio.io/latest/docs/setup/getting-started/)](https://istio.io/latest/docs/setup/getting-started/) -注:安装 Istio 的时候**需要开启 [first-party-jwt 支持](https://istio.io/latest/docs/ops/best-practices/security/#configure-third-party-service-account-tokens)(使用 `istioctl` 工具安装的时候加上 `--set values.global.jwtPolicy=first-party-jwt` 参数)**,否则将导致客户端认证失败的问题。 +Note: When installing Istio, **you must enable [first-party-jwt support](https://istio.io/latest/docs/ops/best-practices/security/#configure-third-party-service-account-tokens) (add the `--set values.global.jwtPolicy=first-party-jwt` parameter when using the `istioctl` tool)**; otherwise, client authentication will fail. -附安装命令参考: +Reference for Installation Commands: ```bash curl -L https://istio.io/downloadIstio | sh - @@ -119,7 +118,7 @@ export PATH=$PWD/bin:$PATH istioctl install --set profile=demo --set values.global.jwtPolicy=first-party-jwt -y ``` -### Step 3: 拉取代码并构建 +### Step 3: Pull Code and Build ```bash git clone https://github.com/apache/dubbo-samples.git @@ -127,9 +126,9 @@ cd dubbo-samples/dubbo-samples-xds mvn clean package -DskipTests ``` -### Step 4: 构建镜像 +### Step 4: Build Images -由于 Kubernetes 采用容器化部署,需要将代码打包在镜像中再进行部署。 +Since Kubernetes adopts containerized deployment, the code needs to be packaged in an image before deployment. ```bash cd ./dubbo-samples-xds-provider/ @@ -141,17 +140,17 @@ docker build -t apache/dubbo-demo:dubbo-samples-xds-consumer_0.0.1 . cd ../ ``` -### Step 5: 创建namespace +### Step 5: Create Namespace ```bash -# 初始化命名空间 +# Initialize namespace kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-xds/deploy/Namespace.yml -# 切换命名空间 +# Switch namespace kubens dubbo-demo ``` -### Step 6: 部署容器 +### Step 6: Deploy Containers ```bash cd ./dubbo-samples-xds-provider/src/main/resources/k8s @@ -165,7 +164,7 @@ kubectl apply -f Deployment.yml cd ../../../../../ ``` -查看 consumer 的日志可以观察到如下的日志: +By checking the logs of the consumer, the following logs can be observed: ``` result: hello, xDS Consumer! from host: 172.17.0.5 result: hello, xDS Consumer! from host: 172.17.0.5 @@ -173,15 +172,15 @@ result: hello, xDS Consumer! from host: 172.17.0.6 result: hello, xDS Consumer! from host: 172.17.0.6 ``` -## 常见问题 +## Common Issues -1. 配置独立的 Istio 集群 `clusterId` +1. Configuring a Separate Istio Cluster `clusterId` -通常在 Kubernetes 体系下 Istio 的 `clusterId` 是 `Kubernetes`,如果你使用的是自建的 istio 生产集群或者云厂商提供的集群则可能需要配置 `clusterId`。 +Typically, in Kubernetes, Istio's `clusterId` is `Kubernetes`. If you are using a self-built Istio production cluster or a cluster provided by a cloud vendor, you may need to configure the `clusterId`. -配置方式:指定 `ISTIO_META_CLUSTER_ID` 环境变量为所需的 `clusterId`。 +Configuration Method: Specify the `ISTIO_META_CLUSTER_ID` environment variable to the desired `clusterId`. -参考配置: +Reference Configuration: ```yaml apiVersion: apps/v1 kind: Deployment @@ -205,25 +204,25 @@ spec: image: xxx ``` -`clusterId` 获取方式: +`clusterId` Retrieval Method: > kubectl describe pod -n istio-system istiod-58b4f65df9-fq2ks -> 读取环境变量中 `CLUSTER_ID` 的值 +> Read the value of `CLUSTER_ID` from the environment variables. -2. Istio 认证失败 +2. Istio Authentication Failure -由于当前 Dubbo 版本还不支持 istio 的 `third-party-jwt` 认证,所以需要配置 `jwtPolicy` 为 `first-party-jwt`。 +Since the current Dubbo version does not support Istio's `third-party-jwt` authentication, it is necessary to configure `jwtPolicy` as `first-party-jwt`. 3. providedBy -由于当前 Dubbo 版本受限于 istio 的通信模型无法获取接口所对应的应用名,因此需要配置 `providedBy` 参数来标记此服务来自哪个应用。 -未来我们将基于 Dubbo Mesh 的控制面实现自动的[服务映射](/en/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/)关系获取,届时将不需要独立配置参数即可将 Dubbo 运行在 Mesh 体系下,敬请期待。 +Due to the current limitations of the Dubbo version with Istio's communication model, it is not possible to obtain the application name corresponding to the interface. Therefore, the `providedBy` parameter needs to be configured to indicate which application this service comes from. In the future, we will implement automatic [service mapping](/en/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/) retrieval based on Dubbo Mesh's control panel. -4. protocol name +4. Protocol Name -Proxyless 模式下应用级服务发现通过 `Kubernetes Native Service` 来进行应用服务发现,而由于 istio 的限制,目前只支持 `http` 协议和 `grpc` 协议的流量拦截转发,所以 `Kubernetes Service` 在配置的时候需要指定 `spec.ports.name` 属性为 `http` 或者 `grpc` 开头。 -因此我们建议使用 triple 协议(完全兼容 grpc 协议)。此处即使 `name` 配置为 `grpc` 开头,但是实际上是 `dubbo` 协议也可以正常服务发现,但是影响流量路由的功能。 +In Proxyless mode, application-level service discovery is performed via `Kubernetes Native Service`. However, due to Istio's limitations, currently, only `http` and `grpc` traffic interception and forwarding are supported. Therefore, the `Kubernetes Service` configuration needs to specify the `spec.ports.name` attribute to start with `http` or `grpc`. -参考配置: +Thus, we recommend using the triple protocol (fully compatible with grpc). Even if the `name` is configured to start with `grpc`, it can still function properly, but it affects the traffic routing capabilities. + +Reference Configuration: ```yaml apiVersion: v1 kind: Service @@ -242,34 +241,35 @@ spec: 5. metadataServicePort -由于 Dubbo 3 应用级服务发现的元数据无法从 istio 中获取,需要走服务自省模式。这要求了 `Dubbo MetadataService` 的端口在全集群的是统一的。 +Since Dubbo 3's application-level service discovery metadata cannot be obtained from Istio, it must rely on service introspection. This requires the `Dubbo MetadataService` port to be unified across the entire cluster. -参考配置: +Reference Configuration: ```properties dubbo.application.metadataServicePort=20885 ``` -未来我们将基于 Dubbo Mesh 的控制面实现自动的[服务元数据](/en/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/)获取,届时将不需要独立配置参数即可将 Dubbo 运行在 Mesh 体系下,敬请期待。 +In the future, we will implement automatic retrieval of [service metadata](/en/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/) based on Dubbo Mesh's control panel. 6. qosAcceptForeignIp -由于 Kubernetes probe 探活机制的工作原理限制,探活请求的发起方不是 `localhost`,所以需要配置 `qosAcceptForeignIp` 参数开启允许全局访问。 +Due to the working principles of Kubernetes probe health checks, if the initiator of the health check request is not `localhost`, the `qosAcceptForeignIp` parameter needs to be configured to allow global access. ```properties dubbo.application.qosAcceptForeignIp=true ``` -注:qos 端口存在危险命令,请先评估网络的安全性。即使 qos 不开放也仅影响 Kubernetes 无法获取 Dubbo 的生命周期状态。 +Note: The qos port contains dangerous commands; please assess network security first. Even if qos is not open, it only affects Kubernetes's ability to retrieve Dubbo's lifecycle status. -7. 不需要开启注入 +7. No Injection Needed -Proxyless 模式下 pod 不需要再开启 envoy 注入,请确认 namespace 中没有 `istio-injection=enabled` 的标签。 +In Proxyless mode, pods do not require envoy injection. Please ensure there are no labels of `istio-injection=enabled` in the namespace. -8. 明文连接istiod +8. Plain Text Connection to Istiod -Proxyless 模式下默认通过ssl方式连接istiod,同时也支持通过明文的方式连接istiod。 +In Proxyless mode, the default connection to Istiod is via SSL, but plain text connections to Istiod are also supported. -明文连接参考配置: +Reference Configuration for Plain Text Connection: ```properties dubbo.registry.secure=plaintext ``` + diff --git a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/no-provider.md b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/no-provider.md index 7393ace8f19b..b6e2b811318d 100644 --- a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/no-provider.md +++ b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/no-provider.md @@ -2,16 +2,16 @@ aliases: - /en/overview/tasks/troubleshoot/no-provider/ - /en/overview/tasks/troubleshoot/no-provider/ -description: 在 Dubbo 抛出地址找不到异常的时候的排查思路 -linkTitle: 地址找不到异常 -title: 地址找不到异常 +description: Troubleshooting thoughts when Dubbo throws an address not found exception +linkTitle: Address not found exception +title: Address not found exception type: docs weight: 2 --- -在开发与生产部署过程中,由于 Dubbo 是一个需要基于服务发现功能进行调用的框架,很容易由于各种客观原因出现 `No Provder` 的异常,本文旨在通过体系化的排查思路,让您能够在异常的时候快速定位原因并解决。 +During the development and production deployment process, since Dubbo is a framework that requires service discovery for calls, it is easy to encounter `No Provider` exceptions due to various objective reasons. This article aims to provide a systematic troubleshooting approach to help you quickly locate and resolve the issue when exceptions occur. ``` java.lang.IllegalStateException: Failed to check the status of the service org.apache.dubbo.samples.api.GreetingsService. No provider available for the service org.apache.dubbo.samples.api.GreetingsService from the url consumer://*** to the consumer 30.221.146.226 use dubbo version 3.2.0-beta.4 @@ -21,23 +21,24 @@ java.lang.IllegalStateException: Failed to check the status of the service org.a Exception in thread "main" org.apache.dubbo.rpc.RpcException: No provider available from registry 127.0.0.1:2181 for service org.apache.dubbo.samples.api.GreetingsService on consumer 30.221.146.226 use dubbo version 3.2.0-beta.4, please check status of providers(disabled, not registered or in blacklist). ``` -## 一句话总结 -服务找不到时先自查服务是否已经开发完部署了,然后在注册中心中确认是否已经注册,如果注册检查服务端发布情况、如果未注册检查消费端订阅情况,中间任何一步出问题都会导致异常。 +## Summary in one sentence +When the service cannot be found, first check whether the service is fully developed and deployed, then corroborate whether it is registered in the registry, check the service side's published status if registered, and consumer side's subscription status if not registered. Any step along this way encountering issues will lead to exceptions. -## 排查思路全览 +## Overview of troubleshooting thoughts ![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676536783437-2e3853cf-68bd-43b1-bc66-81dfc1c4585b.jpeg) -## 详细教程 -### 1 识别异常的服务以及订阅模式 -为了后续正确定位排查的方向,第一步需要先确认有报错的服务名。 +## Detailed tutorial +### 1 Identify the problematic service and subscription mode + +To correctly locate the direction of troubleshooting, the first step is to confirm the service name that reported the error. ![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676616010488-a31451e7-e34e-44b8-ba16-bf6e3f162e33.png) ![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676615807014-5413111b-109e-4976-a25b-d15fe75b314d.png) ![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676616273793-f0bd82b5-bbc6-483f-b945-abe707556b37.png) ![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676616314724-042f1157-cdee-4aaa-b1ac-355c6f1b53e4.png) -如上图所示,常见的地址找不到异常报错中会包括对应的服务名,格式有以下两种。 +As shown in the images above, common address not found exception logs will include the corresponding service name, generally in one of the following two formats: ``` No provider available for the service ${serviceName} @@ -45,119 +46,112 @@ No provider available for the service ${serviceName} No provider available from registry ${registryAddress} for service ${serviceName} ``` -在这个报错日志中可以提取出报错对应的服务名。此处需要注意关注对应的分组与版本号,通常格式如下: +In this error log, the corresponding service name can be extracted. It is important to pay attention to the associated group and version number, usually formatted as follows: ``` ${group}/${interfaceName}:${version} ``` -除了获取报错对应的服务名外,还需要获取该服务的订阅模式。(默认通常为 `APPLICATION_FIRST` 也即是双订阅模式) +In addition to extracting the service name corresponding to the error, the subscription mode of that service also needs to be obtained (usually defaults to `APPLICATION_FIRST`, that is, dual subscription mode). -如一下日志所示,可以在 Dubbo 的日志中搜索 `[DUBBO] Succeed Migrated to` 关键字,获取对应的订阅模式。 +For instance, in the following log, you can search for the keyword `[DUBBO] Succeed Migrated to` in Dubbo's logs to obtain the corresponding subscription mode. ``` [26/02/23 03:27:07:007 CST] main INFO migration.MigrationRuleHandler: [DUBBO] Succeed Migrated to APPLICATION_FIRST mode. Service Name: org.apache.dubbo.samples.api.GreetingsService, dubbo version: 3.2.0-beta.6-SNAPSHOT, current host: 192.168.31.5 ``` -当前 Dubbo 共有三种订阅模式: +Currently, there are three subscription modes in Dubbo: -- FORCE_INTERFACE:仅订阅接口级服务发现模型的数据,这种数据为 2.7.x 及之前的 Dubbo 版本发布的数据模型。 -- FORCE_APPLICATION:仅应用级服务发现模型的数据,这种数据为 3.x 版本开始 Dubbo 为云原生大规模部署的应用所设计的数据模型。 -- APPLICATION_FIRST:同时订阅接口级服务发现模型和应用级服务发现模型的数据,任何一种模型下有数据都可以调用,默认优先使用应用级服务发现模型的数据。 +- FORCE_INTERFACE: Only subscribes to interface-level service discovery model data, which is the data model published in Dubbo versions 2.7.x and earlier. +- FORCE_APPLICATION: Only subscribes to application-level service discovery model data, which is the data model designed for cloud-native large-scale deployments starting from version 3.x of Dubbo. +- APPLICATION_FIRST: Subscribes to both interface-level and application-level service discovery model data; any model with available data can be invoked, prioritizing application-level service discovery data by default. -如果该有问题的服务的订阅模式为 FORCE_INTERFACE,则后续排查中需要检查接口级的地址是否正常发布;如果为 FORCE_APPLICATION 则需要检查应用级地址是否正常发布;如果为 APPLICATION_FIRST 则任意一种地址模型发布都可以。 +If the subscription mode of the problematic service is FORCE_INTERFACE, interface-level addresses must be checked during subsequent troubleshooting. If it is FORCE_APPLICATION, check application-level addresses instead. If it is APPLICATION_FIRST, any model's published address will suffice. -### 2 查询注册中心是否存在服务 -#### 2.1 通过 Dubbo Admin 查询(推荐) -如果您的集群中部署了 Dubbo Admin,可以直接 Dubbo Admin 的控制台中的“服务查询”模块查询该服务的注册情况。 +### 2 Check if the service exists in the registry +#### 2.1 Query through Dubbo Admin (recommended) +If Dubbo Admin is deployed in your cluster, you can directly check the registration status of the service in the "Service Query" module of the Dubbo Admin console. ![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676619545350-62c71bca-44c2-4d28-8660-969e2a24dccb.png) ![img](/imgs/docs3-v2/java-sdk/troubleshoot/1676620038647-54bcbafb-1ee1-470f-8e48-8017dd7321dc.png) -如上图所示,请结合前述第 1 步中服务发现模型确认是否能查询到预期的服务端。 -如果能查到,请跳转到第 x 步继续排查,如果不能查到请跳转到第 3 步进行排查。 +As shown above, please confirm whether you can find the expected service side in conjunction with the service discovery model established in Step 1. If found, proceed with Step x for further troubleshooting. If not found, move to Step 3 for troubleshooting. -#### 2.2 通过注册中心查询 -如果您没有部署 Dubbo Admin,则可以通过注册中心直接查询原始数据。 +#### 2.2 Query through the registry +If you have not deployed Dubbo Admin, you can query the raw data directly through the registry. -#### 2.2.1 Nacos 注册中心 -1)接口级服务发现 -在接口级服务发现模型下,可以直接通过 Nacos 控制台查询服务信息,入口为 "服务管理" - "服务列表",输入服务名在服务名称一栏搜索即可查询。 +#### 2.2.1 Nacos Registry +1)Interface level service discovery +In the interface-level service discovery model, you can directly query service information via the Nacos console by navigating to "Service Management" - "Service List" and searching by service name. -注:Nacos 注册中心下,Dubbo 服务名与 Nacos 服务名映射关系为 `providers:${interfaceName}:${version}:${group}`,如 `dev/com.example.DemoService:1.0.0` 映射为 `providers:com.example.DemoService:1.0.0:dev`。 +Note: In Nacos, the mapping relation of Dubbo service names to Nacos service names is `providers:${interfaceName}:${version}:${group}`, e.g., `dev/com.example.DemoService:1.0.0` maps to `providers:com.example.DemoService:1.0.0:dev`. ![img](/imgs/docs3-v2/java-sdk/troubleshoot/1677399028899-c36dbb0e-a6a9-42f1-85f8-a746410588ec.png) -如上图所示,请结合前述第 1 步中服务发现模型确认是否能查询到预期的服务端。 -如果能查到,请跳转到第 x 步继续排查,如果不能查到请跳转到第 3 步进行排查。 +As shown above, please confirm whether you can query the expected service side in conjunction with the service discovery model established in Step 1. If found, proceed with Step x for further troubleshooting. If not found, move to Step 3 for troubleshooting. -2)应用级服务发现 -在应用级服务发现模型下,需要先查询服务映射的信息,入口为 "配置管理" - "配置列表",Data ID 为接口名,Group 为 `mapping`。 +2)Application level service discovery +In the application-level service discovery model, first check the mapping information of the service by navigating to "Configuration Management" - "Configuration List", where Data ID is the interface name and the Group should be `mapping`. -注:查询服务映射时 Data ID 为接口名,不需要填写分组、版本号。 +Note: When checking service mappings, the Data ID is the interface name, and group and version numbers do not need to be filled. ![img](/imgs/docs3-v2/java-sdk/troubleshoot/1677399521159-399758bd-09c9-4365-a2e3-960fadbf93a8.png) ![img](/imgs/docs3-v2/java-sdk/troubleshoot/1677399582939-a92dbc6a-e197-418d-899e-a13cbd958ec2.png) -如上图所示,查询该配置的配置内容中是否存在预期的应用名。 -如果能查到,请以该应用名为服务名称继续排查,如果不能查到请跳转到第 3 步进行排查。 +As shown above, check if the configuration includes the expected application name. If found, continue troubleshooting using this application name as the service name. If not found, move to Step 3 for troubleshooting. -在查询到应用名以后,需要进一步查询服务信息,入口为 "服务管理" - "服务列表",输入服务名在服务名称一栏搜索即可查询。 +After finding the application name, further query service information through "Service Management" - "Service List", searching by service name. -注:此处的服务名称为上一步查询出的应用名,非接口名。 +Note: Here the service name is the application name queried from the previous step, not the interface name. ![img](/imgs/docs3-v2/java-sdk/troubleshoot/1677399702538-0d198aa5-dd40-49ec-a5ad-b3615c4e9d6a.png) -如上图所示,请结合前述第 1 步中服务发现模型确认是否能查询到预期的服务端。 -如果能查到,请跳转到第 x 步继续排查,如果不能查到请跳转到第 3 步进行排查。 +As shown above, please confirm whether you can find the expected service side based on the service discovery model established in Step 1. If found, proceed with Step x for further troubleshooting. If not found, move to Step 3 for troubleshooting. -#### 2.2.2 通过 Zookeeper 注册中心查询 +#### 2.2.2 Query through Zookeeper Registry -1)接口级服务发现 -在接口级服务发现模型下,可以直接通过 Zookeeper 命令行查询服务信息,路径为 `/dubbo/${interfaceName}/providers`。 +1)Interface level service discovery +In the interface-level service discovery model, you can directly query service information through the Zookeeper command line, with the path being `/dubbo/${interfaceName}/providers`. -注:Zookeeper 注册中心中路径上为接口名,分组和版本号在地址参数上,如果您指定了服务的分组或版本号,需要检查每个地址的参数。 +Note: The interface name is used in the path on the Zookeeper registry, while group and version numbers are parameters in the address. If you specified the group's or version's parameters of the service, check each address parameter. ```bash [zk: localhost:2181(CONNECTED) 1] ls /dubbo/org.apache.dubbo.samples.api.GreetingsService/providers [dubbo%3A%2F%2F30.221.144.195%3A20880%2Forg.apache.dubbo.samples.api.GreetingsService%3Fanyhost%3Dtrue%26application%3Dfirst-dubbo-provider%26background%3Dfalse%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26environment%3Dproduct%26executor-management-mode%3Ddefault%26file-cache%3Dtrue%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.samples.api.GreetingsService%26methods%3DsayHi%26pid%3D37828%26prefer.serialization%3Dfastjson2%2Chessian2%26release%3D3.2.0-beta.6-SNAPSHOT%26service-name-mapping%3Dtrue%26side%3Dprovider%26timestamp%3D1677463548624] ``` -如上所示,请结合前述第 1 步中服务发现模型确认是否能查询到预期的服务端。 -如果能查到,请跳转到第 x 步继续排查,如果不能查到请跳转到第 3 步进行排查。 +As shown above, confirm whether you can query the expected service side based on the service discovery model established in Step 1. If found, proceed with Step x for further troubleshooting. If not found, move to Step 3 for troubleshooting. -2)应用级服务发现 -在应用级服务发现模型下,需要先查询服务映射的信息,可以通过 Zookeeper 的命令行工具查询,路径为 `/dubbo/mapping/${interfaceName}` +2)Application level service discovery +In the application-level service discovery model, you first need to check the service mapping information, which can be queried through the Zookeeper command line with the path `/dubbo/mapping/${interfaceName}`. -注:查询服务映射时 interfaceName 为接口名,不需要填写分组、版本号。 +Note: When checking service mapping, the interfaceName refers to the interface name, and no group or version needs to be specified. ```bash [zk: localhost:2181(CONNECTED) 6] get /dubbo/mapping/org.apache.dubbo.samples.api.GreetingsService first-dubbo-provider ``` -如上所示,查询该配置的配置内容中是否存在预期的应用名。 -如果能查到,请以该应用名为服务名称继续排查,如果不能查到请跳转到第 3 步进行排查。 +As shown above, check if the configuration content contains the expected application name. If found, proceed with this application name to continue troubleshooting. If not found, move to Step 3 for troubleshooting. -在查询到应用名以后,需要进一步查询服务信息,可以直接通过 Zookeeper 命令行查询服务信息,路径为 `/services/${interfaceName}`。 +After finding the application name, further query service information directly via the Zookeeper command line, with the path being `/services/${interfaceName}`. -注:此处的服务名称为上一步查询出的应用名,非接口名。 +Note: The service name here is the application name identified from the previous step, not the interface name. ```bash [zk: localhost:2181(CONNECTED) 7] ls /services/first-dubbo-provider [30.221.144.195:20880] ``` -如上图所示,请结合前述第 1 步中服务发现模型确认是否能查询到预期的服务端。 -如果能查到,请跳转到第 x 步继续排查,如果不能查到请跳转到第 3 步进行排查。 +As shown above, confirm whether you can find the expected service side based on the service discovery model established in Step 1. If found, proceed with Step x for further troubleshooting. If not found, move to Step 3 for troubleshooting. -注:如果采用了应用级服务发现模型后检查消费端地址仍找不到则可能是该服务端没有发布对应的服务,请从第 3 步开始排查。 +Note: If after utilizing the application-level service discovery model, you still cannot locate the consumer-side address, it may indicate that the service provider has not published the corresponding service; therefore, start troubleshooting from Step 3. -### 3 检查服务端是否已经发布服务 -#### 3.1 通过 Dubbo QoS 查询(推荐) -在 Dubbo 应用启动的时候,默认会在本地的 22222 端口发布一个 QoS 服务,可以用于运行时查询节点的状态。通常,如果没有独立配置 `dubbo.application.qos-enable` 或者 `dubbo.application.qos-port` 都可以基于本方法查询服务的信息。 +### 3 Check whether the service provider has published the service +#### 3.1 Check through Dubbo QoS (recommended) +When Dubbo applications start, a QoS service is published by default on port 22222 locally, which can be used to query the status of nodes at runtime. Typically, if `dubbo.application.qos-enable` or `dubbo.application.qos-port` is not explicitly configured, you can use this method to check service information. -找到预期发布该服务的机器,登陆到其控制台,执行 `telnet 127.0.0.1 22222` 和 `ls`: +Find the machine expected to publish this service, log into its console, and execute `telnet 127.0.0.1 22222` and `ls`: ```bash ➜ telnet 127.0.0.1 22222 Trying 127.0.0.1... @@ -185,7 +179,7 @@ dubbo> ``` -如果机器上没有 `telnet` 也可以通过 `cURL` 发起调用,请求地址为 `http://127.0.0.1:22222/ls`: +If `telnet` is not available on the machine, you can also use `cURL` to initiate a call, where the request address is `http://127.0.0.1:22222/ls`: ```bash ➜ curl http://127.0.0.1:22222/ls As Provider side: @@ -202,62 +196,61 @@ As Consumer side: +---------------------+---+ ``` -注:默认情况下 `ls` 命令仅允许本机调用,如果您无法登陆对应的机器,请参考 3.2 通过日志进行检查。 +Note: By default, the `ls` command only allows local calls. If you cannot log into the corresponding machine, refer to 3.2 to check via logs. -如上结果所示,请检查在 `As Provider side` 一栏中是否存在您所发布的服务名,如果存在则代表该服务已经发布。 -第二列 `PUB` 中的信息为该服务的注册情况,格式为 `${registryName}-${registerType}(${status})`。`registerType` 有两种情况,分别是 `A` 和 `I` 代表着应用级服务发现模型和接口级服务发现模型。可以通过该信息判断服务发布的情况。 +As shown in the results, check whether your published service name exists in the `As Provider side` column. If it does, it means the service has been published. The information in the second column, `PUB`, indicates the registration status of the service, formatted as `${registryName}-${registerType}(${status})`. The `registerType` can be either `A` or `I`, representing application-level and interface-level service discovery models. This information can help determine the service publication status. -如果您无法找到您所发布的服务,请检查以下清单: +If you cannot find your published service, please check the following checklist: -1. 该服务是否已经添加到该机器所对应的运行代码中 -2. 该服务是否已经正确配置到 Dubbo 环境中,请检查如 `@EnableDubbo`、`@DubboService` 或者 XML 等配置是否正确 +1. Has the service been added to the running code corresponding to the machine? +2. Is the service properly configured in the Dubbo environment? Check if configurations like `@EnableDubbo`, `@DubboService`, or XML are correct. -如果您找到了您所发布的服务,但是服务状态是 `N`,请检查以下清单: +If you found your published service but its status is `N`, check the following checklist: -1. 该服务配置了 `register=false` -2. 是否有外部的命令调用了 `offline` -3. 应用是否启动成功(包括但不限于如 Tomcat、Spring 的启动状态) +1. Is the service configured with `register=false`? +2. Was there an external command that invoked `offline`? +3. Did the application start successfully (including but not limited to states of Tomcat, Spring)? -如果您找到了您所发布的服务,但是对应的服务发现模型错误,请检查以下清单: +If you found your published service, but its corresponding service discovery model is erroneous, check the following checklist: -1. 注册中心地址是否配置了 `registry-type=service` -2. 是否配置了应用级的注册模式,如 `dubbo.application.register-type` +1. Is the registry address configured with `registry-type=service`? +2. Is the application-level registration model configured, such as `dubbo.application.register-type`? -如果您找到了您所发布的服务,且对应的服务发现模型下服务状态是 `Y`,请跳转到第 4 步进行排查。 +If you found your published service and its corresponding service discovery model status is `Y`, proceed to Step 4 for further troubleshooting. -#### 3.2 通过日志检查 -如果您由于各种原因无法使用 Dubbo QoS,可以在对应机器的日志上搜索 `[DUBBO] Export dubbo service ${serviceName}` 来检查服务是否已经发布。 +#### 3.2 Check through logs +If you cannot use Dubbo QoS for various reasons, search for `[DUBBO] Export dubbo service ${serviceName}` in the logs of the machine to check if the service has been published. ```bash [26/02/23 04:34:41:041 CST] main INFO config.ServiceConfig: [DUBBO] Export dubbo service org.apache.dubbo.samples.api.GreetingsService to local registry url : injvm://***, dubbo version: 3.1.7, current host: 192.168.31.5 ``` -如上所示,则代表着该服务已经发布,如果您无法找到您所发布的服务,请检查以下清单: +As shown above, this indicates that the service has been published. If you cannot find your published service, check the following checklist: -1. 该服务是否已经添加到该机器所对应的运行代码中 -2. 该服务是否已经正确配置到 Dubbo 环境中,请检查如 `@EnableDubbo`、`@DubboService` 或者 XML 等配置是否正确 +1. Has the service been added to the running code corresponding to the machine? +2. Is the service properly configured in the Dubbo environment? Verify configurations like `@EnableDubbo`, `@DubboService`, or XML settings are accurate. -在确定了服务已经发布了以后,可以在对应机器的日志上搜索 `[DUBBO] Register dubbo service ${serviceName} to registry ${registryAddress}` 来检查服务是否已经注册。 +After confirming that the service has been published, search for `[DUBBO] Register dubbo service ${serviceName} to registry ${registryAddress}` in the logs of the corresponding machine to check if the service has been registered. ```bash [26/02/23 04:34:41:041 CST] main INFO config.ServiceConfig: [DUBBO] Register dubbo service org.apache.dubbo.samples.api.GreetingsService url dubbo://*** to registry 127.0.0.1:8848, dubbo version: 3.1.7, current host: 192.168.31.5 ``` -如上所示,则代表着该服务已经注册,如果您无法找到相关日志,请检查以下清单: +As shown above, this indicates that the service has been registered. If you cannot find relevant logs, please check the following checklist: -1. 该服务配置了 `register=false` -2. 是否有外部的命令调用了 `offline` -3. 应用是否启动成功(包括但不限于如 Tomcat、Spring 的启动状态) +1. Is the service configured with `register=false`? +2. Is there an external command that called `offline`? +3. Did the application start successfully (including but not limited to states of Tomcat and Spring)? -如果您找到了您所注册的服务,请跳转到第 4 步进行排查。 +If you found your registered service, proceed to Step 4 for further troubleshooting. -### 4 检查服务端注册中心配置 -#### 4.1 通过 Dubbo Admin 查询(推荐) -注:Dubbo 3.2.0 及以上版本支持 +### 4 Check the service provider's registry configuration +#### 4.1 Check through Dubbo Admin (recommended) +Note: Supported in Dubbo version 3.2.0 and above. -在 Dubbo 应用启动的时候,默认会在本地的 22222 端口发布一个 QoS 服务,可以用于运行时查询节点的状态。通常,如果没有独立配置 `dubbo.application.qos-enable` 或者 `dubbo.application.qos-port` 都可以基于本方法查询服务的信息。 +When Dubbo applications start, a QoS service is published by default on port 22222 locally, which can be used to query node statuses at runtime. Typically, if `dubbo.application.qos-enable` or `dubbo.application.qos-port` was not explicitly configured, you can use this method to check service information. -找到预期发布该服务的机器,登陆到其控制台,执行 `telnet 127.0.0.1 22222` 和 `getConfig RegistryConfig`: +Find the machine expected to publish this service, log into its console, and execute `telnet 127.0.0.1 22222` and `getConfig RegistryConfig`: ```bash ➜ telnet 127.0.0.1 22222 Trying 127.0.0.1... @@ -274,32 +267,30 @@ RegistryConfig: null ``` -如上述结果所示,请检查对应的注册中心配置是否符合预期,如果不符合请修改对应的配置。 -如果第 3 步和第 4 步检查均符合预期,则该服务应该可以在第 2 步的注册中心中查询到,如果查询不到请检查注册中心是否工作正常。 +As shown in the above results, check whether the corresponding registry configuration meets expectations. If not, adjust the configuration accordingly. If checks for Step 3 and Step 4 both meet expectations, the service should be queryable in the registry outlined in Step 2. If it cannot be found, check whether the registry is functioning correctly. -注:`getConfig` 命令仅允许本机调用,如果您无法登陆对应的机器,请参考 4.2 通过日志进行检查。 +Note: The `getConfig` command only allows local calls. If you cannot log into the corresponding machine, refer to 4.2 to check through logs. -#### 4.2 通过日志检查 -如果您由于各种原因无法使用 Dubbo QoS,可以在对应机器的日志上搜索 `[DUBBO] , dubbo version: 3.2.0-beta.6-SNAPSHOT, current host: 30.221.144.195 ``` -如上述结果所示,请检查对应的注册中心配置是否符合预期,如果不符合请修改对应的配置。 -如果第 3 步和第 4 步检查均符合预期,则该服务应该可以在第 2 步的注册中心中查询到,如果查询不到请检查注册中心是否工作正常。 +As shown in the above results, please check whether the corresponding registry configuration meets expectations. If not, modify it accordingly. If checks for Step 3 and Step 4 both meet expectations, the service should be queryable in the registry outlined in Step 2. If it cannot be found, check the registry functionality's status. -### 5 检查服务端网络配置 +### 5 Check the service provider's network configuration -在服务端发布了服务以后,请检查网络防火墙(iptables、ACL 等)是否允许 Dubbo 端口进行通信,默认 Dubbo 协议端口号为 20880、Triple 协议端口号为 50051。具体端口号可以从第 2 步注册中心中的信息获取。 +Once the service has been published at the service provider, check whether the network firewall (iptables, ACL, etc.) allows communication on Dubbo ports. The default Dubbo protocol port number is 20880, while the Triple protocol port number is 50051. Specific port numbers can be obtained from the information in the registry outlined in Step 2. -测试方式:在消费端机器直接 telnet 远程的端口。 +Testing method: Use telnet directly on the consumption machine to reach the remote port. -### 6 检查消费端是否订阅服务 -#### 6.1 通过 Dubbo QoS 查询(推荐) -在 Dubbo 应用启动的时候,默认会在本地的 22222 端口发布一个 QoS 服务,可以用于运行时查询节点的状态。通常,如果没有独立配置 `dubbo.application.qos-enable` 或者 `dubbo.application.qos-port` 都可以基于本方法查询服务的信息。 +### 6 Check whether the consumer has subscribed to the service +#### 6.1 Check through Dubbo QoS (recommended) +When Dubbo applications start, a QoS service is published by default on port 22222 locally, allowing runtime queries of node status. Typically, if `dubbo.application.qos-enable` or `dubbo.application.qos-port` are not specifically configured, you can use this method to check service information. -找到预期发布该服务的机器,登陆到其控制台,执行 `telnet 127.0.0.1 22222` 和 `ls`: +Find the machine expected to publish this service, log into its console, and execute `telnet 127.0.0.1 22222` and `ls`: ```bash ➜ telnet 127.0.0.1 22222 Trying 127.0.0.1... @@ -327,7 +318,7 @@ dubbo> ``` -如果机器上没有 `telnet` 也可以通过 `cURL` 发起调用,请求地址为 `http://127.0.0.1:22222/ls`: +If `telnet` is not available on the machine, you can also initiate a call using `cURL`, where the request address is `http://127.0.0.1:22222/ls`: ```bash ➜ curl http://127.0.0.1:22222/ls As Provider side: @@ -344,65 +335,64 @@ As Consumer side: +---------------------------------------------+---------------------+ ``` -注:默认情况下 `ls` 命令仅允许本机调用,如果您无法登陆对应的机器,请参考 3.2 通过日志进行检查。 +Note: By default, the `ls` command only allows local calls. If you cannot log into the corresponding machine, refer to 3.2 for checks via logs. -如上结果所示,请检查在 `As Consumer side` 一栏中是否存在您所发布的服务名,如果存在则代表该服务已经发布。 -第二列 `NUM` 中的信息为该服务的注册情况,格式为 `${registryName}-${migrationType}(${level}-${count})`。 +As shown in the resulting output, check whether the service name you published exists in the `As Consumer side` column. If it does, it indicates the service has been published. The information in the second column, `NUM`, displays the registration status of the service formatted as `${registryName}-${migrationType}(${level}-${count})`. -1. `migrationType` 有三种情况,分别是 `AF`、`FA` 和 `FI` 代表着订阅的模式。`AF` 会优先使用应用级模型下的地址,如果应用级地址找不到会自动使用接口级模型的地址。`FA` 和 `FI` 则会只使用应用级模型的地址和接口级模型的地址。 -2. `level` 有两种情况,分别是 `I` 和 `A`,代表着接口级模型下的地址和应用级模型下的地址。 +1. `migrationType` can be one of three types: `AF`, `FA`, and `FI`, indicating subscription modes. `AF` prioritizes addresses from the application-level model; if the application-level address is not found, it defaults to using the interface-level model's address. `FA` and `FI` utilize only the application-level and interface-level addresses, respectively. +2. `level` can be `I` or `A`, which indicate whether the address is from the interface-level model or the application-level model. -如果您无法找到您所发布的服务,请检查以下清单: +If you cannot locate your published service, please check the following checklist: -1. 该服务是否已经添加到该机器所对应的运行代码中 -2. 该服务是否已经正确配置到 Dubbo 环境中,请检查如 `@EnableDubbo`、`@DubboReference` 或者 XML 等配置是否正确 +1. Has the service been added to the corresponding running code on the machine? +2. Is the service correctly configured in the Dubbo environment? Check configurations like `@EnableDubbo`, `@DubboReference`, or XML for correctness. -如果您找到了您所发布的服务,但是服务的地址数是 `0`,请检查以下清单: +If you found your published service, but the number of addresses is `0`, please check: -1. 注册中心的工作状态 -2. 从第 2 步重新排查 +1. The working status of the registry. +2. Reassess from Step 2. -如果您找到了您所发布的服务,但是对应的服务发现模型错误,请检查以下清单: +If found with an incorrect service discovery model, check: -1. 是否配置的订阅迁移规则,如 `dubbo-migration.yaml` 或动态配置,请参考 [应用级服务发现地址迁移规则说明](/en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) +1. The configured subscription migration rules in files like `dubbo-migration.yaml` or dynamic configurations. Refer to [Application-level Service Discovery Address Migration Rules](/en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/). -如果您找到了您所发布的服务,且对应的服务发现模型下地址数非 `0`,请跳转到第 7 步进行排查。 +If you located your published service and the corresponding service discovery model shows more than `0` addresses, proceed to Step 7 for further troubleshooting. -#### 6.2 通过日志检查 -如果您由于各种原因无法使用 Dubbo QoS,可以在对应机器的日志上搜索 `[DUBBO] Subscribe: ` 来检查服务是否已经订阅。 +#### 6.2 Check through logs +If you cannot access Dubbo QoS for various reasons, search for `[DUBBO] Subscribe: ` in the logs of the corresponding machine to verify if the service is subscribed. ```bash [27/02/23 11:02:05:005 CST] main INFO zookeeper.ZookeeperRegistry: [DUBBO] Subscribe: consumer://***/org.apache.dubbo.samples.api.GreetingsService?***, dubbo version: 3.2.0-beta.6, current host: 30.221.144.195 ``` -如上所示,则代表着该服务已经发布,如果您无法找到您所发布的服务,请检查以下清单: +If found, it indicates that the service has been published. If you cannot find your published service, please check the following checklist: -1. 该服务是否已经添加到该机器所对应的运行代码中 -2. 该服务是否已经正确配置到 Dubbo 环境中,请检查如 `@EnableDubbo`、`@DubboReference` 或者 XML 等配置是否正确 +1. Has the service been added to the corresponding running code on the machine? +2. Is the service properly configured in the Dubbo environment? Verify configurations like `@EnableDubbo`, `@DubboReference`, or XML settings for correctness. -在确定了服务已经订阅了以后,可以在对应机器的日志上搜索 `[DUBBO] Received invokers changed event from registry. ` 来检查服务是否已经推送。 +After confirming that the service is subscribed, you can check the logs for `[DUBBO] Received invokers changed event from registry.` to assess if the service has been pushed. ```bash [27/02/23 11:02:05:005 CST] main INFO integration.RegistryDirectory: [DUBBO] Received invokers changed event from registry. Registry type: interface. Service Key: org.apache.dubbo.samples.api.GreetingsService. Urls Size : 1. Invokers Size : 1. Available Size: 1. Available Invokers : 30.221.144.195:20880, dubbo version: 3.2.0-beta.6, current host: 30.221.144.195 ``` -如上所示,则代表着该服务已经推送,如果您无法找到相关日志,请检查以下清单: +If it is found, it indicates the service has been pushed. If you cannot locate the relevant logs, please check the following checklist: -1. 注册中心的工作状态 -2. 从第 2 步重新排查 +1. The working status of the registry. +2. Reassess from Step 2. -如果您找到了您所注册的服务,请跳转到第 7 步进行排查。 +If you found your registered service, proceed to Step 7 for further investigation. -注:推送日志仅 3.2.0 及以上版本支持 +Note: The push logs are only supported in version 3.2.0 and above. -### 7 检查消费端注册中心配置 -注:本小节排查思路与第 4 步检查服务端注册中心配置类似。 -#### 7.1 通过 Dubbo Admin 查询(推荐) -注:Dubbo 3.2.0 及以上版本支持 +### 7 Check the configuration of the consumer's registry +Note: The troubleshooting thoughts in this section are similar to Step 4's check on the service provider's registry configuration. +#### 7.1 Check through Dubbo Admin (recommended) +Note: Supported in Dubbo 3.2.0 and above. -在 Dubbo 应用启动的时候,默认会在本地的 22222 端口发布一个 QoS 服务,可以用于运行时查询节点的状态。通常,如果没有独立配置 `dubbo.application.qos-enable` 或者 `dubbo.application.qos-port` 都可以基于本方法查询服务的信息。 +When Dubbo applications start, a QoS service is published by default on port 22222 locally, which can be used to query node statuses at runtime. Typically, if `dubbo.application.qos-enable` or `dubbo.application.qos-port` are not explicitly configured, you can use this method to check service information. -找到预期发布该服务的机器,登陆到其控制台,执行 `telnet 127.0.0.1 22222` 和 `getConfig RegistryConfig`: +Find the expected machine publishing this service, log into its console, and execute `telnet 127.0.0.1 22222` and `getConfig RegistryConfig`: ```bash ➜ telnet 127.0.0.1 22222 Trying 127.0.0.1... @@ -419,27 +409,25 @@ RegistryConfig: null ``` -如上述结果所示,请检查对应的注册中心配置是否符合预期,如果不符合请修改对应的配置。 -如果第 6 步和第 7 步检查均符合预期,则该服务应该可以在第 2 步的注册中心中查询到,如果查询不到请检查注册中心是否工作正常。 +As shown in the above results, check whether the corresponding registry configuration meets expectations. If not, adjust the configuration accordingly. If checks for Step 6 and Step 7 both meet expectations, the service should be queryable in the registry outlined in Step 2. If it cannot be found, check whether the registry is functioning correctly. -注:`getConfig` 命令仅允许本机调用,如果您无法登陆对应的机器,请参考 4.2 通过日志进行检查。 +Note: The `getConfig` command only allows local calls. If you cannot log into the corresponding machine, refer to 4.2 to check via logs. -#### 7.2 通过日志检查 -如果您由于各种原因无法使用 Dubbo QoS,可以在对应机器的日志上搜索 `[DUBBO] , dubbo version: 3.2.0-beta.6-SNAPSHOT, current host: 30.221.144.195 ``` -如上述结果所示,请检查对应的注册中心配置是否符合预期,如果不符合请修改对应的配置。 -如果第 3 步和第 4 步检查均符合预期,则该服务应该可以在第 2 步的注册中心中查询到,如果查询不到请检查注册中心是否工作正常。 +As shown in the above results, examine if the corresponding registry configuration meets expectations. If not, modify accordingly. If checks for Step 3 and Step 4 align with expectations, the service should be queryable in the registry outlined in Step 2. If it cannot be found, check the status of the registry's functionality. -### 8 检查注册中心推送的地址信息 -注:本小节中使用的查询命令 Dubbo 3.2.0 及以上版本支持 +### 8 Check the address information pushed by the registry +Note: The query commands in this section are supported in Dubbo version 3.2.0 and above. -在 Dubbo 应用启动的时候,默认会在本地的 22222 端口发布一个 QoS 服务,可以用于运行时查询节点的状态。通常,如果没有独立配置 `dubbo.application.qos-enable` 或者 `dubbo.application.qos-port` 都可以基于本方法查询服务的信息。 +When Dubbo applications start, a QoS service is published by default on port 22222 locally, which can be used to query node statuses at runtime. Typically, if `dubbo.application.qos-enable` or `dubbo.application.qos-port` are not explicitly configured, you can use this method to check service information. -找到预期发布该服务的机器,登陆到其控制台,执行 `telnet 127.0.0.1 22222` 和 `getAddress ${serviceName}`: +Find the expected machine publishing this service, log into its console, and execute `telnet 127.0.0.1 22222` and `getAddress ${serviceName}`: ```bash ➜ telnet 127.0.0.1 22222 @@ -477,87 +465,87 @@ Disabled Invokers: dubbo> ``` -如上述结果所示,格式如下: +As shown in the results above, the format is as follows: ```bash -ConsumerModel: 订阅的信息 +ConsumerModel: Subscription information -Registry: 注册中心地址 -MigrationStep: 迁移模型(FORCE_APPLICATION, APPLCATION_FIRST, FORCE_INTERFACE) +Registry: Registry address +MigrationStep: Migration model (FORCE_APPLICATION, APPLICATION_FIRST, FORCE_INTERFACE) -Interface-Level: 接口级服务发现模型下地址 +Interface-Level: Address from the interface-level service discovery model All Invokers: -从注册中心推送的所有地址 +All addresses pushed from the registry Valid Invokers: -所有可用地址 +All available addresses Disabled Invokers: -所有被拉黑的地址(通常是主动下线) +All blacklisted addresses (typically taken offline voluntarily) -Application-Level: 应用级服务发现模型下地址 +Application-Level: Addresses from the application-level service discovery model All Invokers: -从注册中心推送的所有地址 +All addresses pushed from the registry Valid Invokers: -所有可用地址 +All available addresses Disabled Invokers: -所有被拉黑的地址(通常是主动下线) +All blacklisted addresses (typically taken offline voluntarily) ``` -请检查对应迁移模型是否符合预期,默认为 `APPLCATION_FIRST`,如果对应的服务发现模型错误,请检查以下清单: +Check whether the corresponding migration model meets your expectations, with the default being `APPLICATION_FIRST`. If the corresponding service discovery model is incorrect, please check the following checklist: -1. 是否配置的订阅迁移规则,如 `dubbo-migration.yaml` 或动态配置,请参考 [应用级服务发现地址迁移规则说明](/en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) +1. The configured subscription migration rule, in files like `dubbo-migration.yaml` or dynamic settings. Refer to [Application-level Service Discovery Address Migration Rules](/en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) -如果迁移模型正确,请检查对应模型下的**所有**地址是否符合预期,如果不符合预期,请检查以下清单: +If the migration model is correct, confirm that **all** addresses in the corresponding model match expectations. If not, check the following checklist: -1. 注册中心的工作状态 -2. 从第 2 步重新排查 +1. The working status of the registry +2. Reassess from Step 2 -如果注册中心推送的地址符合预期,请检查**可用**地址是否符合预期,如果不符合预期,一般为连接异常导致的自动拉黑,通常在四层网络不通或者机房断网等情况下出现,请跳转到第 9 步进行排查。 +If the addresses pushed by the registry meet your expectations, check whether the **available** addresses match expectations. If they do not, it is usually due to connection issues leading to blacklisting, often appearing under conditions like failures in tier-4 networking or room outages. Please proceed to Step 9 for further investigation. -如果**可用**地址符合预期,请跳转到第 10 步进行检查。 +If the **available** addresses are as expected, proceed to Step 10 for inspection. -注:`getAddress` 命令仅允许本机调用。 +Note: The `getAddress` command only allows local calls. -### 9 检查消费端与服务端网络连通性 +### 9 Check the network connectivity between the consumer and service provider -在服务端发布了服务以后,请检查网络防火墙(iptables、ACL 等)是否允许 Dubbo 端口进行通信,默认 Dubbo 协议端口号为 20880、Triple 协议端口号为 50051。具体端口号可以从第 2 步注册中心中的信息获取。 +After the service provider has published the service, ensure that the network firewall (iptables, ACLs, etc.) allows communication on Dubbo ports. The default Dubbo protocol port is 20880, and the Triple protocol port is 50051. Specific port numbers can be obtained from the registry information found in Step 2. -测试方式:在消费端机器直接 telnet 远程的端口。 +Testing method: On the consumer-side machine, use telnet directly to ping the remote port. -常见异常场景: +Common exceptional scenarios: -1. 服务端消费端多集群部署,但是底层网络未打通 -2. 生产与测试共用注册中心,但是测试环境无法调用生产服务(**Dubbo 极其不推荐测试与生产环境混用**) -3. 单机调试,但是网络与大测试网不通 -4. 机房断网导致的节点断连 -5. 四层网络 ACL 规则未开放 Dubbo 端口访问 -6. 网络质量低、服务端负载过高等导致的网络连接质量差 +1. Multi-cluster deployments on both provider and consumer ends, but the underlying network is not connected. +2. Production and testing share a registry, but the testing environment cannot call production services (**Dubbo highly discourages mixing testing and production environments**). +3. Debugging on a single machine, but the network is not connected to the broader test network. +4. Network outages causing node disconnections. +5. Tier-4 network ACL rules not permitting access to Dubbo ports. +6. Poor network quality, service provider overload, or similar conditions impacting connection quality. -### 10 检查路由信息 -注:Dubbo 3.1.0 及以上版本支持 -#### 10.1 报错时检查日志 +### 10 Check routing information +Note: Supported in Dubbo version 3.1.0 and above. +#### 10.1 Check logs during errors -在 Dubbo 出现调用异常的时候,可以在对应机器的日志上搜索 `[DUBBO] No provider available after route for the service` 来检查路由的状态。 +When Dubbo encounters invocation exceptions, you can search for `[DUBBO] No provider available after the route for the service` in the machine's logs to review the routing status. ```bash -[27/02/23 11:33:16:016 CST] main WARN cluster.SingleRouterChain: [DUBBO] No provider available after route for the service org.apache.dubbo.samples.api.GreetingsService from registry 30.221.144.195 on the consumer 30.221.144.195 using the dubbo version 3.2.0-beta.6-SNAPSHOT. Router snapshot is below: +[27/02/23 11:33:16:016 CST] main WARN cluster.SingleRouterChain: [DUBBO] No provider available after the route for the service org.apache.dubbo.samples.api.GreetingsService from registry 30.221.144.195 on the consumer 30.221.144.195 using the dubbo version 3.2.0-beta.6-SNAPSHOT. Router snapshot is below: [ Parent (Input: 1) (Current Node Output: 1) (Chain Node Output: 0) ] Input: 30.221.144.195:20880 -> Chain Node Output: Empty [ MockInvokersSelector (Input: 1) (Current Node Output: 1) (Chain Node Output: 0) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 30.221.144.195:20880 [ StandardMeshRuleRouter (Input: 1) (Current Node Output: 1) (Chain Node Output: 0) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 30.221.144.195:20880 [ TagStateRouter (Input: 1) (Current Node Output: 0) (Chain Node Output: 0) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: Empty, dubbo version: 3.2.0-beta.6-SNAPSHOT, current host: 30.221.144.195, error code: 2-2. This may be caused by No provider available after route for the service, go to https://dubbo.apache.org/faq/2/2 to find instructions ``` -请检查对应的 `Current Node Output: 0` 所在的日志行,通常为该级路由导致的地址为空。 +Check the log line where `Current Node Output: 0` appears; this usually indicates the addresses are empty as a result of routing at that level. -#### 10.2 通过 Dubbo Admin 采样查询 +#### 10.2 Sampling Query through Dubbo Admin -对于线上运行的机器,Dubbo 提供了路由结果动态采样的能力,可以通过 Dubbo QoS 开启。 +For machines operating online, Dubbo offers the ability to dynamically sample routing results, which can be enabled via Dubbo QoS. -开启采样的方式: +To turn on sampling: ```bash dubbo>enableRouterSnapshot com.dubbo.* OK. Found service count: 1. This will cause performance degradation, please be careful! @@ -565,7 +553,7 @@ OK. Found service count: 1. This will cause performance degradation, please be c dubbo> ``` -获取采样结果: +To obtain the sample results: ```bash dubbo>getRecentRouterSnapshot 1658224330156 - Router snapshot service com.dubbo.dubbointegration.BackendService from registry 172.18.111.184 on the consumer 172.18.111.184 using the dubbo version 3.0.9 is below: @@ -589,7 +577,7 @@ dubbo>getRecentRouterSnapshot dubbo> ``` -关闭采样的方式: +To disable sampling: ```bash dubbo>disableRouterSnapshot com.dubbo.* OK. Found service count: 1 @@ -597,5 +585,5 @@ OK. Found service count: 1 dubbo> ``` -注:采集路由信息会消耗一定的性能,排查完毕后请及时关闭。 -参考文档:[路由状态命令](/en/overview/mannual/java-sdk/reference-manual/qos/router-snapshot/) +Note: Collecting routing information will consume some performance, so kindly ensure to disable it promptly after troubleshooting is complete. Reference document: [Routing State Commands](/en/overview/mannual/java-sdk/reference-manual/qos/router-snapshot/) + diff --git a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/request-failed.md b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/request-failed.md index 7b752557b3ce..eb68530e3edd 100644 --- a/content/en/overview/mannual/java-sdk/tasks/troubleshoot/request-failed.md +++ b/content/en/overview/mannual/java-sdk/tasks/troubleshoot/request-failed.md @@ -2,28 +2,28 @@ aliases: - /en/overview/tasks/troubleshoot/request-failed/ - /en/overview/tasks/troubleshoot/request-failed/ -description: 在 Dubbo 请求成功率低时的排查思路 -linkTitle: 请求成功率低 -title: 请求成功率低 +description: Troubleshooting approaches when the request success rate is low in Dubbo +linkTitle: Low Request Success Rate +title: Low Request Success Rate type: docs weight: 3 --- -在生产环境中,请求成功率与延时是最关键的指标,本文将介绍在请求成功率下降时候的排查思路。 +In a production environment, the request success rate and latency are the most critical metrics. This article will introduce troubleshooting approaches when the request success rate decreases. -## 一句话总结 -全链路指标(消费端、网络、服务端、外部依赖等)分析瓶颈 +## Summary in One Sentence +Analyze bottlenecks through end-to-end metrics (consumer end, network, server end, external dependencies, etc.) ![img](/imgs/docs3-v2/java-sdk/troubleshoot/1677487652373-fdc41dbd-0fe0-461f-b827-fa8db68ba2a2.jpeg) -## 排查思路 -### 1 消费端是否正常构造请求 -#### 1.1 检查类对象是否都是可以序列化的 -在使用 Dubbo 进行 RPC 进行远程调用的时候,由于是跨进程的调用,为了防止非预期的数据在网络中请求,Dubbo 遵循 Java 的序列化最佳实践会检查所有数据对象是否实现了 `Serializable` 接口。 +## Troubleshooting Approaches +### 1 Is the Consumer End Constructing Requests Normally? +#### 1.1 Check if Class Objects Are Serializable +When using Dubbo for RPC remote calls, due to cross-process calls, Dubbo checks whether all data objects implement the `Serializable` interface to prevent unexpected data requests over the network. -以下是检查到序列化异常时的日志样例: +Here is a sample log when a serialization exception is detected: ``` io.netty.handler.codec.EncoderException: java.lang.IllegalArgumentException: [Serialization Security] Serialized class org.apache.dubbo.samples.api.GreetingsService$Data has not implement Serializable interface. Current mode is strict check, will disallow to deserialize it by default. at io.netty.handler.codec.MessageToByteEncoder.write(MessageToByteEncoder.java:125) @@ -64,81 +64,75 @@ Caused by: java.lang.IllegalArgumentException: [Serialization Security] Serializ ... 22 more ``` -典型的日志关键字为 `has not implement Serializable interface`。 +Typical log keywords include `has not implement Serializable interface`. -如果存在报错的类信息,请添加实现 `Serializable` 接口后重新部署。 +If class information is reported with errors, please add the `Serializable` interface implementation and redeploy. -#### 1.2 检查自定义扩展的逻辑是否正常 -如果您基于 Dubbo 的 SPI 机制扩展了如 Filter、Cluster、Router 等,请检查对应的实现是否有报错,任何一个组件报错都将影响业务的正常请求。 +#### 1.2 Check if Custom Extensions Are Functioning Normally +If you have extended Dubbo's SPI mechanism with Filters, Clusters, Routers, etc., please check if there are any errors in their implementations as any component error will affect normal business requests. -### 2 消费端是否正常写入请求 -#### 2.1 检查机器性能指标 -在消费端发起网络请求的时候,需要关注机器的 CPU 状态,如使用率、上下文切换次数等。如果机器负载过高,也将影响 Dubbo 请求处理的效率。 +### 2 Is the Consumer End Writing Requests Normally? +#### 2.1 Check Machine Performance Metrics +When the consumer end initiates network requests, monitor the CPU status of the machine, such as usage rate and context switch counts. High machine load will also impact Dubbo's request handling efficiency. -#### 2.2 检查 JVM 指标 -除了机器性能之外,JVM 虚拟机的性能也将直接影响 Dubbo,请关注 JVM 进程的以下指标: +#### 2.2 Check JVM Metrics +In addition to machine performance, the performance of the JVM also directly affects Dubbo. Monitor the following metrics of the JVM process: -1. GC 次数(特别是 Full GC) -2. Young / Old Gen 大小 -3. C1 / C2 编译情况 +1. Number of GC times (especially Full GC) +2. Young / Old Gen size +3. C1 / C2 compilation status -为了更好地观测 JVM 虚拟机,可以通过 Java Flight Recorder 工具进行采样分析,参考。 +For better observation of the JVM, you can use the Java Flight Recorder tool for sampling analysis. -### 3 网络传输是否正常 -#### 3.1 检查网络可达性 -对于绝大多数多机房部署的应用,机器之间的互通经过至少 1 个交换机,请检查: +### 3 Is Network Transmission Normal? +#### 3.1 Check Network Reachability +For most applications deployed across multiple data centers, inter-machine communication goes through at least one switch. Check: -1. 转发(路由)规则是否正常 -2. ACL 是否对 Dubbo 开放 +1. If forwarding (routing) rules are normal +2. If ACL allows Dubbo traffic -#### 3.2 检查网络延迟与重传率 -除了可达性之外,Dubbo 作为同步调用的 RPC,对时延和重传是非常敏感的,请检查: +#### 3.2 Check Network Latency and Retransmission Rates +Besides reachability, Dubbo is very sensitive to latency and retransmission, being a synchronous RPC framework. Check: -1. 节点之间的 RT -2. 网络的丢包率 -3. 网络的重传率(包括 TCP 重传) +1. RT between nodes +2. Network packet loss rate +3. Network retransmission rate (including TCP retransmission) -对于丢包率和重传率,可以通过 tcpdump 进行流量采样,然后通过 wireshark 进行分析。Dubbo 默认采用长连接复用模式,如果存在网络抖动将严重影响当下的所有在途请求。如果您希望您的请求成功率尽可能接近 100% 需要保证网络的 RT 是平稳的,丢包率和重传率接近于 0。 +For packet loss and retransmission rates, use tcpdump for traffic sampling and analyze with wireshark. Dubbo defaults to a long connection reuse mode. Network jitter will severely affect all ongoing requests. To keep your request success rate close to 100%, ensure stable network RT with packet loss and retransmission rates close to 0. -#### 3.3 检查网络吞吐量 -对于存在跨机房调用的用户来说,请密切关注网络的带宽指标,一旦达到运营商所限制的最大值将导致严重的请求丢包等情况,这对于 Dubbo 来说的影响是巨大的。 +#### 3.3 Check Network Throughput +For users making cross-data-center calls, monitor network bandwidth metrics closely as reaching the provider's maximum limit can lead to severe request packet loss, greatly impacting Dubbo. -### 4 服务端是否正常接收请求 -#### 4.1 检查机器性能指标 -在服务端处理网络请求的时候,需要关注机器的 CPU 状态,如使用率、上下文切换次数等。如果机器负载过高,也将影响 Dubbo 请求处理的效率。 +### 4 Is the Server Receiving Requests Normally? +#### 4.1 Check Machine Performance Metrics +During network request handling on the server side, monitor the CPU status, such as usage and context switch counts. High machine load will also affect Dubbo's request handling efficiency. -#### 4.2 检查 JVM 指标 -除了机器性能之外,JVM 虚拟机的性能也将直接影响 Dubbo,请关注 JVM 进程的以下指标: +#### 4.2 Check JVM Metrics +Additionally, monitor the JVM's performance metrics as mentioned earlier. -1. GC 次数(特别是 Full GC) -2. Young / Old Gen 大小 -3. C1 / C2 编译情况 +### 5 Is the Server Processing Requests Normally? +#### 5.1 Check if the Server Thread Pool Is Full +Dubbo defaults to a concurrency limit of 200 (modifiable). If this limit is exceeded, new requests will be rejected to protect the server. -为了更好地观测 JVM 虚拟机,可以通过 Java Flight Recorder 工具进行采样分析,参考。 - -### 5 服务端是否正常处理请求 -#### 5.1 检查是否服务端线程池满 -Dubbo 默认为服务端配置了 200(可修改)并发值的限制,如果某一时刻下超过了该限制将拒绝所有的新请求1⃣以保护服务端。 - -以下为线程池满时的日志样例: +Sample log when the thread pool is full: ``` -[27/02/23 05:37:40:040 CST] NettyServerWorker-5-2 WARN support.AbortPolicyWithReport: [DUBBO] Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-30.221.144.195:20880, Pool Size: 20 (active: 20, core: 20, max: 20, largest: 20), Task: 27 (completed: 7), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://30.221.144.195:20880!, dubbo version: 3.1.7, current host: 30.221.144.195, error code: 0-1. This may be caused by too much client requesting provider, go to https://dubbo.apache.org/faq/0/1 to find instructions. +[27/02/23 05:37:40:040 CST] NettyServerWorker-5-2 WARN support.AbortPolicyWithReport: [DUBBO] Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-30.221.144.195:20880, Pool Size: 20 (active: 20, core: 20, max: 20, largest: 20), Task: 27 (completed: 7), ... ``` -典型的日志关键字为 `Thread pool is EXHAUSTED` +Typical log keyword is `Thread pool is EXHAUSTED`. -Dubbo 默认会在 `user.home` 目录下打印异常时的 `jstack` 信息,您也可以自行执行 `jstack` 进行排查。 +Dubbo defaults to printing `jstack` information when an exception occurs in the `user.home` directory; you can also run `jstack` manually for troubleshooting. -#### 5.2 检查是否被限流了 -如果您开启了 Dubbo 的 TPS 限流或者是引入了如 Sentinel、Hystrix 等限流组件,请检查是否触发限流值。 +#### 5.2 Check for Traffic Limiting +If you have enabled Dubbo's TPS limiting or introduced components like Sentinel or Hystrix for traffic limiting, check if the limiting values are triggered. -#### 5.3 检查自定义扩展的逻辑是否正常 -如果您基于 Dubbo 的 SPI 机制扩展了如 Filter 等,请检查对应的实现是否有报错,任何一个组件报错都将影响业务的正常请求。 +#### 5.3 Check if Custom Extensions Are Working Normally +If you've extended Dubbo's SPI for Filters or similar components, check if there are errors in their implementations, as any component error will affect normal business requests. -#### 5.4 检查服务端处理时长 -如果服务端处理的时长接近或者是超过客户端配置的超时时间,则客户端会直接快速抛出异常。 +#### 5.4 Check Server Processing Duration +If the processing duration on the server approaches or exceeds the timeout configured on the client, the client will quickly throw an exception. -关于服务端处理的时长可以参考以下日志: +Regarding server processing duration, refer to the following log: ``` [27/02/23 05:30:04:004 CST] DubboServerHandler-30.221.144.195:20880-thread-5 WARN filter.ProfilerServerFilter: [DUBBO] [Dubbo-Provider] execute service org.apache.dubbo.samples.api.GreetingsService:0.0.0#sayHi cost 3001.533827 ms, this invocation almost (maybe already) timeout. Timeout: 1000ms @@ -157,10 +151,11 @@ Start time: 4237588012688 +-[ Offset: 0.045578ms; Usage: 3001.436721ms, 99% ] Receive request. Server biz impl invoke begin., dubbo version: 3.1.7, current host: 30.221.144.195, error code: 3-7. This may be caused by , go to https://dubbo.apache.org/faq/3/7 to find instructions. ``` -可以搜索 `execute service *** cost *** ms, this invocation almost (maybe already) timeout`相关日志。 +Search for logs related to `execute service *** cost *** ms, this invocation almost (maybe already) timeout`. + +Typically when this log appears, your service implementation may be experiencing one of the following situations: -通常在出现此日志的时候,您的服务实现中可能存在以下情况: +1. Long lock waits +2. External dependencies (RPC, MQ, Cache, DB, etc.) taking too long, requiring integration with a full-link tracking platform for diagnosis +3. High machine load -1. 长时间的锁等待 -2. 外部依赖(RPC、MQ、Cache、DB 等)处理时长过长,可以接入全链路追踪平台诊断 -3. 机器的负载过高 From 22d3d83a3bfd23bce0e729c6c0c20e9ecc25bba9 Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Mon, 30 Sep 2024 15:44:56 +0800 Subject: [PATCH 12/23] Translate --- .../en/overview/mannual/java-sdk/_index.md | 39 +- .../mannual/java-sdk/quick-start/_index.md | 5 +- .../mannual/java-sdk/quick-start/deploy.md | 90 ++-- .../mannual/java-sdk/quick-start/starter.md | 86 ++-- .../java-sdk/reference-manual/_index.md | 7 +- .../reference-manual/architecture/_index.md | 7 +- .../architecture/code-architecture.md | 123 ++--- .../architecture/multi-instance/_index.md | 7 +- .../architecture/multi-instance/develop.md | Bin 7392 -> 8225 bytes .../architecture/multi-instance/model.md | 240 +++++----- .../multi-instance/multi-instance.md | 84 ++-- .../architecture/multi-instance/workflow.md | 32 +- .../architecture/multi-protocol.md | 78 ++-- .../architecture/service-invocation.md | 81 ++-- .../reference-manual/config-center/_index.md | 25 +- .../reference-manual/config-center/apollo.md | 75 ++-- .../config-center/introduction.md | 27 +- .../reference-manual/config-center/nacos.md | 75 ++-- .../reference-manual/config-center/others.md | 22 +- .../config-center/zookeeper.md | 69 +-- .../reference-manual/config/_index.md | 7 +- .../reference-manual/config/api/_index.md | 7 +- .../reference-manual/config/maven-plugin.md | 62 ++- .../reference-manual/config/spring/_index.md | 5 +- .../config/spring/spring-boot.md | 47 +- .../reference-manual/config/spring/xml.md | 57 +-- .../java-sdk/reference-manual/faq/0/1.md | 30 +- .../java-sdk/reference-manual/faq/0/10.md | 17 +- .../java-sdk/reference-manual/faq/0/11.md | 15 +- .../java-sdk/reference-manual/faq/0/12.md | 17 +- .../java-sdk/reference-manual/faq/0/13.md | 17 +- .../java-sdk/reference-manual/faq/0/14.md | 18 +- .../java-sdk/reference-manual/faq/0/15.md | 19 +- .../java-sdk/reference-manual/faq/0/16.md | 19 +- .../java-sdk/reference-manual/faq/0/17.md | 15 +- .../java-sdk/reference-manual/faq/0/18.md | 15 +- .../java-sdk/reference-manual/faq/0/19.md | 15 +- .../java-sdk/reference-manual/faq/0/2.md | 15 +- .../java-sdk/reference-manual/faq/0/20.md | 19 +- .../java-sdk/reference-manual/faq/0/21.md | 15 +- .../java-sdk/reference-manual/faq/0/22.md | 25 +- .../java-sdk/reference-manual/faq/0/23.md | 21 +- .../java-sdk/reference-manual/faq/0/24.md | 19 +- .../java-sdk/reference-manual/faq/0/25.md | 17 +- .../java-sdk/reference-manual/faq/0/26.md | 15 +- .../java-sdk/reference-manual/faq/0/27.md | 15 +- .../java-sdk/reference-manual/faq/0/28.md | 17 +- .../java-sdk/reference-manual/faq/0/29.md | 17 +- .../java-sdk/reference-manual/faq/0/3.md | 23 +- .../java-sdk/reference-manual/faq/0/4.md | 21 +- .../java-sdk/reference-manual/faq/0/5.md | 27 +- .../java-sdk/reference-manual/faq/0/6.md | 17 +- .../java-sdk/reference-manual/faq/0/7.md | 18 +- .../java-sdk/reference-manual/faq/0/8.md | 15 +- .../java-sdk/reference-manual/faq/0/9.md | 15 +- .../java-sdk/reference-manual/faq/0/99.md | 15 +- .../java-sdk/reference-manual/faq/0/_index.md | 9 +- .../java-sdk/reference-manual/faq/1/1.md | 19 +- .../java-sdk/reference-manual/faq/1/10.md | 21 +- .../java-sdk/reference-manual/faq/1/11.md | 19 +- .../java-sdk/reference-manual/faq/1/12.md | 19 +- .../java-sdk/reference-manual/faq/1/13.md | 17 +- .../java-sdk/reference-manual/faq/1/14.md | 19 +- .../java-sdk/reference-manual/faq/1/15.md | 17 +- .../java-sdk/reference-manual/faq/1/16.md | 19 +- .../java-sdk/reference-manual/faq/1/17.md | 21 +- .../java-sdk/reference-manual/faq/1/18.md | 21 +- .../java-sdk/reference-manual/faq/1/19.md | 19 +- .../java-sdk/reference-manual/faq/1/20.md | 17 +- .../java-sdk/reference-manual/faq/1/21.md | 17 +- .../java-sdk/reference-manual/faq/1/22.md | 15 +- .../java-sdk/reference-manual/faq/1/26.md | 15 +- .../java-sdk/reference-manual/faq/1/27.md | 15 +- .../java-sdk/reference-manual/faq/1/28.md | 15 +- .../java-sdk/reference-manual/faq/1/29.md | 17 +- .../java-sdk/reference-manual/faq/1/3.md | 15 +- .../java-sdk/reference-manual/faq/1/30.md | 23 +- .../java-sdk/reference-manual/faq/1/31.md | 19 +- .../java-sdk/reference-manual/faq/1/32.md | 23 +- .../java-sdk/reference-manual/faq/1/33.md | 19 +- .../java-sdk/reference-manual/faq/1/34.md | 15 +- .../java-sdk/reference-manual/faq/1/35.md | 19 +- .../java-sdk/reference-manual/faq/1/36.md | 15 +- .../java-sdk/reference-manual/faq/1/37.md | 15 +- .../java-sdk/reference-manual/faq/1/38.md | 17 +- .../java-sdk/reference-manual/faq/1/39.md | 19 +- .../java-sdk/reference-manual/faq/1/4.md | 25 +- .../java-sdk/reference-manual/faq/1/40.md | 19 +- .../java-sdk/reference-manual/faq/1/41.md | 15 +- .../java-sdk/reference-manual/faq/1/42.md | 15 +- .../java-sdk/reference-manual/faq/1/5.md | 19 +- .../java-sdk/reference-manual/faq/1/6.md | 19 +- .../java-sdk/reference-manual/faq/1/7.md | 17 +- .../java-sdk/reference-manual/faq/1/8.md | 25 +- .../java-sdk/reference-manual/faq/1/9.md | 37 +- .../java-sdk/reference-manual/faq/1/_index.md | 9 +- .../java-sdk/reference-manual/faq/2/1.md | 9 +- .../java-sdk/reference-manual/faq/2/10.md | 23 +- .../java-sdk/reference-manual/faq/2/11.md | 17 +- .../java-sdk/reference-manual/faq/2/12.md | 15 +- .../java-sdk/reference-manual/faq/2/13.md | 15 +- .../java-sdk/reference-manual/faq/2/14.md | 17 +- .../java-sdk/reference-manual/faq/2/15.md | 15 +- .../java-sdk/reference-manual/faq/2/16.md | 15 +- .../java-sdk/reference-manual/faq/2/17.md | 19 +- .../java-sdk/reference-manual/faq/2/18.md | 15 +- .../java-sdk/reference-manual/faq/2/19.md | 19 +- .../java-sdk/reference-manual/faq/2/2.md | 31 +- .../java-sdk/reference-manual/faq/2/20.md | 15 +- .../java-sdk/reference-manual/faq/2/3.md | 15 +- .../java-sdk/reference-manual/faq/2/4.md | 15 +- .../java-sdk/reference-manual/faq/2/5.md | 19 +- .../java-sdk/reference-manual/faq/2/6.md | 17 +- .../java-sdk/reference-manual/faq/2/7.md | 15 +- .../java-sdk/reference-manual/faq/2/8.md | 15 +- .../java-sdk/reference-manual/faq/2/9.md | 15 +- .../java-sdk/reference-manual/faq/2/_index.md | 7 +- .../java-sdk/reference-manual/faq/3/1.md | 23 +- .../java-sdk/reference-manual/faq/3/2.md | 21 +- .../java-sdk/reference-manual/faq/3/3.md | 15 +- .../java-sdk/reference-manual/faq/3/4.md | 19 +- .../java-sdk/reference-manual/faq/3/5.md | 19 +- .../java-sdk/reference-manual/faq/3/6.md | 19 +- .../java-sdk/reference-manual/faq/3/7.md | 24 +- .../java-sdk/reference-manual/faq/3/8.md | 23 +- .../java-sdk/reference-manual/faq/3/_index.md | 7 +- .../java-sdk/reference-manual/faq/4/1.md | 23 +- .../java-sdk/reference-manual/faq/4/10.md | 33 +- .../java-sdk/reference-manual/faq/4/11.md | 23 +- .../java-sdk/reference-manual/faq/4/12.md | 17 +- .../java-sdk/reference-manual/faq/4/13.md | 23 +- .../java-sdk/reference-manual/faq/4/14.md | 19 +- .../java-sdk/reference-manual/faq/4/15.md | 13 +- .../java-sdk/reference-manual/faq/4/16.md | 15 +- .../java-sdk/reference-manual/faq/4/17.md | 17 +- .../java-sdk/reference-manual/faq/4/18.md | 13 +- .../java-sdk/reference-manual/faq/4/19.md | 19 +- .../java-sdk/reference-manual/faq/4/2.md | 15 +- .../java-sdk/reference-manual/faq/4/20.md | 15 +- .../java-sdk/reference-manual/faq/4/21.md | 19 +- .../java-sdk/reference-manual/faq/4/3.md | 15 +- .../java-sdk/reference-manual/faq/4/4.md | 17 +- .../java-sdk/reference-manual/faq/4/5.md | 15 +- .../java-sdk/reference-manual/faq/4/6.md | 17 +- .../java-sdk/reference-manual/faq/4/7.md | 15 +- .../java-sdk/reference-manual/faq/4/8.md | 15 +- .../java-sdk/reference-manual/faq/4/9.md | 17 +- .../java-sdk/reference-manual/faq/4/_index.md | 7 +- .../java-sdk/reference-manual/faq/5/1.md | 23 +- .../java-sdk/reference-manual/faq/5/10.md | 15 +- .../java-sdk/reference-manual/faq/5/11.md | 23 +- .../java-sdk/reference-manual/faq/5/12.md | 23 +- .../java-sdk/reference-manual/faq/5/13.md | 15 +- .../java-sdk/reference-manual/faq/5/14.md | 19 +- .../java-sdk/reference-manual/faq/5/15.md | 15 +- .../java-sdk/reference-manual/faq/5/16.md | 21 +- .../java-sdk/reference-manual/faq/5/17.md | 19 +- .../java-sdk/reference-manual/faq/5/18.md | 19 +- .../java-sdk/reference-manual/faq/5/2.md | 15 +- .../java-sdk/reference-manual/faq/5/20.md | 19 +- .../java-sdk/reference-manual/faq/5/21.md | 15 +- .../java-sdk/reference-manual/faq/5/22.md | 23 +- .../java-sdk/reference-manual/faq/5/23.md | 17 +- .../java-sdk/reference-manual/faq/5/24.md | 15 +- .../java-sdk/reference-manual/faq/5/25.md | 15 +- .../java-sdk/reference-manual/faq/5/26.md | 13 +- .../java-sdk/reference-manual/faq/5/27.md | 15 +- .../java-sdk/reference-manual/faq/5/28.md | 15 +- .../java-sdk/reference-manual/faq/5/29.md | 15 +- .../java-sdk/reference-manual/faq/5/3.md | 17 +- .../java-sdk/reference-manual/faq/5/30.md | 15 +- .../java-sdk/reference-manual/faq/5/31.md | 15 +- .../java-sdk/reference-manual/faq/5/32.md | 15 +- .../java-sdk/reference-manual/faq/5/33.md | 15 +- .../java-sdk/reference-manual/faq/5/34.md | 15 +- .../java-sdk/reference-manual/faq/5/35.md | 17 +- .../java-sdk/reference-manual/faq/5/36.md | 17 +- .../java-sdk/reference-manual/faq/5/37.md | 17 +- .../java-sdk/reference-manual/faq/5/38.md | 15 +- .../java-sdk/reference-manual/faq/5/39.md | 17 +- .../java-sdk/reference-manual/faq/5/4.md | 19 +- .../java-sdk/reference-manual/faq/5/40.md | 17 +- .../java-sdk/reference-manual/faq/5/41.md | 15 +- .../java-sdk/reference-manual/faq/5/42.md | 19 +- .../java-sdk/reference-manual/faq/5/43.md | 15 +- .../java-sdk/reference-manual/faq/5/5.md | 15 +- .../java-sdk/reference-manual/faq/5/6.md | 15 +- .../java-sdk/reference-manual/faq/5/7.md | 23 +- .../java-sdk/reference-manual/faq/5/8.md | 15 +- .../java-sdk/reference-manual/faq/5/9.md | 23 +- .../java-sdk/reference-manual/faq/5/_index.md | 7 +- .../java-sdk/reference-manual/faq/6/1.md | 19 +- .../java-sdk/reference-manual/faq/6/10.md | 15 +- .../java-sdk/reference-manual/faq/6/11.md | 15 +- .../java-sdk/reference-manual/faq/6/12.md | 17 +- .../java-sdk/reference-manual/faq/6/13.md | 15 +- .../java-sdk/reference-manual/faq/6/14.md | 15 +- .../java-sdk/reference-manual/faq/6/15.md | 15 +- .../java-sdk/reference-manual/faq/6/16.md | 15 +- .../java-sdk/reference-manual/faq/6/2.md | 29 +- .../java-sdk/reference-manual/faq/6/3.md | 15 +- .../java-sdk/reference-manual/faq/6/4.md | 15 +- .../java-sdk/reference-manual/faq/6/5.md | 15 +- .../java-sdk/reference-manual/faq/6/6.md | 17 +- .../java-sdk/reference-manual/faq/6/7.md | 15 +- .../java-sdk/reference-manual/faq/6/8.md | 17 +- .../java-sdk/reference-manual/faq/6/9.md | 20 +- .../java-sdk/reference-manual/faq/6/_index.md | 7 +- .../java-sdk/reference-manual/faq/7/1.md | 15 +- .../java-sdk/reference-manual/faq/7/2.md | 15 +- .../java-sdk/reference-manual/faq/7/3.md | 15 +- .../java-sdk/reference-manual/faq/7/4.md | 15 +- .../java-sdk/reference-manual/faq/7/5.md | 17 +- .../java-sdk/reference-manual/faq/7/6.md | 17 +- .../java-sdk/reference-manual/faq/7/7.md | 17 +- .../java-sdk/reference-manual/faq/7/_index.md | 7 +- .../java-sdk/reference-manual/faq/81/1.md | 21 +- .../java-sdk/reference-manual/faq/81/2.md | 17 +- .../java-sdk/reference-manual/faq/81/3.md | 19 +- .../java-sdk/reference-manual/faq/81/4.md | 27 +- .../reference-manual/faq/81/_index.md | 9 +- .../java-sdk/reference-manual/faq/99/0.md | 29 +- .../java-sdk/reference-manual/faq/99/1.md | 19 +- .../reference-manual/faq/99/_index.md | 7 +- .../java-sdk/reference-manual/faq/_index.md | 9 +- .../java-sdk/reference-manual/faq/intro.md | 37 +- .../reference-manual/graalvm/_index.md | 69 ++- .../graalvm/support-graalvm.md | 130 +++--- .../reference-manual/merics/_index.md | 7 +- .../java-sdk/reference-manual/merics/meter.md | 110 ++--- .../java-sdk/reference-manual/mesh/_index.md | 7 +- .../java-sdk/reference-manual/mesh/mesh.md | 83 ++-- .../metadata-center/_index.md | 7 +- .../reference-manual/metadata-center/nacos.md | 67 +-- .../metadata-center/others.md | 26 +- .../metadata-center/overview.md | 99 ++--- .../metadata-center/zookeeper.md | 62 +-- .../reference-manual/performance/_index.md | 7 +- .../performance/benchmarking.md | 43 +- .../performance/page-benchmarking.md | 4 +- .../performance/rpc-benchmarking.md | 47 +- .../reference-manual/protocol/_index.md | 7 +- .../reference-manual/protocol/dubbo.md | 102 ++--- .../protocol/multi-protocols.md | 67 +-- .../protocol/others/_index.md | 7 +- .../protocol/others/hessian.md | 58 +-- .../protocol/others/memcached.md | 33 +- .../reference-manual/protocol/others/redis.md | 33 +- .../reference-manual/protocol/others/rmi.md | 75 ++-- .../protocol/others/thrift.md | 33 +- .../others/v3.2_rest_protocol_design.md | 287 ++++++------ .../protocol/others/webservice.md | 71 +-- .../reference-manual/protocol/overview.md | 56 +-- .../reference-manual/protocol/triple-3.3.md | 169 ++++--- .../reference-manual/protocol/triple.md | 252 ++++++----- .../java-sdk/reference-manual/qos/_index.md | 7 +- .../qos/introduction/_index.md | 7 +- .../qos/introduction/command.md | 24 +- .../qos/introduction/default_metrics.md | 27 +- .../qos/introduction/logger-management.md | 37 +- .../qos/introduction/probe.md | 19 +- .../qos/introduction/profiler.md | 41 +- .../qos/introduction/router-snapshot.md | 45 +- .../qos/introduction/security.md | 27 +- .../qos/introduction/service-management.md | 48 +- .../java-sdk/reference-manual/qos/overview.md | 109 +++-- .../java-sdk/reference-manual/qos/qos-list.md | 88 ++-- .../reference-manual/registry/_index.md | 7 +- .../registry/multiple-registry.md | 117 ++--- .../reference-manual/registry/nacos.md | 138 +++--- .../registry/others/_index.md | 7 +- .../registry/others/consul.md | 27 +- .../reference-manual/registry/others/etcd.md | 23 +- .../registry/others/multicast.md | 32 +- .../reference-manual/registry/others/redis.md | 73 +-- .../reference-manual/registry/overview.md | 45 +- .../reference-manual/routing-rule/_index.md | 7 +- .../reference-manual/serialization/_index.md | 7 +- .../serialization/dubbo/_index.md | 5 +- .../serialization/dubbo/avro.md | 17 +- .../serialization/dubbo/fastjson.md | 20 +- .../serialization/dubbo/fastjson2.md | 36 +- .../serialization/dubbo/gson.md | 17 +- .../serialization/dubbo/hessian.md | 26 +- .../serialization/dubbo/kryo.md | 51 +-- .../serialization/dubbo/msgpack.md | 17 +- .../serialization/serialization-upgrade.md | 31 +- .../serialization/serialization.md | 192 ++++---- .../serialization/triple/_index.md | 5 +- .../serialization/triple/protobuf.md | 35 +- .../serialization/triple/wrapper.md | 36 +- .../java-sdk/reference-manual/spi/_index.md | 7 +- .../spi/description/_index.md | 7 +- .../reference-manual/spi/description/cache.md | 35 +- .../spi/description/cluster.md | 31 +- .../spi/description/compiler.md | 27 +- .../spi/description/config-center.md | 90 ++-- .../spi/description/container.md | 25 +- .../spi/description/dispatcher.md | 26 +- .../spi/description/exchanger.md | 31 +- .../spi/description/exporter-listener.md | 33 +- .../spi/description/extension-factory.md | 29 +- .../spi/description/filter.md | 50 +-- .../spi/description/invoker-listener.md | 33 +- .../spi/description/liveness.md | 32 +- .../spi/description/load-balance.md | 26 +- .../spi/description/logger-adapter.md | 33 +- .../spi/description/merger.md | 24 +- .../spi/description/metadata-report.md | 37 +- .../spi/description/monitor.md | 29 +- .../spi/description/networker.md | 31 +- .../reference-manual/spi/description/page.md | 27 +- .../spi/description/protocol.md | 87 ++-- .../spi/description/proxy-factory.md | 29 +- .../spi/description/qos-permission.md | 31 +- .../spi/description/readiness.md | 30 +- .../spi/description/registry.md | 136 +++--- .../spi/description/remoting.md | 37 +- .../spi/description/router.md | 27 +- .../spi/description/serialize.md | 32 +- .../spi/description/startup.md | 30 +- .../spi/description/status-checker.md | 31 +- .../spi/description/telnet-handler.md | 32 +- .../spi/description/threadpool.md | 31 +- .../spi/description/validation.md | 27 +- .../java-sdk/reference-manual/spi/overview.md | 28 +- .../upgrades-and-compatibility/_index.md | 7 +- .../migration-service-discovery.md | 59 ++- .../migration-triple.md | 93 ++-- .../upgrades-and-compatibility/migration.md | 336 +++++++------- .../version/2.x-to-3.x-compatibility-guide.md | 121 +++-- .../version/3.0-to-3.1-compatibility-guide.md | 23 +- .../version/3.1-to-3.2-compatibility-guide.md | 115 +++-- .../version/3.2-to-3.3-compatibility-guide.md | 201 ++++----- .../version/_index.md | 7 +- .../overview/mannual/java-sdk/tasks/_index.md | 5 +- .../mannual/java-sdk/tasks/deploy/_index.md | 11 +- .../deploy/deploy-on-kubernetes-service.md | 86 ++-- .../tasks/deploy/deploy-on-kubernetes.md | 55 ++- .../java-sdk/tasks/deploy/deploy-on-vm.md | 93 ++-- .../java-sdk/tasks/extensibility/_index.md | 25 +- .../java-sdk/tasks/extensibility/filter.md | 43 +- .../java-sdk/tasks/extensibility/protocol.md | 57 +-- .../java-sdk/tasks/extensibility/registry.md | 30 +- .../java-sdk/tasks/extensibility/router.md | 41 +- .../java-sdk/tasks/extensibility/spi.md | 46 +- .../java-sdk/tasks/framework/_index.md | 6 +- .../mannual/java-sdk/tasks/framework/async.md | 419 +++++++++--------- .../java-sdk/tasks/framework/attachment.md | 96 ++-- .../framework/fault-tolerent-strategy.md | 69 ++- .../java-sdk/tasks/framework/filter.md | 69 ++- .../java-sdk/tasks/framework/generic.md | 60 +-- .../tasks/framework/lightweight-rpc.md | 49 +- .../java-sdk/tasks/framework/more/_index.md | 7 +- .../framework/more/callback-parameter.md | 34 +- .../framework/more/concurrency-control.md | 53 +-- .../framework/more/config-connections.md | 67 +-- .../tasks/framework/more/echo-service.md | 26 +- .../tasks/framework/more/events-notify.md | 49 +- .../tasks/framework/more/explicit-target.md | 49 +- .../tasks/framework/more/generic-impl.md | 54 +-- .../tasks/framework/more/local-call.md | 44 +- .../tasks/framework/more/local-stub.md | 39 +- .../framework/more/parameter-validation.md | 71 +-- .../java-sdk/tasks/framework/more/reactive.md | 57 ++- .../framework/more/reference-config-cache.md | 36 +- .../tasks/framework/more/result-cache.md | 62 +-- .../tasks/framework/more/router-snapshot.md | 57 +-- .../java-sdk/tasks/framework/more/set-host.md | 81 ++-- .../tasks/framework/more/specify-ip.md | 39 +- .../tasks/framework/threading-model.md | 189 ++++---- .../java-sdk/tasks/framework/timeout.md | 42 +- .../java-sdk/tasks/framework/version_group.md | 155 ++++--- .../mannual/java-sdk/tasks/gateway/_index.md | 6 +- .../java-sdk/tasks/gateway/architecture.md | 41 +- .../mannual/java-sdk/tasks/gateway/dubbo.md | 59 +-- .../mannual/java-sdk/tasks/gateway/triple.md | 129 +++--- .../tasks/mesh/migration/dubbo-mesh.md | 163 +++---- .../java-sdk/tasks/observability/_index.md | 7 +- .../java-sdk/tasks/observability/console.md | 96 ++-- .../java-sdk/tasks/observability/grafana.md | 57 +-- .../tasks/observability/prometheus.md | 32 +- .../tasks/observability/tracing/_index.md | 17 +- .../tasks/observability/tracing/otlp.md | 59 +-- .../tasks/observability/tracing/skywalking.md | 33 +- .../tasks/observability/tracing/tracing.md | 75 ++-- .../tasks/observability/tracing/zipkin.md | 91 ++-- .../java-sdk/tasks/protocols/_index.md | 9 +- .../mannual/java-sdk/tasks/protocols/dubbo.md | 67 +-- .../java-sdk/tasks/protocols/protocol.md | 169 +++---- .../java-sdk/tasks/protocols/triple/_index.md | 6 +- .../java-sdk/tasks/protocols/triple/grpc.md | 47 +- .../java-sdk/tasks/protocols/triple/idl.md | 92 ++-- .../tasks/protocols/triple/interface.md | 77 ++-- .../tasks/protocols/triple/streaming.md | 123 ++--- .../java-sdk/tasks/rate-limit/_index.md | 7 +- .../adaptive-concurrency-control.md | 32 +- .../tasks/rate-limit/concurrency-control.md | 60 +-- .../mannual/java-sdk/tasks/security/_index.md | 7 +- .../mannual/java-sdk/tasks/security/auth.md | 35 +- .../mannual/java-sdk/tasks/security/tls.md | 33 +- .../tasks/security/token-authorization.md | 36 +- .../tasks/service-discovery/_index.md | 7 +- .../tasks/service-discovery/kubernetes.md | 16 +- .../tasks/service-discovery/loadbalance.md | 77 ++-- .../java-sdk/tasks/service-discovery/nacos.md | 151 ++++--- .../tasks/service-discovery/zookeeper.md | 148 +++---- .../tasks/traffic-management/_index.md | 52 +-- .../tasks/traffic-management/accesslog.md | 53 ++- .../tasks/traffic-management/architecture.md | 101 ++--- .../tasks/traffic-management/arguments.md | 59 +-- .../java-sdk/tasks/traffic-management/host.md | 49 +- .../tasks/traffic-management/isolation.md | 91 ++-- .../java-sdk/tasks/traffic-management/mock.md | 55 +-- .../tasks/traffic-management/region.md | 65 +-- .../tasks/traffic-management/retry.md | 53 +-- .../tasks/traffic-management/route.md | 63 ++- .../tasks/traffic-management/timeout.md | 53 +-- .../tasks/traffic-management/weight.md | 63 +-- .../java-sdk/tasks/trasaction/_index.md | 7 +- .../trasaction/distributed-transaction.md | 90 ++-- .../java-sdk/tasks/troubleshoot/_index.md | 7 +- .../java-sdk/tasks/troubleshoot/profiler.md | 57 ++- .../tasks/troubleshoot/start-failed.md | 114 ++--- .../en/overview/mannual/java-sdk/versions.md | 25 +- 425 files changed, 8092 insertions(+), 8021 deletions(-) diff --git a/content/en/overview/mannual/java-sdk/_index.md b/content/en/overview/mannual/java-sdk/_index.md index 9186dcf987f6..b1cbfd8a81d3 100755 --- a/content/en/overview/mannual/java-sdk/_index.md +++ b/content/en/overview/mannual/java-sdk/_index.md @@ -3,32 +3,33 @@ aliases: - /en/docs3-v2/java-sdk/ - /en/docs3-v2/java-sdk/ content: - - 快速开始: - - description: 快速体验 Dubbo Java 微服务开发 - name: '[Spring Boot 快速开发 Dubbo 服务](quick-start/starter/)' - - description: 配置参考手册 - name: '[配置参考手册](reference-manual/config/)' - - 高级特性: - - description: 扩展 Filter、Router 拦截流量 - name: '[扩展 Filter、Router 拦截流量](concepts-and-architecture/service-invocation/)' - - 参考手册: - - description: 注册中心配置指南 - name: '[注册中心配置指南](reference-manual/registry/)' - - 升级与兼容性: - - description: 版本迁移指南 - name: '[版本迁移指南](reference-manual/upgrades-and-compatibility/)' - - 历史版本文档: - - description: 历史版本文档 - name: '[2.x 及早期版本文档](/en/docsv2.7/)' -description: Java SDK 手册 + - Quick Start: + - description: Experience Dubbo Java microservices development quickly + name: '[Spring Boot Quick Start for Dubbo Services](quick-start/starter/)' + - description: Configuration Reference Manual + name: '[Configuration Reference Manual](reference-manual/config/)' + - Advanced Features: + - description: Extend Filter and Router to intercept traffic + name: '[Extend Filter and Router to Intercept Traffic](concepts-and-architecture/service-invocation/)' + - Reference Manual: + - description: Registry Center Configuration Guide + name: '[Registry Center Configuration Guide](reference-manual/registry/)' + - Upgrades and Compatibility: + - description: Version Migration Guide + name: '[Version Migration Guide](reference-manual/upgrades-and-compatibility/)' + - Historical Version Documentation: + - description: Historical Version Documentation + name: '[2.x and Earlier Version Documentation](/en/docsv2.7/)' +description: Java SDK Manual hide_feedback: true hide_summary: true linkTitle: Java SDK no_list: true -title: Java SDK 手册 +title: Java SDK Manual type: docs weight: 1 --- {{% docs/content_box %}} + diff --git a/content/en/overview/mannual/java-sdk/quick-start/_index.md b/content/en/overview/mannual/java-sdk/quick-start/_index.md index 09215900ff58..b70767f91f04 100755 --- a/content/en/overview/mannual/java-sdk/quick-start/_index.md +++ b/content/en/overview/mannual/java-sdk/quick-start/_index.md @@ -7,8 +7,9 @@ aliases: - /en/overview/quickstart/ - /en/overview/quickstart/ description: "" -linkTitle: 快速入门 -title: 快速入门 +linkTitle: Quick Start +title: Quick Start type: docs weight: 2 --- + diff --git a/content/en/overview/mannual/java-sdk/quick-start/deploy.md b/content/en/overview/mannual/java-sdk/quick-start/deploy.md index 2838acfdf28f..9198d81efd57 100644 --- a/content/en/overview/mannual/java-sdk/quick-start/deploy.md +++ b/content/en/overview/mannual/java-sdk/quick-start/deploy.md @@ -1,26 +1,26 @@ --- -description: 快速部署Dubbo应用 -linkTitle: 部署Dubbo应用 -title: 快速部署Dubbo应用 +description: Quick Deployment of Dubbo Applications +linkTitle: Deploying Dubbo Applications +title: Quick Deployment of Dubbo Applications type: docs toc_hide: true hide_summary: true weight: 3 --- -在上一篇文章中,我们从头创建了一个 Dubbo 应用并详细介绍了它的代码结构,接下来,我们将学习部署这个 Dubbo 应用。 +In the previous article, we created a Dubbo application from scratch and detailed its code structure. Next, we will learn how to deploy this Dubbo application. -本文将以 Kubernetes 集群作为基础环境来讲解 Dubbo 应用的部署,部署架构如下图所示。 -![Dubbo+Kubernetes+Nacos 部署架构图]() +This article will explain the deployment of Dubbo applications based on a Kubernetes cluster, and the deployment architecture is shown in the diagram below. +![Dubbo+Kubernetes+Nacos Deployment Architecture]() -{{% alert title="注意" color="info" %}} -在实际使用中,部署环境可能变化多样,包括 Kubernetes Service、服务网格(Service Mesh)、虚拟机等多种部署模式,请参考 [部署文档]() 了解更多详细内容。 +{{% alert title="Note" color="info" %}} +In real-world usage, the deployment environment may vary widely, including Kubernetes Services, Service Mesh, virtual machines, and more. Please refer to [Deployment Documentation]() for more detailed content. {{% /alert %}} -## 前置条件 -Dubbo 社区提供了工具和解决方案来简化整个 Kubernetes 环境的打包与部署过程,所以开始前我们需要先安装相关工具。 +## Prerequisites +The Dubbo community provides tools and solutions to simplify the packaging and deployment process in the entire Kubernetes environment. Therefore, we need to install the relevant tools before we begin. -1. 安装 dubboctl(如尚未安装) +1. Install dubboctl (if not already installed) ```sh curl -L https://raw.githubusercontent.com/apache/dubbo-kubernetes/master/release/downloadDubbo.sh | sh - @@ -28,95 +28,83 @@ Dubbo 社区提供了工具和解决方案来简化整个 Kubernetes 环境的 export PATH=$PWD/bin:$PATH ``` +## Deploying the Application -## 部署应用 - -### 初始化微服务集群 - -1. dubboctl 安装完成之后,接下来通过以下命令初始化微服务部署环境 +### Initialize Microservices Cluster +1. Once dubboctl is installed, initialize the microservice deployment environment with the following command: ```sh dubboctl manifest install --profile=demo ``` - 作为演示目的,以上命令会一键安装 Zookeeper、Dubbo Control Plane、Prometheus、Grafana、Zipkin、Ingress 等组件,关于 `--profile=demo` 更多解释及配置请参见文档说明。 - -2. 检查环境准备就绪 + For demonstration purposes, the above command will install Zookeeper, Dubbo Control Plane, Prometheus, Grafana, Zipkin, Ingress, and other components at once. For more explanations and configurations about `--profile=demo`, please refer to the documentation. +2. Check if the environment is ready: ```sh kubectl get services -n dubbo-system ``` -3. 最后,为目标 kubernetes namespace 开启自动注入模式,以便应用部署后能够自动连接到刚刚安装的 Zookeeper 注册中心等组件。 - +3. Finally, enable the automatic injection mode for the target Kubernetes namespace, so that the application can automatically connect to the Zookeeper registry and other components after deployment. ```shell kubectl label namespace dubbo-demo dubbo-injection=enabled --overwrite ``` -### 部署 Dubbo 应用 - -接下来我们为之前创建的应用打包镜像(请确保本地安装有 Docker 环境并且已经启动 Docker 进程),在应用根目录分别运行以下命令: +### Deploying the Dubbo Application +Next, we will package the image for the application created earlier (please ensure that Docker is installed locally and the Docker process is running). Run the following command in the application's root directory: ```shell dubboctl build --dockerfile=./Dockerfile ``` -`build` 命令会将源码打包为镜像,并推送到远端仓库,取决于网络情况,可能需要一定时间等待命令执行完成。 +The `build` command packages the source code into an image and pushes it to a remote repository. Depending on the network situation, it may take some time to complete the command. -接下来,我们需要生成部署应用的 Kubernetes 资源文件,运行以下命令: +Next, we need to generate the Kubernetes resource files for deploying the application by running the following command: ```shell dubboctl deploy ``` -`deploy` 命令会使用刚刚 `build` 打包的镜像生成 Kubernetes 资源清单。命令执行成功后,在当前目录看到生成的 `kube.yaml` 文件,其中包括 deployment、service 等 kubernetes 资源定义。 - - -{{% alert title="注意" color="warning" %}} -本地构建可能会花费比较长时间,如您本地构建遇到问题,也可以使用以下命令跳过 `build` 过程。 +The `deploy` command will generate the Kubernetes resource manifests using the image just packaged by `build`. After successful execution of the command, you will see the generated `kube.yaml` file in the current directory, which includes the definitions of Kubernetes resources such as deployment and service. +{{% alert title="Note" color="warning" %}} +Local builds may take a long time. If you encounter problems with local builds, you can use the following command to skip the `build` process. ```sh dubboctl deploy --image=apache/dubbo-demo:quickstart_0.1 -# `--image` 指定使用官方预先准备好的示例镜像 +# `--image` specifies using an officially prepared example image ``` {{% /alert %}} -接下来,将应用部署到 Kubernetes 环境。 - +Next, deploy the application to the Kubernetes environment. ```shell kubectl apply -f ./kube.yaml ``` -检查部署状态 +Check the deployment status: ```shell kubectl get services -n dubbo-demo ``` -## 访问应用 -部署成功后,可以通过以下方式检查应用状态。 +## Accessing the Application +After a successful deployment, you can check the application status in the following ways. {{< tabpane text=true >}} -{{< tab header="请根据情况选择:" disabled=true />}} -{{% tab header="本地 Kubernetes 集群" lang="en" %}} +{{< tab header="Please choose according to your situation:" disabled=true />}} +{{% tab header="Local Kubernetes Cluster" lang="en" %}}
-1. 如果使用的本地 Kubernetes 集群,请使用以下方式访问应用验证部署状态: - +1. If you are using a local Kubernetes cluster, please use the following method to access the application and verify the deployment status: ```shell dubboctl dashboard admin ``` -2. 以上命令会自动打开 admin 控制台,如果在您的环境下没有打开,请使用浏览器访问以下地址: - +2. The above command will automatically open the admin console. If it doesn't open in your environment, please visit the following address with your browser: http://localhost:38080/admin -3. 通过 triple 协议,可以继续测试 Dubbo 服务,执行以下命令进行端口映射: - +3. To continue testing Dubbo services through the triple protocol, execute the following command for port mapping: ```shell kubectl port-forward 50051:50051 ``` -4. 通过 curl 访问服务: - +4. Access the service using curl: ```shell curl \ --header "Content-Type: application/json" \ @@ -126,14 +114,12 @@ kubectl get services -n dubbo-demo {{% /tab %}} -{{% tab header="阿里云ACK" lang="zh-cn" %}} +{{% tab header="Alibaba Cloud ACK" lang="zh-cn" %}}
-对于云上托管的哦 Kubernetes 集群,可以使用以下方式验证,这里以阿里云 ACK 集群为例: - -ACK ingerss-controller 的访问方式...... +For cloud-hosted Kubernetes clusters, you can verify using the following method. Here, taking Alibaba Cloud ACK Cluster as an example: +ACK ingress-controller access method...... {{% /tab %}} {{< /tabpane >}} - diff --git a/content/en/overview/mannual/java-sdk/quick-start/starter.md b/content/en/overview/mannual/java-sdk/quick-start/starter.md index cd44f306ea24..a72adbaadd90 100644 --- a/content/en/overview/mannual/java-sdk/quick-start/starter.md +++ b/content/en/overview/mannual/java-sdk/quick-start/starter.md @@ -3,22 +3,22 @@ aliases: - /en/docs3-v2/java-sdk/reference-manual/config/overview/ - /en/docs3-v2/java-sdk/reference-manual/config/overview/ - /en/overview/mannual/java-sdk/quick-start/spring-boot/ -description: 创建基于Spring Boot的Dubbo应用。 -linkTitle: 创建基于Spring Boot的Dubbo应用 -title: 创建基于Spring Boot的微服务应用 +description: Create a Dubbo application based on Spring Boot. +linkTitle: Create a Dubbo application based on Spring Boot +title: Create a microservice application based on Spring Boot type: docs weight: 2 --- -以下文档将引导您从头创建一个基于 Spring Boot 的 Dubbo 应用,并为应用配置 Triple 通信协议、服务发现等微服务基础能力。 +The following document will guide you in creating a Dubbo application based on Spring Boot from scratch, configuring microservice foundational capabilities such as the Triple communication protocol and service discovery. -## 快速创建应用 -通过访问 start.dubbo.apache.org 在线服务创建 Dubbo 微服务应用。如下图所示依次添加组件,您可以在几十秒之内快速创建一个 Dubbo 应用。下载生成的示例应用并解压源码即可。 +## Quickly Create an Application +Create a Dubbo microservice application by accessing start.dubbo.apache.org. Add components as shown in the image below, and you can quickly create a Dubbo application in seconds. Download and unzip the generated sample application. -项目结构截图 +Project Structure Screenshot -{{% alert title="直接使用官方准备好的示例" color="info" %}} -您还可以直接下载官方预先准备好的示例项目: +{{% alert title="Directly Use the Official Sample" color="info" %}} +You can also download the official pre-prepared sample project directly: ```shell $ git clone -b main --depth 1 https://github.com/apache/dubbo-samples @@ -26,19 +26,18 @@ $ cd dubbo-samples/11-quickstart ```` {{% /alert %}} -## 本地启动应用 -接下来,让我们尝试在本地启动应用。运行以下命令启动应用: +## Start the Application Locally +Next, let's try to start the application locally. Run the following command to start the application: ```shell ./mvnw ``` -{{% alert title="注意" color="warning" %}} -由于配置文件中启用了注册中心,为了能够成功启动应用,您需要首先在本地启动 NacosZookeeper 注册中心 server。 +{{% alert title="Note" color="warning" %}} +Since the configuration file has enabled the registration center, to successfully start the application, you need to first start the Nacos or Zookeeper registration center server locally. {{% /alert %}} - -在应用启动成功后,本地进程使用 Triple 协议在指定端口发布了服务,可直接使用 cURL 测试服务是否已经正常运行: +After the application starts successfully, the local process publishes the service using the Triple protocol on the specified port, and you can directly use cURL to test whether the service is running normally: ```shell curl \ @@ -47,15 +46,15 @@ curl \ http://localhost:50051/com.example.demo.dubbo.api.DemoService/sayHello/ ``` -除了使用命令行之外,我们还可以在 IDE 中启动项目,调整示例或进行本地 debug。 +In addition to using the command line, we can also start the project in the IDE, modify the example, or debug locally. -## 源码解析 -将以上准备好的示例项目导入最喜欢的 IDE 开发工具(以 IntelliJ IDEA 为例),项目结构如下: +## Source Code Analysis +Import the prepared sample project into your favorite IDE development tool (taking IntelliJ IDEA as an example), the project structure is as follows: -项目结构截图 +Project Structure Screenshot -### Maven 依赖 -打开 pom.xml,可以看到示例项目中 Dubbo 相关核心依赖如下: +### Maven Dependencies +Open pom.xml, and you can see the core dependencies related to Dubbo in the sample project as follows: ```xml @@ -69,7 +68,7 @@ curl \ - + org.apache.dubbo @@ -82,11 +81,11 @@ curl \ ``` -其中,`dubbo-spring-boot-starter`、`dubbo-zookeeper-spring-boot-starter` 分别为我们引入了 Dubbo 内核框架与 Zookeeper 客户端相关的依赖组件,更多内容可以查看 [Dubbo 支持的 Spring Boot Starter 清单]() 。 +Among them, `dubbo-spring-boot-starter` and `dubbo-zookeeper-spring-boot-starter` introduce the dependencies related to the Dubbo kernel framework and Zookeeper client respectively. More content can be viewed in the [list of Spring Boot Starters supported by Dubbo](). -### 服务定义 +### Service Definition -以下是基于 Java Interface 的标准 Dubbo 服务定义。 +The following is the standard Dubbo service definition based on a Java Interface. ```java public interface DemoService { @@ -94,11 +93,11 @@ public interface DemoService { } ``` -在 `DemoService` 中,定义了 `sayHello` 这个方法。后续服务端发布的服务,消费端订阅的服务都是围绕着 `DemoService` 接口展开的。 +In `DemoService`, the method `sayHello` is defined. Subsequent services published by the server and services subscribed by the consumer revolve around the `DemoService` interface. -### 服务实现 +### Service Implementation -定义了服务接口之后,可以在服务端这一侧定义对应的业务逻辑实现。 +After defining the service interface, you can define the corresponding business logic implementation on the server side. ```java @DubboService @@ -110,10 +109,10 @@ public class DemoServiceImpl implements DemoService { } ``` -在`DemoServiceImpl` 类中添加了 `@DubboService` 注解,通过这个配置可以基于 Spring Boot 去发布 Dubbo 服务。 +In the `DemoServiceImpl` class, the `@DubboService` annotation is added, and this configuration allows the Dubbo service to be published based on Spring Boot. -### 发起服务调用 -示例应用中有一个 consumer 包,用于模拟发起对 provider 服务的远程调用。 +### Initiating Service Calls +The sample application contains a consumer package simulating a remote call to the provider service. ```java @Component @@ -129,15 +128,15 @@ public class Consumer implements CommandLineRunner { } ``` -在 `Task` 类中,通过`@DubboReference` 从 Dubbo 获取了一个 RPC 订阅,这个 `demoService` 可以像本地调用一样直接调用: `demoService.sayHello("world")`。 +In the `Task` class, a RPC subscription is obtained from Dubbo via `@DubboReference`, and this `demoService` can be called as if it were a local call: `demoService.sayHello("world")`. -{{% alert title="提示" color="primary" %}} -通常远程调用是跨进程的,示例项目为了方便开发,直接内置了一个 `@DubboReference` 调用。如果您想学习如何开发一个独立的 Consumer(客户端)进程,以便发起对 Dubbo 服务的远程调用,我们有一个 包含独立 consumer、provider 模块的示例项目 可供参考。 +{{% alert title="Tip" color="primary" %}} +Typically, remote calls are inter-process. To facilitate development, the sample project has directly embedded a `@DubboReference` call. If you want to learn how to develop an independent Consumer (client) process for initiating remote calls to Dubbo services, we have a sample project with independent consumer and provider modules for reference. {{% /alert %}} -### 应用入口与配置文件 +### Application Entry and Configuration File -由于我们创建的是一个 Spring Boot 应用,Dubbo 相关配置信息都存放在 `application.yml` 配置文件中。基于以下配置,Dubbo 进程将在 50051 端口监听 triple 协议请求,同时,实例的 ip:port 信息将会被注册到 Zookeeper server。 +Since we created a Spring Boot application, Dubbo-related configuration information is stored in the `application.yml` configuration file. Based on the following configuration, the Dubbo process will listen for triple protocol requests on port 50051, while the instance's ip:port information will be registered to the Zookeeper server. ```yaml # application.yml @@ -151,7 +150,7 @@ dubbo: address: zookeeper://${zookeeper.address:127.0.0.1}:2181 ``` -以下是整个应用的启动入口,`@EnableDubbo` 注解用来加载和启动 Dubbo 相关组件。 +Here is the entry point for the entire application, and the `@EnableDubbo` annotation is used to load and start Dubbo-related components. ```java @SpringBootApplication @@ -163,16 +162,17 @@ public class DemoApplication { } ``` -## 发布服务定义到远端仓库 +## Publish Service Definitions to Remote Repository -应用开发完成后,我们需要将服务定义发布到外部公开的或组织内部的 maven 仓库,以便调用这些服务的应用能够加载并使用这些服务。 +After completing the application development, we need to publish the service definitions to an externally public or organization-internal Maven repository, so that applications that call these services can load and use them. -如之前我们看到的,示例项目包含 api、service 两个模块,切换项目到 api 目录,以下命令即可完成发布动作: +As we saw earlier, the sample project includes two modules, api and service. Switch to the api directory, and the following command will complete the publishing action: ```shell mvn clean deploy ``` -## 更多内容 -- 接下来,可以 [快速部署 Dubbo 应用到微服务集群]() -- Dubbo 内置服务发现、负载均衡、流量管控规则等能力,学习 [如何配置更多服务治理能力]() +## More Content +- Next, you can [quickly deploy Dubbo applications to microservice clusters]() +- Dubbo has built-in capabilities such as service discovery, load balancing, and traffic control rules. Learn [how to configure more service governance capabilities]() + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/_index.md index 1c97c2079aa1..308c5394bb9b 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/_index.md @@ -3,9 +3,10 @@ aliases: - /en/docs3-v2/java-sdk/reference-manual/ - /en/docs3-v2/java-sdk/reference-manual/ - /en/overview/mannual/java-sdk/advanced-features-and-usage/ -description: 参考手册 -linkTitle: 参考手册 -title: 参考手册 +description: Reference Manual +linkTitle: Reference Manual +title: Reference Manual type: docs weight: 5 --- + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/_index.md index 295c268e3ae9..5a7f175aa5b7 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/_index.md @@ -3,9 +3,10 @@ aliases: - /en/docs3-v2/java-sdk/concepts-and-architecture/ - /en/docs3-v2/java-sdk/concepts-and-architecture/ - /en/overview/mannual/java-sdk/concepts-and-architecture/ -description: 概念和架构 -linkTitle: 源码架构 -title: 源码架构 +description: Concepts and Architecture +linkTitle: Source Code Architecture +title: Source Code Architecture type: docs weight: 100 --- + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/code-architecture.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/code-architecture.md index 73d7923f74c5..fd853a5fbd14 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/code-architecture.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/code-architecture.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/concepts-and-architecture/code-architecture/ - /en/docs3-v2/java-sdk/concepts-and-architecture/code-architecture/ - /en/overview/mannual/java-sdk/concepts-and-architecture/code-architecture/ -description: 本文将介绍 Dubbo 代码架构。 -linkTitle: 代码架构 -title: 代码架构 +description: This article will introduce the code architecture of Dubbo. +linkTitle: Code Architecture +title: Code Architecture type: docs weight: 2 --- @@ -16,98 +16,99 @@ weight: 2 -## 整体设计 +## Overall Design ![/dev-guide/images/dubbo-framework.jpg](/imgs/dev/dubbo-framework.jpg) -图例说明: +Legend explanation: -* 图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口。 -* 图中从下至上分为十层,各层均为单向依赖,右边的黑色箭头代表层之间的依赖关系,每一层都可以剥离上层被复用,其中,Service 和 Config 层为 API,其它各层均为 SPI。 -* 图中绿色小块的为扩展接口,蓝色小块为实现类,图中只显示用于关联各层的实现类。 -* 图中蓝色虚线为初始化过程,即启动时组装链,红色实线为方法调用过程,即运行时调用链,紫色三角箭头为继承,可以把子类看作父类的同一个节点,线上的文字为调用的方法。 +* The light blue background on the left side of the diagram represents the interfaces used by service consumers, the light green background on the right side represents the interfaces used by service providers, and the interfaces on the central axis are used by both parties. +* The diagram is divided into ten layers from bottom to top, with each layer being a one-way dependency. The black arrows on the right represent the dependency relationships between layers. Each layer can detach from the upper layer for reuse, where the Service and Config layers are APIs and the others are SPIs. +* The green small blocks represent extension interfaces, and the blue small blocks represent implementation classes. Only the implementation classes related to the inter-layer connections are shown in the diagram. +* The blue dashed lines represent the initialization process, i.e., the assembly chain during startup, the red solid lines represent the method invocation process, i.e., the runtime invocation chain, and the purple triangular arrows represent inheritance, where subclasses can be seen as the same node as their parent class. The text on the lines indicates the invoked methods. -## 各层说明 +## Layer Descriptions -* **Config 配置层**:对外配置接口,以 `ServiceConfig`, `ReferenceConfig` 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类 -* **Proxy 服务代理层**:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以 `ServiceProxy` 为中心,扩展接口为 `ProxyFactory` -* **Registry 注册中心层**:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 `RegistryFactory`, `Registry`, `RegistryService` -* **Cluster 路由层**:封装多个提供者的路由及负载均衡,并桥接注册中心,以 `Invoker` 为中心,扩展接口为 `Cluster`, `Directory`, `Router`, `LoadBalance` -* **Monitor 监控层**:RPC 调用次数和调用时间监控,以 `Statistics` 为中心,扩展接口为 `MonitorFactory`, `Monitor`, `MonitorService` -* **Protocol 远程调用层**:封装 RPC 调用,以 `Invocation`, `Result` 为中心,扩展接口为 `Protocol`, `Invoker`, `Exporter` -* **Exchange 信息交换层**:封装请求响应模式,同步转异步,以 `Request`, `Response` 为中心,扩展接口为 `Exchanger`, `ExchangeChannel`, `ExchangeClient`, `ExchangeServer` -* **Transport 网络传输层**:抽象 mina 和 netty 为统一接口,以 `Message` 为中心,扩展接口为 `Channel`, `Transporter`, `Client`, `Server`, `Codec` -* **Serialize 数据序列化层**:可复用的一些工具,扩展接口为 `Serialization`, `ObjectInput`, `ObjectOutput`, `ThreadPool` +* **Config Layer**: External configuration interface centered around `ServiceConfig` and `ReferenceConfig`, allowing direct initialization of configuration classes or generating configuration classes through Spring. +* **Proxy Layer**: Transparent proxy for service interfaces, generating client Stubs and server Skeletons centered around `ServiceProxy`, with the extension interface being `ProxyFactory`. +* **Registry Layer**: Encapsulates the registration and discovery of service addresses, centered around service URLs, with extension interfaces `RegistryFactory`, `Registry`, `RegistryService`. +* **Cluster Layer**: Encapsulates routing and load balancing for multiple providers and bridges to the registry, centered around `Invoker`, with extension interfaces `Cluster`, `Directory`, `Router`, `LoadBalance`. +* **Monitor Layer**: Monitors RPC call counts and call durations, centered around `Statistics`, with extension interfaces `MonitorFactory`, `Monitor`, `MonitorService`. +* **Protocol Layer**: Encapsulates RPC calls, centered around `Invocation` and `Result`, with extension interfaces `Protocol`, `Invoker`, `Exporter`. +* **Exchange Layer**: Encapsulates request-response patterns, synchronizing to asynchronous, centered around `Request` and `Response`, with extension interfaces `Exchanger`, `ExchangeChannel`, `ExchangeClient`, `ExchangeServer`. +* **Transport Layer**: Abstracts Mina and Netty into a unified interface, centered around `Message`, with extension interfaces `Channel`, `Transporter`, `Client`, `Server`, `Codec`. +* **Serialize Layer**: Reusable tools, with extension interfaces `Serialization`, `ObjectInput`, `ObjectOutput`, `ThreadPool`. -## 关系说明 +## Relationship Explanation -* 在 RPC 中,Protocol 是核心层,也就是只要有 Protocol + Invoker + Exporter 就可以完成非透明的 RPC 调用,然后在 Invoker 的主过程上 Filter 拦截点。 -* 图中的 Consumer 和 Provider 是抽象概念,只是想让看图者更直观的了解哪些类分属于客户端与服务器端,不用 Client 和 Server 的原因是 Dubbo 在很多场景下都使用 Provider, Consumer, Registry, Monitor 划分逻辑拓扑节点,保持统一概念。 -* 而 Cluster 是外围概念,所以 Cluster 的目的是将多个 Invoker 伪装成一个 Invoker,这样其它人只要关注 Protocol 层 Invoker 即可,加上 Cluster 或者去掉 Cluster 对其它层都不会造成影响,因为只有一个提供者时,是不需要 Cluster 的。 -* Proxy 层封装了所有接口的透明化代理,而在其它层都以 Invoker 为中心,只有到了暴露给用户使用时,才用 Proxy 将 Invoker 转成接口,或将接口实现转成 Invoker,也就是去掉 Proxy 层 RPC 是可以 Run 的,只是不那么透明,不那么看起来像调本地服务一样调远程服务。 -* 而 Remoting 实现是 Dubbo 协议的实现,如果你选择 RMI 协议,整个 Remoting 都不会用上,Remoting 内部再划为 Transport 传输层和 Exchange 信息交换层,Transport 层只负责单向消息传输,是对 Mina, Netty, Grizzly 的抽象,它也可以扩展 UDP 传输,而 Exchange 层是在传输层之上封装了 Request-Response 语义。 -* Registry 和 Monitor 实际上不算一层,而是一个独立的节点,只是为了全局概览,用层的方式画在一起。 +* In RPC, the Protocol is the core layer, meaning that as long as there is Protocol + Invoker + Exporter, non-transparent RPC calls can be completed, then applying Filters on the Invoker's main process. +* The Consumer and Provider in the diagram are abstract concepts meant to help viewers understand which classes belong to the client and server side. The reason for not using Client and Server is that Dubbo employs Provider, Consumer, Registry, and Monitor to define logical topological nodes in many scenarios, maintaining a unified concept. +* Cluster is an external concept, meaning its purpose is to disguise multiple Invokers as a single Invoker, allowing others to focus only on the Protocol layer Invoker. Adding or removing Cluster will not affect other layers, as there is no need for Cluster with only one provider. +* The Proxy Layer encapsulates transparent proxying for all interfaces, and in other layers, it revolves around the Invoker. Only at the point of exposing for user use is Proxy used to convert Invoker into an interface or convert interface implementations into Invoker. This means removing the Proxy layer allows RPC to run, though it won't be as transparent or seem as local as remote service calls. +* The Remoting implementation is the Dubbo protocol implementation. If you choose the RMI protocol, the entire Remoting will not be used. Remoting is internally divided into the Transport layer and the Exchange layer, where the Transport layer is responsible for one-way message transmission, abstracting Mina, Netty, and Grizzly, and it can also extend UDP transmission. The Exchange layer encapsulates Request-Response semantics on top of the Transport layer. +* The Registry and Monitor should not be counted as a layer but rather as independent nodes, drawn together for a global view in a layered manner. -## 模块分包 +## Module Packaging ![/dev-guide/images/dubbo-modules.jpg](/imgs/dev/dubbo-modules.jpg) -模块说明: +Module explanations: -* **dubbo-common 公共逻辑模块**:包括 Util 类和通用模型。 -* **dubbo-remoting 远程通讯模块**:相当于 Dubbo 协议的实现,如果 RPC 用 RMI协议则不需要使用此包。 -* **dubbo-rpc 远程调用模块**:抽象各种协议,以及动态代理,只包含一对一的调用,不关心集群的管理。 -* **dubbo-cluster 集群模块**:将多个服务提供方伪装为一个提供方,包括:负载均衡, 容错,路由等,集群的地址列表可以是静态配置的,也可以是由注册中心下发。 -* **dubbo-registry 注册中心模块**:基于注册中心下发地址的集群方式,以及对各种注册中心的抽象。 -* **dubbo-monitor 监控模块**:统计服务调用次数,调用时间的,调用链跟踪的服务。 -* **dubbo-config 配置模块**:是 Dubbo 对外的 API,用户通过 Config 使用Dubbo,隐藏 Dubbo 所有细节。 -* **dubbo-container 容器模块**:是一个 Standlone 的容器,以简单的 Main 加载 Spring 启动,因为服务通常不需要 Tomcat/JBoss 等 Web 容器的特性,没必要用 Web 容器去加载服务。 +* **dubbo-common Common Logic Module**: Includes utility classes and common models. +* **dubbo-remoting Remote Communication Module**: Equivalent to the implementation of the Dubbo protocol. If RPC uses the RMI protocol, this package is not needed. +* **dubbo-rpc Remote Invocation Module**: Abstracts various protocols and dynamic proxies, only containing one-to-one invocation without concerning cluster management. +* **dubbo-cluster Cluster Module**: Disguises multiple service providers as a single provider, including load balancing, fault tolerance, routing, etc. The cluster address list can be statically configured or issued by the registry. +* **dubbo-registry Registry Module**: Based on the cluster method of issuing addresses from the registry, and the abstraction of various registries. +* **dubbo-monitor Monitoring Module**: A service for tracking service call counts, call times, and call chains. +* **dubbo-config Configuration Module**: The API exposed to users by Dubbo, allowing users to use Dubbo through Config while hiding all details of Dubbo. +* **dubbo-container Container Module**: A standalone container using a simple Main to load Spring startup, as services typically do not require features of Web containers like Tomcat/JBoss, making it unnecessary to use a Web container to load services. -整体上按照分层结构进行分包,与分层的不同点在于: +Overall, packaging is done according to a layered structure, with the distinction being: -* Container 为服务容器,用于部署运行服务,没有在层中画出。 -* Protocol 层和 Proxy 层都放在 rpc 模块中,这两层是 rpc 的核心,在不需要集群也就是只有一个提供者时,可以只使用这两层完成 rpc 调用。 -* Transport 层和 Exchange 层都放在 remoting 模块中,为 rpc 调用的通讯基础。 -* Serialize 层放在 common 模块中,以便更大程度复用。 +* The Container is a service container used for deploying and running services, not drawn in the layers. +* Both the Protocol layer and Proxy layer are included in the rpc module; these two layers are the core of rpc, and when a cluster is not needed, meaning there is only one provider, these two layers alone can complete rpc calls. +* Both the Transport layer and Exchange layer are included in the remoting module, serving as the communication basis for rpc calls. +* The Serialize layer is placed in the common module for greater reusability. -## 依赖关系 +## Dependency Relationships ![/dev-guide/images/dubbo-relation.jpg](/imgs/dev/dubbo-relation.jpg) -图例说明: +Legend explanation: -* 图中小方块 Protocol, Cluster, Proxy, Service, Container, Registry, Monitor 代表层或模块,蓝色的表示与业务有交互,绿色的表示只对 Dubbo 内部交互。 -* 图中背景方块 Consumer, Provider, Registry, Monitor 代表部署逻辑拓扑节点。 -* 图中蓝色虚线为初始化时调用,红色虚线为运行时异步调用,红色实线为运行时同步调用。 -* 图中只包含 RPC 的层,不包含 Remoting 的层,Remoting 整体都隐含在 Protocol 中。 +* The small squares in the diagram representing Protocol, Cluster, Proxy, Service, Container, Registry, and Monitor indicate layers or modules, with blue denoting business interactions and green denoting interactions purely within Dubbo. +* The background squares representing Consumer, Provider, Registry, and Monitor denote deployment logical topological nodes. +* The blue dashed lines represent initialization calls, the red dashed lines denote asynchronous calls during runtime, and the red solid lines signify synchronous calls during runtime. +* The diagram includes only the layers of RPC and does not encompass the layers of Remoting, which is implicitly contained within Protocol. -## 调用链 +## Invocation Chain -展开总设计图的红色调用链,如下: +Expanding the red invocation chain from the overall design diagram: ![/dev-guide/images/dubbo-extension.jpg](/imgs/dev/dubbo-extension.jpg) -## 暴露服务时序 +## Service Exposure Sequence -展开总设计图右边服务提供方暴露服务的蓝色初始化链,时序图如下: +Expanding the blue initialization chain of service exposure for the service provider on the right side of the total design diagram, the sequence diagram is as follows: ![/dev-guide/images/dubbo-export.jpg](/imgs/dev/dubbo-export.jpg) -## 引用服务时序 +## Service Referencing Sequence -展开总设计图左边服务消费方引用服务的绿色初始化链,时序图如下: +Expanding the green initialization chain when the service consumer references services on the left side of the total design diagram, the sequence diagram is as follows: ![/dev-guide/images/dubbo-refer.jpg](/imgs/dev/dubbo-refer.jpg) -## 领域模型 +## Domain Model -在 Dubbo 的核心领域模型中: +In the core domain model of Dubbo: -* Protocol 是服务域,它是 Invoker 暴露和引用的主功能入口,它负责 Invoker 的生命周期管理。 -* Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠拢,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。 -* Invocation 是会话域,它持有调用过程中的变量,比如方法名,参数等。 +* Protocol is the service domain, which is the main functional entry for Invoker exposure and referencing, responsible for managing the lifecycle of the Invoker. +* Invoker is the entity domain, which is the core model of Dubbo, with other models converging towards or converting into it. It represents an executable body that can initiate invoke calls; it could be a local implementation, a remote implementation, or a cluster implementation. +* Invocation is the session domain, holding variables during the calling process, such as method names and parameters. -## 基本设计原则 +## Basic Design Principles + +* Adopts the Microkernel + Plugin model; the Microkernel is only responsible for assembling Plugins. Dubbo’s functionality itself is also realized through extension points, meaning all functional points of Dubbo can be user-defined and replaced. +* Uses URL as a unified format for configuration information, where all extension points pass configuration information through the URL. -* 采用 Microkernel + Plugin 模式,Microkernel 只负责组装 Plugin,Dubbo 自身的功能也是通过扩展点实现的,也就是 Dubbo 的所有功能点都可被用户自定义扩展所替换。 -* 采用 URL 作为配置信息的统一格式,所有扩展点都通过传递 URL 携带配置信息。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/_index.md index 8f62be7b075b..46a00a34ff43 100755 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/_index.md @@ -1,7 +1,8 @@ --- -description: "Dubbo 多实例、多应用设计原理、实现与使用方法。" -linkTitle: 多实例部署 -title: 多实例部署 +description: "Principles, implementation, and usage methods of multi-instance and multi-application design in Dubbo." +linkTitle: Multi-instance Deployment +title: Multi-instance Deployment type: docs weight: 100 --- + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/develop.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/develop.md index 347e5cc3013e7e5ce4a300228ea2357835d6b11a..49e53e927009cd9d05adee5568899196b56ebb8e 100644 GIT binary patch literal 8225 zcmb_hZF8K+5&q7vn4GIrQkB>jU}2G?R1{f0t0Gy7WamDlQgs8&YB{mYW(Fj0uKeHg z^bD}$*-RbgJ@YmCN#k{qSj?YsOWTr-fikC7*IUXPoJL zvBVu+FBV*_n4Ga{E?7F}}Dwx z7C`Q0^P*;X$?okY=h(!l?8@tAhu*?#{wVrO**ozh3b|Z}vSQa#33e{&&|i+(mEfvm zALKKg@LVb-(yCao3v*U;&`VlLZyJ5IQ>~WJFO#Wuo<;sJuTGfnxG=Z#ofej4OSd&} zYw+J;I_3`?=gpfp>_ZNtsdS#Fyudj#Q8>Op--8?&HrFdrdsay(k zJ$$eDLOe_LXfN@u{O%x*j-x`d7Z-4`Q$^ zAO3wfud1a!84lB|9FzrDkAqY$hO7ENwHS_u-pCsdv2N)3@i_9m;W+e1Vd#6|WE_X? zD2;_51)=NDLeC9GVdBPq7P?UuM`Iy;5r>?%d6O17{C1h0))PPUf@B)FW8tT6a4>^a zPM2I);$Uu^cx>r*nxY5pFPrg3|~G z3zH;`CgIHY!-HqDYdDRMoC}`LdtU2I%%1b2V5t&_R}-DkC}Vl0nS3r8f?O&DV8s?< zkqD(v9LKdV*8s%3oPaMC?)^>h@;#@E6|U}uddgFACzev@=AN@g%rWB@1q-PwmT;Y? z%wXV{rMzTwS!6~N7}`ef?d6cf4?o{s9Wzm-4Q?r)n1~})2+42Omu5GF76RI2ol@FB zBskj5H6fVs%BCVD7zvwXgmht!pCI&0xDqLfR{jx441y^zI&$O8pNKFM?l_u7Zs7ZY zJDrRGOg;nP(vhEu(RU-!3u1%BF!iR>%+EHF7{o2`ED~dX^bJ6aqagNQ1L7nchfx;# zE>9-D8>Cs{Cdqi@MxLJ`<|0I31H>Sl92uXalri;EmYJa3o`~vMh;qw&1_M-7c9Vrc z;rqL@>x-Xm?*0zEo!#DEU7nwPy1e;_tLvM0pRX=Va_d2&11q6|a#)9*_6b9&tF_Hm zro5TVZ?ckGP%SWETJRDH$vmQJmWd_m8_ux;ettnX0E_@AZDOJdmsB@XN`1(2dYRjj zNT5Y7RI+}U?^gv;GLuCipAmKce;N$@=`%m^ z#PgEzcZ1I#`38Km=_n9c7Hxtr9EHsd3qAnmb?`;wNj!NCdqIqtnvOGfG>#{3z&+nh zvYBxGAe@flEQ#Z&!Ja>w9+})_@*r{or5aPfHj1tB?t{du%d-c#biRL(Onc6r0D@81X1#W*dDxXHbSYS z)cFmXC$a`ek=%CcIHA`Z3_Ene^tXVsxi8F1)4 z$1+l|_q4GIIRml`XnF#B3mY+X_{*|gg4Zu3@D%pLRzzS%=)+)0OTudCK^LaMp7K z4yxyd0#KGBlk*1`syJAtje@k*r$~2Pxh&nw1kMhQzJ4@4vh~v!l;xKfBFwNX)z=a!olPE>98HZ{7 z-Klasowjv4nT?XREH{kNkJ{AOFh(!_hC+>G=TBeDm5Cq39}M3kT*i~;I2(J5kG?7FLW&e@v#_xK(KMUIvZ#6JbBXHwCnP$k+4BVk=J3FAwm zl!jL|$&#AM^1(!B)9hJ90o6*PYIbcwmd}tK2tS~UXfn_qm=Njf!V4|iO#oq{Zf_0r zy5h_fy=rv7(9m%$5OYuh8R~>}DevA;bz-}!YN+oq zyAumpiEB~uj90w5O>N;ZYj4^&+E&$eW4qM(6STB#1q{0Ln9ZSlLi9b_0eZ1O0?k`ByKx|ik`<^Q%_-O<%R zppf#B-l>;1VQpA$SA75xv=BXvWe-ZA71b4tXW|C~2a-_xl&%f{|?({S<{uw-o3ND)E4>m!l!=t@xE>H-SEQv3_uwus%FRZ)xBGMYo zwS*|n+F&35739KLN8g9cl!y)@oRNyKz zj=56z8b#h>3CkzQZXH+bV!26s`)t2!%0{-a{oxT=zjurcBfoW=MxWja^Bzl9P0Tm| zE<&gCUR(dU%8MdJ&s%^`Mh*jrAs6 zpSraKy-k0u+yRD*D5OfRT7~GT_2SpP4%~E@wjSHOx#b+_vH9G1t0;Q5Xw}0v57MP| zkv`mXGi>(Nlp9;xz3tMD2w!u{^%sZTVr~;+uQ%MN+iMxt;rlRP%AP6Moo`=Wd|qIT zAXI~o4RMDhiYSPb;!B)vyOeGv?sawoQC(}<&eb{&u^lfPJ2oKxE}g8s{m$N|#5a7x ze#+3hM!o{Y1HEg>+=3{a9W-zAT&kCKnS;|cGKpD$+x1z+ElsJ{1{gLgZGvbk8!F|1 z-EQ^|Xb^}QuLIwb#y2eJj&qL=N!T8$10_4NT@f}wZr^jfTMPwo5E`qRhTM`lnru=b zX#n+vITZ&hA*R|tjoq!udKFCBLi$KG|j?&D)22R zmzsUVu!v0eY2%xxgO1@FV*1EI`sryk*d&e=pb}nCEfN}L>mZ2E>=dc@GAsBBOWO$# zeg85Hy0eg7&>LOZNjGWV7eizjoQ1Us6rXXL>Psv6X8mRD>VMqa?{wXJq6YEOXuj>- zPSQpi)efM0ZyTaE4z_}YzC>Zx>x663%?UOoQENrXy`y7jwikTWjr)2nIliAG9BDBP zzbKw|&(@ihw5#>TKwu=lE74K*M6xY4UQYc=XsA|DJ3= z=5Ji@{v|(He!EthEI9kKrPaaGtMSs}E*XA9X6DJ{T=`_Nyf#_f%@=onC>8Q#>Tzk| zzLP&F9en#se&}N^X{K)9H0`8uo(IOx@)B9vKt{#gSI)On#iJ#Z&)F_jRiSd>dn6=> zc{20RS$s>LPdU$qem$HduU;1SR$WD3eOFp5P@$g2Ja8;cZ*lfO8pP_BmgVjkX74Tg zJTGzr*o5=Uz^uTF%~mKK&e6lZ_enYK+_`f+*&cF!T5~qm$npfo6%VG#%n#1e_=R*j zX=*C??2ja*>*a6J`m9KRA(xwW^Q+CR$pKs_ph802nNEza3}zDfv~8A zqGC7@lEt7bi(xquQe+{hDTWx8WI;^GVL=MYaX}GvS%~UNG-Mc}p~xx~b52W|M#}Ei zyK)gx4omTvB!mo66Qs68#_H=zt6AG8EV3=P+Qjgw*ge)uoP{}+Nzz)cIj5ifX@R- zqbo%}+G_ST)h#GTLn1ww5se#y6axigQ8<_!k89D0oDfC1?GBSF$CM7v*_;6&*Svz* ztlT>)9xjlvMRKrD_TH5a9+JWW*>)`Q@N9HcKAP|9ZHHj4)@AeJCN1C(dri=Hby#HKSj2!JEsOcoDUEBS9IHW)I24g-WfovW$F z#Bs38J8w41>)$y$2jszOmckMa=;YTaR#!*Mg)K7t&Kb|cBIp5{l^$)7m6iVw_9Q6= zs0<2PGN`u@{yUhCNve$6~su*JDpos!&7h zDPr(Fpr=G7MLY|75jiABby*bDctjK=O^*xlcqk}D!=esR7KNB|p(n|a4$eaha|vJE zo%RPgq-?VP2-0rp&4CNA&w4Igz5M01p1%T+E?mEUrTgNAo88wwho`I8E`4$3GRJ+? z;A{_vn0-8n)phVGKpL|r%{JRZrTukqcQ$R73Tvg=5i;|jc>JvV^BjPM48LILYU08J zId4?4&tup)KM$5RCTPmuouK;v_Jk#gv6vhb1w9njrC<<3I%22*nz$mwBbp*;K|LA{ zO7Uw}QoAjp`in9s_S_sHT~todM= z^2yW6=p-oUkvsF7@JnW2f}Kl?Z=LBEeq*2+S}R;l*WPZxXRZLoD-UG`MN#4TNq6Dhd6{z(0TTvJiS9^=0GF_C(uJ#K^iD1 zSVI_!s(lMmK%pQbZ@{VEd1%m=3n!H)g?hEqCRGNj8ZBs$V$jT(3drIy%?1>Y+e3&Z zlz@hXK8>zJ*4dq)*@z*E)jOmGt#Jn*;l$t>*C&i+(;HNq-=2FS&_aYmVIiSu5kpaQ zA*{%*0*gLv`S=rZBMh znjE*Jj0{)qZPbXtZ_cAl=v8R8dcFWH7X|C=B<*jWJ%PypGY^gxZvLsJ8pM)M1Yg`+ zL2fLTDQ{Mt%Io*Z*i#7cru0Wce0GvT0n~HeJT7lS2n?0;_W+AtO1Z%rOWK-cY`0H? zQK-l0vuxw4VXL}otL}PtUpfhU)m40_I|Z$2N;BO4tEtl?TO(w81p<&_v~ky&7$IXL z(EW*YuG)r@KMBud>_-4P^Z|4g;sIt2co~~QdYYQfg~>|18GvvHH}YNG#?yUU#8spR1ZZh~s6U$~=Y49sfv>S;+e zo8>Pd6#i`W8<`YM-aWabZ#t)Wo;Tr-K?5qwpGNnI?_P&Vgu}4Yq%&r}Y8(8S#|IbE z)Bo`rD3XD!i*KVP`z=%Fvvnv%RGrDSYSa%iETz876aesdc6Pd!c9x-TAA5P5sX!Cg zc)tF|i%UQ`Xg^ao{yd+k)&Rz<72LCcZWkC=%&h(U9-|ljWd@)&*_LJ{>7tP`GJoKc z?x$=EtWeHgPjJOjp{TW=#;KD5qk|ov8iKydUeP@c)j|)-eah&}1mAwqN+#jX2QGhT zgk?L;?B|w!xi4)Gw0o*~XQ7Oll}^*bI}TW>_PT2c`ZoQkZgj$hlL1z-2C53tUG(7H zI_IIU>RpKLs$XmH3@A~*&s>#E`V3L^65KvhMXLVEw%7X@40e}Q3M|0kh5`)1jF(n! z>h>307{oBd{bjXwuZ3=H<>?N$YEZeXwt9{{{hf=+8~`ihf}xIUdkX5^C;Xj^nugQ3 zRnKb+P{msQamMD#`C(6D_2R`%%TP6h!!(tz~#qc9=ZUp7jKLO)<>V?CGQaB zoei89uz`xhDAEEaevm-RR~enbe$q$YLQ&s%;lBiNb%;jR2cG2x#7%wnK*8740CKM>DFcPG4 z$s{z*<&#Hbak;+tS!hw&>q51?#;>CVZ9|qmgBsL_@<CQa=xS+w ziY)CrPd7Q*XnQemden7rG$HtO>a1_oc#I~vm?njL{xrZbr2B>nn3bAZEWA(f?h)wi z$I?bMQPB~UxxgnK+fVSx->%(&{mS4JnI35>cOKQLK&F!#L-EpvUuj^87bt$0)+Pap zIV49E!%hvtu&1foErXNc6U~}9w}FzrnFG0d`a#bImnHN&i|VXN_Fj`w`ZWV^fa^XQ z1O9;YfYf3#u6=vu-!wAxtWnSjg;DtLFG3P1pUgY2*Pu^8e1H^$3%w3t-?C7A7mlH4 N^=F4bEu1*^^FKl2ok{=z diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/model.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/model.md index 3b5bc831856e..061dd95fb84c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/model.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/model.md @@ -1,178 +1,172 @@ --- -description: "Dubbo 多实例相关领域模型与概念" -linkTitle: 模型与概念 -title: 多实例相关的模型与概念定义 +description: "Dubbo Multi-Instance Related Domain Models and Concepts" +linkTitle: Models and Concepts +title: Definitions of Models and Concepts Related to Multi-Instances type: docs weight: 3 --- -## Dubbo 架构 +## Dubbo Architecture -JVM —— 虚拟机层 -目的:Dubbo 框架之间完全隔离(端口不能复用) +JVM — Virtual Machine Layer +Purpose: Complete isolation between Dubbo frameworks (ports cannot be reused) -Dubbo Framework —— 框架层 -目的:将需要全局缓存的进行复用(端口、序列化等) +Dubbo Framework — Framework Layer +Purpose: Reuse resources that need global caching (ports, serialization, etc.) -Application —— 应用层 -目的:隔离应用之间的信息,包括注册中心、配置中心、元数据中心 +Application — Application Layer +Purpose: Isolate information between applications, including registration center, configuration center, and metadata center -Services —— 模块层 -目的:提供热加载能力,可以按 ClassLoader、Spring Context 进行隔离上下文 +Services — Module Layer +Purpose: Provide hot loading capability, allowing isolation contexts per ClassLoader or Spring Context -## Dubbo 概念对齐 +## Dubbo Concept Alignment -1. DubboBoorstrap - 1. 需要拆分 export/refer services、ServiceInstance、Metadata/Config 等 Client +1. DubboBootstrap + 1. Needs to separate export/refer services, ServiceInstance, Metadata/Config, etc. Client 2. ConfigManager - 1. 需要拆分应用级配置信息、模块级配置信息 + 1. Needs to separate application-level configuration information from module-level configuration information 3. ApplicationModel - 1. 实际存储应用层信息,持有到 ConfigManager 应用级配置信息的引用 + 1. Actually stores application layer information, holding a reference to ConfigManager’s application-level configuration information 4. ConsumerModel - 1. 实际存储接口信息,由 ModuleModel 持有引用 + 1. Actually stores interface information, held by ModuleModel 5. ProviderModel - 1. 实际存储接口信息,由 ModuleModel 持有引用 + 1. Actually stores interface information, held by ModuleModel 6. ExtensionLoader - 1. 需要根据不同层级 load 出不同的实例对象 + 1. Needs to load different instance objects based on different levels 7. Registry - 1. 应用级别共享,需要确保多实例订阅正常(考虑单元化场景) + 1. Application level sharing, needs to ensure that multi-instance subscriptions work properly (considering unit scenarios) 8. Router / Filter - 1. 模块级别共享 + 1. Module level sharing 9. Protocol / Remoting - 1. 框架级别共享,复用 IO,多应用间贡献 + 1. Framework level sharing, reusing IO, contributing across multiple applications 10. Metadata - 1. 应用级别共享,考虑应用级服务发现 + 1. Application level sharing, considering application-level service discovery 11. QoS - 1. 框架级别共享,与 IO 有关 + 1. Framework level sharing, related to IO 12. Serialization - 1. 框架级别共享,与 IO 有关 + 1. Framework level sharing, related to IO 13. ConfigCenter - 1. 应用级别贡献 -14. ModuleModel(新) - 1. 实际存储模块层信息,持有接口级信息 -15. FrameworkModel(新) - 1. 实际存储框架层信息 + 1. Application level contribution +14. ModuleModel (new) + 1. Actually stores module layer information, holding interface-level information +15. FrameworkModel (new) + 1. Actually stores framework layer information -## 配置存储梳理 +## Configuration Storage Organization -### FrameworkModel -Qos、Protocol、Remoting、Serialization、ExtensionLoader +### FrameworkModel +Qos, Protocol, Remoting, Serialization, ExtensionLoader -### ApplicationModel -ConfigManager(应用级)、DubboBootstrap(类 Fluent API)、Registry、Metadata、ServiceInstance、ConfigCenter、ExtensionLoader +### ApplicationModel +ConfigManager (Application-level), DubboBootstrap (Fluent API style), Registry, Metadata, ServiceInstance, ConfigCenter, ExtensionLoader -### ModuleModel -ConsumerModel、ProviderModel、Router、Filter、ExtensionLoader +### ModuleModel +ConsumerModel, ProviderModel, Router, Filter, ExtensionLoader -![](https://intranetproxy.alipay.com/skylark/lark/0/2021/jpeg/15256464/1628824598406-95556f0d-7817-4010-97a7-0f8e84a175cb.jpeg) -## Dubbo 流程梳理 +![](https://intranetproxy.alipay.com/skylark/lark/0/2021/jpeg/15256464/1628824598406-95556f0d-7817-4010-97a7-0f8e84a175cb.jpeg) +## Dubbo Process Organization -### Model 创建 +### Model Creation -DefaultModel - FrameworkModel、ApplicationModel、ModuleModel +DefaultModel - FrameworkModel, ApplicationModel, ModuleModel -1. 默认 Model 创建时机 -2. 用户自定义的 Model 的创建方式 +1. Default Model creation timing +2. User-defined Model creation methods -### 消费端初始化 +### Consumer Side Initialization -1. 消费端通过 ReferenceConfig 作为入口进行初始化配置相关信息,当前配置里面需要添加 ClassLoader 属性,ReferenceConfig 生成 ConsumerModel 注入到 ModuleModel -2. 组装的 URL 需要包含当前 ConsumerModel、ModuleModel、ApplicationModel、FrameworkModel(需要梳理全链路内 URL 转换逻辑,保证在中间不会被丢弃) -3. 组装链路上 Registry 为 ApplicationModel 域内的(订阅需要考虑订阅之间互相独立、多注册中心场景) ;Filter、Cluster、LoadBalance 为 ModuleModel 域内的 -4. Directory 需要持有包括详细信息的 ConsumerURL,序列化层需要传入配置信息 -5. ModuleModel 内三元组唯一,总是创建出同一个 proxy;ModuleModel 间允许重复三元组,proxy、invoker 均相互独立 +1. The consumer side initializes configuration information through ReferenceConfig as an entry, where the ClassLoader property needs to be added, and ReferenceConfig generates ConsumerModel injected into ModuleModel +2. The assembled URL needs to include the current ConsumerModel, ModuleModel, ApplicationModel, FrameworkModel (need to organize the entire link’s URL conversion logic to ensure it is not discarded in between) +3. The Registry in the assembly chain is within the ApplicationModel domain (subscription needs to consider mutual independence between subscriptions and multi-registration center scenarios); Filter, Cluster, LoadBalance are within the ModuleModel domain +4. Directory needs to hold the ConsumerURL with detailed information, and the serialization layer needs to pass configuration information +5. The triplet within ModuleModel is unique, always creating the same proxy; redundancies are allowed between ModuleModels, with proxies and invokers being mutually independent -### 服务端初始化 +### Server Side Initialization -1. 服务端通过 ServiceConfig 作为入口进行初始化配置相关信息,当前配置里面需要添加 ClassLoader 属性,ServiceConfig 生成 ProviderModel 注入到 ModuleModel -2. 组装的 URL 需要包含当前 ProviderModel、ModuleModel、ApplicationModel、FrameworkModel(需要梳理全链路内 URL 转换逻辑,保证在中间不会被丢弃) -3. 组装链路上 Registry 为 ApplicationModel 域内的(订阅需要考虑服务之间互相独立、多注册中心场景) ;Filter 为 ModuleModel 域内的 -4. Protocol 层持有的三元组保证唯一,可以直接找到 ProviderModel(FrameworkModel 域内) +1. The server side initializes configuration information through ServiceConfig as an entry, where the ClassLoader property needs to be added, and ServiceConfig generates ProviderModel injected into ModuleModel +2. The assembled URL needs to include the current ProviderModel, ModuleModel, ApplicationModel, FrameworkModel (need to organize the entire link’s URL conversion logic to ensure it is not discarded in between) +3. The Registry in the assembly chain is within the ApplicationModel domain (subscription needs to consider mutual independence among services and multi-registration center scenarios); Filter is within the ModuleModel domain +4. The triplet held by the Protocol layer guarantees uniqueness, allowing direct access to the ProviderModel (within the FrameworkModel domain) -### 地址推送流程 +### Address Push Process -1. 注册中心监听需要确保三元组重复的订阅都能独立收到通知、相同三元组到注册中心的订阅链接可以进行复用 -2. 注册中心工作在 ApplicationModel 域,通过持有监听列表连接 ModuleModel 层,地址的处理为 ModuleModel 域内操作,如果服用地址通知需要保证通知内容不会被某个订阅所修改 -3. 每份地址通知根据不同 ModuleModel 独立创建 Invoker,Invoker 直接持有 ConsumerModel -4. Invoker 的底层 Protocol 层连接复用 TCP 连接 +1. The registration center listens to ensure that subscriptions with duplicate triplets can independently receive notifications, while the subscription links for the same triplet to the registration center can be reused +2. The registration center operates in the ApplicationModel domain, connecting to the ModuleModel layer through the held listening list. Address processing is carried out within the ModuleModel domain. If address notice reuse is needed, it needs to ensure that the notification content is not modified by a specific subscription +3. Each address notification independently creates an Invoker for different ModuleModels, with the Invoker directly holding the ConsumerModel +4. The underlying Protocol layer of the Invoker reuses TCP connections -### 消费端调用链路 +### Consumer Side Call Chain -1. 消费端创建 invocation 时需要携带当前 ConsumerModel、ModuleModel、ApplicationModel、FrameworkModel (通过 consumerURL 携带),需要保证调用全链路 consumerURL 不丢失 +1. When the consumer side creates an invocation, it needs to carry the current ConsumerModel, ModuleModel, ApplicationModel, FrameworkModel (through consumerURL), ensuring that the entire call link’s consumerURL is not lost -### 服务端调用链路 +### Server Side Call Chain -1. 服务端收到请求后根据三元组定位 ProviderModel 及 invoker,进行反序列化时需要考虑 ClassLoader 切换 +1. Upon receiving a request, the server locates the ProviderModel and invoker based on the triplet, considering the ClassLoader switch during deserialization -### 其他流程 +### Other Processes -1. 销毁流程 -2. QoS 聚合方式 +1. Destruction Process +2. QoS Aggregation Method -## 代码改动 +## Code Changes -1. ExtensionLoader 依赖注入 +1. ExtensionLoader Dependency Injection ```java -ModuleModel.getExtensionFactory().getAdaptiveExtension(Protocol.class) -ApplicationModel.getExtensionFactory().getAdaptiveExtension(Protocol.class) -FrameworkModel.getExtensionFactory().getAdaptiveExtension(Protocol.class) +ModuleModel.getExtensionFactory().getAdaptiveExtension(Protocol.class) +ApplicationModel.getExtensionFactory().getAdaptiveExtension(Protocol.class) +FrameworkModel.getExtensionFactory().getAdaptiveExtension(Protocol.class) - -@SPI(scope = FRAMEWORK) -public interface Protocol { -} +@SPI(scope = FRAMEWORK) +public interface Protocol { +} ``` - -- SPI 依赖注入 -2. DubboBootstrap -> 功能拆分(ModuleModel 维护生命周期) +- SPI Dependency Injection +2. DubboBootstrap -> Function Split (ModuleModel maintains lifecycle) ```java -// 创建新应用实例,共享FrameworkModel -DubboBootstrap.newInstance(FrameworkModel) // SharedFrameworkModel -> NewApplicationModel - .addModule() // New ModuleModel - .addReference(ReferenceConfig) // 将服务配置挂到模块下 - .addReference(ReferenceConfig) - .addService(ServiceConfig) - .endModule() - .addModule() - .addReference(ReferenceConfig) - .addService(ServiceConfig) - .endModule() - .addRegistry() - .addConfigCenter() - .start() - -// 兼容旧的Bootstrap API,使用默认应用实例 -DubboBootstrap.getInstance() // DefaultFrameworkModel -> DefaultApplicationModel - .addReference(ReferenceConfig) // DefaultApplicationModel -> DefaultModuleModel - .addService(ServiceConfig) // DefaultApplicationModel -> DefaultModuleModel - .setRegistry() // DefaultApplicationModel - .start() - -// 新建应用实例 -DubboBootstrap.newInstance() // DefaultFrameworkModel -> NewApplicationModel - .addReference(ReferenceConfig) // NewApplicationModel -> DefaultModuleModel - .addService(ServiceConfig) // NewApplicationModel -> DefaultModuleModel - .setRegistry() // NewApplicationModel - .start() - +// Create new application instance, share FrameworkModel +DubboBootstrap.newInstance(FrameworkModel) // SharedFrameworkModel -> NewApplicationModel + .addModule() // New ModuleModel + .addReference(ReferenceConfig) // Attach service configuration to the module + .addReference(ReferenceConfig) + .addService(ServiceConfig) + .endModule() + .addModule() + .addReference(ReferenceConfig) + .addService(ServiceConfig) + .endModule() + .addRegistry() + .addConfigCenter() + .start() + +// Compatible with old Bootstrap API, using default application instance +DubboBootstrap.getInstance() // DefaultFrameworkModel -> DefaultApplicationModel + .addReference(ReferenceConfig) // DefaultApplicationModel -> DefaultModuleModel + .addService(ServiceConfig) // DefaultApplicationModel -> DefaultModuleModel + .setRegistry() // DefaultApplicationModel + .start() + +// Create new application instance +DubboBootstrap.newInstance() // DefaultFrameworkModel -> NewApplicationModel + .addReference(ReferenceConfig) // NewApplicationModel -> DefaultModuleModel + .addService(ServiceConfig) // NewApplicationModel -> DefaultModuleModel + .setRegistry() // NewApplicationModel + .start() ``` - -3. RefenceConfig、ServiceConfig - 1. ModuleModel 动态设置 - 2. 需要把 ExtensionLoader 初始化的地方下放到 setModuleModel - 3. consumerUrl 携带 ModuleModel -4. ModuleModel、ApplicationModel、FrameworkModel - 1. ModuleModel -> ConsumerModels、ProviderModels - 2. ApplicationModel -> ConfigManager(应用级的属性信息)、ModuleModels -5. ConsumerModel、ProviderModel -6. 注册中心需要支持多订阅 +3. ReferenceConfig, ServiceConfig + 1. ModuleModel dynamic setting + 2. Needs to delegate the initialization of ExtensionLoader to setModuleModel + 3. consumerUrl carries ModuleModel +4. ModuleModel, ApplicationModel, FrameworkModel + 1. ModuleModel -> ConsumerModels, ProviderModels + 2. ApplicationModel -> ConfigManager (application-level attribute information), ModuleModels +5. ConsumerModel, ProviderModel +6. The registration center needs to support multiple subscriptions 7. Spring -1. ModuleModel、ApplicationModel、FrameworkModel(ExtensionLoader) -2. RefenceConfig、ServiceConfig(ConsumerModel、ProviderModel) -3. ExtensionLoader (Filter 改动) - - +1. ModuleModel, ApplicationModel, FrameworkModel (ExtensionLoader) +2. ReferenceConfig, ServiceConfig (ConsumerModel, ProviderModel) +3. ExtensionLoader (Filter changes) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/multi-instance.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/multi-instance.md index b11036ba60d3..6fef4a170372 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/multi-instance.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/multi-instance.md @@ -1,55 +1,55 @@ --- -description: "Dubbo 多实例、多应用设计原理、实现与使用方法。" -linkTitle: 多实例设计理念 -title: 多实例部署的设计理念 +description: "The design principles, implementation, and usage methods for multi-instance and multi-application in Dubbo." +linkTitle: Multi-instance Design Concept +title: Design Concept for Multi-instance Deployment type: docs weight: 1 --- -## 背景 +## Background -Java 提供的静态变量(static field)能力可以将持有对象引用的行为绑定到类上面来,这给开发者提供了巨大的便利。注入单例模式、工厂模式等设计模式的实现方案都依赖了静态变量的功能。通过使用静态变量,开发者可以在任何时间、任何地点简单地获取到所需要的对象信息。 +Java's static variable capability allows binding behaviors holding object references to classes, providing significant convenience to developers. Implementation solutions for design patterns like Singleton and Factory rely on static variables. By using static variables, developers can easily access needed object information anytime, anywhere. ```java public class Test { public static Object obj; } Test.obj = xxx; ``` -在一直以来的 Dubbo 框架开发中,静态变量受到了广泛地应用,诸如使用一个全局共享的 ConfigManager 来存储全局配置信息、ServiceRepository 来存储服务信息,不论从中心化管理配置或者是参数获取的便利性的角度来说,这种设计都是最佳的。在 Dubbo 2.7 以前的所有版本,Dubbo 所需要的运行时配置信息都通过全局静态变量获取,通过 RPC 服务三元组(interface + version + group)的方式进行唯一定位。 +In the long-standing development of the Dubbo framework, static variables have been widely used, such as using a globally shared ConfigManager to store global configuration information, and ServiceRepository to store service information. This design is optimal from the perspective of centralized management of configuration or parameter acquisition. In all versions before Dubbo 2.7, runtime configuration information needed by Dubbo was accessed through global static variables, uniquely identified via the RPC service triplet (interface + version + group). -但是随着 Dubbo 用户基数的不断扩大以及在阿里集团内由 Dubbo 作为内核的 HSF3 框架都对原来的这种设计模式提出了挑战。 +However, with the growing user base of Dubbo and challenges brought by the HSF3 framework, which uses Dubbo as its core, new requirements have emerged. -对于开源用户,社区收到的诉求主要包括以下几点: +For open-source users, the community feedback mainly includes: -1. 在同一个应用内能够创建多个三元组一样的订阅。这个行为在 Dubbo 2.7 中虽然没有做强限制,但是由于 Dubbo 很多参数是取自全局的,而这个获取的索引使用的就是三元组。如果用户创建了两个三元组一样的订阅,他们的参数会被相互覆盖,地址推送等功能也会收到很大的影响。 -2. Java 提供了自定义 ClassLoader 的机制可以自定义指定类的加载器来源,但是对于 Dubbo 来说并没有去支持多 ClassLoader 的场景,在动态代理生成和序列化场景下都不支持 ClassLoader 切换的行为。 -3. Dubbo 众多的测试用例都共享了同一份配置信息,导致在进行单元测试的时候极为容易造成环境污染的问题。 +1. The ability to create multiple identical triplet subscriptions within the same application. While Dubbo 2.7 does not strictly limit this behavior, many parameters are sourced from global settings, and the indexing used for retrieval relies on triplets. If users create two identical triplet subscriptions, their parameters could overwrite each other, significantly impacting functionalities such as address pushing. +2. Java provides a mechanism for custom ClassLoader, but Dubbo does not support scenarios requiring multiple ClassLoaders, lacking ClassLoader switching behavior in dynamic proxy generation and serialization. +3. Numerous test cases in Dubbo share the same configuration information, leading to environmental pollution during unit testing. -对于阿里集团内大规模落地来说,我们遇到的问题主要有: +For large-scale implementations within Alibaba Group, the main challenges include: -1. 阿里集团内有众多的中间件框架,这些框架提供了各种各样的类加载方式,同时业务方期望在同一应用内的配置等信息是相互隔离的。 -2. 一些业务方的定制逻辑需要支持动态热部署的模式,具体体现在动态对某个虚拟环境进行销毁,这需要 Dubbo 内的生命周期管理更加完善。 -3. 集团内有多个对 Spring 容器进行定制化开发的框架,需要 Dubbo 能够支持多个 Spring Context 独立管理生命周期的场景。 +1. Numerous middleware frameworks within Alibaba offer various class loading methods, while business parties expect configuration and other information within the same application to be isolated. +2. Customized logic for some business parties needs to support dynamic hot deployment, specifically demonstrated in dynamically destroying certain virtual environments, requiring improved lifecycle management within Dubbo. +3. Multiple frameworks within the group customizing the Spring container require Dubbo to support scenarios with multiple Spring Contexts managing lifecycles independently. -基于众多的这些原因,在八月初的时候我们决定对 Dubbo 的生命周期进行重构,经过一个月的紧张开发,目前社区版本已经完整支持了多实例化的功能,Dubbo 的生命周期也变得更加清晰。 +Based on these reasons, we decided to refactor Dubbo's lifecycle in early August. After a month of intensive development, the community version now fully supports multi-instantiation, and Dubbo's lifecycle has become clearer. -## 设计 +## Design -整个 Dubbo 多实例的设计我们按照了三层模型来配置,分别是 Framework 框架层、Application 应用层、Module 模块层。 +The entire design of Dubbo's multi-instance is configured according to a three-layer model: Framework layer, Application layer, and Module layer. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/209479/1633766738924-498b5ac4-d96b-48f4-a55f-8cc946800bee.png#clientId=uc9c7eb9b-dec6-4&from=paste&height=446&id=ub35f4a80&originHeight=892&originWidth=2366&originalType=binary&ratio=1&size=483065&status=done&style=none&taskId=u01b03e88-733f-422b-94ea-cf45220737c&width=1183) -基于三层机制,我们可以将 Dubbo 按照一定规则进行隔离: +Based on this three-layer mechanism, we can isolate Dubbo according to specific rules: -1. Framework 与 Framework 之间完全隔离,相当于是使用了两个完全不同的 Dubbo 实例 -2. Application 与 Application 之间按照应用名进行隔离,但是相互有些地共享 Protocol、Serialization 层,目标是达到在同一个 dubbo 端口(20880)上可以承载多个应用,而每个应用独立上报地址信息。 -3. Module 与 Module 之间可以由用户自定义进行进行隔离,可以是热部署周期的一个状态、也可以是 Spring Context 的一个 Context。通过 Module,用户可以对 Dubbo 的生命周期粒度进行最小的管理。 +1. Complete isolation between Frameworks, essentially using two entirely different Dubbo instances. +2. Isolation between Applications based on application names while sharing Protocol and Serialization layers minimally, aiming to host multiple applications on the same Dubbo port (20880) while each application independently reports address information. +3. Isolation between Modules can be user-defined, representing either a state of a hot-deployment cycle or a Spring Context. Through Modules, users can perform minimal lifecycle management of Dubbo. -为了实现 Dubbo 多实例化,Dubbo 框架内做的最多的变化是修改掉大部分的从静态变量中获取的参数的逻辑,最明显的逻辑是 Dubbo 内部用于参数传递的 URL 对象带上了 ScopeModel 状态,这个 ScopeModel 对应的就是上面提到的三层模型的具体数据承载对象。 +To achieve Dubbo multi-instantiation, many of the logic changes within the Dubbo framework involved altering the processes that obtained parameters from static variables. The most notable change is that the URL object used for parameter passing within Dubbo now carries ScopeModel status, corresponding to the specific data carrier of the mentioned three-layer model. -## 使用方式 +## Usage -多实例重构版本之后的 Dubbo 对于大多数用户的使用来说是无感知的,改造后的 DubboBootstrap 已经变成一个独立的启动器,用户可以通过 DubboBootstrap 定制多实例的使用。 +The multi-instance refactoring of Dubbo is largely seamless for most users. The modified DubboBootstrap has been transformed into an independent launcher, allowing users to customize the use of multiple instances. -下面是使用多实例的一个简单的例子。 +Here’s a simple example of using multiple instances. ```java ServiceConfig service = new ServiceConfig<>(); @@ -62,42 +62,42 @@ Test.obj = xxx; ReferenceConfig reference2 = new ReferenceConfig<>(); reference2.setInterface(DemoService.class); - // 创建一个启动器(自动创建新 ApplicationModel) + // Create a launcher (automatically create a new ApplicationModel) DubboBootstrap bootstrap1 = DubboBootstrap.newInstance(); - // 指定应用名 + // Specify application name bootstrap1.application(new ApplicationConfig("dubbo-demo-app-1")) .registry(new RegistryConfig("nacos://localhost:8848")) - // 创建一个模块 + // Create a module .newModule() - // 在模块内发布服务 + // Publish service within the module .service(service) .endModule() - // 创建一个模块 + // Create a module .newModule() - // 在模块内订阅服务 + // Subscribe to service within the module .reference(reference1) .endModule() .start(); - // 创建一个启动器(自动创建新 ApplicationModel) + // Create a launcher (automatically create a new ApplicationModel) DubboBootstrap bootstrap2 = DubboBootstrap.newInstance(); - // 指定应用名 + // Specify application name bootstrap2.application(new ApplicationConfig("dubbo-demo-app-2")) .registry(new RegistryConfig("nacos://localhost:8848")) - // 创建一个模块 + // Create a module .newModule() - // 在模块内订阅服务 + // Subscribe to service within the module .reference(reference2) .endModule() .start(); - // stub1 与 stub2 是两个独立的订阅,互相隔离 + // stub1 and stub2 are two independent subscriptions, isolated from each other. - // 订阅的 stub + // Subscribed stub DemoService stub1 = reference1.get(); System.out.println(stub1.sayHello("Hello World!")); - // 订阅的 stub + // Subscribed stub DemoService stub2 = reference2.get(); System.out.println(stub2.sayHello("Hello World!")); @@ -105,9 +105,7 @@ Test.obj = xxx; bootstrap2.stop(); ``` -这个例子对外发布了一个 DemoService 的服务,由 dubbo-demo-app-1 这个应用提供。同时我们创建了两个订阅,分别是在 dubbo-demo-app-1 应用和 dubbo-demo-app-2 应用中,然后我们去对两个订阅进行调用,得到预期的结果。 - -这里需要注意的是虽然两个订阅的服务信息是完全一致的,在多实例化改造后,这两个订阅对于消费端来说是完全隔离的,也就是在最新版本的 Dubbo 中是支持三元组一样的情况下通过变更参数来创建多个订阅的行为的了。 - +This example exposes a DemoService, provided by the application dubbo-demo-app-1. At the same time, we create two subscriptions, in the applications dubbo-demo-app-1 and dubbo-demo-app-2, and we call both subscriptions to achieve the expected results. +It is worth noting that although the service information of the two subscriptions is completely identical, after the multi-instantiation modification, these subscriptions are entirely isolated from the consumer's perspective. The latest version of Dubbo now supports the behavior of creating multiple subscriptions by changing parameters, even when the triplets are identical. diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/workflow.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/workflow.md index 73725af963b1..a6c3e9d94b4c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/workflow.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-instance/workflow.md @@ -1,25 +1,21 @@ --- -description: "Dubbo 多实例启动流程与模块依赖关系。" -linkTitle: 启动流程与模块依赖关系 -title: 多实例启动流程与模块依赖关系 +description: "The process of starting multiple instances of Dubbo and the dependency relationships between modules." +linkTitle: Startup Process and Module Dependency +title: Startup Process and Module Dependency type: docs weight: 3 --- -1、应用启动流程 -初始化应用配置,启动内部模块,启动其它模块。 -应用启动方式包括:DubboBootstrap.start(), ApplicationModel.getDeployer().start() -![Dubbo start process.svg](https://cdn.nlark.com/yuque/0/2021/svg/2391732/1634895625292-99fdac6f-3371-4147-9ad5-9428296cb083.svg#clientId=u82d0d5c2-bff3-4&from=drop&id=u8db161d3&originHeight=2594&originWidth=1050&originalType=binary&ratio=1&size=64242&status=done&style=none&taskId=u8976fa81-5bc5-469a-ab4a-b4cda12cd6d) -2、模块启动流程 -上图中从ModuleDeployer.start() 开始,自动初始化应用配置,启动内部模块,然后启动当前模块。 -模块启动方式包括: -1) Spring context 加载dubbo xml配置或者注解 -2) 手工启动模块:ModuleModel.getDeployer().start() - -3、服务接口API方式启动 -ServiceConfig.export() 或者 ReferenceConfig.get() 先自动启动module,然后执行export/refer服务接口 - - - +1. Application Startup Process +Initialize application configuration, start internal modules, and start other modules. +The application startup methods include: DubboBootstrap.start(), ApplicationModel.getDeployer().start() +![Dubbo start process.svg](https://cdn.nlark.com/yuque/0/2021/svg/2391732/1634895625292-99fdac6f-3371-4147-9ad5-9428296cb083.svg#clientId=u82d0d5c2-bff3-4&from=drop&id=u8db161d3&originHeight=2594&originWidth=1050&originalType=binary&ratio=1&size=64242&status=done&style=none&taskId=u8976fa81-5bc5-469a-ab4a-b4cda12cd6d) +2. Module Startup Process +Starting from ModuleDeployer.start() in the diagram above, automatically initialize application configuration, start internal modules, and then start the current module. +Module startup methods include: +1) Spring context loads dubbo xml configuration or annotations +2) Manually start the module: ModuleModel.getDeployer().start() +3. Service Interface API Startup +ServiceConfig.export() or ReferenceConfig.get() first automatically starts the module, and then executes export/refer service interfaces diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol.md index 0ec10862d2e6..cec5d2cc8278 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/multi-protocol.md @@ -1,45 +1,41 @@ --- -description: "Dubbo 单端口多协议实现原理&源码解析。" -linkTitle: 单端口多协议 -title: 单端口多协议实现原理解析 +description: "Apache Dubbo single-port multi-protocol implementation principle & source code analysis." +linkTitle: Single-Port Multi-Protocol +title: Analysis of Single-Port Multi-Protocol Implementation Principles type: docs weight: 1 --- -通过对protocol进行配置,dubbo3可以支持端口的协议复用。 -比如使用Triple协议启动端口复用后,可以在相同的端口上为服务增加 -Dubbo协议支持,以及Qos协议支持。这些协议的识别都是由一个统一的端口复用 -服务器进行处理的,可以用于服务的协议迁移,并且可以节约端口以及相关的资源,减少运维的复杂性。 +By configuring protocols, Dubbo 3 can support port protocol multiplexing. For instance, after enabling port reuse with the Triple protocol, you can add support for the Dubbo protocol and the Qos protocol on the same port. These protocols are identified by a unified port reuse server, which can facilitate service protocol migration, save ports and related resources, and reduce operational complexity. ![pu-server-image1](/imgs/blog/pu-server/pu-server-flow.png) -- 在服务的创建阶段,通过从Config层获取到服务导出的协议配置从而创建不同的Protocol对象进行导出。在导出的过程 -中,如果不是第一次创建端口复用的Server,那么Exchanger会将Protcol层传递的数据保存到Server,用于后续处理该协议类型的消息。 +- During the service creation phase, different Protocol objects are created for export by retrieving service export protocol configurations from the Config layer. If it's not the first time creating a port-reusing Server, the Exchanger saves data passed from the Protocol layer to the Server for subsequent processing of that protocol type's messages. -- 当客户端的消息传递过来后,首先会通过Server传递给ProtocolDetector,如果完成了识别,那么就会标记该客户端为对应的协议。并通过WireProtocol配置对应的处理逻辑,最后交给ChannelOperator完成底层的IO框架和对应的Dubbo框架的处理逻辑的绑定。 +- When messages from clients arrive, they first go through the Server to the ProtocolDetector. If identification is successful, the corresponding protocol is marked for that client. The handling logic is configured via WireProtocol, and ultimately, it is handed over to ChannelOperator to bind the IO framework and the corresponding Dubbo framework processing logic. -- 以上的协议识别完成之后,Channel已经确定了如何处理远程的客户端消息,通过对应的ServerPipeline进行处理即可(在处理的过程中也会根据配置信息决定消息的处理线程)。 +- Once the protocol recognition is completed, the Channel determines how to handle messages from remote clients, which can be processed through the corresponding ServerPipeline (during processing, the message handling thread is also determined by configuration). -## 使用场景 -- 最常用的是用于服务发现。这允许应用程序通过网络发现服务,然后使用同一端口与它们通信,有助于降低网络通信的复杂性,并使其更易于管理。 +## Usage Scenarios +- The most common application is service discovery. This allows applications to discover services over the network and communicate with them using the same port, which helps reduce the complexity of network communications and makes management easier. -- 可以用于负载平衡。这允许应用程序在多个远程服务或服务集群之间平衡负载,有助于提高服务的可扩展性、可靠性和可用性。 +- It can be used for load balancing. This allows applications to balance loads between multiple remote services or service clusters, which helps improve the scalability, reliability, and availability of services. -- 可以用于服务监控。这允许应用程序监视远程服务的运行状况,并在服务出现故障或变得不可用时发出警报,有助于确保服务的可用性并减少停机时间。 +- It can be used for service monitoring. This allows applications to monitor the health of remote services and issue alerts when a service fails or becomes unavailable, helping to ensure service availability and reduce downtime. -> 参考用例 +> Reference use case [https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-port-unification](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-port-unification) -## 使用方式 -在同一主机上部署多个服务或需要通过负载均衡器访问多个服务。 +## Usage Method +Deploy multiple services on the same host or access multiple services via a load balancer. -> 关于Dubbo支持的配置方式 [配置说明](/en/overview/mannual/java-sdk/reference-manual/config/) +> About the configuration methods supported by Dubbo [Configuration Instructions](/en/overview/mannual/java-sdk/reference-manual/config/) -### 服务多协议导出 +### Service Multi-Protocol Export -ext-protocol参数支持配置多个不同的协议,协议之间通过","进行分隔。 +The ext-protocol parameter supports configuring multiple different protocols, which are separated by ",". -#### xml 配置 +#### XML Configuration ```xml @@ -50,7 +46,7 @@ ext-protocol参数支持配置多个不同的协议,协议之间通过","进 ``` -#### API 配置 +#### API Configuration ```java ProtocolConfig config = new ProtocolConfig(CommonConstants.TRIPLE, -1); @@ -58,7 +54,7 @@ ProtocolConfig config = new ProtocolConfig(CommonConstants.TRIPLE, -1); config.setExtProtocol(CommonConstants.DUBBO+","); ``` -#### yaml 配置 +#### YAML Configuration ``` yaml dubbo: @@ -70,16 +66,16 @@ dubbo: ext-protocol: dubbo, ``` -#### properties 配置 +#### Properties Configuration ```properties dubbo.protocol.name=tri dubbo.protocol.ext-protocol=dubbo, dubbo.protocol.port=20880 ``` -### Qos接入 +### Qos Access -#### Qos模块导入 +#### Qos Module Import ```xml @@ -88,36 +84,34 @@ dubbo.protocol.port=20880 ``` -完成Qos模块的导入之后,相关的配置项可参考[Qos操作手册](/en/overview/mannual/java-sdk/reference-manual/qos/overview/)进行配置。 +After importing the Qos module, related configuration items can refer to the [Qos Operation Manual](/en/overview/mannual/java-sdk/reference-manual/qos/overview/) for configuration. -默认情况下,基于端口复用的Qos服务在模块导入后是启动的。 +By default, the Qos service based on port reuse is started after the module is imported. +### Qos Usage +To integrate the Qos protocol into port reuse scenarios, after establishing a connection, the client must first send a message to the server. Compared to providing Qos service through a single port, the port-reuse version of Qos protocol requires users to perform some operations to complete protocol identification (one of two options). -### Qos使用 +1. Directly invoke commands -将Qos协议接入到端口复用的场景下,需要在建立连接之后,客户端先向服务端发送消息,对比将Qos协议通过单个端口提供服务,端口复用版的Qos协议在处理telnet连接的情况下需要用户执行一些操作,完成协议识别(二选一)。 - -1. 直接调用命令 - - 直接调用telnet支持的命令也可以完成识别,在用户不熟悉的情况下可以调用help指令完成识别 + Directly calling telnet-supported commands can also complete identification; when users are unfamiliar, they can use the help command to aid recognition. ![pu-server-image2](/imgs/blog/pu-server/qos-telnet-directcall.png) -2. 发送telnet命令识别 +2. Sending telnet command identification - 通过telnet命令建立连接之后,执行以下几个步骤: + After establishing a connection with the telnet command, execute the following steps: - 1. 使用 crtl + "]" 进入到telnet交互界面(telnet默认的escape character) - 2. 调用 "send ayt" 向服务端发送特殊识别字段(为telnet协议的一个特殊字段) - 3. 回车完成消息发送并进入到dubbo的交互界面 + 1. Use ctrl + "]" to enter the telnet interactive interface (default escape character for telnet). + 2. Call "send ayt" to send a special identification field to the server (a special field for the telnet protocol). + 3. Press Enter to complete the message sending and enter the dubbo interactive interface. ![pu-server-imgs3](/imgs/blog/pu-server/qos-telnet-sendayt.png) -### 服务引用 +### Service Reference -以[dubbo-samples-port-unification](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-port-unification)中的例子作为基础, 引用不同协议的服务和非端口复用情况下的配置是一致的,下面通过Consumer端的InvokerListener输出调用过程中的URL信息。 +Using the example from [dubbo-samples-port-unification](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-port-unification) as a basis, referencing services with different protocols and configurations in a non-port reuse scenario are consistent. Below is the output of the URL information during the invocation process through the InvokerListener on the Consumer side. ```java ReferenceConfig reference = new ReferenceConfig<>(); diff --git a/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-invocation.md b/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-invocation.md index 4aae3cbc2739..eb844785fea3 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-invocation.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/architecture/service-invocation.md @@ -3,44 +3,44 @@ aliases: - /en/docs3-v2/java-sdk/concepts-and-architecture/service-invocation/ - /en/docs3-v2/java-sdk/concepts-and-architecture/service-invocation/ - /en/overview/mannual/java-sdk/concepts-and-architecture/service-invocation/ -description: 本文将介绍如何在 Dubbo Java 实现中自定义调用链路上核心的扩展点以满足您的需求。 -linkTitle: 服务调用 -title: 服务调用扩展点 +description: This article will introduce how to customize the core extension points in the calling chain of the Dubbo Java implementation to meet your needs. +linkTitle: Service Invocation +title: Service Invocation Extension Points type: docs weight: 4 --- -![dubbo-architucture](/imgs/v3/concepts/invoke-arch.jpg) +![dubbo-architecture](/imgs/v3/concepts/invoke-arch.jpg) -如上图所示,从服务调用的角度来看,Dubbo 在链路中提供了丰富的扩展点,覆盖了负载均衡方式、选址前后的拦截器、服务端处理拦截器等。 -简单来说 Dubbo 发起远程调用的时候,主要工作流程可以分为消费端和服务端两个部分。 +As shown in the figure above, from the perspective of service invocation, Dubbo provides a wealth of extension points in the call chain, covering load balancing methods, interceptors before and after service location, server processing interceptors, and more. +In simple terms, when Dubbo initiates a remote call, the main workflow can be divided into two parts: the consumer side and the server side. -消费端的工作流程如下: -- 通过 Stub 接收来自用户的请求,并且封装在 `Invocation` 对象中 -- 将 `Invocation` 对象传递给 `ClusterFilter`(**扩展点**)做选址前的请求预处理,如请求参数的转换、请求日志记录、限流等操作都是在此阶段进行的 -- 将 `Invocation` 对象传递给 `Cluster`(**扩展点**)进行集群调用逻辑的决策,如快速失败模式、安全失败模式等决策都是在此阶段进行的 - - `Cluster` 调用 `Directory` 获取所有可用的服务端地址信息 - - `Directory` 调用 `StateRouter`(**扩展点**,推荐使用) 和 `Router`(**扩展点**) 对服务端的地址信息进行路由筛选,此阶段主要是从全量的地址信息中筛选出本次调用允许调用到的目标,如基于打标的流量路由就是在此阶段进行的 - - `Cluster` 获得从 `Directory` 提供的可用服务端信息后,会调用 `LoadBalance` (**扩展点**)从多个地址中选择出一个本次调用的目标,如随机调用、轮询调用、一致性哈希等策略都是在此阶段进行的 - - `Cluster` 获得目标的 `Invoker` 以后将 `Invocation` 传递给对应的 `Invoker`,并等待返回结果,如果出现报错则执行对应的决策(如快速失败、安全失败等) -- 经过上面的处理,得到了带有目标地址信息的 `Invoker`,会再调用 `Filter`(**扩展点**)进行选址后的请求处理(由于在消费端侧创建的 `Filter` 数量级和服务端地址量级一致,如无特殊需要建议使用 `ClusterFilter` 进行扩展拦截,以提高性能) -- 最后 `Invocation` 会被通过网络发送给服务端 +The workflow of the consumer side is as follows: +- Receives requests from users through the Stub, encapsulated in the `Invocation` object. +- Passes the `Invocation` object to the `ClusterFilter` (**extension point**) for pre-processing the request before the location, such as request parameter conversion, request logging, rate limiting, etc., are performed at this stage. +- Passes the `Invocation` object to the `Cluster` (**extension point**) to make decisions on cluster call logic, such as fast failure mode, safe failure mode, etc., are made at this stage. + - The `Cluster` calls the `Directory` to obtain all available server address information. + - The `Directory` calls the `StateRouter` (**extension point**, recommended to use) and `Router` (**extension point**) to filter router information from the addresses of service providers, mainly to select the targets allowed for this call from the full address information, such as traffic routing based on tags, done at this stage. + - After obtaining the available server information provided by the `Directory`, the `Cluster` calls `LoadBalance` (**extension point**) to select a target for this call from multiple addresses, such as random calls, polling calls, consistent hashing, etc., are made at this stage. + - After obtaining the target `Invoker`, the `Cluster` passes the `Invocation` to the corresponding `Invoker`, and waits for the return result; if an error occurs, it executes corresponding decisions (like fast failure, safe failure, etc.). +- After the above processing, the `Invoker` with the target address information is obtained, and it will call the `Filter` (**extension point**) for request processing after location (since the number of `Filter` instances created on the consumer side is consistent with the number of server addresses, it is recommended to use `ClusterFilter` for extension interception if there is no special need to improve performance). +- Finally, the `Invocation` will be sent to the server over the network. -服务端的工作流程如下: -- 服务端通信层收到请求以后,会将请求传递给协议层构建出 `Invocation` -- 将 `Invocation` 对象传递给 `Filter` (**扩展点**)做服务端请求的预处理,如服务端鉴权、日志记录、限流等操作都是在此阶段进行的 -- 将 `Invocation` 对象传递给动态代理做真实的服务端调用 +The server side workflow is as follows: +- After receiving the request, the server communication layer will pass the request to the protocol layer to construct the `Invocation`. +- Passes the `Invocation` object to the `Filter` (**extension point**) for pre-processing of the server request, such as server authentication, logging, rate limiting, etc., are all done at this stage. +- Passes the `Invocation` object to the dynamic proxy for the actual server call. -## Filter(拦截器) +## Filter (Interceptor) -拦截器可以实现服务提供方和服务消费方调用过程拦截,Dubbo 本身的大多功能均基于此扩展点实现,每次远程方法执行,该拦截都会被执行,请注意对性能的影响。 -其中在消费端侧,`ClusterFilter` 用于选址前的拦截和 `Filter` 用于选址后的拦截。如无特殊需要使用 `ClusterFilter` 进行扩展拦截,以提高性能。 +Interceptors can implement the interception during the call process of service providers and consumers. Most of the functionalities in Dubbo are based on this extension point, and every remote method execution will trigger this interception, so pay attention to performance impacts. +Among them, on the consumer side, `ClusterFilter` is for interception before location, and `Filter` is for interception after location. It is recommended to use `ClusterFilter` for extension interception to improve performance unless special needs exist. -![filter-architucture](/imgs/v3/concepts/filter-arch.jpg) +![filter-architecture](/imgs/v3/concepts/filter-arch.jpg) -在 Dubbo 3 中,`Filter` 和 `ClusterFilter` 的接口签名被统一抽象到 `BaseFilter` 中,开发者可以分别实现 `Filter` 或 `ClusterFilter` 的接口来实现自己的拦截器。 -如果需要拦截返回状态,可以直接实现 `BaseFilter.Listener` 的接口,Dubbo 将自动识别,并进行调用。 +In Dubbo 3, the interface signatures of `Filter` and `ClusterFilter` have been unified and abstracted into `BaseFilter`, allowing developers to implement their interceptors by implementing the interfaces of `Filter` or `ClusterFilter`. +If you need to intercept the return state, you can directly implement the `BaseFilter.Listener` interface, and Dubbo will automatically recognize and invoke it. ```java package org.apache.dubbo.rpc; @@ -74,25 +74,25 @@ public interface ClusterFilter extends BaseFilter { } ``` -特别的,如果需要在 Consumer 侧生效 `Filter` 或 `ClusterFilter`,需要增加 `@Activate` 注解,并且需要指定 `group` 的值为 `consumer`。 +Specifically, if you need the `Filter` or `ClusterFilter` to take effect on the consumer side, you need to add the `@Activate` annotation and specify the value of `group` as `consumer`. ```java @Activate(group = CommonConstants.CONSUMER) ``` -如果需要在 Provider 侧生效 `Filter` 或 `ClusterFilter`,需要增加 `@Activate` 注解,并且需要指定 `group` 的值为 `provider`。 +If you need the `Filter` or `ClusterFilter` to take effect on the provider side, you need to add the `@Activate` annotation and specify the value of `group` as `provider`. ```java @Activate(group = CommonConstants.PROVIDER) ``` -> [调用拦截扩展方式](/en/overview/mannual/java-sdk/reference-manual/spi/description/filter/) +> [Invocation Interception Extension Method](/en/overview/mannual/java-sdk/reference-manual/spi/description/filter/) -## Router(路由选址) +## Router (Routing) -路由选址提供从多个服务提供方中选择**一批**满足条件的目标提供方进行调用的能力。 -Dubbo 的路由主要需要实现 3 个接口,分别是负责每次调用筛选的 `route` 方法,负责地址推送后缓存的 `notify` 方法,以及销毁路由的 `stop` 方法。 -在 Dubbo 3 中推荐实现 `StateRouter` 接口,能够提供高性能的路由选址方式。 +Routing provides the ability to select **a batch** of suitable target providers for invocation from multiple service providers. +Dubbo routing mainly needs to implement 3 interfaces, which are responsible for the `route` method for filtering each invocation, the `notify` method for caching after address push, and the `stop` method to destroy the routing. +In Dubbo 3, it is recommended to implement the `StateRouter` interface, which can provide high-performance routing. ```java package org.apache.dubbo.rpc.cluster.router.state; @@ -125,11 +125,11 @@ public interface Router extends Comparable { } ``` -> [路由选址扩展方式](/en/overview/mannual/java-sdk/reference-manual/spi/description/router/) +> [Routing Extension Method](/en/overview/mannual/java-sdk/reference-manual/spi/description/router/) -## Cluster(集群规则) +## Cluster (Cluster Rules) -集群规则提供在有多个服务提供方时进行结果聚合、容错等能力。 +Cluster rules provide the ability to aggregate results, fault tolerance, etc., when there are multiple service providers. ```java package org.apache.dubbo.rpc.cluster.support; @@ -142,11 +142,11 @@ public abstract class AbstractClusterInvoker implements ClusterInvoker { ``` -> [集群规则扩展方式](/en/overview/mannual/java-sdk/reference-manual/spi/description/cluster/) +> [Cluster Rule Extension Method](/en/overview/mannual/java-sdk/reference-manual/spi/description/cluster/) -## LoadBalance(负载均衡) +## LoadBalance (Load Balancing) -负载均衡提供从多个服务提供方中选择**一个**目标提供方进行调用的能力。 +Load balancing provides the ability to select **one** target provider for invocation from multiple service providers. ```java package org.apache.dubbo.rpc.cluster; @@ -156,4 +156,5 @@ public interface LoadBalance { Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException; } ``` -> [调用拦截扩展方式](/en/overview/mannual/java-sdk/reference-manual/spi/description/filter/) +> [Invocation Interception Extension Method](/en/overview/mannual/java-sdk/reference-manual/spi/description/filter/) + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/_index.md index a8a5df8bcddf..0375023f4efd 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config-center/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/_index.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/reference-manual/config-center/ - /en/docs3-v2/java-sdk/reference-manual/config-center/ - /en/overview/what/ecosystem/config-center/ -description: Dubbo 配置中心的基本使用和工作原理 -linkTitle: 配置中心 -title: 配置中心 +description: The basic usage and working principle of the Dubbo configuration center +linkTitle: Configuration Center +title: Configuration Center type: docs weight: 6 --- @@ -15,17 +15,18 @@ weight: 6 -配置中心 (config-center) 在 Dubbo 中可承担两类职责: +The configuration center (config-center) in Dubbo can undertake two types of responsibilities: -1. [外部化配置](../config/principle/#33-外部化配置):启动配置的集中式存储 (简单理解为 dubbo.properties 的外部化存储)。 -2. 流量治理规则存储 +1. [External configuration](../config/principle/#33-external-configuration): centralized storage of startup configurations (simply understood as external storage of dubbo.properties). +2. Storage of traffic governance rules. -请参考具体扩展实现了解如何启用配置中心。 +Please refer to the specific extension implementations to understand how to enable the configuration center. -值得注意的是 Dubbo 动态配置中心定义了两个不同层次的隔离选项,分别是 namespace 和 group。 -* namespace - 配置命名空间,默认值 `dubbo`。命名空间通常用于多租户隔离,即对不同用户、不同环境或完全不关联的一系列配置进行逻辑隔离,区别于物理隔离的点是不同的命名空间使用的还是同一物理集群。 -* group - 配置分组,默认值 `dubbo`。`group` 通常用于归类一组相同类型/目的的配置项,是对 `namespace` 下配置项的进一步隔离。 +It is worth noting that the Dubbo dynamic configuration center defines two different levels of isolation options, namely namespace and group. +* namespace - Configuration namespace, default value `dubbo`. The namespace is typically used for multi-tenant isolation, i.e., logical isolation of different configurations for different users or environments, distinct from physical isolation, as different namespaces still use the same physical cluster. +* group - Configuration grouping, default value `dubbo`. `group` is typically used to categorize a set of configuration items of the same type/purpose and is an additional layer of isolation for configuration items under the `namespace`. -参考 [配置说明 - 配置项手册](../config/properties/#config-center) 了解 namespace 和 group 之外 config-center 开放的更多配置项。 +Refer to [Configuration Description - Configuration Item Manual](../config/properties/#config-center) to learn more about configuration items offered by config-center beyond namespace and group. + +> To be compatible with the 2.6.x version configuration, when using Zookeeper as the registry center, and without explicitly configuring the configuration center, the Dubbo framework will default to using this Zookeeper as the configuration center, but it will only be used for service governance purposes. -> 为了兼容 2.6.x 版本配置,在使用 Zookeeper 作为注册中心,且没有显式配置配置中心的情况下,Dubbo 框架会默认将此 Zookeeper 用作配置中心,但将只作服务治理用途。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/apollo.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/apollo.md index 16c7141913a0..9fef9d5bd8f5 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config-center/apollo.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/apollo.md @@ -3,21 +3,21 @@ aliases: - /en/docs3-v2/java-sdk/reference-manual/config-center/apollo/ - /en/docs3-v2/java-sdk/reference-manual/config-center/apollo/ - /en/overview/what/ecosystem/config-center/apollo/ -description: Apollo 配置中心的基本使用和工作原理。 +description: The basic usage and working principles of Apollo Configuration Center. linkTitle: Apollo title: Apollo type: docs weight: 4 --- -## 1 前置条件 -* 了解 [Dubbo 基本开发步骤](../../../quick-start/spring-boot/) -* 安装并启动 [Apollo](https://www.apolloconfig.com/#/zh/README) +## 1 Preconditions +* Understand [the basic development steps of Dubbo](../../../quick-start/spring-boot/) +* Install and start [Apollo](https://www.apolloconfig.com/#/zh/README) -## 2 使用说明 -在此查看[完整示例代码](https://github.com/apache/dubbo-samples/tree/master/3-extensions/configcenter/dubbo-samples-configcenter-apollo) +## 2 Usage Instructions +View the [complete example code](https://github.com/apache/dubbo-samples/tree/master/3-extensions/configcenter/dubbo-samples-configcenter-apollo) -### 2.1 增加 Maven 依赖 +### 2.1 Add Maven Dependency ```xml @@ -37,12 +37,12 @@ weight: 4 ``` -### 2.2 启用 Apollo 配置中心 +### 2.2 Enable Apollo Configuration Center ```xml ``` -或者 +or ```yaml dubbo @@ -50,70 +50,71 @@ dubbo address: apollo://localhost:8080 ``` -或者 +or ```properties dubbo.config-center.address=apollo://localhost:8080 ``` -或者 +or ```java ConfigCenterConfig configCenter = new ConfigCenterConfig(); configCenter.setAddress("apollo://localhost:8080"); ``` -## 3 高级配置 -Apollo中的一个核心概念是命名空间 - namespace,和上面 Zookeeper、Nacos 的 namespace 概念不同,因此使用方式上也比较特殊些,建议充分了解 Apollo 自身的用法后再阅读以下文档内容。 +## 3 Advanced Configuration +A core concept in Apollo is the namespace, which is different from the namespace concepts of Zookeeper and Nacos. Therefore, the usage is somewhat special; it is recommended to fully understand Apollo's usage before reading the following document content. -但总的来说,对 Apollo 的适配而言: -* group 特用于外部化配置的隔离,参见 3.1 -* namespace 特用于流量治理规则隔离,参见 3.2 +Generally speaking, for adaptation to Apollo: +* group is specifically used for the isolation of externalized configurations, see 3.1 +* namespace is specifically used for the isolation of traffic governance rules, see 3.2 -### 3.1 外部化配置 +### 3.1 Externalized Configuration ```xml ``` -config-center 的 `group` 决定了 Apollo 读取外部化配置 `dubbo.properties` 文件的位置: -1. 如果 group 为空,则默认从 `dubbo` namespace 读取配置,用户须将外部化配置写在 `dubbo` namespace 下。 -2. 如果 group 不为空 - 2.1 group 值为应用名,则从应用当前的 namespace 读取配置,用户须将外部化配置写在 Apollo 自动指定的应用默认 namespace 下。 - 2.2 group 值为任意值,则从对应的 namespace 读取配置,用户须将外部化配置写在该 namespace 下。 +The `group` of config-center determines the location of the externalized configuration `dubbo.properties` file in Apollo: +1. If the group is empty, it defaults to reading configurations from the `dubbo` namespace, and users must write externalized configurations under the `dubbo` namespace. +2. If the group is not empty + 2.1 If the group value is the application name, it reads configurations from the current namespace of the application, and users must write externalized configurations under the automatically designated default namespace of Apollo. + 2.2 If the group value is any other value, it reads configurations from the corresponding namespace, and users must write externalized configurations under that namespace. -如以下示例是用的默认 group='dubbo' 的全局外部化配置,即该配置可被所有应用读取到。 +For example, the following example uses the default group='dubbo' for global externalized configuration, meaning this configuration can be read by all applications. ![apollo-configcenter-dubbo.png](/imgs/user/apollo-configcenter-dubbo.png) -如果配置 group='应用名' 则是应用特有配置,只有该应用可以读取到。 +If the group is set to 'application name', then it is application-specific configuration, and only that application can read it. -> 关于外部化文件配置托管,相当于是把 `dubbo.properties` 配置文件的内容存储在了 Apollo 中。每个应用都可以通过关联共享的 `dubbo` namespace 继承公共配置, 进而可以单独覆盖个别配置项。 +> The external file configuration hosting means that the contents of the `dubbo.properties` configuration file are stored in Apollo. Each application can inherit common configurations through the associated shared `dubbo` namespace and can individually override specific configuration items. -### 3.2 流量治理规则 -**流量治理规则一定都是全局共享的,因此每个应用内的 namespace 配置都应该保持一致。** +### 3.2 Traffic Governance Rules +**Traffic governance rules are globally shared, so the namespace configurations within each application should remain consistent.** ```xml ``` -config-center 的 `namespace` 决定了 Apollo 存取 `流量治理规则` 的位置: -1. 如果 namespace 为空,则默认从 `dubbo` namespace 存取配置,须治理规则写在 `dubbo` namespace 下。 -2. 如果 namespace 不为空,则从对应的 namespace 值读取规则,须治理规则写在该 namespace 下。 +The `namespace` of config-center determines the location of the traffic governance rules in Apollo: +1. If the namespace is empty, it defaults to accessing configurations from the `dubbo` namespace, and governance rules must be written under the `dubbo` namespace. +2. If the namespace is not empty, it reads rules from the corresponding namespace value, and governance rules must be written under that namespace. -如以下示例是通过 `namespace='governance'` 将流量治理规则放在了 `governance` namespace 下。 +For example, the following example uses `namespace='governance'` to place traffic governance rules in the `governance` namespace. ![apollo-configcenter-governance-dubbo.png](/imgs/user/apollo-configcenter-governance-dubbo.png) -### 3.3 更多 Apollo 特有配置 -当前 Dubbo 适配了 env、apollo.meta、apollo.cluster、apollo.id 等特有配置项,可通过 config-center 的扩展参数进行配置。 +### 3.3 More Apollo Specific Configurations +Currently, Dubbo has adapted specific configuration items such as env, apollo.meta, apollo.cluster, and apollo.id, which can be configured via the extension parameters of config-center. -如 +For example, ```properties dubbo.config-center.address=apollo://localhost:8080 ``` -或者 +or ```properties -dubbo.config-center.prameters.apollo.meta=xxx -dubbo.config-center.prameters.env=xxx +dubbo.config-center.parameters.apollo.meta=xxx +dubbo.config-center.parameters.env=xxx ``` + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/introduction.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/introduction.md index 261d53a32a0f..ab9ead8405ba 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config-center/introduction.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/introduction.md @@ -3,27 +3,28 @@ aliases: - /en/docs3-v2/java-sdk/reference-manual/config-center/ - /en/docs3-v2/java-sdk/reference-manual/config-center/ - /en/overview/what/ecosystem/config-center/ -description: Dubbo 配置中心的基本使用和工作原理 -linkTitle: 配置中心概述 -title: 配置中心 +description: Basic usage and working principles of the Dubbo Config Center +linkTitle: Overview of Config Center +title: Config Center type: docs weight: 1 --- -配置中心 (config-center) 在 Dubbo 中可承担两类职责: +The Config Center in Dubbo has two main responsibilities: -1. [外部化配置](/en/overview/mannual/java-sdk/reference-manual/config/principle/#33-外部化配置):启动配置的集中式存储 (简单理解为 dubbo.properties 的外部化存储)。 -2. 流量治理规则存储 +1. [Externalized Configuration](/en/overview/mannual/java-sdk/reference-manual/config/principle/#33-外部化配置): Centralized storage for startup configurations (simplified as external storage of dubbo.properties). +2. Storage of traffic governance rules. -请参考具体扩展实现了解如何启用配置中心。 +Please refer to specific extension implementations to learn how to enable the Config Center. -值得注意的是 Dubbo 动态配置中心定义了两个不同层次的隔离选项,分别是 namespace 和 group。 -* namespace - 配置命名空间,默认值 `dubbo`。命名空间通常用于多租户隔离,即对不同用户、不同环境或完全不关联的一系列配置进行逻辑隔离,区别于物理隔离的点是不同的命名空间使用的还是同一物理集群。 -* group - 配置分组,默认值 `dubbo`。`group` 通常用于归类一组相同类型/目的的配置项,是对 `namespace` 下配置项的进一步隔离。 +It is worth noting that the Dubbo dynamic configuration center defines two different levels of isolation options, namely namespace and group. +* namespace - Configuration namespace, default value `dubbo`. The namespace is usually used for multi-tenant isolation, logically isolating different users, different environments, or completely unrelated sets of configurations, as opposed to physical isolation, where different namespaces still use the same physical cluster. +* group - Configuration group, default value `dubbo`. The `group` is typically used to classify a set of configuration items of the same type/purpose, providing further isolation of configuration items under the `namespace`. -参考 [配置说明 - 配置项手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/#dubboconfig-center) 了解 namespace 和 group 之外 config-center 开放的更多配置项。 +Refer to [Configuration Instructions - Configuration Item Manual](/en/overview/mannual/java-sdk/reference-manual/config/properties/#dubboconfig-center) for more configuration items available in the config-center beyond namespace and group. -{{% alert title="使用注册中心作为默认配置中心" color="info" %}} -在使用 Zookeeper、Nacos 作为注册中心且没有显式配置配置中心的情况下,Dubbo 框架会默认将此 Zookeeper、Nacos 用作配置中心,用作服务治理用途。 +{{% alert title="Using the Registry Center as the Default Config Center" color="info" %}} +When using Zookeeper or Nacos as a registry center without explicitly configuring a config center, the Dubbo framework defaults to using Zookeeper or Nacos as the config center for service governance purposes. {{% /alert %}} + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/nacos.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/nacos.md index 79f78267aa50..51aeadf395ff 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config-center/nacos.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/nacos.md @@ -3,32 +3,32 @@ aliases: - /en/docs3-v2/java-sdk/reference-manual/config-center/nacos/ - /en/docs3-v2/java-sdk/reference-manual/config-center/nacos/ - /en/overview/what/ecosystem/config-center/nacos/ -description: Nacos 配置中心的基本使用和工作原理。 +description: Basic usage and working principles of the Nacos configuration center. linkTitle: Nacos title: Nacos type: docs weight: 3 --- -## 1 前置条件 -* 了解 [Dubbo 基本开发步骤](/en/overview/mannual/java-sdk/quick-start/starter/) -* 安装并启动 [Nacos](/en/overview/reference/integrations/nacos/) +## 1 Prerequisites +* Understand [Basic Development Steps of Dubbo](/en/overview/mannual/java-sdk/quick-start/starter/) +* Install and start [Nacos](/en/overview/reference/integrations/nacos/) -> 当Dubbo使用`3.0.0`及以上版本时,需要使用Nacos `2.0.0`及以上版本。请参考 [nacos 注册中心](/en/overview/mannual/java-sdk/reference-manual/registry/nacos/#12-nacos-版本) 了解 nacos 版本适配情况。 +> When Dubbo uses version `3.0.0` or above, Nacos version `2.0.0` or above is required. Please refer to [nacos registry]( /en/overview/mannual/java-sdk/reference-manual/registry/nacos/#12-nacos-version) for Nacos version compatibility. -## 2 使用说明 +## 2 Instructions -### 2.1 增加 Maven 依赖 -如果项目已经启用 Nacos 作为注册中心,则无需增加任何额外配置。 +### 2.1 Add Maven Dependency +If the project has already enabled Nacos as a registry, no additional configuration is required. -如果未启用 Nacos 注册中心,则请参考 [为注册中心增加 Nacos 依赖](/en/overview/mannual/java-sdk/reference-manual/registry/nacos/#11-增加依赖)。 +If Nacos registry is not enabled, please refer to [Add Nacos dependency for registry](/en/overview/mannual/java-sdk/reference-manual/registry/nacos/#11-add-dependency). -### 2.2 启用 Nacos 配置中心 +### 2.2 Enable Nacos Configuration Center ```xml ``` -或者 +or ```yaml dubbo @@ -36,44 +36,44 @@ dubbo address: nacos://127.0.0.1:8848 ``` -或者 +or ```properties dubbo.config-center.address=nacos://127.0.0.1:8848 ``` -或者 +or ```java ConfigCenterConfig configCenter = new ConfigCenterConfig(); configCenter.setAddress("nacos://127.0.0.1:8848"); ``` -`address` 格式请参考 [Nacos 注册中心 - 启用配置](../../registry/nacos/#22-配置并启用-nacos) +For `address` format, please refer to [Nacos Registry - Enable Configuration](../../registry/nacos/#22-configure-and-enable-nacos) -## 3 高级配置 -如要开启认证鉴权,请参考 [Nacos 注册中心 - 启用认证鉴权](../../registry/nacos/#31-认证) +## 3 Advanced Configuration +To enable authentication, please refer to [Nacos Registry - Enable Authentication](../../registry/nacos/#31-authentication) -### 3.1 外部化配置 -#### 3.1.1 全局外部化配置 -**1. 应用开启 config-center 配置** +### 3.1 Externalized Configuration +#### 3.1.1 Global Externalized Configuration +**1. Application enable config-center configuration** ```yaml dubbo config-center address: nacos://127.0.0.1:2181 config-file: dubbo.properties # optional ``` -`config-file` - 全局外部化配置文件 key 值,默认 `dubbo.properties`。`config-file` 代表将 Dubbo 配置文件存储在远端注册中心时,文件在配置中心对应的 key 值,通常不建议修改此配置项。 +`config-file` - Key for global externalized configuration file, default is `dubbo.properties`. It represents the key in the configuration center when storing the Dubbo configuration file remotely. It is generally not recommended to modify this configuration. -**2. Nacos Server 增加配置** +**2. Add Configuration to Nacos Server** ![nacos-configcenter-global-properties.png](/imgs/user/nacos-configcenter-global-properties.png) -dataId 是 `dubbo.properties`,group 分组与 config-center 保持一致,如未设置则默认填 `dubbo`。 +dataId is `dubbo.properties`, group is the same as config-center, default is `dubbo` if not set. -#### 3.1.2 应用特有外部化配置 +#### 3.1.2 Application-Specific Externalized Configuration -**1. 应用开启 config-center 配置** +**1. Application enable config-center configuration** ```yaml dubbo config-center @@ -81,15 +81,15 @@ dubbo app-config-file: dubbo.properties # optional ``` -`app-config-file` - 当前应用特有的外部化配置文件 key 值,如 `app-name-dubbo.properties`,仅在需要覆盖全局外部化配置文件 `config-file` 时才配置。 +`app-config-file` - Key for the application-specific externalized configuration file, such as `app-name-dubbo.properties`, configured only when needing to override the global externalization `config-file`. -**2. Nacos Server 增加配置** +**2. Add Configuration to Nacos Server** ![nacos-configcenter-application-properties.png](/imgs/user/nacos-configcenter-application-properties.png) -dataId 是 `dubbo.properties`,group 分组设置为应用名即 `demo-provider`。 +dataId is `dubbo.properties`, group is the application name `demo-provider`. -### 3.2 设置 group 与 namespace +### 3.2 Set Group and Namespace ```yaml dubbo config-center @@ -98,19 +98,20 @@ dubbo namespace: dev1 ``` -对配置中心而言,`group` 与 `namespace` 应该是全公司(集群)统一的,应该避免不同应用使用不同的值。 +For the configuration center, `group` and `namespace` should be consistent across the company (cluster) and avoid different values for different applications. -### 3.3 Nacos 扩展配置 -更多 Nacos sdk/server 支持的参数配置请参见 [Nacos 注册中心 - 更多配置](../../registry/nacos/#35-更多配置) +### 3.3 Nacos Extended Configuration +For more Nacos sdk/server supported parameter configurations, refer to [Nacos Registry - More Configurations](../../registry/nacos/#35-more-configurations) -## 4 流量治理规则 -对 Nacos 而言,所有流量治理规则和外部化配置都应该是全局可见的,因此相同逻辑集群内的应用都必须使用相同的 namespace 与 group。其中,namespace 的默认值是 `public`,group 默认值是 `dubbo`,应用不得擅自修改 namespace 与 group,除非能保持全局一致。 +## 4 Traffic Governance Rules +For Nacos, all traffic governance rules and externalized configurations should be globally visible, thus applications in the same logical cluster must use the same namespace and group. The default value for namespace is `public` and the default value for group is `dubbo`. Applications must not modify the namespace and group without maintaining global consistency. -流量治理规则的增删改建议通过 dubbo-admin 完成,更多内容可查看 Dubbo 支持的流量治理能力。 +Changes to traffic governance rules are recommended to be made through dubbo-admin; for more details, see Dubbo's supported traffic governance capabilities. ![nacos-configcenter-governance.jpg](/imgs/user/nacos-configcenter-governance.png) -流量治理规则有多种类型,不同类型的规则 dataId 的后缀是不同的: +There are various types of traffic governance rules, and different types of rules have different suffixes for dataId: + +- configurators [override rules](/en/overview/core-features/traffic/configuration-rule/) +- tag-router [tag routing](/en/overview/core-features/traffic/tag-rule/) and condition-router [condition routing](/en/overview/core-features/traffic/condition-rule/) -- configurators [覆盖规则](/en/overview/core-features/traffic/configuration-rule/) -- tag-router [标签路由](/en/overview/core-features/traffic/tag-rule/) 与 condition-router [条件路由](/en/overview/core-features/traffic/condition-rule/) diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/others.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/others.md index 29fe7cc6ed6c..e3cac50512d4 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config-center/others.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/others.md @@ -1,18 +1,18 @@ --- -description: "更多配置中心扩展实现,包括 etcd、consul 等" -linkTitle: 扩展实现 -title: 更多配置中心扩展实现 +description: "More implementations of configuration center extensions, including etcd, consul, etc." +linkTitle: Extension Implementations +title: More Implementations of Configuration Center Extensions type: docs weight: 4 --- -Dubbo 框架还默认提供了 etcd、consul 等配置中心适配实现。 +The Dubbo framework also provides default implementations for configuration centers such as etcd and consul. ## Etcd -Etcd 配置中心由社区生态库维护,具体可参见 [](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-configcenter-extensions/dubbo-configcenter-etcd)。 +The Etcd configuration center is maintained by the community ecosystem library, for more details see [](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-configcenter-extensions/dubbo-configcenter-etcd). -增加依赖: +Add dependency: ```xml @@ -22,7 +22,7 @@ Etcd 配置中心由社区生态库维护,具体可参见 [](https://github.co ``` -调整配置: +Adjust configuration: ```yaml dubbo @@ -33,9 +33,9 @@ dubbo ## Consul -Consul 配置中心由社区生态库维护,具体可参见 [](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-configcenter-extensions/dubbo-configcenter-consul)。 +The Consul configuration center is maintained by the community ecosystem library, for more details see [](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-configcenter-extensions/dubbo-configcenter-consul). -增加依赖: +Add dependency: ```xml @@ -45,10 +45,10 @@ Consul 配置中心由社区生态库维护,具体可参见 [](https://github. ``` -调整配置: +Adjust configuration: ```yaml dubbo config-center address: consul://127.0.0.1:1111 -``` \ No newline at end of file +``` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config-center/zookeeper.md b/content/en/overview/mannual/java-sdk/reference-manual/config-center/zookeeper.md index ce04706a0fca..6b0a9529882c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config-center/zookeeper.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config-center/zookeeper.md @@ -3,7 +3,7 @@ aliases: - /en/docs3-v2/java-sdk/reference-manual/config-center/zookeeper/ - /en/docs3-v2/java-sdk/reference-manual/config-center/zookeeper/ - /en/overview/what/ecosystem/config-center/zookeeper/ -description: Zookeeper 配置中心的基本使用和工作原理。 +description: Basic usage and working principles of the Zookeeper configuration center. linkTitle: Zookeeper title: Zookeeper type: docs @@ -11,24 +11,24 @@ weight: 2 --- -## 1 前置条件 -* 了解 [Dubbo 基本开发步骤](/en/overview/mannual/java-sdk/quick-start/starter/) -* 安装并启动 [Zookeeper](/en/overview/reference/integrations/zookeeper/) +## 1 Prerequisites +* Understand [Dubbo basic development steps](/en/overview/mannual/java-sdk/quick-start/starter/) +* Install and start [Zookeeper](/en/overview/reference/integrations/zookeeper/) -## 2 使用说明 -在此查看[完整示例代码](https://github.com/apache/dubbo-samples/tree/master/3-extensions/configcenter/dubbo-samples-configcenter-annotation) +## 2 Usage Instructions +View the [complete sample code](https://github.com/apache/dubbo-samples/tree/master/3-extensions/configcenter/dubbo-samples-configcenter-annotation) -### 2.1 增加 Maven 依赖 -如果项目已经启用 Zookeeper 作为注册中心,则无需增加任何额外配置。 +### 2.1 Add Maven Dependencies +If the project has already enabled Zookeeper as the registry, no additional configurations are necessary. -如果未使用 Zookeeper 注册中心,则请参考 [为注册中心增加 Zookeeper 相关依赖](/en/overview/mannual/java-sdk/reference-manual/registry/zookeeper/#11-增加-maven-依赖)。 +If Zookeeper is not used as the registry, refer to [Add Zookeeper related dependencies for the registry](/en/overview/mannual/java-sdk/reference-manual/registry/zookeeper/#11-增加-maven-依赖). -### 2.2 启用 Zookeeper 配置中心 +### 2.2 Enable Zookeeper Configuration Center ```xml ``` -或者 +or ```yaml dubbo @@ -36,26 +36,26 @@ dubbo address: zookeeper://127.0.0.1:2181 ``` -或者 +or ```properties dubbo.config-center.address=zookeeper://127.0.0.1:2181 ``` -或者 +or ```java ConfigCenterConfig configCenter = new ConfigCenterConfig(); configCenter.setAddress("zookeeper://127.0.0.1:2181"); ``` -`address` 格式请参考 [zookeeper 注册中心 - 启用配置](../../registry/zookeeper/#13-配置并启用-zookeeper) +For the format of `address`, refer to [zookeeper registry - enable configuration](../../registry/zookeeper/#13-配置并启用-zookeeper) -## 3 高级配置 -如要开启认证鉴权,请参考 [zookeeper 注册中心 - 启用认证鉴权](../../registry/zookeeper/#21-认证与鉴权) +## 3 Advanced Configuration +To enable authentication and authorization, refer to [zookeeper registry - enable authentication and authorization](../../registry/zookeeper/#21-认证与鉴权) -### 3.1 定制外部化配置 key -**1. 启用外部化配置,并指定 key** +### 3.1 Customize Externalized Configuration Key +**1. Enable externalized configuration and specify key** ```yaml dubbo config-center @@ -63,21 +63,21 @@ dubbo config-file: dubbo.properties ``` -`config-file` - 外部化配置文件 key 值,默认 `dubbo.properties`。`config-file` 代表将 Dubbo 配置文件存储在远端注册中心时,文件在配置中心对应的 key 值,通常不建议修改此配置项。 +`config-file` - key value of the externalized configuration file, default `dubbo.properties`. `config-file` represents the key value corresponding to the Dubbo configuration file when stored in the remote registry, and it is generally not recommended to change this configuration item. -**2. Zookeeper 配置中心增加配置** -外部化配置的存储结构如下图所示 +**2. Add configuration to Zookeeper Configuration Center** +The storage structure of externalized configuration is shown in the diagram below. ![zk-configcenter.jpg](/imgs/user/zk-configcenter.jpg) -- namespace,用于不同配置的环境隔离。 -- config,Dubbo约定的固定节点,不可更改,所有配置和流量治理规则都存储在此节点下。 -- dubbo 与 application,分别用来隔离全局配置、应用级别配置:dubbo 是默认 group 值,application 对应应用名 -- dubbo.properties,此节点的node value存储具体配置内容 +- namespace, used for environment isolation of different configurations. +- config, a fixed node defined by Dubbo, cannot be changed, all configurations and traffic governance rules are stored under this node. +- dubbo and application, used for isolating global configuration and application-level configuration: dubbo is the default group value, and application corresponds to the application name. +- dubbo.properties, the node value of this node stores specific configuration content. -> 这里是为了说明工作原理,建议使用 dubbo-admin 进行配置管理。 +> This is to illustrate the working principle; it is recommended to use dubbo-admin for configuration management. -### 3.2 设置 group 与 namespace +### 3.2 Set Group and Namespace ```yaml dubbo config-center @@ -86,14 +86,15 @@ dubbo namespace: dev1 ``` -对配置中心而言,`group` 与 `namespace` 应该是全公司(集群)统一的,应该避免不同应用使用不同的值,外部化配置和治理规则也应该存放在对应的 group 与 namespace。 +For the configuration center, `group` and `namespace` should be unified across the company (cluster), and different applications should avoid using different values. Externalized configurations and governance rules should also be stored under the corresponding group and namespace. -## 4 流量治理规则 -所有流量治理规则默认都存储在 `/dubbo/config` 节点下,具体节点结构图如下。流量治理规则的增删改建议通过 dubbo-control-plane(dubbo-admin) 完成,更多内容可查看 Dubbo 支持的具体流量治理能力 +## 4 Traffic Governance Rules +All traffic governance rules are by default stored under the `/dubbo/config` node. The specific node structure diagram is as follows. It is recommended to use dubbo-control-plane (dubbo-admin) for adding, deleting, or modifying traffic governance rules. More content can be found in Dubbo's supported traffic governance capabilities. ![zk-configcenter-governance](/imgs/user/zk-configcenter-governance.jpg) -- namespace,用于不同配置的环境隔离。 -- config,Dubbo 约定的固定节点,不可更改,所有配置和流量治理规则都存储在此节点下。 -- dubbo,所有服务治理规则都是全局性的,dubbo 为默认节点 -- configurators/tag-router/condition-router/migration,不同的服务治理规则类型,node value 存储具体规则内容 +- namespace, used for environment isolation of different configurations. +- config, a fixed node defined by Dubbo, cannot be changed; all configuration and traffic governance rules are stored in this node. +- dubbo, all service governance rules are global, and dubbo is the default node. +- configurators/tag-router/condition-router/migration, different types of service governance rules, node value stores the specific rules content. + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/config/_index.md index 3a5e73862f4d..06a34b1aa355 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/_index.md @@ -3,9 +3,10 @@ aliases: - /en/docs3-v2/java-sdk/reference-manual/config/ - /en/docs3-v2/java-sdk/reference-manual/config/ - /en/overview/mannual/java-sdk/reference-manual/config/overview/ -description: Dubbo 配置指南 -linkTitle: 配置说明 -title: 配置手册 +description: Dubbo Configuration Guide +linkTitle: Configuration Instructions +title: Configuration Manual type: docs weight: 1 --- + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/api/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/config/api/_index.md index 4556ee3f3583..15c22145ba6e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/api/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/api/_index.md @@ -2,9 +2,10 @@ aliases: - /en/docs3-v2/java-sdk/reference-manual/config/ - /en/docs3-v2/java-sdk/reference-manual/config/ -description: Dubbo 配置指南 -linkTitle: 原生API -title: 配置手册 +description: Dubbo Configuration Guide +linkTitle: Native API +title: Configuration Manual type: docs weight: 1 --- + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/maven-plugin.md b/content/en/overview/mannual/java-sdk/reference-manual/config/maven-plugin.md index fb8caed662dc..0ca2891dc00f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/maven-plugin.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/maven-plugin.md @@ -1,22 +1,22 @@ --- -description: Dubbo Maven Plugin 的配置方式 -linkTitle: Maven Plugin 配置 -title: Dubbo Maven Plugin 的配置方式 +description: Configuration of the Dubbo Maven Plugin +linkTitle: Maven Plugin Configuration +title: Configuration of the Dubbo Maven Plugin type: docs weight: 3 --- -本文主要讲解 Dubbo Maven Plugin 的配置方式。 +This article mainly explains the configuration of the Dubbo Maven Plugin. -当前 Dubbo Maven Plugin 支持以下功能: -- Dubbo Maven Plugin For Protobuf:生成 Dubbo 服务接口的 Stub 代码 -- Dubbo Maven Plugin For Native Image:基于 AOT 机制,生成 Native Image 必要的 Metadata 信息 +The current Dubbo Maven Plugin supports the following features: +- Dubbo Maven Plugin For Protobuf: Generates Stub code for Dubbo service interfaces +- Dubbo Maven Plugin For Native Image: Generates necessary Metadata information for Native Image based on AOT mechanism ## Dubbo Maven Plugin For Protobuf -### 如何使用 Dubbo Maven Plugin 生成 Protobuf Stub 代码 +### How to use Dubbo Maven Plugin to generate Protobuf Stub code -#### 1. 编写 .proto 文件 +#### 1. Write the .proto file greeter.proto @@ -44,10 +44,9 @@ message HelloRequest { message HelloReply { string message = 1; } - ``` -#### 2. 引入 dubbo-maven-plugin 依赖 +#### 2. Include the dubbo-maven-plugin dependency ```xml @@ -65,7 +64,7 @@ message HelloReply { ``` -#### 3. 生成文件示例 +#### 3. Example of generated file ```java /* @@ -104,7 +103,6 @@ public final class DemoServiceDubbo { org.apache.dubbo.demo.HelloRequest.getDefaultInstance()); } } catch (ClassNotFoundException e) { -// ignore } return clazz; } @@ -124,31 +122,27 @@ public final class DemoServiceDubbo { org.apache.dubbo.demo.HelloReply sayHello(org.apache.dubbo.demo.HelloRequest request); CompletableFuture sayHelloAsync(org.apache.dubbo.demo.HelloRequest request); - - } - } - ``` -### 配置列表 +### Configuration List -Dubbo Maven Plugin For Protobuf 支持以下配置: +Dubbo Maven Plugin For Protobuf supports the following configurations: -| 配置参数 | 必填 | 解释 | 默认值 | 示例 | -|----------------------|-------|--------------------------------------------------------|------------------------------------------------------------|---------------------------------------------------------------------------| -| dubboVersion | true | Dubbo 版本号,用于查找 dubbo-compiler 组件 | ${dubbo.version} | 3.3.0 | -| dubboGenerateType | true | 生成的文件类型 | tri | tri 或 tri-reactor | -| protocExecutable | false | 可执行的 protoc 路径,如不配置将自动从 Maven 仓库下载 | | protoc | -| protocArtifact | false | protoc 在 Maven 仓库中定位,用于下载 protoc 文件,如不配置将自动识别操作系统类型并下载 | | com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} | -| protoSourceDir | true | proto 文件目录 | ${basedir}/src/main/proto | ./proto | -| outputDir | true | 生成文件的目标目录 | ${project.build.directory}/generated-sources/protobuf/java | ${basedir}/src/main/java | -| protocPluginDirectory | false | 临时存储 protoc 的目录 | ${project.build.directory}/protoc-plugins | ./target/protoc-plugins | +| Configuration Parameter | Required | Description | Default Value | Example | +|----------------------------|----------|-----------------------------------------------------------|------------------------------------------------------------|----------------------------------------------------------------------------| +| dubboVersion | true | Dubbo version number, used to find the dubbo-compiler component | ${dubbo.version} | 3.3.0 | +| dubboGenerateType | true | Type of the generated file | tri | tri or tri-reactor | +| protocExecutable | false | Path to the executable protoc; if not configured, it will be downloaded from Maven repository | | protoc | +| protocArtifact | false | The protocol used to locate protoc in Maven repository, if not configured, it will automatically detect the OS type and download | | com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} | +| protoSourceDir | true | Directory for proto files | ${basedir}/src/main/proto | ./proto | +| outputDir | true | Target directory for generated files | ${project.build.directory}/generated-sources/protobuf/java | ${basedir}/src/main/java | +| protocPluginDirectory | false | Directory for temporary storage of protoc | ${project.build.directory}/protoc-plugins | ./target/protoc-plugins | ## Dubbo Maven Plugin For Native Image -### 示例 +### Example ```xml @@ -169,11 +163,11 @@ Dubbo Maven Plugin For Protobuf 支持以下配置: ``` +### Configuration List -### 配置列表 +Dubbo Maven Plugin For Native Image supports the following configurations: -Dubbo Maven Plugin For Native Image 支持以下配置: +| Configuration Parameter | Required | Description | Default Value | Example | +|----------------------------|----------|---------------|------------------------------------------------------------|----------------------------------------------------------------------------| +| mainClass | true | Name of the main class | | com.example.nativedemo.NativeDemoApplication | -| 配置参数 | 必填 | 解释 | 默认值 | 示例 | -|----------------------|-------|------|------------------------------------------------------------|---------------------------------------------------------------------------| -| mainClass | true | 启动类名 | | com.example.nativedemo.NativeDemoApplication | diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/_index.md b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/_index.md index bc3f4a4a5b37..bca6c3990b1d 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/_index.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/_index.md @@ -2,9 +2,10 @@ aliases: - /en/docs3-v2/java-sdk/reference-manual/config/ - /en/docs3-v2/java-sdk/reference-manual/config/ -description: Dubbo 配置指南 +description: Dubbo Configuration Guide linkTitle: Spring -title: 配置手册 +title: Configuration Manual type: docs weight: 1 --- + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot.md b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot.md index 7208da3fba8c..0ebcea4dc002 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/spring-boot.md @@ -3,20 +3,20 @@ aliases: - /en/docs3-v2/java-sdk/reference-manual/config/annotation/ - /en/docs3-v2/java-sdk/reference-manual/config/annotation/ - /en/overview/mannual/java-sdk/reference-manual/config/annotation/ -description: 以 Annotation、Spring Boot 开发 Dubbo 应用 +description: Develop Dubbo applications using Annotation and Spring Boot linkTitle: Spring Boot title: Spring Boot type: docs weight: 3 --- -关于 Spring Boot 的注解、基本使用方法等请参考 [使用教程 - Spring Boot](/en/overview/mannual/java-sdk/tasks/develop/springboot/)。以下是 spring boot 支持的配置详情与 starter 列表。 +For details about Spring Boot annotations and basic usage, please refer to [User Guide - Spring Boot](/en/overview/mannual/java-sdk/tasks/develop/springboot/). Below are the configuration details and starter list supported by Spring Boot. ## application.yaml -以下是 Dubbo 框架支持的配置组件列表,可以在 Spring Boot 配置文件中指定所需配置。 +Below is the list of configuration components supported by the Dubbo framework, which can be specified in the Spring Boot configuration file. -### 配置示例 +### Configuration Example ```yaml dubbo: @@ -60,34 +60,35 @@ dubbo: * [**dubbo.tracing.sampling** - `org.apache.dubbo.config.nested.SamplingConfig`](../../properties#dubbotracingsampling) * [**dubbo.tracing.tracing-exporter** - `org.apache.dubbo.config.nested.ExporterConfig`](../../properties#dubbotracingtracing-exporter) -## starter列表 +## Starter List ### dubbo-spring-boot-starter -以下是一些 dubbo-spring-boot-starter 版本对应的 SpringBoot、JDK 依赖: +Here are some version mappings of the dubbo-spring-boot-starter that correspond to Spring Boot and JDK dependencies: -| 版本 | 兼容 Spring Boot 范围 | +| Version | Compatible Spring Boot Range | |-------|---------------| | 3.3.x | [1.x ~ 3.x) | | 3.2.x | [1.x ~ 3.x) | | 3.1.x | [1.x ~ 2.x) | | 2.7.x | [1.x ~ 2.x) | -### 其他组件starter +### Other Component Starters -以下是 Dubbo 官方社区提供的 starter 列表(3.3.0+ 版本),方便在 Spring Boot 应用中快速使用: -* `dubbo-spring-boot-starter`,管理 dubbo 核心依赖,用于识别 application.properties 或 application.yml 中 `dubbo.` 开头的配置项,扫描 @DubboService 等注解。 -* `dubbo-spring-boot-starter3`,管理 dubbo 核心依赖,与 dubbo-spring-boot-starter 相同,支持 spring boot 3.2 版本。 -* `dubbo-nacos-spring-boot-starter`,管理 nacos-client 等依赖,使用 Nacos 作为注册中心、配置中心时引入。 -* `dubbo-zookeeper-spring-boot-starter`,管理 zookeeper、curator 等依赖,使用 Zookeeper 作为注册中心、配置中心时引入(Zookeeper server 3.4 及以下版本使用)。 -* `dubbo-zookeeper-curator5-spring-boot-starter`,管理 zookeeper、curator5 等依赖,使用 Zookeeper 作为注册中心、配置中心时引入。 -* `dubbo-sentinel-spring-boot-starter`,管理 sentinel 等依赖,使用 Sentinel 进行限流降级时引入。 -* `dubbo-seata-spring-boot-starter`,管理 seata 等依赖,使用 Seata 作为分布式事务解决方案时引入。 -* `dubbo-observability-spring-boot-starter`,加入该依赖将自动开启 Dubbo 内置的 metrics 采集,可用于后续的 Prometheus、Grafana 等监控系统。 -* `dubbo-tracing-brave-spring-boot-starter`,管理 brave/zipkin、micrometer 等相关相关依赖,使用 Brave/Zipkin 作为 Tracer,将 Trace 信息 export 到 Zipkin。 -* `dubbo-tracing-otel-otlp-spring-boot-starter`,管理 brave/zipkin、micrometer 等相关相关依赖,使用 OpenTelemetry 作为 Tracer,将 Trace 信息 export 到 OTlp Collector。 -* `dubbo-tracing-otel-zipkin-spring-boot-starter`,管理 brave/zipkin、micrometer 等相关相关依赖,使用 OpenTelemetry 作为 Tracer,将 Trace 信息 export 到 Zipkin。 +Here is the list of starters provided by the Dubbo official community (version 3.3.0+) for quick usage in Spring Boot applications: +* `dubbo-spring-boot-starter`, manages the core dubbo dependencies, identifies configuration items starting with `dubbo.` in application.properties or application.yml, and scans annotations like @DubboService. +* `dubbo-spring-boot-starter3`, manages the same core dubbo dependencies as dubbo-spring-boot-starter, supports Spring Boot version 3.2. +* `dubbo-nacos-spring-boot-starter`, manages nacos-client and other dependencies to introduce when using Nacos as the registry and configuration center. +* `dubbo-zookeeper-spring-boot-starter`, manages zookeeper, curator and other dependencies to introduce when using Zookeeper as the registry and configuration center (for Zookeeper server version 3.4 and below). +* `dubbo-zookeeper-curator5-spring-boot-starter`, manages zookeeper, curator5 and other dependencies to introduce when using Zookeeper as the registry and configuration center. +* `dubbo-sentinel-spring-boot-starter`, manages sentinel and other dependencies to introduce when using Sentinel for rate limiting and degradation. +* `dubbo-seata-spring-boot-starter`, manages seata and other dependencies to introduce when using Seata as a distributed transaction solution. +* `dubbo-observability-spring-boot-starter`, adding this dependency will automatically enable the built-in metrics collection of Dubbo, which can be used for subsequent monitoring systems like Prometheus and Grafana. +* `dubbo-tracing-brave-spring-boot-starter`, manages brave/zipkin, micrometer, and related dependencies, uses Brave/Zipkin as Tracer, and exports Trace information to Zipkin. +* `dubbo-tracing-otel-otlp-spring-boot-starter`, manages brave/zipkin, micrometer, and related dependencies, uses OpenTelemetry as Tracer, and exports Trace information to OTlp Collector. +* `dubbo-tracing-otel-zipkin-spring-boot-starter`, manages brave/zipkin, micrometer, and related dependencies, uses OpenTelemetry as Tracer, and exports Trace information to Zipkin. -{{% alert title="注意" color="info" %}} -* 关于每个 starter 适配的第三方组件版本,请查看 [组件版本映射表](/en/overview/mannual/java-sdk/versions/#版本说明)。 -* 每个 starter 都有对应的 application.yml 配置项,请跟随上文 [配置项列表](./#配置示例) 了解使用细节。 +{{% alert title="Note" color="info" %}} +* For the versions of third-party components compatible with each starter, please refer to the [Component Version Mapping Table](/en/overview/mannual/java-sdk/versions/#版本说明). +* Each starter has corresponding application.yml configuration items; please refer to the above [Configuration Items List](./#配置示例) for detailed usage. {{% /alert %}} + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/xml.md b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/xml.md index 5a9e3e24183f..c5e4063dbeab 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/config/spring/xml.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/config/spring/xml.md @@ -3,20 +3,20 @@ aliases: - /en/docs3-v2/java-sdk/reference-manual/config/xml/ - /en/docs3-v2/java-sdk/reference-manual/config/xml/ - /en/overview/mannual/java-sdk/reference-manual/config/xml/ -description: 以 Spring XML 开发 Dubbo 应用 -linkTitle: XML 配置 -title: XML 配置 +description: Developing Dubbo applications with Spring XML +linkTitle: XML Configuration +title: XML Configuration type: docs weight: 4 --- -Dubbo 有基于 Spring Schema 扩展的自定义配置组件,XML 支持的配置项与 [配置参考手册](../properties) 中描述的一一对。本文使用的示例请参考 [dubbo-samples-spring-xml](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-spring-xml) +Dubbo has a custom configuration component based on Spring Schema, and the configuration options supported by XML correspond to those described in the [configuration reference manual](../properties). Please refer to the examples used in this article at [dubbo-samples-spring-xml](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-spring-xml). -## XML完整示例 -### 服务提供者 +## Complete XML Example +### Service Provider -#### 定义服务接口 +#### Define Service Interface DemoService.java: @@ -28,7 +28,7 @@ public interface DemoService { } ``` -#### 在服务提供方实现接口 +#### Implement Interface in Service Provider DemoServiceImpl.java: @@ -43,7 +43,7 @@ public class DemoServiceImpl implements DemoService { } ``` -#### 用 Spring 配置声明暴露服务 +#### Declare Service Exposure with Spring Configuration ```xml @@ -67,7 +67,7 @@ public class DemoServiceImpl implements DemoService { ``` -#### 加载 Spring 配置 +#### Load Spring Configuration ```java public class Application { @@ -82,9 +82,9 @@ public class Application { } ``` -### 服务消费者 +### Service Consumer -#### 通过 Spring 配置引用远程服务 +#### Reference Remote Service through Spring Configuration ```xml @@ -104,7 +104,7 @@ public class Application { ``` -#### 加载 Spring 配置,并调用远程服务 +#### Load Spring Configuration and Call Remote Service ```java public class Application { @@ -121,17 +121,17 @@ public class Application { } ``` -## 更多示例 +## More Examples -### 版本与分组 +### Version and Group ```xml ``` -### 集群容错 -配置 failover 重试次数: +### Cluster Fault Tolerance +Configure failover retry count: ```xml @@ -141,21 +141,21 @@ public class Application {
``` -### 多协议 +### Multiple Protocols ```xml - + - + - + ``` -### 多注册中心 +### Multiple Registries ```xml - + - + - + ``` -### 全局默认值 -指定全局默认超时时间,多所有服务生效: +### Global Default Values +Specify global default timeout, effective for all services: ```xml ``` -基于分组的默认值: +Based on group default values: ```xml @@ -197,3 +197,4 @@ public class Application { + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/1.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/1.md index dd51c90f6be0..d20e25330d98 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/1.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/1.md @@ -3,27 +3,27 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/1/ - /en/docs3-v2/java-sdk/faq/0/1/ - /en/overview/mannual/java-sdk/faq/0/1/ -description: 0-1 - 线程池资源枯竭 -linkTitle: 0-1 - 线程池资源枯竭 -title: 0-1 - 线程池资源枯竭 +description: 0-1 - Thread Pool Resource Exhaustion +linkTitle: 0-1 - Thread Pool Resource Exhaustion +title: 0-1 - Thread Pool Resource Exhaustion type: docs weight: 1 --- -服务端的线程资源耗尽了。 -默认情况下,Dubbo 服务端的业务线程数是 200 个。如果多个并发请求量超过了 200,就会拒绝新的请求,抛出此错误。 +The server's thread resources have been exhausted. +By default, there are 200 business threads on the Dubbo server. If the number of concurrent requests exceeds 200, new requests will be rejected, and this error will be thrown. -### 可能的原因 -1. Consumer 的并发请求量太大,导致 Provider 端创建的线程数量超限。 -2. 可能 Provider 端在执行业务的时候,由于业务调用外部应用接口,导致线程出现阻塞,从而导致线程池回收不了线程。 +### Possible Causes +1. The consumer's concurrent request volume is too high, causing the number of threads created on the provider side to exceed the limit. +2. The provider side may have blocking threads due to business calls to external application interfaces while executing the business. -### 排查和解决步骤 -* 开启 Dubbo 的访问日志功能,排查是否有短时间内大量调用 RPC 服务的情况。 -* 通过 `jps` 和 `jstack` 指令检查线程池中各个线程的状态,看下是否有业务调用外部应用接口造成阻塞。 -* 如果是 Consumer 的并发请求量太大,那么调整 Provider 端的 `dubbo.provider.threads` 参数,将 Dubbo 的线程池的数目调大。 -* 如果 Provider 业务的 QPS 实在太大,目前的服务器数目处理不完,那么增加 Provider 端服务器的数量,让更多的服务器分担压力。 +### Troubleshooting and Resolution Steps +* Enable Dubbo's access log feature to check for a large number of RPC service calls in a short period. +* Use `jps` and `jstack` commands to check the status of various threads in the thread pool to see if there are blocking issues caused by business calls to external application interfaces. +* If the consumer's concurrent request volume is too high, adjust the provider side's `dubbo.provider.threads` parameter to increase the number of Dubbo's thread pool. +* If the QPS of the provider's business is indeed too high and the current number of servers cannot handle it, increase the number of provider servers to share the load. +> This error code FAQ page references Kongming's [“Common Dubbo Errors and Solutions”](https://github.com/StabilityMan/StabilityGuide/blob/master/docs/diagnosis/plugin/rpc/%E7%B3%BB%E7%BB%9F%E7%A8%B3%E5%AE%9A%E6%80%A7%E2%80%94%E2%80%94Dubbo%E5%B8%B8%E8%A7%81%E9%94%99%E8%AF%AF%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95.md). +The cited article is licensed under [CC-BY-4.0](http://creativecommons.org/licenses/by/4.0/), granting rights for compilation. Special thanks to the original author. -> 这个错误码的 FAQ 页面参考了空冥同学的 [《Dubbo 常见错误及解决方法》](https://github.com/StabilityMan/StabilityGuide/blob/master/docs/diagnosis/plugin/rpc/%E7%B3%BB%E7%BB%9F%E7%A8%B3%E5%AE%9A%E6%80%A7%E2%80%94%E2%80%94Dubbo%E5%B8%B8%E8%A7%81%E9%94%99%E8%AF%AF%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95.md) 。 -所引文章通过 [CC-BY-4.0](http://creativecommons.org/licenses/by/4.0/) 协议赋予了汇编的权利。在此向原作者表示感谢。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/10.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/10.md index 9f8e3789b8fd..8321ccc84af8 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/10.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/10.md @@ -3,23 +3,20 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/10/ - /en/docs3-v2/java-sdk/faq/0/10/ - /en/overview/mannual/java-sdk/faq/0/10/ -description: 0-10 - 当前调用不在支持 -linkTitle: 0-10 - 当前调用不在支持 -title: 0-10 - 当前调用不在支持 +description: 0-10 - Current call is not supported +linkTitle: 0-10 - Current call is not supported +title: 0-10 - Current call is not supported type: docs weight: 10 --- +### Possible Causes +The method currently being called may have been deprecated or marked with `@Deprecated`, which does not affect the execution result. +### Troubleshooting and Resolution Steps +Please use other alternative API methods. -### 可能的原因 - -当前调用的方法可能已经被弃用或声明了 `@Deprecated`,不影响执行结果。 - -### 排查和解决步骤 - -请使用其它可替代的 API 方法。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/11.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/11.md index 272de626bc50..628d74900803 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/11.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/11.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/11/ - /en/docs3-v2/java-sdk/faq/0/11/ - /en/overview/mannual/java-sdk/faq/0/11/ -description: 0-11 - 服务停止失败 -linkTitle: 0-11 - 服务停止失败 -title: 0-11 - 服务停止失败 +description: 0-11 - Service Stopping Failed +linkTitle: 0-11 - Service Stopping Failed +title: 0-11 - Service Stopping Failed type: docs weight: 11 --- @@ -16,10 +16,11 @@ weight: 11 -### 可能的原因 +### Possible Causes -连接没有及时关闭或内存不足,导致服务在停止时会出现一些异常。 +Connections are not closed in a timely manner, or insufficient memory may cause some exceptions when the service stops. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps + +Close the connection after the response content is completed. -在响应内容完成后进行关闭连接。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/12.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/12.md index a589cdf8a3ba..a2d120bf7061 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/12.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/12.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/12/ - /en/docs3-v2/java-sdk/faq/0/12/ - /en/overview/mannual/java-sdk/faq/0/12/ -description: 0-12 - 未知异常 -linkTitle: 0-12 - 未知异常 -title: 0-12 - 未知异常 +description: 0-12 - Unknown Exception +linkTitle: 0-12 - Unknown Exception +title: 0-12 - Unknown Exception type: docs weight: 12 --- @@ -14,12 +14,13 @@ weight: 12 -未知异常,一般为API使用或配置异常 +Unknown exceptions are generally caused by API usage or configuration issues. -### 可能的原因 +### Possible Causes -转码异常、不支持的加解密方法等等 +Encoding exceptions, unsupported encryption and decryption methods, etc. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps + +You can locate the lines of business code based on the stack trace information. -可根据堆栈信息,进行业务代码行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/13.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/13.md index ef70771e6779..6e9710531c34 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/13.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/13.md @@ -3,23 +3,20 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/13/ - /en/docs3-v2/java-sdk/faq/0/13/ - /en/overview/mannual/java-sdk/faq/0/13/ -description: 0-13 - 指标收集器发生异常 -linkTitle: 0-13 - 指标收集器发生异常 -title: 0-13 - 指标收集器发生异常 +description: 0-13 - An exception occurs in the metrics collector +linkTitle: 0-13 - An exception occurs in the metrics collector +title: 0-13 - An exception occurs in the metrics collector type: docs weight: 13 --- +### Possible Causes +Errors occurred during the push of metric data, the server being pushed is unreachable or there are some configuration errors, currently supporting Prometheus. +### Troubleshooting and Resolution Steps +Please refer to the configuration item reference manual [Configuration Item Reference Manual](/en/overview/mannual/java-sdk/reference-manual/config/properties/). -### 可能的原因 - -指标数据在推送过程中发生错误,推送的服务器连接不上或一些配置错误,目前支持 Prometheus。 - -### 排查和解决步骤 - -请参考配置项参考手册[配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/)。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/14.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/14.md index 05ef19696b8d..b71f8b4b62b9 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/14.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/14.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/14/ - /en/docs3-v2/java-sdk/faq/0/14/ - /en/overview/mannual/java-sdk/faq/0/14/ -description: 0-14 - 监控异常 -linkTitle: 0-14 - 监控异常 -title: 0-14 - 监控异常 +description: 0-14 - Monitoring Exceptions +linkTitle: 0-14 - Monitoring Exceptions +title: 0-14 - Monitoring Exceptions type: docs weight: 14 --- @@ -13,15 +13,13 @@ weight: 14 +Used to count the number of RPC calls and the duration of calls, the extension interface is MonitorFactory, and the corresponding implementation class is DubboMonitorFactory. -用来统计 RPC 调用次数和调用耗时时间,扩展接口为 MonitorFactory,对应的实现类为 DubboMonitorFactroy。 +### Possible Causes +Users can implement the MonitorFactory extension interface at this layer to achieve custom monitoring statistics strategies. In the implementation class of the custom monitoring statistics strategy, a runtime business exception has occurred. -### 可能的原因 +### Troubleshooting and Resolution Steps -用户可以实现该层的 MonitorFactory 扩展接口,实现自定义监控统计策略。 -在自定义监控统计策略的实现类,发生了业务运行时异常。 +Check the business class of the `org.apache.dubbo.monitor.MonitorFactory` interface; the implementation method may contain logical errors in the code. -### 排查和解决步骤 - -检查 `org.apache.dubbo.monitor.MonitorFactory` 接口的业务类,实现方法可能存在代码逻辑错误。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/15.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/15.md index f660665af79e..ac9d40156bb6 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/15.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/15.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/15/ - /en/docs3-v2/java-sdk/faq/0/15/ - /en/overview/mannual/java-sdk/faq/0/15/ -description: 0-15 - 加载扩展类时发生异常 -linkTitle: 0-15 - 加载扩展类时发生异常 -title: 0-15 - 加载扩展类时发生异常 +description: 0-15 - Exception Occurred When Loading Extension Class +linkTitle: 0-15 - Exception Occurred When Loading Extension Class +title: 0-15 - Exception Occurred When Loading Extension Class type: docs weight: 15 --- @@ -16,14 +16,15 @@ weight: 15 -### 可能的原因 +### Possible Causes -1. `clazz` 类并没有实现当前扩展点的接口类。 -2. 扩展名可能是个接口或者不存在。 +1. The `clazz` class does not implement the interface class of the current extension point. +2. The extension name may be an interface or does not exist. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps -1. 检查扩展类声明,并没有与之相匹配的扩展实现类。 -2. 扩展实现类需实现扩展点接口类以及方法。 +1. Check the declaration of the extension class and ensure there is a matching extension implementation class. +2. The extension implementation class must implement the extension point interface class and methods.

+ diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/16.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/16.md index 61edaebd6614..aac71377b9f4 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/16.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/16.md @@ -3,25 +3,22 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/16/ - /en/docs3-v2/java-sdk/faq/0/16/ - /en/overview/mannual/java-sdk/faq/0/16/ -description: 0-16 - 没有可用的执行器 -linkTitle: 0-16 - 没有可用的执行器 -title: 0-16 - 没有可用的执行器 +description: 0-16 - No available executor +linkTitle: 0-16 - No available executor +title: 0-16 - No available executor type: docs weight: 16 --- +### Possible Causes +The internal executor is unavailable and thus returns null. +### Troubleshooting and Resolution Steps - -### 可能的原因 - -内部执行器不可用,此时返回空。 - -### 排查和解决步骤 - -不需要进行干预,dubbo 内部会执行`createExecutorIfAbsent` 方法构建一个新的执行器。 +No intervention is needed; Dubbo will internally execute the `createExecutorIfAbsent` method to construct a new executor.

+ diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/17.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/17.md index 70ffd70e0f2c..ed9696252e02 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/17.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/17.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/17/ - /en/docs3-v2/java-sdk/faq/0/17/ - /en/overview/mannual/java-sdk/faq/0/17/ -description: 0-17 - 执行器在关闭时发生未知异常 -linkTitle: 0-17 - 执行器在关闭时发生未知异常 -title: 0-17 - 执行器在关闭时发生未知异常 +description: 0-17 - An unknown exception occurs when the executor is shutting down +linkTitle: 0-17 - An unknown exception occurs when the executor is shutting down +title: 0-17 - An unknown exception occurs when the executor is shutting down type: docs weight: 17 --- @@ -16,10 +16,11 @@ weight: 17 -### 可能的原因 +### Possible Causes -可能使用了自定义的执行器,在编写销毁方法时,产生了异常。 +A custom executor may have been used, and an exception was raised when writing the destroy method. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps + +Check whether a custom implementation of `org.apache.dubbo.common.threadpool.manager.ExecutorRepository` is used and inspect the custom `shutdown` method. -检查是否自定义实现 `org.apache.dubbo.common.threadpool.manager.ExecutorRepository`,检查自定义的 `shutdown` 方法。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/18.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/18.md index 663371be4f49..a37f212aea6c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/18.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/18.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/18/ - /en/docs3-v2/java-sdk/faq/0/18/ - /en/overview/mannual/java-sdk/faq/0/18/ -description: 0-18 - 线程池执行器被错误使用 -linkTitle: 0-18 - 线程池执行器被错误使用 -title: 0-18 - 线程池执行器被错误使用 +description: 0-18 - Thread pool executor is misused +linkTitle: 0-18 - Thread pool executor is misused +title: 0-18 - Thread pool executor is misused type: docs weight: 18 --- @@ -16,10 +16,11 @@ weight: 18 -### 可能的原因 +### Possible Causes -自定义设置了线程数量,系统内部发生了未知异常。 +The number of threads is customized, and an unknown exception occurs within the system. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps + +You can analyze the stack information using some third-party tools or `jstack [PID] > jstack.log` to locate the issue. -可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/19.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/19.md index 20a210d89a89..72dd1c0fceeb 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/19.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/19.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/19/ - /en/docs3-v2/java-sdk/faq/0/19/ - /en/overview/mannual/java-sdk/faq/0/19/ -description: 0-19 - 处理任务时发生异常 -linkTitle: 0-19 - 处理任务时发生异常 -title: 0-19 - 处理任务时发生异常 +description: 0-19 - Exception Occurred While Processing Task +linkTitle: 0-19 - Exception Occurred While Processing Task +title: 0-19 - Exception Occurred While Processing Task type: docs weight: 19 --- @@ -16,10 +16,11 @@ weight: 19 -### 可能的原因 +### Possible Causes -自定义业务类处理逻辑不当。 +Improper handling of custom business logic. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps + +You can analyze the stack information using some third-party tools or `jstack [PID] > jstack.log` to locate the issue. -可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/2.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/2.md index 66488af7ac38..99e2f258ff23 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/2.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/2.md @@ -3,16 +3,17 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/2/ - /en/docs3-v2/java-sdk/faq/0/2/ - /en/overview/mannual/java-sdk/faq/0/2/ -description: 0-2 - 非法属性值 -linkTitle: 0-2 - 非法属性值 -title: 0-2 - 非法属性值 +description: 0-2 - Illegal Property Value +linkTitle: 0-2 - Illegal Property Value +title: 0-2 - Illegal Property Value type: docs weight: 2 --- -### 可能的原因 -这个提示是指用户配置的值与属性本身所需的数据类型并不匹配。比如 `dubbo.comsumer.threads` 属性只能接受数值属性,但是用户所输入的值混入了字母。 +### Possible Causes +This prompt indicates that the value configured by the user does not match the data type required by the attribute itself. For example, the `dubbo.consumer.threads` property can only accept numeric values, but the value entered by the user includes letters. + +### Troubleshooting and Resolution Steps +Refer to the [Configuration Item Reference Manual](/en/overview/mannual/java-sdk/reference-manual/config/properties/) to find the erroneous configuration item, check the specified type of that item, and verify if there is any type inconsistency. -### 排查和解决步骤 -根据[配置项参考手册](/en/overview/mannual/java-sdk/reference-manual/config/properties/),查找出错的配置项,检查该项指定的类型,检查是否出现类型不一致的情况。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/20.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/20.md index 900b134d9fdd..51e05855a292 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/20.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/20.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/20/ - /en/docs3-v2/java-sdk/faq/0/20/ - /en/overview/mannual/java-sdk/faq/0/20/ -description: 0-20 - 存储堆栈信息时发生异常 -linkTitle: 0-20 - 存储堆栈信息时发生异常 -title: 0-20 - 存储堆栈信息时发生异常 +description: 0-20 - Exception occurs when storing stack information +linkTitle: 0-20 - Exception occurs when storing stack information +title: 0-20 - Exception occurs when storing stack information type: docs weight: 20 --- @@ -16,12 +16,13 @@ weight: 20 -### 可能的原因 +### Possible Causes -1. JVM设置了参数 `-XX:+DisableAttachMechanism` -2. 设置了系统不存在的堆栈转储路径,不存在情况,系统会尝试进行创建,创建时发生了 `SecurityException`, 可能是没有权限。 +1. The JVM has set the parameter `-XX:+DisableAttachMechanism` +2. The specified stack dump path does not exist; in this case, the system will attempt to create it, and a `SecurityException` may occur during creation, possibly due to lack of permissions. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps + +1. Check if the JVM has set the above parameter. +2. Check if the account running the service has permissions to create folders. -1. 检查 JVM 是否设置了如上参数。 -2. 检查当前启动服务的账号,是否有权限进行创建文件夹。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/21.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/21.md index 97e6a6941ee8..bfead4d35923 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/21.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/21.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/21/ - /en/docs3-v2/java-sdk/faq/0/21/ - /en/overview/mannual/java-sdk/faq/0/21/ -description: 0-21 - 构建的实例过多 -linkTitle: 0-21 - 构建的实例过多 -title: 0-21 - 构建的实例过多 +description: 0-21 - Too many instances are built +linkTitle: 0-21 - Too many instances are built +title: 0-21 - Too many instances are built type: docs weight: 21 --- @@ -15,10 +15,11 @@ weight: 21 -### 可能的原因 +### Possible Causes -一般指 `org.apache.dubbo.common.timer.HashedWheelTimer` 创建的实例过多。 +It generally refers to too many instances created by `org.apache.dubbo.common.timer.HashedWheelTimer`. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps + +It does not affect the construction of instances, but there may be a risk of memory leaks. -不影响实例的构建,可能存在内存泄露的风险。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/22.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/22.md index b1f19436e128..56f0a6c17837 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/22.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/22.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/22/ - /en/docs3-v2/java-sdk/faq/0/22/ - /en/overview/mannual/java-sdk/faq/0/22/ -description: 0-22 - 输入输出流异常 -linkTitle: 0-22 - 输入输出流异常 -title: 0-22 - 输入输出流异常 +description: 0-22 - Input and Output Stream Exception +linkTitle: 0-22 - Input and Output Stream Exception +title: 0-22 - Input and Output Stream Exception type: docs weight: 22 --- @@ -16,16 +16,17 @@ weight: 22 -### 可能的原因 +### Possible Causes -1. 读取不再可用的本地文件。 -2. 尝试读取/写入文件但没有权限。 -3. 尝试写入文件但磁盘空间不再可用。 +1. Reading a local file that is no longer available. +2. Attempting to read/write a file without permission. +3. Attempting to write to a file but no disk space is available. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps -1. 检查本地文件是否存在。 -2. 检查文件权限。 -3. 检查磁盘空间。 +1. Check if the local file exists. +2. Check file permissions. +3. Check disk space. + +You can analyze the stack trace information with some third-party tools or by using `jstack [PID] > jstack.log` for diagnosis. -可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/23.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/23.md index 07053e2934bd..f56e787fbd56 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/23.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/23.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/23/ - /en/docs3-v2/java-sdk/faq/0/23/ - /en/overview/mannual/java-sdk/faq/0/23/ -description: 0-23 - 序列化数据转换异常 -linkTitle: 0-23 - 序列化数据转换异常 -title: 0-23 - 序列化数据转换异常 +description: 0-23 - Serialization data conversion exception +linkTitle: 0-23 - Serialization data conversion exception +title: 0-23 - Serialization data conversion exception type: docs weight: 23 --- @@ -16,14 +16,15 @@ weight: 23 -### 可能的原因 +### Possible Causes -1. 待序列化数据中存在循环引用,导致堆栈溢出。 -2. 引用的 jar 包版本低或存在兼容性问题。 +1. There are circular references in the data to be serialized, leading to a stack overflow. +2. The referenced jar package version is low or has compatibility issues. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps -1. 如使用 FastJson,去掉 `SerializerFeature.DisableCircularReferenceDetec` -2. 检查下或升级版本进行尝试。 +1. If using FastJson, remove `SerializerFeature.DisableCircularReferenceDetect` +2. Check or upgrade the version for testing. + +You can analyze stack information using some third-party tools or by running `jstack [PID] > jstack.log` for troubleshooting. -可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/24.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/24.md index 5e4076f70056..d0a5c325e66f 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/24.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/24.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/24/ - /en/docs3-v2/java-sdk/faq/0/24/ - /en/overview/mannual/java-sdk/faq/0/24/ -description: 0-24 - 覆盖字段值异常 -linkTitle: 0-24 - 覆盖字段值异常 -title: 0-24 - 覆盖字段值异常 +description: 0-24 - Exception of Overriding Field Values +linkTitle: 0-24 - Exception of Overriding Field Values +title: 0-24 - Exception of Overriding Field Values type: docs weight: 24 --- @@ -16,12 +16,13 @@ weight: 24 -### 可能的原因 +### Possible Causes -1. 实体类未设置 setter/getter 方法。 -2. 可能存在嵌套的属性。 +1. The entity class does not have setter/getter methods set. +2. There may be nested properties. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps + +1. Check the entity class and set the setter/getter methods. +2. Check if nested annotations are used based on the stack trace information. -1. 检查实体类并设置 setter/getter 方法。 -2. 根据堆栈信息,检查是否使用嵌套注解。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/25.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/25.md index 778c5197de9a..39172348d9ca 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/25.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/25.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/25/ - /en/docs3-v2/java-sdk/faq/0/25/ - /en/overview/mannual/java-sdk/faq/0/25/ -description: 0-25 - 加载映射错误 -linkTitle: 0-25 - 加载映射错误 -title: 0-25 - 加载映射错误 +description: 0-25 - Load Mapping Error +linkTitle: 0-25 - Load Mapping Error +title: 0-25 - Load Mapping Error type: docs weight: 25 --- @@ -16,11 +16,12 @@ weight: 25 -### 可能的原因 +### Possible Causes -文件访问权限不足 +Insufficient file access permissions -### 排查和解决步骤 +### Troubleshooting and Resolution Steps + +Check file permissions. +You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information for diagnosis. -检查文件权限。 -可通过一些第三方的工具或者 `jstack [PID] > jstack.log` 分析堆栈信息,进行定位。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/26.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/26.md index 9b15c8da723e..cb20b407721e 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/26.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/26.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/26/ - /en/docs3-v2/java-sdk/faq/0/26/ - /en/overview/mannual/java-sdk/faq/0/26/ -description: 0-26 - 元数据发布服务时的警告信息 -linkTitle: 0-26 - 元数据发布服务时的警告信息 -title: 0-26 - 元数据发布服务时的警告信息 +description: 0-26 - Warning message when publishing metadata service +linkTitle: 0-26 - Warning message when publishing metadata service +title: 0-26 - Warning message when publishing metadata service type: docs weight: 26 --- @@ -15,10 +15,11 @@ weight: 26 -### 可能的原因 +### Possible Causes -元数据在存储接口与应用的映射关系时,显示的提醒类消息。 +The metadata prompts warning messages when storing the mapping relationship between the interface and the application. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps + +Generally, you can analyze based on the stack information, or you may choose not to handle it. -一般可根据堆栈信息进行分析,也可不处理。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/27.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/27.md index a04b06da7151..ff2de85e1577 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/27.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/27.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/27/ - /en/docs3-v2/java-sdk/faq/0/27/ - /en/overview/mannual/java-sdk/faq/0/27/ -description: 0-27 - 线程池隔离配置异常 -linkTitle: 0-27 - 线程池隔离配置异常 -title: 0-27 - 线程池隔离配置异常 +description: 0-27 - Thread Pool Isolation Configuration Exception +linkTitle: 0-27 - Thread Pool Isolation Configuration Exception +title: 0-27 - Thread Pool Isolation Configuration Exception type: docs weight: 27 --- @@ -15,10 +15,11 @@ weight: 27 -### 可能的原因 +### Possible Causes -未开启应用的线程池隔离能力,但是却在 `ServiceConfig` 中配置了隔离的线程池信息。 +The application's thread pool isolation capability is not enabled, but isolation thread pool information is configured in `ServiceConfig`. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps + +Enable the application's thread pool isolation capability: `dubbo.application.executor-management-mode=isolation` -配置开启应用的线程池隔离能力:`dubbo.application.executor-management-mode=isolation` diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/28.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/28.md index e33159430380..eaa2e26a5fdc 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/28.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/28.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/28/ - /en/docs3-v2/java-sdk/faq/0/28/ - /en/overview/mannual/java-sdk/faq/0/28/ -description: 0-28 - 操作了可能会引起危险的行为 -linkTitle: 0-28 - 危险的行为 -title: 0-28 - 操作了可能会引起危险的行为 +description: 0-28 - Actions that may cause dangerous behavior +linkTitle: 0-28 - Dangerous Actions +title: 0-28 - Actions that may cause dangerous behavior type: docs weight: 28 --- @@ -15,11 +15,12 @@ weight: 28 -### 可能的原因 +### Possible Causes -你执行了以下操作之一: -* 尝试或已经调整了 accesslog 的输出位置 +You have performed one of the following actions: +* Attempted to or have adjusted the output location of accesslog -### 排查和解决步骤 +### Troubleshooting and Resolution Steps + +Please check if the `accesslog.fixed.path=true` switch in the application configuration is turned on; if it is not on, it can be ignored. If it is currently on, please confirm whether the action of switching the accesslog path was executed by a trusted person to avoid potential security risks. -请检查应用配置中的 `accesslog.fixed.path=true` 开关是否处于开启状态,如未开启则可忽略;如果当前是开启状态,则请确认是否 acesslog 路径切换的行为是否为可信任的人所执行,以避免可能的安全风险。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/29.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/29.md index 732ffcb46245..dccd6e46cc3c 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/29.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/29.md @@ -3,22 +3,22 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/29/ - /en/docs3-v2/java-sdk/faq/0/29/ - /en/overview/mannual/java-sdk/faq/0/29/ -description: 0-29 - 未找到Tracer依赖 -linkTitle: 0-29 - 未找到Tracer依赖 -title: 0-29 - 未找到Tracer依赖 +description: 0-29 - Tracer dependency not found +linkTitle: 0-29 - Tracer dependency not found +title: 0-29 - Tracer dependency not found type: docs weight: 29 --- -### 可能的原因 +### Possible Causes -你已在配置文件中开启了tracing,但未找到Tracer依赖。 +You have enabled tracing in the configuration file, but the Tracer dependency was not found. -目前Tracer支持两种,OpenTelemetry和Brave。 +Currently, there are two supported Tracers, OpenTelemetry and Brave. -### 排查和解决步骤 +### Troubleshooting and Resolution Steps -选择一个Tracer依赖到你的项目中: +Choose one Tracer dependency for your project: ```xml @@ -37,3 +37,4 @@ weight: 29 true ``` + diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/3.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/3.md index 7a6f674d5279..7f377056b642 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/3.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/3.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/3/ - /en/docs3-v2/java-sdk/faq/0/3/ - /en/overview/mannual/java-sdk/faq/0/3/ -description: 0-3 - 无法访问缓存路径 -linkTitle: 0-3 - 无法访问缓存路径 -title: 0-3 - 无法访问缓存路径 +description: 0-3 - Unable to access cache path +linkTitle: 0-3 - Unable to access cache path +title: 0-3 - Unable to access cache path type: docs weight: 3 --- @@ -15,7 +15,7 @@ weight: 3 -其它模块复用了 Common 层的基于文件的缓存机制(目前是元数据模块),而 Common 层的文件缓存机制无法访问它指定的目录。 +Other modules reuse the file-based caching mechanism from the Common layer (currently the metadata module), while the file cache mechanism in the Common layer cannot access its specified directory. ``` 2022-08-29 00:35:00,189 ERROR [org.apache.dubbo.common.cache.FileCacheStoreFactory:?] - [DUBBO] Cache store path can't be created: , dubbo version: , current host: 10.0.1.1, error code: 0-3. This may be caused by inaccessible of cache path, go to https://dubbo.apache.org/faq/0/3 to find instructions. @@ -31,11 +31,12 @@ java.nio.file.FileAlreadyExistsException: [Path] ... ``` -### 可能的原因 -1. 多个 Dubbo 进程(或其他 Java 进程)使用了同一个缓存文件。 -2. 由于缓存文件所在目录的文件系统权限问题,导致读写失败。 +### Possible Causes +1. Multiple Dubbo processes (or other Java processes) are using the same cache file. +2. Read and write failures due to file system permission issues in the directory containing the cache file. + +### Diagnosis and Resolution Steps +1. Find the inaccessible directory from the actual exception shown below and determine its file access permissions. +2. Check if there are other Dubbo instances accessing this path. +3. Try configuring **Java System Properties (Java system properties configured with -D)** `dubbo.meta.cache.filePath` and `dubbo.mapping.cache.filePath`, specifying a directory that the current user can fully control. -### 排查和解决步骤 -1. 根据下面显示的实际异常找到访问不了的目录,确定下它的文件访问权限。 -2. 确定下是否有别的 Dubbo 实例正在访问这个路径。 -3. 尝试配置 **Java System Property(用 -D 配置的 Java 系统属性)** `dubbo.meta.cache.filePath` 和 `dubbo.mapping.cache.filePath`,将它指定成一个当前用户能够完全控制的目录下。 diff --git a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/4.md b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/4.md index a89c49e24d48..0f9d42096784 100644 --- a/content/en/overview/mannual/java-sdk/reference-manual/faq/0/4.md +++ b/content/en/overview/mannual/java-sdk/reference-manual/faq/0/4.md @@ -3,9 +3,9 @@ aliases: - /en/docs3-v2/java-sdk/faq/0/4/ - /en/docs3-v2/java-sdk/faq/0/4/ - /en/overview/mannual/java-sdk/faq/0/4/ -description: 0-4 - 缓存条目超限 -linkTitle: 0-4 - 缓存条目超限 -title: 0-4 - 缓存条目超限 +description: 0-4 - Cache Entry Limit Exceeded +linkTitle: 0-4 - Cache Entry Limit Exceeded +title: 0-4 - Cache Entry Limit Exceeded type: docs weight: 4 --- @@ -14,13 +14,13 @@ weight: 4 -其它模块复用了 Common 层的基于文件的缓存机制(目前是元数据模块),而 Common 层的文件缓存机制 “发觉” 条目超限。 +Other modules reuse the file-based caching mechanism of the Common layer (currently the metadata module), and the Common layer's file cache mechanism has "detected" that the entry limit has been exceeded. -### 可能的原因 -用户不合理地配置了 **Java System Property** (用 -D 配置的 Java 系统属性) `dubbo.mapping.cache.entrySize` 或者 `dubbo.meta.cache.entrySize` +### Possible Reasons +Users have irrationally configured the **Java System Property** (configured with -D) `dubbo.mapping.cache.entrySize` or `dubbo.meta.cache.entrySize`. -**默认值** +**Default Values** - - - -
- - - - - - - - -``` - - - -再次重启服务器,并访问 "http://localhost:8080" 时,将会看到 swagger UI 页面的展示: - - - -![swagger-ui](/imgs/blog/swagger-ui.png) - - - -通过 Swagger UI 可以很方便的浏览当前服务器提供的 REST 服务的文档信息,甚至可以直接调用来做服务测试。以 '/api/users/{id}' 为例,测试结果如下图所示: - - - -![swagger-ui-execute](/imgs/blog/swagger-ui-execute.png) - - - -## 总结 - -本文主要关注了在 Dubbo 中支持 REST 协议的情况。首先探索了 REST 概念的起源,澄清了 REST 是一种适合互联网的软件架构风格,进一步的说明了 REST 风格的架构可以与 HTTP 协议无关,但是 HTTP 协议的确是 REST 风格架构的最常用甚至是最佳的组合和搭档。然后讨论了如何在 Dubbo 中开发 REST HTTP 的几种典型用法,其中包括了通过不同的配置,如传统的 Spring XML,完全通过 annotation 来配置两种典型的用法,本文中没有涉及到的还有纯 API 编程方式,Spring Boot 配置方式也是完全可以的,因为篇幅原因没有提及;还讨论了如何通过不同的 REST server 来暴露 REST HTTP 服务,包括了 embedded tomcat,netty,以及外置的 servlet 容器等几种用法。最后,在外置的 servlet 容器的基础上,进一步的讨论了如何通过 Swagger 暴露 openAPI 以及集成 Swagger UI 的方法。 - -本文没有涉及的内容包含但不限于国际化支持、Dubbo REST 更高阶的注入扩展的用法、以及 Dubbo REST 支持未来的规划。其中 Dubbo REST 扩展的支持可以参考 https://github.com/beiwei30/dubbo-rest-samples/tree/master/extensions 中的演示。以后有机会会开专门的篇幅来探讨更高级的 Swagger 的支持、以及对未来的展望。 - - - - -[^1]: http://en.wikipedia.org/wiki/Roy_Fielding - -[^2]: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm - -[^3]: https://martinfowler.com/articles/richardsonMaturityModel.html - -[^4]: https://github.com/dangdangdotcom/dubbox -[^5]: http://dubbo.apache.org/zh-cn/blog/dubbo-annotation.html -[^6]: https://www.webjars.org/documentation#servlet3 - - diff --git a/content/en/blog/java/demos/dubbo-stub-mock.md b/content/en/blog/java/demos/dubbo-stub-mock.md deleted file mode 100644 index adae8fec8883..000000000000 --- a/content/en/blog/java/demos/dubbo-stub-mock.md +++ /dev/null @@ -1,263 +0,0 @@ ---- -title: "Local Stubs and Local Mocks" -linkTitle: "Local Stubs and Local Mocks" -tags: ["Java"] -date: 2019-10-22 -description: This article introduces the usage of local stubs and local mocks in Dubbo. ---- - - -## Basic Concepts - -A typical RPC calling client relies solely on interface programming for remote calls. Before making a remote call, users often need to pre-process, such as parameter verification. After obtaining the return result, users may need to cache the results or construct fallback data in case of failure, rather than simply throwing exceptions. - -At this point, users can write code similar to the following to handle these scenarios: - -```java -try { - preProcess(); - return service.invoke(...); -} catch (Throwable e) { - return mockValue; -} finally { - postProcess(); -} -``` - - -Similarly, users can use advanced techniques like Aspect-Oriented Programming *AOP* to address the above requirements. Using *Spring AOP*, configurations similar to the following can be completed. Using *AOP* techniques facilitates a cleaner business logic by avoiding unrelated error handling code as seen in the above code. - -```xml - - - - - - - - - - - - - -``` - - -To further facilitate Dubbo development, the framework introduces the concepts of local stubs *Stub* and local mocks *Mock*. The principle of convention over configuration simplifies configurations further, making usage more convenient, achieving *AOP* effects without relying on an external *AOP* framework. - -The working mechanism of local stubs is similar to the **around** advice in *AOP*, while the method of local mocks corresponds to the **after-throwing** advice in *AOP*, meaning local mocks are only executed when a remote call results in an *exception*. The workflow of local stubs and mocks is illustrated below: - -![dubbo-mock-stub-flow](/imgs/blog/dubbo-mock-stub-flow.png) - - -1. The service consumer initiates a call -2. If a local stub exists on the consumer side, it will execute the local stub first -3. The local stub holds the *Proxy* object of the remote service. When it executes, it first runs its own logic (*before*), then initiates the remote call through the *Proxy*, and finally runs its logic again before the return (*after-returning*) -4. If the remote service's *Proxy* object throws an *exception* during execution, the consumer's local mock logic (*after-throwing*) will be executed, returning fallback data to achieve service degradation. - - -## Developing a Local Stub - -Local stubs are provided by users and deployed on the consumer side. A complete example can be found here [^stub-samples]. - -```java -public class DemoServiceStub implements DemoService { // #1 - private static Logger logger = LoggerFactory.getLogger(DemoServiceStub.class); - - private final DemoService demoService; - - public DemoServiceStub(DemoService demoService) { // #2 - this.demoService = demoService; - } - - @Override - public String sayHello(String name) { // #3 - logger.info("before execute remote service, parameter: " + name); // #4 - try { - String result = demoService.sayHello(name); // #5 - logger.info("after execute remote service, result: " + result); // #6 - return result; - } catch (Exception e) { - logger.warn("fail to execute service", e); // #7 - return null; - } - } -} -``` - -To work with the framework, the implementation of the local stub needs to follow some conventions established by the framework: - -1. Local stubs are implementations of the service interface. -2. The implementation of the local stub must provide a copy constructor to allow the framework to inject the remote call's *Proxy* object. -3. Similarly, the local stub must implement all methods from the service interface. In this example, the *sayHello* method needs to be implemented. -4. Before making the actual remote call, the user can perform some operations locally. In this example, it logs the incoming parameter. -5. The real remote call is initiated through the *Proxy* object provided by the framework. -6. After the remote call ends, local code execution can also be added. In this example, it logs the return value of the remote call. -7. If an error occurs, some error recovery actions can also be performed. In this case, the exception is logged. Of course, if a local mock is provided, the logic in *catch* can be omitted. - -Steps 4, 6, and 7 collectively build a concept equivalent to AOP concepts, corresponding to **before**, **after-returning**, and **after-throwing** respectively. - -*DemoServiceStub* runs on the client side. To use the local stub, the property *stub* needs to be configured in *stub-consumer.xml*. This can simply be done by specifying *stub="true"* to tell the Dubbo framework to use the local stub. At this point, the package name of the local stub must match that of the service interface, and the class name must append **Stub** to the service interface's class name. For instance, when the service interface name is *org.apache.dubbo.samples.stub.api.DemoService*, the full class name of the local stub should be *org.apache.dubbo.samples.stub.api.DemoServiceStub*. - -```xml - -``` - -If you do not want to use the default naming rule, you can directly specify the full class name of the local stub through the *stub* property. - -```xml - -``` - -After starting the service side *StubProvider*, run the client *StubConsumer*, and you can verify the local stub's operational results by observing the client's logs. - -```bash -[09/04/19 11:52:21:021 CST] main INFO api.DemoServiceStub: before execute remote service, parameter: dubbo -[09/04/19 11:52:21:021 CST] main INFO api.DemoServiceStub: after execute remote service, result: greeting dubbo -[09/04/19 11:52:21:021 CST] main INFO stub.StubConsumer: result: greeting dubbo -``` - - -## Developing a Local Mock - -Local mocks are typically used for service degradation in case of errors during remote calls. A complete example can be found here [^mock-samples]. - -Here we simulate a timeout by making the service provider's code sleep, thereby executing the local mock to handle fault tolerance. - -```java -public class DemoServiceImpl implements DemoService { - public String sayHello(String name) { - try { - Thread.sleep(5000); // #1 - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "hello " + name; // #2 - } -} -``` - -1. The default timeout in Dubbo is *1000 ms*; sleeping for *5000ms* triggers a timeout exception. -2. Due to the timeout, this result will not be returned to the client, replaced instead with *org.apache.dubbo.remoting.TimeoutException*. - -On the client side, provide a local mock implementation. When a remote call fails, the response returned to the caller is not "hello name" from the server side, but "mock name" instead. - -```java -public class DemoServiceMock implements DemoService { - private static Logger logger = LoggerFactory.getLogger(DemoServiceMock.class); - - public String sayHello(String name) { - logger.warn("about to execute mock: " + DemoServiceMock.class.getSimpleName()); - return "mock " + name; - } -} -``` - -Similarly, to use the local mock, the property *mock* needs to be configured in *mock-consumer.xml*. This is simply done by specifying *mock="true"* to tell the Dubbo framework to use the local mock. At this time, the package name of the local mock must match that of the service interface, and the class name must append **Mock** to the service interface's class name. For a service interface named *org.apache.dubbo.samples.stub.api.DemoService*, the full class name of the local mock should be *org.apache.dubbo.samples.stub.api.DemoServiceMock*. - -```xml - -``` - -If you'd rather not use the default naming convention, you can directly specify the full class name of the local mock via the *mock* property. - -```xml - -``` - -By providing a local mock class, you can exert maximum control over the fault tolerance logic after an error occurs. Sometimes, there's no need for such flexible mechanisms in business, just a request to return a default value. In such cases, implementing a complete local mock becomes overly complicated. Alternatively, when an error occurs online, and the application hasn't packaged the local mock, service degradation needs to be implemented through push rules. The Dubbo framework provides quick solutions for both scenarios, aiding users in rapid service degradation configuration. - -After starting the service-side *MockProvider*, execute *MockConsumer* to view the results: - -```bash -Caused by: org.apache.dubbo.remoting.TimeoutException: Waiting server-side response timeout by scan timer. start time: 2019-04-09 14:20:48.061, end time: 2019-04-09 14:20:49.077, client elapsed: 0 ms, server elapsed: 1015 ms, timeout: 1000 ms, request: Request [id=2, version=2.0.2, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=sayHello, parameterTypes=[class java.lang.String], arguments=[world], attachments={path=org.apache.dubbo.samples.mock.api.DemoService, interface=org.apache.dubbo.samples.mock.api.DemoService, version=0.0.0}]], channel: /30.5.125.99:56433 -> /30.5.125.99:20880 - at org.apache.dubbo.remoting.exchange.support.DefaultFuture.returnFromResponse(DefaultFuture.java:295) - at org.apache.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:191) - at org.apache.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:164) - at org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(DubboInvoker.java:108) - at org.apache.dubbo.rpc.protocol.AbstractInvoker.invoke(AbstractInvoker.java:157) - at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:88) - at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73) - at org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilter.java:49) - at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73) - at org.apache.dubbo.rpc.filter.ConsumerContextFilter.invoke(ConsumerContextFilter.java:54) - at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73) - at org.apache.dubbo.rpc.listener.ListenerInvokerWrapper.invoke(ListenerInvokerWrapper.java:78) - at org.apache.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:56) - at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:80) - ... 5 more -[09/04/19 02:20:49:049 CST] main WARN api.DemoServiceMock: about to execute mock: DemoServiceMock -[09/04/19 02:20:49:049 CST] main INFO mock.MockConsumer: result: mock world -``` - - -The following example illustrates the use of push rules for quick configuration; for more usages, please refer to the official Dubbo user manual [^mock]. By pushing the specified service configuration to the configuration center, dynamic service degradation can be achieved. - -```yaml ---- # 1 -configVersion: v2.7 -scope: service - key: org.apache.dubbo.samples.mock.api.DemoService #2 - enabled: true - configs: - - addresses: [0.0.0.0] - side: consumer #3 - parameters: - mock: return configured-mock-value #4 - ... -``` - -1. Using *Zookeeper* as an example, the path for the rule is /dubbo/config/org.apache.dubbo.samples.mock.api.DemoService/configurators -2. This rule applies to the *org.apache.dubbo.samples.mock.api.DemoService* service -3. This rule applies on the client-side -4. When an error occurs, the service call returns the default value *configured-mock-value* - - -After starting the server-side *MockProvider*, execute the example [^mock-samples] with *Configurator* to complete the service degradation rule configuration, then run *MockConsumer* to see the results: - -```bash -[09/04/19 02:19:01:001 CST] main INFO integration.AbstractConfiguratorListener: [DUBBO] Notification of overriding rule, change type is: MODIFIED, raw config content is: - --- -configVersion: v2.7 -scope: service -key: org.apache.dubbo.samples.mock.api.DemoService -enabled: true -configs: -- addresses: [0.0.0.0] - side: consumer - parameters: - mock: return configured-mock-value -... -, dubbo version: 2.7.1, current host: 30.5.125.99 - -... - -Caused by: org.apache.dubbo.remoting.TimeoutException: Waiting server-side response timeout. start time: 2019-04-09 14:19:03.737, end time: 2019-04-09 14:19:04.741, client elapsed: 1 ms, server elapsed: 1002 ms, timeout: 1000 ms, request: Request [id=2, version=2.0.2, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=sayHello, parameterTypes=[class java.lang.String], arguments=[world], attachments={path=org.apache.dubbo.samples.mock.api.DemoService, interface=org.apache.dubbo.samples.mock.api.DemoService, version=0.0.0}]], channel: /30.5.125.99:56412 -> /30.5.125.99:20880 - at org.apache.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:188) - at org.apache.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:164) - at org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(DubboInvoker.java:108) - at org.apache.dubbo.rpc.protocol.AbstractInvoker.invoke(AbstractInvoker.java:157) - at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:88) - at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73) - at org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilterWrapper.java:49) - at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73) - at org.apache.dubbo.rpc.filter.ConsumerContextFilter.invoke(ConsumerContextFilter.java:54) - at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73) - at org.apache.dubbo.rpc.listener.ListenerInvokerWrapper.invoke(ListenerInvokerWrapper.java:78) - at org.apache.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:56) - at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:80) - ... 5 more -[09/04/19 02:19:04:004 CST] main INFO mock.MockConsumer: result: configured-mock-value -``` - - -## Summary - -This article introduces the concepts and usage of local stubs and local mocks in Dubbo. Essentially, local stubs and local mocks are equivalent to the concepts found in aspect-oriented programming. The same goals can be achieved through *AOP* programming provided by frameworks such as Spring. Readers can intuitively feel the convenience and speed offered by the framework through examples of developing a local stub and local mock. Furthermore, for many simple scenarios and dynamic configuration push scenarios, the framework provides ways to achieve this through configuration without coding, enhancing the efficiency of framework users. - -[^stub-samples]: https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-stub -[^mock-samples]: https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-mock -[^mock]: https://cn.dubbo.apache.org/zh-cn/docsv2.7/user/examples/local-mock/ - diff --git a/content/en/blog/java/demos/dubbo-supporting-grpc-http2-and-protobuf.md b/content/en/blog/java/demos/dubbo-supporting-grpc-http2-and-protobuf.md deleted file mode 100644 index 60272881c81f..000000000000 --- a/content/en/blog/java/demos/dubbo-supporting-grpc-http2-and-protobuf.md +++ /dev/null @@ -1,670 +0,0 @@ ---- -title: "Exploration of Apache Dubbo in Cross-Language and Protocol Penetration: Support for HTTP/2 gRPC and Protobuf" -linkTitle: "Support for HTTP/2 gRPC and Protobuf" -tags: ["Java"] -date: 2019-10-28 -description: > - This article is compiled from Liu Jun's presentation on "Exploration of Dubbo in Multi-Language and Protocol Penetration" at the Dubbo Chengdu meetup. ---- - -The article can be broadly divided into three parts: an introduction to the basic product, Dubbo's support for gRPC (HTTP/2) and Protobuf, and example demonstrations. The introduction covers the basic concepts and characteristics of Dubbo, HTTP/2, gRPC, and Protobuf; the second part explains why Dubbo supports gRPC (HTTP/2) and Protobuf, as well as the benefits and differences this support brings to gRPC and Dubbo development; the third part demonstrates the usage of Dubbo gRPC and Dubbo Protobuf through two examples. - -## Basic Introduction - -### Dubbo Protocol - -From a protocol perspective, here are the Dubbo protocols supported in version 2.7. - -![image-20191029103919557](/imgs/blog/grpc/dubbo-ptotocol.png) - -As we know, the Dubbo protocol is directly defined on top of the TCP transport layer protocol. The high reliability and full-duplex nature of TCP provide maximum flexibility for defining the Dubbo protocol. However, due to this flexibility, RPC protocols are generally custom private protocols, and Dubbo faces the same issue. Here, we focus on the areas where Dubbo's protocol generality can be improved. For a detailed analysis of the protocol, please refer to the [official blog](/en/blog/2018/10/05/dubbo-协议详解/). - -* The body of the Dubbo protocol has an extendable attachments section, which allows for additional attributes to be passed beyond RPC methods and is a good design. However, a similar attachments section is lacking in the header part, which can be compared to the Ascii Header design defined by HTTP, dividing responsibilities between Body Attachments and Header Attachments. -* Some RPC request locators in the body protocol, such as Service Name, Method Name, Version, etc., can be moved to the header, decoupled from the specific serialization protocol, to be better identified by network infrastructure or used for traffic control. -* The extensibility is insufficient, lacking design for protocol upgrades, such as no reserved status bits in the header or special packets specifically designed for protocol upgrades or negotiations. -* In the Java version of the implementation, it is not concise and generic enough. For instance, during link transmission, there are some language bindings; redundant content exists in the message body, such as Service Name being present in both Body and Attachments. - -### HTTP/1 - -Compared to directly building a private RPC protocol on TPC transport layers, a remote call solution built on HTTP will have better generality, such as WebServices or REST architecture; using HTTP + JSON can be considered a de facto standard solution. - -I believe there are two main advantages to building on HTTP: - -1. The semantics and scalability of HTTP can well meet the requirements for RPC calls. -2. Generality; the HTTP protocol is supported by almost all devices on the network and has good protocol penetration. - -![image-20191029113404906](/imgs/blog/grpc/http1.png) - -Specifically, the advantages and limitations of HTTP/1 are: - -* The typical Request – Response model, where only one waiting Request can exist on a link at a time. - -* HTTP/1 supports Keep-Alive links, avoiding the overhead of repeatedly creating links. - -* Human Readable Headers, using a more universal and human-readable header transmission format. - -* No direct Server Push support; requires using Polling or Long-Polling as workarounds. - - -### HTTP/2 - -HTTP/2 retains all semantics of HTTP/1, while making significant improvements in communication models and transmission efficiency. - -![image-20191029113416731](/imgs/blog/grpc/http2.png) - -* Supports Multiplexing on a single link, achieving higher efficiency by utilizing frames as compared to the exclusive link of Request - Response. - -* Request - Stream semantics, natively supports Server Push and Stream data transmission. - -* Flow Control, granular flow control at the granularity of a single Stream and the entire link. - -* Header compression HPACK. - -* Binary Frame. - -* Native TLS support. - - -### gRPC - -As mentioned, both HTTP and TCP protocols have their respective advantages and disadvantages for building RPC protocols. Compared to Dubbo, which is built on the TPC transport layer, Google chose to define gRPC directly on top of the HTTP/2 protocol. For a [basic introduction](https://grpc.io/docs/what-is-grpc/introduction/) and [design vision](https://grpc.io/blog/principles/?spm=ata.13261165.0.0.2be55017XbUhs8) of gRPC, please refer to these two articles. Here I'll extract a few characteristics from the design vision that reflect the design goals of gRPC. - -* Coverage & Simplicity, protocol design and framework implementation should be sufficiently general and simple, able to run on any device, including resource-constrained ones like IoT and Mobile. -* Interoperability & Reach, built upon a more general protocol, which can be supported by almost all infrastructure on the network. -* General Purpose & Performant, striking a balance between scenarios and performance, so the protocol itself should be suitable for various scenarios, while striving for high performance. -* Payload Agnostic, ensuring payloads transmitted by the protocol remain language and platform neutral. -* Streaming, supporting communication models like Request - Response, Request - Stream, Bi-Stream, etc. -* Flow Control, with capabilities for flow awareness and limiting within the protocol itself. -* Metadata Exchange, providing capabilities for additional data transmission beyond RPC service definitions. - -In summary, guided by such design principles, gRPC is ultimately designed as a cross-language, cross-platform, general-purpose, high-performance RPC protocol and framework based on HTTP/2. - -### Protobuf - -[Protocol Buffers (Protobuf)](https://developers.google.com/protocol-buffers/docs/overview) is a cross-platform, language-neutral structured data description and serialization product introduced by Google. It defines a set of protocols for structured data definitions while also providing the corresponding [Compiler](https://github.com/protocolbuffers/protobuf/releases/tag/v3.10.0) tools to convert language-neutral descriptions into specific language representations. - -Some of its features include: - -* Cross-language and cross-platform, providing a language-neutral data description format with out-of-the-box support for generating multiple languages' compiler tools. -* Security, as the scope of deserialization and output format are pre-generated by the compiler during compilation, bypassing issues like Java Deserialization Vulnerability. -* Binary, high-performance. -* Strong typing. -* Backward compatibility of field changes. - -```idl -message Person { - required string name = 1; - required int32 id = 2; - optional string email = 3; - - enum PhoneType { - MOBILE = 0; - HOME = 1; - WORK = 2; - } - - message PhoneNumber { - required string number = 1; - optional PhoneType type = 2 [default = HOME]; - } - - repeated PhoneNumber phone = 4; -} -``` - -In addition to structured data descriptions, Protobuf also supports defining RPC services. It allows us to define a service description file in `.proto`, which can then utilize the Protobuf Compiler tool to generate interfaces and stubs for specific languages and RPC frameworks. The gRPC + Protobuf, Dubbo-gRPC + Protobuf, and Dubbo + Protobuf scenarios that will be discussed later are all implemented through customized Compiler classes. - - ```idl -service SearchService { - rpc Search (SearchRequest) returns (SearchResponse); -} - ``` - -## Dubbo's Support - -Cross-language service development involves multiple aspects, requiring language neutrality in service definitions, RPC protocols, and serialization protocols, alongside corresponding SDK implementations for each language. While, thanks to community contributions, Dubbo has gradually made progress in multi-language SDK implementations, now offering clients or complete versions including Java, Go, PHP, C#, Python, NodeJs, C, etc., there still exist numerous areas for improvement in the aforementioned cross-language compatibility. - -* Protocol, as analyzed above, the existing flaws in the Dubbo protocol could certainly be avoided if applications are designed on top of HTTP/2. This would certainly enhance the penetration of the protocol, avoiding the need for gateway or protocol conversion components, and benefiting traffic control on the link. Considering that gRPC is built on HTTP/2 and is the recommended communication protocol in the cloud-native field, Dubbo has opted to support the gRPC protocol directly as its current HTTP/2 solution during its first phase. We also recognize that the gRPC framework itself has usability issues and lacks service governance capabilities, which is why most vendors avoid using the gRPC framework directly. By integrating it within the Dubbo framework, users can conveniently utilize combinations of the Dubbo programming model + Dubbo service governance + gRPC protocol communication. - -* Service definition, the current service definition in Dubbo is tied to specific programming languages, lacking a language-neutral service description format. For instance, in Java, it is defined through an Interface, while in other languages, it requires redefinition in a different format. Thus, Dubbo provides language-neutral service definition by supporting Protobuf. -* Serialization, the serialization formats currently supported by Dubbo include Json, Hessian2, Kryo, FST, Java, etc. Among these, only Json and Hessian2 support cross-language capability. Generally, Json has inherent performance issues, while Hessian2 has shortcomings regarding efficiency and multi-language SDK support. Therefore, Dubbo aims to deliver a more efficient and user-friendly cross-language serialization solution by supporting Protobuf serialization. - -## Example - -### Example 1: Developing gRPC Services using Dubbo - -[gRPC](https://grpc.io/) is an open-source RPC communication protocol developed by Google, built on top of HTTP/2. Dubbo leverages its flexible protocol extension mechanism to add support for gRPC (HTTP/2). - -Current support is limited to the Dubbo Java language version; future support for Go or other languages will be provided similarly. Below is a [simple example](https://github.com/apache/dubbo-samples/tree/925c3d150d9030bc72988564e4f97eca1f6fcb89/3-extensions/protocol/dubbo-samples-grpc) that demonstrates how to use gRPC protocol communication in Dubbo. - -#### 1. Define Service IDL - -First, define the service using the standard Protobuf protocol as follows: - -```idl -syntax = "proto3"; - -option java_multiple_files = true; -option java_package = "io.grpc.examples.helloworld"; -option java_outer_classname = "HelloWorldProto"; -option objc_class_prefix = "HLW"; - -package helloworld; - -// The greeting service definition. -service Greeter { - // Sends a greeting - rpc SayHello (HelloRequest) returns (HelloReply) {} -} - -// The request message containing the user's name. -message HelloRequest { - string name = 1; -} - -// The response message containing the greetings -message HelloReply { - string message = 1; -} -``` - -Here, we define a Greeter service with only one method sayHello, along with its input and output parameters. - -#### 2. Compiler Generates Stub - -1. Define the Maven Protobuf Compiler plugin. Here we extended the Protobuf Compiler tool to generate Dubbo-specific RPC stubs, currently released as a Maven plugin. - -```xml - - org.xolstice.maven.plugins - protobuf-maven-plugin - 0.5.1 - - com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier} - - dubbo-grpc-java - org.apache.dubbo:protoc-gen-dubbo-java:1.19.0-SNAPSHOT:exe:${os.detected.classifier} - build/generated/source/proto/main/java - false - grpc - - - - - compile - compile-custom - - - - -``` - -Here, - -pluginArtifact specifies the Dubbo customized version of the Java Protobuf Compiler plugin, which generates the Dubbo customized version of the gRPC stub during the compilation. - -```xml -org.apache.dubbo:protoc-gen-dubbo-java:1.19.0-SNAPSHOT:exe:${os.detected.classifier} -``` -Due to `protoc-gen-dubbo-java` supporting both gRPC and Dubbo protocols, the default generated stub type is gRPC. For usage concerning the Dubbo protocol, please refer to [Developing Dubbo Services using Protobuf](/en/overview/mannual/java-sdk/quick-start/). - -```xml -grpc -``` - -2. Generate Java Bean and Dubbo-gRPC stub - - ```sh - # Run the following maven command - $ mvn clean compile - ``` - - The generated Stub and message classes are as follows: - ![image-20191026130516896](/imgs/blog/grpc/compiler-classes.png) - - Pay special attention to GreeterGrpc, which contains all standard gRPC stub classes/methods while adding Dubbo-specific interfaces, which will be relied upon for service exposure on the Provider side and service calls on the Consumer side. - - ```java - /** - * Code generated for Dubbo - */ - public interface IGreeter { - - default public io.grpc.examples.helloworld.HelloReply sayHello(io.grpc.examples.helloworld.HelloRequest request) { - throw new UnsupportedOperationException("No need to override this method, extend XxxImplBase and override all methods it allows."); - } - - default public com.google.common.util.concurrent.ListenableFuture sayHelloAsync( - io.grpc.examples.helloworld.HelloRequest request) { - throw new UnsupportedOperationException("No need to override this method, extend XxxImplBase and override all methods it allows."); - } - - public void sayHello(io.grpc.examples.helloworld.HelloRequest request, - io.grpc.stub.StreamObserver responseObserver); - } - ``` - -#### 3. Business Logic Development - -Extend `GreeterGrpc.GreeterImplBase` (from Step 2) to implement business logic, which is consistent with native gRPC. - -```java -package org.apache.dubbo.samples.basic.impl; - -import io.grpc.examples.helloworld.GreeterGrpc; -import io.grpc.examples.helloworld.HelloReply; -import io.grpc.examples.helloworld.HelloRequest; -import io.grpc.stub.StreamObserver; - -public class GrpcGreeterImpl extends GreeterGrpc.GreeterImplBase { - @Override - public void sayHello(HelloRequest request, StreamObserver responseObserver) { - System.out.println("Received request from client."); - System.out.println("Executing thread is " + Thread.currentThread().getName()); - HelloReply reply = HelloReply.newBuilder() - .setMessage("Hello " + request.getName()).build(); - responseObserver.onNext(reply); - responseObserver.onCompleted(); - } -} -``` - -#### 4. Expose Dubbo Service on Provider Side - -Using Spring XML as an example - -```xml - - - - - - - - - - - -``` - -```java -public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = - new ClassPathXmlApplicationContext("spring/dubbo-demo-provider.xml"); - context.start(); - - System.out.println("dubbo service started"); - new CountDownLatch(1).await(); -} -``` - -#### 5. Referencing Dubbo Service - -```xml - - - - - - -``` - -```java -public static void main(String[] args) throws IOException { - ClassPathXmlApplicationContext context = - new ClassPathXmlApplicationContext("spring/dubbo-demo-consumer.xml"); - context.start(); - - GreeterGrpc.IGreeter greeter = (GreeterGrpc.IGreeter) context.getBean("greeter"); - - HelloReply reply = greeter.sayHello(HelloRequest.newBuilder().setName("world!").build()); - System.out.println("Result: " + reply.getMessage()); - - System.in.read(); -} -``` - -#### Example 1 Appendix: Advanced Usage - -**1. Asynchronous Calls** - -Let’s review the `protoc-gen-dubbo-java` generated interface again: - -```java -/** - * Code generated for Dubbo - */ -public interface IGreeter { - default public HelloReply sayHello(HelloRequest request) { - // ...... - } - default public ListenableFuture sayHelloAsync(HelloRequest request) { - // ...... - } - public void sayHello(HelloRequest request, StreamObserver responseObserver); -} -``` - -Here three types of overloaded methods are generated for sayHello, for synchronous call, asynchronous call, and streaming call. If the consumer wants to make an asynchronous call, just call sayHelloAsync(): - -```java -public static void main(String[] args) throws IOException { - // ... - GreeterGrpc.IGreeter greeter = (GreeterGrpc.IGreeter) context.getBean("greeter"); - ListenableFuture future = - greeter.sayHelloAsync(HelloRequest.newBuilder().setName("world!").build()); - // ... -} -``` - -**2. Advanced Configuration** - -Since the current implementation is directly integrated with gRPC-java SDK, many configurations have not yet been aligned with Dubbo's side, or haven't been exposed in the form of Dubbo configurations. Therefore, to provide the maximum flexibility, we directly expose the gRPC-java configuration interfaces. - -In the vast majority of scenarios, you may not need the following extensions, as they are more about intercepting the gRPC protocol or configuring at the HTTP/2 layer. Using these extension points may require a basic understanding of HTTP/2 or gRPC. - -**Extension Points** - -Currently, the supported extension points are as follows: - -* org.apache.dubbo.rpc.protocol.grpc.interceptors.ClientInterceptor - -* org.apache.dubbo.rpc.protocol.grpc.interceptors.GrpcConfigurator - -* org.apache.dubbo.rpc.protocol.grpc.interceptors.ServerInterceptor - -* org.apache.dubbo.rpc.protocol.grpc.interceptors.ServerTransportFilter - -GrpcConfigurator is the most general extension point, which we will illustrate as follows: - -```java -public interface GrpcConfigurator { - // Used to customize the gRPC NettyServerBuilder - default NettyServerBuilder configureServerBuilder(NettyServerBuilder builder, URL url) { - return builder; - } - // Used to customize the gRPC NettyChannelBuilder - default NettyChannelBuilder configureChannelBuilder(NettyChannelBuilder builder, URL url) { - return builder; - } - // Used to customize gRPC CallOptions, defining data transfer between requests of a service - default CallOptions configureCallOptions(CallOptions options, URL url) { - return options; - } -} -``` - -Here is an example extension implementation: - -```java -public class MyGrpcConfigurator implements GrpcConfigurator { - private final ExecutorService executor = Executors - .newFixedThreadPool(200, new NamedThreadFactory("Customized-grpc", true)); - - @Override - public NettyServerBuilder configureServerBuilder(NettyServerBuilder builder, URL url) { - return builder.executor(executor); - } - - @Override - public NettyChannelBuilder configureChannelBuilder(NettyChannelBuilder builder, URL url) - { - return builder.flowControlWindow(10); - } - - @Override - public CallOptions configureCallOptions(CallOptions options, URL url) { - return options.withOption(CallOptions.Key.create("key"), "value"); - } -} -``` - -The configuration is defined in Dubbo SPI, with the configuration file added in `resources/META-INF/services`. - -```properties -default=org.apache.dubbo.samples.basic.comtomize.MyGrpcConfigurator -``` - -1. Specify the thread pool on the Provider side - - The default uses Dubbo's thread pool, with types like fixed (default), cached, direct, etc. The example demonstrates switching to a custom business thread pool: - - ```java - private final ExecutorService executor = Executors - .newFixedThreadPool(200, new NamedThreadFactory("Customized-grpc", true)); - - public NettyServerBuilder configureServerBuilder(NettyServerBuilder builder, URL url) - { - return builder.executor(executor); - } - ``` - -2. Set Consumer side flow control value - - Set the Consumer flow control value to 10: - - ```java - @Override - public NettyChannelBuilder configureChannelBuilder(NettyChannelBuilder builder, URL url) - { - return builder.flowControlWindow(10); - } - ``` - -3. Pass additional parameters - - The DemoService service call passes the key: - - ```java - @Override - public CallOptions configureCallOptions(CallOptions options, URL url) { - if (url.getServiceInterface().equals("xxx.DemoService")) { - return options.withOption(CallOptions.Key.create("key"), "value"); - } else { - return options; - } - } - ``` - -**3. TLS Configuration** - -The configuration method is consistent with Dubbo's general [TLS support](/en/overview/mannual/java-sdk/reference-manual/protocol/tls/). Please refer to the documentation. - -### Example 2: Using Protobuf to Develop Dubbo Services - -Next, let's look at a [specific example](https://github.com/apache/dubbo-samples/tree/master/3-extensions/serialization/dubbo-samples-protobuf) of the Dubbo service development process based on Protobuf. - -#### 1. Define Service - -Define the service via standard Protobuf - -```idl -syntax = "proto3"; - -option java_multiple_files = true; -option java_package = "org.apache.dubbo.demo"; -option java_outer_classname = "DemoServiceProto"; -option objc_class_prefix = "DEMOSRV"; - -package demoservice; - -// The demo service definition. -service DemoService { - rpc SayHello (HelloRequest) returns (HelloReply) {} -} - -// The request message containing the user's name. -message HelloRequest { - string name = 1; -} - -// The response message containing the greetings -message HelloReply { - string message = 1; -} -``` - -Here, we define a DemoService service that only includes a sayHello method, along with its input and output parameters. - -#### 2. Compiler Compiles the Service - -1. Introduce the Protobuf Compiler Maven plugin while specifying the `protoc-gen-dubbo-java` RPC extension. - -```xml - - org.xolstice.maven.plugins - protobuf-maven-plugin - 0.5.1 - - com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier} - - dubbo-grpc-java - org.apache.dubbo:protoc-gen-dubbo-java:1.19.0-SNAPSHOT:exe:${os.detected.classifier} - build/generated/source/proto/main/java - false - dubbo - - - - - compile - compile-custom - - - - -``` - -Note that the difference here from the [Dubbo's support for gRPC](https://github.com/apache/dubbo-samples/tree/925c3d150d9030bc72988564e4f97eca1f6fcb89/3-extensions/protocol/dubbo-samples-grpc) part is: -`dubbo` - -2. Generate Dubbo stub - - ```shell - # Run the following maven command - $mvn clean compile - ``` - - The generated Java classes are as follows: - - ![image-20191028201240976](/imgs/blog/grpc/compiler-protobuf.png) - - DemoServiceDubbo is the Dubbo customized stub. - - ```java - public final class DemoServiceDubbo { - - private static final AtomicBoolean registered = new AtomicBoolean(); - - private static Class init() { - Class clazz = null; - try { - clazz = Class.forName(DemoServiceDubbo.class.getName()); - if (registered.compareAndSet(false, true)) { - org.apache.dubbo.common.serialize.protobuf.support.ProtobufUtils.marshaller( - org.apache.dubbo.demo.HelloRequest.getDefaultInstance()); - org.apache.dubbo.common.serialize.protobuf.support.ProtobufUtils.marshaller( - org.apache.dubbo.demo.HelloReply.getDefaultInstance()); - } - } catch (ClassNotFoundException e) { - // ignore - } - return clazz; - } - - private DemoServiceDubbo() {} - - public static final String SERVICE_NAME = "demoservice.DemoService"; - - /** - * Code generated for Dubbo - */ - public interface IDemoService { - - static Class clazz = init(); - org.apache.dubbo.demo.HelloReply sayHello(org.apache.dubbo.demo.HelloRequest request); - - java.util.concurrent.CompletableFuture sayHelloAsync( - org.apache.dubbo.demo.HelloRequest request); - - } - - } - ``` - - The `IDemoService` interface is most noteworthy as it serves as the foundational interface for defining Dubbo services. - -#### 3. Implementing Business Logic - -From this point forward, the development process is identical to directly defining a Java interface. Implement the interface to define the business logic. - -```java -public class DemoServiceImpl implements DemoServiceDubbo.IDemoService { - private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class); - - @Override - public HelloReply sayHello(HelloRequest request) { - logger.info("Hello " + request.getName() + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); - return HelloReply.newBuilder() - .setMessage("Hello " + request.getName() + ", response from provider: " - + RpcContext.getContext().getLocalAddress()) - .build(); - } - - @Override - public CompletableFuture sayHelloAsync(HelloRequest request) { - return CompletableFuture.completedFuture(sayHello(request)); - } -} -``` - -#### 4. Configuring Provider - -Expose Dubbo service - -```xml - - - - - - - - - -``` - -```java -public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = - new ClassPathXmlApplicationContext("spring/dubbo-provider.xml"); - context.start(); - System.in.read(); -} -``` - -#### 5. Configuring Consumer - -Reference Dubbo service - -```xml - - - - - -``` - -```java -public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = - new ClassPathXmlApplicationContext("spring/dubbo-consumer.xml"); - context.start(); - IDemoService demoService = context.getBean("demoService", IDemoService.class); - HelloRequest request = HelloRequest.newBuilder().setName("Hello").build(); - HelloReply reply = demoService.sayHello(request); - System.out.println("result: " + reply.getMessage()); - System.in.read(); -} -``` - diff --git a/content/en/blog/java/demos/dubbo2.7.14-java17.md b/content/en/blog/java/demos/dubbo2.7.14-java17.md deleted file mode 100644 index fe5e726d7e91..000000000000 --- a/content/en/blog/java/demos/dubbo2.7.14-java17.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: "Compile and Run Dubbo 2.7.14 Project Using JDK17" -linkTitle: "Compile and Run Dubbo 2.7.14 Project Using JDK17" -tags: ["Java"] -date: 2018-08-07 -description: > - This article introduces how to compile and run the Dubbo 2.7.14 project in a JDK17 environment. ---- -## Overview -Java 17 is the latest long-term support (LTS) version of Java. However, due to the new features that strongly encapsulate the JDK's internal APIs, the Dubbo project cannot be directly compiled and run with JDK17. By referring to the [OpenJDK documentation](https://openjdk.java.net/jeps/403), we find that we only need to add the corresponding parameters to bypass the constraints of Java 17. -For a standard Dubbo project, just add at runtime: -```--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED``` -If other dependencies in the project have similar issues, more parameters may need to be added, which will be detailed below. -This solution only addresses issues caused by the strong encapsulation of the JDK's internal APIs in Java 17. For other compatibility issues, please seek additional solutions. - -## Obtaining Parameters and Examples -Taking the demo from the Dubbo official repository as an example, first, use Java 17 as our development environment by executing: -``` -git clone git@github.com:apache/dubbo.git -git checkout dubbo-2.7.14 -cd dubbo-demo/dubbo-demo-annotation -``` -Obtain the demo from the Dubbo official repository code, then you can try compiling Dubbo's demo directly with Java 17. -Check the Java version: -``` -➜ ~ java -version -openjdk version "17.0.1" 2021-10-19 -OpenJDK Runtime Environment Temurin-17.0.1+12 (build 17.0.1+12) -OpenJDK 64-Bit Server VM Temurin-17.0.1+12 (build 17.0.1+12, mixed mode, sharing) -``` -Then run: -``` -mvn -U clean package --no-transfer-progress -D maven.test.skip=true -``` -Start Zookeeper `docker run --name some-zookeepep -p 2181:2181 -it --rm zookeeper` as the registry, then try running the provider: -``` -java -jar dubbo-demo-annotation-provider/target/dubbo-demo-annotation-provider-2.7.14.jar -``` -You may see an error like: -```Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @8807e25``` -The key phrase `module `**java.base**` does not "opens `**java.lang**`" to unnamed module @8807e25`. According to the [OpenJDK documentation](https://openjdk.java.net/jeps/403), we only need to add the `--add-opens `**java.base**`/`**java.lang**`=ALL-UNNAMED` parameter to resolve the issue. -Corresponding errors should be solvable in a similar manner. After testing, the Dubbo project in the demo requires: -``` ---add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED -``` -With these parameters, it can run. -Run the provider and consumer in two terminals respectively: -``` -java --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED -jar dubbo-demo-annotation-provider/target/dubbo-demo-annotation-provider-2.7.14.jar -``` -``` -java --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/sun.reflect.generics.reflectiveObjects=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED -jar dubbo-demo-annotation-consumer/target/dubbo-demo-annotation-consumer-2.7.14.jar -``` -You may notice Zookeeper errors; upgrading the Zookeeper version can likely resolve the issue... -Add the latest version of the Zookeeper dependency to the first item in the `pom.xml` of both the provider and consumer: -``` - - org.apache.zookeeper - zookeeper - 3.7.0 - - - io.netty - netty - - - -``` -Run the provider and consumer again. -You will see the consumer successfully outputs a similar result: -``` -result :Hello world, response from provider: *.*.*.*/:20880 -``` -The provider also logs the corresponding information: -``` -Hello world, request from consumer: /*.*.*.*:43346 -``` diff --git a/content/en/blog/java/demos/first-dubbo-filter.md b/content/en/blog/java/demos/first-dubbo-filter.md deleted file mode 100644 index b17e99385bfc..000000000000 --- a/content/en/blog/java/demos/first-dubbo-filter.md +++ /dev/null @@ -1,203 +0,0 @@ ---- -title: "First Dubbo Filter" -linkTitle: "First Dubbo Filter" -tags: ["Java"] -date: 2018-07-01 -description: > - This article introduces how to develop a Dubbo Filter ---- - -### Overview -In the overall design of Dubbo, Filters are an important concept. Most of Dubbo's functionalities are realized based on this extension point, and the interception of Filters is executed during each call. - -#### Loading Mechanism of Dubbo Filter -There are approximately twenty Filters that have been implemented in Dubbo, all entering through ProtocolFilterWrapper. ProtocolFilterWrapper wraps the Protocol and is loaded during extension loading. Let's take a look at how this Filter chain is constructed. - -```java -//ProtocolFilterWrapper.java -public Invoker refer(Class type, URL url) throws RpcException { - if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { - return protocol.refer(type, url); - } - return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER); - } - - private static Invoker buildInvokerChain(final Invoker invoker, String key, String group) { - Invoker last = invoker; - List filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group); - if (filters.size() > 0) { - for (int i = filters.size() - 1; i >= 0; i --) { - final Filter filter = filters.get(i); - final Invoker next = last; - last = new Invoker() { - - public Class getInterface() { - return invoker.getInterface(); - } - - public URL getUrl() { - return invoker.getUrl(); - } - - public boolean isAvailable() { - return invoker.isAvailable(); - } - - public Result invoke(Invocation invocation) throws RpcException { - return filter.invoke(next, invocation); - } - - public void destroy() { - invoker.destroy(); - } - - @Override - public String toString() { - return invoker.toString(); - } - }; - } - } - return last; - } - -``` - -#### Activation Mechanism of Dubbo Filter -From the above code, we can see that in `buildInvokerChain`, all activated invocation chains are first obtained, which are already sorted. The invocation chain can be roughly represented as: Filter1->Filter2->Filter3->......->Invoker. Let's look at the process of obtaining the activated invocation chain: - -```java - public List getActivateExtension(URL url, String key, String group) { - String value = url.getParameter(key); - return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group); - } - - public List getActivateExtension(URL url, String[] values, String group) { - List exts = new ArrayList(); - - List names = values == null ? new ArrayList(0) : Arrays.asList(values); - - if (! names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) { - getExtensionClasses(); - for (Map.Entry entry : cachedActivates.entrySet()) { - String name = entry.getKey(); - Activate activate = entry.getValue(); - if (isMatchGroup(group, activate.group())) { - T ext = getExtension(name); - if (! names.contains(name) && ! names.contains(Constants.REMOVE_VALUE_PREFIX + name) - && isActive(activate, url)) { - exts.add(ext); - } - } - } - Collections.sort(exts, ActivateComparator.COMPARATOR); - } - List usrs = new ArrayList(); - for (int i = 0; i < names.size(); i ++) { - String name = names.get(i); - if (! name.startsWith(Constants.REMOVE_VALUE_PREFIX) - && ! names.contains(Constants.REMOVE_VALUE_PREFIX + name)) { - if (Constants.DEFAULT_KEY.equals(name)) { - if (usrs.size() > 0) { - exts.addAll(0, usrs); - usrs.clear(); - } - } else { - T ext = getExtension(name); - usrs.add(ext); - } - } - } - if (usrs.size() > 0) { - exts.addAll(usrs); - } - return exts; - } -``` -Through the above code, it can be seen that some Filters configured by users are activated by default, while others need to be activated through configuration files. The loading order of all Filters first processes Dubbo's default Filters, followed by user-defined and configured Filters. Through the "-" configuration, Dubbo's native Filters can be replaced, allowing flexible replacement or modification of the order in which Filters are loaded. - -#### Native Dubbo Filters -There are many native Filters in Dubbo, such as RpcContext, accesslog, etc. can be implemented through Dubbo. Below we introduce the ConsumerContextFilter, which is used for context passing on the Consumer side: - -```java -public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - RpcContext.getContext() - .setInvoker(invoker) - .setInvocation(invocation) - .setLocalAddress(NetUtils.getLocalHost(), 0) - .setRemoteAddress(invoker.getUrl().getHost(), - invoker.getUrl().getPort()); - if (invocation instanceof RpcInvocation) { - ((RpcInvocation)invocation).setInvoker(invoker); - } - try { - return invoker.invoke(invocation); - } finally { - RpcContext.getContext().clearAttachments(); - } - } -``` -This Filter records the status information during the call process and passes the attachments parameter set by the client to the server through the invocation object. After the call is completed, these parameters are cleared, which is why the request status information can be recorded and passed accordingly. - -#### Implementing a Dubbo Filter -Thanks to Dubbo's flexible design and good scalability, we can implement our own Dubbo Filter to embed logic within the calling chain, such as time consumption statistics, monitor information statistics, etc. Below we implement a simple Filter: - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxFilter.java (implementing Filter interface) - |-resources - |-META-INF - |-dubbo - |-com.alibaba.dubbo.rpc.Filter (plain text file, content: xxx=com.xxx.XxxFilter) -``` - -XxxFilter.java: - -```java -public class XxxFilter implements Filter { - public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - // before filter ... - Result result = invoker.invoke(invocation); - // after filter ... - return result; - } -} -``` - -META-INF/dubbo/com.alibaba.dubbo.rpc.Filter: -``` -xxx=com.xxx.XxxFilter -``` - -Configuring in XML: - -```xml - - - - - - - - -``` - -Or use annotations: - -```java -@Activate(group = "consumer") -public class XxxFilter implements Filter { - // ... -} -``` - -Using XML configuration is more flexible and granular. - -In before and after, you can implement your business logic to assign functionality to this filter. After writing and configuring, the filter will be activated by the Dubbo framework and executed in the calling chain. - diff --git a/content/en/blog/java/demos/hystrix.md b/content/en/blog/java/demos/hystrix.md deleted file mode 100644 index 2c2503b9c9ae..000000000000 --- a/content/en/blog/java/demos/hystrix.md +++ /dev/null @@ -1,190 +0,0 @@ ---- -aliases: - - /en/overview/what/ecosystem/rate-limit/hystrix/ - - /en/overview/tasks/rate-limit/hystrix/ - - /en/overview/tasks/rate-limit/hystrix/ -description: "Using Hystrix for Circuit Breaker Rate Limiting Protection of Dubbo Services" -linkTitle: Pending Integration-Hystrix Circuit Breaker Degradation -title: Using Hystrix for Circuit Breaker Rate Limiting Protection of Dubbo Services -tags: ["Java", "Hystrix", "Rate Limiting Degradation"] -date: 2023-12-14 ---- - -## Background - -Hystrix aims to provide robust fault tolerance by controlling the nodes that access remote systems, services, and third-party libraries, thereby enhancing resilience to latency and failures. Hystrix has features such as fallback mechanisms, circuit breaker functionality, thread and signal isolation, request caching, request bundling, as well as monitoring and configuration capabilities. - -This article describes how to combine Dubbo and Hystrix in a Spring application. - -- -- - -## Spring Boot Application - -Demo address: - -### Generate a Dubbo Integrated Spring Boot Application - -For those unfamiliar with Dubbo integration with Spring Boot, you can directly generate a Dubbo + Spring Boot project here: - -### Configure spring-cloud-starter-netflix-hystrix - -Spring Boot officially provides integration with Hystrix. Simply add the dependency to your pom.xml: - -```xml - - org.springframework.cloud - spring-cloud-starter-netflix-hystrix - 1.4.4.RELEASE - -``` - -Then, add `@EnableHystrix` on the Application class to enable the Hystrix starter: - -```java -@SpringBootApplication -@EnableHystrix -public class ProviderApplication { -``` -### Configure Provider Side -Increase the `@HystrixCommand` configuration on the Dubbo Provider, so that the calls will go through the Hystrix proxy. -```java -@Service(version = "1.0.0") -public class HelloServiceImpl implements HelloService { - @HystrixCommand(commandProperties = { - @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), - @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") }) - @Override - public String sayHello(String name) { - // System.out.println("async provider received: " + name); - // return "annotation: hello, " + name; - throw new RuntimeException("Exception to show hystrix enabled."); - } -} -``` -### Configure Consumer Side -For the consumer side, you can add an additional method call and configure `@HystrixCommand` on the method. When an error occurs, it will invoke the `fallbackMethod = "reliable"` call. -```java - @Reference(version = "1.0.0") - private HelloService demoService; - @HystrixCommand(fallbackMethod = "reliable") - public String doSayHello(String name) { - return demoService.sayHello(name); - } - public String reliable(String name) { - return "hystrix fallback value"; - } -``` -With the above configuration, the integration of Dubbo + Hystrix in Spring Boot is easily completed. -## Traditional Spring Annotation Application -Demo address: -The configuration for traditional Spring annotation applications is also quite simple. Unlike Spring Boot applications, it requires: -1. Explicitly configure Spring AOP support: `@EnableAspectJAutoProxy` -2. Explicitly configure `HystrixCommandAspect` Bean through `@Configuration`. -```java - @Configuration - @EnableDubbo(scanBasePackages = "com.alibaba.dubbo.samples.annotation.action") - @PropertySource("classpath:/spring/dubbo-consumer.properties") - @ComponentScan(value = {"com.alibaba.dubbo.samples.annotation.action"}) - @EnableAspectJAutoProxy - static public class ConsumerConfiguration { - @Bean - public HystrixCommandAspect hystrixCommandAspect() { - return new HystrixCommandAspect(); - } - } -``` -## Hystrix Integration with Spring AOP Principles -In the above example, it can be seen that Hystrix's integration with Spring is achieved through Spring AOP. Below we briefly analyze the implementation. -```java -@Aspect -public class HystrixCommandAspect { - @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)") - public void hystrixCommandAnnotationPointcut() { - } - @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)") - public void hystrixCollapserAnnotationPointcut() { - } - @Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()") - public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable { - Method method = getMethodFromTarget(joinPoint); - Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint); - if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) { - throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " + - "annotations at the same time"); - } - MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method)); - MetaHolder metaHolder = metaHolderFactory.create(joinPoint); - HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder); - ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ? - metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType(); - Object result; - try { - if (!metaHolder.isObservable()) { - result = CommandExecutor.execute(invokable, executionType, metaHolder); - } else { - result = executeObservable(invokable, executionType, metaHolder); - } - } catch (HystrixBadRequestException e) { - throw e.getCause() != null ? e.getCause() : e; - } catch (HystrixRuntimeException e) { - throw hystrixRuntimeExceptionToThrowable(metaHolder, e); - } - return result; - } -``` -1. `HystrixCommandAspect` defines two AspectJ Pointcuts for the annotations: `@HystrixCommand` and `@HystrixCollapser`. All Spring beans marked with these annotations will be processed via AOP. -2. In the `@Around` AOP processing function, you can see that Hystrix creates a `HystrixInvokable`, and then executes it via the `CommandExecutor`. -## Analysis of spring-cloud-starter-netflix-hystrix Code -1. `@EnableHystrix` introduces `@EnableCircuitBreaker`, and `@EnableCircuitBreaker` imports `EnableCircuitBreakerImportSelector`. - ```java - @EnableCircuitBreaker - public @interface EnableHystrix { - } - - @Import(EnableCircuitBreakerImportSelector.class) - public @interface EnableCircuitBreaker { - } - ``` -2. `EnableCircuitBreakerImportSelector` inherits from `SpringFactoryImportSelector`, allowing Spring to load the configuration declared in `META-INF/spring.factories` for `EnableCircuitBreaker`. - In `META-INF/spring.factories`, you can find the configuration that introduces `HystrixCircuitBreakerConfiguration`. - ```properties - org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\ - org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration - ``` -3. In `HystrixCircuitBreakerConfiguration`, `HystrixCommandAspect` is created. - ```java - @Configuration - public class HystrixCircuitBreakerConfiguration { - - @Bean - public HystrixCommandAspect hystrixCommandAspect() { - return new HystrixCommandAspect(); - } - ``` -It can be seen that `spring-cloud-starter-netflix-hystrix` also creates `HystrixCommandAspect` for the integration of Hystrix. -Additionally, it includes metrics, health, and dashboard integrations. - -## Summary -- For Dubbo providers, the `@Service` is a Spring bean, and you can directly configure `@HystrixCommand` on it. -- For Dubbo consumers, you can add a simple Spring method wrapping and configure `@HystrixCommand`. -- Hystrix itself provides `HystrixCommandAspect` to integrate with Spring AOP, where Spring methods configured with `@HystrixCommand` or `@HystrixCollapser` will be processed by Hystrix. - -### Comparison Between Sentinel and Hystrix - -Currently, the commonly used circuit breaker degradation/isolation library in the industry is Netflix's [Hystrix](https://github.com/Netflix/Hystrix). So what are the similarities and differences between Sentinel and Hystrix? Hystrix focuses on fault tolerance mechanisms centered around _isolation_ and _circuit breaking_, while Sentinel emphasizes diverse traffic control, circuit-breaking degradation, system load protection, real-time monitoring, and console capabilities, indicating that the problems they address are quite different. - -Hystrix uses the command pattern to encapsulate resource invocation logic, and the definition of resources and isolation rules are strongly dependent, meaning that when creating HystrixCommand, the isolation rules must be specified (as its execution model depends on the isolation mode). Sentinel's design is simpler, not focusing on how resources are executed; the definition of resources and the configuration of rules are separated. Users can first define resources and then configure rules as needed. The principle of Sentinel is very straightforward: execute corresponding flow control/degradation/load protection strategies based on the rules configured for the relevant resources; if no rules are configured, only statistics will be collected. Starting from version 0.1.1, Sentinel introduced [annotation support](https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81), making it easier to define resources. - -Isolation is a core function of Hystrix. Hystrix isolates dependencies (corresponding to resources in Sentinel) through thread pools or semaphore methods, where resource isolation is the most commonly used. The benefit of Hystrix's thread pool isolation is thorough, but the drawback is that many thread pools need to be opened, leading to significant context-switching overhead when the number of threads in the application is large. Hystrix's semaphore isolation mode limits concurrent calls without explicitly creating threads, which is lightweight but fails to downgrade slow calls automatically, forcing the client to timeout itself, which may still lead to cascading blockages. Sentinel can provide semaphore isolation functions through flow control based on concurrent thread counts and can automatically downgrade when the average response time of unstable resources is high, thus preventing an excessive number of slow calls from occupying concurrent counts and affecting the entire system. - -Hystrix's circuit breaker degradation function adopts the circuit breaker pattern, automatically breaking the circuit when the failure rate of a service is high. Sentinel's circuit breaker degradation function is more general, supporting both average response time and failure rate as indicators. Sentinel also provides support for various call chain relationships and flow control effects and can dynamically adjust traffic in real-time based on system load to protect the system, leading to a wider range of application scenarios. Additionally, Sentinel offers real-time monitoring APIs and a console, allowing users to quickly understand the current state of the system, ensuring service stability. - -For a more detailed comparison, please refer to [Comparison Between Sentinel and Hystrix](https://github.com/alibaba/Sentinel/wiki/Sentinel-%E4%B8%8E-Hystrix-%E7%9A%84%E5%AF%B9%E6%AF%94). - -### Links -- -- -- -- - diff --git a/content/en/blog/java/demos/introduction-to-dubbo-qos.md b/content/en/blog/java/demos/introduction-to-dubbo-qos.md deleted file mode 100644 index e7841650fbdf..000000000000 --- a/content/en/blog/java/demos/introduction-to-dubbo-qos.md +++ /dev/null @@ -1,262 +0,0 @@ ---- -title: "Dynamically Control Services via QoS" -linkTitle: "Dynamically Control Services via QoS" -tags: ["Java"] -date: 2018-08-14 -description: > - This article explains how to dynamically configure services using Dubbo's QoS functionality, as well as the relevant parameters and configuration methods. ---- - - -QoS, short for `Quality of Service`, is a term commonly found in network devices. For example, in routers, QoS can dynamically adjust and control the weights of certain ports, thereby prioritizing the quality of services running on those ports. - -In Dubbo, the concept of QoS is used for dynamically querying and controlling services. For example, to obtain all currently provided and consumed services, and dynamically bring services online or offline from the registry. - -## QoS Working Mechanism - -Starting from Dubbo 2.5.8, QoS functionality is enabled by default. All QoS functions are abstracted into individual commands, and by executing these commands, QoS will return corresponding results. - -> The QoS functionality is based on Netty 4. In versions prior to Dubbo 2.6.x, it depended on Netty 3 by default, so you need to explicitly add the Netty 4 dependency to ensure it works correctly. If you use the Dubbo application generated by http://start.dubbo.io, no extra configuration is needed, as the Netty 4 dependency is included by default. - -The working mechanism of QoS is illustrated in the following diagram: - -![undefined](/imgs/blog/qos-architecture.png) - - - -1. Start and listen on a port, default port is 22222 -2. Identify the protocol of the target request as either Http or Telnet, and dynamically add the corresponding handler based on the protocol -3. Decode for different protocols and parse out the command to be executed -4. Execute the command and return the result - -## QoS Commands - -The commands currently supported by QoS include: - -* help: Help command, lists commands -* ls: Lists all currently provided and consumed services -* online: Dynamically registers a certain or all services to the registry -* offline: Dynamically removes a certain or all services from the registry (unregister) -* quit: Exits the current telnet session - -Next, let's specifically operate on how to dynamically control services using QoS. - -### Accessing QoS via Telnet - -Assuming our Dubbo server is already running, we connect via Telnet: - -``` -$ telnet localhost 22222 -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. - ????????? ??? ?? ??????????? ??????????? ???????? - ??? ???? ??? ??? ??? ??? ??? ??? ??? ??? - ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? - ??? ??? ??? ??? ?????????? ?????????? ??? ??? - ??? ??? ??? ??? ??????????? ??????????? ??? ??? - ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? - ??? ???? ??? ??? ??? ??? ??? ??? ??? ??? - ????????? ????????? ??????????? ??????????? ???????? - - -dubbo> -``` - -Upon successful connection, the `dubbo>` prompt appears, at which point we enter the `help` command. - -``` -dubbo>help -+---------+----------------------------------------------------------------------------------+ -| help | help command | -+---------+----------------------------------------------------------------------------------+ -| ls | ls service | -+---------+----------------------------------------------------------------------------------+ -| offline | offline dubbo | -+---------+----------------------------------------------------------------------------------+ -| online | online dubbo | -+---------+----------------------------------------------------------------------------------+ -| quit | quit telnet console | -+---------+----------------------------------------------------------------------------------+ - -dubbo> -``` - -This will list all currently available commands and their descriptions. - -We can also use the help operation on a single command to see examples for that command. - -``` -dubbo>help online -+--------------+----------------------------------------------------------------------------------+ -| COMMAND NAME | online | -+--------------+----------------------------------------------------------------------------------+ -| EXAMPLE | online dubbo | -| | online xx.xx.xxx.service | -+--------------+----------------------------------------------------------------------------------+ -``` - -Using `ls` will show the current service status. - -``` -dubbo>ls -As Provider side: -+------------------------------------------+---+ -| Provider Service Name |PUB| -+------------------------------------------+---+ -|org.apache.dubbo.demo.provider.DemoService| Y | -+------------------------------------------+---+ -As Consumer side: -+---------------------+---+ -|Consumer Service Name|NUM| -+---------------------+---+ -``` - -We can see that there is a service `org.apache.dubbo.demo.provider.DemoService` on the provider side, and the second column shows `PUB=Y`, indicating that the service has been published to the registry and is available for consumers. - -Assuming we want to bring this service offline dynamically, we can do so using the `offline` command. - -``` -dubbo>offline org.apache.dubbo.demo.provider.DemoService -OK -``` - -The command returns OK, and we can check the current status using `ls`: - -``` -dubbo>ls -As Provider side: -+------------------------------------------+---+ -| Provider Service Name |PUB| -+------------------------------------------+---+ -|org.apache.dubbo.demo.provider.DemoService| N | -+------------------------------------------+---+ -As Consumer side: -+---------------------+---+ -|Consumer Service Name|NUM| -+---------------------+---+ -``` - -We can see that the `PUB` status of `org.apache.dubbo.demo.provider.DemoService` has been set to `N`. - -Using the `quit` command will exit the current telnet session: - -``` -dubbo>quit -BYE! -Connection closed by foreign host. -``` - - - -### Accessing QoS via HTTP - -In the previous example, we took the `org.apache.dubbo.demo.provider.DemoService` offline, and now we will perform a registration operation on this service using HTTP: - -``` -$ curl -i http://localhost:22222/online?service=org.apache.dubbo.demo.provider.DemoService -HTTP/1.1 200 OK -Content-Type: text/plain -Content-Length: 2 - -OK% -``` - -> Note that the parameters for the online operation need to be provided in `key=value` format, but in practice, the key will be ignored. - -Seeing that the operation returned OK, let’s check the current status using the `ls` command: - -``` -$ curl -i http://localhost:22222/ls -HTTP/1.1 200 OK -Content-Type: text/plain -Content-Length: 365 - -As Provider side: -+------------------------------------------+---+ -| Provider Service Name |PUB| -+------------------------------------------+---+ -|org.apache.dubbo.demo.provider.DemoService| Y | -+------------------------------------------+---+ -As Consumer side: -+---------------------+---+ -|Consumer Service Name|NUM| -+---------------------+---+ -``` - -We can see that the `PUB` status of the service has changed back to `Y`. - - - -## QoS Parameter Descriptions - -QoS provides several startup parameters to configure startup, which mainly include: - -| Parameter | Description | Default Value | -| ------------------ | ----------------- | ------ | -| qosEnable | Whether to start QoS | true | -| qosPort | Port bound for QoS | 22222 | -| qosAcceptForeignIp | Whether to allow remote access | false | - -> Note that starting from 2.6.4/2.7.0, the default configuration for qosAcceptForeignIp is false. If qosAcceptForeignIp is set to true, it may pose security risks, so please evaluate carefully before enabling. - -QoS parameters can be configured in the following ways: - -* System properties -* dubbo.properties -* XML method -* Spring-boot auto-configuration - -Among the above methods, the order of precedence is system properties > dubbo.properties > XML/Spring-boot auto-configuration. - -### Configuring using System Properties - -``` --Ddubbo.application.qos.enable=true --Ddubbo.application.qos.port=33333 --Ddubbo.application.qos.accept.foreign.ip=false -``` - -### Configuring using dubbo.properties file - -Create a `dubbo.properties` file under the project’s `src/main/resources` directory with the following content: -``` -dubbo.application.qos.enable=true -dubbo.application.qos.port=33333 -dubbo.application.qos.accept.foreign.ip=false -``` - -### Configuring using XML - -To configure QoS-related parameters via XML, you can use the following configuration: - -```xml - - - - - - - - - - - - -``` - -### Configuring using Spring-boot auto-configuration - -For Spring-boot applications, you can configure in the `application.properties` or `application.yml`: - -``` -dubbo.application.qosEnable=true -dubbo.application.qosPort=33333 -dubbo.application.qosAcceptForeignIp=false -``` - diff --git a/content/en/blog/java/demos/introduction-to-dubbo-spi-2.md b/content/en/blog/java/demos/introduction-to-dubbo-spi-2.md deleted file mode 100644 index b6b987146945..000000000000 --- a/content/en/blog/java/demos/introduction-to-dubbo-spi-2.md +++ /dev/null @@ -1,409 +0,0 @@ ---- -title: "Source Code Analysis of Dubbo's Extensible Mechanism" -linkTitle: "Source Code Analysis of Dubbo's Extensible Mechanism" -tags: ["Java"] -date: 2019-05-02 -description: > - This article introduces the implementation principles and details of the SPI extension mechanism. ---- - - -In [Practical Application of Dubbo's Extensible Mechanism]({{}} ""), we learned some concepts of Dubbo's extension mechanism, explored the implementation of LoadBalance in Dubbo, and implemented a LoadBalance ourselves. Think Dubbo's extension mechanism is pretty good? Next, we'll dive into the source code of Dubbo and see its true form. - -## ExtensionLoader -ExtensionLoader is the core class responsible for loading extension points and managing their lifecycle. Let's start with this class. -There are quite a few methods in ExtensionLoader, the commonly used ones are: -* `public static ExtensionLoader getExtensionLoader(Class type)` -* `public T getExtension(String name)` -* `public T getAdaptiveExtension()` - -Common usages include: -* `LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName)` -* `RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getAdaptiveExtension()` - -Note: In the source code displayed below, I will omit unrelated code (such as logging, exception handling, etc.) for easier reading and understanding. - -1. getExtensionLoader method - This is a static factory method that takes an extensible interface as a parameter and returns an instance of the ExtensionLoader for that interface. Using this instance, specific extensions can be obtained by name, and adaptive extensions can also be retrieved. - -```java -public static ExtensionLoader getExtensionLoader(Class type) { - // Extension points must be interfaces - if (!type.isInterface()) { - throw new IllegalArgumentException("Extension type(" + type + ") is not an interface!"); - } - // Must have @SPI annotation - if (!withExtensionAnnotation(type)) { - throw new IllegalArgumentException("Extension type without @SPI Annotation!"); - } - // Get the corresponding ExtensionLoader from the cache based on the interface - // Each extension will only be loaded once - ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get(type); - if (loader == null) { - // Initialize extension - EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type)); - loader = (ExtensionLoader) EXTENSION_LOADERS.get(type); - } - return loader; -} - -private ExtensionLoader(Class type) { - this.type = type; - objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); -} -``` - -2. getExtension method - -```java -public T getExtension(String name) { - Holder holder = cachedInstances.get(name); - if (holder == null) { - cachedInstances.putIfAbsent(name, new Holder()); - holder = cachedInstances.get(name); - } - Object instance = holder.get(); - // Get from cache, create if not exists - if (instance == null) { - synchronized (holder) { - instance = holder.get(); - if (instance == null) { - instance = createExtension(name); - holder.set(instance); - } - } - } - return (T) instance; -} -``` -The getExtension method does some checks and caching, the main logic is in the createExtension method. Let's continue with the createExtension method. - -```java -private T createExtension(String name) { - // Get the extension class based on the extension point name, e.g., get RandomLoadBalance class for random - Class clazz = getExtensionClasses().get(name); - - T instance = (T) EXTENSION_INSTANCES.get(clazz); - if (instance == null) { - // Use reflection to call newInstance to create an instance of the extension class - EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance()); - instance = (T) EXTENSION_INSTANCES.get(clazz); - } - // Perform dependency injection on the extension class instance - injectExtension(instance); - // If there's a wrapper, add the wrapper - Set> wrapperClasses = cachedWrapperClasses; - if (wrapperClasses != null && !wrapperClasses.isEmpty()) { - for (Class wrapperClass : wrapperClasses) { - instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); - } - } - return instance; -} -``` -The createExtension method does the following: -1. First, get the corresponding extension class by name. Read extension point configuration files from the `META-INF` folder under ClassPath. -2. Create an instance of the extension class using reflection. -3. Perform dependency injection on the properties of the extension class instance, i.e., IOC. -4. If there's a wrapper, add the wrapper, i.e., AOP. - -Next, let's focus on these 4 processes: -1. Get the corresponding extension class by name. - Looking at the code: - -```java -private Map> getExtensionClasses() { - Map> classes = cachedClasses.get(); - if (classes == null) { - synchronized (cachedClasses) { - classes = cachedClasses.get(); - if (classes == null) { - classes = loadExtensionClasses(); - cachedClasses.set(classes); - } - } - } - return classes; -} - -// synchronized in getExtensionClasses -private Map> loadExtensionClasses() { - final SPI defaultAnnotation = type.getAnnotation(SPI.class); - if (defaultAnnotation != null) { - String value = defaultAnnotation.value(); - if (value != null && (value = value.trim()).length() > 0) { - String[] names = NAME_SEPARATOR.split(value); - if (names.length > 1) { - throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()); - } - if (names.length == 1) cachedDefaultName = names[0]; - } - } - - Map> extensionClasses = new HashMap>(); - loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY); - loadFile(extensionClasses, DUBBO_DIRECTORY); - loadFile(extensionClasses, SERVICES_DIRECTORY); - return extensionClasses; -} -``` -The process is quite simple, first retrieve from the cache, and if not found, load from the configuration files located at: -* `META-INF/dubbo/internal` -* `META-INF/dubbo` -* `META-INF/services` - -2. Using reflection to create an extension instance - This is straightforward, achieved using `clazz.newInstance()`. The properties of the created extension instance are all null. -3. Automatic wiring of the extension instance - In practical scenarios, there are dependencies among classes. The extension instance will reference some dependencies. The dependency injection in Dubbo is relatively complex, and we'll cover this in detail later. For now, we need to understand that Dubbo can correctly inject ordinary dependencies in extension points, or Dubbo extension dependencies, or Spring dependencies, etc. -4. Automatic wrapping of extension instances - Automatic wrapping implements functions similar to Spring's AOP. Dubbo uses it internally to implement common functionalities such as logging and monitoring. This will also be explained later in detail. - -After the above 4 steps, Dubbo creates and initializes an extension instance. This instance's dependencies are injected and wrapped as necessary. At this point, this extension instance can be used. - -## Advanced Use of Dubbo SPI: Automatic Wiring -The relevant code for automatic wiring is in the injectExtension method: - -```java -private T injectExtension(T instance) { - for (Method method : instance.getClass().getMethods()) { - if (method.getName().startsWith("set") - && method.getParameterTypes().length == 1 - && Modifier.isPublic(method.getModifiers())) { - Class pt = method.getParameterTypes()[0]; - - String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : ""; - Object object = objectFactory.getExtension(pt, property); - if (object != null) { - method.invoke(instance, object); - } - } - } - return instance; -} -``` -To implement automatic wiring for extension instance dependencies, it's first necessary to identify what dependencies exist and their types. Dubbo's solution is to look for Java standard setter methods, i.e., methods whose names begin with "set" that take a single parameter. If the extension class has such a set method, Dubbo performs dependency injection akin to Spring's set method injection. -However, Dubbo's dependency injection is more complex than Spring's since dependencies may come from various sources such as another Dubbo extension, a Spring Bean, a Google Guice component, or any component from other frameworks. Dubbo needs to load extensions from any scenario. In the injectExtension method, this is accomplished via `Object object = objectFactory.getExtension(pt, property)`. The objectFactory is of ExtensionFactory type, initialized when creating ExtensionLoader: - -```java -private ExtensionLoader(Class type) { - this.type = type; - objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); - } -``` -The objectFactory itself is also an extension, obtained via `ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()`. - - -![Dubbo-ExtensionFactory](/imgs/blog/dubbo-extensionfactory.png "") - -ExtensionFactory has three implementations: -1. SpiExtensionFactory: Dubbo's own Spi to load Extensions -2. SpringExtensionFactory: Loads Extensions from the Spring container -3. AdaptiveExtensionFactory: Adaptive AdaptiveExtensionLoader - -Note the AdaptiveExtensionFactory; the source code is as follows: - -```java -@Adaptive -public class AdaptiveExtensionFactory implements ExtensionFactory { - - private final List factories; - - public AdaptiveExtensionFactory() { - ExtensionLoader loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class); - List list = new ArrayList(); - for (String name : loader.getSupportedExtensions()) { - list.add(loader.getExtension(name)); - } - factories = Collections.unmodifiableList(list); - } - - public T getExtension(Class type, String name) { - for (ExtensionFactory factory : factories) { - T extension = factory.getExtension(type, name); - if (extension != null) { - return extension; - } - } - return null; - } -} -``` -The AdaptiveExtensionLoader class has the @Adaptive annotation. As mentioned earlier, Dubbo creates an adaptive instance for every extension. If the extension class has @Adaptive, that class will be used as the adaptive class. If not, Dubbo will create one for us. Thus, `ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()` returns an instance of AdaptiveExtensionLoader as the adaptive extension instance. -AdaptiveExtensionLoader traverses all ExtensionFactory implementations to attempt to load extensions. If found, it returns it. If not, it continues looking in the next ExtensionFactory. Dubbo has two built-in ExtensionFactory instances that find from both Dubbo's own extension mechanism and the Spring container. Since ExtensionFactory is also an extension point, we can implement our own ExtensionFactory to allow Dubbo's automatic wiring to support our custom components. For instance, if we used Google Guice as the IoC container in our project, we could create our own GuiceExtensionFactory to make Dubbo support loading extensions from the Guice container. - -## Advanced Use of Dubbo SPI: AOP -While using Spring, we often utilize AOP functionality. Logic is inserted before and after the target class's methods, commonly used for logging, monitoring, and authorization. -Does Dubbo's extension mechanism support similar functionality? The answer is yes. In Dubbo, there is a special type of class known as a Wrapper class. By using the decorator pattern, Wrapper classes wrap the original extension point instances and insert logic before and after the original extension implementations, achieving AOP functionality. - -### What is a Wrapper class? -What types of classes qualify as Wrapper classes in Dubbo's extension mechanism? A Wrapper class is a class that has a copy constructor, displaying the typical decorator pattern. Here is an example of a Wrapper class: - -```java -class A{ - private A a; - public A(A a){ - this.a = a; - } -} -``` -Class A has a constructor `public A(A a)` where the parameter is an instance of A itself. Such a class can be a Wrapper class in Dubbo's extension mechanism. Some examples of Wrapper classes in Dubbo include ProtocolFilterWrapper and ProtocolListenerWrapper; the source code can be reviewed for deeper understanding. - -### How to configure Wrapper classes - -In Dubbo, Wrapper classes are also extension points, and like other extension points, they are configured in the `META-INF` directory. For instance, the ProtocolFilterWrapper and ProtocolListenerWrapper examples mentioned earlier are configured at the path `dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol`: -```text -filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper -listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper -mock=org.apache.dubbo.rpc.support.MockProtocol -``` -When Dubbo loads the extension configuration files, the following code snippet executes: - -```java -try { - clazz.getConstructor(type); - Set> wrappers = cachedWrapperClasses; - if (wrappers == null) { - cachedWrapperClasses = new ConcurrentHashSet>(); - wrappers = cachedWrapperClasses; - } - wrappers.add(clazz); -} catch (NoSuchMethodException e) {} -``` -This means if the extension class has a copy constructor, it's stored for future use. Classes with a copy constructor qualify as Wrapper classes. The constructor is obtained through `clazz.getConstructor(type)`, where the parameter is the extension point interface, not the extension class itself. -Taking Protocol as an example, the configuration file at `dubbo-rpc/dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol` defines `filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper`. -Here’s the code for ProtocolFilterWrapper: - -```java -public class ProtocolFilterWrapper implements Protocol { - - private final Protocol protocol; - - // Copy constructor parameter is Protocol - public ProtocolFilterWrapper(Protocol protocol) { - if (protocol == null) { - throw new IllegalArgumentException("protocol == null"); - } - this.protocol = protocol; - } -} -``` -ProtocolFilterWrapper has a constructor `public ProtocolFilterWrapper(Protocol protocol)`, the parameter is the extension point Protocol, making it a Wrapper class in Dubbo's extension mechanism. ExtensionLoader caches it for use later when creating Extension instances, applying these wrapper classes in sequence to wrap the original extension point. - -## Adaptive extension points - -As mentioned before, Dubbo needs to decide at runtime which extension to use based on method parameters, leading to the need for adaptive instances of extension points. Essentially, these are proxies that defer the choice of extensions from Dubbo startup to RPC invocation time. Each extension point in Dubbo has an adaptive class created automatically by Dubbo if not explicitly provided, using Javaassist by default. -Let’s take a look at the code that creates adaptive extension classes: - -```java -public T getAdaptiveExtension() { - Object instance = cachedAdaptiveInstance.get(); - if (instance == null) { - synchronized (cachedAdaptiveInstance) { - instance = cachedAdaptiveInstance.get(); - if (instance == null) { - instance = createAdaptiveExtension(); - cachedAdaptiveInstance.set(instance); - } - } - } - - return (T) instance; -} -``` -Continuing on to the createAdaptiveExtension method: - -```java -private T createAdaptiveExtension() { - return injectExtension((T) getAdaptiveExtensionClass().newInstance()); -} -``` -Next, let's see the getAdaptiveExtensionClass method: - -```java -private Class getAdaptiveExtensionClass() { - getExtensionClasses(); - if (cachedAdaptiveClass != null) { - return cachedAdaptiveClass; - } - return cachedAdaptiveClass = createAdaptiveExtensionClass(); - } -``` -Continuing to the createAdaptiveExtensionClass method, we finally arrive at the specific implementation. This method generates the Java source code for the adaptive class, compiles it into Java bytecode, and loads it into the JVM. - -```java -private Class createAdaptiveExtensionClass() { - String code = createAdaptiveExtensionClassCode(); - ClassLoader classLoader = findClassLoader(); - org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); - return compiler.compile(code, classLoader); - } -``` -The default implementation of the Compiler is javassist. - -```java -@SPI("javassist") -public interface Compiler { - Class compile(String code, ClassLoader classLoader); -} -``` -In the createAdaptiveExtensionClassCode() method, a StringBuilder is used to build the Java source code for the adaptive class. The implementation is relatively long, which won't be pasted here. This approach of generating bytecode is interesting, initially generating Java source code, then compiling and loading it into the JVM. This allows for better control over generated Java classes without having to care about various bytecode generation framework APIs. As the .java file format is universal in Java and familiar, the content must be constructed incrementally for readability. -Here is an example of the Java code for an adaptive class created for Protocol using the createAdaptiveExtensionClassCode method: - -```java -package org.apache.dubbo.rpc; - -import org.apache.dubbo.common.extension.ExtensionLoader; - -public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol { - public void destroy() { - throw new UnsupportedOperationException("method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!"); - } - - public int getDefaultPort() { - throw new UnsupportedOperationException("method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!"); - } - - public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException { - if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null"); - if (arg0.getUrl() == null) - throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null"); - org.apache.dubbo.common.URL url = arg0.getUrl(); - String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); - if (extName == null) - throw new IllegalStateException("Fail to get extension(org.apache.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); - org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName); - return extension.export(arg0); - } - - public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException { - if (arg1 == null) throw new IllegalArgumentException("url == null"); - org.apache.dubbo.common.URL url = arg1; - String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); - if (extName == null) - throw new IllegalStateException("Fail to get extension(org.apache.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); - org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName); - return extension.refer(arg0, arg1); - } -} -``` -The overall logic is consistent with what was previously stated, where parameters are resolved through URL, and the resolution logic is controlled by the value parameter of the @Adaptive annotation, after which the corresponding extension point implementation is fetched for invocation. For those interested in the specifics of constructing the .java code, the complete implementation of createAdaptiveExtensionClassCode can be referred to. -In the generated Protocol$Adaptive, we observe that the getDefaultPort and destroy methods directly throw exceptions. Why is that? Let's look at the Protocol source code. - -```java -@SPI("dubbo") -public interface Protocol { - - int getDefaultPort(); - - @Adaptive - Exporter export(Invoker invoker) throws RpcException; - - @Adaptive - Invoker refer(Class type, URL url) throws RpcException; - - void destroy(); -} -``` -It can be seen that the Protocol interface has 4 methods, but only the export and refer methods use the @Adaptive annotation. Therefore, only the methods marked with @Adaptive in the automatically generated adaptive instances have concrete implementations, which is why Protocol$Adaptive contains implementations for only the export and refer methods, while the others throw exceptions. - diff --git a/content/en/blog/java/demos/introduction-to-dubbo-spi.md b/content/en/blog/java/demos/introduction-to-dubbo-spi.md deleted file mode 100644 index be9d4a6f0af4..000000000000 --- a/content/en/blog/java/demos/introduction-to-dubbo-spi.md +++ /dev/null @@ -1,232 +0,0 @@ ---- -title: "Dubbo可扩展机制实战" -linkTitle: "Dubbo可扩展机制实战" -tags: ["Java"] -date: 2019-04-25 -description: > - description: 本文介绍了Dubbo框架的核心,SPI扩展机制。 ---- - -## 1. Dubbo的扩展机制 -在Dubbo的官网上,Dubbo描述自己是一个高性能的RPC框架。今天我想聊聊Dubbo的另一个很棒的特性, 就是它的可扩展性。 -如同罗马不是一天建成的,任何系统都一定是从小系统不断发展成为大系统的,想要从一开始就把系统设计的足够完善是不可能的,相反的,我们应该关注当下的需求,然后再不断地对系统进行迭代。在代码层面,要求我们适当的对关注点进行抽象和隔离,在软件不断添加功能和特性时,依然能保持良好的结构和可维护性,同时允许第三方开发者对其功能进行扩展。在某些时候,软件设计者对扩展性的追求甚至超过了性能。 - -在谈到软件设计时,可扩展性一直被谈起,那到底什么才是可扩展性,什么样的框架才算有良好的可扩展性呢?它必须要做到以下两点: -1. 作为框架的维护者,在添加一个新功能时,只需要添加一些新代码,而不用大量的修改现有的代码,即符合开闭原则。 -2. 作为框架的使用者,在添加一个新功能时,不需要去修改框架的源码,在自己的工程中添加代码即可。 - -Dubbo很好的做到了上面两点。这要得益于Dubbo的微内核+插件的机制。接下来的章节中我们会慢慢揭开Dubbo扩展机制的神秘面纱。 - -## 2. 可扩展的几种解决方案 -通常可扩展的实现有下面几种: -* Factory模式 -* IoC容器 -* OSGI容器 - -Dubbo作为一个框架,不希望强依赖其他的IoC容器,比如Spring,Guice。OSGI也是一个很重的实现,不适合Dubbo。最终Dubbo的实现参考了Java原生的SPI机制,但对其进行了一些扩展,以满足Dubbo的需求。 - -## 3. Java SPI机制 -既然Dubbo的扩展机制是基于Java原生的SPI机制,那么我们就先来了解下Java SPI吧。了解了Java的SPI,也就是对Dubbo的扩展机制有一个基本的了解。如果对Java SPI比较了解的同学,可以跳过。 - -Java SPI(Service Provider Interface)是JDK内置的一种动态加载扩展点的实现。在ClassPath的`META-INF/services`目录下放置一个与接口同名的文本文件,文件的内容为接口的实现类,多个实现类用换行符分隔。JDK中使用`java.util.ServiceLoader`来加载具体的实现。 -让我们通过一个简单的例子,来看看Java SPI是如何工作的。 - -1. 定义一个接口IRepository用于实现数据储存 -```java -public interface IRepository { - void save(String data); -} -``` - -2. 提供IRepository的实现 - IRepository有两个实现。MysqlRepository和MongoRepository。 - -```java -public class MysqlRepository implements IRepository { - public void save(String data) { - System.out.println("Save " + data + " to Mysql"); - } -} -``` - -```java -public class MongoRepository implements IRepository { - public void save(String data) { - System.out.println("Save " + data + " to Mongo"); - } -} -``` - -3. 添加配置文件 - 在`META-INF/services`目录添加一个文件,文件名和接口全名称相同,所以文件是`META-INF/services/com.demo.IRepository`。文件内容为: - -```text -com.demo.MongoRepository -com.demo.MysqlRepository -``` - -4. 通过ServiceLoader加载IRepository实现 - -```java -ServiceLoader serviceLoader = ServiceLoader.load(IRepository.class); -Iterator it = serviceLoader.iterator(); -while (it != null && it.hasNext()){ - IRepository demoService = it.next(); - System.out.println("class:" + demoService.getClass().getName()); - demoService.save("tom"); -} -``` -在上面的例子中,我们定义了一个扩展点和它的两个实现。在ClassPath中添加了扩展的配置文件,最后使用ServiceLoader来加载所有的扩展点。 -最终的输出结果为: -class:testDubbo.MongoRepository -Save tom to Mongo -class:testDubbo.MysqlRepository -Save tom to Mysql - -## 4. Dubbo的SPI机制 - -Java SPI的使用很简单。也做到了基本的加载扩展点的功能。但Java SPI有以下的不足: -* 需要遍历所有的实现,并实例化,然后我们在循环中才能找到我们需要的实现。 -* 配置文件中只是简单的列出了所有的扩展实现,而没有给他们命名。导致在程序中很难去准确的引用它们。 -* 扩展如果依赖其他的扩展,做不到自动注入和装配 -* 不提供类似于Spring的IOC和AOP功能 -* 扩展很难和其他的框架集成,比如扩展里面依赖了一个Spring bean,原生的Java SPI不支持 - -所以Java SPI应付一些简单的场景是可以的,但对于Dubbo,它的功能还是比较弱的。Dubbo对原生SPI机制进行了一些扩展。接下来,我们就更深入地了解下Dubbo的SPI机制。 - -## 5. Dubbo扩展点机制基本概念 -在深入学习Dubbo的扩展机制之前,我们先明确Dubbo SPI中的一些基本概念。在接下来的内容中,我们会多次用到这些术语。 - -### 5.1 扩展点(Extension Point) -是一个Java的接口。 - -### 5.2 扩展(Extension) -扩展点的实现类。 - -### 5.3 扩展实例(Extension Instance) -扩展点实现类的实例。 - -### 5.4 扩展自适应实例(Extension Adaptive Instance) -第一次接触这个概念时,可能不太好理解(我第一次也是这样的...)。如果称它为扩展代理类,可能更好理解些。扩展的自适应实例其实就是一个Extension的代理,它实现了扩展点接口。在调用扩展点的接口方法时,会根据实际的参数来决定要使用哪个扩展。比如一个IRepository的扩展点,有一个save方法。有两个实现MysqlRepository和MongoRepository。IRepository的自适应实例在调用接口方法的时候,会根据save方法中的参数,来决定要调用哪个IRepository的实现。如果方法参数中有repository=mysql,那么就调用MysqlRepository的save方法。如果repository=mongo,就调用MongoRepository的save方法。和面向对象的延迟绑定很类似。为什么Dubbo会引入扩展自适应实例的概念呢? -* Dubbo中的配置有两种,一种是固定的系统级别的配置,在Dubbo启动之后就不会再改了。还有一种是运行时的配置,可能对于每一次的RPC,这些配置都不同。比如在xml文件中配置了超时时间是10秒钟,这个配置在Dubbo启动之后,就不会改变了。但针对某一次的RPC调用,可以设置它的超时时间是30秒钟,以覆盖系统级别的配置。对于Dubbo而言,每一次的RPC调用的参数都是未知的。只有在运行时,根据这些参数才能做出正确的决定。 -* 很多时候,我们的类都是一个单例的,比如Spring的bean,在Spring bean都实例化时,如果它依赖某个扩展点,但是在bean实例化时,是不知道究竟该使用哪个具体的扩展实现的。这时候就需要一个代理模式了,它实现了扩展点接口,方法内部可以根据运行时参数,动态的选择合适的扩展实现。而这个代理就是自适应实例。 - 自适应扩展实例在Dubbo中的使用非常广泛,Dubbo中,每一个扩展都会有一个自适应类,如果我们没有提供,Dubbo会使用字节码工具为我们自动生成一个。所以我们基本感觉不到自适应类的存在。后面会有例子说明自适应类是怎么工作的。 - -### 5.5 @SPI -@SPI注解作用于扩展点的接口上,表明该接口是一个扩展点。可以被Dubbo的ExtensionLoader加载。如果没有此ExtensionLoader调用会异常。 - -### 5.6 @Adaptive -@Adaptive注解用在扩展接口的方法上。表示该方法是一个自适应方法。Dubbo在为扩展点生成自适应实例时,如果方法有@Adaptive注解,会为该方法生成对应的代码。方法内部会根据方法的参数,来决定使用哪个扩展。 -@Adaptive注解用在类上代表实现一个装饰类,类似于设计模式中的装饰模式,它主要作用是返回指定类,目前在整个系统中AdaptiveCompiler、AdaptiveExtensionFactory这两个类拥有该注解。 - - -### 5.7 ExtensionLoader -类似于Java SPI的ServiceLoader,负责扩展的加载和生命周期维护。 - -### 5.8 扩展别名 -和Java SPI不同,Dubbo中的扩展都有一个别名,用于在应用中引用它们。比如 - -```bash -random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance -roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance -``` -其中的random,roundrobin就是对应扩展的别名。这样我们在配置文件中使用random或roundrobin就可以了。 - -### 5.9 一些路径 -和Java SPI从`/META-INF/services`目录加载扩展配置类似,Dubbo也会从以下路径去加载扩展配置文件: -* `META-INF/dubbo/internal` -* `META-INF/dubbo` -* `META-INF/services` - -## 6. Dubbo的LoadBalance扩展点解读 -在了解了Dubbo的一些基本概念后,让我们一起来看一个Dubbo中实际的扩展点,对这些概念有一个更直观的认识。 - -我们选择的是Dubbo中的LoadBalance扩展点。Dubbo中的一个服务,通常有多个Provider,consumer调用服务时,需要在多个Provider中选择一个。这就是一个LoadBalance。我们一起来看看在Dubbo中,LoadBalance是如何成为一个扩展点的。 - -### 6.1 LoadBalance接口 - -```java -@SPI(RandomLoadBalance.NAME) -public interface LoadBalance { - - @Adaptive("loadbalance") - Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException; -} -``` -LoadBalance接口只有一个select方法。select方法从多个invoker中选择其中一个。上面代码中和Dubbo SPI相关的元素有: -* @SPI(RandomLoadBalance.NAME) - @SPI作用于LoadBalance接口,表示接口LoadBalance是一个扩展点。如果没有@SPI注解,试图去加载扩展时,会抛出异常。@SPI注解有一个参数,该参数表示该扩展点的默认实现的别名。如果没有显示的指定扩展,就使用默认实现。`RandomLoadBalance.NAME`是一个常量,值是"random",是一个随机负载均衡的实现。 - random的定义在配置文件`META-INF/dubbo/internal/com.alibaba.dubbo.rpc.cluster.LoadBalance`中: - -```bash -random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance -roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance -leastactive=com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance -consistenthash=com.alibaba.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance -``` -可以看到文件中定义了4个LoadBalance的扩展实现。由于负载均衡的实现不是本次的内容,这里就不过多说明。只用知道Dubbo提供了4种负载均衡的实现,我们可以通过xml文件,properties文件,JVM参数显式的指定一个实现。如果没有,默认使用随机。 - - -![img](/imgs/blog/dubbo_loadbalance.png) - -* @Adaptive("loadbalance") - @Adaptive注解修饰select方法,表明方法select方法是一个可自适应的方法。Dubbo会自动生成该方法对应的代码。当调用select方法时,会根据具体的方法参数来决定调用哪个扩展实现的select方法。@Adaptive注解的参数`loadbalance`表示方法参数中的loadbalance的值作为实际要调用的扩展实例。 - 但奇怪的是,我们发现select的方法中并没有loadbalance参数,那怎么获取loadbalance的值呢?select方法中还有一个URL类型的参数,Dubbo就是从URL中获取loadbalance的值的。这里涉及到Dubbo的URL总线模式,简单说,URL中包含了RPC调用中的所有参数。URL类中有一个`Map parameters`字段,parameters中就包含了loadbalance。 - -### 6.2 获取LoadBalance扩展 -Dubbo中获取LoadBalance的代码如下: - -```java -LoadBalance lb = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadbalanceName); -``` -使用ExtensionLoader.getExtensionLoader(LoadBalance.class)方法获取一个ExtensionLoader的实例,然后调用getExtension,传入一个扩展的别名来获取对应的扩展实例。 - -## 7. 自定义一个LoadBalance扩展 -本节中,我们通过一个简单的例子,来自己实现一个LoadBalance,并把它集成到Dubbo中。我会列出一些关键的步骤和代码,也可以从这个地址([https://github.com/vangoleo/dubbo-spi-demo](https://github.com/vangoleo/dubbo-spi-demo))下载完整的demo。 - -### 7.1 实现LoadBalance接口 -首先,编写一个自己实现的LoadBalance,因为是为了演示Dubbo的扩展机制,而不是LoadBalance的实现,所以这里LoadBalance的实现非常简单,选择第一个invoker,并在控制台输出一条日志。 - -```java -package com.dubbo.spi.demo.consumer; -public class DemoLoadBalance implements LoadBalance { - @Override - public Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException { - System.out.println("DemoLoadBalance: Select the first invoker..."); - return invokers.get(0); - } -} -``` - -### 7.2 添加扩展配置文件 -添加文件:`META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.LoadBalance`。文件内容如下: - -```bash -demo=com.dubbo.spi.demo.consumer.DemoLoadBalance -``` - -### 7.3 配置使用自定义LoadBalance -通过上面的两步,已经添加了一个名字为demo的LoadBalance实现,并在配置文件中进行了相应的配置。接下来,需要显式的告诉Dubbo使用demo的负载均衡实现。如果是通过spring的方式使用Dubbo,可以在xml文件中进行设置。 - -```xml - -``` -在consumer端的[dubbo:reference](dubbo:reference)中配置 - -### 7.4 启动Dubbo -启动Dubbo,调用一次IHelloService,可以看到控制台会输出一条`DemoLoadBalance: Select the first invoker...`日志。说明Dubbo的确是使用了我们自定义的LoadBalance。 - - -## 总结 -到此,我们从Java SPI开始,了解了Dubbo SPI 的基本概念,并结合了Dubbo中的LoadBalance加深了理解。最后,我们还实践了一下,创建了一个自定义LoadBalance,并集成到Dubbo中。相信通过这里理论和实践的结合,大家对Dubbo的可扩展有更深入的理解。 -总结一下,Dubbo SPI有以下的特点: -* 对Dubbo进行扩展,不需要改动Dubbo的源码 -* 自定义的Dubbo的扩展点实现,是一个普通的Java类,Dubbo没有引入任何Dubbo特有的元素,对代码侵入性几乎为零。 -* 将扩展注册到Dubbo中,只需要在ClassPath中添加配置文件。使用简单。而且不会对现有代码造成影响。符合开闭原则。 -* dubbo的扩展机制设计默认值:@SPI("dubbo") 代表默认的spi对象 -* Dubbo的扩展机制支持IoC,AoP等高级功能 -* Dubbo的扩展机制能很好的支持第三方IoC容器,默认支持Spring Bean,可自己扩展来支持其他容器,比如Google的Guice。 -* 切换扩展点的实现,只需要在配置文件中修改具体的实现,不需要改代码。使用方便。 - - -下一篇,我们将会一起深入Dubbo的源码,更深入的了解Dubbo的可扩展机制。 diff --git a/content/en/blog/java/demos/multiple-protocols-registries.md b/content/en/blog/java/demos/multiple-protocols-registries.md deleted file mode 100644 index b9b08d15c157..000000000000 --- a/content/en/blog/java/demos/multiple-protocols-registries.md +++ /dev/null @@ -1,291 +0,0 @@ ---- -title: "Dubbo Connecting Heterogeneous Microservice Architecture - Multi-Protocol & Multi-Registry" -linkTitle: "Dubbo Connecting Heterogeneous Microservice Architecture - Multi-Protocol & Multi-Registry" -tags: ["Java"] -date: 2023-01-05 -description: > - This article introduces Dubbo's multi-protocol and multi-registry support solutions, and how to achieve capabilities such as multi-protocol coexistence, intercommunication, and migration. ---- - -From a programming development perspective, Dubbo is primarily an RPC service framework. Its greatest advantage lies in providing an interface-based service programming model that shields developers from the underlying remote communication details. At the same time, Dubbo is also a service governance framework, offering solutions for service discovery, traffic scheduling, and other service governance aspects for microservices deployed in a distributed manner. - -In this article, we will explore how to leverage Dubbo's support for multiple protocols and service discovery models to achieve interconnectivity between heterogeneous microservice architectures. In practical business scenarios, this can address communication issues under heterogeneous technology stacks, facilitate smooth migrations, and solve challenges like address discovery and traffic scheduling in large-scale, cross-regional, and multi-cluster deployments. - -## Interface-Based Transparent Service Development Framework - -We start with the well-known concept that **Dubbo is a microservice development framework**. Just as Spring serves as a foundation for developing Java applications, Dubbo is often chosen as the basic framework for microservices development. I believe Dubbo's biggest advantage is its interface-oriented programming model, allowing developers to invoke remote services as if they were local services (using Java as an example): - -1. Service Definition - -```java -public interface GreetingsService { - String sayHi(String name); -} -``` - -2. Consumer Calls Service - -```java -// Completely transparent, just like calling a local service. -@Reference -private GreetingService greetingService; - -public void doSayHello(String name) { - greetingService.sayHi("Hello world!"); -} -``` - -The diagram below illustrates the basic working principle of Dubbo, where service providers and consumers coordinate addresses via a registry and exchange data using a predefined protocol. - -![Dubbo basic work flow](/imgs/blog/2023/01/protocols/img.png) - -## Problems Faced by Homogeneous/Heterogeneous Microservice Systems - -The specifics of the Dubbo protocol itself and related service governance functionalities are not the focus of this article. Instead, we'll examine the challenges faced by organizations in building internal microservice architectures and discuss how Dubbo can offer solutions for architectural selection and migration. - -An organization's microservices may be developed using the same service framework, such as Dubbo, which we refer to as a **homogeneous microservice system**. On the other hand, some organizations may construct their microservices using multiple different frameworks, which we call a **heterogeneous microservice system**. The co-existence of various technology stack microservice systems within large organizations is quite common, and there can be many reasons for this scenario—ranging from legacy systems to ongoing technology stack migrations, or independent selections made by different business departments to meet specific needs. - -**1. Coexistence of Heterogeneous Microservice Systems** - -One immediate challenge is: **Different systems usually utilize different RPC communication protocols and deploy independent registry clusters. How do we achieve transparent address discovery and transparent RPC calls in such a multi-protocol, multi-registry cluster environment?** If we do nothing, each microservice system can only recognize the service status within its own environment, resulting in isolated traffic. For a smooth migration from system A to system B, or to maintain the coexistence of multiple systems internal to the company, achieving interconnectivity and transparent traffic scheduling will be critical. - -![2](/imgs/blog/2023/01/protocols/img_1.png) - -**2. Within the Dubbo System** - -**The issues of multi-protocol and multi-registry clusters can also exist in homogeneous microservice systems, especially when the scale of microservices within an organization grows significantly.** - -* We may need to use different communication protocols between different services, as they face various business scenarios, leading to distinct data transmission characteristics. We need to adopt protocols that better fit the specific business characteristics. For example, in typical scenarios, we might use the Dubbo protocol for standard business services, HTTP protocol for services interacting with the FrontEnd, and gRPC protocol for services requiring streaming data transmission. - -* Another common issue within the Dubbo system arises in large-scale distributed deployments, where microservices may be deployed across regions and registries, thereby encountering problems with address synchronization and traffic scheduling between multiple clusters. - -In summary, **both homogeneous and heterogeneous systems face challenges with multi-protocol communication and multi-registry address discovery.** Dubbo currently supports multiple protocols and registries, which is essentially designed to address the scenarios analyzed within homogeneous Dubbo systems. Therefore, we will start by discussing the basic multi-protocol and multi-registry support provided by Dubbo in homogeneous systems, before further exploring how to extend this capability to support interconnectivity in heterogeneous microservice systems. - -## Multi-Protocol and Multi-Registry Mechanism in the Dubbo System - -We will illustrate the use and working principles of Dubbo's multi-protocol and multi-registry mechanisms through two scenarios. - -### Multi-Protocol - -![undefined](/imgs/blog/2023/01/protocols/img_2.png) - -The above illustrates a set of microservices developed using Dubbo, with different protocols utilized for communication between services. According to our research, the adoption of multiple protocols within organizations is a common requirement, though we won’t explain specific scenarios here. - -Application B serves as the provider, publishing five services, including: - -* `DemoService1` and `DemoService2` published using the `dubbo` protocol -* `DemoService3` and `DemoService4` published using the `gRPC` protocol -* `DemoService0` published with both `dubbo` and `gRPC` protocols - -Application A acts as a consumer, consuming `DemoService1` and `DemoService2` using the dubbo protocol, and `DemoService0` using the gRPC protocol. - -Application B, as a consumer, consumes `DemoService2` and `DemoService4` using the gRPC protocol, and `DemoService0` using the dubbo protocol. - -Here are the specific code configurations: - -1. Provider Application B - -```xml - - - - - - - -``` - -2. Consumer Application A - -```xml - - - - -``` - -3. Consumer Application C - -```xml - - - - -``` - -#### Current Support Status of Dubbo Multi-Protocol - -The protocols currently supported by Dubbo include Dubbo, REST, Thrift, gRPC, JsonRPC, Hessian, etc., covering most mainstream RPC communication protocols in the industry. It’s worth noting that these protocol supports are implemented through direct integration with official releases, which I believe is a good choice as it ensures protocol parsing stability while allowing the Dubbo community to focus more on improving service governance capabilities around Dubbo. Imagine the amount of energy and time the community would have to spend if they had to provide implementations for every protocol themselves. - -In addition to the officially supported protocols, thanks to Dubbo's flexible extension mechanism, it is very easy for developers to extend Dubbo with additional protocol supports, including proprietary protocol extensions. - -For support regarding gRPC (HTTP/2) protocol, please refer to the previous document. - -![3](/imgs/blog/2023/01/protocols/img_3.png) - -#### Problems Solvable by Multi-Protocol - -* Seamlessly integrating the RPC framework into Dubbo's service governance system. - - By integrating RPC protocols through protocol extensions, we can reuse Dubbo's programming model and capabilities like service discovery and traffic control. For instance, gRPC's service governance system is relatively weak, and its programming API is not very user-friendly, making it difficult to use in microservice development. - -* Meeting diverse calling needs in various scenarios. - - Different services may be developed to meet specific business needs, while the technology stacks of external consumer applications may vary, enabling the optimization of communication needs in different scenarios through the use of various communication protocols. - -* Realizing protocol migration. - - By supporting multiple protocols, and with the coordination of the registry, we can quickly fulfill the need for protocol migration within the company. This could involve upgrading from a proprietary protocol to Dubbo, upgrading Dubbo itself, migrating from Dubbo to gRPC, or migrating from REST to Dubbo. - -### Multi-Registry - -When the service cluster is small, a centralized cluster deployment solution can effectively address our business problems. However, as application scale increases and user traffic grows, we must consider introducing cross-regional, multi-cluster deployment solutions for the business system. This brings forth deployment solution options for the registries closely related to the business systems: - -1. Continue maintaining a globally shared registry cluster. The advantage of this architecture scheme is its simplicity; its drawback is that the registry cluster must keep complete address data, which might impose significant storage and pushing pressures. Additionally, for certain registry products (like Zookeeper), stability and performance may be challenged in cross-cluster network deployments. - -2. Deploy independent registry clusters for each business cluster. The advantages of multi-registry clusters include solving cross-cluster network availability issues and alleviating storage and pushing pressures on the registry. The drawback is that the service framework (like Dubbo) must support publishing/listening to multiple registry clusters simultaneously. - -Let’s look closely at the solutions Dubbo provides for multi-registry cluster scenarios. - -![4](/imgs/blog/2023/01/protocols/img_4.png) - -The diagram above shows two business clusters located in Beijing and Shanghai, each having its own independent registry cluster, solving the issue of transparent RPC communication between the two business clusters. - -1. Service Provider, Dual Registry Publishing - -```xml - - - - -``` - -2. Service Consumer, Subscription to Single/Dual Registries Based on Needs - -```xml - - - - - - - - - -``` - -#### Dubbo's Support for Heterogeneous Registry Clusters - -Although we may deploy multi-registry clusters, we typically use the same registry products, such as all Zookeeper or Nacos. In the context of migrating registries, Dubbo must provide support for a broader range of registry products or, most importantly, offer strong extensibility. Currently, the registry implementations supported officially by Dubbo are: - -![5](/imgs/blog/2023/01/protocols/img_5.png) - -It is particularly important to mention that Dubbo's service registration/discovery model currently operates at the interface granularity, while starting from version 2.7.5, Dubbo has introduced a service registration/discovery model at the application granularity. This not only helps optimize Dubbo's current service discovery mechanism and enhance service capacity but is also crucial for connecting microservice architectures represented by SpringCloud (this point will be elaborated in the next chapter). More information on "Application Granularity Service Discovery: Service Self-Inspection" will be provided in upcoming articles or documents, so please stay tuned. - -#### Traffic Scheduling Issues Arising from Multi-Subscription - -With the introduction of multi-registry clusters, Dubbo introduces an additional layer of load balancing among registry clusters when determining traffic allocation: - -![6](/imgs/blog/2023/01/protocols/img_6.png) - -At the Cluster Invoker level, the selection strategies we support are (for version 2.7.5+; specific usage can be found in the documentation): - -* Specify Priority - - ```xml - - - ``` - -* Same Zone Priority - - ```xml - - - ``` - -* Weight Polling - - ```xml - - - - ``` - -* Default, stick to any available one - -#### Scenarios Suitable for Multi-Registry - -* Same Regional Traffic Priority Scheduling - - For disaster recovery or service scalability needs, services/applications often require deployment across multiple independent data centers/regions. In scenarios where each region has its own independent registry cluster, implementing same-region traffic priority scheduling can effectively resolve latency and availability issues. - -* Registry Migration - - A company’s services may have historically been stored in a single registry, such as Zookeeper. However, at certain points, for various reasons, when we need to migrate to another registry, a multi-registry model ensures a smooth transition. - -* Interconnectivity of Heterogeneous Systems - - Services developed within different microservice architectures are isolated within their own service discovery systems; however, through a unified multi-registry model, services across different systems can discover one another. - -## Leveraging Dubbo to Connect Heterogeneous Microservice Systems - -As mentioned earlier, there are various valid possibilities for the existence of heterogeneous microservice systems within organizations. Now, let's look specifically at real scenarios involving heterogeneous microservice systems and methods utilizing Dubbo for interconnectivity. First, let's visualize what interconnecting heterogeneous microservice systems looks like. - -![7](/imgs/blog/2023/01/protocols/img_7.png) - -As shown in the diagram, some microservices are built on SpringCloud, gRPC, K8S, or self-constructed architectures, and they are typically isolated and unable to communicate with each other. When we construct a set of microservices based on Dubbo, utilizing Dubbo's multi-protocol and multi-service discovery models allows for bi-directional connectivity between heterogeneous microservice systems. Further, as indicated by the orange arrows in the illustration, relying on the Dubbo system as a bridge, we can facilitate connections between two heterogeneous microservice systems. - -For several example scenarios, since there is currently no unified standard for address discovery, we will assume for now that there are no obstacles at the address discovery layer, focusing on the basic migration processes and communication protocols. (We will delve deeper into address discovery in an upcoming article titled "Service Self-Inspection: Application Granularity Service Discovery".) - -### Protocol Migration within the Dubbo System (Coexistence) - -Most developers hold a conventional understanding that using Dubbo to develop microservice systems necessitates employing the Dubbo protocol as the optimal inter-service communication protocol. In reality, we are not limited to only the Dubbo RPC protocol. Dubbo as a microservice development framework and Dubbo as an RPC protocol are distinct concepts and can be considered separately. For instance, it is entirely acceptable for business systems developed using the Dubbo framework to utilize REST or gRPC for communication (as shown in the list of protocols supported by Dubbo); the choice of protocol should be based on business characteristics and technical planning. - -![8](/imgs/blog/2023/01/protocols/img_8.png) - -In the current cloud-native and mesh background, HTTP/1.2 and gRPC protocols are gaining increasing attention; one reason for this is their superior standardization, garnering support from more networking devices and infrastructure and exhibiting better universality and penetration. For many enterprises willing to migrate to cloud-native architectures, transitioning to such protocols undoubtedly aids future architectural upgrades. - -The diagram below illustrates an intermediate state during the migration from the Dubbo protocol to the gRPC protocol within the Dubbo system. - -![9](/imgs/blog/2023/01/protocols/img_9.png) - -* The far-left represents legacy applications that have not yet migrated; these applications must still consume and provide services using the Dubbo protocol during the migration period. -* The middle section signifies applications in the process of migration, potentially acting as service providers by offering Dubbo protocol services to the legacy systems on the left while simultaneously providing gRPC services to the new systems on the right; thus, they expose services using both protocols. -* The far-right represents newly developed or fully migrated applications, where communication can entirely occur over the gRPC protocol. -* After traversing the intermediate state, we expect to achieve a situation where all applications can communicate entirely using the gRPC protocol. - -### Migration from Spring Cloud System to Dubbo System (Coexistence) - -As previously mentioned, due to issues with service discovery models between SpringCloud and Dubbo, enabling address intercommunication necessitates corresponding adaptations on the Dubbo side. During the release of version 2.7.5, we will address this content in the "Service Self-Inspection" section. For now, we will assume the connection has been established. - -![10](/imgs/blog/2023/01/protocols/img_10.png) - -Certain applications within the Dubbo system serve as transparent key nodes for connecting the two systems; some service provider applications must publish dual protocols, and some consumer applications must select protocols for consumption. Since modifications to the legacy Spring Cloud system are not permitted, the key for interconnecting the two architectures lies in the REST protocol. For applications on the Dubbo side: - -* Some applications may consume services from SpringCloud via REST protocol; -* Some applications may expose services for SpringCloud consumers using the REST protocol; -* Internally within Dubbo's own system, communication can occur through a selected protocol, providing flexibility to choose between Dubbo, REST, or gRPC. If REST is chosen, the connection to SpringCloud becomes more natural as both sides utilize the same protocol. - -For applications consuming Spring Cloud services, the service configuration would be: - -```xml - -``` - -For applications exposing services for consumption by Spring Cloud, it can specify the service exposure as a REST protocol or dual-protocol exposure (if that service is intended for calls by applications in the new system): - -```xml - -``` - -As maintainers of Dubbo, while we clearly lean towards discussing migration from SpringCloud to Dubbo, it is equally valid to consider the reverse; if you are currently using or planning to use Dubbo for microservice development, migrating from Dubbo to SpringCloud will follow the same line of reasoning. Dubbo's multi-protocol and multi-registry model provides the same flexibility for bi-directional migration. - -### Migration from Self-Built Systems to Dubbo Systems (Coexistence) - -This scenario is somewhat similar to the previous section on migration from SpringCloud. The key difference lies in the fact that the REST protocol is officially supported by Dubbo, whereas for private communication protocols within an existing microservice system, one must first extend the Dubbo Protocol to provide protocol-level support. - -## Summary and Outlook - -To achieve coexistence or migration between heterogeneous microservice architectures, the key is to bridge the `protocol` and `service discovery` across heterogeneous systems. Thanks to Dubbo's support for multiple protocols and registries, we can easily make Dubbo a bridge connecting heterogeneous microservice systems. Familiarity with Dubbo's multi-protocol implementation details might prompt concerns about performance impact due to the doubling of address numbers in scenarios with numerous services, as outlined in the "Leveraging Dubbo to Connect Heterogeneous Microservice Systems" section where we didn’t detail how to achieve transparent service discovery between heterogeneous systems. We will specifically elucidate this aspect involving service discovery in future articles, detailing how the new service discovery mechanism introduced in version 2.7.5 addresses these challenges. Please stay tuned for upcoming articles and the official Dubbo documentation. - diff --git a/content/en/blog/java/demos/optimization-branch-prediction.md b/content/en/blog/java/demos/optimization-branch-prediction.md deleted file mode 100644 index 8af01af13f9c..000000000000 --- a/content/en/blog/java/demos/optimization-branch-prediction.md +++ /dev/null @@ -1,144 +0,0 @@ ---- -title: "Early if Judgment Helps CPU Branch Prediction" -linkTitle: "Early if Judgment Helps CPU Branch Prediction" -tags: ["Java"] -date: 2019-02-03 -description: > - This article introduces optimization techniques that help CPU branch prediction through early if judgments. ---- - -## Branch Prediction - -There is a very famous question on Stack Overflow: [Why is it faster to process a sorted array than an unsorted array?]( -https://stackoverflow.com/questions/11227809/why-is-it-faster-to-process-a-sorted-array-than-an-unsorted-array), which shows that branch prediction has a significant impact on code execution efficiency. - -Modern CPUs support branch prediction and instruction pipelining, which together can greatly enhance CPU efficiency. For simple if statements, CPUs can do a good job of branch prediction. However, for switch statements, the CPU has limited options. Switch essentially uses indexing to fetch addresses from an array and then jumps. - -To improve code execution efficiency, an important principle is to avoid clearing the CPU pipeline as much as possible, making it vital to enhance the success rate of branch prediction. - -In cases where a certain switch branch has a high probability, could we consider helping the CPU with early judgment to improve code execution efficiency? - -## Switch Judgment in ChannelEventRunnable of Dubbo - -In `ChannelEventRunnable`, there is a switch that assesses the channel state and performs corresponding logic: [View]( -https://github.com/hengyunabc/dubbo/blob/dubbo-2.6.1/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/dispatcher/ChannelEventRunnable.java#L54) - -Once a channel is established, in over 99.9% of instances, its state is `ChannelState.RECEIVED`, so it may be worth considering moving this judgment ahead. - -## Benchmark Validation - -Below we verify with jmh: - -```java -public class TestBenchMarks { - public enum ChannelState { - CONNECTED, DISCONNECTED, SENT, RECEIVED, CAUGHT - } - - @State(Scope.Benchmark) - public static class ExecutionPlan { - @Param({ "1000000" }) - public int size; - public ChannelState[] states = null; - - @Setup - public void setUp() { - ChannelState[] values = ChannelState.values(); - states = new ChannelState[size]; - Random random = new Random(new Date().getTime()); - for (int i = 0; i < size; i++) { - int nextInt = random.nextInt(1000000); - if (nextInt > 100) { - states[i] = ChannelState.RECEIVED; - } else { - states[i] = values[nextInt % values.length]; - } - } - } - } - - @Fork(value = 5) - @Benchmark - @BenchmarkMode(Mode.Throughput) - public void benchSiwtch(ExecutionPlan plan, Blackhole bh) { - int result = 0; - for (int i = 0; i < plan.size; ++i) { - switch (plan.states[i]) { - case CONNECTED: - result += ChannelState.CONNECTED.ordinal(); - break; - case DISCONNECTED: - result += ChannelState.DISCONNECTED.ordinal(); - break; - case SENT: - result += ChannelState.SENT.ordinal(); - break; - case RECEIVED: - result += ChannelState.RECEIVED.ordinal(); - break; - case CAUGHT: - result += ChannelState.CAUGHT.ordinal(); - break; - } - } - bh.consume(result); - } - - @Fork(value = 5) - @Benchmark - @BenchmarkMode(Mode.Throughput) - public void benchIfAndSwitch(ExecutionPlan plan, Blackhole bh) { - int result = 0; - for (int i = 0; i < plan.size; ++i) { - ChannelState state = plan.states[i]; - if (state == ChannelState.RECEIVED) { - result += ChannelState.RECEIVED.ordinal(); - } else { - switch (state) { - case CONNECTED: - result += ChannelState.CONNECTED.ordinal(); - break; - case SENT: - result += ChannelState.SENT.ordinal(); - break; - case DISCONNECTED: - result += ChannelState.DISCONNECTED.ordinal(); - break; - case CAUGHT: - result += ChannelState.CAUGHT.ordinal(); - break; - } - } - } - bh.consume(result); - } -} -``` -* benchSiwtch involves pure switch judgment -* benchIfAndSwitch makes an early if judgment to check if state is `ChannelState.RECEIVED` - -Benchmark results are: - -``` -Result "io.github.hengyunabc.jmh.TestBenchMarks.benchSiwtch": - 576.745 ±(99.9%) 6.806 ops/s [Average] - (min, avg, max) = (490.348, 576.745, 618.360), stdev = 20.066 - CI (99.9%): [569.939, 583.550] (assumes normal distribution) - - -# Run complete. Total time: 00:06:48 - -Benchmark (size) Mode Cnt Score Error Units -TestBenchMarks.benchIfAndSwitch 1000000 thrpt 100 1535.867 ± 61.212 ops/s -TestBenchMarks.benchSiwtch 1000000 thrpt 100 576.745 ± 6.806 ops/s -``` - -It can be seen that the early if judgment indeed improved code efficiency; this technique can be applied in performance-critical areas. - -Benchmark code: https://github.com/hengyunabc/jmh-demo - -## Conclusion - -* Switch statements are difficult for CPUs to perform branch prediction. -* For certain switch conditions with high probabilities, consider early if judgments to fully leverage the CPU's branch prediction mechanism. - diff --git a/content/en/blog/java/demos/proxyless-guide.md b/content/en/blog/java/demos/proxyless-guide.md deleted file mode 100644 index 261fe50534b8..000000000000 --- a/content/en/blog/java/demos/proxyless-guide.md +++ /dev/null @@ -1,509 +0,0 @@ ---- -title: "Proxyless Mesh在Dubbo中的实践" -linkTitle: "Proxyless Mesh在Dubbo中的实践" -tags: ["Java"] -date: 2022-09-05 -description: > - Proxyless 模式是指 Dubbo 直接与 Istiod 通信,通过 xDS 协议实现服务发现和服务治理等能力。本文将带领大家熟悉 Dubbo Proxyless Mesh。 ---- - -## 背景 - -随着 Dubbo 3.1 的 release,Dubbo 在云原生的路上又迈出了重要的一步。在这个版本中添加了 Proxyless Mesh 的新特性,Dubbo Proxyless Mesh 直接实现 xDS 协议解析, -实现 Dubbo 与 Control Plane 的直接通信,进而实现控制面对流量管控、服务治理、可观测性、安全等的统一管控,规避 Sidecar 模式带来的性能损耗与部署架构复杂性。 - -## 什么是Service Mesh - -Service Mesh 又译作 “服务网格”,作为服务间通信的基础设施层。Buoyant 公司的 CEO Willian Morgan 在他的这篇文章 [WHAT’S A Service Mesh? AND WHY DO I NEED ONE? ](https://linkerd.io/2017/04/25/whats-a-service-mesh-and-why-do-i-need-one/) -中解释了什么是 Service Mesh,为什么云原生应用需要 Service Mesh。 - -**下面是 Willian Morgan 对 Service Mesh 的解释。** - -``` -A Service Mesh is a dedicated infrastructure layer for handling service-to-service communication. -It’s responsible for the reliable delivery of requests through the complex topology of services -that comprise a modern, cloud native application. In practice, the Service Mesh is typically implemented -as an array of lightweight network proxies that are deployed alongside application code, without the -application needing to be aware. -``` - -**翻译成中文** - -``` -服务网格(Service Mesh)是处理服务间通信的基础设施层。它负责构成现代云原生应用程序的复杂服务拓扑来可靠地交付请求。 -在实践中,Service Mesh 通常以轻量级网络代理阵列的形式实现,这些代理与应用程序代码部署在一起,对应用程序来说无需感知代理的存在。 -``` - -说到 Service Mesh 一定离不开 Sidecar 经典架构模式。它通过在业务 Pod 中注入 Sidecar 容器,接管业务容器的通信流量,同时 Sidecar 容器与网格平台的控制平面对接, -基于控制平面下发的策略,对代理流量实施治理和管控,将原有服务框架的治理能力下层到 Sidecar 容器中,从而实现了基础框架能力的下沉,与业务系统解耦。 - -![Service Mesh](/imgs/blog/20220905/1.png) - -经典的 Sidecar Mesh 部署架构有很多优势,如平滑升级、多语言、业务侵入小等,但也带来了一些额外的问题,比如: - -* Proxy 带来的性能损耗,在复杂拓扑的网络调用中将变得尤其明显 -* 流量拦截带来的架构复杂性 -* Sidecar 生命周期管理 -* 部署环境受限,并不是所有环境都满足 Sidecar 流量拦截条件 - -针对 Sidecar Mesh 模型的问题,Dubbo 社区自很早之前就做了 Dubbo 直接对接到控制面的设想与思考,并在国内开源社区率先提出了 Proxyless Mesh 的概念,当然就 Proxyless 概念的说法而言,最开始是谷歌提出来的。 - -## Dubbo Proxyless Mesh - -Dubbo Proxyless 模式是指 Dubbo 直接与 Istiod通信,通过 xDS协议实现服务发现和服务治理等能力。 - -![Proxyless](/imgs/blog/20220905/2.png) - -Proxyless 模式使得微服务又回到了 2.x 时代的部署架构,同 Dubbo 经典服务治理模式非常相似,所以说这个模式并不新鲜, Dubbo 从最开始就是这样的设计模式。 -这样做可以极大的提升应用性能,降低网络延迟。有人说这种做法又回到了原始的基于 SDK 的微服务模式,其实非也,它依然使用了 Envoy 的 xDS API, -但是因为不再需要向应用程序中注入 Sidecar 代理,因此可以减少应用程序性能的损耗。 - -但相比于 Mesh 架构,Dubbo 经典服务治理模式并没有强调控制面的统一管控,而这点恰好是 Service Mesh 所强调的,强调对流量、可观测性、证书等的标准化管控与治理,也是 Mesh 理念先进的地方。 - -在 Dubbo Proxyless 架构模式下,Dubbo 进程将直接与控制面通信,Dubbo 进程之间也继续保持直连通信模式,我们可以看出 Proxyless 架构的优势: - -* 没有额外的 Proxy 中转损耗,因此更适用于性能敏感应用 -* 更有利于遗留系统的平滑迁移 -* 架构简单,容易运维部署 -* 适用于几乎所有的部署环境 - -## 服务发现 - -xDS 接入以注册中心的模式对接,节点发现同其他注册中心的服务自省模型一样,对于 xDS 的负载均衡和路由配置通过 ServiceInstance 的动态运行时配置传出, -在构建 Invoker 的时候将配置参数传入配置地址。 - -![服务发现](/imgs/blog/20220905/3.png) - -## 证书管理 - -零信任架构下,需要严格区分工作负载的识别和信任,而签发 X.509 证书是推荐的一种认证方式。在 Kubernetes 集群中,服务间是通过 DNS 名称互相访问的,而网络流量可能被 DNS 欺骗、BGP/路由劫持、ARP 欺骗等手段劫持,为了将服务名称(DNS 名称)与服务身份强关联起来,Istio 使用置于 X.509 证书中的安全命名机制。SPIFFE是 Istio 所采用的安全命名的规范,它也是云原生定义的一种标准化的、可移植的工作负载身份规范。 - -Secure Production Identity Framework For Everyone (SPIFFE) 是一套服务之间相互进行身份识别的标准,主要包含以下内容: - -* SPIFFE ID 标准,SPIFFE ID 是服务的唯一标识,具体实现使用 URI 资源标识符 -* SPIFFE Verifiable Identity Document (SVID) 标准,将 SPIFFE ID 编码到一个加密的可验证的数据格式中 -* 颁发与撤销 SVID 的 API 标准(SVID 是 SPIFFE ID 的识别凭证) - -SPIFFE ID 规定了形如 ```spiffe:///``` 的 URI 格式,作为工作负载(Workload)的唯一标识。 -而 Istio 在自身的生态中只使用到了 SPIFFE ID 作为安全命名,其数据格式由自己实现,通信格式采用 CNCF 支持的 xDS 协议规范(证书认证通信更具体来说是 xDS 的 SDS)。 - -Istio 使用形如 ```spiffe:///ns//sa/``` 格式的 SPIFFE ID 作为安全命名,注入到 X.509 证书的 subjectAltName 扩展中。 -其中"trust_domain"参数通过 Istiod 环境变量TRUST_DOMAIN 注入,用于在多集群环境中交互。 - -以下是 Dubbo Proxyless Mesh 证书颁发的过程 - -![证书颁发](/imgs/blog/20220905/4.png) - -* 创建 RSA 私钥(Istio 还不支持 ECDSA 私钥) -* 构建 CSR(Certificate signing request)模板 -* 自签名 CSR 生成证书 -* 创建 Kubernetes Secret 资源储存 CA 证书和私钥(CA Service处理) - -## 案例实践 - -接下来我将带领大家通过一个例子使已有的项目快速跑在 Proxyless Mesh 模式下。 - -## 环境准备 - -### 安装docker - -[https://www.docker.com/](https://www.docker.com/) - -### 安装minikube - -墙裂推荐:[https://kubernetes.io/zh-cn/docs/tutorials/hello-minikube/](https://kubernetes.io/zh-cn/docs/tutorials/hello-minikube/) - -### 安装istio - -[https://istio.io/latest/docs/setup/getting-started/](https://istio.io/latest/docs/setup/getting-started/) - -❗❗❗ 安装 Istio 的时候需要开启 first-party-jwt 支持(使用 istioctl 工具安装的时候加上 --set values.global.jwtPolicy=first-party-jwt 参数),否则将导致客户端认证失败的问题。 -参考命令如下: - -```bash -curl -L https://istio.io/downloadIstio | sh - -cd istio-1.xx.x -export PATH=$PWD/bin:$PATH -istioctl install --set profile=demo --set values.global.jwtPolicy=first-party-jwt -y -``` - -## 代码准备 - -### xds-provider - -#### 定义一个接口 - -```java -public interface GreetingService { - - String sayHello(String name); -} -``` - -#### 实现对应的接口 - -```java -@DubboService(version = "1.0.0") -public class AnnotatedGreetingService implements GreetingService { - - @Override - public String sayHello(String name) { - System.out.println("greeting service received: " + name); - return "hello, " + name + "! from host: " + NetUtils.getLocalHost(); - } -} -``` - -#### 编写启动类 - -```java -public class ProviderBootstrap { - - public static void main(String[] args) throws Exception { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class); - context.start(); - System.out.println("dubbo service started"); - new CountDownLatch(1).await(); - } - - @Configuration - @EnableDubbo(scanBasePackages = "org.apache.dubbo.samples.impl") - @PropertySource("classpath:/spring/dubbo-provider.properties") - static class ProviderConfiguration { - } -} -``` - -#### 编写配置信息 - -``` -dubbo.application.name=dubbo-samples-xds-provider -# 由于 Dubbo 3 应用级服务发现的元数据无法从 istio 中获取,需要走服务自省模式。 -# 这要求了 Dubbo MetadataService 的端口在全集群的是统一的。 -dubbo.application.metadataServicePort=20885 -# 走xds协议 -dubbo.registry.address=xds://istiod.istio-system.svc:15012 -dubbo.protocol.name=tri -dubbo.protocol.port=50051 -# 对齐k8s pod生命周期,由于 Kubernetes probe 探活机制的工作原理限制, -# 探活请求的发起方不是 localhost,所以需要配置 qosAcceptForeignIp 参数开启允许全局访问 -dubbo.application.qosEnable=true -dubbo.application.qosAcceptForeignIp=true -``` - -#### 编写Deployment.yml和Service.yml - -``` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: dubbo-samples-xds-provider - namespace: dubbo-demo -spec: - replicas: 3 - selector: - matchLabels: - app: dubbo-samples-xds-provider - template: - metadata: - labels: - app: dubbo-samples-xds-provider - spec: - containers: - - name: server - image: apache/dubbo-demo:dubbo-samples-xds-provider_0.0.1 - livenessProbe: - httpGet: - path: /live - port: 22222 - initialDelaySeconds: 5 - periodSeconds: 5 - readinessProbe: - httpGet: - path: /ready - port: 22222 - initialDelaySeconds: 5 - periodSeconds: 5 - startupProbe: - httpGet: - path: /startup - port: 22222 - failureThreshold: 30 - periodSeconds: 10 -``` - -``` -apiVersion: v1 -kind: Service -metadata: - name: dubbo-samples-xds-provider - namespace: dubbo-demo -spec: - clusterIP: None - selector: - app: dubbo-samples-xds-provider - ports: - - name: grpc - protocol: TCP - port: 50051 - targetPort: 50051 -``` - -#### 编写Dockerfile - -``` -FROM openjdk:8-jdk -ADD ./target/dubbo-samples-xds-provider-1.0-SNAPSHOT.jar dubbo-samples-xds-provider-1.0-SNAPSHOT.jar -CMD java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=31000 /dubbo-samples-xds-provider-1.0-SNAPSHOT.jar -``` - -### xds-consumer - -#### 定义一个接口 - -``` -public interface GreetingService { - - String sayHello(String name); -} -``` - -#### 实现对应的接口 - -``` -@Component("annotatedConsumer") -public class GreetingServiceConsumer { - // 这里特别注意的是、由于当前 Dubbo 版本受限于 istio 的通信模型无法获取接口所对应的应用名, - // 因此需要配置 providedBy 参数来标记此服务来自哪个应用。 - @DubboReference(version = "1.0.0", providedBy = "dubbo-samples-xds-provider") - private GreetingService greetingService; - - public String doSayHello(String name) { - return greetingService.sayHello(name); - } -} -``` - -#### 编写启动类 - -``` -public class ConsumerBootstrap { - - public static void main(String[] args) { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class); - context.start(); - GreetingServiceConsumer greetingServiceConsumer = context.getBean(GreetingServiceConsumer.class); - while (true) { - try { - String hello = greetingServiceConsumer.doSayHello("xDS Consumer"); - System.out.println("result: " + hello); - Thread.sleep(100); - } catch (Throwable t) { - t.printStackTrace(); - } - } - } - - @Configuration - @EnableDubbo(scanBasePackages = "org.apache.dubbo.samples.action") - @PropertySource("classpath:/spring/dubbo-consumer.properties") - @ComponentScan(value = {"org.apache.dubbo.samples.action"}) - static class ConsumerConfiguration { - - } -} -``` - -#### 编写配置信息 - -``` -dubbo.application.name=dubbo-samples-xds-consumer -dubbo.application.metadataServicePort=20885 -dubbo.registry.address=xds://istiod.istio-system.svc:15012 -dubbo.consumer.timeout=3000 -dubbo.consumer.check=false -dubbo.application.qosEnable=true -dubbo.application.qosAcceptForeignIp=true -``` - -#### 编写Deployment.yml和Service.yml - -``` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: dubbo-samples-xds-consumer - namespace: dubbo-demo -spec: - replicas: 2 - selector: - matchLabels: - app: dubbo-samples-xds-consumer - template: - metadata: - labels: - app: dubbo-samples-xds-consumer - spec: - containers: - - name: server - image: apache/dubbo-demo:dubbo-samples-xds-consumer_0.0.1 - livenessProbe: - httpGet: - path: /live - port: 22222 - initialDelaySeconds: 5 - periodSeconds: 5 - readinessProbe: - httpGet: - path: /ready - port: 22222 - initialDelaySeconds: 5 - periodSeconds: 5 - startupProbe: - httpGet: - path: /startup - port: 22222 - failureThreshold: 30 - periodSeconds: 10 -``` - -``` -apiVersion: v1 -kind: Service -metadata: - name: dubbo-samples-xds-consumer - namespace: dubbo-demo -spec: - clusterIP: None - selector: - app: dubbo-samples-xds-consumer - ports: - - name: grpc - protocol: TCP - port: 50051 - targetPort: 50051 -``` - -#### 编写Dockerfile - -``` -FROM openjdk:8-jdk -ADD ./target/dubbo-samples-xds-consumer-1.0-SNAPSHOT.jar dubbo-samples-xds-consumer-1.0-SNAPSHOT.jar -CMD java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=31000 /dubbo-samples-xds-consumer-1.0-SNAPSHOT.jar -``` - -✅ 到目前为止我们的环境和代码就全都准备完毕了! - -## 构建镜像 - -### 1、启动docker - -![启动docker](/imgs/blog/20220905/5.png) - -### 2、启动minikube -因为minikube是一个本地的k8s,他启动需要一个虚拟引擎,这里我们用docker来管理。我们通过如下命令启动 - -`minikube start` - -![启动minikube](/imgs/blog/20220905/6.png) - -我们可以在docker里看到minikube - -![minikube](/imgs/blog/20220905/7.png) - -### 3、检查istio的状态 - -![istio的状态](/imgs/blog/20220905/8.png) - -### 4、构建镜像 - -在本地找到代码所在位置、依次执行以下命令 - -``` -# 找到provider所在路径 -cd ./dubbo-samples-xds-provider/ -# 构建provider的镜像 -docker build -t apache/dubbo-demo:dubbo-samples-xds-provider_0.0.1 . -``` - -![构建provider](/imgs/blog/20220905/9.png) - -``` -# 找到consumer所在路径 -cd ../dubbo-samples-xds-consumer/ -# 构建consumer的镜像 -docker build -t apache/dubbo-demo:dubbo-samples-xds-consumer_0.0.1 . -``` - -![构建consumer](/imgs/blog/20220905/10.png) - -### 5、检查本地镜像 - -![检查本地镜像](/imgs/blog/20220905/11.png) - -### 6、创建namespace - -``` -# 初始化命名空间 -kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-xds/deploy/Namespace.yml - -# 切换命名空间 -kubens dubbo-demo -``` - -如果不创建namespace,那么会看到如下错误 - -![错误](/imgs/blog/20220905/12.png) - -## 部署容器 - -``` -# 找到provider所在路径 -cd ./dubbo-samples-xds-provider/src/main/resources/k8s -# dubbo-samples-xds/dubbo-samples-xds-provider/src/main/resources/k8s/Deployment.yml -# dubbo-samples-xds/dubbo-samples-xds-provider/src/main/resources/k8s/Service.yml - -# 部署provider的Deployment和Service -kubectl apply -f Deployment.yml -kubectl apply -f Service.yml -``` - -![部署provider](/imgs/blog/20220905/13.png) - -``` -# 找到consumer所在路径 -cd ../../../../../dubbo-samples-xds-consumer/src/main/resources/k8s -# dubbo-samples-xds/dubbo-samples-xds-consumer/src/main/resources/k8s/Deployment.yml - -# 部署consumer的Deployment -kubectl apply -f Deployment.yml -``` - -![部署provider](/imgs/blog/20220905/14.png) - -在minikube dashboard看到我们已经部署的pod - -![部署provider](/imgs/blog/20220905/15.png) - -## 观察consumer效果 - -``` -kubectl logs xxx - -result: hello, xDS Consumer! from host: 172.17.0.5 -result: hello, xDS Consumer! from host: 172.17.0.5 -result: hello, xDS Consumer! from host: 172.17.0.6 -result: hello, xDS Consumer! from host: 172.17.0.6 -``` - -## 总结&展望 - -本文主要剖析了 Dubbo Proxyless Mesh 的架构、服务发现以及证书管理等核心流程,最后通过示例给大家演示了如何使用 Dubbo Proxyless。 - -![部署provider](/imgs/blog/20220905/16.png) - -随着 Dubbo 3.1 的 release,Dubbo 在云原生的路上又迈出了重要的一步。在今年年底,Dubbo Mesh 将发布具有服务发现能力的版本, -届时将面向所有 Dubbo 用户提供从低版本平滑迁移到 Mesh 架构的能力;在明年年初春季的时候将发布带有治理能力的版本;在明年年底前发布带热插件更新能力的版本, -希望有兴趣见证 Dubbo 云原生之路的同学可以积极参与社区贡献! - -更多关于 Dubbo Mesh 的动态可以关注 Apache Dubbo 社区官方公众号(ApacheDubbo),及时获取最新消息。 \ No newline at end of file diff --git a/content/en/blog/java/demos/resilience4j.md b/content/en/blog/java/demos/resilience4j.md deleted file mode 100644 index db23925509aa..000000000000 --- a/content/en/blog/java/demos/resilience4j.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -aliases: - - /en/overview/tasks/rate-limit/resilience4j/ - - /en/overview/tasks/rate-limit/resilience4j/ -description: "Protect Dubbo applications using Resilience4j circuit breakers, rate limiters, retries, and isolation mechanisms" -linkTitle: Resilience4j -title: Protect Dubbo Applications Using Resilience4j Circuit Breakers, Rate Limiters, Retries, and Isolation Mechanisms -tags: ["Java", "Resilience4j", "Rate Limit Degradation"] -date: 2023-12-14 ---- - -Resilience4j provides a set of higher-order functions (decorators) including circuit breakers, rate limiters, retries, and isolation, which can enhance any functional interface, lambda expression, or method reference, and these decorators can be layered. The benefit of doing this is that you can choose specific decorators to combine as needed. - -For usage examples of integrating Resilience4j with Dubbo, please refer to [dubbo-samples-resilience4j](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-resilience4j) - diff --git a/content/en/blog/java/demos/rpc-introduction.md b/content/en/blog/java/demos/rpc-introduction.md deleted file mode 100644 index 88d2239a7187..000000000000 --- a/content/en/blog/java/demos/rpc-introduction.md +++ /dev/null @@ -1,136 +0,0 @@ ---- -title: "A Brief Discussion on RPC" -linkTitle: "A Brief Discussion on RPC" -tags: ["Java"] -date: 2019-01-07 -description: > - RPC - Remote Procedure Call, it is a protocol that allows requesting services from a remote computer program via a network without needing to understand the underlying network technology. ---- - -In recent years, with the rise of microservices, it has gradually become a mainstream method for large distributed system architectures in many companies. The RPC discussed today plays a crucial role in this process. As companies evolve their projects into microservices, it's observed that RPC is being used implicitly or explicitly in daily development. Some newcomers who just started with RPC may feel confused, while seasoned developers may have extensive experience but lack a deep understanding of its principles, leading to some misuses during development. - -## What is RPC? - -RPC (Remote Procedure Call) is a protocol for requesting services from remote computer programs via a network. In other words, when one application deployed on server A wants to call a method provided by an application on server B, since they are not in the same memory space, it cannot be called directly; the invocation must be expressed through the network. - -RPC assumes the existence of certain transport protocols, such as TCP or UDP, for carrying information between programs. In the OSI networking model, RPC spans the transport layer and application layer, making it easier to develop applications, including network-distributed multiprograms. There are many excellent open-source RPC frameworks in the industry, such as Spring Cloud, Dubbo, and Thrift. - -## Origin of RPC - -The concept of RPC was proposed by **Bruce Jay Nelson** in the 1980s. The motivations for developing RPC can be traced back to a few points mentioned in Nelson's paper "Implementing Remote Procedure Calls": -* Simplicity: The semantics of RPC are clear and simple, making distributed computing easier. -* Efficiency: Procedure calling appears simple and efficient. -* Universality: In single-machine computing, procedures often serve as the most important communication mechanism between different algorithm parts. - -In simpler terms, since programmers are generally familiar with local procedure calls, making RPC function similarly to local calls makes it easier to adopt and use. Nelson's paper, published 30 years ago, was indeed visionary; the RPC frameworks we use today are essentially built around this goal. - -## RPC Structure - -Nelson's paper identifies five components necessary to implement RPC: -1. User -2. User-stub -3. RPCRuntime -4. Server-stub -5. Server - -![RPC Structure](/imgs/blog/rpc/rpc-structure-1.png) - -Here, the user represents the client side. When the user wants to initiate a remote call, it is actually making a local call to the user-stub. The user-stub is responsible for encoding the called interface, method, and parameters according to an agreed protocol and transmitting them to the remote instance through the local RPCRuntime instance. Upon receipt of the request, the remote RPCRuntime instance hands it over to the server-stub for decoding before invoking a local call, and the result is returned to the user. - -The above demonstrates a coarse-grained conceptual structure of RPC implementation, and we will further detail the components as shown in the diagram below. - -![RPC Structure Breakdown](/imgs/blog/rpc/rpc-structure-2.png) - -The RPC service provider uses RpcServer to export remote interface methods, while the client side uses RpcClient to import remote interface methods. The client calls remote interface methods as if they were local, with the RPC framework providing the proxy implementation of the interface. The actual call will be delegated to RpcProxy. The proxy encapsulates call information and forwards the call to RpcInvoker for execution. On the client side, the RpcInvoker maintains the channel with the service provider through the RpcConnector, using RpcProtocol for protocol encoding and sending encoded messages through the channel. - -The RPC server's receiver, RpcAcceptor, accepts client call requests and uses RpcProtocol for protocol decoding. The decoded call information is passed to RpcProcessor to control the call process and delegate the call to RpcInvoker for actual execution, returning the result. Below are the detailed responsibilities of each component: - -``` -1. RpcServer - - Responsible for exporting remote interfaces - -2. RpcClient - - Responsible for importing the proxy implementation of remote interfaces - -3. RpcProxy - - Proxy implementation of remote interfaces - -4. RpcInvoker - - Client-side implementation: responsible for encoding call information and sending it to the service side and waiting for the result. - - Service-side implementation: responsible for implementing the server interface and returning results. - -5. RpcProtocol - - Responsible for protocol encoding/decoding - -6. RpcConnector - - Responsible for maintaining the connection channel between the client and server and sending data to the service side - -7. RpcAcceptor - - Responsible for receiving client requests and returning results - -8. RpcProcessor - - Responsible for controlling the call process on the server side, including managing call thread pools, timeout settings, etc. - -9. RpcChannel - - Data transmission channel -``` - -## Working Principle of RPC - -RPC design consists of Client, Client stub, Network, Server stub, and Server. The Client is used to call the service, while the Client stub serializes the calling method and parameters (since objects must be converted to bytes for network transmission). The Network transmits this information to the Server stub, which deserializes it. The Server provides the service and executes the method ultimately called. - -![Working Principle of RPC](/imgs/blog/rpc/rpc-work-principle.png) - -1. The Client calls the remote service as if it were calling a local service; - -2. The Client stub serializes the method and parameters upon receipt; - -3. The client sends the message to the server through sockets; - -4. The Server stub receives the message and decodes it (deserializes the message object); - -5. The Server stub calls the local service based on the decoded results; - -6. The local service executes (locally, for the server) and returns the results to the Server stub; - -7. The Server stub packages the return results into a message (serializes the result message object); - -8. The server sends the message back to the client through sockets; - -9. The Client stub receives the result message and decodes it (deserializes the result message object); - -10. The client gets the final result. - -RPC calls can be categorized into two types: - -1. Synchronous calls: The client waits for the call to complete and return results. - -2. Asynchronous calls: The client does not wait for the execution result upon calling but can still obtain it through callbacks, etc. If the client doesn't care about the return result, it becomes a one-way asynchronous call, where no result is returned. - -The distinction between asynchronous and synchronous lies in whether to wait for the server's execution to complete and return results. - -## What Can RPC Do? - -The main goal of RPC is to ease the construction of distributed computing (applications) while providing robust remote calling capabilities without losing the semantic simplicity of local calls. To achieve this goal, the RPC framework needs to offer a transparent calling mechanism, so users do not have to explicitly distinguish between local and remote calls. The previously mentioned implementation structure is based on a stub structure. Let's detail the stub structure's implementation further. - -* It supports distributed, modern microservices. -* Flexible deployment. -* Decouples services. -* Strong extensibility. - -The purpose of RPC is to allow you to call remote methods as if they were local, making the invocation transparent, so you may not even know where the method is deployed. By using RPC, services can be decoupled, which is the true intent behind using RPC. - -## Conclusion - -This article introduced some basic principles of RPC, and I believe you've gained a certain understanding of it by now. Implementing RPC is not particularly difficult; the challenge lies in creating a high-performance and reliable RPC framework. For instance, since it is distributed, a service may have multiple instances. How do you obtain the addresses of these instances during calls? You will need a service registry, such as Zookeeper in Dubbo. During calls, you retrieve the list of service instances from Zookeeper and choose one to call. Which instance to call? This brings in the need for load balancing, and you need to consider how to implement complex balancing; Dubbo offers several load balancing strategies. So, please stay tuned for my other two articles, **The Relationship Between RPC and Serviceization** and **A Brief Discussion on Service Registration Center, Configuration Center, and Service Discovery**, which will undoubtedly provide a deeper understanding of RPC design and implementation. - diff --git a/content/en/blog/java/demos/service-and-version.md b/content/en/blog/java/demos/service-and-version.md deleted file mode 100644 index 0c769f5d5627..000000000000 --- a/content/en/blog/java/demos/service-and-version.md +++ /dev/null @@ -1,242 +0,0 @@ ---- -title: "Dubbo服务分组和版本聚合" -linkTitle: "Dubbo服务分组和版本聚合" -tags: ["Java"] -date: 2018-10-27 -description: > - 本文主要介绍了 Dubbo 中服务分组和版本聚合的概念和用法 ---- - -我们在调用Dubbo服务的时候,一般只需要将Consumer端的`dubbo:reference`指定成服务端中`dubbo:service`暴露的服务,就可以找到服务端,完成调用,也就是说,Dubbo只需要服务接口信息就可以找到服务提供者。 -其实除了服务提供者以外,Dubbo也有服务分组和版本的概念,在客户端去寻找“匹配”的服务端的时候,需要服务接口,版本号,组别这三个信息都匹配,才算是一个有效的服务端: - -```java - public static boolean isMatch(URL consumerUrl, URL providerUrl) { - String consumerInterface = consumerUrl.getServiceInterface(); - String providerInterface = providerUrl.getServiceInterface(); - if (!(Constants.ANY_VALUE.equals(consumerInterface) || StringUtils.isEquals(consumerInterface, providerInterface))) - return false; - - if (!isMatchCategory(providerUrl.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY), - consumerUrl.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY))) { - return false; - } - if (!providerUrl.getParameter(Constants.ENABLED_KEY, true) - && !Constants.ANY_VALUE.equals(consumerUrl.getParameter(Constants.ENABLED_KEY))) { - return false; - } - - String consumerGroup = consumerUrl.getParameter(Constants.GROUP_KEY); - String consumerVersion = consumerUrl.getParameter(Constants.VERSION_KEY); - String consumerClassifier = consumerUrl.getParameter(Constants.CLASSIFIER_KEY, Constants.ANY_VALUE); - - String providerGroup = providerUrl.getParameter(Constants.GROUP_KEY); - String providerVersion = providerUrl.getParameter(Constants.VERSION_KEY); - String providerClassifier = providerUrl.getParameter(Constants.CLASSIFIER_KEY, Constants.ANY_VALUE); - return (Constants.ANY_VALUE.equals(consumerGroup) || StringUtils.isEquals(consumerGroup, providerGroup) || StringUtils.isContains(consumerGroup, providerGroup)) - && (Constants.ANY_VALUE.equals(consumerVersion) || StringUtils.isEquals(consumerVersion, providerVersion)) - && (consumerClassifier == null || Constants.ANY_VALUE.equals(consumerClassifier) || StringUtils.isEquals(consumerClassifier, providerClassifier)); - } -``` -如果没有配置组别和版本号,默认值为空。服务端和消费端都没有配,只有服务接口,其他两个信息都为空,也是可以“找到”对方的,那服务名和版本号可以如何使用呢?下面我们来看一下具体的场景: -### 服务分组 -当一个接口有多种实现时,可以用 group 区分。 - -服务 - -```xml - - -``` -引用 - -```xml - - -``` - -任意组 - -```xml - -``` - -### 多版本 -当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。 - -可以按照以下的步骤进行版本迁移: - -1. 在低压力时间段,先升级一半提供者为新版本 -1. 再将所有消费者升级为新版本 -1. 然后将剩下的一半提供者升级为新版本 - -老版本服务提供者配置: - -```xml - -``` - -新版本服务提供者配置: - -```xml - -``` - -老版本服务消费者配置: - -```xml - -``` - -新版本服务消费者配置: - -```xml - -``` - -如果不需要区分版本,可以按照以下的方式配置: - -```xml - -``` - - -### 分组聚合 - -按组合并返回结果,比如菜单服务,接口一样,但有多种实现,用group区分,现在消费方需从每种group中调用一次返回结果,合并结果返回,这样就可以实现聚合菜单项。 - -#### 配置 -搜索所有分组 - -```xml - -``` - -合并指定分组 - -```xml - -``` - -指定方法合并结果,其它未指定的方法,将只调用一个 Group - -```xml - - - - -``` - -某个方法不合并结果,其它都合并结果 - -```xml - - - - -``` - -指定合并策略,缺省根据返回值类型自动匹配,如果同一类型有两个合并器时,需指定合并器的名称 - -```xml - - - -``` -指定合并方法,将调用返回结果的指定方法进行合并,合并方法的参数类型必须是返回结果类型本身 - -```xml - - - -``` - -#### 实现原理 -如果配置了merge,Dubbo会分别调用多个组别的服务提供者,然后把结果聚合,返回给消费端,具体的实现在`MergeableClusterInvoker.java`里: - -```java - public Result invoke(final Invocation invocation) throws RpcException { - List> invokers = directory.list(invocation); - - String merger = getUrl().getMethodParameter(invocation.getMethodName(), Constants.MERGER_KEY); - if (ConfigUtils.isEmpty(merger)) { // If a method doesn't have a merger, only invoke one Group - for (final Invoker invoker : invokers) { - if (invoker.isAvailable()) { - return invoker.invoke(invocation); - } - } - return invokers.iterator().next().invoke(invocation); - } - - Class returnType; - try { - returnType = getInterface().getMethod( - invocation.getMethodName(), invocation.getParameterTypes()).getReturnType(); - } catch (NoSuchMethodException e) { - returnType = null; - } - - Map> results = new HashMap>(); - for (final Invoker invoker : invokers) { - Future future = executor.submit(new Callable() { - @Override - public Result call() throws Exception { - return invoker.invoke(new RpcInvocation(invocation, invoker)); - } - }); - results.put(invoker.getUrl().getServiceKey(), future); - } - - Object result = null; - - List resultList = new ArrayList(results.size()); - - int timeout = getUrl().getMethodParameter(invocation.getMethodName(), Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); - for (Map.Entry> entry : results.entrySet()) { - Future future = entry.getValue(); - try { - Result r = future.get(timeout, TimeUnit.MILLISECONDS); - if (r.hasException()) { - log.error("Invoke " + getGroupDescFromServiceKey(entry.getKey()) + - " failed: " + r.getException().getMessage(), - r.getException()); - } else { - resultList.add(r); - } - } catch (Exception e) { - throw new RpcException("Failed to invoke service " + entry.getKey() + ": " + e.getMessage(), e); - } - } - - if (resultList.isEmpty()) { - return new RpcResult((Object) null); - } else if (resultList.size() == 1) { - return resultList.iterator().next(); - } - - if (returnType == void.class) { - return new RpcResult((Object) null); - } -``` -如果配置了merger,会依次调用,结果都放在results里面,其中value都是future类型,等调用完成之后,再遍历results,通过future.get拿到真正的结果,到此为止,所有调用的结果都放在resultList里面了,接下来要做的是把结果进行聚合: - -```java - Merger resultMerger; - if (ConfigUtils.isDefault(merger)) { - resultMerger = MergerFactory.getMerger(returnType); - } else { - resultMerger = ExtensionLoader.getExtensionLoader(Merger.class).getExtension(merger); - } - if (resultMerger != null) { - List rets = new ArrayList(resultList.size()); - for (Result r : resultList) { - rets.add(r.getValue()); - } - result = resultMerger.merge( - rets.toArray((Object[]) Array.newInstance(returnType, 0))); - } else { - throw new RpcException("There is no merger to merge result.") - } - return new RpcResult(result); -``` -这里会根据返回值的类型,获取到对应的resultMerger,除了Dubbo默认实现的类型外,也可以自己指定merger类型并且添加相应的扩展,通过实现`merge`方法类进行结果聚合。 \ No newline at end of file diff --git a/content/en/blog/java/demos/service-test.md b/content/en/blog/java/demos/service-test.md deleted file mode 100644 index db22f79ab126..000000000000 --- a/content/en/blog/java/demos/service-test.md +++ /dev/null @@ -1,166 +0,0 @@ ---- -title: "Dubbo Admin Service Testing Features" -linkTitle: "Dubbo Admin Service Testing Features" -tags: ["Java"] -date: 2019-08-26 -slug: service-test -description: > - You can call the real service provider on the console through generic invocation ---- - -Based on the metadata of Dubbo 2.7, Dubbo Admin implements service testing functions, allowing real service providers to be called on the console through generic invocation. - -## Usage -* Deploy Service Provider: You can download the demo [here](https://github.com/nzomkxia/dubbo-demo). This project is based on Spring Boot, making it easy to start from an IDE or command line. For service testing, simply start `dubbo-basic-provider`. -* Service Query: After completing the server deployment, you can query the corresponding service on the Dubbo Admin `Service Testing` page: -![testSearch](/imgs/blog/admin/testSearch.jpg) -The information here is similar to the metadata and contains method names, parameter types, and return value information. Click the tab on the right to enter the service testing page. -* Service Testing: -![testSuccess](/imgs/blog/admin/testSuccess.jpg) -The service testing page includes two JSON editors. Parameter type information is stored in JSON format. Here, you need to fill in the corresponding parameter values (in this case, the data type is `String`), and after filling in, click `Execute` to invoke the backend service. The call result is displayed in the editor on the right. If the call fails, detailed failure reasons will be shown. Let's look at an example of a failed call: -![testFail](/imgs/blog/admin/testFail.jpg) -In this example, the Dubbo service provider's process is first shut down, and then the service test is executed. The returned result indicates an exception of `Service provider not found`. Similar to normal calls, business and framework exceptions will be returned in the result, facilitating business troubleshooting. - -* Complex Type Parameters -Consider the following methods and types in `UserService`: -```java -//org.apache.dubbo.demo.api.UserService -Result getUser(String name, UserInfoDO userInfoDO); -``` -```java -public class UserInfoDO { - private int id; - private LocationDO locationDO; - private DepartmentDO departmentDO; - - @Override - public String toString() { - return "UserInfoDO{" + - "id=" + id + - ", locationDO=" + locationDO.toString() + - ", departmentDO=" + departmentDO.toString() + - '}'; - } -} -``` - -```java -public class DepartmentDO { - - private String departName; - private LocationDO departLocation; - - @Override - public String toString() { - return "DepartmentDO{" + - "departName='" + departName + '\'' + - ", departLocation=" + departLocation.toString() + - '}'; - } -} -``` - -```java -public class LocationDO { - private String address; - private int postNum; - - @Override - public String toString() { - return "LocationDO{" + - "address='" + address + '\'' + - ", postNum=" + postNum + - '}'; - } -} -``` -The parameters are relatively complex compound type parameters. During service testing, each field's value needs to be filled in layer by layer, as shown in the figure below: -![complex](/imgs/blog/admin/complex.jpg) -It can also be invoked successfully and return results. - -## Principle: Data Source -In service testing, the most important aspect is the complete method signature information and parameter type information. With this information, each parameter's value can be filled in step by step to assemble a complete service consumer. In Dubbo 2.7, a metadata center has been added, and the method signature and parameter type information of Dubbo Admin come from here: -![medatada](/imgs/blog/admin/metadata.png) -As shown in the figure, the server will register the service's metadata information to the metadata center when running, in the format: -```json -{ - ... - "methods": [ - { - "name": "sayHello", - "parameterTypes": [ - "org.apache.dubbo.demo.model.User" - ], - "returnType": "org.apache.dubbo.demo.model.Result" - }, - ... - ], - "types": [ - { - "type": "char" - }, - { - "type": "long" - }, - { - "type": "org.apache.dubbo.demo.model.Result", - "properties": { - "msg": { - "type": "java.lang.String", - "properties": { - "value": { - "type": "char[]" - }, - "hash": { - "type": "int" - } - } - }, - "userName": { - "type": "java.lang.String", - "properties": { - "value": { - "type": "char[]" - }, - "hash": { - "type": "int" - } - } - } - } - }, - { - "type": "org.apache.dubbo.demo.model.User", - "properties": { - "id": { - "type": "java.lang.Long", - "properties": { - "value": { - "type": "long" - } - } - }, - "username": { - "type": "java.lang.Sring", - "properties": { - "value": { - "type": "char[]" - }, - "hash": { - "type": "int" - } - } - } - } - }, - ... - ] -} -``` -The information related to service testing is contained in the `methods` and `types` sections. Dubbo Admin uses this information to render parameters in the JSON Editor on the service testing page, allowing users to input each parameter and each member variable's value. - -## Principle: Generic Calling -With parameter types identified, the next question is how to invoke the service on the server side. In traditional Dubbo RPC calls, the client needs to rely on the server-side API jar package (refer to the earlier demo for [dubbo-basic-consumer](https://github.com/nzomkxia/dubbo-demo/tree/master/dubbo-basic-consumer)). This is not feasible for Dubbo Admin because services go online and offline dynamically, and Dubbo Admin cannot dynamically add jar package dependencies. Therefore, Dubbo's **generic call** is utilized, which allows the client to initiate a service call directly through the `GenericService` interface without the server API interfaces, using Map to represent data objects in the return value. Generic calls do not require special handling on the server side; they only need to be initiated by the client. - -## Summary and Outlook -This article briefly introduces the usage and principles of service testing. In the future, there will be enhancements for this feature, such as handling abstract class parameter types, supporting importing parameter values from JSON files, and saving parameter values, making it easier for regression testing of service interfaces. diff --git a/content/en/blog/java/demos/spring-boot-dubbo-start-stop-analysis.md b/content/en/blog/java/demos/spring-boot-dubbo-start-stop-analysis.md deleted file mode 100644 index 2c347ef44c59..000000000000 --- a/content/en/blog/java/demos/spring-boot-dubbo-start-stop-analysis.md +++ /dev/null @@ -1,202 +0,0 @@ ---- -title: "Source Code Analysis of Starting and Stopping Spring Boot Dubbo Applications" -linkTitle: "Source Code Analysis of Starting and Stopping Spring Boot Dubbo Applications" -tags: ["Java"] -date: 2018-08-14 -description: > - This article analyzes the implementation principles of Dubbo starting and stopping source code in the `dubbo-spring-boot-project`. ---- - -## Background Introduction - -The [Dubbo Spring Boot](https://github.com/apache/dubbo-spring-boot-project) project aims to simplify the development of the Dubbo RPC framework in Spring Boot application scenarios. It also integrates Spring Boot features: - -- [Auto-configuration](https://github.com/apache/dubbo-spring-boot-project/blob/master/dubbo-spring-boot-autoconfigure) (e.g., annotation-driven, auto-configuration, etc.). -- [Production-Ready](https://github.com/apache/dubbo-spring-boot-project/blob/master/dubbo-spring-boot-actuator) (e.g., security, health checks, externalized configuration, etc.). - -## DubboConsumer Startup Analysis - -Have you ever wondered about a question? In the `dubbo-spring-boot-project`, the `DubboConsumerDemo` application has just one line of code, why does it not exit immediately after executing the `main` method? - -```java -@SpringBootApplication(scanBasePackages = "com.alibaba.boot.dubbo.demo.consumer.controller") -public class DubboConsumerDemo { - - public static void main(String[] args) { - SpringApplication.run(DubboConsumerDemo.class,args); - } - -} -``` - -To answer this question, we first need to abstract it: under what conditions does a JVM process exit? - -Taking Java 8 as an example, a clear description can be found in section 12.8 of the JVM language specification [1]: - -A program terminates all its activity and *exits* when one of two things happens: - -- All the threads that are not daemon threads terminate. -- Some thread invokes the `exit` method of class `Runtime` or class `System`, and the `exit` operation is not forbidden by the security manager. - -This means that there are only two situations that cause the JVM to exit: - -1. All non-daemon processes are completely terminated. -2. Some thread calls `System.exit()` or `Runtime.exit()`. - -Thus, we judge that there is definitely a non-daemon thread that has not exited. We can see all thread information, including whether they are daemon threads, using jstack. - -```sh -➜ jstack 57785 | grep tid | grep -v "daemon" -"container-0" #37 prio=5 os_prio=31 tid=0x00007fbe312f5800 nid=0x7103 waiting on condition [0x0000700010144000] -"container-1" #49 prio=5 os_prio=31 tid=0x00007fbe3117f800 nid=0x7b03 waiting on condition [0x0000700010859000] -... -``` - -> Here, we found all thread summaries by grepping tid and excluded daemon threads using grep -v. - -From the above results, we discovered some information: - -* Two threads, `container-0` and `container-1`, are non-daemon threads and are in a wait state. -* There are some GC-related threads and VM threads, but they are likely JVM internal threads and can be ignored for now. - -Therefore, we can infer that it is most likely due to `container-0` and `container-1` that the JVM does not exit. - -Now, let's use the source code to search for who created these two threads. - -By analyzing the `spring-boot` source code, we found the following code in `org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer`'s `startDaemonAwaitThread`: - -```java - private void startDaemonAwaitThread() { - Thread awaitThread = new Thread("container-" + (containerCounter.get())) { - - @Override - public void run() { - TomcatEmbeddedServletContainer.this.tomcat.getServer().await(); - } - - }; - awaitThread.setContextClassLoader(getClass().getClassLoader()); - awaitThread.setDaemon(false); - awaitThread.start(); - } -``` - -In this method, we can see that during the startup of the Spring Boot application, Tomcat is started by default to expose the HTTP service, therefore executing this method. All threads started by Tomcat are daemons by default. Hence, a separate non-daemon thread is explicitly started to continually wait under certain conditions, preventing exit. - -Next, let's delve into how this behavior of ‘not exiting’ is implemented in the method `this.tomcat.getServer().await()`. - -```java -public void await() { - // ... - if(port==-1) { - try { - awaitThread = Thread.currentThread(); - while(!stopAwait) { - try { - Thread.sleep(10000); - } catch(InterruptedException ex) { - // continue and check the flag - } - } - } finally { - awaitThread = null; - } - return; - } - // ... - } -``` - -In the `await` method, the current thread enters a while loop that checks the `stopAwait` variable every 10 seconds. This is a `volatile` variable, ensuring that if another thread modifies it, the current thread can immediately see the change. If there’s no change, it will remain in the loop, which explains why the thread does not exit and, consequently, why the entire Spring Boot application does not exit. - -Since the Spring Boot application starts both port 8080 and port 8081 (management port), it actually starts two Tomcats, hence the two threads `container-0` and `container-1`. - -Now, let’s see how this Spring Boot application exits. - -## DubboConsumer Exit Analysis - -In previous sections, it was mentioned that a thread continuously checks the `stopAwait` variable. Naturally, we think that during stop, a thread should modify `stopAwait`, breaking this while loop. So who modifies this variable? - -Through source code analysis, we find that only one method modifies `stopAwait`, which is `org.apache.catalina.core.StandardServer#stopAwait`. Let's set a breakpoint there and see who calls it. - -> Note: When we set a breakpoint in Intellij IDEA in debug mode, we need to use `kill -s INT $PID` or `kill -s TERM $PID` in the command line to trigger the breakpoint. Clicking the Stop button on the IDE will not trigger the breakpoint; this is a bug with IDEA. - -It turns out that a thread named `Thread-3` calls this method: - -```java -stopAwait:390, StandardServer (org.apache.catalina.core) -stopInternal:819, StandardServer (org.apache.catalina.core) -stop:226, LifecycleBase (org.apache.catalina.util) -stop:377, Tomcat (org.apache.catalina.startup) -stopTomcat:241, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat) -stop:295, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat) -stopAndReleaseEmbeddedServletContainer:306, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded) -onClose:155, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded) -doClose:1014, AbstractApplicationContext (org.springframework.context.support) -run:929, AbstractApplicationContext$2 (org.springframework.context.support) -``` - -Through the source code analysis, it turns out that this is executed via a `ShutdownHook` registered by Spring: - -```java - @Override - public void registerShutdownHook() { - if (this.shutdownHook == null) { - this.shutdownHook = new Thread() { - @Override - public void run() { - synchronized (startupShutdownMonitor) { - doClose(); - } - } - }; - Runtime.getRuntime().addShutdownHook(this.shutdownHook); - } - } -``` - -From Java's API documentation [2], we know that the ShutdownHook will be executed in the following two scenarios: - -> The Java virtual machine *shuts down* in response to two kinds of events: -> -> - The program *exits* normally, when the last non-daemon thread exits or when the `exit` (equivalently, [`System.exit`](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#exit-int-)) method is invoked, or -> - The virtual machine is *terminated* in response to a user interrupt, such as typing `^C`, or a system-wide event, such as user logoff or system shutdown. - -1. When the `System.exit()` method is invoked. -2. In response to external signals, such as Ctrl+C (which sends the SIGINT signal) or the SIGTERM signal (the default `kill $PID` sends the SIGTERM signal). - -Therefore, during the normal shutdown process (excluding `kill -9 $PID`), the aforementioned ShutdownHook executes, performing not only the shutdown of Tomcat but also other cleanup tasks that will not be elaborated on here. - -## Summary - -1. During the startup of `DubboConsumer`, a separate non-daemon thread is started to continuously check the state of a variable, ensuring the process does not exit. -2. During the shutdown of `DubboConsumer`, the Spring container’s shutdown hook modifies the state of the variable, allowing the program to exit normally. - -## Questions - -In the example of DubboProvider, we see that the Provider does not start Tomcat to provide HTTP services. So how does it implement not exiting? We will answer this question in the next article. - -### Easter Egg - -In `Intellij IDEA`, by running the following unit test, creating a thread that sleeps for 1000 seconds, we were surprised to find that the code does not exit even after the thread completes, why is that? (The created thread is a non-daemon thread) - -```java - @Test - public void test() { - new Thread(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(1000000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - }).start(); - } -``` - -[1] https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.8 - -[2] https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#addShutdownHook - diff --git a/content/en/blog/java/demos/test-verification.md b/content/en/blog/java/demos/test-verification.md deleted file mode 100644 index f50b7228c4dc..000000000000 --- a/content/en/blog/java/demos/test-verification.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: "Dubbo Testing Validation" -linkTitle: "Dubbo Testing Validation" -tags: ["Java"] -date: 2019-12-02 -description: > - Validation tests for features under development or calling services from a specific machine ---- - -In addition to the usual online usage scenarios, we also need some specific usage methods in our daily use, such as validating features under development or calling services from a specific machine. This article introduces the usage methods in these scenarios. - -### Subscribe Only -To facilitate development testing, an all-service available registry is often shared in offline environments. If a service provider under development registers, it may affect the proper functioning of consumers. - -The service provider's development team can subscribe only to the service (as the developed service may depend on other services), without registering the service under development, testing the developing service through a direct connection. -![subscribe-only](/imgs/blog/subscribe-only.jpg) -Disable registration configuration - - -or - - - -### Specify IP for Calling -In development and testing environments, we often need to bypass the registry and test specific service providers. This may require point-to-point connections, where point-to-point connections ignore the provider list from the registry and configure point-to-point for service interfaces, without affecting other interfaces from retrieving lists from the registry. -![subscribe-only](/imgs/blog/dubbo-directly.jpg) - -You can specify IP calling through the following configurations: - -* XML configuration: If point-to-point is required in the online demand, you can configure the URL pointing to the provider in ``, which will bypass the registry, with multiple addresses separated by semicolons, as follows: - `` -* Specify using -D parameter: Add -D parameter to JVM startup parameters to map service address, e.g., `java -Dcom.alibaba.xxx.XxxService=dubbo://localhost:20890` -* File mapping: If there are many services, file mapping can be used; specify the mapping file path using -Ddubbo.resolve.file. This configuration takes precedence over the one in ``, like: -`java -Ddubbo.resolve.file=xxx.properties` -Then add the configuration in the mapping file xxx.properties, where the key is the service name and the value is the service provider URL: `com.alibaba.xxx.XxxService=dubbo://localhost:20890` - -### Echo Testing -#### Usage -Echo testing is used to check the availability of services. It executes according to the normal request process, allowing testing of the whole call flow and can be used for monitoring. - -All services automatically implement the EchoService interface. You just need to force any service reference to be cast to EchoService to use it. - -Spring Configuration: - - -Code: - -``` -// Remote service reference -MemberService memberService = ctx.getBean("memberService"); - -EchoService echoService = (EchoService) memberService; // Force cast to EchoService - -// Echo test availability -String status = echoService.$echo("OK"); - -assert(status.equals("OK")); -``` -#### Implementation Principle -When we implemented the registration of services, we did not configure the EchoService interface. Why can it be used directly? It turns out that Dubbo generates the proxy by already implementing the `EchoService interface` - -```java - @Override - public T getProxy(Invoker invoker) throws RpcException { - Class[] interfaces = null; - String config = invoker.getUrl().getParameter("interfaces"); - if (config != null && config.length() > 0) { - String[] types = Constants.COMMA_SPLIT_PATTERN.split(config); - if (types != null && types.length > 0) { - interfaces = new Class[types.length + 2]; - interfaces[0] = invoker.getInterface(); - interfaces[1] = EchoService.class; - for (int i = 0; i < types.length; i++) { - interfaces[i + 1] = ReflectUtils.forName(types[i]); - } - } - } - if (interfaces == null) { - interfaces = new Class[]{invoker.getInterface(), EchoService.class}; - } - return getProxy(invoker, interfaces); - } -``` -In this way, any bean can be converted into an instance of EchoService, but the method `$echo` is not implemented. Here, Dubbo uses the filter mechanism to handle it: - -```java -public class EchoFilter implements Filter { - - @Override - public Result invoke(Invoker invoker, Invocation inv) throws RpcException { - if (inv.getMethodName().equals(Constants.$ECHO) && inv.getArguments() != null && inv.getArguments().length == 1) - return new RpcResult(inv.getArguments()[0]); - return invoker.invoke(inv); - } - -} -``` -When passing through the EchoFilter.invoke method, if the call is `$echo`, it will interrupt the current call process and directly return the argument of `$echo`; otherwise, it will continue to execute the filter chain. Through dynamic proxy and the EchoFilter mechanism, the entire echo testing process is transparent to the user, requiring no additional configuration; it can be called directly. - diff --git a/content/en/blog/java/demos/v3.2_rest_protocol_design.md b/content/en/blog/java/demos/v3.2_rest_protocol_design.md deleted file mode 100644 index 6463c64ad35a..000000000000 --- a/content/en/blog/java/demos/v3.2_rest_protocol_design.md +++ /dev/null @@ -1,660 +0,0 @@ ---- -aliases: - - /en/docs3-v2/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ - - /en/docs3-v2/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ - - /en/overview/mannual/java-sdk/concepts-and-architecture/v3.2_rest_protocol_design/ - - /en/overview/mannual/java-sdk/reference-manual/protocol/v3.2_rest_protocol_design/ -description: 本文将介绍 Dubbo 2.x 版本中的 Rest 协议及其未来的重构方向。 -linkTitle: 2.7 版本 Rest 协议实现重构设想 -title: Rest 协议 -tags: ["Java"] -date: 2022-07-26 ---- - - - - -# Dubbo RestProtocol 设计文档 - -## 原版本dubbo rest - -consumer - -restClient支持 依赖resteasy 不支持spring mvc  - -provider(较重) - -依赖web container   (tomcat,jetty,)servlet 模式,jaxrs netty server - -### 改版dubbo rest  - -方向: - -更加轻量,具有dubbo风格的rest,微服务体系互通(Springcloud Alibaba) - -1.注解解析 - -2.报文编解码 - -3.restClient - -4.restServer(netty) - -支持程度: - -content-type   text json xml form(后续会扩展) - -注解 - -param,header,body,pathvariable (spring mvc & resteasy) - -## Http 协议报文 - - POST /test/path? HTTP/1.1 - Host: localhost:8080 - Connection: keep-alive - Content-type: application/json - - - {"name":"dubbo","age":10,"address":"hangzhou"} - - - -### dubbo http(header) - - // service key header - path: com.demo.TestInterface - group: demo - port: 80 - version: 1.0.0 - - // 保证长连接 - Keep-Alive,Connection: keep-alive - Keep-alive: 60 - - // RPCContext Attachment - userId: 123456 - - -## 目前支持粒度: - -| 数据位置 | content-type | spring注解 | resteasy注解 | -| --- | --- | --- | --- | -| body | 无要求 | ReuqestBody |  无注解即为body | -| querystring(?test=demo) | 无要求 | RequestParam | QueryParam | -| header | 无要求 | RequestHeader | PathParam | -| form | application/x-www-form-urlencoded | RequestParam ReuqestBody | FormParam | -| path | 无要求 | PathVariable | PathParam | -| method | 无要求 | PostMapping GetMapping | GET POST | -| url | | PostMapping GetMapping path属性 | Path | -| content-type | | PostMapping GetMapping consumers属性 | Consumers | -| Accept | | PostMapping GetMapping produces属性 | Produces | - -## rest注解解析(ServiceRestMetadataResolver) - - JAXRSServiceRestMetadataResolver - - SpringMvcServiceRestMetadataResolver - -ServiceRestMetadata - - public class ServiceRestMetadata implements Serializable { - - private String serviceInterface; // com.demo.TestInterface - - private String version;// 1.0.0 - - private String group;// demo - - private Set meta;// method 元信息 - - private int port;// 端口 for provider service key - - private boolean consumer;// consumer 标志 - - /** - * make a distinction between mvc & resteasy - */ - private Class codeStyle;// - - /** - * for provider - */ - private Map pathToServiceMap; - - /** - * for consumer - */ - private Map> methodToServiceMa - -RestMethodMetadata - - public class RestMethodMetadata implements Serializable { - - private MethodDefinition method; // method 定义信息(name ,pramType,returnType) - - private RequestMetadata request;// 请求元信息 - - private Integer urlIndex; - - private Integer bodyIndex; - - private Integer headerMapIndex; - - private String bodyType; - - private Map> indexToName; - - private List formParams; - - private Map indexToEncoded; - - private ServiceRestMetadata serviceRestMetadata; - - private List argInfos; - - private Method reflectMethod; - - /** - * make a distinction between mvc & resteasy - */ - private Class codeStyle; - - -ArgInfo - - public class ArgInfo { - /** - * method arg index 0,1,2,3 - */ - private int index; - /** - * method annotation name or name - */ - private String annotationNameAttribute; - - /** - * param annotation type - */ - private Class paramAnnotationType; - - /** - * param Type - */ - private Class paramType; - - /** - * param name - */ - private String paramName; - - /** - * url split("/") String[n] index - */ - private int urlSplitIndex; - - private Object defaultValue; - - private boolean formContentType; - -RequestMeatadata - - public class RequestMetadata implements Serializable { - - private static final long serialVersionUID = -240099840085329958L; - - private String method;// 请求method - - private String path;// 请求url - - - private Map> params // param参数?拼接 - - private Map> headers// header; - - private Set consumes // content-type; - - private Set produces // Accept; - -### Consumer 代码: - -refer: - - @Override - protected Invoker protocolBindingRefer(final Class type, final URL url) throws RpcException { - - // restClient spi创建 - ReferenceCountedClient refClient = - clients.computeIfAbsent(url.getAddress(), key -> createReferenceCountedClient(url, clients)); - - refClient.retain(); - - // resolve metadata - Map> metadataMap = MetadataResolver.resolveConsumerServiceMetadata(type, url); - - ReferenceCountedClient finalRefClient = refClient; - Invoker invoker = new AbstractInvoker(type, url, new String[]{INTERFACE_KEY, GROUP_KEY, TOKEN_KEY}) { - @Override - protected Result doInvoke(Invocation invocation) { - try { - // 获取 method的元信息 - RestMethodMetadata restMethodMetadata = metadataMap.get(invocation.getMethodName()).get(ParameterTypesComparator.getInstance(invocation.getParameterTypes())); - - RequestTemplate requestTemplate = new RequestTemplate(invocation, restMethodMetadata.getRequest().getMethod(), url.getAddress(), getContextPath(url)); - - HttpConnectionCreateContext httpConnectionCreateContext = new HttpConnectionCreateContext(); - // TODO dynamic load config - httpConnectionCreateContext.setConnectionConfig(new HttpConnectionConfig()); - httpConnectionCreateContext.setRequestTemplate(requestTemplate); - httpConnectionCreateContext.setRestMethodMetadata(restMethodMetadata); - httpConnectionCreateContext.setInvocation(invocation); - httpConnectionCreateContext.setUrl(url); - - // http 信息构建拦截器 - for (HttpConnectionPreBuildIntercept intercept : httpConnectionPreBuildIntercepts) { - intercept.intercept(httpConnectionCreateContext); - } - - - CompletableFuture future = finalRefClient.getClient().send(requestTemplate); - CompletableFuture responseFuture = new CompletableFuture<>(); - AsyncRpcResult asyncRpcResult = new AsyncRpcResult(responseFuture, invocation); - // response 处理 - future.whenComplete((r, t) -> { - if (t != null) { - responseFuture.completeExceptionally(t); - } else { - AppResponse appResponse = new AppResponse(); - try { - int responseCode = r.getResponseCode(); - MediaType mediaType = MediaType.TEXT_PLAIN; - - if (400 < responseCode && responseCode < 500) { - throw new HttpClientException(r.getMessage()); - } else if (responseCode >= 500) { - throw new RemoteServerInternalException(r.getMessage()); - } else if (responseCode < 400) { - mediaType = MediaTypeUtil.convertMediaType(r.getContentType()); - } - - - Object value = HttpMessageCodecManager.httpMessageDecode(r.getBody(), - restMethodMetadata.getReflectMethod().getReturnType(), mediaType); - appResponse.setValue(value); - Map headers = r.headers() - .entrySet() - .stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0))); - appResponse.setAttachments(headers); - responseFuture.complete(appResponse); - } catch (Exception e) { - responseFuture.completeExceptionally(e); - } - } - }); - return asyncRpcResult; - } catch (RpcException e) { - if (e.getCode() == RpcException.UNKNOWN_EXCEPTION) { - e.setCode(getErrorCode(e.getCause())); - } - throw e; - } - } - - @Override - public void destroy() { - super.destroy(); - invokers.remove(this); - destroyInternal(url); - } - }; - invokers.add(invoker); - return invoker; - -### provider 代码: - -export: - - public Exporter export(final Invoker invoker) throws RpcException { - URL url = invoker.getUrl(); - final String uri = serviceKey(url); - Exporter exporter = (Exporter) exporterMap.get(uri); - if (exporter != null) { - // When modifying the configuration through override, you need to re-expose the newly modified service. - if (Objects.equals(exporter.getInvoker().getUrl(), invoker.getUrl())) { - return exporter; - } - } - - - // TODO addAll metadataMap to RPCInvocationBuilder metadataMap - Map metadataMap = MetadataResolver.resolveProviderServiceMetadata(url.getServiceModel().getProxyObject().getClass(),url); - - PathAndInvokerMapper.addPathAndInvoker(metadataMap, invoker); - - - final Runnable runnable = doExport(proxyFactory.getProxy(invoker, true), invoker.getInterface(), invoker.getUrl()); - exporter = new AbstractExporter(invoker) { - @Override - public void afterUnExport() { - exporterMap.remove(uri); - if (runnable != null) { - try { - runnable.run(); - } catch (Throwable t) { - logger.warn(PROTOCOL_UNSUPPORTED, "", "", t.getMessage(), t); - } - } - } - }; - exporterMap.put(uri, exporter); - return exporter; - } - -RestHandler - - private class RestHandler implements HttpHandler { - - @Override - public void handle(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException, ServletException { - // 有servlet reuqest 和nettyRequest - RequestFacade request = RequestFacadeFactory.createRequestFacade(servletRequest); - RpcContext.getServiceContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort()); - // dispatcher.service(request, servletResponse); - - Pair build = null; - try { - // 根据请求信息创建 RPCInvocation - build = RPCInvocationBuilder.build(request, servletRequest, servletResponse); - } catch (PathNoFoundException e) { - servletResponse.setStatus(404); - } - - Invoker invoker = build.getSecond(); - - Result invoke = invoker.invoke(build.getFirst()); - - // TODO handling exceptions - if (invoke.hasException()) { - servletResponse.setStatus(500); - } else { - - try { - Object value = invoke.getValue(); - String accept = request.getHeader(RestConstant.ACCEPT); - MediaType mediaType = MediaTypeUtil.convertMediaType(accept); - // TODO write response - HttpMessageCodecManager.httpMessageEncode(servletResponse.getOutputStream(), value, invoker.getUrl(), mediaType); - servletResponse.setStatus(200); - } catch (Exception e) { - servletResponse.setStatus(500); - } - - - } - - // TODO add Attachment header - - - } - } - -RPCInvocationBuilder - - { - - - private static final ParamParserManager paramParser = new ParamParserManager(); - - - public static Pair build(RequestFacade request, Object servletRequest, Object servletResponse) { - - // 获取invoker - Pair invokerRestMethodMetadataPair = getRestMethodMetadata(request); - - RpcInvocation rpcInvocation = createBaseRpcInvocation(request, invokerRestMethodMetadataPair.getSecond()); - - ProviderParseContext parseContext = createParseContext(request, servletRequest, servletResponse, invokerRestMethodMetadataPair.getSecond()); - // 参数构建 - Object[] args = paramParser.providerParamParse(parseContext); - - rpcInvocation.setArguments(args); - - return Pair.make(rpcInvocation, invokerRestMethodMetadataPair.getFirst()); - - } - - private static ProviderParseContext createParseContext(RequestFacade request, Object servletRequest, Object servletResponse, RestMethodMetadata restMethodMetadata) { - ProviderParseContext parseContext = new ProviderParseContext(request); - parseContext.setResponse(servletResponse); - parseContext.setRequest(servletRequest); - - Object[] objects = new Object[restMethodMetadata.getArgInfos().size()]; - parseContext.setArgs(Arrays.asList(objects)); - parseContext.setArgInfos(restMethodMetadata.getArgInfos()); - - - return parseContext; - } - - private static RpcInvocation createBaseRpcInvocation(RequestFacade request, RestMethodMetadata restMethodMetadata) { - RpcInvocation rpcInvocation = new RpcInvocation(); - - - int localPort = request.getLocalPort(); - String localAddr = request.getLocalAddr(); - int remotePort = request.getRemotePort(); - String remoteAddr = request.getRemoteAddr(); - - String HOST = request.getHeader(RestConstant.HOST); - String GROUP = request.getHeader(RestConstant.GROUP); - - String PATH = request.getHeader(RestConstant.PATH); - String VERSION = request.getHeader(RestConstant.VERSION); - - String METHOD = restMethodMetadata.getMethod().getName(); - String[] PARAMETER_TYPES_DESC = restMethodMetadata.getMethod().getParameterTypes(); - - rpcInvocation.setParameterTypes(restMethodMetadata.getReflectMethod().getParameterTypes()); - - - rpcInvocation.setMethodName(METHOD); - rpcInvocation.setAttachment(RestConstant.GROUP, GROUP); - rpcInvocation.setAttachment(RestConstant.METHOD, METHOD); - rpcInvocation.setAttachment(RestConstant.PARAMETER_TYPES_DESC, PARAMETER_TYPES_DESC); - rpcInvocation.setAttachment(RestConstant.PATH, PATH); - rpcInvocation.setAttachment(RestConstant.VERSION, VERSION); - rpcInvocation.setAttachment(RestConstant.HOST, HOST); - rpcInvocation.setAttachment(RestConstant.REMOTE_ADDR, remoteAddr); - rpcInvocation.setAttachment(RestConstant.LOCAL_ADDR, localAddr); - rpcInvocation.setAttachment(RestConstant.REMOTE_PORT, remotePort); - rpcInvocation.setAttachment(RestConstant.LOCAL_PORT, localPort); - - Enumeration attachments = request.getHeaders(RestConstant.DUBBO_ATTACHMENT_HEADER); - - while (attachments != null && attachments.hasMoreElements()) { - String s = attachments.nextElement(); - - String[] split = s.split("="); - - rpcInvocation.setAttachment(split[0], split[1]); - } - - - // TODO set path,version,group and so on - return rpcInvocation; - } - - - private static Pair getRestMethodMetadata(RequestFacade request) { - String path = request.getRequestURI(); - String version = request.getHeader(RestConstant.VERSION); - String group = request.getHeader(RestConstant.GROUP); - int port = request.getIntHeader(RestConstant.REST_PORT); - - return PathAndInvokerMapper.getRestMethodMetadata(path, version, group, port); - } - - - } - -## 编码示例 - -API - -mvc: - - @RestController() - @RequestMapping("/demoService") - public interface DemoService { - @RequestMapping(value = "/hello", method = RequestMethod.GET) - Integer hello(@RequestParam Integer a, @RequestParam Integer b); - - @RequestMapping(value = "/error", method = RequestMethod.GET) - String error(); - - @RequestMapping(value = "/say", method = RequestMethod.POST, consumes = MediaType.TEXT_PLAIN_VALUE) - String sayHello(@RequestBody String name); - } - -resteasy: - - @Path("/demoService") - public interface RestDemoService { - @GET - @Path("/hello") - Integer hello(@QueryParam("a")Integer a,@QueryParam("b") Integer b); - - @GET - @Path("/error") - String error(); - - @POST - @Path("/say") - @Consumes({MediaType.TEXT_PLAIN}) - String sayHello(String name); - - boolean isCalled(); - } - -impl(service) - - @DubboService() - public class RestDemoServiceImpl implements RestDemoService { - private static Map context; - private boolean called; - - - @Override - public String sayHello(String name) { - called = true; - return "Hello, " + name; - } - - - public boolean isCalled() { - return called; - } - - @Override - public Integer hello(Integer a, Integer b) { - context = RpcContext.getServerAttachment().getObjectAttachments(); - return a + b; - } - - - @Override - public String error() { - throw new RuntimeException(); - } - - public static Map getAttachments() { - return context; - } - } - -## 流程图 - -**Consumer**   - -![image](https://static.dingtalk.com/media/lQLPJxLOtqTxs9TNA5rNBQCwci8F2QYiGAYD5sSyd4BVAA_1280_922.png) - -**Provider(RestServer)** - -![image](https://static.dingtalk.com/media/lQLPJxZcNUm4M9TNA1_NBMuwZUu6IC3FeYAD5sSydYADAA_1227_863.png) - -## 场景 : - -**非dubbo体系互通(Springcloud alibaba  互通)** - -互通条件: - -| | 协议 | Dubbo | SpringCloud Alibaba | 互通 | -| --- | --- | --- | --- | --- | -| 通信协议 | rest | spring web/resteasy  编码风格 | 集成feignclient,ribbon (spring web 编码风格) | 是 | -| | triple | | | | -| | dubbo | | | | -| | grpc | | | | -| | hessian | | | | -| 注册中心 | zookeeper | | | | -| | nacos | 支持 | 支持 | 应用级别注册 | - -### 2.dubbo 双注册  - - 完成应用级别注册,(dubo2-dubbo3 过度),dubbo版本升级 - -![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/0ceca951-f467-4ab3-9b71-8e7d52e5e7d1.png) - -![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/6bcc7aed-1d22-470f-b185-efbab32df1e5.png) - -### 3.多协议发布 - -配置: - - - -### 4.跨语言 - -![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/1bdf8f91-9666-4c20-9aea-8396c745f554.png) - -### 5.多协议交互 - -![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/af72e3df-05d5-42a2-a333-618be7ec6cb8.png) - -### 6.协议迁移 - -![image](https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/LvBPlNAjAmw3OdG8/img/36d30183-8d5f-494c-8ebb-b57403c88661.png) - -rest编码风格 - -Http协议更通用跨语言调用 - -dubbo rest 对其他http服务 进行调用 - -其他httpclient 对dubbo rest进行调用 - -dubbo restServer 可以与其他web服务,浏览器等客户端直接进行http交互 - -## consumer TODOLIST(功能已经初步实现,可以调通解析response) - -1. org/apache/dubbo/rpc/protocol/rest/RestProtocol.java:157  dynamic load config - -2.org/apache/dubbo/remoting/http/factory/AbstractHttpClientFactory.java:50 load config  HttpClientConfig - -3.org/apache/dubbo/rpc/protocol/rest/annotation/metadata/MetadataResolver.java:52  support Dubbo style service - -4.org/apache/dubbo/remoting/http/restclient/HttpClientRestClient.java:120  TODO config - -5.org/apache/dubbo/remoting/http/restclient/HttpClientRestClient.java:140 TODO close judge - -6.org/apache/dubbo/rpc/protocol/rest/message/decode/MultiValueCodec.java:35  TODO java bean  get set convert - -## provider TODOLIST(待实现) - -基于netty实现支持http协议的NettyServer - -无注解协议定义 - -官网场景补充 - -## Rest使用说明文档及demo: diff --git a/content/en/blog/java/proposals/_index.md b/content/en/blog/java/proposals/_index.md deleted file mode 100644 index cc0426c605d9..000000000000 --- a/content/en/blog/java/proposals/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Scheme Design" -linkTitle: "Scheme Design" -weight: 30 ---- diff --git a/content/en/blog/java/proposals/service-discovery-migration.md b/content/en/blog/java/proposals/service-discovery-migration.md deleted file mode 100644 index 3affc523a121..000000000000 --- a/content/en/blog/java/proposals/service-discovery-migration.md +++ /dev/null @@ -1,350 +0,0 @@ ---- -aliases: - - /en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery/ -title: "Smoothly Migrating from Interface-Level Service Discovery to Application-Level Service Discovery" -linkTitle: "Dubbo3 Service Discovery Smooth Migration Steps and Principles" -tags: ["Java","Service Discovery"] -date: 2024-05-13 -description: > - "Details on migrating to application-level service discovery in Dubbo3, including migration rules and operational principles." ---- - -Overall, in the address registration and discovery phase, `3.x` is fully compatible with `2.x`, which means users can choose to upgrade any number of applications or machines within the cluster to `3.x` while maintaining interoperability with `2.x` during the process. - -> For details on the migration principles, please refer to [migration rules and principles](../service-discovery-rule). - -## 1 Quick Upgrade Steps - -Simply updating the pom.xml to the latest version completes the upgrade; if migrating to application-level addresses, just adjust the switch controlling the default behavior of 3.x. - -1. Upgrade the Provider application to the latest 3.x version dependency and configure the dual registration switch `dubbo.application.register-mode=all` (preferably set through the global configuration center, which is enabled by default), completing the application release. -2. Upgrade the Consumer application to the latest 3.x version dependency and configure the dual subscription switch `dubbo.application.service-discovery.migration=APPLICATION_FIRST` (preferably set through the global configuration center, which is enabled by default), completing the application release. -3. Once all Consumers on the Provider have completed the application-level address migration, the Provider can switch to application-level address single registration to finish the upgrade. - -Below is a detailed description of the migration process. - -## 2 Provider Upgrade Process Explained - -Without changing any Dubbo configurations, an application or instance can be upgraded to version 3.x. The upgraded Dubbo instance will still ensure compatibility with version 2.x, meaning it will register the 2.x formatted addresses to the registry normally, keeping the upgraded instance visible to the entire cluster. - -At the same time, the new address discovery model (registering application-level addresses) will also be automatically registered. - -![//imgs/v3/migration/provider-registration.png](/imgs/v3/migration/provider-registration.png) - -1. Global Switch - -Application configuration (can be set via configuration files or -D) `dubbo.application.register-mode` to instance (register application-level only) or all (register both interface-level and application-level) opens the global registration switch. After configuring this switch, it will, by default, register application-level addresses in all registration centers for consumer service discovery. - -``` -# Dual Registration -dubbo.application.register-mode=all -``` -``` -# Application-Level Registration Only -dubbo.application.register-mode=instance -``` -By using the -D parameter, you can specify the registration behavior when the provider starts. - -```text --Ddubbo.application.register-mode=all -# Optional values are interface, instance, all; the default is all, meaning registering both interface-level and application-level addresses. -``` - -Additionally, you can modify the global default behavior in the configuration center to control the registration behavior of all 3.x instances. The priority of the global switch is lower than the -D parameter. - -2. Registry Address Parameter Configuration - -The address of the registry can be configured with `registry-type=service` to explicitly designate that registry as the application-level service discovery registry. Registries configured with this will only conduct application-level service discovery. -> [Reference Example](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-demo-servicediscovery-xml/servicediscovery-provider/src/main/resources/spring/dubbo-provider.xml) - -```xml - -``` - -To ensure smooth migration so that instances upgraded to 3.x can be discovered by both 2.x and 3.x consumer instances, 3.x instances must enable dual registration; once all upstream consumers have migrated to the 3.x address model, the provider can switch to instance mode (only registering application-level addresses). For information on how to upgrade consumers to 3.x, please refer to the next section. - -### 2.1 Resource Consumption from Dual Registration - -Dual registration will inevitably bring additional storage pressure to the registration center, but considering the significant storage advantage of the application-level address discovery model, even for users with extremely large-scale clusters, the added data volume will not pose a storage problem. Overall, for an ordinary cluster, data growth can be controlled to be between 1/100 and 1/1000 of the previous total data volume. - -For a medium-sized cluster instance: 2000 instances, 50 applications (500 Dubbo interfaces, with an average of 10 interfaces per application). - -Assuming the average size of each interface-level URL is 5kb and each application-level URL is 0.5kb. - -Old interface-level address amount: 2000 * 500 * 5kb ≈ 4.8G - -New application-level address amount: 2000 * 50 * 0.5kb ≈ 48M - -The dual registration only increases the data volume by 48M. - -## 3 Consumer Upgrade Process - -For 2.x consumer instances, they naturally see a list of providers at version 2.x; - -For 3.x consumers, they have the capability to discover both 2.x and 3.x provider addresses. By default, if there exists any consumable 3.x addresses in the cluster, they will automatically consume those, and if not, they will automatically consume 2.x addresses. Dubbo3 provides a switch to control this behavior: - -```text -dubbo.application.service-discovery.migration=APPLICATION_FIRST -# Optional values: -# FORCE_INTERFACE, only consume interface-level addresses, if no address exists, report an error, single subscribe to 2.x address. -# APPLICATION_FIRST, intelligently decide between interface-level and application-level addresses, dual subscription. -# FORCE_APPLICATION, only consume application-level addresses; if no address exists, report an error, single subscribe to 3.x address. -``` - -![//imgs/v3/migration/consumer-subscription.png](/imgs/v3/migration/consumer-subscription.png) - -1. Default Configuration (No configuration needed) - -After upgrading to Dubbo 3.0, the default behavior is to dual subscribe to interface-level and application-level addresses. If application-level addresses can be subscribed, they will use the application-level subscription; if not, they will use the interface-level subscription to ensure maximum compatibility. - -2. Subscription Parameter Configuration - -Application configuration (can be set via configuration files or -D) `dubbo.application.service-discovery.migration` to `APPLICATION_FIRST` enables the dual subscription mode, and configuring it as `FORCE_APPLICATION` forces it to single subscribe to application-level only. -Specific interface subscription can be configured in `ReferenceConfig` within `parameters` with key `migration.step` and value as `APPLICATION_FIRST` or `FORCE_APPLICATION` for single subscription configuration. - -`dubbo.application.service-discovery.migration` can be configured via `-D` and `global configuration center`. - -> [Reference Example](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-consumer/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConfigIT.java) - -```java -System.setProperty("dubbo.application.service-discovery.migration", "APPLICATION_FIRST"); -``` -```java -ReferenceConfig referenceConfig = new ReferenceConfig<>(applicationModel.newModule()); -referenceConfig.setInterface(DemoService.class); -referenceConfig.setParameters(new HashMap<>()); -referenceConfig.getParameters().put("migration.step", mode); -return referenceConfig.get(); -``` - -3. Dynamic Configuration (Highest Priority, can modify configuration at runtime) - -This configuration needs to be pushed based on the configuration center, where the key is the application name + `.migration` (e.g., `demo-application.migration`), and the group is `DUBBO_SERVICEDISCOVERY_MIGRATION`. For detailed configuration of the rule body, refer to [the guide to migrating from interface-level service discovery to application-level service discovery](../migration-service-discovery/). -> [Reference Example](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-consumer/src/main/java/org/apache/dubbo/demo/consumer/UpgradeUtil.java) - -```java -step: FORCE_INTERFACE -``` - -Next, let's take a closer look at how dual subscription mode (APPLICATION_FIRST) allows the upgraded 3.x consumers to migrate to application-level addresses. Before diving into specifics, it's essential to clarify a consumer's addressing behavior: **For dual subscription scenarios, although the consumer can hold both 2.x and 3.x addresses, the addressing process is completely isolated; it will either use the 2.x addresses or the 3.x addresses, without mixing calls from both sets. This decision-making process is completed upon receiving the first address notification.** - -Here’s an example of the operation process under the `APPLICATION_FIRST` strategy. - -First, set a configuration item in the global configuration center Nacos in advance (all consumer instances will execute this addressing strategy by default): - -![//imgs/v3/migration/nacos-migration-item.png](/imgs/v3/migration/nacos-migration-item.png) - -Next, upgrade the consumer to version 3.x and start it. At this point, the consumer reads the `APPLICATION_FIRST` config and executes the dual subscription logic (subscribing to both the 2.x interface-level addresses and the 3.x application-level addresses). - -Thus, the upgrade operation is completed, and the remaining task is handled internally by the framework. Before invocation occurs, the framework will have an "addressing process" at the consumer end, which differs from the previous 2.x version; this addressing process includes two levels of filtering: - -* First, filter the address list (ClusterInvoker) (interface-level address or application-level address) -* Then filter the actual provider addresses (Invoker). - -![//imgs/v3/migration/migration-cluster-item.png](/imgs/v3/migration/migration-cluster-invoker.png) - -The basis upon which ClusterInvoker filters can be defined through the MigrationAddressComparator SPI. Currently, there is a simple address count comparison strategy provided by the official; it allows migration when `the number of application-level addresses == the number of interface-level addresses`. - -> Actually, FORCE_INTERFACE, APPLICATION_FIRST, and FORCE_APPLICATION all control the filtering strategy of ClusterInvoker. - -### 3.1 Resource Consumption from Dual Subscription - -Dual subscription will inevitably increase memory consumption on the consumer side, but due to the advantages of application-level address discovery in terms of the total number of addresses, this increase is usually acceptable. We will analyze it from two perspectives: - -1. Increase in address-push data volume due to dual subscription. This was addressed in the section on "Resource Consumption from Dual Registration" where the increase in registration center data volume from application-level service discovery is very limited. -2. Increase in memory on the consumer side caused by dual subscription. Note that dual subscription only exists transiently at startup; after the ClusterInvoker's decision-making process, one set of addresses will be completely discarded; for a single service, the memory increase during the startup phase caused by dual subscription is generally controllable within 30% ~ 40% of the original memory volume, after which it will decrease to single subscription levels. If it switches to application-level addresses, a reduction of up to 50% in memory can be achieved. - -### 3.2 Finer Control on Consumer Side - -In addition to the global migration strategy, Dubbo provides finer-grained migration strategy support on the consumer side. Control can be at the level of a particular consumer application, with services A and B consuming it potentially having their respective independent migration strategies. This is achieved by configuring migration rules on the consumer side: - -```yaml -key: demo-consumer -step: APPLICATION_FIRST -applications: - - name: demo-provider - step: FORCE_APPLICATION -services: - - serviceKey: org.apache.dubbo.config.api.DemoService:1.0.0 - step: FORCE_INTERFACE -``` - -This method allows for precise migration control, but the modification cost for both now and in the future can be high, and we do not generally recommend activating this configuration mode except in special cases. -Officially, the recommended global switch migration strategy in the [migration guide](../service-discovery-rule/) allows consumer instances to decide which available address list to use during the startup phase. - -## 4 Convergence of Migration States - -To simultaneously support version 2.x while upgrading to version 3.x, applications will need to either be in a dual registration state or a dual subscription state for a period. - -To resolve this, we will look at it from the provider perspective. Once all Providers have switched to application-level address registration, the dual subscription issue will no longer exist. - -### 4.1 The Impact of Different Upgrade Strategies - -Undoubtedly, the sooner and more thoroughly the upgrade can be performed, the quicker this situation can be resolved. Suppose all applications within the organization can be upgraded to version 3.x; then the version convergence process becomes very straightforward: during the upgrade, Providers continue to maintain dual registration, and once all applications are upgraded to 3.x, the global default behavior can be adjusted, enabling Providers to switch to application-level single registration. This transition will not confuse Consumer applications because they will already be able to recognize application-level addresses as 3.x versions. - -If a full upgrade of applications is not feasible and only a portion can be upgraded for a considerable amount of time, the migration state will inevitably persist longer. -In this case, our goal can only be to maintain version and function convergence for upgraded applications in upstream and downstream implementations as much as possible. Encourage certain upstream consumers of Providers to upgrade to Dubbo3; doing so will allow for the removal of dual registration for those Providers. Achieving this may require support from auxiliary statistical tools. - -1. The ability to analyze the dependency relationships between applications, such as which consumer applications consume a Provider application, can be implemented using the service metadata reporting capability provided by Dubbo. -2. Knowing which Dubbo version each application is currently using can be achieved through scanning or active reporting methods. - -## 5 Migration State Model - -Before Dubbo 3, the address registration model registered at the interface level granularity in the registry, whereas the new application-level registration model in Dubbo 3 registers at the application level granularity. From the perspective of registry implementation, they are almost completely different, which leads to the fact that invokers obtained from interface-level registrations cannot be merged with those obtained from application-level registrations. To help users migrate from interface-level to application-level, Dubbo 3 has designed a Migration mechanism that implements address model switching through three state transitions. - -![//imgs/v3/migration/migration-1.png](/imgs/v3/migration/migration-1.png) - -Currently, there are three states: FORCE_INTERFACE (force interface level), APPLICATION_FIRST (application level first), FORCE_APPLICATION (force application level). - -FORCE_INTERFACE: Only enable the registry logic for interface-level service discovery under compatibility mode, where 100% of invocation traffic flows through the original process. -APPLICATION_FIRST: Enable dual subscription for interface-level and application-level, dynamically deciding the invocation traffic direction based on thresholds and gray traffic ratios. -FORCE_APPLICATION: Only enable the registry logic for application-level service discovery under the new model, where 100% of invocation traffic flows through application-level subscribed addresses. - -### 5.1 Rule Body Description - -The rules are configured in YAML format, with specific configurations as shown below: -```yaml -key: Consumer Application Name (required) -step: State Name (required) -threshold: Decision Threshold (default 1.0) -proportion: Gray Ratio (default 100) -delay: Decision Delay Time (default 0) -force: Forced Switch (default false) -interfaces: Interface Granularity Configuration (optional) - - serviceKey: Interface Name (Interface + : + Version Number) (required) - threshold: Decision Threshold - proportion: Gray Ratio - delay: Decision Delay Time - force: Forced Switch - step: State Name (required) - - serviceKey: Interface Name (Interface + : + Version Number) - step: State Name -applications: Application Granularity Configuration (optional) - - serviceKey: Application Name (name of the upstream application consumed) (required) - threshold: Decision Threshold - proportion: Gray Ratio - delay: Decision Delay Time - force: Forced Switch - step: State Name (required) -``` - -- key: Consumer Application Name -- step: State Name (FORCE_INTERFACE, APPLICATION_FIRST, FORCE_APPLICATION) -- threshold: Decision Threshold (float, see further explanation below) -- proportion: Gray Ratio (0 to 100, determines the call frequency ratio) -- delay: Decision Delay Time (the actual waiting time is 1 to 2 times the delay time, depending on the timing of the first notification from the registry; for the current registries implemented by Dubbo, this configuration can be kept at 0) -- force: Forced Switch (whether to switch directly without considering decisions for FORCE_INTERFACE and FORCE_APPLICATION, which may lead to addressing failures) -- interfaces: Interface Granularity Configuration - -Reference configuration example: -```yaml -key: demo-consumer -step: APPLICATION_FIRST -threshold: 1.0 -proportion: 60 -delay: 0 -force: false -interfaces: - - serviceKey: DemoService:1.0.0 - threshold: 0.5 - proportion: 30 - delay: 0 - force: true - step: APPLICATION_FIRST - - serviceKey: GreetingService:1.0.0 - step: FORCE_APPLICATION -``` - -### 5.1 Configuration Method Description -#### 1. Configuration Center File Delivery (Recommended) - -- Key: Consumer application name + ".migration" -- Group: DUBBO_SERVICEDISCOVERY_MIGRATION - -Configuration item content refers to the previous section. - -When the program starts, this configuration will be pulled as the highest priority startup item; if the configuration item is a startup item, no checking operation will be executed, directly reaching the terminal state based on state information. -During the program's operation, upon receiving a new configuration item, migration will be executed, following which checks will occur based on configuration details; if the checks fail, it will roll back to the state before migration. Migration will be executed at the interface granularity, so if an application has 10 interfaces, and 8 migrate successfully while 2 fail, the terminal state will have the 8 successfully migrated interfaces executing new behaviors, while the 2 that failed will remain in the old state. If a re-triggering of migration is necessary, this can be accomplished by resubmitting the rules. - -Note: If the program rolls back due to check failures during migration, since there is no write-back behavior for configuration items, a program restart will cause it to initialize directly according to the new behaviors without checks. - -#### 2. Startup Parameter Configuration - -- Configuration Name: dubbo.application.service-discovery.migration -- Allowed Value Range: FORCE_INTERFACE, APPLICATION_FIRST, FORCE_APPLICATION - -This configuration item can be passed through environment variables or the configuration center and has a lower priority than configurations from configuration files at startup, meaning that when the configuration center’s configuration file does not exist, this configuration item will be read as the startup state. - -#### 3. Local File Configuration - -| Configuration Name | Default Value | Description | -| --- | --- | --- | -| dubbo.migration.file | dubbo-migration.yaml | Local configuration file path | -| dubbo.application.migration.delay | 60000 | Delay effect time for configuration file (milliseconds) | - -The format of configurations within local files is consistent with the aforementioned rules. - -The local file configuration method essentially serves as a delayed notification method; the local file will not affect the default startup method. Once the delay time is reached, it triggers a notification containing the same content as the local file. This delay time is independent of the delay field in the rules body. -The local file configuration method can ensure that the initialization starts with default behavior and trigger migration operations with corresponding checks after the delay time has been reached. - -### 5.2 Decision Explanation -##### 1. Threshold Detection - -The threshold mechanism aims to check the number of available addresses before switching traffic. If the number of usable application-level addresses compared to the interface-level addresses does not meet the threshold, the check will fail. - -The core code is as follows: -```java -if (((float) newAddressSize / (float) oldAddressSize) >= threshold) { - return true; -} -return false; -``` - -Additionally, the MigrationAddressComparator serves as an SPI extension point, allowing users to create their own extensions, with all check results yielding an intersection. - -##### 2. Gray Ratio - -The gray ratio function is only effective under application-level priority status. This function enables users to decide the call frequency ratio to new application-level registered center addresses. Gray effects are dependent on threshold detection being satisfied. In application-level priority status, if the threshold detection passes, `currentAvailableInvoker` will switch to the corresponding application-level address invoker; if detection fails, `currentAvailableInvoker` will still reference the existing interface-level address invoker. - -The flowchart shows: -Detection Phase -![//imgs/v3/migration/migration-2.png](/imgs/v3/migration/migration-2.png) -Invocation Phase -![//imgs/v3/migration/migration-3.png](/imgs/v3/migration/migration-3.png) - -Core code is as follows: -```java -// currentAvailableInvoker is based on MigrationAddressComparator's result -if (currentAvailableInvoker != null) { - if (step == APPLICATION_FIRST) { - // call ratio calculation based on random value - if (ThreadLocalRandom.current().nextDouble(100) > promotion) { - return invoker.invoke(invocation); - } - } - return currentAvailableInvoker.invoke(invocation); -} -``` - -### 5.3 Switching Process Description - -The address migration process involves state switching. To ensure a smooth migration, a total of 6 switch paths need to be supported. These can be summarized as switching from forced interface-level or forced application-level to application-level priority; from application-level priority to forced interface-level or forced application-level; and mutual switching between forced interface-level and forced application-level. -For the process of switching the same interface, it is always synchronized; if the previous rule has not been completed before receiving a new rule, the process will wait. - -###### 1. Switch to Application-Level Priority - -Switching from forced interface-level or forced application-level to application-level priority fundamentally transitions from single to dual subscription, retaining the original subscription and creating an additional subscription. In this switching mode, the delay configurations specified in the rule body will not take effect, meaning that after the subscription is created, threshold detection and decision-making will occur immediately to select one group of subscriptions for priority invocation. As the application-level priority mode supports dynamic threshold detection at runtime, for some registries where the full addresses cannot be obtained at startup, the thresholds will be recalculated and switched once all address notifications are complete. -The dynamic switching mechanism in application-level priority mode is based on service directory (Directory) address listeners. -![//imgs/v3/migration/migration-4.png](/imgs/v3/migration/migration-4.png) - -###### 2. Application-Level Priority Switch to Forced - -The process of switching from application-level priority to forced interface-level or forced application-level involves checking the dual subscriptions; if satisfied, the other subscription will be destroyed, and if not satisfied, it will roll back to the original application-level priority state. -If users wish for the switch process to occur without checks, they can enable the force parameter. -![//imgs/v3/migration/migration-5.png](/imgs/v3/migration/migration-5.png) - -###### 3. Mutual Switching Between Forced Interface-Level and Forced Application-Level - -Mutual switching between forced interface-level and forced application-level requires temporarily creating a new subscription to determine whether the new subscription (i.e., use the number of addresses in new subscriptions after threshold calculations to deduce the number of old subscriptions) meets the standards for switching; if met, the switch will proceed; if not, the new subscription will be destroyed, rolling back to the previous state. -![//imgs/v3/migration/migration-6.png](/imgs/v3/migration/migration-6.png) - diff --git a/content/en/blog/java/proposals/service-discovery-rule.md b/content/en/blog/java/proposals/service-discovery-rule.md deleted file mode 100644 index 497a2973383b..000000000000 --- a/content/en/blog/java/proposals/service-discovery-rule.md +++ /dev/null @@ -1,205 +0,0 @@ ---- -aliases: - - /en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/ - - /en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/ - - /en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/ -description: This article specifically describes the rule body information used during the address migration process, allowing users to customize migration rules according to their needs. -linkTitle: Application-Level Service Discovery Address Migration Rules -title: Application-Level Service Discovery Address Migration Rules Description -tags: ["Java","Service Discovery"] -date: 2024-05-13 ---- - - - - -## State Model - - -Before Dubbo 3, the address registration model was registered at the interface level to the registry, while Dubbo 3 introduces a new application-level registration model with application-level granularity. From the registry implementation perspective, the two are almost different, leading to incompatibility in merging invokers obtained from the interface-level registration model with those from the application-level registration model. To assist users in migrating from interface-level to application-level, Dubbo 3 designed a Migration mechanism that implements the transition of address models based on the switching of three states. - - -Current states include: FORCE_INTERFACE, APPLICATION_FIRST, FORCE_APPLICATION. - - -FORCE_INTERFACE: Only enables the registry logic for interface-level service discovery in compatibility mode, with 100% of call traffic following the original flow. -APPLICATION_FIRST: Enables dual subscription for both interface and application levels, dynamically determining the call traffic direction based on thresholds and gray traffic ratios at runtime. -FORCE_APPLICATION: Only enables the registry logic for application-level service discovery, with 100% of call traffic directed to application-level subscribed addresses. - - -## Rule Body Description - - -The rules are configured in YAML format. Refer to the specific configuration example below: -```yaml -key: Consumer application name (required) -step: State name (required) -threshold: Decision threshold (default 1.0) -proportion: Gray ratio (default 100) -delay: Delay decision time (default 0) -force: Force switch (default false) -interfaces: Interface-level configuration (optional) - - serviceKey: Interface name (interface + : + version number) (required) - threshold: Decision threshold - proportion: Gray ratio - delay: Delay decision time - force: Force switch - step: State name (required) - - serviceKey: Interface name (interface + : + version number) - step: State name -applications: Application-level configuration (optional) - - serviceKey: Application name (upstream application name being consumed) (required) - threshold: Decision threshold - proportion: Gray ratio - delay: Delay decision time - force: Force switch - step: State name (required) -``` - - -- key: Consumer application name -- step: State name (FORCE_INTERFACE, APPLICATION_FIRST, FORCE_APPLICATION) -- threshold: Decision threshold (float, further meaning is explained later) -- proportion: Gray ratio (0-100, determines the call count ratio) -- delay: Delay decision time (the actual wait time is 1 to 2 times the delay time, depending on the time of the first notification from the registry) -- force: Force switch (whether to directly switch without considering decisions for FORCE_INTERFACE, FORCE_APPLICATION, which may lead to failures in calls due to lack of addresses) -- interfaces: Interface-level configuration - - -Reference configuration example: -```yaml -key: demo-consumer -step: APPLICATION_FIRST -threshold: 1.0 -proportion: 60 -delay: 0 -force: false -interfaces: - - serviceKey: DemoService:1.0.0 - threshold: 0.5 - proportion: 30 - delay: 0 - force: true - step: APPLICATION_FIRST - - serviceKey: GreetingService:1.0.0 - step: FORCE_APPLICATION -``` - - -## Configuration Method Description -### 1. Configuration File Distributed from Configuration Center (Recommended) - - -- Key: Consumer application name + ".migration" -- Group: DUBBO_SERVICEDISCOVERY_MIGRATION - - -Configuration item content refers to the previous section. - - -During program startup, this configuration will be pulled as the highest priority startup item. When the configuration item is the startup item, no check operation is performed, and the end state is reached directly according to the state information. If new configuration items are received during program operation, migration operations will be executed, with checks performed based on configuration information. If checks fail, it will roll back to the pre-migration state. Migration is executed at the interface level; if an application has 10 interfaces where 8 migrate successfully and 2 fail, the end state will have 8 successfully migrated interfaces executing the new behavior, while 2 that failed will remain in the old state. If a re-trigger of migration is needed, it can be achieved by redistributing the rules. - - -Note: If a program rolls back due to check failure during migration, since the program does not have a configuration item write-back behavior, if the program restarts at this time, it will directly follow the new behavior without checking and initialize directly. - - -### 2. Startup Parameter Configuration - - -- Configuration item name: dubbo.application.service-discovery.migration -- Allowed value range: FORCE_INTERFACE, APPLICATION_FIRST, FORCE_APPLICATION - - -This configuration item can be passed through environment variables or the configuration center. Its startup priority is lower than that of configuration files, meaning that when the configuration file in the configuration center does not exist, this configuration item will be read as the startup state. - - -### 3. Local File Configuration - - - -| Configuration Item Name | Default Value | Description | -| --- | --- | --- | -| dubbo.migration.file | dubbo-migration.yaml | Local configuration file path | -| dubbo.application.migration.delay | 60000 | Configuration file delay activation time (milliseconds) | - -The format in the configuration file is consistent with the rules mentioned earlier. - - -The local file configuration method is essentially a delayed configuration notification method. The local file will not affect the default startup method; after reaching the delay time, it triggers a notification with content consistent with the local file. The delay time here is not related to the delay field in the rule body. -Local file configurations ensure that startup initializes with the default behavior, triggering migration operations after reaching the delay time, avoiding starting in the end state mode. - - -## Decision Explanation -### 1. Threshold Detection - - -The threshold mechanism is designed to check the available address count before traffic switching. If the available address count for application level does not meet the threshold when compared to the available address count for interface level, the check fails. - - -Core code: -```java -if (((float) newAddressSize / (float) oldAddressSize) >= threshold) { - return true; -} -return false; -``` - - -Moreover, MigrationAddressComparator is also a SPI extension point, allowing users to expand it themselves; all results of checks are taken as an intersection. - - -### 2. Gray Ratio - - -The gray ratio function is only effective in the application-first state. This feature allows the user to determine the call count ratio towards the new application-level registry addresses. Gray activation is contingent upon meeting the threshold detection; in the application-first state, if threshold detection passes, `currentAvailableInvoker` will be switched to the corresponding application-level address invoker; if detection fails, `currentAvailableInvoker` remains the original interface-level address invoker. - - -Flowchart: -Detection Phase -![//imgs/v3/migration/migration-2.png](/imgs/v3/migration/migration-2.png) -Call Phase -![//imgs/v3/migration/migration-3.png](/imgs/v3/migration/migration-3.png) - - -Core code: -```java -// currentAvailableInvoker is based on MigrationAddressComparator's result -if (currentAvailableInvoker != null) { - if (step == APPLICATION_FIRST) { - // call ratio calculation based on random value - if (ThreadLocalRandom.current().nextDouble(100) > promotion) { - return invoker.invoke(invocation); - } - } - return currentAvailableInvoker.invoke(invocation); -} -``` - - -## Switching Process Description - - -The address migration process involves switching among three states; to ensure smooth migration, a total of 6 switching paths need to be supported. These can be summarized as switching from forced interface level and forced application level to application-first; switching from application-first to forced interface level and forced application level; as well as mutual switching between forced interface level and forced application level. -The switching process for the same interface is always synchronous; if the previous rule has not been completed, it will wait upon receiving a new rule. - - -### 1. Switching to Application-Level First - - -Switching from forced interface level and forced application level to application-first essentially represents switching from a single subscription to dual subscriptions, preserving the original subscription and creating another subscription. During this switching mode, the delay configuration in the rule body will not take effect, meaning that threshold detection and decision-making will occur immediately after the subscription creation, selecting a subscription group for actual prioritized invocation. Due to the application-first mode supporting runtime dynamic threshold detection, if some registries cannot obtain all addresses upon startup, a recalculation of the threshold and switching will still occur once all addresses are notified. -Dynamic switching in application-first mode is implemented based on service directory (Directory) address listeners. -![//imgs/v3/migration/migration-4.png](/imgs/v3/migration/migration-4.png) - - -### 2. Application-Level First Switching to Forced - - -The process of switching from application-first to forced interface level and forced application level involves checking the addresses from the dual subscription. If satisfied, the other subscription is destroyed; if not satisfied, it rolls back to retain the original application-first state. -If users wish this switching process to skip checks and switch directly, they can achieve this by configuring the force parameter. -![//imgs/v3/migration/migration-5.png](/imgs/v3/migration/migration-5.png) -### 3. Mutual Switching between Forced Interface Level and Forced Application Level - - -Mutual switching between forced interface level and forced application level requires temporarily creating a new subscription, determining whether the new subscription (i.e., using the address counts from the new subscription minus those from the old subscription during threshold calculation) meets the criteria. If so, the switching occurs; if it does not meet the criteria, the new subscription is destroyed, reverting to the previous state. -![//imgs/v3/migration/migration-6.png](/imgs/v3/migration/migration-6.png) - diff --git a/content/en/blog/java/proposals/service-discovery-samples.md b/content/en/blog/java/proposals/service-discovery-samples.md deleted file mode 100644 index 0558682c36d2..000000000000 --- a/content/en/blog/java/proposals/service-discovery-samples.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -aliases: - - /en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/ - - /en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/ - - /en/overview/mannual/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/ -linkTitle: Application-Level Service Discovery Migration Example -title: Application-Level Service Discovery Migration Example -tags: ["Java","Service Discovery"] -date: 2024-05-13 ---- - - - - - - -Application-level service discovery serves as a protocol for service discovery between applications. Therefore, to utilize application-level service discovery, both the consumer and provider must upgrade to Dubbo version 3.0 and enable the new features (enabled by default) to effectively leverage the advantages of application-level service discovery. - -## Enabling Methods -### Provider -After the application is upgraded to Dubbo 3.0, the provider automatically activates dual registration for interface-level + application-level, requiring no modification from developers. - -### Consumer -After the application is upgraded to Dubbo 3.0, the consumer automatically starts the dual subscription for interface-level + application-level, with no configuration changes needed from developers. It is recommended to close interface-level subscription in the consumer after all providers upgrade to Dubbo 3.0 and enable application-level registration to free up corresponding memory. - -## Detailed Explanation -### Provider Configuration - -1. Global Switch - -The application configuration (can be specified via configuration files or -D) `dubbo.application.register-mode` as instance (registers only application level) or all (registers both interface level and application level) enables the global registration switch. With this switch configured, application-level addresses will be registered with all registries for consumer service discovery. -> [Reference Example](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-provider1/src/main/resources/application.yml) - -``` -# Dual Registration -dubbo: - registry: - register-mode: all -``` -``` -# Application-Level Registration Only -dubbo: - registry: - register-mode: instance -``` - -2. Registry Address Parameter Configuration - -You can configure the registry address with `registry-type=service` to explicitly specify that this registry is for application-level service discovery, and registries with this configuration will only perform application-level service discovery. - -```xml - -``` -### Consumer Subscription Mode -FORCE_INTERFACE: Only interface-level subscription, consistent with Dubbo 2.7 and previous versions. -APPLICATION_FIRST: Dual subscription for interface-level + application-level; if addresses can be subscribed at the application level, it will use that, otherwise it falls back to interface-level subscription to ensure maximum compatibility during migration. (Note: Due to simultaneous subscriptions, memory usage will increase; thus, after all providers upgrade to Dubbo 3.0, it is recommended to switch to FORCE_APPLICATION mode to reduce memory consumption.) -FORCE_APPLICATION: Only application-level subscription, adopting the new service discovery model exclusively. -### Consumer Configuration - -1. Default Configuration (No configuration needed) - -After upgrading to Dubbo 3.0, the default behavior is dual subscription for interface-level + application-level; if addresses can be subscribed at the application level, it uses that, otherwise it falls back to interface-level subscription for maximum compatibility. - -2. Subscription Parameter Configuration - -Application configuration (can be specified via configuration files or -D) `dubbo.application.service-discovery.migration` set to `APPLICATION_FIRST` enables dual subscription mode; configuring it as `FORCE_APPLICATION` enforces application-level subscription mode only. Specific interface subscriptions can be configured in `ReferenceConfig` under `parameters` with key `migration.step`, value either `APPLICATION_FIRST` or `FORCE_APPLICATION`. -> [Reference Example](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-consumer/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConfigIT.java) - -```java -System.setProperty("dubbo.application.service-discovery.migration", "APPLICATION_FIRST"); -``` -```java -ReferenceConfig referenceConfig = new ReferenceConfig<>(applicationModel.newModule()); -referenceConfig.setInterface(DemoService.class); -referenceConfig.setParameters(new HashMap<>()); -referenceConfig.getParameters().put("migration.step", mode); -return referenceConfig.get(); -``` - -3. Dynamic Configuration (Highest Priority, can be modified at runtime) - -This configuration needs to be pushed based on the configuration center, with the key being the application name + `.migration` (e.g., `demo-application.migration`), and group set to `DUBBO_SERVICEDISCOVERY_MIGRATION`. For rule body configuration, refer to the [Guidelines for Migrating Interface-Level Service Discovery to Application-Level Service Discovery](../migration-service-discovery/). -> [Reference Example](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-consumer/src/main/java/org/apache/dubbo/demo/consumer/UpgradeUtil.java) - -```java -step: FORCE_INTERFACE -``` - diff --git a/content/en/blog/pixiu/_index.md b/content/en/blog/pixiu/_index.md deleted file mode 100644 index 3257f3c1a4f6..000000000000 --- a/content/en/blog/pixiu/_index.md +++ /dev/null @@ -1,8 +0,0 @@ - ---- -title: "Pixiu" -linkTitle: "Pixiu" -weight: 35 -date: 2022-02-19 ---- - diff --git a/content/en/blog/pixiu/dubbo-go-pixiu-animal.md b/content/en/blog/pixiu/dubbo-go-pixiu-animal.md deleted file mode 100644 index 8ee36bdf8a29..000000000000 --- a/content/en/blog/pixiu/dubbo-go-pixiu-animal.md +++ /dev/null @@ -1,222 +0,0 @@ ---- -title: The Cross-Language Invocation Beast of Dubbo: dubbo-go-pixiu -keywords: Introduction to Pixiu -description: The dubbo-go-pixiu project is based on dubbo-go and currently supports the HTTP request invocation at the interface protocol layer. -author: Feng Zhenyu, Yu Yu -tags: ["Go", "Pixiu", "Gateway"] -date: 2021-08-25 ---- - -## What is Pixiu - -Before answering what Pixiu is, let's briefly explain what Dubbo is. Dubbo is an open-source high-performance RPC framework with rich service governance capabilities and excellent extensibility. Dubbo has further extended into Dubbo-go【1】, providing users with a Dubbo solution in Golang, bridging the gap between two languages, and bringing Dubbo closer to cloud-native environments. - -As a Golang service, Dubbo-go enables mutual invocation between Dubbo and Golang services. However, in daily use cases, users often have the need to expose Dubbo services in a RESTful style while also considering internal Dubbo calls. To address this scenario, Pixiu【2】 (formerly known as dubbo-go-proxy), which serves as the Dubbo API gateway, was born. The name Pixiu was chosen because the similar product Zuul in Java is represented by a Western monster, while Pixiu, as a domestic product, uses the Chinese mythical creature Pixiu as its project name. This also expresses the Dubbo community's determination to expand a whole cloud-native ecosystem. - -Currently, the best-developed multilingual ecosystem of Dubbo is Java, followed by Golang, while other languages are less promising. The dubbo-go-pixiu project is based on dubbo-go, currently supporting the 7-layer HTTP request invocation, and plans to support gRPC request invocations in the upcoming 0.5 version, serving as a new Dubbo multilingual solution. - -## Why Use Pixiu -Pixiu is a cloud-native, high-performance, and extensible microservices API gateway based on Dubbogo. As a gateway product, Pixiu helps users easily create, publish, maintain, monitor, and protect APIs of any scale, handling thousands of concurrent API calls, including traffic management, CORS support, authorization and access control, limiting, monitoring, and API version management. Additionally, as a derivative product of Dubbo, Pixiu can assist Dubbo users in protocol conversion, enabling inter-system and inter-protocol service interoperability. - -The overall design of Pixiu adheres to the following principles: - -- High performance: high throughput and millisecond-level latency. -- Extensible: Through go-plugin, users can extend Pixiu's functionality based on their needs. -- Easy to use: Users can go live with minimal configuration. - -## Features and Core Functions of Pixiu - -- Support for RESTful API and Dubbo API - -Non-RESTful APIs and Dubbo protocol services often require modifications to be exposed in a RESTful API style. Pixiu provides protocol conversion features; developers can configure their HTTP APIs or Dubbo APIs to be exposed in a RESTful API style through Pixiu. Version 0.2.1 has supported HTTP to Dubbo protocol conversion based on generic calls and the proxying of HTTP protocols. Future versions will add support for gRPC and HTTP2 protocols. - -- User-oriented configuration methods - -Traditional gateway configurations are often cumbersome and complex. Pixiu, aiming to be an easy-to-use gateway product, has three configuration layers: global Gateway layer configuration, API resource layer configuration, and HTTP verbs method layer configuration. This multiple-layer configuration allows for deep customization while supporting unified default configurations; it also supports local configuration files and can use a unified configuration server. Furthermore, it provides a console module that supports hot configuration updates. The corresponding console interface for Pixiu is also under concurrent development. - -- Integration of common features - -Common features such as retry, circuit breaking, traffic control, and access control no longer need to be repeatedly implemented on each backend service. Using Pixiu, developers can control globally through filter configurations or set specific rules based on API configurations. This allows developers to focus on business logic and services rather than spending time maintaining infrastructure. - -- Extensible - -Different usage scenarios have their unique requirements. To meet the customization needs of different users, Pixiu employs a plugin model. Developers can embed their specific business logic as filters within the Pixiu gateway by writing Go plugins. - -![img](/imgs/blog/1/01/01/dubbo-go-pixiu/fd38da297d095e4c3af1c89b18804ef1.webp) - -Figure 1: Core feature list of Pixiu - -## Architectural Design of Pixiu - -![img](/imgs/blog/1/01/01/dubbo-go-pixiu/2b2fd6ea1cc0375392919d9e0c181f2b.webp) - -Figure 2: Pixiu Architecture - -Pixiu, consisting of four main modules: Listener, Router, Filters, and Clients; - -- Dubbo Cluster: The cluster where the Dubbo services are located, containing one or more Dubbo Services. -- Other Cluster: The cluster where services outside of Dubbo are located, currently supporting HTTP services, with future plans to expand support to gRPC and other services. -- Registry Center: The registry center maintains invocation address information for each business service. -- Metadata Center: The metadata center maintains configuration information for each business service and stores Pixiu’s own configuration information. - -As an API gateway derived from Dubbo, Pixiu is built using Golang, primarily because: 1. Features like Golang's G-M-P, net poller make it very suitable for building IO-intensive applications; 2. Using Golang allows direct integration of some components from dubbo-go, simplifying development. - -The overall Pixiu can be roughly divided into four main modules: Listener, Router, Filters, and Client. - -### 1. Listener - -In Pixiu, the Listener represents the accessible methods to Pixiu. By configuring specific protocol types, addresses, ports, and other properties, the Gateway is exposed. Currently, only HTTP protocol is supported, with gRPC planned for the future. - -``` -listeners: - - - name: "net/http" - - address: - - socket_address: - - protocol_type: "HTTP" - - address: "0.0.0.0" - - port: 8888 - - config: - - idle_timeout: 5s - - read_timeout: 5s - - write_timeout: 5s -``` - -### 2. Router - -Router is Pixiu's routing component. Based on the configuration file, Pixiu stores the exposed URLs in memory in a tree structure. When requests reach the router component, it finds the corresponding backend services and their API configurations based on the URL and HTTP method, encapsulating the information within the request to provide sufficient content for subsequent filters and client calls. - -Currently, Router provides the following functionalities: - -- Supports one-to-one forwarding routing configurations or wildcard routing configurations. -- Supports forwarding HTTP requests to backend HTTP services. -- Supports transforming HTTP requests into dubbo generic invocation requests. - -### 3. Filters - -Filters are the main component that implements additional functionalities and extensibility in Pixiu. Its implementation is similar to the filters in Dubbo-go, generating a call chain based on the specified filters in the configuration to execute the logic in each filter before invoking the backend services, achieving functionalities such as throttling, logging, etc. - -If users require custom filters, they can implement them by writing Go plugins. In the configuration, filters can be loaded from .so files and specified in the API config regarding the plugin group and plugin name to use. - -``` -pluginFilePath: "" -pluginsGroup: - - groupName: "group1" - plugins: - - name: "rate limit" - version: "0.0.1" - priority: 1000 - externalLookupName: "ExternalPluginRateLimit" - - name: "access" - version: "0.0.1" - priority: 1000 - externalLookupName: "ExternalPluginAccess" - - groupName: "group2" - plugins: - - name: "blacklist" - version: "0.0.1" - priority: 1000 - externalLookupName: "ExternalPluginBlackList" -``` - -### 4. Client - -Client is responsible for invoking specific services. Currently, Pixiu supports HTTP and Dubbo backend services. The community will gradually add other clients like gRPC to meet different protocols. - -The implementation of the HTTP client is relatively simple, generating requests and invoking them using the Golang official package net/http based on the backend service information retrieved from the Router. - -The implementation of the Dubbo client is slightly more complex compared to the HTTP client. Its foundation is the generic invocation of Dubbo services. The generic invocation technology is a very basic feature provided by Dubbo that only requires the method name, parameter types, and return value types to initiate a service call. The client can discover services through the registry center or connect directly to the service provider for dynamic invocation. - -As shown in the code below, Pixiu generates the Dubbo Generic Client (Generic Invocation Client) for the next step of invocation by dynamically configuring referenceConfig and then calling GetRPCService. - -``` -referenceConfig := dg.NewReferenceConfig(irequest.Interface, context.TODO()) - referenceConfig.InterfaceName = irequest.Interface - referenceConfig.Cluster = constant.DEFAULT_CLUSTER - var registers []string - for k := range dgCfg.Registries { - registers = append(registers, k) - } - referenceConfig.Registry = strings.Join(registers, ",") - - if len(irequest.DubboBackendConfig.Protocol) == 0 { - referenceConfig.Protocol = dubbo.DUBBO - } else { - referenceConfig.Protocol = irequest.DubboBackendConfig.Protocol - } - - referenceConfig.Version = irequest.DubboBackendConfig.Version - referenceConfig.Group = irequest.Group - referenceConfig.Generic = true - if len(irequest.DubboBackendConfig.Retries) == 0 { - referenceConfig.Retries = "3" - } else { - referenceConfig.Retries = irequest.DubboBackendConfig.Retries - } - dc.lock.Lock() - defer dc.lock.Unlock() - referenceConfig.GenericLoad(key) - clientService := referenceConfig.GetRPCService().(*dg.GenericService) -``` - -In fact, in the client for generic invocation, the key step to execute the generic call is the generic_filter in Dubbo-go (as shown in the code snippet below). When calling Invoke on the generic_filter, it is agreed that the first parameter of the invocation is the method name, the second is the parameter types list, and the third is the parameter values list. The generic_filter converts the list of parameter values from the user request into a unified format map (struct2MapAll in the code), transforming the serialization and deserialization operations of classes (structs in Golang) into map operations. This allows for the completion of Dubbo service generic invocation without a POJO description through hardcoded injection of the hessian library. - -``` -func (ef *GenericFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { - if invocation.MethodName() == constant.GENERIC && len(invocation.Arguments()) == 3 { - oldArguments := invocation.Arguments() - if oldParams, ok := oldArguments[2].([]interface{}); ok { - newParams := make([]hessian.Object, 0, len(oldParams)) - for i := range oldParams { - newParams = append(newParams, hessian.Object(struct2MapAll(oldParams[i]))) - } - newArguments := []interface{}{ - oldArguments[0], - oldArguments[1], - newParams, - } - newInvocation := invocation2.NewRPCInvocation(invocation.MethodName(), newArguments, invocation.Attachments()) - newInvocation.SetReply(invocation.Reply()) - return invoker.Invoke(ctx, newInvocation) - } - } - return invoker.Invoke(ctx, invocation) -} -``` - -## Summary - -From the introduction of the four modules and the registry center, it is not difficult to see that once a request is received by Pixiu through the listener, it is passed to the router. The router finds the destination backend service along with the relevant API configurations from the original request according to the interface's configuration and delivers it to the filter component. The filter component sequentially executes based on the original request, API configurations, and other information until the request reaches the client, invoking the backend service. - -### The Future of Pixiu - -![img](/imgs/blog/1/01/01/dubbo-go-pixiu/e57050f224f658b96cd6bd917050b259.webp) -Figure 3: Pixiu Iteration Milestones - -Pixel's derivative projects will also be on our future plans, primarily aimed at providing better usability. For example, due to the lack of native annotations in Golang, Dubbo-go needs to generate service metadata through configuration files written into the registry. Relevant colleagues from the Kaike company have developed a tool for scanning code https://github.com/jack15083/dubbo-go-proxy-tool, which adds corresponding comments before each RPC service method, thus generating metadata through annotative scanning before service startup. Pixiu also plans to enable services to generate API configurations and register with Pixiu using annotations with the help of https://github.com/MarcGrol/golangAnnotations in future versions. - -Currently, Pixiu is positioned as a seven-layer protocol gateway, initially defined as a Dubbo service gateway. As a product for the cloud era, Pixiu's development direction certainly aims at cloud-native. The current version is 0.2.1, which has already implemented basic Dubbo/HTTP service proxying and part of the gateway's common functions. Work is ongoing on the 0.4 version and subsequent versions to support gRPC and Spring Cloud service calls, and MQ service support will also be provided later. In addition, the community will continue to optimize configuration methods, reduce user usage difficulties, and enhance official filters, allowing Pixiu to realize more common gateway functionalities at the official level. - -![img](/imgs/blog/1/01/01/dubbo-go-pixiu/0c1afe00699eb3e5cc022e48966ef5a6.webp) - -In the coming year, the community plans to support xDS API, evolving Pixiu into a sidecar for the Dubbo mesh. The ultimate goal is to evolve into a Proxy Service Mesh form within the current Dubbo mesh architecture. Based on this architecture, scripting language programs such as JavaScript, Python, PHP, Ruby, and Perl are likely to gain performance boosts in addition to enjoying the existing technical dividends of the Dubbo mesh. - -The ultimate aim of Pixiu in the Dubbo Mesh is to gradually unify east-west and north-south data plane traffic within Pixiu while enabling it to possess Application Runtime capabilities, thus serving as a key solution for Dubbo's multilingual ecosystem. - -Relevant links: - -【1】Dubbo-go:https://github.com/apache/dubbo-go - -【2】Pixiu:https://github.com/apache/dubbo-go-pixiu - -Feng Zhenyu, Apache Dubbo Committer, currently manages the IT department team of a consumer goods company in Hong Kong. After casually looking at an article introducing dubbogo in the summer of 2020, he joined the dubbogo community and is currently leading the development of Pixiu version 0.4.0. - diff --git a/content/en/blog/pixiu/filter-intro.md b/content/en/blog/pixiu/filter-intro.md deleted file mode 100644 index 395ec84cf788..000000000000 --- a/content/en/blog/pixiu/filter-intro.md +++ /dev/null @@ -1,211 +0,0 @@ ---- -title: Talk About Pixiu's Filter -keywords: Introduction to Pixiu -description: The Filter is usually the most important part of the gateway. So how does Pixiu's filter chain work? -tags: ["Go", "Pixiu"] -author: mark4z -date: 2022-02-19 ---- - -## **Lifecycle of the Filter** - -As a cloud-native gateway, Pixiu can proxy Http to Dubbo 2, Tripe, or even Spring Cloud requests through simple configuration. So how does the Filter operate? - -First, the **Filter Plugin** registers itself with the **Filter Manager**. Then, the **Filter Manager** creates **Filter Factory** based on configuration and holds them. When a request comes in, the **Manager** creates a one-time Filter Chain for this request, then uses the **Factory** to create **Decode/Encode Filters** and adds them to the chain. Then it runs the Decode Filters in order, goes to the **Upstream** to get the Response, and runs the Encode Filters in reverse order, allowing the Filter to access the Response. - -Key concepts: - -**Filter Manager** - -> Filter Manger... - -```go -// FilterManager manage filters -type FilterManager struct { - filters map[string]HttpFilterFactory - filtersArray []*HttpFilterFactory -} -``` - -**Filter Plugin**: Defines the (unique) name of the Filter and describes how to create a Filter Factory. - -> The Plugin can be considered a Factory for Filter Factory in conjunction with the definition of Filter Factory. - -```go -// HttpFilterPlugin describe plugin -HttpFilterPlugin interface { - // Kind returns the unique kind name to represent itself. - Kind() string - - // CreateFilterFactory return the filter factory - CreateFilterFactory() (HttpFilterFactory, error) -} -``` - -**Filter Factory**: Defines the configurations of the Filter itself, creates the real Filter when a request comes in, and adds it to the FilterChain. - -> - The purpose of Config() is to give the Filter Manager a chance to pass configurations to the Factory (at this point, Golang generics have not landed yet). -> - Apply() allows for some checks and initializes work after the config is injected into the Factory. -> - PrepareFilterChain() creates the Filter and appends it to the Filter Chain. - -```go -// HttpFilterFactory describe http filter -HttpFilterFactory interface { - // Config Expose the config so that Filter Manager can inject it, so it must be a pointer - Config() interface{} - - // Apply After the config is injected, check it or make it default - Apply() error - - // PrepareFilterChain create filter and append it to FilterChain - PrepareFilterChain(ctx *http.HttpContext, chain FilterChain) error -} -``` - -**Decode/Encode Filter**: The Filter is divided into two parts; **Decode** occurs before actual requests to **Upstream**, allowing for authorization, rate limiting, and intercepting requests at the gateway level. **Encode** runs after receiving the **Upstream** response, allowing for logging and even modifying the Response. - -> A Filter can be both a Decode Filter and an Encode Filter without restrictions! -> -> Assume there are three Filters A, B, C, all Decode/Encode Filters; if the configured order is A, B, C, the execution will proceed as follows: -> -> In the Decode phase A->B->C, while in the Encode phase the order will be reversed! C->B->A. - -```go -// decode filters will be invoked in the config order: A、B、C, and decode filters will be -// invoked in the reverse order: C、B、A -HttpDecodeFilter interface { - Decode(ctx *http.HttpContext) FilterStatus -} - -// HttpEncodeFilter after invoke upstream, -// decode filters will be invoked in the reverse order -HttpEncodeFilter interface { - Encode(ctx *http.HttpContext) FilterStatus -} -``` - -In more detail, each Decode/Encode Filter can return a FilterStatus to decide whether to continue or stop here! For example, for JWT authorization, return 401 to Downstream if the token is invalid. Note that the stop command issued by Decode Filter will only terminate the Decode phase. Why? Consider how to implement an Access Log Filter to record failure results even when requests fail! - -## **How to Write a Custom Filter** - -Let’s try to create a simple Filter. This Filter will have basic configurations, logging the request body in the Decode phase and returning it as a mock response after reversing it. Finally, it will log the return value based on the configurations in the Encode phase. - -1. First, create a Filter. - -```go -type DemoFilter struct { - logPrefix string -} - -func (f *DemoFilter) Decode(ctx *contexthttp.HttpContext) filter.FilterStatus { - body, _ := ioutil.ReadAll(ctx.Request.Body) - logger.Infof("request body: %s", body) - - // Reverse res str - runes := []rune(string(body)) - for i := 0; i < len(runes)/2; i += 1 { - runes[i], runes[len(runes)-1-i] = runes[len(runes)-1-i], runes[i] - } - reverse := string(runes) - - // Mock response - ctx.SendLocalReply(200, []byte(reverse)) - return filter.Stop -} - -func (f *DemoFilter) Encode(ctx *contexthttp.HttpContext) filter.FilterStatus { - res := ctx.SourceResp.(string) - logger.Infof("%s: %s", f.logPrefix, res) - return filter.Continue -} -``` - -2. Create Filter Factory. - -```go -type ( - DemoFilterFactory struct { - conf *Config - } - // Config describe the config of Filter - Config struct { - LogPrefix string `yaml:"logPrefix,omitempty"` - } -) - -func (f *DemoFilterFactory) PrepareFilterChain(ctx *contexthttp.HttpContext, chain filter.FilterChain) error { - demo := &DemoFilter{logPrefix: f.conf.LogPrefix} - - chain.AppendDecodeFilters(demo) - chain.AppendEncodeFilters(demo) - return nil -} - -func (f *DemoFilterFactory) Config() interface{} { - return f.conf -} - -func (f *DemoFilterFactory) Apply() error { - return nil -} -``` - -3. Create Filter Plugin and register it. - -```go -// Important -func init() { - filter.RegisterHttpFilter(&Plugin{}) -} - -type Plugin struct { -} - -func (p *Plugin) Kind() string { - return "dgp.filters.demo" -} - -func (p *Plugin) CreateFilterFactory() (filter.HttpFilterFactory, error) { - return &DemoFilterFactory{conf: &Config{}}, nil -} -``` - -4. Configure this Filter in the configuration file and start Pixiu. - -```yaml -static_resources: - listeners: - - name: "net/http" - protocol_type: "HTTP" - address: - socket_address: - address: "0.0.0.0" - port: 8888 - filter_chains: - filters: - - name: dgp.filter.httpconnectionmanager - config: - route_config: - routes: - - match: - prefix: "/" - http_filters: - - name: dgp.filters.demo - config: -``` - -5. Access and check the logs and results. - -```shell -curl localhost:8888/demo -d "eiv al tse’c" - -c’est la vie% -``` - -Logs - -``` -2022-02-19T20:20:11.900+0800 INFO demo/demo.go:62 request body: eiv al tse’c -2022-02-19T20:20:11.900+0800 INFO demo/demo.go:71 : eiv al tse’c -``` - From d54d6571be9cebf901ad9fe87b7dea708d74886f Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Mon, 30 Sep 2024 17:33:33 +0800 Subject: [PATCH 22/23] Translate --- content/en/blog/integration/dubbo-zk.md | 138 +++-- content/en/blog/news/Dubbo-proxyless.md | 162 +++--- .../news/apachecon2023/dubbo-on-kubernetes.md | 182 ------ .../news/apachecon2023/ecosystem-opensergo.md | 200 ------- .../news/apachecon2023/ecosystem-seata.md | 105 ---- .../apachecon2023/graalvm-native-image.md | 225 -------- .../blog/news/apachecon2023/observability.md | 165 ------ .../triple-to-connect-frontend-and-backend.md | 128 ----- .../news/apachecon2023/usecase-zhengcaiyun.md | 203 ------- content/en/blog/news/dubbo-10years.md | 214 ++++--- content/en/blog/news/dubbo-meetup-chengdu.md | 3 +- content/en/blog/news/dubbo2-js.md | 57 +- content/en/blog/news/meet-dubbo.md | 66 +-- .../openatom-opensopurce-competition-2024.md | 2 +- .../en/blog/news/prepare-an-apache-release.md | 240 ++++---- .../google-service-weaver-paper-2023.md | 346 ------------ content/en/blog/proposals/metrics.md | 523 ------------------ content/en/blog/users/eleme.md | 3 +- content/en/blog/users/pingan.md | 5 +- content/en/blog/users/xiaomi.md | 36 +- 20 files changed, 458 insertions(+), 2545 deletions(-) delete mode 100644 content/en/blog/news/apachecon2023/dubbo-on-kubernetes.md delete mode 100644 content/en/blog/news/apachecon2023/ecosystem-opensergo.md delete mode 100644 content/en/blog/news/apachecon2023/ecosystem-seata.md delete mode 100644 content/en/blog/news/apachecon2023/graalvm-native-image.md delete mode 100644 content/en/blog/news/apachecon2023/observability.md delete mode 100644 content/en/blog/news/apachecon2023/triple-to-connect-frontend-and-backend.md delete mode 100644 content/en/blog/news/apachecon2023/usecase-zhengcaiyun.md delete mode 100644 content/en/blog/proposals/google-service-weaver-paper-2023.md delete mode 100644 content/en/blog/proposals/metrics.md diff --git a/content/en/blog/integration/dubbo-zk.md b/content/en/blog/integration/dubbo-zk.md index 9397641c4064..e5e7d75de94e 100644 --- a/content/en/blog/integration/dubbo-zk.md +++ b/content/en/blog/integration/dubbo-zk.md @@ -1,47 +1,47 @@ --- -title: "在 Dubbo 应用中使用 Zookeeper" -linkTitle: "在 Dubbo 应用中使用 Zookeeper" +title: "Using Zookeeper in Dubbo Applications" +linkTitle: "Using Zookeeper in Dubbo Applications" date: 2018-08-07 -tags: ["生态", "Java"] +tags: ["Ecosystem", "Java"] description: > - 本文介绍了 Zookeeper 的基本概念、用法,以及如何在 Dubbo 应用中使用 Zookeeper 作为注册中心。 + This article introduces the basic concepts and usage of Zookeeper, as well as how to use Zookeeper as a registry in Dubbo applications. --- -## Zookeeper 介绍 +## Introduction to Zookeeper -### 基本概念 +### Basic Concepts -在现代的分布式应用中,往往会出现节点和节点之间的协调问题,其中就包括了:选主、集群管理、分布式锁、分布式配置管理、统一命名服务、状态同步等诉求。[Apache Zookeeper](https://zookeeper.apache.org),正如它的名字所暗示的那样,*动物园管理员*,就是为了解决这些诉求的一个分布式协调服务框架。 +In modern distributed applications, coordination issues often arise between nodes, including leader election, cluster management, distributed locks, distributed configuration management, unified naming services, and state synchronization. [Apache Zookeeper](https://zookeeper.apache.org), as its name suggests, is a distributed coordination service framework designed to address these concerns. -为了保证高可用,ZooKeeper 本身也可以部署成集群模式,称之为 *ZooKeeper ensemble*。ZooKeeper 集群中始终确保其中的一台为 leader 的角色,并通过 *ZAB (Zookeeper Atomic Broadcast Protocol) [^1]* 协议确保所有节点上的信息的一致。客户端可以访问集群中的任何一台进行读写操作,而不用担心数据出现不一致的现象。 +To ensure high availability, ZooKeeper can be deployed in a cluster mode, known as a *ZooKeeper ensemble*. Within a ZooKeeper cluster, one node always acts as the leader, and through the *ZAB (Zookeeper Atomic Broadcast Protocol) [^1]* protocol, it ensures the consistency of information across all nodes. Clients can access any node in the cluster for read and write operations without worrying about data inconsistency. ![Diagram shows client-server architecture of ZooKeeper](/imgs/blog/zk-emsemble.png) *Image Credit : ebook -Zookeeper-Distributed Process Coordination from O'Reilly* -Zookeeper 中的数据存储方式与传统的 UNIX 文件系统相似,节点按照树状结构来组织,其中,节点被称之为 *znodes (ZooKeeper data nodes)* +Zookeeper stores data in a manner similar to a traditional UNIX file system, organized in a tree structure where nodes are called *znodes (ZooKeeper data nodes)*. ![zk-tree](/imgs/blog/zk-tree.png) *Image Credit : ebook -Zookeeper-Distributed Process Coordination from O'Reilly* -### 基本用法 +### Basic Usage -可以通过直接下载的方式 [^2]安装并运行 Zookeeper ,在 Mac 上也可以通过 Homebrew [^3] `brew install zookeeper` 来安装,考虑到通用性,本文采用 docker 的方式来运行 Zookeeper。如果没有安装 docker,请先准备好 docker 环境 [^4]。 +You can install and run Zookeeper by downloading it directly [^2], or on a Mac using Homebrew [^3] with `brew install zookeeper`. This article uses Docker to run Zookeeper for general usability. Please prepare your Docker environment first if it is not installed [^4]. -#### 1. 启动 Zookeeper +#### 1. Start Zookeeper -执行命令将 Zookeeper 运行在 docker 容器中 +Run Zookeeper in a Docker container with the following command: ```shell docker run --rm --name zookeeper -p 2181:2181 zookeeper ``` -#### 2. 进入 Zookeeper 容器 +#### 2. Access the Zookeeper Container ```shell docker exec -it zookeeper bash ``` -在 `bin` 目录下有启动 Zookeeper 的命令 `zkServer` 以及管理控制台 `zkCli` +The `bin` directory contains the command to start Zookeeper `zkServer` and the management console `zkCli`. ```shell bash-4.4# ls -l bin @@ -56,9 +56,9 @@ total 36 -rwxr-xr-x 1 zookeepe zookeepe 6773 Mar 27 04:32 zkServer.sh ``` -#### 3. 通过 zkCli 进入 Zookeeper 管理界面 +#### 3. Enter the Zookeeper Management Interface via zkCli -由于是通过 Docker 启动,Zookeeper 进程已经启动,并通过 2181 端口对外提供服务。 +Since you started Zookeeper through Docker, the Zookeeper process is already running and is available at port 2181. ```shell bash-4.4# ps @@ -68,7 +68,7 @@ PID USER TIME COMMAND 42 root 0:00 ps ``` -因此可以直接通过 `zkCli` 来访问 Zookeeper 的控制台来进行管理。 +You can directly access the Zookeeper console for management using `zkCli`. ```shell bash-4.4# bin/zkCli.sh -server 127.0.0.1:2181 @@ -103,30 +103,30 @@ ZooKeeper -server host:port cmd args connect host:port ``` -#### 4. zkCli 上的一些基本操作 +#### 4. Basic Operations in zkCli -创建 `/hello-zone` 节点: +Create the node `/hello-zone`: ```shell [zk: 127.0.0.1:2181(CONNECTED) 19] create /hello-zone 'world' Created /hello-zone ``` -列出 `/` 下的子节点,确认 `hello-zone` 被创建: +List child nodes under `/` to confirm that `hello-zone` was created: ```shell [zk: 127.0.0.1:2181(CONNECTED) 20] ls / [zookeeper, hello-zone] ``` -列出 `/hello-zone` 的子节点,确认为空: +List child nodes under `/hello-zone` to confirm it is empty: ```shell [zk: 127.0.0.1:2181(CONNECTED) 21] ls /hello-zone [] ``` -获取存储在 `/hello-zone` 节点上的数据: +Get the data stored in the `/hello-zone` node: ```shell [zk: 127.0.0.1:2181(CONNECTED) 22] get /hello-zone @@ -135,27 +135,27 @@ world -## 在 Dubbo 中使用 Zookeeper +## Using Zookeeper in Dubbo -Dubbo 使用 Zookeeper 用于服务的注册发现和配置管理,在 Zookeeper 中数据的组织由下图所示: +Dubbo uses Zookeeper for service registration, discovery, and configuration management. The organization of data in Zookeeper is illustrated in the following diagram: ![dubbo-in-zk](/imgs/blog/dubbo-in-zk.jpg) -首先,所有 Dubbo 相关的数据都组织在 `/dubbo` 的根节点下。 +First, all Dubbo-related data is organized under the root node `/dubbo`. -二级目录是服务名,如 `com.foo.BarService`。 +The second-level directory represents the service name, such as `com.foo.BarService`. -三级目录有两个子节点,分别是 `providers` 和 `consumers`,表示该服务的提供者和消费者。 +The third-level directory has two subnodes, `providers` and `consumers`, indicating the service providers and consumers, respectively. -四级目录记录了与该服务相关的每一个应用实例的 URL 信息,在 `providers` 下的表示该服务的所有提供者,而在 `consumers` 下的表示该服务的所有消费者。举例说明,`com.foo.BarService` 的服务提供者在启动时将自己的 URL 信息注册到 `/dubbo/com.foo.BarService/providers` 下;同样的,服务消费者将自己的信息注册到相应的 `consumers` 下,同时,服务消费者会订阅其所对应的 `providers` 节点,以便能够感知到服务提供方地址列表的变化。 +The fourth-level directory records the URL information of each application instance related to that service. Under `providers`, it shows all providers of the service, and under `consumers`, it shows all consumers. For example, the service provider for `com.foo.BarService` registers its URL information under `/dubbo/com.foo.BarService/providers` when it starts; similarly, the service consumer registers its information under the corresponding `consumers` node, and subscribes to the corresponding `providers` node to be notified of any changes to the service provider address list. -### 准备示例代码 +### Preparing Example Code -本文的代码可以在 https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-zookeeper 中找到。 +The code for this article can be found at https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-zookeeper. -#### 1. 接口定义 +#### 1. Interface Definition -定义一个简单的 `GreetingService` 接口,里面只有一个简单的方法 `sayHello` 向调用者问好。 +Define a simple `GreetingService` interface with a simple method `sayHello` that greets the caller. ```java public interface GreetingService { @@ -163,9 +163,9 @@ public interface GreetingService { } ``` -#### 2. 服务端:服务实现 +#### 2. Server: Service Implementation -实现 `GreetingService` 接口,并通过 `@Service` 来标注其为 Dubbo 的一个服务。 +Implement the `GreetingService` interface and annotate it with `@Service` to mark it as a Dubbo service. ```java @Service @@ -176,9 +176,9 @@ public class AnnotatedGreetingService implements GreetingService { } ``` -#### 3. 服务端:组装 +#### 3. Server: Assembly -定义 ProviderConfiguration 来组装 Dubbo 服务。 +Define `ProviderConfiguration` to assemble Dubbo services. ```java @Configuration @@ -187,7 +187,7 @@ public class AnnotatedGreetingService implements GreetingService { static class ProviderConfiguration {} ``` -dubbo-provider.properties 是在 Spring 应用中外置配置的方式,内容如下: +The `dubbo-provider.properties` file is an external configuration method in a Spring application, with the following contents: ```properties dubbo.application.name=demo-provider @@ -196,15 +196,15 @@ dubbo.protocol.name=dubbo dubbo.protocol.port=20880 ``` -由于 Zookeeper 运行在 Docker 容器中,需要注意的是: +Since Zookeeper runs in a Docker container, it is important to note: -* 本文假定 Dubbo 应用运行在宿主机上,也就是 Docker 容器外,需要将 Zookeeper 的地址替换成环境变量 *${DOCKER_HOST}* 所指定的 IP 地址,相关信息请查阅 Docker 官方文档 -* 如果 Dubbo 应用也是 Docker 化的应用,只需要用 Zookeeper 的容器名,在本文中容器名是 **zookeeper** -* 当然,如果不用容器方式启动 Zookeeper,只需要简单的将这里的 *$DOCKER_HOST* 换成 **localhost** 即可 +* This article assumes that the Dubbo application runs on the host machine, i.e., outside the Docker container, and you need to replace Zookeeper's address with the IP address specified by the environment variable *${DOCKER_HOST}*. Please refer to the Docker official documentation for details. +* If the Dubbo application is also a Dockerized application, you simply use the container name for Zookeeper, which is **zookeeper** in this article. +* Of course, if you start Zookeeper without using a container, you can simply change the *$DOCKER_HOST* here to **localhost**. -#### 4. 服务端:启动服务 +#### 4. Server: Start Service -在 `main` 方法中通过启动一个 Spring Context 来对外提供 Dubbo 服务。 +In the `main` method, start a Spring Context to expose the Dubbo service. ```java public class ProviderBootstrap { @@ -216,13 +216,13 @@ public class ProviderBootstrap { } ``` -启动服务端的 `main` 方法,将会看到下面的输出,代表服务端启动成功,并在注册中心(ZookeeperRegistry)上注册了 `GreetingService` 这个服务: +When you run the server's `main` method, you will see the following output, indicating that the server has started successfully and registered the `GreetingService` at the registry (ZookeeperRegistry): ```sh [03/08/18 10:50:33:033 CST] main INFO zookeeper.ZookeeperRegistry: [DUBBO] Register: dubbo://192.168.99.1:20880/com.alibaba.dubbo.samples.api.GreetingService?anyhost=true&application=demo-provider&dubbo=2.6.2&generic=false&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=12938&side=provider×tamp=1533264631849, dubbo version: 2.6.2, current host: 192.168.99.1 ``` -通过 Zookeeper 管理终端观察服务提供方的注册信息: +Use the Zookeeper management terminal to observe the registration information of the service provider: ```sh $ docker exec -it zookeeper bash @@ -236,11 +236,11 @@ JLine support is enabled [dubbo%3A%2F%2F192.168.99.1%3A20880%2Fcom.alibaba.dubbo.samples.api.GreetingService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26dubbo%3D2.6.2%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.samples.api.GreetingService%26methods%3DsayHello%26pid%3D12938%26side%3Dprovider%26timestamp%3D1533264631849] ``` -可以看到刚刚启动的 Dubbo 的服务在 `providers` 节点下注册了自己的 URL 地址:*dubbo://192.168.99.1:20880/com.alibaba.dubbo.samples.api.GreetingService?anyhost=true&application=demo-provider&dubbo=2.6.2&generic=false&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=12938&side=provider×tamp=1533264631849* +You can see that the just-started Dubbo service registered its URL at the `providers` node: *dubbo://192.168.99.1:20880/com.alibaba.dubbo.samples.api.GreetingService?anyhost=true&application=demo-provider&dubbo=2.6.2&generic=false&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=12938&side=provider×tamp=1533264631849*. -#### 5. 客户端:引用服务 +#### 5. Client: Reference Service -通过 `@Reference` 来在客户端声明服务的引用,运行时将会通过该引用发起全程调用,而服务的目标地址将会从 Zookeeper 的 `provider` 节点下查询。 +Use `@Reference` to declare a reference to the service in the client. At runtime, this reference will launch a full call, and the service's target address will be queried from the `provider` node in Zookeeper. ```java @Component("annotatedConsumer") @@ -254,9 +254,9 @@ public class GreetingServiceConsumer { } ``` -#### 6. 客户端:组装 +#### 6. Client: Assembly -定义 ConsumerConfiguration 来组装 Dubbo 服务。 +Define `ConsumerConfiguration` to assemble Dubbo services. ```java @Configuration @@ -266,7 +266,7 @@ public class GreetingServiceConsumer { static class ConsumerConfiguration {} ``` -dubbo-consumer.properties 是在 Spring 应用中外置配置的方式,内容如下: +The `dubbo-consumer.properties` file is an external configuration method in a Spring application, with the following contents: ```properties dubbo.application.name=demo-consumer @@ -274,11 +274,11 @@ dubbo.registry.address=zookeeper://$DOCKER_HOST:2181 dubbo.consumer.timeout=3000 ``` -与 **3. 服务端:组装** 相同,需要根据自己的运行环境来修改 *dubbo.registry.address* 中定义的 *$DOCKER_HOST*。请参阅步骤 3 的说明部分。 +As with **3. Server: Assembly**, you need to modify the *$DOCKER_HOST* defined in *dubbo.registry.address* according to your running environment. Please refer to the explanation in step 3. -#### 7. 客户端:发起远程调用 +#### 7. Client: Initiate Remote Call -运行 `main` 向已经启动的服务提供方发起一次远程调用。Dubbo 会先向 Zookeeper 订阅服务地址,然后从返回的地址列表中选取一个,向对端发起调用: +Run the `main` method to make a remote call to the already started service provider. Dubbo will first subscribe to the service address from Zookeeper, then select one from the returned address list to call the remote service: ```java public class ConsumerBootstrap { @@ -296,7 +296,7 @@ public class ConsumerBootstrap { } ``` -运行结果如下: +The output is as follows: ```shell [03/08/18 01:42:31:031 CST] main INFO zookeeper.ZookeeperRegistry: [DUBBO] Register: consumer://192.168.99.1/com.alibaba.dubbo.samples.api.GreetingService?application=demo-consumer&category=consumers&check=false&default.timeout=3000&dubbo=2.6.2&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=82406&side=consumer×tamp=1533274951195, dubbo version: 2.6.2, current host: 192.168.99.1 #1 @@ -305,12 +305,12 @@ public class ConsumerBootstrap { result: hello, zookeeper ``` -说明: +Notes: -1. **Register**: consumer://192.168.99.1/...&**category=consumers**&:消费者向 Zookeeper 注册自己的信息,并放在 `consumers` 节点下 -2. **Subscribe**: consumer://192.168.99.1/...&**category=providers,configurators,routers**&:消费者同时向 Zookeeper 订阅了 `providers`、`configurators`、`routers` 节点,其中 `configurations` 与 Dubbo 配置相关,`routers` 与路由规则相关,值得注意的是 `providers` 节点的订阅,当有新的服务提供方加入后,由于订阅的关系,新的地址列表会推送给订阅方,服务的消费者也因此动态感知到了地址列表的变化。 +1. **Register**: consumer://192.168.99.1/...&**category=consumers**&: The consumer registers its information with Zookeeper under the `consumers` node. +2. **Subscribe**: consumer://192.168.99.1/...&**category=providers,configurators,routers**&: The consumer subscribes to the `providers`, `configurators`, and `routers` nodes, where `configurations` are related to Dubbo configurations and `routers` are related to routing rules. Notably, the subscription to the `providers` node means that when new service providers join, the new address list will be pushed to subscribers, allowing service consumers to dynamically perceive changes to the address list. -通过 Zookeeper 管理终端观察服务提供方的注册信息: +Use the Zookeeper management terminal to observe the registration information of the service provider: ```sh $ docker exec -it zookeeper bash @@ -324,20 +324,18 @@ JLine support is enabled [consumer%3A%2F%2F192.168.99.1%2Fcom.alibaba.dubbo.samples.api.GreetingService%3Fapplication%3Ddemo-consumer%26category%3Dconsumers%26check%3Dfalse%26default.timeout%3D3000%26dubbo%3D2.6.2%26interface%3Dcom.alibaba.dubbo.samples.api.GreetingService%26methods%3DsayHello%26pid%3D82406%26side%3Dconsumer%26timestamp%3D1533274951195] ``` -可以看到 Dubbo 的服务消费者在 `consumers` 节点下注册了自己的 URL 地址:*consumer://192.168.99.1/com.alibaba.dubbo.samples.api.GreetingService?application=demo-consumer&category=providers,configurators,routers&default.timeout=3000&dubbo=2.6.2&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=82406&side=consumer×tamp=1533274951195* +You can see that the Dubbo service consumer registered its URL at the `consumers` node: *consumer://192.168.99.1/com.alibaba.dubbo.samples.api.GreetingService?application=demo-consumer&category=providers,configurators,routers&default.timeout=3000&dubbo=2.6.2&interface=com.alibaba.dubbo.samples.api.GreetingService&methods=sayHello&pid=82406&side=consumer×tamp=1533274951195*. -## 总结 +## Conclusion -本文侧重介绍了如何在 Dubbo 应用中使用 Zookeeper 做为注册中心,当然,本文也提到了 Zookeeper 在 Dubbo 的应用场景下还承担了配置中心和服务治理的职责。本文中的 Zookeeper 是单节点、Standalone 的模式,在生产环境中为了高可用的诉求,往往会组件 Zookeeper 集群,也就是 *Zookeeper ensemble* 模式。 - -通过本文的学习,读者可以掌握到: - -* Zookeeper 的基本概念和基本用法 -* Zookeeper 在 Dubbo 应用中的作用 -* 通过实战了解 Zookeeper 与 Dubbo 的交互 -* Dubbo 在 Zookeeper 中服务注册、消费信息的存储方式 +This article focuses on how to use Zookeeper as a registry in Dubbo applications. Additionally, it mentions that Zookeeper also serves as a configuration center and service governance role in the context of Dubbo. The Zookeeper discussed in this article is a single-node, standalone mode; in production environments, to meet the requirement of high availability, a Zookeeper cluster is usually assembled, known as *Zookeeper ensemble* mode. +Through this article, readers will grasp: +* The basic concepts and usage of Zookeeper. +* The role of Zookeeper in Dubbo applications. +* Practical understanding of the interaction between Zookeeper and Dubbo. +* How Dubbo stores service registration and consumption information in Zookeeper. [^1]: https://en.wikipedia.org/wiki/Atomic_broadcast [^2]: https://www.apache.org/dyn/closer.cgi/zookeeper/ diff --git a/content/en/blog/news/Dubbo-proxyless.md b/content/en/blog/news/Dubbo-proxyless.md index 9a07234ba7ac..eab4ebbcca26 100644 --- a/content/en/blog/news/Dubbo-proxyless.md +++ b/content/en/blog/news/Dubbo-proxyless.md @@ -1,88 +1,87 @@ --- -title: "Dubbo 在 Proxyless Mesh 模式下的探索与改进" -linkTitle: "Dubbo 在 Proxyless Mesh 模式下的探索与改进" +title: "Exploration and Improvement of Dubbo in Proxyless Mesh Mode" +linkTitle: "Exploration and Improvement of Dubbo in Proxyless Mesh Mode" date: 2023-02-02 --- -## 一、背景 -随着 Docker 和 Kubernetes 的出现,一个庞大的单体应用可以被拆分成多个独立部署的微服务,并被打包运行于对应的容器中。不同应用之间相互通信,以共同完成某一功能模块。微服务架构与容器化部署带来的好处是显而易见的,它降低了服务间的耦合性,利于开发和维护,能更有效地利用计算资源。当然,微服务架构也存在相应的缺点: +## I. Background +With the emergence of Docker and Kubernetes, a large monolithic application can be split into multiple independently deployed microservices, packaged, and run in corresponding containers. Different applications communicate with each other to jointly complete a function module. The benefits of microservices architecture and containerized deployment are evident as they reduce the coupling between services, facilitate development and maintenance, and make better use of computing resources. However, microservices architecture also has corresponding drawbacks: -- 强依赖于 SDK,业务模块与治理模块耦合较为严重。 除了相关依赖,往往还需要在业务代码中嵌入SDK代码或配置。 -- 统一治理难。每次框架升级都需要修改 SDK 版本,并重新进行回归测试,确认功能正常后再对每一台机器重新部署上线。不同服务引用的 SDK 版本不统一、能力参差不齐,增大了统一治理的难度。 -- 缺少一套统一解决方案。目前市场不存在一整套功能完善、无死角的微服务治理与解决方案。在实际生产环境往往还需要引入多个治理组件来完成像灰度发布、故障注入等功能。 +- Strong reliance on SDKs, resulting in significant coupling between business modules and governance modules. This often requires embedding SDK code or configuration in business code, in addition to related dependencies. +- Unified governance is challenging. Each framework upgrade requires modifying the SDK version and re-running regression tests, confirming functionality before redeploying on every machine. Different services referencing different SDK versions increase the difficulty of unified governance. +- Lack of a comprehensive solution. Currently, the market does not provide a complete and well-rounded microservices governance and solution. Often, multiple governance components must be introduced to achieve functionalities like grey releases and fault injection in actual production environments. -为解决这些痛点,Service Mesh诞生了。以经典的 Sidecar 模式为例,它通过在业务 Pod 中注入 Sidecar 容器,对代理流量实施治理和管控,将框架的治理能力下层到 Sidecar 容器中,与业务系统解耦,从而轻松实现多语言、多协议的统一流量管控、监控等需求。通过剥离SDK能力并拆解为独立进程,从而解决了强依赖于SDK的问题,从而使开发人员可以更加专注于业务本身,实现了基础框架能力的下沉,如下图所示(源自dubbo官网): +To address these pain points, Service Mesh emerged. Taking the classic Sidecar mode as an example, it implements governance and control of proxy traffic by injecting a Sidecar container into the business Pod, thereby decoupling the governance capability of the framework from the business system. This makes it easy to achieve unified traffic control, monitoring, and other needs across multiple languages and protocols. By decoupling SDK capabilities and breaking them down into independent processes, it alleviates the dependency on SDKs, allowing developers to focus more on the business itself. The foundational framework capabilities have thus been optimized, as illustrated in the following figure (source: dubbo official website): ![image.png](/imgs/blog/2023/2/2/1.png) -经典的 Sidecar Mesh 部署架构有很多优势,如减少SDK耦合、业务侵入小等,但增加了一层代理,也带来了一些额外的问题,比如: +The classic Sidecar Mesh deployment architecture has many advantages, such as reduced SDK coupling and minimal business intrusion, but it also adds a layer of proxy, introducing additional issues, such as: -- Sidecar 代理会损耗一部分性能,当网络结构层级比较复杂时尤其明显,对性能要求很高的业务造成了一定的困扰。 -- 架构更加复杂,对运维人员要求高。 -- 对部署环境有一定的要求,需要其能支持 Sidecar 代理的运行。 +- Sidecar proxies incur some performance loss, which is particularly noticeable in complex network structures, causing certain difficulties for performance-sensitive businesses. +- Increased architectural complexity and higher demands on operations personnel. +- Certain requirements for the deployment environment, needing to support Sidecar proxy operations. -为解决这些痛点,Proxyless Service Mesh 模式诞生了。传统服务网格通过代理的方式拦截所有的业务网络流量,代理需要感知到控制平面下发的配置资源,从而按照要求控制网络流量的走向。以istio为例,Proxyless 模式是指应用直接与负责控制平面的 istiod 进程通信,istiod 进程通过监听并获取 Kubernetes 的资源,例如 Service、Endpoint 等,并将这些资源统一通过 xDS 协议下发到不同的 RPC 框架,由 RPC 框架进行请求转发,从而实现服务发现和服务治理等能力。 -Dubbo 社区是国内最早开始对 Proxyless Service Mesh 模式进行探索的社区,这是由于相比于 Service Mesh,Proxyless 模式落地成本较低,对于中小企业来说是一个较好的选择。Dubbo 在 3.1 版本中通过对 xDS 协议进行解析,新增了对 Proxyless 的支持。xDS 是一类发现服务的总称,应用通过 xDS API 可以动态获取 Listener(监听器)、Route(路由)、Cluster(集群)、Endpoint(集群成员) 以及 Secret(证书)配置。 +To solve these pain points, the Proxyless Service Mesh mode was introduced. Traditional service meshes intercept all business network traffic through proxies, which must be aware of the configuration resources issued by the control plane to control the flow of network traffic as required. Taking Istio as an example, the Proxyless mode allows applications to communicate directly with the istiod process responsible for the control plane. The istiod process listens for and obtains Kubernetes resources, such as Service and Endpoint, and distributes these resources uniformly via the xDS protocol to different RPC frameworks, enabling service discovery and governance capabilities. The Dubbo community was one of the first to explore the Proxyless Service Mesh mode in China, as the Proxyless mode has a lower implementation cost compared to Service Mesh, making it a good option for small and medium-sized enterprises. In version 3.1, Dubbo added Proxyless support by parsing the xDS protocol. xDS is a general term for service discovery, where applications can dynamically obtain Listener, Route, Cluster, Endpoint, and Secret configurations through the xDS API. ![image.png](/imgs/blog/2023/2/2/2.jpeg) -通过 Proxyless 模式,Dubbo 与 Control Plane 直接建立通信,进而实现控制面对流量管控、服务治理、可观测性、安全等的统一管控,从而规避 Sidecar 模式带来的性能损耗与部署架构复杂性。 +Through the Proxyless model, Dubbo establishes direct communication with the Control Plane, thereby achieving unified management over traffic control, service governance, observability, and security, avoiding the performance loss and deployment complexity associated with the Sidecar model. -## 二、Dubbo xDS 推送机制详解 +## II. Detailed Explanation of Dubbo xDS Push Mechanism -从整体上看,istio control plane 和 dubbo 的交互时序图如上。Dubbo 里 xDS 处理的主要逻辑在 PilotExchanger 和各个 DS (LDS、RDS、CDS、EDS) 的对应协议的具体实现里。PilotExchanger 统一负责串联逻辑,主要有三大逻辑: +Overall, the interaction timing diagram between the Istio control plane and Dubbo is shown above. The main logic of xDS handling in Dubbo resides in the PilotExchanger and the specific implementations of each DS (LDS, RDS, CDS, EDS) protocols. The PilotExchanger is responsible for unifying the linkage logic, primarily encompassing three major logics: -- 获取授信证书。 -- 调用不同 protocol 的 getResource 获取资源。 -- 调用不同 protocol 得 observeResource 方法监听资源变更。 +- Obtaining authorization certificates. +- Calling different protocol's getResource to acquire resources. +- Calling observeResource methods of different protocols to listen to resource changes. -例如对于 lds 和 rds,PilotExchanger 会调用 lds 的 getResource 方法与 istio 建立通信连接,发送数据并解析来自 istio 的响应,解析完成后的 resource 资源会作 为rds 调用 getResource 方法的入参,并由 rds 发送数据给 istio。当 lds 发生变更时,则由 lds 的 observeResource 方法去触发自身与 rds 的变更。上述关系对于 rds 和 eds 同样如此。现有交互如下,上述过程对应图里红线的流程: +For instance, for LDS and RDS, the PilotExchanger invokes the getResource method of LDS to establish communication with Istio, sending data and parsing responses from Istio. Upon completing the parsing, the resource is used as an argument for RDS's getResource method, which sends data to Istio. When changes occur in LDS, the observeResource method of LDS triggers changes in itself and RDS. The existing interaction is as follows, corresponding to the red-line process in the figure above: ![image.png](/imgs/blog/2023/2/2/3.jpeg) -在第一次成功获取资源之后,各个DS会通过定时任务去不断发送请求给 istio,并解析响应结果和保持与 istio 之间的交互,进而实现控制面对流量管控、服务治理、可观测性方面的管控,其流程对应上图蓝线部分。 +After successfully acquiring resources for the first time, each DS will continuously send requests to Istio via scheduled tasks, parse response results, and maintain interaction with Istio. This process corresponds to the blue line part of the figure above. -## 三、当前Dubbo Proxyless实现存在的不足 +## III. Current Shortcomings of Dubbo Proxyless Implementation -Dubbo Proxyless 模式经过验证之后,已经证明了其可靠性。现有 Dubbo proxyless 的实现方案存在以下问题: +Dubbo Proxyless mode has proven its reliability after validation. However, existing Dubbo Proxyless implementation schemes face the following issues: -- 目前与 istio 交互的逻辑是推送模式。getResource 和 observeResource 是两条不同的 stream 流,每次发送新请求都需要重新建立连接。但我们建立的 stream 流是双向流动的,istio 在监听到资源变化后由主动推送即可,LDS、RDS、EDS 分别只需要维护一条 stream 流。 -- Stream 流模式改为建立持久化连接之后,需要设计一个本地的缓存池,去存储已经存在的资源。当 istio 主动推送更新后,需要去刷新缓存池的数据。 -- 现有observeResource 逻辑是通过定时任务去轮询istio。现在 observeResource 不再需要定时去轮询,只需要将需要监听的资源加入到缓存池,等 istio 自动推送即可,且 istio 推送回来的数据需要按照 app 切分好,实现多点监听,后续 dubbo 支持其他 DS 模式,也可复用相应的逻辑。 -- 目前由 istio 托管的 dubbo 应用在 istio 掉线后会抛出异常,断线后无法重新连接,只能重新部署应用,增加了运维和管理的复杂度。我们需增加断线重连的功能,等 istio 恢复正常后无需重新部署即可重连。 +- The current interaction logic with Istio is push-mode. getResource and observeResource are two different stream flows, requiring a new connection each time a new request is sent. However, the stream flow we establish should be bidirectional; Istio can actively push after detecting resource changes, and LDS, RDS, and EDS need to maintain just one stream flow each. +- After changing to a persistent connection for the stream flow model, a local cache pool must be designed to store already existing resources. When Istio actively pushes updates, the cached data needs to be refreshed. +- The current observeResource logic polls Istio via scheduled tasks. observeResource no longer needs to poll regularly; it only needs to add the resources to be observed to the cache pool and wait for Istio to automatically push. The data returned from Istio needs to be split according to the app for multi-point listening. Subsequently, Dubbo support for other DS modes can also reuse the corresponding logic. +- Currently, Dubbo applications managed by Istio will throw exceptions when Istio goes offline, and after disconnections, they cannot reconnect, requiring redeployment of applications, thus increasing operational and management complexity. We need to add disconnection reconnection functionality, allowing reconnection when Istio recovers normally without redeployment. -改造完成后的交互逻辑: +The interaction logic after the transformation: ![image.png](/imgs/blog/2023/2/2/4.jpeg) -## 四、Xds 监听模式实现方案 +## IV. Implementation Plan for Xds Listening Mode -### 4.1 资源缓存池 +### 4.1 Resource Cache Pool -目前 Dubbo 的资源类型有LDS,RDS,EDS。对于同一个进程,三种资源监听的所有资源都与 istio 对该进程所缓存的资源监听列表一一对应。因此针对这三种资源,我们应该设计分别对应的本地的资源缓存池,dubbo 尝试资源的时候先去缓存池查询,若有结果则直接返回;否则将本地缓存池的资源列表与想要发送的资源聚合后,发送给 istio 让其更新自身的监听列表。缓存池如下,其中 key 代表单个资源,T 为不同 DS 的返回结果: +Currently, Dubbo's resource types include LDS, RDS, EDS. For the same process, all resources being listened to for the three resource types correspond one-to-one with the cached resource listening list for that process in Istio. Therefore, we should design separate local resource cache pools for these three resource types. When Dubbo attempts to access resources, it first checks the cache pool; if results are found, it returns directly; otherwise, it aggregates the resource list in the local cache pool with the resources to be sent to Istio for updating its listening list. The cache pool is as follows, where key represents a single resource, and T is the return result of different DS: ```java protected Map resourcesMap = new ConcurrentHashMap<>(); ``` -有了缓存池我们必须有一个监听缓存池的结构或者容器,在这里我们设计为 Map 的形式,如下: +With a cache pool, we must have a structure or container for listening to the cache pool. Here we design it as a Map, as follows: ```java protected Map, List>>> consumerObserveMap = new ConcurrentHashMap<>(); ``` -其中key为想要监听的资源,value 为一个 List, 之所以设计为 List 是为了可以支持重复订阅。 List 存储的 item 为 jdk8 中的 Consumer 类型,它可以用于传递一个函数或者行为,其入参为 Map,其 key 对应所要监听的单个资源,便于从缓存池中获取。如上文所述,PilotExchanger 负责串联整个流程,不同 DS 之间的更新关系可以用 Consumer 进行传递。以监听 LDS observeResource 为例, 大致代码如下: +Where the key represents the resources to be observed, and the value is a List. The List is designed to support repeated subscriptions. Items stored in the List are of Consumer type in jdk8, which can convey a function or behavior, with the parameter being Map, allowing retrieval from the cache pool. As mentioned, the PilotExchanger is responsible for linking the complete process, where the update relationships between different DS can be conveyed using Consumer. Taking observing LDS as an example, the code is roughly as follows: ```java -// 监听 +// Listen void observeResource(Set resourceNames, Consumer> consumer, boolean isReConnect); // Observe LDS updated ldsProtocol.observeResource(ldsResourcesName, (newListener) -> { - // LDS数据不一致 + // Inconsistent LDS data if (!newListener.equals(listenerResult)) { - //更新LDS数据 + // Update LDS data this.listenerResult = newListener; - // 触发RDS监听 + // Trigger RDS listening if (isRdsObserve.get()) { createRouteObserve(); } @@ -90,19 +89,19 @@ ldsProtocol.observeResource(ldsResourcesName, (newListener) -> { }, false); ``` -Stream流模式改为建立持久化连接之后,我们也需要把这个 Consumer 的行为存储在本地的缓存池中。Istio 收到来自 dubbo 的推送请求后,刷新自身缓存的资源列表并返回响应。此时 istio 返回的响应内容是聚合后的结果,Dubbo 收到响应后,将响应资源拆分为更小的资源粒度,再推送给对应的 Dubbo应用通知其进行变更。 +Once the stream flow model transforms to establish a persistent connection, we also need to store the behavior of this Consumer in the local cache pool. Once Istio receives the push request from Dubbo, it refreshes its cached resource list and returns a response. At this time, the response content returned by Istio is an aggregated result. Upon receiving the response, Dubbo splits the response resources into smaller granular resources and pushes them to the corresponding Dubbo application to notify it of any changes. -踩坑点: +Pitfalls: -- istio推送的数据可能为空字符串,此时缓存池子无需存储,直接跳过即可。否则dubbo会绕过缓冲池,不断向istio发送请求。 -- 考虑以下场景,dubbo应用同时订阅了两个接口,分别由app1和app2提供。为避免监听之间的相互覆盖,因此向istio发送数据时,需要聚合所有监听的资源名一次性发起。 +- The data pushed by Istio may be an empty string; in this case, the cache pool does not need to store it and can be skipped. Otherwise, Dubbo will bypass the cache pool and continuously send requests to Istio. +- Consider the following scenario—Dubbo applications simultaneously subscribe to two interfaces provided by app1 and app2. To avoid mutual overwriting between listeners, it is necessary to aggregate all observed resource names and initiate requests to Istio at once. -### 4.2 多点独立监听 +### 4.2 Multi-Point Independent Listening -在第一次向istio发送请求时会调用getResource方法先去cache查询,缺失了再聚合数据去istio请求数据,istio再返回相应的结果给dubbo。我们处理istio的响应有两种实现方案: -1. 由用户在getResource方案中new 一个completeFuture,由cache分析是否是需要的数据,若确认是新数据则由该future回调传递结果。 -2. getResource建立资源的监听器consumerObserveMap,定义一个consumer并把取到的数据同步到原来的线程,cache 收到来自istio的推送后会做两件事:将数据推送所有监听器和将数据发送给该资源的监听器。 -以上两种方案都能实现,但最大的区别就是用户调用onNext发送数据给istio的时候需不需要感知getResource 的存在。综上,最终选择方案2进行实现。具体实现逻辑是让dubbo与istio建立连接后,istio会推送自身监听到资源列表给dubbo,dubbo解析响应,并根据监听的不同app切分数据,并刷新本地缓存池的数据,并发送ACK响应给istio,大致流程如下: +When the first request is sent to Istio, it calls the getResource method to query the cache. If absent, it aggregates the data to send a request to Istio, which then returns the corresponding results to Dubbo. There are two implementation plans for processing Istio's responses: +1. The user creates a completeFuture in the getResource plan, with the cache analyzing whether the data is needed, and if confirmed as new data, the future callback transmits the result. +2. The getResource creates resource listeners in consumerObserveMap, defining a consumer that synchronizes the obtained data to the original thread, where the cache sends data to all listeners and to the listener of that resource when it receives a push from Istio. +Both plans can be implemented, but the key difference is whether the user's call to onNext must recognize the existence of getResource. Thus, plan 2 is ultimately chosen for implementation. The specific implementation logic ensures that Dubbo establishes a connection with Istio, which then pushes its monitored resource list to Dubbo. Dubbo parses the response, splits the data based on different apps, refreshes the local cache pool data, and sends an ACK response to Istio, as illustrated in the following process: ![image.png](/imgs/blog/2023/2/2/5.svg) @@ -110,11 +109,11 @@ Stream流模式改为建立持久化连接之后,我们也需要把这个 Cons public class ResponseObserver implements XXX { ... public void onNext(DiscoveryResponse value) { - //接受来自istio的数据并切分 + // Accept data from Istio and split Map newResult = decodeDiscoveryResponse(value); - //本地缓存池数据 + // Local cache pool data Map oldResource = resourcesMap; - //刷新缓存池数据 + // Refresh cache pool data discoveryResponseListener(oldResource, newResult); resourcesMap = newResult; // for ACK @@ -126,61 +125,58 @@ public class ResponseObserver implements XXX { .... } } -//具体实现交由LDS、RDS、EDS自身 +// Specific implementation left to LDS, RDS, EDS protected abstract Map decodeDiscoveryResponse(DiscoveryResponse response){ - //比对新数据和缓存池的资源,并将不同时存在于两种池子的资源取出 + // Compare new data with cache pool resources to extract resources absent in either pool ... for (Map.Entry, List>>> entry : consumerObserveMap.entrySet()) { - // 本地缓存池不存在则跳过 + // Skip if not present in the local cache pool ... - //聚合资源 + // Aggregate resources Map dsResultMap = entry.getKey() .stream() .collect(Collectors.toMap(k -> k, v -> newResult.get(v))); - //刷新缓存池数据 + // Refresh cache pool data entry.getValue().forEach(o -> o.accept(dsResultMap)); } } ``` -踩坑点: +Pitfalls: -- 原本多个stream流的情况下,会用递增的requestId来复用stream流,改成持久化连接之后,一种resource会有多个requestid,可能会相互覆盖,因此必须去掉这个机制。 -- 初始实现方案并没有对资源进行切分,而是一把梭,考虑到后续对其他DS的支持,对istio返回的数据进行切分,也导致consumerObserveMap有点奇形怪状。 -- 三种DS在发送数据时可以共享同一channel,但监听所用到的必须是同一channel,否则数据变更时istio不会进行推送。 -- 建立双向stream流之后,初始方案future为全局共享。但可能有这样的场景:相同的ds两次相邻时间的onNext事件,记为A事件和B事件,可能是A事件先发送,B随后;但可能是B事件的结果先返回,不确定istio推送的时间,因此future必须是局部变量而不是全局共享。 +- In the case of multiple stream flows, incremental requestId was used to reuse stream flows. After changing to persistent connections, one resource has multiple requestIds that may overwrite each other, thus this mechanism must be removed. +- The initial implementation plan did not split resources but treated them as a whole. Considering future support for other DS, splitting the data returned from Istio led to some oddities in consumerObserveMap. +- While all three DS can share the same channel when sending data, the channels used for listening must be the same; otherwise, Istio will not push updates when data changes. +- After establishing a bidirectional stream, the initial plan used a globally shared future. However, there may be a scenario where the onNext events for the same ds occur in quick succession, referred to as event A and event B, with event A possibly being sent first. Yet event B's result may return first. The timing of Istio's push being uncertain means futures must be local variables instead of globally shared. -### 4.3 采用读写锁避免并发冲突 +### 4.3 Using Read-Write Locks to Avoid Concurrency Conflicts -监听器consumerObserveMap和缓存池resourcesMap均可能产生并发冲突。对于resourcemap,由于put操作都集中在getResource方法,因此可以采用悲观锁就能锁住相应的资源,避免资源的并发监听。对于consumerObserveMap,同时存在put、remove和遍历操作,从时序上,采用读写锁可规避冲突,对于遍历操作加读锁,对于put和remove操作加写锁,即可避免并发冲突。综上,resourcesMap加悲观锁即可,consumerObserveMap涉及的操作场景如下: +Listeners in consumerObserveMap and resourcesMap caching pools are likely to result in concurrent conflicts. For resourceMap, as put operations are concentrated in the getResource method, pessimistic locking can secure the corresponding resources and avoid concurrent listening. For consumerObserveMap, with simultaneous put, remove, and traversal operations, using read-write locks can mitigate conflicts. Read locks can be applied for traversals while write locks can be utilized for put and remove operations to prevent concurrency conflicts. Thus, a pessimistic lock on resourcesMap suffices whereas the operations involving consumerObserveMap are as follows: -- 远程请求istio时候会往consumerObserveMap 新增数据,加写锁。 -- CompleteFuture跨线程返回数据后,去掉监听future,加写锁。 -- 监听缓存池时会往consumerObserveMap新增监听,加写锁。 -- 断线重连时会往consumerObserveMap新增监听,加写锁。 -- 解析istio返回的数据,遍历缓存池并刷新数据,加读锁。 +- Adding data to consumerObserveMap during remote requests to Istio, applying a write lock. +- Removing the listening future when completeFuture returns data across threads, applying a write lock. +- Adding listeners to consumerObserveMap when observing the cache pool, applying a write lock. +- Adding listeners to consumerObserveMap during disconnection reconnections, applying a write lock. +- Parsing data returned from Istio, traversing the cache pool, and refreshing data, applying a read lock. -踩坑点: +Pitfalls: -- 由于dubbo和istio建立的是是双向stream流,相同的ds两次相邻时间的onNext事件,记为A事件和B事件,可能是A事件先发送,B随后;但可能是B事件的结果先返回,不确定istio推送的时间。因此需要加锁。 +- Because Dubbo and Istio establish a bidirectional stream, the onNext events for the same ds may occur in quick succession, requiring event A and event B to be sent in order; however, the result of B could return first. Therefore, locking is necessary. -### 4.4 断线重连 +### 4.4 Disconnection Reconnection -断线重连只需要用定时任务去定时与istio交互,尝试获取授信证书,证书获取成功即可视为istio成功重新上线,dubbo会聚合本地的资源去istio请求数据,并解析响应和刷新本地缓存池数据,最后再关闭定时任务。 -踩坑点: +Disconnection reconnection only requires a scheduled task to interact with Istio regularly, trying to obtain authorization certificates. Successfully obtaining the certificate signifies that Istio has come back online. Dubbo will aggregate local resources to request data from Istio, parse the response and refresh local cache pool data, and finally close the scheduled task when completed. +Pitfalls: -- 采用全局共享的定时任务池,不能进行关闭,否则会影响其他业务。 +- Using a globally shared scheduled task pool cannot be closed; otherwise, it will affect other services. - -## 五、感想与总结 -在这次功能的改造中,笔者着实掉了一波头发,怎么找bug也找不到的情形不在少数。除了上述提到的坑点之外,其他的坑点包括但不局限于: - -- dubbo在某一次迭代里更改了获取k8s证书的方式,授权失败。 -- 原本的功能没问题,merge了下master代码,grpc版本与envoy版本不兼容,各种报错,最后靠降低版本成功解决。 -- 原本的功能没问题,merge了下master代码,最新分支代码里metadataservice发成了triple,然而在Proxyless模式下只支持dubbo协议,debug了三四天,最后发现需要增加配置。 - - ...... -但不得不承认,Proxyless Service Mesh确实有它自身的优势和广阔的市场前景。自dubbo3.1.0 release版本之后,dubbo已经实现了Proxyless Service Mesh能力,未来dubbo社区将深度联动业务,解决更多实际生产环境中的痛点,更好地完善service mesh能力。 - +## V. Reflections and Summary +During this functionality transformation, I genuinely lost a bit of hair, as encountering bugs that couldn't be found was not uncommon. Besides the pitfalls mentioned above, other issues include but are not limited to: +- Dubbo altered the method for obtaining k8s certificates in one iteration, resulting in authorization failures. +- The original functionality was problem-free, but merging the master code rendered incompatibility between grpc and envoy versions, causing various errors. Ultimately, the issue was resolved by reducing the version. +- The original functionality was still intact, but merging the master code caused the latest branch code to send metadataservice in triple; however, Proxyless mode only supports the Dubbo protocol. After debugging for three or four days, it became apparent that additional configuration was needed. +...... +However, it must be acknowledged that Proxyless Service Mesh indeed has its own advantages and broad market prospects. Since the release of Dubbo 3.1.0, Dubbo has already implemented Proxyless Service Mesh capabilities. In the future, the Dubbo community will closely align with businesses to address more real-world production pain points, further refining service mesh capabilities. diff --git a/content/en/blog/news/apachecon2023/dubbo-on-kubernetes.md b/content/en/blog/news/apachecon2023/dubbo-on-kubernetes.md deleted file mode 100644 index d4309f5f249c..000000000000 --- a/content/en/blog/news/apachecon2023/dubbo-on-kubernetes.md +++ /dev/null @@ -1,182 +0,0 @@ ---- -title: "Step-by-Step Guide to Deploying Dubbo Applications to Kubernetes – Apache Dubbo Kubernetes Best Practices" -linkTitle: "Step-by-Step Guide to Deploying Dubbo Applications to Kubernetes – Apache Dubbo Kubernetes Best Practices" -tags: ["apachecon2023", "observability", "metrics", "tracing"] -date: 2023-10-07 -authors: ["Jiang Heqing"] -description: Step-by-Step Guide to Deploying Dubbo Applications to Kubernetes – Apache Dubbo Kubernetes Best Practices ---- - -Refining Cloud Native – Dubbo Kubernetes Best Practices - -Abstract: This article is compiled from the sharing by Jiang Heqing, a research and development engineer at Alibaba Cloud and a member of the Apache Dubbo PMC. The content is primarily divided into six parts: - -- 1. Initializing the project using Dubbo Starter -- 2. Protocol selection for microservices development -- 3. Quickly initializing the environment based on Kubernetes -- 4. Rapidly deploying applications to the Kubernetes cluster -- 5. Best practices for cloud-native microservices observability -- 6. Managing microservice applications in Kubernetes - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img.png) - -The image above is a demo inspired by Istio, consisting of four components: Product Page, Reviews, Details, and Ratings, which create an entire microservice architecture that enables simple calls. - -## 1. Initializing the Project using Dubbo Starter - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_1.png) - -First, let’s introduce the functionality of the Starter. For many developers, creating a new application under the Java ecosystem typically involves using an IDE to create a new project, using a Maven artifact, or based on Spring's Initializer. - -The image above shows that we built our project initialization based on Spring's Initializer. By clicking the URL at the top, you can view this page directly, where you need to enter the corresponding group and artifact. Then, select the components you wish to use, such as Nacos and Prometheus. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_2.png) - -Additionally, we provide a Dubbo plugin in the IDE. This plugin can be installed as shown in the above image, or if you are using Dubbo configuration in your repository, it will prompt you for direct installation. Once installed, there will be a corresponding initialization project on the right. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_3.png) - -The image above is an example, where a Dubbo project is established. You need to select the required component information here, click create, and it will create a brand new project locally for you to develop on this template. - -## 2. Protocol Selection for Microservices Development - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_4.png) - -We will use the latest Triple protocol, which overall supports compatibility with gRPC, HTTP/1, and HTTP/2. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_5.png) - -The main point to share here is that we have capabilities based on curl, meaning tools like POSTMAN and HttpClient are supported. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_6.png) - -Now, let’s take a look at our project, which is the one we just created. I will start the application, configure some registry center addresses, and this follows a standard Spring startup process. An interface is defined that returns a "hello" message. With a simple command, I can directly return my hello world result. This significantly aids our testing, as we can directly test the interface once launched locally. - -## 3. Quickly Initializing the Environment Based on Kubernetes - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_7.png) - -Assuming we have completed the development of the code for the four applications mentioned earlier, next, I want to deploy it to the K8s environment. A very important step before deployment is that we need to initialize the environment first. Components like Nacos, ZK, Skywalking, Zipkin, and Prometheus need to be installed as they are prerequisite dependencies for the application. The installation process for these components is quite complex; how can we simplify this process? - -Dubbo provides a command that allows you to pull up all the components on the left in the K8s ecosystem with one click. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_8.png) - -Here’s a simple example. Once pulled up, it will assist you in launching all the components. Note that we will continue to use Prometheus later on. The entire address of Nacos and Zookeeper will be given to you directly. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_9.png) - -This is another example. By executing a simple command, the local environment will prepare the kubectl configuration, and it will automatically create all the components for you. In this way, we can get all service deployments with one click. - -## 4. Rapidly Deploying Applications to the Kubernetes Cluster - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_10.png) - -There are three key points in deploying applications: containerization of the application, stateless deployment, and lifecycle alignment. - -First, let’s introduce application containerization. To containerize an application, you need to create a Dockerfile, include a JDK package, and add the startup command and script. Additionally, write a Java compilation script to include the resulting jar package. This process is quite complex, so we can use the Jib plugin. This plugin is a Maven plugin; you just need to set up the configuration and specify your Image. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_11.png) - -As you can see, I only need to add a corresponding configuration dependency in my pom file, and with one-click Maven compile mode, it will build the image during the Maven packaging process and push it directly to a remote repository. This can all be accomplished with just one command, and after configuration, all future image updates can be automated, without the need to write cumbersome Dockerfiles. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_12.png) - -Next, let's discuss stateless deployment. After creating the image, the next step is to run it. We can use the K8s deployment model, which is pulled directly from the K8s website. Once pulled down, we can specify the corresponding application name, image information, etc. This is essential for K8s; we need to configure a demo like this. Of course, cloud vendors will provide a visual interface for you, and the underlying configuration is such a YAML. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_13.png) - -This is a simple example. After configuring the deployment, the specified image is assigned. I've also declared a service, which is very important as it will serve as the ingress configuration for the from_end application. Upon applying the image, we can run this environment on K8s. - -Here, let me do a simple test. I introduced a curl container, and similarly, we can use the earlier curl command to access the newly deployed container node, and it returns the hello world data. - -In summary, through deployment, we can run containers on K8s; additionally, it can provide services externally, which I can invoke using the curl command below. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_14.png) - -Finally, let’s discuss lifecycle alignment. Once the overall deployment is completed, multiple Pods will be deployed, which involves batching behaviors. If we divide it into two batches, ensuring that my business is non-disruptive, we will need K8s to assist us with batch processing. K8s only knows that processes are up, so we need to let K8s understand whether the application is in the startup state, ready, and alive. This is the process provided by K8s; how do we match it with Dubbo's process? - -The right side of the image displays some port information provided natively by Dubbo, which will be exposed to supply such state information to K8s, allowing the lifecycle to align completely. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_15.png) - -The above image is an example. When the application starts, it sleeps for 20 seconds, then configures the corresponding Pro information. - -Let’s assume that if it waits 20 seconds, then my application must exceed 20 seconds to start up. Because I modified the code, it needs to be recompiled, using one-click Maven compile mode to push it again. After that, I apply the deployment, and at this point, the Pod state is all not ready, all are zero states. - -Since Dubbo has not finished starting after the initial 20 seconds, it remains in not ready state. Once the sleep phase is over, it changes to ready status, and then batch processing can occur, which is the lifecycle alignment process. - -This way, K8s knows when the application has started successfully or failed, allowing for better scheduling. - -## 5. Best Practices for Cloud-Native Microservices Observability - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_16.png) - -Once deployed, we will also involve the observability of the entire application. As our application may be deployed on many nodes, I need to sense the application's state. - -The observability system includes the Metrics system and the Tracing system. The Metrics system includes several indicators, such as Google's four environmental indicators: latency, traffic, etc. In relation to Dubbo, it will provide QPS, RT, etc., as best practices for Metrics in this system. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_17.png) - -Earlier when initializing the environment for deployment, we mentioned the Prometheus service, which is utilized now. After deploying the Prometheus environment, we just need to configure a few simple lines of Metrics collection information. Then Prometheus will help you gather many Metrics on your nodes and get the panel information on the right, which is also provided by Dubbo, showing Dubbo's state. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_18.png) - -The above image is a demonstration example. We add the Metrics collection information to the previous deployment example, and after applying it, we can use the entire Grafana to export. After running for some time, there will be corresponding traffic information, such as QPS, RT, success rate, etc. - -Once we obtain these metrics, we can also set up alerts. For instance, if QPS suddenly drops from 100 to 0, or if the success rate suddenly decreases significantly, we need to issue a warning to inform everyone of the current issue. We can rely on Prometheus collection for proactive pushes, which is the alerting process. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_19.png) - -Tracing includes built-in tracing and agent injection solutions. Currently, mainstream languages like Go usually use SDK dependencies for an open tracing mechanism. As agent injection under the Go framework is not very complete, Dubbo itself also offers native tracing capability support. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_20.png) - -As you can see, you only need to depend on the Dubbo starter in the dependencies section, enable the Tracing capability in the configuration, and initiate an indicator report. 9411 is the backend for our Zipkin. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_21.png) - -This is also an example where I only need to configure these settings, and its data will be reported to Zipkin. Just add this dependency. - -Similarly, package it using the earlier command to push the image up, and we'll wait a moment. During the push process, we can observe the Zipkin component, which was also pulled up together during the K8s environment initialization, so everything can be done just by prior deployment. - -Then we execute a curl command because I need my environment to have traffic. After deployment, let's execute the curl command to fetch; this has essentially completed the backend development and returned real results. - -Next, we go to Zipkin to see if we can locate this tracing. First, we map 9411 over, and we can see the corresponding metric information by using a simple query. All of the end-to-end call details will be visible here; this is the complete workflow for the end-to-end integration. Essentially, you only need to include the dependencies and reporting configurations upfront, and everything will be handled behind the scenes, allowing you to see what happened across the entire link. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_22.png) - -Additionally, you can also utilize agent-based methods. If we deploy based on K8s, integrating an agent is also very convenient. You can directly inject the entire Java configuration information using an initContainer, allowing you to see the corresponding end-to-end info on Skywalking. Since it's similar to what was previously mentioned, I won't elaborate on its demo project. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_23.png) - -Overall, for observability, we can view QPS and RT information through Metrics, and see full link access information through Tracing. Here provides us an excellent solution: we should first monitor the service to better troubleshoot the overall issues, immediately knowing if the application has crashed. For instance, if the availability rate drops to zero at two in the morning, a series of automated mechanisms can inform you of the application issue for quick recovery. This quick recovery could involve rollback strategies or traffic isolation measures executed promptly. - -With such a rapid chain from observation to troubleshooting and then to quick recovery, an overall secure and stable system can be constructed in the production environment. Thus, our goal after observation is to ensure the entire application's stability. - -## 6. Managing Microservice Applications in Kubernetes - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_24.png) - -The benefits brought by K8s include rapid scaling—where I can quickly scale from one Pod to multiple Pods based on K8s. K8s operates from the process of deploying entire Images, meaning once the image is packaged, your environment is fixed, and you only need to expand horizontally. - -Rapid horizontal scaling may encounter several bottlenecks. If I want my application to scale quickly, even if the scaling takes several minutes, by the time it completes, the peak workload may have already passed; this introduces the concept of Native Images. - -With Native Images, we can achieve efficient serverless horizontal scaling. If we can achieve millisecond-level startup, during traffic peaks, I can scale my Pods many times; when traffic diminishes, they can be quickly terminated, effectively compressing costs. - -Another issue is how to determine when to scale. This requires monitoring based on Metrics and analyzing historical data to predict how much traffic there will be at specific points and then scaling up in advance or automating the scaling process. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_25.png) - -Let’s say, for instance, if there are issues with my ratings, and I need to isolate the faults and promote an adaptive result. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_26.png) - -At this point, you simply need to configure the rule in the image above, and it will return the result. This is the Admin use case, which I won’t delve further into. Also, as mentioned earlier, we are enhancing our Go version's capabilities, which will see more improvements in the future. - -![dubbo-kubernetes-best-practice](/imgs/blog/2023/8/apachecon-scripts/kubernetes/img_27.png) - -Moreover, based on Istio's Service Mesh governance, we selected the Triple protocol for protocol selection, which is completely based on the HTTP standard. Therefore, by utilizing the entire Istio system, once you attach subcard, it helps you manage traffic governance. The prerequisite for all this is that your protocol must be visible to Istio. - -For example, if you originally used Dubbo 2’s Dubbo protocol, which is a private TCP protocol, it would be difficult for Istio to recognize your protocol content. However, using the Triple protocol based on HTTP standards allows Istio to know what's in your header, facilitating traffic forwarding. Thus, it fully embraces the Mesh system and supports all Istio governance capabilities. - diff --git a/content/en/blog/news/apachecon2023/ecosystem-opensergo.md b/content/en/blog/news/apachecon2023/ecosystem-opensergo.md deleted file mode 100644 index c722e1dd1927..000000000000 --- a/content/en/blog/news/apachecon2023/ecosystem-opensergo.md +++ /dev/null @@ -1,200 +0,0 @@ ---- -title: "OpenSergo & Dubbo 微服务治理最佳实践" -linkTitle: "OpenSergo & Dubbo 微服务治理最佳实践" -tags: ["apachecon2023", "opensergo", "ecosystem"] -date: 2023-10-07 -authors: ["何家欢"] -description: OpenSergo & Dubbo 微服务治理最佳实践 ---- - -摘要:本文整理自阿里云 MSE 研发工程师何家欢的分享。本篇内容主要分为四个部分: - -* 一、Why 微服务治理? -* 二、OpenSergo:服务治理控制面与标准规范 -* 三、OpenSergo & Dubbo 最佳实践 -* 四、OpenSergo 的未来之路 - -## 一、Why 微服务治理? - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img.png) - -现代的微服务架构里,我们通过将系统分解成一系列的服务并通过远程过程调用联接在一起,在带来一些优势的同时也为我们带来了一些挑战。 - -如上图所示,可以看到一个词云,这些都是目前微服务架构在生产上所遇到的挑战。比如,最常见的流量激增的场景,近一年内AIGC突然爆火,相关网站/服务都存在过因为激增流量导致服务不可用的情况,可能会让我们错过一个最佳的增长窗口。 - -再比如缺乏容错机制,某视频网站的某个服务异常,随调用链扩散,导致全站入口不可用,影响千万用户,产生实质性的经济损失。这些生产故障频频发生,也是在提醒我们稳定性是用好微服务的重大挑战之一。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_1.png) - -为了保障微服务的稳定性,我们就需要做一些架构的演进。 - -我们先看一下左侧的微服务3大件,这个大家已经很熟悉了,通过这三者的配合,我们的应用就能够正常使用了,但是距离生产可用其实还有很大一段距离,各个企业和社区为了消除这其中的gap都有一些探索和实践,比如Dubbo社区在Dubbo3中引入一系列诸如流量管理、高可用性的能力来保障微服务的稳定性,这些措施可以统称为微服务治理。 - -所以其实大家已经意识到,从把微服务跑起来到真的生产可用,微服务治理是必不可少的一环。但微服务治理要做些什么,如何去做其实都还比较模糊。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_2.png) - -从软件生命周期的角度,我们可以把微服务治理分成三个域,开发态与测试态、变更态、运行态。 - -在这三个域中都面临着很多挑战,对于这些挑战大家也有着一些探索和实践,比如对于发布有损的问题,我们可以通过无损上下线来解决,变更的影响面通过灰度来控制,对于不确定流量使用流控、热点防护,不稳定调用使用熔断与隔离。 - -可以看到在各个域中都有一些成熟的方案和效果很好的实践。但是不管是阿里还是其他公司,在体系化落地微服务治理时都会遇到很多问题。 - -## 二、OpenSergo:服务治理控制面与标准规范 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_3.png) - -首先我们涉及的组件有很多,在微服务架构中,往往会涉及很多组件,它们需要有Dubbo这样的调用框架,nacos这样注册中心,snetinel、hystrix这样的稳定性中间件等等,因此也没办法进行统一治理,管控成本就非常高。 - -其次时概念不统一,比如在envoy中的隔离与 sentinel中的隔离完全不是一个意思,envoy的隔离是摘除不健康实例,sentinel的隔离是并发控制,这就会使开发者理解成本很高。 - -同时各个企业社区都有自己的最佳实践,这也就导致大家能力上是不对齐的,没有统一的标准。 - -还有配置不统一的问题相信大家都很有体感,比如sentinel、hystrix、istio都有熔断的能力,但是配置却各有差别,需要开发者分别学习,还要注意不混淆,不利于理解,也不利于统一管控。 - -可以发现由于这些问题,我们在落地体系化微服务治理时会有很大的阻力,我们需要的是一个统一的治理界面来让我们更好地做微服务治理,因此我们提出了OpenSergo这个项目。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_4.png) - -而OpenSergo期望提出一套开放通用的、面向云原生架构的微服务治理解决方案及标准规范,来助力保障微服务高可用,上图的四个部分就是OpenSergo社区的愿景。 - -OpenSergo社区会基于业界微服务治理场景与实践抽象成规范,通过这种方式去解决前面提到的概念、配置、能力不统一的问题,并用统一的管控面去承载,降低使用和维护成本。 - -同时在纵向上,我们针对链路上的每一环进行抽象,覆盖完整的场景,在横向上,无论是Java生态,Go生态或是其他语言,无论是传统微服务还是Mesh架构,都会纳入到这套统一的体系中。 - -但是OpenSergo作为一个开放标准,仅凭借阿里是不够的,所以我们联合了多家公司以及社区比如bilibili、中国移动、字节跳动的cloudwego社区等,共同建设这套开放标准,希望能够真正解决微服务稳定性的风险。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_5.png) - -接下来简单介绍一下OpenSergo的架构体系,前面也介绍了OpenSergo社区会基于场景抽象出OpenSergo的Spec,但这只是第一步,为了承载这些标准规范我们就需要一个控制面,社区在一开始的演进中选择从0开始开发一个控制面来做治理规则的管控、监听与下发。 - -但是随着社区的演进,我们发现基于Istion去扩展,成本更低,也能够复用更多的能力,因此在后续的演进中我们会选择结合Istio扩展控制面与决策中心实现治理规则统一管控、治理策略预计算。 - -在有了控制面后我们还需要数据面来进行具体治理能力的实现,它可以是像sentinel这样的中间件,也可以是框架本身。控制面与数据面之间的通讯在初始的架构中是基于grpc构建的链路,但在确定了后续演进方向会基于istio扩展后,社区选择拥抱xds,尽可能服用它的链路,对于一些无法承载的我们再使用自身的grpc链路。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_6.png) - -前面也提到社区控制面的后续演进是基于Istio扩展的,Istio本身也有一些流量治能力,并有着一定的普及度。但是Istio主要关注流量管理,让流量到达该去的地方而不是微服务治理治理,所以在微服务稳定性的场景下,Istio所提供的这些能力是不足以满足我们的需求的。 - -因此我们在Istio的基础上,基于微服务稳定性的一些场景,比如前面提到的变更态稳定性、运行时稳定性去抽象、制定了满足需求的规范标准,希望能够更加贴合微服务场景。所以整体上我们在微服务治理领域会是Istio的超集,而不是互斥关系。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_7.png) - -接下来我们一起看一下OpenSergo的标准规范是如何解决前面所提到的这些场景。 - -首先我们聊一下流量路由,它的主要作用是将符合一定特征的流量路由到指定的workload上,一般大家会用这种能力来实现灰度、同AZ路由等方案。 - -基于 Istio VirtualService/DestinationRule 的格式社区定义了流量路由spec,但我们在调研以及实践的过程中发现,它并不能很好的满足微服务场景下的需求。所以为了更贴近微服务的场景去扩展去做了扩展。比如我们增加了路由失败后的处理逻辑,这在微服务架构中是很常见的需求。 - -又由于Istio主要关注的是HTTP请求,它的CRD不能够很好地承载像Dubbo这样的RPC调用,所以我们为此增加了更多RPC模型的支持。后续我们也会探索与社区标准结合的方案,使我们的Spec更加通用与标准。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_8.png) - -前面所提到的灰度,在阿里集团内部数年的安全生产实践中,与可监控、可回滚一起被定义为安全变更的三板斧,其中灰度是控制变更影响面,保障变更稳定性的必不可少的能力。 - -为了实现灰度,我们通常有几种方案,第一种是物理隔离,我们通过部署两套一样的环境来实现灰度,但是这种方案的部署和维护成本都很高。 - -为了提高资源利用率,便产生了第二种方案,流量灰度。我们不部署独立的环境,而是在流量的每一跳进行流量的特征匹配,并且由此决定去往灰度实例还是base实例,这种方案相较与前者更加灵活高效,可以通过前面提到的流量路由能力来实现。但是需要我们在每一跳都配置路由规则,相对比较繁琐。 - -并且由于有些信息在后续链路是获取不到的,比如uid,导致这个方案的实施有一定的困难。于是便产生了第三种方案,全链路灰度,我们通过在流量入口处进行流量匹配并打上标签,标签会自动沿着调用链路透传,后续链路根据标签来进行路由。通过这种方式,我们就能够更简洁地去定义灰度。Opensergo针对这种场景抽象了对应的CRD。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_9.png) - -我们将这个CRD称之为TrafficLane也就是泳道,我觉得还是比较形象的,大家看一下上边的图片,橙色的是正常的流量走向,灰色的是灰度流量的走向,就像是将一个池子分成了多个泳道。 - -泳道的CRD有三个部分组成,也比较好理解,首先我们需要去匹配灰度流量,所以就要去定义匹配的条件,然后定义为这些流量打上什么标签,最后再定义这个标签以什么方式去透传。 - -通过这样的CRD我们就定义了一条灰度泳道。但是如果只是定义是不足以实现全路灰度的,我们还需要借助OpenSergo体系全链路全方位框架的一个支持,才能让标签在这些框架中自动的透传,这些框架也能通过标签进行路由。其中流量染色和标签透传会借助标准的trcae体系去实现,比如OT。 - -上图右侧是一个CRD的例子,大家可以简单看一下。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_10.png) - -接下来我们一起看一下运行态稳定性的场景。 - -我们主要提两个场景,第一个是流量激增的场景,比如双十一的秒杀活动,一开始流量是稳定的情况下,系统也处于稳态。但是当流量激增的时候,系统就会开始往不稳定的方向发展,异常调用也会激增,最后就会变成不可用的状态。对于这类场景,我们可以用流量控制的能力拒绝超出容量的请求,或是通过流量平滑的能力削峰填谷,让流量处于比较平稳的状态,避免服务的不可用。 - -第二个是不稳定调用导致服务不可用的场景,比如我们调用一些第三方服务经常会出现不稳定的情况,这里的不稳定主要指异常或是慢调用。以dubbo为例,当服务提供方出现慢调用的时候,会导致服务消费方的线程堆积,影响到其他的正常调用甚至是整个服务的稳定性,并且这种风险会沿着调用链反向传递、扩散最终影响整个系统的稳定性。这时我们可以通过并发控制或是熔断保护来限制慢调用对资源的占用,保障系统的整体稳定性。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_11.png) - -针对前面提到的这些场景,OpenSergo也制定了相关的CRD。在业界的实践中sentinel是一个成熟的流量防护方案,在阿里内部积累了大量的流量防护相关的场景和实践,2018年开源依赖在业界进一步丰富了这些积累,我们从这些积累中抽象出了一套流量防护的规范标准。 - -那么一条流量防护的规则应该包含哪些内容,大家可以简单想一下。 - -首先我们要确定的是要针对怎样的流量,我们可以按接口去划,也可以按请求中的特征去划。确定了目标之后,我们就需要定义要采取怎样的治理策略。这里的策略包括了刚才提到的这些策略,以及更高阶的比如自身过载保护等策略。 - -最后由于限流本身是有损的,但是我们不希望这种有损传递到用户侧,因此我们需要为不同的规则配置不同行为,从而使得在用户侧的表现是比较友好的,比如最基本的对于抢购场景的限流,我们可以返回一个排队中,请稍后的提示。 - -上图右侧是一个CRD的示例,流量目标为接口名为/foo的请求,策略为阈值为10的全局限流,fallback为特定的返回体。 - -通过这样的CRD配置,不管是Dubbo框架还是其他框架,我们都能很方便的使用流量防护的能力。 - -## 三、OpenSergo & Dubbo 最佳实践 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_12.png) - -对于框架开发者来说想要接入到OpenSergo的体系中其实有两种方式 - -一种是通过对接OpenSergo体系的数据面来接入,框架开发者只需要实现对接Sentinel的适配模块就可以完成对接工作。而对于有特殊要求或是更贴近特定场景的框架,也可以自行对接OpenSergo的标准,来接入OpenSergo体系。 - -对于用户来说,不管是哪一种方式,都只需要简单地引入一些依赖,就可以无感地获取OpenSergo定义的微服务治理能力,并能在统一的控制面管控这些框架的微服务治理能力,大大提高使用微服务治理的体验与效率。讲完了接入的方式,我们再一起来看下实现的效果。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_13.png) - -第一个实践是全链路灰度控制消除变更态稳定性风险。这是一个简单的demo,我们只需要部署这样的一个CRD,定义/A/dubbo的请求,当它的参数里出现xiaoing的时候,我们就把它导向灰度的环境。可以看到现在的请求走向是符合我们预期的,有灰度环境的就是灰度环境了。对于不符合要求的流量,就还是走基线环境,我们只需要简单的CRD就可以实现。 - -但我们的生产环境会比demo复杂的多,会涉及各种框架,比如RokcetMQ、spring cloud alibabab。但只要这些框架对接了Opensergo的体系,就可以用这一个CRD来做到全链路,全框架的灰度。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_14.png) - -第二个实践是流量防护与容错保障运行时稳定性——不稳定调用场景。这里使用一个简单的Demo,应用A通过Dubbo调用应用B。右侧是一个正常接口和慢调用接口的流量图,蓝色的是总流量,黄色的是拒绝流量,橙色的异常流量。在一开始慢调用还没有发生,系统处于稳态,没有异常流量。 - -在第一个时间点,我手动调整了慢调用接口的RT,慢调用发生,异常流量出现,同时由于慢调用大量地占用了Dubbo的线程资源,导致正常调用的资源受到挤占,同样出现大量的异常流量,Dubbo侧也出现了线程池耗尽的异常。 - -大家可以想一下,这种场景下我们应该配置什么规则来解决这个问题,其实这个时候很多人会想要流量控制来做限流希望能解决这个问题,我们一起看下它的一个效果。 - -在第二个时间我配置了一条限流规则,可以看到情况虽然有所缓解,但是依旧有大量报错,这是因为在慢调用场景下,请求已经出现堆积,仅仅通过QPS限流还是会导致请求涌入进一步堆积。 - -所以我们真正需要的并发控制,在第三个时间点我配置并发控制规则来限制慢调用接口的并发数,也就是正在处理的请求数。可以看到通过这种限制,即便慢调用仍然存在,但是它所能占用的线程资源被限制,正常接口得以正常调用,从而避免稳定性风险的扩展,保障应用的稳定性。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_15.png) - -第三个实践是流量防护与容错保障运行时稳定性——自适应过载保护。可以看到我们的demo在持续的高负载下,异常流量开始逐渐上升,系统的稳态被破坏,这时我们可以通过配置自适应过载保护规则,来自适应地调节限流行为,达到消除异常请求,帮助系统重新回到稳态的效果。 - -目前的策略我们在开源已经支持了BBR,在内部的实践中我们也有用PID。这些策略我就不在这里详细介绍了,大家感兴趣可以去我们的开源社区一起参与讨论。 - -从这三个例子可以看到Dubbo通过对接Sentinel接入OpenSergo体系后就无感地具备了OpenSergo所定义的通用的治理能力,并且能够通过统一的控制平面来管控。 - -而对于其他框架也是一样,可以设想一下如果我们生产上所涉及的所有框架都对接了OpenSergo体系,那我们就可以在一个控制面上管控所有服务,所有框架的微服务治理能力,更好地保障系统的稳定性。 - -## 四、OpenSergo 的未来之路 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_16.png) - -这是多语言服务治理的生态大图。在生态上,我们希望OpenSergo是全链路多语言异构化的,我们会主要关注Java/Go + Gateway + Mesh 生态,在生态上不断去覆盖更多的框架。 - -在能力上我们会不断抽象并落地更多的通用的微服务治理能力。包括流量防护、自愈、服务容错、健全、发现等等。 - -目前我们已经和很多社区建立了联系和合作,比如Dubbo、ShenYu、APISIX、Higress、RocketMQ、MOSN等等,其中也有不少已经有了一些实质性的进展。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_17.png) - -接下来分享一下我们近期的规划。 - -- 控制面方面,我们会逐步推动控制面的生产可用,在明年3月份发布GA版本,让大家能够在生产上去验证微服务治理体系。 -- Spec方面,我们会去支持微服务安全治理、离群实例摘除,并持续地与社区标准集成。 -- 治理能力的演进上,我们会重点完成Sentinel 2.0 流量治理的升级,并在安全和自适应方向上进行探索。 -- 在社区合作上,我们会继续推进与社区间的交流与合作,推进各个微服务治理领域的生态落地,统一控制面、Spec 共建。 - -![dubbo-opensergo-服务治理最佳实践](/imgs/blog/2023/8/apachecon-scripts/opensergo/img_18.png) - -虽然阿里在集团以及云上积累了大量的经验和场景,但稳定性的问题是复杂的,场景是多样的,仅凭一方不足以覆盖所有稳定性的场景,也不足以成为标准,所以微服务治理技术、生态与标准化的演进还需要各个企业和社区的共同参与。 - -大家可以从以下三个方面入手来参与社区。 - -- 微服务治理的spec,各个社区和企业都是各自领域中引领者,大家能从各自的场景和最佳实践出发,一起制定与完善标准规范。 -- 微服务统一控制面的演进,这一块其实有很多的可能性,作为控制面其实它处在一个决策者的位置,一定程度上具备整个系统的上帝视角,在AI技术火爆的当下大有可为。 -- 治理能力与社区生态的贡献,大家可以参与到服务治理能力的演进中,也可以贡献各个社区和OpenSergo体系的对接。 - -最后我想说,微服务治理其实是一个很广阔的平台,参与其中,你可以接触到各个领域的技术与场景,而不是被限制在单点技术范围内摸爬滚打。欢迎企业与社区同学加入开源贡献小组,一起主导下一代微服务技术体系的演进! \ No newline at end of file diff --git a/content/en/blog/news/apachecon2023/ecosystem-seata.md b/content/en/blog/news/apachecon2023/ecosystem-seata.md deleted file mode 100644 index b895d5ec82f5..000000000000 --- a/content/en/blog/news/apachecon2023/ecosystem-seata.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: "One-stop Distributed Transaction Solution in Seata Microservices Architecture" -linkTitle: "One-stop Distributed Transaction Solution in Seata Microservices Architecture" -tags: ["apachecon2023", "seata", "ecosystem"] -date: 2023-10-07 -authors: ["Ji Min"] -description: One-stop Distributed Transaction Solution in Seata Microservices Architecture ---- - -Abstract: This article is derived from the sharing by Ji Min, the product manager of Alibaba Cloud's distributed transaction, founder of the Seata open-source project, and head of microservice open-source governance. The content is mainly divided into three parts: - -* 1. Challenges of Data Consistency in Microservices Architecture -* 2. Architectural Evolution of Seata Distributed Transactions -* 3. How to Extend RPC and Database Based on Seata - -## 1. Challenges of Data Consistency in Microservices Architecture - -![dubbo-seata-distributed-transaction-best-practice](/imgs/blog/2023/8/apachecon-scripts/seata/img.png) - -In 2019, during the Dubbo Ecosystem Meetup, we collected over 2,000 survey responses regarding the core issues developers are most concerned about in microservices architecture, with distributed transactions accounting for the largest share at 54%. - -However, before Seata, it was commonly said that distributed transactions should be avoided, as eventual consistency addressed the issues. But after Seata became open-source, these problems were resolved. For me, the ultimate concern is data. Regardless of how the front-end business interacts, it ultimately boils down to data. If the business data is inconsistent, the underlying architecture is less meaningful, hence data is the core asset of an enterprise. - -![dubbo-seata-distributed-transaction-best-practice](/imgs/blog/2023/8/apachecon-scripts/seata/img_1.png) - -So what scenarios will encounter distributed transaction issues? - -The first scenario is that after splitting into microservices, different services may be managed by different teams causing inconsistencies during service publishing. - -The second scenario involves unreliable or unstable infrastructure, which leads to network failures or individual host outages. - -The third scenario is timeouts in distributed architectures, as service call timeouts raise questions about the execution of the business logic and data consistency. - -The fourth scenario involves the integration of third-party components, such as caches and Redis, leading to consistency challenges. - -The fifth scenario appears when the parameters passed between services are invalid, requiring the upstream service to reject the invalid input. - -Overall, distributed transaction scenarios involve cross-database, cross-service, and resource diversity, with exceptions including business and system anomalies. - -Is distributed transactions a problem unique to microservices architecture? Not really; it also exists in monolithic applications, although it is more pronounced in microservices. - -In monolithic architecture, scenarios include modifying multiple databases or modules. Essentially, local transactions within a monolithic database can lead to distributed transaction issues when crossing local transaction boundaries. - -Distributed transactions encompass extensive applications across both distributed and monolithic architectures. - -![dubbo-seata-distributed-transaction-best-practice](/imgs/blog/2023/8/apachecon-scripts/seata/img_2.png) - -There are six types of distributed transaction solutions available in the market: - -- XA model, which has lower throughput and performance but the highest level of consistency. -- TCC and SAGA models, which represent business-level distributed transactions; they do not intercept data. -- Eventual consistency, which allows for decoupling and asynchronous operation but has rollback issues. -- Compensating scheduled tasks, which have low learning costs but high practical costs. -- AT model, which balances consistency and performance, is easy to learn but may have restrictions. - -## 2. Architectural Evolution of Seata Distributed Transactions - -![dubbo-seata-distributed-transaction-best-practice](/imgs/blog/2023/8/apachecon-scripts/seata/img_3.png) - -Seata is internally codenamed TXC at Alibaba and DTX at Ant Financial. Its origin lies in the group’s Rainbow Stone project, which transitioned from monolithic to distributed architecture. TXC serves as a guarantee for service consistency. - -We deeply integrated with three key components in the group: the service invocation framework HSF, the TDDL component for database sharding, and MetaQ for asynchronous messaging. - -Currently, Seata is used widely with billions of daily calls and can handle around 100,000 TPS on a standard three-node cluster. - -Our SLA offers availability and performance guarantees, ensuring that additional overhead for each transaction does not exceed specified limits. Transaction processing can reach millisecond levels, ensuring stability year-round. - -![dubbo-seata-distributed-transaction-best-practice](/imgs/blog/2023/8/apachecon-scripts/seata/img_4.png) - -Initially, we considered at which level to implement distributed transactions. - -From an application architecture perspective, there are several layers, including the application development framework, service invocation framework (like Apache Dubbo), data middleware (ORM frameworks, transactions), and database connectivity (like JDBC). - -We compared where to implement distributed transactions—at the DB level, data middleware level, or application framework level. - -At the application framework level, consistency is relatively weak due to various uncontrolled factors, such as service invocation timeouts, which introduce uncertainty. - -In the data middleware layer, consistency is better than in the application framework, though there can still be issues with concurrent transactions because it is not at the DB layer. - -The best consistency is at the DB layer, but it is often vendor-specific. A significant challenge is coordinating data consistency across services. - -We designed the AT model to operate at the database middleware level while aligning with the application development framework. - -The theoretical model was initially underdeveloped, so we extended existing models like Spring's transaction model to lower developers' learning costs. - -Additionally, we defined how to establish consistency, whether across nodes or within business application data. - -![dubbo-seata-distributed-transaction-best-practice](/imgs/blog/2023/8/apachecon-scripts/seata/img_5.png) - -What is the model definition of distributed transactions? For example, during a bank transfer, if a network timeout occurs, it's uncertain whether the funds were deducted, which could lead to asset loss or damage to the company's reputation. - -We often discuss distributed architecture, but not everything is inherently distributed. The totality of application architecture, including what today is called a distributed database, appears as integrated data storage. - -In a distributed architecture, each business node only has partial information, necessitating integrated solutions for troubleshooting. The core of distributed transactions is coordination, requiring global awareness. - -This is where the Transaction Coordinator comes into play, acting as a third-party coordinator with a "God perspective." Resource Managers do the actual work, while Transaction Managers execute transaction actions along the business execution chain. - -![dubbo-seata-distributed-transaction-best-practice](/imgs/blog/2023/8/apachecon-scripts/seata/img_6.png) - -Seata went open-source in January 2019, starting with the AT model. By version 0.4, TCC was added to supplement compatibility with various databases. - -In version 0.9, we integrated the Saga transaction model to address long transaction scenarios. Version 1.1 introduced XA transaction models for clients using Seata's AT model needing a unified solution across diverse business transactions. - -Ultimately, we developed a one-stop distributed transaction solution. Seata's versatility across different business scenarios has no equal in current distributed transaction solutions, addressing synchronization and asynchronous needs for diverse consistency requirements. - diff --git a/content/en/blog/news/apachecon2023/graalvm-native-image.md b/content/en/blog/news/apachecon2023/graalvm-native-image.md deleted file mode 100644 index a656e7ec8c1f..000000000000 --- a/content/en/blog/news/apachecon2023/graalvm-native-image.md +++ /dev/null @@ -1,225 +0,0 @@ ---- -title: "启动速度提升10倍:Apache Dubbo 静态化 GraalVM Native Image 深度解析" -linkTitle: "启动速度提升10倍:Apache Dubbo 静态化 GraalVM Native Image 深度解析" -tags: ["apachecon2023", "native image", "dubbo aot"] -date: 2023-10-07 -authors: ["华钟明"] -description: 启动速度提升10倍:Apache Dubbo 静态化 GraalVM Native Image 深度解析 ---- - -摘要:本文整理自杭州有赞科技有限公司中间件技术专家、Apache Dubbo PMC华钟明在 Community Over Code 2023 大会上的分享。本篇内容主要分为五个部分: - -- 一、GraalVM 直面Java应用在云时代的挑战 -- 二、Dubbo 享受 AOT 带来的技术红利 -- 三、Dubbo Native Image 的实践和示例 -- 四、Dubbo 集成 Native Image 的原理和思考 -- 五、Dubbo 在 Native Image 技术的未来规划 - -## 一、GraalVM 直面Java应用在云时代的挑战 -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img.png) - -云计算时代比较显著的特点包括: - -- 基于云计算的基础设施,Java应用能够在云计算的基础设施上快速、轻松、高效的做到弹性。 -- 基于容器化技术,系统资源切分的更加细,资源的利用率也更高了。 -- 基于云计算的开发平台,让应用部署的更加容易,更加敏捷。 - -那么在云计算时代,Java应用存在哪些问题呢? - -- 冷启动速度较慢。 -- 应用预热时间过长,无法立即达到性能峰值。 -- 内存、CPU等系统资源占用高。 -- Java构建的应用程序繁重,执行还需要具备JDK环境。 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_1.png) - -在Serverless场景上,Java的问题会尤为突出,因为Serverless不仅能简化开发场景和开发体验,还能做到极致的弹性,甚至是秒级的弹性。 - -上图是Datalog统计的Fast和AWS两个产品。Java语言虽然更流行,但相较于Python和Node.JS,它的占比还是比较低的。Java本身在Serverless层面,比如在做容器的调度、镜像的下载的时候,启动时间、冷启动的时间、预热时间等等,都会影响Serverless场景下它弹性扩容的时间。 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_2.png) - -下面介绍一下GraalVM,它是可以把Java应用提前编译到独立的二进制包内,这些二进制包相对于跑在JVM上它可以更小,更快的启动,不需要预热就能够达到极限的峰值,还可以减少内存和CPU的占比。 - -可以看到它的介绍和Java语言的应用所涉及到的问题都一一对应。GraalVM应该算是JDK的"超集",除了包含完整的JDK发行版本外,还有GraalVM Compiler、Native image、Truffle等,甚至还涉及到多语言汇编的能力。 - -总结一下,GraalVM本身涉及两部分,JIT和AOT。 - -- JIT,是在编译后的class文件、字节码文件,它会在运行时把它翻译成机器码。 -- AOT, 它和JIT的区别是,它在编译期就能把字节码直接转化为机器码,无需在运行时再去处理。所以它的CPU和内存会相对更低。 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_3.png) - -上图左侧是一张Java生命周期的全景图。可以看到,它从JVM的启动,再到Java的main函数的启动,再到Java的应用预热,再到它的稳定期,最后到达效果,这是Java完整的生命周期的呈现。 - -而AOT的区别在于,它没有红色的VM。另外,JIT相对于AOT而言是没有的,也没有浅绿色的解释器。所以AOT对于JIT来说,只有内加载,GC以及它能够瞬间达到应用的稳定期。 - -根据右侧的图可以看出: - -- AOT的启动耗时相对较低,内存损耗和它打出来的二进制包相对较小。 -- JIT因为有及时编译的效果,所以现在极限的分值比AOT要好,比如它的极限吞吐量比AOT好。 - -## 二、Dubbo 享受 AOT 带来的技术红利 - -1. 多产物形态 - -![dubbo-graalvm-native-image.png](/imgs/blog/2023/8/apachecon-scripts/native/img_4.png) - -我们在编码之后,Soft Code的产物形态新增了。 - -第一种是我们传统认知上的Jar包形态,比如mvn、clean、package。第二种是Docker Image,它能轻松的帮我们直接打到镜像里面去,不用写dockerfile等文件。第三种是我们集成GraalVM后新产生的一种Native可执行文件的形态。这种形态无需JDK的环境就能启动,它能像GO一样把二进制文件直接启动。 - -2. 启动耗时大幅降低 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_5.png) - -上图的跑分都是基于4c16g的micro24的系统上跑出来的。左边和右边的区别是,左边的Provider端提供了一个Dubbo服务跑出来的,右边是提供了一个调用者的身份跑分出来的。从左边这张图可以看到,Native的可视性文件比Jar包方式的启动耗时降低了12倍+,在客户端应用,它的启动耗时降低了11倍+。所以在刚刚提到的Serverless场景上,它能提供一个非常好的启动速度。在扩容的时候能够达到秒级,甚至达到毫秒级。 - -3. 启动后立即达到性能峰值 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_6.png) - -上图也是跑分跑出来的数据,可以看到Consumer和Provider端通过静态化执行文件执行后,比都为Jar包的情况,第一次调用的耗时降低6倍。这第一次调用代表的是预热的时长,以及第一次需要解析的类,包括资源的情况等等。这让我们在Serverless场景下能够瞬间达到性能峰值。 - -4. 内存损耗大幅降低 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_7.png) - -上面有左右两张图,在Dubbo应用的基础上,它的内存损耗也降低大概3.5倍。Native静态化执行文件可以做到60M的内存占比,在客户端它的内存损耗也大概降低了4倍。 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_8.png) - -这是Dubbo在Native Image技术场景中做的努力: - -- 易用性增强:在注解和XML方式中自动识别服务接口,生成Reachability Metadata。 -- 可维护性增强:自动生成Source code,减轻了Dubbo开发者维护Adaptive的维护成本。自动扫描生成Dubbo core 所需的Reachability Metadata。 -- 多平台的支持:Linux、MacOS、Windows。 -- 多功能的覆盖:Dubbo、Triple协议。 - -## 三、Dubbo Native Image 的实践和示例 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_9.png) - -首先需要安装Dubbo Native Image,这里就不过多介绍了,大家可以根据官方的文档进行下载。 - -然后安装插件,可以看到上图中有三个插件需要安装,但和Dubbo相关的只有一个,是Dubbo Maven Plugin。除此之外,还有Spring Boot 的Maven Plugin,它提供的是Spring的AOT的能力。如果是API的接入方式我们无需加这个插件,如果是XML和注解就还需要加这个插件。第三个是GraalVM提供的插件,可以看到这里加了一个reachabilitu-metadata的执行,这个后面会介绍到。 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_10.png) - -然后配置依赖,现在Dubbo关于可达性元数据的扫描、执行,以及配置文件和Source code的生成都在Dubbo Native的依赖下面,我们需要引入这个依赖。 - -另外,注解和XML的还是需要接入一个Spring6的兼容的包。因为Dubbo现在还兼容JDK 8的版本,而Spring6发布后支持的最低版本是JDK 17,所以我们还是需要有这么一个模块做一下兼容。 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_11.png) - -最后还需要加一个插件和依赖,然后就能轻松的把应用转化成Native Image的形式。 - -最下面是完整的代码示例,大家感兴趣的话,可以尝试一下编译打包,看一下执行的效果。 - -## 四、Dubbo 集成 Native Image 的原理和思考 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_12.png) - -首先看一下Dubbo集成GraalVM Native Image技术的发展历程。2021年6月我们发布了Dubbo 3.0版本,初步探索了Native Image技术,提供了一个实验性的版本和Demo,涉及到的问题包括以下三个。 - -- 维护繁重的Adaptive源码、维护Dubbo所需的全量Reachability Metadata。可能涉及到的问题是,比如要新增一个功能,我们需要考虑coding以及code review的时候是否要添加可达性的元数据,这也会造成维护成本非常高。 -- 仅支持API方式,不支持注解和XML方式。 -- dubbo-native-plugin的插件,在后面3.1版本的时候,Native Image的发展并不多。 - -2022年11月Spring6+Spring Boot3正式发布了,它把Native Image技术作为发布的亮点展现给大家。但Dubbo社区认为我们应该对Native Image技术有一个新的跨越,所以在2023年4月发布了Dubbo 3.2版本,将Native Image技术进行了思考和重构。支持以下四个方面: - -- 编译阶段自动生成Adaptive源码,已经不需要开发者维护了。 -- 支持编译阶段自动生成Dubbo所需的Reachability Metadata。减小了打在业务启动的可执行文件里包的大小。因为在之前的版本里,它是把Dubbo所涉及的全量的可达性的元数据都打在二进制包里。比如业务用jka作为注册中心,我们把nacos也打在那里面,这就会导致它的二进制包非常大。现在这个版本如果用到jka,我们在box上解析不到nacos相关的依赖。所以我们就不会再把相关的内容打进去了,而且现在都是自动识别的。 -- 新增dubbo-maven-plugin,用于替代dubbo-native-plugin。因为dubbo-native-plugin的能力和内容是比较聚焦的,我们把它重新归名为dubbo-maven-plugin后,涉及到的是我们能够降低业务接入的心智负担。后面Dubbo相关的maven插件,都通过它来做就行了。 -- 兼容了Spring6+Spring Boot3,这就是我们在下个版本把XML和注解支持上去的技术的基础。 - -2023年12月将会发布Dubbo 3.3x版本。它基于Spring6,完成对XML和注解方式的支持,还移除了dubbo-native-plugin。 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_13.png) - -刚刚提到了非常多次Reachability Metadata可达性的元数据,到底是什么呢? - -我们先来聊一聊AOT的局限性,它本身就有局限,它遵循封闭世界的一个假设。比如它只关注能看到的所有字节码的信息,这就会带来一个问题,Java动态语言的功能就不再支持了。也及时说JNI、Java反射、动态代理、ClassPath资源的获取等都不再支持。 - -我们知道,在组件/业务开发/使用产品上涉及到的这些功能是非常多的,既然GraalVM出了这个功能,当然也考虑到了这个问题,所以它利用Reachability Metadata的能力解决了这些问题。 - -右边的这张图分为了五类,它涉及到了JNI、反射、序列化、resource、proxy相关的元数据的配置信息。它可以让开发者在编译前就提供好这些元数据信息,提前打包到可执行的二进制文件中。还有第六种分类,是预定义的类型,他需要提供完整的字节码Hash值,所以就没列出来,它可能需要和Tracing的agent联合起来使用。 - -下面我们主要介绍一下这五类。 - -第一,GraalVM 提供了Tracing Agent来辅助应用采集Reachability Metadata,也就是说在运行期间它会去采集你的行为,比如你要用到反射,他会把反射的元素自动生成出来,然后生成出一个配置文件提供给你。但是并无法确保把所有都采集完整。 - -第二,GraalVM提供了Reachability Metadata Repository,用于管理三方组件的Reachability Metadata。我们在Java反射、动态代理这种纯业务的场景,用的相对较少,在运用到组件中相对多一点。举个例子,比如Native里用到反射,我们可以在仓库中直接找到Native反射的metadata。然后通过刚刚提到三个插件中的Native自身提供的插件,它会把仓库里的元数据直接打在二进制包里,我们也就不需要关心这些公共组件的元数据信息了。 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_14.png) - -和Dubbo相关的元数据信息包括以下五类: - -第一,反射的元数据。 - -- 内外部的service。我们知道Dubbo是rpc框架,所以定义服务接口是最通用的一种能力。内部提供的服务包括metric service、metadata service,用户服务就是业务定义的服务接口。 -- SPI扩展。Dubbo的扩展能力得益于自己建的一套SPI机制。 -- 多实例。 -- 配置相关的内容。 -- 业务上自己用到的反射的行为。 - -第二,resource的元数据。如果业务上要做扩展,配置文件,resource的元数据主要涉及的就是META-INF下的三个路径。此外,还有一个是在Dubbo 3里支持对安全性的增强,序列化的黑白名单的resources的配置。 - -第三,序列化的元数据。作为rpc调用的框架,它的接口定义、方法定义、内外部分的服务、parameter、请求参数、返回类型等都需要用到序列化的接口。 - -第四,动态代理的元数据。在传统的rpc框架里动态代理是用的比较多的产品。内外部分服务的引用就是代理的元数据。 - -第五,JNI的元数据,暂时没有用到。 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_15.png) - -这是Dubbo 相关的 Reachability Metadata 总结和处理策略,我们把它分为了四类。 - -- 规律性的内容,是刚刚提到的Adaptive Source Code的生成。 -- 确定性资源和行为,是Dubbo内部的扩展以及资源的配置。 -- 不确定性的资源和行为,是业务自定义的扩展实现以及定义的服务。 -- 集成和依赖的组件,比如刚刚提到jka是其他社区的生态,它涉及到注解的元数据信息,我们会提供官方的支持,还会提供内部的适配逻辑。 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_16.png) - -这是AOT的执行流程。可以看到它的源码在编译之后,它的区别是它会从main函数开始启动Java应用进程,然后去找所有的source code和Bean的元数据信息。 - -下面是Spring Server自动生成的一个source code,它会把它生成一个Bean定义的获取的类。 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_17.png) - -而Dubbo并不是从main函数启动的,它启动了一个扫描的进程,把确定性的、不确定性的元素以及规律性的内容扫描进来,自动帮大家生成元数据信息。 - -下面是用Dubbo service生成后的一些信息。 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_18.png) - -上图是Spring本身提供的一个产物的内容以及Dubbo的AOT产物的内容。可以看到Dubbo下面是Adaptive的一些source code。最后Native在执行的时候会读取到这里所有的配置。 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_19.png) - -这是Dubbo和AOT之间的边界,可以看到API的接入方式和注解、XML的接入方式是有所区别的。注解和XML借用了Spring AOT的能力,包括ServiceBean、ReferenceBean等等,而Dubbo AOT的能力主要是自身的元数据的生产。 - -## 五、Dubbo 在 Native Image 技术的未来规划 - -1. 提升开发者体验&开发效率 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_20.png) - -Dubbo在3.0之后提供了CTL、脚手架、IDEA插件,Dubbo Native Image目前还在建设中,之后也会加进去。此外,还有一些文档的建设。 - -2. 性能优化与提升 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_21.png) - -刚刚已经分享了很多内容,但还是有很多可以做的事情。在GraalVM提供的能力上,我们还可以把一些类相关的可达性的配置加上去,产生作用之后能让最后打出来的二进制包更小,编译时间更短。 - -3. 覆盖更多的组件 - -![dubbo-graalvm-native-image](/imgs/blog/2023/8/apachecon-scripts/native/img_22.png) - -因为目前很多组件都还不支持,所以我们现在的主要思路是把Dubbo主仓库的扩展性支持完成,然后再往wpi的扩展上做相应的支持。 - -另外,内核所需要的可达性的元数据,我们会把它推到program的可达性的元数据的仓库上面去,让业务开发能够正常使用大陆内核里的元数据信息。 - -最后我们的思路还是优先考虑GraalVM官方的支持。 diff --git a/content/en/blog/news/apachecon2023/observability.md b/content/en/blog/news/apachecon2023/observability.md deleted file mode 100644 index 498c089f3aa5..000000000000 --- a/content/en/blog/news/apachecon2023/observability.md +++ /dev/null @@ -1,165 +0,0 @@ ---- -title: "Exploration and Practice of Cloud Native Observability in Apache Dubbo" -linkTitle: "Exploration and Practice of Cloud Native Observability in Apache Dubbo" -tags: ["apachecon2023", "observability", "metrics", "tracing"] -date: 2023-10-07 -authors: ["Song Xiaosheng"] -description: Exploration and Practice of Cloud Native Observability in Apache Dubbo ---- - -Abstract: This article is organized from the sharing of Song Xiaosheng, a senior engineer at Ping An Yiqian Wallet and an Apache Dubbo committer, at the Community Over Code 2023 conference. The content is mainly divided into five parts: - -- I. Building Observability -- II. Multidimensional Metrics System -- III. Link Tracing Interface -- IV. Log Management and Analysis -- V. Stability Practices - -## I. Building Observability - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img.png) - -First, let's talk about the challenges of cloud-native upgrades. Most companies currently have CICD and OPS to help improve development efficiency and quality, along with containerization for operational efficiency. However, the frequent changes in large-scale containers during the cloud-native era can lead to numerous stability issues. These issues may include known exceptions that we can avoid in advance as well as unavoidable ones like network failures and machine crashes. - -If we can detect these issues early, we can mitigate many risks. Thus, having an observability system that timely senses these problems, analyzes anomalies effectively, and quickly recovers the system is of paramount importance in the cloud-native era. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_1.png) - -As a microservices RPG framework, it is unrealistic for Dubbo to build a comprehensive observability system or platform, and its functionality does not fit that either. The observability system emphasizes correlation through single or multidimensional observation for diagnosing system issues. - -First, let's look at the metrics that measure the health status of the system. Dubbo exposes internal metrics data to external monitoring systems while also collecting internal Dubbo metrics. These monitoring metrics include a lot of application information, host details, Dubbo service tags, and so on. When issues arise, we can use these tags to trace back to the full link system. Then, the entire link system can perform request-level or application-level performance analysis and abnormal diagnostics. - -Dubbo supports exporting data to major link platforms with minimal dependency through adaptations to various vendor interfaces. Regardless of the popular platform enterprises choose, after upgrading Dubbo, they can export the links directly. - -Additionally, the link system includes full link Trace IDs or local disk IDs. Through these IDs, we can directly navigate from the link system to the logging platform, which contains detailed log contexts that can provide precise anomaly diagnostics. - -Dubbo also provides a detailed error code mechanism and expert advice in the form of logs, allowing users to navigate to help documentation on the official website using error codes. - -## II. Multidimensional Metrics System - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_2.png) - -In the practice of the multidimensional metrics system in Dubbo, we mainly look at it from two dimensions. - -The first is the vertical dimension. There is an access and export process when collecting Dubbo metrics. Dubbo provides an easy-to-use access interface for users and developers. Once accessed, the service collects metrics during its operation through the metrics collectors. Dubbo offers many metrics collectors, including aggregate and non-aggregate metrics. - -The collected metrics are temporarily stored in memory. Some metrics (like QPS with sliding window min/max aggregation metrics) will be aggregated for calculation before export to external systems. We support metrics export in the Dubbo QPS service quality or direct queries via HTTP. - -The second is the horizontal dimension. Dubbo metrics collection covers areas where anomalies are likely to occur. For example, Dubbo 3 provides three primary centers: the registry, metadata, and configuration centers, where external network interactions are prone to issues. - -Another key aspect is RPC circuit sampling, such as request response time, exceptions, unit network, IO metrics, and other related metrics from Dubbo thread pools. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_3.png) - -Earlier, we discussed a broad overview of metrics collection; we also researched various popular methodologies to identify which metrics should be collected in Dubbo. - -- The first image represents the four golden metrics summarized in Google's SRE book. These metrics help measure service quality at the request level, mainly including latency, traffic, errors, and saturation. -- The second image shows the RED method, emphasizing requests and viewing service health from an external perspective, including rate, errors, and duration. -- The third image depicts the USE method, focusing on internal resource usage, including utilization, saturation, and errors. - -It can be seen that all three methodologies include error metrics, which are a significant concern for developers. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_4.png) - -We have completed the system refinement of the metrics. In Dubbo 3.2, the multidimensional metrics system is now finished and is undergoing rapid continuous iteration. In this version, a quick integration Spring Boot starter package allows automatic metrics collection. Accessing it can be done via Dubbo's QPS service quality port. If local, it can be accessed through the browser; on the server, it can be accessed using cURL on port 52 with a Metric path, providing detailed default metrics export. - -These metrics are prefixed with "Dubbo," with different types reflecting various Dubbo modules, such as consumer-provided request levels across the three registration centers. - -The following shows the behavior of current Dubbo metrics; for example, the response time will include some units, referencing the official Prometheus format. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_5.png) - -Some may directly reuse the default manager port in Spring Boot; Dubbo has adapted the Spring Boot Actuator extensions. The operation is the same—simply introduce the Spring Boot starter package. There's no need for any additional configuration to view detailed metrics in the Spring port, including built-in JVM metrics and Dubbo metrics. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_6.png) - -After integrating the metrics system, if accessed through the command line, one can only see instantaneous data. However, in the monitoring metrics system, we are more concerned with multidimensional vector data. If we treat these data as points, it may be difficult to identify issues, so we need to store this data and view it as applicable vector data. - -Dubbo provides default integration for Prometheus metrics collection. Prometheus, as a monitoring system integrating metric storage and monitoring, offers numerous service discovery models. For example, if services are deployed on K8s, metrics can be collected based on K8s label service discovery mechanisms. If a company has a self-built CMDB system, it can extend HTTP interfaces for metrics collection. Besides, files or static service discovery mechanisms can also collect metrics as long as they can discover Dubbo service IPs and service interfaces. Collected metrics will be automatically stored in Prometheus's actual database. - -The above image shows the latest response time metrics collected through Prometheus's query interface. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_7.png) - -Prometheus metrics emphasize storage and alerts, but for more visual representations, we need to incorporate Grafana. Grafana aims to provide easy-to-access monitoring dashboards for enterprises, as shown in the simple global dashboard image above. - -By filtering at the application level / querying by machine IP / and examining service interface dimensions, we can check the service health status. The metrics are generally based on previous methodologies, including QPS, request count, success rate, failure rate, and request delay, among others. - -Additionally, some application information metrics are available, such as when upgrading to Dubbo 3, allowing users to see which applications have been updated to the new version, the new application version numbers, instance IP distributions, and resource availability. - -## III. Link Tracing Interface - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_8.png) - -The metrics previously mentioned are relatively abstract, aiding in problem discovery; next, we will conduct simple problem diagnostics. Microservice systems often have interdependencies, so diagnostics between services rely heavily on a full link system. - -For full link systems like Dubbo, the Agent approach was considered, making it convenient for users to integrate, as some metric collection methods could be injected directly at the proxy layer. This makes full link coverage in enterprises quite simple; however, if Dubbo only collects its own metrics, associated risks could arise. After agent integration, issues like bytecode modification incompatibilities could occur, which might be challenging to identify early. - -Moreover, Dubbo has researched some open-source link tracing interfaces. Dubbo chose to use a native built-in interface, allowing professionals to handle specialized matters. By adopting various vendor-based full link tracing systems, Dubbo enables rapid adaptation for users with minimal configuration changes for exporting link data. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_9.png) - -In the selection of link tracing interfaces, we referred to several popular industry options and selected two for further evaluation: OpenTelemetry and Micrometer. - -OpenTelemetry is well-known; it supports multiple languages with a unified API and integrates with most popular third-party full link tracing systems. It is one of the CNCF incubated projects, with many middleware applications already adopting this standard. - -Micrometer, on the other hand, is often associated with metrics collection integration. Its major limitation is Java-only support; however, it provides the default metrics collection and link collection support via micrometer-tracing in Spring Boot 3. Additionally, Micrometer can convert to open protocols through bridging packages, indirectly supporting various third-party data collection frameworks. Micrometer itself also adjusts many full link vendor mechanisms through its tuning mechanism. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_10.png) - -To unify with the previously used metrics collection, utilizing Micrometer eliminates the need to introduce additional third-party dependencies; simply using the Micrometer Tracing bridge package allows for rapid integration. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_11.png) - -The above image illustrates the simple structure of the link tracing system. Dubbo's edge collection primarily gathers RPC request traces. When a consumer triggers a request, if a link ID exists, it will be reused; if not, a new link ID will be generated and reported to the collector. Similarly, consumers will relay link data through RPC context to the provider. The provider will then associate this link data with a parent-child relationship before reporting it to the collector. - -The collector initially operates at the memory level, minimizing system performance impact. Asynchronous exports will follow, similar to the aforementioned metrics system, with synchronous collection in memory exporting data asynchronously to third-party link systems. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_12.png) - -Integrating link systems is straightforward and primarily involves introducing the Spring Boot Starter dependency package and simple configuration, including details like different vendor export addresses. - -Link systems can assist in analyzing performance and anomalies; however, some issues in system diagnostics may require more detailed log contexts. In such cases, the link system appends data to the MDC log system context, extracting link content from the log context to present it in log files. - -Log files may also interface with third-party log platforms; if you possess secondary development capabilities, you can embed links allowing the Trace ID to automatically redirect—enabling seamless navigation between the full link system and the logging platform, making issue queries far more efficient. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_13.png) - -The above image presents the integration page for Zipkin. It illustrates application-level performance analysis and interface-level performance evaluations. Additionally, we can see some Dubbo metadata; its tags can be associated with metric dashboard metrics. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_14.png) - -This depicts Skywalking's format, featuring both list and tabular forms. It utilizes Trace IDs to uncover full link request paths, along with performance and anomaly diagnostics. - -## IV. Log Management Analysis - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_15.png) - -Dubbo adapts to major logging components through logs. Due to the many systems stemming from our log components' historical development, Dubbo has adapted various logging components via its interfaces. - -Areas prone to issues during system operation include service registration and discovery, the registration model for services, service provider registrations, service consumer subscriptions and notifications, and RPC request links. - -When these issues arise, the system may experience exceptions. Directly checking exceptions, searching online, or analyzing through source code can be both difficult and time-consuming. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_16.png) - -In light of this, Dubbo has created an expert advice document. After upgrading to Dubbo 3, users will find a help document in log entries' SQ links, providing potential reasons for issues and problem-solving approaches. - -For those interested in diagnostics, please refer to the official website, which contains numerous problem diagnosis methodologies from seasoned experts, aiming to collaboratively build with community users and developers. - -## V. Stability Practices - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_17.png) - -Finally, we will introduce stability practices combining metrics, links, and logs—primarily divided into two sections: observing system anomalies and rapid recovery. - -Observing system anomalies involves having operations personnel monitoring dashboards, actively discovering alerts, alongside passive notifications via email, SMS, or WeChat. Regardless of the alert format, upon receiving an alert, observable thinking can be applied to investigate common indicators associated with the anomaly. - -Through this approach, you might discover certain issues, though these may not necessarily be root causes. In such cases, identify the section of the full link system where the metrics have shown issues, subsequently analyzing the specific problem. - -If the issue remains elusive, you can link the full link ID from the link system to the logs to examine detailed reasons. If logs fail to illuminate the issue, root cause analyses using tools may be necessary after isolating the system traffic. - -![dubbo-observability-metrics-and-tracing](/imgs/blog/2023/8/apachecon-scripts/observability/img_18.png) - -With the earlier cause identification, locating the problem becomes straightforward. Based on these findings, traffic governance can be implemented—such as switching room traffic, limiting traffic, or rolling back the system if anomalies arise. - diff --git a/content/en/blog/news/apachecon2023/triple-to-connect-frontend-and-backend.md b/content/en/blog/news/apachecon2023/triple-to-connect-frontend-and-backend.md deleted file mode 100644 index ea62748d433b..000000000000 --- a/content/en/blog/news/apachecon2023/triple-to-connect-frontend-and-backend.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: "Web Mobile Backend Integration Based on Triple" -linkTitle: "Web Mobile Backend Integration Based on Triple" -tags: ["apachecon2023", "triple", "protocol"] -date: 2023-10-07 -authors: ["Chen Youwei"] -description: Web Mobile Backend Integration Based on Triple ---- - -Abstract: This article is compiled from a presentation by Momo R&D engineer and Apache Dubbo PMC Chen Youwei at the Community Over Code 2023 conference. The content is mainly divided into four parts: - -- 1. Developing Microservices with RPC Protocols -- 2. The Newly Upgraded Triple Protocol -- 3. Developing Microservices with Triple Protocol -- 4. Governance Capability of Dubbo for Triple Protocol - -## 1. Developing Microservices with RPC Protocols - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img.png) - -When we normally develop microservices, traditional RPC services may be at the bottom layer. The upper layers may include browsers, mobile devices, external servers, internal testing, curl, etc. We might use an external server like Tomcat to assemble our RPC layer, which is also known as BFF. Alternatively, if we don't have a BFF, our RPC directly provides services. However, since browsers need to access it, we require a gateway, such as Apisix or ShenYu HTTP gateway. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_1.png) - -The above figure shows our process, but there are some issues. - -If our service is lightweight, needing only a forwarding layer can be troublesome. Whether it's setting up a gateway or starting a web server for forwarding, it can be quite complicated. - -Additionally, most RPC services are binary-based, which cannot be tested locally. Hence, our company might develop some background or intermediary processes to facilitate our testing. However, this requires deployment to a testing environment, thus still not allowing for local testing. - -Overall, these two issues make ease of use quite low and development costs relatively high due to repetitive tasks. - -## 2. The Newly Upgraded Triple Protocol - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_2.png) - -Addressing the above two problems, let's introduce the Triple protocol. - -First, let’s mention why the previous generation protocol was developed. We all know Dubbo originally used the Dubbo protocol, which is TCP-based and has a specific package design. This design limits the gateway's ability to perform special rule judgments and filtering operations. While it is possible to sacrifice performance to fully unpack the package, reassemble it, and then transparently pass it through, most people are not willing to compromise on performance. - -So we wondered if we could separate the original data from the actual package. We now have an existing HTTP and a mainstream gRPC, so our goal is to be compatible with gRPC. gRPC currently uses IDL, which poses problems, especially on the Java side. The complexity arises from writing interfaces and defining packages, making it cumbersome. The Go side is more manageable as developers are accustomed to this development model. - -Thus, we developed the Triple protocol, which is fully compatible with gRPC, allowing complete interoperability with gRPC. Additionally, we’ve introduced self-defined interface methods, sacrificing some performance for increased ease of use, as RPC is generally not the bottleneck for business; most bottlenecks are still found in the database. - -However, there's one more issue: although we support gRPC, it is based on TPC, so if the front-end or other third-party systems only use HTTP, they still cannot accept our system. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_3.png) - -To address all of the above issues, we aim to launch a brand new Triple protocol. We reference various protocols such as gRPC, gRPC Web, and general HTTP to facilitate browser access, support Streaming, and run simultaneously on HTTP/1 and HTTP/2 protocols. Currently, HTTP/3 has not been widely adopted, but we will support HTTP/3 in the future. - -The final design is entirely based on HTTP, making it friendly for both human users and developers. We can access it through simple browser requests or curl, especially for unary RPC. Furthermore, we have complete interoperability with gRPC, meaning HTTP traffic does not have to worry about compatibility issues or protocol signing issues. For stability, we only use popular industry networking libraries like Java's Netty or Go's basic net package. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_4.png) - -Although both the Triple and gRPC protocols are based on HTTP, gRPC operates on HTTP/2, while Triple works on both HTTP/1 and HTTP/2. - -As we entered the gRPC space, we extended some functionalities for ease of use. For instance, we support application JSON, curl access, and in the previous protocol, we supported a secondary serialization process for traditional interface definitions. Here, we aim to use a special tag to define the structure of our body, resolving the secondary serialization issue. Moreover, this feature is extensible, so theoretically, any future HTTP functionalities can be implemented within the Triple protocol. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_5.png) - -With the introduction of the Triple protocol, our development process has also transformed. If you don’t require assembly or there’s no external proxy, your access process may go directly from external requests (browser, other servers, curl, internal testing) straight to the server. - -Communication with other gRPC services poses no problem, and the process effectively eliminates a layer. For most users who don’t need this scenario, it brings substantial advantages. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_6.png) - -The Triple protocol, at its inception, was compatible with gRPC, which was based on HTTP/2 and had Streaming capabilities, thus it inherently supports Streaming. Specially, our new protocol also allows Stream under HTTP/1, but it only supports Server Stream, meaning the client sends one request, and the server sends several responses back—this implements HTTP/1 Server Push. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_7.png) - -Client Stream and Bi Stream are straightforward. However, notably, there is no Bi Stream on the Java side; it’s not present in the encoding yet is implemented. - -## 3. Developing Microservices with Triple Protocol - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_8.png) - -Currently, the Triple protocol flexibly supports two definition methods: IDL definition and direct definition. Direct definitions can be synchronous, asynchronous, or handwritten. Moreover, in a more extreme case, while defining an interface, one can utilize IDL to generate protobuf classes; not defining its service and only using its interface is also feasible—it will automatically recognize whether the interface uses protobuf or not. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_9.png) - -The server only needs to implement its service. The figure above provides an example; I employed the API assembly method directly— in true business settings, it could be achieved via annotations or XML. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_10.png) - -By supporting the standard HTTP protocol, our testing theoretically simplifies significantly. - -Since we support gRPC, we can invoke our service using gRPC curl. However, there are prerequisites: you must have a reflective service and then manually enable it, as it is not enabled by default. It can retrieve interface source data via reflection and convert it to pb format in JSON. Alternatively, we can directly call it using Application JSON. Notably, under HTTP/1, we can also use Stream. - -Additionally, as we support HTTP, theoretically, any third-party HTTP client can call our service. Furthermore, our admin can conduct tests, but it must be registered first. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_11.png) - -For the calling client, whether using POJO or IDL, there is essentially no difference. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_12.png) - -Now that we have the Triple protocol, it’s not operational without a host for the protocol. Therefore, we still need a framework with some service governance for our microservices. Service governance is also an indispensable part of microservices. - -## 4. Governance Capability of Dubbo for Triple Protocol - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_13.png) - -The positioning of Triple is just one of the protocols in Dubbo. Of course, for compatibility, you may continue to use the original Dubbo protocol or other protocols. Moreover, we support multiple protocols on the same port, enabling users to choose as needed. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_14.png) - -At the same time, Dubbo offers a multi-language implementation for Triple. Currently, the official implementations will be available in Rust, Go, Java, JS, Node, and Python. This means users do not need to implement it based on the experimental protocol specifications. If you have some customization needs, such as internal frameworks, you can implement it based on the specifications as well. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_15.png) - -Dubbo integrates well with service frameworks. Theoretically, during the development process, especially on the Java side, service definitions, governance, and service registration/discovery do not require concern from clients; it's ready to use out of the box. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_16.png) - -Dubbo provides a rich ecosystem, including third-party ecosystems like Nacos and Zookeeper; we don’t need to innovate but directly introduce the necessary packages. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_17.png) - -This shows an example of service registration using the Triple protocol. You can select Nacos, Zookeeper, or K8s above, with a Client and a Server on the left, making the call. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_18.png) - -Let’s take a look at the implementation on the admin side. It’s worth mentioning that our admin has also been restructured in the new version, implemented using Go, so stay tuned. - -![dubbo-triple-protocol](/imgs/blog/2023/8/apachecon-scripts/triple/img_19.png) - -We often encounter needs for gray release or traffic shaping. We can send a tag from the admin, label some instances, and the traffic will sequentially flow from the entrance. - diff --git a/content/en/blog/news/apachecon2023/usecase-zhengcaiyun.md b/content/en/blog/news/apachecon2023/usecase-zhengcaiyun.md deleted file mode 100644 index 15e809cab839..000000000000 --- a/content/en/blog/news/apachecon2023/usecase-zhengcaiyun.md +++ /dev/null @@ -1,203 +0,0 @@ ---- -title: "Zhengcaiyun's Hybrid Cloud Data Cross-Network Practice Based on Dubbo" -linkTitle: "Zhengcaiyun's Hybrid Cloud Data Cross-Network Practice Based on Dubbo" -tags: ["apachecon2023", "case study", "Zhengcaiyun"] -date: 2023-10-07 -authors: ["Wang Xiaobin"] -description: Zhengcaiyun's Hybrid Cloud Data Cross-Network Practice Based on Dubbo ---- - -Abstract: This article is organized from the sharing of Wang Xiaobin, a senior development engineer at Zhengcaiyun. The content is mainly divided into four parts: - -* 1. Project Background -* 2. Why is it called the Highway -* 3. Road Construction Practice -* 4. Future Planning - -## 1. Project Background - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img.png) - -We have a cloud island business called Zhengcaiyun, which is a shopping website for the government, similar to Taobao. Government procurement conducts corporate purchases and government procurement business on Zhengcaiyun. - -The "cloud" in cloud island refers to our cloud platform, a self-deployed shopping website corresponding to a microservice framework. The "island" refers to local networks in places like Anhui or Shanxi where we would deploy this framework, calling it an "island". Our cloud is mainly used by Zhejiang Province and related regional divisions. - -There is a data transmission issue between our cloud and island. For example, if I receive a government announcement that's national, I may record it on the management platform of the cloud and then push it out, creating cross-network data between the cloud and the island. - -1. Cloud Island Network - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_1.png) - -For our cloud platform, the local area network is completely controllable within our company. For instance, opening a port is straightforward. The import side may be a local or private network; for instance, we previously worked on a project with Zhejiang Merchants Bank, which is a fully isolated island. They define their own security policies and port openings, reflecting the business structure of our cloud island. - -2. Hybrid Cloud Island Network - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_2.png) - -The above graphic is a general data link diagram. Below the cloud platform are branches and subsidiaries correspondingly linked to a set of business systems. The government cloud refers to the provincial (Anhui Province) or municipal (Wuxi City) segmented areas, resulting in isolated government clouds. Private deployments involve typical hybrid cloud network architecture such as banks, state-owned enterprises, military, and government enterprises. - -3. Characteristics of Hybrid Cloud Island Network - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_3.png) - -Our hybrid cloud network architecture features: - -- Consistency of the platform. The code deployed on public clouds, cloud platforms, government clouds, and private clouds is identical. Deploying one set of code in various locations translates into multiple platforms. -- Network connection and capability reuse. We depend on some third-party services, such as SMS, but private clouds have stringent network controls complicating the process of connecting with third parties. Here, we intend to reuse the capabilities of our cloud platform, leading to data exchange. -- Cross-domain access migration. -- Unified platform management. For instance, if we need to issue an announcement, we hope to manage it on one platform instead of separate ones for Zhejiang and Anhui, which would increase maintenance costs. - -4. Pain Points in Government and Enterprise Networks - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_4.png) - -Many companies interact with the government, and government-enterprise networks have the following characteristics: - -Complex networks. For example, bank networks are intricate due to their security requirements and numerous processes that require regular follow-ups, leading to new issues after evaluations. - -High security requirements. For example, when opening ports, data transmission needs to comply with specific serialization protocols; otherwise, these requests get rejected, leading to timeouts or generic exceptions, creating unknown risks. - -Business-driven operations. Deployment occurs only after business requirements arise, leading to repetitive investments of time and manpower, especially for private deployments. - -5. Existing Solutions - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_5.png) - -Based on the aforementioned pain points, we devised two solutions. - -The first solution is a unidirectional plan based on Dubbo Filter. This approach is fairly historic with two characteristics. - -The first characteristic is unidirectional transmission. It moves from the "island" to the "cloud" in one direction, and this is based on Dubbo Filter since our company’s internal microservices are all called through Dubbo, making it a strong dependency for cross-network data solutions. - -The second characteristic is that the locally deployed business provider as a filter creates an operational burden. When the import side needs to sync data to the cloud side, data is transmitted from the island's business web to the cloud's business provider. Hence, I must also deploy a business provider on the import side. The need for this deployment arises from the requirement to intercept requests and forward them to the Dubbo gateway deployed on the cloud platform. - -However, this creates a burden. If the import side already has data storage, this could be manageable as the provider exists. But if some business processes are solely for cross-network use without local storage, then the business provider becomes redundant. - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_6.png) - -The second solution is a mesh point-to-point approach. Because there's a need for network interconnectivity between islands, ports are specifically opened between this point and the destination point. Once opened, calls can be made, typically through Dubbo. - -This solution has a clear flaw; there are numerous lines which increase the complexity of establishing connections between points and may hinder future scaling. - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_7.png) - -The aforementioned solutions encounter issues including unidirectional transmission, high whitelist opening costs, high platform maintenance costs, and the absence of shared functionalities. - -Based on the above issues, we created a new plan called the Highway. - -## 2. Why is it called the Highway - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_8.png) - -Why it is called the Highway? Primarily because the desired effect is: - -Built once, reusable. For example, the highway from Beijing to Shanghai only needs to be wide enough; one road suffices. You can reuse this for travel from Shanghai to Beijing or Hangzhou to Beijing, without needing to build another. - -Tunnel mechanism. Highways don't only traverse plains; they may run near rivers, seas, or mountains. If we construct a tunnel under the highway, it's seamless for drivers. Our goal aligns with this; if the government-enterprise network seems intricate to you, we aim to shield that complexity, so you won't have to perceive it. - -Considering transmission performance. If each business department builds its own transmission path, the performance only needs to sustain their own operations, as it is not necessarily shared. However, if establishing a reusable path, transmission performance must be prioritized. - -## 3. Road Construction Practice - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_9.png) - -Next, we will detail the challenges encountered during highway construction as well as specific practices. We faced the following issues when integrating with clients: - -The first issue is a strong dependence on Dubbo. - -The second issue is transparent transmission without altering how Dubbo is used. In other words, I should not need to write annotations to replace Dubbo or API calls to Dubbo. Writing such interactions could be alienating for newcomers who may not grasp or adapt to them and might not realize potential pitfalls. Therefore, using the original Dubbo might facilitate a better experience for users. - -The third issue is flexible integration supporting multiple forms. Although we must support Dubbo due to our strong reliance, we also need to endorse other forms, like HTTP. However, flexibility must be considered prior to integration. - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_10.png) - -Now, let's introduce Dubbo integration methods. The objective means of integrating Dubbo includes three methods: - -First, an annotation method. Using @DubboReference provides optional common parameters to set routing targets, achieving method-level routing. Routing information is written in the intermediate parameters, which are common parameters provided by Dubbo. - -If it's standard, and I write this information, Dubbo does not process anything as it holds no significance. However, because you introduced the highway SDK, when you write this, we will parse it, intercepting Dubbo requests and leveraging parameters for routing. This form does not change the usage of Dubbo. - -Second, specifying in the configuration center. If we utilize the Apollo configuration center, it can entirely replace the integration method; parameters can also be configured in the configuration center as long as the SDK supports it. This method actually has fully intrusive code, presenting no differences before and after cross-network implementation. Yet, it turns out our business doesn’t favor this method because Apollo is unpopular and it lacks clarity. If a newcomer views this code, they might assume they’re calling a local interface. - -Third, thread specification. When you specify routing information in a thread and call again, this call will follow your routing. If called again, it defaults to local. However, because this is thread-based, Dubbo extensions will clean up the thread info after the call is complete. So, be mindful, as multiple calls demand writing multiple specifications. If you want to avoid multiple writings, utilize the previous method, as long as you're in the current context, it will always route to Shanghai. - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_11.png) - -Now, let’s discuss the highway architecture; the previous point-to-point method has complex whitelist openings. Our highway architecture is a novel construction, thus simplifying the complexity of opening whitelists. - -As illustrated, for instance, the leftmost node is Shanghai, and the uppermost is Anhui. If I wish to move from Anhui to Shanghai, the central gateway needs to open a whitelist. Once opened, this link can be used directly. There are a total of six lines, hence the complexity has been reduced. - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_12.png) - -Above is the core architecture diagram of the highway. - -For example, when the Shanxi cluster’s APP1 interacts with APP2, and I want to connect to Shanghai’s APP2, if no action is taken, it defaults to call Shanxi cluster APP2. If during this APP call some routing information is added, the SDK in Shanxi cluster APP1 will direct its traffic to the Dubbo gateway in Shanxi cluster. - -Subsequently, the Dubbo gateway will traverse through the unified gateway via the HTTP protocol, then to the Shanghai cluster’s Dubbo gateway via the same protocol. Routing information will be gathered here, including the service called, methods, version numbers, parameters, etc. This information will then be used to invoke APP1 of the Shanghai cluster in a generalized manner, ultimately returning and completing this cross-network call. - -So why is the Dubbo Proxy role necessary? Why not redirect directly from APP1 to the unified gateway? Wouldn't omitting one step be better? There are three reasons involved: - -Although this diagram depicts only one APP1, numerous calls occur within the Shanxi cluster. If hundreds of applications connect directly to the unified gateway, it needs to establish many long connections, with limited resources available for the unified gateway. - -For security concerns, each call may need to traverse the whitelist to ensure safety. Therefore, with Dubbo Proxy, IP aggregation can occur. The island doesn't need to interact with Dubbo Proxy as they exist within the same environment, negating security considerations. Once a request passes to the gateway from Dubbo Proxy, it follows only one link between the gateway and unified gateway; thus, IPs are aggregated. - -Moreover, there's a functional consolidation aspect. During future upgrades, if SDK updates are necessary, each application must upgrade, which can be labor-intensive. Hence, we aim to store upgrade functionalities within a single application, ensuring it remains unnoticed by the business functions, with no need for SDK updates as the SDK needs only to handle routing, minimizing updates. - -Consequently, for businesses, this liberates them. I perceive this as a functional benefit. This model is termed a distributed runtime, which is currently trending. We can interpret this as Dapper, moving burdensome operations to a shared service while keeping the business SDK very streamlined. - -Additionally, why use the HTTP protocol? It's not necessarily the most efficient protocol. The Dubbo2 protocol inside Dubbo is actually quite impressive, consisting mostly of data aside from some ambiguities. Consequently, we could consider upgrading HTTP later to enhance performance. - -Currently, the adoption of HTTP protocol is due to its standardized nature. Throughout various devices, even though we've illustrated only one link, HTTP protocol encounters no hindrances. If using Dubbo protocol, numerous connections would need to be established. - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_13.png) - -To realize this architecture, Dubbo itself cannot be applied directly since it does not provide cross-network capabilities; thus, we need to address the challenges encountered at the Dubbo level. - -In the facet of dynamic IP switching, Dubbo supports this feature; however, as it’s relatively new, some issues may arise. Its support is partial; for instance, earlier versions like Dubbo2 did not, while Dubbo3 does. Moreover, bugs may occur. - -In terms of 404 extensions, with HTTP, requesting a non-existent interface returns a 404 error to the frontend. When directing the traffic from APP1 to Dubbo Proxy, the Dubbo Proxy acts as a Dubbo-based application that incorporates a Dubbo jar, functioning as a minimal application. When this traffic reaches the Dubbo gateway, it fails to recognize it and must forward it; thus, we need to integrate this extension. - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_14.png) - -Next, we'll discuss the tunnel mechanism. The tunnel mechanism aims to mask network complexities and intermediates protocol conversion, offering users a unified, transparent calling method. - -The HTTP protocol’s body carries an original body. After inversion, the packaging extracts it and utilizes generalization for calls. In such cases, tunnels can match these disparities. - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_15.png) - -Moreover, the tunnel mechanism offers higher support for the Dubbo protocol. For instance, when APP1 and local APP3 ultimately call APP2, the observed binary streams are identical. This is accomplished by merely wrapping the processes and ultimately unpacking them. Other than a bit of routing information, everything remains consistent. - -The advantage of this method is that it supports almost all Dubbo features. Yet, there are exceptions, such as token or network-derived mechanisms. - -## 4. Future Planning - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_16.png) - -Leveraging online network architecture layers, we have planned for the highway as follows: - -The first layer, physical network connectivity. This is somewhat peripheral as I interpret it as port openings, summarizing experiences or methodologies for expedited processes. - -The second layer, acceleration of communication protocol. The HTTP protocol forwarding in between can be accelerated. For instance, the Triple protocol, based on HTTP2, enhances recognition of network devices and resolves issues. Thus, we may consider researching optimizations at the communication protocol layer. - -The third layer, language layer compilation acceleration. Discussions on GraalVM had been held previously, and some genuine tests were undertaken; although not fully implemented, compilation acceleration is achievable. Especially at the gateway level, characterized by substantial traffic, yet each connection is minimal, creating high-performance demands on the language itself. Implementing this with Go would provide significant acceleration. - -The fourth layer, functional upgrades at the framework level. We also accomplished many initiatives at the middleware layer. - -The fifth layer: General task scheduling and orchestration. Calls will typically pass through many nodes, e.g., from a to b to c to d to e; as operations grow more complex, additional routing may be necessary, e.g., from a to c while combining c and d before proceeding to d, with future adjustments planned. - -The sixth layer: Custom task scheduling and orchestration. - -The seventh layer: Monitoring & Alerts & Observability. - -The eighth layer: Standards & Procedures & Security. - -![dubbo enterprise practice - Zhengcaiyun](/imgs/blog/2023/8/apachecon-scripts/zhengcaiyun/img_17.png) - -In conclusion. - -Why undertake this project? Existing solutions were relatively numerous, yet costly. We need a unified approach that accounts for broader public testing to promote this initiative. We have successfully integrated numerous applications, making it a standard solution for cross-network data among legal personnel. - -The effects we aim to achieve have already been detailed in the project architecture and future plans. - -Emphasizing our open-source and community collaboration, the previous solutions were designed for internal company use, involving deep customizations of Dubbo. Typically, we prefer private versions for development; however, we intended to open-source from the outset, so we communicated with the Dubbo community to discuss implementing this at the open-source level. The community can assist in reviewing these features and ensuring safety controls. Additionally, we can share our developments with the community, especially pulling public elements back for communal benefit. - diff --git a/content/en/blog/news/dubbo-10years.md b/content/en/blog/news/dubbo-10years.md index 2b46aae53eb3..d28383f1bd5b 100644 --- a/content/en/blog/news/dubbo-10years.md +++ b/content/en/blog/news/dubbo-10years.md @@ -1,193 +1,189 @@ --- -title: "都已经十岁的 Apache Dubbo,还能再乘风破浪吗?" -linkTitle: "都已经十岁的 Apache Dubbo,还能再乘风破浪吗?" +title: "Can Apache Dubbo, Now a Decade Old, Ride the Waves Again?" +linkTitle: "Can Apache Dubbo, Now a Decade Old, Ride the Waves Again?" date: 2021-01-14 -tags: ["新闻动态"] +tags: ["News"] description: > - 在云原生时代,Apache Dubbo 将如何延续当前光芒? + How will Apache Dubbo continue to shine in the cloud-native era? --- ![img](/imgs/blog/dubbo-go/10years/dubbo-home.png) -纵观中国开源历史,你真的没法找到第二个像 Dubbo 一样自带争议和讨论热度的开源项目。 +Throughout the history of open source in China, it is hard to find a second project as controversial and discussed as Dubbo. -一方面,2011 年,它的开源填补了当时生产环境使用的 RPC 框架的空白,一发布就被广泛采用;另一方面,它经历了停止维护、重启维护后捐献给 Apache 基金会、接着又以顶级项目的身份毕业。 +On one hand, its open source in 2011 filled the gap of RPC frameworks used in production environments, and it was widely adopted upon release; on the other hand, it experienced a halt in maintenance, a restart, donation to the Apache Foundation, and then graduated as a top-level project. -面对多疑的开发者,在云原生时代,Apache Dubbo 将如何延续当前光芒? +Facing skeptical developers, how will Apache Dubbo continue to shine in the cloud-native era? -今年是 Dubbo 从 Apache 基金会毕业的一周年,同时也是推进 Dubbo 3.0,即全面拥抱云原生的重要一年。开源中国与 Apaceh Dubbo 共同策划**【Dubbo 云原生之路】**系列文章,和大家一起回顾 Apache Dubbo 社区的发展。系列文章主要涵盖 Dubbo 技术解读、社区、应用案例解析三大部分,之后每周都会和大家见面。 +This year marks the first anniversary of Dubbo's graduation from the Apache Foundation and is also an important year for promoting Dubbo 3.0, which fully embraces cloud-native. Open Source China and Apache Dubbo have jointly planned the **【Dubbo Cloud Native Journey】** series of articles to review the development of the Apache Dubbo community. The series will primarily cover three main parts: technical interpretations of Dubbo, community updates, and application case analyses, and it will connect with everyone weekly. -**在【阿里巴巴云原生公众号】留言说出与 Apache Dubbo 的故事**,点赞排名前十的同学可领取 Dubbo 送出的专属奖品杯子一只;另外由Apache Dubbo PMC @Chickenlj 随机抽取一名幸运读者,赠送价值 260 元护眼灯一台。下周三开奖。 +**Leave a message on the【Alibaba Cloud Native WeChat account】to share your story with Apache Dubbo**, and the top ten liked participants can receive a special Dubbo prize cup; additionally, Apache Dubbo PMC member @Chickenlj will randomly draw a lucky reader to receive an eye protection lamp worth 260 yuan. The draw will take place next Wednesday. -**作者简介** +**Author Profile** -**刘军**,花名陆龟,GitHub 账号 Chickenlj,Apache Dubbo PMC,项目核心开发,见证了 Dubbo 重启开源,到从 Apache 基金会毕业的整个过程。现任职阿里云云原生应用平台团队,参与服务框架、微服务相关工作,目前主要在推动 Dubbo 3.0 - Dubbo 云原生。 +**Liu Jun**, alias Lu Gui, GitHub account Chickenlj, Apache Dubbo PMC, core project developer, witnessed the entire process from Dubbo's restart in open source to its graduation from the Apache Foundation. He is currently with Alibaba Cloud's cloud-native application platform team, involved in service framework and microservices work, primarily promoting Dubbo 3.0 - Dubbo Cloud Native. -# 系列开篇:3.0 全面铺开、ASF 毕业一周年 +# Series Opening: 3.0 Launched, One Year Since ASF Graduation -从 2019 年到现在,在 Dubbo 毕业的这一年时间里,Dubbo 社区和产品都取得长足进步,同时 Dubbo 云原生版本 - Dubbo 3.0 的开发工作也已经全面铺开。 +From 2019 until now, in the year since Dubbo's graduation, both the Dubbo community and product have made significant progress, while the development of the cloud-native version - Dubbo 3.0 has also fully kicked off. -社区方面。需要重点提及的有两点:一个是落地与贡献的企业用户进一步增加,主动与社区取得联系的中、大规模公司达 200 多家,如携程、工商银行、瓜子二手车、网联清算、中通等;另一个是[**以 Dubbo-go 为代表的子社区**](http://mp.weixin.qq.com/s?__biz=MjM5NzM0MjcyMQ==&mid=2650091639&idx=1&sn=9733d57fd9babe53826bc93c2a466adf&chksm=bedaeb1989ad620f99abfee5902d69dc6c7544d1d70803d854f20ea7a1a44c1d0c4ba82f8d3a&scene=21#wechat_redirect)蓬勃发展。 +In the community aspect, two key points need to be highlighted: one is the increase in enterprise users participating and contributing, with over 200 mid-to-large companies proactively contacting the community, such as Ctrip, Industrial and Commercial Bank of China, Guazi Used Cars, UnionPay Clearing, Zhongtong, etc.; the other is the thriving [**sub-community represented by Dubbo-go**](http://mp.weixin.qq.com/s?__biz=MjM5NzM0MjcyMQ==&mid=2650091639&idx=1&sn=9733d57fd9babe53826bc93c2a466adf&chksm=bedaeb1989ad620f99abfee5902d69dc6c7544d1d70803d854f20ea7a1a44c1d0c4ba82f8d3a&scene=21#wechat_redirect). -产品技术演进方面。Dubbo Java 版发布 10 个版本,在多语言、协议、性能、服务治理模型等方面都有深度探索。Dubbo go 发布超过 8 个版本,在功能基本对齐 Java 版本的基础上,一些方向上也已经走在了 Java 版本前面。 +In terms of product tech evolution, the Dubbo Java version has released 10 versions, deeply exploring multi-language, protocol, performance, and service governance models. Dubbo go has released over 8 versions, aligning its functionality with that of the Java version, and in some areas, it has taken the lead. -值得一提的是,阿里巴巴内部也正在积极推动 Dubbo 社区版本在内部的落地,从今年开始逐步实现**以 Dubbo 升级其内部的 HSF 框架**。这一方面有利于阿里将其在 HSF 上的丰富服务治理经验回馈输出到社区,另一方面阿里官方的落地也将直接加速 Dubbo 云原生的发展。 +It is noteworthy that Alibaba is actively promoting the internal adaptation of the Dubbo community version, gradually realizing **the upgrade of HSF framework internally using Dubbo** from this year. This not only allows Alibaba to bring back its rich service governance experience from HSF to the community but also accelerates the development of Dubbo cloud-native directly. -在云原生大潮下,**3.0 已被正式列为今年 Dubbo 产品建设的核心目标**,涉及下一代 RPC 协议、服务治理模型、云原生基础设施适配等多方面的内容。其中,很多方面已经在当前的 2.7 版本中做了前置性探索,如近期发布的基于 HTTP/2 的协议支持、应用级服务发现等,后续工作将以此为基础展开。系列文章也会有对 Dubbo 3.0 Roadmap 及技术方案的详细解析。 +In the wave of cloud-native, **3.0 has officially been set as the core goal for Dubbo's product development this year**, covering the next generation RPC protocol, service governance models, cloud-native infrastructure adaptation, and more. Many aspects have already been explored in the current 2.7 version, such as the recent release of HTTP/2 protocol support and application-level service discovery, establishing a foundation for future work. The series will also provide detailed analyses of the Dubbo 3.0 Roadmap and technical solutions. -## Dubbo 毕业一周年回顾 +## One Year Since Dubbo Graduation Review -2017 年 7 月,Dubbo 开源项目被重新激活,2018 年捐献到 Apache 基金会,2019 年 5 月,Dubbo 正式从 Apache 基金会孵化毕业,成为 Apache 顶级项目。接下来,文章分别从社区、子社区、产品三方面介绍 Dubbo 过去一年的成绩。 +In July 2017, the Dubbo open-source project was reactivated, and in 2018 it was donated to the Apache Foundation. In May 2019, Dubbo graduated from incubation at the Apache Foundation and became an Apache top-level project. The following sections will introduce Dubbo's achievements over the past year in terms of community, sub-communities, and products. -### 社区一年发布 24 个版本,贡献者已超 300 +### Community Released 24 Versions in a Year, Contributors Exceed 300 -如果说最开始重新激活是以阿里巴巴为主导的项目维护投入,那自 Dubbo 加入 Apache 起,它就已经开始成为一个社区主导、社区贡献为主的完全开放的基金会项目。 +If the early reactivation was primarily led by Alibaba's project maintenance investment, Dubbo has become a fully open foundation project led by the community and primarily contributed to by the community since joining Apache. -到今天,这一趋势正变得更明显。包括阿里巴巴、携程、工商银行、瓜子二手车、网联清算、中通等在内的互联网、传统企业公司,在 Dubbo 的使用与社区代码贡献上都有投入。Dubbo 社区正变得非常活跃和多样化。 +Today, this trend is becoming more evident. Internet and traditional companies, including Alibaba, Ctrip, Industrial and Commercial Bank of China, Guazi Used Cars, UnionPay Clearing, and Zhongtong, have made contributions in using Dubbo and community code contributions. The Dubbo community is becoming very active and diverse. -过去一年,Dubbo 社区项目总共发布 24 个版本,发展 Committer/PMC 27 人,其中有 20% 的贡献者是来自于阿里巴巴,80% 以上来自不同组织的开发者或爱好者。 +In the past year, the Dubbo community project has released a total of 24 versions and developed 27 Committer/PMC members, of which 20% of contributors are from Alibaba, while over 80% come from various organizations of developers or enthusiasts. -Dubbo 社区组织了超过 10 场线下 meetup 活动,基本覆盖了国内开发者聚集的城市。通过线下或线上直播活动,分享超过 100 个 topic 的演讲,深度讲解 Dubbo 社区最新动态、功能模块开发和近期规划等。主题演讲大多是社区采集方式,由 Dubbo 的深度企业分享实践经验,其中典型的代表包括携程、工商银行、考拉、信用算力等。 +The Dubbo community organized more than 10 offline meetup events, basically covering cities where developers gather domestically. Through offline or online live events, more than 100 topics were shared, deeply explaining Dubbo community's latest dynamics, functional module development, and recent plans. Most keynote speeches are gathered from deep enterprises sharing practical experience, with typical representatives including Ctrip, Industrial and Commercial Bank of China, Koala, and Credit Computing Power. -从 GitHub 统计数据来看,Dubbo Star 数取得新的里程碑,已超过 3 万,相比重启开源时增长了近 5 倍;贡献者由最初的几十个增长到现在的 300 多个,而这其中有 60 多人已经被提名为 committer,不论是贡献者数量还是 committer 比例都得到很大的提升;Dubbo Java 发布的有 65 个。 +From GitHub statistics, Dubbo Star has achieved a new milestone, surpassing 30,000, which is nearly five times higher than when it was restarted; contributors have grown from tens to over 300, with more than 60 nominated as committers. Both the number of contributors and the ratio of committers have significantly increased; there have been 65 releases of Dubbo Java. -上述主要是对 Dubbo Java 项目社区发展的总结,下面将介绍 Dubbo Java 产品方面的进展。 +The above primarily summarizes the community development of the Dubbo Java project; the following will introduce the advancements in Dubbo Java products. -### Dubbo Java 迭代,目前主要维护 3 个大版本 +### Dubbo Java Iteration, Currently Mainly Maintaining 3 Major Versions -当前社区维护的 Dubbo Java 大版本主要有 3 个,分别是 2.5.x、2.6.x 和 2.7.x。 +The main major versions maintained by the community currently are 2.5.x, 2.6.x, and 2.7.x. -- 2.7.x 是社区的主要开发版本,在过去的一年共发布了 8 个版本(2.7.0 - 2.7.7),每个版本都有一些值得关注的特性或功能升级,涵盖从编程模型、服务治理、性能到协议的多个方面的增强; -- 2.6.x 版本则定位为 bugfix 版本,过去一年共发布了 3 个版本,主要以修复问题和安全漏洞为主,并没有增加太多新的 feature; -- 2.5.x 版本从 2019 年初开始已宣布 EOF,只做安全修复;而到了下半年已经完全停止了维护。 +- 2.7.x is the community's primary development version, releasing 8 versions in the past year (2.7.0 - 2.7.7), each featuring noteworthy enhancements or upgrades across multiple aspects from programming models, service governance, performance to protocols; +- The 2.6.x version is designated as a bugfix version, with 3 versions released in the past year, mainly fixing issues and security vulnerabilities without adding many new features; +- The 2.5.x version was declared EOF at the beginning of 2019 and has only undergone security fixes; by the second half of the year, maintenance had completely stopped. -下面通过一个简要分层模块图,回顾过去一段时间 Dubbo 的技术架构演进,从编程模型、服务治理、传输协议、性能优化等角度切入: +Below is a brief layered module diagram recounting the evolution of Dubbo's technical architecture from aspects like programming model, service governance, transmission protocol, and performance optimization: ![img](/imgs/blog/dubbo-go/10years/dubbo-layer.png) +Many of the above functions have been implemented by major vendors to solve specific business problems. We also look forward to more in-depth summaries of Dubbo practices brought by these vendors in the future. -以上很多功能都已被各大厂商落地,用于解决具体的业务问题。我们也期待,接下来这些厂商带来更多关于 Dubbo 实践经验的深度总结。 +### Dubbo-go's Fifth Year Developments in Parallel with Dubbo -### Dubbo-go 发展的第五年,正与 Dubbo 齐头并进 +Apart from Dubbo Java, many excellent sub-projects (sub-communities) have also been developed around Dubbo, including Dubbo-spring-boot-project, Dubbo-go, etc. Here, we will focus on introducing the Dubbo-go sub-community. -除 Dubbo Java 之外,Dubbo 周边也发展出了很多优秀的子项目(子社区),其中包括 Dubbo-spring-boot-project、Dubbo-go 等,这里先着重介绍 Dubbo-go 子社区。 - -Dubbo-go 项目最早由于雨在 2016 年 5 月构建,同年 9 月发布并开源,如下时间轴图清晰记录了 Dubbo-go 的前世今生。 +The Dubbo-go project was first built in May 2016 and released and open-sourced in September of the same year. The timeline below clearly records Dubbo-go's origins and developments. ![img](/imgs/blog/dubbo-go/10years/dubbo-go-events.png) -秉承 "bridge the gap between Java and Go" 天然使命的 Dubbo-go,已经进入第五个年头,也走出了自己独特的发展路径: +Inheriting the natural mission of "bridging the gap between Java and Go", Dubbo-go has now entered its fifth year and has carved out its unique development path: -- 当前的 v1.4.0 版本已对齐 2.6.x 版本,即将发布的版本将与 v2.7.x【对标 v2.7.5】对齐,而后将会发布对标 Dubbo 3.x 的 v1.6.0版本; -- 独立维护从底层的 hessian2 协议库 Dubbo-go-hessian2、网络库 getty 到上层对标 Dubbo 的 Dubbo-go 的全套实现; -- 独立的 TCP + Protobuf 和 gRPC + JSON 通信方案也已开发完成【将包含着在版本 v1.5.0 中】; -- 已与 Dubbo/gRPC/[Spring Boot](https://mp.weixin.qq.com/s?__biz=MzA4ODg0NDkzOA==&mid=2247487916&idx=1&sn=894316507590793285d0e15734db0bde&scene=21#wechat_redirect) 实现互联互通; -- 通过接入 [Opentracing](https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247488596&idx=2&sn=4d554d32fdd167b6b74fc792c78fb341&scene=21#wechat_redirect) 和 Promethus,Dubbo-go 在可观测性等微服务方向的进行了自己独特的探索; -- 已实现了基于 HTTPS 的[可信 RPC 调用](https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247489539&idx=3&sn=379514cac71b91d57643e6f3d2701cdf&scene=21#wechat_redirect); -- 已经实现了自己独特的[把 Kubernetes 作为注册中心的微服务方案](https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247489465&idx=3&sn=514144ef1a217a50b9f5a640ca122ac8&scene=21#wechat_redirect); +- The current v1.4.0 version aligns with the 2.6.x version, with the upcoming version set to align with v2.7.x【matching v2.7.5】, and thereafter release the v1.6.0 version corresponding to Dubbo 3.x; +- Independently maintain the complete implementation of the underlying hessian2 protocol library Dubbo-go-hessian2, network library getty, to the upper layer aligning with Dubbo; +- Independent TCP + Protobuf and gRPC + JSON communication solutions have been developed【to be included in version v1.5.0】; +- Already achieved interoperability with Dubbo/gRPC/[Spring Boot](https://mp.weixin.qq.com/s?__biz=MzA4ODg0NDkzOA==&mid=2247487916&idx=1&sn=894316507590793285d0e15734db0bde&scene=21#wechat_redirect); +- By integrating [Opentracing](https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247488596&idx=2&sn=4d554d32fdd167b6b74fc792c78fb341&scene=21#wechat_redirect) and Prometheus, Dubbo-go has embarked on its unique explorations in observability and other microservice directions; +- Achieved trusted RPC calling based on HTTPS[https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247489539&idx=3&sn=379514cac71b91d57643e6f3d2701cdf&scene=21#wechat_redirect]; +- Developed its unique microservice solutions using Kubernetes as a registry[https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247489465&idx=3&sn=514144ef1a217a50b9f5a640ca122ac8&scene=21#wechat_redirect]; -Dubbo-go 从最开始 Dubbo 的 Go 语言实现,已发展成为目前 Dubbo 多语言版本中功能最强大者,它的发展离不开背后强大的 Dubbo-go 社区。除了上述 Dubbo-go 的自身特性外,通过跨社区合作,取得了如下成绩: +Dubbo-go has evolved from its initial implementation of Dubbo in Go language to currently being the most powerful among Dubbo's multi-language versions, with its development backed by the strong Dubbo-go community. In addition to the above characteristics, cross-community collaboration has achieved the following results: -- 通过与 MOSN 社区合作,已经实现 Dubbo/Dubbo-go 应用可以零成本接入基于 MOSN 实现 Dubbo Mesh,实现微服务和云原生共存的 **“双模微服务”**; -- 与 sentinel 社区合作,在 Dubbo/Dubbo-go 完整接入 sentinel 的降级和限流方案; -- 与 Apollo 社区合作,在 Dubbo-go 中实现远程配置下发; -- 与 Nacos 社区合作,实现基于 Nacos 的服务发现; +- Through collaboration with the MOSN community, Dubbo/Dubbo-go applications can seamlessly integrate with the Dubbo Mesh based on MOSN, realizing coexistence of microservices and cloud-native in a **"dual-mode microservices"**; +- Collaborated with the Sentinel community to seamlessly integrate downgrade and rate limiting solutions into Dubbo/Dubbo-go; +- Partnered with the Apollo community to implement remote configuration rollout in Dubbo-go; +- Collaborated with the Nacos community for service discovery based on Nacos; -Dubbo-go 社区 2020 年 Q2 主要目标有: +The Dubbo-go community's primary goals for Q2 2020 include: -- 发布完全对齐 Dubbo 2.7.x 的 v1.5.0 版本; -- 发布对标 Dubbo 3.0 的 v1.6.0版本; -- 在云原生方面继续自己的探索; -- 继续与兄弟社区保持合作共进态势,扩大自身使用范围; -- 生产实践上推进在阿里集团,以及更多厂家的落地。 +- Release v1.5.0 fully aligning with Dubbo 2.7.x; +- Release v1.6.0 that matches Dubbo 3.0; +- Continue exploration in cloud-native aspects; +- Maintain cooperative momentum with brother communities to expand usability; +- Advance production practices within Alibaba Group and other vendors. -项目(包括子项目)目前已先后在携程、涂鸦智能和蚂蚁金服等公司生产落地。 +The project (including sub-projects) has been successfully implemented in companies such as Ctrip, Tuya Smart, and Ant Group. -今年阿里集团完成 HSF 和 Dubbo 的融合后,项目也将在阿里集团双十一战场经受考验。 +This year, after the integration of HSF and Dubbo within Alibaba Group, the project will also be tested in the Alibaba Group's Double Eleven battlefield. -## 云原生 Dubbo - Dubbo 3.0 +## Cloud-Native Dubbo - Dubbo 3.0 -3.0 是下一代 Dubbo 架构的代号。一年前,最开始探索 Reactive Stream 之时,社区也曾有过对 Dubbo 3.0的广泛讨论。而这一次,在云原生大背景下,3.0 代表了更全面的 Dubbo 架构升级,涉及到下一代 RPC 协议、全新的服务治理模型和云原生基础设施适配等。 +3.0 is the codename for the next-generation Dubbo architecture. A year ago, during the initial exploration of Reactive Streams, the community had extensive discussions about Dubbo 3.0. Now, against the backdrop of cloud-native, 3.0 represents a more comprehensive upgrade of the Dubbo architecture, covering the next generation RPC protocol, a brand-new service governance model, and adaptation to cloud-native infrastructure. -阿里巴巴是参与 Dubbo 3.0 开发建设的主要力量之一,这款始于阿里的开源项目正重新回归阿里内部落地。 +Alibaba is one of the main forces involved in the development and construction of Dubbo 3.0. This Alibaba-originated open-source project is returning to internal implementation at Alibaba. -去年开始,阿里巴巴就已经在逐步推动以 Dubbo 替换其内部的 HSF 框架的工作,通过将 Dubbo 与 HSF 两个框架融为一体,并在此基础上发展出适应云原生架构的 Dubbo 版本。Dubbo 重回阿里巴巴的落地是拥抱社区、拥抱云原生、拥抱标准化的一次很好的实践。 +Since last year, Alibaba has been gradually promoting the replacement of its internal HSF framework with Dubbo, integrating the two frameworks and developing a Dubbo version suited for cloud-native architecture based on this integration. The return of Dubbo to Alibaba's implementation represents a great practice of embracing the community, cloud-native, and standardization. -阿里巴巴内部 Dubbo 3.0 的落地,对社区也是一个重大利好,这一方面有利于阿里巴巴将其在 HSF 上的丰富服务治理经验回馈输出到社区,另一方面也将直接推动 Dubbo 云原生架构的快速演进。除了阿里巴巴之外,包括斗鱼、工商银行、爱奇艺等厂商也都在参与下一代 Dubbo 3.0 的建设。 +The internal rollout of Dubbo 3.0 at Alibaba is a significant benefit for the community, enabling Alibaba to share its rich service governance experience from HSF back to the community and directly driving the rapid evolution of Dubbo's cloud-native architecture. Aside from Alibaba, vendors like Douyu, Industrial and Commercial Bank of China, and iQIYI are also involved in the construction of the next-generation Dubbo 3.0. -下面列出了 Dubbo 3.0 中的三个重要方向,具体的 Roadmap 将在接下来文章中单独说明: +The following lists three important directions in Dubbo 3.0; the specific Roadmap will be explained separately in upcoming articles: -- 下一代 RPC 协议。新协议将提供更丰富的如 Stream、Flow Control 等内置语义,同时将具有更好的扩展性、网关的友好性等; -- 基于应用粒度的服务发现机制。在兼顾 Dubbo 面向接口的易用性与功能性的基础上,解决与 Kubernetes Native Service 适配问题,解决大规模集群下的地址推送性能瓶颈问题; -- 适配云原生基础设施的解决方案。这涉及到 Dubbo 服务与基础设施生命周期对接、Kubernetes Native Service 适配、适应基础设施调度的服务治理规则、适配 Service Mesh 架构的解决方案等; +- Next-generation RPC protocol. The new protocol will provide richer built-in semantics such as Stream, Flow Control, and will have better extensibility and friendlier gateway compatibility; +- Application-granularity-based service discovery mechanism. Balancing Dubbo's interface-oriented usability and functionality, the aim is to resolve compatibility issues with Kubernetes Native Services and address performance bottlenecks in address pushing within large clusters; +- Solutions to adapt to cloud-native infrastructures. This involves aligning Dbubo service and infrastructure lifecycle, adapting to Kubernetes Native Service, services governance rules compliant with infrastructure scheduling, solutions for integrating Service Mesh architecture, etc.; -接下来沿着这三个方面简要展开。 +Let’s briefly expand on these three aspects. -### 下一代 RPC 协议 +### Next-Generation RPC Protocol -专注在协议自身来说,下一代的协议主要聚焦在 HTTP/2、Reactive Stream、Flow Control 等方面: +Focusing on the protocol itself, the next-generation protocol mainly centers around HTTP/2, Reactive Streams, Flow Control, etc.: -- **Reactive Stream:** Reactive Stream 引入 RPC,带来更丰富的通信语义和 API 编程模型支持,如 Request-Stream、Bi-Stream 等; -- **HTTP/2:** 微服务云原生场景下,基于 HTTP/2 构建的通信协议具有更好的通用性和穿透性; -- **Flow Control:** 协议内置流控机制,支持类似 Reqctive Stream 的 Request (n) 流控机制。 +- **Reactive Stream:** Introduces RPC, providing richer communication semantics and support for API programming models such as Request-Stream, Bi-Stream, etc.; +- **HTTP/2:** Communication protocols built on HTTP/2 for microservices in cloud-native scenarios have better universality and penetration; +- **Flow Control:** Built-in flow control mechanisms support request (n) flow control mechanisms similar to Reactive Streams. -从解决的业务场景问题上来说,基于新的协议 Dubbo 在框架层面要支持智能决策的负载均衡算法、对 Mesh 和网关更友好、更容易提供多语言实现与互通等。 +From the perspective of solving business scenario problems, based on the new protocol, Dubbo at the framework level will support intelligent decision-making load balancing algorithms, become friendlier to Mesh and gateways, and provide easier multi-language implementations and interoperability. -- **Mesh:** 协议对穿透 Mesh 更友好,区分协议头 Metadata 与 RPC Payload,方便完成与 Mesh 的协作,包括流量控制机制、应用层配置协商等; -- **协议通用性:** 兼顾通用性与性能,支持协议能在各种设备上运行; -- **多语言支持:** 如通过支持 Protobuf 提供了更完善的 跨语言服务定义 与 序列化传输的支持。 +- **Mesh:** The protocol is more friendly in penetrating Mesh, distinguishing protocol headers Metadata from RPC Payload, facilitating cooperation with Mesh, including flow control mechanisms and application-level configuration negotiations; +- **Protocol Universality:** Balancing universality and performance, ensuring protocols can run on various devices; +- **Multi-Language Support:** For instance, by supporting Protobuf, more comprehensive cross-language service definitions and serialization support are provided. -### 应用级服务治理 +### Application-Level Service Governance -面向接口一直以来都是 Dubbo 框架的优势。一方面它的易用性,为开发者屏蔽了远程调用的存在;另一方面面向接口的地址发现、服务治理带来了更强大的能力,使得整个 Dubbo 治理体系非常强大与灵活。 +Being interface-oriented has always been a strength of the Dubbo framework. Its ease of use shields developers from the complexity of remote calls; at the same time, the interface-oriented address discovery and service governance provide more robust capabilities, making the entire Dubbo governance system very strong and flexible. -既然面向接口有如此多的好处,那为什么我们还要探索面向应用的服务治理模式呢? +Given the many benefits of being interface-oriented, why should we also explore application-oriented governance models? -听起来似乎有些矛盾。其实到底是面向接口,还是面向应用,只是从不同的角度看 Dubbo。我们所聊的“面向接口 -> 面向应用”的改造,主要体现在服务注册、发现层面: +It may sound contradictory. In fact, whether interface-oriented or application-oriented is just a different perspective on looking at Dubbo. What we refer to as "interface-oriented -> application-oriented" transformation mainly reflects the changes in service registration and discovery: ![img](/imgs/blog/dubbo-go/10years/dubbo-triangle.png) -而我们说的面向应用的新模型,主要对第 2 点,即注册中心的数据组织转变为 “面向应用/实例” 粒度。这为我们解决两个问题: - -- 在服务发现层面与 Kubernetes Service 等微服务模型对齐; -- 服务发现的数据量将有一个量级的下降,从 “接口数 * 实例数 ”下降到 “应用数 * 实例数”。 - -具体可以参见文章《[Dubbo 迈出云原生重要一步 - 应用级服务发现解析](https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247489653&idx=1&sn=445692c491f68aed3f649730d3d9ba96&scene=21#wechat_redirect)》,本系列文章后续也会有对这部分机制和实现的更深度解析。 - -### 云原生基础设施 +The new application-oriented model focuses on the second point, which transforms the data organization in the registry center to an "application/instance" granularity. This addresses two problems: -云原生带来了底层基础设施,应用开发、部署和运维等全方位的变化: +- Aligning with microservice models such as Kubernetes Services at service discovery levels; +- Reducing the amount of data in service discovery from "number of interfaces * number of instances" to "number of applications * number of instances". -**基础设施** +For more details, refer to the article "[Dubbo Takes an Important Step Towards Cloud Native - Analysis of Application-Level Service Discovery](https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247489653&idx=1&sn=445692c491f68aed3f649730d3d9ba96&scene=21#wechat_redirect)", and this series will also include deeper analyses of this mechanism and its implementation. -- 基础设施调度机制变化,带来运维(生命周期)、服务治理等方面的变化; -- 服务发现能力下沉, Kubernetes 抽象了 Native Service Discovery。 +### Cloud-Native Infrastructure -**Service Mesh - 云原生微服务解决方案** +Cloud-native brings encompassing changes to the underlying infrastructure, application development, deployment, and operations: -- Mesh 为跨语言、sdk 升级等提供了解决方案,Dubbo sdk 要与 Mesh 协作,做到功能、协议、服务治理等多方便的适配; -- Mesh 尚未大规模铺开,且其更适合对流量管控更关注的应用,传统 SDK 的性能优势仍旧存在,两者混部迁移场景可能会长期存在。 +**Infrastructure** -从应用场景上,Dubbo 可能的部署环境包括: +- Changes in infrastructure scheduling mechanisms, leading to changes in operations (lifecycle), service governance, etc.; +- Service discovery capabilities are being decentralized, with Kubernetes abstracting Native Service Discovery. -1. 不使用 Kubernetes Native Service,Kubernetes 只作为容器编排调度设施,继续使用 Dubbo 自建的服务注册、发现机制; -2. 复用 Kubernetes Native Service,Dubbo 不再关心服务注册,Dubbo Client 负责服务发现与流量分配; -3. Dubbo sdk 往 Mesh 迁移,一方面要做到适应 Mesh 架构,成为 Mesh 体系下的 RPC 编程和通信方案;另一方面要做到 Dubbo 与 Mesh 架构长期共存,互相打通服务发现和治理体系; -4. Kubernetes 上与云下混合部署的平滑迁移支持,包括服务发现的统一与网络通信方案的打通。 +**Service Mesh - Cloud-Native Microservices Solutions** -从 Dubbo 功能划分上,将着重从以下方面提供对云原生基础设施的支持: +- Mesh provides solutions for cross-language and SDK upgrades; the Dubbo SDK needs to collaborate with Mesh to achieve functional, protocol, service governance, and other adaptations; +- Mesh has not been widely rolled out yet; its suitability is more geared towards applications that focus on traffic control, and the performance advantages of traditional SDKs still exist; mixed deployment scenarios might persist for a long time. -- **生命周期**:Dubbo 与 Kubernetes 调度机制绑定,保持服务生命周期与 Pod 容器等生命周期的自动对齐; -- **治理规则**:服务治理规则在规则体、规则格式方面进行优化,如规则体以 YAML 描述、取消过滤规则对 IP 的直接依赖,定义规则特有的 CRD 资源等; -- **服务发现**:支持 K8S Native Service 的服务发现,包括 DNS、API-Server,支持 xDS 的服务发现; -- **Mesh 架构协作**:构建下一代的基于 HTTP/2的通信协议,支持 xDS 的标准化的数据下发。 +Application scenarios for Dubbo's deployment may include: -新一代的 RPC 协议和应用级服务发现模型将会是这一部分的前置基础。 +1. Not using Kubernetes Native Service, where Kubernetes serves solely as a container orchestration and scheduling facility, continuing to use the self-built service registration and discovery mechanisms in Dubbo; +2. Reutilizing Kubernetes Native Service, where Dubbo no longer concerns itself with service registration and Dubbo Client is responsible for service discovery and traffic allocation; +3. Transitioning Dubbo SDK towards Mesh, where it needs to adapt to Mesh architecture, establishing an RPC programming and communication solution under the Mesh system; used to ensure long-term coexistence and interoperability of service discovery and governance systems between Dubbo and Mesh architectures; +4. Smooth migration support for hybrid deployments between K8S and non-cloud environments, including unification of service discovery and facilitation of network communication solutions. -# 总结与展望 +From Dubbo's functional perspective, support for cloud-native infrastructures will focus on the following areas: -作为系列文章开篇,我们在这里对 Dubbo 过去一年的成绩做了简要的总结与回顾,包括 Dubbo 社区、产品迭代的发展。接下来我们会看到更多来自深度 Dubbo 用户的落地经验分享,Dubbo-go 子社区的发展故事等。更重要的,我们也对下一代云原生 Dubbo - Dubbo 3.0 做了展望,后续关于 Dubbo 3.0 Roadmap、方案设计与进展解析等也将在此系列中发布。 +- **Lifecycle:** Binding Dubbo with Kubernetes scheduling mechanisms to keep service lifecycles autonomously aligned with Pod container lifecycles; +- **Governance Rules:** Optimizing service governance rules in terms of rule bodies and formats, such as describing rule bodies in YAML, eliminating dependencies on filtering rules for IPs, and defining unique CRD resources for rules; +- **Service Discovery:** Supporting service discovery of K8S Native Service, including DNS and API-Server, supporting xDS for service discovery; +- **Mesh Architecture Collaboration:** Building next-generation communication protocols based on HTTP/2 and supporting standardized data dispatching for xDS. +The next-generation RPC protocol and application-level service discovery model will serve as foundational elements of this part. +# Summary and Outlook +As the opening of the series of articles, we provided a brief summary and review of Dubbo's achievements over the past year, including the development of the Dubbo community and product iterations. Next, we will see more in-depth experience sharing from deep Dubbo users and the development stories of the Dubbo-go sub-community. More importantly, we have also projected the next-generation cloud-native Dubbo - Dubbo 3.0, with future releases regarding the Dubbo 3.0 Roadmap, design plans, and progress analyses set to be published in this series. diff --git a/content/en/blog/news/dubbo-meetup-chengdu.md b/content/en/blog/news/dubbo-meetup-chengdu.md index fc4c4625253a..16f9f97b464b 100644 --- a/content/en/blog/news/dubbo-meetup-chengdu.md +++ b/content/en/blog/news/dubbo-meetup-chengdu.md @@ -11,7 +11,7 @@ description: The 4th Dubbo Developer Salon was held in Chengdu on August 26. ## In-depth Communication with Users -On August 26, from 10:00 to 12:00, we invited four companies: Truck Alliance, Yuntu Jin控, former BBD, and Feiyu Star, to participate in face-to-face discussions with open-source enthusiasts and heavy users. According to participant feedback, many questions about Dubbo were answered, especially about how to contribute to the community and the value points brought by donating code. We hope to engage more deeply in the Dubbo community and activities in the future. +On August 26, from 10:00 to 12:00, we invited four companies: Truck Alliance, Yuntu Jin Control, former BBD, and Feiyu Star, to participate in face-to-face discussions with open-source enthusiasts and heavy users. According to participant feedback, many questions about Dubbo were answered, especially regarding how to contribute to the community and the value points brought by donating code. We hope to engage more deeply in the Dubbo community and activities in the future. ## Meetup Event Information @@ -25,3 +25,4 @@ Aliware Open Source•Chengdu Station - Apache Dubbo Developer Salon was held on Registration link: http://www.huodongxing.com/event/7453091088400 ![img](/imgs/blog/dubbo-chengdu-meetup-img.jpg) + diff --git a/content/en/blog/news/dubbo2-js.md b/content/en/blog/news/dubbo2-js.md index c99c3039530e..da31c0ac8af1 100644 --- a/content/en/blog/news/dubbo2-js.md +++ b/content/en/blog/news/dubbo2-js.md @@ -6,22 +6,22 @@ description: > This article introduces how to use Dubbo.js to implement cross-language calls. --- -> [dubbo2.js](https://github.com/dubbo/dubbo2.js) is a Dubbo client for node.js developped by [Qianmiwang](https://www.qianmi.com/). It supports Dubbo's native protocol, which makes the RPC calls between javascript and java efficient and agile. This tool has been contributed to Dubbo's community. +> [dubbo2.js](https://github.com/dubbo/dubbo2.js) is a Dubbo client for node.js developed by [Qianmiwang](https://www.qianmi.com/). It supports Dubbo's native protocol, which makes the RPC calls between javascript and java efficient and agile. This tool has been contributed to Dubbo's community. ## Cross-language calls for micro service -Nowadays, Internet architecture tends to be micro-service way. The discussions about micro-service architecture becomes the most mentioned topic in different technical conferences. In China, most of the companies, such as Qianmiwang, choose Dubbo as their micro-servie architecture solution. As most of the internet companies, Qianmiwang uses various of programming languages. Java is for most of the backend services. Each business based on these backend can choose its own programming language such as go, python and javascript. Therefore, here comes a challenge, cross language calls. Some well mentioned solutions are as follows: +Nowadays, Internet architecture tends to be micro-service way. The discussions about micro-service architecture become the most mentioned topic in different technical conferences. In China, most of the companies, such as Qianmiwang, choose Dubbo as their micro-service architecture solution. As most of the internet companies, Qianmiwang uses various programming languages. Java is for most of the backend services. Each business based on these backend can choose its own programming language such as go, python and javascript. Therefore, here comes a challenge, cross-language calls. Some well-known solutions are as follows: - - Spring cloud. Spring cloud provides a set of components for micro-service development. It is based on HTTP protocol and is designed in the restful way, which makes it support cross-language calls. Other languages can call the services simply by implementing an HTTP interface. - - Service mesh. People call service mesh the next generation of micro-service framework. The core of this solution is SideCar. Even though the concept of SideCar changes a lot during the revolution of Service mesh, its main job never changed: providing reliable communication between different services. - - Motan. [Motan](https://github.com/weibocom/motan) is an open source cross-language service framework developped by Sina Weibo. Its early version only supports motan-java. However, as the new versions come out, more languages are supported in order to handle the cross-language problem. Its newest version(1.1.0) provides motan-go, motan-php, motan-openresty, etc. Similar to SideCar in Service mesh, Motan forwards messages by mortan-go, which can be considered as an agent. Meanwhile, motan2, its own protocol, is built for cross-language calls. + - Spring cloud. Spring cloud provides a set of components for micro-service development. It is based on HTTP protocol and is designed in the RESTful way, which makes it support cross-language calls. Other languages can call the services simply by implementing an HTTP interface. + - Service mesh. People call service mesh the next generation of micro-service framework. The core of this solution is SideCar. Even though the concept of SideCar changes a lot during the evolution of Service mesh, its main job never changed: providing reliable communication between different services. + - Motan. [Motan](https://github.com/weibocom/motan) is an open-source cross-language service framework developed by Sina Weibo. Its early version only supports motan-java. However, as new versions come out, more languages are supported to handle the cross-language problem. Its newest version (1.1.0) provides motan-go, motan-php, motan-openresty, etc. Similar to SideCar in Service mesh, Motan forwards messages via mortan-go, which can be considered as an agent. Meanwhile, motan2, its own protocol, is built for cross-language calls. According to the solutions below, there are two ways to solve the cross-language calls problem: - communicating by a common protocol. - implementing an agent as a protocol adapter. - When a new team is choosing technical solutions, what I mentioned below could be our candidates. Meanwhile, the old system's compatibility and migration costs should also be considered. The first trial we did is to work on RPC protocol. + When a new team is choosing technical solutions, what I mentioned could be our candidates. Meanwhile, the old system's compatibility and migration costs should also be considered. The first trial we did is to work on RPC protocol. ## Cross-language calls by a common protocol @@ -29,17 +29,17 @@ Nowadays, Internet architecture tends to be micro-service way. The discussions a ![springmvc](/imgs/blog/springmvc.png) - Before achieving the real cross-language calls, the most common solution is to use the http protocol. We can call Dubbo provider indirectly by controller/restController provided by springmvc. This is easy to carry out, but there are lots of inconveniences. firstly, a call will go through too many nodes. Secondly, an extra communication layer (for http protocol) will be involved, but it could have been handled simply by the TCP protocol. Thirdly, we need to implement the RPC interface in the controller part. This will be extra work for developers. + Before achieving the real cross-language calls, the most common solution is to use the http protocol. We can call Dubbo provider indirectly by controller/restController provided by springmvc. This is easy to carry out, but there are lots of inconveniences. Firstly, a call will go through too many nodes. Secondly, an extra communication layer (for http protocol) will be involved, but it could have been handled simply by the TCP protocol. Thirdly, we need to implement the RPC interface in the controller part. This will be extra work for developers. ### We support some common protocols Most of the service management frameworks support multiple protocols, dubbo as well. Besides its own protocol, the common protocols such as Dangdangwang's [Rest](https://dangdangdotcom.github.io/dubbox/rest.html) protocol and Qianmiwang's [json-rpc](https://github.com/apache/dubbo-rpc-jsonrpc) protocol are also supported. - The developers getting used to traditional RPC interfaces might feel uncomfortable while working on restful RPC interfaces. On the one hand, this is not good for rebuilding new interfaces. On the other hand, restful style might make these interfaces incompatible with the other protocols used by old interfaces. Of course, if there is no old system problems, using Rest protocol is the easiest implementation of cross-language calls, since most of the languages support it. + The developers used to traditional RPC interfaces might feel uncomfortable while working on restful RPC interfaces. On the one hand, this is not good for rebuilding new interfaces. On the other hand, restful style might make these interfaces incompatible with the other protocols used by old interfaces. Of course, if there are no old system problems, using Rest protocol is the easiest implementation of cross-language calls since most of the languages support it. - Even if Dubbo has tried on restful interface, the difference between rest architecture and RPC architecture should not be ignored. Rest architecture defines each resources, and it needs basic operations of http protocols such as GET, POST, DELETE, PUT. In my opinion, a Rest protocol is more for calls between different systems on the internet, while RPC is suitable for inner system calls. Similar to Rest protocol, json-rpc is also implemented by text sequence and http protocol. Using json-rpc can also solve the cross-language problems, meanwhile, it makes our solution compatible with old interfaces and there is no need to adapt to the restful style. + Even if Dubbo has tried on restful interface, the difference between rest architecture and RPC architecture should not be ignored. Rest architecture defines each resource, and it needs basic operations of http protocols such as GET, POST, DELETE, PUT. In my opinion, a Rest protocol is more for calls between different systems on the internet, while RPC is suitable for inner system calls. Similar to Rest protocol, json-rpc is also implemented by text sequence and http protocol. Using json-rpc can also solve the cross-language problems, meanwhile, it makes our solution compatible with old interfaces and there is no need to adapt to the restful style. - Json-rpc is Qianmiwang's early solution for cross-language protocol. They open-sourced their [dubbo-client-py](https://github.com/dubbo/dubbo-client-py) and [dubbo-node-client](https://github.com/QianmiOpen/dubbo-node-client), two clients based on json-rpc protocol. With these tools, we can easily call the rpc services provided by dubbo-provider-java with while using python or node.js. The inner system calls for java services are still mainly implemented by Dubbo protocol. In addition, in order to adapt the old system, two protocols could be configured. + Json-rpc is Qianmiwang's early solution for cross-language protocol. They open-sourced their [dubbo-client-py](https://github.com/dubbo/dubbo-client-py) and [dubbo-node-client](https://github.com/QianmiOpen/dubbo-node-client), two clients based on json-rpc protocol. With these tools, we can easily call the rpc services provided by dubbo-provider-java while using python or node.js. The inner system calls for java services are still mainly implemented by Dubbo protocol. In addition, in order to adapt the old system, two protocols could be configured. ``` xml @@ -48,18 +48,18 @@ Nowadays, Internet architecture tends to be micro-service way. The discussions a ### Customized Protocols for Cross-language Support -The so-called protocol of the microservice framework can be simply interpreted as: message format and serialization scheme. Generally, the service governance framework would provide numbers of protocol configuration items for users to choose from. In addition to the above two common protocols,there exists some other customized protocols like the dubbo protocol, the default protocol for the dubbo framework, and Motan2, a cross-language protocol provided by the motan framework. +The so-called protocol of the microservice framework can be simply interpreted as: message format and serialization scheme. Generally, the service governance framework would provide numbers of protocol configuration items for users to choose from. In addition to the above two common protocols, there exist some other customized protocols like the dubbo protocol, the default protocol for the dubbo framework, and Motan2, a cross-language protocol provided by the motan framework. #### Motan2 for cross-language support ![motan2](/imgs/blog/motan-protocol-en.png) -In the original Motan protocol, the protocol message consisted only of the Header and the Body, making deserialization indispensable for acquiring data stored in the Body, like path, param and group, which is terribly unfriendly for cross-language support. Therefore, the content of the protocol was modifiedin Motan2, Weibo released the open-source projects, [motan-go](https://github.com/weibocom/motan-go/), [motan-php](https://github.com/weibocom/motan-php) and [motan-openresty](https://github.com/weibocom/motan-openresty). It used motan-go as an interpreter and the Simple serialization scheme to serialize the Body of protocol message. (Simple is a comparably weaker serialization scheme) +In the original Motan protocol, the protocol message consisted only of the Header and the Body, making deserialization indispensable for acquiring data stored in the Body, like path, param and group, which is terribly unfriendly for cross-language support. Therefore, the content of the protocol was modified in Motan2, Weibo released the open-source projects, [motan-go](https://github.com/weibocom/motan-go/), [motan-php](https://github.com/weibocom/motan-php) and [motan-openresty](https://github.com/weibocom/motan-openresty). It used motan-go as an interpreter and the Simple serialization scheme to serialize the Body of protocol message. (Simple is a comparably weaker serialization scheme) ![agent](/imgs/blog/motan-agent.png) -After observation we find out that there is no big difference between the configuration of Motan2 and the dual protocol. It’s just that the agent here is implicit, and it co-exists with the main service. The most obvious difference is that different languages do not interact directly in agent scheme. +After observation, we find out that there is no big difference between the configuration of Motan2 and the dual protocol. It’s just that the agent here is implicit, and it co-exists with the main service. The most obvious difference is that different languages do not interact directly in the agent scheme. #### Dubbo for cross-language support @@ -71,22 +71,22 @@ Instead of cross-language support, the dubbo protocol was originally designed on Details in dubbo protocol header message: -- Magic: similar to magic number in Java bytes code files, which is used to determine whether it is a data pack of dubbo protocol. The magic number is the constant, 0xdabb. -- Flag: contains 8 bits. The lower four bits are used to indicate the type of serialization tool used for message body data (default hessian). Among the upper four bits, the 1 at first bit indicates request, the 1 at second bit indicates dual transfer, 1 at third bits indicates the heartbeat. -- Status: used toset response status. Dubbo defines some types for response. Details can be found in com.alibaba.dubbo.remoting.exchange.Response -- Invoke id: Message id,Type long, Unique indentifier for each request (Due to asynchronous communication, it is used to match the request to the corresponding returned response) -- Body length: message body length, type int,record bytes of body content. -- Body content: request param, where serializedresponse parameters are stored. +- Magic: similar to magic number in Java bytecode files, which is used to determine whether it is a data pack of dubbo protocol. The magic number is the constant, 0xdabb. +- Flag: contains 8 bits. The lower four bits are used to indicate the type of serialization tool used for message body data (default hessian). Among the upper four bits, the 1 at the first bit indicates request, the 1 at the second bit indicates dual transfer, the 1 at the third bit indicates the heartbeat. +- Status: used to set response status. Dubbo defines some types for response. Details can be found in com.alibaba.dubbo.remoting.exchange.Response +- Invoke id: Message id, Type long, Unique identifier for each request (Due to asynchronous communication, it is used to match the request to the corresponding returned response) +- Body length: message body length, type int, record bytes of body content. +- Body content: request param, where serialized response parameters are stored. -Protocol messages will eventually become bytes and be transmitted using TCP. Any language that supports network modules and has a socket will be able to be communicatedwith. Then, why cross-language support is difficult? There are two main obstaclesin calling service in Java using other languages: +Protocol messages will eventually become bytes and be transmitted using TCP. Any language that supports network modules and has a socket will be able to be communicated with. Then, why is cross-language support difficult? There are two main obstacles in calling a service in Java using other languages: -1. How can different languages ​​represent data types in java, especially dynamiclanguages with possible non-strict data types? -2. How to serialize string across language? +1. How can different languages ​​represent data types in java, especially dynamic languages with possible non-strict data types? +2. How to serialize string across languages? ## How does dubbo2.js solve problems? -We have analyzed two obstacles above. The key to dubbo2.js in solving these two problems depends on two class libraries: [js-to-java](https://github.com/node-modules/js-to-java),[hessian.js](https://github.com/node-modules/hessian.js). js-to-java, which makes nodejs have the ability to express Java objects. Hessian.js provides serialization capabilities. With the help of nodejs socket, and a duplicate set of dubbo protocol message format, we can finally achieve nodejs call to java-dubbo-provider. +We have analyzed two obstacles above. The key to dubbo2.js in solving these two problems depends on two class libraries: [js-to-java](https://github.com/node-modules/js-to-java), [hessian.js](https://github.com/node-modules/hessian.js). js-to-java, which makes nodejs have the ability to express Java objects. Hessian.js provides serialization capabilities. With the help of nodejs socket, and a duplicate set of dubbo protocol message formats, we can finally achieve nodejs calling to java-dubbo-provider. ## Quick Start @@ -110,7 +110,7 @@ Then we implement the interface: public class DemoProviderImpl implements DemoProvider { public String sayHello(String name) { System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); - return "Hello " + name + ", response form provider: " + RpcContext.getContext().getLocalAddress(); + return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); } @Override public String echo() { @@ -162,7 +162,7 @@ After that, we expose the dubbo se ``` -After we implemented all the configurations on server side, initiate an object initiater to register a dubbo service locally: +After we implemented all the configurations on the server side, initiate an object initiator to register a dubbo service locally: ```java public class Provider { @@ -245,7 +245,7 @@ DEBUG=dubbo* ts-node main.ts Checkout running results: ```sh -Hello kirito, response form provider: 172.19.6.151:20880 +Hello kirito, response from provider: 172.19.6.151:20880 ``` Congratulations! @@ -255,13 +255,12 @@ Congratulations! - Support zookeeper as register center - Support TCP Dubbo Native protocol -- Support directly Dubbo connection +- Support direct Dubbo connection - Support link tracing - Generate dubbo interface Automatically ## More details The sample code in this article is available here, [https://github.com/dubbo/dubbo2.js](https://github.com/dubbo/dubbo2.js). -If you don't know much about the dubbo protocol and want to understand how it works, the project provides a sub-moudle: java-socket-consumer, which is implemented in a process-oriented approach, realizing a process of sending dubbo protocal message with native socket and making function calls, and then get response. - +If you don't know much about the dubbo protocol and want to understand how it works, the project provides a sub-module: java-socket-consumer, which is implemented in a process-oriented approach, realizing a process of sending dubbo protocol message with native socket and making function calls, and then getting responses. diff --git a/content/en/blog/news/meet-dubbo.md b/content/en/blog/news/meet-dubbo.md index 2dcef366f349..08e7d34afad0 100644 --- a/content/en/blog/news/meet-dubbo.md +++ b/content/en/blog/news/meet-dubbo.md @@ -1,65 +1,65 @@ --- -title: "遇见Dubbo" -linkTitle: "遇见Dubbo" +title: "Meet Dubbo" +linkTitle: "Meet Dubbo" date: 2019-01-26 -tags: ["新闻动态"] +tags: ["News"] description: > - 本文记录了一个小白成长为Dubbo committer的过程。 + This article documents the journey of a novice growing into a Dubbo committer. --- -我是一个有Dubbo情节的程序员。 +I am a programmer with a Dubbo obsession. -Dubbo以不同方式,陪伴了我时间不长的整个代码生涯。不久前,通过社区投票,我被选举为`Committer`。当时我在朋友圈发了一句话,也是贯穿我从开始使用Dubbo、研究Dubbo、贡献Dubbo到最后成为`Committer`的全过程,一直为我提供内心无与伦比愉悦的源泉:成长这种事,能看见脚印特别幸福。 +Dubbo has accompanied me throughout my coding career for a short time in various ways. Not long ago, I was elected as a `Committer` through community voting. At that time, I posted a phrase on my social network, which encapsulated my journey from starting to use Dubbo, researching Dubbo, contributing to Dubbo, and finally becoming a `Committer`, providing me with a unique source of internal joy: it’s particularly happy to see footprints in the process of growth. -今天来个回忆杀,把我和Dubbo的那些事拿出来说说。 +Today, let’s take a nostalgic look back at my experiences with Dubbo. -## 小白 +## Novice -我知道Dubbo,是在我大三翘课出去实习的时候,那个时候是无知的,我眼里最牛的人就是能熟练使用各种配置,精通SSH框架的人。就是在那种情况下,我外出实习,遇到了一群影响我至今的人。当时也是机缘巧合,我们进行了两个非常小的模块的服务化改造。那时的团队除了我们老大,全是一群新兵蛋子,老大指哪我们打哪。老大说,就用Dubbo吧,从那时候开始,我才知道,哦!原来还有一种东西叫做RPC,还有个阿里巴巴的RPC框架叫Dubbo。 +I first learned about Dubbo when I was an intern skipping classes in my junior year. Back then, I was ignorant, and the coolest people in my eyes were those who could skillfully use various configurations and were proficient in the SSH framework. In that situation, during my internship, I encountered a group of people who have influenced me to this day. By chance, we undertook the service transformation for two very small modules. At that time, besides our team leader, the rest were all newbies, following his lead. He suggested using Dubbo, and that’s when I learned, oh! There’s something called RPC, and Alibaba's RPC framework is Dubbo. -苦于当时非常有限的水平和高强度的工作,我和Dubbo的缘分也就停留在一面之缘的程度——要说认识谈不上,说不认识也牵强。 +Due to my limited skills and intense work, my connection with Dubbo was superficial—not quite knowing it, but not completely unfamiliar either. ## Contributor -我在二维火任职的一年算是我Dubbo生涯里承上启下的一年。二维火当时自己维护了一个Dubbo的分支,有一群对Dubbo非常了解的人。那时候,工作结束搞Dubbo,周六加班研究Dubbo。看源码,看不懂就debug一下,debug也不明白就问,问人,问google,里外折腾了个遍。 +My year at Two-dimensional Fire was a transitional period in my Dubbo journey. At that time, Two-dimensional Fire maintained a branch of Dubbo and had a group of individuals very familiar with it. After work, we would discuss Dubbo, often working overtime on Saturdays to study it. I’d look at the source code, debug when I didn’t understand, and if I was still stuck, I’d ask people or Google, going through all sorts of efforts. -后来毕业加入网易云音乐。大概是今年五月份的时候,我发现了一个Dubbo的小bug,并且给Dubbo提交了pull request。在第一次被merge之后,非常受鼓舞,这才有了后续的故事。后来,回看这第一次提交,真的算是我和Dubbo的一个拐点,拐弯之后,我才逐渐走上一条成为`Committer`的路。 +Later, I graduated and joined NetEase Cloud Music. Around May this year, I discovered a small bug in Dubbo and submitted a pull request. After my first merge, I was very encouraged, leading to further developments. Reflecting back on this first submission, it truly marked a turning point in my journey with Dubbo, paving my path toward becoming a `Committer`. -可能很多人看到这里要望而却步了,这也是做开源给很多人留下的固有的印象——是不是没发现BUG就不能提交pull request,不能做贡献?其实完全不是的,这里给大家敲黑板划重点:其实很多贡献者的第一次贡献,贡献的并非代码,而是文档修改或者单元测试。相比于BUG或者新的Feature,单测和文档上的修复门槛就比较低了。 +Many people may hesitate when reading this, which is a common misconception about contributing to open source—thinking they must find a BUG to submit a pull request. This is entirely untrue; let's highlight a key point: many contributors' first contributions are not code, but documentation changes or unit tests. Compared to bugs or new features, the barrier for unit tests and documentation fixes is lower. -我自己的方法论就是:**先尝试增加单元测试,写单测的时候顺手debug+看代码。或者多看文档,了解框架的同时,发现错别字、语意不明或者文档上的链接干脆点不开的情况,直接提交PR到对应的仓库**。 +My method is: **try to add unit tests first, debug while writing tests and reading the code. Or read documentation more, while learning the framework, find typos, ambiguous meanings, or broken links, and submit PRs to the corresponding repository directly**. -万事开头难。第一次被merge代码,你就可以成为一个`Contributor`了。`Contributor`很多,但是`Committer`很少,下面继续说怎么从一个`Contributor`成长为独当一面的`Committer`。 +Starting is always difficult. Once your code gets merged for the first time, you become a `Contributor`. There are many Contributors, but few Committers. Next, I’ll continue discussing how to grow from a `Contributor` to an independent `Committer`. ## Committer -做开源和写代码一样,都不是一朝一夕的事情,而是量变促成质变的过程。这是一个没捷径可走的过程,欲带皇冠必承其重。身后的Dubbo功底自不必多说,这个部分主要是想跟大家说一下除了钻研和热爱之外,其他需要注意的地方。 +Contributing to open source is like writing code; it’s not something that happens overnight. It’s a process where quantitative change leads to qualitative change. This is a process with no shortcuts; to wear the crown, one must bear its weight. The foundational knowledge of Dubbo goes without saying—this section highlights other important aspects to consider beyond research and passion. -首先是多提交高质量PR。任何一个PR都会被review,代码中的问题,思路上的偏差,都会被指正。提交PR是一个反复琢磨的过程。PR的质量不能简单的归结于新增了多少行代码,高质量的PR一定是经过缜密思考的,为什么删除代码,新增的代码有什么意义,修改之后有什么效果等等。希望大家更加重视质量而非数量,眼光放长远,相信你的收获一定会非常大! +First, submit high-quality PRs. Every PR will be reviewed; issues in code or deviations in thought will be pointed out. Submitting a PR is a reflective process. The quality of a PR cannot simply be measured by how many lines of code are added. A high-quality PR is the result of meticulous consideration—why certain code is deleted, the significance of the new code, and the effects of the changes, etc. I hope everyone prioritizes quality over quantity, aiming for long-term benefits. -第二个就是,我们需要培养一种思维方式——Apache Way。一句话概括就是**社区重于代码**。Apache是一个注重社区的的开源组织,其行为方式相比于目前我们的开发方式,还是有所不同,这里我举一个Apache Way的例子,用以说明传统方式相较于Apache Way的区别在哪里,这里假设我想为Dubbo开发一个功能A。 +The second point is that we need to cultivate a mindset—the Apache Way. In summary, **the community is more important than the code**. The Apache Software Foundation emphasizes community, and its operational methods differ from our current development practices. Here's an example of the Apache Way to illustrate the difference between traditional methods and the Apache Way, assuming I want to develop a feature A for Dubbo. -**Old Way**: +**Old Way**: -1. 功能设计:做一个设计文档(根据功能大小而定),大概划定需要修改或新增的类,大体设计接口等。 -2. 开发代码。 -3. 提交PR。 -4. Review & Merge +1. Design the feature: Create a design document (depending on the feature size), outline necessary class modifications or additions, and roughly design interfaces. +2. Develop the code. +3. Submit the PR. +4. Review & Merge. -可以看到,我们整个过程中,真正与社区交互的只有最后一步。 +As you can see, in this process, the only real interaction with the community is in the final step. -**Apache Way**: +**Apache Way**: -1. 功能设计:发送邮件至mailing list并且提交ISSUE,与社区成员共同探讨,产出一个设计文档(根据功能大小而定),大概划定需要修改或新增的类,大体设计接口等。然后再次发送邮件并且回复ISSUE,通知社区设计文档定稿或者方案确定。 -2. 开发代码:发送邮件至社区,通知社区成员我即将投入开发功能A,如需帮助,可以同时说明需要协助。 -3. 提交PR:发送邮件并且回复ISSUE,提醒社区开发结束,贴上PR地址以通知社区review代码。 -4. Review + Merge后,发送邮件并且关闭ISSUE,通知社区功能A的开发功能告一段落。 +1. Design the feature: Send an email to the mailing list and submit an ISSUE for discussion with community members, produce a design document (depending on the feature size), and outline necessary class modifications or additions. Then, resend the email and reply to the ISSUE to notify the community that the design document is finalized or the plan is determined. +2. Develop the code: Send an email to the community, notifying members that I will start developing feature A and state any help needed. +3. Submit the PR: Send an email and respond to the ISSUE, reminding the community that the development is complete, and share the PR link for review. +4. After Review + Merge, send an email and close the ISSUE, notifying the community that development of feature A is complete. -可以看到,Apache Way就是在整个开发过程中,不断地与社区交互,最大发挥社区的功能,汲取众人之力,这才是所谓**社区**以及所谓**开源**的含义。 +As you can see, the Apache Way involves constant interaction with the community throughout the development process, maximizing community engagement and harnessing collective strength. This is the essence of **community** and **open source**. -## 结尾 +## Conclusion -Dubbo目前还在孵化阶段,整个Dubbo社区还不完善,我们也在跟着Dubbo一起成长,我们非常希望更多的Dubbo爱好者深度参与到Dubbo中,为你的代码生涯树一个里程碑。 +Dubbo is still in its incubation phase, and the entire Dubbo community isn’t fully developed yet. We are growing alongside Dubbo and sincerely hope more Dubbo enthusiasts will participate deeply to create a milestone in your coding career. -相信过程,收获结果;天道酬勤,功不唐捐! +Believe in the process, and you will reap the results; diligence is rewarded, and efforts are not in vain! diff --git a/content/en/blog/news/openatom-opensopurce-competition-2024.md b/content/en/blog/news/openatom-opensopurce-competition-2024.md index 3b3ad55189d8..779e69a78917 100644 --- a/content/en/blog/news/openatom-opensopurce-competition-2024.md +++ b/content/en/blog/news/openatom-opensopurce-competition-2024.md @@ -120,7 +120,6 @@ Overall, this topic aims to construct a universal zero-trust system, offering th - [https://kuma.io/docs/2.5.x/policies/mutual-tls/](https://kuma.io/docs/2.5.x/policies/mutual-tls/) - [https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol#xds-protocol-delta](https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol#xds-protocol-delta) - ### 4 Next Generation Microservice Cluster Monitoring Mechanism for Cloud Native, Covering Kubernetes, Nacos (Golang) #### 4.1 Topic Background and Goals @@ -235,3 +234,4 @@ For any questions about the competition topics, please scan to join the followin ### Competition Details Poster ![openatom-2024](/imgs/blog/2024/01/openatom/openatom-2024.png) + diff --git a/content/en/blog/news/prepare-an-apache-release.md b/content/en/blog/news/prepare-an-apache-release.md index b326660f005e..3ff274b09542 100644 --- a/content/en/blog/news/prepare-an-apache-release.md +++ b/content/en/blog/news/prepare-an-apache-release.md @@ -1,40 +1,40 @@ --- -title: "如何准备Apache Release" -linkTitle: "如何准备Apache Release" +title: "How to Prepare Apache Release" +linkTitle: "How to Prepare Apache Release" date: 2018-09-02 -tags: ["新闻动态"] +tags: ["News"] description: > - 本文介绍了Apache如何发布内容和流程 + This article describes how Apache releases content and the processes involved. --- -## 理解Apache发布的内容和流程 +## Understanding Apache Release Content and Processes -总的来说,Source Release是Apache关注的重点,也是发布的必须内容;而Binary Release是可选项,Dubbo可以选择是否发布二进制包到Apache仓库或者发布到Maven中央仓库。 +In general, the Source Release is the focus of Apache and is essential for the release; the Binary Release is optional. Dubbo can choose whether to publish a binary package to the Apache repository or release it to the Maven Central Repository. -请参考以下链接,找到更多关于ASF的发布指南: +Please refer to the following links for more about ASF's release guidelines: - [Apache Release Guide](http://www.apache.org/dev/release-publishing) - [Apache Release Policy](http://www.apache.org/dev/release.html) - [Maven Release Info](http://www.apache.org/dev/publishing-maven-artifacts.html) -## 本地构建环境准备 +## Preparing Local Build Environment -主要包括签名工具、Maven仓库认证相关准备 +Mainly includes signing tools and Maven repository authentication preparations. -### 安装GPG +### Installing GPG -详细文档请参见[这里](https://www.gnupg.org/download/index.html), Mac OS下配置如下 +See detailed documentation [here](https://www.gnupg.org/download/index.html), for Mac OS the configuration is as follows: ```sh $ brew install gpg -$ gpg --version #检查版本,应该为2.x +$ gpg --version # check version, should be 2.x ``` -### 用gpg生成key +### Generate Key with gpg -根据提示,生成key +Follow the prompts to generate the key. - ```shell +```shell $ gpg --full-gen-key gpg (GnuPG) 2.0.12; Copyright (C) 2009 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. @@ -68,41 +68,41 @@ $ gpg --version #检查版本,应该为2.x "Robert Burrell Donkin (CODE SIGNING KEY) " Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O - You need a Passphrase to protect your secret key. # 填入密码,以后打包过程中会经常用到 - ``` + You need a Passphrase to protect your secret key. # Enter the password, it will be needed often during the packaging process +``` -### 查看key id +### View Key ID ```sh $ gpg --list-keys -pub rsa4096/28681CB1 2018-04-26 # 28681CB1就是key id +pub rsa4096/28681CB1 2018-04-26 # 28681CB1 is the key id uid [ultimate] liujun (apache-dubbo) sub rsa4096/D3D6984B 2018-04-26 -# 通过key id发送public key到keyserver +# Send public key to keyserver using key id $ gpg --keyserver pgpkeys.mit.edu --send-key 28681CB1 -# 其中,pgpkeys.mit.edu为随意挑选的keyserver,keyserver列表为:https://sks-keyservers.net/status/,为相互之间是自动同步的,选任意一个都可以。 +# Here, pgpkeys.mit.edu is a randomly selected keyserver, the keyserver list is: https://sks-keyservers.net/status/, which automatically syncs with each other; any one can be selected. ``` -如果有多个public key,设置默认key。修改`~/.gnupg/gpg.conf` +If there are multiple public keys, set a default key. Modify `~/.gnupg/gpg.conf`. ```sh # If you have more than 1 secret key in your keyring, you may want to # uncomment the following option and set your preferred keyid. default-key 28681CB1 ``` -如果有多个public key, 也可以删除无用的key: +If there are multiple public keys, you can also delete unused keys: ```sh -### 先删除私钥,再删除公钥 -$ gpg --yes --delete-secret-keys shenglicao2@gmail.com ###老的私钥,指明邮箱即可 +### First delete the private key, then delete the public key +$ gpg --yes --delete-secret-keys shenglicao2@gmail.com ### Old private key, specify the email address $ gpg --delete-keys 1808C6444C781C0AEA0AAD4C4D6A8007D20DB8A4 ``` -> PS: 最新版本经过实测,本地没有gpg.conf这个文件,因此如果在执行过程中遇到签名失败,可以参考这个文章:https://blog.csdn.net/wenbo20182/article/details/72850810 或 https://d.sb/2016/11/gpg-inappropriate-ioctl-for-device-errors +> PS: The latest version has been tested, and there is no gpg.conf file locally, so if you encounter signing failures during the execution process, you can refer to this article: https://blog.csdn.net/wenbo20182/article/details/72850810 or https://d.sb/2016/11/gpg-inappropriate-ioctl-for-device-errors -### 设置Apache中央仓库 +### Set Up Apache Central Repository -Dubbo项目的父pom为Apache pom(2.7.0以上版本需要,2.6.x发布版本不需要此操作) +The parent POM for the Dubbo project is Apache POM (required for versions 2.7.0 and above, not needed for 2.6.x release versions). ```xml @@ -111,8 +111,7 @@ Dubbo项目的父pom为Apache pom(2.7.0以上版本需要,2.6.x发布版本不 19 ``` - 添加以下内容到.m2/settings.xml - 所有密码请使用[maven-encryption-plugin](http://maven.apache.org/guides/mini/guide-encryption.html)加密后再填入 +Add the following content to .m2/settings.xml. All passwords should be filled in after being encrypted with [maven-encryption-plugin](http://maven.apache.org/guides/mini/guide-encryption.html). ```xml ... @@ -130,7 +129,7 @@ Dubbo项目的父pom为Apache pom(2.7.0以上版本需要,2.6.x发布版本不 ... - + gpg.passphrase @@ -140,195 +139,193 @@ Dubbo项目的父pom为Apache pom(2.7.0以上版本需要,2.6.x发布版本不 ``` -## 打包&上传 +## Packaging & Uploading -### 准备分支 +### Prepare Branch -从主干分支拉取新分支作为发布分支,如现在要发布$`{release_version}`版本,则从2.6.x拉出新分支`${release_version}-release`,此后`${release_version}` Release Candidates涉及的修改及打标签等都在`${release_version}-release`分支进行,最终发布完成后合入主干分支。 +Pull a new branch from the main branch as a release branch. If you are going to release version `$`{release_version}`, create a new branch `${release_version}-release` from 2.6.x. All modifications and tagging related to `${release_version} Release Candidates` will be done in the `${release_version}-release` branch, and after the final release is completed, it will be merged back into the main branch. -### 编译打包 +### Compile and Package -首先,在`${release_version}-release`分支验证maven组件打包、source源码打包、签名等是否都正常工作。**2.6.x记得要使用1.6进行编译打包** +First, verify that the Maven components packaging, source code packaging, signing, etc., are functioning correctly in the `${release_version}-release` branch. **For 2.6.x, make sure to use 1.6 for compiling and packaging.** ```shell $ mvn clean install -Prelease $ mvn deploy ``` -上述命令将snapshot包推送到maven中央仓库 +The above commands will push the snapshot package to the Maven Central Repository. -### 用maven-release-plugin发布 +### Release with maven-release-plugin -先用dryRun验证是否ok +First, use dryRun to verify that it is okay. ```shell $ mvn release:prepare -Prelease -Darguments="-DskipTests" -DautoVersionSubmodules=true -Dusername=YOUR GITHUB ID-DdryRun=true ``` -验证通过后,执行release:prepare +After validation passes, execute release:prepare. ```shell $ mvn release:clean $ mvn release:prepare -Prelease -Darguments="-DskipTests" -DautoVersionSubmodules=true -Dusername=YOUR GITHUB ID -DpushChanges=false ``` -> 执行release插件时,如果指定了`-DpushChanges=true`, 插件会自动提交到远端的GitHub仓库中,此时就需要输入GitHub的密码,注意不是输入web页面的登录密码,而是一个`Personal access tokens`,获取方式详见[这里](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) +> When executing the release plugin, if `-DpushChanges=true` is specified, the plugin will automatically commit to the remote GitHub repository. At this time, you need to enter the GitHub password, which is not the web page login password, but rather a `Personal access tokens`. Please see [here](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) for how to obtain it. -> 这里有一点要注意的是tag, 在执行过程中,需要选择发布的artifactId, 下一个版本artifactId以及发布版本的tag, tag默认的是dubbo-parent-xxxx,需要改成dubbo-xxxx +> One thing to note is the tag. During execution, you need to select the released artifactId, the next version artifactId, and the released version tag. The tag defaults to dubbo-parent-xxxx, which needs to be changed to dubbo-xxxx. -执行完上述步骤后,你会发现: -1. `source-release.zip` 和 `bin-release.zip`包已经生成在`dubbo-distribution`目录下,请解压并检查文件是否完整 -2. 本地已经打出相应的tag,同时新增一个commit,名叫`[maven-release-plugin] prepare release dubbo-x.x.x` -3. 分支版本自动升级为`${release_version+1}-SNAPSHOT`,同时新增一个commit,名叫`[[maven-release-plugin] prepare for next development iteration` +After completing the above steps, you will find: +1. `source-release.zip` and `bin-release.zip` packages have been generated in the `dubbo-distribution` directory. Please unzip and check if the files are complete. +2. A corresponding tag has been created locally, along with a new commit named `[maven-release-plugin] prepare release dubbo-x.x.x`. +3. The branch version automatically upgrades to `${release_version+1}-SNAPSHOT`, along with a new commit named `[[maven-release-plugin] prepare for next development iteration`. -> 如果指定了`-DpushChanges=true`, 则本地提交会自动推送到远端的GitHub仓库。根据经验,建议不要指定为true,请设置为false,待本地检查通过之后再手动提交 +> If `-DpushChanges=true` is specified, local commits will be automatically pushed to the remote GitHub repository. Based on experience, it is recommended not to set it as true, please set it to false, and manually commit after local verification. -执行release:perform,做staging发布 +Execute release:perform to do the staging release. ```shell $ mvn -Prelease release:perform -Darguments="-DskipTests" -DautoVersionSubmodules=true -Dusername=YOUR GITHUB ID ``` -此时插件会自动下载远端的tag对应的源码,编译后,将所有Artifacts发布到配置的远程[maven仓库](http://repository.apache.org),处于staging状态。 +At this time, the plugin will automatically download the source code corresponding to the remote tag, compile it, and publish all artifacts to the configured remote [Maven repository](http://repository.apache.org), which is in a staging state. -#### 注意点 +#### Notes -- 在deploy执行过程中,有可能因为网络等原因被中断,如果是这样,可以重新开始执行。 -- deploy执行到maven仓库的时候,请确认下包的总量是否正确。多次出现了包丢失的情况,特别是dubbo-parent包。 +- During the deploy execution, it may be interrupted due to network issues. If this is the case, you can start executing again. +- When the deploy command reaches the Maven repository, please confirm whether the total number of packages is correct. There have been multiple cases of package loss, especially for the dubbo-parent package. -## 准备Apache发布 +## Preparing for Apache Release -1. 准备svn本机环境(Apache使用svn托管项目的发布内容) +1. Prepare the local environment for svn (Apache uses svn to host project release content). -2. 将dubbo checkout到本地目录 +2. Check out dubbo to the local directory. ```shell $ svn checkout https://dist.apache.org/repos/dist/dev/dubbo - # 假定本地目录为 ~/apache/incubator/dubbo + # Assume the local directory is ~/apache/incubator/dubbo ``` -3. 当前发布版本为${release_version},新建目录 +3. For the current release version of ${release_version}, create a new directory. ```shell - $ cd ~/apache/incubator/dubbo # dubbo svn根目录 + $ cd ~/apache/incubator/dubbo # Dubbo svn root directory $ mkdir ${release_version} ``` -4. 添加public key到[KEYS](https://dist.apache.org/repos/dist/dev/dubbo/KEYS)文件并提交到SVN仓库(第一次做发布的人需要做这个操作,具体操作参考KEYS文件里的说明)。KEYS主要是让参与投票的人在本地导入,用来校验sign的正确性 +4. Add the public key to the [KEYS](https://dist.apache.org/repos/dist/dev/dubbo/KEYS) file and commit it to the SVN repository (first-timers need to perform this operation; refer to the KEYS file for specific instructions). The KEYS file mainly allows voters to import it locally to verify the correctness of the signatures. ```sh $ gpg -a --export your_key_id >> KEYS ``` -5. 拷贝`distribution/target`下的source相关的包到svn本地仓库`dubbo/${release_version}` +5. Copy the source-related packages from `distribution/target` to the SVN local repository `dubbo/${release_version}`. -6. 生成sha512签名 +6. Generate sha512 signatures. - 针对`source-release.zip` + For `source-release.zip`: ```shell $ shasum -a 512 apache-dubbo-${release_version}-source-release.zip >> apache-dubbo-${release_version}-source-release.zip.sha512 ``` - - 针对`bin-release.zip`,需要增加`-b`参数,表明是一个二进制文件 + + For `bin-release.zip`, the `-b` parameter needs to be added to indicate that it is a binary file. ```shell $ shasum -b -a 512 apache-dubbo-${release_version}-bin-release.zip >> apache-dubbo-${release_version}-bin-release.zip.sha512 ``` +7. If there is a binary release to publish simultaneously. -7. 如果有binary release要同时发布 + In the `distribution/target` directory, copy `bin-release.zip` and `bin-release.zip.asc` to the SVN local repository `dubbo/${release_version}`, referencing step 6 to generate sha512 signatures. - 在`distribution/target`目录下,拷贝`bin-release.zip`以及`bin-release.zip.asc`到svn本地仓库`dubbo/${release_version}`,参考第6步,生成sha512签名。 - -8. 提交到Apache svn +8. Commit to Apache svn. ```shell $ svn status $ svn commit -m 'prepare for ${release_version} RC1' ``` -## 验证Release Candidates +## Validate Release Candidates -详细的检查列表请参考官方的[check list](https://cwiki.apache.org/confluence/display/INCUBATOR/Incubator+Release+Checklist) +For a detailed checklist, refer to the official [check list](https://cwiki.apache.org/confluence/display/INCUBATOR/Incubator+Release+Checklist). -首先,从一下地址下载要发布的Release Candidate到本地环境: +First, download the release Candidate you want to validate from the following address to the local environment:
 https://dist.apache.org/repos/dist/dev/dubbo/${release_version}/
 
-然后,开始验证环节,验证包含但不限于以下内容和形式 +Then, begin the validation phase, which includes but is not limited to the following content and forms. -### 检查签名和hash等信息 +### Check Signature and Hash Information -#### 检查sha512哈希 +#### Check sha512 Hash ```sh $ shasum -c apache-dubbo-${release_version}-source-release.zip.sha512 $ shasum -c apache-dubbo-${release_version}-bin-release.zip.sha512 ``` -#### 检查gpg签名 +#### Check gpg Signature -如果是第一次检查,需要首先导入公钥。 +If it's the first check, you need to import the public key first. ```sh - $ curl https://dist.apache.org/repos/dist/dev/dubbo/KEYS >> KEYS # download public keys to local directory - $ gpg --import KEYS # import keys + $ curl https://dist.apache.org/repos/dist/dev/dubbo/KEYS >> KEYS # Download public keys to local directory + $ gpg --import KEYS # Import keys $ gpg —edit-key liujun - > trust # type trust command - ``` -然后使用如下命令检查签名 - - ```sh + > trust # Type trust command +``` +Then, use the following command to check the signature. + +```sh gpg --verify apache-dubbo-2.6.3-source-release.zip.asc apache-dubbo-2.6.3-source-release.zip gpg --verify apache-dubbo-2.6.3-bin-release.zip.asc apache-dubbo-2.6.3-bin-release.zip - ``` - +``` -### 检查源码包的文件内容 +### Check Source Package File Content -解压缩`apache-dubbo-${release_version}-source-release.zip`,进行如下检查: +Unzip `apache-dubbo-${release_version}-source-release.zip` and perform the following checks: - Directory with 'incubating' in name `apache-dubbo-${release_version}-source-release` - DISCLAIMER exists -- LICENSE and NOTICE exists and contents are good +- LICENSE and NOTICE exist and contents are good - All files and no binary files exist -- All files has standard ASF License header +- All files have standard ASF License header - Can compile from source - All unit tests can pass ```sh mvn clean test # This will run all unit tests - # you can also open rat and style plugin to check if every file meets requirements. + # You can also open rat and style plugin to check if every file meets requirements. mvn clean test -Drat.skip=false -Dcheckstyle.skip=false ``` -- Release candidates match with corresponding tags, you can find tag link and hash in vote email. - - check the version number in pom.xml are the same - - check there are no extra files or directories in the source package, for example, no empty directories or useless log files,这里需要注意换行符是否一致 +- Release candidates match with corresponding tags; you can find tag links and hashes in the vote email. + - Check that the version number in pom.xml is the same + - Check that there are no extra files or directories in the source package, for example, no empty directories or useless log files, paying attention to whether line endings are consistent. `diff -r a rc_dir tag_dir` - - check the top n tag commits, dive into the related files and check if the source package has the same changes + - Check the top n tag commits, dive into the related files and check if the source package has the same changes. -### 检查二进制包的文件内容C +### Check Binary Package File Content -解压缩`apache-dubbo-${release_version}-bin-release.zip`,进行如下检查: +Unzip `apache-dubbo-${release_version}-bin-release.zip` and perform the following checks: * Check signatures are good * 'incubating' in name -* LICENSE and NOTICE exists and contents are good +* LICENSE and NOTICE exist and contents are good -注意,如果二进制包里面引入了第三方依赖,则需要更新LICENSE,加入第三方依赖的LICENSE,如果第三方依赖的LICENSE是Apache 2.0,并且对应的项目中包含了NOTICE,还需要更新NOTICE文件 +Note that if third-party dependencies are introduced in the binary package, the LICENSE needs to be updated to include the LICENSE of the third-party dependencies. If the third-party dependencies' LICENSE is Apache 2.0 and the corresponding project includes a NOTICE, the NOTICE file also needs to be updated. -## 进入投票 +## Entering Voting -投票分两个阶段: +Voting consists of two phases: -1. Dubbo社区投票,发起投票邮件到dev@dubbo.apache.org。在社区开发者Review,经过至少72小时并统计到3个同意发版的binding票后(只有PMC的票才是binding),即可进入下一阶段的投票。 -2. Apache社区投票,发起投票邮件到general@incubator.apache.org。经过至少72小时并统计到3个同意发版的binding票后(只有IPMC Member的票才是binding),即可进行正式发布。 +1. Dubbo community vote, initiate the voting email to dev@dubbo.apache.org. After the community developers review, if there are at least 72 hours and three binding votes in favor of the version (only PMC votes are binding), it can proceed to the next phase of voting. +2. Apache community vote, initiate the voting email to general@incubator.apache.org. After at least 72 hours and counting three binding votes in favor of the version (only IPMC Member votes are binding), formal release can proceed. -Dubbo社区投票邮件模板: +Dubbo community voting email template: ```text Hello Dubbo Community, @@ -362,7 +359,7 @@ Thanks, The Apache Dubbo (Incubating) Team ``` -Apache社区投票邮件模板: +Apache community voting email template: ```text Hello all, @@ -382,7 +379,7 @@ automatic service registration & discovery. Dubbo community vote and result thread: https://lists.apache.org/thread.html/8d5c39eece6288beed2e22ca976350728c571d2a9cef1c9a9e56a409@%3Cdev.dubbo.apache.org%3E -A minor issue also can be found in the above thread. +A minor issue can also be found in the above thread. The release candidates (RC1): https://dist.apache.org/repos/dist/dev/dubbo/2.6.4 @@ -416,7 +413,7 @@ Thanks, The Apache Dubbo (Incubating) Team ``` -宣布投票结果模板: +Announcement voting result template: ```text We’ve received 3 +1 binding votes and one +1 non-binding vote: @@ -426,23 +423,23 @@ We’ve received 3 +1 binding votes and one +1 non-binding vote: +1 non-binding, Jerrick -I will create a new vote thread in Apache community now. +I will create a new vote thread in the Apache community now. Best regards, The Apache Dubbo (Incubating) Team ``` -## 正式发布 +## Formal Release -1. 将[dev](https://dist.apache.org/repos/dist/dev/dubbo)目录下的发布包添加到[release](https://dist.apache.org/repos/dist/release/dubbo)目录下,KEYS有更新的,也需要同步更新。 -2. 删除[dev](https://dist.apache.org/repos/dist/dev/dubbo)目录下的发布包 -3. 删除[release](https://dist.apache.org/repos/dist/release/dubbo)目录下上一个版本的发布包,这些包会被自动保存在[这里](https://archive.apache.org/dist/incubator/dubbo) -4. 发布GitHub上的[release notes](https://github.com/apache/dubbo/releases) -5. 修改GitHub的Readme文件,将版本号更新到最新发布的版本 -6. 在官网下载[页面](/en/blog/2020/05/18/past-releases/)上添加最新版本的下载链接。最新的下载链接应该类似`https://www.apache.org/dyn/closer.cgi?path=incubator/dubbo/$VERSION/apache-dubbo-$VERSION-source-release.zip`. 同时更新以前版本的下载链接,改为类似`https://archive.apache.org/dist/dubbo/$VERSION/apache-dubbo-$VERSION-bin-release.zip`. 具体可以参考过往的[下载链接](/en/blog/2020/05/18/past-releases/) -7. 合并`${release-version}-release`分支到对应的主干分支, 然后删除相应的release分支,例如: `git push origin --delete 2.7.0-release` -8. 发邮件到 `dev@dubbo.apache.org` 和 `general@incubator.apache.org` -宣布release邮件模板: +1. Add the released package from the [dev](https://dist.apache.org/repos/dist/dev/dubbo) directory to the [release](https://dist.apache.org/repos/dist/release/dubbo) directory. If KEYS have been updated, they also need to be synchronized. +2. Delete the released package from the [dev](https://dist.apache.org/repos/dist/dev/dubbo) directory. +3. Delete the released package of the previous version in the [release](https://dist.apache.org/repos/dist/release/dubbo) directory. These packages will be automatically saved [here](https://archive.apache.org/dist/incubator/dubbo). +4. Publish the release notes on GitHub [here](https://github.com/apache/dubbo/releases). +5. Update the version number to the latest released version in the GitHub README file. +6. Add the latest version download link on the download [page](/en/blog/2020/05/18/past-releases/). The latest download link should be similar to `https://www.apache.org/dyn/closer.cgi?path=incubator/dubbo/$VERSION/apache-dubbo-$VERSION-source-release.zip`. At the same time, update the download links for older versions to something like `https://archive.apache.org/dist/dubbo/$VERSION/apache-dubbo-$VERSION-bin-release.zip`. Specifics can refer to previous [download links](/en/blog/2020/05/18/past-releases/). +7. Merge the `${release-version}-release` branch into the corresponding main branch, then delete the respective release branch, for example: `git push origin --delete 2.7.0-release`. +8. Send an email to `dev@dubbo.apache.org` and `general@incubator.apache.org`. +The release announcement email template: ```text Hello Community, @@ -480,18 +477,19 @@ Apache Dubbo is an effort undergoing incubation at The Apache Software Foundatio ``` -## 完成Maven Convenient Binary发布(可选) +## Completing Maven Convenient Binary Release (Optional) -**repository.apache.org** nexus仓库的权限已经申请,参见[jira](https://issues.apache.org/jira/browse/INFRA-16451) +**repository.apache.org** Nexus repository permissions have been applied for, see [jira](https://issues.apache.org/jira/browse/INFRA-16451). -发布jar包到maven仓库,首先访问[repository.apache.org](https://repository.apache.org), 选择`staging repository`, 点击`release`按钮。等待一段时间之后,在[这里](https://repository.apache.org/content/repositories/releases/org/apache/dubbo/)确认完整性和正确性. 发布到Maven中央仓库则还需要等待一段时间。可以在[这里](https://repo.maven.apache.org/maven2/org/apache/dubbo)进行确认。 +To publish the jar package to the Maven repository, first visit [repository.apache.org](https://repository.apache.org), select the `staging repository`, and click the `release` button. After a while, confirm integrity and correctness [here](https://repository.apache.org/content/repositories/releases/org/apache/dubbo/). It will take some time to release to the Maven Central Repository as well. You can confirm [here](https://repo.maven.apache.org/maven2/org/apache/dubbo). ## FAQ #### gpg: signing failed: Inappropriate ioctl for device -If you've encoutered this error, try the following commands: +If you've encountered this error, try the following commands: ``` export GPG_TTY=$(tty) ``` + diff --git a/content/en/blog/proposals/google-service-weaver-paper-2023.md b/content/en/blog/proposals/google-service-weaver-paper-2023.md deleted file mode 100644 index aa798f092185..000000000000 --- a/content/en/blog/proposals/google-service-weaver-paper-2023.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -title: "[Google Paper] 面向云时代的应用开发新模式" -linkTitle: "面向云时代的应用开发新模式" -date: 2023-05-26 -author: Google -description: "面向云时代的应用开发新模式:谷歌发布的关于单体&微服务开发与部署的论文,文中原型实现为 Service Weaver" ---- -> 本文翻译自发表在以下地址的论文:https://serviceweaver.dev/assets/docs/hotos23_vision_paper.pdf - -> 原文作者(Authors): Sanjay Ghemawat, Robert Grandl, Srdjan Petrovic, Michael Whittaker, Parveen Patel, Ivan Posva, Amin Vahdat -> -> 转载或发布请遵循原文许可: -> Permission to make digital or hard copies of part or all of this work for -> personal or classroom use is granted without fee provided that copies are -> not made or distributed for profit or commercial advantage and that copies -> bear this notice and the full citation on the first page. Copyrights for thirdparty components of this work must be honored. For all other uses, contact -> the owner/author(s). -> HOTOS ’23, June 22–24, 2023, Providence, RI, USA -> © 2023 Copyright held by the owner/author(s). -> ACM ISBN 979-8-4007-0195-5/23/06. -> https://doi.org/10.1145/3593856.3595909 - -## 摘要 -在编写分布式应用程序时,传统的明智做法是将您的应用程序拆分为可以分别拉起的独立服务。这种方式的用意是好的,但像这样基于微服务的架构经常会适得其反,带来的挑战抵消了架构试图实现的好处。从根本上说,这是因为微服务将逻辑边界(代码的编写方式)与物理边界(代码的部署方式)混为一谈。在本文中,我们提出了一种不同的编程方法,将两者(代码编写与部署方式)分离以解决这些挑战。通过我们的方法,开发人员将他们的应用程序编写为逻辑上的单体,将有关如何分发和运行应用程序的决策放到一套自动化运行时 (runtime),并以原子方式部署应用程序。与当前的微服务开发模式相比,我们的原型应用最多可减少延迟 15 倍、成本最多减少了 9 倍。 - -ACM 参考格式: -Sanjay Ghemawat, Robert Grandl, Srdjan Petrovic, Michael Whit-taker, Parveen Patel, Ivan Posva, Amin Vahdat. 2023. Towards Mod-ern Development of Cloud Applications. In Workshop on Hot Topics in Operating Systems (HOTOS ’23), June 22–24, 2023, Providence, RI, USA. ACM, New York, NY, USA, 8 pages. https://doi.org/10.1145/3593856.3595909 - -## 1 介绍 -近年来,云计算出现了前所未有的增长。编写和部署可扩展到数百万用户的分布式应用程序从未如此简单,这在很大程度上归功于 Kubernetes [25] 等框架,[7, 18, 31, 33, 40, 60] 等消息传递解决方案,以及数据格式如 [5,6, 23, 30]。使用这些技术时,普遍的做法是手动将您的应用程序拆分为可以独立部署的独立微服务。 -通过对各种基础设施团队的内部调查,我们发现大多数开发人员出于以下原因之一将他们的应用程序拆分为多个二进制包:(1) 提升性能。单独的二进制包可以独立扩展,从而提高资源利用率。 (2) 提升容错能力。一个微服务的崩溃不会导致其他微服务崩溃,从而限制了错误的传播范围。 (3) 改进抽象边界。微服务需要清晰明确的 API,并且代码纠缠的可能性会大大降低。 (4) 允许灵活的滚动发布。不同的二进制包可以以不同的速率发布,从而导致更敏捷的代码升级。 -然而,将应用程序拆分为可独立部署的微服务并非没有挑战,其中一些直接与收益相矛盾。 - -- C1:影响性能。序列化数据并通过网络发送数据的开销越来越成为瓶颈 [72]。当开发人员过度拆分他们的应用程序时,这些开销也会增加 [55]。 -- C2:损害正确性。推断每个微服务的每个已部署版本之间的交互是极具挑战性的。在对八个广泛使用的系统的 100 多个灾难性故障进行的案例研究中,三分之二的故障是由系统的多个版本之间的交互引起的 [78]。 -- C3:很难管理。开发人员必须按照自己的发布计划管理不同的二进制包,而不是使用一个二进制文件来构建、测试和部署。如果在本地运行一个应用程序,同时需要执行端到端的集成测试,那可是一个不小的工程。 -- C4:API 冻结。一旦微服务建立了 API,就很难在不破坏使用该 API 的其他服务的情况下进行更改。遗留的 API 不得不长期存在,只能不停的在上面打补丁。 -- C5:降低应用程序的开发速度。当开发活动影响多个微服务的更改时,开发人员无法以原子方式实施和部署更改。 - -开发人员必须仔细计划规划发布时间表,已决定在何时跨微服务引入更改。根据我们的经验,我们发现许多开发人员将上述挑战视为开展业务的必要部分,并且这个比例是压倒性的。许多云原生公司实际上正在开发旨在缓解上述一些挑战的内部框架和流程,但这不会从根本上改变或完全消除它们。例如, - -持续部署框架 [12, 22, 37] 简化了单个二进制包的构建、推送到生产环境的方式,但它们没有解决版本控制问题;如果它有提供这个能力的话,情况可能会更糟,因为代码将以更快的速度被发布并投入生产。各种编程库 [13、27] 使创建和发现网络端点变得更加容易,但对简化应用程序管理没有任何帮助。像 gRPC [18] 这样的网络协议和像 Protocol Buffers [30]这样的数据格式在不断改进,但仍然占据了应用程序执行成本的主要部分。 - -这些基于微服务的解决方案无法解决上述 C1-C5 的原因有两个。第一个原因是他们都假设开发人员手动将他们的应用程序拆分为多个二进制包。这意味着应用程序的网络布局由应用程序开发人员预先确定。此外,一旦确定,网络布局就会通过将网络代码添加到应用程序中而变得更加坚固(例如,网络端点、客户端/服务器存根、网络优化数据结构,如 [30] )。这意味着撤消或修改拆分变得更加困难,即使这样做是有意义的。这隐含地促成了上述挑战 C1、C2 和 C4。 - -第二个原因是假设应用程序二进制包是单独(在某些情况下是连续的)发布到生产环境中。这使得对跨二进制协议进行更改变得更加困难。此外,它还引入了版本控制问题并强制使用更低效的数据格式,如[23、30]。这反过来又会导致上面列出的挑战 C1-C5。 - -在本文中,我们提出了一种不同的编写和部署分布式应用程序的方法,一种解决 C1-C5 问题的方法。我们的编程方法包括三个核心原则: -- (1) 以模块化的方式编写逻辑上划分为多个组件的单体应用程序。 -- (2) 利用运行时根据执行特征动态自动地将逻辑组件分配给物理进程。 -- (3) 以原子方式部署应用程序,防止应用程序的不同版本交互。 - -其他解决方案(例如 actor 系统)也尝试提高抽象度。但是,它们无法解决其中一项或多项挑战(第 7 节)。尽管这些挑战和我们的提案是在服务型应用 (serving application) 的背景下讨论的,但我们相信我们的观察和解决方案具有广泛的用途。 - -## 2 提出的解决方案 -我们提案的两个主要部分是 (1) 具有抽象的编程模型(programing model),允许开发人员编写仅关注业务逻辑的单一二进制模块化应用程序,(2) 用于构建、部署和优化这些应用程序的运行时(runtime)。 - -编程模型使开发人员能够将分布式应用程序编写为单个程序,其中代码被拆分为称为组件的模块化单元(第 3 节)。这类似于将应用程序拆分为微服务,除了微服务将逻辑和物理边界混为一谈。相反,我们的解决方案将两者分离:组件以基于应用程序业务逻辑的逻辑边界为中心,而运行时以基于应用程序性能的物理边界为中心(例如,两个组件应位于同一位置以提高性能)。这种解耦——连同边界可以自动更改的事实——解决了 C4。 - -通过将所有执行责任委托给运行时,我们的解决方案能够提供与微服务相同的优势,但性能更高,成本更低(解决 C1)。例如,运行时决定如何运行、放置、复制和缩放组件(第 4 节)。由于应用程序是原子部署的,因此运行时可以鸟瞰应用程序的执行情况,从而实现进一步的优化。例如,运行时可以使用自定义序列化和传输协议,利用所有参与者都以相同版本执行的事实。 - -将应用程序编写为单个二进制文件并以原子方式部署它还可以更轻松地推断其正确性(解决 C2)并使应用程序更易于管理(解决 C3)。我们的提案为开发人员提供了一个编程模型,使他们能够专注于应用程序业务逻辑,将部署复杂性委托给运行时(解决 C5)。最后,我们的提案支持未来的创新,例如分布式应用程序的自动化测试(第 5 节)。 - -## 3 编程模型 -### 3.1 组件 - -我们提案的关键抽象是组件 (component)。组件是一种长期存在的、可复制的计算代理,类似于 actor [2]。每个组件都实现一个接口(interface),与组件交互的唯一方法是调用其接口上的方法。组件可能由不同的操作系统进程托管(可能跨越多台机器)。组件方法调用在必要时变成远程过程调用,但如果调用者和被调用者组件在同一个进程中,则仍然是本地过程调用。 - -组件如 图-1 所示。示例应用程序包含三个组件:A、B 和 C。当部署应用程序时,运行时决定如何共同定位和复制组件。在此示例中,组件 A 和组件 B 位于同一个操作系统进程中,因此它们之间的方法调用作为常规方法调用执行。组件 C 不与任何其他组件位于同一位置,同时组件 C 被部署到了两台不同机器上,组件 C 之间的方法调用是通过跨网络 RPC 完成的。 - -![pic1-arch.png](/imgs/blog/2023/5/pic1-arch.png) - -图-1:说明如何编写和部署组件。应用程序被编写为一组组件(左)并跨机器部署(右)。请注意,组件可以复制和放置在同一位置。 - -组件通常是长期存在的,但运行时可能会根据负载随时间增加或减少组件的副本数量。同样,组件副本可能会失败并重新启动。运行时还可以四处移动组件副本,例如,将两个交互非常多的组件放在同一个操作系统进程中,以便组件之间的通信在本地而不是通过网络完成。 - -### 3.2 接口 - -为了具体起见,我们在 Go 中提供了一个组件 API,尽管我们的想法与语言无关。图-2 给出了一个“Hello, World!” 应用程序。组件接口表示为 Go 接口,组件实现表示为实现这些接口的 Go 结构。在图-2 中, `hello` 结构嵌入了 **Implements[ Hello] **结构来表示它是 `Hello` 组件的实现。 - -**Init **初始化应用程序。**Get[Hello] **将客户端返回给具有接口 `Hello` 的组件,必要时创建它。对 `hello.Greet` 的调用看起来像是常规方法调用,开发人员不需要关心任何序列化和远程过程调用相关内容。 - -![image.png](/imgs/blog/2023/5/pic2-hello-world.png) - -图-2: “Hello, World!” 应用 - -## 4 运行时 - -### 4.1 概述 - -在编程模型之下是一个负责分发(distributing)和执行(executing)组件的运行时。运行时做出关于如何运行组件的所有高级决策。例如,它决定将哪些组件放在一起并进行多副本部署。运行时还负责底层细节,例如将组件运行到物理资源以及在组件失败时重新启动组件。最后,运行时负责执行原子滚动更新,确保一个应用程序版本中的组件永远不会与不同版本中的组件进行通信。 - -有许多方法可以实现运行时。本文的目的不是规定任何特定的实现。不过,重要的是要认识到运行时并没有什么神奇魔法。在本节的其余部分,我们将概述运行时的关键部分并揭开其内部工作原理的神秘面纱。 - -### 4.2 代码生成 - -运行时的首要职责是代码生成。通过检查一个项目中使用 **Implements[T] **的相关源码调用,代码生成器即可计算出所有组件接口和实现的集合。然后它生成代码来编码和解码组件方法的参数。它还生成代码以将这些方法作为远程过程调用来执行。生成的代码将与开发人员的代码一起编译成一个二进制文件。 - -### 4.3 应用-运行时交互 - -根据我们的提案,应用程序不需要包含任何特定于其部署环境的代码,但由于它们最终必须运行并集成到特定环境中(例如在本地集群中跨机器或在公共云中跨区域运行),为了支持这种集成,我们引入了一个 API(在表-1 中进行了部分概述),它将应用程序逻辑与部署环境的细节隔离开来。 - -![table1.png](/imgs/blog/2023/5/table1.png) - -表-1:应用程序和运行时之间的示例 API。 - -API 的调用者是一个 `proclet`。每个应用程序二进制文件都会运行一个小型的、与环境无关的守护进程,称为 `proclet`,它在编译期间链接到二进制文件中。 proclet 管理正在运行的二进制文件中的组件:运行、启动、停止、在失败时重新启动这些组件等等。 -API 的实现者是运行时,它负责所有控制平面操作。运行时决定 `proclet` 应该如何运行以及在何处运行。例如,多进程运行时可以运行子进程中的每个 `proclet`; SSH 运行时可以通过 SSH 运行 `proclet`;云运行时可以将 `proclet` 作为 Kubernetes pod [25、28] 运行。 - -具体而言,`proclet` 通过 Unix Pipeline 与运行时交互。例如,当构造一个 `proclet` 时,它会通过管道发送一条 `RegisterReplica` 消息,以将自己标记为活动和就绪。它定期发出 `ComponentsToHost` 请求以了解它应该运行哪些组件。如果组件调用不同组件的方法,`proclet` 会发出 `StartComponent` 请求以确保它已启动。 - -运行时以对部署环境有意义的方式实现这些 API。我们希望大多数运行时实现包含以下两部分: -- (1) 一组通过 UNIX 管道与 proclet 直接通信的信封(Envelope)进程,以及 -- (2) 协调 proclet 执行的全局管理器(Global Manager)(参见图-3)。 - -![image.png](/imgs/blog/2023/5/pic3-runtime.png) - -图-3:提案中的 Deployer 架构 - -信封(Envelope)作为 proclet 的父进程运行,并将 API 调用中继到管理器。管理器跨可用资源集(例如服务器、VM)启动信封和(间接)proclet。在应用程序的整个生命周期中,管理器与信封交互以收集运行组件的健康和负载信息;聚合组件导出的指标、日志和跟踪;并处理启动新组件的请求。管理器还发布特定于环境的 API(例如,谷歌云[16]、AWS [4])更新流量分配并根据负载、健康状况和性能约束扩展和缩减组件。请注意,运行时实现控制平面(Golbal Manager)而不是数据平面,Proclet 直接相互通信。 - -### 4.4 原子滚动更新(Rollout) - -开发人员不可避免地必须发布其应用程序的新版本。一种广泛使用的方法是执行滚动更新,其中部署中的机器一台一台地从旧版本更新到新版本。在滚动更新期间,运行不同版本代码的机器必须相互通信,这可能会导致失败。 [78]表明大多数更新失败是由这些跨版本交互引起的。 -为了解决这些复杂性,我们提出了一种不同的方法。运行时确保应用程序版本以原子方式推出,这意味着所有组件通信都发生在应用程序的单个版本中。运行时逐渐将流量从旧版本转移到新版本,但是一旦用户请求转发到特定版本,它就会完全在该版本内处理。原子部署的一种流行实现是使用蓝/绿部署[9]。 - -## 5 启用创新 -### 5.1 传输(Transport)、放置(Placement)和缩容(Scaling) -运行时可以鸟瞰应用程序执行,这为性能优化开辟了新途径。例如,我们的框架可以在组件之间构建一个细粒度的调用图,并用它来识别关键的路径路径、瓶颈组件、频繁交互型组件等。使用这些信息,运行时可以做出更智能的扩缩容、独立部署和组合部署决策。此外,由于序列化和传输机制对开发者透明(Code Generate 机制自动实现),运行时可以自由地优化它们。例如,对于网络瓶颈应用程序,运行时可能决定压缩网络上的消息,对于某些部署,传输可能会利用 RDMA [32] 等技术。 - -### 5.2 路由(Routing) -当请求以亲和力(affinity)路由时,某些组件的性能会大大提高。例如,考虑由基于磁盘的底层存储系统支持的内存缓存组件。当对相同键的请求被路由到相同的缓存副本时,缓存命中率和整体性能会提高。 Slicer [44]表明,许多应用程序可以从这种基于亲和力的路由中受益,并且当路由嵌入到应用程序本身时,路由效率最高[43]。我们的编程框架可以自然地扩展为包含路由 API。运行时还可以了解哪些方法从路由中获益最多并自动路由它们。 - -### 5.3 自动化测试(Automated Testing) -微服务架构被吹捧的好处之一是容错。这个想法是,如果应用中的一个服务组件失败,应用的部分功能可用性会降低,但整个应用仍然可用。这在理论上很棒,但在实践中它依赖于开发人员确保他们的应用对故障具有弹性,更重要的是,测试他们的故障处理逻辑是否正确。由于构建和运行不同的微服务、系统地失败和恢复它们以及检查正确行为的开销,测试尤其具有挑战性。结果,只有一小部分基于微服务的系统针对这种类型的容错进行了测试。根据我们的建议,运行端到端测试能带来的帮助是微不足道的。因为应用程序是用单一编程语言编写的单个二进制文件,所以端到端测试变成了简单的单元测试。这为自动化容错测试打开了大门,类似于混沌测试[47]、Jepsen 测试[14]和模型检查[62]。 - -### 5.4 有状态应用滚动更新(Rollout) -我们的建议确保一个应用程序版本中的组件永远不会与不同版本中的组件通信。这使开发人员更容易推理正确性。但是,如果应用程序更新持久存储系统(如数据库)中的状态,则应用程序的不同版本将通过它们读取和写入的数据间接影响彼此。这些跨版本交互是不可避免的——持久状态,根据定义,跨版本持续存在 —— 但一个悬而未决的问题是如何测试这些交互并及早发现错误以避免在推出期间出现灾难性故障。 - -### 5.5 讨论 -请注意,本节讨论的领域中的创新并不是我们提案所独有的。对传输协议[63、64]、路由[44、65]、测试[45、75]、资源管理[57、67、71]、故障排除[54、56]等。然而,我们的编程模型的独特功能支持新的创新,并使现有的创新更容易实现实施。 - -例如,通过在我们的提议中利用原子部署,我们可以设计高效的序列化协议,可以安全地假设所有参与者都使用相同的模式。此外,我们的编程模型可以轻松地将路由逻辑直接嵌入到用户的应用程序中,从而提供一系列好处[43]。同样,我们的提案提供应用程序鸟瞰图的能力允许 -研究人员专注于开发用于调整应用程序和降低部署成本的新解决方案。 - -## 6 原型实现 -我们的原型实现是用 Go [38]编写的,包括图2 中描述的组件 API、第4.2节中描述的代码生成器以及第 4.3 节中描述的 proclet 架构。该实现使用自定义序列化格式和直接构建在 TCP 之上的自定义传输协议。该原型还带有一个谷歌 Kubernetes 引擎 (GKE) 部署器,它通过渐进的蓝/绿部署实现多区域部署。它使用 Horizontal Pod Autoscalers [20]根据负载动态调整容器副本的数量,并遵循类似于图3中的架构。我们的实现可在github.com/ServiceWeaver 获得。 - -### 6.1 评价 -为了评估我们的原型,我们使用了一个流行的 Web 应用程序[41],它代表了开发人员编写的各种微服务应用程序。该应用程序有 11 个微服务,并使用 gRPC [18]和 Kubernetes [25]部署在云端。该应用程序是用各种编程语言编写的,因此为了公平比较,我们将应用程序移植为完全用 Go 编写。然后我们将应用程序移植到我们的原型中,每个微服务都被重写为一个组件。我们使用 Locust [26],一种工作负载生成器,在有和没有我们的原型的情况下对应用程序进行负载测试。 - -工作负载生成器向应用程序发送稳定速率的 HTTP 请求。两个应用程序版本都配置为自动缩放容器副本的数量以响应负载。我们测量了应用程序版本在稳定状态下使用的 CPU 内核数量,以及它们的端到端延迟。表-2 显示了我们的结果。 - -![table2.png](/imgs/blog/2023/5/table2.png) - -表-2 - -我们原型的大部分性能优势来自它使用专为非版本化数据交换设计的自定义序列化格式,以及它使用直接构建在 TCP 之上的流线型传输协议。例如,使用的序列化格式不需要对字段编号或类型信息进行任何编码。这是因为所有编码器和解码器都以完全相同的版本运行,并且预先就字段集以及它们的编码和解码顺序达成一致。 - -为了与基线进行同类比较,我们没有将任何组件放在一起。当我们共同定位所有将 11 个组件集成到单个操作系统进程中,内核数量下降到 9,中值延迟下降到 0.38 毫秒,均比基线低一个数量级。这反映了行业经验[34、39]。 - -## 7 相关工作 -演员系统。最接近我们建议的解决方案是 Orleans [74]和 Akka [3]。这些框架还使用抽象来解耦应用程序和运行时。 Ray [70]是另一个基于角色的框架,但专注于 ML 应用程序。这些系统都不支持原子部署,而原子部署是完全应对 C2-C5 挑战的必要组成部分。其他流行的基于 actor 的框架,如 Er-lang [61]、E [52]、Thorn [48]和 C++ Actor Framework [10],给开发人员带来了处理系统和有关部署和执行的低级细节的负担,因此它们未能分离应用程序和运行时之间的关注点,因此没有完全解决 C1-C5。 CORBA、DCOM 和 Java RMI 等分布式对象框架使用与我们类似的编程模型,但存在许多技术和组织问题[58],并且也没有完全解决 C1-C5。 - -基于微服务的系统。 Kubernetes [25]广泛用于在云中部署基于容器的应用程序。但是,它的重点与我们的提案正交,不涉及 C1-C5 中的任何一个。 Docker Compose [15]、Acorn [1]、Helm [19]、Skaffold [35]和 Istio [21]抽象出了一些微服务挑战(例如,配置生成)。然而,与将应用程序拆分为微服务、版本化推出和测试相关的挑战仍然留给了用户。因此,它们不满足 C1-C5。 - -其他系统。还有许多其他解决方案可以让开发人员更轻松地编写分布式应用程序,包括数据流系统[51、59、77]、ML 推理服务系统[8、17、42、50、73]、无服务器解决方案[11, 24、36]、数据库[29、49]和 Web 应用程序[66]。最近,服务网格[46、69]提出了网络抽象以分解出常见的通信功能。我们的提案体现了这些相同的想法,但在通用服务系统和分布式应用程序的新领域中。在这种情况下,出现了新的挑战(例如,原子推出)。 - -## 8 讨论 -### 8.1 多个应用程序二进制文件 -我们认为应用程序应该作为单个二进制文件来编写和构建,但我们承认这可能并不总是可行的。例如,应用程序的大小可能超出单个团队的能力,或者不同的应用程序服务可能出于组织原因需要不同的发布周期。在所有这些情况下,应用程序可能需要包含多个二进制文件。 - -虽然本文没有解决需要使用多个二进制文件的情况,但我们相信我们的提议允许开发人员编写更少的二进制文件(即尽可能将多个服务分组为单个二进制文件),实现更好的性能,并推迟做出艰难的决定与如何划分应用程序有关。我们正在探索如何容纳以多种语言编写并编译成单独的二进制文件的应用程序。 - -### 8.2 与外部服务集成 -应用程序通常需要与外部服务(例如,Postgres 数据库[29])进行交互。我们的编程模型允许应用程序像任何应用程序一样与这些服务交互。什么都不是,一切都必须是一个组件。但是,当外部服务在应用程序内部和跨应用程序广泛使用时,定义相应的组件可能会提供更好的代码重用。 - -### 8.3 分布式系统挑战 -虽然我们的编程模型允许开发人员专注于他们的业务逻辑并推迟将他们的应用程序部署到运行时的大量复杂性,但我们的提议并没有解决分布式系统的基本挑战 [53, 68, 76]。应用程序开发人员仍然需要意识到组件可能会失败或经历高延迟。 - -### 8.4 编程指导 -没有关于如何编写分布式应用程序的官方指南,因此关于将应用程序编写为单体应用程序还是微服务是更好的选择,一直存在着长期而激烈的争论。但是,每种方法都有其优点和缺点。我们认为开发人员应该使用我们的建议将他们的应用程序编写为单个二进制文件,然后再决定他们是否真的需要迁移到基于微服务的架构。通过推迟决定如何准确地拆分成不同的微服务,它允许他们编写更少但更好的微服务。 - -## 9 结论 -编写分布式应用程序时的现状涉及将应用程序拆分为可独立部署的服务。这种架构有很多好处,但也有很多缺点。在本文中,我们提出了一种不同的编程范式来回避这些缺点。我们的提议鼓励开发人员 (1) 编写划分为逻辑组件的单体应用程序,(2) 将物理分布和执行模块化单体的挑战推迟到运行时,以及 (3) 原子部署应用程序。这三个指导原则带来了许多好处,并为未来的创新打开了大门。与现状相比,我们的原型实施将应用程序延迟最多减少了 15 倍,并将成本最多减少了 9 倍。 - - -[1] Acorn. [https://www.acorn.io/.](https://www.acorn.io/) - -[2] Actor model. [https://en.wikipedia.org/wiki/Actor_model.](https://en.wikipedia.org/wiki/Actor_model) - -[3] Akka. [https://akka.io.](https://akka.io) - -[4] Amazon Web Services. [https://aws.amazon.com/.](https://aws.amazon.com/) - -[5] Apache avro. [https://avro.apache.org/docs/1.2.0/.](https://avro.apache.org/docs/1.2.0/) - -[6] Apache thrift. [https://thrift.apache.org/.](https://thrift.apache.org/) - -[7] AWS Cloud Map. [https://aws.amazon.com/cloud-map/.](https://aws.amazon.com/cloud-map/) - -[8] Azure Machine Learning. [https://docs.microsoft.com/en-us/azure/](https://docs.microsoft.com/en-us/azure/machine-learning)[machine-learning.](https://docs.microsoft.com/en-us/azure/machine-learning) - -[9] Blue/green deployments. [https://tinyurl.com/3bk64ch2.](https://tinyurl.com/3bk64ch2) - -[10] The c++ actor framework. [https://www.actor-framework.org/.](https://www.actor-framework.org/) - -[11] Cloudflare Workers. [https://workers.cloudflare.com/.](https://workers.cloudflare.com/) - -[12] Continuous integration and delivery - circleci. [https://circleci.com/.](https://circleci.com/) - -[13] Dapr - distributed application runtime. [https://dapr.io/.](https://dapr.io/) - -[14] Distributed systems safety research. `https://jespen.io.` - -[15] Docker compose. [https://docs.docker.com/compose/.](https://docs.docker.com/compose/) - -[16] Google Cloud. [https://cloud.google.com/.](https://cloud.google.com/) - -[17] Google Cloud AI Platform. [https://cloud.google.com/ai-platform.](https://cloud.google.com/ai-platform) - -[18] grpc. [https://grpc.io/.](https://grpc.io/) - -[19] Helm. [http://helm.sh.](http://helm.sh) - -[20] Horizontal Pod Autoscaling. [https://kubernetes.io/docs/tasks/run-](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/)[application/horizontal-pod-autoscale/.](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) - -[21] Istio. [https://istio.io/.](https://istio.io/) - -[22] Jenkins. [https://www.jenkins.io/.](https://www.jenkins.io/) - -[23] Json. [https://www.json.org/json-en.html.](https://www.json.org/json-en.html) - -[24] Kalix. [https://www.kalix.io/.](https://www.kalix.io/) - -[25] Kubernetes. [https://kubernetes.io/.](https://kubernetes.io/) - -[26] Locust. [https://locust.io/.](https://locust.io/) - -[27] Micro | powering the future of cloud. [https://micro.dev/.](https://micro.dev/) - -[28] Pods. [https://kubernetes.io/docs/concepts/workloads/pods/.](https://kubernetes.io/docs/concepts/workloads/pods/) - -[29] Postgresql. [https://www.postgresql.org/.](https://www.postgresql.org/) - -[30] Protocol buffers. [https://developers.google.com/protocol-buffers.](https://developers.google.com/protocol-buffers) - -[31] RabbitMQ. [https://www.rabbitmq.com/.](https://www.rabbitmq.com/) - -[32] Remote direct memory access. [https://en.wikipedia.org/wiki/Remote_](https://en.wikipedia.org/wiki/Remote_direct_memory_access)[direct_memory_access.](https://en.wikipedia.org/wiki/Remote_direct_memory_access) - -[33] REST API. [https://restfulapi.net/.](https://restfulapi.net/) - -[34] Scaling up the Prime Video audio/video monitoring service and reduc-ing costs by 90%. [https://tinyurl.com/yt6nxt63.](https://tinyurl.com/yt6nxt63) - -[35] Skaffold. [https://skaffold.dev/.](https://skaffold.dev/) - -[36] Temporal. [https://temporal.io/.](https://temporal.io/) - -[37] Terraform. [https://www.terraform.io/.](https://www.terraform.io/) - -[38] The Go programming language. [https://go.dev/.](https://go.dev/) - -[39] To Microservices and Back Again - Why Segment Went Back to a Monolith. [https://tinyurl.com/5932ce5n.](https://tinyurl.com/5932ce5n) - -[40] WebSocket. [https://en.wikipedia.org/wiki/WebSocket.](https://en.wikipedia.org/wiki/WebSocket) - -[41] Online boutique. [https://github.com/GoogleCloudPlatform/](https://github.com/GoogleCloudPlatform/microservices-demo)[microservices-demo,](https://github.com/GoogleCloudPlatform/microservices-demo)2023. - -[42] M. Abadi, P. Barham, J. Chen, Z. Chen, A. Davis, J. Dean, M. Devin, -S.Ghemawat, G. Irving, M. Isard, M. Kudlur, J. Levenberg, R. Monga, -S.Moore, D. G. Murray, B. Steiner, P. Tucker, V. Vasudevan, P. Warden, -M.Wicke, Y. Yu, and X. Zheng. Tensorflow: A system for large-scale machine learning. In OSDI, 2016. - -[43] A. Adya, R. Grandl, D. Myers, and H. Qin. Fast key-value stores: An idea whose time has come and gone. In HotOS, 2019. - -[44] A. Adya, D. Myers, J. Howell, J. Elson, C. Meek, V. Khemani, S. Fulger, -P.Gu, L. Bhuvanagiri, J. Hunter, R. Peon, L. Kai, A. Shraer, A. Merchant, and K. Lev-Ari. Slicer: Auto-sharding for datacenter applications. In OSDI, 2016. - -[45] D. Ardelean, A. Diwan, and C. Erdman. Performance analysis of cloud applications. In NSDI, 2018. - -[46] S. Ashok, P. B. Godfrey, and R. Mittal. Leveraging service meshes as a new network layer. In HotNets, 2021. - -[47] A. Basiri, N. Behnam, R. De Rooij, L. Hochstein, L. Kosewski, J.Reynolds, and C. Rosenthal. Chaos engineering. In IEEE Software, 2016. - -[48] B. Bloom, J. Field, N. Nystrom, J. Östlund, G. Richards, R. Strniša, J.Vitek, and T. Wrigstad. Thorn: Robust, concurrent, extensible script-ing on the jvm. In OOPSLA, 2009. - -[49] J. C. Corbett, J. Dean, M. Epstein, A. Fikes, C. Frost, J. J. Furman, S. Ghe-mawat, A. Gubarev, C. Heiser, P. Hochschild, W. Hsieh, S. Kanthak, E.Kogan, H. Li, A. Lloyd, S. Melnik, D. Mwaura, D. Nagle, S. Quin-lan, R. Rao, L. Rolig, Y. Saito, M. Szymaniak, C. Taylor, R. Wang, and D.Woodford. Spanner: Google’s globally-distributed database. In OSDI, 2012. - -[50] D. Crankshaw, X. Wang, G. Zhou, M. J. Franklin, J. E. Gonzalez, and I.Stoica. Clipper: A low-latency online prediction serving system. In NSDI, 2017. - -[51] J. Dean and S. Ghemawat. Mapreduce: Simplified data processing on large clusters. In OSDI, 2004. -[52] J. Eker, J. Janneck, E. Lee, J. Liu, X. Liu, J. Ludvig, S. Neuendorffer, S.Sachs, and Y. Xiong. Taming heterogeneity - the ptolemy approach. In Proceedings of the IEEE, 2003. - -[53] M. J. Fischer, N. A. Lynch, and M. S. Paterson. Impossibility of dis-tributed consensus with one faulty process. In ACM Journal, 1985. - -[54] Y. Gan, M. Liang, S. Dev, D. Lo, and C. Delimitrou. Sage: Practical and Scalable ML-Driven Performance Debugging in Microservices. In ASPLOS, 2021. - -[55] Y. Gan, Y. Zhang, D. Cheng, A. Shetty, P. Rathi, N. Katarki, A. Bruno, J.Hu, B. Ritchken, B. Jackson, et al. An open-source benchmark suite for microservices and their hardware-software implications for cloud & edge systems. In ASPLOS, 2019. - -[56] Y. Gan, Y. Zhang, K. Hu, Y. He, M. Pancholi, D. Cheng, and C. De-limitrou. Seer: Leveraging Big Data to Navigate the Complexity of Performance Debugging in Cloud Microservices. In ASPLOS, 2019. - -[57] R. Grandl, G. Ananthanarayanan, S. Kandula, S. Rao, and A. Akella. Multi-resource packing for cluster schedulers. In SIGCOMM, 2014. - -[58] M. Henning. The rise and fall of corba: There’s a lot we can learn from corba’s mistakes. In Queue, 2006. - -[59] M. Isard, M. Budiu, Y. Yu, A. Birrell, and D. Fetterly. Dryad: Distributed data-parallel programs from sequential building blocks. In Eurosys, 2007. - -[60] K. Jay, N. Neha, and R. Jun. Kafka : a distributed messaging system for log processing. In NetDB, 2011. - -[61] A. Joe. Erlang. In Communications of the ACM, 2010. - -[62] L. Lamport. The temporal logic of actions. In ACM TOPLS, 1994. - -[63] A. Langley, A. Riddoch, A. Wilk, A. Vicente, C. Krasic, D. Zhang, F.Yang, F. Kouranov, I. Swett, J. Iyengar, J. Bailey, J. Dorfman, J. Roskind, J.Kulik, P. Westin, R. Tenneti, R. Shade, R. Hamilton, V. Vasiliev, W.-T. Chang, and Z. Shi. The quic transport protocol: Design and internet-scale deployment. In SIGCOMM, 2017. - -[64] N. Lazarev, N. Adit, S. Xiang, Z. Zhang, and C. Delimitrou. Dagger: Towards Efficient RPCs in Cloud Microservices with Near-Memory Reconfigurable NICs. In ASPLOS, 2021. - -[65] S. Lee, Z. Guo, O. Sunercan, J. Ying, T. Kooburat, S. Biswal, J. Chen, K.Huang, Y. Cheung, Y. Zhou, K. Veeraraghavan, B. Damani, P. M. Ruiz, V.Mehta, and C. Tang. Shard manager: A generic shard management framework for geo-distributed applications. In SOSP, 2021. - -[66] B. Livshits and E. Kiciman. Doloto: Code splitting for network-bound web 2.0 applications. In FSE, 2008. - -[67] S. Luo, H. Xu, C. Lu, K. Ye, G. Xu, L. Zhang, Y. Ding, J. He, and C. Xu. Characterizing microservice dependency and performance: Alibaba trace analysis. In SOCC, 2021. - -[68] N. A. Lynch. Distributed algorithms. In Morgan Kaufmann Publishers Inc., 1996. - -[69] S. McClure, S. Ratnasamy, D. Bansal, and J. Padhye. Rethinking net-working abstractions for cloud tenants. In HotOS, 2021. - -[70] P. Moritz, R. Nishihara, S. Wang, A. Tumanov, R. Liaw, E. Liang, M. Eli-bol, Z. Yang, W. Paul, M. I. Jordan, and I. Stoica. Ray: A distributed framework for emerging ai applications. In OSDI, 2018. - -[71] H. Qiu, S. S. Banerjee, S. Jha, Z. T. Kalbarczyk, and R. K. Iyer. FIRM: An intelligent fine-grained resource management framework for SLO-Oriented microservices. In OSDI, 2020. - -[72] D. Raghavan, P. Levis, M. Zaharia, and I. Zhang. Breakfast of champi-ons: towards zero-copy serialization with nic scatter-gather. In HotOS, 2021. - -[73] F. Romero, Q. Li, N. J. Yadwadkar, and C. Kozyrakis. Infaas: Automated model-less inference serving. In ATC, 2021. - -[74] B. Sergey, G. Allan, K. Gabriel, L. James, P. Ravi, and T. Jorgen. Orleans: Cloud computing for everyong. In SOCC, 2011. - -[75] M. Waseem, P. Liang, G. Márquez, and A. D. Salle. Testing microser-vices architecture-based applications: A systematic mapping study. In APSEC, 2020. - -[76] Wikipedia contributors. Fallacies of distributed computing. - -[77] M. Zaharia, M. Chowdhury, T. Das, A. Dave, J. Ma, M. McCauly, M. J. Franklin, S. Shenker, and I. Stoica. Resilient distributed datasets: A fault-tolerant abstraction for in-memory cluster computing. In NSDI, 2012. - -[78] Y. Zhang, J. Yang, Z. Jin, U. Sethi, K. Rodrigues, S. Lu, and D. Yuan. Understanding and detecting software upgrade failures in distributed systems. In SOSP, 2021. - diff --git a/content/en/blog/proposals/metrics.md b/content/en/blog/proposals/metrics.md deleted file mode 100644 index fcad31a9f673..000000000000 --- a/content/en/blog/proposals/metrics.md +++ /dev/null @@ -1,523 +0,0 @@ ---- -title: "指标埋点" -linkTitle: "指标埋点" -date: 2023-02-20 -author: Song Xiaosheng -description: "" ---- - -# 概述 - -## 1. 指标接入说明 - -## 2. 指标体系设计 - -Dubbo的指标体系,总共涉及三块,指标收集、本地聚合、指标推送 -* 指标收集:将Dubbo内部需要监控的指标推送至统一的Collector中进行存储 -* 本地聚合:指标收集获取的均为基础指标,而一些分位数指标则需通过本地聚合计算得出 -* 指标推送:收集和聚合后的指标通过一定的方式推送至第三方服务器,目前只涉及Prometheus - -## 3. 结构设计 -- 移除原来与 Metrics 相关的类 -- 创建新模块 dubbo-metrics/dubbo-metrics-api、dubbo-metrics/dubbo-metrics-prometheus,MetricsConfig 作为该模块的配置类 -- 使用micrometer,在Collector中使用基本类型代表指标,如Long、Double等,并在dubbo-metrics-api中引入micrometer,由micrometer对内部指标进行转换 -## 4. 数据流转 - ![img.png](/imgs/docs3-v2/java-sdk/observability/dataflow.png) - - -## 5. 目标 - 指标接口将提供一个 MetricsService,该 Service 不仅提供柔性服务所的接口级数据,也提供所有指标的查询方式,其中方法级指标的查询的接口可按如下方式声明 - -```java -public interface MetricsService { - - /** - * Default {@link MetricsService} extension name. - */ - String DEFAULT_EXTENSION_NAME = "default"; - - /** - * The contract version of {@link MetricsService}, the future update must make sure compatible. - */ - String VERSION = "1.0.0"; - - /** - * Get metrics by prefixes - * - * @param categories categories - * @return metrics - key=MetricCategory value=MetricsEntityList - */ - Map> getMetricsByCategories(List categories); - - /** - * Get metrics by interface and prefixes - * - * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) - * @param categories categories - * @return metrics - key=MetricCategory value=MetricsEntityList - */ - Map> getMetricsByCategories(String serviceUniqueName, List categories); - - /** - * Get metrics by interface、method and prefixes - * - * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) - * @param methodName methodName - * @param parameterTypes method parameter types - * @param categories categories - * @return metrics - key=MetricCategory value=MetricsEntityList - */ - Map> getMetricsByCategories(String serviceUniqueName, String methodName, Class[] parameterTypes, List categories); -} -``` - -其中 MetricsCategory 设计如下: -```java -public enum MetricsCategory { - RT, - QPS, - REQUESTS, -} -``` - -MetricsEntity 设计如下 -```java -public class MetricsEntity { - private String name; - private Map tags; - private MetricsCategory category; - private Object value; -} -``` - -# 指标收集 -## 1. 嵌入位置 - Dubbo 架构图如下 - ![img.png](/imgs/docs3-v2/java-sdk/observability/dubbo.png) - -在 provider 中添加一层 MetricsFilter 重写 invoke 方法嵌入调用链路用于收集指标,用 try-catch-finally 处理,核心代码如下 - -```java -@Activate(group = PROVIDER, order = -1) -public class MetricsFilter implements Filter, ScopeModelAware { - @Override - public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - collector.increaseTotalRequests(interfaceName, methodName, group, version); - collector.increaseProcessingRequests(interfaceName, methodName, group, version); - Long startTime = System.currentTimeMillis(); - try { - Result invoke = invoker.invoke(invocation); - collector.increaseSucceedRequests(interfaceName, methodName, group, version); - return invoke; - } catch (RpcException e) { - collector.increaseFailedRequests(interfaceName, methodName, group, version); - throw e; - } finally { - Long endTime = System.currentTimeMillis(); - Long rt = endTime - startTime; - collector.addRT(interfaceName, methodName, group, version, rt); - collector.decreaseProcessingRequests(interfaceName, methodName, group, version); - } - } -} - -``` - - -## 2. 指标标识 - 用以下五个属性作为隔离级别区分标识不同方法,也是各个 ConcurrentHashMap 的 key -```java -public class MethodMetric { - private String applicationName; - private String interfaceName; - private String methodName; - private String group; - private String version; -} -``` - -## 3. 基础指标 - 指标通过 common 模块下的 MetricsCollector 存储所有指标数据 - -```java -public class DefaultMetricsCollector implements MetricsCollector { - private Boolean collectEnabled = false; - private final List listeners = new ArrayList<>(); - private final ApplicationModel applicationModel; - private final String applicationName; - - private final Map totalRequests = new ConcurrentHashMap<>(); - private final Map succeedRequests = new ConcurrentHashMap<>(); - private final Map failedRequests = new ConcurrentHashMap<>(); - private final Map processingRequests = new ConcurrentHashMap<>(); - - private final Map lastRT = new ConcurrentHashMap<>(); - private final Map minRT = new ConcurrentHashMap<>(); - private final Map maxRT = new ConcurrentHashMap<>(); - private final Map avgRT = new ConcurrentHashMap<>(); - private final Map totalRT = new ConcurrentHashMap<>(); - private final Map rtCount = new ConcurrentHashMap<>(); - } -``` - -# 本地聚合 -本地聚合指将一些简单的指标通过计算获取各分位数指标的过程 -## 1. 参数设计 - 收集指标时,默认只收集基础指标,而一些单机聚合指标则需要开启服务柔性或者本地聚合后另起线程计算。此处若开启服务柔性,则本地聚合默认开启 - -### 1.1 本地聚合开启方式 -```xml - - - -``` - -### 1.2 指标聚合参数 -```xml - - - -``` - -## 2. 具体指标 - -Dubbo的指标模块帮助用户从外部观察正在运行的系统的内部服务状况 ,Dubbo参考 ["四大黄金信号"](https://sre.google/sre-book/monitoring-distributed-systems/)、*RED方法*、*USE方法*等理论并结合实际企业应用场景从不同维度统计了丰富的关键指标,关注这些核心指标对于提供可用性的服务是至关重要的。 - -Dubbo的关键指标包含:**延迟(Latency)**、**流量(Traffic)**、 **错误(Errors)** 和 **饱和度(Saturation)** 等内容 。同时,为了更好的监测服务运行状态,Dubbo 还提供了对核心组件状态的监控,如Dubbo应用信息、线程池信息、三大中心交互的指标数据等。 - -在Dubbo中主要包含如下监控指标: - -| | 基础设施 | 业务监控 | -| :------- | :----------------------------------------------------------- |:-----------------------------| -| 延迟类 | IO 等待; 网络延迟; | 接口、服务的平均耗时、TP90、TP99、TP999 等 | -| 流量类 | 网络和磁盘 IO; | 服务层面的 QPS、 | -| 错误类 | 宕机; 磁盘(坏盘或文件系统错误); 进程或端口挂掉; 网络丢包; | 错误日志;业务状态码、错误码走势; | -| 饱和度类 | 系统资源利用率: CPU、内存、磁盘、网络等; 饱和度:等待线程数,队列积压长度; | 这里主要包含JVM、线程池等| - -- qps: 基于滑动窗口获取动态qps -- rt: 基于滑动窗口获取动态rt -- 失败请求数: 基于滑动窗口获取最近时间内的失败请求数 -- 成功请求数: 基于滑动窗口获取最近时间内的成功请求数 -- 处理中请求数: 前后增加Filter简单统计 -- 具体指标依赖滑动窗口,额外使用 AggregateMetricsCollector 收集 - -输出到普罗米修斯的相关指标可以参考的内容如下: -``` -# HELP jvm_gc_live_data_size_bytes Size of long-lived heap memory pool after reclamation -# TYPE jvm_gc_live_data_size_bytes gauge -jvm_gc_live_data_size_bytes 1.6086528E7 -# HELP requests_succeed_aggregate Aggregated Succeed Requests -# TYPE requests_succeed_aggregate gauge -requests_succeed_aggregate{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 39.0 -# HELP jvm_buffer_memory_used_bytes An estimate of the memory that the Java virtual machine is using for this buffer pool -# TYPE jvm_buffer_memory_used_bytes gauge -jvm_buffer_memory_used_bytes{id="direct",} 1.679975E7 -jvm_buffer_memory_used_bytes{id="mapped",} 0.0 -# HELP jvm_gc_memory_allocated_bytes_total Incremented for an increase in the size of the (young) heap memory pool after one GC to before the next -# TYPE jvm_gc_memory_allocated_bytes_total counter -jvm_gc_memory_allocated_bytes_total 2.9884416E9 -# HELP requests_total_aggregate Aggregated Total Requests -# TYPE requests_total_aggregate gauge -requests_total_aggregate{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 39.0 -# HELP system_load_average_1m The sum of the number of runnable entities queued to available processors and the number of runnable entities running on the available processors averaged over a period of time -# TYPE system_load_average_1m gauge -system_load_average_1m 0.0 -# HELP system_cpu_usage The "recent cpu usage" for the whole system -# TYPE system_cpu_usage gauge -system_cpu_usage 0.015802269043760128 -# HELP jvm_threads_peak_threads The peak live thread count since the Java virtual machine started or peak was reset -# TYPE jvm_threads_peak_threads gauge -jvm_threads_peak_threads 40.0 -# HELP requests_processing Processing Requests -# TYPE requests_processing gauge -requests_processing{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 -# HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management -# TYPE jvm_memory_max_bytes gauge -jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'profiled nmethods'",} 1.22912768E8 -jvm_memory_max_bytes{area="heap",id="G1 Survivor Space",} -1.0 -jvm_memory_max_bytes{area="heap",id="G1 Old Gen",} 9.52107008E8 -jvm_memory_max_bytes{area="nonheap",id="Metaspace",} -1.0 -jvm_memory_max_bytes{area="heap",id="G1 Eden Space",} -1.0 -jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 5828608.0 -jvm_memory_max_bytes{area="nonheap",id="Compressed Class Space",} 1.073741824E9 -jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 1.22916864E8 -# HELP jvm_threads_states_threads The current number of threads having BLOCKED state -# TYPE jvm_threads_states_threads gauge -jvm_threads_states_threads{state="blocked",} 0.0 -jvm_threads_states_threads{state="runnable",} 10.0 -jvm_threads_states_threads{state="waiting",} 16.0 -jvm_threads_states_threads{state="timed-waiting",} 13.0 -jvm_threads_states_threads{state="new",} 0.0 -jvm_threads_states_threads{state="terminated",} 0.0 -# HELP jvm_buffer_total_capacity_bytes An estimate of the total capacity of the buffers in this pool -# TYPE jvm_buffer_total_capacity_bytes gauge -jvm_buffer_total_capacity_bytes{id="direct",} 1.6799749E7 -jvm_buffer_total_capacity_bytes{id="mapped",} 0.0 -# HELP rt_p99 Response Time P99 -# TYPE rt_p99 gauge -rt_p99{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 1.0 -# HELP jvm_memory_used_bytes The amount of used memory -# TYPE jvm_memory_used_bytes gauge -jvm_memory_used_bytes{area="heap",id="G1 Survivor Space",} 1048576.0 -jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'profiled nmethods'",} 1.462464E7 -jvm_memory_used_bytes{area="heap",id="G1 Old Gen",} 1.6098728E7 -jvm_memory_used_bytes{area="nonheap",id="Metaspace",} 4.0126952E7 -jvm_memory_used_bytes{area="heap",id="G1 Eden Space",} 8.2837504E7 -jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 1372032.0 -jvm_memory_used_bytes{area="nonheap",id="Compressed Class Space",} 4519248.0 -jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 5697408.0 -# HELP qps Query Per Seconds -# TYPE qps gauge -qps{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.3333333333333333 -# HELP rt_min Min Response Time -# TYPE rt_min gauge -rt_min{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 -# HELP jvm_buffer_count_buffers An estimate of the number of buffers in the pool -# TYPE jvm_buffer_count_buffers gauge -jvm_buffer_count_buffers{id="mapped",} 0.0 -jvm_buffer_count_buffers{id="direct",} 10.0 -# HELP system_cpu_count The number of processors available to the Java virtual machine -# TYPE system_cpu_count gauge -system_cpu_count 2.0 -# HELP jvm_classes_loaded_classes The number of classes that are currently loaded in the Java virtual machine -# TYPE jvm_classes_loaded_classes gauge -jvm_classes_loaded_classes 7325.0 -# HELP rt_total Total Response Time -# TYPE rt_total gauge -rt_total{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 2783.0 -# HELP rt_last Last Response Time -# TYPE rt_last gauge -rt_last{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 -# HELP jvm_gc_memory_promoted_bytes_total Count of positive increases in the size of the old generation memory pool before GC to after GC -# TYPE jvm_gc_memory_promoted_bytes_total counter -jvm_gc_memory_promoted_bytes_total 1.4450952E7 -# HELP jvm_gc_pause_seconds Time spent in GC pause -# TYPE jvm_gc_pause_seconds summary -jvm_gc_pause_seconds_count{action="end of minor GC",cause="Metadata GC Threshold",} 2.0 -jvm_gc_pause_seconds_sum{action="end of minor GC",cause="Metadata GC Threshold",} 0.026 -jvm_gc_pause_seconds_count{action="end of minor GC",cause="G1 Evacuation Pause",} 37.0 -jvm_gc_pause_seconds_sum{action="end of minor GC",cause="G1 Evacuation Pause",} 0.156 -# HELP jvm_gc_pause_seconds_max Time spent in GC pause -# TYPE jvm_gc_pause_seconds_max gauge -jvm_gc_pause_seconds_max{action="end of minor GC",cause="Metadata GC Threshold",} 0.0 -jvm_gc_pause_seconds_max{action="end of minor GC",cause="G1 Evacuation Pause",} 0.0 -# HELP rt_p95 Response Time P95 -# TYPE rt_p95 gauge -rt_p95{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 -# HELP requests_total Total Requests -# TYPE requests_total gauge -requests_total{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 27738.0 -# HELP process_cpu_usage The "recent cpu usage" for the Java Virtual Machine process -# TYPE process_cpu_usage gauge -process_cpu_usage 8.103727714748784E-4 -# HELP rt_max Max Response Time -# TYPE rt_max gauge -rt_max{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 4.0 -# HELP jvm_gc_max_data_size_bytes Max size of long-lived heap memory pool -# TYPE jvm_gc_max_data_size_bytes gauge -jvm_gc_max_data_size_bytes 9.52107008E8 -# HELP jvm_threads_live_threads The current number of live threads including both daemon and non-daemon threads -# TYPE jvm_threads_live_threads gauge -jvm_threads_live_threads 39.0 -# HELP jvm_threads_daemon_threads The current number of live daemon threads -# TYPE jvm_threads_daemon_threads gauge -jvm_threads_daemon_threads 36.0 -# HELP jvm_classes_unloaded_classes_total The total number of classes unloaded since the Java virtual machine has started execution -# TYPE jvm_classes_unloaded_classes_total counter -jvm_classes_unloaded_classes_total 0.0 -# HELP jvm_memory_committed_bytes The amount of memory in bytes that is committed for the Java virtual machine to use -# TYPE jvm_memory_committed_bytes gauge -jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'profiled nmethods'",} 1.4680064E7 -jvm_memory_committed_bytes{area="heap",id="G1 Survivor Space",} 1048576.0 -jvm_memory_committed_bytes{area="heap",id="G1 Old Gen",} 5.24288E7 -jvm_memory_committed_bytes{area="nonheap",id="Metaspace",} 4.1623552E7 -jvm_memory_committed_bytes{area="heap",id="G1 Eden Space",} 9.0177536E7 -jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 2555904.0 -jvm_memory_committed_bytes{area="nonheap",id="Compressed Class Space",} 5111808.0 -jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 5701632.0 -# HELP requests_succeed Succeed Requests -# TYPE requests_succeed gauge -requests_succeed{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 27738.0 -# HELP rt_avg Average Response Time -# TYPE rt_avg gauge -rt_avg{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 -``` - -## 聚合收集器 -```java -public class AggregateMetricsCollector implements MetricsCollector, MetricsListener { - private int bucketNum; - private int timeWindowSeconds; - - private final Map totalRequests = new ConcurrentHashMap<>(); - private final Map succeedRequests = new ConcurrentHashMap<>(); - private final Map failedRequests = new ConcurrentHashMap<>(); - private final Map qps = new ConcurrentHashMap<>(); - private final Map rt = new ConcurrentHashMap<>(); - - private final ApplicationModel applicationModel; - - private static final Integer DEFAULT_COMPRESSION = 100; - private static final Integer DEFAULT_BUCKET_NUM = 10; - private static final Integer DEFAULT_TIME_WINDOW_SECONDS = 120; - -//在构造函数中解析配置信息 - - public AggregateMetricsCollector(ApplicationModel applicationModel) { - this.applicationModel = applicationModel; - ConfigManager configManager = applicationModel.getApplicationConfigManager(); - MetricsConfig config = configManager.getMetrics().orElse(null); - if (config != null && config.getAggregation() != null && Boolean.TRUE.equals(config.getAggregation().getEnabled())) { - // only registered when aggregation is enabled. - registerListener(); - - AggregationConfig aggregation = config.getAggregation(); - this.bucketNum = aggregation.getBucketNum() == null ? DEFAULT_BUCKET_NUM : aggregation.getBucketNum(); - this.timeWindowSeconds = aggregation.getTimeWindowSeconds() == null ? DEFAULT_TIME_WINDOW_SECONDS : aggregation.getTimeWindowSeconds(); - } - } -} -``` - -如果开启了本地聚合,则通过 spring 的 BeanFactory 添加监听,将 AggregateMetricsCollector 与 DefaultMetricsCollector 绑定,实现一种生产者消费者的模式,DefaultMetricsCollector 中使用监听器列表,方便扩展 - -```java -private void registerListener() { - applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).addListener(this); -} -``` - -## 3. 指标聚合 -滑动窗口 -假设我们初始有6个bucket,每个窗口时间设置为2分钟 -每次写入指标数据时,会将数据分别写入6个bucket内,每隔两分钟移动一个bucket并且清除原来bucket内的数据 -读取指标时,读取当前current指向的bucket,以达到滑动窗口的效果 -具体如下图所示,实现了当前 bucket 内存储了配置中设置的 bucket 生命周期内的数据,即近期数据 -![img_1.png](/imgs/docs3-v2/java-sdk/observability/aggre.png) - -在每个bucket内,使用**TDigest 算法**计算分位数指标 - -> **TDigest 算法**(极端分位精确度高,如p1 p99,中间分位精确度低,如p50),相关资料如下 -> -> - https://op8867555.github.io/posts/2018-04-09-tdigest.html -> - https://blog.csdn.net/csdnnews/article/details/116246540 -> - 开源实现:https://github.com/tdunning/t-digest - -代码实现如下,除了 TimeWindowQuantile 用来计算分位数指标外,另外提供了 TimeWindowCounter 来收集时间区间内的指标数量 -```java -public class TimeWindowQuantile { - private final double compression; - private final TDigest[] ringBuffer; - private int currentBucket; - private long lastRotateTimestampMillis; - private final long durationBetweenRotatesMillis; - - public TimeWindowQuantile(double compression, int bucketNum, int timeWindowSeconds) { - this.compression = compression; - this.ringBuffer = new TDigest[bucketNum]; - for (int i = 0; i < bucketNum; i++) { - this.ringBuffer[i] = TDigest.createDigest(compression); - } - - this.currentBucket = 0; - this.lastRotateTimestampMillis = System.currentTimeMillis(); - this.durationBetweenRotatesMillis = TimeUnit.SECONDS.toMillis(timeWindowSeconds) / bucketNum; - } - - public synchronized double quantile(double q) { - TDigest currentBucket = rotate(); - return currentBucket.quantile(q); - } - - public synchronized void add(double value) { - rotate(); - for (TDigest bucket : ringBuffer) { - bucket.add(value); - } - } - - private TDigest rotate() { - long timeSinceLastRotateMillis = System.currentTimeMillis() - lastRotateTimestampMillis; - while (timeSinceLastRotateMillis > durationBetweenRotatesMillis) { - ringBuffer[currentBucket] = TDigest.createDigest(compression); - if (++currentBucket >= ringBuffer.length) { - currentBucket = 0; - } - timeSinceLastRotateMillis -= durationBetweenRotatesMillis; - lastRotateTimestampMillis += durationBetweenRotatesMillis; - } - return ringBuffer[currentBucket]; - } -} -``` - -# 指标推送 -指标推送只有用户在设置了配置且配置protocol参数后才开启,若只开启指标聚合,则默认不推送指标。 -## 1. Promehteus Pull ServiceDiscovery - 使用dubbo-admin等类似的中间层,启动时根据配置将本机 IP、Port、MetricsURL 推送地址信息至dubbo-admin(或任意中间层)的方式,暴露HTTP ServiceDiscovery供prometheus读取,配置方式如,其中在pull模式下address为可选参数,若不填则需用户手动在Prometheus配置文件中配置地址 - -```java -private void exportHttpServer() { - boolean exporterEnabled = url.getParameter(PROMETHEUS_EXPORTER_ENABLED_KEY, false); - if (exporterEnabled) { - int port = url.getParameter(PROMETHEUS_EXPORTER_METRICS_PORT_KEY, PROMETHEUS_DEFAULT_METRICS_PORT); - String path = url.getParameter(PROMETHEUS_EXPORTER_METRICS_PATH_KEY, PROMETHEUS_DEFAULT_METRICS_PATH); - if (!path.startsWith("/")) { - path = "/" + path; - } - - try { - prometheusExporterHttpServer = HttpServer.create(new InetSocketAddress(port), 0); - prometheusExporterHttpServer.createContext(path, httpExchange -> { - String response = prometheusRegistry.scrape(); - httpExchange.sendResponseHeaders(200, response.getBytes().length); - try (OutputStream os = httpExchange.getResponseBody()) { - os.write(response.getBytes()); - } - }); - - httpServerThread = new Thread(prometheusExporterHttpServer::start); - httpServerThread.start(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } -} -``` - -## 2. Prometheus Push Pushgateway -用户直接在Dubbo配置文件中配置Prometheus Pushgateway的地址即可,如,其中interval代表推送间隔 - -```java - -private void schedulePushJob() { - boolean pushEnabled = url.getParameter(PROMETHEUS_PUSHGATEWAY_ENABLED_KEY, false); - if (pushEnabled) { - String baseUrl = url.getParameter(PROMETHEUS_PUSHGATEWAY_BASE_URL_KEY); - String job = url.getParameter(PROMETHEUS_PUSHGATEWAY_JOB_KEY, PROMETHEUS_DEFAULT_JOB_NAME); - int pushInterval = url.getParameter(PROMETHEUS_PUSHGATEWAY_PUSH_INTERVAL_KEY, PROMETHEUS_DEFAULT_PUSH_INTERVAL); - String username = url.getParameter(PROMETHEUS_PUSHGATEWAY_USERNAME_KEY); - String password = url.getParameter(PROMETHEUS_PUSHGATEWAY_PASSWORD_KEY); - - NamedThreadFactory threadFactory = new NamedThreadFactory("prometheus-push-job", true); - pushJobExecutor = Executors.newScheduledThreadPool(1, threadFactory); - PushGateway pushGateway = new PushGateway(baseUrl); - if (!StringUtils.isBlank(username)) { - pushGateway.setConnectionFactory(new BasicAuthHttpConnectionFactory(username, password)); - } - - pushJobExecutor.scheduleWithFixedDelay(() -> push(pushGateway, job), pushInterval, pushInterval, TimeUnit.SECONDS); - } -} - -protected void push(PushGateway pushGateway, String job) { - try { - pushGateway.pushAdd(prometheusRegistry.getPrometheusRegistry(), job); - } catch (IOException e) { - logger.error("Error occurred when pushing metrics to prometheus: ", e); - } -} -``` - -## 可视化展示 -目前推荐使用 Prometheus 来进行服务监控,Grafana 来展示指标数据。可以通过案例来快速入门 [Dubbo 可视化监控](/en/overview/tasks/observability/grafana/)。 diff --git a/content/en/blog/users/eleme.md b/content/en/blog/users/eleme.md index b2e4a77a4c29..dbf1a783c9a3 100644 --- a/content/en/blog/users/eleme.md +++ b/content/en/blog/users/eleme.md @@ -34,7 +34,7 @@ Some may worry about the storage pressure on the registration center caused by d Similar to the provider side, the consumer side must also undergo a dual subscription process for smooth migration, which we will not elaborate on further. The consumer's dual subscription behavior can also be dynamically adjusted through rules or switches to control the migration of a certain service or application to the application-level address model. Additionally, Dubbo3 has a built-in automatic decision mechanism that will automatically complete the switch when application-level addresses are available, and this behavior is default. -以下是消费端双订阅时的选址流程: +Here is the selection process during consumer-side dual subscription: ![elem-upgrade-consumer1](/imgs/user/eleme/elem-upgrade-consumer1.png) @@ -47,3 +47,4 @@ Ele.me successfully upgraded to Dubbo3 and the application-level service discove * Overall resource consumption of the registration center’s data storage decreased by 90% * Permanent memory consumption of the consumer framework itself decreased by 50% The overall stability and performance of the cluster have significantly improved, also preparing for future capacity expansion. + diff --git a/content/en/blog/users/pingan.md b/content/en/blog/users/pingan.md index 20a6edc43314..d6fd0036355b 100644 --- a/content/en/blog/users/pingan.md +++ b/content/en/blog/users/pingan.md @@ -146,9 +146,9 @@ RPC monitoring in Dubbo has traditionally been provided by MonitorFilter and Dub These capabilities can meet basic migration tasks. However, from our current status concerning the need for a smooth migration, the observability of migration traffic, and gray and controllable procedures, there still seems to be some distance. Yet while sorting out Dubbo3’s capabilities, we found relatively simple extension solutions. Thus, a general outline of the overall migration方案 is established. -# 4 Design of Upgrade & Migration方案 +# 4 Design of Upgrade & Migration -The design of the方案 focuses on "smooth and controllable." Based on the new architecture of Dubbo3, the current migration方案 schematic is being validated as follows: +The design of the focuses on "smooth and controllable." Based on the new architecture of Dubbo3, the current migration方案 schematic is being validated as follows: ![pingan](/imgs/v3/users/pingan-8.png) @@ -227,3 +227,4 @@ The overall architectural upgrade of Dubbo3 has resolved past pressures on servi # 5 Community Collaboration Currently, this project is still under continuous upgrading, and we maintain close contact with the community. During this period, we have encountered many problems, all of which have been patiently resolved by community developers. Users looking to upgrade to Dubbo3 can register on the community's GitHub User Issue ([https://github.com/apache/dubbo/issues/9436](https://github.com/apache/dubbo/issues/9436)), and those interested in participating in the community can follow the official Dubbo public account (search for Apache Dubbo) to learn more about the developments in the Dubbo community. + diff --git a/content/en/blog/users/xiaomi.md b/content/en/blog/users/xiaomi.md index 6fa2e4399109..3ce69d2e48bc 100644 --- a/content/en/blog/users/xiaomi.md +++ b/content/en/blog/users/xiaomi.md @@ -1,48 +1,48 @@ --- date: 2023-01-15 -title: "小米与 Dubbo 社区的合作" -linkTitle: "小米" -tags: ["用户案例"] +title: "Xiaomi's Collaboration with the Dubbo Community" +linkTitle: "Xiaomi" +tags: ["User Case"] weight: 4 --- -Xiaomi is devoted to making continuous contribution to the open source community. Since the introduction of Dubbo3, internal projects are rapidly upgrading to the latest version of Dubbo. Currently, At present the numbers of instances has been upgrade to a certain proportion. Not only performance improvements have been seen, but services are also running smoothly with improvements in availability. Statistics provide proof that Dubbo’s switch from api-level discovery to application-level discovery has improved the availability and reliability of service discovery, which leads to lower operations cost. In addition, using ProtoBuf for serialization and deserialization has reduced data exchange size. Lastly, full compatibility with grpc provides convenience to Xiaomi’s multi-language development environment. +Xiaomi is devoted to making continuous contributions to the open-source community. Since the introduction of Dubbo3, internal projects are rapidly upgrading to the latest version of Dubbo. Currently, the number of instances has been upgraded to a certain proportion. Not only have performance improvements been seen, but services are also running smoothly with improvements in availability. Statistics provide proof that Dubbo’s switch from API-level discovery to application-level discovery has improved the availability and reliability of service discovery, leading to lower operation costs. In addition, using ProtoBuf for serialization and deserialization has reduced the data exchange size. Lastly, full compatibility with gRPC provides convenience to Xiaomi’s multi-language development environment. -Having evolved from Dubbo2, Dubbo3 is a major upgrade in several areas including, Cloud Native adaptation, service discovery, communication protocols. Furthermore, upgrading to version 3.0 requires no changes in application code. The following is a detailed introduction to Dubbo3’s features. +Having evolved from Dubbo2, Dubbo3 is a major upgrade in several areas including Cloud Native adaptation, service discovery, and communication protocols. Furthermore, upgrading to version 3.0 requires no changes in application code. The following is a detailed introduction to Dubbo3’s features. -### 云原生适配 Cloud Native Adaptation +### Cloud Native Adaptation -To be future proof, the design and development of Dubbo3 has fully adapted Cloud Native. To meet this goal, Dubbo has made some trade-offs.Several core components of Dubbo3 support Kubernetes. In particular, Dubbo3 implements Kubernetes service and container life-cycle. Serverless and native image support will be release in the future. +To be future-proof, the design and development of Dubbo3 has fully adapted to Cloud Native. To meet this goal, Dubbo has made some trade-offs. Several core components of Dubbo3 support Kubernetes. In particular, Dubbo3 implements Kubernetes service and container lifecycle. Serverless and native image support will be released in the future. To support Kubernetes, Dubbo3 places service registration and discovery down to the Kubernetes Service layer, thus reestablishing the boundary between Dubbo and Kubernetes. However, this requires deprecating Dubbo’s own service discovery events. -### 全新服务发现模型 New Service Discovery Model +### New Service Discovery Model -Previous versions of Dubbo differs from other mainstream service discovery middle-ware such as Spring Cloud and gRPC in its service discovery granularity. In the past Dubbo discovers services at the API level. Dubbo3, however, utilizes application level service discovery. This provides the following benefits. +Previous versions of Dubbo differed from other mainstream service discovery middleware such as Spring Cloud and gRPC in its service discovery granularity. In the past, Dubbo discovered services at the API level. Dubbo3, however, utilizes application-level service discovery. This provides the following benefits. 1. Eliminates incompatibility issues with other service discovery platforms, which is crucial since Xiaomi has diverse languages and development frameworks. -2. The new service discovery model improves resource utilization, lowers Dubbo address’s single machine memory usage, lowers service discover cluster’s load. +2. The new service discovery model improves resource utilization, lowers Dubbo address’s single machine memory usage, and lowers service discovery cluster’s load. -### 全新RPC 通信协议 New RPC Communication Protocal +### New RPC Communication Protocol Introduction of a new RPC communication protocol based on HTTP/2 called Triple. Using Triple has the following benefits. 1. Complete compatibility with gRPC. 2. Protobuf support for serialization and deserialization. -### 升级与兼容性 Upgrade and Backwards Compatibility +### Upgrade and Backwards Compatibility -For production systems, upgrading a dependency while maintaining backward compatibility is challenging. Supporting users of older versions of Dubbo (2.5, 2.6, 2,7) is a goal of Dubbo3’s design and development. Thus, upgrading to Dubbo3 is painless. No changes are required to be made to existing production systems. However to use Dubbo3’s new features, additional changes are needed to existing code. Thus, there are two suggested upgrade paths. +For production systems, upgrading a dependency while maintaining backward compatibility is challenging. Supporting users of older versions of Dubbo (2.5, 2.6, 2.7) is a goal of Dubbo3’s design and development. Thus, upgrading to Dubbo3 is painless. No changes are required to be made to existing production systems. However, to use Dubbo3’s new features, additional changes are needed to existing code. Thus, there are two suggested upgrade paths. 1. Upgrade to Dubbo3 but do not use Dubbo3’s new features. This path requires no code changes. 2. Upgrade to Dubbo3 while making additional changes to support the new features. ### Suggestions -1. Since Dubbo3 is closely compatible with Cloud Native, further work can be done to enhance Dubbo’s support of istio and other service mesh frameworks to speed up Dubbo users’ adaption of service mesh. +1. Since Dubbo3 is closely compatible with Cloud Native, further work can be done to enhance Dubbo’s support of Istio and other service mesh frameworks to speed up Dubbo users’ adaptation of service mesh. 2. Add more performance metrics to monitor Dubbo consumers and providers. -### 作者 -* 张志勇 -* 张平 -* 许铮 +### Author +* Zhang Zhiyong +* Zhang Ping +* Xu Zheng From 06771adce7637d8742b3b698217782fbd34ebf41 Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Mon, 30 Sep 2024 17:35:15 +0800 Subject: [PATCH 23/23] Translate --- content/en/contact/_index.md | 132 ++ content/en/contact/books/_index.md | 43 + content/en/contact/committer/_index.md | 9 + .../committer/apache-dubbo-page_dev.md | 39 + .../committer/cla-signing-guide_dev.md | 35 + .../committer/label-an-issue-guide_dev.md | 37 + .../committer/new-committer-guide_dev.md | 86 ++ .../contact/committer/release-guide/_index.md | 9 + .../contact/committer/release-guide/common.md | 179 +++ .../committer/release-guide/java-sdk.md | 463 ++++++ .../en/contact/committer/website-guide_dev.md | 15 + content/en/contact/contributor/_index.md | 9 + .../contributor/become-a-committer_dev.md | 25 + .../contributor/dubbo-extension-guide_dev.md | 53 + .../mailing-list-subscription-guide_dev.md | 27 +- .../contributor/new-contributor-guide_dev.md | 141 ++ .../reporting-security-issues_dev.md | 31 + .../software-donation-guide_dev.md | 33 +- .../contributor/test-coverage-guide_dev.md | 26 + content/en/contribution-guidelines/_index.md | 8 + content/en/docs/_index.md | 10 - .../en/docs/contribution-guidelines/_index.md | 87 -- .../committer/_index.md | 11 - .../committer/apache-dubbo-page_dev.md | 32 - .../committer/label-an-issue-guide_dev.md | 36 - .../committer/new-committer-guide_dev.md | 100 -- .../committer/release-guide_dev.md | 504 ------- .../committer/website-guide_dev.md | 9 - .../contributor/_index.md | 11 - .../contributor/become-a-committer_dev.md | 21 - .../contributor/cla-signing-guide_dev.md | 31 - .../contributor/dubbo-extension-guide_dev.md | 43 - .../contributor/new-contributor-guide_dev.md | 67 - .../reporting-security-issues_dev.md | 27 - .../contributor/test-coverage-guide_dev.md | 26 - content/en/docs/faq/_index.md | 35 - content/en/docs/v2.7/_index.md | 10 - content/en/docs/v2.7/admin/_index.md | 8 - content/en/docs/v2.7/admin/install/_index.md | 21 - .../docs/v2.7/admin/install/admin-console.md | 47 - .../docs/v2.7/admin/install/consumer-demo.md | 24 - .../docs/v2.7/admin/install/monitor-center.md | 9 - .../docs/v2.7/admin/install/provider-demo.md | 24 - content/en/docs/v2.7/admin/install/redis.md | 57 - .../en/docs/v2.7/admin/install/zookeeper.md | 103 -- content/en/docs/v2.7/admin/ops/_index.md | 8 - content/en/docs/v2.7/admin/ops/apidocs.md | 103 -- content/en/docs/v2.7/admin/ops/functions.md | 31 - content/en/docs/v2.7/admin/ops/governance.md | 60 - .../en/docs/v2.7/admin/ops/introduction.md | 71 - content/en/docs/v2.7/admin/ops/pinpoint.md | 416 ------ content/en/docs/v2.7/admin/ops/search.md | 16 - content/en/docs/v2.7/admin/ops/skywalking.md | 150 -- content/en/docs/v2.7/admin/ops/test.md | 8 - content/en/docs/v2.7/dev/SPI.md | 244 ---- content/en/docs/v2.7/dev/TCK.md | 26 - content/en/docs/v2.7/dev/_index.md | 10 - content/en/docs/v2.7/dev/build.md | 88 -- content/en/docs/v2.7/dev/checklist.md | 26 - content/en/docs/v2.7/dev/code-smell.md | 211 --- content/en/docs/v2.7/dev/coding.md | 59 - content/en/docs/v2.7/dev/contract.md | 20 - content/en/docs/v2.7/dev/design.md | 105 -- content/en/docs/v2.7/dev/implementation.md | 231 --- content/en/docs/v2.7/dev/impls/_index.md | 10 - content/en/docs/v2.7/dev/impls/cache.md | 89 -- content/en/docs/v2.7/dev/impls/cluster.md | 84 -- content/en/docs/v2.7/dev/impls/compiler.md | 60 - .../en/docs/v2.7/dev/impls/config-center.md | 101 -- content/en/docs/v2.7/dev/impls/container.md | 68 - content/en/docs/v2.7/dev/impls/dispatcher.md | 67 - content/en/docs/v2.7/dev/impls/exchanger.md | 96 -- .../docs/v2.7/dev/impls/exporter-listener.md | 71 - .../docs/v2.7/dev/impls/extension-factory.md | 62 - content/en/docs/v2.7/dev/impls/filter.md | 95 -- .../docs/v2.7/dev/impls/invoker-listener.md | 70 - .../en/docs/v2.7/dev/impls/load-balance.md | 70 - .../en/docs/v2.7/dev/impls/logger-adapter.md | 90 -- content/en/docs/v2.7/dev/impls/merger.md | 73 - content/en/docs/v2.7/dev/impls/monitor.md | 80 -- content/en/docs/v2.7/dev/impls/networker.md | 64 - content/en/docs/v2.7/dev/impls/page.md | 67 - content/en/docs/v2.7/dev/impls/protocol.md | 161 --- .../en/docs/v2.7/dev/impls/proxy-factory.md | 71 - content/en/docs/v2.7/dev/impls/registry.md | 212 --- content/en/docs/v2.7/dev/impls/remoting.md | 127 -- content/en/docs/v2.7/dev/impls/router.md | 69 - content/en/docs/v2.7/dev/impls/serialize.md | 77 - .../en/docs/v2.7/dev/impls/status-checker.md | 69 - .../en/docs/v2.7/dev/impls/telnet-handler.md | 83 -- content/en/docs/v2.7/dev/impls/threadpool.md | 67 - content/en/docs/v2.7/dev/impls/validation.md | 80 -- content/en/docs/v2.7/dev/principals/_index.md | 10 - .../docs/v2.7/dev/principals/code-detail.md | 39 - .../docs/v2.7/dev/principals/configuration.md | 89 -- content/en/docs/v2.7/dev/principals/dummy.md | 208 --- .../docs/v2.7/dev/principals/expansibility.md | 23 - .../en/docs/v2.7/dev/principals/extension.md | 141 -- .../v2.7/dev/principals/general-knowledge.md | 73 - .../en/docs/v2.7/dev/principals/robustness.md | 85 -- content/en/docs/v2.7/dev/release.md | 40 - content/en/docs/v2.7/user/_index.md | 7 - content/en/docs/v2.7/user/benchmark-tool.md | 40 - content/en/docs/v2.7/user/best-practice.md | 69 - content/en/docs/v2.7/user/capacity-plan.md | 23 - .../en/docs/v2.7/user/configuration/_index.md | 7 - .../v2.7/user/configuration/annotation.md | 96 -- .../en/docs/v2.7/user/configuration/api.md | 127 -- .../configuration-load-process.md | 186 --- .../v2.7/user/configuration/properties.md | 49 - .../en/docs/v2.7/user/configuration/xml.md | 84 -- content/en/docs/v2.7/user/coveragence.md | 31 - content/en/docs/v2.7/user/dependencies.md | 64 - content/en/docs/v2.7/user/examples/_index.md | 13 - .../en/docs/v2.7/user/examples/accesslog.md | 67 - .../en/docs/v2.7/user/examples/async-call.md | 67 - .../examples/async-execute-on-provider.md | 96 -- .../en/docs/v2.7/user/examples/attachment.md | 33 - .../user/examples/broadcast-resp-collect.md | 71 - .../v2.7/user/examples/callback-parameter.md | 118 -- .../v2.7/user/examples/concurrency-control.md | 66 - .../v2.7/user/examples/config-connections.md | 42 - .../en/docs/v2.7/user/examples/config-rule.md | 56 - content/en/docs/v2.7/user/examples/context.md | 45 - .../docs/v2.7/user/examples/delay-publish.md | 62 - .../user/examples/distributed-transaction.md | 16 - content/en/docs/v2.7/user/examples/dump.md | 26 - .../docs/v2.7/user/examples/echo-service.md | 31 - .../docs/v2.7/user/examples/events-notify.md | 103 -- .../v2.7/user/examples/explicit-target.md | 46 - .../user/examples/fault-tolerent-strategy.md | 93 -- .../user/examples/generic-invoke-with-json.md | 67 - .../v2.7/user/examples/generic-reference.md | 103 -- .../v2.7/user/examples/generic-service.md | 51 - .../v2.7/user/examples/graceful-shutdown.md | 36 - .../docs/v2.7/user/examples/group-merger.md | 60 - .../v2.7/user/examples/hostname-binding.md | 65 - .../user/examples/invoke-with-specified-ip.md | 78 - .../docs/v2.7/user/examples/lazy-connect.md | 15 - .../en/docs/v2.7/user/examples/loadbalance.md | 70 - .../en/docs/v2.7/user/examples/local-call.md | 54 - .../en/docs/v2.7/user/examples/local-mock.md | 106 -- .../en/docs/v2.7/user/examples/local-stub.md | 53 - .../v2.7/user/examples/logger-strategy.md | 29 - .../user/examples/msgpack-serialization.md | 126 -- .../v2.7/user/examples/multi-protocols.md | 52 - .../docs/v2.7/user/examples/multi-registry.md | 90 -- .../docs/v2.7/user/examples/multi-versions.md | 51 - content/en/docs/v2.7/user/examples/netty4.md | 45 - .../user/examples/parameter-validation.md | 189 --- .../v2.7/user/examples/preflight-check.md | 62 - .../user/examples/provider-timeout-release.md | 137 -- .../user/examples/reference-config-cache.md | 44 - .../docs/v2.7/user/examples/registry-only.md | 25 - .../docs/v2.7/user/examples/result-cache.md | 37 - .../docs/v2.7/user/examples/routing-rule.md | 199 --- .../docs/v2.7/user/examples/serialization.md | 78 - .../v2.7/user/examples/service-container.md | 67 - .../v2.7/user/examples/service-downgrade.md | 25 - .../docs/v2.7/user/examples/service-group.md | 36 - .../docs/v2.7/user/examples/static-service.md | 33 - .../en/docs/v2.7/user/examples/stickiness.md | 23 - .../docs/v2.7/user/examples/subscribe-only.md | 25 - .../docs/v2.7/user/examples/thread-model.md | 36 - .../v2.7/user/examples/token-authorization.md | 51 - content/en/docs/v2.7/user/languages/_index.md | 9 - .../docs/v2.7/user/languages/erlang/_index.md | 9 - .../v2.7/user/languages/erlang/quick-start.md | 68 - .../v2.7/user/languages/erlang/reference.md | 24 - .../user/languages/erlang/serialization.md | 25 - .../v2.7/user/languages/erlang/service.md | 30 - content/en/docs/v2.7/user/maturity.md | 99 -- content/en/docs/v2.7/user/perf-test.md | 174 --- content/en/docs/v2.7/user/preface/_index.md | 8 - .../en/docs/v2.7/user/preface/architecture.md | 73 - .../en/docs/v2.7/user/preface/background.md | 29 - .../en/docs/v2.7/user/preface/requirements.md | 21 - content/en/docs/v2.7/user/preface/usage.md | 46 - content/en/docs/v2.7/user/quick-start.md | 257 ---- content/en/docs/v2.7/user/recommend.md | 175 --- .../en/docs/v2.7/user/references/_index.md | 7 - content/en/docs/v2.7/user/references/api.md | 70 - content/en/docs/v2.7/user/references/maven.md | 27 - .../en/docs/v2.7/user/references/metadata.md | 382 ----- .../v2.7/user/references/protocol/_index.md | 9 - .../v2.7/user/references/protocol/dubbo.md | 115 -- .../v2.7/user/references/protocol/hessian.md | 76 - .../v2.7/user/references/protocol/http.md | 64 - .../user/references/protocol/memcached.md | 48 - .../v2.7/user/references/protocol/redis.md | 48 - .../v2.7/user/references/protocol/rest.md | 748 ---------- .../docs/v2.7/user/references/protocol/rmi.md | 88 -- .../v2.7/user/references/protocol/thrift.md | 38 - .../user/references/protocol/webservice.md | 119 -- content/en/docs/v2.7/user/references/qos.md | 233 --- .../v2.7/user/references/registry/_index.md | 9 - .../user/references/registry/multicast.md | 47 - .../v2.7/user/references/registry/nacos.md | 139 -- .../v2.7/user/references/registry/redis.md | 81 -- .../v2.7/user/references/registry/simple.md | 55 - .../user/references/registry/zookeeper.md | 160 --- .../en/docs/v2.7/user/references/telnet.md | 108 -- .../docs/v2.7/user/references/xml/_index.md | 23 - .../user/references/xml/dubbo-application.md | 21 - .../user/references/xml/dubbo-argument.md | 20 - .../references/xml/dubbo-config-center.md | 27 - .../user/references/xml/dubbo-consumer.md | 30 - .../v2.7/user/references/xml/dubbo-method.md | 37 - .../v2.7/user/references/xml/dubbo-module.md | 16 - .../v2.7/user/references/xml/dubbo-monitor.md | 15 - .../user/references/xml/dubbo-parameter.md | 28 - .../user/references/xml/dubbo-protocol.md | 36 - .../user/references/xml/dubbo-provider.md | 56 - .../user/references/xml/dubbo-reference.md | 39 - .../user/references/xml/dubbo-registry.md | 30 - .../v2.7/user/references/xml/dubbo-service.md | 43 - content/en/docs/v2.7/user/rest.md | 1260 ----------------- content/en/docs/v2.7/user/simple-monitor.md | 95 -- content/en/docs/v3.0/_index.md | 14 - content/en/docs/v3.0/languages/_index.md | 8 - .../en/docs/v3.0/languages/erlang/_index.md | 9 - .../docs/v3.0/languages/erlang/quick-start.md | 71 - .../docs/v3.0/languages/erlang/reference.md | 24 - .../v3.0/languages/erlang/serialization.md | 26 - .../en/docs/v3.0/languages/erlang/service.md | 30 - .../en/docs/v3.0/languages/golang/_index.md | 9 - .../docs/v3.0/languages/golang/go-specific.md | 7 - .../docs/v3.0/languages/golang/quick-start.md | 212 --- content/en/docs/v3.0/languages/rust/_index.md | 10 - content/en/docs/v3.0/loadbalance/_index.md | 71 - content/en/docs/v3.0/references/_index.md | 8 - .../en/docs/v3.0/references/graalvm/_index.md | 7 - .../references/graalvm/support-graalvm.md | 152 -- .../docs/v3.0/references/lifecycle/_index.md | 7 - .../docs/v3.0/references/lifecycle/brief.md | 68 - .../v3.0/references/lifecycle/liveness.md | 73 - .../v3.0/references/lifecycle/readiness.md | 74 - .../docs/v3.0/references/lifecycle/startup.md | 74 - .../docs/v3.0/whats-new-in-dubbo3/_index.md | 72 - content/en/docs3-v2/_index.md | 9 - content/en/docs3-v2/erlang-sdk/_index.md | 9 - content/en/docs3-v2/golang-sdk/_index.md | 7 - .../golang-sdk/preface/3.0_feature.md | 70 - .../en/docs3-v2/golang-sdk/preface/_index.md | 15 - .../golang-sdk/preface/concept/_index.md | 7 - .../golang-sdk/preface/concept/generic.md | 153 -- .../preface/concept/multi_language.md | 20 - .../golang-sdk/preface/concept/protocol.md | 108 -- .../golang-sdk/preface/concept/registry.md | 87 -- .../golang-sdk/preface/design/_index.md | 7 - .../preface/design/aop_and_extension.md | 107 -- .../preface/design/app_and_interface.md | 65 - .../golang-sdk/preface/design/architecture.md | 19 - .../en/docs3-v2/golang-sdk/preface/samples.md | 176 --- .../en/docs3-v2/golang-sdk/preface/what.md | 15 - .../docs3-v2/golang-sdk/quickstart/_index.md | 6 - .../docs3-v2/golang-sdk/quickstart/install.md | 46 - .../quickstart/quickstart_triple.md | 119 -- .../quickstart_triple_with_customize.md | 207 --- .../en/docs3-v2/golang-sdk/refer/_index.md | 5 - .../golang-sdk/refer/basic_concept.md | 34 - .../golang-sdk/refer/compatible_version.md | 14 - .../en/docs3-v2/golang-sdk/refer/config.md | 121 -- .../en/docs3-v2/golang-sdk/refer/ecology.md | 46 - .../golang-sdk/refer/use_dubbogo_cli.md | 429 ------ .../docs3-v2/golang-sdk/sourcecode/_index.md | 5 - .../golang-sdk/sourcecode/protocol.md | 24 - .../golang-sdk/sourcecode/registry.md | 52 - .../en/docs3-v2/golang-sdk/tutorial/_index.md | 5 - .../golang-sdk/tutorial/debugging/_index.md | 5 - .../golang-sdk/tutorial/debugging/grpc_cli.md | 75 - .../golang-sdk/tutorial/deployment/_index.md | 5 - .../tutorial/deployment/docker/_index.md | 5 - .../tutorial/deployment/kubernetes/_index.md | 5 - .../tutorial/deployment/practice/_index.md | 5 - .../golang-sdk/tutorial/develop/_index.md | 5 - .../tutorial/develop/config-center/_index.md | 5 - .../config-center/config-center-dynamic.md | 148 -- .../tutorial/develop/config-center/desc.md | 5 - .../develop/config-center/remote_config.md | 45 - .../tutorial/develop/features/_index.md | 5 - .../tutorial/develop/features/config_api.md | 98 -- .../tutorial/develop/features/context.md | 14 - .../develop/features/custom-logger.md | 85 -- .../tutorial/develop/features/generic-2.md | 100 -- .../tutorial/develop/features/generic.md | 98 -- .../tutorial/develop/interflow/_index.md | 5 - .../tutorial/develop/interflow/call_grpc.md | 14 - .../tutorial/develop/interflow/call_java.md | 842 ----------- .../tutorial/develop/protocol/_index.md | 5 - .../develop/protocol/choose_protocol.md | 231 --- .../tutorial/develop/protocol/error.md | 122 -- .../develop/protocol/exception_response.md | 115 -- .../tutorial/develop/registry/_index.md | 5 - .../tutorial/develop/registry/desc.md | 5 - .../develop/registry/multi_registry.md | 116 -- .../tutorial/develop/registry/nacos-2.md | 157 -- .../tutorial/develop/registry/nacos.md | 141 -- .../tutorial/develop/registry/polaris.md | 7 - .../tutorial/develop/registry/registry.md | 109 -- .../develop/registry/service-discovery.md | 56 - .../tutorial/develop/registry/zookeeper.md | 7 - .../golang-sdk/tutorial/develop/template.md | 87 -- .../golang-sdk/tutorial/governance/_index.md | 5 - .../tutorial/governance/features/_index.md | 5 - .../tutorial/governance/features/aop.md | 64 - .../governance/features/custom-filter.md | 113 -- .../tutorial/governance/features/timeout.md | 57 - .../tutorial/governance/health/_index.md | 5 - .../tutorial/governance/health/kubernetes.md | 5 - .../tutorial/governance/health/start-check.md | 29 - .../governance/health/triple-health-check.md | 105 -- .../tutorial/governance/limit/_index.md | 5 - .../governance/limit/adaptive-service.md | 26 - .../governance/limit/internally/_index.md | 5 - .../governance/limit/polaris/_index.md | 5 - .../governance/limit/sentinel/_index.md | 5 - .../tutorial/governance/limit/tps_limiter.md | 103 -- .../tutorial/governance/monitor/_index.md | 5 - .../governance/monitor/grafana/_index.md | 5 - .../governance/monitor/http/_index.md | 5 - .../governance/monitor/logger/_index.md | 5 - .../tutorial/governance/monitor/metrics.md | 205 --- .../governance/monitor/promethus/_index.md | 5 - .../governance/monitor/rpc_metrics.md | 49 - .../governance/service-mesh/_index.md | 5 - .../governance/service-mesh/deploy.md | 426 ------ .../tutorial/governance/service-mesh/istio.md | 31 - .../governance/service-mesh/pixiu/_index.md | 5 - .../service-mesh/pixiu/http_triple.md | 79 -- .../service-mesh/pixiu/pixiu-nacos-triple.md | 70 - .../service-mesh/proxyless_service_mesh.md | 107 -- .../service-mesh/traffic_management.md | 416 ------ .../tutorial/governance/tracing/_index.md | 5 - .../governance/tracing/jaeger/_index.md | 5 - .../tracing/opentelmentry/_index.md | 5 - .../governance/tracing/skywalking/_index.md | 5 - .../tutorial/governance/traffic/_index.md | 5 - .../governance/traffic/graceful_shutdown.md | 24 - .../governance/traffic/mesh_router.md | 144 -- content/en/docs3-v2/java-sdk/_index.md | 19 - .../advanced-features-and-usage/_index.md | 11 - .../observability/_index.md | 26 - .../observability/doc.md | 9 - .../observability/health-information.md | 8 - .../observability/kubernetes-probes.md | 8 - .../observability/logging.md | 8 - .../observability/meter.md | 505 ------- .../observability/tracing.md | 181 --- .../others/Docker.md | 68 - .../others/_index.md | 8 - .../others/dubbo-kubernetes-probe.md | 70 - .../others/graceful-shutdown.md | 50 - .../others/logger-howto.md | 177 --- .../others/logger-management.md | 120 -- .../others/service-container.md | 60 - .../others/set-host.md | 80 -- .../performance/_index.md | 6 - .../performance/concurrency-control.md | 74 - .../performance/config-connections.md | 44 - .../performance/dump.md | 55 - .../performance/lazy-connect.md | 18 - .../performance/loadbalance.md | 105 -- .../performance/profiler.md | 189 --- .../performance/reference-config-cache.md | 43 - .../performance/result-cache.md | 36 - .../performance/router-snapshot.md | 79 -- .../performance/serialization.md | 241 ---- .../performance/simplify-registry-data.md | 255 ---- .../performance/stickiness.md | 26 - .../performance/support-graalvm.md | 213 --- .../performance/threading-model/_index.md | 6 - .../performance/threading-model/consumer.md | 45 - .../performance/threading-model/provider.md | 127 -- .../security/_index.md | 6 - .../security/auth.md | 40 - .../security/class-check.md | 215 --- .../security/tls.md | 55 - .../security/token-authorization.md | 48 - .../service/_index.md | 6 - .../service/accesslog.md | 27 - .../service/async-call.md | 177 --- .../service/async-execute-on-provider.md | 98 -- .../service/attachment.md | 103 -- .../service/callback-parameter.md | 118 -- .../service/consistent-hash.md | 47 - .../service/context.md | 49 - .../service/delay-publish.md | 59 - .../service/distributed-transaction.md | 15 - .../service/echo-service.md | 36 - .../service/events-notify.md | 108 -- .../service/explicit-target.md | 60 - .../service/fault-tolerent-strategy.md | 137 -- .../service/generic-reference.md | 376 ----- .../service/generic-service.md | 54 - .../service/group-merger.md | 69 - .../service/isolation-executor.md | 230 --- .../service/local-call.md | 76 - .../service/local-mock.md | 157 -- .../service/local-stub.md | 55 - .../service/multi-protocols.md | 53 - .../service/multi-registry.md | 87 -- .../service/multi-versions.md | 50 - .../service/parameter-validation.md | 196 --- .../service/port-unification.md | 125 -- .../service/preflight-check.md | 67 - .../service/reactive.md | 235 --- .../service/registry-only.md | 27 - .../service/service-downgrade.md | 86 -- .../service/service-group.md | 184 --- .../service/specify-ip.md | 103 -- .../service/streaming.md | 9 - .../service/subscribe-only.md | 27 - .../service/transaction.md | 397 ------ .../traffic/_index.md | 37 - .../traffic/config-rule.md | 172 --- .../traffic/mesh-style/_index.md | 268 ---- .../mesh-style/ab-testing-deployment.md | 19 - .../mesh-style/blue-green-deployment.md | 19 - .../traffic/mesh-style/canary-deployment.md | 20 - .../mesh-style/demo-rule-deployment.md | 349 ----- .../traffic/mesh-style/destination-rule.md | 94 -- .../mesh-style/dynamic-rule-deployment.md | 78 - .../traffic/mesh-style/virtualservice.md | 481 ------- .../mesh-style/weight-rule-deployment.md | 47 - .../traffic/routing-rule.md | 254 ---- .../concepts-and-architecture/_index.md | 8 - .../code-architecture.md | 103 -- .../concepts-and-architecture/mesh.md | 71 - .../overall-architecture.md | 72 - .../service-discovery.md | 59 - .../service-invocation.md | 155 -- .../concepts-and-architecture/triple.md | 24 - content/en/docs3-v2/java-sdk/faq/0/1.md | 22 - content/en/docs3-v2/java-sdk/faq/0/10.md | 17 - content/en/docs3-v2/java-sdk/faq/0/11.md | 17 - content/en/docs3-v2/java-sdk/faq/0/12.md | 17 - content/en/docs3-v2/java-sdk/faq/0/13.md | 17 - content/en/docs3-v2/java-sdk/faq/0/14.md | 19 - content/en/docs3-v2/java-sdk/faq/0/15.md | 19 - content/en/docs3-v2/java-sdk/faq/0/16.md | 17 - content/en/docs3-v2/java-sdk/faq/0/17.md | 17 - content/en/docs3-v2/java-sdk/faq/0/18.md | 17 - content/en/docs3-v2/java-sdk/faq/0/19.md | 17 - content/en/docs3-v2/java-sdk/faq/0/2.md | 14 - content/en/docs3-v2/java-sdk/faq/0/20.md | 20 - content/en/docs3-v2/java-sdk/faq/0/21.md | 16 - content/en/docs3-v2/java-sdk/faq/0/22.md | 23 - content/en/docs3-v2/java-sdk/faq/0/23.md | 21 - content/en/docs3-v2/java-sdk/faq/0/24.md | 19 - content/en/docs3-v2/java-sdk/faq/0/25.md | 18 - content/en/docs3-v2/java-sdk/faq/0/26.md | 16 - content/en/docs3-v2/java-sdk/faq/0/27.md | 16 - content/en/docs3-v2/java-sdk/faq/0/3.md | 31 - content/en/docs3-v2/java-sdk/faq/0/4.md | 48 - content/en/docs3-v2/java-sdk/faq/0/5.md | 23 - content/en/docs3-v2/java-sdk/faq/0/6.md | 18 - content/en/docs3-v2/java-sdk/faq/0/7.md | 19 - content/en/docs3-v2/java-sdk/faq/0/8.md | 17 - content/en/docs3-v2/java-sdk/faq/0/9.md | 17 - content/en/docs3-v2/java-sdk/faq/0/_index.md | 8 - content/en/docs3-v2/java-sdk/faq/1/1.md | 15 - content/en/docs3-v2/java-sdk/faq/1/10.md | 16 - content/en/docs3-v2/java-sdk/faq/1/11.md | 14 - content/en/docs3-v2/java-sdk/faq/1/12.md | 15 - content/en/docs3-v2/java-sdk/faq/1/13.md | 14 - content/en/docs3-v2/java-sdk/faq/1/14.md | 15 - content/en/docs3-v2/java-sdk/faq/1/15.md | 15 - content/en/docs3-v2/java-sdk/faq/1/16.md | 19 - content/en/docs3-v2/java-sdk/faq/1/17.md | 18 - content/en/docs3-v2/java-sdk/faq/1/18.md | 18 - content/en/docs3-v2/java-sdk/faq/1/19.md | 18 - content/en/docs3-v2/java-sdk/faq/1/20.md | 16 - content/en/docs3-v2/java-sdk/faq/1/21.md | 17 - content/en/docs3-v2/java-sdk/faq/1/22.md | 16 - content/en/docs3-v2/java-sdk/faq/1/23.md | 18 - content/en/docs3-v2/java-sdk/faq/1/24.md | 20 - content/en/docs3-v2/java-sdk/faq/1/25.md | 17 - content/en/docs3-v2/java-sdk/faq/1/26.md | 16 - content/en/docs3-v2/java-sdk/faq/1/27.md | 16 - content/en/docs3-v2/java-sdk/faq/1/28.md | 16 - content/en/docs3-v2/java-sdk/faq/1/29.md | 17 - content/en/docs3-v2/java-sdk/faq/1/3.md | 13 - content/en/docs3-v2/java-sdk/faq/1/30.md | 20 - content/en/docs3-v2/java-sdk/faq/1/31.md | 18 - content/en/docs3-v2/java-sdk/faq/1/32.md | 20 - content/en/docs3-v2/java-sdk/faq/1/33.md | 18 - content/en/docs3-v2/java-sdk/faq/1/34.md | 16 - content/en/docs3-v2/java-sdk/faq/1/35.md | 18 - content/en/docs3-v2/java-sdk/faq/1/36.md | 15 - content/en/docs3-v2/java-sdk/faq/1/37.md | 16 - content/en/docs3-v2/java-sdk/faq/1/38.md | 17 - content/en/docs3-v2/java-sdk/faq/1/39.md | 18 - content/en/docs3-v2/java-sdk/faq/1/4.md | 18 - content/en/docs3-v2/java-sdk/faq/1/40.md | 18 - content/en/docs3-v2/java-sdk/faq/1/41.md | 16 - content/en/docs3-v2/java-sdk/faq/1/42.md | 15 - content/en/docs3-v2/java-sdk/faq/1/5.md | 14 - content/en/docs3-v2/java-sdk/faq/1/6.md | 15 - content/en/docs3-v2/java-sdk/faq/1/7.md | 15 - content/en/docs3-v2/java-sdk/faq/1/8.md | 18 - content/en/docs3-v2/java-sdk/faq/1/9.md | 25 - content/en/docs3-v2/java-sdk/faq/1/_index.md | 8 - content/en/docs3-v2/java-sdk/faq/2/1.md | 8 - content/en/docs3-v2/java-sdk/faq/2/10.md | 21 - content/en/docs3-v2/java-sdk/faq/2/11.md | 18 - content/en/docs3-v2/java-sdk/faq/2/12.md | 16 - content/en/docs3-v2/java-sdk/faq/2/13.md | 17 - content/en/docs3-v2/java-sdk/faq/2/14.md | 18 - content/en/docs3-v2/java-sdk/faq/2/15.md | 17 - content/en/docs3-v2/java-sdk/faq/2/16.md | 17 - content/en/docs3-v2/java-sdk/faq/2/17.md | 19 - content/en/docs3-v2/java-sdk/faq/2/18.md | 17 - content/en/docs3-v2/java-sdk/faq/2/19.md | 19 - content/en/docs3-v2/java-sdk/faq/2/2.md | 27 - content/en/docs3-v2/java-sdk/faq/2/20.md | 16 - content/en/docs3-v2/java-sdk/faq/2/3.md | 17 - content/en/docs3-v2/java-sdk/faq/2/4.md | 17 - content/en/docs3-v2/java-sdk/faq/2/5.md | 18 - content/en/docs3-v2/java-sdk/faq/2/6.md | 18 - content/en/docs3-v2/java-sdk/faq/2/7.md | 17 - content/en/docs3-v2/java-sdk/faq/2/8.md | 17 - content/en/docs3-v2/java-sdk/faq/2/9.md | 17 - content/en/docs3-v2/java-sdk/faq/2/_index.md | 6 - content/en/docs3-v2/java-sdk/faq/3/1.md | 22 - content/en/docs3-v2/java-sdk/faq/3/2.md | 19 - content/en/docs3-v2/java-sdk/faq/3/3.md | 13 - content/en/docs3-v2/java-sdk/faq/3/4.md | 19 - content/en/docs3-v2/java-sdk/faq/3/5.md | 18 - content/en/docs3-v2/java-sdk/faq/3/6.md | 18 - content/en/docs3-v2/java-sdk/faq/3/7.md | 21 - content/en/docs3-v2/java-sdk/faq/3/8.md | 22 - content/en/docs3-v2/java-sdk/faq/3/_index.md | 6 - content/en/docs3-v2/java-sdk/faq/4/1.md | 21 - content/en/docs3-v2/java-sdk/faq/4/10.md | 17 - content/en/docs3-v2/java-sdk/faq/4/11.md | 20 - content/en/docs3-v2/java-sdk/faq/4/12.md | 17 - content/en/docs3-v2/java-sdk/faq/4/13.md | 20 - content/en/docs3-v2/java-sdk/faq/4/14.md | 18 - content/en/docs3-v2/java-sdk/faq/4/15.md | 15 - content/en/docs3-v2/java-sdk/faq/4/16.md | 16 - content/en/docs3-v2/java-sdk/faq/4/17.md | 17 - content/en/docs3-v2/java-sdk/faq/4/18.md | 15 - content/en/docs3-v2/java-sdk/faq/4/19.md | 19 - content/en/docs3-v2/java-sdk/faq/4/2.md | 16 - content/en/docs3-v2/java-sdk/faq/4/20.md | 16 - content/en/docs3-v2/java-sdk/faq/4/21.md | 21 - content/en/docs3-v2/java-sdk/faq/4/3.md | 16 - content/en/docs3-v2/java-sdk/faq/4/4.md | 16 - content/en/docs3-v2/java-sdk/faq/4/5.md | 16 - content/en/docs3-v2/java-sdk/faq/4/6.md | 16 - content/en/docs3-v2/java-sdk/faq/4/7.md | 15 - content/en/docs3-v2/java-sdk/faq/4/8.md | 15 - content/en/docs3-v2/java-sdk/faq/4/9.md | 16 - content/en/docs3-v2/java-sdk/faq/4/_index.md | 6 - content/en/docs3-v2/java-sdk/faq/5/1.md | 21 - content/en/docs3-v2/java-sdk/faq/5/10.md | 16 - content/en/docs3-v2/java-sdk/faq/5/11.md | 20 - content/en/docs3-v2/java-sdk/faq/5/12.md | 20 - content/en/docs3-v2/java-sdk/faq/5/13.md | 16 - content/en/docs3-v2/java-sdk/faq/5/14.md | 18 - content/en/docs3-v2/java-sdk/faq/5/15.md | 16 - content/en/docs3-v2/java-sdk/faq/5/16.md | 19 - content/en/docs3-v2/java-sdk/faq/5/17.md | 18 - content/en/docs3-v2/java-sdk/faq/5/18.md | 18 - content/en/docs3-v2/java-sdk/faq/5/19.md | 22 - content/en/docs3-v2/java-sdk/faq/5/2.md | 16 - content/en/docs3-v2/java-sdk/faq/5/20.md | 18 - content/en/docs3-v2/java-sdk/faq/5/21.md | 18 - content/en/docs3-v2/java-sdk/faq/5/22.md | 21 - content/en/docs3-v2/java-sdk/faq/5/23.md | 19 - content/en/docs3-v2/java-sdk/faq/5/24.md | 17 - content/en/docs3-v2/java-sdk/faq/5/25.md | 16 - content/en/docs3-v2/java-sdk/faq/5/26.md | 15 - content/en/docs3-v2/java-sdk/faq/5/27.md | 16 - content/en/docs3-v2/java-sdk/faq/5/28.md | 16 - content/en/docs3-v2/java-sdk/faq/5/29.md | 16 - content/en/docs3-v2/java-sdk/faq/5/3.md | 16 - content/en/docs3-v2/java-sdk/faq/5/30.md | 16 - content/en/docs3-v2/java-sdk/faq/5/31.md | 16 - content/en/docs3-v2/java-sdk/faq/5/32.md | 16 - content/en/docs3-v2/java-sdk/faq/5/33.md | 16 - content/en/docs3-v2/java-sdk/faq/5/34.md | 16 - content/en/docs3-v2/java-sdk/faq/5/35.md | 17 - content/en/docs3-v2/java-sdk/faq/5/36.md | 16 - content/en/docs3-v2/java-sdk/faq/5/37.md | 17 - content/en/docs3-v2/java-sdk/faq/5/38.md | 16 - content/en/docs3-v2/java-sdk/faq/5/39.md | 17 - content/en/docs3-v2/java-sdk/faq/5/4.md | 18 - content/en/docs3-v2/java-sdk/faq/5/40.md | 17 - content/en/docs3-v2/java-sdk/faq/5/41.md | 14 - content/en/docs3-v2/java-sdk/faq/5/42.md | 16 - content/en/docs3-v2/java-sdk/faq/5/43.md | 14 - content/en/docs3-v2/java-sdk/faq/5/5.md | 16 - content/en/docs3-v2/java-sdk/faq/5/6.md | 16 - content/en/docs3-v2/java-sdk/faq/5/7.md | 20 - content/en/docs3-v2/java-sdk/faq/5/8.md | 16 - content/en/docs3-v2/java-sdk/faq/5/9.md | 20 - content/en/docs3-v2/java-sdk/faq/5/_index.md | 6 - content/en/docs3-v2/java-sdk/faq/6/1.md | 18 - content/en/docs3-v2/java-sdk/faq/6/10.md | 16 - content/en/docs3-v2/java-sdk/faq/6/11.md | 16 - content/en/docs3-v2/java-sdk/faq/6/12.md | 18 - content/en/docs3-v2/java-sdk/faq/6/13.md | 17 - content/en/docs3-v2/java-sdk/faq/6/14.md | 16 - content/en/docs3-v2/java-sdk/faq/6/15.md | 15 - content/en/docs3-v2/java-sdk/faq/6/16.md | 17 - content/en/docs3-v2/java-sdk/faq/6/2.md | 27 - content/en/docs3-v2/java-sdk/faq/6/3.md | 17 - content/en/docs3-v2/java-sdk/faq/6/4.md | 12 - content/en/docs3-v2/java-sdk/faq/6/5.md | 17 - content/en/docs3-v2/java-sdk/faq/6/6.md | 19 - content/en/docs3-v2/java-sdk/faq/6/7.md | 17 - content/en/docs3-v2/java-sdk/faq/6/8.md | 17 - content/en/docs3-v2/java-sdk/faq/6/9.md | 20 - content/en/docs3-v2/java-sdk/faq/6/_index.md | 6 - content/en/docs3-v2/java-sdk/faq/7/1.md | 16 - content/en/docs3-v2/java-sdk/faq/7/2.md | 16 - content/en/docs3-v2/java-sdk/faq/7/3.md | 16 - content/en/docs3-v2/java-sdk/faq/7/4.md | 16 - content/en/docs3-v2/java-sdk/faq/7/5.md | 17 - content/en/docs3-v2/java-sdk/faq/7/6.md | 18 - content/en/docs3-v2/java-sdk/faq/7/7.md | 17 - content/en/docs3-v2/java-sdk/faq/7/_index.md | 6 - content/en/docs3-v2/java-sdk/faq/99/0.md | 20 - content/en/docs3-v2/java-sdk/faq/99/1.md | 17 - content/en/docs3-v2/java-sdk/faq/99/_index.md | 6 - content/en/docs3-v2/java-sdk/faq/_index.md | 9 - content/en/docs3-v2/java-sdk/faq/intro.md | 40 - .../docs3-v2/java-sdk/quick-start/_index.md | 8 - .../en/docs3-v2/java-sdk/quick-start/api.md | 343 ----- .../en/docs3-v2/java-sdk/quick-start/brief.md | 311 ---- .../en/docs3-v2/java-sdk/quick-start/idl.md | 233 --- .../java-sdk/quick-start/spring-boot.md | 643 --------- .../java-sdk/quick-start/spring-xml.md | 393 ----- .../java-sdk/reference-manual/_index.md | 8 - .../reference-manual/config-center/_index.md | 22 - .../reference-manual/config-center/apollo.md | 115 -- .../reference-manual/config-center/nacos.md | 112 -- .../config-center/zookeeper.md | 94 -- .../reference-manual/config/_index.md | 8 - .../reference-manual/config/annotation.md | 209 --- .../java-sdk/reference-manual/config/api.md | 311 ---- .../reference-manual/config/overview.md | 166 --- .../reference-manual/config/principle.md | 374 ----- .../reference-manual/config/properties.md | 558 -------- .../java-sdk/reference-manual/config/xml.md | 115 -- .../reference-manual/graalvm/_index.md | 216 --- .../java-sdk/reference-manual/mesh/_index.md | 9 - .../java-sdk/reference-manual/mesh/mesh.md | 157 -- .../metadata-center/_index.md | 7 - .../reference-manual/metadata-center/nacos.md | 114 -- .../metadata-center/overview.md | 212 --- .../reference-manual/metadata-center/redis.md | 8 - .../metadata-center/zookeeper.md | 173 --- .../reference-manual/performance/_index.md | 6 - .../performance/benchmarking.md | 48 - .../performance/rpc-benchmarking.md | 55 - .../reference-manual/protocol/_index.md | 6 - .../reference-manual/protocol/dubbo.md | 125 -- .../reference-manual/protocol/grpc.md | 34 - .../reference-manual/protocol/hessian.md | 80 -- .../reference-manual/protocol/http.md | 74 - .../reference-manual/protocol/memcached.md | 60 - .../reference-manual/protocol/overview.md | 200 --- .../reference-manual/protocol/redis.md | 61 - .../reference-manual/protocol/rest.md | 747 ---------- .../java-sdk/reference-manual/protocol/rmi.md | 96 -- .../reference-manual/protocol/thrift.md | 51 - .../reference-manual/protocol/tripe-3.3.md | 282 ---- .../protocol/tripe-rest-manual.md | 984 ------------- .../protocol/triple/_index.md | 6 - .../reference-manual/protocol/triple/guide.md | 278 ---- .../reference-manual/protocol/triple/idl.md | 238 ---- .../protocol/triple/migration.md | 83 -- .../protocol/triple/overview.md | 39 - .../reference-manual/protocol/triple/pojo.md | 189 --- .../protocol/triple/streaming.md | 153 -- .../reference-manual/protocol/webservice.md | 112 -- .../java-sdk/reference-manual/qos/_index.md | 6 - .../java-sdk/reference-manual/qos/command.md | 48 - .../reference-manual/qos/logger-management.md | 94 -- .../java-sdk/reference-manual/qos/overview.md | 212 --- .../java-sdk/reference-manual/qos/probe.md | 42 - .../java-sdk/reference-manual/qos/profiler.md | 74 - .../reference-manual/qos/router-snapshot.md | 110 -- .../java-sdk/reference-manual/qos/security.md | 75 - .../qos/service-management.md | 74 - .../reference-manual/registry/_index.md | 7 - .../registry/multicast/_index.md | 52 - .../registry/multiple-registry/_index.md | 187 --- .../reference-manual/registry/nacos/_index.md | 190 --- .../registry/overview/_index.md | 76 - .../reference-manual/registry/redis/_index.md | 74 - .../reference-manual/registry/simple.md | 58 - .../registry/zookeeper/_index.md | 133 -- .../java-sdk/reference-manual/spi/_index.md | 6 - .../spi/description/_index.md | 6 - .../reference-manual/spi/description/cache.md | 88 -- .../spi/description/cluster.md | 83 -- .../spi/description/compiler.md | 60 - .../spi/description/config-center.md | 102 -- .../spi/description/container.md | 67 - .../spi/description/dispatcher.md | 67 - .../spi/description/dubbo-spi.md | 705 --------- .../spi/description/exchanger.md | 96 -- .../spi/description/exporter-listener.md | 70 - .../spi/description/extension-factory.md | 62 - .../spi/description/filter.md | 94 -- .../spi/description/invoker-listener.md | 69 - .../spi/description/liveness.md | 72 - .../spi/description/load-balance.md | 70 - .../spi/description/logger-adapter.md | 89 -- .../spi/description/merger.md | 72 - .../spi/description/metadata-report.md | 91 -- .../spi/description/monitor.md | 80 -- .../spi/description/networker.md | 64 - .../reference-manual/spi/description/page.md | 68 - .../spi/description/protocol.md | 158 --- .../spi/description/proxy-factory.md | 70 - .../spi/description/qos-permission.md | 62 - .../spi/description/readiness.md | 74 - .../spi/description/registry.md | 210 --- .../spi/description/remoting.md | 127 -- .../spi/description/router.md | 67 - .../spi/description/serialize.md | 77 - .../spi/description/startup.md | 73 - .../spi/description/status-checker.md | 69 - .../spi/description/telnet-handler.md | 82 -- .../spi/description/threadpool.md | 65 - .../spi/description/validation.md | 80 -- .../java-sdk/reference-manual/spi/overview.md | 101 -- .../2.x-to-3.x-compatibility-guide.md | 96 -- .../3.0-to-3.1-compatibility-guide.md | 22 - .../3.1-to-3.2-compatibility-guide.md | 140 -- .../upgrades-and-compatibility/_index.md | 8 - .../migration-triple.md | 344 ----- .../protobuf&interface.md | 141 -- .../serialization-upgrade.md | 26 - .../service-discovery/_index.md | 6 - .../migration-service-discovery.md | 159 --- .../service-discovery-rule.md | 203 --- .../service-discovery-samples.md | 76 - content/en/docs3-v2/rust-sdk/_index.md | 9 - .../rust-sdk/java-interoperability.md | 70 - content/en/docs3-v2/rust-sdk/protocol.md | 7 - content/en/docs3-v2/rust-sdk/quick-start.md | 458 ------ .../java-sdk/tasks/extensibility/filter.md | 2 +- 748 files changed, 1376 insertions(+), 52167 deletions(-) create mode 100755 content/en/contact/_index.md create mode 100644 content/en/contact/books/_index.md create mode 100755 content/en/contact/committer/_index.md create mode 100644 content/en/contact/committer/apache-dubbo-page_dev.md create mode 100644 content/en/contact/committer/cla-signing-guide_dev.md create mode 100644 content/en/contact/committer/label-an-issue-guide_dev.md create mode 100644 content/en/contact/committer/new-committer-guide_dev.md create mode 100755 content/en/contact/committer/release-guide/_index.md create mode 100644 content/en/contact/committer/release-guide/common.md create mode 100644 content/en/contact/committer/release-guide/java-sdk.md create mode 100644 content/en/contact/committer/website-guide_dev.md create mode 100755 content/en/contact/contributor/_index.md create mode 100644 content/en/contact/contributor/become-a-committer_dev.md create mode 100644 content/en/contact/contributor/dubbo-extension-guide_dev.md rename content/en/{docs/contribution-guidelines => contact}/contributor/mailing-list-subscription-guide_dev.md (54%) create mode 100644 content/en/contact/contributor/new-contributor-guide_dev.md create mode 100644 content/en/contact/contributor/reporting-security-issues_dev.md rename content/en/{docs/contribution-guidelines => contact}/contributor/software-donation-guide_dev.md (80%) create mode 100644 content/en/contact/contributor/test-coverage-guide_dev.md create mode 100644 content/en/contribution-guidelines/_index.md delete mode 100755 content/en/docs/_index.md delete mode 100755 content/en/docs/contribution-guidelines/_index.md delete mode 100755 content/en/docs/contribution-guidelines/committer/_index.md delete mode 100644 content/en/docs/contribution-guidelines/committer/apache-dubbo-page_dev.md delete mode 100644 content/en/docs/contribution-guidelines/committer/label-an-issue-guide_dev.md delete mode 100644 content/en/docs/contribution-guidelines/committer/new-committer-guide_dev.md delete mode 100644 content/en/docs/contribution-guidelines/committer/release-guide_dev.md delete mode 100644 content/en/docs/contribution-guidelines/committer/website-guide_dev.md delete mode 100755 content/en/docs/contribution-guidelines/contributor/_index.md delete mode 100644 content/en/docs/contribution-guidelines/contributor/become-a-committer_dev.md delete mode 100644 content/en/docs/contribution-guidelines/contributor/cla-signing-guide_dev.md delete mode 100644 content/en/docs/contribution-guidelines/contributor/dubbo-extension-guide_dev.md delete mode 100644 content/en/docs/contribution-guidelines/contributor/new-contributor-guide_dev.md delete mode 100644 content/en/docs/contribution-guidelines/contributor/reporting-security-issues_dev.md delete mode 100644 content/en/docs/contribution-guidelines/contributor/test-coverage-guide_dev.md delete mode 100644 content/en/docs/faq/_index.md delete mode 100755 content/en/docs/v2.7/_index.md delete mode 100644 content/en/docs/v2.7/admin/_index.md delete mode 100644 content/en/docs/v2.7/admin/install/_index.md delete mode 100644 content/en/docs/v2.7/admin/install/admin-console.md delete mode 100644 content/en/docs/v2.7/admin/install/consumer-demo.md delete mode 100644 content/en/docs/v2.7/admin/install/monitor-center.md delete mode 100644 content/en/docs/v2.7/admin/install/provider-demo.md delete mode 100644 content/en/docs/v2.7/admin/install/redis.md delete mode 100644 content/en/docs/v2.7/admin/install/zookeeper.md delete mode 100644 content/en/docs/v2.7/admin/ops/_index.md delete mode 100644 content/en/docs/v2.7/admin/ops/apidocs.md delete mode 100644 content/en/docs/v2.7/admin/ops/functions.md delete mode 100644 content/en/docs/v2.7/admin/ops/governance.md delete mode 100644 content/en/docs/v2.7/admin/ops/introduction.md delete mode 100644 content/en/docs/v2.7/admin/ops/pinpoint.md delete mode 100644 content/en/docs/v2.7/admin/ops/search.md delete mode 100644 content/en/docs/v2.7/admin/ops/skywalking.md delete mode 100644 content/en/docs/v2.7/admin/ops/test.md delete mode 100644 content/en/docs/v2.7/dev/SPI.md delete mode 100644 content/en/docs/v2.7/dev/TCK.md delete mode 100755 content/en/docs/v2.7/dev/_index.md delete mode 100644 content/en/docs/v2.7/dev/build.md delete mode 100644 content/en/docs/v2.7/dev/checklist.md delete mode 100644 content/en/docs/v2.7/dev/code-smell.md delete mode 100644 content/en/docs/v2.7/dev/coding.md delete mode 100644 content/en/docs/v2.7/dev/contract.md delete mode 100644 content/en/docs/v2.7/dev/design.md delete mode 100644 content/en/docs/v2.7/dev/implementation.md delete mode 100755 content/en/docs/v2.7/dev/impls/_index.md delete mode 100644 content/en/docs/v2.7/dev/impls/cache.md delete mode 100644 content/en/docs/v2.7/dev/impls/cluster.md delete mode 100644 content/en/docs/v2.7/dev/impls/compiler.md delete mode 100644 content/en/docs/v2.7/dev/impls/config-center.md delete mode 100644 content/en/docs/v2.7/dev/impls/container.md delete mode 100644 content/en/docs/v2.7/dev/impls/dispatcher.md delete mode 100644 content/en/docs/v2.7/dev/impls/exchanger.md delete mode 100644 content/en/docs/v2.7/dev/impls/exporter-listener.md delete mode 100644 content/en/docs/v2.7/dev/impls/extension-factory.md delete mode 100644 content/en/docs/v2.7/dev/impls/filter.md delete mode 100644 content/en/docs/v2.7/dev/impls/invoker-listener.md delete mode 100644 content/en/docs/v2.7/dev/impls/load-balance.md delete mode 100644 content/en/docs/v2.7/dev/impls/logger-adapter.md delete mode 100644 content/en/docs/v2.7/dev/impls/merger.md delete mode 100644 content/en/docs/v2.7/dev/impls/monitor.md delete mode 100644 content/en/docs/v2.7/dev/impls/networker.md delete mode 100644 content/en/docs/v2.7/dev/impls/page.md delete mode 100644 content/en/docs/v2.7/dev/impls/protocol.md delete mode 100644 content/en/docs/v2.7/dev/impls/proxy-factory.md delete mode 100644 content/en/docs/v2.7/dev/impls/registry.md delete mode 100644 content/en/docs/v2.7/dev/impls/remoting.md delete mode 100644 content/en/docs/v2.7/dev/impls/router.md delete mode 100644 content/en/docs/v2.7/dev/impls/serialize.md delete mode 100644 content/en/docs/v2.7/dev/impls/status-checker.md delete mode 100644 content/en/docs/v2.7/dev/impls/telnet-handler.md delete mode 100644 content/en/docs/v2.7/dev/impls/threadpool.md delete mode 100644 content/en/docs/v2.7/dev/impls/validation.md delete mode 100755 content/en/docs/v2.7/dev/principals/_index.md delete mode 100644 content/en/docs/v2.7/dev/principals/code-detail.md delete mode 100644 content/en/docs/v2.7/dev/principals/configuration.md delete mode 100644 content/en/docs/v2.7/dev/principals/dummy.md delete mode 100644 content/en/docs/v2.7/dev/principals/expansibility.md delete mode 100644 content/en/docs/v2.7/dev/principals/extension.md delete mode 100644 content/en/docs/v2.7/dev/principals/general-knowledge.md delete mode 100644 content/en/docs/v2.7/dev/principals/robustness.md delete mode 100644 content/en/docs/v2.7/dev/release.md delete mode 100644 content/en/docs/v2.7/user/_index.md delete mode 100644 content/en/docs/v2.7/user/benchmark-tool.md delete mode 100644 content/en/docs/v2.7/user/best-practice.md delete mode 100644 content/en/docs/v2.7/user/capacity-plan.md delete mode 100644 content/en/docs/v2.7/user/configuration/_index.md delete mode 100644 content/en/docs/v2.7/user/configuration/annotation.md delete mode 100644 content/en/docs/v2.7/user/configuration/api.md delete mode 100644 content/en/docs/v2.7/user/configuration/configuration-load-process.md delete mode 100644 content/en/docs/v2.7/user/configuration/properties.md delete mode 100644 content/en/docs/v2.7/user/configuration/xml.md delete mode 100644 content/en/docs/v2.7/user/coveragence.md delete mode 100644 content/en/docs/v2.7/user/dependencies.md delete mode 100644 content/en/docs/v2.7/user/examples/_index.md delete mode 100644 content/en/docs/v2.7/user/examples/accesslog.md delete mode 100644 content/en/docs/v2.7/user/examples/async-call.md delete mode 100644 content/en/docs/v2.7/user/examples/async-execute-on-provider.md delete mode 100644 content/en/docs/v2.7/user/examples/attachment.md delete mode 100644 content/en/docs/v2.7/user/examples/broadcast-resp-collect.md delete mode 100644 content/en/docs/v2.7/user/examples/callback-parameter.md delete mode 100644 content/en/docs/v2.7/user/examples/concurrency-control.md delete mode 100644 content/en/docs/v2.7/user/examples/config-connections.md delete mode 100644 content/en/docs/v2.7/user/examples/config-rule.md delete mode 100644 content/en/docs/v2.7/user/examples/context.md delete mode 100644 content/en/docs/v2.7/user/examples/delay-publish.md delete mode 100644 content/en/docs/v2.7/user/examples/distributed-transaction.md delete mode 100644 content/en/docs/v2.7/user/examples/dump.md delete mode 100644 content/en/docs/v2.7/user/examples/echo-service.md delete mode 100644 content/en/docs/v2.7/user/examples/events-notify.md delete mode 100644 content/en/docs/v2.7/user/examples/explicit-target.md delete mode 100644 content/en/docs/v2.7/user/examples/fault-tolerent-strategy.md delete mode 100644 content/en/docs/v2.7/user/examples/generic-invoke-with-json.md delete mode 100644 content/en/docs/v2.7/user/examples/generic-reference.md delete mode 100644 content/en/docs/v2.7/user/examples/generic-service.md delete mode 100644 content/en/docs/v2.7/user/examples/graceful-shutdown.md delete mode 100644 content/en/docs/v2.7/user/examples/group-merger.md delete mode 100644 content/en/docs/v2.7/user/examples/hostname-binding.md delete mode 100644 content/en/docs/v2.7/user/examples/invoke-with-specified-ip.md delete mode 100644 content/en/docs/v2.7/user/examples/lazy-connect.md delete mode 100644 content/en/docs/v2.7/user/examples/loadbalance.md delete mode 100644 content/en/docs/v2.7/user/examples/local-call.md delete mode 100644 content/en/docs/v2.7/user/examples/local-mock.md delete mode 100644 content/en/docs/v2.7/user/examples/local-stub.md delete mode 100644 content/en/docs/v2.7/user/examples/logger-strategy.md delete mode 100644 content/en/docs/v2.7/user/examples/msgpack-serialization.md delete mode 100644 content/en/docs/v2.7/user/examples/multi-protocols.md delete mode 100644 content/en/docs/v2.7/user/examples/multi-registry.md delete mode 100644 content/en/docs/v2.7/user/examples/multi-versions.md delete mode 100644 content/en/docs/v2.7/user/examples/netty4.md delete mode 100644 content/en/docs/v2.7/user/examples/parameter-validation.md delete mode 100644 content/en/docs/v2.7/user/examples/preflight-check.md delete mode 100644 content/en/docs/v2.7/user/examples/provider-timeout-release.md delete mode 100644 content/en/docs/v2.7/user/examples/reference-config-cache.md delete mode 100644 content/en/docs/v2.7/user/examples/registry-only.md delete mode 100644 content/en/docs/v2.7/user/examples/result-cache.md delete mode 100644 content/en/docs/v2.7/user/examples/routing-rule.md delete mode 100644 content/en/docs/v2.7/user/examples/serialization.md delete mode 100644 content/en/docs/v2.7/user/examples/service-container.md delete mode 100644 content/en/docs/v2.7/user/examples/service-downgrade.md delete mode 100644 content/en/docs/v2.7/user/examples/service-group.md delete mode 100644 content/en/docs/v2.7/user/examples/static-service.md delete mode 100644 content/en/docs/v2.7/user/examples/stickiness.md delete mode 100644 content/en/docs/v2.7/user/examples/subscribe-only.md delete mode 100644 content/en/docs/v2.7/user/examples/thread-model.md delete mode 100644 content/en/docs/v2.7/user/examples/token-authorization.md delete mode 100755 content/en/docs/v2.7/user/languages/_index.md delete mode 100755 content/en/docs/v2.7/user/languages/erlang/_index.md delete mode 100644 content/en/docs/v2.7/user/languages/erlang/quick-start.md delete mode 100644 content/en/docs/v2.7/user/languages/erlang/reference.md delete mode 100644 content/en/docs/v2.7/user/languages/erlang/serialization.md delete mode 100644 content/en/docs/v2.7/user/languages/erlang/service.md delete mode 100644 content/en/docs/v2.7/user/maturity.md delete mode 100644 content/en/docs/v2.7/user/perf-test.md delete mode 100755 content/en/docs/v2.7/user/preface/_index.md delete mode 100644 content/en/docs/v2.7/user/preface/architecture.md delete mode 100644 content/en/docs/v2.7/user/preface/background.md delete mode 100644 content/en/docs/v2.7/user/preface/requirements.md delete mode 100644 content/en/docs/v2.7/user/preface/usage.md delete mode 100644 content/en/docs/v2.7/user/quick-start.md delete mode 100644 content/en/docs/v2.7/user/recommend.md delete mode 100644 content/en/docs/v2.7/user/references/_index.md delete mode 100644 content/en/docs/v2.7/user/references/api.md delete mode 100644 content/en/docs/v2.7/user/references/maven.md delete mode 100644 content/en/docs/v2.7/user/references/metadata.md delete mode 100644 content/en/docs/v2.7/user/references/protocol/_index.md delete mode 100644 content/en/docs/v2.7/user/references/protocol/dubbo.md delete mode 100644 content/en/docs/v2.7/user/references/protocol/hessian.md delete mode 100644 content/en/docs/v2.7/user/references/protocol/http.md delete mode 100644 content/en/docs/v2.7/user/references/protocol/memcached.md delete mode 100644 content/en/docs/v2.7/user/references/protocol/redis.md delete mode 100644 content/en/docs/v2.7/user/references/protocol/rest.md delete mode 100644 content/en/docs/v2.7/user/references/protocol/rmi.md delete mode 100644 content/en/docs/v2.7/user/references/protocol/thrift.md delete mode 100644 content/en/docs/v2.7/user/references/protocol/webservice.md delete mode 100644 content/en/docs/v2.7/user/references/qos.md delete mode 100644 content/en/docs/v2.7/user/references/registry/_index.md delete mode 100644 content/en/docs/v2.7/user/references/registry/multicast.md delete mode 100644 content/en/docs/v2.7/user/references/registry/nacos.md delete mode 100644 content/en/docs/v2.7/user/references/registry/redis.md delete mode 100644 content/en/docs/v2.7/user/references/registry/simple.md delete mode 100644 content/en/docs/v2.7/user/references/registry/zookeeper.md delete mode 100644 content/en/docs/v2.7/user/references/telnet.md delete mode 100644 content/en/docs/v2.7/user/references/xml/_index.md delete mode 100644 content/en/docs/v2.7/user/references/xml/dubbo-application.md delete mode 100644 content/en/docs/v2.7/user/references/xml/dubbo-argument.md delete mode 100644 content/en/docs/v2.7/user/references/xml/dubbo-config-center.md delete mode 100644 content/en/docs/v2.7/user/references/xml/dubbo-consumer.md delete mode 100644 content/en/docs/v2.7/user/references/xml/dubbo-method.md delete mode 100644 content/en/docs/v2.7/user/references/xml/dubbo-module.md delete mode 100644 content/en/docs/v2.7/user/references/xml/dubbo-monitor.md delete mode 100644 content/en/docs/v2.7/user/references/xml/dubbo-parameter.md delete mode 100644 content/en/docs/v2.7/user/references/xml/dubbo-protocol.md delete mode 100644 content/en/docs/v2.7/user/references/xml/dubbo-provider.md delete mode 100644 content/en/docs/v2.7/user/references/xml/dubbo-reference.md delete mode 100644 content/en/docs/v2.7/user/references/xml/dubbo-registry.md delete mode 100644 content/en/docs/v2.7/user/references/xml/dubbo-service.md delete mode 100644 content/en/docs/v2.7/user/rest.md delete mode 100644 content/en/docs/v2.7/user/simple-monitor.md delete mode 100755 content/en/docs/v3.0/_index.md delete mode 100755 content/en/docs/v3.0/languages/_index.md delete mode 100755 content/en/docs/v3.0/languages/erlang/_index.md delete mode 100644 content/en/docs/v3.0/languages/erlang/quick-start.md delete mode 100644 content/en/docs/v3.0/languages/erlang/reference.md delete mode 100644 content/en/docs/v3.0/languages/erlang/serialization.md delete mode 100644 content/en/docs/v3.0/languages/erlang/service.md delete mode 100755 content/en/docs/v3.0/languages/golang/_index.md delete mode 100644 content/en/docs/v3.0/languages/golang/go-specific.md delete mode 100644 content/en/docs/v3.0/languages/golang/quick-start.md delete mode 100755 content/en/docs/v3.0/languages/rust/_index.md delete mode 100644 content/en/docs/v3.0/loadbalance/_index.md delete mode 100644 content/en/docs/v3.0/references/_index.md delete mode 100644 content/en/docs/v3.0/references/graalvm/_index.md delete mode 100644 content/en/docs/v3.0/references/graalvm/support-graalvm.md delete mode 100644 content/en/docs/v3.0/references/lifecycle/_index.md delete mode 100644 content/en/docs/v3.0/references/lifecycle/brief.md delete mode 100644 content/en/docs/v3.0/references/lifecycle/liveness.md delete mode 100644 content/en/docs/v3.0/references/lifecycle/readiness.md delete mode 100644 content/en/docs/v3.0/references/lifecycle/startup.md delete mode 100644 content/en/docs/v3.0/whats-new-in-dubbo3/_index.md delete mode 100755 content/en/docs3-v2/_index.md delete mode 100755 content/en/docs3-v2/erlang-sdk/_index.md delete mode 100755 content/en/docs3-v2/golang-sdk/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/preface/3.0_feature.md delete mode 100644 content/en/docs3-v2/golang-sdk/preface/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/preface/concept/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/preface/concept/generic.md delete mode 100644 content/en/docs3-v2/golang-sdk/preface/concept/multi_language.md delete mode 100644 content/en/docs3-v2/golang-sdk/preface/concept/protocol.md delete mode 100644 content/en/docs3-v2/golang-sdk/preface/concept/registry.md delete mode 100644 content/en/docs3-v2/golang-sdk/preface/design/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/preface/design/aop_and_extension.md delete mode 100644 content/en/docs3-v2/golang-sdk/preface/design/app_and_interface.md delete mode 100644 content/en/docs3-v2/golang-sdk/preface/design/architecture.md delete mode 100644 content/en/docs3-v2/golang-sdk/preface/samples.md delete mode 100644 content/en/docs3-v2/golang-sdk/preface/what.md delete mode 100644 content/en/docs3-v2/golang-sdk/quickstart/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/quickstart/install.md delete mode 100644 content/en/docs3-v2/golang-sdk/quickstart/quickstart_triple.md delete mode 100644 content/en/docs3-v2/golang-sdk/quickstart/quickstart_triple_with_customize.md delete mode 100644 content/en/docs3-v2/golang-sdk/refer/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/refer/basic_concept.md delete mode 100644 content/en/docs3-v2/golang-sdk/refer/compatible_version.md delete mode 100644 content/en/docs3-v2/golang-sdk/refer/config.md delete mode 100644 content/en/docs3-v2/golang-sdk/refer/ecology.md delete mode 100644 content/en/docs3-v2/golang-sdk/refer/use_dubbogo_cli.md delete mode 100644 content/en/docs3-v2/golang-sdk/sourcecode/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/sourcecode/protocol.md delete mode 100644 content/en/docs3-v2/golang-sdk/sourcecode/registry.md delete mode 100755 content/en/docs3-v2/golang-sdk/tutorial/_index.md delete mode 100755 content/en/docs3-v2/golang-sdk/tutorial/debugging/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/debugging/grpc_cli.md delete mode 100755 content/en/docs3-v2/golang-sdk/tutorial/deployment/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/deployment/docker/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/deployment/kubernetes/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/deployment/practice/_index.md delete mode 100755 content/en/docs3-v2/golang-sdk/tutorial/develop/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/config-center-dynamic.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/desc.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/remote_config.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/features/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/features/config_api.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/features/context.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/features/custom-logger.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/features/generic-2.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/features/generic.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/interflow/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_grpc.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/choose_protocol.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/error.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/exception_response.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/registry/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/registry/desc.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/registry/multi_registry.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/registry/nacos-2.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/registry/nacos.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/registry/polaris.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/registry/registry.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/registry/service-discovery.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/registry/zookeeper.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/develop/template.md delete mode 100755 content/en/docs3-v2/golang-sdk/tutorial/governance/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/features/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/features/aop.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/features/custom-filter.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/features/timeout.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/health/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/health/kubernetes.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/health/start-check.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/health/triple-health-check.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/limit/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/limit/adaptive-service.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/limit/internally/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/limit/polaris/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/limit/sentinel/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/limit/tps_limiter.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/grafana/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/http/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/logger/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/metrics.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/promethus/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/rpc_metrics.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/deploy.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/istio.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/http_triple.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/pixiu-nacos-triple.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/proxyless_service_mesh.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/traffic_management.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/jaeger/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/opentelmentry/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/skywalking/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/traffic/_index.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/traffic/graceful_shutdown.md delete mode 100644 content/en/docs3-v2/golang-sdk/tutorial/governance/traffic/mesh_router.md delete mode 100755 content/en/docs3-v2/java-sdk/_index.md delete mode 100755 content/en/docs3-v2/java-sdk/advanced-features-and-usage/_index.md delete mode 100755 content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/doc.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/health-information.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/kubernetes-probes.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/logging.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/meter.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/tracing.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/Docker.md delete mode 100755 content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/dubbo-kubernetes-probe.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/graceful-shutdown.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/logger-howto.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/logger-management.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/service-container.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/set-host.md delete mode 100755 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/config-connections.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/dump.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/lazy-connect.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/profiler.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/reference-config-cache.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/result-cache.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/router-snapshot.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/serialization.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/simplify-registry-data.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/stickiness.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/support-graalvm.md delete mode 100755 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/consumer.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/provider.md delete mode 100755 content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/auth.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/class-check.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/tls.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/token-authorization.md delete mode 100755 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/accesslog.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/async-call.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/async-execute-on-provider.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/attachment.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/callback-parameter.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/consistent-hash.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/context.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/delay-publish.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/echo-service.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/events-notify.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/explicit-target.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/fault-tolerent-strategy.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-reference.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-service.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/group-merger.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/isolation-executor.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-call.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-mock.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-stub.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-protocols.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-registry.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-versions.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/parameter-validation.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/port-unification.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/preflight-check.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/reactive.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/registry-only.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-group.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/streaming.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/subscribe-only.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/transaction.md delete mode 100755 content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/config-rule.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/ab-testing-deployment.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/blue-green-deployment.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/canary-deployment.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/demo-rule-deployment.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/destination-rule.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/dynamic-rule-deployment.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/virtualservice.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/weight-rule-deployment.md delete mode 100644 content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/routing-rule.md delete mode 100755 content/en/docs3-v2/java-sdk/concepts-and-architecture/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/concepts-and-architecture/code-architecture.md delete mode 100644 content/en/docs3-v2/java-sdk/concepts-and-architecture/mesh.md delete mode 100644 content/en/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture.md delete mode 100644 content/en/docs3-v2/java-sdk/concepts-and-architecture/service-discovery.md delete mode 100644 content/en/docs3-v2/java-sdk/concepts-and-architecture/service-invocation.md delete mode 100644 content/en/docs3-v2/java-sdk/concepts-and-architecture/triple.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/1.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/10.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/11.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/12.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/13.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/14.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/15.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/16.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/17.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/18.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/19.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/2.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/20.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/21.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/22.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/23.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/24.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/25.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/26.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/27.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/3.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/4.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/5.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/6.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/7.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/8.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/9.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/0/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/1.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/10.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/11.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/12.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/13.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/14.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/15.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/16.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/17.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/18.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/19.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/20.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/21.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/22.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/23.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/24.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/25.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/26.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/27.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/28.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/29.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/3.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/30.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/31.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/32.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/33.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/34.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/35.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/36.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/37.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/38.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/39.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/4.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/40.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/41.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/42.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/5.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/6.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/7.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/8.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/1/9.md delete mode 100755 content/en/docs3-v2/java-sdk/faq/1/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/1.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/10.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/11.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/12.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/13.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/14.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/15.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/16.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/17.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/18.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/19.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/2.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/20.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/3.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/4.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/5.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/6.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/7.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/8.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/9.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/2/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/3/1.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/3/2.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/3/3.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/3/4.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/3/5.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/3/6.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/3/7.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/3/8.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/3/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/1.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/10.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/11.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/12.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/13.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/14.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/15.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/16.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/17.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/18.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/19.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/2.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/20.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/21.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/3.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/4.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/5.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/6.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/7.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/8.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/9.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/4/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/1.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/10.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/11.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/12.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/13.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/14.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/15.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/16.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/17.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/18.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/19.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/2.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/20.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/21.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/22.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/23.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/24.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/25.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/26.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/27.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/28.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/29.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/3.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/30.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/31.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/32.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/33.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/34.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/35.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/36.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/37.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/38.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/39.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/4.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/40.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/41.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/42.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/43.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/5.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/6.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/7.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/8.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/9.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/5/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/1.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/10.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/11.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/12.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/13.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/14.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/15.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/16.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/2.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/3.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/4.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/5.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/6.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/7.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/8.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/9.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/6/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/7/1.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/7/2.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/7/3.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/7/4.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/7/5.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/7/6.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/7/7.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/7/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/99/0.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/99/1.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/99/_index.md delete mode 100755 content/en/docs3-v2/java-sdk/faq/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/faq/intro.md delete mode 100755 content/en/docs3-v2/java-sdk/quick-start/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/quick-start/api.md delete mode 100644 content/en/docs3-v2/java-sdk/quick-start/brief.md delete mode 100755 content/en/docs3-v2/java-sdk/quick-start/idl.md delete mode 100644 content/en/docs3-v2/java-sdk/quick-start/spring-boot.md delete mode 100644 content/en/docs3-v2/java-sdk/quick-start/spring-xml.md delete mode 100755 content/en/docs3-v2/java-sdk/reference-manual/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/config-center/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/config-center/apollo.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/config-center/nacos.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/config-center/zookeeper.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/config/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/config/annotation.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/config/api.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/config/overview.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/config/principle.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/config/properties.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/config/xml.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/graalvm/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/mesh/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/mesh/mesh.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/metadata-center/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/metadata-center/nacos.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/metadata-center/overview.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/metadata-center/redis.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/metadata-center/zookeeper.md delete mode 100755 content/en/docs3-v2/java-sdk/reference-manual/performance/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/performance/benchmarking.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/performance/rpc-benchmarking.md delete mode 100755 content/en/docs3-v2/java-sdk/reference-manual/protocol/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/dubbo.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/grpc.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/hessian.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/http.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/memcached.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/overview.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/redis.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/rest.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/rmi.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/thrift.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-3.3.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-rest-manual.md delete mode 100755 content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/guide.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/idl.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/migration.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/pojo.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/streaming.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/protocol/webservice.md delete mode 100755 content/en/docs3-v2/java-sdk/reference-manual/qos/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/qos/command.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/qos/logger-management.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/qos/overview.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/qos/probe.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/qos/profiler.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/qos/router-snapshot.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/qos/security.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/qos/service-management.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/registry/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/registry/multicast/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/registry/multiple-registry/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/registry/nacos/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/registry/overview/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/registry/redis/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/registry/simple.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/registry/zookeeper/_index.md delete mode 100755 content/en/docs3-v2/java-sdk/reference-manual/spi/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/cache.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/cluster.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/compiler.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/config-center.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/container.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/dispatcher.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/dubbo-spi.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/exchanger.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/exporter-listener.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/extension-factory.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/filter.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/invoker-listener.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/liveness.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/load-balance.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/logger-adapter.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/merger.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/metadata-report.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/monitor.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/networker.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/page.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/protocol.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/proxy-factory.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/qos-permission.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/readiness.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/registry.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/remoting.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/router.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/serialize.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/startup.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/status-checker.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/telnet-handler.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/threadpool.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/description/validation.md delete mode 100644 content/en/docs3-v2/java-sdk/reference-manual/spi/overview.md delete mode 100644 content/en/docs3-v2/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide.md delete mode 100644 content/en/docs3-v2/java-sdk/upgrades-and-compatibility/3.0-to-3.1-compatibility-guide.md delete mode 100644 content/en/docs3-v2/java-sdk/upgrades-and-compatibility/3.1-to-3.2-compatibility-guide.md delete mode 100755 content/en/docs3-v2/java-sdk/upgrades-and-compatibility/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple.md delete mode 100644 content/en/docs3-v2/java-sdk/upgrades-and-compatibility/protobuf&interface.md delete mode 100644 content/en/docs3-v2/java-sdk/upgrades-and-compatibility/serialization-upgrade.md delete mode 100755 content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/_index.md delete mode 100644 content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery.md delete mode 100644 content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule.md delete mode 100644 content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples.md delete mode 100755 content/en/docs3-v2/rust-sdk/_index.md delete mode 100644 content/en/docs3-v2/rust-sdk/java-interoperability.md delete mode 100644 content/en/docs3-v2/rust-sdk/protocol.md delete mode 100644 content/en/docs3-v2/rust-sdk/quick-start.md diff --git a/content/en/contact/_index.md b/content/en/contact/_index.md new file mode 100755 index 000000000000..d2cde263b288 --- /dev/null +++ b/content/en/contact/_index.md @@ -0,0 +1,132 @@ +--- +aliases: + - /zh/contact/ + - /zh/contribution-guidelines/ +description: 联系社区,Dubbo 社区贡献指南 +linkTitle: 联系社区 +# menu: +# main: +# weight: 40 +title: 联系社区 +type: docs +--- + + + +## 为 Dubbo 做贡献 + +Dubbo 是在非限制性的 Apache 2.0 许可下发布的,遵循标准的 Github 开发流程,使用Github追踪处理问题,并将 pull request 合并到 master 中。如果您想为 Dubbo 做贡献(即便是一些微小的),请不要犹豫,遵循下面的指导方针。 + +### 联系我们 + +#### 社交媒体 +{{< cardpane >}} + {{< card header="微信公众号" >}} +
+ + Wechat + +

官方微信公众号(Apache Dubbo)

+
+ {{< /card >}} + {{< card header="钉钉群组" >}} +
+ + Dingtalk + +

定期举办线上社区会议或开发者双周会

+
+ {{< /card >}} + {{< card header="Twitter" >}} +
+ + Twitter + + Twitter ▶ +

#apachedubbo

+

关于 Apache Dubbo 项目的国际社区动态与业界国际资讯

+
+ {{< /card >}} + {{< card header="Github" >}} +
+ + GitHub + + GitHub ▶ +

找到对应语言实现或生态项目的 GitHub 地址,即刻参与 Dubbo 项目源码贡献

+
+ {{< /card >}} +{{< /cardpane >}} + +#### 邮件列表 + + +邮件列表是讨论几乎所有与 Dubbo 有关事情的推荐方式。有关如何订阅的详细文档,请参阅[指南](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide)。 + +- [dev@dubbo.apache.org](mailto:dev-subscribe@dubbo.apache.org): 开发邮件列表,如果您在使用或开发Dubbo时遇到任何问题,您可以在此提出问题。 +- [commits@dubbo.apache.org](mailto:commits-subscribe@dubbo.apache.org): 所有提交将被发送到这个邮件列表。如果您对Dubbo的发展感兴趣,您可以订阅它。 +- [notification@dubbo.apache.org](mailto:notification-subscribe@dubbo.apache.org): 所有Github [issue](https://github.com/apache/dubbo/issues)和[pull request](https://github.com/apache/dubbo/pulls)的更新都会被发送到这个邮件列表。 + +### 报告问题 + +在报告任何问题时请遵循[模版](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md)。 + +### 代码约定 +我们的代码风格几乎和标准 Java 约定一致(流行IDE的默认设置满足这一点),主要有以下附加限制: + +* 如果当前行中有超过 120 个字符,则起一个新的行。 + +* 确保所有新的 .java 文件都有一个简单的 JavaDoc 类注释,其中至少有一个标识创建日期的标签,最好至少有一个关于该类的解释说明。 + +* 将ASF许可注释添加到所有新的 .java 文件(从项目中的现有文件复制) + +* 请确保没有将 @author 标记添加到您所贡献的文件中,因为 Apache 不使用 @author 标记,其他方式(如cvs)将公平地记录所有您的贡献。 + +* 为代码添加一些 JavaDoc,如果您更改命名空间,则需要一些 XSD DOC 元素。 + +* 对于新的特征或重要的修复程序,应该添加单元测试。 + +* 如果没有其他人使用您的分支,请将它与 master(或主项目中的其他目标分支)同步。 + +* 当编写提交消息时,请遵循这些约定,如果您正在修复一个现有问题,请在提交消息的末尾添加 Fixes XXX(其中XXX是问题编号)。 + +### 贡献流程 + +这是一个贡献者工作流程的大致说明: + +* 克隆当前项目 +* 从希望贡献的分支上创新新的分支,通常是 master 分支。 +* 提交您的更改。 +* 确保提交消息的格式正确。 +* 将新分支推送到您克隆的代码库中。 +* 执行检查表 [pull request模版](https://github.com/apache/dubbo/blob/master/PULL_REQUEST_TEMPLATE.md)。 +* 在提交 pull request 请求前, 请将您克隆的代码和远程代码库同步,这样您的 pull request 会简单清晰。具体操作如下: +``` +git remote add upstream git@github.com:apache/dubbo.git +git fetch upstream +git rebase upstream/master +git checkout -b your_awesome_patch +... add some work +git push origin your_awesome_patch +``` +* 提交 pull request 请求到 apache/dubbo 并等待回复。 + +谢谢您的贡献! + +### 代码风格 + + +我们提供了 IntelliJ idea 的模版文件[dubbo_codestyle_for_idea.xml](https://github.com/apache/dubbo/tree/master/codestyle/dubbo_codestyle_for_idea.xml),您可以将它导入到IDE。 + +如果使用 Eclipse,可以通过参考该文件手动配置。 + +**注意事项** + +使用 dubbo_codestyle_for_idea.xml 为你的 IDEA 设置代码格式是贡献代码前至关重要的一个步骤,否则你将会无法通过 Travis CI 的代码风格校验,下面几个步骤给你演示了如何配置代码格式: + +1. 进入菜单页 `Editor > Code Style` +2. 在 Code Style 页面的 scheme 菜单中点击 manage profiles 选项 +在下拉列表中选择 `Import Scheme`, 接着选择 `IntelliJ IDEA code style XML` 导入 xml 文件 +3. 输入你的格式名称,方便在不同工程之间进行识别,最后别忘了 ⏎ 来保存更改. + +设置完成后,IDEA 会帮助你自动 reformat 代码 diff --git a/content/en/contact/books/_index.md b/content/en/contact/books/_index.md new file mode 100644 index 000000000000..ae805b2952ad --- /dev/null +++ b/content/en/contact/books/_index.md @@ -0,0 +1,43 @@ +--- +aliases: + - /zh/contact/books/ +description: "" +linkTitle: 书籍与资料 +title: 书籍与资料 +type: docs +weight: 1 +--- + + + +以下是 Apache Dubbo 社区及贡献者编写的部分书籍资料。 + +{{< cardpane >}} +{{< card header="《Apache Dubbo3 源码深入解析》电子书" title="源码视角深入剖析 Dubbo3 实现与原理" subtitle="宋小生 著" url="https://developer.aliyun.com/ebook/7894" >}} +book-source-code + +下载地址: +* Github +* 阿里云开发者社区 +{{< /card >}} +{{< card header="《Apache Dubbo3 微服务开发从入门到精通》电子书" title="从 Dubbo 的基本开发模式、到高阶的治理与运维技巧" subtitle="Dubbo社区 著" url="https://developer.aliyun.com/ebook/7913" >}} +apache-dubbo-microservice-guide + +下载地址: +* Github +* 阿里云开发者社区 +{{< /card >}} +{{< /cardpane >}} + +{{< cardpane >}} +{{< card header="《Apache Dubbo Go 微服务开发》" title="跟随 Apache Dubbo 进入 Go 微服务开发的世界" subtitle="Dubbo社区 著" >}} +

+将于近期发布,敬请期待... +

+{{< /card >}} +{{< card header="《云原生微服务与 Apache Dubbo3》" title="" subtitle="Dubbo社区 著" >}} +

+将于近期发布,敬请期待... +

+{{< /card >}} +{{< /cardpane >}} \ No newline at end of file diff --git a/content/en/contact/committer/_index.md b/content/en/contact/committer/_index.md new file mode 100755 index 000000000000..41befd8f3429 --- /dev/null +++ b/content/en/contact/committer/_index.md @@ -0,0 +1,9 @@ +--- +aliases: + - /zh/contact/committer/ +description: Dubbo Committer 指南 +linkTitle: Committer 指南 +title: Committer 指南 +type: docs +weight: 3 +--- diff --git a/content/en/contact/committer/apache-dubbo-page_dev.md b/content/en/contact/committer/apache-dubbo-page_dev.md new file mode 100644 index 000000000000..f40e8915ad4b --- /dev/null +++ b/content/en/contact/committer/apache-dubbo-page_dev.md @@ -0,0 +1,39 @@ +--- +aliases: + - /zh/contact/committer/apache-dubbo-page_dev/ +description: 官方 Dubbo 主页的维护 +linkTitle: 官方主页 +title: 官方 Dubbo 主页的维护 +type: docs +weight: 5 +--- + + + + +Apache 有一个官方的网站,用来维护所有的孵化项目的信息。每一个孵化项目在这个网站下都有一个信息页。 +Dubbo 的信息页地址是 [https://incubator.apache.org/projects/dubbo.html](https://incubator.apache.org/projects/dubbo.html)。 + +当项目发生比较大的变化,比如新的 committer 的加入,新的 PMC 的当选,或是新版本的 Release 等,都需要将这些更新信息维护到这个页面。 + +这个官方网站的项目地址是[https://svn.apache.org/repos/asf/incubator/public/trunk](https://svn.apache.org/repos/asf/incubator/public/trunk)。 + +维护这个页面的方法如下: + +1.安装 SVN。若是 Mac OS X 系统或是 Linux 系统,则自带了 SVN。若是 Windows 系统,则请首先自行安装 SVN。 + +2.用 SVN 将这个[项目](https://svn.apache.org/repos/asf/incubator/public/trunk) checkout 下来 。 + +3.修改 content/projects/dubbo.xml 文件,并保存。 + +4.安装 ANT。执行 trunk 目录下的 build.sh 或者 build.bat 脚本构建项目。 + +5.构建完成后,可以用浏览器打开 target/site/projects/dubbo.html 文件,预览修改是否生效。 + +6.用 SVN 的 commit 命令将 dubbo.xml 文件提交到服务器,并且不要提交 dubbo.html 文件(因为服务器端会定时自动构建)。 +此过程会要求输入Apache id和密码。 + +参考: + +1. http://incubator.apache.org/guides/website.html +2. https://svn.apache.org/repos/asf/incubator/public/trunk/README.txt \ No newline at end of file diff --git a/content/en/contact/committer/cla-signing-guide_dev.md b/content/en/contact/committer/cla-signing-guide_dev.md new file mode 100644 index 000000000000..82e1475339b7 --- /dev/null +++ b/content/en/contact/committer/cla-signing-guide_dev.md @@ -0,0 +1,35 @@ +--- +aliases: + - /zh/contact/committer/cla-signing-guide_dev/ +description: CLA 签署向导 +linkTitle: CLA 签署向导 +title: CLA 签署向导 +type: docs +weight: 2 +--- + + + + +以下情况,需要您签署 Apache ICLA: + +* 在 Dubbo 被捐赠给 Apache 之前,您已经为 Dubbo 作出了很多贡献,并且您以前没有签署过 Alibaba-CLA。 +* 您已经为 Dubbo 作出了很多贡献,并且您被邀请成为 Dubbo 提交者,且之前没有签署过 Alibaba-CLA 或者 Apache ICLA。 + +### 步骤 + +* 下载这篇 [pdf 文档](https://www.apache.org/licenses/icla.pdf) +* 编辑该文档,在必要的空格处填上适当的内容 +* 打印 +* 在打印好的文件上签字 +* 扫描 +* 发送一封邮件到secretary@apache.org,并抄送给private@dubbo.apache.org: + * 邮件标题为 “ICLA submission” + * 请在邮件正文附上您的github账号链接 + * 请记得将您的 ICLA 文档放入邮件的附件里 + +### 空格填写必要说明 + +* Mailing address:首选英文格式的公司地址 +* Preferred apache id(s):如果您被邀请成为一名提交者,那么需要您填写一个apache账号,否则,可以不填 +* Notify project:Dubbo(意思就是Dubbo就是通知您签署ICLA的项目) \ No newline at end of file diff --git a/content/en/contact/committer/label-an-issue-guide_dev.md b/content/en/contact/committer/label-an-issue-guide_dev.md new file mode 100644 index 000000000000..a78211d79140 --- /dev/null +++ b/content/en/contact/committer/label-an-issue-guide_dev.md @@ -0,0 +1,37 @@ +--- +aliases: + - /zh/contact/committer/label-an-issue-guide_dev/ +description: 给问题打标签 +linkTitle: 问题标签 +title: 给问题打标签 +type: docs +weight: 3 +--- + + + +如果您正在处理一个问题,请记得**给这个问题标记一个或者多个您认为有意义的标签**。有了标签,其他开发人员就会很轻松地识别出问题,以便对其进行分类并跟踪进度。 + +对于需要编码和发版修复的 issues 和 pull requests,需要您**将其标记为 [milestone](https://github.com/apache/dubbo/milestones)**。 + +一些常用的标签: + +* 请求帮助 + * help wanted + * good first issue +* 优先级 + * priority/blocker + * priority/high + * priority/low + * priority/normal +* 状态 + * status/need-triage + * status/DO-NOT-MERGE + * status/READY-TO-MERGE + * status/invalid + * status/wontfix +* 类型 + * type/bug + * type/documentation + * type/enhancement + * type/feature \ No newline at end of file diff --git a/content/en/contact/committer/new-committer-guide_dev.md b/content/en/contact/committer/new-committer-guide_dev.md new file mode 100644 index 000000000000..f3fa2c668f77 --- /dev/null +++ b/content/en/contact/committer/new-committer-guide_dev.md @@ -0,0 +1,86 @@ +--- +aliases: + - /zh/contact/committer/new-committer-guide_dev/ +description: Apache 提交者注册流程 +linkTitle: 注册流程 +title: Apache 提交者注册流程 +type: docs +weight: 1 +--- + + + + +## 一、Apache 提交者的产生 + +### 项目孵化初始化提交者 + +项目孵化阶段,在孵化项目提案中,会有初始化提交者列表这一选项。确认你是初始化提交者的一员。项目在 apache 孵化器社区投票通过后,提交者可以开始准备注册账户了。可以参看[孵化器 wiki](https://wiki.apache.org/incubator/) + +### 活跃的贡献者被选举为提交者 + +在后期的开发过程中,活跃的贡献者可以被选举为提交者。见[如何成为 committer](https://www.apache.org/dev/new-committers-guide.html#becoming-a-committer) + +## 二、个人开发者提交 ICLA + +### 1、选择 apache id +在[ apache 提交者列表页](http://people.apache.org/committer-index.html)查看已经注册过的 apache id, + +### 2、个人提交者授权协议(ICLA): +下载[ ICLA 模板](https://www.apache.org/licenses/icla.pdf),查找可用的 id。将 icla.pdf 个人信息填写正确后打印,签名、扫描、并当做附件发送邮件给秘书 secretary@apache.org,秘书会帮忙创建 apache 用户 id。同时会创建一个 your_id@apache.org 的邮箱,可以在[ apache 提交者列表页](http://people.apache.org/committer-index.html)查看查找用户是否已经创建。 + +### 3、导师帮助提交用户id创建请求 +导师将帮助提交 apache 账户创建请求给 root 邮件组,会有人帮助建立 id。一般需要2天时间账户会建立,请等待并在[ apache 提交者列表页](http://people.apache.org/committer-index.html)查看查找用户是否已经创建。 + +## 三、加入apache开发者组 +1. 登陆 [Apache 账户工具](https://id.apache.org/),在登陆页面点击"忘记密码"设置始化密码,会有一封密码重置邮件发送到 forward 邮箱(在孵化项目提案中提交的开发者邮件) +2. 关于 apache 邮箱:apache.org 邮箱并没有自己的邮件内容存储服务器。它需要借用其他邮件提供商的邮件内容存储、分发功能。在很多投票环节是建议使用 apache 邮箱的。 + 这里就有一个问题,怎么在其它邮箱里面配置 apache.org 邮箱转发功能: + * 收件箱:收取发送到 apache.org 的邮件。这个在第一步配置好 Apache 账户工具的 forward 邮箱就可以用 forward 邮箱收取邮件了 + * 发件箱:将发出的邮件显示发件邮箱为 apache.org 邮箱。请参考:[设置 apache 邮箱指南](https://reference.apache.org/committer/email)和[ gmail 邮箱设置方式](https://support.google.com/mail/answer/22370)。 其他邮箱服务的设置方式不方便找到,gmail 的最方便,建议换成 gmail 邮箱(不是广告)。 +3. 修改编辑页面的 homepage url,[apache 提交者列表页](http://people.apache.org/committer-index.html)中你的账户能加主页链接。 +4. 修改编辑页面的 github 账户(username),提交确认后两个小时内会有邮件邀请你加入 github.com/apache-committers 组。这期间可以阅读[ ASF 工作方式](http://www.apache.org/foundation/how-it-works.html#developers)以对 ASF 开发做一些基本了解。 +## 四、提交者获得对项目的写权限 + +[GitBox 账户链接工具](https://gitbox.apache.org/setup/)的操作 + +### Apache账户授权 +按照提示授权对 Apache 账户的 OAuth 协议登入 + +### Github账户授权 +按照提示授权对 github 账户的 OAuth 协议登入 + +### 在 github.com 设置 github 账户两因素授权(2FA) +按照[授权 GitHub 2FA wiki](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication) 操作如下: +* 在手机安装 “google 身份验证器” app +* 按照[授权 GitHub 2FA wiki](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication) 一步一步操作。 + + 在[两因素授权验证](https://github.com/settings/security)界面,不建议选择用手机扫描二维码,因为有些手机会扫描不出来。 + 请打开手机 “google 身份验证器” app,点“+”选择“输入提供的秘钥”: 在“账户名” input 框写入 github 账户。在“您的秘钥” input 框写入:打开的网页中 "enter this text code" 链接里面的文本。在 app 中点击"添加" 后,将为此账户生成6位数字动态。将此6位数字写入网页中的文本框,然后点 “Enable”。这样 2FA 就设置成功了。 + +* 退出并重新登陆 github,输入用户名、密码后会多一步动态密码的填写,该动态密码就是 google 身份验证器上面的动态密码 + +* 大概需要半个小时,会有邮件通知你已经加入了 xx project-committers 开发者组。你也可以进入 [apache teams](https://github.com/orgs/apache/teams) 页面查看。 + +* 2FA 提交后,你已经 clone 的项目会有权限校验问题,解决方法为下面二选一: + * 申请 Access Token: + 在 github 上生成 access token 后,指令行需要密码的地方就粘贴token。 + 参考官网[帮助链接一](https://docs.github.com/cn/repositories/creating-and-managing-repositories/troubleshooting-cloning-errors#provide-access-token-if-2fa-enabled)和[帮助链接二](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) + * 改用 ssh: + 在命令行执行 ssh-keygen 命令, 然后把pub文件中的内容粘贴到 github 上 + +* 注意:一定要保证 github 的 2FA 为 "enable" 状态。当你将 2FA 设置为 "off" 时候,将会被对应的 apache committer 写权限组除名,直到你再次设置成功为止。 + +## 五、其他 + +### The Apache Way +详情请参考 [wiki](http://apache.org/foundation/governance/) + +社区重于代码,如果某问题或者方案没有在社区(邮件列表)讨论过,就当没有发生过 + +### 小福利 + +Jetbrains 给 apache 提交者一个小福利,就是可以免费使用 idea 的全产品系列。具体注册地址为:https://www.jetbrains.com/shop/eform/apache?product=ALL + +### 相关 wiki +https://www.apache.org/dev/new-committers-guide.html \ No newline at end of file diff --git a/content/en/contact/committer/release-guide/_index.md b/content/en/contact/committer/release-guide/_index.md new file mode 100755 index 000000000000..09887b2839c5 --- /dev/null +++ b/content/en/contact/committer/release-guide/_index.md @@ -0,0 +1,9 @@ +--- +aliases: + - /zh/contact/committer/release-guide/ +description: 如何准备 Apache Release +linkTitle: 发版准备 +title: 如何准备 Apache Release +type: docs +weight: 2 +--- diff --git a/content/en/contact/committer/release-guide/common.md b/content/en/contact/committer/release-guide/common.md new file mode 100644 index 000000000000..f092c6dbfe90 --- /dev/null +++ b/content/en/contact/committer/release-guide/common.md @@ -0,0 +1,179 @@ +--- +aliases: + - /zh/contact/committer/release-guide/common/ +description: 通用 Release 流程 +linkTitle: 通用 Release +title: 通用 Release 流程 +type: docs +weight: 1 +--- + + + +## 理解 Apache 发布的内容和流程 + +总的来说,Source Release 是 Apache 关注的重点,也是发布的必须内容;而 Binary Release 是可选项,Dubbo 可以选择是否发布二进制包到 Apache 仓库或者发布到 Maven 中央仓库。 + +请参考以下链接,找到更多关于 ASF 的发布指南: + +- [Apache Release Guide](http://www.apache.org/dev/release-publishing) +- [Apache Release Policy](http://www.apache.org/dev/release.html) +- [Maven Release Info](http://www.apache.org/dev/publishing-maven-artifacts.html) + +## 发布流程 + +### 1. 准备分支 + +从主干分支拉取新分支作为发布分支,如现在要发布 `${release_version}` 版本,则从开发分支拉出新分支 `${release_version}-release`,此后`${release_version}` Release Candidates 涉及的修改及打标签等都在`${release_version}-release`分支进行,最终发布完成后合入主干分支。 + +例:如 Java SDK 需要发布 `3.0.10` 版本,从 `3.0` 分支拉出新分支 `3.0.10-release`,并在此分支提交从 Snapshot 替换为 `3.0.10` 版本号的 commit。 + +### 2. Github 打标签并发布 Pre Release 状态 + +在对应 GitHub 仓库中基于 `${release_version}-release` 分支,打标签 `${release_version}-release`,填写 Release Note 并发布 Pre Release 状态。(**不允许在投票流程正式通过前把 Release 状态置为正式发布状态**) + +注:打完标签之后此分支不允许再提交任何 commit,需要保证分支中最后一个 commit 就是标签的 commit 和投票中的 commit。 + +### 3. 预发布二进制包(可选) + +通过构建工具推送二进制包到托管平台,如 Java SDK 发布到 Maven 仓库,状态为 Staging。 + +注:如果托管平台不支持预发布功能,则需要在投票正式通过后再发布。 + +### 4. 构建 Source Release 文件 + +将源码使用 zip 格式进行打包,使用个人 gpg 证书进行签名得到 asc 文件以及使用 shasum 工具生成 sha512 文件。 + +例:如 Java SDK 发布 `3.0.10` 版本,需要构建 `apache-dubbo-3.0.10-src.zip` 、 `apache-dubbo-3.0.10-src.zip.asc` 和 `apache-dubbo-3.0.10-src.zip.sha512` 三个文件。 + +### 5. 提交 Source Release 文件到 Apache SVN 仓库 + +将 Source Release 文件推送到 `https://dist.apache.org/repos/dist/dev/dubbo/` 仓库中,文件存储到 `https://dist.apache.org/repos/dist/dev/dubbo/${component_name}/${release_version}/` 目录下。(需要 Committer 权限才能推送) + +### 6. 发送投票邮件 + +使用 Apache 邮箱发送投票邮件,投票邮件的标题为:`[VOTE] Release ${component_name} ${release_version} RC1`,邮件内容需要包含以下内容: +- Source Release 的链接 +- 二进制包预发布的链接(如有) +- GitHub Tag 标签 +- 最后一个 Commit 的 Hash +- Release Note 链接 +- Source Release 使用的签名文件 + +以上的 Source Release、Tag、Hash、Release Note 必须完全对应 + +例:如 Java SDK 发布 `3.0.10` 版本,发送的邮件如下 + +``` +Project: [VOTE] Release Apache Dubbo 3.0.10 RC1 + +Hello Community, + +This is a call for vote to release Apache Dubbo version 3.0.10 + +The release candidates: +https://dist.apache.org/repos/dist/dev/dubbo/dubbo/3.0.10/ + +The staging repo: +https://repository.apache.org/content/repositories/orgapachedubbo-1216/ + +Git tag for the release: +https://github.com/apache/dubbo/tree/dubbo-3.0.10 + +Hash for the release tag: +e7894ca374e966a1d807e34b2744f276b843f39f + +Release Notes: +https://github.com/apache/dubbo/releases/tag/dubbo-3.0.10 + +The artifacts have been signed with Key 2B249EDD, which can be +found in the keys file: +https://dist.apache.org/repos/dist/dev/dubbo/KEYS + +The vote will be open for at least 72 hours or until the necessary number of +votes are reached. + +Please vote accordingly: + +[ ] +1 approve +[ ] +0 no opinion +[ ] -1 disapprove with the reason + +Thanks, +The Apache Dubbo Team +``` + +### 7. PMC 检查版本信息,并进行投票 + +详细的检查列表请参考官方的 [check list](https://cwiki.apache.org/confluence/display/INCUBATOR/Incubator+Release+Checklist) + +### 8. 投票通过,发布投票结果 + +在至少等待 72 小时且至少 3 位 PMC 投 +1 approve 票之后,可以发送邮件宣布投票结果。 +投票结果邮件的标题为:`[RESULT] [VOTE] Release ${component_name} ${release_version} RC1`,邮件内容需要包含投票的 PMC 信息和投票的 thread。 +(可以通过 [https://lists.apache.org/list.html?dev@dubbo.apache.org](https://lists.apache.org/list.html?dev@dubbo.apache.org) 找到) + +例:如 Java SDK 发布 `2.7.16` 版本,发送的邮件如下 + +``` +Project: [RESULT] [VOTE] Release Apache Dubbo 2.7.16 RC1 + +Hello Dubbo Community, + +The release vote finished, We’ve received + ++1 binding, Jun Liu ++1 binding, Laurence ++1 binding, Hao Guo + +The vote and result thread: +https://lists.apache.org/thread/o4hk0b0rok78kw7ftqh0ly49wg8whgps +The vote passed. I am working on the further release process, thanks. + +Best regards, +The Apache Dubbo Team +``` + +### 9. Github 标记正式 Release + +在 GitHub 上正式把前面第 2 步打的标签更新为正式发布状态。 + +### 10. 合并 Release 分支回主干 + +将 `${release_version}-release` 合并回开发主干,并更新最新 snapshot 版本号。(`${release_version}-release` 可以不保留) + +### 11. 移动 Source Release 到 release 仓库(重要) + +将 `https://dist.apache.org/repos/dist/dev/dubbo/` 仓库中存储的 Source Release 文件移动到 `https://dist.apache.org/repos/dist/release/dubbo/` 仓库中。(仅 PMC 有权限) +同时删除之前的 Source Release 文件。(会被自动存放在 Archive 仓库) + +### 12. 正式发布二进制包(如有) + +将前面第 3 步发布的预发布状态的二进制包更新为正式发布状态。 + +### 13. 更新 Dubbo Website 文档 + +更新最新的 Source Release 等信息到 `dubbo-website` 对应文件中,至少包括 Source Release 的下载方式和二进制包的引用方式(如有),同时将历史的发布的链接更新到 archive 的域名下。 + +### 14. 发布正式发布结果通知 + +投票结果邮件的标题为:`[Announce] Release ${component_name} ${release_version} released`。 + +注:最好等二进制包发布正式同步生效后发布此邮件。 + +``` +Project: [Announce] Apache Dubbo 3.0.9 released + +Hello Dubbo Community, + +I am glad to announce that Apache Dubbo 3.0.9 was released. + +You can check detailed release notes here: +https://github.com/apache/dubbo/releases/tag/dubbo-3.0.9 + +If you have any questions using this version, please send mail to here or +report the issue on Github. + +Best regards, +Dubbo Team +``` \ No newline at end of file diff --git a/content/en/contact/committer/release-guide/java-sdk.md b/content/en/contact/committer/release-guide/java-sdk.md new file mode 100644 index 000000000000..7f3b9f8a8ef2 --- /dev/null +++ b/content/en/contact/committer/release-guide/java-sdk.md @@ -0,0 +1,463 @@ +--- +aliases: + - /zh/contact/committer/release-guide/java-sdk/ +description: Java SDK Release 流程 +linkTitle: Java SDK Release +title: Java SDK Release 流程 +type: docs +weight: 2 +--- + + + + +## 理解 Apache 发布的内容和流程 + +总的来说,Source Release 是 Apache 关注的重点,也是发布的必须内容;而 Binary Release 是可选项,Dubbo 可以选择是否发布二进制包到 Apache 仓库或者发布到 Maven 中央仓库。 + +请参考以下链接,找到更多关于 ASF 的发布指南: + +- [Apache Release Guide](http://www.apache.org/dev/release-publishing) +- [Apache Release Policy](http://www.apache.org/dev/release.html) +- [Maven Release Info](http://www.apache.org/dev/publishing-maven-artifacts.html) + +## 本地构建环境准备 + +主要包括签名工具、Maven 仓库认证相关准备 + +### 安装GPG + +详细文档请参见[这里](https://www.gnupg.org/download/index.html), Mac OS 下配置如下 + +```sh +$ brew install gpg +$ gpg --version #检查版本,应该为2.x +``` + +### 用gpg生成key + +根据提示,生成 key + + ```shell + $ gpg --full-gen-key + gpg (GnuPG) 2.0.12; Copyright (C) 2009 Free Software Foundation, Inc. + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. + + Please select what kind of key you want: + (1) RSA and RSA (default) + (2) DSA and Elgamal + (3) DSA (sign only) + (4) RSA (sign only) + Your selection? 1 + RSA keys may be between 1024 and 4096 bits long. + What keysize do you want? (2048) 4096 + Requested keysize is 4096 bits + Please specify how long the key should be valid. + 0 = key does not expire + = key expires in n days + w = key expires in n weeks + m = key expires in n months + y = key expires in n years + Key is valid for? (0) + Key does not expire at all + Is this correct? (y/N) y + + GnuPG needs to construct a user ID to identify your key. + + Real name: Robert Burrell Donkin + Email address: rdonkin@apache.org + Comment: CODE SIGNING KEY + You selected this USER-ID: + "Robert Burrell Donkin (CODE SIGNING KEY) " + + Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O + You need a Passphrase to protect your secret key. # 填入密码,以后打包过程中会经常用到 + ``` + +### 查看 key id + +```sh +$ gpg --list-keys +pub rsa4096/28681CB1 2018-04-26 # 28681CB1就是key id +uid [ultimate] liujun (apache-dubbo) +sub rsa4096/D3D6984B 2018-04-26 + +# 通过key id发送public key到keyserver +$ gpg --keyserver pgpkeys.mit.edu --send-key 28681CB1 +# 其中,pgpkeys.mit.edu为随意挑选的keyserver,keyserver列表为:https://sks-keyservers.net/status/,为相互之间是自动同步的,选任意一个都可以。 +``` +如果有多个 public key,设置默认 key。修改`~/.gnupg/gpg.conf` + +```sh +# If you have more than 1 secret key in your keyring, you may want to +# uncomment the following option and set your preferred keyid. +default-key 28681CB1 +``` +如果有多个 public key, 也可以删除无用的 key: + +```sh +### 先删除私钥,再删除公钥 +$ gpg --yes --delete-secret-keys shenglicao2@gmail.com ###老的私钥,指明邮箱即可 +$ gpg --delete-keys 1808C6444C781C0AEA0AAD4C4D6A8007D20DB8A4 +``` + +> PS: 最新版本经过实测,本地没有gpg.conf这个文件,因此如果在执行过程中遇到签名失败,可以参考这个文章:https://blog.csdn.net/wenbo20182/article/details/72850810 或 https://d.sb/2016/11/gpg-inappropriate-ioctl-for-device-errors + +由于公钥服务器没有检查机制,任何人都可以用你的名义上传公钥,所以没有办法保证服务器上的公钥的可靠性。 +通常,你可以在网站上公布一个公钥指纹,让其他人核对下载到的公钥是否为真。 +```sh +# fingerprint参数生成公钥指纹: +$ gpg --fingerprint liujun +pub rsa4096 2019-10-17 [SC] + 1376 A2FF 67E4 C477 5739 09BD 7DB6 8550 D366 E4C0 +uid [ultimate] liujun (CODE SIGNING KEY) +sub rsa4096 2019-10-17 [E] +``` +登录 https://id.apache.org, 将上面的 fingerprint (即 1376 A2FF 67E4 C477 5739 09BD 7DB6 8550 D366 E4C0) +粘贴到自己的用户信息中 OpenPGP Public Key Primary Fingerprint + +### 设置 Apache 中央仓库 + +Dubbo 项目的父 pom 为 Apache pom(2.7.0 以上版本需要,2.6.x 发布版本不需要此操作) + +```xml + +org.apache +apache +19 + +``` + + 添加以下内容到 .m2/settings.xml + 所有密码请使用 [maven-encryption-plugin](http://maven.apache.org/guides/mini/guide-encryption.html)加密后再填入 + +```xml + +... + + + + apache.snapshots.https + + + + + + apache.releases.https + + + + ... + + + gpg.passphrase + + + + +``` + +## 打包&上传 + +### 准备分支 + +从主干分支拉取新分支作为发布分支,如现在要发布$`{release_version}`版本,则从2.6.x拉出新分支`${release_version}-release`,此后`${release_version}` Release Candidates涉及的修改及打标签等都在`${release_version}-release`分支进行,最终发布完成后合入主干分支。 + +### 编译打包 + +首先,在`${release_version}-release`分支验证maven组件打包、source源码打包、签名等是否都正常工作。**2.6.x记得要使用1.6进行编译打包** + +```shell +$ mvn clean install -Prelease +$ mvn deploy +``` + +上述命令将snapshot包推送到maven中央仓库 + +### 使用mvn deploy进行deploy + +> 要求:maven 3.5+ + +修改pom文件中的版本号,从2.7.x-SNAPSHOT改为2.7.x, 目前有3个地方需要修改。建议全文搜索。 + +```shell +$ mvn clean install -Prelease +$ mvn deploy -Prelease -DskipTests +``` + +所有被deploy到远程[maven仓库](http://repository.apache.org)的Artifacts都会处于staging状态 + +#### 注意点 + +- 在deploy执行过程中,有可能因为网络等原因被中断,如果是这样,可以重新开始执行。 +- deploy执行到maven仓库的时候,请确认下包的总量是否正确。多次出现了包丢失的情况,特别是dubbo-parent包。 + + +## 准备Apache发布 + +1. 准备svn本机环境(Apache使用svn托管项目的发布内容) + +2. 将dubbo checkout到本地目录 + + ```shell + $ svn checkout https://dist.apache.org/repos/dist/dev/dubbo + # 假定本地目录为 ~/apache/dubbo + ``` + +3. 当前发布版本为${release_version},新建目录 + + ```shell + $ cd ~/apache/dubbo # dubbo svn根目录 + $ mkdir ${release_version} + ``` + +4. 添加public key到[KEYS](https://dist.apache.org/repos/dist/dev/dubbo/KEYS)文件并提交到SVN仓库(第一次做发布的人需要做这个操作,具体操作参考KEYS文件里的说明)。KEYS主要是让参与投票的人在本地导入,用来校验sign的正确性 + + ```sh + $ (gpg --list-sigs && gpg --armor --export ) >> KEYS + ``` + +5. 拷贝`dubbo-distribution/dubbo-apache-release/target`下的source相关的包到svn本地仓库`dubbo/${release_version}` + +6. 生成sha512签名和asc签名 + + 针对`src.zip` 进行sha512签名 + + ```shell + $ shasum -a 512 apache-dubbo-${release_version}-src.zip >> apache-dubbo-${release_version}-src.zip.sha512 + ``` + + 针对`bin-release.zip`,需要增加`-b`参数,表明是一个二进制文件 + + ```shell + $ shasum -b -a 512 apache-dubbo-${release_version}-bin.zip >> apache-dubbo-${release_version}-bin.zip.sha512 + ``` + + 针对`src.zip` 进行asc签名 + ```shell + $ gpg --armor --output apache-dubbo-${release_version}-src.zip.asc --detach-sig apache-dubbo-${release_version}-src.zip + ``` + + +7. 如果有binary release要同时发布 + + 在`dubbo-distribution/dubbo-apache-release/target`目录下,拷贝`bin.zip`以及`bin.zip.asc`到svn本地仓库`dubbo/${release_version}`,参考第6步,生成sha512签名。 + +8. 提交到Apache svn + + ```shell + $ svn status + $ svn commit -m 'prepare for ${release_version} RC1' + ``` + +9. 关闭Maven的staging仓库 + + 此步骤为发布2.7.0及以上版本必须要的步骤。在此之前请先确保所有的artifact都是ok的。登录http://repository.apache.org,点击左侧的`Staging repositories`,然后搜索Dubbo关键字,会出现一系列的仓库,选择你最近上传的仓库,然后点击上方的Close按钮,这个过程会进行一系列检查,检查通过以后,在下方的Summary标签页上出现一个连接,请保存好这个链接,需要放在接下来的投票邮件当中。链接应该是类似这样的: `https://repository.apache.org/content/repositories/orgapachedubbo-1015` + + > 请注意点击Close可能会出现失败,通常是网络原因,只要重试几次就可以了。可以点击Summary旁边的Activity标签来确认。 + +## 验证Release Candidates + +详细的检查列表请参考官方的[check list](https://cwiki.apache.org/confluence/display/INCUBATOR/Incubator+Release+Checklist) + +首先,从一下地址下载要发布的Release Candidate到本地环境: + +
+https://dist.apache.org/repos/dist/dev/dubbo/${release_version}/
+
+ +然后,开始验证环节,验证包含但不限于以下内容和形式 + +### 检查签名和hash等信息 + +#### 检查sha512哈希 + +```sh +$ shasum -c apache-dubbo-${release_version}-src.zip.sha512 +$ shasum -c apache-dubbo-${release_version}-bin.zip.sha512 +``` +#### 检查asc签名 +```shell +$ gpg --verify apache-dubbo-${release_version}-src.zip.asc +``` + +#### 检查gpg签名 + +如果是第一次检查,需要首先导入公钥。 + +```sh + $ curl https://dist.apache.org/repos/dist/dev/dubbo/KEYS >> KEYS # download public keys to local directory + $ gpg --import KEYS # import keys + $ gpg —-edit-key liujun + > trust # type trust command +``` +然后使用如下命令检查签名 + + ```sh +gpg --verify apache-dubbo-3.0.4-src.zip.asc apache-dubbo-3.0.4-src.zip +gpg --verify apache-dubbo-3.0.4-bin.zip.asc apache-dubbo-3.0.4-bin.zip + ``` + + +### 检查源码包的文件内容 + +解压缩`apache-dubbo-${release_version}-src.zip`,进行如下检查: + +- DISCLAIMER exists +- LICENSE and NOTICE exists and contents are good +- All files and no binary files exist +- All files has standard ASF License header +- Can compile from source +- All unit tests can pass + ```sh + mvn clean test # This will run all unit tests + # you can also open rat and style plugin to check if every file meets requirements. + mvn clean test -Drat.skip=false -Dcheckstyle.skip=false + ``` +- Release candidates match with corresponding tags, you can find tag link and hash in vote email. + - check the version number in pom.xml are the same + - check there are no extra files or directories in the source package, for example, no empty directories or useless log files,这里需要注意换行符是否一致 + `diff -r a rc_dir tag_dir` + - check the top n tag commits, dive into the related files and check if the source package has the same changes + +### 检查三方依赖的合规性 + +按照Apache基金会合规性规定,源码或者是二进制分发包中均不能包含Category X的依赖,其中就常见的是包含了GPL/LGPL的依赖,即使是传递依赖也不行。因此在发版的时候需要通过以下的命令进行检查: + +```sh +mvn license:add-third-party -Dlicense.useMissingFile +find . -name THIRD-PARTY.txt | xargs grep -E 'GPL|General Public License' | grep -v Apache | grep -v MIT | grep -v CDDL +``` + +如果一个依赖提供了双协议或多重协议,可以选择与Apache最兼容的一个协议。 + +你可以参考此文章:[ASF第三方许可证策](https://apache.org/legal/resolved.html) + + +### 检查二进制包的文件内容 + +解压缩`apache-dubbo-${release_version}-bin.zip`,进行如下检查: + +* Check signatures are good +* LICENSE and NOTICE exists and contents are good + +注意,如果二进制包里面引入了第三方依赖,则需要更新LICENSE,加入第三方依赖的LICENSE,如果第三方依赖的LICENSE是Apache 2.0,并且对应的项目中包含了NOTICE,还需要更新NOTICE文件 + +## 进入投票 + +dubbo毕业之后,投票分只需要一次: + +1. Dubbo社区投票,发起投票邮件到dev@dubbo.apache.org。在社区开发者Review,经过至少72小时并统计到3个同意发版的binding票后(只有PMC的票才是binding),即可进入下一阶段的投票。 + +Dubbo社区投票邮件模板: + +```text +Hello Dubbo Community, + +This is a call for vote to release Apache Dubbo version 2.7.2. + +The release candidates: +https://dist.apache.org/repos/dist/dev/dubbo/2.7.2/ + +The staging repo: +https://repository.apache.org/content/repositories/orgapachedubbo-1005 + +Git tag for the release: +https://github.com/apache/dubbo/tree/dubbo-2.7.2 + +Hash for the release tag: +afab04c53edab38d52275d2a198ea1aff7a4f41e + +Release Notes: +https://github.com/apache/dubbo/releases/tag/untagged-4775c0a22c60fca55118 + +The artifacts have been signed with Key : 28681CB1, which can be found in the keys file: +https://dist.apache.org/repos/dist/dev/dubbo/KEYS + +The vote will be open for at least 72 hours or until necessary number of votes are reached. + +Please vote accordingly: + +[ ] +1 approve +[ ] +0 no opinion +[ ] -1 disapprove with the reason + +Thanks, +The Apache Dubbo Team +``` + + +宣布投票结果模板: +```text +We’ve received 3 +1 binding votes and one +1 non-binding vote: + ++1 binding, Ian Luo ++1 binding, Huxing Zhang ++1 binding, Jun Liu + ++1 non-binding, Jerrick + +I will start to release today. + +Best regards, +The Apache Dubbo Team +``` + +## 正式发布 + +1. 将[dev](https://dist.apache.org/repos/dist/dev/dubbo)目录下的发布包添加到[release](https://dist.apache.org/repos/dist/release/dubbo)目录下,KEYS有更新的,也需要同步更新。 +2. 删除[dev](https://dist.apache.org/repos/dist/dev/dubbo)目录下的发布包 +3. 删除[release](https://dist.apache.org/repos/dist/release/dubbo)目录下上一个版本的发布包,这些包会被自动保存在[这里](https://archive.apache.org/dist/dubbo) +4. 此步骤为发布2.7.0及以上版本必须要的步骤。在此之前请先确保所有的artifact都是ok的。登录http://repository.apache.org,点击左侧的`Staging repositories`,然后搜索Dubbo关键字,会出现一系列的仓库,选择你最近上传的仓库,然后点击上方的Release按钮. +5. 发布GitHub上的[release notes](https://github.com/apache/dubbo/releases) +6. 修改GitHub的Readme文件,将版本号更新到最新发布的版本 +7. 在官网下载[页面](/en/blog/2020/05/18/past-releases/)上添加最新版本的下载链接。最新的下载链接应该类似[这样](https://www.apache.org/dyn/closer.cgi?path=dubbo/$VERSION/apache-dubbo-$VERSION-source-release.zip). 同时更新以前版本的下载链接,改为类似`https://archive.apache.org/dist/dubbo/$VERSION/apache-dubbo-$VERSION-bin-release.zip`. 具体可以参考过往的[下载链接](/en/blog/2020/05/18/past-releases/) [可以参考] (https://github.com/apache/dubbo-website/pull/887) +8. 合并`${release-version}-release`分支到对应的主干分支, 然后删除相应的release分支,例如: `git push origin --delete 2.7.0-release` +9. 发邮件到 `dev@dubbo.apache.org` + 宣布release邮件模板: + +```text +Hello Community, + +The Apache Dubbo team is pleased to announce that the +2.6.6 has just been released. + +Apache Dubbo™ is a high-performance, java based, open source +RPC framework. Dubbo offers three key functionalities, which include +interface based remote call, fault tolerance & load balancing, and +automatic service registration & discovery. + +Both the source release[1] and the maven binary release[2] are available +now, you can also find the detailed release notes here[3]. + + +If you have any usage questions, or have problems when upgrading or find +any problems about enhancements included in this release, please don’t +hesitate to let us know by sending feedback to this mailing list or filing +an issue on GitHub[4]. + + +[1] https://dubbo.apache.org/en/blog/2020/05/18/past-releases/ +[2] https://repo1.maven.org/maven2/org/apache/dubbo/dubbo +[3] https://github.com/apache/dubbo/releases +[4] https://github.com/apache/dubbo/issues + +``` + + +## 完成Maven Convenient Binary发布(可选) + +**repository.apache.org** nexus仓库的权限已经申请,参见[jira](https://issues.apache.org/jira/browse/INFRA-16451) + +发布jar包到maven仓库,首先访问[repository.apache.org](https://repository.apache.org), 选择`staging repository`, 点击`release`按钮。等待一段时间之后,在[这里](https://repository.apache.org/content/repositories/releases/org/apache/dubbo/)确认完整性和正确性. 发布到Maven中央仓库则还需要等待一段时间。可以在[这里](https://repo.maven.apache.org/maven2/org/apache/dubbo)进行确认。 + +## FAQ + +#### gpg: signing failed: Inappropriate ioctl for device + +If you've encountered this error, try the following commands: + +``` +export GPG_TTY=$(tty) +``` \ No newline at end of file diff --git a/content/en/contact/committer/website-guide_dev.md b/content/en/contact/committer/website-guide_dev.md new file mode 100644 index 000000000000..dd433c9f9699 --- /dev/null +++ b/content/en/contact/committer/website-guide_dev.md @@ -0,0 +1,15 @@ +--- +aliases: + - /zh/contact/committer/website-guide_dev/ +description: 网站向导 +linkTitle: 网站向导 +title: 网站向导 +type: docs +weight: 3 +--- + + + + +1. Apache Dubbo 的网站仓库是 https://github.com/apache/dubbo-website +2. 网站构建完毕后,它会被自动发布到 dubbo.apache.org,您也可以通过 https://selfserve.apache.org 手动触发(需要使用 Apache 账号登陆) \ No newline at end of file diff --git a/content/en/contact/contributor/_index.md b/content/en/contact/contributor/_index.md new file mode 100755 index 000000000000..ce5efafa087f --- /dev/null +++ b/content/en/contact/contributor/_index.md @@ -0,0 +1,9 @@ +--- +aliases: + - /zh/contact/contributor/ +description: Dubbo Contributor 指南 +linkTitle: Contributor 指南 +title: Contributor 指南 +type: docs +weight: 2 +--- diff --git a/content/en/contact/contributor/become-a-committer_dev.md b/content/en/contact/contributor/become-a-committer_dev.md new file mode 100644 index 000000000000..9820c573c21b --- /dev/null +++ b/content/en/contact/contributor/become-a-committer_dev.md @@ -0,0 +1,25 @@ +--- +aliases: + - /zh/contact/contributor/become-a-committer_dev/ +description: 如何成为 Dubbo Committer +linkTitle: 成为 Committer +title: 如何成为 Dubbo Committer +type: docs +weight: 1 +--- + + + +每个人都可以成为 Apache 项目的贡献者。作为一个贡献者只是意味着你对项目感兴趣并以某种方式做出贡献,从提出合理的问题(这些问题记录了项目并向开发人员提供反馈)到提供新的特性作为补丁。 + +如果你成为对一个项目有价值的贡献者,你有可能被邀请成为一个 Committer。Committer 是 ASF(Apache 软件基金会)中用来表示提交特定项目的人的术语。它给你带来对项目仓库和资源写的权限。 + +在 Dubbo 社区,如果一个 Committer 获得大量的优秀成绩,就可以被邀请加入项目管理委员会(PMC)。 + +当您不熟悉ASF使用的开源的开发过程时,有时难以理解的一点,就是我们更重视社区而不是代码。一个强大而健康的社区将受到尊重,成为一个有趣和有益的地方。更重要的是,一个多元化和健康的社区可以长时间的持续支持代码,即使个别公司在这个领域来来往往,也是如此。 + +更多详细信息可以在 [这里](https://community.apache.org/contributors/) 找到。 + +### 我可以贡献什么? + +请参阅[新的贡献者指南](../new-contributor-guide_dev/)。 \ No newline at end of file diff --git a/content/en/contact/contributor/dubbo-extension-guide_dev.md b/content/en/contact/contributor/dubbo-extension-guide_dev.md new file mode 100644 index 000000000000..d718ad687829 --- /dev/null +++ b/content/en/contact/contributor/dubbo-extension-guide_dev.md @@ -0,0 +1,53 @@ +--- +aliases: + - /zh/contact/contributor/dubbo-extension-guide_dev/ +description: 扩展 Dubbo 向导 +linkTitle: 扩展 Dubbo +title: 扩展 Dubbo 向导 +type: docs +weight: 5 +--- + + + + +Dubbo 使用微内核+插件的设计模式。内核只负责组装插件,Dubbo 的功能都是由扩展点(插件)实现,这就意味着 Dubbo 的所有功能都可以被用户定制的扩展所替代。 + +### Dubbo 生态系统 + +我们建议您将扩展加入到 Dubbo 生态系统。使用这种模式,可以使 Dubbo 的核心仓库更干净,并且可以减少维护工作。更少的代码也可以提高核心仓库的构建速度。 + +### 依赖 + +要实现您自己的 Dubbo 扩展,通常只需依赖 API jar 就可以满足您的需求。例如: + +```xml + + org.apache.dubbo + dubbo-serialization-api + ${dubbo.version} + +``` + +### Src指导 + +通常,要实现特殊的扩展,只需要参考[开发者指南](../new-contributor-guide_dev),实现Dubbo必要的接口和合适的扩展即可。除此之外,还有一些其它的事项需要注意: + +1. 良好的测试,您需要编写单元测试和冒烟测试以消除潜在的 bug。 +2. 没有警告,如有不可避免的警告,请使用 @SuppressWarnings 阻止它,但是请不要乱用。 +3. README。添加必要的自述以说明如何使用扩展,以及需要注意的事项。 +4. 许可证:请确保使用Apache License 2.0。 + +### 通知社区 + +1. 提交您的代码到 [github](https://github.com)。 +2. 加入邮件列表(建议)。点击[这里](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide)查看如何加入邮件列表。 +3. 发送一封邮件到 dev@incubator.dubbo.apache.org 通知社区。 +4. 通常,发送邮件之后,社区会对您的扩展进行讨论,dubbo 组的管理员会联系您转移您的项目到 dubbo 生态系统。 + +### 转移项目到dubbo生态系统 + +1. dubbo 组的管理员会请您将您的项目的所有者转让给 dubbo。 +2. dubbo 组的管理员会在 dubbo 组下新建一个项目并邀请您加入到这个项目。 +3. 一旦您接受邀请,您可以将您的项目转移到 dubbo 组下的新项目里。 +4. dubbo 组的成员会对您的项目进行代码审查。随后,您可以对这些代码进行改进。 \ No newline at end of file diff --git a/content/en/docs/contribution-guidelines/contributor/mailing-list-subscription-guide_dev.md b/content/en/contact/contributor/mailing-list-subscription-guide_dev.md similarity index 54% rename from content/en/docs/contribution-guidelines/contributor/mailing-list-subscription-guide_dev.md rename to content/en/contact/contributor/mailing-list-subscription-guide_dev.md index 8dadaa12926e..eb51f1d96cef 100644 --- a/content/en/docs/contribution-guidelines/contributor/mailing-list-subscription-guide_dev.md +++ b/content/en/contact/contributor/mailing-list-subscription-guide_dev.md @@ -1,18 +1,23 @@ --- +aliases: + - /zh/contact/contributor/mailing-list-subscription-guide_dev/ +description: 邮件列表订阅向导 +linkTitle: 邮件组向导 +title: 邮件列表订阅向导 type: docs -title: "Mailing List Subscription Guide" -linkTitle: "Mailing List" weight: 3 --- -The Dubbo developer mailing list (dev@dubbo.apache.org) for Apache Incubator has been established, please feel free to subscribe and refer to [^1] for more details. -You can also view [the archive of the mailing list](https://lists.apache.org/list.html?dev@dubbo.apache.org) -Here is a brief guide specific to Dubbo: +Apache incubator 的 Dubbo 开发者邮件列表(dev@dubbo.apache.org)已经建立,请随时订阅并参考[^1]获取更多细节。 -1. Send an email to dev-subscribe@dubbo.apache.org, you can have empty subject and empty content. You will receive an email with the following content: +你也可以直接查看[历史邮件](https://lists.apache.org/list.html?dev@dubbo.apache.org) + +下面是一个关于 Dubbo 邮件列表订阅的简短指南: + +1. 发一封邮件到 dev-subscribe@dubbo.apache.org,其内容和标题均可为空。随后,您会收到一封邮件,其内容如下: ``` from: dev-help@dubbo.apache.org @@ -47,7 +52,7 @@ or click here: ... ``` -2. Reply the email directly, you can have empty subject and empty content. You will receive an email with the following content: +2. 直接回复邮件,其内容和标题仍然可以为空,随后,您将再次收到一封邮件,其内容如下: ``` from: dev-help@dubbo.apache.org @@ -77,10 +82,10 @@ subscription address. ... ``` -3. After that, you will receive any email that is posted to this mailing list. If you have any further questions, just send email to dev@dubbo.apache.org and hopefully someone will answer your questions. +3. 到此,邮件列表订阅完毕,从现在开始,您将收到很多发送到该邮件列表的邮件,如果您有更多的问题,只需发送邮件到dev@dubbo.apache.org,就会有人回答您的问题。 -4. If you want to unsubscribe, just send an email to dev-unsubscribe@dubbo.apache.org, and follow the steps once you get an reply. +4. 如果您想取消订阅,只需发送一封邮件到dev-unsubscribe@dubbo.apache.org,收到回复后,请按其指定步骤执行。 -> Note that dev@dubbo.apache.org is valid. dev@dubbo.incubator.apache.org is no longer applicable. +> 请注意:dev@dubbo.apache.org是有效的。dev@dubbo.incubator.apache.org已经不再使用。 -[^1] http://apache.org/foundation/mailinglists.html#subscribing +[^1] https://apache.org/foundation/mailinglists.html#subscribing \ No newline at end of file diff --git a/content/en/contact/contributor/new-contributor-guide_dev.md b/content/en/contact/contributor/new-contributor-guide_dev.md new file mode 100644 index 000000000000..fb64f2bfeb70 --- /dev/null +++ b/content/en/contact/contributor/new-contributor-guide_dev.md @@ -0,0 +1,141 @@ +--- +aliases: + - /zh/contact/contributor/new-contributor-guide_dev/ +description: 新贡献者向导 +linkTitle: 新手向导 +title: 新贡献者向导 +type: docs +weight: 2 +--- + + + + +这篇向导旨在给正在准备向 Dubbo 提交贡献的新手提供指导。 + +### 邮件列表描述 + +邮件列表是 Dubbo 官方推荐的讨论方式,所有与 Dubbo 相关的内容都可以在这里讨论,请点击 [Issue](https://github.com/apache/dubbo/issues/1393) 了解更多关于邮件列表订阅的内容 + +如需订阅如下邮件列表,请参考 [邮件列表订阅向导](../mailing-list-subscription-guide_dev) + +* dev@dubbo.apache.org:开发邮件列表,您在使用或者开发 Dubbo 的过程中遇到的任何问题,都可以在这里进行提问。 +* commits@dubbo.apache.org:所有的提交内容都会推送到这个邮件列表,如果您对 Dubbo 的进展感兴趣,可以订阅这个邮件列表。 +* issues@dubbo.apache.org:所有的 [JIRA Issues](https://issues.apache.org/jira/projects/DUBBO/issues) 和修改信息都会推送到这个邮件列表。Dubbo 社区已经决定使用 GitHub Issues 代替 JIRA Issues,因此大部分 Issues 将由 GitHub Issues 进行跟踪。JIRA Issues 用于跟踪 ASF 相关问题。 + +### 报告问题 +* 非安全问题直接在 GitHub Issue 中提出,另请参考 [Issue Template](https://github.com/apache/dubbo/blob/master/.github/ISSUE_TEMPLATE/dubbo-issue-report-template.md) 。 +* 安全问题请参考 [“反馈漏洞”](../reporting-security-issues_dev) 。 + +### 贡献代码流程 +此贡献流程适用于所有的 Apache Dubbo 社区内容,包括但不限于 dubbo(主干仓库)、dubbo-admin、dubbo-website。 + +以下以贡献 dubbo (主干仓库) 为例,详细说明贡献流程。 + +#### 1. **Fork apache/dubbo 项目到您的 GitHub 帐号下** + +#### 2. **克隆您 Fork 的 Dubbo 代码仓库到您本地** +```shell +git clone ${your fork dubbo repo address,for example:https://github.com/${your github id}/dubbo.git} +cd dubbo +``` + +#### 3. **添加 apache/dubbo 仓库为 upstream 仓库** +```shell +git remote add upstream https://github.com/apache/dubbo.git + +git remote -v + + origin ${your fork dubbo repo address} (fetch) + origin ${your fork dubbo repo address} (push) + upstream https://github.com/apache/dubbo.git (fetch) + upstream https://github.com/apache/dubbo.git (push) + +git fetch origin +git fetch upstream +``` +#### 4. **我们的工作以 Issue 为驱动,认领个 Issue,或者创建一个 Issue 并描述清楚要做什么。** +新人推荐标记为: `good first issue` 的 Issue + +#### 5. **选择一个开发的基础分支,通常是 master / 3.0 / 3.1,并基于此创建一个新的本地分支** +* 3.1 分支是 3.1 版本的开发分支 +* 3.0 分支是 3.0 版本的开发分支 +* master 分支是 2.7 版本的开发分支 + +```shell +# 从远程仓库创建分支到本地 +git checkout -b up-dev-issue#${issue-number} upstream/master +``` +为了避免一些不必要的麻烦,我们推荐以 "upstream" 中的分支为基础创建新的本地分支。 +可以以要做的事情的简单描述作为分支名(只要你能看懂就行),通常情况下我们会把 Issue 号包含到分支名中,例如上面的 checkout 命令中的。 + +#### 6. **在本地新建的开发分支上进行各种修改** +首先请保证您阅读并正确设置 Dubbo code style,相关内容请阅读 [编码规范](#编码规范) 。 + +修改时请保证该本地分支上的修改仅和 Issue 相关,并尽量细化,做到一个分支只修改一件事,一个PR只修改一件事。 + +可以在提交注释中添加 "#Issue号",将该提交与 Issue 关联。 + +#### 7. **将您开发完成后的分支,上传到您fork的仓库** +```shell +git push origin up-dev-issue#${issue-number} +``` + +#### 8. **创建 Pull Request** + +* 参考 [Pull Request Template](https://github.com/apache/dubbo/blob/master/PULL_REQUEST_TEMPLATE.md) 中的检查列表 + +Dubbo 社区将会 Review 您的 Pull Request,并可能提出修改意见,您可以根据修改意见回到步骤6进行修改,并使用步骤7进行重新提交。 + +#### 9. **如果没有问题,Dubbo 社区将会把您的修改合并,恭喜您成为 Dubbo 的贡献者。** + +#### 特别说明: +* 开源项目一般都是以分支的方式工作,每件事情都创建一个分支。 +* 创建分支时,不要从本地仓库里的分支里创建,而是从指向主仓库的远程仓库创建。 +* 不要一直在同一个分支工作, 一个分支只做一件事情,不要在同一个分支做多件事情。 +* 一直在同一分支中修改,提交都会一直在该分支中。这样就会造成每次PR都会带着之前的所有被 merge、未被 merge 的提交。 +* 一件事情可以是一个 Issue,也可以是一个 Issue 中的部分 (Issue 太大可以拆解)。 +* 一个分支(一件事情)只提一个PR。 +* 提了 PR 后,如果 PR 有问题需要修改,可以继续在这个 PR 关联的分支修改提交。在 PR 被 merge 前,向这个分支继提交都会进入这个 PR。 +* 如果只是想纯更新代码,可以从主仓库提 PR 到你fork的仓库,源选择主仓库里的分支,目标选你 fork 的仓库的分支。 +* 这种方式更新代码,你 Fork 的仓库中会多一个提交。如果以你 Fork 的仓库中的分支为源创建分支, 这个提交纪录会被带过去并出现在PR中,所以要以主仓库的分支为源创建分支。 +* Issue 认领: 在要认领的 Issue 中回复,明确表式你将处理这个 Issue。这样社区的 PMC 和 Committer 会把该 Issue assign 给你。当然认领前先看下这个 Issue 有没有被别人认领了。 + 为了方便,我们可以把认领的回复统一为: **@i will solve it@**, 当然这不是必须的。 + +#### 编码规范 +请按照 [CONTRIBUTING.md](https://github.com/apache/dubbo/blob/master/CONTRIBUTING.md) 中的编码规范对自己的代码进行检查。 +##### **代码约定** +我们的代码风格几乎和标准 Java 约定一致(流行IDE的默认设置满足这一点),主要有以下附加限制: +* 如果当前行中有超过 120 个字符,则起一个新的行。 +* 确保所有新的 .java 文件都有一个简单的 JavaDoc 类注释,最好至少有一个关于该类的解释说明。 +* 将ASF许可注释添加到所有新的 .java 文件(从项目中的现有文件复制) +* 请确保没有将 @author 标记添加到您所贡献的文件中,因为 Apache 不使用 @author 标记,其他方式(如 CVS、Git)将公平地记录所有您的贡献。 +* 为代码添加一些 JavaDoc,如果您更改命名空间,则需要一些 XSD DOC 元素。 +* 对于新的特征或重要的修复程序,应该添加单元测试。 +* 如果没有其他人使用您的分支,请将它与 master(或主项目中的其他目标分支)同步。 +* 当编写提交消息时,请遵循这些约定,如果您正在修复一个现有问题,请在提交消息的末尾添加 Fixes XXX(其中XXX是问题编号)。 + +##### **代码风格** +我们提供了 IntelliJ idea 的模版文件 dubbo根目录/codestyle/dubbo_codestyle_for_idea.xml,您可以将它导入到IDE。 +如果使用 Eclipse,可以通过参考该文件手动配置。 + +**代码风格检查:** + +1. 安装 checkstyle 插件(IDEA可以在插件市场搜索) +2. 插件安装好后,在IDEA的settings==>tool==>checkstyle中设置: +![checkstyle1](/imgs/dev/checkstyle1.png) +![checkstyle2](/imgs/dev/checkstyle2.png) +![checkstyle3](/imgs/dev/checkstyle3.png) +![checkstyle4](/imgs/dev/checkstyle4.png) + +**注意事项** + +使用 dubbo_codestyle_for_idea.xml 为你的 IDEA 设置代码格式是贡献代码前至关重要的一个步骤,否则你将会无法通过 CI 的代码风格校验,下面几个步骤给你演示了如何配置代码格式: +1. 进入菜单页 Editor > Code Style +2. 在 Code Style 页面的 scheme 菜单中点击 manage profiles 选项 在下拉列表中选择 Import Scheme, 接着选择 IntelliJ IDEA code style XML 导入 xml 文件 +3. 输入你的格式名称,方便在不同工程之间进行识别,最后别忘了 ⏎ 来保存更改. + 设置完成后,IDEA 会帮助你自动 reformat 代码 + +### 参与发布投票 + +参与发布投票是一种重要的贡献社区的方式,Dubbo 社区非常欢迎和鼓励任何人参与投票,每当一个版本需要正式发布的时候,会在开发者邮件列表上进行发布投票,只有当投票取得通过之后,才会正式发布,可以参考这个 [检查列表](https://cwiki.apache.org/confluence/display/INCUBATOR/Incubator+Release+Checklist) 对源码进行合规性检查。如果有任何问题,可以在开发者邮件列表上提问。 \ No newline at end of file diff --git a/content/en/contact/contributor/reporting-security-issues_dev.md b/content/en/contact/contributor/reporting-security-issues_dev.md new file mode 100644 index 000000000000..40505611ee55 --- /dev/null +++ b/content/en/contact/contributor/reporting-security-issues_dev.md @@ -0,0 +1,31 @@ +--- +aliases: + - /zh/contact/contributor/reporting-security-issues_dev/ +description: 报告安全问题 +linkTitle: 反馈漏洞 +title: 报告安全问题 +type: docs +weight: 4 +--- + + + +Apache Software Foundation 在消除其软件项目中的安全性问题方面采取严格的立场。Apache Dubbo 对与其功能和特性有关的问题非常敏感并很快提出。 + +## 报告漏洞 + +如果您对 Dubbo 的安全性有担心,或者发现漏洞或潜在威胁,请发送电子邮件至 security@dubbo.apache.org 与 Apache Dubbo 安全团队联系。在邮件中,指定问题或潜在威胁的描述。还敦促您推荐重现和复制问题的方法。Dubbo 社区会在评估和分析调查结果之后与您联系。 + +请先注意在安全电子邮件中报告安全问题,然后再在公共领域公开该问题。 + + +## 漏洞处理 + +漏洞处理过程的概述是: + +* 报告者将漏洞秘密报告给 Apache。 +* 相应项目的安全团队与报告者私下合作来解决漏洞。 +* 制作了包含该修复程序的有关 Apache 产品的新版本。 +* 该漏洞已公开宣布。 + +有关此过程的详细说明,请参见[此处](https://www.apache.org/security/committers.html) \ No newline at end of file diff --git a/content/en/docs/contribution-guidelines/contributor/software-donation-guide_dev.md b/content/en/contact/contributor/software-donation-guide_dev.md similarity index 80% rename from content/en/docs/contribution-guidelines/contributor/software-donation-guide_dev.md rename to content/en/contact/contributor/software-donation-guide_dev.md index ae49057d9e1f..a177aadc380d 100644 --- a/content/en/docs/contribution-guidelines/contributor/software-donation-guide_dev.md +++ b/content/en/contact/contributor/software-donation-guide_dev.md @@ -1,26 +1,31 @@ --- +aliases: + - /zh/contact/contributor/software-donation-guide_dev/ +description: 软件捐献向导 +linkTitle: 捐献向导 +title: 软件捐献向导 type: docs -title: "Software Donation Guide" -linkTitle: "Donation" weight: 4 --- -Before you go through this guide, make sure you have confirmed with PMC that a SGA is actually needed. -If you are donating significant amount of code or documentation to Apache Dubbo , you will be required to sign a [Software Grant](https://www.apache.org/licenses/#grants) before your code/doc could be merged. -#### Steps +在您阅读这篇指南之前,请确保您已经向PMC确认了实际需要的 SGA。 -1. Download this [pdf](https://www.apache.org/licenses/software-grant-template.pdf) -2. Print it out -3. Fill in the blanks (see below as an example) -4. Request your boss to sign it -5. Scan it -6. Send an email to secretary@apache.org and cc private@dubbo.apache.org +如果您向 Apache Dubbo 捐赠了大量的代码或文档,则需要在合并代码或者文档之前签署[软件授权书](https://www.apache.org/licenses/#grants)。 -#### Example: +### 操作步骤 -Below is an text versioned **example**, original text could be found [here](https://www.apache.org/licenses/software-grant.txt) +1. 下载这篇[pdf文档](https://www.apache.org/licenses/software-grant-template.pdf) +2. 打印下载好的文档 +3. 按要求填充表格(请看下边示例) +4. 请您的领导在上边签字 +5. 扫描 +6. 将扫描好的文档以邮件的方式发送给secretary@apache.org,并抄送给private@dubbo.apache.org + +### 示例 + +下边是一个文本示例,原始文本可以在[这里](https://www.apache.org/licenses/software-grant.txt)找到 ``` License Agreement @@ -108,4 +113,4 @@ List of software and other intellectual property covered by this agreement: * Github address where your code is hosted * Pull request link -``` +``` \ No newline at end of file diff --git a/content/en/contact/contributor/test-coverage-guide_dev.md b/content/en/contact/contributor/test-coverage-guide_dev.md new file mode 100644 index 000000000000..4e90f9e390a4 --- /dev/null +++ b/content/en/contact/contributor/test-coverage-guide_dev.md @@ -0,0 +1,26 @@ +--- +aliases: + - /zh/contact/contributor/test-coverage-guide_dev/ +description: 测试覆盖率向导 +linkTitle: 测试覆盖率向导 +title: 测试覆盖率向导 +type: docs +weight: 7 +--- + + + +### 写单元测试的收益 +* 单元测试能帮助每个人深入代码细节,了解代码的功能。 +* 通过测试用例我们能发现bug,并提交代码的健壮性。 +* 测试用例同时也是代码的demo用法。 +### 单元测试用例的一些设计原则 +* 应该精心设计好步骤,颗粒度和组合条件。 +* 注意边界条件。 +* 单元测试也应该好好设计,不要写无用的代码。 +* 当你发现一个`方法`很难写单元测试时,如果可以确认这个`方法`是`臭代码`,那么就和开发者一起重构它。 +* Dubbo中用的mock框架是: [mockito](http://site.mockito.org/). 下面是一些开发向导:[mockito tutorial](https://www.baeldung.com/bdd-mockito),[mockito refcard](https://dzone.com/refcardz/mockito) +* TDD(可选):当你开始写一个新的功能时,你可以试着先写测试用例。 +### 测试覆盖率设定值 +* 在现阶段,Delta更改代码的测试覆盖设定值为:>=60%,越高越好。 +* 我们可以在这个页面中看到测试报告: https://codecov.io/gh/apache/dubbo \ No newline at end of file diff --git a/content/en/contribution-guidelines/_index.md b/content/en/contribution-guidelines/_index.md new file mode 100644 index 000000000000..4ba866133bd6 --- /dev/null +++ b/content/en/contribution-guidelines/_index.md @@ -0,0 +1,8 @@ +--- +_build: + render: link +description: Dubbo 贡献指南 +linkTitle: 贡献指南 +title: 为 Dubbo 做贡献 +type: docs +--- diff --git a/content/en/docs/_index.md b/content/en/docs/_index.md deleted file mode 100755 index 703cca0682dc..000000000000 --- a/content/en/docs/_index.md +++ /dev/null @@ -1,10 +0,0 @@ - ---- -title: "Documentation" -linkTitle: "Documentation" -weight: 20 ---- - -Welcome to the Dubbo documentation site! - - diff --git a/content/en/docs/contribution-guidelines/_index.md b/content/en/docs/contribution-guidelines/_index.md deleted file mode 100755 index 0c556af9a0f8..000000000000 --- a/content/en/docs/contribution-guidelines/_index.md +++ /dev/null @@ -1,87 +0,0 @@ - ---- -type: docs -title: "Contribution Guideline" -linkTitle: "Contribution Guideline" -description: "Guidelines for contributing to Dubbo" -weight: 90 ---- - - -Dubbo is released under the non-restrictive Apache 2.0 license, and follows a very standard Github development process, using Github tracker for issues and merging pull requests into master. If you want to contribute even something trivial please do not hesitate, but follow the guidelines below. - -### Contact - -#### Mailing list - -The mailing list is the recommended way for discussing almost anything that related to Dubbo. Please refer to this [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide) for detailed documentation on how to subscribe. - -- [dev@dubbo.apache.org](mailto:dev-subscribe@dubbo.apache.org): the develop mailing list, you can ask question here if you have encountered any problem when using or developing Dubbo. -- [commits@dubbo.apache.org](mailto:commits-subscribe@dubbo.apache.org): all the commits will be sent to this mailing list. You can subscribe to it if you are interested in Dubbo's development. -- [notification@dubbo.apache.org](mailto:notification-subscribe@dubbo.apache.org): all the Github [issue](https://github.com/apache/dubbo/issues) updates and [pull request](https://github.com/apache/dubbo/pulls) updates will be sent to this mailing list. - -### Reporting issue - -Please follow the [template](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md) for reporting any issues. - -### Code Conventions -Our code style is almost in line with the standard java conventions (Popular IDE's default setting satisfy this), with the following additional restricts: -* If there are more than 120 characters in current line, start a new line. - -* Make sure all new .java files to have a simple Javadoc class comment with at least a @date tag identifying birth, and preferably at least a paragraph on what the class is for. - -* Add the ASF license header comment to all new .java files (copy from existing files in the project) - -* Make sure no @author tag added to the file you contribute since @author tag is not used at Apache, other ways such as cvs will record all your contributions fairly. - -* Add some Javadocs and, if you change the namespace, some XSD doc elements. - -* A few unit tests should be added for a new feature or an important bugfix. - -* If no-one else is using your branch, please rebase it against the current master (or other target branch in the main project). - -* When writing a commit message please follow these conventions, if you are fixing an existing issue please add Fixes #XXX at the end of the commit message (where XXX is the issue number). - -### Contribution flow - -This is a rough outline of what a contributor's workflow looks like: - -* Fork the current repository -* Create a topic branch from where to base the contribution. This is usually master. -* Make commits of logical units. -* Make sure commit messages are in the proper format (see below). -* Push changes in a topic branch to your forked repository. -* Follow the checklist in the [pull request template](https://github.com/apache/dubbo/blob/master/PULL_REQUEST_TEMPLATE.md) -* Before you sending out the pull request, please sync your forked repository with remote repository, this will make your pull request simple and clear. See guide below: - - ```bash - git remote add upstream git@github.com:apache/dubbo.git - git fetch upstream - git rebase upstream/master - git checkout -b your_awesome_patch - ... add some work - git push origin your_awesome_patch - ``` -* Submit a pull request to apache/dubbo and wait for the reply. -* All pull requests are automatically tested on [GitHub Actions](https://github.com/apache/dubbo/actions) for AMD64 CPU architecture. Please check that all builds are successful! Additionally there are nightly tests set up at [TravisCI](https://travis-ci.com/github/apache/dubbo) to prevent any regressions on ARM64 CPU architecture. - -Thanks for contributing! - -### Code style - -We provide a template file [dubbo_codestyle_for_idea.xml](https://github.com/apache/dubbo/tree/master/codestyle/dubbo_codestyle_for_idea.xml) for IntelliJ idea, you can import it to you IDE. -If you use Eclipse you can config manually by referencing the same file. - -{{% alert title="Notice" color="primary" %}} -It is very important to set the dubbo_codestyle_for_idea.xml, otherwise you will fail to pass the Travis CI. Steps to set the code style are as below: - -1. Enter `Editor > Code Style` -2. To manage a code style scheme, in the Code Style page, select the desired scheme from the drop-down list, and click "manage profiles" -From the drop-down list, select `Import Scheme`, then select this option `IntelliJ IDEA code style XML` to import scheme -3. In the Scheme field, type the name of the new scheme and press ⏎ to save the changes. -{{% /alert %}} - - - - - diff --git a/content/en/docs/contribution-guidelines/committer/_index.md b/content/en/docs/contribution-guidelines/committer/_index.md deleted file mode 100755 index cfdfdad0ffc9..000000000000 --- a/content/en/docs/contribution-guidelines/committer/_index.md +++ /dev/null @@ -1,11 +0,0 @@ - ---- -type: docs -title: "Committer Guide" -linkTitle: "Committer" -description: "Guidelines for dubbo committer" -weight: 2 ---- - - - diff --git a/content/en/docs/contribution-guidelines/committer/apache-dubbo-page_dev.md b/content/en/docs/contribution-guidelines/committer/apache-dubbo-page_dev.md deleted file mode 100644 index 46c74c981c5c..000000000000 --- a/content/en/docs/contribution-guidelines/committer/apache-dubbo-page_dev.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -type: docs -title: "Apache Official Dubbo Page Maintenance" -linkTitle: "Official Page" -weight: 5 ---- - -Apache has an official website that maintains information about all incubation projects. -Each incubation project has an information page under this website. -Dubbo's information page address is https://incubator.apache.org/projects/dubbo.html. - -When the project has undergone major changes, such as the addition of a new committer, -the election of a new PMC, or a new version of Release, etc, these updates need to be maintained on this page. -The project address for this official website is -https://svn.apache.org/repos/asf/incubator/public/trunk. - -Here's how to maintain this page: - -1. Install the SVN. If it is a Mac OS X system or a Linux system, it comes with SVN. If it is a Windows system, -please install SVN first. -2. Check out the [project](https://svn.apache.org/repos/asf/incubator/public/trunk) with SVN. -3. Modify the content/projects/dubbo.xml file and save it. -4. Install ANT. And execute the ant command in the trunk directory to build. -5. After the build is complete, open the target/site/projects/dubbo.html file with your browser to see if the changes take effect. -6. Use the commit command of SVN to submit the dubbo.xml file to the server, and do not submit the dubbo.html file -(because the server will automatically build it at regular intervals). -This process will ask for the Apache id and password. - -References: - -1. http://incubator.apache.org/guides/website.html -2. https://svn.apache.org/repos/asf/incubator/public/trunk/README.txt diff --git a/content/en/docs/contribution-guidelines/committer/label-an-issue-guide_dev.md b/content/en/docs/contribution-guidelines/committer/label-an-issue-guide_dev.md deleted file mode 100644 index 7ec61a7e115f..000000000000 --- a/content/en/docs/contribution-guidelines/committer/label-an-issue-guide_dev.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -type: docs -title: "Label an Issue" -linkTitle: "Issue Guide" -weight: 3 ---- - - -If you are handling an issue, remember to **mark the issue cearly with one or more labels** whenever you think it's meaningful. With labels on, other developers can easily recognize problems, classify them or track progress. - -For issues or pull requests that need coding and further version release to fix, you should always **mark it with a [milestone](https://github.com/apache/dubbo/milestones)**. - -Some frequently used labels: - -* Help Wanted - * help wanted - * good first issue - -* Prority - * priority/blocker - * priority/high - * priority/low - * priority/normal - -* Status - * status/need-triage - * status/DO-NOT-MERGE - * status/READY-TO-MERGE - * status/invalid - * status/wontfix - -* Type - * type/bug - * type/documentation - * type/enhancement - * type/feature diff --git a/content/en/docs/contribution-guidelines/committer/new-committer-guide_dev.md b/content/en/docs/contribution-guidelines/committer/new-committer-guide_dev.md deleted file mode 100644 index 0117075a40fc..000000000000 --- a/content/en/docs/contribution-guidelines/committer/new-committer-guide_dev.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -type: docs -title: "Apache Committer Guide" -linkTitle: "Committer Guide" -weight: 1 ---- - -## First: How to become a committer - -### Initial committers at the project incubator stage -At the project incubator stage, there will be an initial committers list in the proposal of the incubator project. Confirm that you are one of the initial committers. After the vote is passed in the Apache incubator community, these committers can start preparing their account. See [incubator wiki](https://wiki.apache.org/incubator/) for details. - -### The active contributor is elected as a committer -At the late development stage, an active contributor can be elected as a committer. See [how to become a committer](https://www.apache.org/dev/new-committers-guide.html#becoming-a-committer) - -## Second: The individual contributor signs ICLA - -### 1, Apache ID -Choose a Apache ID not in the [apache committers list page](http://people.apache.org/committer-index.html). - -### 2, Individual Contributor License Agreement (ICLA): -Download the [ICLA template](https://www.apache.org/licenses/icla.pdf). After filling the icla.pdf with personal information correctly, print, sign, scan, and send it in mail as an attachment to the secretary secretary@apache.org, the secretary will help to create the Apache user ID. At the same time, a your-id@apache.org mailbox will be created. You can see if the user has been created on the [apache committers list page (http://people.apache.org/committer-index.html). - -## Third: Join The Apache Developer Group - -* 1, login via the [Apache account tool](https://id.apache.org/), when you login at the first time, you can select the "Change password?" checkbox to get the initial password. Then the initial password will be sent to the forward mailbox (the developer mail recorded in the project incubator proposal) - -* 2, about Apache mailbox: does not have its own mail content storage server. It needs to borrow the mail content storage and mail sending functions of other mail providers. In many voting sessions, Apache mailbox is recommended. - -There is a question about how to configure the apache.org mailbox forwarding function using other mailboxes. - -1) inbox: to receive mails that sent to youer-id@apache.org mailbox. The forward mailbox configured in the Apache account tool in the first step can use the forward mailbox to pick up incoming mail. - -2) the Outbox: emails sent out will show the sender as your-id@apache.org account. Please refer to: [set up Apache mailbox guide](https://reference.apache.org/committer/email) and [Gmail mailbox setting](http://gmailblog.blogspot.com/2009/07/send-mail-from-another-address-without.html). In other mailbox service settings, this forwarding mode is not easy to find. Gmail is the most convenient, which is recommended (no advertising). - -* 3, Modify the homepage URL option in the edit page, homepage link of your account can be added in [apache committer index page](http://people.apache.org/committer-index.html) - -* 4, Modify the GitHub account in the edit page, and an email will be sent to invite you to join the github.com/apache-commiiters group. Now, please learn from the way [ASF works](http://www.apache.org/foundation/how-it-works.html#developers) to do some basic preparation of ASF development. - -## Fourth: To obtain write permission of the project - -Operation of the [GitBox account link tool](https://gitbox.apache.org/setup/) - -### 1, Apache account authorization - -According to the prompt, the OAuth protocol of Apache account is authorized to login. - -### 2, Github account authorization - -According to the prompt, the OAuth protocol of Github account is authorized to login. - -### 3, Set up GitHub account in github.com, two-factors authorization (2FA) - -* 1) install "Google Authenticator" app on your cell phone -* 2), Following the [authorized GitHub 2FA wiki](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication), you can operation step by step . - -In the [two-factors authorization authentication (2. Scan this barcode with your app.)](https://github.com/settings/security) page, it is not recommended to select a two-dimensional code with a cell phone, because some of the cell phones will not be able to scan. - -Please open the cell phone "Google Authenticator" app, click "+" to select "input the secret key": write the GitHub account in the account name input box. In your "secret key" input box, write the text of the "enter this text code" link in the open web page. After clicking "add" in app, 6 digit dynamic will be generated for this account. Write the 6 digit number to the text box in the web page, and then click "Enable". In this way, the 2fa is set successfully. - -* 3), logout and login to Github again, and one more step will appear after entering user name and password. Fill in the 6 digit number dynamic password generated by the app - -* 4),It will take about half an hour, and you will be notified by mail that you have joined the XX project-committers developer group. You can also check it in the [apache teams] (https://github.com/orgs/apache/teams) page yourself. - -* 5), After the 2fa has been submitted, you will have the permission check problem for the cloned projects. The solution is one of below two: - -* A. Apply for Access Token - -When access token is generated on GitHub, the token where the instruction line needs a password is pasted. - -Refer to website [referenced link one](https://docs.github.com/en/repositories/creating-and-managing-repositories/troubleshooting-cloning-errors) and [referenced link two](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) - -* B. switch to SSH - -ssh-keygen then paste the content in the pub file into GitHub. - -**Note**: ensure that GitHub's 2fa is "enabled". When you set 2fa to "off", it will be delisted by the corresponding Apache committer write permission group until you set it up again. - -## Fifth: other - -### The Apache way - -See [wiki](http://apache.org/foundation/governance/). - -The community is more important than the code -If not discussed in the community (mailing list), just as it did not happen. - -### Add your name - -Please update Dubbo incubator status [page](https://incubator.apache.org/projects/dubbo.html) to add your name. See this [guide](/en/latest/contribution-guidelines/contributor/) for instructions. - -Please update Dubbo official [website](/en/latest/contribution-guidelines/committer) to update your name. - - -### A small benefit - -Jetbrains company gives Apache committers a small benefit, which is free to use IDEA's full series products. The specific address is: https://www.jetbrains.com/shop/eform/apache?Product=ALL - -### Reference wiki -https://www.apache.org/dev/new-committers-guide.html diff --git a/content/en/docs/contribution-guidelines/committer/release-guide_dev.md b/content/en/docs/contribution-guidelines/committer/release-guide_dev.md deleted file mode 100644 index e766c510d5e9..000000000000 --- a/content/en/docs/contribution-guidelines/committer/release-guide_dev.md +++ /dev/null @@ -1,504 +0,0 @@ ---- -type: docs -title: "Release Guide" -linkTitle: "Release Guide" -weight: 2 ---- - -## Understanding the Apache Release Cycle - -In general, Source Release is the key and the required content of Apache. But Binary Release is optional, Dubbo can choose whether to release binary packages to the Apache repository or to the Maven central repository. - -Please refer to the following links for more information on ASF's release guide: - -- [Apache Release Guide](http://www.apache.org/dev/release-publishing) -- [Apache Release Policy](http://www.apache.org/dev/release.html) -- [Maven Release Info](http://www.apache.org/dev/publishing-maven-artifacts.html) - -## Preparation of Local Building Environment - -Mainly including the related preparation of signature utilities and Maven repository certification - -1. Install GPG,refer to https://www.gnupg.org/download/index.html - - - For example, in Mac OS - - ```sh - $ brew install gpg - $ gpg --version #check version,should be 2.x - ``` - -2. Generate the key with GPG - - - Generate the key according to the prompt - - ```shell - $ gpg2 --full-gen-key - gpg (GnuPG) 2.0.12; Copyright (C) 2009 Free Software Foundation, Inc. - This is free software: you are free to change and redistribute it. - There is NO WARRANTY, to the extent permitted by law. - - Please select what kind of key you want: - (1) RSA and RSA (default) - (2) DSA and Elgamal - (3) DSA (sign only) - (4) RSA (sign only) - Your selection? 1 - RSA keys may be between 1024 and 4096 bits long. - What keysize do you want? (2048) 4096 - Requested keysize is 4096 bits - Please specify how long the key should be valid. - 0 = key does not expire - = key expires in n days - w = key expires in n weeks - m = key expires in n months - y = key expires in n years - Key is valid for? (0) - Key does not expire at all - Is this correct? (y/N) y - - GnuPG needs to construct a user ID to identify your key. - - Real name: Robert Burrell Donkin - Email address: rdonkin@apache.org - Comment: CODE SIGNING KEY - You selected this USER-ID: - "Robert Burrell Donkin (CODE SIGNING KEY) " - - Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O - You need a Passphrase to protect your secret key. # enter the password, which will be used frequently when packaging. - ``` - - - View key id - - ```sh - $ gpg --list-keys - pub rsa4096/28681CB1 2018-04-26 # 28681CB1 is the key id - uid [ultimate] liujun (apache-dubbo) - sub rsa4096/D3D6984B 2018-04-26 - - ########### Note: Different diaplay for different version. - $ gpg --list-keys - pub rsa4096 2018-11-12 [SC] - 63AAE9838F4A303E40BAF5FEA3A1CA7A5D4A3981 # Last 8 character(5D4A3981) as key id,it will be used when send public key to keyserver - uid [ 绝对 ] Victory Cao (CODE SIGNING KEY) - sub rsa4096 2018-11-12 [E] - - - # send public key to keyserver via key id - $ gpg --keyserver pgpkeys.mit.edu --send-key 28681CB1 - # Here pgpkeys.mit.edu is a random selection of keyserver. Any key server from the list https://sks-keyservers.net/status/ is acceptable because they are automatically synchronized. - ``` - - - If there are multiple public keys,you can set the default key - - ~/.gnupg/gpg.conf - - ```proper - # If you have more than 1 secret key in your keyring, you may want to - # uncomment the following option and set your preferred keyid. - - default-key 28681CB1 - ``` - - - If there are multiple public keys, you can also delete unuseful key: - - ```sh - ### Delete the private key first, then delete the public key. - - $ gpg --yes --delete-secret-keys shenglicao2@gmail.com ### indicate email address - - $ gpg --delete-keys 1808C6444C781C0AEA0AAD4C4D6A8007D20DB8A4 - - ``` - - - config your fingerprint. - ```sh - ### Show fingerprint info: - $ gpg --fingerprint liujun - pub rsa4096 2019-10-17 [SC] - 1376 A2FF 67E4 C477 5739 09BD 7DB6 8550 D366 E4C0 - uid [ultimate] liujun (CODE SIGNING KEY) - sub rsa4096 2019-10-17 [E] - ``` - Save the fingerprint, as above `1376 A2FF 67E4 C477 5739 09BD 7DB6 8550 D366 E4C0`, - to the field `OpenPGP Public Key Primary Fingerprint` in you profile page at https://id.apache.org. - -3. Set up Apache central repository. - - - The parent pom of Dubbo project is apache pom - - ```xml - - org.apache - apache - 19 - - ``` - - - Add the following contents to .m2/settings.xml - - Enter the passwords after - encrypting by [maven-encryption-plugin](http://maven.apache.org/guides/mini/guide-encryption.html) - - ```xml - - ... - - - - apache.snapshots.https - - - - - - apache.releases.https - - - - ... - - - gpg.passphrase - - - - - ``` - - -## Pack & Upload - -1. Pull the new branch from the master branch as the release branch. If you want to release the ${release_version} version now, pull the new branch ${release_version}-release from 2.6.x. Then the -modifications and taggings related to ${release_version} Release Candidates are applied to ${release_version}-release branch, and is merged into the master branch after the final release. - -2. First of all, verify that the maven component packing, source packing, signature, etc are working properly on the ${release_version}-release branch. - - ```shell - $ mvn clean install -Papache-release - $ mvn deploy - ``` - - This push the snapshot package to the maven central repository. - -3. ~~Release with maven-release-plugin~~ (`Deprecated`,Skip this step and refer to next step) - - - ~~verify with dryRun~~ - - ```shell - $ mvn release:prepare -Prelease -Darguments="-Dmaven.test.skip=true" -DautoVersionSubmodules=true -Dusername=YOUR GITHUB ID -DdryRun=true - ``` - - - ~~After verification, run release:prepare~~ - - ```shell - $ mvn release:clean - $ mvn release:prepare -Prelease -Darguments="-Dmaven.test.skip=true" -DautoVersionSubmodules=true -Dusername=YOUR GITHUB ID -DpushChanges=false - ``` - - > If you are promted to input password for pushing to GitHub (basically including adding new commits and tags), do not input your login password of GitHub. Use `Personal access tokens` instead. You can go to https://github.com/settings/profile, click `Developer settings` -> `Personal access tokens`, and generate a new token if not. Please refer to this [guide](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) for more infomation. - > you need to choose the release artifactId, next artifactId and the release tag, the default tag is dubbo-parent-xxxx, you need to change it to dubbo-xxxx - - - After executing the above commands, you will find that: - 1. source-release.zip and bin-release.zip are generated under dubbo-distribution directory, please unzip it and check the file structure - 2. `-DpushChanges=false` tells maven not to push the commits and tags to the remote repostiroy. If not specified, the version tag will be pushed to github repository, you will see a commit called `[maven-release-plugin] prepare release dubbo-x.x.x` added. - 3. The branch version is upgraded to ${release_version+1}-SNAPSHOT automatically. If `-DpushChanges=true` is specified, the modifications will be pushed to the remote repository, you will see a commit called `[maven-release-plugin] prepare for next development iteration` added. - - If `-DpushChanges=false` is specified, you will have to manually push the commit to remote repository before go to next step. - - - ~~Run release:perform~~ - - ```shell - $ mvn release:perform -Prelease -Darguments="-Dmaven.test.skip=true" -DautoVersionSubmodules=true -Dusername=YOUR GITHUB ID - ``` - - Maven will download the source code from the tag you just pushed, compile it, and deploy to remote maven repsoitry in staging state. - -### use `mvn deploy` to deploy - -> Requirement:maven 3.5+ - -modify pom version from 2.7.x-SNAPSHOT to 2.7.x . You can search the full-text in the dubbo project. - -```shell -$ mvn clean install -Prelease -$ mvn deploy -Prelease -DskipTests -``` - -After this, maven will deploy jar to remote maven repsoitry in staging state. - -### Note - -> When you deploy the package into repository, it will be interrupted for network. So you must restart to desploy. -> The problem is that missing package occurred many times at deploying. So you should check the quantity of package, especially parent package. - -## Prepare Apache Release - -1. Prepare the svn local environment (Apache hosting the release content of project by svn) - -2. Checkout dubbo to local directory - - ```shell - $ svn checkout https://dist.apache.org/repos/dist/dev/dubbo - ``` - Assume that the local directory is `~/apache/dubbo` - -3. The current release version is ${release_version}, new directory - - ```shell - $ cd ~/apache/dubbo # dubbo svn root directory - $ mkdir ${release_version} - ``` - -4. Add public key to [KEYS](https://dist.apache.org/repos/dist/dev/dubbo/KEYS) file if you are the first time to be a release manager. KEYS is mainly used to allow people who participate in the voting to be imported locally to verify the correctness of the sign. - - ```shell - $ (gpg --list-sigs && gpg --armor --export ) >> KEYS - ``` - - For more information on how to get your key id, please refer to this [guide](https://docs.github.com/en/authentication/managing-commit-signature-verification/generating-a-new-gpg-key) - -5. Copy the source.zip package from the Dubbo root directory to the svn local repository dubbo/${release_version} - -6. Generate sha512 sign - - For source-release.zip - - ```shell - $ shasum -a 512 apache-dubbo-${release_version}-source-release.zip >> apache-dubbo-${release_version}-source-release.zip.sha512 - ``` - - For bin-release.zip - - Please add `-b` paramter when generating sha512 for bin-release.zip, which indicates it is a binary file. - - ```shell - $ shasum -b -a 512 apache-dubbo-${release_version}-bin-release.zip >> apache-dubbo-${release_version}-bin-release.zip.sha512 - ``` - You should generate something like this: - - ``` - b8f13d1df6d6c9a1facc72fafc00b2d22bea1e600517c507467d8fca2f776a7a3877101742da53114bfa629ca5b941eb4d9ef989de43f0833e2a794e7ccf5c8a *apache-dubbo-spring-boot-project-2.7.0-bin-release.zip - ``` - - Note there is a `*` sign before the file name. - -7. If the binary release is accompanied with the source release. Run the following command in the dubbo-distribution module: - - ```shell - $ mvn install - ``` - Go to target directory, copy bin-release.zip and bin-release.zip.asc to svn local repository dubbo/${release_version}, and refer to step 6 to generate sha512 sign. - -8. Commit to Apache svn - - ```shell - $ svn status - $ svn commit -m 'prepare for ${release_version} RC1' - ``` - -9. Close the maven staging repository - - This step is required when prepare for a 2.7.0+ release, where package name has been changed to org.apache. Before that, please make sure all the maven artifacts look good. Login to http://repository.apache.org, click the `Staging repositories` on the left bar, search with keyword Dubbo, and you will see a list of repositories. Find the one you just uploaded, and then click the close button in the top area. This will do some sannity check, such as gpg signature check, and checksum check. After that, a link will be shown in the summary tab in the bottom. Please copy that link, it will be used for release vote. The link should look like this: `https://repository.apache.org/content/repositories/orgapachedubbo-1015`. - - > Please be aware that it may fail when you close the repository, this is normally due to network issues, please try again if it failed. You can confirm it by clicking the `Activiey` tab next to `Summary`. - -## Verify Release Candidates - -**A full check list can be found [here](https://cwiki.apache.org/confluence/display/INCUBATOR/Incubator+Release+Checklist)** - -The verification link includes but is not limited to the following contents and forms: - -### Check signatures and hashes are good - -#### check the sha512 sum - - -```sh -$ shasum -c apache-dubbo-${release_version}-source-release.zip.sha512 -$ shasum -c apache-dubbo-${release_version}-bin-release.zip.sha512 -``` -#### check the gpg signarure - -If it's your first time verify a release candidte, you should import public keys first. - -```sh - $ curl https://dist.apache.org/repos/dist/dev/dubbo/KEYS >> KEYS # download public keys to local directory - $ gpg --import KEYS # import keys - $ gpg -—edit-key liujun - > trust # type trust command - ``` -Now, you can verify signature with command - - ```sh -gpg --verify apache-dubbo-2.6.3-source-release.zip.asc apache-dubbo-2.6.3-source-release.zip -gpg --verify apache-dubbo-2.6.3-bin-release.zip.asc apache-dubbo-2.6.3-bin-release.zip - ``` - -### Check source release file content - -Unzip apache-dubbo-${release_version}-source-release.zip to the default directory and check the following: - -- DISCLAIMER exists -- LICENSE and NOTICE exists and contents are good -- All files and no binary files exist -- All files has standard ASF License header -- Can compile from source -- All unit tests can pass - ```sh - mvn clean test # This will run all unit tests - # you can also open rat and style plugin to check if every file meets requirements. - mvn clean test -Drat.skip=false -Dcheckstyle.skip=false - ``` -- Release candidates match with corresponding tags, you can find tag link and hash in vote email. - - check the version number in pom.xml are the same - - check there are no extra files or directories in the source package, for example, no empty directories or useless log files. - `diff -r rc_dir tag_dir` - - check the top n tag commits, dive into the related files and check if the source package has the same changes - - -### check third party dependencies - -According to ASF policy, any [Category X](https://www.apache.org/legal/resolved.html#what-can-we-not-include-in-an-asf-project-category-x) dependency can not be included in ASF product, this includes common LGPL/GPL licensed dependencies. Even transitive dependencies are not allowed. Therefore we need to run the following command to ensure no such dependencies are included. - -```sh -mvn license:add-third-party -Dlicense.useMissingFile -find . -name THIRD-PARTY.txt | xargs grep -E 'GPL|General Public License' | grep -v Apache | grep -v MIT | grep -v CDDL -``` - -If one dependency is dual/multiple licensed, just choose the most permissive one. - -You can refer to this article : [ASF 3RD PARTY LICENSE POLICY](https://apache.org/legal/resolved.html) - -### Check binary distribution file content - -Unzip apache-dubbo-${release_version}-bin-release.zip and check: - -* Check signatures are good -* LICENSE and NOTICE exists and contents are good - -Note that if the binary distribution contains third party files, you may need to update LICENSE file by adding the 3rd party license files. If these dependency is Apache License 2.0, and it contains NOTICE file, you may also need to update NOTICE file as well. - -## Release vote - -The voting just only one round: - -Dubbo community votes and sends the voting email to dev@dubbo.apache.org. After reviewing by community developers and winning 3 binding tickets that agree to release, you can go to the next stage of voting. - -The mail template for Apache Dubbo vote: - -```tex -Hello Dubbo Community, - -This is a call for vote to release Apache Dubbo version 2.7.2. - -The release candidates: -https://dist.apache.org/repos/dist/dev/dubbo/2.7.2/ - -The staging repo: -https://repository.apache.org/content/repositories/orgapachedubbo-1005 - -Git tag for the release: -https://github.com/apache/dubbo/tree/dubbo-2.6.2 - -Hash for the release tag: -afab04c53edab38d52275d2a198ea1aff7a4f41e - -Release Notes: -https://github.com/apache/dubbo/releases/tag/untagged-4775c0a22c60fca55118 - -The artifacts have been signed with Key : 28681CB1, which can be found in the keys file: -https://dist.apache.org/repos/dist/dev/dubbo/KEYS - -The vote will be open for at least 72 hours or until necessary number of votes are reached. - -Please vote accordingly: - -[ ] +1 approve -[ ] +0 no opinion -[ ] -1 disapprove with the reason - -Thanks, -The Apache Dubbo Team -``` - - - -The mail template to announce the vote result: - -```text -We’ve received 3 +1 binding votes and one +1 non-binding vote: - -+1 binding, Ian Luo -+1 binding, Huxing Zhang -+1 binding, Jun Liu - -+1 non-binding, Jerrick - -I will release this version today. - -Best regards, -The Apache Dubbo Team -``` - -## Official Release - -When the release vote has passed, - - -1. Add the release files to [official release directory](https://dist.apache.org/repos/dist/release/dubbo) -2. Remove the release files in [dev directory](https://dist.apache.org/repos/dist/dev/dubbo) -3. Remove the the release file for the previous release under [official release directory](https://dist.apache.org/repos/dist/release/dubbo/), which will be archived and can be found [here](https://archive.apache.org/dist/dubbo/) -5. Publish [release notes](https://github.com/apache/dubbo/releases) on Github. -6. Update the recommend dependency on [Github](https://github.com/apache/dubbo#maven-dependency) to the latest version, also update the version in other place if necessary. -7. Add the download link to official website https://dubbo.apache.org/en/blog/2020/05/18/past-releases/, using the ASF mirror system. The latest release download link should be something like [this](https://www.apache.org/dyn/closer.cgi?path=dubbo/$VERSION/apache-dubbo-$VERSION-source-release.zip). The download link for the previous release version should be changed like `https://archive.apache.org/dist/dubbo/$VERSION/apache-dubbo-$VERSION-bin-release.zip`. Please refer to the [download page](/en/blog/2020/05/18/past-releases/) for more details. -8. Make sure all the commits in the release branch are merged into master branch, and then remove the remote release branch. For example: `git push origin --delete 2.7.0-release` -9. Send mail to dev@dubbo.apache.org , notify the community that the release is completed. -The mail template to announce release: -```text -Hello Community, - -The Apache Dubbo team is pleased to announce that the -2.6.6 has just been released. - -Apache Dubbo™ is a high-performance, java based, open source -RPC framework. Dubbo offers three key functionalities, which include -interface based remote call, fault tolerance & load balancing, and -automatic service registration & discovery. - -Both the source release[1] and the maven binary release[2] are available -now, you can also find the detailed release notes here[3]. - - -If you have any usage questions, or have problems when upgrading or find -any problems about enhancements included in this release, please don’t -hesitate to let us know by sending feedback to this mailing list or filing -an issue on GitHub[4]. - - - -[1] https://dubbo.apache.org/en/blog/2020/05/18/past-releases/ -[2] https://repo1.maven.org/maven2/org/apache/dubbo/dubbo -[3] https://github.com/apache/dubbo/releases -[4] https://github.com/apache/dubbo/issues - -``` - - -## Complete Maven Convenient Binary release - -**[repository.apache.org](https://repository.apache.org/) The permissions of the nexus repository have been applied, see [jira](https://issues.apache.org/jira/browse/INFRA-16451)。** - -To release the maven artifacts, go to [repository.apache.org](https://repository.apache.org), and choose the staging repository, click the release button. Wait for a moment and verify it at [here](https://repository.apache.org/content/repositories/releases/org/apache/dubbo/), make sure your artifacts are there and correct. It will take some time to sync to maven central repository. You can verify it at [here](https://repo.maven.apache.org/maven2/org/apache/dubbo) - -## FAQ - -#### gpg: signing failed: Inappropriate ioctl for device - -If you've encountered this error, try the following commands: - -``` -export GPG_TTY=$(tty) -``` diff --git a/content/en/docs/contribution-guidelines/committer/website-guide_dev.md b/content/en/docs/contribution-guidelines/committer/website-guide_dev.md deleted file mode 100644 index 6b762932d59b..000000000000 --- a/content/en/docs/contribution-guidelines/committer/website-guide_dev.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -type: docs -title: "Website Guide" -linkTitle: "Website Guide" -weight: 3 ---- - -1. The website repository of Apache Dubbo is https://github.com/apache/dubbo-website -2. After building the website, it'll be published to dubbo.apache.org automatically, you can also trigger it manually via https://selfserve.apache.org (need to login with Apache account) diff --git a/content/en/docs/contribution-guidelines/contributor/_index.md b/content/en/docs/contribution-guidelines/contributor/_index.md deleted file mode 100755 index 3e619901d767..000000000000 --- a/content/en/docs/contribution-guidelines/contributor/_index.md +++ /dev/null @@ -1,11 +0,0 @@ - ---- -type: docs -title: "Contributor Guide" -linkTitle: "Contributor" -description: "Guidelines for dubbo contributor" -weight: 1 ---- - - - diff --git a/content/en/docs/contribution-guidelines/contributor/become-a-committer_dev.md b/content/en/docs/contribution-guidelines/contributor/become-a-committer_dev.md deleted file mode 100644 index 02dcaff1222f..000000000000 --- a/content/en/docs/contribution-guidelines/contributor/become-a-committer_dev.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -type: docs -title: "How to become a Dubbo committer" -linkTitle: "How To" -weight: 1 ---- - - -Anyone can be a contributor to an Apache project. Being a contributor simply means that you take an interest in the project and contribute in some way, ranging from asking sensible questions (which documents the project and provides feedback to developers) through to providing new features as patches. - -If you become a valuable contributor to the project you may well be invited to become a committer. Committer is a term used at the ASF to signify someone who is committed to a particular project. It brings with it the privilege of write access to the project repository and resources. - -In Dubbo community, if a committer who have earned even more merit, can be invited to be a part of the Project Management Committee (PMC). - -One thing that is sometimes hard to understand when you are new to the open development process used at the ASF, is that we value the community more than the code. A strong and healthy community will be respectful and be a fun and rewarding place. More importantly, a diverse and healthy community can continue to support the code over the longer term, even as individual companies come and go from the field. - -More details could be found [here](https://community.apache.org/contributors/). - -### What can I contribute? - -Please refer to the [new contributor guide](/en/docs/contribution-guidelines/contributor/new-contributor-guide_dev). diff --git a/content/en/docs/contribution-guidelines/contributor/cla-signing-guide_dev.md b/content/en/docs/contribution-guidelines/contributor/cla-signing-guide_dev.md deleted file mode 100644 index ce5999f11e6a..000000000000 --- a/content/en/docs/contribution-guidelines/contributor/cla-signing-guide_dev.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -type: docs -title: "CLA Signing Guide" -linkTitle: "CLA" -weight: 2 ---- - - -You are required to sign the Apache ICLA under the following condition: -* You have made lots of contribution to Dubbo before Dubbo get donated to Apache, and you haven't sign the Alibaba-CLA before. -* You have made lots of contribution to Dubbo, and you are invited to become committer of Dubbo, and you have not signed Alibaba-CLA or Apache ICLA before. - -#### Steps - -* Download this [pdf](https://www.apache.org/licenses/icla.pdf) -* Fill in the necessary blanks -* Print it out -* Sign the printed file -* Scan it -* Send an email to secretary@apache.org and cc private@dubbo.apache.org: - * entitled with "ICLA submission" - * please also provide the link to your github account in the email body - * remember to add you ICLA as attachment. - - -#### Explanation to the fields - -* Mailing address: Your company address in English is preferred. -* preferred apache id(s): if you are invited to become committers, you have to choose one apache id, otherwise you can leave it blank. -* notify project: Dubbo (This means Dubbo is the project who notifies you to sign the ICLA) - diff --git a/content/en/docs/contribution-guidelines/contributor/dubbo-extension-guide_dev.md b/content/en/docs/contribution-guidelines/contributor/dubbo-extension-guide_dev.md deleted file mode 100644 index 24db3203b4f5..000000000000 --- a/content/en/docs/contribution-guidelines/contributor/dubbo-extension-guide_dev.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -type: docs -title: "Extension Guide" -linkTitle: "Developing Extension" -weight: 5 ---- - - -Dubbo Use microkernel + plugin design pattern. Microkernel is only responsible for assembling plugins, the functions of Dubbo are implemented by extension points(plugins), which means that all functions of Dubbo can be replaced by user customized extension. - -## Dubbo Ecosystem - -We recommend you to put extension to Dubbo [ecosystem](https://github.com/dubbo). Using this pattern will keep the core repository cleaner and decrease the maintains work. With less code also speed up core repository build process. - -## Dependency -Implement your own Dubbo extension, in general is just dependence on API jar correspond to what you want. -For example: -```xml - - org.apache.dubbo - dubbo-serialization-api - ${dubbo.version} - -``` - -## Src Guide -Usually, implement special extension, just need reference the [Developer Guide](/en/latest/contribution-guidelines/) docs. Implement necessary interface and adapt extension to dubbo. Besides, some others should be considered: -1. Well tested. You should write unit test and mock test to eliminate potential bugs. -2. No warning, if some warning cannot to avoid, use @SuppressWarnings to suppress it, but do not abuse it. -3. README. Add necessary readme to show how to use your extension, and something to take notice. -4. License. Make sure of use Apache License 2.0. - -## Notify the Community -1. Commit your code to [GitHub](https://github.com). -2. Join the mail list (recommended). [HowTo](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide) -2. Send email to dev@incubator.dubbo.apache.org to notify the community -3. Usually, after sending email, community will discuss your extension, and Administrators of dubbo group will contact you for transfer project to dubbo ecosystem. - -## Transfer Project to Dubbo Group -1. Administrators of dubbo group will ask you, grant your project owner to dubbo. -2. Administrators of dubbo group will create a new project under dubbo group and invite you join the project. -3. Once you accept the invitation, you can transfer your project to new project under dubbo group. -4. Existing members of dubbo group will do the code review. After that you may make some improvement to code. diff --git a/content/en/docs/contribution-guidelines/contributor/new-contributor-guide_dev.md b/content/en/docs/contribution-guidelines/contributor/new-contributor-guide_dev.md deleted file mode 100644 index 3cabc65a13f3..000000000000 --- a/content/en/docs/contribution-guidelines/contributor/new-contributor-guide_dev.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -type: docs -title: "New Contributor Guide" -linkTitle: "New Contributor" -weight: 2 ---- - -This is a guide for new comers who wants to contribute to Dubbo. - -### Subscribe to the mailing list - -The mailing list is the recommended way for discussing almost anything that related to Dubbo. Please refer to this [issue](https://github.com/apache/dubbo/issues/1393) for detailed documentation on how to subscribe. - -To subscribe to the following mailing list, please refer to [Mailing list subscription guide](/en/docs/contribution-guidelines/contributor/mailing-list-subscription-guide_dev) - -* dev@dubbo.apache.org: the develop mailing list, you can ask question here if you have encountered any problem when using or developing Dubbo. -* commits@dubbo.apache.org: all the commits will be sent to this mailing list. You can subscribe to it if you are interested in Dubbo's development. -* issues@dubbo.apache.org: all the JIRA [issues](https://issues.apache.org/jira/projects/DUBBO/issues) and updates will be sent to this mailing list. The Dubbo community has decided to use github issues rather than JIRA issues, therefore it is expected that most of the issues will be tracked by github issues. The JIRA issues are used to track ASF related issues. - - -### Reporting issue - -You can always reporting an issue to Dubbo via Github [Issues](https://github.com/apache/dubbo/issues). - -If you are reporting bugs, please refer to the issue report [template](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md). - -If you are reporting regualur issues, like raise an question, you can open an [regular issue](https://github.com/apache/dubbo/issues/new) - -### Sending pull request - -* Follow the checklist in the [pull request template](https://github.com/apache/dubbo/blob/master/PULL_REQUEST_TEMPLATE.md) -* Before you sending out the pull request, please sync your forked repository with remote repository, this will make your pull request simple and clear. See guide below: - -```sh -git remote add upstream git@github.com:apache/dubbo.git -git fetch upstream -git rebase upstream/master -git checkout -b your_awesome_patch -... add some work -git push origin your_awesome_patch -``` - -### Code convention - -Please check the [CONTRIBUTING.md](https://github.com/apache/dubbo/blob/master/CONTRIBUTING.md) for code convention. - -### Participate in the release vote - -Participate in the release vote is an important way to contribute to Dubbo. The Dubbo community welcomes everyone to partipate, you can check the release vote using this [check list](https://cwiki.apache.org/confluence/display/INCUBATOR/Incubator+Release+Checklist). -If you have any question regarding the check list, please feel free to ask on dev@dubbo.apache.org. - - -### What can I contribute? - -* Take a look at issues with tag called [`Good first issue`](https://github.com/apache/dubbo/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) or [`Help wanted`](https://github.com/apache/dubbo/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22). -* Join the discussion on mailing list, subscription [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide). -* Answer questions on [issues](https://github.com/apache/dubbo/issues). -* Fix bugs reported on [issues](https://github.com/apache/dubbo/issues), and send us pull request. -* Review the existing [pull request](https://github.com/apache/dubbo/pulls). -* Improve the [website](https://github.com/apache/dubbo-website), typically we need - * blog post - * translation on documentation - * use cases about how Dubbo is being used in enterprise system. -* Improve the [dubbo-admin/dubbo-monitor](https://github.com/apache/dubbo-admin). -* Contribute to the projects listed in [ecosystem](https://github.com/dubbo). -* Any form of contribution that is not mentioned above. -* If you would like to contribute, please send an email to dev@dubbo.apache.org to let us know! diff --git a/content/en/docs/contribution-guidelines/contributor/reporting-security-issues_dev.md b/content/en/docs/contribution-guidelines/contributor/reporting-security-issues_dev.md deleted file mode 100644 index 6e931ed99679..000000000000 --- a/content/en/docs/contribution-guidelines/contributor/reporting-security-issues_dev.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -type: docs -title: "Reporting Security Issues" -linkTitle: "Security Issue" -weight: 4 ---- - - -The Apache Software Foundation takes a rigorous standpoint in annihilating the security issues in its software projects. Apache Dubbo is highly sensitive and forthcoming to issues pertaining to its features and functionality. - -## REPORTING VULNERABILITY - -If you have apprehensions regarding Dubbo's security or you discover vulnerability or potential threat, don’t hesitate to get in touch with the Apache Dubbo Security Team by dropping a mail at security@dubbo.apache.org. In the mail, specify the description of the issue or potential threat. You are also urged to recommend the way to reproduce and replicate the issue. The Dubbo community will get back to you after assessing and analysing the findings. - -PLEASE PAY ATTENTION to report the security issue on the security email before disclosing it on public domain. - - -## VULNERABILITY HANDLING - -An overview of the vulnerability handling process is: - -* The reporter reports the vulnerability privately to Apache. -* The appropriate project's security team works privately with the reporter to resolve the vulnerability. -* A new release of the Apache product concerned is made that includes the fix. -* The vulnerability is publically announced. - -A more detailed description of the process can be found [here](https://www.apache.org/security/committers.html) diff --git a/content/en/docs/contribution-guidelines/contributor/test-coverage-guide_dev.md b/content/en/docs/contribution-guidelines/contributor/test-coverage-guide_dev.md deleted file mode 100644 index d20a6335d32f..000000000000 --- a/content/en/docs/contribution-guidelines/contributor/test-coverage-guide_dev.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -type: docs -title: "Test Coverage Guide" -linkTitle: "Test Coverage" -weight: 7 ---- - -### The benefits of unit testing - - * Unit test code can help everyone to go into details and understand the function of the code. - * We can find bugs by test case, and then enhance the robustness of the code. - * Test case code is also the demo usage of the core code. - -### Some design principle of unit test case - - * Steps, fine-grained and combination conditions should be well designed. - * Attention to boundary condition test - * Test code should also be designed without writing useless code. - * When you find a `method` that is hard to write unit test, if you can be sure the `method` is "smelly code", then refactor it with the committer. - * The mock framework in dubbo is: [mockito](http://site.mockito.org/). Some tutorials:[mockito tutorial](https://www.baeldung.com/bdd-mockito),[mockito refcard](https://dzone.com/refcardz/mockito) - * TDD(optional):When you start a new issue, you can try to write test case at first - -### The specified value of the test coverage - - * In the stage, the test coverage specified value of delta changed codes is :>=60%. The higher, the better. - * We can see the coverage report in this page: https://codecov.io/gh/apache/dubbo diff --git a/content/en/docs/faq/_index.md b/content/en/docs/faq/_index.md deleted file mode 100644 index 1ff12ad818ac..000000000000 --- a/content/en/docs/faq/_index.md +++ /dev/null @@ -1,35 +0,0 @@ - ---- -type: docs -title: "FAQ - Frequently Asked Questions" -linkTitle: "FAQ - Frequently Asked Questions" -description: "FAQ - Frequently Asked Questions" -weight: 90 ---- -### Which version should I choose? - -Currently, Apache Dubbo it's maintaining four versions in parallel: - -- 3.0.x: requires Java 1.8, compatible with Spring 3.2.x, and added a Kubernetes Service Integration and remarkable performance improvement - -- 2.7.x (master): requires Java 1.8, major feature branch. - -- 2.6.x: requires Java 1.6, minor feature & bugfix branch, GA, production ready. - -- 2.5.x: requires Java 1.6, maintenance branch, only accept security vulnerability and critical bugfix, the support will end on 2019-6-15, please upgrade to 2.6.x as soon as possible. - -For contributors, please make sure all changes on the right branch, that is, most of the pull request should go to 2.7.x, and be backported to 2.6.x and 2.5.x if necessary. If the fix is specific to a branch, please make sure your pull request goes to the right branch. - -For committers, make sure select the right label and target branch for every PR, and don't forget to back port the fix to lower version is necessary. - -### Where is dubbo-admin? - -The dubbo-admin has been moved from core repository to https://github.com/apache/dubbo-admin since 2.6.1 - - -### How to register IP correctly in Docker? - -Dubbo supports specifying IP/port via system environment variables, examples can be found [here](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-docker). - - - diff --git a/content/en/docs/v2.7/_index.md b/content/en/docs/v2.7/_index.md deleted file mode 100755 index c94f2a8083e2..000000000000 --- a/content/en/docs/v2.7/_index.md +++ /dev/null @@ -1,10 +0,0 @@ - ---- -type: docs -title: "Dubbo 2.7" -linkTitle: "Dubbo 2.7" -weight: 20 -description: Dubbo 2.7 documentation ---- - - diff --git a/content/en/docs/v2.7/admin/_index.md b/content/en/docs/v2.7/admin/_index.md deleted file mode 100644 index 645150f63bab..000000000000 --- a/content/en/docs/v2.7/admin/_index.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "Admin Guide" -linkTitle: "Admin" -weight: 30 -description: "Guide for dubbo administrator" ---- - diff --git a/content/en/docs/v2.7/admin/install/_index.md b/content/en/docs/v2.7/admin/install/_index.md deleted file mode 100644 index a410659f9735..000000000000 --- a/content/en/docs/v2.7/admin/install/_index.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -type: docs -title: "Dubbo Installation Guide" -linkTitle: "Installation" -weight: 2 -description: "Guide for install dubbo" ---- - -You can run Demo Provider and Demo Consumer only, the default discovery strategy is Multicast by configuration center broadcast, do not run the two parts on the same machine, if you have to do so, set `unicast=false`, like `multicast://224.5.6.7:1234?unicast=false`, or the unicast send to consumer will be taken by provider, and the same for consumers. Only multicast has this issue - -You can run multiple Demo Provider and Demo consumer to verify load balance. Demo Consumer can run multi instance directly. Because of port conflict, you can either run multi Demo Providers on different machines or modify the value of `dubbo.protocol.port` in `conf/dubbo.properties` under the install directory of `conf/dubbo.properties` - -You can add Simple Monitor as a monitor center, the default discovery strategy is Multicast by configuration center broadcast, display the dependency relationship, call times and cost - -You can use Zookeeper instead of Multicast as the configuration center, after Zookeeper Registry installation, modify `conf/dubbo.properties` under the installation directory of Demo Provider, Demo Consumer and Simple Monitor, change the value of `dubbo.registry.address` to `zookeeper://127.0.0.1:2181`(`redis://127.0.0.1:6379` for Redis Registry). the value for Simple Registry is `dubbo://127.0.0.1:9090` - -Zookeeper configuration address is recommended - -[^1]: NOTICE: multicast can be neither 127.0.0.1 nor the machine's IP address, it must be a type D broadcast address, from 224.0.0.0 to 239.255.255.255 - - diff --git a/content/en/docs/v2.7/admin/install/admin-console.md b/content/en/docs/v2.7/admin/install/admin-console.md deleted file mode 100644 index cc89366d06f4..000000000000 --- a/content/en/docs/v2.7/admin/install/admin-console.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -type: docs -title: "Install Admin Console" -linkTitle: "Admin Console" -weight: 1 ---- - -The current version of dubbo admin is under development, including: route rule, dynamic configuration, access control, weight adjustment, load balance, etc. - -Install: - -```sh -git clone https://github.com/apache/dubbo-admin.git /var/tmp/dubbo-admin -cd /var/tmp/dubbo-admin -mvn clean package -``` - -Configuration [^1]: - -```sh -configuration file: -dubbo-admin-server/src/main/resources/application.properties -configurations: -admin.registry.address=zookeeper://127.0.0.1:2181 -admin.config-center=zookeeper://127.0.0.1:2181 -admin.metadata-report.address=zookeeper://127.0.0.1:2181 -``` - -Start: - -```sh -mvn --projects dubbo-admin-backend spring-boot:run -``` - -For more information, please visit: - -```sh -https://github.com/apache/dubbo-admin -``` - -Visit [^2]: - -``` -http://127.0.0.1:8080 -``` - -[^1]: There's no login for current version, will be added later diff --git a/content/en/docs/v2.7/admin/install/consumer-demo.md b/content/en/docs/v2.7/admin/install/consumer-demo.md deleted file mode 100644 index ffaba675d047..000000000000 --- a/content/en/docs/v2.7/admin/install/consumer-demo.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -type: docs -title: "Install Demo Consumer" -linkTitle: "Demo Consumer" -weight: 3 ---- - -Install: - -```sh -$ git clone https://github.com/apache/dubbo.git -$ cd dubbo/dubbo-demo/dubbo-demo-xml -# run org.apache.dubbo.demo.consumer.Application under dubbo-demo-xml-consumer module -# please start Provider first -# add -Djava.net.preferIPv4Stack=true if your IDE is Intellij Idea -``` - -Configuration: - -```sh -# resources/spring/dubbo-consumer.xml -# change dubbo:registry to the real registry center address, for example: -# -``` diff --git a/content/en/docs/v2.7/admin/install/monitor-center.md b/content/en/docs/v2.7/admin/install/monitor-center.md deleted file mode 100644 index 017310d90ad8..000000000000 --- a/content/en/docs/v2.7/admin/install/monitor-center.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -type: docs -title: "Install Simple monitor center" -linkTitle: "Monitor Center" -weight: 5 ---- - - -The function of monitor center will be merged to dubbo admin, based on metrics, coming soon \ No newline at end of file diff --git a/content/en/docs/v2.7/admin/install/provider-demo.md b/content/en/docs/v2.7/admin/install/provider-demo.md deleted file mode 100644 index a840b15fb5ab..000000000000 --- a/content/en/docs/v2.7/admin/install/provider-demo.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -type: docs -title: "Install Demo Provider" -linkTitle: "Demo Provider" -weight: 2 ---- - - -install: - -```sh -$ git clone https://github.com/apache/dubbo.git -$ cd dubbo/dubbo-demo/dubbo-demo-xml -# run org.apache.dubbo.demo.provider.Application under dubbo-demo-xml-provider module -# add -Djava.net.preferIPv4Stack=true if your IDE is Intellij Idea -``` - -configuration: - -```sh -# resources/spring/dubbo-provider.xml -# change dubbo:registry to a real registry server address, zookeeper is recommended, for example: -# -``` diff --git a/content/en/docs/v2.7/admin/install/redis.md b/content/en/docs/v2.7/admin/install/redis.md deleted file mode 100644 index 9e74ec634c56..000000000000 --- a/content/en/docs/v2.7/admin/install/redis.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -type: docs -title: "Install Redis Register Center" -linkTitle: "Register Center" -weight: 4 ---- - -Redis [^1] introductions, please refer to: [Redis application center manual](../../../user/references/registry/redis). - -you need an origin Redis server only, and change the value from `dubbo.registry.address` to `redis://127.0.0.1:6379` in `conf/dubbo.properties` of [quick start](../../../user/quick-start) - -Redis configuration center cluster [^2] write multiple server in client side and read from a single server. - -Install: - -```sh -wget http://redis.googlecode.com/files/redis-2.4.8.tar.gz -tar xzf redis-2.4.8.tar.gz -cd redis-2.4.8 -make -``` - -Configuration: - -```sh -vi redis.conf -``` - -Start: - -```sh -nohup ./src/redis-server redis.conf & -``` - -Stop: - -```sh -killall redis-server -``` - -* Command line [^3]: - -```sh -./src/redis-cli -hgetall /dubbo/com.foo.BarService/providers -``` - -Or: - -```sh -telnet 127.0.0.1 6379 -hgetall /dubbo/com.foo.BarService/providers -``` - -[^1]: Redis is a high performance KV store server, please refer to: http://redis.io/topics/quickstart -[^2]: Support for version `2.1.0` and higher -[^3]: Please refer to: http://redis.io/commands \ No newline at end of file diff --git a/content/en/docs/v2.7/admin/install/zookeeper.md b/content/en/docs/v2.7/admin/install/zookeeper.md deleted file mode 100644 index 10b120b56058..000000000000 --- a/content/en/docs/v2.7/admin/install/zookeeper.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -type: docs -title: "install Zookeeper Configuration Center" -linkTitle: "Config Center" -weight: 4 ---- - -zookeeper register center client version: `dubbo-2.3.3` and above[^1] - -Dubbo changes nothing of Zookeeper's server side, an original Zookeeper server is fine. All change happens while calling Zookeeper's client side - -install: - -```sh -wget http://archive.apache.org/dist/zookeeper/zookeeper-3.3.3/zookeeper-3.3.3.tar.gz -tar zxvf zookeeper-3.3.3.tar.gz -cd zookeeper-3.3.3 -cp conf/zoo_sample.cfg conf/zoo.cfg -``` - -configuration: - -```sh -vi conf/zoo.cfg -``` - -If cluster is not needed, the content of `zoo.cfg` is as below [^2]: - -```properties -tickTime=2000 -initLimit=10 -syncLimit=5 -dataDir=/home/dubbo/zookeeper-3.3.3/data -clientPort=2181 -``` - -If cluster is needed, the content of `zoo.cfg` is as below [^3]: - -```properties -tickTime=2000 -initLimit=10 -syncLimit=5 -dataDir=/home/dubbo/zookeeper-3.3.3/data -clientPort=2181 -server.1=10.20.153.10:2555:3555 -server.2=10.20.153.11:2555:3555 -``` - -Put myid file in data directory [^4]: - -```sh -mkdir data -vi myid -``` - -Myid is the number after `server` in `zoo.cfg`. The first one's content is 1, the second one's content is 2: - -``` -1 -``` - -Start: - -```sh -./bin/zkServer.sh start -``` - -Stop: - -```sh -./bin/zkServer.sh stop -``` - -Command line [^5]: - -```sh -telnet 127.0.0.1 2181 -dump -``` - -Or: - -```shell -echo dump | nc 127.0.0.1 2181 -``` - -Usage: - -```xml -dubbo.registry.address=zookeeper://10.20.153.10:2181?backup=10.20.153.11:2181 -``` - -Or: - -```xml - -``` - -[^1]: Zookeeper is a sub project of Apache Hadoop.As it is robust, we recommend to use in production environment. -[^2]: Data directory should be changed into your real output directory -[^3]: Data directory and server address should be changed into your real machine information -[^4]: `dataDir` in `zoo.cfg` -[^5]: http://zookeeper.apache.org/doc/r3.3.3/zookeeperAdmin.html diff --git a/content/en/docs/v2.7/admin/ops/_index.md b/content/en/docs/v2.7/admin/ops/_index.md deleted file mode 100644 index 6f32ff1a0b7b..000000000000 --- a/content/en/docs/v2.7/admin/ops/_index.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "Dubbo Admin Guide" -linkTitle: "Dubbo Admin" -weight: 1 -description: "Guide for dubbo-admin" ---- - diff --git a/content/en/docs/v2.7/admin/ops/apidocs.md b/content/en/docs/v2.7/admin/ops/apidocs.md deleted file mode 100644 index 2ac603883824..000000000000 --- a/content/en/docs/v2.7/admin/ops/apidocs.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -type: docs -title: "API Docs&Test" -linkTitle: "API Docs&Test" -weight: 4 ---- - -## dubbo api docs - -Dubbo api documents, test tools, generate documents according to annotations, and provide test functions - -Adding some annotations can generate a swagger like document without turning a non web Dubbo project into a web project - -## How to use? - -1. Dubbo api docs annotation added to method parameters of Dubbo project - * Dubbo provider project introduces dubbo-api-docs-core - * If Dubbo's interface and parameters are a separate jar package project, introduce dubbo-api-docs-annotations - * Add the annotation @EnableDubboApiDocs to the project startup class (marked with @SpringBootApplication) - or configuration class (marked with @Configuration) of the provider project to enable the Dubbo API Docs - * In order to avoid increasing the resource consumption in the production environment, it is recommended - to create a configuration class to enable Dubbo API Docs, and use it with the @Profile("dev") annotation - * Of course, Dubbo API Docs consumed a little CPU resources when the project starting and used a little - memory for caching. In the future, it will consider putting the contents of the cache into the metadata - center - -### Current Version: Same as Dubbo version - -``` - - org.apache.dubbo - dubbo-api-docs-annotations - ${dubbo-version} - - - - org.apache.dubbo - dubbo-api-docs-core - ${dubbo-version} - -``` - -2. -Download [dubbo-admin](https://github.com/apache/dubbo-admin) [Download](https://github.com/apache/dubbo-admin/releases) - -3. Start dubbo-admin - -4. Visit: http:// localhost:8080 - -5. Enter the "API Doc" module - -### Annotation use - -* @EnableDubboApiDocs: 配制注解, 启用 dubbo api docs 功能 -* @ApiModule: class annotation, dubbo API module information, used to mark the purpose of an interface class module - * value: module name - * apiInterface: Provider implemented interface - * version: module version -* @ApiDoc: method annotation, dubbo API information, used to mark the purpose of an dubbo API - * value: API name - * description: API description(HTML tags available) - * version: API version - * responseClassDescription: response class description -* @RequestParam: class property/method Parameter annotation, mark request parameters - * value: parameter name - * required: true/false required parameter - * description: parameter description - * example: parameter example - * defaultValue: parameter default value - * allowableValues: Allowed values. After setting this property, a drop-down list will be generated for the parameter - * Note: a drop-down selection box will be generated after using this property - * Parameters of boolean type do not need to be set with this property. A drop-down list of true / false will be - generated by default - * Parameters of enumeration type will automatically generate a drop-down list. If you do not want to open all - enumeration values, you can set this property separately. -* @ResponseProperty: Class attribute annotation, mark response parameters - * value: parameter name - * example: example - -## Involving repositorys -* [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions) - [\branch: 2.7.x\dubbo-api-docs](https://github.com/apache/dubbo-spi-extensions/tree/2.7.x/dubbo-api-docs): - Dubbo-Api-Docs related annotation ,annotation parsing -* [dubbo-admin](https://github.com/KeRan213539/dubbo-admin): Dubbo-Api-Docs document display, test function - -### Use note - -* Get API list direct connection: - -> Because Dubbo services with different functions may be registered in the same registration center, -> but the name of the interface used by Dubbo doc is the same, so the interface of Dubbo doc uses direct connection to obtain the list of different interfaces of different functions. -> The test can be connected directly or through the registration center - -* The response bean (the return type of the interface) supports custom generics, but only one generic placeholder. -* About the use of Map: the key of map can only use the basic data type. If the key of map is not the basic data type, - the generated key is not in the standard JSON format, and an exception will occur -* The API's synchronous / asynchronous is from org.apache.dubbo.config.annotation.Service.async - - - -## Screenshot - -![Screenshot](/imgs/admin/dubbo_docs_en.png) diff --git a/content/en/docs/v2.7/admin/ops/functions.md b/content/en/docs/v2.7/admin/ops/functions.md deleted file mode 100644 index be14123fc202..000000000000 --- a/content/en/docs/v2.7/admin/ops/functions.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -type: docs -title: "Dubbo Admin Functions" -linkTitle: "Functions" -weight: 1 ---- - -## Page search - -If you need to manage a Dubbo service, you need to search it first and open it's management page - -![/admin-guide/images/dubbo-search.png](/imgs/admin/dubbo-search.jpg) - -## Service provider page - -![/admin-guide/images/dubbo-providers.png](/imgs/admin/dubbo-providers.jpg) - -## Service consumer page - -![/admin-guide/images/dubbo-consumers.png](/imgs/admin/dubbo-consumers.jpg) - - - -## Add route rule page - -![/admin-guide/images/dubbo-add-route.png](/imgs/admin/dubbo-add-route.jpg) - -## Add dynamic configuration page - -![/admin-guide/images/dubbo-add-config.png](/imgs/admin/dubbo-add-config.jpg) - diff --git a/content/en/docs/v2.7/admin/ops/governance.md b/content/en/docs/v2.7/admin/ops/governance.md deleted file mode 100644 index a6816a34b70d..000000000000 --- a/content/en/docs/v2.7/admin/ops/governance.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -type: docs -title: "Service Governance And Configuration Management" -linkTitle: "Governance" -weight: 4 ---- - -## Service governance -the basic function of service governance is changing the runtime behaviour and routing logic, to do weight configuration and current limiting: - -### application level service governance -In Dubbo 2.6 or earlier version, all service governance rule are in service scope, if you need to make application scope rule, you need to set the same rule for all services under an application, modify and delete need the same operation, this is very unfriendly. In Dubbo 2.7, application scope service governance is supported, condition route(including black white list) and dynamic configuration(including weight, load balance) all support application scope config. - -![condition](/imgs/blog/admin/conditionRoute.jpg) - -picture above is condition route configuration, can create and search by both application name and service name. - -### tag route -tag route is a new feature in Dubbo2.7, in application scope, to set different tag on different server, the screenshot is shown as below: - -![tag](/imgs/blog/admin/route.jpg) - -the client can use `setAttachment` to specify different tag, is the above case, `setAttachment(tag1)`, the client will choose from the three servers in the picture above. In this way, you can implement features such as traffic isolation and gray release. - -### condition route -condition route is a traditional function in Dubbo, now you can create it in either service scope or application scope. Condition route is in `yaml` format, you can read [here](../../../user/examples/routing-rule/) to find more. - -### black white list -black white list is a part of condition route and store with condition route together, you can set black list or white list, in either service scope or application scope: - -![blackList](/imgs/admin/blackList.jpg) - -### dynamic configuration -dynamic configuration has the same level with routing rule, it can change the RPC behaviour dynamically without restart service. It supports application scope since Dubbo 2,7, in Dubbo format, the screen shot shows in below: - -![config](/imgs/admin/config.jpg) - -to read more, please refer [here](../../../user/examples/config-rule/) - -### weight adjust -weigth adjuest is part of dynamic configuration, change the weight of server side to do traffic control dynamically: - -![weight](/imgs/admin/weight.jpg) - -### load balancing -load balancing is also poart of dynamic configuration, to specify the route strategy in client side. now we have three strategies: random, least active and round robin, to read more, please refer [here](../../../user/examples/loadbalance) - -## configuration management -configuration management is also a new feaature for Dubbo 2.7. In Dubbo 2.7, we can specify configurations in global scope and application scope(including services in application), you can view, modify and create new configurations in Dubbo Admin. -* global configuration: - -![config](/imgs/blog/admin/config.jpg) - -you can set registry center, metadata center, timeout for provider and consumer in global configurations. If the implementation of registry center and metadata center is zookeeper, you can also check the location of configuration file. -* application and service scope configuration: - -![appConfig](/imgs/blog/admin/appConfig.jpg) - -application configuration can also set service configuration in this application. you need to specify consumer and provider in service scope: `dubbo.reference.{serviceName}`stands for configuration as consumer side,`dubbo.provider.{servcieName}`stands for configuration as provider side. the address of registry address and metadata center address can only be configured in global configuration, which is also the recommendation way in Dubbo 2.7 -* priority service configuration > application configuration > global configuration diff --git a/content/en/docs/v2.7/admin/ops/introduction.md b/content/en/docs/v2.7/admin/ops/introduction.md deleted file mode 100644 index 90ccc1aac8e6..000000000000 --- a/content/en/docs/v2.7/admin/ops/introduction.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -type: docs -title: "Dubbo Admin Introductions" -linkTitle: "Introductions" -weight: 2 ---- - -Now version 0.1 has been released, frontend uses Vue and Vuetify as javascript framework and UI framework, backend uses spring framework, you can deploy the whole project with maven or deploy frontend and backend separately. - -### Deploy the whole project through maven - -* install -```sh -git clone https://github.com/apache/dubbo-admin.git -cd dubbo-admin -mvn clean package -cd dubbo-admin-distribution/target -java -jar dubbo-admin-0.1.jar -``` -* visit -`http://localhost:8080` - - -### Deploy frontend and backend separately - -* frontend deploy -```sh -cd dubbo-admin-ui -npm install -npm run dev -``` -* backend deploy -```sh -cd dubbo-admin-server -mvn clean package -cd target -java -jar dubbo-admin-server-0.1.jar -``` -* visit -http://localhost:8081 -* in this mode, any modify of frontend will be hot reloaded - - -### configuration: [^1] - -configuration file location -```sh -dubbo-admin-server/src/main/resources/application.properties -``` -configuration: -```properties -admin.config-center=zookeeper://127.0.0.1:2181 -admin.registry.address=zookeeper://127.0.0.1:2181 -admin.metadata-report.address=zookeeper://127.0.0.1:2181 -``` - -Same as Dubbo 2.7, you can set the addresses of metadata center and registry center on configuration center, in zookeeper, the path and content are as below: -```properties -# /dubbo/config/dubbo/dubbo.properties -dubbo.registry.address=zookeeper://127.0.0.1:2181 -dubbo.metadata-report.address=zookeeper://127.0.0.1:2181 -``` -the addresses in configuration center have higher priority than those in `application.properties` - -visit documents on github: - -```sh -https://github.com/apache/dubbo-admin -``` - -[^1]: there's no login module in the current version. diff --git a/content/en/docs/v2.7/admin/ops/pinpoint.md b/content/en/docs/v2.7/admin/ops/pinpoint.md deleted file mode 100644 index 92cb3366f5d2..000000000000 --- a/content/en/docs/v2.7/admin/ops/pinpoint.md +++ /dev/null @@ -1,416 +0,0 @@ ---- -type: docs -title: "Tracking with Pinpoint" -linkTitle: "Pinpoint" -weight: 5 ---- - -After using Dubbo to serve or integrate applications, assuming that a service backstage log shows an exception and that the service is invoked by multiple applications, it is often difficult to determine which application is called, and what is the cause of the problem, so we need a set of distributed tracking systems to quickly locate the problem. Pinpoint can help us quickly locate problems (of course, there are more than one solution). - -## What is Pinpoint - -[Pinpoint](https://github.com/naver/pinpoint) is an APM (Application Performance Management) tool for large-scale distributed systems written in Java. Inspired by Dapper, Pinpoint provides a solution to help analyze the overall structure of the system and how components within them are interconnected by tracing transactions across distributed applications. - -You should definitely check Pinpoint out If you want to - -understand your application topology at a glance -monitor your application in Real-Time -gain code-level visibility to every transaction -install APM Agents without changing a single line of code -have minimal impact on the performance (approximately 3% increase in resource usage) - -### ServerMap - -Understand the topology of any distributed systems by visualizing how their components are interconnected. Clicking on a node reveals details about the component, such as its current status, and transaction count. - -### Realtime Active Thread Chart - -Monitor active threads inside applications in real-time. - -### Request/Response Scatter Chart - -Visualize request count and response patterns over time to identify potential problems. Transactions can be selected for additional detail by dragging over the chart. - -### CallStack - -Gain code-level visibility to every transaction in a distributed environment, identifying bottlenecks and points of failure in a single view. - -### Inspector - -View additional details on the application such as CPU usage, Memory/Garbage Collection, TPS, and JVM arguments. - -### Supported Modules (last updated 2018/04/01) - -* JDK 6+ -* Tomcat 6/7/8, Jetty 8/9, JBoss EAP 6, Resin 4, Websphere 6/7/8, Vertx 3.3/3.4/3.5 -* Spring, Spring Boot (Embedded Tomcat, Jetty) -* Apache HTTP Client 3.x/4.x, JDK HttpConnector, GoogleHttpClient, OkHttpClient, NingAsyncHttpClient -* Thrift Client, Thrift Service, DUBBO PROVIDER, DUBBO CONSUMER -* ActiveMQ, RabbitMQ -* MySQL, Oracle, MSSQL, CUBRID,POSTGRESQL, MARIA -* Arcus, Memcached, Redis, CASSANDRA -* iBATIS, MyBatis -* DBCP, DBCP2, HIKARICP -* gson, Jackson, Json Lib -* log4j, Logback - -## Pinpoint and Dubbo - -### Quickstart Pinpoint - -[Quick start](https://pinpoint-apm.github.io/pinpoint/quickstart.html)(No neet to start TestApp) - -### Dubbo demo - -#### Create API module - -pom.xml -```xml - - - 4.0.0 - - com.example - demo-api - 0.0.1-SNAPSHOT - -``` - -Create API interface: -``` -package com.example.demoapi; - -public interface HelloService { - String sayHello(String name); -} -``` - -#### Dubbo provider - -pom.xml -```xml - - - 4.0.0 - - com.example - demo-provider - 0.0.1-SNAPSHOT - jar - - demo-provider - - - org.springframework.boot - spring-boot-starter-parent - 2.0.3.RELEASE - - - - - UTF-8 - UTF-8 - 1.8 - - - - - sonatype-nexus-snapshots - https://oss.sonatype.org/content/repositories/snapshots - - false - - - true - - - - - - - org.springframework.boot - spring-boot-starter - - - com.alibaba.boot - dubbo-spring-boot-starter - 0.2.0 - - - com.example - demo-api - 0.0.1-SNAPSHOT - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - -``` - -1. `HelloService` interface: -```java -package com.example.demoprovider.provider; - -import org.apache.dubbo.config.annotation.Service; -import com.example.demoapi.HelloService; - -@Service(version = "${demo.service.version}", - application = "${dubbo.application.id}", - protocol = "${dubbo.protocol.id}", - registry = "${dubbo.registry.id}") -public class HelloServiceImpl implements HelloService { - static int i = 0; - @Override - public String sayHello(String name) { - i++; - if (i % 3 == 0) { - throw new RuntimeException("ex"); - } - return "Hello " + name + "!"; - } -} -``` - -2. Spring Boot bootstrap: -```java -package com.example.demoprovider; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class DemoProviderApplication { - - public static void main(String[] args) { - SpringApplication.run(DemoProviderApplication.class, args); - } -} -``` - -3. `application.properties`: - -```properties -# Spring boot application -spring.application.name = dubbo-provider-demo -server.port = 9090 -management.port = 9091 - -# Service version -demo.service.version = 1.0.0 - -# Base packages to scan Dubbo Components (e.g @Service , @Reference) -dubbo.scan.basePackages = com.example.demoprovider - -# Dubbo Config properties -## ApplicationConfig Bean -dubbo.application.id = dubbo-provider-demo -dubbo.application.name = dubbo-provider-demo - -## ProtocolConfig Bean -dubbo.protocol.id = dubbo -dubbo.protocol.name = dubbo -dubbo.protocol.port = 12345 - -## RegistryConfig Bean -dubbo.registry.id = my-registry -dubbo.registry.address = N/A -``` - -#### Dubbo consumer - -pom.xml -```xml - - - 4.0.0 - - com.example - demo-consumer - 0.0.1-SNAPSHOT - jar - - demo-consumer - - - org.springframework.boot - spring-boot-starter-parent - 2.0.3.RELEASE - - - - - UTF-8 - UTF-8 - 1.8 - - - - - sonatype-nexus-snapshots - https://oss.sonatype.org/content/repositories/snapshots - - false - - - true - - - - - - - org.springframework.boot - spring-boot-starter-web - - - com.alibaba.boot - dubbo-spring-boot-starter - 0.2.0 - - - com.example - demo-api - 0.0.1-SNAPSHOT - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - exec - - - - - - -``` - -1. `@Reference` injection `HelloService` -```java -package com.example.democonsumer.controller; - -import org.apache.dubbo.config.annotation.Reference; -import com.example.demoapi.HelloService; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class DemoConsumerController { - @Reference(version = "${demo.service.version}", - application = "${dubbo.application.id}", - url = "dubbo://:12345") - private HelloService helloService; - - @RequestMapping("/sayHello") - public String sayHello(@RequestParam String name) { - return helloService.sayHello(name); - } -} -``` - -2. Spring Boot bootstrap: -```java -package com.example.democonsumer; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class DemoConsumerApplication { - - public static void main(String[] args) { - SpringApplication.run(DemoConsumerApplication.class, args); - } -} -``` - -3. `application.properties`: -```properties -# Spring boot application -spring.application.name=dubbo-consumer-demo -server.port=8080 -management.port=8081 - -# Service Version -demo.service.version=1.0.0 - -# Dubbo Config properties -## ApplicationConfig Bean -dubbo.application.id=dubbo-consumer-demo -dubbo.application.name=dubbo-consumer-demo - -## ProtocolConfig Bean -dubbo.protocol.id=dubbo -dubbo.protocol.name=dubbo -dubbo.protocol.port=12345 -``` - -### Using Pinpoint-agent to start `Dubbo provider` and `Dubbo consumer` - -1. Maven clean package -``` -mvn clean package -``` - -2. Start provider -``` -java -jar -javaagent:$AGENT_PATH/pinpoint-bootstrap-$VERSION.jar -Dpinpoint.agentId=demo-provider -Dpinpoint.applicationName=DP target/demo-provider-0.0.1-SNAPSHOT.jar -``` - -3. Start consumer -``` -java -jar -javaagent:$AGENT_PATH/pinpoint-bootstrap-$VERSION.jar -Dpinpoint.agentId=demo-consumer -Dpinpoint.applicationName=DC target/demo-comsumer-0.0.1-SNAPSHOT-exec.jar -``` - -4. Access the consumer address to simulate user requests - -`http://localhost:8080/sayHello?name=ABC` - -## Using Pinpoint locate problems - -### Homepage - -![/admin-guide/images/pinpoint-home.png](/imgs/admin/pinpoint-home.png) - -> The user request here is double the number of requests for DubboProvider, because the favicon.ico icon request is recorded. - -### Call tree - -![/admin-guide/images/pinpoint-calltree.png](/imgs/admin/pinpoint-calltree.png) - -### Mixed view - -![/admin-guide/images/pinpoint-mixedview.png](/imgs/admin/pinpoint-mixedview.png) - -### Other - -The example simply simulates the provision and call of Dubbo, and does not carry out the application of other middleware such as database. For detailed use, please refer to the Pinpoint document. diff --git a/content/en/docs/v2.7/admin/ops/search.md b/content/en/docs/v2.7/admin/ops/search.md deleted file mode 100644 index 216d341d040c..000000000000 --- a/content/en/docs/v2.7/admin/ops/search.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "Service Search And Service Detail" -linkTitle: "Search" -weight: 3 ---- - -Service search is the basic function of Dubbo OPS, you can search by service name, application name and IP address, the service name and application name support wildcard and autocomplete: - -![searchResult](/imgs/admin/searchResult.png) - -the service detail page display providers, consumers, medata information is supported in Dubbo 2.7 or higher version: - -![detail](/imgs/admin/detail.jpg) - - diff --git a/content/en/docs/v2.7/admin/ops/skywalking.md b/content/en/docs/v2.7/admin/ops/skywalking.md deleted file mode 100644 index 7277686e8715..000000000000 --- a/content/en/docs/v2.7/admin/ops/skywalking.md +++ /dev/null @@ -1,150 +0,0 @@ ---- -type: docs -title: "Tracing Dubbo service with Apache Skywalking" -linkTitle: "Skywalking" -weight: 5 ---- - -## Introduction to Apache Skywalking - -[Apache Skywalking(Incubator)](https://github.com/apache/skywalking) is the APM system that it designed for micro-services architectures and cloud native architecture systems and supports distribute tracking. [Apache skywalking (incubator)](https://github.com/apache/skywalking) collects and analyzes the trace data and generates the relationship between the application and the service metric, Apache skywalking supports multiple languages agent, for example [Java](https://github.com/apache/skywalking),[.net core](https://github.com/OpenSkywalking/skywalking-netcore),[Node.js](https://github.com/OpenSkywalking/skywalking-nodejs) and [Go](https://github.com/SkyAPM/go2sky). - -Currently, Skywalking has supported analysis the operation of distributed systems from 6 visual dimensions. The overview view is a global view of your applications and components, including the number of components and applications, application alarm fluctuations, slow service lists, and application throughput; The topology shows the topological relationship of the whole application; The application view represents the upstream and downstream relationship of the application from single application, TOP N services and servers, JVM, host and process info. The service view focuses on the operation of a single service portal and the upstream and downstream dependencies of this service and it helps the user to optimize and monitor a single service; the trace graph shows all the buried points of the invocation and the execution time of each burial point, and the alarm view is based on the configuration threshold for the application, server, service for real-time alarms - -## Dubbo and Apache Skywalking - -### Build the Dubbo demo project - -The Dubbo demo has been uploaded to the [GitHub repository](https://github.com/SkywalkingTest/dubbo-trace-example). - -#### API project - -Service interface definition: - -```java -package org.apache.skywalking.demo.interfaces; - -public interface HelloService { - String sayHello(String name); -} -``` - -#### Service provider project - -```java -package org.apache.skywalking.demo.provider; - -@Service(version = "${demo.service.version}", - application = "${dubbo.application.id}", - protocol = "${dubbo.protocol.id}", - registry = "${dubbo.registry.id}", timeout = 60000) -public class HelloServiceImpl implements HelloService { - - public String sayHello(String name) { - LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1)); - return "Hello, " + name; - } - -} -``` - -#### Service consumer project - -```java -package org.apache.skywalking.demo.consumer; - -@RestController -public class ConsumerController { - - private static int COUNT = 0; - - @Reference(version = "${demo.service.version}", - application = "${dubbo.application.id}", - url = "dubbo://localhost:20880", timeout = 60000) - private HelloService helloService; - - @GetMapping("/sayHello/{name}") - public String sayHello(@PathVariable(name = "name") String name) { - if ((COUNT++) % 3 == 0){ - throw new RuntimeException(); - } - LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2)); - return helloService.sayHello(name); - } -} -``` - -### Deploy Apache Skywalking - -[Apache skywalking (Incubator)](https://github.com/apache/skywalking) offers two deployment modes: single-node mode and cluster mode,Here is the single-node mode deployment step, and more about how to deploy skywalking with cluster mode, please reference [document](https://skywalking.apache.org/docs/main/next/en/setup/backend/backend-setup/). - -#### Third-party components - -1. JDK 8+ -2. Elasticsearch 5.x - -#### Deployment step - -1. Download [Apache Skywalking Collector](http://skywalking.apache.org/downloads/) -2. Deploy Elasticsearch service - * Set `cluster.name` to `CollectorDBCluster` - * Set `network.host` to `0.0.0.0` - * Start elasticsearch service -3. Unzip and start the Skywalking Collector. Run the ' bin/startup.sh ' command to start skywalking Collector - -#### Deploy the demo - -Before you deploy the demo service, please run the following command: - -```bash -./mvnw clean package -``` - -#### Deploy the provider service - -```bash -java -jar -javaagent:$AGENT_PATH/skywalking-agent.jar -Dskywalking.agent.application_code=dubbo-provider -Dskywalking.collector.servers=localhost:10800 dubbo-provider/target/dubbo-provider.jar -``` - -#### Deploy the consumer service - -``` -java -jar -javaagent:$AGENT_PATH/skywalking-agent.jar -Dskywalking.agent.application_code=dubbo-consumer -Dskywalking.collector.servers=localhost:10800 dubbo-consumer/target/dubbo-consumer.jar -``` - -#### visit demo service - -```bash -curl http://localhost:8080/sayHello/test -``` - -## Skywalking scren snapshot - -### Dashboard -![/admin-guide/images/skywalking-dashboard.png](/imgs/admin/skywalking-dashboard.png) - -### Topology -![/admin-guide/images/skywalking-topology.png](/imgs/admin/skywalking-topology.png) - -### Application view -![/admin-guide/images/skywalking-application.png](/imgs/admin/skywalking-application.png) - -JVM Information -![/admin-guide/images/skywalking-application_instance.png](/imgs/admin/skywalking-application_instance.png) - -### Service view - -Consumer side -![/admin-guide/images/skywalking-service-consumer.png](/imgs/admin/skywalking-service-consumer.png) - -provider side -![/admin-guide/images/skywalking-service-provider.png](/imgs/admin/skywalking-service-provider.png) - -### Trace -![/admin-guide/images/skywalking-trace.png](/imgs/admin/skywalking-trace.png) - -Span info -![/admin-guide/images/skywalking-span-Info.png](/imgs/admin/skywalking-span-Info.png) - -### Alarm view -![/admin-guide/images/skywalking-alarm.png](/imgs/admin/skywalking-alarm.png) diff --git a/content/en/docs/v2.7/admin/ops/test.md b/content/en/docs/v2.7/admin/ops/test.md deleted file mode 100644 index 10e9a3acf51e..000000000000 --- a/content/en/docs/v2.7/admin/ops/test.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "Service Test" -linkTitle: "Test" -weight: 3 ---- - -please refer to this [blog](/en/blog/2019/08/26/service-test/) diff --git a/content/en/docs/v2.7/dev/SPI.md b/content/en/docs/v2.7/dev/SPI.md deleted file mode 100644 index df3c4dd91e64..000000000000 --- a/content/en/docs/v2.7/dev/SPI.md +++ /dev/null @@ -1,244 +0,0 @@ ---- -type: docs -title: "SPI Loading" -linkTitle: "SPI" -weight: 3 -description: "How Dubbo SPI works" ---- - - -## SPI Config - -### Source: - -Dubbo SPI is inherited from standard JDK SPI(Service Provider Interface) and makes it more powerful. - -Dubbo fixed below issues of the standard JDK SPI: - -* The standard JDK SPI will load and instantize all the implementations at once. It will be a waste of resources if one implementation is timecosted, but never be used. -* We can't accquire the SPI name, if loading the SPI implementation is failed.For example: standard JDK ScriptEngine, get script type by invoking method getName(). RubyScriptEngine class will load failed if the depenency jar jruby.jar is missing, and the real error info will be lost. When user executes ruby scripts, the program throws exception that doesn't support ruby, but it is not the real cause. -* Enhance the SPI functionality by supporting IoC and AOP, one SPI can be easily injected by another SPI simply using setter. - -### Appointment: - -In the jar file containing extension class [^1], places a config file `META-INF/dubbo/full interface name`, file content pattern: `SPI name=the fully qualified name for the extension class`, use new line seperator for multiple implementation. - -### Example: - -To extend Dubbo Protocol, place a text file in the extension jar file: `META-INF/dubbo/org.apache.dubbo.rpc.Protocol`, content: - -```properties -xxx=com.alibaba.xxx.XxxProtocol -``` - -content of the implementation [^2]: - -```java -package com.alibaba.xxx; - -import org.apache.dubbo.rpc.Protocol; - -public class XxxProtocol implements Protocol { - // ... -} -``` - -### Configuration in config module - -In Dubbo config module, all SPI points have related attributes or labels, we can choose the specific SPI implementation by using its name. Like: - -```xml - -``` - -## SPI Features - -### SPI Auto Wrap - -Auto wrap the SPI's Wrapper class. `ExtensionLoader` loads the SPI implementation, if the SPI has a copy instructor, it will be regarded as the SPI's Wrapper class. - -Wrapper class content: - -```java -package com.alibaba.xxx; - -import org.apache.dubbo.rpc.Protocol; - -public class XxxProtocolWrapper implements Protocol { - Protocol impl; - - public XxxProtocolWrapper(Protocol protocol) { impl = protocol; } - - //after interface method is executed, the method in extension will be executed - public void refer() { - //... some operation - impl.refer(); - // ... some operation - } - - // ... -} -``` - -Wrapper class also implements the same SPI interface, but Wrapper is not the real implementation. It is used for wrap the real implementation returned from the `ExtensionLoader`. The real returned instance by `ExtensionLoader` is the Wrapper class instance, Wrapper holder the real SPI implementation class. - -There can be many Wrapper for one spi, simply add one if you need. - -With Wrapper class, you will be able to move same logics into Wrapper for all SPIs. Newly added Wrapper class add external logics for all SPIs, looks like AOP, Wrapper acts as a proxy for SPI. - -### SPI Auto Load - -when loading the SPI, Dubbo will auto load the depency SPI. When one SPI implementation contains attribute which is also an SPI of another type,`ExtensionLoader` will automatically load the depency SPI. `ExtensionLoader` knows all the members of the specific SPI by scanning the setter method of all implementation class. - -Demo: two SPI `CarMaker`(car maker)、`WheelMaker` (wheel maker) - -Intefaces look like: - -```java -public interface CarMaker { - Car makeCar(); -} - -public interface WheelMaker { - Wheel makeWheel(); -} -``` - -`CarMaker`'s implementation: - -```java -public class RaceCarMaker implements CarMaker { - WheelMaker wheelMaker; - - public void setWheelMaker(WheelMaker wheelMaker) { - this.wheelMaker = wheelMaker; - } - - public Car makeCar() { - // ... - Wheel wheel = wheelMaker.makeWheel(); - // ... - return new RaceCar(wheel, ...); - } -} -``` - -when `ExtensionLoader` loads `CarMaker`'s implementation `RaceCarMaker`, the method `setWheelMaker` needs paramType `WheelMaker` which is also a SPI, It will be automatically loaded. - -This brings a new question:How `ExtensionLoader` determines which implementation to use when load the injected SPI. As for this demo, when existing multi `WheelMaker` implementation, which one should the `ExtensionLoader` chooses. - -Good question, we will explain it in the following chapter: SPI Auto Adaptive. - -### SPI Auto Adaptive - -The depency SPI that `ExtensionLoader` injects is an instance of `Adaptive`, the real spi implementation is known until the adaptive instance is executed. - -Dubbo use URL (containing Key-Value) to pass the configuration. - -The SPI method invocation has the URL parameter(Or Entity that has URL attribute) - -In this way depended SPI can get configuration from URL, after config all SPI key needed, configuration information will be passed from outer by URL. URL acts as a bus when passing the config information. - -Demo: two SPI `CarMaker`、`WheelMaker` - -interface looks like: - -```java -public interface CarMaker { - Car makeCar(URL url); -} - -public interface WheelMaker { - Wheel makeWheel(URL url); -} -``` - -`CarMaker`'s implementation: - -```java -public class RaceCarMaker implements CarMaker { - WheelMaker wheelMaker; - - public void setWheelMaker(WheelMaker wheelMaker) { - this.wheelMaker = wheelMaker; - } - - public Car makeCar(URL url) { - // ... - Wheel wheel = wheelMaker.makeWheel(url); - // ... - return new RaceCar(wheel, ...); - } -} -``` - -when execute the code above - -```java -// ... -Wheel wheel = wheelMaker.makeWheel(url); -// ... -``` - -, the injected `Adaptive` object determine which `WheelMaker`'s `makeWheel` method will be executed by predefined Key. Such as `wheel.type`, key `url.get("wheel.type")` will determine `WheelMake` implementation. The logic of`Adaptive` instance of fixed, getting the predefined Key of the URL, dynamically creating the real implementation and execute it. - -For Dubbo, the SPI `Adaptive` implementation in `ExtensionLoader` is dynamically created when dubbo is loading the SPI. Get the Key from URL, the Key will be provided through `@Adaptive` annotation for the interface method definition. - -Below is Dubbo Transporter SPI codes: - -```java -public interface Transporter { - @Adaptive({"server", "transport"}) - Server bind(URL url, ChannelHandler handler) throws RemotingException; - - @Adaptive({"client", "transport"}) - Client connect(URL url, ChannelHandler handler) throws RemotingException; -} -``` - -for the method bind(), Adaptive will firstly search `server` key, if no Key were founded then will search `transport` key, to determine the implementation that the proxy represent for. - - -### SPI Auto Activation - -As for Collections SPI, such as: `Filter`, `InvokerListener`, `ExportListener`, `TelnetHandler`, `StatusChecker` etc, multi implementations can be loaded at one time. User can simplify configuration by using auto activation, Like: - -```java -import org.apache.dubbo.common.extension.Activate; -import org.apache.dubbo.rpc.Filter; - -@Activate // Active for any condition -public class XxxFilter implements Filter { - // ... -} -``` - -Or: - -```java -import org.apache.dubbo.common.extension.Activate; -import org.apache.dubbo.rpc.Filter; - -@Activate("xxx") // when configed xxx parameter and the parameter has a valid value,the SPI is activated, for example configed cache="lru", auto acitivate CacheFilter. -public class XxxFilter implements Filter { - // ... -} -``` - -Or: - -```java -import org.apache.dubbo.common.extension.Activate; -import org.apache.dubbo.rpc.Filter; - -@Activate(group = "provider", value = "xxx") // only activate for provider, group can be "provider" or "consumer" -public class XxxFilter implements Filter { - // ... -} -``` - - -[^1]: Note: The config file here is in you own jar file, not in dubbo release jar file, Dubbo will scan all jar files with the same filename in classpath and then merge them together -[^2]: Note: SPI will be loaded in singleton pattern(Please ensure thread safety), cached in `ExtensionLoader` - - diff --git a/content/en/docs/v2.7/dev/TCK.md b/content/en/docs/v2.7/dev/TCK.md deleted file mode 100644 index bfe47bff93c8..000000000000 --- a/content/en/docs/v2.7/dev/TCK.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -type: docs -title: "Compatibility Test" -linkTitle: "TCK" -weight: 13 -description: "Dubbo compatibility test" ---- - - -Dubbo's protocol, communication, serialization, registry, load balancing and other SPI all offer alternative strategies for different application scenarios while our test cases are very scattered. Ours is always uncertain whether it can satisfy the complete contract of the extension point when users need to add a new implementation. - -Thus we need to use TCK (Technology Compatibility Kit) for the core extension points. When users add a new implementaion, compatibility with the rest of the framework can be ensured with TCK. This can effectively improve the overall health and also facilitate the access of the third party extenders, which accelerates the maturity of the open source community. - -Xingzhi from the open source community is already working on this part. His preliminary idea is to build a TCK framework for Dubbo drawing on the CDI-TCK of JBoss first, then realize the TCK implementing case of Dubbo. - -Reference:http://docs.jboss.org/cdi/tck/reference/1.0.1-Final/html/introduction.html - -Anyone interested is welcomed to work on this together. - -#### Protocol TCK - -> TODO - -#### Registry TCK - -> TODO \ No newline at end of file diff --git a/content/en/docs/v2.7/dev/_index.md b/content/en/docs/v2.7/dev/_index.md deleted file mode 100755 index 596a4788d755..000000000000 --- a/content/en/docs/v2.7/dev/_index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -type: docs -title: "Dubbo Developer Guide" -linkTitle: "Developer" -weight: 20 -description: "Developer guide" ---- - -This book dives into the design principles of dubbo, mainly covers the following topics: extension, coding styles, version, build, etc. - diff --git a/content/en/docs/v2.7/dev/build.md b/content/en/docs/v2.7/dev/build.md deleted file mode 100644 index 6836539a6118..000000000000 --- a/content/en/docs/v2.7/dev/build.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -type: docs -title: "Source Code Build" -linkTitle: "Build" -weight: 1 -description: "Build dubbo from source code" ---- - - -## Checkout - -checkout the lastest project source code with commands blow: - -```sh -git clone https://github.com/apache/dubbo.git dubbo -``` - -## Branches - -We use `master` as the major branch for new feature development, and use other branches for maintenance. Tags for all versions can be checked via https://github.com/apache/dubbo/tags. - -## Building - -Dubbo relies on [maven](http://maven.apache.org) as the building tool. - -Requirements: - -* Java above 1.8 version -* Maven version 2.2.1 or above - -The following `MAVEN_OPTS`should be configured before building: - -```sh -export MAVEN_OPTS=-Xmx1024m -XX:MaxPermSize=512m -``` - -build with below command: - -```sh -mvn clean install -``` - -skip testing using below building command: - -```sh -mvn install -Dmaven.test.skip -``` - -## Building jar package of source code - -build Dubbo source code jar package with below command. - -```sh -mvn clean source:jar install -Dmaven.test.skip -``` -and modify the dubbo dependency in your sample project to the SANPSHOT version of the local repository, and then use remote debugger to debug dubbo. - - -## IDE support - -use below command to generate IDE. - -### Intellij Idea - -```sh -mvn idea:idea -``` - -### Eclipse - -```sh -mvn eclipse:eclipse -``` - -Importing into eclipse - -Firstly, a maven repository needs to be configured in eclipse. Define `M2_REPO` and point it to the local maven repository by clicking `Preferences -> Java -> Build Path -> Classpath`. - - -Use the following maven command as well: - -```sh -mvn eclipse:configure-workspace -Declipse.workspace=/path/to/the/workspace/ -``` - -1. view the source code through https://github.com/apache/dubbo -2. path under UNIX is ${HOME}/.m2/repository, path under Windows is C:\Documents and Settings\\.m2\repository - diff --git a/content/en/docs/v2.7/dev/checklist.md b/content/en/docs/v2.7/dev/checklist.md deleted file mode 100644 index a27449326c44..000000000000 --- a/content/en/docs/v2.7/dev/checklist.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -type: docs -title: "Checklist" -linkTitle: "Checklist" -weight: 11 -description: "Checklist before release" ---- - - -## Checklist before release - -* github milestones -* github change lists -* Travis CI -* test code -* find bugs - -## Checklist for bigfix versions - -* Create a _github issue_ before coding -* Create _unit test_ before bugfix -* Review -* Test your code (Normal process / Abnormal process) -* Record your design on _github issue_ -* Complete javadoc and comment in code -* Manager for every version, responsible for scope and check \ No newline at end of file diff --git a/content/en/docs/v2.7/dev/code-smell.md b/content/en/docs/v2.7/dev/code-smell.md deleted file mode 100644 index 615d96339cc8..000000000000 --- a/content/en/docs/v2.7/dev/code-smell.md +++ /dev/null @@ -1,211 +0,0 @@ ---- -type: docs -title: "Bad Smell" -linkTitle: "Bad Smell" -weight: 12 -description: "Bad code smells which should be avoided" ---- - -Ugly Dubbo design or implementation will be record here. - -## URL Convertion - -### 1. Point to Point Service export and refer - -service directly export: - -``` -EXPORT(dubbo://provider-address/com.xxx.XxxService?version=1.0.0") -``` - -service directly refer: - -``` -REFER(dubbo://provider-address/com.xxx.XxxService?version=1.0.0) -``` - -### 2. Export servie by registry - -export service to registry: - -``` -EXPORT(registry://registry-address/org.apache.dubbo.registry.RegistrySerevice?registry=dubbo&export=ENCODE(dubbo://provider-address/com.xxx.XxxService?version=1.0.0)) -``` - -accquire registry: - -``` -url.setProtocol(url.getParameter("registry", "dubbo")) -GETREGISTRY(dubbo://registry-address/org.apache.dubbo.registry.RegistrySerevice) -``` - -registry service address: - -``` -url.getParameterAndDecoded("export")) -REGISTER(dubbo://provider-address/com.xxx.XxxService?version=1.0.0) -``` - -### 3. Refer service from registry - -refer service from registry: - -``` -REFER(registry://registry-address/org.apache.dubbo.registry.RegistrySerevice?registry=dubbo&refer=ENCODE(version=1.0.0)) -``` - -accquire registry: - -``` -url.setProtocol(url.getParameter("registry", "dubbo")) -GETREGISTRY(dubbo://registry-address/org.apache.dubbo.registry.RegistrySerevice) -``` - -subscribe service address: - -``` -url.addParameters(url.getParameterAndDecoded("refer")) -SUBSCRIBE(dubbo://registry-address/com.xxx.XxxService?version=1.0.0) -``` - -notify service address: - -``` -url.addParameters(url.getParameterAndDecoded("refer")) -NOTIFY(dubbo://provider-address/com.xxx.XxxService?version=1.0.0) -``` - -### 4. Registry push route rule - -registry push route rule: - -``` -NOTIFY(route://registry-address/com.xxx.XxxService?router=script&type=js&rule=ENCODE(function{...})) -``` - -accquire routers: - -``` -url.setProtocol(url.getParameter("router", "script")) -GETROUTE(script://registry-address/com.xxx.XxxService?type=js&rule=ENCODE(function{...})) -``` - -### 5. Load route rule from file - -load route rule from file: - -``` -GETROUTE(file://path/file.js?router=script) -``` - -accquire routers: - -``` -url.setProtocol(url.getParameter("router", "script")).addParameter("type", SUFFIX(file)).addParameter("rule", READ(file)) -GETROUTE(script://path/file.js?type=js&rule=ENCODE(function{...})) -``` - -## Invoke parameters - -* path service path -* group service group -* version service version -* dubbo current dubbo release version -* token verify token -* timeout invocation timeout - -## SPI Loading - -### 1. SPI Auto Adaptive - -When ExtensionLoader loads SPI, It will check spi attributes(using set method) . If one attribute is SPI, ExtensionLoader will load the SPI implementation. Auto injected object is an adaptive instance(proxy) ,because the real implementation is confirmed only in execution stage.。when adaptive spi is invoked, Dubbo will choose the real implementation and executes it. Dubbo choose the right implementation according to the parameters that the mehod defines. - -All the inner SPIs that Dubbo defines have the URL parameter defined for the method invocation. Adaptive SPI uses URL to determine which implementation is needed. One specific Key and Value in the URL confirms the usage of the specific implementation, All these is done by adding `@Adaptive` annotation. - -```java -@Extension -public interface Car { - @Adaptive({"http://10.20.160.198/wiki/display/dubbo/car.type", "http://10.20.160.198/wiki/display/dubbo/transport.type"}) - public run(URL url, Type1 arg1, Type2 arg2); -} -``` - -For the rules above,ExtensionLoader will create a adaptive instance for each SPI injected. - -ExtensionLoader generated adaptive classes look like : - -```java -package ; - -public class $Adpative implements { - public () { - if(parameters containing URL Type?) using URL parameter - else if(method returns URL) using the return URL - # - - if(URL accquired == null) { - throw new IllegalArgumentException("url == null"); - } - - According to the Key order from @Adaptive annotation,get the Value from the URL as the real SPI name - if no value is found then use the default SPI implementation。If no SPI point, throw new IllegalStateException("Fail to get extension"); - - Invoke the method using the spi and return the result. - } - - public () { - throw new UnsupportedOperationException("is not adaptive method!"); - } -} -``` - -`@Adaptive` annotation usage: - -If no value is configed for those Keys in URL,default SPI implementation is used。For example ,String[] {"key1", "key2"},firstly Dubbo will look up value for key1 and use it as SPI name;if key1 value is not founded then look up for key2,if value of key2 is also not found ,then use default spi implementation. If no default implementation is configed, then the method will throw IllegalStateException。if not configed , then default implement is lower case of the interface class full package name. For Extension interface `org.apache.dubbo.xxx.YyyInvokerWrapper` , default value is `new String[] {"yyy.invoker.wrapper"}` - -## Callback Function - -### 1. Parameter Callback - -main theory : in the persistent connection for one consumer->provider,export a service in Consumer side,provider side can reversely call the instance in consumer side. - -Implement details: - -* For exchanging interface instance in transmition, auto export and auto refer is implemented in DubboCodec . Need to seperate business logic and codec logic. -* you will need to judge whether needing callback when getting exporter from invocation,if needed, get the callback instance id from the attachments. By using this method, consumer side can implement the callback interface with different implementations. - -### 2. Event Notification - -main theory : when Consumer executing invoke method,judging if any configuration for onreturn/onerror... put the method for onreturn to the callback list of the async invocatioin. - -Implement details:parameters is passed using URL,but string-object is not supported for URL, so the method is stored in staticMap,it needs to be optimized. - -## Lazy Connection - -DubboProtocol specific features, default disabled - -When client creating proxy for server, do not establish TCP persistent connection at first, only init the connecton when data is needing transmision. - -This feather will disable the connection retry policy , resend the data again(if connection is lost when sending data ,try to establish a new connection to send data) - -## Share Connection - -DubboProtocol specific features, default enabled。 - -JVM A export many services,JVM B refer more than one services of A,Share Connection means those different services invocations between A and B uses the same TCP connection to transmit data, reducing server connections. - -Implement details:when using share connection for the same address,you need pay more attention to the invoker's destroy action.on one hand, you should close the connection when all the invokers refering the same address is destroyed, on another hand ,you should not close the connection when not all of the invokers are destroyed. In design implementation, we uses a strategy called reference count , we create a connection called Lazy connection for exceptions not affacting business when closing the connection just in case. - -## sticky policy - -when existing many providers and configing the sticky policy,invocation will be sent to the same provider as last invocation. Sticky Policy opens the lazy attribute of connection, for avoiding open useless connectons. - -## provider selecting logic - -0. existing multi providers,firstly select by Loadbalance 。If the selected provider is available ,then just doing the invocation -1. If the selected provider is not available in stage 1, then choose from the remaining ,if available then doing the inovation -2. If all providers are not available , rescan the list(not choosen invoker first),juding if any provider is available, if existing,doing the invocatiion. -3. If no available provider in stage 3, then the next invoker of the invoker of stage 1 will be choosen(if not the last one),avoiding collision. - - - diff --git a/content/en/docs/v2.7/dev/coding.md b/content/en/docs/v2.7/dev/coding.md deleted file mode 100644 index 5e55eb3215e6..000000000000 --- a/content/en/docs/v2.7/dev/coding.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -type: docs -title: "Coding Convention" -linkTitle: "Coding Convention" -weight: 12 -description: "Dubbo coding convention" ---- - -## Code style - -The source and JavaDoc of Dubbo follow below specifications: - -* [Code Conventions for the Java Programming Language](http://www.oracle.com/technetwork/java/codeconvtoc-136057.html) -* [How to Write Doc Comments for the Javadoc Tool](http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html) - -## Exception and Logging - -* Log more context information as possible, such as error reason, error server address, client address, registry center address, dubbo version and so on. -* Try to put the main cause at the front, and display all other context information with key-value paris after it. -* Log is not printed where the exception is thrown, log level is determined by the final exception handler, and must print log when dicarding exception. -* `ERROR` log means NEED TO ALARM, `WARN` log means COULD AUTO RECOVERY, `INFO` long mean NORMAL. -* Suggestion: config `ERROR` log in Monitor center for real-time alarm, summary and send `WARN` log weekly. -* `RpcException` is the ONLY external exception of Dubbo,all internal exceptions mush be transfered to `RpcException` if need to throw out to user. -* `RpcException` CAN NOT have sub-class, all types of information are identified with ErrorCode in order to keep compatible. - -## Configuration and URL - -* Use initials and camelCase for multiple words for object properties [^1]. -* Use lowercase and split by '-' for multiple words for config properties [^2]. -* Use lowercase and split by '.' for multiple words for URL properties [^3]. -* Use URL transfer parameters as possible, Don't define Map or other types, config information also transfer to URL style. -* Minimize URL nesting to keep URL simplicity. - -## Unit testing and integration testing - -* Use JUnit and EasyMock for unit testing, use TestNG for integration testing, use DBUnit for database testing. -* Don't put large integration test case in unit testing for running speed of unit test case. -* Use `try...finally` or `tearDown` to release resource for all test cases of unit testing. -* Minimize test case that with `while` loop which need waiting repsonse, use to make the logic in timer as function for timer and net testing. -* For fail-safe testing, unified use `LogUtil` assertion log output. - -## Extension point base class and AOP - -* AOP class should be named as `XxxWrapper`,Base class should be named as `AbstractXxx`. -* Use AOP for combine relationship between extension points, `ExtensionLoader` only loads extension points, including AOP extension. -* Try to use Ioc inject dependency of extension points, Don't direct dependent on factory method of `ExtensionLoader`. -* Try to use AOP implement the common action of extension points, instead of using base class, such as the `isAvailable` checking before load balancing, which is independent of load balance. Close the URL paramters which no need to check. -* Use base class for abstaction for a variety of similar types, such as RMI, Hessian 3rd protocols which have generated interface proxy, only transfer interface proxy to `Invoker` to complete bridging, and public base class can do the logic. -* The base class is also part of the SPI, and each extension should have a convenient base class support. - -## Module and packaging - -* Base on reusability for packaging, dividing the interface, base class and large implementation into separate modules. -* Put all interfaces under the base package of module, and put base classes in support subpackage, different implementations are placed under the subpackage named by extension point. -* Try to keep subpackage dependent on parent package, NOT reverse. - -[^1]: Java convention -[^2]: Spring convention -[^3]: Dubbo convention \ No newline at end of file diff --git a/content/en/docs/v2.7/dev/contract.md b/content/en/docs/v2.7/dev/contract.md deleted file mode 100644 index 9b95b6d46efb..000000000000 --- a/content/en/docs/v2.7/dev/contract.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "Public Agreement" -linkTitle: "Public Agreement" -weight: 6 -description: "Dubbo public agreement" ---- - -This document is Dubbo public agreement, we expect all extension points comply with it. - -## URL - -* All extension points must include URL parameter, design URL as a context information which throughouts the whole extension point design system. -* URL standard style: `protocol://username:password@host:port/path?key=value&key=value` - -## Logging - -* Print `ERROR` log for unrecoverable and NEED TO ALARM situation. -* Print `WARN` log for recoverable exception or transient state inconsistency. -* Print `INFO` log for normally status. \ No newline at end of file diff --git a/content/en/docs/v2.7/dev/design.md b/content/en/docs/v2.7/dev/design.md deleted file mode 100644 index 57f28f6a7a2a..000000000000 --- a/content/en/docs/v2.7/dev/design.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -type: docs -title: "Framework Design" -linkTitle: "Design" -weight: 2 -description: "Dubbo frame design" ---- - -## Overall design - -![/dev-guide/images/dubbo-framework.jpg](/imgs/dev/dubbo-framework.jpg) - -Image description: - -* Left area with light blue background shows service consumer interfaces, Right area with light green background shows service provider interfaces, center area shows both side interfaces. -* The image is divided into 10 layers from the bottom to the top, and the layers are one-way dependence. The black arrow on the right represents the dependency between layers, and each layer can be stripped from the upper layer to be reused, the Service and Config layers are API, and the other layers are SPI. -* Green boxes are extension interfaces, blue boxes are implementation classes, image only shows implementation class of associated layers. -* The blue dashed line is the initialization process, which is assembly chain when starting, red line for the method call process, which is calling chain when running, purple triangle arrow is inherited, can treat subclass as the same node of parent class, text of lines are the method invocation. - -## Layer description - -* **config layer**: external config interface, `ServiceConfig` and `ReferenceConfig` is the center of the layer, you can directly initialize config class, also can generate config class by spring. -* **proxy layer**: transparent proxy of service interface, generate client Stub of service and server Skeletion of service, `ServiceProxy` is the center, extension interface is `ProxyFactory`. -* **registry layer**: encapsulation of service registry and discovery, service URL is the center, extension interfaces are `RegistryFactory`, `Registry` and `RegistryService`. -* **cluster layer**: encapsulation of cluster of muliple providers and load balance, and bridging registration center, `Invoker` is the center, extension interfaces are `Cluster`, `Directory`, `Router`, `LoadBalance`. -* **monitor layer**: monitor of RPC call times and call execute time, `Statistics` is the center, extension interface are `MonitorFactory`, `Monitor`, `MonitorService` -* **protocol layer**: encapsulation of RPC, `Invocation` and `Result` are the center, extension interfaces are `Protocol`, `Invoker`, `Exporter` -* **exchange layer**: encapsulation of request and response, synchronous transfer asynchronous, `Request` and `Response` are the center, extension interfaces are `Exchanger`, `ExchangeChannel`, `ExchangeClient`, `ExchangeServer` -* **transport layer**: abstraction of mina and netty, `Message` is the center, extension interfaces are `Channel`, `Transporter`, `Client`, `Server`, `Codec` -* **serialize layer**: reusable tools, extension interfaces are `Serialization`, `ObjectInput`, `ObjectOutput`, `ThreadPool` - -## Relationship description - -* In RPC, Protocol is the core layer, it means that you can complete RPC calling by Protocol + Invoker + Exporter, then filter at the main process of Invoker. -* Consumer and Provider are abstraction concepts, just want you have a more intuitive understanding of which classes belong to the client and server side, the reason not use Client and Server is that Dubbo uses Provider, Consumer, Registry, Monitor divide logical topology node in many scenes, keep the concept of unity. -* Cluster is external concept, the purpose of Cluster is that make various Invoker disguise to one Invoker, so that we just pay attention to the Invoker in Protocol layer, adding Cluster or removing Cluster will not affect other layers, because we don't need Cluster when only have one provider. -* The Proxy layer encapsulates the transparent proxy for all interfaces, and in other layers with Invoker as the center, turn Invoker into interface, or turn interface implementation into Invoker by Proxy only when exposuring to user. RPC still work even removing Proxy layer, but not so transparent, making remote service calling don't look like local service calling. -* Remoting is the implemetation of Dubbo protocols, you can remove Remoting if choosing RMI. The Remoting is divided into Transport layer and Exchange layer, Transport layer is responsible for one-way message transmission, it's abstraction of Mina, Netty, Grizzly, it also can extend UDP transmission. The Exchange layer encapsulates the Request-Response semantics over the transport layer. -* Actually Registry and Monitor are not at the same layer, they are independent nodes, draw them together by layer just for global view. - -## Modules packaging - -![/dev-guide/images/dubbo-modules.jpg](/imgs/dev/dubbo-modules.jpg) - -Modules description: - -* **dubbo-common module**: includes Util classes and common modules. -* **dubbo-remoting module**: is Dubbo protocol implementation, no need to use this module if using RMI for RPC. -* **dubbo-rpc module**: abstraction of various protocols, and dynamic proxy, only one to one call, not concerned with the management of cluster. -* **dubbo-cluster module**: disguise many service providers as one provider, including load balancing, fault tolerance, routing, etc. the address list of clusters can be either static or send by registry. -* **dubbo-registry module**: Based on the cluster of registry send address and the abstraction of various registry centers. -* **dubbo-monitor module**: statistics of service call times, call time, call chain tracked services. -* **dubbo-config module**: is Dubbo external API, users use Dubbo by Config, hide Dubbo details. -* **dubbo-container module**: is a Standlone container, just use Main method to load Spring, because usually service no need Tomcat/JBoss features. - -Package dividing according to the layer structure, and the difference with layer dividing: - -* container is service container, for service running deployment, not showed in the image. -* protocol layer and proxy layer are placed in RPC module, they are the core of RPC module, you can use these 2 layers complete RPC call when only have 1 provider. -* transport layer and exchange layer are placed in remoting module, for RPC call base comminucation. -* serialize layer is placed in common module, for reuse. - -## Dependence relationship - -![/dev-guide/images/dubbo-relation.jpg](/imgs/dev/dubbo-relation.jpg) - -Image description: - -* The boxes in image, Protocol, Cluster, Proxy, Service, Container, Registry, Monitor represent layer or module, the blues mean interactive with business, the greens mean only internal interactive with Dubbo. -* The backgroud boxes in image, Consumer, Provider, Registry, Monitor represent deployment logical topology node. -* The blue dashed line in the image is called for initialization, the red dashed line is called asynchronously for runtime, and the red line is called synchronously for runtime. -* The image only includes RPC layer, don't includes Remoting layer, the whole Remoting hides in Protocol layer. - -## Call chain - -Expand the red call chain of the overall design map: - -![/dev-guide/images/dubbo-extension.jpg](/imgs/dev/dubbo-extension.jpg) - -## Expose service sequence - -Expand the initialization chain of service provider exposes service which at the left of the overall design map, the sequence diagram shows below: - -![/dev-guide/images/dubbo-export.jpg](/imgs/dev/dubbo-export.jpg) - -## Reference service sequence - -Expand the initialization chain of service consumer references service which at the right of the overall design map, the sequence diagram shows below: - -![/dev-guide/images/dubbo-refer.jpg](/imgs/dev/dubbo-refer.jpg) - -## Domain model - -The core domain models of Dubbo: - -* Protocol is service domain, it is the main function entrance of Invoker exposure and reference, it is responsible for the life cycle management of Invoker. -* Invoker is entity domain, it is the core model of Dubbo, all the other models are disturbed, or converted to it, it represents an executable, you can call it by calling invoke, it can be a local implementation, a remote implementation, or a cluster implementation. -* Invocation is session domain, it holds variables in the calling process, such as the method name, the parameters, and so on. - -## Base design principle - -* Use Microkernel + Plugin design pattern,Microkernel only responsible for assembly Plugin, the functions of Dubbo are implemented by extension points, it means that all functions of Dubbo can be replaced by self defined extension by user. -* Use URL to be the startdard format of config information, all extension points transfer config information by URL. - -More design principles refer to: [Framework design principle](../principals) \ No newline at end of file diff --git a/content/en/docs/v2.7/dev/implementation.md b/content/en/docs/v2.7/dev/implementation.md deleted file mode 100644 index 649333ab10d8..000000000000 --- a/content/en/docs/v2.7/dev/implementation.md +++ /dev/null @@ -1,231 +0,0 @@ ---- -type: docs -title: "Implementation details" -linkTitle: "Implementation" -weight: 4 -description: "Dubbo implementation details" ---- - -## Initialization details - -### Service parsing - -Based on `META-INF/spring.handlers` config in dubbo.jar, Spring calls `DubboNamespaceHandler` when meeting dubbo namespace. - -All Dubbo tags are parsed by `DubboBeanDefinitionParser`, based on one to one attribute mapping, the XML label is parsed as a Bean object. - -Transfer Bean object to URL, and transfer all attributes of Bean to URL parameters when `ServiceConfig.export()` or `ReferenceConfig.get()` initialization. - -Then pase URL to [Protocol extension point](../impls/protocol), based on [Extension point adaptive mechanism](../spi/) of extension point, processing service exposure or reference for different protocols according to URL protocol header. - -### Service Exposure - -#### 1. Only expose service port: - -Direct exposing to provider when have not Registry, [^1], the URL format which parsing by `ServiceConfig`: -`dubbo://service-host/com.foo.FooService?version=1.0.0`. - -Based on extension point adaptive mechanism, call `export()` method of `DubboProtocol` and open server port by identifying `dubbo://` protocol header of URL. - -#### 2. Expose to Registry: - -Expose provider address to Registry [^2], the URL format which parsing by `ServiceConfig`: `registry://registry-host/org.apache.dubbo.registry.RegistryService?export=URL.encode("dubbo://service-host/com.foo.FooService?version=1.0.0")`, - -Based on extension point adaptive mechanism, call `export()` method of `RegistryProtocol` by identifying `registry://` protocol header, register the provider URL parameter of `export` to Registry. - -Resend to `Protocol` extension point to do exposure: `dubbo://service-host/com.foo.FooService?version=1.0.0`, then based on extension point adaptive mechanism, call `export()` method of `DubboProtocol` and open server port by identifying `dubbo://` protocol header of provider URL. - -### Service Reference - -#### 1. Direct connect service - -Direct connect provider when have not Registry [^3], the URL format which parsing by `ReferenceConfig`: `dubbo://service-host/com.foo.FooService?version=1.0.0`. - -Based on extension point adaptive mechanism, call `refer()` method of `DubboProtocol` by identifying `dubbo://` protocol header of URL, and return provider reference. - -#### 2. Service Registry discovery - -Discover provider address by Registry [^4], the URL format which parsing by `ReferenceConfig`: -`registry://registry-host/org.apache.dubbo.registry.RegistryService?refer=URL.encode("consumer://consumer-host/com.foo.FooService?version=1.0.0")`. - -Based on extension point adaptive mechanism, call `refer()` method of `RegistryProtocol` by identifying `registry://` protocol header of URL, then based on the condition of parameter of `refer` to search provider URL, for example: `dubbo://service-host/com.foo.FooService?version=1.0.0`. - -Then based on extension point adaptive mechanism, call `refer()` method of `DubboProtocol` to get provider reference by identifying `dubbo://` protocol header of provider URL. - -Then `RegistryProtocol` disguise various provider references to single provider by `Cluster` extension point and return. - -### Service Filter - -Based on extension point adaptive mechanism, all `Protocol` extension points are auto wrapped `Wrapper` class. - -Based on `ProtocolFilterWrapper` class, make all `Filter` as chain, call the real reference at the end of the chain. - -Based on `ProtocolListenerWrapper` class, make all `InvokerListener` and `ExporterListener` as list, perform call back before and after exposure and reference. - -All additional functions would be implementated by `Filter`, including Monitor. - -## RPC details - -### The detail process of exposing service by service provider - -![/dev-guide/images/dubbo_rpc_export.jpg](/imgs/dev/dubbo_rpc_export.jpg) - -The above image shows the main process of exposing service by service provider: - -First `ServiceConfig` class get the actual class `ref` that provides service(e.g. 如:HelloWorldImpl), then generating a `AbstractProxyInvoker` instance by the `getInvoker` method of `ProxyFactory` class, to this step, complete the transformation of specific service to `Invoker`, next is the process of converting `Invoker` to `Exporter`. - -The key of Dubbo processing service exposure is the process of converting `Invoker` to `Exporter`, the red part in the above image. Here we introduce the implementation of the two typical protocols, Dubbo and RMI: - -#### Dubbo implementation - -The transformation from `Invoker` of Dubbo protocol to `Exporter` takes place in the `export` method of `DubboProtocol` class, it mainly opens the socket to listen service and receive all kinds of requests sent by the client, and the communication details are implementated by Dubbo itself. - -#### RMI implementation - -The transformation from `Invoker` of RMI protocol to `Exporter` takes place in the `export` method of `RmiProtocol` class, the RMI service is implementated by Spring, Dubbo or JDK, and the communication details are implementated by JDK, which saves a lot of work. - -### The detail process of serving service for service consumer - -![/dev-guide/images/dubbo_rpc_refer.jpg](/imgs/dev/dubbo_rpc_refer.jpg) - -The above image is the main process of service consumption: - -First, the `init` method of `ReferenceConfig` class calls the `refer` method of `Protocol` to generate `Invoker` instance(such as the red part in the above image), which is the key of service consumption. Then the `Invoker` is converted to the interface required by the client (such as: HelloWorld). - -For each protocol such as RMI/Dubbo/Web service, the details they call `refer` method generate `Invoker` instance are similar to the previous section. - -### Invoker everywhere - -Because of `Invoker` is a very important concept in the Dubbo domain model, many of the design ideas are close to it. This makes `Invoker` permeate the entire implementation code, and it's really easy to mix up for people who have just started Dubbo. - -Let's use a simple image below to describe the 2 important `Invoker`: service provider `Invoker` and service consumer `Invoker`: - -![/dev-guide/images/dubbo_rpc_invoke.jpg](/imgs/dev/dubbo_rpc_invoke.jpg) - -To better explain the above image, we provide the below code examples of service consumption and providers: - -Service consumer code: - -```java -public class DemoClientAction { - - private DemoService demoService; - - public void setDemoService(DemoService demoService) { - this.demoService = demoService; - } - - public void start() { - String hello = demoService.sayHello("world"); - } -} -``` - -The `DemoService` in above code is the proxy of service consumer in above image, user can call `Invoker` [^5] which implementate the real RPC by the proxy. - -Service provider code: - -```java -public class DemoServiceImpl implements DemoService { - - public String sayHello(String name) throws RemoteException { - return "Hello " + name; - } -} -``` - -The above class would be encapsulated to be a `AbstractProxyInvoker` instance, and create a new `Exporter` instance, then find corresponding `Exporter` instance and call its corresponding `AbstractProxyInvoker` instance when network communication layer recieve request, so that real call service provider code. There are some other `Invoker` classes, but the above 2 are the most important. - -## Remote communication details - -### Protocol header agreement - -![/dev-guide/images/dubbo_protocol_header.jpg](/imgs/dev/dubbo_protocol_header.png) - -- Magic - Magic High & Magic Low (16 bits) - - Identify protocol version, Dubbo protocol: 0xdabb - -- Req/Res (1 bit) - - Identify a request or response. request: 1; response: 0. - -- 2 Way (1 bit) - - Only useful when Req/Res is 1(request), identifying if you expect to return a value from the server. Set to 1 if a return value from the server is required. - -- Event (1 bit) - - Identifies whether it is an event message, for example, a heartbeat event. Set to 1 if this is an event. - -- Serialization ID (5 bit) - - Identifies the serialization type: for example, the value of fastjson is 6. - -- Status (8 bits) - - Only useful when Req/Res is 0 (response), used to identify the status of the response - - - 20 - OK - - 30 - CLIENT_TIMEOUT - - 31 - SERVER_TIMEOUT - - 40 - BAD_REQUEST - - 50 - BAD_RESPONSE - - 60 - SERVICE_NOT_FOUND - - 70 - SERVICE_ERROR - - 80 - SERVER_ERROR - - 90 - CLIENT_ERROR - - 100 - SERVER_THREADPOOL_EXHAUSTED_ERROR - -- Request ID (64 bits) - - Identifies the only request, the type is long. - -- Data Length (32 bits) - - The length of the serialized content (variable part), counted in bytes, the type is int. - -- Variable Part - - After being serialized by a specific serialization type (identified by the serialization ID), each part is a byte [] or byte. - - - If it is a request packet (Req/Res = 1), each part is: - - Dubbo version - - Service name - - Service version - - Method name - - Method parameter types - - Method arguments - - Attachments - - If it is a response packet (Req/Res = 0), each part is: - - Return value's type (byte), identifying the type of value returned from the server: - - Return null: RESPONSE_NULL_VALUE 2 - - Normal response value: RESPONSE_VALUE 1 - - Exception: RESPONSE_WITH_EXCEPTION 0 - - Return value: response bytes returned from the server - -**Note:** For the variable part, when uses json serialization in current version of Dubbo framework, an additional line break is added as a separator between each part of the content. Please add a new line break after each part of the variable part, such as: - -``` -Dubbo version bytes (line break) -Service name bytes (line break) -... -``` - -### Thread dispatch model - -![/dev-guide/images/dubbo-protocol.jpg](/imgs/dev/dubbo-protocol.jpg) - -* Dispather: `all`, `direct`, `message`, `execution`, `connection` -* ThreadPool: `fixed`, `cached` - - -[^1]: is `` or `` - -[^2]: is `` - -[^3]: is `` - -[^4]: is `` - -[^5]: is one of `DubboInvoker`, `HessianRpcInvoker`, `InjvmInvoker`, `RmiInvoker`, `WebServiceInvoker` diff --git a/content/en/docs/v2.7/dev/impls/_index.md b/content/en/docs/v2.7/dev/impls/_index.md deleted file mode 100755 index a187b6cc4a05..000000000000 --- a/content/en/docs/v2.7/dev/impls/_index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -type: docs -title: "SPI Extension Implementations" -linkTitle: "SPI Impls" -weight: 5 -description: "Existing SPI extension implementations in dubbo" ---- - -SPI extension interface is used for system integration, it's also useful for dubbo contributor to extend dubbo functionality. - diff --git a/content/en/docs/v2.7/dev/impls/cache.md b/content/en/docs/v2.7/dev/impls/cache.md deleted file mode 100644 index 19542836dc2a..000000000000 --- a/content/en/docs/v2.7/dev/impls/cache.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -type: docs -title: "Cache Extension" -linkTitle: "Cache" -weight: 24 ---- - -## Summary - -Cache the return value, use request parameter as the key. - -## Extension Interface - -`org.apache.dubbo.cache.CacheFactory` - -## Extension Configuration - -```xml - - - - - - -``` - -## Existing Extensions - -* `org.apache.dubbo.cache.support.lru.LruCacheFactory` -* `org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory` -* `org.apache.dubbo.cache.support.jcache.JCacheFactory` - - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxCacheFactory.java (CacheFactory implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.cache.CacheFactory (plain text file with contents: xxx=com.xxx.XxxCacheFactory) -``` - -XxxCacheFactory.java: - -```java -package com.xxx; - -import org.apache.dubbo.cache.CacheFactory; - -public class XxxCacheFactory implements CacheFactory { - public Cache getCache(URL url, String name) { - return new XxxCache(url, name); - } -} -``` - -XxxCache.java: - -```java -package com.xxx; - -import org.apache.dubbo.cache.Cache; - -public class XxxCache implements Cache { - public Cache(URL url, String name) { - // ... - } - public void put(Object key, Object value) { - // ... - } - public Object get(Object key) { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.cache.CacheFactory: - -```properties -xxx=com.xxx.XxxCacheFactory -``` diff --git a/content/en/docs/v2.7/dev/impls/cluster.md b/content/en/docs/v2.7/dev/impls/cluster.md deleted file mode 100644 index 0a0dcbd9d325..000000000000 --- a/content/en/docs/v2.7/dev/impls/cluster.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -type: docs -title: "Cluster Extension" -linkTitle: "Cluster" -weight: 5 ---- - - -## Summary - -Group service providers in a cluster, and treat them as one single provider. - -## Extension Interface - -`org.apache.dubbo.rpc.cluster.Cluster` - -## Extension Configuration - -```xml - - - -``` - -## Existing Extensions - -* `org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper` -* `org.apache.dubbo.rpc.cluster.support.FailoverCluster` -* `org.apache.dubbo.rpc.cluster.support.FailfastCluster` -* `org.apache.dubbo.rpc.cluster.support.FailsafeCluster` -* `org.apache.dubbo.rpc.cluster.support.FailbackCluster` -* `org.apache.dubbo.rpc.cluster.support.ForkingCluster` -* `org.apache.dubbo.rpc.cluster.support.AvailableCluster` -* `org.apache.dubbo.rpc.cluster.support.MergeableCluster` -* `org.apache.dubbo.rpc.cluster.support.BroadcastCluster` -* `org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxCluster.java (Cluster implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.cluster.Cluster (plain text file with the content: xxx=com.xxx.XxxCluster) -``` - -XxxCluster.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.cluster.Cluster; -import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker; -import org.apache.dubbo.rpc.cluster.Directory; -import org.apache.dubbo.rpc.cluster.LoadBalance; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.Invocation; -import org.apache.dubbo.rpc.Result; -import org.apache.dubbo.rpc.RpcException; - -public class XxxCluster implements Cluster { - public Invoker merge(Directory directory) throws RpcException { - return new AbstractClusterInvoker(directory) { - public Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { - // ... - } - }; - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.cluster.Cluster: - -```properties -xxx=com.xxx.XxxCluster -``` diff --git a/content/en/docs/v2.7/dev/impls/compiler.md b/content/en/docs/v2.7/dev/impls/compiler.md deleted file mode 100644 index 2c929512dcbc..000000000000 --- a/content/en/docs/v2.7/dev/impls/compiler.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -type: docs -title: "Compiler Extension" -linkTitle: "Compiler" -weight: 13 ---- - -## Summary - -Java compiler, used for byte code dynamic generation for RPC invocation. - -## Extension Interface - -`org.apache.dubbo.common.compiler.Compiler` - -## Extension Configuration - -No configuration required, the extension will be automatically discovered and loaded. - -## Existing Extensions - -* `org.apache.dubbo.common.compiler.support.JdkCompiler` -* `org.apache.dubbo.common.compiler.support.JavassistCompiler` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxCompiler.java (Compiler implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.common.compiler.Compiler (plain text file with the content: xxx=com.xxx.XxxCompiler) -``` - -XxxCompiler.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.compiler.Compiler; - -public class XxxCompiler implements Compiler { - public Object getExtension(Class type, String name) { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.common.compiler.Compiler: - -```properties -xxx=com.xxx.XxxCompiler -``` diff --git a/content/en/docs/v2.7/dev/impls/config-center.md b/content/en/docs/v2.7/dev/impls/config-center.md deleted file mode 100644 index c52aaab58d3e..000000000000 --- a/content/en/docs/v2.7/dev/impls/config-center.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -type: docs -title: "Dubbo Configuration Center Extensions" -linkTitle: "Config Center" -weight: 13 ---- - -## Design Purpose - -The key function of CC(Configuration Center) is to act as a Key-Value store. Dubbo Framework tells CC the key it care about, CC return the corresponding value. - -Divided by application scenarios, CC mainly undertake the following responsibilities in Dubbo Framework: - -- As a external configuration center, CC store configuration files like dubbo.properties, where the key is usually file name like dubbo.properties, and value is content of the file. -- Store single configuration items, like all kinds of switchs, contants, etc. -- Store service governance rules, where the key is usually formated like "ServiceName+RuleType", while value is the specific governance rule. - -Dubbo CC also introduced concepts of `namespace` and `group` to better manage Key-Value pairs by group, those concepts are already built-in in many professional third-party configuration centers. In most cases, `namespace` is used to isolate different tetants, while `group` is used to divid the key set from one tetant into groups. - -Dubbo CC has currently supported Zookeeper, Nacos, Etcd, Consul, Apollo, next we will see how Dubbo CC is mapped to a specific third-party implementation. - -## Extension Interface - -* `org.apache.dubbo.configcenter.DynamicConfigurationFactory` -* `org.apache.dubbo.configcenter.DynamicConfiguration` - -## Existing Extension - -* `org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfigurationFactory` -* `org.apache.dubbo.configcenter.support.nacos.NacosDynamicConfigurationFactory` -* `org.apache.dubbo.configcenter.support.etcd.EtcdDynamicConfigurationFactory` -* `org.apache.dubbo.configcenter.consul.ConsulDynamicConfigurationFactory` -* `org.apache.dubbo.configcenter.support.apollo.ApolloDynamicConfigurationFactory` -* `org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfigurationFactory` - -## Implementation - -### Zookeeper - -Zookeeper provided a tree-structure storage model, the implementation is as follows: - -![image-20190127225608553](/imgs/dev/configcenter_zk_model.jpg) - -namespace, group, key are corresponded to different levels of ZNodes, while value is content of the key ZNode. - -1. External configuration cetner dubbo.properties - - ![image-20190127225608553](/imgs/dev/configcenter_zk_properties.jpg) - - The figure above shows the storage structure of the dubbo.properties file in two different scopes in zookeeper: - - namespace: both are 'dubbo' - - group: 'dubbo' is globally shared by all applications; 'demo-provider' is application level, only affect the specific application - - key: dubbo.properties - -2. Single configuration item - - ![image-20190127225608553](/imgs/dev/configcenter_zk_singleitem.jpg) - - The figure above shows how we set the shutdown wait time to 15000: - - namespace: dubbo - - group: dubbo - - key: dubbo.service.shutdown.wait - - value: 15000 - -3. Service governance rule - - ![image-20190127225608553](/imgs/dev/configcenter_zk_rule.jpg) - - The figure above shows an application-level conditional routing rule: - - - namespace:dubbo - - group:dubbo - - key:governance-conditionrouter-consumer.condition-router, in wich governance-conditionrouter-consumer is application name, condition-router represents condition router. - - - > Notice: - > - > Dubbo support two level of governance rules: application, service. The key format are as follows: - > * application level {application name + rule suffix}, such as: `demo-application.configurators`,`demo-application.tag-router`, etc. - > * service level {service interface name:[version]:[group] + rule suffix}, in which version and group are optional, such as: `org.apache.dubbo.demo.DemoService::.configurators`,`org.apache.dubbo.demo.DemoService:1.0.0:group1.configurators`, etc. - -### Etcd & Consul - -Etcd and Consul are essencially tree-structure storage like Zookeeper, see zookeeper for implementation. - -### Nacos - -Nacos is a professional third-party configuration center, it has a storage structure designed specifically for the configuration center, including built-in concepts like namespace, group, dataid, etc. And these concepts basically correspond to the configuration center of the Dubbo framework abstraction. - -The correspondence with the Zookeeper implementation is as follows: - -![image-20190127225608553](/imgs/dev/configcenter_nacos_model.jpg) - -Refer to the example described in the zookeeper implementation above, where dataid might be: -* External configuration center: dubbo.properties -* Single configuration item: dubbo.service.shutdown.wait -* Service governance rule: org.apache.dubbo.demo.DemoService:1.0.0:group1.configurators - -### Apollo - -Apollo is similar to Nacos. Please refer to the documentation on the Apollo section. diff --git a/content/en/docs/v2.7/dev/impls/container.md b/content/en/docs/v2.7/dev/impls/container.md deleted file mode 100644 index e0a84bed89d9..000000000000 --- a/content/en/docs/v2.7/dev/impls/container.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -type: docs -title: "Container Extension" -linkTitle: "Container" -weight: 22 ---- - - -## Summary - -Service container extension, useful for loading custom contents. - -## Extension Interface - -`org.apache.dubbo.container.Container` - -## Extension Configuration - -```sh -java org.apache.dubbo.container.Main spring jetty log4j -``` - -## Existing Extensions - -* `org.apache.dubbo.container.spring.SpringContainer` -* `org.apache.dubbo.container.spring.JettyContainer` -* `org.apache.dubbo.container.spring.Log4jContainer` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxContainer.java (Container implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.container.Container (plain text file with the content: xxx=com.xxx.XxxContainer) -``` - -XxxContainer.java: - -```java -package com.xxx; - -org.apache.dubbo.container.Container; - - -public class XxxContainer implements Container { - public Status start() { - // ... - } - public Status stop() { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.container.Container: - -```properties -xxx=com.xxx.XxxContainer -``` diff --git a/content/en/docs/v2.7/dev/impls/dispatcher.md b/content/en/docs/v2.7/dev/impls/dispatcher.md deleted file mode 100644 index ff1e8ac09591..000000000000 --- a/content/en/docs/v2.7/dev/impls/dispatcher.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -type: docs -title: "Dispatcher Extension" -linkTitle: "Dispatcher" -weight: 14 ---- - -## Summary - -Thread pool dispatch strategy. - -## Extension Interface - -`org.apache.dubbo.remoting.Dispatcher` - -## Extension Configuration - -```xml - - - -``` - -## Existing Extensions - -* `org.apache.dubbo.remoting.transport.dispatcher.all.AllDispatcher` -* `org.apache.dubbo.remoting.transport.dispatcher.direct.DirectDispatcher` -* `org.apache.dubbo.remoting.transport.dispatcher.message.MessageOnlyDispatcher` -* `org.apache.dubbo.remoting.transport.dispatcher.execution.ExecutionDispatcher` -* `org.apache.dubbo.remoting.transport.dispatcher.connection.ConnectionOrderedDispatcher` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxDispatcher.java (Dispatcher implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.remoting.Dispatcher (plain text file with the content: xxx=com.xxx.XxxDispatcher) -``` - -XxxDispatcher.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.Dispatcher; - -public class XxxDispatcher implements Dispatcher { - public Group lookup(URL url) { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.remoting.Dispatcher: - -```properties -xxx=com.xxx.XxxDispatcher -``` diff --git a/content/en/docs/v2.7/dev/impls/exchanger.md b/content/en/docs/v2.7/dev/impls/exchanger.md deleted file mode 100644 index ca54ed54876a..000000000000 --- a/content/en/docs/v2.7/dev/impls/exchanger.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -type: docs -title: "Exchanger Extension" -linkTitle: "Exchanger" -weight: 18 ---- - -## Summary - -Exchange message between request and response on network transport layer. - -## Extension Interface - -* `org.apache.dubbo.remoting.exchange.Exchanger` -* `org.apache.dubbo.remoting.exchange.ExchangeServer` -* `org.apache.dubbo.remoting.exchange.ExchangeClient` - -## Extension Configuration - -```xml - - - -``` - -## Existing Extension - -`org.apache.dubbo.remoting.exchange.exchanger.HeaderExchanger` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxExchanger.java (Exchanger implementation) - |-XxxExchangeServer.java (ExchangeServer implementation) - |-XxxExchangeClient.java (ExchangeClient implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.remoting.exchange.Exchanger (plain text file with the content: xxx=com.xxx.XxxExchanger) -``` - -XxxExchanger.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.exchange.Exchanger; - - -public class XxxExchanger implements Exchanger { - public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException { - return new XxxExchangeServer(url, handler); - } - public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException { - return new XxxExchangeClient(url, handler); - } -} -``` - -XxxExchangeServer.java: - -```java - -package com.xxx; - -import org.apache.dubbo.remoting.exchange.ExchangeServer; - -public class XxxExchangeServer impelements ExchangeServer { - // ... -} -``` - -XxxExchangeClient.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.exchange.ExchangeClient; - -public class XxxExchangeClient impelments ExchangeClient { - // ... -} -``` - -META-INF/dubbo/org.apache.dubbo.remoting.exchange.Exchanger: - -```properties -xxx=com.xxx.XxxExchanger -``` diff --git a/content/en/docs/v2.7/dev/impls/exporter-listener.md b/content/en/docs/v2.7/dev/impls/exporter-listener.md deleted file mode 100644 index db28a22f1be7..000000000000 --- a/content/en/docs/v2.7/dev/impls/exporter-listener.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -type: docs -title: "ExporterListener Extension" -linkTitle: "ExporterListener" -weight: 4 ---- - -## Summary - -Fire events when there's any service exported. - -## Extension Interface - -`org.apache.dubbo.rpc.ExporterListener` - -## Extension Configuration - -```xml - - - - -``` - -## Existing Extension - -`org.apache.dubbo.registry.directory.RegistryExporterListener` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxExporterListener.java (ExporterListener implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.ExporterListener (plain text file with the content: xxx=com.xxx.XxxExporterListener) -``` - -XxxExporterListener.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.ExporterListener; -import org.apache.dubbo.rpc.Exporter; -import org.apache.dubbo.rpc.RpcException; - - -public class XxxExporterListener implements ExporterListener { - public void exported(Exporter exporter) throws RpcException { - // ... - } - public void unexported(Exporter exporter) throws RpcException { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.ExporterListener: - -```properties -xxx=com.xxx.XxxExporterListener -``` - diff --git a/content/en/docs/v2.7/dev/impls/extension-factory.md b/content/en/docs/v2.7/dev/impls/extension-factory.md deleted file mode 100644 index 29633a444176..000000000000 --- a/content/en/docs/v2.7/dev/impls/extension-factory.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -type: docs -title: "ExtensionFactory Extension" -linkTitle: "ExtensionFactory" -weight: 11 ---- - -## Summary - -Factory to load dubbo extensions. - -## Extension Interface - -`org.apache.dubbo.common.extension.ExtensionFactory` - -## Extension Configuration - -```xml - -``` - -## Existing Extension - -* `org.apache.dubbo.common.extension.factory.SpiExtensionFactory` -* `org.apache.dubbo.config.spring.extension.SpringExtensionFactory` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxExtensionFactory.java (ExtensionFactory implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.common.extension.ExtensionFactory (plain text file with the content: xxx=com.xxx.XxxExtensionFactory) -``` - -XxxExtensionFactory.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.extension.ExtensionFactory; - -public class XxxExtensionFactory implements ExtensionFactory { - public Object getExtension(Class type, String name) { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.common.extension.ExtensionFactory: - -```properties -xxx=com.xxx.XxxExtensionFactory -``` diff --git a/content/en/docs/v2.7/dev/impls/filter.md b/content/en/docs/v2.7/dev/impls/filter.md deleted file mode 100644 index 340d1d5fe83b..000000000000 --- a/content/en/docs/v2.7/dev/impls/filter.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -type: docs -title: "Filter Extension" -linkTitle: "Filter" -weight: 2 ---- - - -## Summary - -Extension for intercepting the invocation for both service provider and consumer, furthermore, most of functions in dubbo are implemented base on the same mechanism. Since every time when remote method is invoked, the filter extensions will be executed too, the corresponding penalty should be considered before more filters are added. - -Contract: - -* User defined filters are executed after built-in filters by default. -* Special value `default` is introduced to represent the default extension location. For example: for `filter="xxx,default,yyy"`, `xxx` is before default filter, and `yyy` is after the default filter. -* Special value `-` means delete. For example: `filter="-foo1"` excludes `foo1` extension. For example, `filter="-default"` exclues all default filters. -* When provider and service have filter configured at the same moment, all filters are accumulated together instead of override, for example: for `` and ``,`xxx`, `yyy`, `aaa`, `bbb` are all count as filters. In order to change to override, use: `` - -## Extension Interface - -`org.apache.dubbo.rpc.Filter` - -## Extension Configuration - -```xml - - - - - - - - -``` - -## Existing Extension - -* `org.apache.dubbo.rpc.filter.EchoFilter` -* `org.apache.dubbo.rpc.filter.GenericFilter` -* `org.apache.dubbo.rpc.filter.GenericImplFilter` -* `org.apache.dubbo.rpc.filter.TokenFilter` -* `org.apache.dubbo.rpc.filter.AccessLogFilter` -* `org.apache.dubbo.rpc.filter.CountFilter` -* `org.apache.dubbo.rpc.filter.ActiveLimitFilter` -* `org.apache.dubbo.rpc.filter.ClassLoaderFilter` -* `org.apache.dubbo.rpc.filter.ContextFilter` -* `org.apache.dubbo.rpc.filter.ConsumerContextFilter` -* `org.apache.dubbo.rpc.filter.ExceptionFilter` -* `org.apache.dubbo.rpc.filter.ExecuteLimitFilter` -* `org.apache.dubbo.rpc.filter.DeprecatedFilter` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxFilter.java (Filter implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.Filter (plain text file with the content: xxx=com.xxx.XxxFilter) -``` - -XxxFilter.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.Filter; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.Invocation; -import org.apache.dubbo.rpc.Result; -import org.apache.dubbo.rpc.RpcException; - -public class XxxFilter implements Filter { - public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - // before filter ... - Result result = invoker.invoke(invocation); - // after filter ... - return result; - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.Filter: - -```properties -xxx=com.xxx.XxxFilter -``` \ No newline at end of file diff --git a/content/en/docs/v2.7/dev/impls/invoker-listener.md b/content/en/docs/v2.7/dev/impls/invoker-listener.md deleted file mode 100644 index 7c0654485b63..000000000000 --- a/content/en/docs/v2.7/dev/impls/invoker-listener.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -type: docs -title: "InvokerListener Extension" -linkTitle: "InvokerListener" -weight: 3 ---- - -## Summary - -Fire event when there's any service referenced. - -## Extension Interface - -`org.apache.dubbo.rpc.InvokerListener` - -## Extension Configuration - -```xml - - - - - -``` - -## Existing Extension - -`org.apache.dubbo.rpc.listener.DeprecatedInvokerListener` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxInvokerListener.java (InvokerListener implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.InvokerListener (plain text file with the content: xxx=com.xxx.XxxInvokerListener) -``` - -XxxInvokerListener.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.InvokerListener; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.RpcException; - -public class XxxInvokerListener implements InvokerListener { - public void referred(Invoker invoker) throws RpcException { - // ... - } - public void destroyed(Invoker invoker) throws RpcException { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.InvokerListener: - -```properties -xxx=com.xxx.XxxInvokerListener -``` diff --git a/content/en/docs/v2.7/dev/impls/load-balance.md b/content/en/docs/v2.7/dev/impls/load-balance.md deleted file mode 100644 index fba9edb0590f..000000000000 --- a/content/en/docs/v2.7/dev/impls/load-balance.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -type: docs -title: "LoadBalance Extension" -linkTitle: "LoadBalance" -weight: 7 ---- - -## Summary - -Pick one from service providers and fire the invocation. - -## Extension Interface - -`org.apache.dubbo.rpc.cluster.LoadBalance` - -## Extension Configuration - -```xml - - - -``` - -## Existing Extension - -* `org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance` -* `org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance` -* `org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance` -* `org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance` -* `org.apache.dubbo.rpc.cluster.loadbalance.ShortestResponseLoadBalance` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxLoadBalance.java (LoadBalance implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.cluster.LoadBalance (plain text file with the content: xxx=com.xxx.XxxLoadBalance) -``` - -XxxLoadBalance.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.cluster.LoadBalance; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.Invocation; -import org.apache.dubbo.rpc.RpcException; - -public class XxxLoadBalance implements LoadBalance { - public Invoker select(List> invokers, Invocation invocation) throws RpcException { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.cluster.LoadBalance: - -```properties -xxx=com.xxx.XxxLoadBalance -``` diff --git a/content/en/docs/v2.7/dev/impls/logger-adapter.md b/content/en/docs/v2.7/dev/impls/logger-adapter.md deleted file mode 100644 index 65a9ecb8c143..000000000000 --- a/content/en/docs/v2.7/dev/impls/logger-adapter.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -type: docs -title: "LoggerAdapter Extension" -linkTitle: "LoggerAdapter" -weight: 26 ---- - - -## Summary - -Extension for adapting logger output - -## Extension Interface - -`org.apache.dubbo.common.logger.LoggerAdapter` - -## Extension Configuration - -```xml - -``` - -Or: - -```sh --Ddubbo:application.logger=xxx -``` - -## Existing Extension - -* `org.apache.dubbo.common.logger.slf4j.Slf4jLoggerAdapter` -* `org.apache.dubbo.common.logger.jcl.JclLoggerAdapter` -* `org.apache.dubbo.common.logger.log4j.Log4jLoggerAdapter` -* `org.apache.dubbo.common.logger.log4j2.Log4j2LoggerAdapter` -* `org.apache.dubbo.common.logger.jdk.JdkLoggerAdapter` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxLoggerAdapter.java (LoggerAdapter implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.common.logger.LoggerAdapter (plain text file with the content: xxx=com.xxx.XxxLoggerAdapter) -``` - -XxxLoggerAdapter.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.logger.LoggerAdapter; - -public class XxxLoggerAdapter implements LoggerAdapter { - public Logger getLogger(URL url) { - // ... - } -} -``` - -XxxLogger.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.logger.Logger; - -public class XxxLogger implements Logger { - public XxxLogger(URL url) { - // ... - } - public void info(String msg) { - // ... - } - // ... -} -``` - -META-INF/dubbo/org.apache.dubbo.common.logger.LoggerAdapter: - -```properties -xxx=com.xxx.XxxLoggerAdapter -``` \ No newline at end of file diff --git a/content/en/docs/v2.7/dev/impls/merger.md b/content/en/docs/v2.7/dev/impls/merger.md deleted file mode 100644 index 89fba2dd1248..000000000000 --- a/content/en/docs/v2.7/dev/impls/merger.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -type: docs -title: "Merger Extension" -linkTitle: "Merger" -weight: 8 ---- - -## Summary - -Merge strategy for return result aggregation in group. - -## Extension Interface - -`org.apache.dubbo.rpc.cluster.Merger` - -## Extension Configuration - -```xml - -``` - -## Existing Extension - -* `org.apache.dubbo.rpc.cluster.merger.ArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.ListMerger` -* `org.apache.dubbo.rpc.cluster.merger.SetMerger` -* `org.apache.dubbo.rpc.cluster.merger.MapMerger` -* `org.apache.dubbo.rpc.cluster.merger.ByteArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.CharArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.ShortArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.IntArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.LongArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.FloatArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.DoubleArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.BooleanArrayMerger` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxMerger.java (Merger implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.cluster.Merger (plain text file with the content: xxx=com.xxx.XxxMerger) -``` - -XxxMerger.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.cluster.Merger; - -public class XxxMerger implements Merger { - public T merge(T... results) { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.cluster.Merger: - -```properties -xxx=com.xxx.XxxMerger -``` - diff --git a/content/en/docs/v2.7/dev/impls/monitor.md b/content/en/docs/v2.7/dev/impls/monitor.md deleted file mode 100644 index 64ef5027908a..000000000000 --- a/content/en/docs/v2.7/dev/impls/monitor.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -type: docs -title: "Monitor Extension" -linkTitle: "Monitor" -weight: 10 ---- - -## Summary - -Extension to monitor service invocation times and time taken for each service invocation. - -## Extension Interface - -* `org.apache.dubbo.monitor.MonitorFactory` -* `org.apache.dubbo.monitor.Monitor` - -## Extension Configuration - -```xml - - -``` - -## Existing Extension - -org.apache.dubbo.monitor.support.dubbo.DubboMonitorFactory - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxMonitorFactoryjava (MonitorFactory implementation) - |-XxxMonitor.java (Monitor implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.monitor.MonitorFactory (plain text file with the format: xxx=com.xxx.XxxMonitorFactory) -``` - -XxxMonitorFactory.java: - -```java -package com.xxx; - -import org.apache.dubbo.monitor.MonitorFactory; -import org.apache.dubbo.monitor.Monitor; -import org.apache.dubbo.common.URL; - -public class XxxMonitorFactory implements MonitorFactory { - public Monitor getMonitor(URL url) { - return new XxxMonitor(url); - } -} -``` - -XxxMonitor.java: - -```java -package com.xxx; - -import org.apache.dubbo.monitor.Monitor; - -public class XxxMonitor implements Monitor { - public void count(URL statistics) { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.monitor.MonitorFactory: - -```properties -xxx=com.xxx.XxxMonitorFactory -``` \ No newline at end of file diff --git a/content/en/docs/v2.7/dev/impls/networker.md b/content/en/docs/v2.7/dev/impls/networker.md deleted file mode 100644 index d5addb69efc1..000000000000 --- a/content/en/docs/v2.7/dev/impls/networker.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -type: docs -title: "Networker Extension" -linkTitle: "Networker" -weight: 19 ---- - -## Summary - -Extension for peer to peer network grouping. - -## Extension Interface - -`org.apache.dubbo.remoting.p2p.Networker` - -## Extension Configuration - -```xml - - - -``` - -## Existing Extension - -* `org.apache.dubbo.remoting.p2p.support.MulticastNetworker` -* `org.apache.dubbo.remoting.p2p.support.FileNetworker` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxNetworker.java (Networker implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.remoting.p2p.Networker (plain text file with the content: xxx=com.xxx.XxxNetworker) -``` - -XxxNetworker.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.p2p.Networker; - -public class XxxNetworker implements Networker { - public Group lookup(URL url) { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.remoting.p2p.Networker: - -```properties -xxx=com.xxx.XxxNetworker -``` diff --git a/content/en/docs/v2.7/dev/impls/page.md b/content/en/docs/v2.7/dev/impls/page.md deleted file mode 100644 index 8a330e0e9bbf..000000000000 --- a/content/en/docs/v2.7/dev/impls/page.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -type: docs -title: "PageHandler Extension" -linkTitle: "PageHandler" -weight: 23 ---- - - -## Summary - -Extension for page handler - -## Extension Interface - -`org.apache.dubbo.container.page.PageHandler` - -## Extension Configuration - -```xml - - - -``` - -## Existing Extension - -* `org.apache.dubbo.container.page.pages.HomePageHandler` -* `org.apache.dubbo.container.page.pages.StatusPageHandler` -* `org.apache.dubbo.container.page.pages.LogPageHandler` -* `org.apache.dubbo.container.page.pages.SystemPageHandler` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxPageHandler.java (PageHandler implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.container.page.PageHandler (plain text file with the content: xxx=com.xxx.XxxPageHandler) -``` - -XxxPageHandler.java: - -```java -package com.xxx; - -import org.apache.dubbo.container.page.PageHandler; - -public class XxxPageHandler implements PageHandler { - public Group lookup(URL url) { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.container.page.PageHandler: - -```properties -xxx=com.xxx.XxxPageHandler -``` diff --git a/content/en/docs/v2.7/dev/impls/protocol.md b/content/en/docs/v2.7/dev/impls/protocol.md deleted file mode 100644 index 468faeff7be2..000000000000 --- a/content/en/docs/v2.7/dev/impls/protocol.md +++ /dev/null @@ -1,161 +0,0 @@ ---- -type: docs -title: "Protocol Extension" -linkTitle: "Protocol" -weight: 1 ---- - -## Summary - -Extension to RPC protocol, hide details of remote call. - -Contract: - -* When user calls `invoke()` method of `Invoker` object which's returned from `refer()` call, the protocol needs to correspondingly execute `invoke()` method of `Invoker` object passed from remote `export()` method associated with the same URL. -* Moreover, it's protocol's responsibility to implement `Invoker` which's returned from `refer()`. Generally speaking, protocol sends remote request in the `Invoker` implementation, but needs not to care about the `Invoker` passed into `export()` since the framework will implement the logic and pass in the instance. - -Notes: - -* Protocol does not need to care about the proxy of the business interface. The upper layer of the framework will convert `Invoker` into business interface. -* It is not a requirement that the protocol must use TCP for network communication. It could be file-sharing, IPC, or others. - -## Extension Interface - -* `org.apache.dubbo.rpc.Protocol` -* `org.apache.dubbo.rpc.Exporter` -* `org.apache.dubbo.rpc.Invoker` - -```java -public interface Protocol { - /** - * Export remote service:
- * 1. Should save address info for the request when the protocol receives it: RpcContext.getContext().setRemoteAddress();
- * 2. export() must be implemented as idempotent, that is, it should not introduce side effect when the implementation gets called with the same Invoker for more than once. - * 3. Invoker is passed by the framework, and the protocol should not care about it.
- * - * @param Service type - * @param invoker Service invoker - * @return exporter The reference of service exporter, used for cancelling service export. - * @throws RpcException throw when there's any error during service export, e.g. the port is occupied - */ - Exporter export(Invoker invoker) throws RpcException; - - /** - * Reference remote service:
- * 1. When user calls `invoke()` method of `Invoker` object which's returned from `refer()` call, the protocol needs to correspondingly execute `invoke()` method of `Invoker` object passed from remote `export()` method associated with the same URL.
- * 2. It's protocol's responsibility to implement `Invoker` which's returned from `refer()`. Generally speaking, protocol sends remote request in the `Invoker` implementation.
- * 3. When there's check=false set in URL, the implementation must not throw exception but try to recover when connection fails. - * - * @param Service type - * @param type Service type - * @param url URL address for the remote service - * @return invoker service's local proxy - * @throws RpcException throw when there's any error while connecting to the service provider - */ - Invoker refer(Class type, URL url) throws RpcException; - -} -``` - -## Extension Configuration - -```xml - - - - - - -``` - -## Existing Protocol - -* `org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol` -* `org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol` -* `org.apache.dubbo.rpc.protocol.rmi.RmiProtocol` -* `org.apache.dubbo.rpc.protocol.http.HttpProtocol` -* `org.apache.dubbo.rpc.protocol.http.hessian.HessianProtocol` -* `org.apache.dubbo.rpc.protocol.memcached.MemcachedProtocol` -* `org.apache.dubbo.rpc.support.MockProtocol` -* `org.apache.dubbo.rpc.protocol.redis.RedisProtocol` -* `org.apache.dubbo.rpc.protocol.nativethrift.ThriftProtocol` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxProtocol.java (Protocol implementation) - |-XxxExporter.java (Exporter implementation) - |-XxxInvoker.java (Invoker implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.Protocol (plain text file with the content: xxx=com.xxx.XxxProtocol) -``` - -XxxProtocol.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.Protocol; - -public class XxxProtocol implements Protocol { - public Exporter export(Invoker invoker) throws RpcException { - return new XxxExporter(invoker); - } - public Invoker refer(Class type, URL url) throws RpcException { - return new XxxInvoker(type, url); - } -} -``` - -XxxExporter.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.support.AbstractExporter; - -public class XxxExporter extends AbstractExporter { - public XxxExporter(Invoker invoker) throws RemotingException{ - super(invoker); - // ... - } - public void unexport() { - super.unexport(); - // ... - } -} -``` - -XxxInvoker.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.support.AbstractInvoker; - -public class XxxInvoker extends AbstractInvoker { - public XxxInvoker(Class type, URL url) throws RemotingException{ - super(type, url); - } - - @Override - protected Result doInvoke(Invocation invocation) throws Throwable { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.Protocol: - -```properties -xxx=com.xxx.XxxProtocol -``` diff --git a/content/en/docs/v2.7/dev/impls/proxy-factory.md b/content/en/docs/v2.7/dev/impls/proxy-factory.md deleted file mode 100644 index 3bd74eaa8815..000000000000 --- a/content/en/docs/v2.7/dev/impls/proxy-factory.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -type: docs -title: "ProxyFactory Extension" -linkTitle: "ProxyFactory" -weight: 12 ---- - - -## Summary - -Convert `Invoker` into business interface. - -## Extension Interface - -`org.apache.dubbo.rpc.ProxyFactory` - -## Extension Configuration - -```xml - - - -``` - -## Existing Extension - -* `org.apache.dubbo.rpc.proxy.JdkProxyFactory` -* `org.apache.dubbo.rpc.proxy.JavassistProxyFactory` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxProxyFactory.java (ProxyFactory implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.ProxyFactory (plain text file with the content: xxx=com.xxx.XxxProxyFactory) -``` - -XxxProxyFactory.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.ProxyFactory; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.RpcException; - - -public class XxxProxyFactory implements ProxyFactory { - public T getProxy(Invoker invoker) throws RpcException { - // ... - } - public Invoker getInvoker(T proxy, Class type, URL url) throws RpcException { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.ProxyFactory: - -```properties -xxx=com.xxx.XxxProxyFactory -``` diff --git a/content/en/docs/v2.7/dev/impls/registry.md b/content/en/docs/v2.7/dev/impls/registry.md deleted file mode 100644 index f87f239b4444..000000000000 --- a/content/en/docs/v2.7/dev/impls/registry.md +++ /dev/null @@ -1,212 +0,0 @@ ---- -type: docs -title: "Registry Extension" -linkTitle: "Registry" -weight: 9 ---- - -## Summary - -Registry extension is used for service registration and discovery. - -## Extension Interface - -* `org.apache.dubbo.registry.RegistryFactory` -* `org.apache.dubbo.registry.Registry` - -## Extension Configuration - -```xml - - - - - - -``` - -## Extension Contract - -RegistryFactory.java: - -```java -public interface RegistryFactory { - /** - * Connect to registry server - * - * The contract for connecting to registry server:
- * 1. Will not check connection when check=false is set, otherwise exception will be thrown if connection fails.
- * 2. Support authorizing against username:password in the URL
- * 3. Support registry server backup with backup=10.20.153.10
- * 4. Support cache on local disk with file=registry.cache
- * 5. Support timeout setup with timeout=1000
- * 6. Support session expiration setup with session=60000
- * - * @param url registry server address, null is not allowed - * @return reference to registry server, never return null - */ - Registry getRegistry(URL url); -} -``` - -RegistryService.java: - -```java -public interface RegistryService { // Registry extends RegistryService - /** - * Register service. - * - * Contract for registering service:
- * 1. Registration failure will be ignored and kept retrying if check=false is set in URL, otherwise exception will be thrown
- * 2. Persistence is required if dynamic=false is set in URL, otherwise, the registration info will be removed automatically when register quits accidentally
- * 3. Persistent by category if category=overrides is set in URL, default category is providers. It is possible to notify by category.
- * 4. Data lost is not tolerant when registry server reboots or network jitter happens.
- * 5. It is not allowed to override each other when URLs have same URI part but different parameters
- * - * @param url registration info,null is not allowed, e.g.: dubbo://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin - */ - void register(URL url); - - /** - * Unregister service. - * - * Contract for unregistering service:
- * 1. IllegalStateException should be thrown when registration info which's supposed to be persistent (with dynamic=false set) cannot be found, otherwise it should be ignored.
- * 2. To cancel one service, extract match on its URL will be honored
- * - * @param url registration info,null is not allowed, e.g.: dubbo://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin - */ - void unregister(URL url); - - /** - * 订阅服务. - * Subscribe service. - * - * Contract for subscribing service:
- * 1. Subscription failure will be ignored and kept retrying if check=false is set in URL
- * 2. Only the specified category will be notified if category=overrides is set in URL. Categories are seperated with comma, and all categorized data will be subscribed when wildcard "*" is specified.
- * 3. Allow to query by interface, group, version, classifier, e.g.: interface=com.alibaba.foo.BarService&version=1.0.0
- * 4. Allow to query with wildcard "*" to subscribe all versions under all categories for all interfaces, e.g.: interface=*&group=*&version=*&classifier=*
- * 5. Subscription will be automatically recoverred when registry server reboots or network jitter happens.
- * 6. It is not allowed to override each other when URLs have same URI part but different parameters
- * 7. Subscription procedure will not return until the first notification happens.
- * - * @param url URL for subscription, null isn't allowed, e.g.: consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin - * @param listener notification listener, null is not allowed - */ - void subscribe(URL url, NotifyListener listener); - - /** - * Unsubscribe service. - * - * Contract for unsubscribing service:
- * 1. Simply ignore if not subscribe
- * 2. Unsubscribe with URL exact match
- * - * @param url URL for unsubscription, null is not allowed, e.g.: consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin - * @param listener notification listener, null is not allowed - */ - void unsubscribe(URL url, NotifyListener listener); - - /** - * 查询注册列表,与订阅的推模式相对应,这里为拉模式,只返回一次结果。 - * Lookup subscription list. Compared to push mode for subscription, this is pull mode and returns result only once. - * - * @see org.apache.dubbo.registry.NotifyListener#notify(List) - * @param url URL for query, null is not allowed, e.g.: consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin - * @return subscription list, could be null, has the same meaning as the parameters in {@link org.apache.dubbo.registry.NotifyListener#notify(List)}. - */ - List lookup(URL url); - -} -``` - -NotifyListener.java: - -```java -public interface NotifyListener { - /** - * Fire event when receive service change notification. - * - * Contract for notify:
- * 1. Always notify with the whole data instead of partial data from the perspective of service interface and data type. In this way, user needs not compare with the previous result.
- * 2. First notification for subscription must contain the full set of data for one particular service
- * 3. It is allowed to separate the different type of data in the upcoming notifications, e.g.: it is legal to only notify one of types among providers, consumers, routes or overrides each time, but pls. note for this particular type, the data must be a full set.
- * 4. If the data for one particular type is empty, need to notify with a special URL which has empty as its protocol and has category parameter for this particluar type. - * 5. Notifier (usually it is monitor center) needs to guarantee the notification sequence by, for say: single thread push, queuing in order, versioning, etc.
- * - * @param urls subscription list, always not empty, equivalent to the return result of {@link org.apache.dubbo.registry.RegistryService#lookup(URL)}. - */ - void notify(List urls); - -} -``` - -## Existing Extension - -`org.apache.dubbo.registry.support.dubbo.DubboRegistryFactory` - -## Extension Guide - -Directory structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxRegistryFactoryjava (RegistryFactory implementation) - |-XxxRegistry.java (Registry implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.registry.RegistryFactory (plain text file with the content: xxx=com.xxx.XxxRegistryFactory) -``` - -XxxRegistryFactory.java: - -```java -package com.xxx; - -import org.apache.dubbo.registry.RegistryFactory; -import org.apache.dubbo.registry.Registry; -import org.apache.dubbo.common.URL; - -public class XxxRegistryFactory implements RegistryFactory { - public Registry getRegistry(URL url) { - return new XxxRegistry(url); - } -} -``` - -XxxRegistry.java: - -```java -package com.xxx; - -import org.apache.dubbo.registry.Registry; -import org.apache.dubbo.registry.NotifyListener; -import org.apache.dubbo.common.URL; - -public class XxxRegistry implements Registry { - public void register(URL url) { - // ... - } - public void unregister(URL url) { - // ... - } - public void subscribe(URL url, NotifyListener listener) { - // ... - } - public void unsubscribe(URL url, NotifyListener listener) { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.registry.RegistryFactory: - -```properties -xxx=com.xxx.XxxRegistryFactory -``` \ No newline at end of file diff --git a/content/en/docs/v2.7/dev/impls/remoting.md b/content/en/docs/v2.7/dev/impls/remoting.md deleted file mode 100644 index 3d6f8aadd9c9..000000000000 --- a/content/en/docs/v2.7/dev/impls/remoting.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -type: docs -title: "Transporter Extension" -linkTitle: "Transporter" -weight: 17 ---- - -## Summary - -Transportation extension for communication between server and client. - -## Extension Interface - -* `org.apache.dubbo.remoting.Transporter` -* `org.apache.dubbo.remoting.Server` -* `org.apache.dubbo.remoting.Client` - -## Extension Configuration - -```xml - - - - - - -``` - -## Existing Extension - -* `org.apache.dubbo.remoting.transport.transporter.netty.NettyTransporter` -* `org.apache.dubbo.remoting.transport.transporter.mina.MinaTransporter` -* `org.apache.dubbo.remoting.transport.transporter.grizzly.GrizzlyTransporter` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxTransporter.java (Transporter implementation) - |-XxxServer.java (Server implementation) - |-XxxClient.java (Client implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.remoting.Transporter (plain text file with the content: xxx=com.xxx.XxxTransporter) -``` - -XxxTransporter.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.Transporter; - -public class XxxTransporter implements Transporter { - public Server bind(URL url, ChannelHandler handler) throws RemotingException { - return new XxxServer(url, handler); - } - public Client connect(URL url, ChannelHandler handler) throws RemotingException { - return new XxxClient(url, handler); - } -} -``` - -XxxServer.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.transport.transporter.AbstractServer; - -public class XxxServer extends AbstractServer { - public XxxServer(URL url, ChannelHandler handler) throws RemotingException{ - super(url, handler); - } - protected void doOpen() throws Throwable { - // ... - } - protected void doClose() throws Throwable { - // ... - } - public Collection getChannels() { - // ... - } - public Channel getChannel(InetSocketAddress remoteAddress) { - // ... - } -} -``` - -XxxClient.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.transport.transporter.AbstractClient; - -public class XxxClient extends AbstractClient { - public XxxServer(URL url, ChannelHandler handler) throws RemotingException{ - super(url, handler); - } - protected void doOpen() throws Throwable { - // ... - } - protected void doClose() throws Throwable { - // ... - } - protected void doConnect() throws Throwable { - // ... - } - public Channel getChannel() { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.remoting.Transporter: - -```properties -xxx=com.xxx.XxxTransporter -``` diff --git a/content/en/docs/v2.7/dev/impls/router.md b/content/en/docs/v2.7/dev/impls/router.md deleted file mode 100644 index 3a26e0202429..000000000000 --- a/content/en/docs/v2.7/dev/impls/router.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -type: docs -title: "Router Extension" -linkTitle: "Router" -weight: 6 ---- - -## Summary - -Pick one from service providers and fire the invocation. - -## Extension Interface - -* `org.apache.dubbo.rpc.cluster.RouterFactory` -* `org.apache.dubbo.rpc.cluster.Router` - -## Existing Extension - -* `org.apache.dubbo.rpc.cluster.router.ScriptRouterFactory` -* `org.apache.dubbo.rpc.cluster.router.FileRouterFactory` -* `org.apache.dubbo.rpc.cluster.router.condition.config.AppRouterFactory` -* `org.apache.dubbo.rpc.cluster.CacheableRouterFactory` -* `org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory` -* `org.apache.dubbo.rpc.cluster.router.mock.MockRouterFactory` -* `org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouterFactory` -* `org.apache.dubbo.rpc.cluster.router.tag.TagRouterFactory` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxRouterFactory.java (RouterFactory implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.cluster.RouterFactory (plain text file with the content: xxx=com.xxx.XxxRouterFactory) - -``` - -XxxRouterFactory.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.cluster.RouterFactory; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.Invocation; -import org.apache.dubbo.rpc.RpcException; - -public class XxxRouterFactory implements RouterFactory { - public Router getRouter(URL url) { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.cluster.RouterFactory: - -```properties -xxx=com.xxx.XxxRouterFactory -``` - - diff --git a/content/en/docs/v2.7/dev/impls/serialize.md b/content/en/docs/v2.7/dev/impls/serialize.md deleted file mode 100644 index 2918d1bd5d20..000000000000 --- a/content/en/docs/v2.7/dev/impls/serialize.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -type: docs -title: "Serialization Extension" -linkTitle: "Serialization" -weight: 16 ---- - -## Summary - -Extension to serializing java object into byte code stream for transporting on the network, and vise versa. - -## Extension Interface - -* `org.apache.dubbo.common.serialize.Serialization` -* `org.apache.dubbo.common.serialize.ObjectInput` -* `org.apache.dubbo.common.serialize.ObjectOutput` - -## Extension Configuration - -```xml - - - - -``` - -## Existing Extension - -* `org.apache.dubbo.common.serialize.dubbo.DubboSerialization` -* `org.apache.dubbo.common.serialize.hessian.Hessian2Serialization` -* `org.apache.dubbo.common.serialize.java.JavaSerialization` -* `org.apache.dubbo.common.serialize.java.CompactedJavaSerialization` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxSerialization.java (Serialization implementation) - |-XxxObjectInput.java (ObjectInput implementation) - |-XxxObjectOutput.java (ObjectOutput implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.common.serialize.Serialization (plain text file with the content: xxx=com.xxx.XxxSerialization) -``` - -XxxSerialization.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.serialize.Serialization; -import org.apache.dubbo.common.serialize.ObjectInput; -import org.apache.dubbo.common.serialize.ObjectOutput; - - -public class XxxSerialization implements Serialization { - public ObjectOutput serialize(Parameters parameters, OutputStream output) throws IOException { - return new XxxObjectOutput(output); - } - public ObjectInput deserialize(Parameters parameters, InputStream input) throws IOException { - return new XxxObjectInput(input); - } -} -``` - -META-INF/dubbo/org.apache.dubbo.common.serialize.Serialization: - -```properties -xxx=com.xxx.XxxSerialization -``` diff --git a/content/en/docs/v2.7/dev/impls/status-checker.md b/content/en/docs/v2.7/dev/impls/status-checker.md deleted file mode 100644 index 497971d012ea..000000000000 --- a/content/en/docs/v2.7/dev/impls/status-checker.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -type: docs -title: "StatusChecker Extension" -linkTitle: "StatusChecker" -weight: 21 ---- - -## Summary - -Extension to check status of resources service depends on. This status checker can be used in both telnet status command and status page. - -## Extension Interface - -`org.apache.dubbo.common.status.StatusChecker` - -## Extension Configuration - -```xml - - - -``` - -## Existing Extension - -* `org.apache.dubbo.common.status.support.MemoryStatusChecker` -* `org.apache.dubbo.common.status.support.LoadStatusChecker` -* `org.apache.dubbo.rpc.dubbo.status.ServerStatusChecker` -* `org.apache.dubbo.rpc.dubbo.status.ThreadPoolStatusChecker` -* `org.apache.dubbo.registry.directory.RegistryStatusChecker` -* `org.apache.dubbo.rpc.config.spring.status.SpringStatusChecker` -* `org.apache.dubbo.rpc.config.spring.status.DataSourceStatusChecker` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxStatusChecker.java (StatusChecker implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.common.status.StatusChecker (plain text file with the content: xxx=com.xxx.XxxStatusChecker) -``` - -XxxStatusChecker.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.status.StatusChecker; - -public class XxxStatusChecker implements StatusChecker { - public Status check() { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.common.status.StatusChecker: - -```properties -xxx=com.xxx.XxxStatusChecker -``` diff --git a/content/en/docs/v2.7/dev/impls/telnet-handler.md b/content/en/docs/v2.7/dev/impls/telnet-handler.md deleted file mode 100644 index 70322e3e7ccb..000000000000 --- a/content/en/docs/v2.7/dev/impls/telnet-handler.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -type: docs -title: "TelnetHandler Extension" -linkTitle: "TelnetHandler" -weight: 20 ---- - - -## Summary - -Extension to telnet command. All server should support telnet access for operation convenience. - -## Extension Interface - -`org.apache.dubbo.remoting.telnet.TelnetHandler` - -## Extension Configuration - -```xml - - - -``` - -## Existing Extension - -* `org.apache.dubbo.remoting.telnet.support.ClearTelnetHandler` -* `org.apache.dubbo.remoting.telnet.support.ExitTelnetHandler` -* `org.apache.dubbo.remoting.telnet.support.HelpTelnetHandler` -* `org.apache.dubbo.remoting.telnet.support.StatusTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.ListTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.ChangeTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.CurrentTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.InvokeTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.TraceTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.CountTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.PortTelnetHandler` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxTelnetHandler.java (TelnetHandler implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.remoting.telnet.TelnetHandler (plain text file with the content: xxx=com.xxx.XxxTelnetHandler) -``` - -XxxTelnetHandler.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.telnet.TelnetHandler; - -@Help(parameter="...", summary="...", detail="...") - -public class XxxTelnetHandler implements TelnetHandler { - public String telnet(Channel channel, String message) throws RemotingException { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.remoting.telnet.TelnetHandler: - -```properties -xxx=com.xxx.XxxTelnetHandler -``` - -## How To Use - -```sh -telnet 127.0.0.1 20880 -dubbo> xxx args -``` diff --git a/content/en/docs/v2.7/dev/impls/threadpool.md b/content/en/docs/v2.7/dev/impls/threadpool.md deleted file mode 100644 index 7536489b4119..000000000000 --- a/content/en/docs/v2.7/dev/impls/threadpool.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -type: docs -title: "ThreadPool Extension" -linkTitle: "ThreadPool" -weight: 15 ---- - - -## Summary - -Thread pool strategy extension for service provider. When server receives one request, it needs a thread from thread pool to execute business logic in service provider. - -## Extension Interface - -`org.apache.dubbo.common.threadpool.ThreadPool` - -## Extension Configuration - -```xml - - - -``` - -## Existing Extension - -* `org.apache.dubbo.common.threadpool.FixedThreadPool` -* `org.apache.dubbo.common.threadpool.CachedThreadPool` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxThreadPool.java (ThreadPool implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.common.threadpool.ThreadPool (plain text file with the content: xxx=com.xxx.XxxThreadPool) -``` - -XxxThreadPool.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.threadpool.ThreadPool; -import java.util.concurrent.Executor; - -public class XxxThreadPool implements ThreadPool { - public Executor getExecutor() { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.common.threadpool.ThreadPool: - -```properties -xxx=com.xxx.XxxThreadPool -``` - diff --git a/content/en/docs/v2.7/dev/impls/validation.md b/content/en/docs/v2.7/dev/impls/validation.md deleted file mode 100644 index 9ebf066cd03f..000000000000 --- a/content/en/docs/v2.7/dev/impls/validation.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -type: docs -title: "Validation Extension" -linkTitle: "Validation" -weight: 25 ---- - -## Summary - -Extension for parameter validation. - -## Extension Interface - -`org.apache.dubbo.validation.Validation` - -## Extension Configuration - -```xml - - - -``` - -## Existing Extension - -`org.apache.dubbo.validation.support.jvalidation.JValidation` - -## Extension Guide - -Directory layout: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxValidation.java (Validation implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.validation.Validation (plain text file with the content: xxx=com.xxx.XxxValidation) -``` - -XxxValidation.java: - -```java -package com.xxx; - -import org.apache.dubbo.validation.Validation; - -public class XxxValidation implements Validation { - public Object getValidator(URL url) { - // ... - } -} -``` - -XxxValidator.java: - -```java -package com.xxx; - -import org.apache.dubbo.validation.Validator; - -public class XxxValidator implements Validator { - public XxxValidator(URL url) { - // ... - } - public void validate(Invocation invocation) throws Exception { - // ... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.validation.Validation: - -```properties -xxx=com.xxx.XxxValidation -``` \ No newline at end of file diff --git a/content/en/docs/v2.7/dev/principals/_index.md b/content/en/docs/v2.7/dev/principals/_index.md deleted file mode 100755 index bb780c9177e5..000000000000 --- a/content/en/docs/v2.7/dev/principals/_index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -type: docs -title: "Dubbo Design Principals" -linkTitle: "Design Principals" -weight: 5 -description: "Dubbo design principals collections" ---- - -The design principles in this chapter are taken from a series of articles published by Liang Fei on javaeye. - diff --git a/content/en/docs/v2.7/dev/principals/code-detail.md b/content/en/docs/v2.7/dev/principals/code-detail.md deleted file mode 100644 index 7136f2cc0056..000000000000 --- a/content/en/docs/v2.7/dev/principals/code-detail.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -type: docs -title: "The Devil Is In The Details" -linkTitle: "Details" -weight: 1 ---- - -Recently, I have been worried about the quality of the Dubbo distributed service framework. If there are more maintenance personnel or changes, there will be a decline in quality. I am thinking, is there any need for everyone to abide by it, according to a habit when writing code, I have summarized it. The code process, especially the framework code, should always keep in mind the details. Maybe the following will be said, everyone will feel very simple, very basic, but always keep in mind. Considering these factors in every line of code requires a lot of patience. It is often said that the devil is in the details. - -## Prevent null pointer dereference and index out of bounds - -This is the exception I least like to see, especially in the core framework, in contrast I would like to see a parameter not legal exception with detail information. This is also a robust program developer who should be prevented in the subconscious by writing every line of code. Basically, you must be able to ensure that the code that is written once will not appear in the case of no test. - -## Ensure thread safety and visibility - -For framework developers, a deep understanding of thread safety and visibility is the most basic requirement. Developers are required to ensure that they are correct in the subconscious when writing each line of code. Because of this kind of code, it will look normal when doing functional tests under small concurrency. However, under high concurrency, there will be inexplicable problems, and the scene is difficult to reproduce, and it is extremely difficult to check. - -## Fail fast and precondition - -Fail fast should also become a subconscious mind, assert at the entrance when there are incoming parameters and state changes. An illegal value and state should be reported at the first time, rather than waiting until the time is needed. Because when it is time to use, other related states may have been modified before, and few people in the program handle the rollback logic. After this error, the internal state may be confusing, and it is easy to cause the program to be unrecoverable on a hidden branch. - -## Separate reliable operation and unreliable operation - -The reliability here is narrowly defined whether it will throw an exception or cause a state inconsistency. For example, writing a thread-safe Map can be considered reliable, but writing to a database can be considered unreliable. Developers must pay attention to its reliability when writing each line of code, divide it as much as possible in the code, and handle exceptions for failures, and provide clear logic for fault-tolerant, self-protection, automatic recovery or switching. The entry point ensures that the code that is subsequently added is not misplaced, and the original fault-tolerant processing is confusing. - -## Safeguard against exceptions, but does not ignore exceptions - -The exception defense mentioned here refers to the maximum tolerance of the code on the non-crucial path, including the bug on the program. For example, the version number of program is retrieved by scanning the Manifest and jar package names. This logic is auxiliary, but the code is quite a bit. Although the initial test works well but you should add a try-catch block to cover the whole getVersion() function, if something goes wrong then print error message and return the basic version. Because getVersion() may encounter exception for specific unknown scene, or other developers mistakenly modify the logic (usually they won't remove try-catch). Otherwise if it throws an exception, the main process will be interrupted which we don't want to see. It should be controlled properly, do not abuse try-catch, and do not eat the exception silently. - -## Reduce scope of variable and use final liberally - -If a class can be an Immutable Class, it is preferred to design it as an Immutable Class. The immutable class has natural concurrency advantages, reduce synchronization and replication, it can efficiently help analyze the scope of thread safety. Even if a mutable class, for references passed in from constructor then held internally, it is better to make this field final, so as not to be mistakenly modified. Don't assume that the field won't be reassigned if this field is private or this class is written by myself. One factor to consider is that this code may be modified by others. He may not aware your weak convention, and the Final is a invariant contract. - -## Reduce misunderstanding when modifying, do not bury mine - -It is repeatedly mentioned that the code being modified by the others, and this is something developers should keep in mind. This other person includes the future of yourself, you always have to think about this code, someone may change it. I should give the modified person a hint, let him know my current design intent, instead of adding hidden rules in the program, or bury some easily overlooked mines, such as: use null to indicate that it is not available, the size is equal to 0 means black list, this is a mine. The next modifier, including yourself, will not remember to have such an agreement, may later change some of the other bugs, accidentally changed to here, directly detonated the fault. For this example, one principle is to never distinguish between null references and null values. - -## Improve code testability -The testability here mainly refers to the ease of Mock and the isolation of the test cases. As for the automation, repeatability, stability, disorder, completeness (full coverage), lightweight (fast execution) of the test, the general developer, plus the assist of tools such as JUnit can do it. Can also understand its benefits, just the matter of workload. Primary emphasis on unicity(only test the target class itself) and isolation(do not propagate failure). Nowadays there is too much emphasis on completeness, a lot of crossed and repeated test cases. It seems fine, but the more test code, the higher maintenance cost. A common problem is that modifying a line of code or adding an assertion causes more than 100 test cases to fail. It will cost a lot of time to fix these variance test cases. Over time, this test cases can't really reflect the current state of the code, and it will often be compromised to bypass. In the best case, modify a line of code, and only one line of test code does not pass. If the code is modified and the test case can still pass, that doesn't work, indicating that the scenario is not covered. In addition, Mockability is the basis of isolation, it hide the logic of indirect dependencies. One of the biggest killers of Mockability is the static method, which should be avoid as possible. diff --git a/content/en/docs/v2.7/dev/principals/configuration.md b/content/en/docs/v2.7/dev/principals/configuration.md deleted file mode 100644 index e6a767aa4af5..000000000000 --- a/content/en/docs/v2.7/dev/principals/configuration.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -type: docs -title: "The Configuration Design" -linkTitle: "Configuration" -weight: 2 ---- - - -> http://javatar.iteye.com/blog/949527 - -Dubbo design is now completely unobtrusive, namely the user only depends on the configuration of contract.After multiple versions of the development, in order to meet the demand of various scenarios, configuration is more and more.In order to maintain compatibility with only grow, lurking inside all sorts of styles, convention, rules.The new version will also be configured for a adjustment, remove the dubbo, properties, instead of all the spring configuration.Will think of some written in this memo. - -## Classification of configuration - -First of all, the purpose is to have a variety of configuration, which can be roughly divided into: - -0. Environment configuration, such as: the number of connections, the timeout configuration, etc. -0. Describe the configuration, such as: service interface description, service version, etc. -0. Extension configuration, such as: protocol extension, strategy to expand, etc. - -## Configuration format - -Usually environment configuration, using the configuration properties will be more convenient, because is some simple discrete values, with the key - value configuration can reduce the learning cost configuration. - -Describe the configuration, information more often, and even have a hierarchy, using XML configuration would be more convenient, because the tree structure configuration expression was stronger.If very complex, and can also custom DSL as configuration.Sometimes such configuration can also use the Annotation instead of, because the configuration and related business logic, in the code is also reasonable. - -Another extension configuration, which may be different.If only policy interface implementation class to replace, can consider the properties of the structure.If there is a complex life cycle management, may need to configure such as XML.Sometimes extended by registering interface provided. - -## Configuration is loaded - -For environment configuration, in the Java world, comparing to conventional approach, was agreed in a project under the classpath for the name of the configuration properties, such as: log4j. Properties, velocity. The properties and so on.Product during initialization, automatically from the classpath under loading the configuration.Our platform of many programs use a similar strategy, such as: dubbo. Properties, comsat. XML, etc.This has its advantages, is based on agreement, simplifies the user to configure the loading process of intervention.But also has its disadvantages, when the classpath is the same configuration, may be loaded by mistake, and when this isolation, may can't find the configuration, and, when the user wants to configure into the unified directory, not very convenient. - -Dubbo new version removes `dubbo.properties`, because the contract often conflicts configuration. - -And to describe the configuration, because want to participate in the business logic, usually embedded into the application of life cycle management.There are more and more using spring projects, directly using the spring configuration is common, and spring permits custom schema, configuration simplified is very convenient.Also has its disadvantages, of course, is strongly dependent on the spring, can ask programming interface to do the matching scheme - -In Dubbo configuration is described, but also environment configuration.Part with spring schame configuration is loaded, in part, from the classpath scanning properties configuration is loaded.Users feel very inconvenient, so in the new version of the merged, unified into spring schame configuration load, also increases the flexibility of configuration. - -Extension configuration, usually to the configuration of aggregate demand is higher.Because the product need to find the third party implementation, add it to the product inside.Agreed in the Java world, usually in a specified file each jar package down load, such as: the eclipse plugin. The XML, struts 2 struts - plugin. XML, and so on, this kind of configuration can consider Java standard service discovery mechanisms, namely in the jar meta-inf/services placed under the interface class name file, content is an implementation class name of the class in a row, like encryption algorithm in the JDK extension, the script engine extension, new JDBC driver, etc., are all in this way.see:[ServiceProvider Provider](https://docs.oracle.com/en/cloud/saas/financials/22a/fafcf/service-provider-models.html)。 - -Dubbo old version under each jar package through agreement, place called Dubbo - context. The spring configuration XML extensions and integration, the new version to use the JDK's own meta-inf/services, spring from too much dependence. - -## Programmable configuration - -Configuration of programmability is very necessary, no matter in what way you load the configuration file, should provide a programming way of configuration, allows the user to not using a configuration file, complete the configuration process with code directly.As a product, especially the component products, usually require collaboration use and other products, when a user integration of your product, may need adapter configuration mode. - -Dubbo new version offers one-on-one configuration class with XML configuration, such as: ServiceConfig corresponding ` < Dubbo: service / > `, and one-to-one attributes, this configuration file configuration and programming the consistency of the understanding, reduce the learning cost. - -## Configure the default - -Configuration of the default, usually set the reasonable value of a regular environment, thus reducing the user's configuration.Is generally recommended that in online environment for reference, the development environment can adapt by changing the configuration.The default Settings, had better be in the outermost configuration do processing load.The underlying program if found configuration is not correct, you should direct error, fault tolerance in the outermost layer.If, when the underlying program to use, found unreasonable configuration values, just fill a default value, it is easy to cover up the surface, and trigger a deeper problem.And configuration of the middle layer, probably don't know the underlying USES a default value, some may be failure in the middle of the testing conditions.Dubbo first appeared in this problem, the middle layer with "address" as the cache Key, and the bottom, to "address" a default port number, lead to don't add port number "address" and add the default port "address" did not use the same cache. - -## Configuration consistency - -Configuration is always implied some style or hidden rules, should as far as possible to keep its consistency.For example: a lot of functions have switch, and then have a configuration value: - -0. Whether to use the registry, the registry address. -0. Whether to allow a retry, retries. - -You may agree: - -0. Each is to configure a Boolean type of switch, to configure a value. -0. On behalf of the closed with an invalid values, N/A address 0 retries, etc. - -No matter which way, all the configuration items, should keep the same style, Dubbo selected is the second.Also, similar to that of timeout, retry time, timer interval.If a unit is second, another unit is milliseconds (C3P0 configuration item is) so, staff will be crazy. - -## Configuration coverage - -Provide configuration, want to consider developers, testers, piping, the system administrator.Testers can't modify the code, and test environment is likely to be more complex, need to have some set aside for testers "back door", can be modified in the peripheral configuration items.Like spring is accomplished configuration, support ` SYSTEM_PROPERTIES_MODE_OVERRIDE `, can through the JVM -d parameters, or like hosts agreed a cover configuration files, on the outside of the program, modify some configuration, easy to test. - - -Dubbo support through the JVM parameter ` - Dcom. XXX. XxxService = Dubbo: / / 10.1.1.1:1234` directly make the remote service call bypass registry, point to point test.There is a kind of situation, developers to increase the configuration, can according to the deployment of online configuration, such as: ` < dubbo: registry address = "${dubbo. Registry. Address}" / > ` because only one online registry, this configuration is no problem, and the testing environment may have two registry, testers can't to modify configuration, changed to: -``, -``,So this place, Dubbo support in the ${Dubbo. Registry. Address} value, through vertical dividing multiple registry addresses, used to represent a registry address. - -## Configuration inheritance - -Configuration is also "duplicate code", there is also a "generalization and elaboration" problem.Such as: Dubbo timeout Settings, each service, and each method, should be can set the timeout.But a lot of service don't care about overtime, if required each method configuration, it is not realistic.So Dubbo adopted method inherit service timeout, overtime service timeout to inherit the default timeout, no configuration, opens up search. - -Dubbo, moreover, the old version all the timeout, retries, load balancing strategies are only in the service consumer configuration.But in the process of actual use, found that the service provider knows better than consumer, but the configuration items are used in consumer.The new version, joined in the provider can match these parameters, through the registry to the consumer,As a reference, if there is no configuration, consumer to provide configuration shall prevail, the equivalent of consumption ji-cheng fang the provider's advice configuration values.And at the time of the relay configuration registry, can also be on the way to modify configuration, so that achieve the purpose of governance, the equivalent of inheritance relationship:Service consumers --> Registry --> Service provider -Dubbo, moreover, the old version all the timeout, retries, load balancing strategies are only in the service consumer configuration.But in the process of actual use, found that the service provider knows better than consumer, but the configuration items are used in consumer.The new version, joined in the provider can match these parameters, through the registry to the consumer. - -![configuration-override](/imgs/dev/configuration-override.png) - -## Configuration backward compatibility - -Forwards compatibility is very good, as long as you guarantee configuration only grow, basically can guarantee forwards compatibility.But backward compatibility, but also should pay attention to, to prepare for subsequent to join the new configuration items.If a special configuration in configuration, you should make an appointment a compatibility for the "special" case rules, because the special case, probably will happen later.For example, have a configuration file is save "service = address mapping", one of the special line, is saved "registry = address".Now application load time to define "registry" the Key is special, do special processing, the other is "service".New version found, however, to add a "monitoring center" = address, at this point, the old version of the program will handle "monitoring center" as a "service", because the old code can't be change, compatibility is will be very troublesome.If previously agreed upon in the "special" logo + XXX for special treatment, follow-up will be more convenient. - -Backward compatibility, can learn a lot from HTML5, refer to:[HTML5 design principle](http://javatar.iteye.com/blog/949390) diff --git a/content/en/docs/v2.7/dev/principals/dummy.md b/content/en/docs/v2.7/dev/principals/dummy.md deleted file mode 100644 index 6631539165d2..000000000000 --- a/content/en/docs/v2.7/dev/principals/dummy.md +++ /dev/null @@ -1,208 +0,0 @@ ---- -type: docs -title: " \"Fool-proof\" Design" -linkTitle: "Fool-proof" -weight: 3 ---- - -> http://javatar.iteye.com/blog/804187 - -Recently I was feeling stupid because I solved too many stupid problems. The service framework is becoming more widely used. Every day, I have to help the endpoint user to resolve problems. Gradually, it is found that most of the problems are configuration errors, or duplicated files or classes, or network failure. So I prepare to add some "fool-proof" design to the further version. It may be very simple, but it is still a little help for troubleshooting speed. I hope that I can throw a brick to attract jade, and everyone can help to come up with more preventive measures to share. - -## Check for duplicated jars - -The most annoying problem is that, if we have several jars with different version number at the same time, there will be a problem. Imagine that, a new version of the Class A may invoke a old version of the Class B, it's related to the JVM loading order. The problem may encounter occasionally and hard to resolve. So the first, let's try to avoid it. For each jar package, pick a class that will be loaded, check it for duplication for example: - -```java -static { - Duplicate.checkDuplicate(Xxx.class); -} -``` - -Utility class for check duplication: - -```java -public final class Duplicate { - - private Duplicate() {} - - public static void checkDuplicate(Class cls) { - checkDuplicate(cls.getName().replace('.', '/') + ".class"); - } - - public static void checkDuplicate(String path) { - try { - // search from ClassPath - Enumeration urls = Thread.currentThread().getContextClassLoader().getResources(path); - Set files = new HashSet(); - while (urls.hasMoreElements()) { - URL url = urls.nextElement(); - if (url != null) { - String file = url.getFile(); - if (file != null && file.length() > 0) { - files.add(file); - } - } - } - // if there are more than one indicates duplication - if (files.size() > 1) { - logger.error("Duplicate class " + path + " in " + files.size() + " jar " + files); - } - } catch (Throwable e) { // safe guard - logger.error(e.getMessage(), e); - } - } - -} -``` - -## Check for duplicate configuration files - -It is also a frequently encountered problem that the configuration file is loaded incorrectly. Users often complain that they have the right configuration but program says something is wrong. After some troubleshooting, found that the configuration file is not even loaded. Many products put a default configuration file under classpath, if there are several, usually the first one loaded by JVM is effective. In order not to be bothered by such problem, just like checking duplicate jars, add this: - -```java -Duplicate.checkDuplicate("xxx.properties"); -``` - -## Check for optional configuration - -The required configuration is estimated to be checked by everyone, because without it the program may not even start. However, for some optional parameters, some checks should also be made. For example, the service framework allows the service consumers and service providers to be associated with the registry, and allows direct configuring the service provider address to point-to-point direct connect. At this time, the registry address is optional, but if there is no point-to-point direct connect configured, the registry center address must be matched, and this time you have to check accordingly. - -## Provide error message with a solution if possible - -It's hard to troubleshooting problem with a simple error message which has no detail information. For example, the last time I encountered a "Failed to get session" exception, just the few words. I'm wondering which session is wrong? What is the reason Failed? It makes me crazy, the problem happens in an production environment and it's hard to reproduce. The exception should have some basic context information, such as author info, operation system, failed reason. The best exception information should be given a solution, such as the above: "From 10.20.16.3 to 10.20.130.20:20880 The network is unreachable. Please use telnet 10.20.130.20 20880 to test the network at 10.20.16.3. If it is called across data center, it may be blocked by the firewall. Please contact SA to grant access permission." etc. The above can even judge whether it is cross data center based on IP address. Another example is the spring-web context loading, If spring is not started when getBean, spring will report an error. The error message says: "Please add: `......`", just copy and paste. We should learn from it. You can deliberately make a common mistake and see if you can solve the problem yourself by the error message. Or we can write some solution of common problems in error message. - -## And also the environment information - -Every time an application error occurs, the developer or QA will send the error message and ask the reason. At this time, I will ask some question again, which version is used? Is it a production environment or a development environment? Which registry center? Which project is it? Which machine? And which service? The problem is, some developers or QA can't tell the difference, it waste me a lot of time. So, it is best to log some environment information, we can make a wrapper. Decorate the Logger interface such as: - -```java -public void error(String msg, Throwable e) { - delegate.error(msg + " on server " + InetAddress.getLocalHost() + " using version " + Version.getVersion(), e); -} -``` - -Utility class for retrieve version: - -```java -public final class Version { - - private Version() {} - - private static final Logger logger = LoggerFactory.getLogger(Version.class); - - private static final Pattern VERSION_PATTERN = Pattern.compile("([0-9][0-9\\.\\-]*)\\.jar"); - - private static final String VERSION = getVersion(Version.class, "2.0.0"); - - public static String getVersion(){ - return VERSION; - } - - public static String getVersion(Class cls, String defaultVersion) { - try { - // search version number from MANIFEST.MF - String version = cls.getPackage().getImplementationVersion(); - if (version == null || version.length() == 0) { - version = cls.getPackage().getSpecificationVersion(); - } - if (version == null || version.length() == 0) { - // if not found, extract from jar name - String file = cls.getProtectionDomain().getCodeSource().getLocation().getFile(); - if (file != null && file.length() > 0 && file.endsWith(".jar")) { - Matcher matcher = VERSION_PATTERN.matcher(file); - while (matcher.find() && matcher.groupCount() > 0) { - version = matcher.group(1); - } - } - } - // return version, return default if null - return version == null || version.length() == 0 ? defaultVersion : version; - } catch (Throwable e) { - // ignore exception, return default version - logger.error(e.getMessage(), e); - return defaultVersion; - } - } - -} -``` - -## Dump before kill - -Every time there is a problem with the production environment, everyone panics. Usually the most direct way is to rollback and restart, to reduce the downtime. So that the scene is destroyed, and it's hard to check the problem afterwards. Some problem is hard to reproduce in development environment and may happen under hard pressure. It is unlikely let the developer or Appops manually backup all the data before. Therefore, it is best to call dump before the kill script to backup automatically and avoid mistake. Dump script for example: - -```sh -JAVA_HOME=/usr/java -OUTPUT_HOME=~/output -DEPLOY_HOME=`dirname $0` -HOST_NAME=`hostname` - -DUMP_PIDS=`ps --no-heading -C java -f --width 1000 | grep "$DEPLOY_HOME" |awk '{print $2}'` -if [ -z "$DUMP_PIDS" ]; then - echo "The server $HOST_NAME is not started!" - exit 1; -fi - -DUMP_ROOT=$OUTPUT_HOME/dump -if [ ! -d $DUMP_ROOT ]; then - mkdir $DUMP_ROOT -fi - -DUMP_DATE=`date +%Y%m%d%H%M%S` -DUMP_DIR=$DUMP_ROOT/dump-$DUMP_DATE -if [ ! -d $DUMP_DIR ]; then - mkdir $DUMP_DIR -fi - -echo -e "Dumping the server $HOST_NAME ...\c" -for PID in $DUMP_PIDS ; do - $JAVA_HOME/bin/jstack $PID > $DUMP_DIR/jstack-$PID.dump 2>&1 - echo -e ".\c" - $JAVA_HOME/bin/jinfo $PID > $DUMP_DIR/jinfo-$PID.dump 2>&1 - echo -e ".\c" - $JAVA_HOME/bin/jstat -gcutil $PID > $DUMP_DIR/jstat-gcutil-$PID.dump 2>&1 - echo -e ".\c" - $JAVA_HOME/bin/jstat -gccapacity $PID > $DUMP_DIR/jstat-gccapacity-$PID.dump 2>&1 - echo -e ".\c" - $JAVA_HOME/bin/jmap $PID > $DUMP_DIR/jmap-$PID.dump 2>&1 - echo -e ".\c" - $JAVA_HOME/bin/jmap -heap $PID > $DUMP_DIR/jmap-heap-$PID.dump 2>&1 - echo -e ".\c" - $JAVA_HOME/bin/jmap -histo $PID > $DUMP_DIR/jmap-histo-$PID.dump 2>&1 - echo -e ".\c" - if [ -r /usr/sbin/lsof ]; then - /usr/sbin/lsof -p $PID > $DUMP_DIR/lsof-$PID.dump - echo -e ".\c" - fi -done -if [ -r /usr/bin/sar ]; then -/usr/bin/sar > $DUMP_DIR/sar.dump -echo -e ".\c" -fi -if [ -r /usr/bin/uptime ]; then -/usr/bin/uptime > $DUMP_DIR/uptime.dump -echo -e ".\c" -fi -if [ -r /usr/bin/free ]; then -/usr/bin/free -t > $DUMP_DIR/free.dump -echo -e ".\c" -fi -if [ -r /usr/bin/vmstat ]; then -/usr/bin/vmstat > $DUMP_DIR/vmstat.dump -echo -e ".\c" -fi -if [ -r /usr/bin/mpstat ]; then -/usr/bin/mpstat > $DUMP_DIR/mpstat.dump -echo -e ".\c" -fi -if [ -r /usr/bin/iostat ]; then -/usr/bin/iostat > $DUMP_DIR/iostat.dump -echo -e ".\c" -fi -if [ -r /bin/netstat ]; then -/bin/netstat > $DUMP_DIR/netstat.dump -echo -e ".\c" -fi -echo "OK!" -``` diff --git a/content/en/docs/v2.7/dev/principals/expansibility.md b/content/en/docs/v2.7/dev/principals/expansibility.md deleted file mode 100644 index b0e9ab051e9b..000000000000 --- a/content/en/docs/v2.7/dev/principals/expansibility.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -type: docs -title: "Talk About Expansion Of Extension And Incremental Extension" -linkTitle: "Extensibility" -weight: 4 ---- - -> http://javatar.iteye.com/blog/690845 - - -There are more and more products in our platform, the function of the product also more and more.Platform products in order to meet the requirement of each BU and department as well as product line, will surely will be a lot of irrelevant function together, the customer can use selective.In order to compatible with more demand for each product, each framework, are constantly expanding, and we often choose some extension of the extension, namely to old and new function expanded into a general implementation.I want to discuss is, in some cases also can consider to the expansion of the incremental way, also is to retain the original function of simplicity, new feature implementation independence.I have been doing the development of distributed service framework, and then take such problem in our project. - -Such as: remote invocation framework, definitely not serialize function, function is very simple, is to transfer as object, the object into a stream.But because of some places may be using osgi, such serialization, IO in this may be isolated and the business side of this.Need to stream into byte [] array, and then passed on to the business side of this serialization.In order to adapt itself to the requirements of the osgi, expanded the original non osgi with osgi scenes, so, no matter whether the osgi environment, all will move into a byte [] array, first copy again.However, most of the scenes with osgi, paid the price, but for the osgi.And if adopts incremental extension method, the osgi code intact, plus an osgi implementation, when wanting to use osgi, rely on osgi implementation can directly. - -Such as: remote invocation framework, definitely not serialize function, function is very simple, is to transfer as object, the object into a stream.But because of some places may be using osgi, such serialization, IO in this may be isolated and the business side of this.Need to stream into byte [] array, and then passed on to the business side of this serialization.In order to adapt itself to the requirements of the osgi, expanded the original non osgi with osgi scenes, so, no matter whether the osgi environment, all will move into a byte [] array, first copy again.However, most of the scenes with osgi, paid the price, but for the osgi.And if adopts incremental extension method, the osgi code intact, plus an osgi implementation, when wanting to use osgi, rely on osgi implementation can directly. - -Such as: no status messages before, is very simple, just pass a serialized object.Later a synchronous message send demand, need a Request/Response matching, using extended extension, naturally thought, stateless news is actually a Request without Response, add a Boolean state so in the Request, said do you want to return the Response.If the message is sent to a Session needs again, then add a Session interaction, and then found that the original synchronous message sent is a special case of Session message, all scenarios Session, don't need the Session can be ignored. - -![open-expand](/imgs/dev/open-expand.jpg) - -If the incremental extension, stateless messages intact, synchronous message is sent, on the basis of stateless news add a Request/Response processing, message sending session, plus a SessionRequest/SessionResponse processing. - -![close-expand](/imgs/dev/close-expand.jpg) diff --git a/content/en/docs/v2.7/dev/principals/extension.md b/content/en/docs/v2.7/dev/principals/extension.md deleted file mode 100644 index d84628c5d459..000000000000 --- a/content/en/docs/v2.7/dev/principals/extension.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -type: docs -title: "Extension Points To Reconstruct" -linkTitle: "Extension" -weight: 5 ---- - - -> http://javatar.iteye.com/blog/1041832 - -With the promotion of service, the website of Dubbo service framework requirements gradually increase, Dubbo existing developers can implement demand is limited, many requirements have been delay, and site classmates also want to participate, combined with field, so the platform will be open to internal part of the project, let everyone together to implement, Dubbo as one of the pilot project. - -Now that want to open it, about to take some extension point Dubbo, let participants black box extend as far as possible, rather than a white box to modify the code, or branch, quality, merger, the conflict will be hard to manage. - -First look at the Dubbo existing design: - -![design-step-1](/imgs/dev/design-step1.png) - -There though some extension interface, but not very good collaboration, and loading and configuration of extension points are not unified handling, so face it under the refactoring. - -## Step 1, the core plug-in, equal treatment to the third party - -Now that want to expand, extension point loading mode, the first thing to unification, micro core + plug-in, can achieve the principle of OCP is train of thought. - -Made up of a plugin lifecycle management container, core, core does not include any functions, this will ensure that all functions can be replaced, and framework, the authors can achieve the function of the extension must also can do it, so as to guarantee the equal treatment to a third party, so, the function of the framework itself also want to use the plug-in way, cannot have any hard coded. - -Micro core usually adopt the Factory, the IoC, the OSGi plugin lifecycle management.Consider the applicable Dubbo, strong don't want to rely on the Spring IoC container.The IoC container that you made a small also feel a little too much design, so intend to use the most simple way of Factory management plug-in. - -Finally decided to adopt the JDK standard SPI extension mechanism, see: ` Java. Util. The ServiceLoader `, namely extension in the jar package ` meta-inf/services / ` directory placed with interface of text files, with the same content for interface implementation class name, multiple separate implementation class name with a newline.Need to expand Dubbo agreement, for example, simply by XXX. Placed in a jar file: ` meta-inf/services/com. Alibaba. Dubbo. RPC. Protocol `, contents for ` com. Alibaba. XXX. XxxProtocol `.Dubbo by ServiceLoader scanning to all Protocol implementation. - -All plug-in and agreed, must be marked with: ` @ the Extension ` (" name "), as the identity of the name, after loading is used to configure option. - -## Step 2 each extension point encapsulate a change factor, only to maximize reuse - -Each extension point implementers, usually only care about one thing, now the extension points, is not entirely separate.Such as: Failover, the Route, LoadBalance, Directory not completely separate, all written by RoutingInvokerGroup died. - -Again, for example, protocol extension, the extension may just want to replace the serialization way, or just replace transmission mode, and Remoting and Http can also reuse serialization, etc.In this way, the need for transport, the client, the server implementation, protocol parsing, data serialization, allow different extension point. - -After break up, the design is as follows: - -![design-step-2](/imgs/dev/design-step2.png) - - -## Step 3, the entire pipeline design, logic framework itself, are implemented using cross section intercept - -Now a lot of logic, are placed in the base class implementation, then by the method of template back to the realization of the tone categories, including: local, mock, generic, echo, token, accesslog, monitor, count, limit, etc., can use the Filter to realize all split, each function is called a ring on the chain.Such as: (the base class template method) - -```java -public abstract AbstractInvoker implements Invoker { - - public Result invoke(Invocation inv) throws RpcException { - // Pseudo code - active ++; - if (active > max) - wait(); - - doInvoke(inv); - - active --; - notify(); - } - - protected abstract Result doInvoke(Invocation inv) throws RpcException - -} -``` - -To: (chain filter) - -```java -public abstract LimitFilter implements Filter { - - public Result invoke(Invoker chain, Invocation inv) throws RpcException { - // Pseudo code - active ++; - if (active > max) - wait(); - - chain.invoke(inv); - - active --; - notify(); - } - -} -``` - -## Step 4, a minimum concept, consistent conceptual model - -Keep the concept of as little as possible, help to understand, for open systems is particularly important.In addition, the interface can use a consistent conceptual model, can guide each other, and reduce the model transformation, - -For example, Invoker method signature as follows: - -```java -Result invoke(Invocation invocation) throws RpcException; -``` - -The Exporter method signature as follows: - -```java -Object invoke(Method method, Object[] args) throws Throwable; -``` - -But they are the same, only is a on the client side, one on the server side, different model classes are applied. - -For example, the URL string, parse and assembled, not a URL model classes, and the Parameters of the URL, but sometimes the Map, and sometimes the Parameters class wrapping, - -```java -export(String url) -createExporter(String host, int port, Parameters params); -``` - -Use consistent model: - -```java -export(URL url) -createExporter(URL url); -``` - -For example, the existing: Invoker, Exporter, InvocationHandler, FilterChainAre actually invoke behavior at different stages, can abstract away completely, unified for the Invoker, reduce the concept. - -## Step 5, hierarchical, modular extensions, rather than generic type extension - -Why see:[expansibility](../expansibility) - -Generalization expansion refers to: the extension point gradually abstraction, take all functions, sets and new function is always set in and expand the function of the old concept. - -Combined extension refers to: the extension points orthogonal decomposition, all functions of overlap, new function is always based on the old function implementation. - -The above design, unconsciously will Dubbo existing function as the core functionality.Above contains the concept of Dubbo existing RPC all functions, including: the Proxy, the Router, Failover, LoadBalance, Subscriber, Publisher, Invoker, Exporter, Filter, etc., -But these are the core?RPC can Run, kicked off what?And what is not kick off?Based on this consideration, the RPC can be broken down into two levels, Protocol and Invoker is the core of RPC.Other, including the Router, Failover, Loadbalance, Subscriber, the Publisher is the core, but the Routing.Therefore, the Routing as an extension of the Rpc core, design is as follows: - -![design-step-3](/imgs/dev/design-step3.png) - -## Step 6, and networking - -After finishing, the design is as follows: - -![design-step-4](/imgs/dev/design-step4.png) - - diff --git a/content/en/docs/v2.7/dev/principals/general-knowledge.md b/content/en/docs/v2.7/dev/principals/general-knowledge.md deleted file mode 100644 index 9d974123c816..000000000000 --- a/content/en/docs/v2.7/dev/principals/general-knowledge.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -type: docs -title: "Some In The Design Of The Basic Common Sense" -linkTitle: "General Rule" -weight: 6 ---- - -> http://javatar.iteye.com/blog/706098 - -Recently told the new team some design on the common sense, is likely to be new and some other help, the thought of a few temporarily, first write here. - -## The API and SPI separation - -Framework or component there are generally two types of customers, one is a consumer, is an extension.API (Application Programming Interface) is used to users, and SPI (Service dojo.provide Interface) is used to expand.At design time, try to put them off, and don't mix.In other words, the user is can't see write the implementation of the extension. - -For example, a Web framework, it has an API interface to call the Action, there is a the execute () method, which is for the user to write business logic.Then, Web frameworks have a SPI interface to extend the control output, such as velocity templates output or a json output, etc.If this Web framework using an inheritance VelocityAction and a JsonAction as extension of the Action, with output velocity templates will inherit VelocityAction, want to use the json output will inherit JsonAction, this is the opposite of the API and SPI no separation example, SPI interface in the API interface. - -![mix-api-spi](/imgs/dev/mix-api-spi.jpg) - - -Is a reasonable way, there is a separate Renderer interface, VelocityRenderer and JsonRenderer implementation, Web framework will transfer the output of the Action to the Renderer interface for rendering output. - -![seperate-api-spi](/imgs/dev/seperate-api-spi.jpg) - - -## Service domain/entity/session domains separation - -Any framework or component, there will always be the core domain model, such as: Spring Bean, Struts Action, Service of Dubbo, Napoli Queue, and so on.The core areas of the model and its component is called physical domain, it represents our goal to operate on itself.Physical domain is thread-safe, usually either through the same class, sync, or copy the way. - -Service domain, that is, behavior domain, it is the function of the components, but also is responsible for the entity and session domains of life cycle management, such as Spring ApplicationContext, Dubbo ServiceManager, etc.Service domain objects often is heavy, and is thread-safe, and serve all calls to a single instance. - -What is a session?Is an interactive process.Session key is the concept of context, the context is what?For example, we said: "old place", the "old place" is the context information.Why do you say "old place" other person will know, because we defined earlier the specific content of the "old place".So, the context often hold state variables in the process of interaction, etc.The session object, were generally mild and every request to create an instance, destroyed after the request.In short: the meta information held by the entity domain, the temporary state of a request by the session domain, by the service domain throughout the entire process. - -![ddd](/imgs/dev/ddd.jpg) - - -## On the important process to interceptor interface - -If you want to write a remote invocation framework, the remote call block the process should have a unified interface.If you want to write an ORM framework, that at least the SQL execution, the Mapping process to intercept interface;If you want to write a Web framework, the request execution should be interception interfaces, and so on.No common framework can Cover all requirements, allowing external behavior, is the basic extension of the framework.Before a remote call, so that if someone wants to verify ordered CARDS, verification of black and white list, log statistics;If someone wants to add paging under packing before SQL execution, do data access control, statistics under the SQL execution time.If someone wants to check before the request execution, packaging, input and output flow request quantity statistics, and so on, can accomplish on their own, rather than into frame inside.Interception interfaces, usually to encapsulate process itself with an object, to the interceptor chain, such as: remote calls the main process for the invoke (), the interceptor interface to invoke usually (Invocation), Invocation object encapsulates the would have the execution context, and Invocation in an invoke () method, performed by the interceptor decide when, at the same time, also on behalf of the interceptor Invocation itself, such a interceptor Invocation is actually the process of packaging the next interceptor, until the last interceptor Invocation is packing the final invoke () process;Similarly, the main process for the execute SQL (), the interceptor interface is usually the execute (Execution), principle.Can implement ways, of course, the above is only for example. - -![filter-chain](/imgs/dev/filter-chain.jpg) - -## The important status of sending events and set aside to monitor interface - -Here to tell the difference between an event and the interceptor above, the interceptor is in the process of intervention, it is part of the process, is based on process behavior, and event is based on state data, any behavior changes of the same condition, the event should be consistent.Event is usually after the event notification is a Callback interface, the method name is usually past tense, such as onChanged ().Remote invocation framework, for example, when the network disconnect or even should send out an event, when there is an error can also be considered an event, such peripheral applications could be observed within the framework of change, make corresponding adjustment. - -![event-listener](/imgs/dev/event-listener.jpg) - -## Extension interface functions as a single, composability - -For example, the remote invocation framework agreement is to replace it.If only provide a general extension interface, switch can deal, of course, but the protocol support can be subdivided into the underlying communication, serialization, dynamic proxy mode and so on.If the interface split, orthogonal decomposition, will be easier to reuse existing logical extension, and just replace a part of the implementation strategy.Of course the decomposition the granularity of the need to grasp. - -## Micronucleus plug-in, equal treatment to the third party - -"A good framework of development, abide by the concept of micronucleus.Eclipse is OSGi microkernel, Spring's microkernel is the BeanFactory, Maven microkernel is breadth.With functional core is usually should not be, but a life cycle and integrated container, so that each function can interact through the same way and extension, and any function can be replaced.If they do not microkernel, must be at least equal treatment to a third party, namely, the author can realize the function of extension should can be done by extending all the way.The author want to regard themselves as extension, so as to ensure framework of sustainability and stability of the outside introversion. - -## Don't control the external object lifecycle - -Such as the above said the Action using the interface and the Renderer extension interface.Framework if let users or extend the Action or the Renderer implementation class name of the class or kind of meta information submitted, then internally by reflecting newInstance () to create an instance of this framework is to control the Action or the Renderer implementation class life cycle, the Action or the Renderer physical, frameworks do it himself, external extension or integration are powerless.Good idea is to let the user or extend the Action or submitted to the realization of the Renderer class instance, framework just use these instances, is how to create these objects, how to destroy, had nothing to do with frame, frame up to provide assistant management tools, rather than absolute control. - -## Configurable must be programmable, and maintain friendly CoC conventions - -Framework using the environment uncertainty because of the many, there will always be some configuration, usually to a specified name classpath straight sweep configuration, or startup allows you to specify the configuration path.As a common framework, should do all can do configuration file must be able to programmatically, or when the user needs to be your frame with another frame integration will bring a lot of unnecessary trouble. - -In addition, as far as possible do a standard contract, if the user has to do things by some sort of agreement, there is no need for the configuration items.Such as: configuration templates location, you can agree, if in the templates directory doesn't have to match, if you want to change the directory, and configuration. - -## Distinguish between commands and queries, clear pre-conditions and post-conditions - -This is part of the design by contract, try to keep to a return value method is to query methods, void return method is to command.Query methods are usually idempotence, without side effects, also is not change any state, the n results are the same, such as the get a property value, or query a database record.Command is to point to have side effects, namely will change state, such as set a value, or update a database record.If you have modified the status of the operation, do a query returns again, if possible, to split it into writing reading separation of the two methods, such as: User deleteUser (id), delete users and returns the deleted users, consider to the getUser () and void deleteUser ().In addition, each method is front-facing assert that the legitimacy of the incoming parameters, as far as possible the rear assertion returns the legitimacy, and documented. - -## Incremental extension, and not to extend the original core concept - -refer to:[expansibility](../expansibility) diff --git a/content/en/docs/v2.7/dev/principals/robustness.md b/content/en/docs/v2.7/dev/principals/robustness.md deleted file mode 100644 index b870adb27ad8..000000000000 --- a/content/en/docs/v2.7/dev/principals/robustness.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -type: docs -title: "The Robustness Of The Design Implementation" -linkTitle: "Robustness" -weight: 7 ---- - -Dubbo as a remote service exposure, calls and management solutions, through the meridians of the application is running, its itself to achieve robustness of importance is self-evident. - -Here are some Dubbo principle and method of use. - -## The log - -Logging is one of the most commonly used way to find, discover problems. Log quality is often neglected, there is no log on using expressly agreed upon. Attaches great importance to the use of the Log, and improve the concentration of the Log information. Log too much, too much chaos, could lead to useful information. - -To effectively use this tool to note: - -### Record the contents of the stipulated strictly WARN, the ERROR level - -* WARN that can restore the problem without human intervention. -* The ERROR says requires human intervention. - -With such agreement, the regulatory system found in the ERROR log file of the string will call the police, and to minimize the occurrence. Excessive alarm can let a person tired, make the person lose vigilance in alarm, make the ERROR log. Along with artificial, regularly check the WARN level information to assess the degree of "subhealth" system. - -### In the log, as much as possible to collect key information - -What is the key information? - -* Site information at the time of the problem, namely the screening questions to use information. Such as service invocation fails, to give the use of Dubbo version, the service provider's IP, which is used in the registry; Which service invocation, which method and so on. This information if not given, then later artificial collection, problem after the site may have already can't recover, increase the difficulty of the problem. -* If possible, the cause of the problem and the solution is given. This makes maintenance and problem solving becomes simple, rather than seeking savvy (often the implementer) for help. - -### Don't duplicate records many times the same or a class of problems - -The same or a kind of abnormal log continuous there dozens of times, still can often see.The human eye is easy to miss under the different important log information. Try to avoid this situation. Will appear in the foreseeable, it is necessary to add some logic to avoid. - -As a symbol for a question, a problem after log Settings after sign and avoid a repeat of the log. The problem clear sign after recovery. - -Although a bit troublesome, but do ensure log information concentration, the more effective for monitoring. - -## Limit set - -Resources are limited, CPU, memory, IO, etc. Don't cry because it is outside of the request, the data is not limited. - -### The size of the thread pool (ExectorService) and saturated strategy - -The Server end ExectorService set limit for processing requests. Use limited queue ExecutorService task waiting queue, avoid resource depletion. When the task waiting queue saturated, choose a suitable saturated strategy. This ensures smooth degradation. - -In Dubbo, saturated strategy is to discard data, waiting for the result is only a request timeout. - -Saturated, the specification has reached the maximum load, the service provider to logging in the operation of the saturated strategy of the problem, in order to monitor warnings. Remember to be careful not to repeat many times record well. (note that the default saturation strategy will not have these additional operation.) According to the frequency of the alarm, has decided to increase adjustment, etc., avoid system problems are ignored. - -### The collection capacity - -If to ensure element is controlled on the collection and is small enough, then you can rest assured use.This is most of the situation. If can't guarantee anything, use a bounded set. When reach the boundary, choose a suitable strategy. - -## Fault tolerant - retry - recovery - -High availability components to tolerate its dependence on the failure of the component. - -### Dubbo service registry - -The service registry using the database to store the information service providers and consumers. Different registry registry cluster through the database to synchronize data, to perceive other providers on the registry. Registry would ensure a provider and consumer data in memory, the database is unavailable, independent of the normal operation of foreign registry, just can't get other registry data. When the database recovery, retry logic will modify memory write data back to the database, and get a new database data. - -### Service consumers - -After the message service provider list from the registry, will save the provider list to memory and disk file. Consumers can function properly after this registry is down, even in the registry during outage restart consumers. Consumers started, find the registry is not available, will read the list stored in the disk file provider. Retry logic to ensure the registry after recovery, update the information. - -## Retry delay strategy - -On a bit of the subproblem. Dubbo encountered two related scenario. - -### On the database lock - -Registration center will regularly update the database of a record timestamp, such cluster other registry perceive it is alive. Overdue registry and its associated data will be cleared. Database is normal, the mechanism as well. But the database load is high, its every action is slow. This occurs: - -A registry that B expired, delete B data. B find their data, to write their own data repeatedly. These repeated operation and increase load the database, deterioration. - -Use the following logic: - -When data is deleted B found themselves fail (write), choose to wait for this period of time and try again. Can choose to retry time exponentially, such as first class 1 minute, the second for 10 minutes, 100 minutes for the third time. -This decrease after operation, ensure database can cooling Down (Cool Down). - -### The Client reconnection registry - -When a registry downtime, other Client will receive events at the same time, and to reconnect to another registry. The Client number is relatively more, will be the impact of the registry. Avoid method can be a Client reconnection random delay for 3 minutes, when the reconnection spread out. diff --git a/content/en/docs/v2.7/dev/release.md b/content/en/docs/v2.7/dev/release.md deleted file mode 100644 index 68881c84749e..000000000000 --- a/content/en/docs/v2.7/dev/release.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -type: docs -title: "Versions" -linkTitle: "Versions" -weight: 9 -description: "Dubbo versioning contract" ---- - -**New feature development** and **stability improvement** are equally important to product. But adding new features will affect stability, dubbo uses the following version development pattern to achieve a good balance. - -## Two versions evolving at the same time - -* BugFix Version:low version,e.g. `2.4.x`. This is called the GA version, which can be applied in production. We are supposed only to fix bugs in this version, and increase the third version number when release. -* Feature Version:high version, e.g. `2.5.x`. We add new features to this version, so applications have opportunities try new features. - -When features in `2.5.x` are proved stable enough, we will announce `2.5.x` as a beta release. - -When `2.5.x` proved stable after enough test on enough applications: - -* `2.5.x`, the GA Version, only do BugFix, the main version to be used. We can try to promote applications to upgrade to GA at the desired time. -* `2.4.x`, no longer maintained. When bugs appear, applications have no choice but upgrade to the latest stable version- Sunset Clause -* We create a new branch `2.6.0` based on `2.5.x` for new features. - -## Pros - -* GA Version are promised stable: - * only BugFix - * GA Version got enough tests before promotion -* New features can respond quickly in Feature Version and allow applications to try that -* Significantly reduces development and maintenance costs - -## The responsibilities of users - -Users should always keep in track with the GA Version, make sure all bugs were fixed. - -There is a fake proposition: regular upgrades bring more risks. Here's the reasons: - -* GA remains stable after a trial period. -* Bugs find on GA will be fixed immediately. -* Comparing with the on-need-upgrade (only upgrade when find a serious problem, and may span multiple versions), upgrade periodically can flat risk. Experienced a long cycle of large projects, students will have such an experience, the tripartite library version does not upgrade for a long time, the result of the problem had to upgrade to the new version (across multiple versions) a huge risk. diff --git a/content/en/docs/v2.7/user/_index.md b/content/en/docs/v2.7/user/_index.md deleted file mode 100644 index 4d7edc7b753a..000000000000 --- a/content/en/docs/v2.7/user/_index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: docs -title: "User Documentation" -linkTitle: "User" -weight: 10 -description: "Learn about Dubbo including its main features and capabilities" ---- \ No newline at end of file diff --git a/content/en/docs/v2.7/user/benchmark-tool.md b/content/en/docs/v2.7/user/benchmark-tool.md deleted file mode 100644 index c8c32fccdf23..000000000000 --- a/content/en/docs/v2.7/user/benchmark-tool.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -type: docs -title: "Benchmark Suite" -linkTitle: "Benchmark Suite" -weight: 18 -description: "Run Dubbo benchmark suite" ---- - -* download: git clone https://github.com/apache/dubbo.git -* compile benchmark: cd dubbo/dubbo-test/dubbo-test-benchmark; mvn clean install -* uncompress benchmark: dubbo/dubbo-test/dubbo-test-benchmark/target/dubbo-test-benchmark-2.6.2-SNAPSHOT.tar.gz - -Read ReadMe.txt (the contents are as follows, in the compressed package.) - -* Build a new benchmark project, such as demo.benchmark - -* Import the your own interface api jar and dubbo.benchmark.jar (Unzip dubbo.benchmark.tar.gz, under the lib directory ) - -* Create a new class to implement AbstractClientRunnable - - * Implement the constructor of the parent class - * Implement the invoke method and create a local interface proxy by serviceFactory,and finish your own business logic, as follows: - - ```java - public Object invoke(ServiceFactory serviceFactory) { - DemoService demoService = (DemoService) serviceFactory.get(DemoService.class); - return demoService.sendRequest("hello"); - } - ``` - -* Make your own benchmark project into a jar package, such as demo.benchmark.jar - -* Put the demo.benchmark.jar and service API jar into directory dubbo.benchmark/lib - -* Configuring dubbo.properties - -* Run run.bat(windows) or run.sh(linux) - -If you want to test the different versions of Dubbo, you can replace the jar of the Dubbo. - diff --git a/content/en/docs/v2.7/user/best-practice.md b/content/en/docs/v2.7/user/best-practice.md deleted file mode 100644 index afb06690eb85..000000000000 --- a/content/en/docs/v2.7/user/best-practice.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -type: docs -title: "Best practice" -linkTitle: "Best practice" -weight: 13 -description: "Best practices of using dubbo" ---- - -## Modularization - -It is recommended to put service interfaces, service models, service exceptions, and so on in the API package,Because the service model and exception are part of the API, it is also in conformity with the modularization principle:Reusing the publish equivalence principle (REP) and the Common Reuse Principle (CRP). - -If you need, you can also consider placing a spring reference configuration in the API package, so that the user can only use the configuration in the spring loading process, and the configuration suggestion is placed in the package directory of the module, so as not to conflict, eg:`com/alibaba/china/xxx/dubbo-reference.xml`。 - -## Granularity - -The service interface should have large granularity as possible.Each service method should represent a function rather than a step of a function, otherwise it will be faced with distributed transaction problem. Dubbo does not provide distributed transaction support at present. - -The service interface recommends the division of the business scene as a unit and abstract the similar business to prevent the explosion of the number of interfaces. - -It is not recommended to use an too abstract universal interface, such as Map query (Map), which has no explicit semantics, which will inconvenience later maintenance. - -## Version - -Each interface should define a version number to provide possible subsequent incompatible upgrades,eg: ``。 - -It is recommended to use a two bit version number, because the third - bit version number is usually compatible with a compatible upgrade, and a change of service version is required only when incompatible. - -When incompatible, half of the provider is upgraded to a new version, and all the consumers are upgraded to a new version, and the remaining half providers are upgraded to a new version. - -## Compatibility - -The service interface adds method or the service model adds fields. It can be backward compatible, delete methods or delete fields, and will not be compatible. The new fields of the enumerated type are not compatible, so we need to upgrade by changing the version number. - -The compatibility of each protocol is different, see: [Protocol introduction](../references/protocol/) - -## Enumeration type - -If it is a complete set, you can use Enum, eg:`ENABLE`, `DISABLE`。 - -If it is the type of business, there will be an obvious type of increase in the future, and it is not recommended to use `Enum`, and it is not recommended to use Enum and can be replaced by `String` . - -If you use`Enum`in the return value,And add the `Enum` value,suggestions to upgrade the service consumption, so that the service provider does not return a new value. - -If the `Enum` value is used in the incoming parameter,and add the `Enum` value,it is suggested that the service provider be upgraded first, so that the service consumer will not pass the new value. - -## Serialization - -The service parameters and return values suggest that the POJO object is used, that is, the object of the attribute is represented by the `setter`, `getter` method. - -Service parameters and return values do not recommend the use of interfaces, because data model abstraction is of little significance, and serialization requires interfaces to implement meta information of classes, and can not play the purpose of hiding implementation. - -Service parameters and return values must be byValue, but not byReference. The reference or return values of consumers and providers are not the same, but the values are the same. Dubbo does not support remote objects. - -## Exception - -It is suggested that abnormal reporting errors are used rather than return error codes, and exception information can carry more information and have more semantic friendliness. - -If you are worried about performance problems, you can use the override () method of fillInStackTrace () out of the exception class as an empty method to make it not a copy of the stack information when necessary. - -Query method is not recommended throws checked, otherwise the caller in the query will be too much `try...catch, and can not be processed.` - -Service providers should not throw the exception of DAO or SQL to the consumer side. They should package the exception that consumers do not care about in service implementation, otherwise consumers may not be able to serialize the corresponding exception. - -## Call - -Not just because it is a Dubbo call, wrap the call logic with `try...catch`clause. `try...catch` should be added to the appropriate rollback boundary. - -The check logic for the input parameters should be available at the Provider side. For performance considerations, the service implementer may consider adding a service Stub class to the API package to complete the test. diff --git a/content/en/docs/v2.7/user/capacity-plan.md b/content/en/docs/v2.7/user/capacity-plan.md deleted file mode 100644 index a4c8cbb80c93..000000000000 --- a/content/en/docs/v2.7/user/capacity-plan.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -type: docs -title: "Capacity plan" -linkTitle: "Capacity plan" -weight: 15 -description: "Dubbo capacity plan" ---- - -The following data for reference: - -## Use member service project of Dubbo - -* Receive 400,000,000 remote calls one day -* Use 12 standard servers to provide services (CPU:8 core, memory: 8G) -* The average load is less than 1 (For 8 core CPU, the load is very low) -* The average response time is 2.3 to 2.5 ms,Network cost about 1.5 to 1.6 ms(Related to the size of the packet ) - -## Use product authorization service project of Dubbo - -* Receive 300,000,000 remote calls one day -* Use 8 standard servers to provide services (CPU:8 core, memory: 8G) -* The average load is less than 1 (For 8 core CPU, the load is very low) -* The average response time is 1.4 to 2.8 ms,Network cost about 1.0 to 1.1 ms(Related to the size of the packet ) \ No newline at end of file diff --git a/content/en/docs/v2.7/user/configuration/_index.md b/content/en/docs/v2.7/user/configuration/_index.md deleted file mode 100644 index b67304f3958e..000000000000 --- a/content/en/docs/v2.7/user/configuration/_index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: docs -title: "Dubbo Configuration" -linkTitle: "Configuration" -weight: 5 -description: "Learn about dubbo configuration" ---- \ No newline at end of file diff --git a/content/en/docs/v2.7/user/configuration/annotation.md b/content/en/docs/v2.7/user/configuration/annotation.md deleted file mode 100644 index aa903e311b11..000000000000 --- a/content/en/docs/v2.7/user/configuration/annotation.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -type: docs -title: "Annotation Configuration" -linkTitle: "Annotation" -weight: 4 -description: "Configure Dubbo with annotation" ---- - -{{% pageinfo %}} - Requires`2.6.3` or higher, click here to view the [complete sample](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-annotation) -{{% /pageinfo %}} - - -## Provider Side -k -### `@DubboService` annotation for exporting - -```java -@DubboService -public class AnnotationServiceImpl implements AnnotationService { - @Override - public String sayHello(String name) { - return "annotation: hello, " + name; - } -} -``` - -### Add application sharing configuration - -```properties -# dubbo-provider.properties -dubbo.application.name=annotation-provider -dubbo.registry.address=zookeeper://127.0.0.1:2181 -dubbo.protocol.name=dubbo -dubbo.protocol.port=20880 -``` - -### Spring scan path - -```java -@Configuration -@EnableDubbo(scanBasePackages = "org.apache.dubbo.samples.simple.annotation.impl") -@PropertySource("classpath:/spring/dubbo-provider.properties") -static public class ProviderConfiguration { - -} -``` - -## Consumer Side - -### `@Reference` annotation for reference - -```java -@Component("annotationAction") -public class AnnotationAction { - - @Reference - private AnnotationService annotationService; - - public String doSayHello(String name) { - return annotationService.sayHello(name); - } -} -``` - -### Add application sharing configuration - -``` -# dubbo-consumer.properties -dubbo.application.name=annotation-consumer -dubbo.registry.address=zookeeper://127.0.0.1:2181 -dubbo.consumer.timeout=3000 -``` - -### Spring scan path - -```java -@Configuration -@EnableDubbo(scanBasePackages = "org.apache.dubbo.samples.simple.annotation.action") -@PropertySource("classpath:/spring/dubbo-consumer.properties") -@ComponentScan(value = {"org.apache.dubbo.samples.simple.annotation.action"}) -static public class ConsumerConfiguration { - -} -``` - -### Invoke service - -```java -public static void main(String[] args) throws Exception { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class); - context.start(); - final AnnotationAction annotationAction = (AnnotationAction) context.getBean("annotationAction"); - String hello = annotationAction.doSayHello("world"); -} -``` diff --git a/content/en/docs/v2.7/user/configuration/api.md b/content/en/docs/v2.7/user/configuration/api.md deleted file mode 100644 index 5a9c79c8b4a9..000000000000 --- a/content/en/docs/v2.7/user/configuration/api.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -type: docs -title: "API Configuration" -linkTitle: "API" -weight: 3 -description: "Configure Dubbo with API" ---- - -> All API properties have counterparts in XML, see [XML References](../../references/xml/) for details. For example `ApplicationConfig.setName("xxx")` equals to `` [^1] - - -## Provider Side - -```java -import org.apache.dubbo.rpc.config.ApplicationConfig; -import org.apache.dubbo.rpc.config.RegistryConfig; -import org.apache.dubbo.rpc.config.ProviderConfig; -import org.apache.dubbo.rpc.config.ServiceConfig; -import com.xxx.XxxService; -import com.xxx.XxxServiceImpl; - -// Implementation -XxxService xxxService = new XxxServiceImpl(); - -// Application Info -ApplicationConfig application = new ApplicationConfig(); -application.setName("xxx"); - -// Registry Info -RegistryConfig registry = new RegistryConfig(); -registry.setAddress("10.20.130.230:9090"); -registry.setUsername("aaa"); -registry.setPassword("bbb"); - -// Protocol -ProtocolConfig protocol = new ProtocolConfig(); -protocol.setName("dubbo"); -protocol.setPort(12345); -protocol.setThreads(200); - -// NOTES: ServiceConfig holds the serversocket instance and keeps connections to registry, please cache it for performance. - -// Exporting -ServiceConfig service = new ServiceConfig(); // In case of memory leak, please cache. -service.setApplication(application); -service.setRegistry(registry); // Use setRegistries() for multi-registry case -service.setProtocol(protocol); // Use setProtocols() for multi-protocol case -service.setInterface(XxxService.class); -service.setRef(xxxService); -service.setVersion("1.0.0"); - -// Local export and register -service.export(); -``` - -## Consumer Side - -```java -import org.apache.dubbo.rpc.config.ApplicationConfig; -import org.apache.dubbo.rpc.config.RegistryConfig; -import org.apache.dubbo.rpc.config.ConsumerConfig; -import org.apache.dubbo.rpc.config.ReferenceConfig; -import com.xxx.XxxService; - -// Application Info -ApplicationConfig application = new ApplicationConfig(); -application.setName("yyy"); - -// Registry Info -RegistryConfig registry = new RegistryConfig(); -registry.setAddress("10.20.130.230:9090"); -registry.setUsername("aaa"); -registry.setPassword("bbb"); - -// NOTES: ReferenceConfig holds the connections to registry and providers, please cache it for performance. - -// Refer remote service -ReferenceConfig reference = new ReferenceConfig(); // In case of memory leak, please cache. -reference.setApplication(application); -reference.setRegistry(registry); -reference.setInterface(XxxService.class); -reference.setVersion("1.0.0"); - -// Use xxxService just like a local bean -XxxService xxxService = reference.get(); // NOTES: Please cache this proxy instance. -``` - -## Specials - -Only care about the differences: - -### Configuration of Method level - -```java -... - -// Method level config -List methods = new ArrayList(); -MethodConfig method = new MethodConfig(); -method.setName("createXxx"); -method.setTimeout(10000); -method.setRetries(0); -methods.add(method); - -// Referring -ReferenceConfig reference = new ReferenceConfig(); -... -reference.setMethods(methods); - -... -``` - -### Peer to Peer - -```java - -... - -ReferenceConfig reference = new ReferenceConfig(); -// If you know the address of the provider and want to bypass the registry, use `reference.setUrl()` to specify the provider directly. Refer [How to Invoke a specific provider](../demos/explicit-target/) for details. -reference.setUrl("dubbo://10.20.130.230:20880/com.xxx.XxxService"); - -... -``` - - -[^1]: When should we usd API: API is very useful for integrating with systems like OpenAPI, ESB, Test, Mock, etc. General Providers and Consumers, we still recommend use [XML Configuration](../xml). diff --git a/content/en/docs/v2.7/user/configuration/configuration-load-process.md b/content/en/docs/v2.7/user/configuration/configuration-load-process.md deleted file mode 100644 index 2668dc7cf498..000000000000 --- a/content/en/docs/v2.7/user/configuration/configuration-load-process.md +++ /dev/null @@ -1,186 +0,0 @@ ---- -type: docs -title: "Configuration Loading Process" -linkTitle: "Loading Process" -weight: 5 -description: "Loading process for dubbo configuration" ---- - -This document focuses on **how the Dubbo framework collects the required configuration** (including application configuration, registry configuration, service configuration, etc.) **during the application startup phase** to complete the process of service exposure and reference. - -Depending on how you drive it (such as Spring or naked API programming), the configuration form will certainly vary, for detail please refer to [XML Configuration](../xml), [Annotation Configuration](../annotation) and [API Configuration](../api). In addition to the differences in peripheral drivers, Dubbo's configuration reads generally follow the following principles: - -1. Dubbo supports multiple levels of configuration and automatically override configurations according to predetermined priorities. Eventually, all configurations are aggregated to the data bus URL to drive subsequent service exposure, reference and other processes. -2. ApplicationConfig, ServiceConfig and ReferenceConfig can be regarded as configuration sources, which collect configuration by directly user-oriented programming. -3. The configuration format is mainly `Properties`, and the configuration content follows conventions -3. The configuration format is mainly Properties, and the configuration content follows the agreed `path-based` naming [specification](#Configuration Format). - -## Configuration Source - -First, starting with the configuration sources that Dubbo supports, there are four default configuration sources: - -- JVM System Properties,-Dproperty -- Externalized Configuration -- ServiceConfig, ReferenceConfig and other programming interface collected configuration -- Local configuration file dubbo.properties - -### Override Priority - -The figure below shows the priority of configuration override, decreasing from top to bottom: - -![Override Priority](/imgs/blog/configuration.jpg) - -click here to view [Externalize configuration details](/zh-cn/docsv2.7/user/configuration/config-center/) - - -## Configuration Format - -Currently, all configurations supported by Dubbo are in the format of `.properties`, including `-D`, `Externalized Configuration`, etc., and all configuration items in `.properties` follow a `path-based` Configuration format: - -```properties -# Application level -dubbo.{config-type}[.{config-id}].{config-item}={config-item-value} -# Service level -dubbo.service.{interface-name}[.{method-name}].{config-item}={config-item-value} -dubbo.reference.{interface-name}[.{method-name}].{config-item}={config-item-value} -# Multiple configuration items -dubbo.{config-type}s.{config-id}.{config-item}={config-item-value} -``` - -- Application level - -```properties -dubbo.application.name=demo-provider -dubbo.registry.address=zookeeper://127.0.0.1:2181 -dubbo.protocol.port=-1 -``` - -- Service level - -```properties -dubbo.service.org.apache.dubbo.samples.api.DemoService.timeout=5000 -dubbo.reference.org.apache.dubbo.samples.api.DemoService.timeout=6000 -dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.timeout=7000 -``` - -- Multiple configuration items - -```properties -dubbo.registries.unit1.address=zookeeper://127.0.0.1:2181 -dubbo.registries.unit2.address=zookeeper://127.0.0.1:2182 - -dubbo.protocols.dubbo.name=dubbo -dubbo.protocols.dubbo.port=20880 -dubbo.protocols.hessian.name=hessian -dubbo.protocols.hessian.port=8089 -``` - -- Extended configuration - -```properties -dubbo.application.parameters.item1=value1 -dubbo.application.parameters.item2=value2 -dubbo.registry.parameters.item3=value3 -dubbo.reference.org.apache.dubbo.samples.api.DemoService.parameters.item4=value4 -``` - -## Several programming approaches of configuration - -Next, let's look at the changes corresponding to `ServiceConfig, ReferenceConfig and other programming interface collected configuration` when selecting different development methods. - -### Spring - -- XML - -Refer to [the sample](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-spring-xml) - -```xml - - - - - - - - - - - - ``` - - - -- Annotation - -Refer to [the sample](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-annotation) - -```java - // AnnotationService implementation - - @Service - public class AnnotationServiceImpl implements AnnotationService { - @Override - public String sayHello(String name) { - System.out.println("async provider received: " + name); - return "annotation: hello, " + name; - } - } - ``` - -```properties - ## dubbo.properties - - dubbo.application.name=annotation-provider - dubbo.registry.address=zookeeper://127.0.0.1:2181 - dubbo.protocol.name=dubbo - dubbo.protocol.port=20880 -``` - - - -- Spring Boot - -Refer to [the sample](https://github.com/apache/dubbo-spring-boot-project/tree/master/dubbo-spring-boot-samples) - -```properties - ## application.properties - - # Spring boot application - spring.application.name=dubbo-externalized-configuration-provider-sample - - # Base packages to scan Dubbo Component: @com.alibaba.dubbo.config.annotation.Service - dubbo.scan.base-packages=com.alibaba.boot.dubbo.demo.provider.service - - # Dubbo Application - ## The default value of dubbo.application.name is ${spring.application.name} - ## dubbo.application.name=${spring.application.name} - - # Dubbo Protocol - dubbo.protocol.name=dubbo - dubbo.protocol.port=12345 - - ## Dubbo Registry - dubbo.registry.address=N/A - - ## DemoService version - demo.service.version=1.0.0 -``` - - - -### API - -```java -public static void main(String[] args) throws IOException { - ServiceConfig service = new ServiceConfig<>(); - service.setApplication(new ApplicationConfig("first-dubbo-provider")); - service.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234")); - service.setInterface(GreetingsService.class); - service.setRef(new GreetingsServiceImpl()); - service.export(); - System.out.println("first-dubbo-provider is running."); - System.in.read(); -} -``` - -Refer to [the sample](https://github.com/apache/dubbo-samples/tree/master/1-basic/dubbo-samples-api) diff --git a/content/en/docs/v2.7/user/configuration/properties.md b/content/en/docs/v2.7/user/configuration/properties.md deleted file mode 100644 index db0030947f6a..000000000000 --- a/content/en/docs/v2.7/user/configuration/properties.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -type: docs -title: "Properties Configuration" -linkTitle: "Properties" -weight: 2 -description: "Configure Dubbo with properties" ---- - -If your application is simple enough, say, you do not need multi-registries or multi-protocols, and you want to share configuration among Spring containers. You can use `dubbo.properties` as default configuration. - -Dubbo will load dubbo.properties under the root of classpath automatically, you can also specify the path for loading this file by using JVM parameter: `-Ddubbo.properties.file=xxx.properties`. - - - -## Mapping Rules - -Combine the tag name and attribute name of the XML tag, use `.` to split. One property per line. - -* `dubbo.application.name=foo` equals to `` -* `dubbo.registry.address=10.20.153.10:9090` equals to ` ` - -If you have more than one tags in a XML configuration, you can use the `id` value to distinguish. If you don't specify a id, ti will applied to all tags. - -* `dubbo.protocol.rmi.port=1099` equals to ` ` -* `dubbo.registry.china.address=10.20.153.10:9090` equals to `` - -Here is a typical dubbo.properties demo configuration: - -```properties -dubbo.application.name=foo -dubbo.application.owner=bar -dubbo.registry.address=10.20.153.10:9090 -``` - -## Overrides and Priorities - -![properties-override](/imgs/user/dubbo-properties-override.jpg) - -Priorities from high to low: - -* JVM -D parameters, you can easily override configuration when deploying or starting applications, e.g., change the port of dubbo protocol. - -* XML, the properties present in XML will override that in dubbo.properties. - -* Properties, the default value, only works when it is not configured with XML or JVM. - - -1: If more than one dubbo.properties under classpath, say, two jars contains dubbo.properties separately, Dubbo will arbitarily choose one to to load, and log Error info. -2: If `id` not configured on `protocol`, will use `name` property as default diff --git a/content/en/docs/v2.7/user/configuration/xml.md b/content/en/docs/v2.7/user/configuration/xml.md deleted file mode 100644 index 27ffc92f70ab..000000000000 --- a/content/en/docs/v2.7/user/configuration/xml.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -type: docs -title: "XML Configuration" -linkTitle: "XML" -weight: 1 -description: "Configure Dubbo with XML" ---- - - -> About the XML configuration items, see:[XML References](/en/docs/v2.7/user/references/xml/). If you prefer use API directly instead of using Spring, see [API Configuration](../api). Want an example of how to use configuration, see [Quick Start](../../quick-start). - - -## provider.xml demo - -``` xml - - - - - - - - -``` - -All tags support custom parameters, so we can meet the special config requirements at different extension points, such as: - -```xml - - - -``` - -Or: - -``` xml - - - -``` - -## The relations between configuration tags - -![dubbo-config](/imgs/user/dubbo-config.jpg) - -tag | purpose | introduction -------------- | ------------- | ------------- -`` | Service Export | Used to export service, define service metadata, export service with multiple protocols, register service to multiple registries -`` | Service Reference | Used to create a remote proxy, subscribe to multiple registries -`` | Protocol Config | Configure the protocol for services on provider side, the consumer side follows. -`` | Application Config | Applies to both provider and consumer. -`` | Module Config | Optional. -`` | Registry Center | Registry info: address, protocol, etc. -`` | Monitor Center | Monitor info: address, address, etc. Optional. -`` | Default Config for Providers | Default Config for ServiceConfigs. Optional. -`` | Default Config for Consumers | Default Config for ReferenceConfigs. Optional. -`` | Method level Config | Method level Config for ServiceConfig and ReferenceConfig. -`` | Argument Config | Used to specify the method parameter configuration. - - -## Overrides and Priorities - -Take timeout as an example, here is the priorities, from high to low (retries, loadbalance, actives also applies the same rule): - -* method level,interface level,default/global level。 -* at the same level, consumer has higher priority than provider - -Configurations on the provider side are passed to the consumer side through registry in the form of URL. - -![dubbo-config-override](/imgs/user/dubbo-config-override.jpg) - -It is recommended that the provider set a timeout for every service, because the provider knows exactly how long a method needs to be executed. If a consumer cites multiple services at the same time, it doesn't need to care about the timeout settings of each service. - -Theoretically, almost all configuration items supported in ReferenceConfig can be configured with a default value using ConsumerConfig, ServiceConfig, ProviderConfig. - -1. Requires spring `3.2.16+`, see announcement for details:`xmlns:p="http://www.springframework.org/schema/p"` -2. The reference bean obeys lazy init by default, only if it is refered by other beans or other instance try to get its instance using `getBean()` method will the reference be initialized. If you need eager init, config this way: `` diff --git a/content/en/docs/v2.7/user/coveragence.md b/content/en/docs/v2.7/user/coveragence.md deleted file mode 100644 index 9bd0d66c5559..000000000000 --- a/content/en/docs/v2.7/user/coveragence.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -type: docs -title: "Test coverage report" -linkTitle: "Test coverage" -weight: 17 -description: "Dubbo test coverage report" ---- - -* v2.0 Codecov report , Statistics since 2017-12-29 - The test coverage is : [![codecov](https://codecov.io/gh/apache/dubbo/branch/master/graph/badge.svg)](https://codecov.io/gh/apache/dubbo) , we can get the report in https://codecov.io/gh/apache/dubbo -* v1.0 Based on version `2.0.12`,Statistics on 2012-02-03 - -![code-quality1.jpg](/imgs/user/code-quality1.jpg) - -![code-quality2.jpg](/imgs/user/code-quality2.jpg) - -![code-quality3.jpg](/imgs/user/code-quality3.jpg) - -![code-quality4.jpg](/imgs/user/code-quality4.jpg) - -![code-quality5.jpg](/imgs/user/code-quality5.jpg) - -![code-quality6.jpg](/imgs/user/code-quality6.jpg) - -![code-quality7.jpg](/imgs/user/code-quality7.jpg) - -![code-coverage.jpg](/imgs/user/code-coverage.jpg) - -![code-tendency.jpg](/imgs/user/code-tendency.jpg) - -![code-dependency.jpg](/imgs/user/code-dependency.jpg) diff --git a/content/en/docs/v2.7/user/dependencies.md b/content/en/docs/v2.7/user/dependencies.md deleted file mode 100644 index 367b61f7cd6f..000000000000 --- a/content/en/docs/v2.7/user/dependencies.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -type: docs -title: "Dependencies" -linkTitle: "Dependencies" -weight: 3 -description: "Dubbo dependencies" ---- - -## Necessary dependencies -JDK 1.6+ [^1] - -## Default dependencies -use `mvn dependency:tree > dep.log` command to analysis,Dubbo default depends on the following 3rd party libraries: - -```shell script -[INFO] +- com.alibaba:dubbo:jar:2.5.9-SNAPSHOT:compile -[INFO] | +- org.springframework:spring-context:jar:4.3.10.RELEASE:compile -[INFO] | +- org.javassist:javassist:jar:3.21.0-GA:compile -[INFO] | \- org.jboss.netty:netty:jar:3.2.5.Final:compile -``` - -All dependencies here are selected for the default configuration of the Dubbo, which are based on stability and performance considerations. - -* javassist.jar [^3]: if `` or ``,or ``, is not required. -* spring-context.jar [^4]: If you are using `ServiceConfig` and `ReferenceConfig` API calls, is not required. -* netty.jar [^5]: if `` or ``,Then change to mina.jar or grizzly.jar. If ``, is not required. - -## Optional dependencies -These dependencies needs to be added to project manually,when you need them. - -* netty-all 4.0.35.Final -* mina: 1.1.7 -* grizzly: 2.1.4 -* httpclient: 4.5.3 -* hessian_lite: 3.2.1-fixed -* fastjson: 1.2.31 -* zookeeper: 3.4.9 -* jedis: 2.9.0 -* xmemcached: 1.3.6 -* hessian: 4.0.38 -* jetty: 6.1.26 -* hibernate-validator: 5.4.1.Final -* zkclient: 0.2 -* curator: 2.12.0 -* cxf: 3.0.14 -* thrift: 0.8.0 -* servlet: 3.0 [^6] -* validation-api: 1.1.0.GA [^6] -* jcache: 1.0.0 [^6] -* javax.el: 3.0.1-b08 [^6] -* kryo: 4.0.1 -* kryo-serializers: 0.42 -* fst: 2.48-jdk-6 -* resteasy: 3.0.19.Final -* tomcat-embed-core: 8.0.11 -* slf4j: 1.7.25 -* log4j: 1.2.16 - -[^1]: In theory, Dubbo only depend on JDK, not depend on any 3rd party libs, you can finish logic by using JDK. -[^2]: Log output jar -[^3]: Bytecode generation -[^4]: Configuration parsing -[^5]: Network transmission -[^6]: JAVAEE diff --git a/content/en/docs/v2.7/user/examples/_index.md b/content/en/docs/v2.7/user/examples/_index.md deleted file mode 100644 index 16b81dceeb48..000000000000 --- a/content/en/docs/v2.7/user/examples/_index.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -type: docs -title: "Dubbo Examples" -linkTitle: "Examples" -weight: 6 -description: "Learn about Dubbo by examples" ---- - -{{% alert title="Tips" color="primary" %}} -To complete run, please see: [quick start](../quick-start), here just lists the configuration of various scenarios. - -The following examples are all based on Spring configuration: [XML configuration](../configuration/xml) for reference, if you do not want to use Spring, but want to be use it via the directly API, please see: [API configuration](../configuration/api) -{{% /alert %}} diff --git a/content/en/docs/v2.7/user/examples/accesslog.md b/content/en/docs/v2.7/user/examples/accesslog.md deleted file mode 100644 index db8c1bc859cf..000000000000 --- a/content/en/docs/v2.7/user/examples/accesslog.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -type: docs -title: "Access Log" -linkTitle: "Access Log" -weight: 39 -description: "Config dubbo access log" ---- - -If you want to log the access information for each provide service,you can turn on the `accesslog` switch,which like the access log of `Apache`. - -{{% alert title="Warning" color="warning" %}} -The size of the access log maybe too much,please check the disk capacity. Now I will show you how to config the access log. -{{% /alert %}} - - -## Logging by logging framework - -```xml - -``` -The above configuration will turn on `accesslog` switch for all provide services,and logging the access log with logging framework(log4j/logback/slf4j...).You can config the logging framework of `logger` and `appender` for logging the access log.The simplest way is config logger name with `dubbo.accesslog`. The Example: - -```xml - - ${loggingRoot}/accesslog/logging.log - ${loggingCharset} - true - - ${loggingRoot}/accesslog/%d{yyyyMMdd}/logging.log.%d{yyyyMMdd}%i.gz - - 15 - - 1024MB - - - - - - - - - -``` -The above is the demonstration of logback framework.Other logging framework is same too. It will logging the access log of all provide services into single file(`accesslog/logging.log`). And you can also config the access log of each provide service to logging separately,Only change `name` attribute of the `logger` tag,set the `name` attribute to `dubbo.accesslog.serviceInterfaceClassFullName`.The Example: - -```xml - - - -``` - -If you only want logging the access log of specified provide service,but not all services, it's supported too.The Example: -```xml - -``` - -## Logging by specified file path - -You can specify the file path with the `accesslog` attribute.The Example: - -```xml - -``` -OR -```xml - -``` diff --git a/content/en/docs/v2.7/user/examples/async-call.md b/content/en/docs/v2.7/user/examples/async-call.md deleted file mode 100644 index 9374b498507e..000000000000 --- a/content/en/docs/v2.7/user/examples/async-call.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -type: docs -title: "Asynchronous Call" -linkTitle: "Async Call" -weight: 21 -description: "Asynchronous call in dubbo" ---- - -As dubbo is based on a non-blocking NIO network layer, the client can start parallel call to multiple remote services without explicitly starting mulithreads, which costs relatively fewer resources. - -![/user-guide/images/future.jpg](/imgs/user/future.jpg) - - -You can config at `consumer.xml` for setup asynchronous call some remote service. - -```xml - - - - - - -``` -Configure the above configuration information,you can invoke the remote service in your code. - -```java -// the invoke will return null immediately -fooService.findFoo(fooId); -// get current invoke Future instance,when the remote service has return result,will notify this Future instance. -Future fooFuture = RpcContext.getContext().getFuture(); - -// the invoke will return null immediately -barService.findBar(barId); -// get current invoke Future instance,when the remote service has return result,will notify this Future instance. -Future barFuture = RpcContext.getContext().getFuture(); - -// now the request of findFoo and findBar was executed at same time,The client not need setup multithreading for parallel call, which is NIO-based non-blocking implementation of parallel calls - -// Current thread will be blocking,and wait findFoo has return. when remote service has return findFoo result,the current thread will be wake up. -Foo foo = fooFuture.get(); -// same to findFoo -Bar bar = barFuture.get(); - -// if findFoo expend five second for wait remote service return result,and findBar expend six second. Actually,only expend six second will get findFoo and findBar result,and proceed to the next step. -``` - - -You can also set whether to wait for the message to be sent: - -* `sent="true"` wait for the message to be send,if send failure,will throw exception. -* `sent="false"` do not wait for the message to be send,when the message will push into io queue,will return immediately. - -The Example: - -```xml - -``` -if you only want to asynchronous call,and don't care the return.you can config `return="false"`,To reduce the cost of creating and managing Future objects. - -```xml - -``` - - {{% alert title="Notice" color="primary" %}} - support on `2.0.6` or above. - {{% /alert %}} - diff --git a/content/en/docs/v2.7/user/examples/async-execute-on-provider.md b/content/en/docs/v2.7/user/examples/async-execute-on-provider.md deleted file mode 100644 index 02225f75a029..000000000000 --- a/content/en/docs/v2.7/user/examples/async-execute-on-provider.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -type: docs -title: "Asynchronous Execution" -linkTitle: "Async Execution" -weight: 21 -description: "Asynchronous execution on dubbo provider side" ---- - -The asynchronous execute on provider switches the blocked service from the internal thread pool of Dubbo to the service custom thread to avoid over-occupation of the Dubbo thread pool, which helps to avoid mutual influence between different services.Asynchronous-Execution is not conducive to saving resources or improving RPC responsiveness, because if business execution needs to be blocked, there is always a thread to be responsible for execution. - -{{% alert title="Notice" color="primary" %}} -Note: Asynchronous execute on provider and asynchronous execute on consumer are independent of each other. You can configure ends of any orthogonal combination. - -- Synchronous Execution On Consumer - Synchronous Execution On Provider -- Asynchronous Executio On Consumer - Synchronous Execution On Provider -- Synchronous Execution On Consumer - Asynchronous Executio On Provider -- Asynchronous Execution On Consumer - Asynchronous Executio On Provider -{{% /alert %}} - -## Interface that defines the CompletableFuture signature - -Service interface definition: - -```java -public interface AsyncService { - CompletableFuture sayHello(String name); -} -``` - -Service implementation: - -```java -public class AsyncServiceImpl implements AsyncService { - @Override - public CompletableFuture sayHello(String name) { - RpcContext savedContext = RpcContext.getContext(); - // It is recommended to provide a custom thread pool for supplyAsync to avoid using the JDK common thread pool. - return CompletableFuture.supplyAsync(() -> { - System.out.println(savedContext.getAttachment("consumer-key1")); - try { - Thread.sleep(5000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "async response from provider."; - }); - } -} -``` - -The business execution has been switched from the Dubbo thread to the business thread by `return CompletableFuture.supplyAsync()`, avoiding blocking of the Dubbo thread pool. - - - -## Use AsyncContext - -Dubbo provides an asynchronous interface `AsyncContext` similar to Serverlet 3.0. It can also implement asynchronous execution of the Provider without the CompletableFuture signature interface. - -Service interface definition: - -```java -public interface AsyncService { - String sayHello(String name); -} -``` - -Service export, exactly the same as ordinary service: - -```xml - - -``` - -Service implementation: - -```java -public class AsyncServiceImpl implements AsyncService { - public String sayHello(String name) { - final AsyncContext asyncContext = RpcContext.startAsync(); - new Thread(() -> { - // If you want to use context, you must do it at the very beginning - asyncContext.signalContextSwitch(); - try { - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - // Write to response - asyncContext.write("Hello " + name + ", response from provider."); - }).start(); - return null; - } -} -``` - - diff --git a/content/en/docs/v2.7/user/examples/attachment.md b/content/en/docs/v2.7/user/examples/attachment.md deleted file mode 100644 index 78ac8aa9b3c4..000000000000 --- a/content/en/docs/v2.7/user/examples/attachment.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -type: docs -title: "Implicit parameters" -linkTitle: "Attachment" -weight: 20 -description: "Pass implicit parameters between consumer and provider" ---- - -You can implicitly pass parameters between service consumers and providers via `setAttachment` and` getAttachment` on `RpcContext`. -![/user-guide/images/context.png](/imgs/user/context.png) - -## Set the implicit parameters at service consumer side - -Via `setAttachment` on `RpcContext` set key/value pair for implicitly pass parameters.When finished once remote invoke,will be clear,so multi-invoke must set multi-times. - - -```java -RpcContext.getContext().setAttachment("index", "1"); // implicitly pass parameters,behind the remote call will implicitly send these parameters to the server side, similar to the cookie, for the framework of integration, not recommended for regular business use -xxxService.xxx(); // remote call -// ... -``` - -## Fetch the implicit parameters at service provider side - -```java -public class XxxServiceImpl implements XxxService { - - public void xxx() { - // get parameters which passed by the consumer side,for the framework of integration, not recommended for regular business use - String index = RpcContext.getContext().getAttachment("index"); - } -} -``` diff --git a/content/en/docs/v2.7/user/examples/broadcast-resp-collect.md b/content/en/docs/v2.7/user/examples/broadcast-resp-collect.md deleted file mode 100644 index 3a2aff03b8ff..000000000000 --- a/content/en/docs/v2.7/user/examples/broadcast-resp-collect.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -type: docs -title: "Collect Broadcast Responses" -linkTitle: "Collect Broadcast Responses" -weight: 15 -description: "Dubbo broadcast2 broadcast mode collects port responses from all providers" ---- - -Applicable scenario: for any Dubbo consumer, broadcast calls multiple service providers. The consumer is able to collect responses from all of the providers. - -{{% alert title="Notice" color="primary" %}} -support on `2.7.12` or above. -{{% /alert %}} - -## Demo - -- consumer demo - -@Reference imports providers. Within the brackets, letting cluster = "broadcast2" represents doing one broadcast call that collects providers' responses. - -Broadcast calls all service providers one by one. Is able to return all service providers’ execution outcomes (success or exceptions) completely and stores -providers' responses in RpcContext. - -```java -@RestController -public class TestServiceConsumer { - @Reference(interfaceClass = DubboHealthService.class,cluster = "broadcast2") - private DubboHealthService dubboHealthService; - - @GetMapping("/health") - public String broadCast(){ - try{ - dubboHealthService.health(); - }catch (Exception e){ - Map m = RpcContext.getServerContext().getAttachments(); - return m.toString()+"|"+"fail"; - } - Map m = RpcContext.getServerContext().getAttachments(); - return m.toString()+"|"+"success"; - } -} -``` - -- provider demo - -```java -@Service -public class DubboHealthServiceImpl implements DubboHealthService { - @Override - public String health() { -// int i = 1/0; - return "i am provider2"; - } -} -``` - -- execution outcome - -All providers succeed: - -``` ->curl http://localhost:8081/health ->{broadcast.results=[{"ip":"10.220.47.253","port":20880,"data":"i am provider1"},{"ip":"10.220.47.253","port":20881,"data":"i am provider2"}]}|success% -``` - -Let one of the providers divide by zero: - -``` ->curl http://localhost:8081/health ->{broadcast.results=[{"ip":"10.220.47.253","port":20880,"data":"i am provider1"},{"ip":"10.220.47.253","port":20881,"exceptionMsg":"/ by zero"}]}|success% -``` diff --git a/content/en/docs/v2.7/user/examples/callback-parameter.md b/content/en/docs/v2.7/user/examples/callback-parameter.md deleted file mode 100644 index 8f59e818804e..000000000000 --- a/content/en/docs/v2.7/user/examples/callback-parameter.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -type: docs -title: "Callback parameter" -linkTitle: "Callback" -weight: 23 -description: "Callback parameter in dubbo" ---- - -The parameter callback is the same as calling a local callback or listener, just declare which parameter is a callback type in Spring's configuration file, and Dubbo will generate a reverse proxy based on the long connection so that client logic can be called from the server.Can ref to [Sample code in the dubbo project](https://github.com/dubbo/dubbo-samples/tree/master/2-advanced/dubbo-samples-callback). - -## Example of service interface - -### CallbackService.java - -```java -package com.callback; - -public interface CallbackService { - void addListener(String key, CallbackListener listener); -} -``` - -### CallbackListener.java - -```java -package com.callback; - -public interface CallbackListener { - void changed(String msg); -} -``` -## Example of service provider interface implementation - -```java -package com.callback.impl; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import com.callback.CallbackListener; -import com.callback.CallbackService; - -public class CallbackServiceImpl implements CallbackService { - - private final Map listeners = new ConcurrentHashMap(); - - public CallbackServiceImpl() { - Thread t = new Thread(new Runnable() { - public void run() { - while(true) { - try { - for(Map.Entry entry : listeners.entrySet()){ - try { - entry.getValue().changed(getChanged(entry.getKey())); - } catch (Throwable t) { - listeners.remove(entry.getKey()); - } - } - Thread.sleep(5000); // Timed trigger change notification - } catch (Throwable t) { // Defense fault tolerance - t.printStackTrace(); - } - } - } - }); - t.setDaemon(true); - t.start(); - } - - public void addListener(String key, CallbackListener listener) { - listeners.put(key, listener); - listener.changed(getChanged(key)); // send change notification - } - - private String getChanged(String key) { - return "Changed: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); - } -} -``` - -## Example of service provider configuration - -```xml - - - - - - - - -``` - -## Example of service consumer configuration - -```xml - -``` -## Example of service consumer call - -```java -ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:consumer.xml"); -context.start(); - -CallbackService callbackService = (CallbackService) context.getBean("callbackService"); - -callbackService.addListener("foo.bar", new CallbackListener(){ - public void changed(String msg) { - System.out.println("callback1:" + msg); - } -}); -``` - -{{% alert title="Notice" color="primary" %}} -support on `2.0.6` or above -{{% /alert %}} diff --git a/content/en/docs/v2.7/user/examples/concurrency-control.md b/content/en/docs/v2.7/user/examples/concurrency-control.md deleted file mode 100644 index 5ad4e11f8c0f..000000000000 --- a/content/en/docs/v2.7/user/examples/concurrency-control.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -type: docs -title: "Concurrency Control" -linkTitle: "Concurrency" -weight: 28 -description: "Concurrency control in dubbo" ---- - -## Example of configuration - -* Example 1: Control the concurrency of all method for a specified service interface at server-side - -Limit each method of `com.foo.BarService` to no more than 10 concurrent server-side executions (or take up thread pool threads): - -```xml - -``` - -* Example 2: Control the concurrency of specified method for a specified service interface at server-side - -Limit the `sayHello` method of `com.foo.BarService` to no more than 10 concurrent server-side executions(or take up thread pool threads): - -```xml - - - -``` - -* Example 3: Control the concurrency of all method for a specified service interface at client-side -Limit each method of `com.foo.BarService` to no more than 10 concurrent client-side executions (or take up thread pool threads): -```xml - -``` -OR -```xml - -``` - -* Example 4: Control the concurrency of specified method for a specified service interface at client-side -Limit the `sayHello` method of `com.foo.BarService` to no more than 10 concurrent client-side executions(or take up thread pool threads): -```xml - - - -``` - -OR - -```xml - - - -``` - -If `` and `` are both configured with `actives`,`` is preferred.Ref to:[Configuration coverage strategy](../config-rule). - -## Load Balance -You can config the `loadbalance` attribute with `leastactive` at server-side or client-side,then the framework will make consumer call the minimum number of concurrent one. - -```xml - -``` -OR -```xml - -``` diff --git a/content/en/docs/v2.7/user/examples/config-connections.md b/content/en/docs/v2.7/user/examples/config-connections.md deleted file mode 100644 index ed48cc1ecbec..000000000000 --- a/content/en/docs/v2.7/user/examples/config-connections.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -type: docs -title: "Config connections" -linkTitle: "Connection" -weight: 29 -description: "Config connections in dubbo" ---- - -## Control connections at server-side -Limit server-side accept to no more than 10 connections - -```xml - -``` -OR - -```xml - -``` - -## Control connections at client-side -Limit client-side creating connection to no more than 10 connections for interface `com.foo.BarService`. -```xml - -``` - -OR - -```xml - -``` - -{{% alert title="Warning" color="warning" %}} -If used default protocol(`dubbo` protocol), and the value of `connections` attribute is great than 0,then each service reference will has itself connection,else all service which belong to same remote server will share only one connection. In this framework,we called `private` connection or `share` connection. - -If `` and `` are both configured accepts/connections,`` is preferred, refer to [Configuration coverage strategy](../../configuration/xml/). - -Because connection is connect on Server, so configure on provider side. -{{% /alert %}} - - - diff --git a/content/en/docs/v2.7/user/examples/config-rule.md b/content/en/docs/v2.7/user/examples/config-rule.md deleted file mode 100644 index 4efa1b4f43df..000000000000 --- a/content/en/docs/v2.7/user/examples/config-rule.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -type: docs -title: "Configure rule" -linkTitle: "Configure rule" -weight: 34 -description: "Configure rule in dubbo" ---- - -Write then dynamic configuration to the registry center,This feature is usually done by the monitoring center or the center's page. - -```java -RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); -Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); -registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&timeout=1000")); -``` - -In the config override url: -* `override://` Indicates that the data is overwritten,support `override` and `absent`,can extends,**Required**. -* `0.0.0.0` Indicates that the configurations is valid for all IP addresses,If only want to overwritten specified ip data,you can replace that specified ip address.**Required**. -* `com.foo.BarService` Indicates that is valid for specified service,**Required**. -* `category=configurators` Indicates that the data is dynamic configuration,**Required**。 -* `dynamic=false` Indicates that the data is persistent,When the registered party withdraws,the data is still stored in the registry **Required**。 -* `enabled=true` override strategy is enable,can absent,if absent,then enable. -* `application=foo` Indicates that is valid for specified application,can absent,if absent,then valid for all application. -* `timeout=1000` Indicates that the value of the `timeout` parameter that satisfies the above conditions is overwritten by 1000,if want to override another parameters, add directly to the `override` URL parameter. - -Example: - -1. Disable service provider.(Usually used to temporarily kick off a provider machine, similar to the prohibition of consumer access, please use the routing rules) - - ``` - override://10.20.153.10/com.foo.BarService?category=configurators&dynamic=false&disabled=true - ``` - -2. Adjustment weight:(Usually used to capacity assessment,default is 100) - - ``` - override://10.20.153.10/com.foo.BarService?category=configurators&dynamic=false&weight=200 - ``` - -3. Adjustment load balance strategy.(default random) - - ``` - override://10.20.153.10/com.foo.BarService?category=configurators&dynamic=false&loadbalance=leastactive - ``` - -4. Service downgrade:(Usually used to temporarily mask an error of non-critical services) - - ``` - override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null - ``` - -{{% alert title="Notice" color="primary" %}} -supported on `2.2.0` or above. -{{% /alert %}} - diff --git a/content/en/docs/v2.7/user/examples/context.md b/content/en/docs/v2.7/user/examples/context.md deleted file mode 100644 index 01207f6bd12e..000000000000 --- a/content/en/docs/v2.7/user/examples/context.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -type: docs -title: "Context" -linkTitle: "Context" -weight: 19 -description: "Dubbo context" ---- - -All environment information of during the current call will put into the context,and all configuration information will convert the parameters of `URL` instance,Ref to the column of **URL parameters** at the [schema configuration reference book](/en/docs/v2.7/user/references/xml) - - -`RpcContext` is a temporary status recorder of `ThreadLocal`,when accept `RPC` request or send `RPC` request,The `RpcContext` will be changed.Such as: `A` call `B` and `B` call `C`. On `B` machine,before `B` call `C`,the `RpcContext` will record the information of `A` call `B`.After `B` call `C`,the `RpcContext` record the information of `B` call `C`. - -## At service consumer - -```java -// remote invoke -xxxService.xxx(); -// if return true,then the current side is consumer. -boolean isConsumerSide = RpcContext.getContext().isConsumerSide(); -// get the provider ip address of the last invoke. -String serverIP = RpcContext.getContext().getRemoteHost(); -// because all configuration information has convert the URL's parameters,so at this place can get the application parameter value. -String application = RpcContext.getContext().getUrl().getParameter("application"); -// Note:every rpc invoke,then context will be changed. -yyyService.yyy(); -``` - -## At service provider - -```java -public class XxxServiceImpl implements XxxService { - - public void xxx() { - // if return true,then the current side is provider. - boolean isProviderSide = RpcContext.getContext().isProviderSide(); - // get the invoker ip - String clientIP = RpcContext.getContext().getRemoteHost(); - // because all configuration information has convert the URL's parameters,so at this place can get the application parameter value. - String application = RpcContext.getContext().getUrl().getParameter("application"); - // Note:every rpc invoke,then context will be changed. - yyyService.yyy();; - } -} -``` diff --git a/content/en/docs/v2.7/user/examples/delay-publish.md b/content/en/docs/v2.7/user/examples/delay-publish.md deleted file mode 100644 index f730324f991e..000000000000 --- a/content/en/docs/v2.7/user/examples/delay-publish.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -type: docs -title: "Delay Publish" -linkTitle: "Delay Publish" -weight: 27 -description: "Delay publish dubbo service" ---- - -If your services need time to warm up, such as: initialization cache or another reference resources has to be ready. You can use the delay feature to delay publishing services. We fine-tuned the service delay exposure logic in Dubbo 2.6.5, delaying the countdown of services that require delayed exposure until Spring initialization is complete. You won't be aware of this change while using Dubbo, so please be assured that use. - - -{{% alert title="Notice" color="primary" %}} -Prior to Dubbo-2.6.5 -{{% /alert %}} - -### Delay five second publish - -```xml - -``` - -### Delay until Spring initialization is complete before exposing the service -```xml - -``` - -{{% alert title="Notice" color="primary" %}} -Dubbo-2.6.5 and later -{{% /alert %}} - -All services will be exposed after Spring initialization is complete, and you don't need to configure delay if you don't need to delay exposing the service. - -### Delay five second publish - -```xml - -``` - -## The initialization deadlock problem of Spring 2.x - -### Trigger condition - -The service has already published when `Spring` parse the `` element,but the `Spring` is still initializing other beans.If there is a request coming in, and the service implementation class has a call to `applicationContext.getBean ()` usage. - -1. Request thread applicationContext.getBean() call, the first synchronization `singletonObjects` determine whether the existence of the bean, the synchronization does not exist to initialize the `beanDefinitionMap`, and re-synchronize `singletonObjects` write Bean instance cache. - - ![deadlock](/imgs/user/lock-get-bean.jpg) - -2. But the `Spring` initialization thread,because need to determine the `Bean` is exist,Directly synchronize beanDefinitionMap to initialize, and synchronize singletonObjects write Bean instance cache. - - ![/user-guide/images/lock-init-context.jpg](/imgs/user/lock-init-context.jpg) - -This will cause the getBean thread to lock the singletonObjects first, then lock the beanDefinitionMap, and lock the singletonObjects again.The Spring initialization thread, the first lock beanDefinitionMap, then lock singletonObjects. Reverse lock thread deadlock, can not provide services, can not start. - -### Avoid ways - -1. It is highly recommended not to call applicationContext.getBean() in the service implementation class, all using Spring's beans using IoC injection. -2. If you really want to tune getBean(), you can put the configuration of Dubbo Spring final loading. -3. If you do not want to rely on the configuration order, you can use `` to make Dubbo expose the service after the Spring container has been initialized. -4. If you use getBean() extensively, the equivalent of degenerating Spring to factory mode is to isolate Dubbo's service from a separate Spring container. - -[^1]: Base on the `ContextRefreshedEvent` event of the Spring to trigger publish service. diff --git a/content/en/docs/v2.7/user/examples/distributed-transaction.md b/content/en/docs/v2.7/user/examples/distributed-transaction.md deleted file mode 100644 index 35c19d1e2a97..000000000000 --- a/content/en/docs/v2.7/user/examples/distributed-transaction.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "Distributed transaction" -linkTitle: "Transaction" -weight: 42 -description: "Distributed transaction support in dubbo" ---- - -Distributed transactions are based on the JTA / XA specification(this feature has not yet been implemented) - -Two-phase commit: - -![/user-guide/images/jta-xa.jpg](/imgs/user/jta-xa.jpg) - - -In Dubbo, [Seate](/en/blog/2019/01/17/how-to-use-seata-to-ensure-consistency-between-dubbo-microservices/) can be used to support distributed transactions. \ No newline at end of file diff --git a/content/en/docs/v2.7/user/examples/dump.md b/content/en/docs/v2.7/user/examples/dump.md deleted file mode 100644 index 03b66fed2435..000000000000 --- a/content/en/docs/v2.7/user/examples/dump.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -type: docs -title: "Thread Dump" -linkTitle: "Thread Dump" -weight: 43 -description: "Automatical thread dump in dubbo" ---- - -When the business thread pool is full, we need to know what resources/conditions are waiting for the thread , to find the bottleneck point of the system or abnormal point. `dubbo` automatically export thread stack through `Jstack` to keep the scene for easy to troubleshoot the problem. - -Default policy: - -* Export file path,user.home directory -* Export interval,The shortest interval allows you to export every 10 minutes - -Specified export file path: -```properties -# dubbo.properties -dubbo.application.dump.directory=/tmp -``` - -```xml - - - -``` diff --git a/content/en/docs/v2.7/user/examples/echo-service.md b/content/en/docs/v2.7/user/examples/echo-service.md deleted file mode 100644 index f4774aa7741a..000000000000 --- a/content/en/docs/v2.7/user/examples/echo-service.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -type: docs -title: "Echo Testing Service" -linkTitle: "Echo Service" -weight: 18 -description: "Echo testing service in dubbo" ---- - -Echo testing is used for check the service is available,Echo testing is performed according to the normal request flow and is able to test whether the entire call is unobstructed and can be used for monitoring. - -All the services will be automatically implemented `EchoService` interface,just cast any service reference to `EchoService` to use it. - -Spring configuration: - -```xml - -``` - -The java code: - -```java -// reference the remote service -MemberService memberService = ctx.getBean("memberService"); -// case the service reference to EchoService -EchoService echoService = (EchoService) memberService; - -// Echo test usability -String status = echoService.$echo("OK"); - -assert(status.equals("OK")); -``` diff --git a/content/en/docs/v2.7/user/examples/events-notify.md b/content/en/docs/v2.7/user/examples/events-notify.md deleted file mode 100644 index 1f1e5932ee8b..000000000000 --- a/content/en/docs/v2.7/user/examples/events-notify.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -type: docs -title: "Event Notification" -linkTitle: "Event Notification" -weight: 24 -description: "Event notification in dubbo" ---- - -Before calling, after calling, when an exception occurs,will trigger `oninvoke`, `onreturn`, `onthrow` events.You can configure which method to notify when an event occurs. - -## Service Interface - -```java -interface IDemoService { - public Person get(int id); -} -``` - -## Service provider implement the service. - -```java -class NormalDemoService implements IDemoService { - public Person get(int id) { - return new Person(id, "charles`son", 4); - } -} -``` - -## Service provider configure the service which it provided. - -```xml - - - - -``` - -## Declare the Callback interface at service consumer-side. - -```java -interface Notify { - public void onreturn(Person msg, Integer id); - public void onthrow(Throwable ex, Integer id); -} -``` - -## Implement the Callback at service consumer-side. - -```java -class NotifyImpl implements Notify { - public Map ret = new HashMap(); - public Map errors = new HashMap(); - - public void onreturn(Person msg, Integer id) { - System.out.println("onreturn:" + msg); - ret.put(id, msg); - } - - public void onthrow(Throwable ex, Integer id) { - errors.put(id, ex); - } -} -``` - -## Configure the Callback at service consumer-side. - -```xml - - - - -``` -`callback` and` async` functions are orthogonally decomposed. `async = true` means that the result is returned immediately.` onreturn` means that a callback is required. - -There are several situations with the tow attributes[^2]. - -* Asynchronous callback mode:`async=true onreturn="xxx"` -* Synchronous callback mode:`async=false onreturn="xxx"` -* Asynchronous no callback:`async=true` -* Synchronous no callback:`async=true` - -## Testing code - -```java -IDemoService demoService = (IDemoService) context.getBean("demoService"); -NotifyImpl notify = (NotifyImpl) context.getBean("demoCallback"); -int requestId = 2; -Person ret = demoService.get(requestId); -Assert.assertEquals(null, ret); -//for Test:Just used to illustrate the normal callback callback, the specific business decisions. -for (int i = 0; i < 10; i++) { - if (!notify.ret.containsKey(requestId)) { - Thread.sleep(200); - } else { - break; - } -} -Assert.assertEquals(requestId, notify.ret.get(requestId).getId()); -``` - -{{% alert title="Notice" color="warning" %}} -since `2.0.7+` version, the default value is `async=false`. -{{% /alert %}} \ No newline at end of file diff --git a/content/en/docs/v2.7/user/examples/explicit-target.md b/content/en/docs/v2.7/user/examples/explicit-target.md deleted file mode 100644 index ecf52335d363..000000000000 --- a/content/en/docs/v2.7/user/examples/explicit-target.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -type: docs -title: "Explicit Target" -linkTitle: "Explicit Target" -weight: 5 -description: "Specify explicit target in dubbo" ---- - -In the development and testing environment, it is often necessary to bypass the registry and test only designated service providers. In this case, point-to-point direct connection may be required, and the service provider will ignore the list of provider registration providers. The interface A configure Point-to-point, does not affect the B interface to obtain a list from the registry. - -![/user-guide/images/dubbo-directly.jpg](/imgs/user/dubbo-directly.jpg) - -## Configure with XML - -If it is online demand needs the point-to-point feature,You can configure the specified provider url at ``.it will bypass the registry, multiple addresses separated by semicolons, the following configuration: - -```xml - -``` - -## Configure with the `-D` argument - -Add the -D parameter mapping service address to the JVM startup parameters: - -```sh -java -Dcom.alibaba.xxx.XxxService=dubbo://localhost:20890 -``` - -## Configure with the `.properties` file - -If you have more services, you can also use file mapping to specify the mapping file path with `-Ddubbo.resolve.file`. This configuration takes precedence over the configuration in` `, for example: - -```sh -java -Ddubbo.resolve.file=xxx.properties -``` - -Then add the configuration in the mapping file `xxx.properties`, where key is the service name and value is the service provider URL: - -```properties -com.alibaba.xxx.XxxService=dubbo://localhost:20890 -``` - - -{{% alert title="Notice" color="primary" %}} -To avoid complicating the online environment, do not use this feature online and should only be used during the testing phase -{{% /alert %}} \ No newline at end of file diff --git a/content/en/docs/v2.7/user/examples/fault-tolerent-strategy.md b/content/en/docs/v2.7/user/examples/fault-tolerent-strategy.md deleted file mode 100644 index 5d10b45c49bb..000000000000 --- a/content/en/docs/v2.7/user/examples/fault-tolerent-strategy.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -type: docs -title: "Fault Tolerance Strategy" -linkTitle: "Fault Tolerance" -weight: 2 -description: "Fault tolerance strategy in dubbo" ---- - -Dubbo offers a variety of fault-tolerant scenarios when a cluster call fails, with a default failover retry. - -![cluster](/imgs/user/cluster.jpg) - -The relationship between nodes: - -* This `Invoker` is the callable Service's abstract of the` Provider`, and the `Invoker` packaging the` Provider`'s address and `Service`'s interface. -* The `Directory` represent multiple `Invoker`,You can think of it as `List`,But unlike `List`,its value can be dynamically changing.such as registry push changes -* The `Cluster` disguises multiple` Invoker` in `Directory` as a` Invoker`,The upper transparent, masquerade process contains fault-tolerant logic, call failed, try another -* The `Router` is responsible for selecting subsets according to routing rules from multiple `Invoker`s, such as read-write separation, application isolation, etc. -* `LoadBalance` is responsible for selecting a specific one from multiple` Invoker` for this call. The selection process includes the load balancing algorithm. If the call fails, it needs to be re-selected - -## Cluster fault-tolerant mode - -You can also customize the cluster fault tolerance strategy, see [Cluster extension](../../../dev/impls/cluster) for more details. - -## Failover Cluster - -Failure automatically switch, when there is failure, retry the other server (default). Usually used for read operations, but retries can result in longer delays. The times of retries can be set via `retries =2` (excluding the first time). - -The times of retries is configured as follows: - -```xml - -``` - -OR - -```xml - -``` - -OR - -```xml - - - -``` - -### Failfast Cluster - -Fast failure, only made a call, failure immediately error. Usually used for non-idempotent write operations, such as adding records - -### Failsafe Cluster - -Failure of security, anomalies, directly ignored. Usually used to write audit logs and other operations. - -### Failback Cluster - -Failure automatically restored, failed to record the background request, regular retransmission. Usually used for message notification operations. - -### Forking Cluster - -Multiple servers are invoked in parallel, returning as soon as one succeeds. Usually used for real-time demanding read operations, but need to waste more service resources. The maximum number of parallelism can be set with `forks=2`. - -### Broadcast Cluster - -Calling all providers broadcast, one by one call, any error is reported (`2.1.0+`). It is usually used to notify all providers to update local resource information such as caches or logs. - -Now in the broadcast call, the proportion of node call failures can be configured through broadcast.fail.percent. When this proportion is reached, BroadcastClusterInvoker will no longer call other nodes and directly throw an exception. The value of broadcast.fail.percent is in the range of 0-100. By default, an exception will be thrown when all calls fail. -broadcast.fail.percent only controls whether to continue to call other nodes after failure, and does not change the result (any one will report an error). broadcast.fail.percent parameters -Effective in dubbo2.7.10 and above. - -Broadcast Cluster configuration broadcast.fail.percent. - -broadcast.fail.percent=20 means that when 20% of the nodes fail to call, an exception will be thrown and no other nodes will be called. - -```text -@reference(cluster = "broadcast", parameters = {"broadcast.fail.percent", "20"}) -``` - -## Cluster mode configuration - -Follow the example below to configure cluster mode on service providers and consumers - -```xml - -``` - -OR - -```xml - -``` diff --git a/content/en/docs/v2.7/user/examples/generic-invoke-with-json.md b/content/en/docs/v2.7/user/examples/generic-invoke-with-json.md deleted file mode 100644 index 11ca6650dca3..000000000000 --- a/content/en/docs/v2.7/user/examples/generic-invoke-with-json.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -type: docs -title: "json generic invoke" -linkTitle: "json generic invoke" -weight: 15 -description: "support generic invoke of json string parameters" ---- - -{{% alert title="Notice" color="primary" %}} -support on `2.7.12` or above. -{{% /alert %}} - -A new method is provided for Dubbo generic invoke: directly passing on String to complete an invoke. In other words, users can directly pass on -parameter object's json String to complete a generic invoke. - -## Using generic invoke through API method - -For the following providers: - -```java -public User setUser(User user) { - return user; - } -``` - -```java -@Data -public class User { - String name; - int age; -} -``` - -do one generic invoke: - -```java -public class GenericInvoke { - public static void main(String[] args) { - ApplicationConfig app = new ApplicationConfig("ConsumerTest"); - RegistryConfig reg = new RegistryConfig("nacos://localhost:8848"); - DubboBootstrap bootstrap = DubboBootstrap.getInstance(); - bootstrap.application(app); - bootstrap.registry(reg); - bootstrap.start(); - try { - // config remote service - ReferenceConfig reference = new ReferenceConfig<>(); - // name of the weakly typed interface - reference.setInterface("com.xxx.api.service.TestService"); - reference.setGroup("dev"); - reference.setVersion("1.0"); - reference.setRetries(0); - // set generic=gson in RpcContext - RpcContext.getContext().setAttachment("generic","gson"); - // declare the interface to be generic - reference.setGeneric(true); - reference.setCheck(false); - GenericService genericService = ReferenceConfigCache.getCache().get(reference); - // pass on parameter object's json String for an invoke - Object res = genericService.$invoke("setUser", new String[]{"com.xxx.api.service.User"}, new Object[]{"{'name':'Tom','age':24}"}); - System.out.println("result[setUser]:"+res); // response output:result[setUser]:{name=Tom, class=com.xxx.api.service.User, age=24} - } catch (Throwable ex) { - ex.printStackTrace(); - } - } -} -``` diff --git a/content/en/docs/v2.7/user/examples/generic-reference.md b/content/en/docs/v2.7/user/examples/generic-reference.md deleted file mode 100644 index e71ffa9835a5..000000000000 --- a/content/en/docs/v2.7/user/examples/generic-reference.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -type: docs -title: "Generic Reference" -linkTitle: "Generic Reference" -weight: 16 -description: "Generic reference in dubbo" ---- - -Generic invocation is mainly used when the client does not have API interface or model class, all POJOs in parameters and return values are represented by `Map`.Commonly used for framework integration such as: implementing a common service testing framework, all service implementations can be invoked via `GenericService`. - -## Use generic invocation via Spring - -Declared in the Spring configuration file `generic =" true "`: - -```xml - -``` - -In Java code, get `barService` and start generic invocation: - -```java -GenericService barService = (GenericService) applicationContext.getBean("barService"); -Object result = barService.$invoke("sayHello", new String[] { "java.lang.String" }, new Object[] { "World" }); -``` - -## Use generic invocation via API - -```java -import org.apache.dubbo.rpc.service.GenericService; -... - -// reference remote service -// The instance is very heavy, which encapsulates all the registration center and service provider connection, please cache -ReferenceConfig reference = new ReferenceConfig(); -// weak type service interface name -reference.setInterface("com.xxx.XxxService"); -reference.setVersion("1.0.0"); -// declared as generic service -reference.setGeneric(true); - -// service stub type is also the org.apache.dubbo.rpc.service.GenericService -GenericService genericService = reference.get(); - -// basic types and Date, List, Map, etc. do not need conversion, direct use them -Object result = genericService.$invoke("sayHello", new String[] {"java.lang.String"}, new Object[] {"world"}); - -// map POJO parameters, if the return value is POJO will automatically turn into map -Map person = new HashMap(); -person.put("name", "xxx"); -person.put("password", "yyy"); -// if the return value is POJO will automatically turn into map -Object result = genericService.$invoke("findPerson", new String[] -{"com.xxx.Person"}, new Object[]{person}); - -... -``` - -## Further explanation of generalized types - -Consider POJO like this: - -```java -package com.xxx; - -public class PersonImpl implements Person { - private String name; - private String password; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } -} -``` - -The POJO data: - -```java -Person person = new PersonImpl(); -person.setName("xxx"); -person.setPassword("yyy"); -``` - -Data represented by `Map`: - -```java -Map map = new HashMap(); -// Note: If the parameter type is an interface, or List lost the generic class, you can specify the type of the class attribute -map.put("class", "com.xxx.PersonImpl"); -map.put("name", "xxx"); -map.put("password", "yyy"); -``` diff --git a/content/en/docs/v2.7/user/examples/generic-service.md b/content/en/docs/v2.7/user/examples/generic-service.md deleted file mode 100644 index 5a610035d240..000000000000 --- a/content/en/docs/v2.7/user/examples/generic-service.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -type: docs -title: "Generic Service" -linkTitle: "Generic Service" -weight: 17 -description: "Generic service in dubbo" ---- - -The implementation of the generic interface is mainly used when there is no API interface and model class on the server side. All POJOs in the parameters and return values are represented by the Map and are usually used for framework integration. For example, to implement a universal remote service Mock framework, handle all service requests by implementing the GenericService interface. - -In Java code, implement `GenericService` interface: - -```java -package com.foo; -public class MyGenericService implements GenericService { - - public Object $invoke(String methodName, String[] parameterTypes, Object[] args) throws GenericException { - if ("sayHello".equals(methodName)) { - return "Welcome " + args[0]; - } - } -} -``` - -## Export generic implements via Spring - -Declared in the Spring configuration file: - -```xml - - -``` - -## Export generic implements via API - -```java -... -// use org.apache.dubbo.rpc.service.GenericService can replace all implements -GenericService xxxService = new XxxGenericService(); - -// The instance is very heavy, which encapsulates all the registration center and service provider connection, please cache -ServiceConfig service = new ServiceConfig(); -// weak type service interface name -service.setInterface("com.xxx.XxxService"); -service.setVersion("1.0.0"); -// point to a generic serivce instance -service.setRef(xxxService); - -// export service to registration center -service.export(); -``` diff --git a/content/en/docs/v2.7/user/examples/graceful-shutdown.md b/content/en/docs/v2.7/user/examples/graceful-shutdown.md deleted file mode 100644 index 29579e22a7a3..000000000000 --- a/content/en/docs/v2.7/user/examples/graceful-shutdown.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -type: docs -title: "Graceful Shutdown" -linkTitle: "Graceful Shutdown" -weight: 36 -description: "Graceful shutdown in dubbo" ---- - -Dubbo is graceful shutdown through the `ShutdownHook` of the JDK, so graceful shutdowns are not performed if you force shutdown the command, such as `kill -9 PID`, and will only be executed if `kill PID` is passed. - -## Howto - -### Service provider - -* When stop, first marked as not receiving new requests, the new request directly return the error, so that the client retries other machines. -* Then check thread pool thread is running, if any, waiting for all threads to complete execution, unless overtime, then forced to close. - -### Service consumer - -* When stop, No longer initiate a new request, all request on the client that got an error. -* Then check the request has not returned the response, waiting for the response to return, unless overtime, then forced to close. - -## Configuration shutdown wait time - -Set graceful shutdown timeout, the default timeout is 10 seconds, if the overtime is forced to close. - -```properties -# dubbo.properties -dubbo.service.shutdown.wait=15000 -``` - -If ShutdownHook does not take effect, you can call it yourself, **in tomcat, it is recommended by extending the ContextListener and call the following code for graceful shutdown**: - -```java -DubboShutdownHook.destroyAll(); -``` diff --git a/content/en/docs/v2.7/user/examples/group-merger.md b/content/en/docs/v2.7/user/examples/group-merger.md deleted file mode 100644 index c0e49b84de00..000000000000 --- a/content/en/docs/v2.7/user/examples/group-merger.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -type: docs -title: "Group Merger" -linkTitle: "Group Merger" -weight: 13 -description: "Group merger in dubbo" ---- - -According to the group to invoke server and return the merge result [^1], such as the menu service, the same interface, but there are a variety of implementations, using group distinction, consumers call each group and get the results, the merger can merge the resules, so that you can achieve aggregation Menu Item. - -Related code can refer to [dubbo project example](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-merge) - -## Configuration - -Merge all groups - -```xml - -``` - -Merge the specified group - -```xml - -``` - -The specified method to merge the results, other unspecified methods, will only call one group - -```xml - - - -``` - -The Specified a method does not merge the results, others merge the results - -```xml - - - -``` - -Specify the merge strategy, the default according to the type of return value automatically match, if the same type has two mergers, you need to specify the name of the merger[^2] - -```xml - - - -``` - -Specify the merge method, it will call the return type's method for merging, the merging method parameter type must be the return type - -```xml - - - -``` - -[^1]: since `2.1.0` began to support -[^2]: See also:[merger extensions](../group-merger) diff --git a/content/en/docs/v2.7/user/examples/hostname-binding.md b/content/en/docs/v2.7/user/examples/hostname-binding.md deleted file mode 100644 index 11926491ab8e..000000000000 --- a/content/en/docs/v2.7/user/examples/hostname-binding.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -type: docs -title: "Hostname Binding" -linkTitle: "Hostname Binding" -weight: 37 -description: "Hostname binding in dubbo" ---- - - -## Lookup order - -Default host IP lookup order: - -* Get local address via `LocalHost.getLocalHost()`. -* If it is `127. *` loopback address, then scan the network for host IP - -## Host configuration - -Registered address if it is not correct, such as the need to register public address, you can do this: - -1. edit `/etc/hosts` : add machinename and public ip, such as: - - ``` - test1 205.182.23.201 - ``` - -2. in `dubbo.xml` add host address configuration: - - ```xml - - ``` - -3. or config that in `dubbo.properties`: - - ```properties - dubbo.protocol.host=205.182.23.201 - ``` - -## Port configuration - -The default port and protocol: - -Protocol | Port -------------- | ------------- -dubbo | 20880 -rmi | 1099 -http | 80 -hessian | 80 -webservice | 80 -memcached | 11211 -redis | 6379 - -You can configure the port as follows: - -1. in `dubbo.xml` add port configuration: - - ```xml - - ``` - -2. or config that in `dubbo.properties`: - - ```properties - dubbo.protocol.dubbo.port=20880 - ``` diff --git a/content/en/docs/v2.7/user/examples/invoke-with-specified-ip.md b/content/en/docs/v2.7/user/examples/invoke-with-specified-ip.md deleted file mode 100644 index cee10d332797..000000000000 --- a/content/en/docs/v2.7/user/examples/invoke-with-specified-ip.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -type: docs -title: "Invoke provider with specified IP port" -linkTitle: "Specified IP port" -weight: 15 -description: "For multiple instances registered in the provider cluster, specify Ip:Port to invoke." ---- - -When multiple providers are registered at the register center, dynamically specifying one of the instances’ IP through RpcContext is enabled. Port does Dubbo invoke. - -{{% alert title="Notice" color="primary" %}} -support on `2.7.12` or above. -{{% /alert %}} - -## Demo - -- provider demo - -Assume two registered providers at the register center are provided, which are 10.220.47.253:20880;10.220.47.253:20881; respectively. - -```java -// 10.220.47.253:20880 -@Service(interfaceClass = TestService.class) -public class TestServiceImpl implements TestService { - @Override - public String sayHello(String name) { - return "Hello "+name+" i am provider1"; - } -} -// 10.220.47.253:20881 -@Service(interfaceClass = TestService.class) -public class TestServiceImpl implements TestService { - @Override - public String sayHello(String name) { - return "Hello "+name+" i am provider2"; - } -} -``` - -- consumer demo - -@DubboReference introduces provider. Setting parameters = {"router","address"} specifies routing method. - -For the instance that is going to be invoked, specify its IP, construct Address object with Port and set RpcContext key as "address". Value is that object. - -```java -// require dependent class -import org.apache.dubbo.rpc.RpcContext; -import org.apache.dubbo.rpc.cluster.router.address.Address; - -@RestController -public class TestServiceConsumer { - @DubboReference(interfaceClass = TestService.class,group = "dev",parameters = {"router","address"}) - private TestService testService; - - @GetMapping("/invokeByIpPortSpecified") - public String invokeByIp(){ - try { - // create Address instance based on provider's ip port - Address address = new Address("10.220.47.253", 20880); - RpcContext.getContext().setObjectAttachment("address", address); - return testService.sayHello("Tom"); - }catch (Throwable ex){ - return ex.getMessage(); - } - } - -} -``` - -- execution outcome - -After running the code multiple times we can see that the same "Hello Tom i am provider1" is returned. In other words, we always route to the instance where port 20880 is located. - -``` ->curl http://localhost:8081/invokeByIpPortSpecified ->Hello Tom i am provider1 -``` diff --git a/content/en/docs/v2.7/user/examples/lazy-connect.md b/content/en/docs/v2.7/user/examples/lazy-connect.md deleted file mode 100644 index 96332e66570a..000000000000 --- a/content/en/docs/v2.7/user/examples/lazy-connect.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "Lazy Connect" -linkTitle: "Lazy Connect" -weight: 30 -description: "Lazy connect in dubbo" ---- - -Lazy connect can reduce the number of keep-alive connections. When a call is initiated, create a keep-alive connection.[^1] - -```xml - -``` - -[^1]: Note: This configuration takes effect only for dubbo protocols that use keep-alive connections. diff --git a/content/en/docs/v2.7/user/examples/loadbalance.md b/content/en/docs/v2.7/user/examples/loadbalance.md deleted file mode 100644 index f3ae50b402ea..000000000000 --- a/content/en/docs/v2.7/user/examples/loadbalance.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -type: docs -title: "Load Balance" -linkTitle: "Load Balance" -weight: 3 -description: "Load Balance in dubbo" ---- - -Dubbo offers a number of balancing strategies for cluster load balancing, which defaults to `random`. - -You can extend the load balancing strategy by yourself, see: [LoadBalance extension](../../../dev/impls/load-balance) - -## LoadBalance strategy - -### Random LoadBalance - -* **Ramdom**, set random probabilities by weight. -* The probability of collisions on one section is high, but the larger the amount of calls, the more uniform the distribution. And when use weight based on probability the distribution turns out to be uniform, which also helps to dynamically adjust the provider weights. - -### RoundRobin LoadBalance - -* **RoundRobin**, use the weight's common advisor to determine round robin ratio. -* Traffic flow to slower providers may cause requests piled up, e.g., if there's a provider processing requests in a very slow speed, but it's still alive, which means it can receive request as normal. According to RoundRobin policy, consumers will continuously send requests to this provider on predetermined pace, have no aware of the provider's bad status. Finally, we will get many requests stuck on this unhealthy provider. - -### LeastActive LoadBalance - -* **LeastActive**, a random mechanism based on actives, `actives` means the num of requests a consumer have sent but not return yet。 -* Slower providers will receive fewer requests, cause slower provider have higher `actives`. - -### ConsistentHash LoadBalance - -* **ConsistentHash**, the same parameters of the request is always sent to the same provider. -* When a provider fails, the original request to the provider, based on the virtual node algorithm, averages to other providers, does not cause drastic changes. -* Algorithm reference:http://en.wikipedia.org/wiki/Consistent_hashing -* By default only the first parameter Hash, if you want to modify, please configure `` -* By default 160 virtual nodes, if you want to modify, please configure `` - - -See the algorithm at http://en.wikipedia.org/wiki/Consistent_hashing - - -## Configuration - -### Server service level - -```xml - -``` - -### Client service level - -```xml - -``` - -### Server method level - -```xml - - - -``` - -### Client method level - -```xml - - - -``` diff --git a/content/en/docs/v2.7/user/examples/local-call.md b/content/en/docs/v2.7/user/examples/local-call.md deleted file mode 100644 index 9c054e9523a5..000000000000 --- a/content/en/docs/v2.7/user/examples/local-call.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -type: docs -title: "Local Call" -linkTitle: "Local Call" -weight: 22 -description: "Local call in dubbo" ---- - -The local call uses the `injvm` protocol, a pseudo-protocol that does not turn on the port, does not initiate remote calls, is directly associated within the JVM, but executes the Dubbo Filter chain. - -## Configuration - -Configure `injvm` protocol - -```xml - -``` - -Configure default provider - -```xml - -``` - -Configure default service - -```xml - -``` - -Use injvm first - -```xml - - -``` - -or - -```xml - - -``` - -Note: Dubbo services are exposed locally from `2.2.0` by default. It can be referenced locally without any configuration. If you don't want the service to be exposed remotely, you only need to set the protocol to injvm in the provider. - -## Automatically exposed, local service references - -`2.2.0` or later, each service is exposed locally by default. When referring to the service, the local service is referenced by default. If you want to reference a remote service, you can use the following configuration to force a reference to a remote service. - - -```xml - -``` diff --git a/content/en/docs/v2.7/user/examples/local-mock.md b/content/en/docs/v2.7/user/examples/local-mock.md deleted file mode 100644 index 50eb713dad52..000000000000 --- a/content/en/docs/v2.7/user/examples/local-mock.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -type: docs -title: "Local Mock" -linkTitle: "Local Mock" -weight: 26 -description: "Local mock in dubbo" ---- - -Local mock [^1] is usually used for service downgrade, such as a verification service, the client does not throw an exception when the service provider hangs up all the time, but returns the authorization failed through the Mock data. - -Configured in the spring configuration file as follows: - -```xml - -``` - -or - -```xml - -``` - -Mock implementation in the project [^2]: - -```java -package com.foo; -public class BarServiceMock implements BarService { - public String sayHello(String name) { - // You can return mock data, this method is only executed when an RpcException is thrown. - return "mock data"; - } -} -``` - -If the service consumer often needs `try-catch` to catch exceptions, such as: - -```java -Offer offer = null; -try { - offer = offerService.findOffer(offerId); -} catch (RpcException e) { - logger.error(e); -} -``` - -Consider changing to Mock implementation and return null in Mock implementation. If you just want to simply ignore the exception, `2.0.11` version or later version is available: - -```xml - -``` - -## Advanced Usage - -### return - -`return` can be used to return an object's string representation as the mocked return value. The legal values incude: -* *empty*: empty value, default value for primary type, and empty value for collections. -* *null*: `null` -* *true*: `true` -* *false*: `false` -* *JSON format*: a mocked return value in JSON format, will be deserialized at runtime - -### throw - -`throw` can be used to throw an exception object as the mocked return value. - -Throw a default RPCException when invocation gets wrong: - -```xml - -``` - -Throw a specified exception when invocation gets wrong: - -```xml - -``` - -### force & fail - -Since `2.6.6` and above, it is possible to use `fail:` and `force:` in Spring's XML configuration to define mock behavior. `force:` means the mocked value is forced to use no matter the invocation gets wrong or not, in fact, the remote invocation will not happen at all. `fail:` is consistent with the default behavior, that is, mock happens only when invocation gets wrong. Futhermore, both `force:` and `fail:` can be used together with `throw` or `return` to define the mock behavior further. - -Force to return the specified value: - -```xml - -``` - -Force to throw the specified exception: - -```xml - -``` - -### Specify Mock For Particular Method Only - -Mock behavior can be specified on the method level. Assume there are a couple of methods on `com.foo.BarService`, we can specify the mock behavior for one particular method only, say `sayHello()`. In the example below, "fake" is forced to return everytime when `sayHello()` is called, but other methods will not be effected: - -```xml - - - -``` - -[^1]: Mock is a subset of the Stub. If you use Stub, you may need to rely on the RpcException class. If you use Mock, you do not need to rely on RpcException, when throwing RpcException, it will callback Mock implementation class. -[^2]: BarServiceMock implements BarService and has a no-argument constructor. diff --git a/content/en/docs/v2.7/user/examples/local-stub.md b/content/en/docs/v2.7/user/examples/local-stub.md deleted file mode 100644 index 76c7baca29aa..000000000000 --- a/content/en/docs/v2.7/user/examples/local-stub.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -type: docs -title: "Local Stub" -linkTitle: "Local Stub" -weight: 25 -description: "Local stub in dubbo" ---- - -When using rpc, the client usually only the interface, but sometimes the client also want to perform part of the logic in the client. For example: do ThreadLocal cache, verify parameters, return mock data when call fails., etc. - -To solve this problem, you can configure the stub in the API, so that when the client generates the proxy instance, it passes the proxy to the `Stub` via the constructor [^1], and then you can implement your logic in the stub implementation code. - - -![/user-guide/images/stub.jpg](/imgs/user/stub.jpg) - -Configured in the spring configuration file as follows: - -```xml - -``` - -or - -```xml - -``` - -Provide Stub implementation [^2]: - -```java -package com.foo; -public class BarServiceStub implements BarService { - private final BarService barService; - - // The real remote proxy object is passed in through the constructor - public BarServiceStub(BarService barService){ - this.barService = barService; - } - - public String sayHello(String name) { - // The following code is executed on the client. You can do local ThreadLocal caching on the client side, or verify parameters, etc. - try { - return barService.sayHello(name); - } catch (Exception e) { - // You can return the mock data. - return "MockData"; - } - } -} -``` - -[^1]: The Stub must have a constructor that can pass in the proxy. -[^2]: BarServiceStub implements BarService ,it has a constructor passed in the remote BarService instance diff --git a/content/en/docs/v2.7/user/examples/logger-strategy.md b/content/en/docs/v2.7/user/examples/logger-strategy.md deleted file mode 100644 index 43076820e9cb..000000000000 --- a/content/en/docs/v2.7/user/examples/logger-strategy.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -type: docs -title: "Logger Strategy" -linkTitle: "Logger Strategy" -weight: 38 -description: "Config logger Strategy in dubbo" ---- - -`2.2.1` or later, dubbo support log4j、slf4j、jcl、jdk adapters [^1], you can also explicitly configure the log output policy in the following ways: - -1. Command - - ```sh - java -Ddubbo.application.logger=log4j - ``` - -1. Configure in `dubbo.properties` - - ```properties - dubbo.application.logger=log4j - ``` - -1. Configure in `dubbo.xml` - - ```xml - - ``` - -[^1]: Custom Extensions: [logger-adapter](/en/docs/v2.7/dev/impls/logger-adapter) diff --git a/content/en/docs/v2.7/user/examples/msgpack-serialization.md b/content/en/docs/v2.7/user/examples/msgpack-serialization.md deleted file mode 100644 index dd88eae4ce59..000000000000 --- a/content/en/docs/v2.7/user/examples/msgpack-serialization.md +++ /dev/null @@ -1,126 +0,0 @@ ---- -type: docs -title: "msgpack serialization" -linkTitle: "msgpack serialization" -weight: 15 -description: "Using msgpack serialization in Dubbo" ---- - -MessagePack is an efficient binary serialization format. It lets you exchange data among multiple languages like JSON. -But it's faster and smaller. Small integers are encoded into a single byte, and typical short strings require only one -extra byte in addition to the strings themselves. - -{{% alert title="Notice" color="primary" %}} -support on `2.7.12` or above. -{{% /alert %}} - -## msgpack demo - -- 1. provider and consumer import msgpack dependencies - -```xml - - org.msgpack - msgpack-core - 0.8.22 - - - - org.msgpack - jackson-dataformat-msgpack - 0.8.22 - -``` - -- 2. provider demo - -Add the following protocol configurations into Dubbo configuration class: - -```java -... - @Bean - public ProtocolConfig msgpackProtocol(){ - ProtocolConfig protocolConfig = new ProtocolConfig(); - protocolConfig.setName("dubbo"); - protocolConfig.setId("msgpack"); - protocolConfig.setSerialization("msgpack"); - return protocolConfig; - } -``` - -Dubbo provider: - -Add protocol declaration protocol = {"msgpackProtocol"} to annotations of @Service implemented by Dubbo provider interface. - -Dubbo provider interface: -```java -public interface MsgpackService { - int tint(int i); - long tlong(long i); - List tlist(List l); - String multiParams(String str, int i, MyParam myParam); -} -``` - -Dubbo provider interface implement: - -```java -@Service(interfaceClass = MsgpackService.class,protocol = {"msgpackProtocol"}) -public class MsgpackServiceImpl implements MsgpackService { - @Override - public int tint(int i) { - return i; - } - @Override - public long tlong(long i) { - return i; - } - @Override - public List tlist(List l) { - return l; - } - @Override - public String multiParams(String str, int i, MyParam myParam) { - return str + i + myParam.getName() + myParam.getAge(); - } -} -``` - -Entities used: - -```java -@Data -public class MyParam { - private String name; - private int age; - public MyParam(String name, int age) { - this.name = name; - this.age = age; - } - - // parameterless construct function needed - public MyParam(){} -} -``` - -- 3. consumer demo - -```java - @DubboReference(interfaceClass = MsgpackService.class) - private MsgpackService msgPackService; - @GetMapping("/msgpack") - public String testMsgpack(){ - int v1 = msgPackService.tint(1); - long v2 = msgPackService.tlong(2); - List v3 = msgPackService.tlist(Lists.newArrayList("1","2","3")); - String v4 = msgPackService.multiParams("hello", 3, new MyParam("Tom", 24)); - return "msgpack"+v1+" "+v2+" "+v3+" "+v4; - } -``` - -- 4. invoke - -``` -> curl http://localhost:8081/msgpack -> msgpack1 2 [1, 2, 3] hello3Tom24 -``` diff --git a/content/en/docs/v2.7/user/examples/multi-protocols.md b/content/en/docs/v2.7/user/examples/multi-protocols.md deleted file mode 100644 index f94c14ab9345..000000000000 --- a/content/en/docs/v2.7/user/examples/multi-protocols.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -type: docs -title: "Multiple Protocols" -linkTitle: "Multiple Protocols" -weight: 9 -description: "Config multiple protocols in dubbo" ---- - - -Dubbo allows you to configure multiple protocols, support different protocols on different services, or support multiple protocols on the same service. - -## Every service export to one specific protocol separately - -Different protocol performance is not the same. Such as big data should use short connection protocol, small data and concurrent should use long connection protocol. - -```xml - - - - - - - - - - - - -``` - -## One service export to several protocols - -```xml - - - - - - - - - - -``` - -[^1]: custom protocol, see:[protocol extension](/en/docs/v2.7/dev/impls/protocol/) diff --git a/content/en/docs/v2.7/user/examples/multi-registry.md b/content/en/docs/v2.7/user/examples/multi-registry.md deleted file mode 100644 index ea825415afb3..000000000000 --- a/content/en/docs/v2.7/user/examples/multi-registry.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -type: docs -title: "Multiple Registries" -linkTitle: "Multiple Registries" -weight: 10 -description: "Config multiple registries in dubbo" ---- - - -Dubbo supports the same service to register multiple registries, or different services were registered to different registries, or even reference the same name service from different registries. In addition, the registry supports custom extensions [^1]。 - -## One service register to multiple registries - -For example: Alibaba some services are not deployed in Qingdao, only deployed in Hangzhou. While other applications in Qingdao need to reference this service, you can register your services to both registries at the same time. - -```xml - - - - - - - - - -``` - -## Different services register to different registries - -For example: Some CRM services are specifically designed for international stations, and some services are specifically designed for Chinese stations. - -```xml - - - - - - - - - - - -``` - - -## Reference services from multiple registries - -For example: CRM needs to call the PC2 service of Chinese station and international station at the same time. PC2 is deployed in both Chinese station and international station. The interfaces and version numbers are the same, but the database used is different. - -```xml - - - - - - - - - - - -``` - -When testing, the service needs to be temporarily register to two registries, which can use vertical signs to separate multiple different registry addresses: - -```xml - - - - - - - - -``` - -[^1]: custom registry, see:[registry extension](/en/docs/v2.7/dev/impls/registry/) diff --git a/content/en/docs/v2.7/user/examples/multi-versions.md b/content/en/docs/v2.7/user/examples/multi-versions.md deleted file mode 100644 index a161d702d43c..000000000000 --- a/content/en/docs/v2.7/user/examples/multi-versions.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -type: docs -title: "Multiple Versions" -linkTitle: "Multiple Versions" -weight: 12 -description: "Config multiple versions for services in dubbo" ---- - -When an interface to achieve an incompatible upgrade, you can use the version number transition. Different versions of the services do not reference each other. - -You can follow the steps below for version migration: - -0. In the low pressure period, upgrade to half of the provider to the new version -0. Then upgrade all consumers to the new version -0. Then upgrade the remaining half providers to the new version - - -Old version of the service provider configuration: - -```xml - -``` - -New version of the service provider configuration: - -```xml - -``` - -Old version of the service consumer configuration: - -```xml - -``` - -New version of the service consumer configuration: - -```xml - -``` - -If you do not need to distinguish between versions, can be configured as follows: - -```xml - -``` - -{{% alert title="Notice" color="primary" %}} -`version="*"` is supported in `2.2.0` or above. -{{% /alert %}} - diff --git a/content/en/docs/v2.7/user/examples/netty4.md b/content/en/docs/v2.7/user/examples/netty4.md deleted file mode 100644 index efef553901bb..000000000000 --- a/content/en/docs/v2.7/user/examples/netty4.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -type: docs -title: "Netty4" -linkTitle: "Netty4" -weight: 44 -description: "Config netty4 support in dubbo" ---- - -Add support for netty4 communication module in 2.5.6 version of dubbo, enabled as follows: - -provider: -```xml - -``` - -or - -```xml - -``` - -consumer: -```xml - - -``` - -{{% alert title="Warning" color="warning" %}} -1. If provider need to use different communication layer framework for different protocols , please configure multiple protocols separately. -2. consumer configuration as follow: - ```xml - - - - ``` - - ```xml - - - - ``` - -Next we will continue to do something:We will provide a reference data on the performance test indicators and performance test comparison with the version of netty 3. -{{% /alert %}} - diff --git a/content/en/docs/v2.7/user/examples/parameter-validation.md b/content/en/docs/v2.7/user/examples/parameter-validation.md deleted file mode 100644 index b2009ca461a4..000000000000 --- a/content/en/docs/v2.7/user/examples/parameter-validation.md +++ /dev/null @@ -1,189 +0,0 @@ ---- -type: docs -title: "Parameter Validation" -linkTitle: "Parameter Validation" -weight: 14 -description: "Parameter validation in dubbo" ---- - -The parameter validation [^1] is based on [JSR303] (https://jcp.org/en/jsr/detail?id=303). The user simply add the validation annotation of the JSR303 and declares the filter for validation [^2]. - -## Maven Dependency - -```xml - - javax.validation - validation-api - 1.0.0.GA - - - org.hibernate - hibernate-validator - 4.2.0.Final - -``` - -## Sample - -### Example of Parameter Annotation - -```java -import java.io.Serializable; -import java.util.Date; - -import javax.validation.constraints.Future; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Past; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; - -public class ValidationParameter implements Serializable { - private static final long serialVersionUID = 7158911668568000392L; - - @NotNull // Required - @Size(min = 1, max = 20) // range - private String name; - - @NotNull(groups = ValidationService.Save.class) // It is not allowed to be blank when saving. When it is updated, it is allowed to be blank, indicating that the field is not updated - @Pattern(regexp = "^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$") - private String email; - - @Min(18) // min value - @Max(100) // max value - private int age; - - @Past // Must be a past time - private Date loginDate; - - @Future // Must be a future time - private Date expiryDate; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - - public Date getLoginDate() { - return loginDate; - } - - public void setLoginDate(Date loginDate) { - this.loginDate = loginDate; - } - - public Date getExpiryDate() { - return expiryDate; - } - - public void setExpiryDate(Date expiryDate) { - this.expiryDate = expiryDate; - } -} -``` - -### Example of group validation - -```java -public interface ValidationService { // By default, service interfaces are used to differentiate authentication scenarios. For example:@NotNull(groups = ValidationService.class) - @interface Save{} // The same name as the method interface, the first letter capitalized, used to distinguish between authentication scene. For example:@NotNull(groups = ValidationService.Save.class),option - void save(ValidationParameter parameter); - void update(ValidationParameter parameter); -} -``` - -### Example of Cascading Validation - -```java -import javax.validation.GroupSequence; - -public interface ValidationService { - @GroupSequence(Update.class) // validate the Update group rules at the same time - @interface Save{} - void save(ValidationParameter parameter); - - @interface Update{} - void update(ValidationParameter parameter); -} -``` - -### Example of parameter validation - -```java -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; - -public interface ValidationService { - void save(@NotNull ValidationParameter parameter); // Param must not be null - void delete(@Min(1) int id); // validate the range -} -``` - -## Configuration - -### Validate Parameter on the client - -```xml - -``` - -### Validate Parameter on the server - -```xml - -``` - -## Validate Exception - -```java -import javax.validation.ConstraintViolationException; -import javax.validation.ConstraintViolationException; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import org.apache.dubbo.examples.validation.api.ValidationParameter; -import org.apache.dubbo.examples.validation.api.ValidationService; -import org.apache.dubbo.rpc.RpcException; - -public class ValidationConsumer { - public static void main(String[] args) throws Exception { - String config = ValidationConsumer.class.getPackage().getName().replace('.', '/') + "/validation-consumer.xml"; - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(config); - context.start(); - ValidationService validationService = (ValidationService)context.getBean("validationService"); - // Error - try { - parameter = new ValidationParameter(); - validationService.save(parameter); - System.out.println("Validation ERROR"); - } catch (RpcException e) { // throw RpcException - ConstraintViolationException ve = (ConstraintViolationException) e.getCause(); // Inside a ConstraintViolationException - Set> violations = ve.getConstraintViolations(); // You can get the collection of validation error details - System.out.println(violations); - } - } -} -``` - -[^1]: Support since `2.1.0` version. If you want to know how to use it, refer to [Sample code in dubbo project] (https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-validation) -[^2]: The validation method is extensible, refer to [Developer Extension](/en/docs/v2.7/dev/impls/validation) in the developer's manual. diff --git a/content/en/docs/v2.7/user/examples/preflight-check.md b/content/en/docs/v2.7/user/examples/preflight-check.md deleted file mode 100644 index 74c74a0a41e0..000000000000 --- a/content/en/docs/v2.7/user/examples/preflight-check.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -type: docs -title: "Preflight Check" -linkTitle: "Preflight Check" -weight: 1 -description: "Config preflight check in dubbo" ---- - -By default dubbo will check if the dependent service is available at startup . It will throw an exception to prevent Spring complete initialization when it is not available, so that you can find the problems early before publishing you application, the default setting: `check=true`. - -You can turn off checking by `check=false`. For example, some services do not care it when you run testing, or you must have one started firstly because of circular dependency. - -In addition, if your Spring bean is lazy-loaded or you delay reference service with API programming, turn off the check, -otherwise the service will throw an exception when the service is temporarily unavailable ,then get a null reference. If you configure `check=false` ,you can get a reference . When the service is restored, the service can automatically reconnect. - -## Example - -### Use the spring configuration file - -Disable the startup check of a service (throw some exception/error when no provider is provided): - -```xml - -``` - -Disable startup checking for all services (throw some exception/error when not provided): - -```xml - -``` - -Disable the registration center startup check (registration subscription failed error): - -```xml - -``` - -### Use dubbo.properties - -```properties -dubbo.reference.com.foo.BarService.check = false -dubbo.reference.check = false -dubbo.consumer.check = false -dubbo.registry.check = false -``` - -### Use the -D parameter - -```sh -java -Ddubbo.reference.com.foo.BarService.check = false -java -Ddubbo.reference.check = false -java -Ddubbo.consumer.check = false -java -Ddubbo.registry.check = false -``` - -## Configuration Meaning - -`dubbo.reference.check=false`, Change the check value of all references forcibly, even if the configuration has a declaration, it also will be overwritten. - -`dubbo.consumer.check=false` The default value of `check`. It will not be affected if there is an explicit declaration in the configuration such as` ``. - -`dubbo.registry.check=false`, The two configuration above is to express success of the subscription. If the subscription is also allowed to start when the registration fails for the provider list is empty, you need to use this configuration. The system will try again in the background regularly. \ No newline at end of file diff --git a/content/en/docs/v2.7/user/examples/provider-timeout-release.md b/content/en/docs/v2.7/user/examples/provider-timeout-release.md deleted file mode 100644 index ff93221db299..000000000000 --- a/content/en/docs/v2.7/user/examples/provider-timeout-release.md +++ /dev/null @@ -1,137 +0,0 @@ ---- -type: docs -title: "provider timeout release" -linkTitle: "provider timeout release" -weight: 15 -description: "Dubbo provider executes timeout release" ---- - -Dubbo allows providers to shutdown operations based on how long the timeout lasts. - -Applicable scenario: when a certain operation times out, providers can release that thread instead of simply printing out the timeout log message. - -{{% alert title="Notice" color="primary" %}} -support on `2.7.12` or above. -{{% /alert %}} - -## Main Logic - -```java -public class AllChannelHandler2 extends AllChannelHandler { - public static final Timer TIME_OUT_TIMER = new HashedWheelTimer( - new NamedThreadFactory("dubbo-server-future-timeout", true), - 30, - TimeUnit.MILLISECONDS); - public AllChannelHandler2(ChannelHandler handler, URL url) { - super(handler, url); - } - @Override - public void received(Channel channel, Object message) throws RemotingException { - ExecutorService executor = getPreferredExecutorService(message); - try { - Future future = executor.submit(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message)); - long timeout = this.url.getParameter("timeout", 1000) + 90; - TIME_OUT_TIMER.newTimeout(t -> { - if (!future.isDone() && (!future.isCancelled())) { - try { - future.cancel(true); - } catch (Throwable ex) { - //ignore - } - } - }, timeout, TimeUnit.MILLISECONDS); - } catch (Throwable t) { - if (message instanceof Request && t instanceof RejectedExecutionException) { - sendFeedback(channel, (Request) message, t); - return; - } - throw new ExecutionException(message, channel, getClass() + " error when process received event .", t); - } - } -} -``` - -## Demo - -- Set Dubbo ProtocolConfig thread dispatch strategy as "all2". - -```java - /** - * Configuration Protocol - */ - @Bean - public ProtocolConfig protocolConfig() { - ProtocolConfig protocolConfig = new ProtocolConfig(); - protocolConfig.setName("dubbo"); - protocolConfig.setPort(-1); - protocolConfig.setTransporter("netty4"); - protocolConfig.setThreadpool("fixed"); - // Set up thread dispatch strategy - protocolConfig.setDispatcher("all2"); - protocolConfig.setThreads(200); - return protocolConfig; - } -``` - -- provider demo - -When timeout, the thread will be stopped. In other words, if providers cannot return results to the consumers in time, then the thread will be stopped. - -```java -// Set provider timeout period as 1000ms -@Service(interfaceClass = TestService.class,timeout = 1000) -public class TestServiceImpl implements TestService { - @Override - public Integer sum(int a, int b) { - CountDownLatch latch = new CountDownLatch(2); - AtomicInteger i = new AtomicInteger(); - new Thread(()->{ - i.incrementAndGet(); - latch.countDown(); - }).start(); - new Thread(()->{ - try { - TimeUnit.MILLISECONDS.sleep(2000); - }catch (InterruptedException e){ - e.printStackTrace(); - } - i.incrementAndGet(); - latch.countDown(); - }).start(); - try { - latch.await(); - return i.get(); - }catch (InterruptedException e){ - // when timeout, return the following - throw new RuntimeException("call sum timeout"); - } - } -} -``` -As for the provider demo above, when running the last try-catch, if the thread is released then catch InterruptedException and return "call sum timeout". - - -- consumer demo - -```java - // Set consumer timeout period as 2000 longer than the server execution period - @Reference(check = false,interfaceClass = TestService.class,timeout = 3000) - private TestService testService; - @GetMapping("/sum") - public String consumeSum(){ - Integer ret = 0; - try{ - ret = testService.sum(1,1); - }catch (Exception e){ - return e.getMessage(); - } - return String.valueOf(ret); - } -``` - -- execution outcome - -``` -curl http://localhost:8081/sum ->call sum timeout -``` diff --git a/content/en/docs/v2.7/user/examples/reference-config-cache.md b/content/en/docs/v2.7/user/examples/reference-config-cache.md deleted file mode 100644 index 48e12ca22e79..000000000000 --- a/content/en/docs/v2.7/user/examples/reference-config-cache.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -type: docs -title: "ReferenceConfig Cache" -linkTitle: "ReferenceConfig Cache" -weight: 41 -description: "Cache ReferenceConfig in dubbo" ---- - -The instance of `ReferenceConfig` is heavy. It encapsulates the connection to the registry and the connection to the provider, so it need to be cached. Otherwise, repeatedly generating `ReferenceConfig` may cause performance problems , memory and connection leaks. This problem is easy to ignored when programming in API mode. - -Therefore, since `2.4.0`, dubbo provides a simple utility ReferenceConfigCache for caching instances of `ReferenceConfig`. - - -Use as follows: - -```java -ReferenceConfig reference = new ReferenceConfig(); -reference.setInterface(XxxService.class); -reference.setVersion("1.0.0"); -...... -ReferenceConfigCache cache = ReferenceConfigCache.getCache(); -// cache.get will cache the instance of Reference ,and call ReferenceConfig.get method to start ReferenceConfig -XxxService xxxService = cache.get(reference); -// Note: Cache will hold ReferenceConfig, do not call destroy method of ReferenceConfig outside. If you do this, it will invalidate ReferenceConfig in Cache! -// Use xxxService instance -xxxService.sayHello(); -``` - -Destroy `ReferenceConfig` in the Cache, it also remove `ReferenceConfig` and release the corresponding resources。 - -```java -ReferenceConfigCache cache = ReferenceConfigCache.getCache(); -cache.destroy(reference); -``` - -By default ,`ReferenceConfigCache` caches one ` ReferenceConfig` for the same service Group, interface, version. The key of `ReferenceConfigCache` is from the group of service Group, interface, and the version. - -You can modify the strategy. Define an instance of KeyGenerator, pass it as parameter of getCache method. Refer to `ReferenceConfigCache` for information。 - -```java -KeyGenerator keyGenerator = new ... -ReferenceConfigCache cache = ReferenceConfigCache.getCache(keyGenerator ); -``` - diff --git a/content/en/docs/v2.7/user/examples/registry-only.md b/content/en/docs/v2.7/user/examples/registry-only.md deleted file mode 100644 index e3036d039a4f..000000000000 --- a/content/en/docs/v2.7/user/examples/registry-only.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -type: docs -title: "Register Only" -linkTitle: "Register Only" -weight: 41 -description: "Config registry only service in dubbo" ---- - -You have two mirroring environments, two registries. -You have deployed one service at only one of the registries, another registries have not had time to deploy, and other applications at both registries need to rely on the service. -At this time, the service provider registers service to another registrar, but the service consumers do not consume the service from another registrar. - -Disable subscription configuration - -```xml - - -``` - -or - -```xml - - -``` diff --git a/content/en/docs/v2.7/user/examples/result-cache.md b/content/en/docs/v2.7/user/examples/result-cache.md deleted file mode 100644 index 0fc51658c980..000000000000 --- a/content/en/docs/v2.7/user/examples/result-cache.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -type: docs -title: "Cache Result" -linkTitle: "Cache Result" -weight: 15 -description: "Cache result in dubbo" ---- - -Cache result is used to speed up access to popular data. Dubbo provides declarative caching to reduce the user work of adding cache [^1]. - -## Cache Type - -* `lru` Delete excess cache Based on the principle of least recently used. The hottest data is cached. -* `threadlocal` The current thread cache. For example, a page have a lot of portal and each portal need to check user information, you can reduce this redundant visit with this cache. -* `jcache` integrate with [JSR107](http://jcp.org/en/jsr/detail?id=107%27) , you can bridge a variety of cache implementation. - -Caching type can be extended,refer to:[Cache extension](/en/docs/v2.7/dev/impls/cache) - -## Configuration - -```xml - -``` - -or: - -```xml - - - -``` - -{{% alert title="Notice" color="primary" %}} -supported in `2.1.0` or above. -{{% /alert %}} - -[^1]: [examples](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-cache) diff --git a/content/en/docs/v2.7/user/examples/routing-rule.md b/content/en/docs/v2.7/user/examples/routing-rule.md deleted file mode 100644 index 6006204f607d..000000000000 --- a/content/en/docs/v2.7/user/examples/routing-rule.md +++ /dev/null @@ -1,199 +0,0 @@ ---- -type: docs -title: "Routing Rule" -linkTitle: "Routing Rule" -weight: 33 -description: "Config routing rule in dubbo" ---- - -The routing rules [^1] determine the target server of one service call. It has two kinds of routing rules: conditional routing rules and script routing rules. It also support extension[^2]. - -## Write Routing Rules - -Writing routing rules to the registry is usually done by the monitoring center or the console page. - -```java -RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); -Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); -registry.register(URL.valueOf("route://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=" + URL.encode("host = 10.20.153.10 => host = 10.20.153.11"))); -``` - -其中: - -* `route://` It indicates the type of routing rules, supports routing rules and script routing rules, and can be extended. **Required**。 -* `0.0.0.0` It indicates that all IP addresses are valid. If you want to take effect for only one IP address, fill in the IP address. **Required**。 -* `com.foo.BarService` It indicates that the specified service is effective. **Required**。 -* `group=foo` It indicates that the specified service in specified group is effective. When absent, the specified service which dosen't configure group is effective. -* `version=1.0`It indicates that the specified service in specified version is effective. When absent, the specified service which dosen't configure version is effective. -* `category=routers` It indicates that the data is a dynamic configuration type. **Required**。 -* `dynamic=false` It indicates that it is persistent data. When the registrant exits, the data is still stored in the registry. **Required**。 -* `enabled=true` It indicates whether this routing rules is effective. Option, and default effective. -* `force=false` It indicates whether it is forced to be executed when the routing result is null. If it is not enforced, the route will be automatically invalidated. Option, and default `false`. -* `runtime=false` It indicates whether to execute routing rules at every call. If not, the result is only pre-executed and cached when the provider's address list changes. It will get routing result from cache when the service is invoked. If you use parameter routing, you must to configure it as `true`. Be careful that the configuration will affect the performance. Option, and default `false`. -* `priority=1` The priority of the routing rules. it is used for sorting, the greater the priority, the more front execution. Option, and default `0`。 -* `rule=URL.encode("host = 10.20.153.10 => host = 10.20.153.11")` It indicates the content of routing rule,**Required**。 - -## Conditional routing rules - -Routing rules based on conditional expressions, such as:`host = 10.20.153.10 => host = 10.20.153.11` - -### Rules: - -* The previous of `=>` is matched condition for consumer. All parameters compare with URL of consumers. When the consumer meet the condition, it will continue to execute the behind filter rules for consumer. -* After the `=>` aims to filter the provider address list. All the parameters are compared against the provider's URL, and consumer get only the filtered address list at finally. -* If the previous condition for consumer is empty, it means all consumers can matched. such as : `=> host != 10.20.153.11` -* If the filter condition for provider is empty, it means it is forbidden to visit. such as :`host = 10.20.153.10 =>` - -### Expressions: - -Parameter Support: - -* Service call information, such as: method, argument etc. Parameter routing is currently not supported -* URL field (On URL own), such as: protocol, host, port etc. -* All parameters on the URL. such as: application, organization etc. - -Condition Support: - -* Equal sign `=` indicates match. such as: `host = 10.20.153.10` -* Not equal sign `!=` indicates "does not match". such as: `host != 10.20.153.10`. - -Value Support: - -* Separate multiple values with a comma `,` . Such as:`host != 10.20.153.10,10.20.153.11` -* End with `*` to indicate wildcard. Such as: `host != 10.20.*` -* Start with `$` to indicate reference to consumer parameters. Such as: `host = $host` - -### Samples - -0. Exclude pre-release machine: - - ``` - => host != 172.22.3.91 - ``` -1. Whitelist [^3]: - - ``` - register.ip != 10.20.153.10,10.20.153.11 => - ``` -2. Blacklist: - - ``` - register.ip = 10.20.153.10,10.20.153.11 => - ``` -3. Service boarding application only expose part of the machine to prevent the entire cluster hanging up: - - ``` - => host = 172.22.3.1*,172.22.3.2* - ``` -4. Additional machines for important applications: - - ``` - application != kylin => host != 172.22.3.95,172.22.3.96 - ``` -5. Read and write separation: - - ``` - method = find*,list*,get*,is* => host = 172.22.3.94,172.22.3.95,172.22.3.96 - method != find*,list*,get*,is* => host = 172.22.3.97,172.22.3.98 - ``` - -6. Separation of Front and Background Application: - - ``` - application = bops => host = 172.22.3.91,172.22.3.92,172.22.3.93 - application != bops => host = 172.22.3.94,172.22.3.95,172.22.3.96 - ``` - -7. Isolate different network segments: - - ``` - host != 172.22.3.* => host != 172.22.3.* - ``` - -8. Providers and consumers deployed in the same cluster, the machine only visit the local service: - - ``` - => host = $host - ``` - -## Script routing rules - -Script routing rules [^4] support all scripts of JDK script engine. such as: javascript, jruby, groovy, etc. Configure the script type by `type=javascript`, the default is javascript. - - -``` -"script://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=" + URL.encode("(function route(invokers) { ... } (invokers))") -``` - -Routing rules that base on script engine is as follow: - -```javascript -(function route(invokers) { - var result = new java.util.ArrayList(invokers.size()); - for (i = 0; i < invokers.size(); i ++) { - if ("10.20.153.10".equals(invokers.get(i).getUrl().getHost())) { - result.add(invokers.get(i)); - } - } - return result; -} (invokers)); // Indicates that the method is executed immediately -``` - -## Tag routing rules - -Tag routing rules [^5] , when the application configures the `TagRouter` , a tagged dubbo invocation can intelligently route to the service provider which has the corresponding tag. - -### Provider - -1. configure TagRouter for the application - -```Java -@Bean -public ApplicationConfig applicationConfig() { - ApplicationConfig applicationConfig = new ApplicationConfig(); - applicationConfig.setName("provider-book"); - applicationConfig.setQosEnable(false); - // instruct tag router - Map parameters = new HashMap<>(); - parameters.put(Constants.ROUTER_KEY, "tag"); - applicationConfig.setParameters(parameters); - return applicationConfig; -} -``` - -2. configure specfic tag for the provider - -```java -@Bean -public ProviderConfig providerConfig(){ - ProviderConfig providerConfig = new ProviderConfig(); - providerConfig.setTag("red"); - return providerConfig; -} -``` - -The application which configures no tag will be considered as the default application, and these default apps will be treated as downgrades when the invocation fails to match the provider. - -### Consumer - -```Java -RpcContext.getContext().setAttachment(Constants.TAG_KEY,"red"); -``` - -The scope of the `dubbo.tag` is for each invocation, using the attachment to pass the request tag. Note that the value stored in the attachment will be passed continuously in a complete remote invocation, thanks to this feature, we only need to set the tag at the beginning of a invocation. - -> Currently, only **hardcoding** is supported to set dubboTag. Note that RpcContext is thread-bound, elegantly using the TagRouter feature, it is recommended to set the request tag via a servlet filter (in the web environment) or a custom dubbo SPI filter. - -### Rules: - -1. `dubbo.tag=red` will firstlt choose the provider which configures as `tag=red`. If there is no service corresponding to the request tag in the cluster, it will downgrade to `tag=null` provider, seen as default provider。 - -2. when `dubbo.tag=null`, only `tag=null` provider will be matched. Even if there are services available in the cluster, the tags do not match, they cannot be called. This is different from rule 1. Tagged invocation can be downgraded to untagged services, but invocations that do not carry tags/carry other types of tags can never be accessed other tag services. - - - -[^1]: Support since `2.2.0` -[^2]: Routing Rules Extension Point: [Route Extension](/en/docs/v2.7/dev/impls/router/) -[^3]: Note: A service can only have one whitelist rule, otherwise the two rules will be filtered out. -[^4]: Note: Scripts have no sandbox constraints, can execute arbitrary code, and poses a backdoor risk. -[^5]: Support since `2.7.0` diff --git a/content/en/docs/v2.7/user/examples/serialization.md b/content/en/docs/v2.7/user/examples/serialization.md deleted file mode 100644 index 01a6128ba0d5..000000000000 --- a/content/en/docs/v2.7/user/examples/serialization.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -type: docs -title: "Serialization" -linkTitle: "Serialization" -weight: 44 -description: "Using Efficient Java Serialization in Dubbo (Kryo and FST)" ---- - -Using Kryo and FST is very simple, just add an attribute to the dubbo RPC XML configurition: - -``` - -``` - -``` - -``` - -## Register serialized class - -For releasing the high ability of Kryo and FST, it's best to register the classes that need serializing into the dubbo system. For example, we can implement the following callback interface: - -```java -public class SerializationOptimizerImpl implements SerializationOptimizer { - public Collection getSerializableClasses() { - List classes = new LinkedList(); - classes.add(BidRequest.class); - classes.add(BidResponse.class); - classes.add(Device.class); - classes.add(Geo.class); - classes.add(Impression.class); - classes.add(SeatBid.class); - return classes; - } -} -``` - -Then add in the XML configuration: - -```xml - -``` - -After registering these classes, serialization performance can be greatly improved, especially for small numbers of nested objects. - -Of course, when serializing a class, you might also cascade references to many classes, such as Java collection classes. In this case, we've automatically registered common classes in the JDK, so you don't need to register them repeatedly (and of course, it doesn't matter if you register them again), including: -* GregorianCalendar -* InvocationHandler -* BigDecimal -* BigInteger -* Pattern -* BitSet -* URI -* UUID -* HashMap -* ArrayList -* LinkedList -* HashSet -* TreeSet -* Hashtable -* Date -* Calendar -* ConcurrentHashMap -* SimpleDateFormat -* Vector -* BitSet -* StringBuffer -* StringBuilder -* Object -* Object[] -* String[] -* byte[] -* char[] -* int[] -* float[] -* double[] - -Since registering serialized classes is only for performance optimization purposes, it doesn't matter if you forget to register some classes. In fact, Kryo and FST generally perform better than Hessian and Dubbo serializations even if no classes are registered. diff --git a/content/en/docs/v2.7/user/examples/service-container.md b/content/en/docs/v2.7/user/examples/service-container.md deleted file mode 100644 index 656b182e8faf..000000000000 --- a/content/en/docs/v2.7/user/examples/service-container.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -type: docs -title: "Service Container" -linkTitle: "Service Container" -weight: 40 -description: "Use service container in dubbo" ---- - -The service container is a standalone launcher because the backend service does not require the functionality of a Web container ,such as Tomcat or JBoss. If you insist on using web containers to load service providers, that increase complexity and is waste of resources. - -The service container is just a simple Main method and loads a simple Spring container to expose the service. - -The content of Service container can be extended, built-in spring, jetty, log4j etc.. This can be expanded with [Container Extension Points](/en/docs/v2.7/dev/impls/container/). Configure it with the -D parameter in the java command or `dubbo.properties`. - -## Container type - -### Spring Container - -* Automatically load all spring configurations in the `META-INF/spring`. - - ```properties - dubbo.spring.config=classpath*:META-INF/spring/*.xml - ``` - -### Jetty Container - -* Start an embedded Jetty for reporting status. -* Configure: - * `dubbo.jetty.port=8080`: configure jetty start up port - * `dubbo.jetty.directory=/foo/bar`: static file that can be visited by jetty directly. - * `dubbo.jetty.page=log,status,system`: configure the displayed page, loading all pages by default - - -### Log4j Container - -* Automatic configuration log4j configuration. At the start of the multi-process, log files automatically by process sub-directory. -* Configure: - * `dubbo.log4j.file=/foo/bar.log`: configure log file path - * `dubbo.log4j.level=WARN`: configure log level - * `dubbo.log4j.subdirectory=20880`: configure log sub directory for multi-process startup and avoiding conflict - -## Container startup - -load spring by default. - -```sh -java org.apache.dubbo.container.Main -``` - -Load the container that passed in by the main method - -```sh -java org.apache.dubbo.container.Main spring jetty log4j -``` - -Load the container that passed in by the JVM option. - - -```sh -java org.apache.dubbo.container.Main -Ddubbo.container=spring,jetty,log4j -``` - -Load the container that passed in by `dubbo.properties` in the classpath. - -``` -dubbo.container=spring,jetty,log4j -``` diff --git a/content/en/docs/v2.7/user/examples/service-downgrade.md b/content/en/docs/v2.7/user/examples/service-downgrade.md deleted file mode 100644 index 996d2a83f4c5..000000000000 --- a/content/en/docs/v2.7/user/examples/service-downgrade.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -type: docs -title: "Service Downgrade" -linkTitle: "Service Downgrade" -weight: 35 -description: "Downgrade service in dubbo" ---- - -You can temporarily shield a non-critical service through the service downgrade and define the return policy for it. - - -Publish dynamic configuration rule to the registry: - -```java -RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); -Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); -registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null")); -``` - -* The configuration `mock=force:return+null` means that all calls of this service will return null value directly,without making remote calls.Usually used to reduce the effect of some slow non-critical services. - -* Also you can change that configuration to `mock=fail:return+null`.Then you will get null value after a failed call.Consumer will try to make a remote call to get the truely result if succeed,and if the call failed you will get null value.Usually used to tolerate some non-critical services. - - -[^1]: supported after version `2.2.0` diff --git a/content/en/docs/v2.7/user/examples/service-group.md b/content/en/docs/v2.7/user/examples/service-group.md deleted file mode 100644 index 28b9ab5343cc..000000000000 --- a/content/en/docs/v2.7/user/examples/service-group.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -type: docs -title: "Service Group" -linkTitle: "Service Group" -weight: 11 -description: "Grouping service in dubbo" ---- - -When you have multi-impls of a interface,you can distinguish them with the group. - -## Service - -```xml - - -``` - -## Reference - -```xml - - -``` - -Any group: - -```xml - -``` - -{{% alert title="Warning" color="warning" %}} -`group="*"` is supported after version `2.2.0`, always select only one available group of implementations to invoke. -{{% /alert %}} - - - diff --git a/content/en/docs/v2.7/user/examples/static-service.md b/content/en/docs/v2.7/user/examples/static-service.md deleted file mode 100644 index 2d6c0d31c0fe..000000000000 --- a/content/en/docs/v2.7/user/examples/static-service.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -type: docs -title: "Static Service" -linkTitle: "Static Service" -weight: 11 -description: "Config static service in dubbo" ---- - -Sometimes we want to manually manage the registration and deregistration for service provider, we need to set registry to non-dynamoic mode. - -```xml - -``` - -Or - -```xml - -``` - - -dynamic mode is disabled when service provider initially registers, then we need to enable it manually. When disconnects, the setting will not be deleted automatically, need to disable it manually. - -For a third party service provider like “memcachd”, it can directly write the address information of service provider to registry, which can be used by consumer. - -```java -RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); -Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); -registry.register(URL.valueOf("memcached://10.20.153.11/com.foo.BarService?category=providers&dynamic=false&application=foo")); -``` - - -[^1]: usually called by monitor system \ No newline at end of file diff --git a/content/en/docs/v2.7/user/examples/stickiness.md b/content/en/docs/v2.7/user/examples/stickiness.md deleted file mode 100644 index 4575743482d6..000000000000 --- a/content/en/docs/v2.7/user/examples/stickiness.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -type: docs -title: "Stickiness Connection" -linkTitle: "Stickiness" -weight: 31 -description: "Config stickiness connection in dubbo" ---- - -Sticky connections are used for stateful services, as much as possible so that clients always make calls to the same provider, unless the provider hangs up and connects to the other one. - -Sticky connections will automatically open [Lazy Connection](../lazy-connect) to reduce the number of long connections. - -```xml - -``` - -Dubbo supports method-level sticky connection, and if you want more granular control, you can also configure as follows. - -```xml - - - -``` diff --git a/content/en/docs/v2.7/user/examples/subscribe-only.md b/content/en/docs/v2.7/user/examples/subscribe-only.md deleted file mode 100644 index f966bde50d2c..000000000000 --- a/content/en/docs/v2.7/user/examples/subscribe-only.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -type: docs -title: "Subscribe Only" -linkTitle: "Subscribe Only" -weight: 6 -description: "Config subscribe only in dubbo" ---- - -To facilitate the development of tests, it is common to have a registry of all services available in develop environment.And the registration of a service provider under development may affect consumers' inability to run. - -You can let service provider developers only subscribe to services only (services developed may rely on other services) ,don't register services under development and testing services under development with directly connection. - -![/user-guide/images/subscribe-only.jpg](/imgs/user/subscribe-only.jpg) - -User configuration: - -```xml - -``` - -or - -```xml - -``` \ No newline at end of file diff --git a/content/en/docs/v2.7/user/examples/thread-model.md b/content/en/docs/v2.7/user/examples/thread-model.md deleted file mode 100644 index 269bf4d2e2d4..000000000000 --- a/content/en/docs/v2.7/user/examples/thread-model.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -type: docs -title: "Thread Model" -linkTitle: "Thread Model" -weight: 4 -description: "Config thread pool model in dubbo" ---- - -## Thread Model - -* If events handing can be executed quickly without sending new request like marking in memory. Events should be handled by I/O thread since it reduces thread dispatching. -* If event handling will be executed slowly or needs to send new I/O request like querying from database, events should be handled in thread pool. Otherwise, I/O thread will be blocked and then will be not able to receive requests. -* If events are handled by I/O thread, and send new I/O requests during the handling like sending a l login request during connect event, it will alert with “Potentially leading to deadlock”, but deadlock will not happen actually. - -![dubbo-protocol](/imgs/user/dubbo-protocol.jpg) - - -Thus, we need different dispatch strategies and different thread pool configurations to face difference scenarios. - -```xml - -``` - -## Dispatcher - -* all: All messages will be dispatched to thread pool, including request, response, connect event, disconnect event and heartbeat. -* direct: All messages will not be dispatched to thread pool and will be executed directly by I/O thread. -* message: Only request, response messages will be dispatched to I/O thread. Other messages like disconnect, connect, heartbeat messages will be executed by I/O thread. -* execution: Only request message will be dispatched to thread pool. Other messages like response, connect, disconnect, heartbeat will be directly executed by I/O thread. -* connection: I/O thread will put disconnect and connect events in the queue and execute them sequentially, other messages will be dispatched to the thread pool. - -## Thread pool - -* fixed: A fixed size of thread pool. It creates threads when starts, never shut down.(default). -* cached: A cached thread pool. Automatically delete the thread when it’s in idle for one minute. Recreate when needed. -* limit: elastic thread pool. But it can only increase the size of the thread pool. The reason is to avoid performance issue caused by traffic spike when decrease the size of the thread pool. diff --git a/content/en/docs/v2.7/user/examples/token-authorization.md b/content/en/docs/v2.7/user/examples/token-authorization.md deleted file mode 100644 index d968f4256aa8..000000000000 --- a/content/en/docs/v2.7/user/examples/token-authorization.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -type: docs -title: "Token Authorization" -linkTitle: "Token Authorization" -weight: 32 -description: "Config token based authorization in dubbo" ---- - -Through the token authorization control center at the registry to decide whether to issue tokens to consumers, you can prevent consumers from bypassing the registry access provider, another through the registry can flexibly change the authorization without modification or upgrade provider - - -![/user-guide/images/dubbo-token.jpg](/imgs/user/dubbo-token.jpg) - -You can turn on token authentication globally: - -```xml - - -``` -or - -```xml - - -``` - -Of course can turn on token authentication at service level: - -```xml - - -``` -or - -```xml - - -``` - -Also can turn on token authentication at protocol level: - -```xml - - -``` -or - -```xml - - -``` diff --git a/content/en/docs/v2.7/user/languages/_index.md b/content/en/docs/v2.7/user/languages/_index.md deleted file mode 100755 index 3f124a14041d..000000000000 --- a/content/en/docs/v2.7/user/languages/_index.md +++ /dev/null @@ -1,9 +0,0 @@ - ---- -type: docs -title: "Other Languages" -linkTitle: "Other Languages" -weight: 50 -description: "Other languages support" ---- - diff --git a/content/en/docs/v2.7/user/languages/erlang/_index.md b/content/en/docs/v2.7/user/languages/erlang/_index.md deleted file mode 100755 index f984c9e82ed4..000000000000 --- a/content/en/docs/v2.7/user/languages/erlang/_index.md +++ /dev/null @@ -1,9 +0,0 @@ - ---- -type: docs -title: "Erlang" -linkTitle: "Erlang" -weight: 200 -description: "Erlang support" ---- - diff --git a/content/en/docs/v2.7/user/languages/erlang/quick-start.md b/content/en/docs/v2.7/user/languages/erlang/quick-start.md deleted file mode 100644 index ba8d42ecbfb4..000000000000 --- a/content/en/docs/v2.7/user/languages/erlang/quick-start.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -type: docs -title: "Quick Start" -linkTitle: "Quick Start" -weight: 1 -description: "Erlang quick start" ---- - -We recommend using java to define the Dubbo interface. And use [erlanalysis](https://github.com/apache/dubbo-erlang/tree/master/tools/erlanalysis) -tool parse java interface transfer to erlang lib. - -## Import Dependency Lib - - -### Using Rebar Build Tool -Add dubblerl to rebar.config with your project -```erlang -{deps, [ - {dubboerl, {git, "https://github.com/apache/dubbo-erlang.git", {branch, "master"}}} -]}. -``` - -### User erlang.mk Build Tool -`Waiting for improvement` - -## Import interface lib -Suppose the interface lib you exported is called dubbo_service. -* If you didn't upload your lib to your git repository, It is recommended that you copy the `dubbo_service` lib -into the project's `apps` directory. -* If it is upload to your git repository, you can import like this: -```erlang -{deps, [ - {dubboerl, {git, "https://github.com/apache/dubbo-erlang.git", {branch, "master"}}}, - {dubbo_service,{git,"${INTERFACE_LIB_URL}",{branch,"master"}}} %% replace ${INTERFACE_LIB_URL} with your lib git repos url -]}. -``` - -## Consumer Configuration -Please reference [Reference Config](../reference) - -## Init dubbolib in your project -It is need you -```erlang -dubboerl:init(). -``` - -## How to invoke? - -### Sync Call -```erlang -Request = #userInfoRequest{requestId = 123, username = "testname"}, -{ok,RequestRef,Response,RpcContent} = userOperator:queryUserInfo(Request,#{sync=> true}). -``` -If it occur error, is reponse `{error,Reason}`. - -### Async Call - -Default is Async call. -```erlang -Request = #userInfoRequest{requestId = 123, username = "testname"}, -{ok,RequestRef} = userOperator:queryUserInfo(Request). - -%% you can receive the message after. -{msg_back,RequestRef,Response,RpcContent}. -``` - -## Sample -Reference the demo project [dubboerl_demo](https://github.com/apache/dubbo-erlang/tree/master/samples) \ No newline at end of file diff --git a/content/en/docs/v2.7/user/languages/erlang/reference.md b/content/en/docs/v2.7/user/languages/erlang/reference.md deleted file mode 100644 index 47c5985fb760..000000000000 --- a/content/en/docs/v2.7/user/languages/erlang/reference.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -type: docs -title: "Consumer Configuration" -linkTitle: "Consumer" -weight: 2 -description: "Consumer configurations in erlang" ---- - -## Base Config - -Consumer config is under the dubboerl application with sys.config - -```erlang -{dubboerl,[ - %% other config ... - {consumer,[ - {<<"interface fullname">>,[Option]}, - %% eg: - {<<"org.apache.dubbo.erlang.sample.service.facade.UserOperator">>,[]}, - ]} -]} -``` - -Option is to be added. diff --git a/content/en/docs/v2.7/user/languages/erlang/serialization.md b/content/en/docs/v2.7/user/languages/erlang/serialization.md deleted file mode 100644 index c77e76be4a14..000000000000 --- a/content/en/docs/v2.7/user/languages/erlang/serialization.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -type: docs -title: "Protocol Configuration" -linkTitle: "Protocol" -weight: 4 -description: "Protocol configurations in erlang" ---- - -The library now only supports hessian and json serialization. - -## Configuration example - -Protocol config is under the dubboerl application with sys.config - -```erlang -{dubboerl,[ - %% other config ... - {protocol,hessian} -]} -``` - -| ConfigName | Type | DefaultValue | Remarks | -| --- | --- | --- | --- | -| protocol | atom() | hessian | hessian,json | - \ No newline at end of file diff --git a/content/en/docs/v2.7/user/languages/erlang/service.md b/content/en/docs/v2.7/user/languages/erlang/service.md deleted file mode 100644 index de4e08b4127d..000000000000 --- a/content/en/docs/v2.7/user/languages/erlang/service.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -type: docs -title: "Provider Configuration" -linkTitle: "Provider" -weight: 3 -description: "Protocol configurations in erlang" ---- - -## Base Config - -Provider config is under the dubboerl application with sys.config - -```erlang -{dubboerl,[ - %% other config ... - {provider,[ - {module_implements,interface_module,interface_fullname,[Options]}, - %% eg: - {userOperator_impl,userOperator,<<"org.apache.dubbo.erlang.sample.service.facade.UserOperator">>,[Option]} - ]} -]} -``` - -| ConfigName | Type | DefaultValue | Remarks | -| --- | --- | --- | --- | -| module_implements | atom() | - | The service implements module name| -| interface_module | atom() | - | Interface module name is transfer form java jar | -| interface_fullname | binary() | - | Interface full name is the java class name | - -Option is to be added. \ No newline at end of file diff --git a/content/en/docs/v2.7/user/maturity.md b/content/en/docs/v2.7/user/maturity.md deleted file mode 100644 index 621ebfb24bb9..000000000000 --- a/content/en/docs/v2.7/user/maturity.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -type: docs -title: "Maturity" -linkTitle: "Maturity" -weight: 4 -description: "Dubbo maturity report" ---- - -## Function maturity - -| Feature | Maturity | Strength | Problem | Advise | User | -| -------------------------------------- | -------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | -------- | -| Concurrency control | Tested | concurrency control | | On trial | | -| Connection control | Tested | connection number control | | On trial | | -| Connecting certain provider straightly | Tested | Provider service for point-to-point connecting straightly, for test | | Can be used in the test environment | Alibaba | -| Grouping polymerization | Tested | Return value of grouping polymerization, service for menu aggregation and other services | Used in special scenes | Can be used in the production environment | | -| Parameters validator | Tested | parameters validator, JSR303 validation framework integration | Have effect on Performance | On trial | LaiWang | -| Result cache | Tested | result cache, for accelerating requests | | On trial | | -| Generic reference | Stable | Generic reference, remote call without a business interface class,for test platforms, open api proxy service, and so on | | Can be used in the production environment | Alibaba | -| Generic service | Stable | Generic service, no interface class is required to implement any interface, for mock platform | | Can be used in the production environment | Alibaba | -| Echo test | Tested | echo test | | On trial | | -| Attachment | Stable | Attachment | | Can be used in the production environment | | -| Asynchronous call | Tested | Unavailable asynchronous call | | On trial | | -| Local call | Tested | Local call | | On trial | | -| Callback parameter | Tested | Callback parameter | Used in special scenes | On trial | Registry | -| Events notify | Tested | Events notify, triggering before and after the remote call is executed | | On trial | | -| Local stub | Stable | Performing part of the logic on the client side | | Can be used in the production environment | Alibaba | -| Local mock | Stable | Forged return results, which can be executed when failed or directly executed, for service degradation | Need support of registry | Can be used in the production environment | Alibaba | -| Delay publish | Stable | Delay publish, used to wait for the application to load warmup data or wait for spring context to load completely | | Can be used in the production environment | Alibaba | -| Lazy connect | Tested | Delay setting up connections, when invocation is set up | | On trial | Registry | -| Stickness connections | Tested | Stickness connections, always make a request to the same provider service unless the service is down, and then switch to another | | On trial | Registry | -| Token authorization | Tested | Token authorization, is used for service authorization | Need support of registry | On trial | | -| Routing rule | Tested | Dynamically determining the call relationship | Need support of registry | On trial | | -| Configuration rule | Tested | Distribute the configuration dynamically, is the switch of business logic | Need support of registry | On trial | | -| Accesslog | Tested | Accesslog, used to record call information | Local storage, impact performance, limited by disk size | On trial | | -| Distributed transaction | Research | JTA/XA three phase submission transaction(TCC) | Unstable | Unavailable | | - -## Strategy maturity -| Feature | Maturity | Strength | Problem | Advise | User | -| -------------------------- | -------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | -------- | -| Zookeeper registry | Stable | Support the cluster, have various of related open source products, dubbo-2.3.3 and above versions are recommended | Depended on the stability of zookeeper | Can be used in the production environment | | -| Redis registry | Stable | Support the client - based double - write clustering method with high performance | Please ensure server time synchronization, be used to check the expired dirty data of heartbeat | Can be used in the production environment | | -| Multicast registry | Tested | Decentration, no registry needs to be installed | Depending on the network topology and routing, there is a risk across the server rooms | Can be used in a small range, in development/test environment | | -| Simple registry | Tested | Dogfooding, the registry itself is also a standard RPC service | No cluster support, may occur single-point failure | On trial | | - -| Feature | Maturity | Strength | Problem | Advise | User | -| -------------------------- | -------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | -------- | -| Simple monitor system | Stable | Support JFreeChart statistics report | No cluster support, may occur single-point failure, but the failure does not affect the RPC call | Can be used in the production environment | | - -| Feature | Maturity | Strength | Problem | Advise | User | -| -------------------------- | -------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | -------- | -| Dubbo protocol | Stable | Use NIO to reuse a single long connection and use a thread pool to process requests concurrently, Reduce handshake and increase concurrency efficiency, good performance | A single connection will become a bottleneck in the transmission of large files | Can be used in the production environment | Alibaba | -| Rmi protocol | Stable | Interoperable with native RMI, based on the TCP protocol | Occasionally the connection fails, and the stub needs to be rebuilt | Can be used in the production environment | Alibaba | -| Hessian protocol | Stable | Interoperable with native Hessian, based on the HTTP protocol | Hessian.jar support is required, and the overhead of HTTP short connections is large | Can be used in the production environment | | - -| Feature | Maturity | Strength | Problem | Advise | User | -| -------------------------- | -------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | -------- | -| Netty Transporter | Stable | The NIO framework of JBoss, has good performance | A request sends two events and needs to shield useless events | Can be used in the production environment | Alibaba | -| Mina Transporter | Stable | Classic NIO framework,stable | The dispatch of the message queue is not timely, under great pressure, there will be FullGC | Can be used in the production environment | Alibaba | -| Grizzly Transporter | Tested | The NIO framework of Sun, applied in the GlassFish container | The thread pool is not extensible, and Filter can't intercept the next filter | On trial | | - -| Feature | Maturity | Strength | Problem | Advise | User | -| -------------------------- | -------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | -------- | -| Hessian Serialization | Stable | Good performance, multilingual support (recommended) | The compatibility of various versions of Hessian is not good, it may be in conflict with the Hessian used in the application, and the Dubbo is embedded with the source code of the hessian3.2.1 | Can be used in the production environment | Alibaba | -| Dubbo Serialization | Tested | The performance is better in a large number of POJO transmission by not transmitting the class information of POJO. | When a field is added to the parameter object, an external file declaration is required | On trial | | -| Json Serialization | Tested | pure text, can be cross-language parsed, default using FastJson | Poor performance | On trial | | -| Java Serialization | Stable | Java native support | Poor performance | Can be used in the production environment | | - -| Feature | Maturity | Strength | Problem | Advise | User | -| -------------------------- | -------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | -------- | -| Javassist ProxyFactory | Stable | Bytecode generation instead of reflection, good performance(recommended) | Depending on the javassist.jar and taking up the JVM's Perm memory, the Perm may have to be larger:java -XX:PermSize=128m | Can be used in the production environment | Alibaba | -| Jdk ProxyFactory | Stable | JDK native support | Poor performance | Can be used in the production environment | | - -| Feature | Maturity | Strength | Problem | Advise | User | -| -------------------------- | -------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | -------- | -| Failover Cluster | Stable | Failure automatically switches, when failure occurs, retries other servers, usually used for read operations.(recommended) | Retry will lead to longer delays | Can be used in the production environment | Alibaba | -| Failfast Cluster | Stable | Fast failure, only one call, failure to be reported immediately, usually used for non idempotent writing. | If a server is being restarted, a call failure may occur | Can be used in the production environment | Alibaba | -| Failsafe Cluster | Stable | Failsafe, when abnormal, directly ignored, usually used to write to the audit log and other operations | Call information loss | Can be used in the production environment | Monitor | -| Failback Cluster | Tested | Failure auto recovery, backstage record failure request, regular retransmission, usually used for message notification operations | Unreliable, lost when restart the server | Can be used in the production environment | Registry | -| Forking Cluster | Tested | Multiple servers are invoked in parallel, as long as one success is returned, often used for high real-time reading operations. | Need to waste more service resources | Can be used in the production environment | | -| Broadcast Cluster | Tested | A broadcast calls all providers, one by one, and any error is wrongly reported, usually used to update the provider's local state | The speed is slow, and any false report is wrong. | Can be used in the production environment | | - -| Feature | Maturity | Strength | Problem | Advise | User | -| -------------------------- | -------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | -------- | -| Random LoadBalance | Stable | Random probability, set random probability according to weight(recommended) | The probability of a collision on a cross section is high. When retrying, there may be an unequal instantaneous pressure. | Can be used in the production environment | Alibaba | -| RoundRobin LoadBalance | Stable | Round Robin, setting wheel based ratio according to the weight after the Convention | There is a slow machine accumulation request problem, and extreme circumstances may cause an avalanche | Can be used in the production environment | | -| LeastActive LoadBalance | Stable | The least active call number, the random number of the same active number, the active number is the count difference before and after the call, making the slow machine receive less request. | Do not support the weight, in the capacity planning, not to pressure a machine oriented pressure measurement by weight capacity | Can be used in the production environment | | -| ConsistentHash LoadBalance | Stable | The consistency hash, the same parameters always request to the same provider, when one provider hung, originally sent to the provider's request, based on virtual nodes, spread to other providers, will not cause dramatic changes | Uneven distribution of pressure | Can be used in the production environment | | - -| Feature | Maturity | Strength | Problem | Advise | User | -| -------------------------- | -------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | -------- | -| Condition routing rule | Stable | Routing rules based on conditional expressions, simple and easy to use | There are some complex multi branch conditions, and the rules are difficult to describe | Can be used in the production environment | Alibaba | -| Script routing rules | Tested | Routing rules based on the script engine, powerful | No sandbox is running, scripting ability is too powerful and may be the back door | On trial | | - -| Feature | Maturity | Strength | Problem | Advise | User | -| -------------------------- | -------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | -------- | -| Spring Container | Stable | Automatically load all Spring configurations under the META-INF/spring directory | | Can be used in the production environment | Alibaba | -| Jetty Container | Stable | Start an embedded Jetty for reporting state | When a large number of pages are accessed, the threads and memory of the server are affected | Can be used in the production environment | Alibaba | -| Log4j Container | Stable | Configuring the configuration of the log4j automatically, automatically subdirecting the log files by process at the startup of multiple processes | The user can't control the configuration of log4j, inflexible | Can be used in the production environment | Alibaba | diff --git a/content/en/docs/v2.7/user/perf-test.md b/content/en/docs/v2.7/user/perf-test.md deleted file mode 100644 index c0564ea39232..000000000000 --- a/content/en/docs/v2.7/user/perf-test.md +++ /dev/null @@ -1,174 +0,0 @@ ---- -type: docs -title: "Performance" -linkTitle: "Performance" -weight: 16 -description: "Dubbo performance report" ---- - -## Test instructions - -0. In this performance test, the performance of all Dubbo 2.0 supported protocols in different sizes and data types is tested and compared with the Dubbo 1.0. -1. The overall performance is increased by 1.0 compared with 10%, and the average increase is 10%. The performance improvement of 10%~50% can also be achieved by using the new Dubbo serialization of Dubbo 2.0 . -2. In the stability test, because the underlying communication framework is changed from Mina to netty, the growth of objects in old area is greatly reduced, and the 50 hour operation increases less than 200m and no fullgc. -3. There is a problem: performance of 2.0 is less than 1.0 in 50K data, and it is doubted that it may be a buffer setting problem, and the next version will be further confirmed. - -## Test environment - -### Hardware deployment and parameter adjustment - -| Model | CPU | Memory | Network | Disk | Kernel | -| ----------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | ------------------ | ------------------------ | -| Tecal BH620 | model name : Intel(R) Xeon(R) CPU E5520 @ 2.27GHz cache size : 8192 KB processor_count : 16 | Total System Memory: 6G Hardware Memory Info: Size: 4096MB | eth0: Link is up at 1000 Mbps, full duplex. peth0: Link is up at 1000 Mbps, full duplex. | /dev/sda: 597.9 GB | 2.6.18-128.el5xen x86_64 | - -### Software architecture - -| Software name and version | key parameter | -| ---------------------------------------- | ---------------------------------------- | -| java version "1.6.0_18" Java(TM) SE Runtime Environment (build 1.6.0_18-b07) Java HotSpot(TM) 64-Bit Server VM (build 16.0-b13, mixed mode) | -server -Xmx2g -Xms2g -Xmn256m -XX:PermSize=128m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 | -| jboss-4.0.5.GA | | -| httpd-2.0.61 | KeepAlive On MaxKeepAliveRequests 100000 KeepAliveTimeout 180 MaxRequestsPerChild 1000000 StartServers 5 MaxClients 1024 MinSpareThreads 25 MaxSpareThreads 75 ThreadsPerChild 64 ThreadLimit 128 ServerLimit 16 | - -## Test purpose - -### Expected performance indicators (quantized) - -| Scene name | Corresponding index name | Range of expected values | Actual value | Whether or not to meet expectations (yes / no) | -| ---------- | ------------------------ | ------------------------ | ------------ | ---------------------------------------- | -| 1k data | Response time | 0.9ms | 0.79ms | Yes | -| 1k data | TPS | 10000 | 11994 | Yes | - -### Expected operating conditions (non quantified, optional) - -* The performance of 2.0 is not less than 1, and the performance of the intermodulation of 2.0 and 1.0 is not significantly reduced. In addition to 50K string, the rest are passed -* JVM memory is running stable, no OOM, and there is no reasonable large object in the heap memory. Passed -* CPU, memory, network, disk, file handle are occupied smoothly. Passed -* There is no frequent thread lock, and the number of threads is stable. Passed -* Business thread load balance. Passed - -## Test script - -0. Performance test scence (10 concurrency) - * Pass in 1K String, do not do anything, return the original - * Pass in 50K String, do not do anything, return the original - * Pass in 200K String, do not do anything, return the original - * Incoming 1K POJO (nested complex person objects) without any processing, return to the original - - The above scenario is tested for 10 minutes in Dubbo 1.0, Dubbo 2.0 (hessian2 serialization), Dubbo 2.0 (Dubbo serialization), RMI, Hessian 3.2.0, HTTP (JSON serialization). It mainly examines the performance of serialization and network IO, so the server has no business logic. 10 is to consider the concurrent HTTP protocol in high with the use of CPU high rate may hit the bottleneck. -1. Concurrent scene (20 concurrency) - 1K String is introduced into the server segment for 1W times, and a random number is regenerated each time and then assembled. Examine whether business threads can be assigned to each CPU. - -2. Stability scence (20 concurrency) - At the same time, we call the 1 parameter String (5K) method, the 1 parameter is the person object method, the 1 parameter is map (the value is 3 person), and it runs for 50 hours continuously. - -3. High pressure scene (20 concurrency) - On the basis of the stability scenario, the providers and consumers are arranged into 2 sets (one machine and 2 instances), and the parameters of String are 20byte to 200K, and are randomly transformed every 10 minutes. - -## Test result - -### Scene name: scence POJO - -| | TPS success avg value | Response time avg value(ms) | -| ---------------------------------------- | --------------------- | --------------------------- | -| dubbo1 (hessian2 serialization+mina) | 10813.5 | 0.9 | -| dubbo2 (hessian2 serialization+netty) | 11994 | 0.79 | -| dubbo2 (dubbo serialization+netty) | 13620 | 0.67 | -| rmi | 2461.79 | 4 | -| hessian | 2417.7 | 4.1 | -| http(json serialization) | 8179.08 | 1.15 | -| The default percentage of 2.0 and 1.0 | 10.92 | -12.22 | -| Dubbo serialization compared to the percentage of hessian2 serialization | 13.56 | -15.19 | - -POJO TPS - -![pojotps.png](/imgs/user/pojotps.png) - -POJO Response - -![pojores.png](/imgs/user/pojores.png) - -### Scene name: scence 1k string - -| | TPS success avg value | Response time avg value(ms) | -| ---------------------------------------- | --------------------- | --------------------------- | -| dubbo1(hessian2 serialization+mina) | 11940 | 0.8 | -| dubbo2 (hessian2 serialization+netty) | 14402 | 0.64 | -| dubbo2 (dubbo serialization+netty) | 15096 | 0.6 | -| rmi | 11136.02 | 0.81 | -| hessian | 11426.83 | 0.79 | -| http(json serialization) | 8919.27 | 1.04 | -| The default percentage of 2.0 and 1.0 | 20.62 | -20.00 | -| Dubbo serialization compared to the percentage of hessian2 serialization | 4.82 | -6.25 | - -1k TPS - -![1ktps.png](/imgs/user/1ktps.png) - -1k Response - -![1kres.png](/imgs/user/1kres.png) - -### Scene name: scence 50k string - -| TPS success avg value | Response time avg value(ms) | -| ---------------------------------------- | --------------------------- | -| dubbo1(hessian2 serialization+mina | 1962.7 | -| dubbo2 (hessian2 serialization+netty) | 1293 | -| dubbo2 (dubbo serialization+netty) | 1966 | -| rmi | 3349.88 | -| hessian | 1925.33 | -| http(json serialization) | 3247.1 | -| The default percentage of 2.0 and 1.0 | -34.12 | -| Dubbo serialization compared to the percentage of hessian2 serialization | 52.05 | - -50K TPS - -![50ktps.png](/imgs/user/50ktps.png) - -50K Response - -![50kres.png](/imgs/user/50kres.png) - - -### Scene name: scence 200k string - -| TPS success avg value | Response time avg value(ms) | -| ---------------------------------------- | --------------------------- | -| dubbo1(hessian2 serialization+mina) | 324.2 | -| dubbo2 (hessian2 serialization+netty) | 362.92 | -| dubbo2 (dubbo serialization+netty) | 569.5 | -| rmi | 1031.28 | -| hessian | 628.06 | -| http(json serialization) | 1011.97 | -| The default percentage of 2.0 and 1.0 | 11.94 | -| Dubbo serialization compared to the percentage of hessian2 serialization | 56.92 | - -200K TPS - -![200ktps.png](/imgs/user/200ktps.png) - -**200K Response** - -![200kres.png](/imgs/user/200kres.png) - -## Test analysis - -### Performance analysis and evaluation - -The performance test conclusion of Dubbo 2 has been improved and improved from performance, memory footprint and stability. Because of its memory management, the change of Mina into netty greatly reduces the 1 version of the large memory sawtooth in high concurrency and large data. - -### Performance comparison analysis (new and old environment, different data magnitude, etc.) - -The performance of Dubbo 2 is compared with that of Dubbo 1, which is all hessian2 serialization. The performance is improved (except for 50K String). See the performance data of the fifth chapter in detail. - -For compatibility default serialization and 1 consistent with hessian2, such as have higher requirements on the performance of Dubbo serialization can be used, which is in the process of complicated object, can be obtained in 50% large data upgrade (but it is not recommended for use Dubbo protocol). - -The purpose of Dubbo is to meet the RPC calls with high concurrent and small data volume. The performance is not good under large data volume. It is recommended to use RMI or HTTP protocol. - -### Test limitation analysis (optional) - -This performance test examines the performance of the Dubbo itself, and the performance of the actual use needs to be verified. - -Because the performance of Dubbo itself is in millisecond and the base number is small, performance improvement may not change the performance of the application as a whole. - -All the monitoring charts are not listed because of the limit of length. \ No newline at end of file diff --git a/content/en/docs/v2.7/user/preface/_index.md b/content/en/docs/v2.7/user/preface/_index.md deleted file mode 100755 index bddecaa49d4f..000000000000 --- a/content/en/docs/v2.7/user/preface/_index.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "Preface" -linkTitle: "Preface" -weight: 1 -description: "Dubbo Preface" ---- - diff --git a/content/en/docs/v2.7/user/preface/architecture.md b/content/en/docs/v2.7/user/preface/architecture.md deleted file mode 100644 index d85f9fe5a844..000000000000 --- a/content/en/docs/v2.7/user/preface/architecture.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -type: docs -title: "Architecture" -linkTitle: "Architecture" -weight: 3 -description: "Dubbo Architecture" ---- - - -![dubbo-architucture](/imgs/user/dubbo-architecture.jpg) - -##### Specification of Node's Role - -| Node | Role Spec | -| ------------- | ------------- | -| `Provider` | The provider exposes remote services | -| `Consumer` | The consumer calls the remote services | -| `Registry` | The registry is responsible for service discovery and configuration | -| `Monitor` | The monitor counts the number of service invocations and time-consuming | -| `Container` | The container manages the services's lifetime | - -##### Service relationship - -0. `Container` is responsible for launching, loading, and running the service `Provider`. -1. `Provider` registers its services to `Register` at the time it starts. -2. `Consumer` subscribes the services it needs from the `Register` when it starts. -3. `Register` returns the `Provider`s list to `Consumer`, when it changes, the `Register` will push the changed data to `Consumer` through long connection. -4. `Consumer` selects one of the `Provider`s based on soft load balancing algorithm and executes the invocation, if fails, it will choose another `Provider`. -5. Both `Consumer` and `Provider` will count the number service invocations and time-consuming in memory, and send the statistics to `Monitor` every minute. - -Dubbo has the following features: Connectivity, Robustness, Scalability and Upgradeability. - -## Connectivity - -* `Register` is responsible for the registration and search of service addresses, like directory services, `Provider` and `Consumer` only interact with the registry during startup, and the registry does not forward requests, so it is less stressed -* 'Monitor' is responsible for counting the number of service invocations and time-consuming, the statistics will assembles in `Provider`'s and `Consumer`'s memory first and then sent to `Monitor` -* 'Provider' registers services to 'Register' and report time-consuming statistic(not include network overhead) to 'Monitor' -* 'Consumer' gets a list of service provider addresses from `Registry`, call the provider directly according to the LB algorithm, report the time-consuming statistic to `Monitor`, which includes network overhead -* The connections between `Register`, `Provider` and `Consumer` are long connections, `Moniter` is an exception -* `Register` is aware of the existence of `Provider` through the long connection, when `Provider` gets down, `Register` will push the event to `Consumer` -* It doesn't affect the already running instances of `Provider` and `Consumer` even all of the `Register` and `Monitor` get down, since `Consumer` got a cache of `Provider`s list -* `Register` and `Monitor` are optional, `Consumer` can connect `Provider` directly - -## Robustness - -* `Monitor`'s downtime doesn't affect the usage, only lose some sampling data -* When the DB server goes down, `Register` can return service `Provider`s list to `Consumer` by checking its cache, but new `Provider` cannot register any services -* `Register` is a peer cluster, it will automatically switch to another when any instance goes down -* Even all `Register`'s instances go down, `Provider` and `Consumer` can still conmunicate by checking their local cache -* Service `Provider`s are stateless, one instance's downtime doesn't affect the usage -* After all the `Provider`s of one service go down, `Consumer` can not use that service, and infinitely reconnect to wait for service `Provider` to recover - -## Scalability - -* `Register` is a peer cluster that can dynamically increases its instances, all clients will automatically discover the new instances. -* `Provider` is stateless, it can dynamically increases the deployment instances, and the registry will push the new service provider information to the `Consumer`. - -## Upgradeablity - -When the service cluster is further expanded and the IT governance structure is further upgraded, dynamic deployment is needed, and the current distributed service architecture will not bring resistance. Here is a possible future architecture: - -![dubbo-architucture-futures](/imgs/user/dubbo-architecture-future.jpg) - -##### Specification of Node's Role - -| Node | Role Spec | -| ------------- | ------------- | -| `Deployer ` | Local proxy for automatic services deployment | -| `Repository` | The repository is used to store application packages | -| `Scheduler` | The scheduler automatically increases or decreases service providers based on the access pressure | -| `Admin` | Unified management console | -| `Registry` | the registry is responsible for service discovery and configuration | -| `Monitor` | The monitor counts the service call times and time-consuming | diff --git a/content/en/docs/v2.7/user/preface/background.md b/content/en/docs/v2.7/user/preface/background.md deleted file mode 100644 index ffd04a19bd19..000000000000 --- a/content/en/docs/v2.7/user/preface/background.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -type: docs -title: "Background" -linkTitle: "Background" -weight: 1 -description: "Why use dubbo" ---- - -# Background - -With the fast development of Internet, the scale of web applications expands unceasingly, and finally we find that the traditional vertical architecture(monolithic) can not handle this any more. Distributed service architecture and the flow computing architecture are imperative, and a governance system is urgently needed to ensure an orderly evolution of the architecture. - -![image](/imgs/user/dubbo-architecture-roadmap.jpg) - -#### Monolithic architecture - -When the traffic is very low, there is only one application, all the features are deployed together to reduce the deployment node and cost. At this point, the data access framework (ORM) is the key to simplifying the workload of the CRUD. - -#### Vertical architecture - -When the traffic gets heavier, add monolithic application instances can not accelerate the access very well, one way to improve efficiency is to split the monolithic into discrete applications. At this point, the Web framework (MVC) used to accelerate front-end page development is the key. - -#### Distributed service architecture - -When there are more and more vertical applications, the interaction between applications is inevitable, some core businesses are extracted and served as independent services, which gradually forms a stable service center,this way the front-end application can respond to the changeable market demand more quickly. At this point, the distributed service framework (RPC) for business reuse and integration is the key. - -#### Flow computing architecture - -When there are more and more services, capacity evaluation becomes difficult, and also services with small scales often causes waste of resources. To solve these problems, a scheduling center should be added to manage the cluster capacity based on traffics and to improve the utilization of the cluster. At this time, the resource scheduling and governance centers (SOA), which are used to improve machine utilization, are the keys. diff --git a/content/en/docs/v2.7/user/preface/requirements.md b/content/en/docs/v2.7/user/preface/requirements.md deleted file mode 100644 index 692939e87e6f..000000000000 --- a/content/en/docs/v2.7/user/preface/requirements.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -type: docs -title: "Requirements" -linkTitle: "Requirements" -weight: 1 -description: "Basic requirements of Dubbo" ---- - -# Requirements - -![image](/imgs/user/dubbo-service-governance.jpg) - -Before the advent of large-scale services, an application might just exposes or references remote service by using RMI or Hessian, the call is done by configuring service URL, and load balance is done through hardwares, like F5. - -**When there are more and more services, it becomes very difficult to configure the service URL, the single point pressure of F5 hardware load balancer is also increasing.** At this point, a service registry is needed to dynamically register and discover services to make the service's location transparent. By obtaining the list of service provider addresses in the consumer side, the soft load balancing and Failover can be realized, this reduces the dependence on the F5 hardware load balancer and some of the costs. - -**When things go further, the service dependencies become so complex that it can't even tell which applications to start before, even the architect can't fully describe the application architecture relationships**. At this time, automatically draw the dependency diagram of the applications is needed to help the architect to be clear of the relationship. - -**Then, the traffic becomes even heavier, the capacity problem of the service is exposed, how many machines are needed to support this service? When should the machine be added?** To solve these problems, first, the daily service calls and the amount of response time should be counted as a reference for capacity planning. Second, dynamically adjust the weight, increase the weight of an online machine, and recorded the response time changes until it reaches the threshold, record the visits times at this time, then multiply this number of visits by the total number of machines to calculate the capacity in turn. - -Above are the most basic requirements of Dubbo. diff --git a/content/en/docs/v2.7/user/preface/usage.md b/content/en/docs/v2.7/user/preface/usage.md deleted file mode 100644 index 07f42f352b3a..000000000000 --- a/content/en/docs/v2.7/user/preface/usage.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -type: docs -title: "Usage" -linkTitle: "Usage" -weight: 4 -description: "First glance at dubbo" ---- - - -## Spring configuration of local service - -local.xml: - -```xml - - - - -``` - -## Spring configuration of remote service - -The remote configuration can be done by very little change based on the local configuration: - -* split the `local.xml` into two part, put the service define part into `remote-privider.xml`(exists in the provider node), meanwhile the refrence part into `remote-consumer.xml`(exists in the consumer node). -* add `` to the provider's configuration, and `` to the consumer's configuration. - -remote-provider.xml: - -```xml - - - - -``` - -remote-consumer.xml: - -```xml - - - - - - -``` diff --git a/content/en/docs/v2.7/user/quick-start.md b/content/en/docs/v2.7/user/quick-start.md deleted file mode 100644 index 5c16a607e159..000000000000 --- a/content/en/docs/v2.7/user/quick-start.md +++ /dev/null @@ -1,257 +0,0 @@ ---- -type: docs -title: "Quick start" -linkTitle: "Quick start" -weight: 2 -description: "Quick start to use Dubbo" ---- - -The most common way to use Dubbo is to run it in Spring framework. The following content will guide you to develop a Dubbo application with Spring framework's [XML configuration](https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/xsd-configuration.html). - -If you don't want to rely on Spring, you can try using [API configuration](../configuration/api). - -First let's create a root directory called dubbo-demo: - -```shell script -mkdir dubbo-demo -cd dubbo-demo -``` - -Next, we are going to create 3 sub-directories under root directory: - -* dubbo-demo-api: the common service api -* dubbo-demo-provider: the demo provider codes -* dubbo-demo-consumer: the demo consumer codes - -## Service provider - -### Defining service interfaces - -DemoService.java [^1]: - -```java -package org.apache.dubbo.demo; - -public interface DemoService { - String sayHello(String name); - -} -``` - -The project structure should look like this: - -```shell script -. -├── dubbo-demo-api -│   ├── pom.xml -│   └── src -│   └── main -│   └── java -│   └── org -│   └── apache -│   └── dubbo -│   └── demo -│   └── DemoService.java -``` - -### Implement interface in service provider - -DemoServiceImpl.java [^2]: - -```java -package org.apache.dubbo.demo.provider; -import org.apache.dubbo.demo.DemoService; - -public class DemoServiceImpl implements DemoService { - public String sayHello(String name) { - return "Hello " + name; - } -} -``` - -### Exposing service with Spring configuration - -provider.xml: - -```xml - - - - - - - - - - - - - -``` - -The demo uses multicast as the registry since it is simple and does not require to extra installation. -If you prefer a registry like zookeeper, please check out examples [here](https://github.com/dubbo/dubbo-samples). - -### Configure the logging system - -Dubbo use log4j as logging system by default, it also support slf4j, Apache Commons Logging, and JUL logging. - -Following is a sample configuration: - -log4j.properties - -```properties -###set log levels### -log4j.rootLogger=info, stdout -###output to the console### -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n -``` - -### Bootstrap the service provider - -Provider.java - -```java -package org.apache.dubbo.demo.provider; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -public class Provider { - - public static void main(String[] args) throws Exception { - System.setProperty("java.net.preferIPv4Stack", "true"); - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-provider.xml"}); - context.start(); - System.out.println("Provider started."); - System.in.read(); // press any key to exit - } -} -``` - -Finally, the project structure should look like this: - -```shell script -├── dubbo-demo-provider -│   ├── pom.xml -│   └── src -│   └── main -│   ├── java -│   │   └── org -│   │   └── apache -│   │   └── dubbo -│   │   └── demo -│   │   └── provider -│   │   ├── DemoServiceImpl.java -│   │   └── Provider.java -│   └── resources -│   ├── META-INF -│   │   └── spring -│   │   └── dubbo-demo-provider.xml -│   └── log4j.properties -``` - -## Service consumer - -Complete installation steps, see:[Consumer demo installation](../../admin/install/consumer-demo) - -### Using the Spring configuration to reference a remote service - -consumer.xml: - -```xml - - - - - - - - - - -``` - -### Bootstrap the consumer - -Consumer.java [^3]: - -```java -import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.apache.dubbo.demo.DemoService; - -public class Consumer { - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"META-INF/spring/dubbo-demo-consumer.xml"}); - context.start(); - // Obtaining a remote service proxy - DemoService demoService = (DemoService)context.getBean("demoService"); - // Executing remote methods - String hello = demoService.sayHello("world"); - // Display the call result - System.out.println(hello); - } -} -``` - -### Config the logging system - -This is the same as how to config it on provider side. - -Finally, the project structure should be look like this: - -```shell script -├── dubbo-demo-consumer -│   ├── pom.xml -│   └── src -│   └── main -│   ├── java -│   │   └── org -│   │   └── apache -│   │   └── dubbo -│   │   └── demo -│   │   └── consumer -│   │   └── Consumer.java -│   └── resources -│   ├── META-INF -│   │   └── spring -│   │   └── dubbo-demo-consumer.xml -│   └── log4j.properties -``` - -## Start the demo - -### Start service provider - -Run the `org.apache.dubbo.demo.provider.Provider` class to start the provider. - -### Start service consumer - -Run the `org.apache.dubbo.demo.provider.Consumer` class to start the consumer, and you should be able to see the following result: - -```shell script -Hello world -``` - -## Complete example - -You can find the complete example code in the Github repository. - -* [Provider demo](../../admin/install/provider-demo) -* [Consumer demo](../../admin/install/consumer-demo) - -[^1]: The interface needs to be packaged separately, shared by the service provider and the consumer -[^2]: Hidden realization for service consumer -[^3]: IoC injection can also be used \ No newline at end of file diff --git a/content/en/docs/v2.7/user/recommend.md b/content/en/docs/v2.7/user/recommend.md deleted file mode 100644 index cd996f8c2be8..000000000000 --- a/content/en/docs/v2.7/user/recommend.md +++ /dev/null @@ -1,175 +0,0 @@ ---- -type: docs -title: "Recommended usage" -linkTitle: "Recommended usage" -weight: 14 -description: "Recommended usage for use dubbo" ---- - -## Configuring the attributes of the consumer side as much as possible on the provider side - -the reason is: - -* Service providers are more aware of service performance parameters than service users,Such as the timeout time of the call, the reasonable retry times, and so on. -* If a attribute is configurated in provider side, not configurated in consumer side, consumer service will use the attribute in provider side. That is to say, the provider side's attribute can be used as consumer's default value [^1]. Otherwise, consumer service will use consumer-side's attribute,but can't cnotrol the provider service,it's usually unreasonable. - -Configuring the attributes of the consumer side as much as possible on the provider side,Make the provider service developer think more about the characteristics and quality of the provider side service. - -Examples: - -```xml - - - - - -``` - -The consumer side properties that can be configured on provider are: - -0. `timeout` Method call timeout -1. `retries` The number of failed retries, default value is 1 [^2] -2. `loadbalance` Load balance algorithm [^3],default algorithm is random `random`,and polling `roundrobin`、least active [^4] `leastactive` -3. `actives` Consumer side, maximum concurrent call limitation. That is , when the concurrent requests of consumer service reach maximum configuration,the new call will wait until to catch a timeout error. - Configurated in `dubbo:method`(method level configuration) , then the concurrent limitation point at method.Configurated in `dubbo:service`(service level configuration),then the concurrent limitation point at service. - -Detailed configuration instructions see:[Dubbo configuration introduction](../references/xml/) - -## Configuring reasonable provider end properties on provider - -```xml - - - - -``` - -The provider side properties that can be configured on provider service are: - -0. `threads` service thread pool size -1. `executes` If concurrent requests number that a provider service handled reach the maximum thead pool count , the new call will wait,then the consumer call may catch a timeout error. Configurated in `dubbo:method`(method level configuration) , then the concurrent limitation point at method.Configurated in `dubbo:service`(service level configuration),then the concurrent limitation point at service. - -## Configuration management information - -Now we have the owner information and organization infomation to differentiate the sites。It's easy to contact with the service owners when there is a problem, please write at least two persons for backup. The information of owners and organizations can be seen in the registry. - -application configuration owners,organizations: - -```xml - -``` - -service configuration owners: - -```xml - -``` - -reference configuration owners: - -```xml - -``` - -`dubbo:service`、`dubbo:reference` have no configuration owner, then use the owner configured in `dubbo:application`. - -## Set up the Dubbo cache file - -Provider service list caching file: - -```xml - -``` - -Notations: - -0. You can modify the cahe file path of the application according to the needs. Ensure that the file will not be cleared during the release process. -1. If there are more than one application process, do not use the same file path to avoid the content being overwritten. - -This file caches the list of the registry and the list of service providers. With this configuration, when the application is restarted , if the Dubbo registry is not available, the application will read the information from the service provider list from the cache file. That can ensure the availability of the application. - -## Monitor configuration - -0. Expose service with a fixed port, instead of using a random port - - - In this way, when there is a delay in the registry push, the consumer can also call the original provider service address hrough the cache list and succeed。 - -1. Use Dragoon's HTTP monitoring item to monitor the service provider on the registry - - The state of Dragoon monitoring service in the registry : `http://dubbo-reg1.hst.xyi.cn.alidc.net:8080/status/com.alibaba.morgan.member.MemberService:1.0.5` Ensure that the service exists on the registry . - -2. Service provider,use Dragoon's telnet mommand or shell monitor command - - Monitoring service provider port status :`echo status | nc -i 1 20880 | grep OK | wc -l`, 20880 is the service port - -3. Service consumer side, cast the service to EchoService,and call `$echo()` to test whether the provider of the service is available - - eg: `assertEqauls(“OK”, ((EchoService)memberService).$echo(“OK”));` - -## Don't use the configuration of dubbo.properties file, suggeset to use the configuration of XML - -All of the configuration items in the dubbo can be configured in the spring configuration file,and can be configured for a single service. - -The Dubbo default value is used if completely not set up , please see the instructions in the article [Dubbo configuration introduction](../references/xml/) . - -### The relation between attribute name of dubbo.properties and XML - -0. application name `dubbo.application.name` - - ```xml - - ``` - -1. registry address `dubbo.registry.address` - - ```xml - - ``` - -2. call timeout `dubbo.service.*.timeout` - - Timeout can be set in multiple configuration items `timeout`,cover from top to bottom (The top one have a higher priority )[^5],The coverage strategy of other parameters(`retries`、`loadbalance`、`actives` and so on)is: - - Certain method Configuration of a provider service - - ```xml - - - - ``` - - Configuration of a provider specific interface - - ```xml - - ``` - -3. Service provider protocol `dubbo.service.protocol`、Service monitor port `dubbo.service.server.port` - - ```xml - - ``` - -5. Service thread pool size `dubbo.service.max.thread.threads.size` - - ```xml - - ``` - -6. No provider throws exceptions (Fast-Fail) when the consumer is started () - `alibaba.intl.commons.dubbo.service.allow.no.provider` - - ```xml - - ``` - -[^1]: Overlay rules for configuration: 1) The method level configuration has a higher priority than the interface level, that is to say,small scope have a high priority 2) Consumer side configuration has a higher priority than provider side, better than global configuration, the last one is the Dubbo hard coded configuration value([Dubbo configuration introduction](/en/docs/v2.7/user/configuration/properties/)) -[^2]: With the first call, the call will be called 3 times -[^3]: How to select a service to call when there are multiple Provider services -[^4]: It means that consumer service can call the best provider service, and reduce to call the the slow provider service. -[^5]: `timeout` Can be set in multiple places, configuration items and overlay rules: [Dubbo Schema configuration introduction](../references/xml/) \ No newline at end of file diff --git a/content/en/docs/v2.7/user/references/_index.md b/content/en/docs/v2.7/user/references/_index.md deleted file mode 100644 index 477d3d5269c7..000000000000 --- a/content/en/docs/v2.7/user/references/_index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: docs -title: "References" -linkTitle: "References" -weight: 7 -description: "References documentation for all dubbo features" ---- \ No newline at end of file diff --git a/content/en/docs/v2.7/user/references/api.md b/content/en/docs/v2.7/user/references/api.md deleted file mode 100644 index 77324fed1e1e..000000000000 --- a/content/en/docs/v2.7/user/references/api.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -type: docs -title: "API Reference" -linkTitle: "API" -weight: 7 -description: "References documentation for dubbo API" ---- - -Generally speaking, dubbo keeps its functionality no intrusive as much as possible, but for some particular features, there's no other way not only API can achieve. -{{% alert title="Warning" color="warning" %}} -Do not rely on APIs other than what're mentioned here, otherwise your application may face the risk of incompatibility after upgrade dubbo. -{{% /alert %}} -These APIs are summarized here below: - -## Configuration API - -``` -org.apache.dubbo.config.ServiceConfig -org.apache.dubbo.config.ReferenceConfig -org.apache.dubbo.config.ProtocolConfig -org.apache.dubbo.config.RegistryConfig -org.apache.dubbo.config.MonitorConfig -org.apache.dubbo.config.ApplicationConfig -org.apache.dubbo.config.ModuleConfig -org.apache.dubbo.config.ProviderConfig -org.apache.dubbo.config.ConsumerConfig -org.apache.dubbo.config.MethodConfig -org.apache.dubbo.config.ArgumentConfig -``` - -Pls. refer to [API Configuration](../../configuration/api) for further information. - -## Annotation API - -``` -org.apache.dubbo.config.annotation.Service -org.apache.dubbo.config.annotation.Reference -``` - -Pls. refer to [Annotation Configuration](../../configuration/annotation) for further information. - -## Model API - -``` -org.apache.dubbo.common.URL -org.apache.dubbo.rpc.RpcException -``` - -## Context API - -``` -org.apache.dubbo.rpc.RpcContext -``` - -Pls. refer to [context](../../examples/context) & [pass parameter in attachment](../../examples/attachment) & [asynchronous call](../../examples/async-call) for further information. - -## Service API - -``` -org.apache.dubbo.rpc.service.GenericService -org.apache.dubbo.rpc.service.GenericException -``` - -Pls. refer to [generic reference](../../examples/generic-reference) & [generic service](../../examples/generic-service) for further information. - -``` -org.apache.dubbo.rpc.service.EchoService -``` -Pls. refer to [test via echo service](../../examples/echo-service) for further details. - diff --git a/content/en/docs/v2.7/user/references/maven.md b/content/en/docs/v2.7/user/references/maven.md deleted file mode 100644 index 61668975863f..000000000000 --- a/content/en/docs/v2.7/user/references/maven.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -type: docs -title: "Maven Plugin Reference" -linkTitle: "Maven" -weight: 12 -description: "Maven plugin reference in dubbo" ---- - -## Start a simple registry server - -Start a simple registry server listening on port 9099: - -{{% alert title="Info" color="primary" %}} -Default port is 9090 if the port is not specified -{{% /alert %}} - -```bash -mvn dubbo:registry -Dport=9099 -``` - -## Generate a service provider demo application - -Generate a service provider with the specified interface and version: - -```bash -mvn dubbo:create -Dapplication=xxx -Dpackage=com.alibaba.xxx -Dservice=XxxService,YyyService -Dversion=1.0.0 -``` diff --git a/content/en/docs/v2.7/user/references/metadata.md b/content/en/docs/v2.7/user/references/metadata.md deleted file mode 100644 index fc48f71b3f01..000000000000 --- a/content/en/docs/v2.7/user/references/metadata.md +++ /dev/null @@ -1,382 +0,0 @@ ---- -type: docs -title: "Metadata Reference" -linkTitle: "Metadata" -weight: 5 -description: "References documentation for dubbo metadata" ---- - -## Background -There are close to [30 configurations](/en/docs/v2.7/user/references/xml/dubbo-service/) in dubbo provider. Excluding registry center governance requirements, a large part of configurations are used by the provider itself and do not need to be delivered to the consumer. This part of the data does not need to be written to the registry, but only needs to be persisted as key-value. -There are also [20+ configurations](/en/docs/v2.7/user/references/xml/dubbo-reference/) in dubbo consumer. In the registry center, only a few configurations such as application, version, group, ip, dubbo version are needed in the list of service consumers. Other configurations can also be persisted in key-value form. -This data is registered into the registry in the service dimension, which leads to the expansion of data volume, and then causes the increased network overhead of the registry (such as zookeeper) and decreased performance. - -In addition to the storage of the above configuration items, Dubbo service metadata information also needs to be stored. Metadata information includes service interface and method information of interface. This information will be used for service mock, service test. - -## Goal - -The original data and metadata information in the registry center need to be stored in a separate key-value store, which can be DB, redis or other persistent storage. The core code supports zookeeper, redis(recommended) by default. - -The format of provider storage content is the storage after gson's serialization of org.apache.dubbo.metadata.definition.model.FullServiceDefinition. -Consumer gets parameter information from the URL that it wrote to the registry and stores it in Map. That is, get the Map with URL.getParameterMap() and store it after gson's serialization. - -For more details, you can refer to the sample below. - -## Configuration - -The default metadata storage supports the following additional features: -* Failed retry -* Refresh regularly - -#### Failed retry -Failed retries can be configured by retrytimes (retry times, default 100), retryperiod (retry cycle, default 3000ms). - -#### Refresh regularly -It's opening by default and can be turned off by setting cycleReport=false. - -#### Complete configurations: - -```properties -dubbo.metadata-report.address=zookeeper://127.0.0.1:2181 -dubbo.metadata-report.username=xxx ##Not necessary -dubbo.metadata-report.password=xxx ##Not necessary -dubbo.metadata-report.retry-times=30 ##Not necessary,default 100 -dubbo.metadata-report.retry-period=5000 ##Not necessary,default 3000 -dubbo.metadata-report.cycle-report=false ##Not necessary,default true -``` -> If the metadata address (dubbo.metadata-report.address) is not configured, the writing of the entire metadata will not take effect, but it will not affect the running of the program. - - -Let's look at a few sample configurations. Regardless of the configuration, some maven dependencies need to be introduced: - -```xml - - org.apache.dubbo - dubbo-metadata-report-zookeeper - -``` -If redis is needed, the corresponding redis dependencies can be introduced: - -```xml - - org.apache.dubbo - dubbo-metadata-report-redis - -``` -> **Complete sample,refer to[sample-2.7](https://github.com/dubbo/dubbo-samples/tree/master)** - -### Method 1: Config in Configcenter - -Refer to the sample: dubbo-samples-metadata-report/dubbo-samples-metadata-report-configcenter. - -##### Configcenter Configuration - -Configurations of Configcenter,can refer to the document of Configcenter. As follows: - -```properties -dubbo.registry.address=zookeeper://127.0.0.1:2181 -### Notice the hump style -dubbo.metadata-report.address=zookeeper://127.0.0.1:2181 ###Address of metadata storage -``` -In the sample, Zookeeper is used as the Configcenter. Run directly: org.Apache.Dubbo.Samples.Metadatareport.Configcenter.ZKTools after starting a local zookeeper service, then writing finished. -You can also use Nacos, Apollo as the Configcenter. These products themselves support ops configuration. - -##### Application Configuration - -```properties -###dubbo.properties -dubbo.config-center.address=zookeeper://127.0.0.1:2181 -... -``` - -After completing the above two steps, the registry address and metadata address are retrieved from the Configcenter. You can now run the Provider and the Consumer in turn and get the corresponding output in console or view it directly through the client of zookeeper. - -##### Provider Configuration - -The metadata stored on the Provider side is as follows: - -```json -{ - "parameters": { - "side": "provider", - "methods": "sayHello", - "dubbo": "2.0.2", - "threads": "100", - "interface": "org.apache.dubbo.samples.metadatareport.configcenter.api.AnnotationService", - "threadpool": "fixed", - "version": "1.1.1", - "generic": "false", - "revision": "1.1.1", - "valid": "true", - "application": "metadatareport-configcenter-provider", - "default.timeout": "5000", - "group": "d-test", - "anyhost": "true" - }, - "canonicalName": "org.apache.dubbo.samples.metadatareport.configcenter.api.AnnotationService", - "codeSource": "file:/Users/cvictory/workspace/work-mw/dubbo-samples/dubbo-samples-metadata-report/dubbo-samples-metadata-report-configcenter/target/classes/", - "methods": [{ - "name": "sayHello", - "parameterTypes": ["java.lang.String"], - "returnType": "java.lang.String" - }], - "types": [{ - "type": "java.lang.String", - "properties": { - "value": { - "type": "char[]" - }, - "hash": { - "type": "int" - } - } - }, { - "type": "int" - }, { - "type": "char" - }] -} - -``` -The Provider side stores all the parameters that the Provider service fills in to the registry, as well as the method information of the service (method name, input and output format). - -##### Consumer Configuration - -```json -{ - "valid": "true", - "side": "consumer", - "application": "metadatareport-configcenter-consumer", - "methods": "sayHello", - "default.timeout": "6666", - "dubbo": "2.0.2", - "interface": "org.apache.dubbo.samples.metadatareport.configcenter.api.AnnotationService", - "version": "1.1.1", - "revision": "1.1.1", - "group": "d-test" -} -``` - -The Consumer side stores all the parameters that the Consumer fills in to the registry. - - - -The above example is mainly a presentation of the provider side service information and consumer side service information stored in the metadata area by placing the metadata address in the Configcenter. -The next two examples focus on configuring in a project: the XML mode and the annotation mode . - -### Method 2: Config project in properties way - -Refer to the sample: dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-xml. - -##### dubbo.properties - -```properties -dubbo.metadata-report.address=zookeeper://127.0.0.1:2181 -``` - -After setting this configuration, have not to focus on others. You can also view the service information of the corresponding provider and consumer directly. - -##### Provider stores: - -```json -{ - "parameters": { - "valid": "true", - "async": "true", - "side": "provider", - "application": "metadatareport-local-xml-provider", - "methods": "sayHello", - "dubbo": "2.0.2", - "interface": "org.apache.dubbo.samples.metadatareport.local.xml.api.DemoService", - "generic": "false", - "anyhost": "true" - }, - "canonicalName": "org.apache.dubbo.samples.metadatareport.local.xml.api.DemoService", - "codeSource": "file:/Users/cvictory/workspace/work-mw/dubbo-samples/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-xml/target/classes/", - "methods": [{ - "name": "sayHello", - "parameterTypes": ["java.lang.String"], - "returnType": "java.lang.String" - }], - "types": [{ - "type": "int" - }, { - "type": "char" - }, { - "type": "java.lang.String", - "properties": { - "value": { - "type": "char[]" - }, - "hash": { - "type": "int" - } - } - }] -} - -``` - -##### Consumer stores: - -```json -{ - "valid": "true", - "side": "consumer", - "application": "metadatareport-local-xml-consumer", - "methods": "sayHello", - "dubbo": "2.0.2", - "interface": "org.apache.dubbo.samples.metadatareport.local.xml.api.DemoService" -} - -``` - - - -### Method 3: Config project in annotation way - -Refer to the sample: dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-annotaion. - -##### @Bean introduce Bean - -```java -@Bean -public MetadataReportConfig metadataReportConfig() { - MetadataReportConfig metadataReportConfig = new MetadataReportConfig(); - metadataReportConfig.setAddress("zookeeper://127.0.0.1:2181"); - return metadataReportConfig; -} - -``` -After introducing Bean, also have not to set others. View corresponding service information directly: - -##### Provider stores: - -```json -{ - "parameters": { - "side": "provider", - "methods": "sayHello", - "dubbo": "2.0.2", - "interface": "org.apache.dubbo.samples.metadatareport.local.annotation.api.AnnotationService", - "version": "1.1.8", - "generic": "false", - "revision": "1.1.8", - "valid": "true", - "application": "metadatareport-local-annotaion-provider", - "default.timeout": "1000", - "group": "d-test", - "anyhost": "true" - }, - "canonicalName": "org.apache.dubbo.samples.metadatareport.local.annotation.api.AnnotationService", - "codeSource": "file:/Users/cvictory/workspace/work-mw/dubbo-samples/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-annotaion/target/classes/", - "methods": [{ - "name": "sayHello", - "parameterTypes": ["java.lang.String"], - "returnType": "java.lang.String" - }], - "types": [{ - "type": "int" - }, { - "type": "java.lang.String", - "properties": { - "value": { - "type": "char[]" - }, - "hash": { - "type": "int" - } - } - }, { - "type": "char" - }] -} -``` - -##### Consumer stores: - -```json -{ - "valid": "true", - "side": "consumer", - "application": "metadatareport-local-annotaion-consumer", - "methods": "sayHello", - "dubbo": "2.0.2", - "interface": "org.apache.dubbo.samples.metadatareport.local.annotation.api.AnnotationService", - "version": "1.1.8", - "revision": "1.1.8", - "group": "d-test" -} -``` - -## Extension -### SPI Definition - -Refer to: org.apache.dubbo.metadata.store.MetadataReportFactory, org.apache.dubbo.metadata.store.MetadataReport - -```java -@SPI("redis") -public interface MetadataReportFactory { - @Adaptive({"protocol"}) - MetadataReport getMetadataReport(URL url); -} -``` - - - -### Custom metadata storage - -Let's take Redis storage as an example to illustrate. - -Create a new project supporting the following modifications: - -#### Extend AbstractMetadataReport - -```java -public class RedisMetadataReport extends AbstractMetadataReport { - private final static Logger logger = LoggerFactory.getLogger(RedisMetadataReport.class); - final JedisPool pool; - - public RedisMetadataReport(URL url) { - super(url); - pool = new JedisPool(new JedisPoolConfig(), url.getHost(), url.getPort()); - } - @Override - protected void doStoreProviderMetadata(ProviderMetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) { - this.storeMetadata(providerMetadataIdentifier, serviceDefinitions); - } - @Override - protected void doStoreConsumerMetadata(ConsumerMetadataIdentifier consumerMetadataIdentifier, String value) { - this.storeMetadata(consumerMetadataIdentifier, value); - } - private void storeMetadata(MetadataIdentifier metadataIdentifier, String v) { - try (Jedis jedis = pool.getResource()) { - jedis.set(metadataIdentifier.getIdentifierKey() + META_DATA_SOTRE_TAG, v); - } catch (Throwable e) { - logger.error("Failed to put " + metadataIdentifier + " to redis " + v + ", cause: " + e.getMessage(), e); - throw new RpcException("Failed to put " + metadataIdentifier + " to redis " + v + ", cause: " + e.getMessage(), e); - } - } -} -``` - -#### Extend AbstractMetadataReportFactory - -```java -public class RedisMetadataReportFactory extends AbstractMetadataReportFactory { - @Override - public MetadataReport createMetadataReport(URL url) { - return new RedisMetadataReport(url); - } -} -``` - -#### New META-INF/dubbo/internal/org.apache.dubbo.metadata.store.MetadataReportFactory - -```properties -redis=org.apache.dubbo.metadata.store.redis.RedisMetadataReportFactory -``` - -As long as the above modifications along with the project are packaged into a jar, then config metadata center url: redis://10.20.153.10:6379. - -Up to now, a custom metadata store is ready to run. diff --git a/content/en/docs/v2.7/user/references/protocol/_index.md b/content/en/docs/v2.7/user/references/protocol/_index.md deleted file mode 100644 index b192cd03414f..000000000000 --- a/content/en/docs/v2.7/user/references/protocol/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -type: docs -title: "Protocol References" -linkTitle: "Protocol" -weight: 2 -description: "References documentation for dubbo protocols" ---- - -Dubbo protocol is recommended. The performance of each protocol, see: [Performance](../../perf-test) diff --git a/content/en/docs/v2.7/user/references/protocol/dubbo.md b/content/en/docs/v2.7/user/references/protocol/dubbo.md deleted file mode 100644 index 60b583aaabb3..000000000000 --- a/content/en/docs/v2.7/user/references/protocol/dubbo.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -type: docs -title: "dubbo protocol" -linkTitle: "dubbo://" -weight: 1 -description: "References documentation for dubbo protocol" ---- - -Dubbo protocol which is the default protocol of Dubbo RPC Framework uses a single long connection and NIO asynchronous communication,it is suitable for small data but with high concurrency RPC call and the number of consumer machine is much greater than provider - -On the other hand, the Dubbo protocol is not suitable for transmitting large amounts of data, such as file transmission, video transmission, etc., unless the request is very low. - -![dubbo-protocol.jpg](/imgs/user/dubbo-protocol.jpg) - -* Transporter: mina, netty, grizzy -* Serialization: dubbo, hessian2, java, json -* Dispatcher: all, direct, message, execution, connection -* ThreadPool: fixed, cached - -## Features - - -The default protocol is Dubbo protocol ,based on netty `3.2.5.Final` and Hessian2 `3.2.1-fixed-2(Alibaba embed version)`. - -* Default connection number: single connection -* Default connection mode: long connection -* Transmission protocol: TCP -* Transmission mode: NIO asynchronous transmission -* Serialization: Hessian2 serialization -* Scope of application: incoming and outgoing data packets are small (recommended less than 100K),try not to transfer large files or large strings with Dubbo protocol. -* Applicable scenarios:: most RPC scenarios - - -## Constraint - -* Parameters and return values must implement `Serializable` interface -* Parameters and return values can not be customized to implement `List`,` Map`, `Number`,` Date`, `Calendar` interface, can only be implemented with the JDK, because Hessian2 will do some special treatment, Attribute values in the class will be lost. -* Hessian serialization:to solve compatibility issues, only serialize class name,all the fields declared by the class,not included static fields,method information - - -| Data transformation | Cases | Result | -| ------------- | ------------- | ------------- | -| A->B | Class A has one more property than Class B| It doesn't throw exception ,Class B doesn't have Class A new property,other is normal | -| A->B | enum Class A has one more new enum than enum Class B,when use Class A new enum to transfor to B | throw exception | -| A->B | enum Class A has one more new enum than enum Class B,when don't use Class A new enum to transfor to B | It doesn't throw exception| -| A->B | Class A and Class B have same property name,but the property type is different | throw exception | -| A->B | serialId is not same | normal | - - -The interface new addition method has no effect on the client. If the method is not required by the client, the client does not need to redeploy it. The input parameter and result class add new properties, and if the client does not need new properties, it does not need to be redeployed too. - -The change of input parameter and result property name has no effect on client serialization, but if the client is not redeployed, no matter the input or output, the value of which property name had change is not available. - -Summary: the server side and the client do not need to be fully consistent with the domain objects,but you still should know about what would happen. - - -## Configuration - - -configure protocol - -```xml - -``` - -configure provider level default protocol: - -```xml - -``` - -configure service level default protocol: - -```xml - -``` - -configure multiple port: - -```xml - - -``` - -configure protocol options: - -```xml - -``` - - -configure multiple connectios: - -Dubbo protocol default uses a single long connection per service per consumer for each service provider,and multiple connections can be used if the amount of data is large - -```xml - -``` - -* `` OR `` It means that the service uses a share long connection per provider. `default` -* `` OR `` It means that the service uses a separate long connection. -* `` OR`` It means that the service uses two separate long connection. - -To prevent being hung up by a large number of connections, you can limit the number of connections at the service provider side. - -```xml - -``` - -or configure in `dubbo.properties`: - -``` -dubbo.service.protocol=dubbo -``` - diff --git a/content/en/docs/v2.7/user/references/protocol/hessian.md b/content/en/docs/v2.7/user/references/protocol/hessian.md deleted file mode 100644 index 9161530f294c..000000000000 --- a/content/en/docs/v2.7/user/references/protocol/hessian.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -type: docs -title: "hessian protocol" -linkTitle: "hessian://" -weight: 4 -description: "References documentation for hessian protocol" ---- - -Hessian protocol is used for integrate Hessian services, and it use http protocol to communicate and expose services by servlet.Dubbo use Jetty server as default servlet container. - -Dubbo's Hessian protocol interoperates with native Hessian services: - - -* Providers use Dubbo's Hessian protocol to expose services that consumers call directly using standard Hessian interfaces -* Alternatively, the provider exposes the service using standard Hessian and the consumer calls it using Dubbo's Hessian protocol. - - -## Features - -* Number of connections: multiple connections -* Connection: short connection -* Transmission protocol: HTTP -* Transmission: synchronous transmission -* Serialization: Hessian binary serialization -* Scope of application: Incoming and outgoing parameter packets are large, the number of providers is more than that of consumers and can transfer files. -* Applicable scenarios: page transfer, file transfer, or interoperability with native hessian services - -## dependency - -```xml - - com.caucho - hessian - 4.0.7 - -``` - -## Constraint - -* Parameters and return class must implement `Serializable` interface -* Parameters and return values can not be customized to implement `List`,` Map`, `Number`,` Date`, `Calendar` interface, can only be implemented with the JDK, because Hessian2 will do some special treatment, Attribute values in the class will be lost. - -## Configuration - -configure hessian protocol: - -```xml - -``` - -configure provider level default protocol: - -```xml - -``` - -configure service level default protocol: - -```xml - -``` - -configure multiple port: - -```xml - - -``` - -configure direct connect mode: - -```xml - -``` - - diff --git a/content/en/docs/v2.7/user/references/protocol/http.md b/content/en/docs/v2.7/user/references/protocol/http.md deleted file mode 100644 index 779214f23dbb..000000000000 --- a/content/en/docs/v2.7/user/references/protocol/http.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -type: docs -title: "http protocol" -linkTitle: "http://" -weight: 3 -description: "References documentation for http protocol" ---- - -Dubbo http protocol is base on HTTP form and Spring's HttpInvoker - - -## Features - -* Number of connections: multiple connections -* Connection: short connection -* Transmission protocol: HTTP -* Transmission: synchronous transmission -* Serialization: form serialization -* Scope of application: Available browser view, the form or URL can be passed parameters, Temporary files are not supported. -* Applicable scenarios: Services that need to be available to both application and browser - -## Constraint -* Parameters and return values must be consistent with Bean specifications - -## Configuration - -configure http protocol: - -```xml - -``` - -configure Jetty Server (default): - -```xml - -``` - -configure Servlet Bridge Server (recommend): - -```xml - -``` - -configure DispatcherServlet: - -```xml - - dubbo - org.apache.dubbo.remoting.http.servlet.DispatcherServlet - 1 - - - dubbo - /* - -``` - -Note that if you use servlets to dispatch requests: - -* the port of protocol `` must same as servlet container's. -* the context path of protocol `` must same as servlet application's. - - diff --git a/content/en/docs/v2.7/user/references/protocol/memcached.md b/content/en/docs/v2.7/user/references/protocol/memcached.md deleted file mode 100644 index 0c0bbb2d0498..000000000000 --- a/content/en/docs/v2.7/user/references/protocol/memcached.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -type: docs -title: "memcached protocol" -linkTitle: "memcached://" -weight: 5 -description: "References documentation for memcached protocol" ---- - -RPC protocol based on memcached implementation. - -## Register memcached service address - -```java -RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); -Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); -registry.register(URL.valueOf("memcached://10.20.153.11/com.foo.BarService?category=providers&dynamic=false&application=foo&group=member&loadbalance=consistenthash")); -``` - -## Use in client - -get service reference: - -```xml - -``` - -or direct access by IP: - -```xml - -``` - -you can also use a custom interface: - -```xml - -``` - - -The method name is the same as the standard method name of memcached, just like get(key), set(key, value), delete(key)。 - -If the method name and the memcached standard method name are not the same, you need to configure the mapping - -```xml - -``` - - diff --git a/content/en/docs/v2.7/user/references/protocol/redis.md b/content/en/docs/v2.7/user/references/protocol/redis.md deleted file mode 100644 index 9c01e8f0c142..000000000000 --- a/content/en/docs/v2.7/user/references/protocol/redis.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -type: docs -title: "redis protocol" -linkTitle: "redis://" -weight: 4 -description: "References documentation for redis protocol" ---- - -RPC protocol based on redis implementation. - -## Register redis service address - -```java -RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); -Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); -registry.register(URL.valueOf("redis://10.20.153.11/com.foo.BarService?category=providers&dynamic=false&application=foo&group=member&loadbalance=consistenthash")); -``` - -## Use in client - -get service reference: - -```xml - -``` - -or direct access by IP: - - -```xml - -``` - -you can also use a custom interface: - -```xml - -``` - -The method name is the same as the standard method name of memcached, just like get(key), set(key, value), delete(key)。 - -If the method name and the memcached standard method name are not the same, you need to configure the mapping - -```xml - -``` - - diff --git a/content/en/docs/v2.7/user/references/protocol/rest.md b/content/en/docs/v2.7/user/references/protocol/rest.md deleted file mode 100644 index c20fe508165f..000000000000 --- a/content/en/docs/v2.7/user/references/protocol/rest.md +++ /dev/null @@ -1,748 +0,0 @@ ---- -type: docs -title: "rest protocol" -linkTitle: "rest://" -weight: 2 -description: "References documentation for rest protocol" ---- - - -基于标准的Java REST API——JAX-RS 2.0(Java API for RESTful Web Services的简写)实现的REST调用支持 - - -## 快速入门 - -在dubbo中开发一个REST风格的服务会比较简单,下面以一个注册用户的简单服务为例说明。 - -这个服务要实现的功能是提供如下URL(注:这个URL不是完全符合REST的风格,但是更简单实用): - -``` -http://localhost:8080/users/register -``` - -而任何客户端都可以将包含用户信息的JSON字符串POST到以上URL来完成用户注册。 - -首先,开发服务的接口: - -```java -public class UserService { - void registerUser(User user); -} -``` - -然后,开发服务的实现: - -```java -@Path("users") -public class UserServiceImpl implements UserService { - - @POST - @Path("register") - @Consumes({MediaType.APPLICATION_JSON}) - public void registerUser(User user) { - // save the user... - } -} -``` -上面的实现非常简单,但是由于该 REST 服务是要发布到指定 URL 上,供任意语言的客户端甚至浏览器来访问,所以这里额外添加了几个 JAX-RS 的标准 annotation 来做相关的配置。 - -@Path("users"):指定访问UserService的URL相对路径是/users,即http://localhost:8080/users - -@Path("register"):指定访问registerUser()方法的URL相对路径是/register,再结合上一个@Path为UserService指定的路径,则调用UserService.register()的完整路径为http://localhost:8080/users/register - -@POST:指定访问registerUser()用HTTP POST方法 - -@Consumes({MediaType.APPLICATION_JSON}):指定registerUser()接收JSON格式的数据。REST框架会自动将JSON数据反序列化为User对象 - -最后,在spring配置文件中添加此服务,即完成所有服务开发工作: - - ```xml - - - - - - - - -``` - -## REST服务提供端详解 - -下面我们扩充“快速入门”中的UserService,进一步展示在dubbo中REST服务提供端的开发要点。 - -### HTTP POST/GET的实现 - -REST服务中虽然建议使用HTTP协议中四种标准方法POST、DELETE、PUT、GET来分别实现常见的“增删改查”,但实际中,我们一般情况直接用POST来实现“增改”,GET来实现“删查”即可(DELETE和PUT甚至会被一些防火墙阻挡)。 - -前面已经简单演示了POST的实现,在此,我们为UserService添加一个获取注册用户资料的功能,来演示GET的实现。 - -这个功能就是要实现客户端通过访问如下不同URL来获取不同ID的用户资料: - -``` -http://localhost:8080/users/1001 -http://localhost:8080/users/1002 -http://localhost:8080/users/1003 -``` - -当然,也可以通过其他形式的URL来访问不同ID的用户资料,例如: - -``` -http://localhost:8080/users/load?id=1001 -``` - -JAX-RS本身可以支持所有这些形式。但是上面那种在URL路径中包含查询参数的形式(http://localhost:8080/users/1001) 更符合REST的一般习惯,所以更推荐大家来使用。下面我们就为UserService添加一个getUser()方法来实现这种形式的URL访问: - -```java -@GET -@Path("{id : \\d+}") -@Produces({MediaType.APPLICATION_JSON}) -public User getUser(@PathParam("id") Long id) { - // ... -} -``` - -@GET:指定用HTTP GET方法访问 - -@Path("{id : \\d+}"):根据上面的功能需求,访问getUser()的URL应当是“http://localhost:8080/users/ + 任意数字",并且这个数字要被做为参数传入getUser()方法。 这里的annotation配置中,@Path中间的{id: xxx}指定URL相对路径中包含了名为id参数,而它的值也将被自动传递给下面用@PathParam("id")修饰的方法参数id。{id:后面紧跟的\\d+是一个正则表达式,指定了id参数必须是数字。 - -@Produces({MediaType.APPLICATION_JSON}):指定getUser()输出JSON格式的数据。框架会自动将User对象序列化为JSON数据。 - -### Annotation放在接口类还是实现类 - -在Dubbo中开发REST服务主要都是通过JAX-RS的annotation来完成配置的,在上面的示例中,我们都是将annotation放在服务的实现类中。但其实,我们完全也可以将annotation放到服务的接口上,这两种方式是完全等价的,例如: - -```java -@Path("users") -public interface UserService { - - @GET - @Path("{id : \\d+}") - @Produces({MediaType.APPLICATION_JSON}) - User getUser(@PathParam("id") Long id); -} -``` - -在一般应用中,我们建议将annotation放到服务实现类,这样annotation和java实现代码位置更接近,更便于开发和维护。另外更重要的是,我们一般倾向于避免对接口的污染,保持接口的纯净性和广泛适用性。 - -但是,如后文所述,如果我们要用dubbo直接开发的消费端来访问此服务,则annotation必须放到接口上。 - -如果接口和实现类都同时添加了annotation,则实现类的annotation配置会生效,接口上的annotation被直接忽略。 - -### JSON、XML等多数据格式的支持 - -在dubbo中开发的REST服务可以同时支持传输多种格式的数据,以给客户端提供最大的灵活性。其中我们目前对最常用的JSON和XML格式特别添加了额外的功能。 - -比如,我们要让上例中的getUser()方法支持分别返回JSON和XML格式的数据,只需要在annotation中同时包含两种格式即可: - -```java -@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) -User getUser(@PathParam("id") Long id); -``` - -或者也可以直接用字符串(还支持通配符)表示MediaType: - -```java -@Produces({"application/json", "text/xml"}) -User getUser(@PathParam("id") Long id); -``` - -如果所有方法都支持同样类型的输入输出数据格式,则我们无需在每个方法上做配置,只需要在服务类上添加annotation即可: - -```java -@Path("users") -@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) -@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) -public class UserServiceImpl implements UserService { - // ... -} - -``` - -在一个REST服务同时对多种数据格式支持的情况下,根据JAX-RS标准,一般是通过HTTP中的MIME header(content-type和accept)来指定当前想用的是哪种格式的数据。 - -但是在dubbo中,我们还自动支持目前业界普遍使用的方式,即用一个URL后缀(.json和.xml)来指定想用的数据格式。例如,在添加上述annotation后,直接访问http://localhost:8888/users/1001.json则表示用json格式,直接访问http://localhost:8888/users/1002.xml则表示用xml格式,比用HTTP Header更简单直观。Twitter、微博等的REST API都是采用这种方式。 - -如果你既不加HTTP header,也不加后缀,则dubbo的REST会优先启用在以上annotation定义中排位最靠前的那种数据格式。 - -> 注意:这里要支持XML格式数据,在annotation中既可以用MediaType.TEXT_XML,也可以用MediaType.APPLICATION_XML,但是TEXT_XML是更常用的,并且如果要利用上述的URL后缀方式来指定数据格式,只能配置为TEXT_XML才能生效。 - -### 中文字符支持 - -为了在dubbo REST中正常输出中文字符,和通常的Java web应用一样,我们需要将HTTP响应的contentType设置为UTF-8编码。 - -基于JAX-RS的标准用法,我们只需要做如下annotation配置即可: - -```java -@Produces({"application/json; charset=UTF-8", "text/xml; charset=UTF-8"}) -User getUser(@PathParam("id") Long id); -``` - -为了方便用户,我们在dubbo REST中直接添加了一个支持类,来定义以上的常量,可以直接使用,减少出错的可能性。 - -```java -@Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8}) -User getUser(@PathParam("id") Long id); -``` - -### XML数据格式的额外要求 - -由于JAX-RS的实现一般都用标准的JAXB(Java API for XML Binding)来序列化和反序列化XML格式数据,所以我们需要为每一个要用XML传输的对象添加一个类级别的JAXB annotation,否则序列化将报错。例如为getUser()中返回的User添加如下: - -```java -@XmlRootElement -public class User implements Serializable { - // ... -} -``` - -此外,如果service方法中的返回值是Java的 primitive类型(如int,long,float,double等),最好为它们添加一层wrapper对象,因为JAXB不能直接序列化primitive类型。 - -例如,我们想让前述的registerUser()方法返回服务器端为用户生成的ID号: - -```java -long registerUser(User user); -``` - -由于primitive类型不被JAXB序列化支持,所以添加一个wrapper对象: - -```java -@XmlRootElement -public class RegistrationResult implements Serializable { - - private Long id; - - public RegistrationResult() { - } - - public RegistrationResult(Long id) { - this.id = id; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } -} -``` - -并修改service方法: - -```java -RegistrationResult registerUser(User user); -``` - -这样不但能够解决XML序列化的问题,而且使得返回的数据都符合XML和JSON的规范。例如,在JSON中,返回的将是如下形式: - -```javascript -{"id": 1001} -``` - -如果不加wrapper,JSON返回值将直接是 - -``` -1001 -``` - -而在XML中,加wrapper后返回值将是: - -```xml - - 1002 - -``` - -这种wrapper对象其实利用所谓Data Transfer Object(DTO)模式,采用DTO还能对传输数据做更多有用的定制。 - -### 定制序列化 - -如上所述,REST的底层实现会在service的对象和JSON/XML数据格式之间自动做序列化/反序列化。但有些场景下,如果觉得这种自动转换不满足要求,可以对其做定制。 - -Dubbo中的REST实现是用JAXB做XML序列化,用Jackson做JSON序列化,所以在对象上添加JAXB或Jackson的annotation即可以定制映射。 - -例如,定制对象属性映射到XML元素的名字: - -```java -@XmlRootElement -@XmlAccessorType(XmlAccessType.FIELD) -public class User implements Serializable { - - @XmlElement(name="username") - private String name; -} -``` - -定制对象属性映射到JSON字段的名字: - -```java -public class User implements Serializable { - - @JsonProperty("username") - private String name; -} -``` - -更多资料请参考JAXB和Jackson的官方文档,或自行google。 - -### 配置REST Server的实现 - -目前在dubbo中,我们支持5种嵌入式rest server的实现,并同时支持采用外部应用服务器来做rest server的实现。rest server可以通过如下配置实现: - -```xml - -``` - -以上配置选用了嵌入式的jetty来做rest server,同时,如果不配置server属性,rest协议默认也是选用jetty。jetty是非常成熟的java servlet容器,并和dubbo已经有较好的集成(目前5种嵌入式server中只有jetty和后面所述的tomcat、tjws,与dubbo监控系统等完成了无缝的集成),所以,如果你的dubbo系统是单独启动的进程,你可以直接默认采用jetty即可。 - - -```xml - -``` - -以上配置选用了嵌入式的tomcat来做rest server。在嵌入式tomcat上,REST的性能比jetty上要好得多(参见后面的基准测试),建议在需要高性能的场景下采用tomcat。 - -```xml - -``` - -以上配置选用嵌入式的netty来做rest server。(TODO more contents to add) - -```xml - (tjws is now deprecated) - -``` - -以上配置选用嵌入式的tjws或Sun HTTP server来做rest server。这两个server实现非常轻量级,非常方便在集成测试中快速启动使用,当然也可以在负荷不高的生产环境中使用。 注:tjws目前已经被deprecated掉了,因为它不能很好的和servlet 3.1 API工作。 - -如果你的dubbo系统不是单独启动的进程,而是部署到了Java应用服务器中,则建议你采用以下配置: - -```xml - -``` - -通过将server设置为servlet,dubbo将采用外部应用服务器的servlet容器来做rest server。同时,还要在dubbo系统的web.xml中添加如下配置: - -```xml - - - contextConfigLocation - /WEB-INF/classes/META-INF/spring/dubbo-demo-provider.xml - - - - org.apache.dubbo.remoting.http.servlet.BootstrapListener - - - - org.springframework.web.context.ContextLoaderListener - - - - dispatcher - org.apache.dubbo.remoting.http.servlet.DispatcherServlet - 1 - - - - dispatcher - /* - - -``` - -即必须将dubbo的BootstrapListener和DispatherServlet添加到web.xml,以完成dubbo的REST功能与外部servlet容器的集成。 - -> 注意:如果你是用spring的ContextLoaderListener来加载spring,则必须保证BootstrapListener配置在ContextLoaderListener之前,否则dubbo初始化会出错。 - -其实,这种场景下你依然可以坚持用嵌入式server,但外部应用服务器的servlet容器往往比嵌入式server更加强大(特别是如果你是部署到更健壮更可伸缩的WebLogic,WebSphere等),另外有时也便于在应用服务器做统一管理、监控等等。 - -### 获取上下文(Context)信息 - -在远程调用中,值得获取的上下文信息可能有很多种,这里特别以获取客户端IP为例。 - -在dubbo的REST中,我们有两种方式获取客户端IP。 - -第一种方式,用JAX-RS标准的@Context annotation: - -```java -public User getUser(@PathParam("id") Long id, @Context HttpServletRequest request) { - System.out.println("Client address is " + request.getRemoteAddr()); -} -``` - -用Context修饰getUser()的一个方法参数后,就可以将当前的HttpServletRequest注入进来,然后直接调用servlet api获取IP。 - -> 注意:这种方式只能在将server设置为 tjws、tomcat、jetty 或者 servlet 的时候才能工作,因为只有这几种 server 的实现才提供了 servlet 容器。另外,标准的JAX-RS还支持用@Context修饰service类的一个实例字段来获取HttpServletRequest,但在dubbo中我们没有对此作出支持。 - -第二种方式,用dubbo中常用的RpcContext: - -```java -public User getUser(@PathParam("id") Long id) { - System.out.println("Client address is " + RpcContext.getContext().getRemoteAddressString()); -} -``` - -> 注意:这种方式只能在设置server="jetty"或者server="tomcat"或者server="servlet"或者server="tjws"的时候才能工作。另外,目前dubbo的RpcContext是一种比较有侵入性的用法,未来我们很可能会做出重构。 - -如果你想保持你的项目对JAX-RS的兼容性,未来脱离dubbo也可以运行,请选择第一种方式。如果你想要更优雅的服务接口定义,请选用第二种方式。 - -此外,在最新的dubbo rest中,还支持通过RpcContext来获取HttpServletRequest和HttpServletResponse,以提供更大的灵活性来方便用户实现某些复杂功能,比如在dubbo标准的filter中访问HTTP Header。用法示例如下: - -```java -if (RpcContext.getContext().getRequest() != null && RpcContext.getContext().getRequest() instanceof HttpServletRequest) { - System.out.println("Client address is " + ((HttpServletRequest) RpcContext.getContext().getRequest()).getRemoteAddr()); -} - -if (RpcContext.getContext().getResponse() != null && RpcContext.getContext().getResponse() instanceof HttpServletResponse) { - System.out.println("Response object from RpcContext: " + RpcContext.getContext().getResponse()); -} -``` - -> 注意:为了保持协议的中立性,RpcContext.getRequest()和RpcContext.getResponse()返回的仅仅是一个Object类,而且可能为null。所以,你必须自己做null和类型的检查。 - -> 注意:只有在设置server="jetty"或者server="tomcat"或者server="servlet"的时候,你才能通过以上方法正确的得到HttpServletRequest和HttpServletResponse,因为只有这几种server实现了servlet容器。 - -为了简化编程,在此你也可以用泛型的方式来直接获取特定类型的request/response: - -```java -if (RpcContext.getContext().getRequest(HttpServletRequest.class) != null) { - System.out.println("Client address is " + RpcContext.getContext().getRequest(HttpServletRequest.class).getRemoteAddr()); -} - -if (RpcContext.getContext().getResponse(HttpServletResponse.class) != null) { - System.out.println("Response object from RpcContext: " + RpcContext.getContext().getResponse(HttpServletResponse.class)); -} -``` - -如果request/response不符合指定的类型,这里也会返回null。 - -### 配置端口号和Context Path - -dubbo中的rest协议默认将采用80端口,如果想修改端口,直接配置: - -```xml - -``` - -另外,如前所述,我们可以用@Path来配置单个rest服务的URL相对路径。但其实,我们还可以设置一个所有rest服务都适用的基础相对路径,即java web应用中常说的context path。 - -只需要添加如下contextpath属性即可: - -```xml - -``` - -以前面代码为例: - -```java -@Path("users") -public class UserServiceImpl implements UserService { - - @POST - @Path("register") - @Consumes({MediaType.APPLICATION_JSON}) - public void registerUser(User user) { - // save the user... - } -} -``` - -现在registerUser()的完整访问路径为: - -``` -http://localhost:8888/services/users/register -``` - -注意:如果你是选用外部应用服务器做rest server,即配置: - -```xml - -``` - -则必须保证这里设置的port、contextpath,与外部应用服务器的端口、DispatcherServlet的上下文路径(即webapp path加上servlet url pattern)保持一致。例如,对于部署为tomcat ROOT路径的应用,这里的contextpath必须与web.xml中DispacherServlet的``完全一致: - -```xml - - dispatcher - /services/* - -``` - -### 配置线程数和IO线程数 - -可以为rest服务配置线程池大小: - -```xml - -``` - -> 注意:目前线程池的设置只有当server="netty"或者server="jetty"或者server="tomcat"的时候才能生效。另外,如果server="servlet",由于这时候启用的是外部应用服务器做rest server,不受dubbo控制,所以这里的线程池设置也无效。 - -如果是选用netty server,还可以配置Netty的IO worker线程数: - -```xml - -``` - -### 配置长连接 - -Dubbo中的rest服务默认都是采用http长连接来访问,如果想切换为短连接,直接配置: - -```xml - -``` - -> 注意:这个配置目前只对server="netty"和server="tomcat"才能生效。 - -### 配置最大的HTTP连接数 - -可以配置服务器提供端所能同时接收的最大HTTP连接数,防止REST server被过多连接撑爆,以作为一种最基本的自我保护机制: - -```xml - -``` - -当然,由于这个配置针对消费端生效的,所以也可以在消费端配置: - -```xml - -``` - -但是,通常我们建议配置在服务提供端提供此类配置。按照dubbo官方文档的说法:“Provider上尽量多配置Consumer端的属性,让Provider实现者一开始就思考Provider服务特点、服务质量的问题。” - -> 注意:如果dubbo的REST服务是发布给非dubbo的客户端使用,则这里``上的配置完全无效,因为这种客户端不受dubbo控制。 - - -### 用Annotation取代部分Spring XML配置 - -以上所有的讨论都是基于dubbo在spring中的xml配置。但是,dubbo/spring本身也支持用annotation来作配置,所以我们也可以按dubbo官方文档中的步骤,把相关annotation加到REST服务的实现中,取代一些xml配置,例如: - -```java -@Service(protocol = "rest") -@Path("users") -public class UserServiceImpl implements UserService { - - @Autowired - private UserRepository userRepository; - - @POST - @Path("register") - @Consumes({MediaType.APPLICATION_JSON}) - public void registerUser(User user) { - // save the user - userRepository.save(user); - } -} -``` - -annotation的配置更简单更精确,通常也更便于维护(当然现代IDE都可以在xml中支持比如类名重构,所以就这里的特定用例而言,xml的维护性也很好)。而xml对代码的侵入性更小一些,尤其有利于动态修改配置,特别是比如你要针对单个服务配置连接超时时间、每客户端最大连接数、集群策略、权重等等。另外,特别对复杂应用或者模块来说,xml提供了一个中心点来涵盖的所有组件和配置,更一目了然,一般更便于项目长时期的维护。 - -当然,选择哪种配置方式没有绝对的优劣,和个人的偏好也不无关系。 - -### 添加自定义的Filter、Interceptor等 - -Dubbo的REST也支持JAX-RS标准的Filter和Interceptor,以方便对REST的请求与响应过程做定制化的拦截处理。 - -其中,Filter主要用于访问和设置HTTP请求和响应的参数、URI等等。例如,设置HTTP响应的cache header: - -```java -public class CacheControlFilter implements ContainerResponseFilter { - - public void filter(ContainerRequestContext req, ContainerResponseContext res) { - if (req.getMethod().equals("GET")) { - res.getHeaders().add("Cache-Control", "someValue"); - } - } -} -``` - -Interceptor主要用于访问和修改输入与输出字节流,例如,手动添加GZIP压缩: - -```java -public class GZIPWriterInterceptor implements WriterInterceptor { - - @Override - public void aroundWriteTo(WriterInterceptorContext context) - throws IOException, WebApplicationException { - OutputStream outputStream = context.getOutputStream(); - context.setOutputStream(new GZIPOutputStream(outputStream)); - context.proceed(); - } -} -``` - -在标准JAX-RS应用中,我们一般是为Filter和Interceptor添加@Provider annotation,然后JAX-RS runtime会自动发现并启用它们。而在dubbo中,我们是通过添加XML配置的方式来注册Filter和Interceptor: - -```xml - -``` - -在此,我们可以将Filter、Interceptor和DynamicFeature这三种类型的对象都添加到`extension`属性上,多个之间用逗号分隔。(DynamicFeature是另一个接口,可以方便我们更动态的启用Filter和Interceptor,感兴趣请自行google。) - -当然,dubbo自身也支持Filter的概念,但我们这里讨论的Filter和Interceptor更加接近协议实现的底层,相比dubbo的filter,可以做更底层的定制化。 - -> 注:这里的XML属性叫extension,而不是叫interceptor或者filter,是因为除了Interceptor和Filter,未来我们还会添加更多的扩展类型。 - -如果REST的消费端也是dubbo系统(参见下文的讨论),则也可以用类似方式为消费端配置Interceptor和Filter。但注意,JAX-RS中消费端的Filter和提供端的Filter是两种不同的接口。例如前面例子中服务端是ContainerResponseFilter接口,而消费端对应的是ClientResponseFilter: - -```java -public class LoggingFilter implements ClientResponseFilter { - - public void filter(ClientRequestContext reqCtx, ClientResponseContext resCtx) throws IOException { - System.out.println("status: " + resCtx.getStatus()); - System.out.println("date: " + resCtx.getDate()); - System.out.println("last-modified: " + resCtx.getLastModified()); - System.out.println("location: " + resCtx.getLocation()); - System.out.println("headers:"); - for (Entry> header : resCtx.getHeaders().entrySet()) { - System.out.print("\t" + header.getKey() + " :"); - for (String value : header.getValue()) { - System.out.print(value + ", "); - } - System.out.print("\n"); - } - System.out.println("media-type: " + resCtx.getMediaType().getType()); - } -} -``` - -### 添加自定义的Exception处理 - -Dubbo的REST也支持JAX-RS标准的ExceptionMapper,可以用来定制特定exception发生后应该返回的HTTP响应。 - -```java -public class CustomExceptionMapper implements ExceptionMapper { - - public Response toResponse(NotFoundException e) { - return Response.status(Response.Status.NOT_FOUND).entity("Oops! the requested resource is not found!").type("text/plain").build(); - } -} -``` - -和Interceptor、Filter类似,将其添加到XML配置文件中即可启用: - -```xml - -``` - -### 配置HTTP日志输出 - -Dubbo rest支持输出所有HTTP请求/响应中的header字段和body消息体。 - -在XML配置中添加如下自带的REST filter: - -```xml - -``` - -然后配置在logging配置中至少为org.apache.dubbo.rpc.protocol.rest.support打开INFO级别日志输出,例如,在log4j.xml中配置: - -```xml - - - - -``` - -当然,你也可以直接在ROOT logger打开INFO级别日志输出: - -```xml - - - - -``` - -然后在日志中会有类似如下的内容输出: - -``` -The HTTP headers are: -accept: application/json;charset=UTF-8 -accept-encoding: gzip, deflate -connection: Keep-Alive -content-length: 22 -content-type: application/json -host: 192.168.1.100:8888 -user-agent: Apache-HttpClient/4.2.1 (java 1.5) -``` - -``` -The contents of request body is: -{"id":1,"name":"dang"} -``` - -打开HTTP日志输出后,除了正常日志输出的性能开销外,也会在比如HTTP请求解析时产生额外的开销,因为需要建立额外的内存缓冲区来为日志的输出做数据准备。 - -### 输入参数的校验 - -dubbo的rest支持采用Java标准的bean validation annotation(JSR 303)来做输入校验http://beanvalidation.org/ - -为了和其他dubbo远程调用协议保持一致,在rest中作校验的annotation必须放在服务的接口上,例如: - -```java -public interface UserService { - - User getUser(@Min(value=1L, message="User ID must be greater than 1") Long id); -} - -``` - -当然,在很多其他的bean validation的应用场景都是将annotation放到实现类而不是接口上。把annotation放在接口上至少有一个好处是,dubbo的客户端可以共享这个接口的信息,dubbo甚至不需要做远程调用,在本地就可以完成输入校验。 - -然后按照dubbo的标准方式在XML配置中打开验证: - -```xml - -``` - -在dubbo的其他很多远程调用协议中,如果输入验证出错,是直接将`RpcException`抛向客户端,而在rest中由于客户端经常是非dubbo,甚至非java的系统,所以不便直接抛出Java异常。因此,目前我们将校验错误以XML的格式返回: - -```xml - - - getUserArgument0 - User ID must be greater than 1 - 0 - - -``` - -稍后也会支持其他数据格式的返回值。至于如何对验证错误消息作国际化处理,直接参考bean validation的相关文档即可。 - -如果你认为默认的校验错误返回格式不符合你的要求,可以如上面章节所述,添加自定义的ExceptionMapper来自由的定制错误返回格式。需要注意的是,这个ExceptionMapper必须用泛型声明来捕获dubbo的RpcException,才能成功覆盖dubbo rest默认的异常处理策略。为了简化操作,其实这里最简单的方式是直接继承dubbo rest的RpcExceptionMapper,并覆盖其中处理校验异常的方法即可: - -```java -public class MyValidationExceptionMapper extends RpcExceptionMapper { - - protected Response handleConstraintViolationException(ConstraintViolationException cve) { - ViolationReport report = new ViolationReport(); - for (ConstraintViolation cv : cve.getConstraintViolations()) { - report.addConstraintViolation(new RestConstraintViolation( - cv.getPropertyPath().toString(), - cv.getMessage(), - cv.getInvalidValue() == null ? "null" : cv.getInvalidValue().toString())); - } - // 采用json输出代替xml输出 - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(report).type(ContentType.APPLICATION_JSON_UTF_8).build(); - } -} -``` - -然后将这个ExceptionMapper添加到XML配置中即可: - -```xml - -``` diff --git a/content/en/docs/v2.7/user/references/protocol/rmi.md b/content/en/docs/v2.7/user/references/protocol/rmi.md deleted file mode 100644 index 0b293df39a37..000000000000 --- a/content/en/docs/v2.7/user/references/protocol/rmi.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -type: docs -title: "rmi protocol" -linkTitle: "rmi://" -weight: 5 -description: "References documentation for rmi protocol" ---- - -The RMI protocol uses the JDK standard `java.rmi.*` Implementation, using a block short connection and JDK standard serialization. - -## Features - -* Number of connections: multiple connections -* Connection: short connection -* Transmission protocol: HTTP -* Transmission: synchronous transmission -* Serialization: Java standard Object Serialization -* Scope of application:the number of providers is more than that of consumers and can transfer files. -* Applicable scenarios: Conventional remote service method calls, interoperating with native RMI services - -## Constraint - -* Parameters and return values must implement `Serializable` interface -* The timeout configuration for RMI is invalid, you need to use java startup parameter settings:`-Dsun.rmi.transport.tcp.responseTimeout=3000`,see the RMI configuration below - -## Configuration in dubbo.properties - -```properties -dubbo.service.protocol=rmi -``` - -## RMI Configuration - -```sh -java -Dsun.rmi.transport.tcp.responseTimeout=3000 -``` -more RMI options please check [JDK Document](https://docs.oracle.com/javase/6/docs/technotes/guides/rmi/sunrmiproperties.html) - - -## Interface - -If the service interface implement the `java.rmi.Remote` interface, it can interoperate with the native RMI, ie: - -* Providers expose services using Dubbo's RMI protocol, consumers call directly with the standard RMI interface, -* Or the provider exposes services using standard RMI, and consumers invoke with Dubbo's RMI protocol. - -If the service interface doesn't implement the `java.rmi.Remote` interface: - - -* Default Dubbo will automatically generate a `com.xxx.XxxService$Remote` interface and implement the` java.rmi.Remote` interface, expose the service as this interface, -* But if ` `is set, the`$Remote` interface will not be generated, but Spring's `RmiInvocationHandler` interface will be used to expose services. - -## Configuration - -configure RMI protocol: - -```xml - -``` - -configure provider level default protocol: - -```xml - -``` - -configure service level default protocol: - - -```xml - -``` - -configure multiple port: - -```xml - - - - -``` - -Compatible with Spring: - -```xml - -``` - diff --git a/content/en/docs/v2.7/user/references/protocol/thrift.md b/content/en/docs/v2.7/user/references/protocol/thrift.md deleted file mode 100644 index e3237424670f..000000000000 --- a/content/en/docs/v2.7/user/references/protocol/thrift.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -type: docs -title: "thrift protocol" -linkTitle: "thrift://" -weight: 4 -description: "References documentation for thrift protocol" ---- - -The current dubbo support thrift protocol is an extension of the thrift native protocol, adding some additional header information to the native protocol, such as service name, magic number, and so on. - -The use of dubbo thrift protocol also need to use thrift idl compiler to generate the corresponding java code, follow-up version will do some enhancement in this aspect. - -## dependency - -```xml - - org.apache.thrift - libthrift - 0.8.0 - -``` - -## Configuration - - -```xml - -``` - -## Example - -you can check [dubbo thrift example](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-thrift) - -## Common problem - -* Thrift does not support null values, that is, you can not pass null values - - diff --git a/content/en/docs/v2.7/user/references/protocol/webservice.md b/content/en/docs/v2.7/user/references/protocol/webservice.md deleted file mode 100644 index d29976ee90ae..000000000000 --- a/content/en/docs/v2.7/user/references/protocol/webservice.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -type: docs -title: "webservice protocol" -linkTitle: "webservice://" -weight: 5 -description: "References documentation for webservice protocol" ---- - -WebService-based remote calling protocol,base on [Apache CXF](http://cxf.apache.org) `frontend-simple` and `transports-http` implements。 - -Interoperable with native WebService services: - -* Providers expose services using Dubbo's WebService protocol, which consumers invoke directly using the standard WebService interface, -* Or the provider exposes the service using the standard WebService, which consumers invoke using the Dubbo WebService protocol. - -## dependency - -```xml - - org.apache.cxf - cxf-rt-frontend-simple - 2.6.1 - - - org.apache.cxf - cxf-rt-transports-http - 2.6.1 - -``` - -## Features - -* Number of connections: multiple connections -* Connection: short connection -* Transmission protocol: HTTP -* Transmission: synchronous transmission -* Serialization: SOAP text serialization -* Applicable scenarios: System integration, cross-language calls - - -## Constraint - -* Parameters and return class should implement `Serializable` interface -* Parameters should try to use the basic types and POJO - -## Configuration - -configure webservice protocol: - -```xml - -``` - -configure provider level default protocol: - -```xml - -``` - -configure service level default protocol: - -```xml - -``` - -configure multiple port: - -```xml - - -``` - -configure direct connect mode: - -```xml - -``` - -WSDL: - -``` -http://10.20.153.10:8080/com.foo.HelloWorld?wsdl -``` - -Jetty Server (Default): - -```xml - -``` - -Servlet Bridge Server (recommend): - -```xml - -``` - -configure DispatcherServlet: - -```xml - - dubbo - org.apache.dubbo.remoting.http.servlet.DispatcherServlet - 1 - - - dubbo - /* - -``` - -Note that if you use servlets to dispatch requests: - -* the port of protocol `` must same as servlet container's. -* the context path of protocol `` must same as servlet application's. - - - - - diff --git a/content/en/docs/v2.7/user/references/qos.md b/content/en/docs/v2.7/user/references/qos.md deleted file mode 100644 index d57aadfb9191..000000000000 --- a/content/en/docs/v2.7/user/references/qos.md +++ /dev/null @@ -1,233 +0,0 @@ ---- -type: docs -title: "Qos Command Usage " -linkTitle: "Qos" -weight: 11 -description: "Telnet (new version) command usage in dubbo" ---- - -In dubbo `2.5.8` a new QOS module is introduced, to provide new telnet command support. - -## Port -the port of new version telnet is different from the port of dubbo protocol. The default port is `22222`, which can be changed by modifying configuration file `dubbo.properties` - -``` -dubbo.application.qos.port=33333 -``` - -or by modifying the JVM parameter - -``` --Ddubbo.application.qos.port=33333 -``` - -## Safety - -By default, dubbo can receive any command sent from the host, which can be changed by modifying the configuration file `dubbo.properties` - -``` -dubbo.application.qos.accept.foreign.ip=false -``` - -or by configuring the JVM parameter - -``` --Ddubbo.application.qos.accept.foreign.ip=false -``` - -to reject command sent from the remote host, allowing only the local server to run the command - -## Telnet and HTTP protocol - -The telnet module supports both http and telnet protocol, in order to facilitate the use of various situations - -For example, - -``` -➜ ~ telnet localhost 22222 -Trying ::1... -telnet: connect to address ::1: Connection refused -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. - ████████▄ ███ █▄ ▀█████████▄ ▀█████████▄ ▄██████▄ - ███ ▀███ ███ ███ ███ ███ ███ ███ ███ ███ - ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ - ███ ███ ███ ███ ▄███▄▄▄██▀ ▄███▄▄▄██▀ ███ ███ - ███ ███ ███ ███ ▀▀███▀▀▀██▄ ▀▀███▀▀▀██▄ ███ ███ - ███ ███ ███ ███ ███ ██▄ ███ ██▄ ███ ███ - ███ ▄███ ███ ███ ███ ███ ███ ███ ███ ███ - ████████▀ ████████▀ ▄█████████▀ ▄█████████▀ ▀██████▀ - - -dubbo>ls -As Provider side: -+----------------------------------+---+ -| Provider Service Name |PUB| -+----------------------------------+---+ -|org.apache.dubbo.demo.DemoService| N | -+----------------------------------+---+ -As Consumer side: -+---------------------+---+ -|Consumer Service Name|NUM| -+---------------------+---+ - -dubbo> -``` - - -``` -➜ ~ curl "localhost:22222/ls?arg1=xxx&arg2=xxxx" -As Provider side: -+----------------------------------+---+ -| Provider Service Name |PUB| -+----------------------------------+---+ -|org.apache.dubbo.demo.DemoService| N | -+----------------------------------+---+ -As Consumer side: -+---------------------+---+ -|Consumer Service Name|NUM| -+---------------------+---+ -``` - -## Supported Commands - -### ls List consumers and providers - -``` -dubbo>ls -As Provider side: -+----------------------------------+---+ -| Provider Service Name |PUB| -+----------------------------------+---+ -|org.apache.dubbo.demo.DemoService| Y | -+----------------------------------+---+ -As Consumer side: -+---------------------+---+ -|Consumer Service Name|NUM| -+---------------------+---+ -``` - -List the services of the provides and the consumers that dubbo provide - -### Online service command - -When using delay publishing function(org.apache.dubbo.config.AbstractServiceConfig#register set as false), you can use “online” command to online the service - -``` -//online all services -dubbo>online -OK - -//online part of servies according to regularity. -dubbo>online com.* -OK -``` - -Common usage situations: -- Because there is no JIT or the related resources warm-up, when the machine is restarted and the online QPS is relatively high , a large amount of timeout situations may occur. At this time,the problem can be solved by distributing the batch service and increasing the traffic gradually. -- A machine needs to be back online after going offline due to some reasons. - -### Offline service Command - -Offline command can be used if temporary offline service is needed when fault occurs. - -``` -//offline all service -dubbo>offline -OK - -//offline some services according to regular rules -dubbo>offline com.* -OK -``` - -### help command - -``` -//list all commands -dubbo>help - -//list the specific use case of a command -dubbo>help online -+--------------+----------------------------------------------------------------------------------+ -| COMMAND NAME | online | -+--------------+----------------------------------------------------------------------------------+ -| EXAMPLE | online dubbo | -| | online xx.xx.xxx.service | -+--------------+----------------------------------------------------------------------------------+ -dubbo> -``` - -## QoS' Parameters - -You can use parameters that QoS provides to config its startup. These parameters include: - -| Parameter | Explanation | Default | -| ------------------ | ----------------- | ------ | -| qosEnable | Activate QoS or not | true | -| qosPort | The port QoS would bind to | 22222 | -| qosAcceptForeignIp | Enable remote access or not | false | - -> Attention. From 2.6.4/2.7.0, `qosAcceptForeignIp` is set to `false` by default, because it's risky if this property is set to `true`. Think twice before you turn it on. - -You can configure these parameters in the following ways: - -* System property -* `dubbo.properties` -* XML -* Spring-boot auto configuration - -They have priority in the following order: system property > `dubbo.properties` > XML > spring-boot. - -### System Property - -``` --Ddubbo.application.qos.enable=true --Ddubbo.application.qos.port=33333 --Ddubbo.application.qos.accept.foreign.ip=false -``` - -### `Dubbo.properties` - -Create a `dubbo.properties` file in this directory `src/main/resources` in your project, and copy the following codes into it: - -``` -dubbo.application.qos.enable=true -dubbo.application.qos.port=33333 -dubbo.application.qos.accept.foreign.ip=false -``` - -### XML - -If you are going to config using XML, you can try this: - -```xml - - - - - - - - - - - - -``` - -### spring-boot auto configuration - -If you are developing a spring-boot application, you can configure in `application.properties` or `application.yml`: - -``` -dubbo.application.qosEnable=true -dubbo.application.qosPort=33333 -dubbo.application.qosAcceptForeignIp=false -``` diff --git a/content/en/docs/v2.7/user/references/registry/_index.md b/content/en/docs/v2.7/user/references/registry/_index.md deleted file mode 100644 index 1360ce8e9ca0..000000000000 --- a/content/en/docs/v2.7/user/references/registry/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -type: docs -title: "Registry Server References" -linkTitle: "Registry Server" -weight: 3 -description: "Registry server references for dubbo" ---- - -It is recommended to use [zookeeper registry server](zookeeper) \ No newline at end of file diff --git a/content/en/docs/v2.7/user/references/registry/multicast.md b/content/en/docs/v2.7/user/references/registry/multicast.md deleted file mode 100644 index fa22abd21769..000000000000 --- a/content/en/docs/v2.7/user/references/registry/multicast.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -type: docs -title: "Multicast Registry" -linkTitle: "Multicast" -weight: 2 -description: "Multicast registry for dubbo" ---- - - -Multicast registry doesn't require to setup any central node. Just like IP address broadcast, dubbo service providers and consumers can discover each other through this mechanism. - -![/user-guide/images/multicast.jpg](/imgs/user/multicast.jpg) - -0. Service provider broadcasts its address when it boots up. -1. Service consumer broadcasts its subscription request when it boots up. -2. Once service provider receives subscription request, it unicasts its own address to the corresponding consumer, if `unicast=false` is set, then broadcast will be used instead. -3. When service consumer receives provider's address, it can start RPC invocation on the received address. - -Multicast is limited to network topology, and is only suitable for development purpose or small deployment. The valid multcast addresses scope is: 224.0.0.0 - 239.255.255.255. - -## Configuration - -```xml - -``` - -Or - -```xml - -``` - -In order to avoid multicast as much as possible, dubbo uses unicast for address information from service provider to service consumer, if there are multiple consumer processes on one single machine, consumers need to set `unicast=false`, otherwise only one consumer can be able to receive the address info: - -```xml - - - -``` - -Or - -```xml - - - -``` diff --git a/content/en/docs/v2.7/user/references/registry/nacos.md b/content/en/docs/v2.7/user/references/registry/nacos.md deleted file mode 100644 index 9c46d4d3ea4e..000000000000 --- a/content/en/docs/v2.7/user/references/registry/nacos.md +++ /dev/null @@ -1,139 +0,0 @@ ---- -type: docs -title: "Nacos Registry Center" -linkTitle: "Nacos" -weight: 1 -description: "Nacos registry center for dubbo" ---- - -Nacos is a very important registry center for Dubbo ecosystem, [`dubbo-registry-nacos`](https://github.com/apache/incubator-dubbo/tree/master/dubbo-registry/dubbo-registry-nacos) is the implementation of Nacos integration to Nacos. - -## Prepare Work - -When you integrate [`dubbo-registry-nacos`](https://github.com/apache/incubator-dubbo/tree/master/dubbo-registry/dubbo-registry-nacos) into your Dubbo project, please Make sure the Nacos service is started in the background. If you are not familiar with the basic use of Nacos, you can refer to [Nacos Quick Start](https://nacos.io/en-us/docs/quick-start.html). It is recommended to use the version equal or above Nacos `1.0.0`. - - -## Quick Start - -The steps for Dubbo to integrate Nacos as a registry center are very simple. The general steps can be divided into "add Maven dependencies" and "configure registry center". - - -### Add Maven Dependencies - -First, you need to add the `dubbo-registry-nacos` Maven dependency to your project's `pom.xml` file, and we strongly recommend that you use Dubbo `2.6.5`: - - -```xml - - - ... - - - - com.alibaba - dubbo-registry-nacos - 0.0.2 - - - - - com.alibaba.nacos - nacos-client - [0.6.1,) - - - - - com.alibaba - dubbo - 2.6.5 - - - - - com.alibaba.spring - spring-context-support - 1.0.2 - - - ... - - -``` - -When you add `dubbo-registry-nacos` to your project, you don't need to explicitly program the service discovery and registration logic. The actual implementation is provided by the three-party package. - - -### Configure Registry Center - -Assuming your Dubbo app uses the Spring Framework assembly, there are two configuration options available: [Dubbo Spring Externalization Configuration](https://mercyblitz.github.io/2018/01/18/Dubbo-%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE/) and the Spring XML configuration file. - - -### [Dubbo Spring Externalization Configuration](https://mercyblitz.github.io/2018/01/18/Dubbo-%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE/) - - -The Dubbo Spring externalization configuration is a new feature introduced by Dubbo `2.5.8` that automatically generates and binds Dubbo configuration beans through the Spring `Environment` property, simplifying configuration and lowering the microservice development threshold. - -Assuming your Nacos Server is also running on server `10.20.153.10` and using the default Nacos service port `8848`, you only need to adjust the `dubbo.registry.address` property as follows: - - -```properties -## Other properties remain unchanged - -## Nacos registry address -dubbo.registry.address = nacos://10.20.153.10:8848 -... -``` - -Then, restart your Dubbo app, Dubbo's service provider and consumer information can be displayed on the Nacos console: - -![dubbo-registry-nacos-1.png](/imgs/blog/dubbo-registry-nacos-1.png) - - -As shown in the figure, the information whose service name prefix is `providers:` is the meta information of the service provider, and the `consumers:` represents the meta information of the service consumer. Click on "**Details**" to view service status details: - -![dubbo-registry-nacos-2.png](/imgs/blog/dubbo-registry-nacos-2.png) - - - -If you are using the Spring XML configuration file to assemble the Dubbo registry, please refer to the next section. - - - -### Spring XML Configuration File - -Similar to [Dubbo Spring Externalization Configuration](https://mercyblitz.github.io/2018/01/18/Dubbo-%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE/), just adjust the `address` attribute to configure: - -```xml - - - - - - - - - ... - -``` - - -After restarting the Dubbo app, you can also find that the registration meta-information of the service provider and consumer is presented on the Nacos console: - -![dubbo-registry-nacos-3.png](/imgs/blog/dubbo-registry-nacos-3.png) - - -**Additional information**: since nacos-server@1.0.0, support client report instance info which contains particular key in metadata to control some behavior. - -Such as: -`preserved.heart.beat.timeout` : The time of the instance from healthy to unhealthy after heartbeat is not send.(unit:millisecond) -`preserved.ip.delete.timeout` : The time of the instance is dropped by server after the heartbeat is not send.(unit:millisecond) -`preserved.heart.beat.interval` : The interval of the instance to send heartbeat (unit:millisecond) -`preserved.instance.id.generator`: The id generator strategy, value set as `snowflake` means the id will be increment from 0. -`preserved.register.source` : Reserved key, not used at now. - -This feature will be support since Dubbo@`2.7.10`, you can use this feature by append param in nacos address. -Such as: `nacos://10.20.153.10:8848?preserved.heart.beat.timeout=15000&preserved.ip.delete.timeout=30000&preserved.heart.beat.interval=10000` diff --git a/content/en/docs/v2.7/user/references/registry/redis.md b/content/en/docs/v2.7/user/references/registry/redis.md deleted file mode 100644 index ca68a2bca207..000000000000 --- a/content/en/docs/v2.7/user/references/registry/redis.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -type: docs -title: "Redis Registry Server" -linkTitle: "Redis" -weight: 3 -description: "Redis registry server for dubbo" ---- - -# Redis Registry Server - -It is a registry server implementation [^2] based on redis [^1]. - -![/user-guide/images/dubbo-redis-registry.jpg](/imgs/user/dubbo-redis-registry.jpg) - -Use key/map structure in redis to save the registration info: - -* Main key for service name and type -* Key in the map is URL address -* Value in the map is the expiration time. Monitor center uses it to track and remove dirty data [^3] - -Publish/Subscribe events in redis is leveraged for data change notification: - -* Distinguish event type with event's value: `register`, `unregister`, `subscribe`, `unsubscribe`. -* Regular subscriber subscribes the particular key presenting service provider, then will receive `register` and `unregister` events fired from the specified service. -* Monitor center subscribes `/dubbo/*` via `psubscribe`, then will receive all change notifications from all services. - -Procedure: - -0. When service provider boots up, it adds its address under `Key:/dubbo/com.foo.BarService/providers`. -1. Then service provider sends `register` event to `Channel:/dubbo/com.foo.BarService/providers` -2. When service consumer boots up, it subscribe events `register` and `unregister` from `Channel:/dubbo/com.foo.BarService/providers` -3. Then service consumer add its address under `Key:/dubbo/com.foo.BarService/consumers` -4. When service consumer receives events `register` and `unregister`, it will fetch provider's addresses from `Key:/dubbo/com.foo.BarService/providers` -5. When monitor center boots up, it subscribes events `register`, `unregister`, `subscribe`, and `unsubsribe`. -6. After monitor center receives `register` and `unregister`, it fetches provider's addresses from `Key:/dubbo/com.foo.BarService/providers` -7. After monitor center receives `subscribe` and `unsubscribe`, it fetches consumer's addresses from `Key:/dubbo/com.foo.BarService/consumers` - -## Configuration - -```xml - -``` - -Or - -```xml - -``` - -Or - -```xml - -``` - -Or - -```xml - -``` - -## Options - -* Config key's prefix in redis via ``, the default value is `dubbo`. -* Config redis cluster strategy via ``, the default value is `failover`: - * `failover`: when read/write error happens, try another instance, require the cluster to support data replication. - * `replicate`: client writes to all nodes of the cluster, but only peeks a random node for read. The cluster doesn't need to take care of data replication, but may require more nodes and higher performance for each node, compared to option 1. - -## Declaration of Reliability - -A home-brewed service registry server is used in Alibaba instead of redis server. Redis based registry center does not have long-run practice within Alibaba, therefore we cannot guarantee its reliability. This registry server implementation is provided for dubbo community, and its reliability relies on redis itself largely. - -## Installation - - -Pls. refer to [redis install manual](/en/docs/v2.7/admin/install/redis/) for how to install a redis based registry server. To set it up, specify `dubbo.registry.address` to `redis://127.0.0.1:6379` in `conf/dubbo.properties` for both provider and consumer (you can refer to [quick start](/en/docs/v2.7/user/quick-start/)) after install a redis server. - - -[^1]: [Redis](http://redis.io) is a high performance KV cache server -[^2]: Support since `2.1.0` -[^3]: Heartbeat mechanism is used to detect the dirty data in redis. It requires time among servers must be sync in advanced, otherwise expiration check may inaccurate, plus, heartbeats may add extra pressure on servers. diff --git a/content/en/docs/v2.7/user/references/registry/simple.md b/content/en/docs/v2.7/user/references/registry/simple.md deleted file mode 100644 index 179e5b3c57e2..000000000000 --- a/content/en/docs/v2.7/user/references/registry/simple.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -type: docs -title: "Simple Registry Server" -linkTitle: "Simple" -weight: 4 -description: "Simple registry server for dubbo" ---- - -Simple registry server itself is a regular dubbo service. In this way, third-party dependency is unnecessary, and communication keeps consistent at the same moment. - -## Configuration - -Register simple registry server as dubbo service: - -```xml - - - - - - - - - - - - - - -``` - -Reference simple registry server service: - -```xml - -``` - -Or: - -```xml - -``` - -Or: - -```xml - -``` - -## Applicability - -This `SimpleRegistryService` is just a simple implementation for register server, and it doesn't have cluster support. It is useful for the implementation reference for the custom registry server, but not suitable for use in production environment directly. diff --git a/content/en/docs/v2.7/user/references/registry/zookeeper.md b/content/en/docs/v2.7/user/references/registry/zookeeper.md deleted file mode 100644 index bd94ed851cb8..000000000000 --- a/content/en/docs/v2.7/user/references/registry/zookeeper.md +++ /dev/null @@ -1,160 +0,0 @@ ---- -type: docs -title: "Zookeeper Registry Server" -linkTitle: "Zookeeper" -weight: 1 -description: "Zookeeper registry server for dubbo" ---- - -[Zookeeper](http://zookeeper.apache.org) is the child project of apache hadoop. Since it offers tree-like directory service and supports change notification, it's suitable to use it as dubbo's registry server. It's a field-proven product, therefore it's recommended to use it in the production environment. [^1] - -![/user-guide/images/zookeeper.jpg](/imgs/user/zookeeper.jpg) - -Description on registration procedure: - -* When service provider boots up: write service URL address under directory `/dubbo/com.foo.BarService/providers` -* When service consumer boots up: subscribe to `/dubbo/com.foo.BarService/providers` for provider's URL addresses. At the same time, write consumer's URL address under `/dubbo/com.foo.BarService/consumers`. -* When monitor center boots up: subscribe to `/dubbo/com.foo.BarService` for the URL addresses from all providers and consumers. - -The following abilities are supported: -* When provider stops by accident, registry server can remove its info automatically. -* When registry server reboots, all registration data and subscription requests can be recovered automatically. -* When session is expired, all registration data and subscription requests can be recovered automatically. -* When `` is configured, failed requests for subscription and registration will be recorded and kept retrying in the background. -* Configure `` for zookeeper login. -* Configure `` for dubbo's root node on zookeeper. Default root node will be used if it's not specified. -* Support to use wildcard `*` in `` in order to subscribe all groups and all versions for the services to be referenced. - -## How to Use - -Add zookeeper client dependency in both provider and consumer: - -```xml - - org.apache.zookeeper - zookeeper - 3.3.3 - -``` - -Or [download](https://repo1.maven.org/maven2/org/apache/zookeeper/zookeeper) directly from apache. - -Dubbo supports two zookeeper clients: zkclient and curator: - -### Use zkclient - -Since `2.2.0` dubbo uses zkclient by default, in order to improve the robustness. [zkclient](https://github.com/sgroschupf/zkclient) is a zookeeper client implementation open-sourced by Datameer. - -**Note: The implementation of zkclient has been removed in the 2.7.x version. If you want to use the zkclient client, you need to extend it yourself.** - -Default configuration: - -```xml - -``` - -Or: - -```sh -dubbo.registry.client=zkclient -``` - -Or: - -```sh -zookeeper://10.20.153.10:2181?client=zkclient -``` - -In order to use it, need to explicitly declare the following maven dependency or [download its client](https://repo1.maven.org/maven2/com/github/sgroschupf/zkclient). - -```xml - - com.github.sgroschupf - zkclient - 0.1 - -``` - -### Use curator - -Since `2.3.0` dubbo also supports curator but explicit configuration is required. [Curator](https://github.com/Netflix/curator) is the zookeeper client open-sourced by Netflix. - -In order to switch to curator, use the configuration below: - -```xml - -``` - -Or: - -```sh -dubbo.registry.client=curator -``` - -Or: - -```sh -zookeeper://10.20.153.10:2181?client=curator -``` - -Also need to explicitly add maven dependency or directly [download](https://repo1.maven.org/maven2/com/netflix/curator/curator-framework) the jar: - -```xml - - com.netflix.curator - curator-framework - 1.1.10 - -``` - -Zookeeper single node configuration: - -```xml - -``` - -Or: - -```xml - -``` - -Zookeeper cluster configuration: - -```xml - - -``` - -Or: - -```xml - -``` - -Configure single zookeeper to serve as multiple registry servers: - -```xml - - -``` - -## Zookeeper Installation - - -Pls. refer to [zookeeper install manual](/en/docs/v2.7/admin/install/zookeeper/) for how to install zookeeper based registry server. To set it up, specify `dubbo.registry.address` to `zookeeper://127.0.0.1:2181` in `conf/dubbo.properties` for both provider and consumer (you can refer to [quick start](/en/docs/v2.7/user/quick-start/)) after install a zookeeper server. - - -## Declaration of Reliability - -A home-brewed service registry server is used in Alibaba instead of zookeeper server. Zookeeper based registry center does not have long-run practice within Alibaba, therefore we cannot guarantee its reliability. Zookeeper registry server is provided for dubbo community, and its reliability relies on zookeeper itself largely. - -## Declaration of Compatibility - -The original designed data structure for zookeeper in `2.0.8` has the limitation that data type cannot extended, it's redesigned in `2.0.9`. But at the same time incompatibility is introduced, thereby `2.0.9` is required for all service providers and service consumers. - -Since `2.2.0` zkclient is used by default, therefore its dependency is needed. - -Since `2.3.0` curator is supported as alternative option. - -[^1]: Suggest to use `2.3.3` or above for zookeeper registry client diff --git a/content/en/docs/v2.7/user/references/telnet.md b/content/en/docs/v2.7/user/references/telnet.md deleted file mode 100644 index 80c7ad65244f..000000000000 --- a/content/en/docs/v2.7/user/references/telnet.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -type: docs -title: "Telnet Command Reference" -linkTitle: "Telnet" -weight: 11 -description: "Telnet command reference in dubbo" ---- - -Since `2.0.5` dubbo starts supporting to use telnet command to govern services. - -## How To Use - -```sh -telnet localhost 20880 -``` - -Or: - -```sh -echo status | nc -i 1 localhost 20880 -``` - -## Supported Commands - -The built-in telnet commands are listed below. Furthermore, it is possible to extend telnet commands, pls. refer to -[extend telnet command](/en/docs/v2.7/user/references/telnet/) for more details. - -### `ls` - -0. `ls`: list services -0. `ls -l`: list services in more details -0. `ls XxxService`: list methods for the particular service -0. `ls -l XxxService`: list methods for the particular service in more dtails - -### `ps` - -0. `ps`: list service ports -0. `ps -l`: list service addresses -0. `ps 20880`: show connection info for the particular port -0. `ps -l 20880`: show connection info for the particular port in more details - -### `cd` - -0. `cd XxxService`: switch default service. When default service is set, service parameter can be ignored in all commands when it's needed -0. `cd /`: reset default service - -### `pwd` - -`pwd`: show what current default service is - -### `trace` - -0. `trace XxxService`: trace method invocation once for the given service -0. `trace XxxService 10`: trace method invocations 10 times for the given service -0. `trace XxxService xxxMethod`: trace particular method invocation once for the given service -0. `trace XxxService xxxMethod 10`: trace particular method invocations 10 times for the given service - -### `count` - -0. `count XxxService`: count method invocation once for the given service -0. `count XxxService 10`: count method invocations 10 times for the given service -0. `count XxxService xxxMethod`: count particular method invocation once for the given service -0. `count XxxService xxxMethod 10`: count particular method invocation 10 times for the given service - -### `invoke` - -0. `invoke XxxService.xxxMethod(1234, "abcd", {"prop" : "value"})`: invoke particular method for the given service -0. `invoke com.xxx.XxxService.XxxService.xxxMethod(1234, "abcd", {"prop" : "value"})`: invoke particular method for the given service -0. `invoke xxxMethod(1234, "abcd", {"prop" : "value"})`: invoke particular method for the default service -0. `invoke xxxMethod({"name":"zhangsan","age":12,"class":"org.apache.dubbo.qos.legacy.service.Person"})` :When there is parameter overload, or the type conversion fails, you can specify the class to be converted by adding the class attribute -0. When the parameter is Map and the key type is Integer, it is recommended to specify the type. E.g:`invoke com.xxx.xxxApiService({"3":0.123, "class":"java.util.HashMap"})` - -### `select` [^2] - -0. `select 1`: used when the invoke command matches multiple methods, select the method to be called according to the prompt list - -### `status` - -0. `status`: show summarized status. This status summarizes statuses from all resources, and it shows OK when all resources are OK, shows ERROR when any resource has ERROR, and WARN when any has WARN. -0. `status -l`: show status list - -### `log` [^1] - -0. `log debug`: modify logger level to debug -0. `log 100`: examine the last 100 characters from the file logger - -### `help` - -0. `help`: show help for telnet commands -0. `help xxx`: show help for particular telnet command - -### `clear` - -0. `clear`: clear screen -0. `clear 100`: only clear particular lines on the screen - -### `exit` - -`exit`: exit current telnet session - -### `shutdown` [^2] - -0. `shutdown`: shutdown dubbo application -0. `shutdown -t 1000`: delay 1000 ms to shutdown dubbo application - -[^1]: support since `2.0.6` -[^2]: support since `2.7.1` - diff --git a/content/en/docs/v2.7/user/references/xml/_index.md b/content/en/docs/v2.7/user/references/xml/_index.md deleted file mode 100644 index c7d3fd3eb028..000000000000 --- a/content/en/docs/v2.7/user/references/xml/_index.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -type: docs -title: "Schema Configuration Reference" -linkTitle: "XML" -weight: 1 -description: "XML schema configuration reference for dubbo" ---- - - -The following pages show all the configuration properties [^2] with XML Config [^1] as an example. For other configurations, please reference: [Properties Configuration](../../configuration/properties), [Annotation Configuration](../../configuration/annotation), [API Configuration](../../configuration/api). - -All configuration properties fall into three categories, see the "Function" in the table below. - -* Service discovery: used for service registration and discovery in order to find providers for consumers. -* Service governance: used for service management and governance, such as to provide conveninence for dev or test. -* Performance optinize: used for optimizing performance. Diffenent properties may has different performance impact. -* All properties will transform into URL [^3] which is generated by provider. The url will be subscribed by consumers through registry. Please see the `Corresponding URL parameter` in the table below for each property. - - -[^1]: XML Schema: http://dubbo.apache.org/schema/dubbo/dubbo.xsd -[^2]: Notice: These three properties, group, interface, and version determine a service. All other properties are used for service governance or performance optimize. -[^3]: URL format:`protocol://username:password@host:port/path?key=value&key=value` - diff --git a/content/en/docs/v2.7/user/references/xml/dubbo-application.md b/content/en/docs/v2.7/user/references/xml/dubbo-application.md deleted file mode 100644 index a264341e7b6b..000000000000 --- a/content/en/docs/v2.7/user/references/xml/dubbo-application.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -type: docs -title: "dubbo:application" -linkTitle: "dubbo:application" -weight: 1 -description: "dubbo:application element" ---- - - -Application configuration. The corresponding class: `org.apache.dubbo.config.ApplicationConfig` - -| Property | Corresponding URL parameter | Type | Requisite | Default | Effect | Description | Compatibility | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| name | application | string | Y | | service governance | Application name is the unique identifier of an application. It is for registry combing the dependencies of applications. Note: Consumer and provider application name should not be the same, and this parameter is not a match condition. As a suggestion, you can name it as your project name. For example, kylin application invokes the service of morgan application, then you can name kylin application as "kylin", and morgan application as "morgan". Maybe kylin also works as a provider, but kylin should still called "kylin". In this way, registry can understand the dependence of applications | above 1.0.16 | -| version | application.version | string | N | | service governance | The version of current application | above 2.2.0 | -| owner | owner | string | N | | service governance | Application manager. Pls. fill in the mailbox prefix of the person in charge | above 2.0.5 | -| organization | organization | string | N | | service governance | Organization name is for registry distinguishing between the source of service. As a suggestion, this property should be written in config file directly. Such as china,intl,itu,crm,asc,dw,aliexpress etc. | above 2.0.0 | -| architecture
| architecture
| string | N | | service governance | The architecture of service layering. Like intl,china and so on. Different architecture use different layer | above 2.0.7 | -| environment | environment | string | N | | service governance | Application environment. Like develop,test,product. Work as the limit condition of developing new function| above 2.0.0 | -| compiler | compiler | string | N | javassist | performance optimization | Java class compile.It is used for the generating of dynamic class. The options are JDK and javassist | above 2.1.0 | -| logger | logger | string | N | slf4j | performance optimization | The format of log output,The options are slf4j,jcl,log4j,log4j2 and jdk | above 2.2.0 | diff --git a/content/en/docs/v2.7/user/references/xml/dubbo-argument.md b/content/en/docs/v2.7/user/references/xml/dubbo-argument.md deleted file mode 100644 index d8a114503d49..000000000000 --- a/content/en/docs/v2.7/user/references/xml/dubbo-argument.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "dubbo:argument" -linkTitle: "dubbo:argument" -weight: 1 -description: "dubbo:argument element" ---- - -Method argument configuration. The corresponding class:`org.apache.dubbo.config.ArgumentConfig`. This tag is child of ``, which is for feature description of method argument, such as: - -```xml - - - -``` -| Property | Corresponding URL parameter | Type | Requisite | Default | Effect | Description | Compatibility | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| index | | int | Y | | identification | method name | above 2.0.6 | -| type | | String | Index and type choose one | | identification | Find index of argument by it | above 2.0.6 | -| callback | <metodName><index>.retries | boolean | N | | service governance | Mark whether this argument is a callback service. If true, provider will generate reverse proxy,which can invoke consumer in turn. Generally for event pushing | above 2.0.6 | diff --git a/content/en/docs/v2.7/user/references/xml/dubbo-config-center.md b/content/en/docs/v2.7/user/references/xml/dubbo-config-center.md deleted file mode 100644 index 2ca848b65e5c..000000000000 --- a/content/en/docs/v2.7/user/references/xml/dubbo-config-center.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -type: docs -title: "dubbo:config-center" -linkTitle: "dubbo:config-center" -weight: 1 -description: "dubbo:config-center element" ---- - - - -Configuration center. Corresponding configuration class: `org.apache.dubbo.config.ConfigCenterConfig` - -| property | Corresponding URL parameter | type | required | default value | description | compatibility | -| ---------------- | ---------------------- | ------------------- | -------- | ---------------- | ------------------------------------------------------------ | ------ | -| protocol | config.protocol | string | optional | zookeeper | Which configuration center to use: apollo, zookeeper, nacos, etc.
take zookeeper for example
1. If protocol is specified, address can be simplified to `127.0.0.1:2181`;
2. If protocol is not specified, address is set to `zookeeper://127.0.0.1:2181` | 2.7.0+ | -| address | config.address | string | required | | Configuration center address.
See protocol description for values | 2.7.0+ | -| highest-priority | config.highestPriority | boolean | optional | true | Configuration items from the configuration center have the highest priority, it means that the local configuration items will be overwritten. | 2.7.0+ | -| namespace | config.namespace | string | optional | dubbo | Using for multi-tenant isolation generally, the actual meaning varies depending on the configuration center.
For example:
zookeeper - Environment isolation, default `dubbo`;
apollo - Distinguish between sets of configurations for different domains and use them by default `dubbo` and `application` | 2.7.0+ | -| cluster | config.cluster | string | optional | | The meaning varies according to the configuration center selected.
For example, it's used to distinguish between different configuration clusters in apollo | 2.7.0+ | -| group | config.group | string | optional | dubbo | The meaning varies according to the configuration center selected.
nacos - Isolate different configuration sets
zookeeper - Isolate different configuration sets | 2.7.0+ | -| check | config.check | boolean | optional | true | Whether to terminate application startup when the configuration hub connection fails. | 2.7.0+ | -| config-file | config.configFile | string | optional | dubbo.properties | The key mapped to the global level profile
zookeeper - $DEFAULT_PATH/dubbo/config/dubbo/dubbo.properties
apollo - The dubbo.properties key in dubbo namespace | 2.7.0+ | -| timeout | config.timeout | integer | | 3000ms | Gets the configured timeout | 2.7.0+ | -| username | | string | | | the username if the configuration center requires validation
Apollo is not yet enabled | 2.7.0+ | -| password | | string | | | password if configuration center needs to do check
Apollo is not yet enabled | 2.7.0+ | -| parameters | | Map | | | Extended parameters to support customized configuration parameters for different configuration centers | 2.7.0+ | -| include-spring-env | | boolean | optional | false | With the Spring framework support, when the value is `true`, it will automatically reads the configuration from the Spring Environment
Read by default
Configuration with key `dubbo.properties`
PropertySource with key `dubbo.properties` | 2.7.0+ | diff --git a/content/en/docs/v2.7/user/references/xml/dubbo-consumer.md b/content/en/docs/v2.7/user/references/xml/dubbo-consumer.md deleted file mode 100644 index 86b34a12cee1..000000000000 --- a/content/en/docs/v2.7/user/references/xml/dubbo-consumer.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -type: docs -title: "dubbo:consumer" -linkTitle: "dubbo:consumer" -weight: 1 -description: "dubbo:consumer element" ---- - -Consumer default configuration. The corresponding clas: `org.apache.dubbo.config.ConsumerConfig`. It is also default configuration of ``. - -| Property | Corresponding URL parameter | Type | Requisite | Default | Effect | Description | Compatibility | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| timeout | default.timeout | int | N | 1000 | performance optimization | invoking timeout(ms) | above 1.0.16 | -| retries | default.retries | int | N | 2 | performance optimization | Invoking retry times, exclude the first invoking. Set 0 to disable it.Only valid if the cluster's value is failback/failover | above 1.0.16 | -| loadbalance | default.loadbalance | string | N | random | performance optimization | Load balancing strategy. Choices:random, roundrobin(polling), leastactive(invoking least active service) | above 1.0.16 | -| async | default.async | boolean | N | false | performance optimization | Whether invoke asynchronously | above 2.0.0 | -| connections | default.connections | int | N | 100 | performance optimization | The maximum number of connections of per service provider. Only short link protocol such as rmi,http,hessian etc. supports. Long link protocol such as dubbo doesn't support | above 1.0.16 | -| generic | generic | boolean | N | false | service governance | Whether default generic interface. A instance of GenericService will be got if true. | above 2.0.0 | -| check | check | boolean | N | true | service governance | Whether check the survival of provider. If true, throw exception when no provider of some services is alive. Otherwise, just ignore it| above 1.0.16 | -| proxy | proxy | string | N | javassist | performance optimization | Java class compile.It is used for the generating of dynamic class. The options are JDK and javassist | above 2.0.5 | -| owner | owner | string | N | | service governance | Application manager. Pls. fill in the mailbox prefix of the person in charge | above 2.0.5 | -| actives | default.actives | int | N | 0 | performance optimization | The max concurrency of per service method for each corresponding consumer | above 2.0.5 | -| cluster | default.cluster | string | N | failover | performance optimization | Cluster tolerance. Choices:failover/failfast/failsafe/failback/forking | above 2.0.5 | -| filter | reference.filter | string | N | | performance optimization | The name of filter which intercepts consumer remote invoke. Multiple names are separated by commas | above 2.0.5 | -| listener | invoker.listener | string | N | | performance optimization | The consumer referenced service listener name. Multiple names are separated by commas | above 2.0.5 | -| registry | | string | N | register with the registry | configuration relevant | Register with the designated registry. Generally,for multiple registries, and value is the "id" of <dubbo:registry>. Multiple registries are separated by commas.If you do not want to register the service to any registry,pls set "N/A" | above 2.0.5 | -| layer | layer | string | N | | service governance | The layer of consumer. Such as: biz, dao, intl:web, china:acton | above 2.0.7 | -| init | init | boolean | N | false | performance optimization | If true, initialize when "afterPropertiesSet()" is invoked. Otherwise wait until the instance is referenced to initialize | above 2.0.10 | -| cache | cache | string/boolean | N | | service governance | Cache return result, and key is call parameters. Choices: lru, threadlocal, jcache and so on | at least 2.1.0 | -| validation | validation | boolean | N | | service governance | Whether enable JSR303 standard annotation validation| at least 2.1.0 | diff --git a/content/en/docs/v2.7/user/references/xml/dubbo-method.md b/content/en/docs/v2.7/user/references/xml/dubbo-method.md deleted file mode 100644 index f77292281bd8..000000000000 --- a/content/en/docs/v2.7/user/references/xml/dubbo-method.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -type: docs -title: "dubbo:method" -linkTitle: "dubbo:method" -weight: 1 -description: "dubbo:method element" ---- - - -Method level configuration. The corresponding class: `org.apache.dubbo.config.MethodConfig`. This tag is a child tag of `` or ``, for accuracy to method level. - -| Property | Corresponding URL parameter | Type | Requisite | Default | Effect | Description | Compatibility | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| name | | string | Y | | identifier | Method name | above 1.0.8 | -| timeout | <metodName>.timeout | int | N | <dubbo:reference> timeout | performance optimization | Method call timeout(ms)| above 1.0.8 | -| retries | <metodName>.retries | int | N | <dubbo:reference> retries | performance optimization | Invoking retry times, exclude the first invoking. Set 0 to disable it| above 2.0.0 | -| loadbalance | <metodName>.loadbalance | string | N | <dubbo:reference> loadbalance | performance optimization | Load balancing strategy. Choices:random, roundrobin(polling), leastactive(invoking least active service) | above 2.0.0 | -| async | <metodName>.async | boolean | N |<dubbo:reference> async | performance optimization | Whether invoke asynchronously | above 1.0.9 | -| sent | <methodName>.sent | boolean | N | true | performance optimization | Generally used when async is true, and If true, indicate that the network has sent out data | above 2.0.6 | -| actives | <metodName>.actives | int | N | 0 | performance optimization | The max concurrency of per service method for each corresponding consumer | above 2.0.5 | -| executes | <metodName>.executes | int | N | 0 | performance optimization | The maximum number of threads of per service method is limited- -. Only take effect when <dubbo:method> is <dubbo:service> child tag | above 2.0.5 | -| deprecated | <methodName>.deprecated | boolean | N | false | service governance | Whether is deprecated method. Only take effect when <dubbo:method> is <dubbo:service> child tag | above 2.0.5 | -| sticky | <methodName>.sticky | boolean | N | false | service governance | If true, all methods on this interface use the same provider. If more complex rules are required, use routing | above 2.0.6 | -| return | <methodName>.return | boolean | N | true | performance optimization | Whether need return value. Only take effect when async is true. If true, return future, or callback such as "onreturn" method. Otherwise, return null. | above 2.0.6 | -| oninvoke | | String | N | | performance optimization | Intercept before invoke | above 2.0.6 | -| onreturn | | String | N | | performance optimization | Intercept after invoke| above 2.0.6 | -| onthrow | | String | N | | performance optimization | Intercept when catch exception | above 2.0.6 | -| cache | <methodName>.cache | string/boolean | N | | service governance | Cache return result, and key is call parameters. Choices: lru, threadlocal, jcache and so on | at least 2.1.0 | -| validation | <methodName>.validation | boolean | N | | service governance | Whether enable JSR303 standard annotation validation| at least 2.1.0| - -For example: - -```xml - - - -``` diff --git a/content/en/docs/v2.7/user/references/xml/dubbo-module.md b/content/en/docs/v2.7/user/references/xml/dubbo-module.md deleted file mode 100644 index 5d79053934bc..000000000000 --- a/content/en/docs/v2.7/user/references/xml/dubbo-module.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "dubbo:module" -linkTitle: "dubbo:module" -weight: 1 -description: "dubbo:module element" ---- - -Module configuration. The corresponding class `org.apache.dubbo.config.ModuleConfig` - -| Property | The corresponding class | Type | Requisite | Default | Effect | Description | Compatibility | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| name | module | string | Y | | service governance | Module name is for registry combing the dependencies of modules. | above 2.2.0 | -| version | module.version | string | N | | service governance | module version | above 2.2.0 | -| owner | owner | string | N | | service governance | Module manager, Pls. fill in the mailbox prefix of the person in charge | above 2.2.0 | -| organization | organization | string | N | | service governance |Organization name is for registry distinguishing between the source of service. As a suggestion, this property should be written in config file directly. Such as china,intl,itu,crm,asc,dw,aliexpress etc. | above 2.2.0 | diff --git a/content/en/docs/v2.7/user/references/xml/dubbo-monitor.md b/content/en/docs/v2.7/user/references/xml/dubbo-monitor.md deleted file mode 100644 index e6f329bb578d..000000000000 --- a/content/en/docs/v2.7/user/references/xml/dubbo-monitor.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "dubbo:monitor" -linkTitle: "dubbo:monitor" -weight: 1 -description: "dubbo:monitor element" ---- - - -Monitor center configuration. The corresponding class: `org.apache.dubbo.config.MonitorConfig` - -| Property | The corresponding class | Type | Requisite | Default | Effect | Description | Compatibility | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| protocol | protocol | string | N | dubbo | service governance | Monitor center protocol. "registry" means looking up monitor center from registry. Others mean communicating to monitor center directly | above 2.0.9 | -| address | <url> | string | N | N/A | service governance | Communicating to monitor center directly. address="10.20.130.230:12080" | above 1.0.16 | diff --git a/content/en/docs/v2.7/user/references/xml/dubbo-parameter.md b/content/en/docs/v2.7/user/references/xml/dubbo-parameter.md deleted file mode 100644 index c62bb0caf460..000000000000 --- a/content/en/docs/v2.7/user/references/xml/dubbo-parameter.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -type: docs -title: "dubbo:parameter" -linkTitle: "dubbo:parameter" -weight: 1 -description: "dubbo:parameter element" ---- - -Optional parameter configuration. The corresponding class is `java.util.Map`. This tag is used as a sub tag to configure custom parameters for extending ``, ``, ``, `` or ``. - -| Attribute | Corresponding URL parameter | Type | Required | Default Value | Function | Description | Compatibility | -| --------- | --------------------------- | ------ | ----------- | ------------- | ------------------ | ----------------------- | ------------- | -| key | key | string | True | | Service governance | routing parameter key | Above 2.0.0 | -| value | value | string | True | | Service governance | routing parameter value | Above 2.0.0 | - -For example: - -```xml - - - -``` - -you can also use it like this: - -```xml - -``` diff --git a/content/en/docs/v2.7/user/references/xml/dubbo-protocol.md b/content/en/docs/v2.7/user/references/xml/dubbo-protocol.md deleted file mode 100644 index 2ce922a13988..000000000000 --- a/content/en/docs/v2.7/user/references/xml/dubbo-protocol.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -type: docs -title: "dubbo:protocol" -linkTitle: "dubbo:protocol" -weight: 1 -description: "dubbo:protocol element" ---- - -Service provider protocol configuration. The corresponding class is `org.apache.dubbo.config.ProtocolConfig`. If you need to support multiple protocols, you could declare multiple `` tags, and specify the protocol via `protocol` property. - -| Attribute | Corresponding URL parameter | Type | Required | Default Value | Function | Description | Compatibility | -| ------------- | --------------------------- | -------------- | ----------- | ---------------------------------------- | ------------------------- | ---------------------------------------- | ------------- | -| id | | string | False | dubbo | Configuration association | Bean Id of the protocol, can be referenced in <dubbo:service protocol=""> The default value is equal to the value of `name` attribute while `id` is not filled. If `name` value has already existed, it will add index to it's suffix. | Above 2.0.5 | -| name | <protocol> | string | True | dubbo | Performance optimize | Protocol name | Above 2.0.5 | -| port | <port> | int | False | The default port of dubbo protocol is 20880, rmi protocol is 1099, http and hessian protocol are 80;It will allocate the default port if `port` is not filled; It will allocate an unused port if `port` equals `-1`. To ensure the ports scope is controllable, the port will increase based on the corresponding protocol default port after Dubbo 2.4.0+ | Service discovery | Service port | Above 2.0.5 | -| host | <host> | string | False | Find local IP automatically | Service discovery | -The host name of services, to specify VIP and domain, or having multiple network cards. If null, it will find local IP automatically- It's recommended to let Dubbo find local IP automatically | Above 2.0.5 | -| threadpool | threadpool | string | False | fixed | Performance optimize | The type of Thread Pool, fixed/cached are available | Above 2.0.5 | -| threads | threads | int | False | 200 | Performance optimize | The size of the services' Thread Pool(Fixed) | Above 2.0.5 | -| iothreads | threads | int | False | The count of CPU + 1 | Performance optimize | The size of io Thread Pool(Fixed) | Above 2.0.5 | -| accepts | accepts | int | False | 0 | Performance optimize | The maximum connection count of the service provider | Above 2.0.5 | -| payload | payload | int | False | 8388608(=8M) | Performance optimize | The length limit of request and response, unit is byte | Above 2.0.5 | -| codec | codec | string | False | dubbo | Performance optimize | Protocol encoding | Above 2.0.5 | -| serialization | serialization | string | False | The default serialization of dubbo protocol is hessian2, rmi protocol is java, http protocol is json | Performance optimize | Protocol serialization, It's used when a protocol has multiple serializations. For example, `dubbo` protocol has 4 serializations, they are `dubbo`, `hessian2`, `java` and `compactedjava`. | Above 2.0.5 | -| accesslog | accesslog | string/boolean | False | | Service discovery | `true` will write access log to logger. Specifying it to a log path, you can write access logs to special log file. | Above 2.0.5 | -| path | <path> | string | False | | Service discovery | Context path, the prefix of the service path | Above 2.0.5 | -| transporter | transporter | string | False | The default value of dubbo protocol is netty | Performance optimize | The server and client implements of the protocol. For example, mina and netty for dubbo protocol. You can configure server or client side separately. | Above 2.0.5 | -| server | server | string | False | The default value of dubbo protocol is netty, http protocol is servlet | Performance optimize | The server implement of the protocol. For example, mina and netty for dubbo ptotocol, jetty and servlet for http protocol. | Above 2.0.5 | -| client | client | string | False | The default value of dubbo protocol is netty | Performance optimize | The client implement of the protocol. For example, mina and netty for dubbo protocol. | Above 2.0.5 | -| dispatcher | dispatcher | string | False | The default value of dubbo protocol is all | Performance optimize | specify the thread model of the way to dispatching. Such as `all`, `direct`, `message`, `execution`, and `connection` for dubbo protocol. | Above 2.1.0 | -| queues | queues | int | False | 0 | Performance optimize | The queue size of the Thread Pool. It's recommended not to specify it in order to invoke other provides rather than queueing unless you have special requirement. | Above 2.0.5 | -| charset | charset | string | False | UTF-8 | Performance optimize | Serialization encoding | Above 2.0.5 | -| buffer | buffer | int | False | 8192 | Performance optimize | The buffer size of networking IO | Above 2.0.5 | -| heartbeat | heartbeat | int | False | 0 | Performance optimize | Heartbeat interval. For long connection, it's difficult to receive closing event while the physical layer is disconnected. So heartbeat is necessary to help checking the connection quality | Above 2.0.10 | -| telnet | telnet | string | False | | Service discovery | Supported telnet commands, use `,` to separate commands. | Above 2.0.5 | -| register | register | boolean | False | true | Service discovery | Whether registering the corresponding services to registry center | Above 2.0.8 | -| contextpath | contextpath | String | False | Default value is an empty string | Service discovery | | Above 2.0.6 | diff --git a/content/en/docs/v2.7/user/references/xml/dubbo-provider.md b/content/en/docs/v2.7/user/references/xml/dubbo-provider.md deleted file mode 100644 index 69d5e95dc56c..000000000000 --- a/content/en/docs/v2.7/user/references/xml/dubbo-provider.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -type: docs -title: "dubbo:provider" -linkTitle: "dubbo:provider" -weight: 1 -description: "dubbo:provider element" ---- - -The default configuration of service provider. The corresponding class is `org.apache.dubbo.config.ProviderConfig`. This tag provider default values for `` and ``. - -| Attribute | Corresponding URL parameter | Type | Required | Default Value | Function | Description | Compatibility | -| ------------- | --------------------------- | -------------- | -------- | ---------------------------------------- | ------------------------- | ---------------------------------------- | ------------- | -| id | | string | False | dubbo | Configuration association | Bean Id of the protocol, can be referenced in <dubbo:service proivder=""> | Above 1.0.16 | -| protocol | <protocol> | string | False | dubbo | Performance optimize | Protocol name | Above 1.0.16 | -| host | <host> | string | False | Find local IP automatically | Service discovery | The host name of services, to specify VIP and domain, or having multiple network cards. If null, it will find local IP automatically. It's recommended to let Dubbo find local IP automatically | Above 1.0.16 | -| threads | threads | int | False | 200 | Performance optimize | The size of the services' Thread Pool(Fixed) | Above 1.0.16 | -| payload | payload | int | False | 8388608(=8M) | Performance optimize | The length limit of request and response, unit is byte | Above 2.0.0 | -| path | <path> | string | False | | Service discovery | Context path of the service provider, the prefix of the service path | Above 2.0.0 | -| server | server | string | False | Default is netty for dubbo protocol, servlet for http protocol | Performance optimize | The server implement of the protocol. For example, mina and netty for dubbo ptotocol, jetty and servlet for http protocol. | Above 2.0.0 | -| client | client | string | False | Default is netty for dubbo protocol | Performance optimize | The client implement of the protocol. For example, mina and netty for dubbo protocol. | Above 2.0.0 | -| codec | codec | string | False | dubbo | Performance optimize | Protocol encoding | Above 2.0.0 | -| serialization | serialization | string | False | Default is hessian2 for dubbo protocol, json for http protocol | Performance optimize | Protocol serialization, It's used when a protocol has multiple serializations. For example, `dubbo` protocol has 4 serializations, they are `dubbo`, `hessian2`, `java` and `compactedjava`, `http` protocol has `json` and `xml`. | Above 2.0.5 | -| default | | boolean | False | false | Configuration association | To specify the default protocol for support multiple protocols. | Above 1.0.16 | -| filter | service.filter | string | False | | Performance optimize | The filter name of the RPC process of the provider, use `,` to separate multiple filter names. | Above 2.0.5 | -| listener | exporter.listener | string | False | | Performance optimize | The listener name of the provider, use `,` to separate multiple listener names. | Above 2.0.5 | -| threadpool | threadpool | string | False | fixed | Performance optimize | The type of Thread Pool, fixed/cached are available | Above 2.0.5 | -| accepts | accepts | int | False | 0 | Performance optimize | The maximum connection count of the service provider | Above 2.0.5 | -| version | version | string | False | 0.0.0 | Service discovery | Service version. It's recommended to use 2 digitals such as `1.0`. It's necessary to upgrade version only when the service is not compatible. | Above 2.0.5 | -| group | group | string | False | | Service discovery | The group of the service providers. It can distinguish services when it has multiple implements. | Above 2.0.5 | -| delay | delay | int | False | 0 | Performance optimize | The delay time(ms) for registering services. When set to -1, it indicates that the services will expose to registry after the Spring context is initialized | Above 2.0.5 | -| timeout | default.timeout | int | False | 1000 | Performance optimize | The RPC timeout(ms) | Above 2.0.5 | -| retries | default.retries | int | False | 2 | Performance optimize | The retry count for RPC, not including the first invoke. Please set it to 0 if don't need to retry. | Above 2.0.5 | -| connections | default.connections | int | False | 0 | Performance optimize | The maximum connections of every provider. For short connection such as rmi, http and hessian, it's connection limit, but for long connection such as dubbo, it's connection count. | Above 2.0.5 | -| loadbalance | default.loadbalance | string | False | random | Performance optimize | Strategy of load balance, `random`, `roundrobin` and `leastactive` are available. | Above 2.0.5 | -| async | default.async | boolean | False | false | Performance optimize | Asynchronous execution, not reliable. It does not block the execution thread just only ignores the return value. | Above 2.0.5 | -| stub | stub | boolean | False | false | Service governance | `true` means use the default proxy class name, which is the interface name with `Local` as the suffix. | Above 2.0.5 | -| mock | mock | boolean | False | false | Service governance | `true` means use the default mock class name, which is the interface name with `Mock` suffix. | Above 2.0.5 | -| token | token | boolean | False | false | Service governance | Enable token validation. Disable token if it's null. It will generate token randomly when it is enable. | Above 2.0.5 | -| registry | registry | string | False | By default, register to all registries | Configuration association | Register services to specified registry while having multiple registries. It is the `id` value of the <dubbo:registry>. If don't want to register to any registry, set it as `N/A` | Above 2.0.5 | -| dynamic | dynamic | boolean | False | true | Service governance | Whether the service is registered dynamically. If false, services will be showed as `disable`, you need to enable it manually. And you also need to disable it when provider shut down. | Above 2.0.5 | -| accesslog | accesslog | string/boolean | False | false | Service governance | `true` will write access log to logger. Specifying it to a log path, you can write access logs to special log file. | Above 2.0.5 | -| owner | owner | string | False | | Service governance | The owner of the service. It's used for service governance. | Above 2.0.5 | -| document | document | string | False | | Service governance | Service document URL | Above 2.0.5 | -| weight | weight | int | False | | Performance optimize | The weight of the service | Above 2.0.5 | -| executes | executes | int | False | 0 | Performance optimize | The maximum parallel execution request count per method per service for the provider. | Above 2.0.5 | -| actives | default.actives | int | False | 0 | Performance optimize | The maximum concurrent calls per method per service of the consumer. | Above 2.0.5 | -| proxy | proxy | string | False | javassist | Performance optimize | The proxy implement, jdk/javassist are available. | Above 2.0.5 | -| cluster | default.cluster | string | False | failover | Performance optimize | failover/failfast/failsafe/failback/forking are available. | Above 2.0.5 | -| deprecated | deprecated | boolean | False | false | Service governance | Mark the service is deprecated. If true, there will log an error log on the client side. | Above 2.0.5 | -| queues | queues | int | False | 0 | Performance optimize | The queue size of the Thread Pool. It's recommended not to specify it in order to invoke other provides rather than queueing unless you have special requirement. | Above 2.0.5 | -| charset | charset | string | False | UTF-8 | Performance optimize | Serialization encoding | Above 2.0.5 | -| buffer | buffer | int | False | 8192 | Performance optimize | The buffer size of networking IO | Above 2.0.5 | -| iothreads | iothreads | int | False | CPU + 1 | Performance optimize | The size of io Thread Pool(Fixed). These threads are used to receive, serialize and deserialize IO data. See `threads` for configuring business thread pool. It's not recommended to configure this. | Above 2.0.5 | -| telnet | telnet | string | False | | Service governance | Supported telnet commands, use `,` to separate commands. | Above 2.0.5 | -| contextpath | contextpath | String | False | Empty string | Service governance | | | -| layer | layer | string | False | | Service governance | The biz layer of the service provider, such as biz, dao, intl:web and china:acton. | Above 2.0.7 | diff --git a/content/en/docs/v2.7/user/references/xml/dubbo-reference.md b/content/en/docs/v2.7/user/references/xml/dubbo-reference.md deleted file mode 100644 index 143048184ddc..000000000000 --- a/content/en/docs/v2.7/user/references/xml/dubbo-reference.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -type: docs -title: "dubbo:reference" -linkTitle: "dubbo:reference" -weight: 1 -description: "dubbo:reference element" ---- - -The configuration of service consumer. The corresponding class is`org.apache.dubbo.config.ReferenceConfig` - -| Attribute | Corresponding URL parameter | Type | Required | Default Value | Function | Description | Compatibility | -| ----------- | --------------------------- | -------------- | ----------- | ---------------------------------------- | ------------------------- | ---------------------------------------- | ------------- | -| id | | string | True | | Configuration association | Bean Id of the service reference | Above 1.0.0 | -| interface | | class | True | | Service discovery | Interface name of the service | Above 1.0.0 | -| version | version | string | False | | Service discovery | Service version, must be equal to the provider's version | Above 1.0.0 | -| group | group | string | False | | Service discovery | The group of the service reference, must be equal to the provider's group. It can distinguish services when it has multiple implements. | Above 1.0.7 | -| timeout | timeout | long | False | By default, use ` tags, and then reference specified registry with `registry` property in `` or `` tag. - -| Attribute | Corresponding URL parameter | Type | Required | Default Value | Function | Description | Compatibility | -| --------- | --------------------------- | ------- | ----------- | ------------- | ------------------------- | ---------------------------------------- | ------------- | -| id | | string | False | | Configuration association | Bean Id of the registry center, can be referenced in <dubbo:service registry="">or <dubbo:reference registry=""> | Above 1.0.16 | -| address | <host:port> | string | True | | Service discovery | The address of the registry center. If the address has no port, default port 9999 will be adopted. Multiple addresses within the same cluster use `,` to seperate, such as `ip:port,ip:port`. Multiple registries within different cluster, please configure different `dubbo:registry` tag. | Above 1.0.16 | -| protocol | <protocol> | string | False | dubbo | Service discovery | The protocol of the registry center. `dubbo`, `multicast`, `zookeeper`, `redis`, `consul(2.7.1)`, `sofa(2.7.2)`, `etcd(2.7.2)`, `nacos(2.7.2)` are available. | Above 2.0.0 | -| port | <port> | int | False | 9090 | Service discovery | The default port of the registry. When the `address` has no port, this default port will be adopted. | Above 2.0.0 | -| username | <username> | string | False | | Service governance | The usename of the registry. Do not set it if the registry doesn't need validation. | Above 2.0.0 | -| password | <password> | string | False | | Service governance | The password of the registry. Do not set it if the registry doesn't need validation. | Above 2.0.0 | -| transport | registry.transporter | string | False | netty | Performance optimize | mina, netty are available. | Above 2.0.0 | -| timeout | registry.timeout | int | False | 5000 | Performance optimize | The timeout(ms) of the request to registry. | Above 2.0.0 | -| session | registry.session | int | False | 60000 | Performance optimize | The session timeout(ms) of the registry. It's used to check whether the providers are alive. It depends on the implement of the registry. For example, for HeartBeat implement, the timeout is the interval of two heart beats. | Above 2.1.0 | -| file | registry.file | string | False | | Service governance | The local file to cache the address list of registries and providers. When application restarts, it will restore the registries and providers. Please use different file for different registy. | Above 2.0.0 | -| wait | registry.wait | int | False | 0 | Performance optimize | Stop wait for a notice completion time (ms) | Above 2.0.0 | -| check | check | boolean | False | true | Service governance | Whether throwing exception while the registry isn't existed. | Above 2.0.0 | -| register | register | boolean | False | true | Service governance | whether registering to the registry center. If false, just subscribing, not registering. | Above 2.0.5 | -| subscribe | subscribe | boolean | False | true | Service governance | whether subscribing from the registry center. If false, just registering, not subscribing. | Above 2.0.5 | -| dynamic | dynamic | boolean | False | true | Service governance | Whether the service is registered dynamically. If false, services will be showed as `disable`, you need to enable it manually. And you also need to disable it when provider shut down. | Above 2.0.5 | -| group | group | string | False | dubbo | Service governance | Service registration grouping, cross-group services will not affect each other, and can not be called each other, suitable for environmental isolation. | Above 2.0.5 | -| simplified| simplified | boolean | False | false | Service governance | Registered with the registry URL whether to adopt the lean mode (compatible with low version) | Above 2.7.0 | -| extra-keys| extraKeys | string | False | | Service governance | In simplified = true, extraKeys allows you to outside the default arguments put additional key in the URL, format: "interface, key1, key2". | Above 2.7.0 | diff --git a/content/en/docs/v2.7/user/references/xml/dubbo-service.md b/content/en/docs/v2.7/user/references/xml/dubbo-service.md deleted file mode 100644 index ff46c19a789b..000000000000 --- a/content/en/docs/v2.7/user/references/xml/dubbo-service.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -type: docs -title: "dubbo:service" -linkTitle: "dubbo:service" -weight: 1 -description: "dubbo:service element" ---- - -The configuration of the service provider. The corresponding class is `org.apache.dubbo.config.ServiceConfig`. - -| Attribute | Corresponding URL parameter | Type | Required | Default Value | Function | Description | Compatibility | -| ----------- | --------------------------- | -------------- | ----------- | ------------------------------------- | ------------------------- | ---------------------------------------- | ------------- | -| interface | | class | True | | Service discovery | The service interface name | Above 1.0.0 | -| ref | | object | True | | Service discovery | The reference to the service implementation | Above 1.0.0 | -| version | version | string | False | 0.0.0 | Service discovery | Service version. It's recommended to use 2 digitals such as `1.0`. It's necessary to upgrade version only when the service is not compatible. | Above 1.0.0 | -| group | group | string | False | | Service discovery | The group of the service providers. It can distinguish services when it has multiple implements. | Above 1.0.7 | -| path | <path> | string | False | default value is the interface name | Service discovery | In 1.0, service path is not supported, it's always equals to the interface name. So it may not compitable when a service reference in 1.0 calls a service provider in 2.0 that specified path. | Above 1.0.12 | -| delay | delay | int | False | 0 | Performance optimize | The delay time(ms) for registering services. When set to -1, it indicates that the services will expose to registry after the Spring context is initialized | Above 1.0.14 | -| timeout | timeout | int | False | 1000 | Performance optimize | The RPC timeout(ms) | Above 2.0.0 | -| retries | retries | int | False | 2 | Performance optimize | The retry count for RPC, not including the first invoke. Please set it to 0 if don't need to retry. | Above 2.0.0 | -| connections | connections | int | False | 100 | Performance optimize | The maximum connections of every provider. For short connection such as rmi, http and hessian, it's connection limit, but for long connection such as dubbo, it's connection count. | Above 2.0.0 | -| loadbalance | loadbalance | string | False | random | Performance optimize | Strategy of load balance, `random`, `roundrobin` and `leastactive` are available. | Above 2.0.0 | -| async | async | boolean | False | false | Performance optimize | Asynchronous execution, not reliable. It does not block the execution thread just only ignores the return value. | Above 2.0.0 | -| local | local | class/boolean | False | false | Service governance | `true` means use the default proxy class name, which is the interface name with `Local` as the suffix. But it has been marked as @Deprecated.Pleas see also stub.| Above 2.0.0 | -| stub | stub | class/boolean | False | false | Service governance | `true` means use the default proxy class name, which is the interface name with `Stub` as the suffix. It's used to execute local logic such as caching. The proxy class must have a constructor with the remote proxy object as a parameter, such as `public XxxServiceStub(XxxService xxxService)` | Above 2.0.0 | -| mock | mock | class/boolean | False | false | Service governance | `true` means use the default mock class name, which is the interface name with `Mock` suffix. It's called when the RPC is failed, such as timeout or IO exception. The mock class must carry a none parameter constructor. The difference between mock and local proxy is that local proxy is always invoked before RPC but mock is invoked only when exception after RPC. | Above 2.0.0 | -| token | token | string/boolean | False | false | Service governance | Enable token validation. Disable token if it's null. It will generate token randomly when enable, or will use static token. The token is designed to prevent consumers from bypassing the registry direct access to provider. If you want peer to peer, token validation must disbable. | Above 2.0.0 | -| registry | | string | False | register to all registries by default | Configuration association | Register services to specified registry while having multiple registries. It is the `id` value of the <dubbo:registry>. If don't want to register to any registry, set it as `N/A` | Above 2.0.0 | -| provider | | string | False | use the first configured provider | Configuration association | The reference to `` | Above 2.0.0 | -| deprecated | deprecated | boolean | False | false | Service governance | Mark the service is deprecated. If true, there will log an error log on the client side. | Above 2.0.5 | -| dynamic | dynamic | boolean | False | true | Service governance | Whether the service is registered dynamically. If false, services will be showed as `disable`, you need to enable it manually. And you also need to disable it when provider shut down. | Above 2.0.5 | -| accesslog | accesslog | string/boolean | False | false | Service governance | `true` will write access log to logger. Specifying it to a log path, you can write access logs to special log file. | Above 2.0.5 | -| owner | owner | string | False | | Service governance | The owner of the service. It's used for service governance. | Above 2.0.5 | -| document | document | string | False | | Service governance | Service document URL | Above 2.0.5 | -| weight | weight | int | False | | Performance optimize | The weight of the service | Above 2.0.5 | -| executes | executes | int | False | 0 | Performance optimize | The maximum parallel execution request count per method per service for the provider. | Above 2.0.5 | -| proxy | proxy | string | False | javassist | Performance optimize | The proxy implement, jdk/javassist are available. | Above 2.0.5 | -| cluster | cluster | string | False | failover | Performance optimize | failover/failfast/failsafe/failback/forking are available. | Above 2.0.5 | -| filter | service.filter | string | False | default | Performance optimize | The filter name of the RPC process of the provider, use `,` to separate multiple filter names. | Above 2.0.5 | -| listener | exporter.listener | string | False | default | Performance optimize | The listener name of the provider, use `,` to separate multiple listener names. | | -| protocol | | string | False | | Configuration association | Specify the protocol for service provider. It references the `id` of `` tag. Use `,` to separate multiple protocols. | Above 2.0.5 | -| layer | layer | string | False | | Service governance | The biz layer of the service provider, such as biz, dao, intl:web and china:acton. | Above 2.0.7 | -| register | register | boolean | False | true | Service governance | Whether registering service providers to registry. | Above 2.0.8 | diff --git a/content/en/docs/v2.7/user/rest.md b/content/en/docs/v2.7/user/rest.md deleted file mode 100644 index 9bb95d93fa63..000000000000 --- a/content/en/docs/v2.7/user/rest.md +++ /dev/null @@ -1,1260 +0,0 @@ ---- -type: docs -title: "REST support" -linkTitle: "REST support" -weight: 19 -description: "Develop RESTful application in Dubbo" ---- - -{{% pageinfo %}} -Original author: Li Shen -Document copyright: [Apache 2.0license Signature - No interpretation](HTTP://www.apache.org/licenses/LICENSE-2.0) - -Working in progress ... -{{% /pageinfo %}} - -> This article is lengthy since REST involves many aspects. Besides, it refers to the document style of Spring and so on. Not only limited to usage of the framework but also strives to present the design concept of the framework and the architectural idea of an excellent application. -> For people who only want to get a glimpse of Dubbo and REST, all they need is to browse through the `Overview` to `Introduction to Standard Java REST API: JAX-RS`. - -## CONTENT - -* Overview -* Advantages of REST -* Application Scenarios -* Quick Start -* Introduction to Standard Java REST API: JAX-RS -* Details of REST Service Provider - * Implementation of HTTP POST/GET - * Should Annotation be Placed in the Interface or Implementation - * Support for Multiple Data Formats (JSON, XML, etc.) - * Support for Chinese Characters - * Additional Requirements for XML Format - * Custom Serialization - * Configure the Implementation of REST Server - * Access Context Data - * Configure the Port Number and Context Path - * Configure Number of Threads and IO Threads - * Configure Persistent Connection - * Configure Maximum Number of HTTP Connections - * Configure Timeout and HTTP Connections Per Consumer - * Gzip Data Compression - * Replace Part of Spring XML Configuration With Annotation - * Add Custom Filter, Interceptor, etc. - * Add Custom Exception Handler - * Configure HTTP Log Output - * Verification of Input Parameters - * Should REST Services be Published Transparently - * Get Headers In Dubbo Rest Provider -* Details of REST Service Consumer - * Scenario 1: Non-Dubbo Consumer Calls Dubbo REST Service - * Scenario 2: Dubbo Consumer Calls Dubbo REST Service - * Scenario 3: Dubbo Consumer Calls Non-Dubbo REST Service - * Custom Header By Dubbo Consumer while Calling REST Service -* JAX-RS Restrictions in Dubbo -* REST FAQ - * Can Dubbo REST Services be Integrated With Dubbo Registration Center and Monitoring Center? - * How to Implement Load Balancing and Failover in Dubbo REST? - * Can Overloaded Methods in JAX-RS Map to Single URL? - * Can a Method in JAX-RS Receive Multiple Parameters Via POST? -* Possible shortcomings of Current Dubbo System (Related to REST) - * Invasiveness of Rpc Context - * Limitations of Protocol Configuration - * XML Naming Does Not Conform to the Convention of Spring -* REST Best Practices -* Performance Benchmark - * Test Environment - * Test Script - * Test Result -* Extended Discussion - * Comparison of REST, Thrift, Protobuf, etc. - * Comparison Between REST and Traditional Web Services - * Comparison Between JAX-RS and Spring MVC -* Future - -## Overview - -Dubbo supports a variety of remote calling methods, such as Dubbo RPC (Binary Serialization + TCP), HTTP Invoker (Binary Serialization + HTTP, at least there is no support for Text Serialization in the open source version), Hessian (Binary Serialization + HTTP), Web Services (Text Serialization + HTTP), etc., but lacks support for trending RESTful Remote Calls (Text Serialization + HTTP). - -Therefore, based on the standard Java REST API: JAX-RS 2.0 (Abbreviation of Java API for RESTful Web Services), we provide a mostly transparent REST Call support for Dubbo. Since it is fully compatible with the Standard Java API, all REST services developed for Dubbo may normally work without Dubbo or any specific underlying REST implementation. - -It is particularly worth noting that we do not need to strictly adhere to the original definition and architectural style of REST. Even the famous Twitter REST API will make modest adjustments according to the situations, rather than mechanically follow the original REST style. - -> Note: We call this feature RESTful Remoting (abstracted remote process or call) rather than a RESTful RPC (specific remote "procedure" call) because REST and RPC can be thought of two different styles. In Dubbo's REST implementation, there are two aspects, one is to provide or consume regular REST services, the other is to make REST a protocol implementation in the Dubbo RPC system, and RESTful Remoting covers both aspects. - -## Advantages of REST - -The following is quoted from Wikipedia: - -* REST can use cache to improve response speed more efficiently. -* The stateless nature of the communication allows a set of servers to handle different requests in series, resulting in the increment of server scalability. -* Browser can be used as a client to simplify software requirements. -* REST software dependency is smaller than other mechanisms superimposed on HTTP. -* REST does not require additional resource discovery mechanism. -* REST's long-term compatibility is better in software technology evolution. - -Here I also want to add a particular advantage of REST: REST bases on simple text format messages and universal HTTP. Therefore, it has a broad applicability and is supported by almost all languages and platforms, together with a lower threshold in using and learning. - -## Application scenarios - -Because of the advantages of REST in applicability, supporting REST in Dubbo can bring (significant) benefits to most of current mainstream remoting call scenarios: - -1. Significantly simplify (cross-language) calls between heterogeneous systems within the enterprise. This is mainly for the following scene: Dubbo acts as a service provider, and systems that are written by other languages (including some java systems that do not base on Dubbo) works as service consumers. The two systems communicate through HTTP and text messages. REST has its unique advantages even comparing to binary cross-language RPC frameworks such as Thrift and ProtoBuf. (See discussion below) - -2. Significantly simplify the development of the external Open API (Open Platform). You can use Dubbo to develop a specific Open API application, or you can directly publish the internal Dubbo service as a "transparent" REST API (Of course, it's better for Dubbo itself to provide more features transparently, for example, permission control, frequency control, billing and so on). - -3. Significantly simplify the development of mobile (tablet) apps or desktop clients. Similar to point 2, you can use Dubbo to develop a specialized server for the applications, or transparently expose the internal Dubbo service. Of course in some projects, mobile or desktop applications can directly access the Open API described in point 2. - -4. Significantly simplify the development of AJAX applications on the browser. Similar to point 2, you can use Dubbo to develop a specialized server for AJAX, or transparently expose the internal Dubbo service directly to JavaScript in the browser. Of course, many AJAX applications work better with web frameworks, so direct access to the Dubbo service may not be an exquisite architecture in many web projects. - -5. Provide a text-based, easy-to-read remote call method for Dubbo systems within the enterprise (that is, both the service provider and the consumer are Dubbo-based systems). - -6. Simplify the call from the Dubbo system to other heterogeneous systems. You can use a simple way like Dubbo to "transparently" call REST services provided by Non-Dubbo systems (regardless of whether the service provider is inside or outside the enterprise) - -It should be pointed out that I think that 1~3 are the most valuable application scenarios for Dubbo's REST call. And the main purpose why we add REST calls for Dubbo is to provide a service-oriented provider. In other words, to develop REST services for Non-Dubbo (heterogeneous) consumers. - -To sum up, all application scenarios are shown below: -![rest.jpg](/imgs/user/rest.jpg) - -Borrowing the most famous slogan of Java in the past, by adding REST calls to Dubbo, you can implement the "Write once, access everywhere" service, which can theoretically be accessed all over the world, thus truly achieving an idealized Service-oriented Architecture (SOA). - -Of course, traditional Web Services (WSDL/SOAP) can meet the requirements (even those that require enterprise-level features) of the above scenarios (except for scenario 4). But due to the complexity and other issues, they are less and less used. - -## Quick Start - -Developing a RESTful service in Dubbo is relatively straightforward. Let's take a simple user registration service for example. - -The function to be implemented by this service is to provide the following URL (Note: This URL is not entirely RESTful, but more straightforward and more practical): - -``` -http://localhost:8080/users/register -``` - -Any client can POST a JSON string containing the user's information to the above URL to complete the user registration. - -First, implement the interface of the service: - -```java -public class UserService { - void registerUser(User user); -} -``` - -Then, implement the service: - -```java -@Path("users") -public class UserServiceImpl implements UserService { - - @POST - @Path("register") - @Consumes({MediaType.APPLICATION_JSON}) - public void registerUser(User user) { - // save the user... - } -} -``` -The above implementation code for the service is very simple, but since the REST service is to be published to a specific HTTP URL so they can be accessed by clients written by any language or even a browser, there are a few additional JAX-RS standard annotations to be added for the relevant configuration: - -@Path("users"): Specify that the relative path for `UserService` is `/users`, standing for http://localhost:8080/users - -@Path("register"): Specify that the relative path for `registerUser()` is `/register`. Combining the previous @Path specified for `UserService`, the URL to call `UserService.register()` is HTTP://localhost:8080/users/register - -@POST: Specify that `registerUser()` should be accessed with HTTP POST method - -@Consumes({MediaType.APPLICATION_JSON}): Specify that `registerUser()` receives data in JSON format. The REST framework will automatically deserialize JSON data into a User object. - -Finally, add this service to the spring configuration file and finish all service development work: - - ```xml - - - - - - - - -``` - -## Introduction to Standard Java REST API: JAX-RS - -JAX-RS is a standard Java REST API that has been widely supported and applied in the industry. There are many well-known open source implementations, including Oracle's Jersey, RedHat's RestEasy, Apache's CXF and Wink, restlet, etc. In addition, all commercial JavaEE application servers that support the JavaEE 6.0 specifications or above support JAX-RS. Therefore, JAX-RS is a very mature solution, and it does not have any so-called vendor lock-in problems. - -JAX-RS has a wealth of information on the web, such as the following introductory tutorial: - -* Oracle official tutorial: https://www.oracle.com/technical-resources/articles/java/jax-rs.html -* Article on IBM developerWorks China: http://www.ibm.com/developerworks/cn/java/j-lo-jaxrs/ - -For more information, please feel free to Google or Baidu. As far as learning JAX-RS is concerned, it is generally enough to master the usage of various annotations. - -> Note: Dubbo is based on the JAX-RS 2.0, and sometimes you need to pay attention to the version of the reference material or REST implementation. - -## REST Service Provider Details - -In this section, we will expand the `UserService` in the "Quick Start" to further demonstrate the development points of the REST service provider in Dubbo. - -### Implementation of HTTP POST/GET - -Although it's recommended to use the four standard methods (POST, DELETE, PUT and GET) in the HTTP protocol to implement common CRUD in REST services, but in practice, we generally use POST to implement create and update, and use GET to implement delete and read (DELETE and PUT will even be blocked by some firewalls). - -The implementation of POST has already been briefly demonstrated. Here, we will add a function to get the registered user data to `UserService`, in order to demonstrate the implementation of GET. - -This function is to enable the client to obtain user data of different IDs by accessing different URLs as follows: - -``` -http://localhost:8080/users/1001 -http://localhost:8080/users/1002 -http://localhost:8080/users/1003 -``` - -Of course, you can use other forms of URLs to access user data of different IDs, for example: - -``` -http://localhost:8080/users/load?id=1001 -``` - -JAX-RS itself can support all of these forms. However, the first form of including query parameters in the URL path (http://localhost:8080/users/1001) is more in line with the general habit of REST, so it is recommended to use. Below we will add a `getUser()` method to the `UserService` to implement this form of URL access: - -```java -@GET -@Path("{id : \\d+}") -@Produces({MediaType.APPLICATION_JSON}) -public User getUser(@PathParam("id") Long id) { - // ... -} -``` - -@GET: Specify that the method shoule be accessed with HTTP GET method - -@Path("{id : \d+}"): According to the above functional requirements, the URL to access `getUser()` should be "http://localhost:8080/users/ + any number", and this number should passed to `getUser()` method as parameter passed to the getUser() method. In the annotation here, the {id: xxx} in @Path specifies that the relative path contains the id parameter, and its value will be automatically passed to the method parameter `id` annotated with @PathParam("id"). `\d+` following `{id:` is a regular expression specifies that the id parameter must be a number. - -@Produces({MediaType.APPLICATION_JSON}): Specify that `getUser()` outputs data in JSON format. The REST framework automatically serializes the User object into JSON data. - -### Is annotation put in interface class or implementation class? - -The development of REST services based on Dubbo is mainly configured through JAX-RS annotations. In the above example, we put the annotation in the implementation class of the service. But in fact, we can completely put the annotation in the interface of the service. These two methods are completely equivalent, for example: - -```java -@Path("users") -public interface UserService { - - @GET - @Path("{id : \\d+}") - @Produces({MediaType.APPLICATION_JSON}) - User getUser(@PathParam("id") Long id); -} -``` - -In a typical application, we recommend put the annotation in the service implementation class. Then, annotations are closer to Java implementation code and easier to develop and maintain. More importantly, we generally tend to avoid contamination of the interface, maintaining the purity and wide applicability of the interface. - -However, as will be described later, if we access this service by using the consumer directly developed by Dubbo, the annotation must be put in the interface. - -If the interface and the implementation class are both added annotation at the same time, the implementation configuration of the implementation class will take effect, and the annotation on the interface will be ignored. - -### Support for JSON, XML and other data formats - -The dubbo REST services can support the transmission of data in multiple formats to provide maximum flexibility to the client. And we add extra functions to the JSON and XML formats which is most commonly used. - -For example, we want the `getUser()` method in the above example support returning JSON and XML format data separately, just need to include two formats in the annotation: - -```java -@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) -User getUser(@PathParam("id") Long id); -``` - -Or you can directly represent a MediaType with a string (also supports wildcards): - -```java -@Produces({"application/json", "text/xml"}) -User getUser(@PathParam("id") Long id); -``` - -If all methods support the same type of input and output data format, then we do not need to make configure on each method, just add annotation to the service class: - - -```java -@Path("users") -@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) -@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) -public class UserServiceImpl implements UserService { - // ... -} -``` - -In the case where a REST service supports multiple data formats, according to the JAX-RS standard, the MIME header (content-type and accept) in HTTP is generally used to specify which format data is currently used. - -But in dubbo, we also automatically support the current common use of the industry, that is, use a URL suffix (.json and .xml) to specify the data format you want to use. For example, after adding the above annotation, directly accessing `http://localhost:8888/users/1001.json` means using the json format, and directly accessing `http://localhost:8888/users/1002.xml` means using the xml format. It's simpler and more intuitive than using HTTP Header. This way is used by the REST APIs of Twitter, Weibo, etc. - -If you don't add HTTP header or suffix, the REST of dubbo will give priority to enable the top ranked data format in the above definition of annotation. - -> Note: To support XML format data, you can use either `MediaType.TEXT_XML` or `MediaType.APPLICATION_XML` in annotation, but TEXT_XML is more commonly used, and if you want to use the above URL suffix to specify the data format, you can only configure it as TEXT_XML to take effect. - -### Chinese character support - -In order to output Chinese characters normally in dubbo REST, as with the usual Java web applications, we need to set the contentType of the HTTP response to UTF-8 encoding. - -Based on the standard usage of JAX-RS, we only need to do the following annotation configuration: - -```java -@Produces({"application/json; charset=UTF-8", "text/xml; charset=UTF-8"}) -User getUser(@PathParam("id") Long id); -``` - -For the convenience of users, we add a support class directly in dubbo REST to define the above constants, which can be used directly and reduce the possibility of error. - -```java -@Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8}) -User getUser(@PathParam("id") Long id); -``` - -### Additional requirements for XML data format - -Because the implementation of JAX-RS generally use standard JAXB (Java API for XML Binding) to serialize and deserialize XML format data, we need to add a class-level JAXB annotation for each object to be transferred in XML. Otherwise serialization will report an error. For example, add follows to the User returned in `getUser()` : - -```java -@XmlRootElement -public class User implements Serializable { - // ... -} -``` - -In addition, if the return value in the service method is Java primitive type (such as int, long, float, double, etc.), it is best to add a wrapper object to them, because JAXB can not directly serialize the primitive type. - -For example, we want the above `registerUser()` method to return the ID number generated by the server for the user: - -```java -long registerUser(User user); -``` - -Because the primitive type is not supported by JAXB serialization, add a wrapper object: - -```java -@XmlRootElement -public class RegistrationResult implements Serializable { - - private Long id; - - public RegistrationResult() { - } - - public RegistrationResult(Long id) { - this.id = id; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } -} -``` - -And modify the service method: - -```java -RegistrationResult registerUser(User user); -``` - -This not only solves the problem of XML serialization, but also makes the returned data conform to the specifications of XML and JSON. For example, in JSON, the returned form would be as follows: - -```javascript -{"id": 1001} -``` - -If you do not add a wrapper, the JSON return value will be directly - -``` -1001 -``` - -In XML, the return value after adding wrapper will be: - -```xml - - 1002 - -``` - -This wrapper object actually uses the so-called Data Transfer Object (DTO) mode, and DTO can also make more useful customizations for transferring data. -While in XML, after adding wrapper, the return value will be - -```xml - - 1002 - -``` - -In fact, this wrapper object uses the so-called Data Transfer Object (DTO) mode. DTO can also be used to make more useful customizations to transfer data. - -### Custom Serialization - -As mentioned above, the underlying implementation of REST will automatically serialize/deserialize between the service object and the JSON/XML data format. - -The REST implementation in Dubbo uses JAXB for XML serialization and Jackson for JSON serialization,so you can customize the mapping by adding JAXB or Jackson's annotation to the object. - -For example, customizing the object properties to map to the names of the XML elements: - -```java -@XmlRootElement -@XmlAccessorType(XmlAccessType.FIELD) -public class User implements Serializable { - - @XmlElement(name="username") - private String name; -} -``` - -Customizing the object properties to map to the names of the JSON field: - -```java -public class User implements Serializable { - - @JsonProperty("username") - private String name; -} -``` - -For more information, please refer to the official documentation of JAXB and Jackson, or google yourself. - -### Configuring REST Server implementation - -Currently in dubbo, we support the implementation of five embedded rest servers. The implementation of the rest server is selected by the following XML attribute of the server: - -```xml - -``` - -The above configuration uses the embedded jetty to do the rest server. At the same time, if you do not configure the server attribute, the rest protocol also uses jetty by default. jetty is a very mature java servlet container and has a good integration with dubbob (Among the five embedded servers, Only jetty and later tomcat、tjws, complete seamless integration with Dubbo monitoring system.), so, if your dubbo system is a separate process, you can use jetty by default. - -```xml - -``` - -The above configuration uses the embedded tomcat to do the rest server.On embedded tomcat, REST performance is much better than jetty (See the benchmark below). It is recommended that Tomcat is used in scenarios where high performance is required. - -```xml - -``` - -The above configuration uses embedded netty to do the rest server. (TODO more contents to add) - -```xml - (tjws is now deprecated) - -``` - -The above configuration uses embedded tjws or Sun HTTP server to do the rest server. These two server implementations are very lightweight, it is very convenient for quick start-up in integration testing, of course, it can also be used in a production environment with low load. Note: tjws is currently deprecated because it does not work well with the servlet 3.1 API. - -If your dubbo system is not a separate process, -instead of deploying to a Java application server, we recommend the following configuration: - -```xml - -``` - -By setting the server as the servlet, dubbo will use the servlet container of the external application server to do the rest server. At the same time, add the following configuration to the web.xml of the dubbo system: - -```xml - - - contextConfigLocation - /WEB-INF/classes/META-INF/spring/dubbo-demo-provider.xml - - - - org.apache.dubbo.remoting.http.servlet.BootstrapListener - - - - org.springframework.web.context.ContextLoaderListener - - - - dispatcher - org.apache.dubbo.remoting.http.servlet.DispatcherServlet - 1 - - - - dispatcher - /* - - -``` - -In other words, you must add dubbo's BootstrapListener and DispatherServlet to web.xml to complete the integration of dubbo's REST functionality with the external servlet container. - -> Note:If you are using spring's ContextLoaderListener to load spring, you must ensure that the BootstrapListener is configured before the ContextLoaderListener, otherwise the dubbo initialization will fail. - -In fact, you can still stick to the embedded server in this scenario, but the servlet container of the external application server is often more powerful than the embedded server(Especially if you are deploying to a more robust and scalable WebLogic, WebSphere, etc.). In addition, it is sometimes convenient to do unified management, monitoring, and so on in the application server. - -### Get Context Information - -Varieties of context information are valuable when calling procedures remotely. For instance, the IP address from the Client. - -We provide two methods to get the Client's IP in dubbo. - -The first one is using @Context annotation from JAX-RS: - -```java -public User getUser(@PathParam("id") Long id, @Context HttpServletRequest request) { - System.out.println("Client address is " + request.getRemoteAddr()); -} -``` - -After decorating a parameter of `getUser()` with Context, we can inject the current HttpServletRequest and then call the servlet api to get the IP. - -> Notice: This method can only be used when the server is one of the followings: twjs, tomecat, jetty or servlet. All of them provide servlet container. In addition, standard JAX-RS also allow us to get HttpServletRequest using an instance field in service Class decorated by `@Context`. - -The second method is to use RpcContext, which is commonly seen in dubbo: - -```java -public User getUser(@PathParam("id") Long id) { - System.out.println("Client address is " + RpcContext.getContext().getRemoteAddressString()); -} -``` - -> Notice: Similarly, this method only works in the jetty, tomcat, servlet or tjws server. In dubbo, the usage of RpcContext is rather invasive. We are likely to refactor it in the future. - -The first method is suggested when your project may run without dubbo and need the compatibility with JAX-RS. But if you want a more elegant service interface definition, the second method would be the better choice. - -What's more, in the newest version of dubbo REST service, RpcContext could be used to get HttpServletRequest and HttpServletResponse, providing great flexibility for users to implement some complex functions. The following is an example: - -```java -if (RpcContext.getContext().getRequest() != null && RpcContext.getContext().getRequest() instanceof HttpServletRequest) { - System.out.println("Client address is " + ((HttpServletRequest) RpcContext.getContext().getRequest()).getRemoteAddr()); -} - -if (RpcContext.getContext().getResponse() != null && RpcContext.getContext().getResponse() instanceof HttpServletResponse) { - System.out.println("Response object from RpcContext: " + RpcContext.getContext().getResponse()); -} -``` - -> Notice: -In order to maintain the neutrality of the protocol, `RpcContext.getRequest()` and `RpcContext.getResponse()` only return an Object which could be null. Therefore, you have to check the type on your own. - -> Notice: only when you use jetty, tomcat, servlet as the server can you get the HttpServletRequest and HttpServletResponse as expected. Because only these server -implemented the servlet container. - -To simplify the programme, you can also use generic to get a specific type of request/response: - -```java -if (RpcContext.getContext().getRequest(HttpServletRequest.class) != null) { - System.out.println("Client address is " + RpcContext.getContext().getRequest(HttpServletRequest.class).getRemoteAddr()); -} - -if (RpcContext.getContext().getResponse(HttpServletResponse.class) != null) { - System.out.println("Response object from RpcContext: " + RpcContext.getContext().getResponse(HttpServletResponse.class)); -} -``` - -If request/response does not correspond to the specific type, it would return null. - -### Configure The Port Number and Context Path - -The REST protocol in dubbo use 80 as the default port. But you are also allowed to modify it: - -```xml - -``` - -As what have been metioned before, we can use `@Path` to configure relative URL path in single REST service. In fact, we can also set a basic relative path which is known as context path for all REST service. - -All we need to do is to add the contextpath property: - -```xml - -``` - -Let's have a look at the previous code: - -```java -@Path("users") -public class UserServiceImpl implements UserService { - - @POST - @Path("register") - @Consumes({MediaType.APPLICATION_JSON}) - public void registerUser(User user) { - // save the user... - } -} -``` - -Now the complete path would be: - -``` -http://localhost:8888/services/users/register -``` - -Notice: If you use external server as REST server, you should configure as followings, - -```xml - -``` - -meaning that you should keep the config of port and contextpath are the same with the port and DispatcherServlet's context path (webapp path + servlet url pattern) in external server. For example, when we are configuring the application on tomcat Root path, we need to make sure the contextpath here is totally the same with the `` of DispacherServlet in web.xml: - -```xml - - dispatcher - /services/* - -``` - -### Configure the number of threads and IO threads - -We can set the number of threads of rest service: - -```xml - -``` - -> Notice: Currently, the setting only works when the server is netty, jetty or tomcat. If you use servlet as the server, you are using the external server as the REST server which is out of dubboes' control, so the setting would not work expectedly. - -You can also set threads number of IO worker of netty server: - -```xml - -``` - -### Configure long connections - -The REST service in Dubbo is accessed by default with http long connection, if you want to switch to short connection, you can configure it as below: - -```xml - -``` - -> Notice: This configuration only works in netty and tomcat. - -### Configure the maximum number of HTTP connections - -Configuring the maximum number of HTTP connections can prevent REST server from -overload as the basic self-protection mechanism. - -```xml - -``` - -Of course, since this configuration is valid for the consumer, it can also be configured on the consumer side: - -```xml - -``` - -However, we generally recommend configuring the service provider to provide such a configuration. According to the official dubbo documentation, “Provider should configure the properties of the Consumer side as much as possible. -Let the Provider implementer think about the service features and service quality of the Provider from the beginning.” - -> Note: If dubbo REST service is released to non-dubbo clients, the configuration on `` is completely invalid because the client is not under dubbo control. - -### GZIP data compresssion - -Dubbo RESTful Remoting supports the use of Gzip to compress request and response data to reduce network transmission time and bandwidth consumption, but this will also increase CPU overhead. - -TODO more contents to add. - -### Replacing part of the spring XML configuration with annotation - -Above discussions are based on the XML configuration of Dubbo in spring. -However, dubbo/spring itself supports the use of annotation for configuration, so we can also follow the steps in the Dubbo document and add the relevant annotation to the REST service implementation, replacing some XML configurations, such as: - -```java -@Service(protocol = "rest") -@Path("users") -public class UserServiceImpl implements UserService { - - @Autowired - private UserRepository userRepository; - - @POST - @Path("register") - @Consumes({MediaType.APPLICATION_JSON}) - public void registerUser(User user) { - // save the user - userRepository.save(user); - } -} -``` - -Annotation-based configuration is more concise and precise, and often easier to maintain (modern IDE can support such things as class name refactoring in XML, and therefore the maintenance of XML is good for specific use cases here). XML is less intrusive to code, especially for dynamically modifying configurations, especially when you want to modify the timeout for connection of a single service configuration, the maximum number of connections per client, cluster policy, weights, and so on. In addition, for complex applications or modules, XML provides a central point to cover all the components and configurations. It is at a glance, and generally more convenient for long term maintenance of the project. - -Of course, there's no right or wrong of different choices of configuration method. Sometimes it's just personal preference. - -### Adding a custom Filter, Interceptor, etc - -Dubbo RESTful Remoting also supports JAX-RS standard Filter and Interceptor to facilitate customized interception of REST request and response processes. - -Here, Filter is mainly used to access and set parameters, URIs for HTTP request and response, and so on, for example, setting the cache header for HTTP response: - -```java -public class CacheControlFilter implements ContainerResponseFilter { - - public void filter(ContainerRequestContext req, ContainerResponseContext res) { - if (req.getMethod().equals("GET")) { - res.getHeaders().add("Cache-Control", "someValue"); - } - } -} -``` - -Interceptor is mainly used to access and modify the input and output byte streams, for example, manually adding GZIP compression: - -```java -public class GZIPWriterInterceptor implements WriterInterceptor { - - @Override - public void aroundWriteTo(WriterInterceptorContext context) - throws IOException, WebApplicationException { - OutputStream outputStream = context.getOutputStream(); - context.setOutputStream(new GZIPOutputStream(outputStream)); - context.proceed(); - } -} -``` - -In standard JAX-RS applications, we generally add @Provider annotations to Filter and Interceptor, and JAX-RS runtime will automatically discover and enable them. In Dubbo, we register Filter and Interceptor by adding an XML configuration: - -```xml - -``` - -Here, we can add these three types of objects, Filter, Interceptor and DynamicFeature, to the `extension` attributes, separated by commas. (DynamicFeature is another interface that allows us to enable Filter and Interceptor more dynamically. Please feel free to google.) - -Of course, Dubbo itself also supports Filter, but the Filter and Interceptor we discuss here are more like the bottom of the protocol implementation. Compared to Dubbo's filter, you can do a lower level of customization here. - -> Note: The XML attribute here is called extension, not interceptor or filter. That is because we will add more extension types in addition to Interceptor and Filter in the future. - -If the REST consumer is also a Dubbo system (see discussion below), you can also configure the Interceptor and Filter for the consumer in a similar way. - -However, it should be noted that the consumer-side Filter and the provider-side Filter in JAX-RS are two different interfaces. For example, in the previous example, the server is the ContainerResponseFilter interface, and the consumer side corresponds to the ClientResponseFilter: - -```java -public class LoggingFilter implements ClientResponseFilter { - - public void filter(ClientRequestContext reqCtx, ClientResponseContext resCtx) throws IOException { - System.out.println("status: " + resCtx.getStatus()); - System.out.println("date: " + resCtx.getDate()); - System.out.println("last-modified: " + resCtx.getLastModified()); - System.out.println("location: " + resCtx.getLocation()); - System.out.println("headers:"); - for (Entry> header : resCtx.getHeaders().entrySet()) { - System.out.print("\t" + header.getKey() + " :"); - for (String value : header.getValue()) { - System.out.print(value + ", "); - } - System.out.print("\n"); - } - System.out.println("media-type: " + resCtx.getMediaType().getType()); - } -} -``` - -### Adding custom Exception handler - -Dubbo RESTful Remoting also supports JAX-RS standard ExceptionMapper, which can be used to customize the HTTP response after a particular exception occurs. - -```java -public class CustomExceptionMapper implements ExceptionMapper { - - public Response toResponse(NotFoundException e) { - return Response.status(Response.Status.NOT_FOUND).entity("Oops! the requested resource is not found!").type("text/plain").build(); - } -} -``` - -Similar to Interceptor and Filter, it can be enabled by adding it to an XML configuration file: - -```xml - -``` - -### Configuring HTTP log output - -Dubbo RESTful Remoting supports outputting the header and body in all HTTP requests/responses. - - Add the following REST filter to the XML configuration: - -```xml - -``` - -**Then turn on at least INFO level log output for org.apache.dubbo.rpc.protocol.rest.support in the logging configuration**,for example,in log4j.xml: - -```xml - - - - -``` - -Of course, you can also turn on INFO level log output directly in the ROOT logger: - -```xml - - - - -``` - - Then there will be something like the following output in the log: - -``` -The HTTP headers are: -accept: application/json;charset=UTF-8 -accept-encoding: gzip, deflate -connection: Keep-Alive -content-length: 22 -content-type: application/json -host: 192.168.1.100:8888 -user-agent: Apache-HttpClient/4.2.1 (java 1.5) -``` - -``` -The contents of request body is: -{"id":1,"name":"dang"} -``` - -After the HTTP log output is turned on, in addition to the performance overhead of the normal log output, additional overhead is generated in, for example, HTTP request parsing, because an additional memory buffer needs to be allocated to prepare the data for the log output. - -### Inputing parameter validation - -Dubbo RESTful Remoting supports the use of the Java standard bean validation annotation(JSR 303) for input validation http://beanvalidation.org/. - - In order to be consistent with other Dubbo remote invocation protocols, the annotations that are checked for rest must be placed on the interface of the service, for example: - -```java -public interface UserService { - - User getUser(@Min(value=1L, message="User ID must be greater than 1") Long id); -} -``` - -Of course, in many other bean validation scenarios, annotations are placed on implementation classes rather than interfaces. At least one advantage of placing an annotation on an interface is that the Dubbo client can share information about the interface. The input validation can be done locally even without RPC. - -Then turn on the validation in the XML configuration in the same way as Dubbo: - -```xml - -``` - -In many other RPC protocols of Dubbo, if the input validation error occurs, the `RpcException` is directly thrown to the client, but in the rest, since the client is often non-Dubbo or even non-Java system, it is inconvenient to directly throw a Java exception. Therefore, at present we will return the validation error in XML format: - -```xml - - - getUserArgument0 - User ID must be greater than 1 - 0 - - -``` - -The return values of other data formats will also be supported later. As for how to internationalize the verification error message, refer directly to the relevant documentation of the bean validation. - - If you think that the default validation error return format does not meet your requirements, you can add custom ExceptionMapper to custom error return format freely as described in the previous section. It should be noted that this ExceptionMapper must use the generic declaration to capture the RpcException of Dubbo in order to successfully override the default exception handling strategy of Dubbo rest. In order to simplify the operation, the easiest way to do this is to directly inherit the RpcExceptionMapper of Dubbo rest and override the method that handles the validation exception: - -```java -public class MyValidationExceptionMapper extends RpcExceptionMapper { - - protected Response handleConstraintViolationException(ConstraintViolationException cve) { - ViolationReport report = new ViolationReport(); - for (ConstraintViolation cv : cve.getConstraintViolations()) { - report.addConstraintViolation(new RestConstraintViolation( - cv.getPropertyPath().toString(), - cv.getMessage(), - cv.getInvalidValue() == null ? "null" : cv.getInvalidValue().toString())); - } - // Use json output instead of xml output - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(report).type(ContentType.APPLICATION_JSON_UTF_8).build(); - } -} -``` - -Then add this ExceptionMapper to the XML configuration: - -```xml - -``` - -### Whether to transparently publish REST service - -Dubbo RESTful Remoting differs from some other RPCs in Dubbo in that you need to add JAX-RS annotations (and JAXB, Jackson's annotation) to your service code. If you think these annotations "pollute" your service code to a certain extent,you can consider writing additional Facade and DTO classes, adding annotations to that, and Facade forwards the calls to the real service implementation class. Of course, adding annotations directly to the service code basically has no negative effects, and this is itself a standard usage in Java EE. In addition, JAX-RS and JAXB annotations belong to the Java standard. Compared with spring, Dubbo, etc., which we often use, annotations have no problem with vendor lock-in, so there is usually no need to introduce additional objects. - -In addition,when you want to use the @Context annotation mentioned above, injecting HttpServletRequest through method parameters (such as `public User getUser(@PathParam("id") Long id, @Context HttpServletRequest request)`), the method signature of service is changed and HttpServletRequest is a REST-specific parameter, you should introduce additional Facade classes if your service supports multiple RPC mechanisms. - -Of course, your service code may already act as a Facade and DTO before adding RESTful Remoting (as to why some scenarios require these roles, and if you are interested, you can refer to [Micro-SOA: Service Design Principles and Practices] Http://www.infoq.com/cn/articles/micro-soa-1). In this case, after adding REST, if you add additional REST-related Facade and DTO, it is equivalent to wrapping the original code again, which forms the following call chain: - -`RestFacade/RestDTO -> Facade/DTO -> Service` - -This kind of system is cumbersome, and the workload of data conversion is not small, so it should be avoided if possible. - -### Get Headers In Dubbo Rest Provider - -Dubbo take out and split headers by RpcContextFilter and put them into attachments of RpcContext, so provider can get headers from RpcContext attachments like: - -``` - String header-value1 = RpcContext.getContext().getAttachment(header-key1) - String header-value2 = RpcContext.getContext().getAttachment(header-key2) -``` - -### Consumer of RESTful Remoting - -Here we use three scenarios: - -1. The non-Dubbo consumer calls Dubbo REST service (non-Dubbo --> Dubbo) -2. The Dubbo consumer calls Dubbo REST service (Dubbo --> Dubbo) -3. The consumer of Dubbo calls the non-Dubbo REST service (Dubbo --> non-Dubbo) - -### Scenario 1: Non-Dubbo consumer calls Dubbo REST Service - -The client of this scenario has nothing to do with Dubbo itself, and it can be directly selected in the appropriate language and framework. - -If it is still a Java client (but not using Dubbo), consider using the standard JAX-RS Client API or a specific REST-implemented Client API to invoke the REST service. The following is the registerUser() that uses the JAX-RS Client API to access the above UserService: - -```java -User user = new User(); -user.setName("Larry"); - -Client client = ClientBuilder.newClient(); -WebTarget target = client.target("http://localhost:8080/services/users/register.json"); -Response response = target.request().post(Entity.entity(user, MediaType.APPLICATION_JSON_TYPE)); - -try { - if (response.getStatus() != 200) { - throw new RuntimeException("Failed with HTTP error code : " + response.getStatus()); - } - System.out.println("The generated id is " + response.readEntity(RegistrationResult.class).getId()); -} finally { - response.close(); - client.close(); //Do not close the client every time in real development, such as HTTP long connection is held by the client -} -``` - -The User and RegistrationResult classes in the code snippet above are written by the consumer itself, and the JAX-RS Client API automatically serializes/deserializes them. - -Of course, in Java, you can also use the familiar technologies such as HttpClient, FastJson, XStream, etc. to implement the REST client, which will not be detailed here. - -### Scenario 2: Dubbo consumer calls Dubbo RESTful Remoting - -In this scenario, same as other Dubbo remote calling methods, the Java service interface is shared directly between the service provider and the service consumer, and the Spring XML configuration is added (of course, the Spring/Dubbo annotation configuration can also be used),the remote REST service can be called transparently: - -```xml - -``` - -As mentioned earlier, in this scenario, JAX-RS annotations must be added to the service interface, so that the corresponding REST configuration information can be shared on the consumer side of Dubbo and remotely called accordingly: - -```java -@Path("users") -public interface UserService { - - @GET - @Path("{id : \\d+}") - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) - User getUser(@PathParam("id") Long id); -} -``` - -If a variety of data formats are configured in the annotation of the service interface, since both ends are Dubbo systems, a lot of details of REST are blocked, so there is no possibility to select a data format using the aforementioned URL suffix. Currently in this case, the top ranked data format will be used directly. - -Therefore, we recommend that you put the most appropriate data format in front of defining an annotation. For example, we put JSON in front of XML because JSON's transmission performance is better than XML. - -### Scenario 3: The consumer of Dubbo calls a non-Dubbo RESTful Remoting - -In this scenario, the REST service can be called directly using the Java method described in Scenario 1. But in fact, you can also use the way described in Scenario 2, that is, calling the REST service more transparently, even if this service is not provided by Dubbo. - -If the scenario 2 is used, since the REST service is not provided by Dubbo, there is generally no shared Java service interface mentioned above, so we need to write the Java interface and the corresponding parameter class according to the external REST service. Add JAX-RS, JAXB, Jackson and other annotations, Dubbo's REST underlying implementation will automatically generate request messages, automatically parse response messages, etc., so as to transparently make remote calls. Or this way can also be understood as, we try to use JAX-RS to copy the implementation of the external REST service provider, and then put the written service interface to the client to use directly, Dubbo REST underlying implementation can call other REST services as it calls Dubbo's REST service . - -For example, we want to call the following external service. - -``` -http://api.foo.com/services/users/1001 -http://api.foo.com/services/users/1002 -``` - -Get user data of different IDs, the return format is JSON - -```java -{ - "id": 1001, - "name": "Larry" -} -``` - -We can write service interfaces and parameter classes based on this information: - -```java -@Path("users") -public interface UserService { - - @GET - @Path("{id : \\d+}") - @Produces({MediaType.APPLICATION_JSON}) - User getUser(@PathParam("id") Long id); -} -``` - -```java -public class User implements Serializable { - - private Long id; - - private String name; - - // … -} -``` - -For the configuration in Spring, because the REST service is not provided by Dubbo, you can not use the Dubbo registry to directly configure the url address of the external REST service (such as multiple addresses separated by commas): - -```xml - -``` - -> Note: The protocol here must use rest:// instead of http://. If the external REST service has a context path, it must also be added to the url (unless you have a context path in the @Path annotation for each service interface), such as /services/ above. At the same time, the services here must be followed by /, in order to make Dubbo work properly. -> -> In addition, you can still configure the maximum number of connections and timeouts that the client can start: - -```xml - -``` - -### Custom Header By Dubbo Consumer while Calls REST Service - -When Dubbo calls rest, it uses the method of converting the attachments of RpcContext to header. - -Therefore, you can set headers in the following ways: - -``` - RpcContext.getContext().setAttachment("header-key1", "header-value1"); - RpcContext.getContext().setAttachment("header-key2", "header-value2"); -``` - -Then the headers will be looks like following: - -``` - header-key1 = header-value1 - header-key2 = header-value2 -``` - -### JAX-RS restrictions in Dubbo - -The REST development in Dubbo is fully compatible with standard JAX-RS, but the features it supports are currently a subset of full JAX-RS, in part because it is limited to the specific architecture of Dubbo and Spring. The limitations of JAX-RS used in Dubbo include but are not limited to: - -1. Service implementation can only be singleton, and it can not support per-request scope and per-lookup scope -2. It is not supported to inject into ServletConfig, ServletContext, HttpServletRequest, HttpServletResponse, etc. with the @Context annotation for the instance field of the service, but it can support the injection of service method parameters. However, for certain REST server implementations (see the previous section), injection of service method parameters is not supported. - -## REST FAQ - ------- - -### Can Dubbo REST services be integrated with Dubbo Registry and Monitor? - -Yes, and it will integrate automatically. That is, all the REST services you develop in Dubbo are automatically registered to the Registry and Monitor, by which you can managed your services. -However, many of the service governance operations in the Registry can only be fully functional when the REST consumer is based on Dubbo. If the consumer side is non-Dubbo, it is naturally not managed by the Registry, so that many of the operations will not work for the consumer. - - - -### How to implement load balancing and failover in Dubbo REST? - -If the consumer side of Dubbo REST is based on Dubbo, then Dubbo REST is basically the same as other Dubbo remote call protocols: Dubbo framework transparently performs load balancing, failover, etc. on the consumer side. -If the consumer side of Dubbo REST is non-Dubbo or even non-Java, it is better to configure the soft load balancing mechanism on the service provider. Currently, you can consider LVS, HAProxy, Nginx, and so on to achieve load balancing for HTTP requests. - - -### Can overloaded method in JAX-RS maps to the same URL address? - -http://stackoverflow.com/questions/17196766/can-resteasy-choose-method-based-on-query-params - -### Can a POST method in JAX-RS receive multiple parameters? - -http://stackoverflow.com/questions/5553218/jax-rs-post-multiple-objects - - -## The shortcomings of Dubbo's current system (related to REST) ---- - -I think there are obviously a lot of deficiencies in Dubbo's current system. Here are a few REST-related issues that affect users (not including internal implementation issues) for reference and comments, which can help prepare for the refactoring later. - - -### Invasiveness of RpcContext - -We have already mentioned the intrusiveness of RpcContext(See above). Because it uses a singleton to access context information, which is completely inconsistent with the general style of spring applications as well as not conducive to application extension and unit testing. In the future, we may inject an interface with dependency injection, and then use it to access the context information in ThreadLocal. - -### limitations of Protocol configuration - -Dubbo supports multiple remote call methods, but all call methods are configured with , for example: -```xml - -``` -Dubbo supports multiple remote call methods, but all call methods are configured with , for example: -In fact, many of the above properties are uniquely held by the Dubbo RPC remote call method and many other remote call methods in Dubbo do not support server, client, codec, iothreads, accepts, payload, etc. (of course, some are not supported because of limited conditions, some have no need to be supported at all). This adds a lot of confusions to users when they use Dubbo, and they actually do not know that some attributes (such as performance tuning) will not work after adding them. - - -On the other hand, various remote call methods often have a large number of unique configuration requirements, especially as we gradually add much richer and more advanced functions to each kind of remote call method, which cause the expands in attributes inevitably (for example, we have added keepalive and extension two attributes in REST at the moment) and then lead to bloated and user confusion. - -Of course, there is a way to expand in Dubbo by using , but this method is obviously very limited, the usage is complicated and the schema verification is lacking. -So that the best method is to set your own protocol elements for each remote call, such as , , etc. Each element specifies its own attributes using XML Schema. (Of course, it is best to use common attributes between a variety of remote call methods) -In this way, a freer way can be used when doing the extension configuration mentioned above, so that it can be much clearer and more extensible (the following is just an example, of course there may be a better way): - -```xml - - someInterceptor - someFilter - someDynamicFeature - someEntityProvider - -``` - -### XML naming does not conform to the spring specification - -A lot of naming in XML configuration of Dubbo dose not conform to the spring specification, such as: -```xml - -``` -The above threadpool should be changed to thread-pool, iothreads should be changed to io-threads, and words should be separated by "-". While this may seem like a minor issue, it also involves readability, especially scalability, because sometimes we will inevitably use more words to describe XML elements and attributes. - -In fact, Dubbo itself also recommended to follow the naming convention of spring to XML. - - -## Best practices of REST ---- -TODO - - - -## Performance benchmark ---- - -### Test Environment - -Roughly as follows: - - - 4-core Intel(R) Xeon(R) CPU E5-2603 0 @ 1.80GHz - - 8G memory - - The network between servers passes through a 100 Mbps switch - - CentOS 5 - - JDK 7 - - Tomcat 7 - - JVM parameter -server -Xms1g -Xmx1g -XX:PermSize=64M -XX:+UseConcMarkSweepGC - - -### Test Script - -Similar to Dubbo's own benchmarks: -10 concurrent clients send requests continuously: -• Pass in nested complex objects (single data is small), do nothing and return -• Pass in a 50K string, do nothing and return (TODO: the result is not listed yet) -Excute a five-minute performance test. (Reference to Dubbo's own test considerations: "Mainly consider the serialization and performance of network IO, so that the server side does not have any business logic. Take 10 to run simultaneously because of the consideration that the bottleneck can be hit first when the high CPU usage rate is reached by HTTP protocol under the high concurrency situation.") - - - - -### Test Result -The following results are mainly from the comparison between to the two remote call methods, REST and Dubbo RPC which are configured differently, for example: - - - “REST: Jetty + XML + GZIP” means: Test REST, use jetty server and XML data format, and enable GZIP compression. - - “Dubbo: hessian2” means: test Dubbo RPC and use hessian2 serialization. - -The results for complex objects are as follows (the smaller Response Time and the larger TPS, the better results): - -|Remote Call Mode |Average Response Time |Average TPS(Num of transactions per second)| -| ------ | ------ | ------ | -|REST: Jetty + JSON | 7.806 | 1280| -|REST: Jetty + JSON + GZIP | TODO| TODO| -|REST: Jetty + XML | TODO| TODO| -|REST: Jetty + XML + GZIP| TODO| TODO| -|REST: Tomcat + JSON| 2.082| 4796| -|REST: Netty + JSON| 2.182| 4576| -|Dubbo: FST| 1.211| 8244| -|Dubbo: kyro| 1.182| 8444| -|Dubbo: Dubbo serialization| 1.43| 6982| -|Dubbo: hessian2| 1.49| 6701| -|Dubbo: fastjson| 1.572| 6352 - - - -Just a brief summary of the current results: - - - Dubbo RPC (especially when based on efficient java serialization methods such as kryo and fst) has a significant advantage response time and throughput over REST. Dubbo RPC is preferred in the intranet Dubbo systems. - - When choosinf REST implementation, tomcat7 and netty are optimal (of course, the current versions of jetty and netty are lower) currently only considering performance. Tjws and sun http server performed extremely poorly in performance tests, with an average response time of more than 200ms and an average tps of only about 50 (to avoid affecting the picture effect, the results are not listed above). - - Performance of JSON data format is better than XML in REST (data is not listed above). - - Enabling GZIP in REST has little to do with complex objects with small data volume in the intranet, but performance has declined (data is not listed above). - - -## Performance Optimization Recommendations - -If you deploy Dubbo REST to an external Tomcat and configure server="servlet", that is, enable external tomcat as the underlying implementation of rest server, it is best to add the following configuration to tomcat: -```xml - -``` - -Especially the configuration maxKeepAliveRequests="-1" ,which is mainly to ensure that tomcat always enables http long connection, in order to improve the performance of REST call. Note, however, that if the REST consumer side is not continuously call REST services, it is not always best to enable long connections all time. In addition, the way to always enable long connections is generally not suitable for ordinary webapps, but more suitable for such rpc-like scenarios. So that in order to get high performance, Dubbo REST applications and ordinary web applications are best not to be mixed deployment, but should use a separate instance in tomcat. - - -##Extended discussion ---- - -### Comparison among Rest, Thrift, Protobuf and so on - -TODO - -### Comparison between REST and traditional Webservers - -TODO - - -### Comparison of JAX-RS Between Spring MVC - -A preliminary view from http://www.infoq.com/cn/news/2014/10/Dubbox-open-source?utm_source=infoq&utm_medium=popular_links_homepage#theCommentsSection -> Thank you, in fact, for jax-rs and Spring MVC, I do not have a deep look at the rest support of Spring MVC. I would like to give you some preliminary ideas. Please correct me: - -> Spring MVC also supports configuration using annotation, which actually looks very similar to jax-rs. - -> Personally, I think Spring MVC is better suited to restful services of web applications, such as being invoked by AJAX, or possibly outputting HTML or something like page jump processes in applications. Spring MVC can handle both normal web page requests and rest requests at the same time. But in general, the restful service is implemented in the presentation layer or the web layer. - -> But Jax-rs is more suitable for pure service-oriented applications, that is, the middle-tier services in traditional Java EE, for example, it can publish traditional EJB as restful services. In a Spring application, the bean that acts as a service in the Spring is directly published as a restful service. In general, the restful service is at the business layer, application layer, or facade layer. And MVC hierarchies and concepts are often of little value in such (back-end) applications. - -> Of course, some implementations of jax-rs, such as jersey, also try to include MVC to better accommodate the web applications described above, but not as well as Spring MVC. - -> In Dubbo applications, I think a lot of people prefer to publish a local Spring service bean (or manager) as a remote service directly and transparently, so that it is more straightforward to use JAX-RS here, and there is no need to introduce the MVC concept. Of course, we do not discuss whether transparent publishing of remote services is a best practice or whether to add facade things here first. - -> Of course, I know that many people use Spring MVC restful to call Dubbo (spring) service to publish restful services under the situation that Dubbo does not support rest now. It’s a good method also in my opinion, but if you do not modify Spring MVC and integrate it deeply with Dubbo, restful services cannot enjoy many advanced services such as registering to the Dubbo Registry, monitoring the number of calls, TPS, response time through the Dubbo Monitor, controlling the size of the thread pool and the maximum number of connections through the unified configuration of Dubbo, and controlling the service flow, authority and frequency through Dubbo unified mode like other remote call protocol such as webservices, Dubbo rpc, hessian and so on in Dubbo system. In addition, Spring MVC only works in server side and Spring restTemplate are usually used on consumer side. If restTemplate is not integrated with Dubbo, the service can be downgraded by Dubbo client automatically or manually. If the server and consumer are all Dubbo system, you cannot use unified routing and other functions in Dubbo if the Spring rest is not deeply integrated into Dubbo through interaction of Spring and rest. - -> Of course, I personally think that these things are not necessarily to be one or the other. I heard that Rod Johnson, the founder of spring usually says ‘the customer is always right,’ In fact, it is better to support both ways at the same time rather than discuss which way is better, so that originally I wrote in the document that we plan to support Spring rest annotation, but the feasibility is unknown. - -##Future ---- -Functions may be supported later: - - - Rest annotation for Spring MVC - - Safety System - - OAuth - - Asynchronous calls - - Gzip - - Payload maxsize diff --git a/content/en/docs/v2.7/user/simple-monitor.md b/content/en/docs/v2.7/user/simple-monitor.md deleted file mode 100644 index 8d711aa57fa7..000000000000 --- a/content/en/docs/v2.7/user/simple-monitor.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -type: docs -title: "Simple Monitor" -linkTitle: "Simple monitor" -weight: 20 -description: "Dubbo simple monitor service" ---- - -{{% alert title="Warning" color="warning" %}} -Monitor service is a standard Dubbo service,can be exported to the registry,also can be connected straightly. - -[Install the simple registry](/en/docs/v2.7/admin/install/) -{{% /alert %}} - - -0. export a simple monitor service to the registry: (If you use the installer, you don't need to write this configuration yourself. if you implement the monitor service yourself,need it) - - ```xml - - - - - - - - - - - - - - - - - ``` - -1. Discovery the monitor service int the registry: - - ```xml - - ``` - - or - - > dubbo.properties - - ```xml - dubbo.monitor.protocol=registry - ``` - -2. Export a simple monitor service ,but don't register it to th registry: (If you use the installer, you don't need to write this configuration yourself. if you implement the monitor service yourself,need it) - - ```xml - - - - - - - - - - - - - - ``` - -3. connected to the monitor service straightly - - ```xml - - ``` - - or: - - ```sh - - ``` - - or: - - **dubbo.properties** - - ```sh - dubbo.monitor.address=127.0.0.1:7070 - ``` - - diff --git a/content/en/docs/v3.0/_index.md b/content/en/docs/v3.0/_index.md deleted file mode 100755 index dcf6d68870d1..000000000000 --- a/content/en/docs/v3.0/_index.md +++ /dev/null @@ -1,14 +0,0 @@ - ---- -type: docs -title: "Dubbo 3.0" -linkTitle: "Dubbo 3.0" -weight: 20 -description: "Dubbo 3.0 documentation" ---- - -{{% pageinfo %}} -Under Construction -{{% /pageinfo %}} - - diff --git a/content/en/docs/v3.0/languages/_index.md b/content/en/docs/v3.0/languages/_index.md deleted file mode 100755 index 3b63699773d8..000000000000 --- a/content/en/docs/v3.0/languages/_index.md +++ /dev/null @@ -1,8 +0,0 @@ - ---- -type: docs -title: "Multi-language implementation" -linkTitle: "multi-language" -weight: 60 -description: "Dubbo support multi-language implementation, please learn about the special usage of each language" ---- diff --git a/content/en/docs/v3.0/languages/erlang/_index.md b/content/en/docs/v3.0/languages/erlang/_index.md deleted file mode 100755 index f984c9e82ed4..000000000000 --- a/content/en/docs/v3.0/languages/erlang/_index.md +++ /dev/null @@ -1,9 +0,0 @@ - ---- -type: docs -title: "Erlang" -linkTitle: "Erlang" -weight: 200 -description: "Erlang support" ---- - diff --git a/content/en/docs/v3.0/languages/erlang/quick-start.md b/content/en/docs/v3.0/languages/erlang/quick-start.md deleted file mode 100644 index dedb2691fa88..000000000000 --- a/content/en/docs/v3.0/languages/erlang/quick-start.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -type: docs -title: "Quick start " -linkTitle: "Quick start" -weight: 1 -description: "Erlang Quick start" ---- - -It is recommended to use java to define the interface jar first, and use the [erlanalysis](https://github.com/apache/dubbo-erlang/tree/master/tools/erlanalysis) tool to parse the java interface to Erlang lib - - -## Import dependent libraries - -### Use the Rebar compilation tool. - -Add dubblerl to rebar.config to your project - -```erlang -{deps, [ - {dubboerl, {git, "https://github.com/apache/dubbo-erlang.git", {branch, "master"}}} -]}. -``` - -### Use erlang.mk compilation tool - -`in progress...` - -## Import interface library -Suppose the interface lib you exported is called dubbo_service. -* If you didn't upload your lib to your git repository, It is recommended that you copy the `dubbo_service` lib -into the project's `apps` directory. -* If it is uploaded to your git repository, you can import like this: -```erlang -{deps, [ - {dubboerl, {git, "https://github.com/apache/dubbo-erlang.git", {branch, "master"}}}, - {dubbo_service,{git,"${INTERFACE_LIB_URL}",{branch,"master"}}} %% replace ${INTERFACE_LIB_URL} with your lib git repos url -]}. -``` - -## Consumer configuration -Please reference [Reference Config](../reference/) - -## Init dubbolib in your project -It is need you -```erlang -dubboerl:init(). -``` - -## How to call? - -### Synchronous call - -```erlang -Request = #userInfoRequest{requestId = 123, username = "testname"}, -{ok,RequestRef,Response,RpcContent} = userOperator:queryUserInfo(Request,#{sync=> true}). -``` -If it occur error, is reponse `{error,Reason}`. - -### Asynchronous call - -Default is Async call. -```erlang -Request = #userInfoRequest{requestId = 123, username = "testname"}, -{ok,RequestRef} = userOperator:queryUserInfo(Request). - -%% you can receive the message after. -handle_cast({msg_back,RequestRef,Response,RpcContent},State). -``` - -## Example -Refer to [dubboerl_demo](https://github.com/apache/dubbo-erlang/tree/master/samples) diff --git a/content/en/docs/v3.0/languages/erlang/reference.md b/content/en/docs/v3.0/languages/erlang/reference.md deleted file mode 100644 index 0b3de6fdbec0..000000000000 --- a/content/en/docs/v3.0/languages/erlang/reference.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -type: docs -title: "Consumer configuration" -linkTitle: "Consumer configuration" -weight: 2 -description: "Configure consumers in erlang" ---- - -## Basic configuration - -Consumers need to add configuration items to `sys.config` file `dubboerl` filed. - -```erlang -{dubboerl,[ - %% other config ... - {consumer,[ - {<<"interface fullname">>,[Option]}, - %% eg: - {<<"org.apache.dubbo.erlang.sample.service.facade.UserOperator">>,[]}, - ]} -]} -``` - -Option is to be added. diff --git a/content/en/docs/v3.0/languages/erlang/serialization.md b/content/en/docs/v3.0/languages/erlang/serialization.md deleted file mode 100644 index e1ff3dc6bf48..000000000000 --- a/content/en/docs/v3.0/languages/erlang/serialization.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -type: docs -title: "Serialized configuration items" -linkTitle: "Serialized configuration items" -weight: 4 -description: "Configure the serialization method in erlang" ---- - -The library currently only implements the `dubbo://` communication protocol. - -It supports `hessian` and `json` as serialization method. - -## Configuration example - -Provider configuration items to add to the `sys.config` file `dubboerl` field. - -```erlang -{dubboerl,[ - %% other config ... - {protocol,hessian} -]} -``` - -| ConfigName | Type | DefaultValue | Remarks | -| --- | --- | --- | --- | -| protocol | atom() | hessian | hessian,json | diff --git a/content/en/docs/v3.0/languages/erlang/service.md b/content/en/docs/v3.0/languages/erlang/service.md deleted file mode 100644 index 2b86723305b2..000000000000 --- a/content/en/docs/v3.0/languages/erlang/service.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -type: docs -title: "Provider configuration" -linkTitle: "Provider configuration" -weight: 3 -description: "Configure service provider in erlang" ---- - -## basic configuration - -Provider configuration items to add to the `sys.config` file `dubboerl` field - -```erlang -{dubboerl,[ - %% other config ... - {provider,[ - {module_implements,interface_module,interface_fullname,[Options]}, - %% eg: - {userOperator_impl,userOperator,<<"org.apache.dubbo.erlang.sample.service.facade.UserOperator">>,[Option]} - ]} -]} -``` - -| ConfigName | Type | DefaultValue | Remarks | -| --- | --- | --- | --- | -| module_implements | atom() | - | The service implements module name| -| interface_module | atom() | - | Interface module name is transfer form java jar | -| interface_fullname | binary() | - | Interface full name is the java class name | - -Option is to be added. diff --git a/content/en/docs/v3.0/languages/golang/_index.md b/content/en/docs/v3.0/languages/golang/_index.md deleted file mode 100755 index cba0e1b75475..000000000000 --- a/content/en/docs/v3.0/languages/golang/_index.md +++ /dev/null @@ -1,9 +0,0 @@ - ---- -type: docs -title: "golang" -linkTitle: "golang" -weight: 200 -description: "golang support" ---- - diff --git a/content/en/docs/v3.0/languages/golang/go-specific.md b/content/en/docs/v3.0/languages/golang/go-specific.md deleted file mode 100644 index 3ead6fdd7e9c..000000000000 --- a/content/en/docs/v3.0/languages/golang/go-specific.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: docs -title: "Go language definition service" -linkTitle: "Go language definition service" -weight: 10 -description: "" ---- diff --git a/content/en/docs/v3.0/languages/golang/quick-start.md b/content/en/docs/v3.0/languages/golang/quick-start.md deleted file mode 100644 index 3374e99e542c..000000000000 --- a/content/en/docs/v3.0/languages/golang/quick-start.md +++ /dev/null @@ -1,212 +0,0 @@ ---- -type: docs -title: "Go quick start" -linkTitle: "Go quick start" -weight: 10 -description: "" ---- - -It is recommended to use IDL to define cross-language services and coding formats. - -The following shows the service definition and development methods of the Golang language version. If you have a legacy system or do not have multi-language development requirements, you can refer to the following usage methods. - -# Quick start -use `hello world` example to show how to start with the Dubbo-go framework. - -Protocol: Dubbo - -Coding: Hessian2 - -Registration Center: Zookeeper - -## environment - -* Go programming environment -* Zookeeper service, you can also use a remote instance - - -## Server - -### The first step: writing `Provider` structure and method for providing services - -> - - -1. Write structure which needs to be transferred, since we are using `Hessian2`, so the `User` class needs to implement the `JavaClassName` method. It will include class names. - -```go -type User struct { - Id string - Name string - Age int32 - Time time.Time -} - -func (u User) JavaClassName() string { - return "com.ikurento.user.User" -} -``` - -2.Writing business logic in `UserProvider` which is the same as what we do in dubbo java. -Need to implement the `Reference` method, the return value is uniquely identified in the service, corresponding to the dubbo `beans` and `path` fields. - -```go -type UserProvider struct { -} - -func (u *UserProvider) GetUser(ctx context.Context, req []interface{}) (*User, error) { - println("req:%#v", req) - rsp := User{"A001", "hellowworld", 18, time.Now()} - println("rsp:%#v", rsp) - return &rsp, nil -} - -func (u *UserProvider) Reference() string { - return "UserProvider" -} -``` - -3. Register services and objects - -```go -func init() { - config.SetProviderService(new(UserProvider)) - // ------for hessian2------ - hessian.RegisterPOJO(&User{}) -} -``` - -### Step 2: Write the main program - -> - -1. Introduce the necessary dubbo-go package - -```go -import ( - hessian "github.com/apache/dubbo-go-hessian2" - "github.com/apache/dubbo-go/config" - _ "github.com/apache/dubbo-go/registry/protocol" - _ "github.com/apache/dubbo-go/common/proxy/proxy_factory" - _ "github.com/apache/dubbo-go/filter/impl" - _ "github.com/apache/dubbo-go/cluster/cluster_impl" - _ "github.com/apache/dubbo-go/cluster/loadbalance" - _ "github.com/apache/dubbo-go/registry/zookeeper" - - _ "github.com/apache/dubbo-go/protocol/dubbo" -) - -``` - -2. main function - -```go -func main() { - config.Load() -} -``` - -### Step 3: Write a configuration file and configure environment variables - -1. Reference to [log](https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-server/profiles/release/log.yml) and [server](https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-server/profiles/release/server.yml) to edit configuration file。 - -Mainly edit the following parts: - -* `registries`: The number and address of zk server - -* `services`: Service specific information in the configuration node, modify `interfacec` to the interface to the corresponding service name, modify `key` to the value which is the same as the first step `Referenc` return value. - -2. Configure the above two configuration files as environment variables - -```shell -export CONF_PROVIDER_FILE_PATH="xxx" -export APP_LOG_CONF_FILE="xxx" -``` - -## Client - -### The first step: writing the client `Provider` - -> - -1. Refer to the first point of the first step on the server side. - -2. Different from the server side, the method of providing the service is used as the parameter of the structure, and there is no need to write specific business logic. In addition, `Provider` does not correspond to the interface in dubbo, but corresponds to an implementation. - -```go -type UserProvider struct { - GetUser func(ctx context.Context, req []interface{}, rsp *User) error -} - -func (u *UserProvider) Reference() string { - return "UserProvider" -} -``` - -3. Register services and objects - -```go -func init() { - config.SetConsumerService(userProvider) - hessian.RegisterPOJO(&User{}) -} -``` - -### Step 2: Write the client main program - -> - -1. Introduce the necessary dubbo-go package - -```go -import ( - hessian "github.com/apache/dubbo-go-hessian2" - "github.com/apache/dubbo-go/config" - _ "github.com/apache/dubbo-go/registry/protocol" - _ "github.com/apache/dubbo-go/common/proxy/proxy_factory" - _ "github.com/apache/dubbo-go/filter/impl" - _ "github.com/apache/dubbo-go/cluster/cluster_impl" - _ "github.com/apache/dubbo-go/cluster/loadbalance" - _ "github.com/apache/dubbo-go/registry/zookeeper" - - _ "github.com/apache/dubbo-go/protocol/dubbo" -) -``` - -2. main function - -```go -func main() { - config.Load() - time.Sleep(3e9) - - println("\n\n\nstart to test dubbo") - user := &User{} - err := userProvider.GetUser(context.TODO(), []interface{}{"A001"}, user) - if err != nil { - panic(err) - } - println("response result: %v\n", user) -} -func println(format string, args ...interface{}) { - fmt.Printf("\033[32;40m"+format+"\033[0m\n", args...) -} -``` - -### Step 3: Write a configuration file and configure environment variables - - -1. Refer to [log](https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-client/profiles/release/log.yml) and [client](https://github.com/dubbogo/dubbo-samples/blob/master/golang/helloworld/dubbo/go-client/profiles/release/client.yml) to modify configuration file。 - -Mainly edit the following parts: - -* `registries`: The number and address of zk server - -* `services`: Service specific information in the configuration node, modify `interfacec` to the interface to the corresponding service name, modify `key` to the value which is the same as the first step `Reference` return value. - -2. Configure the above two configuration files as environment variables. In order to prevent the log environment variables from conflicting with the server-side log environment variables, it is recommended that all environment variables should not be configured globally, and they can take effect at present. - -```shell -export CONF_CONSUMER_FILE_PATH="xxx" -export APP_LOG_CONF_FILE="xxx" -``` diff --git a/content/en/docs/v3.0/languages/rust/_index.md b/content/en/docs/v3.0/languages/rust/_index.md deleted file mode 100755 index 036471905ce7..000000000000 --- a/content/en/docs/v3.0/languages/rust/_index.md +++ /dev/null @@ -1,10 +0,0 @@ - ---- -type: docs -title: "Rust" -linkTitle: "Rust" -weight: 200 -description: "Dubbo-rust support" -manualLinkRelref: ../../../../docs3-v2/rust-sdk/ ---- - diff --git a/content/en/docs/v3.0/loadbalance/_index.md b/content/en/docs/v3.0/loadbalance/_index.md deleted file mode 100644 index af2dddc7e122..000000000000 --- a/content/en/docs/v3.0/loadbalance/_index.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -type: docs -title: "Load Balance" -linkTitle: "Load Balance" -weight: 3 -description: "Load Balance in Apache Dubbo 3.x" ---- - -Dubbo offers a number of balancing strategies for cluster load balancing, which defaults to `random`. - -You can extend the load balancing strategy by yourself, see: [LoadBalance extension](../../v2.7/dev/impls/load-balance/) - -## LoadBalance strategy - -### Random LoadBalance - -* **Ramdom**, set random probabilities by weight. - -* The probability of collisions on one section is high, but the larger the amount of calls, the more uniform the distribution. And when use weight based on probability the distribution turns out to be uniform, which also helps to dynamically adjust the provider weights. - -### RoundRobin LoadBalance - -* **RoundRobin**, use the weight's common advisor to determine round robin ratio. - -* Traffic flow to slower providers may cause requests piled up, e.g., if there's a provider processing requests in a very slow speed, but it's still alive, which means it can receive request as normal. According to RoundRobin policy, consumers will continuously send requests to this provider on predetermined pace, have no aware of the provider's bad status. Finally, we will get many requests stuck on this unhealthy provider. - -### LeastActive LoadBalance - -* **LeastActive**, a random mechanism based on actives, `actives` means the num of requests a consumer have sent but not return yet。 - -* Slower providers will receive fewer requests, cause slower provider have higher `actives`. - -### ConsistentHash LoadBalance - -* **ConsistentHash**, the provider always receive the same parameters of the request. - -* When a provider fails, the original request to the provider, based on the virtual node algorithm, averages to other providers, does not cause drastic changes. - -* Algorithm reference:http://en.wikipedia.org/wiki/Consistent_hashing - -* By default only the first parameter Hash, if you want to modify, please configure `` - -* By default 160 virtual nodes, if you want to modify, please configure `` - -See the algorithm at http://en.wikipedia.org/wiki/Consistent_hashing - -### ShortestResponse LoadBalance - -* Give priority to the shorter response time of the current interval of time. If there are multiple invokers and the same weight, then randomly is called. - -* Providers with faster response times can handle more requests. - -* Disadvantages: It may cause traffic to be too concentrated on high-performance nodes. - -* The response time is the average response time of providers in the interval of time. The interval of time is 30 seconds by default. - -## Configuration - -### Server Service Level and Client Service Level - -```xml - -``` - -### Server Method Level and Client Method Level - -```xml - - - -``` \ No newline at end of file diff --git a/content/en/docs/v3.0/references/_index.md b/content/en/docs/v3.0/references/_index.md deleted file mode 100644 index 9785bb68a1c7..000000000000 --- a/content/en/docs/v3.0/references/_index.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "Function Reference Manual" -linkTitle: "Reference" -weight: 12 -description: "User-oriented reference manual, covering all core functions of Dubbo3" ---- - diff --git a/content/en/docs/v3.0/references/graalvm/_index.md b/content/en/docs/v3.0/references/graalvm/_index.md deleted file mode 100644 index 269e85622b4f..000000000000 --- a/content/en/docs/v3.0/references/graalvm/_index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: docs -title: "graalvm support" -linkTitle: "support graalvm" -weight: 40 -description: "" ---- diff --git a/content/en/docs/v3.0/references/graalvm/support-graalvm.md b/content/en/docs/v3.0/references/graalvm/support-graalvm.md deleted file mode 100644 index 521c41265dae..000000000000 --- a/content/en/docs/v3.0/references/graalvm/support-graalvm.md +++ /dev/null @@ -1,152 +0,0 @@ -## Overview - -This document will show you how to access GraalVM with a dubbo project and how to compile the project to a binary executable using native-image. - -For more information about GraalVM, read https://www.graalvm.org/docs/getting-started/container-images/. - -## Demo - -Before compiling the dubbo project, make sure that we are programming based on the GraalVM environment. - -1. Install GraalVM - - Visite the official website (https://www.graalvm.org/ ) and install the latest version based on your system: - -![img](/imgs/blog/dubbo3.0-graalvm-support/graalvmgw.jpg) - - After installation, configure the path of JAVA_HOME. You should see thr following in your local jdk after this step: - -![img](/imgs/blog/dubbo3.0-graalvm-support/graalvm_env.jpg) - - GraalVM we use here is based on jdk version 1.8. - To install native-image, run 'gu install native-image'. - -2. Pull dubbo code and switch to branch [apache:3.0](https://github.com/apache/dubbo). - -3. Manually generate SPI code - - Currently native-image compiling does not support dynamic code generation. Therefore we need to first manually generate the part of the code that is generated dynamically. The tool function is provided here: - -![img](/imgs/blog/dubbo3.0-graalvm-support/code_generator.jpg) - - Execute CodeGenerator can generate SPI code under the dubbo-native module. - -4. Execute 'install' under the root directory - - ```ruby - MacdeMacBook-pro-3:incubator-dubbo mac$ pwd - /Users/mac/Documents/Mi/project/incubator-dubbo - MacdeMacBook-pro-3:incubator-dubbo mac$ mvn clean package install -Dmaven.test.skip=true - ``` - -5. Compile the project demo - - Here we provide a demo project that can be directly compiled: dubbo-demo / dubbo-demo-native. After installation, first go to the provider in dubbo-demo-native and execute native-image compilation: - - ```java - mvn clean package -P native -Dmaven.test.skip=true - ``` - - Since we have imported native-image plugin in maven, here we can use '-P native' to execute the plugin. - -![img](/imgs/blog/dubbo3.0-graalvm-support/native_image_build.jpg) - - After a success compilation, we can find the generated binary file under target. Succefully iniate a zookeeper locally and execute the binary executable file should show us this: - -![img](/imgs/blog/dubbo3.0-graalvm-support/run_provider.jpg) - - Compile on consumer' side will generate a binary executable file 'demo-native-consumer' under consumer's target. Execute the file will give us the following output: - -![img](/imgs/blog/dubbo3.0-graalvm-support/run_consumer.jpg) - -### Additional Steps - -In this demo, we did extra work to make sure the project can be compiled. Here are the additional steps: - -- Import dependency dubbo-native - - ```html - - org.apache.dubbo - dubbo-native - ${project.version} - - ``` - - Our generated SPI code is in this module. - -- Import native-image plug-in - - ```Lua - - org.graalvm.nativeimage - native-image-maven-plugin - 21.0.0.2 - - - - native-image - - package - - - - false - demo-native-provider - org.apache.dubbo.demo.graalvm.provider.Application - - --no-fallback - --initialize-at-build-time=org.slf4j.MDC - --initialize-at-build-time=org.slf4j.LoggerFactory - --initialize-at-build-time=org.slf4j.impl.StaticLoggerBinder - --initialize-at-build-time=org.apache.log4j.helpers.Loader - --initialize-at-build-time=org.apache.log4j.Logger - --initialize-at-build-time=org.apache.log4j.helpers.LogLog - --initialize-at-build-time=org.apache.log4j.LogManager - --initialize-at-build-time=org.apache.log4j.spi.LoggingEvent - --initialize-at-build-time=org.slf4j.impl.Log4jLoggerFactory - --initialize-at-build-time=org.slf4j.impl.Log4jLoggerAdapter - --initialize-at-build-time=org.eclipse.collections.api.factory.Sets - --initialize-at-run-time=io.netty.channel.epoll.Epoll - --initialize-at-run-time=io.netty.channel.epoll.Native - --initialize-at-run-time=io.netty.channel.epoll.EpollEventLoop - --initialize-at-run-time=io.netty.channel.epoll.EpollEventArray - --initialize-at-run-time=io.netty.channel.DefaultFileRegion - --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventArray - --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventLoop - --initialize-at-run-time=io.netty.channel.kqueue.Native - --initialize-at-run-time=io.netty.channel.unix.Errors - --initialize-at-run-time=io.netty.channel.unix.IovArray - --initialize-at-run-time=io.netty.channel.unix.Limits - --initialize-at-run-time=io.netty.util.internal.logging.Log4JLogger - --initialize-at-run-time=io.netty.channel.unix.Socket - --initialize-at-run-time=io.netty.channel.ChannelHandlerMask - - --report-unsupported-elements-at-runtime - --allow-incomplete-classpath - --enable-url-protocols=http - -H:+ReportExceptionStackTraces - - - - ``` - - Generated image names and parameters used for generating image are defined. - -- Mount native-image-agent - - Since some classes, including reflection and JNI, need to be assigned, we have to use the agent to run the json information that generate these classes. - - Add the following to startup parameters: - - ```xml - -agentlib:native-image-agent=config-output-dir=/tmp/config/,config-write-period-secs=300,config-write-initial-delay-secs=5 - ``` - - Launch in conventional way, create folder 'META-INF.native-image' under the resources folder and paste the generated files in the local directory into the folder. - -![img](/imgs/blog/dubbo3.0-graalvm-support/resources.jpg) - - (Missing classes' information may exist. These information need to be manually added according to the error message reported while compiling or running.) - - **Finished the steps above, now you can compile your project.** diff --git a/content/en/docs/v3.0/references/lifecycle/_index.md b/content/en/docs/v3.0/references/lifecycle/_index.md deleted file mode 100644 index 2a0c14727325..000000000000 --- a/content/en/docs/v3.0/references/lifecycle/_index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: docs -title: "Align with Kubernetes Lifecycle" -linkTitle: "Probe" -weight: 9 ---- - diff --git a/content/en/docs/v3.0/references/lifecycle/brief.md b/content/en/docs/v3.0/references/lifecycle/brief.md deleted file mode 100644 index a4fd9f32b627..000000000000 --- a/content/en/docs/v3.0/references/lifecycle/brief.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -type: docs -title: "Brief" -linkTitle: "Brief" -weight: 9 ---- - -[Pod Lifecycle](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/) is closely related to micro-service scheduling. Through the implementation of official Kubernetes probes, the life cycle of Dubbo and even the entire application can be aligned with the Pod Lifecycle. -Using Dubbo's SPI mechanism, a variety of "probes" are implemented internally. Based on the HTTP service of the Dubbo QOS operation and maintenance module, the container probe can obtain the status of the corresponding probe in the application. In addition, the implementation mechanism of SPI is also conducive to users to expand their own internal "probes", so that the entire application life cycle can be more effectively controlled. - - -## Usage - - -Example (For details, please refer to the configuration file of the Kubernetes Registry in dubbo-samples) -```yaml -livenessProbe: - httpGet: - path: /live - port: 22222 - initialDelaySeconds: 5 - periodSeconds: 5 -readinessProbe: - httpGet: - path: /ready - port: 22222 - initialDelaySeconds: 5 - periodSeconds: 5 -startupProbe: - httpGet: - path: /startup - port: 22222 - failureThreshold: 30 - periodSeconds: 10 -``` - - -At present, the three probes have corresponding interfaces. The `path` section is the command in Dubbo QOS. Please modify the `port` section according to the QOS configuration ( default port is 22222 ). For other     parameters, please refer to the [official documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). - - -Note: In order to enable the Kubernetes cluster to access the probe correctlly, you need to enable allow remote access for Dubbo QOS. This operation may bring security risks. Please carefully evaluate and then open it. - - -## Implementation details - - -The SPI interfaces corresponding to the three probes in Kubernetes are as follows: - -- livenessProbe: `org.apache.dubbo.qos.probe.LivenessProbe` -- readinessProbe: `org.apache.dubbo.qos.probe.ReadinessProbe` -- startupProbe: `org.apache.dubbo.qos.probe.StartupProbe` - - - -The QOS command will automatically obtain all SPI implementations of the current application. When all of the SPI implementations of the corresponding interfaces are in ready mode, and the command will returns success. - - -#### Liveness -For livenessProbe, because the Dubbo framework itself cannot obtain the liveness status of the application, there is no default implementation of this interface and it will always return success by default. Developers can expand this SPI interface according to the SPI definition and judge whether it is alive at the application level. - - -#### Readiness -For readinessProbe, Dubbo currently provides two detection dimensions by default. One is to judge whether the Dubbo service itself is started or stopped, and the other is to determine whether all services have registered interfaces. If all services have been offline from the registry ( you can offline them through Dubbo QOS ) will return to not ready state. - - -#### Startup -For startupProbe, Dubbo currently provides one detection dimension by default, which is to return to the ready state after all startup processes (interface exposure, registry writing, etc.) are completed. - diff --git a/content/en/docs/v3.0/references/lifecycle/liveness.md b/content/en/docs/v3.0/references/lifecycle/liveness.md deleted file mode 100644 index 6119178318ee..000000000000 --- a/content/en/docs/v3.0/references/lifecycle/liveness.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -type: docs -title: "Liveness Probe" -linkTitle: "Liveness" -weight: 12 ---- - -## Summary - - -Extend the detection point of application survival. -## Extension Interface - - -`org.apache.dubbo.qos.probe.LivenessProbe` - - -## Extension Configuration - - -Dubbo QOS `live` command will automaticly discovery. - - -## Existing Extensions - - -No default implementation - - -## Extension Guide - - -Directory layout: - - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxLivenessProbe.java (LivenessProbe implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.qos.probe.LivenessProbe (plain text file with the content:xxx=com.xxx.XxxLivenessProbe) -``` - - -XxxLivenessProbe.java: - - -```java -package com.xxx; - -public class XxxLivenessProbe implements LivenessProbe { - - public boolean check() { - // ... - } -} -``` - - -META-INF/dubbo/org.apache.dubbo.qos.probe.LivenessProbe: - - -``` -xxx=com.xxx.XxxLivenessProbe -``` - - - diff --git a/content/en/docs/v3.0/references/lifecycle/readiness.md b/content/en/docs/v3.0/references/lifecycle/readiness.md deleted file mode 100644 index 564bd0ed13e1..000000000000 --- a/content/en/docs/v3.0/references/lifecycle/readiness.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -type: docs -title: "Readiness Probe" -linkTitle: "Readiness" -weight: 12 ---- - -## Summary - - -Extend the detection point of application readiness. -## Extension Interface - - -`org.apache.dubbo.qos.probe.ReadinessProbe` - - -## Extension Configuration - - -Dubbo QOS `ready` command will automaticly discovery. - - -## Existing Extensions - - -- `org.apache.dubbo.qos.probe.impl.BootstrapReadinessProbe` -- `org.apache.dubbo.qos.probe.impl.ProviderReadinessProbe` - - - -## Extension Guide - - -Directory layout: - - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxReadinessProbe.java (ReadinessProbe implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.qos.probe.ReadinessProbe (plain text file with the content:xxx=com.xxx.XxxReadinessProbe) -``` - - -XxxReadinessProbe.java: - - -```java -package com.xxx; - -public class XxxReadinessProbe implements ReadinessProbe { - - public boolean check() { - // ... - } -} -``` - - -META-INF/dubbo/org.apache.dubbo.qos.probe.ReadinessProbe: - - -``` -xxx=com.xxx.XxxReadinessProbe -``` - - diff --git a/content/en/docs/v3.0/references/lifecycle/startup.md b/content/en/docs/v3.0/references/lifecycle/startup.md deleted file mode 100644 index 18f877dd2fb1..000000000000 --- a/content/en/docs/v3.0/references/lifecycle/startup.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -type: docs -title: "Startup Probe" -linkTitle: "Startup" -weight: 12 ---- - -## Summary - - -Extend the detection point of application startup. -## Extension Interface - - -`org.apache.dubbo.qos.probe.StartupProbe` - - -## Extension Configuration - - -Dubbo QOS `startup` command will automaticly discovery. - - -## Existing Extensions - - -- `org.apache.dubbo.qos.probe.impl.BootstrapStartupProbe` - - - -## Extension Guide - - -Directory layout: - - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxStartupProbe.java (StartupProbe implementation) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.qos.probe.StartupProbe (plain text file with the content:xxx=com.xxx.XxxStartupProbe) -``` - - -XxxStartupProbe.java: - - -```java -package com.xxx; - -public class XxxStartupProbe implements StartupProbe { - - public boolean check() { - // ... - } -} -``` - - -META-INF/dubbo/org.apache.dubbo.qos.probe.StartupProbe: - - -``` -xxx=com.xxx.XxxStartupProbe -``` - - - diff --git a/content/en/docs/v3.0/whats-new-in-dubbo3/_index.md b/content/en/docs/v3.0/whats-new-in-dubbo3/_index.md deleted file mode 100644 index 9f9e128b0eb5..000000000000 --- a/content/en/docs/v3.0/whats-new-in-dubbo3/_index.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -type: docs -title: "What's new in Apache Dubbo 3.x?" -linkTitle: "What's new in Apache Dubbo 3.x?" -weight: 10 -description: "A summary of the new features available in Dubbo 3.x" ---- - - -## New Service Discovery Mechanism - -* Performance improvements - -* Support for connecting with other microservices such as Spring Cloud, Kubernetes, gRPC, etc. - -## Triple: The new protocol based on HTTP/2 - -* Compatible with gRPC - -* Multi-language friendly: You can use Protobuf to encode data - -* Support for streams such as Request Stream, Response Stream, and Bidirectional Stream. - -## Cloud-Native - -* Deployment of Dubbo 3.x Applications in Kubernetes, VM, and Container. - -## Package distribution - -* Dubbo 3.x only includes the core dependency package and now the user has to include each optional dependency. - -Example - -```xml - - 3.0.0 - - - - - org.apache.dubbo - dubbo - ${dubbo.version} - - - - org.apache.dubbo - dubbo-registry-redis - ${dubbo.version} - - -``` - -## Removed dependencies - -* org.eclipse.collections:eclipse-collections - -* com.google.guava:guava - -## Dependency changes - -* Upgrade to Jetty 9.4.43.v20210629 - -* Upgrade to Apollo Client 1.8.0 - -* Upgrade to Snakeyaml 1.29 - -* Upgrade to Tomcat Embed 8.5.69 - -* Upgrade to Nacos Client 2.0.2 - -* Upgrade to Swagger 1.5.24 diff --git a/content/en/docs3-v2/_index.md b/content/en/docs3-v2/_index.md deleted file mode 100755 index 11f11b8ffcf9..000000000000 --- a/content/en/docs3-v2/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -type: docs -title: "SDK Manual" -linkTitle: "SDK Manual" -hide_summary: true -# menu: -# main: -# weight: 21 ---- diff --git a/content/en/docs3-v2/erlang-sdk/_index.md b/content/en/docs3-v2/erlang-sdk/_index.md deleted file mode 100755 index 6641d6ff4f69..000000000000 --- a/content/en/docs3-v2/erlang-sdk/_index.md +++ /dev/null @@ -1,9 +0,0 @@ - ---- -type: docs -title: "Erlang" -linkTitle: "Erlang" -weight: 500 -description: "Erlang SDK Manual" ---- - diff --git a/content/en/docs3-v2/golang-sdk/_index.md b/content/en/docs3-v2/golang-sdk/_index.md deleted file mode 100755 index 414202a739e8..000000000000 --- a/content/en/docs3-v2/golang-sdk/_index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: docs -title: "Golang" -linkTitle: "Golang" -weight: 20 -description: "Go SDK Manual" ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/preface/3.0_feature.md b/content/en/docs3-v2/golang-sdk/preface/3.0_feature.md deleted file mode 100644 index 4ed5de32fb88..000000000000 --- a/content/en/docs3-v2/golang-sdk/preface/3.0_feature.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -type: docs -title: New Features of Dubbo-go 3.0 -keywords: 3.0 new features -weight: 3 ---- - -![star](https://shields.io/github/stars/apache/dubbo-go?style=dark) - -## 1. Triple protocol - -### 1.1 Overview - -![img](/imgs/docs3-v2/golang-sdk/concept/more/3.0_feature/tri.png) - -- communication level - - The Triple protocol, also known as the Dubbo3 protocol, is an extension protocol based on the HTTP2 + gRPC protocol, adding specific fields and logic, ensuring interoperability with the **native gRPC protocol**. On this basis, Triple's new protocol will more natively support **Dubbo service governance capabilities**. And supports **streaming RPC calls**. - - In simple terms, it can be understood as Triple = gRPC + Dubbo - -- Serialization - - The Triple protocol uses an efficient **PB serialization method**, and adds **scalable support** of the serialization protocol on this basis. - -- User development habits: - - Triple service requires a **predefined .proto file** before development, which is convenient for Go language developers who are accustomed to defining IDL before coding. Different from the Dubbo-go 1.x version that conforms to java programming habits, JavaClassName is defined to describe the interface. - -- Cross-language interoperability: - - It can realize **cross-language intercommunication** with Dubbo-Java. - - -## 2. Application-level service discovery - -### 2.1 Introduction - -![img](/imgs/docs3-v2/golang-sdk/concept/more/3.0_feature/disc.png) - -In the service registration phase, the server instance registers the application-level registration information, mainly including the mapping from the application name to the instance IP, to the registration center. In the service discovery phase, the client instance obtains the IP of the service instance to be requested through the registration center. Entering the service introspection stage, the service introspection process is the process of obtaining interface information through application information. As shown above, there are two modes: - -1. remote mode: Obtain the mapping applied to the interface metadata through the metadata center (such as zk) -2. Local mode: Obtain the mapping from the application to the interface metadata directly through the server (initiate an RPC call for the Metadata Service through the Dubbo protocol) - -After service introspection, the client formally initiates a call to the corresponding instance. The most obvious benefit of doing this is to reduce the amount of data in the registry, that is, the registry only saves application-level data. - -When using the application-level service discovery capability of Dubbo-go 3.0, users can follow the examples and directly configure the service introspection mode and metadata center information in the configuration file, introduce dependencies, and enable application-level service discovery. - -### 2.2 Application-level service discovery introduction article - -[Analysis of application-level service discovery](https://baijiahao.baidu.com/s?id=1669266413887039723&wfr=spider&for=pc) - -## 3. Mesh Routing Rules - -User definable routing files: - -virtual_service.yaml - -![img](/imgs/docs3-v2/golang-sdk/concept/more/3.0_feature/virtual_service.png) - -and dist_rule.yml - -![img](/imgs/docs3-v2/golang-sdk/concept/more/3.0_feature/dest_rule.png) - -The framework can forward traffic for specific requests according to routing files. - -## 4. Related articles - -Alibaba Cloud official introduction article: ["Dubbo 3.0 - Opening the Next Generation of Cloud Native Microservices"](https://developer.aliyun.com/article/770964?utm_content=g_1000175535) diff --git a/content/en/docs3-v2/golang-sdk/preface/_index.md b/content/en/docs3-v2/golang-sdk/preface/_index.md deleted file mode 100644 index c9afb9872bfa..000000000000 --- a/content/en/docs3-v2/golang-sdk/preface/_index.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "Preface" -linkTitle: "Preface" -description: Introduction to Dubbo-go -weight: 1 ---- - -![img](/imgs/docs3-v2/golang-sdk/concept/dubbogo.png) - -Apache/Dubbo-go ([github.com/apache/dubbo-go](https://github.com/apache/dubbo-go)) - -It is a distributed RPC framework; it is the Go language implementation of Apache/Dubbo. It aims to provide developers with a convenient microservice application development experience. - -Dubbo-go builds a bridge between Java and Go languages, interconnects with the gRPC/Dubbo/SpringCloud ecology, and relies on the Go language ecology to explore the technical dividends of the cloud-native era. \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/preface/concept/_index.md b/content/en/docs3-v2/golang-sdk/preface/concept/_index.md deleted file mode 100644 index 357cf37ceff8..000000000000 --- a/content/en/docs3-v2/golang-sdk/preface/concept/_index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: docs -title: "Concept" -linkTitle: "Concept" -description: Dubbo-go framework concept system -weight: 2 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/preface/concept/generic.md b/content/en/docs3-v2/golang-sdk/preface/concept/generic.md deleted file mode 100644 index 8f2af4998b2f..000000000000 --- a/content/en/docs3-v2/golang-sdk/preface/concept/generic.md +++ /dev/null @@ -1,153 +0,0 @@ ---- -type: docs -title: generalization call -keywords: generalization call ---- - -Generalized call is a special call method of Dubbo-Go, which allows intermediate nodes to pass call information without interface information, and is often used in test and gateway scenarios. Generalized calls support Dubbo and Triple protocols, but the current serialization scheme only supports Hessian. - -## background - -For ease of understanding, this document uses gateway usage scenarios to introduce generalized calls. Let's consider ordinary calls first (non-generic calls). The figure below contains two key roles of consumer and provider (endpoint is used to represent a consumer or a provider in the following), and each has a definition of the org.apache.dubbo.sample.User interface. Assume that the org.apache.dubbo.sample.User interface needs to be used in the calling behavior. - -![img](/imgs/docs3-v2/golang-sdk/concept/rpc/generic/1631941941270-86ce9845-5a88-4cb5-8c8a-da8ae7eeb4d5.png) - -RPC needs to be transmitted through network media, so data cannot be transmitted in go struct form, but must be transmitted in binary form. This requires the consumer side to serialize the structure that implements the org.apache.dubbo.sample.User interface into a binary format before transmission. Similarly, for the provider side, binary data needs to be deserialized into structure information. **In short, common calls require that the interface information must have the same definition at each endpoint, so as to ensure that the results of data serialization and deserialization are consistent with expectations**. - -In the gateway scenario, it is impossible for the gateway to store all interface definitions. For example, a gateway needs to forward 100 service calls, and the number of interfaces required for each service is 10. Common calls require all 1000 (100 * 10) interface definitions to be stored in the gateway in advance, which is obviously difficult to achieve. So is there a way to forward calls correctly without storing interface definitions in advance? The answer is yes, which is why generic calls are used. - -## principle - -The essence of generalized calls is to transform complex structures into general structures. The general structures mentioned here refer to maps, strings, etc., and the gateway can smoothly parse and transfer these general structures. - -![img](/imgs/docs3-v2/golang-sdk/concept/rpc/generic/1632207075184-25939db4-f384-452e-a0b8-e1deff7971de.png) - -Currently, Dubbo-go v3 only supports Map generalization (default). Let's take the User interface as an example, and its definition is as follows. - -```go -// definition -type User struct { -ID string -name string -Age int32 -} - -func (u *User) JavaClassName() string { -return "org.apache.dubbo.sample.User" -} -``` - -Assume that calling a service requires a user as an input parameter, and its definition is as follows. - -```go -// an instance of the User -user := &User{ - ID: "1", - Name: "Zhangsan", - Age: 20, -} -``` - -Then, when using Map generalization, user will be automatically converted to Map format, as shown below. - -```go -usermap := map[interface{}]interface{} { - "iD": "1", - "name": "zhangsan", - "age": 20, - "class": "org.apache.dubbo.sample.User", -} -``` - -have to be aware of is: - -- Map generalization will automatically lowercase the first letter, that is, ID will be converted to iD. If you need to align Dubbo-Java, please consider changing ID to Id; -- A class field is automatically inserted in the Map to identify the original interface class. - -## use - -The generalization call is transparent to the provider side, that is, the provider side can correctly handle the generalization request without any explicit configuration. - -### Generalized call based on Dubbo URL - -The call based on Filter generalization is transparent to the consumer, and the typical application scenario is a gateway. This method needs to require the Dubbo URL to include a generic call identifier, as shown below. - -```plain -dubbo://127.0.0.1:20000/org.apache.dubbo.sample.UserProvider?generic=true&... -``` - -The meaning expressed by this Dubbo URL is: - -- The RPC protocol is dubbo; -- org.apache.dubbo.sample.UserProvider interface at 127.0.0.1:20000; -- Use generic calls (generic=true). - -The Filter on the Consumer side will automatically convert ordinary calls into generalized calls according to the configuration carried by the Dubbo URL, but it should be noted that in this way, the response result is returned in a generalized format and will not be automatically converted into the corresponding object. For example, in the map generalization mode, if the User class needs to be returned, then the consumer will get a map corresponding to the User class. - -### Manual generalization call - -The request initiated by the manual generalization call does not pass through the filter, so the consumer side needs to initiate the generalization call explicitly. The typical application scenario is testing. In [dubbo-go-samples](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/generic), manual calls are used for the convenience of testing. - -The generalized call does not need to create a configuration file (dubbogo.yaml), but it needs to manually configure the registration center, reference and other information in the code. The initialization method is encapsulated into the newRefConf method, as shown below. - -```go -func newRefConf(appName, iface, protocol string) config.ReferenceConfig { -registryConfig := &config.RegistryConfig{ -Protocol: "zookeeper", -Address: "127.0.0.1:2181", -} - -refConf := config.ReferenceConfig{ -InterfaceName: iface, -Cluster: "failover", -Registry: []string{"zk"}, -Protocol: protocol, -Generic: "true", -} - -rootConfig := config.NewRootConfig(config.WithRootRegistryConfig("zk", registryConfig)) -_ = rootConfig.Init() -_ = refConf.Init(rootConfig) -refConf. GenericLoad(appName) - -return refConf -} -``` - -The newRefConf method receives three parameters, which are: - -- appName: application name; -- iface: service interface name; -- protocol: RPC protocol, currently only supports dubbo and tri (triple protocol). - -In the above method, in order to keep the function simple, the registration center is set to a fixed value, that is, ZooKeeper at 127.0.0.1:2181 is used as the registration center, which can be freely customized according to the actual situation in practice. - -We can easily get a ReferenceConfig instance, temporarily named refConf. - -```go -refConf := newRefConf("example.dubbo.io", "org.apache.dubbo.sample.UserProvider", "tri") -``` - -Then we can initiate a generic call to the GetUser method of the org.apache.dubbo.sample.UserProvider service. - -```go -resp, err := refConf. -GetRPCService().(*generic.GenericService). -Invoke( -context. TODO(), -"GetUser", -[]string{"java. lang. String"}, -[]hessian. Object{"A003"}, - ) -``` - -The Invoke method of GenericService receives four parameters, which are: - -- context; -- Method name: In this example, it means calling the GetUser method; -- Parameter type: GetUser method accepts a parameter of string type. If the target method accepts multiple parameters, it can be written as `[]string{"type1", "type2", ...}`, if the current method has no parameters , you need to fill in an empty array `[]string{}`; -- Actual parameter: The writing method is the same as the parameter type. If it is a parameterless function, an empty array `[]hessian.Object{}` should still be filled in. - -Note: In the current version, there will be a crash problem when calling without parameters. - -Related reading: [[Dubbo-go service proxy model]](https://blog.csdn.net/weixin_39860915/article/details/122738548) diff --git a/content/en/docs3-v2/golang-sdk/preface/concept/multi_language.md b/content/en/docs3-v2/golang-sdk/preface/concept/multi_language.md deleted file mode 100644 index 7ccf8df7b766..000000000000 --- a/content/en/docs3-v2/golang-sdk/preface/concept/multi_language.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: Multilingual RPC -keywords: multilingual RPC ---- - - -![img](/imgs/docs3-v2/golang-sdk/concept/rpc/multi_language/dubbogo-3.0-invocation.png) - -### Cross-language call - -With the wide-scale application of microservice scenarios, multi-language scenarios are becoming more and more common, and developers are more willing to use more suitable languages to implement different modules of a complex system. For example, use C to write gateways, use Go to write K8S resource operators, and use Java to write business applications. Languages and scenarios are not bound. Enterprises can often choose the appropriate language by combining their own technology stack and the expertise of developers. - -In multilingual scenarios, the ability to call across languages is very important. - -Cross-language capability is essentially the capability provided by [[Network Protocol]](../protocol/). How to conveniently allow users to use the required network protocols, develop for appropriate cross-language scenarios, and enjoy the service governance capabilities of the Dubbo ecosystem are the concerns of the Dubbo-go service framework. - -### Cross Ecology - -The Dubbo-go service framework provides cross-ecology capabilities. Developers can use Dubbo-go and its [ecology project](../../../refer/ecology/) to build HTTP/front-end services, Dubbo/Spring applications , The connection between gRPC ecological applications. \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/preface/concept/protocol.md b/content/en/docs3-v2/golang-sdk/preface/concept/protocol.md deleted file mode 100644 index 1b0a0a53c50e..000000000000 --- a/content/en/docs3-v2/golang-sdk/preface/concept/protocol.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -type: docs -title: Network Protocol ---- - -## 1. RPC service framework and network protocol - -The network protocol is very important in the RPC scenario. In the microservice scenario, the communication between service processes depends on the network that can be connected, and the network protocol that is consistent between the client and the server. Network protocol is an abstract concept. From the perspective of Dubbo-go application development, we might as well divide the protocols we care about into three dimensions for discussion. - -### 1.1 unpacking protocol - -The built-in packaging and unpacking protocols of the Dubbo-go service framework are all based on the TCP/IP protocol stack. On this basis, various protocols are encapsulated/introduced, such as Triple (dubbo3), Dubbo, and gRPC. - -This type of protocol focuses on the encapsulation and disassembly process of TCP packets to ensure reliable point-to-point communication. - -In the dubbo-go ecosystem, supporting multiple networks is often worth this type of protocol. - - - -### 1.2 Serialization protocol - -The serialization protocol is responsible for serializing objects in memory into a binary stream in a specific format. Some mainstream serialization libraries include: the json serialization method with good readability and wide application; the protobuf serialization method with high compression efficiency and better performance; the hessian2 serialization method adapted to the Java language, etc. Dubbo-go has these three built-in serialization methods - -The serialization protocol needs to be paid attention to by developers during the business development process. The serialization protocol often requires specific object annotations: - -An example of a protobuf sequence object generated by protoc-gen-go: - -```protobuf -type HelloRequest struct { -state protoimpl.MessageState -sizeCache protoimpl.SizeCache -unknownFields protoimpl.UnknownFields - -Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` -} -``` - -A hessian2 serialized object that can communicate with java services - -```go -type HelloRequest struct { -Name string `hessian:"name"` -} - -func (u *HelloRequest) JavaClassName() string { -return "org.apache.dubbo.sample.User" -} -``` - -The relationship between the serialization protocol and the unpacking protocol - -- A packaging and unpacking protocol can be adapted to support multiple serialization protocols: for example, you can use dubbogo's triple protocol to pass hessian serialization parameters to communicate with the Dubbo-java service framework; pass pb serialization parameters to communicate with native gRPC services Interoperability; by implementing the interface to customize your desired serialization method, such as json, so as to pass parameters with strong readability. - -### 1.3 Interface protocol - -The interface protocol is a protocol developed and maintained by business developers, which is used to describe the information of the service interface. Such as interface name, method, parameter type. - -Taking Triple/gRPC as an example, developers can use plug-ins to generate a stub (.pb.go file) from the interface defined in the proto file. The stub file contains all the information of the interface and the interface protocol. - -When writing a service, the client and the server introduce the same interface at the same time, which can ensure that the client initiates a call for a specific interface and method, which can be correctly identified and responded by the server. - -An interface description file written by proto: - -```protobuf -syntax = "proto3"; -package api; - -option go_package = "./;api"; - -// The greeting service definition. -service Greeter { - // Sends a greeting - rpc SayHello (HelloRequest) returns (User) {} - // Sends a greeting via stream - rpc SayHelloStream (stream HelloRequest) returns (stream User) {} -} - -// The request message containing the user's name. -message HelloRequest { - string name = 1; -} - -// The response message containing the greetings -message User { - string name = 1; - string id = 2; - int32 age = 3; -} -``` - -The relationship between interface protocol and serialization protocol - -- Interface protocol is an abstract concept. An interface protocol can be written in multiple interface description languages, and can be converted into multiple serialized protocol objects. - -## 2. Network protocols supported by Dubbo-go - -The network protocols and serialization methods supported by Dubbo-go are as follows: - -| protocol | protocol name (for configuration) | serialization method | default serialization method | -| --------------- | ----------------- | :------------- ----------: | -------------- | -| Triple 【Recommend】 | tri | pb/hessian2/msgpack/custom | pb | -| Dubbo | dubbo | hessian2 | hessian2 | -| gRPC | grpc | pb | pb | -| jsonRPC | jsonrpc | json | json | - - - -Related reading: [[Dubbo-go Service Proxy Model]](https://developer.aliyun.com/article/878252) \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/preface/concept/registry.md b/content/en/docs3-v2/golang-sdk/preface/concept/registry.md deleted file mode 100644 index fa9ca49866ad..000000000000 --- a/content/en/docs3-v2/golang-sdk/preface/concept/registry.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -type: docs -title: Service Registration Discovery -keywords: service registration discovery -description: service registration discovery ---- - -## 1. Dubbo's registration center - -The registration center is responsible for saving the information of the server application in the RPC scenario. - -The server registers the interface information and sends its own address to the registration center, and the client reads and subscribes to the list of addresses that need to be called from the registration center. The entire structure is shown in the figure: - -![img](/imgs/architecture.png) - -For details about Dubbo service discovery, please refer to [Dubbo Official Website Concept Introduction](/zh-cn/docs/concepts/service-discovery/) - -## 2. Service discovery concept - -In the Dubbo ecosystem, service discovery has the following main concepts: - -- Application Application - - The application is a dubbo service process, corresponding to an application name. - -- interface (service) - - An interface is an RPC interface class, such as a Service defined by proto, or a Java Interface class. A dubbo process can contain multiple services/interfaces. - -- method - - Methods are defined in interfaces, and an interface can contain multiple methods. - -- parameter list - - The parameter list is defined in the method. Since Java supports overloading, a method can contain multiple parameter lists. For Go it is a one-to-one relationship. - -- registration message - - In the "interface-level service discovery" scenario, the registration information mainly includes the application name, interface list, metadata information, and the IP address of the server. It is stored in the registration center in the form of URL for the client to query before initiating a call. - - In the "application-level service discovery" scenario, the registration information only includes a small amount of application-level information such as the application name and the mapping from the application name to the interface, and the interface-level information is stored as metadata in the metadata center. - -- metadata - - Metadata refers to interface information, such as interface name, contained methods, parameters corresponding to methods, serialization methods, protocols, and other information. - -- Registry - - The registration center is used to save the information of the server. - -- Metadata center - - The metadata center is used to save the metadata information of the server, and in the "application-level service discovery" scenario, it serves as the dependency of the "service introspection" stage. - -Dubbo-go's most advanced service grid capability introduces the following concepts - -- CPU name - - The host name currently applies to the Service name registered on k8s. Other applications can access this application instance through the hostname. - -- endpoint - - Endpoints include the instance's IP address, port. - -- cluster - - The cluster ID holds the data from {hostname, cluster_subset_name, port} - - A cluster maintains a mapping of cluster IDs to all of its contained endpoints. - -- Service Mesh Metadata - - The service mesh metadata is an interface name-to-hostname-to-map, which is used by clients to query the hostname information of the desired interface. - -## 3. Dubbo-go Registration Center - -The registry types supported by Dubbo-go are as follows: - -| registry | registry name (for configuration) | -| --------- | ---------------------- | -| Zookeeper | zookeeper | -| Nacos | nacos | -| Etcd | etcd | -| Consul | consul | - -Related reading: [[Analysis of application-level service discovery]](https://developer.aliyun.com/article/764173) diff --git a/content/en/docs3-v2/golang-sdk/preface/design/_index.md b/content/en/docs3-v2/golang-sdk/preface/design/_index.md deleted file mode 100644 index 21732e5abbff..000000000000 --- a/content/en/docs3-v2/golang-sdk/preface/design/_index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: docs -title: "Architecture" -linkTitle: "Architecture" -description: Dubbo-go framework code structure -weight: 4 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/preface/design/aop_and_extension.md b/content/en/docs3-v2/golang-sdk/preface/design/aop_and_extension.md deleted file mode 100644 index d4724fa354bc..000000000000 --- a/content/en/docs3-v2/golang-sdk/preface/design/aop_and_extension.md +++ /dev/null @@ -1,107 +0,0 @@ ---- -type: docs -title: AOP and Extensibility Mechanisms -keywords: AOP and extensibility mechanisms -description: AOP and extensibility mechanisms ---- - -## 1. extension module and init method - -### 1.1 Interface and implementation - -An interface in golang is often accompanied by multiple implementation classes, dubbo-go provides a pluggable and extensible mechanism for interface implementation classes. Reduce the coupling between modules, making it easier for developers to introduce and customize components. - -### 1.2 init method in golang - -The init method is a special method in golang. After the user introduces a group of modules, the init method in these modules will be executed first when the program starts to perform loading logic. This method is an important way for dubbogo to register extension components. - -### 1.3 extension module - -In the framework source code, there is a special module: common/extension, which is responsible for caching the implementation of all extensible components. - -Take the load balancing module as an example: common/extension/loadbalance.go - -```go -package extension - -import ( -"dubbo.apache.org/dubbo-go/v3/cluster/loadbalance" -) - -var loadbalances = make(map[string]func() loadbalance. LoadBalance) - -// SetLoadbalance sets the loadbalance extension with @name -// For example: random/round_robin/consistent_hash/least_active/... -func SetLoadbalance(name string, fcn func() loadbalance. LoadBalance) { -loadbalances[name] = fcn -} - -// GetLoadbalance finds the loadbalance extension with @name -func GetLoadbalance(name string) loadbalance. LoadBalance { -if loadbalances[name] == nil { -panic("loadbalance for " + name + " is not existing, make sure you have import the package.") -} - -return loadbalances[name]() -} -``` - -This module contains Get method and Set method. Get returns the instantiated LoadBalance interface, the Set method is used to register factory functions, and map is used to cache factory functions. - -When the user imports _ "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance/random", the init function of the corresponding module will be loaded, and the Set method will be called to register the unique key and factory function and add them to the above map. - -cluster/loadbalance/random/loadbalance.go - -```go -package random - -import ( -"math/rand" -) - -import ( -"dubbo.apache.org/dubbo-go/v3/cluster/loadbalance" -"dubbo.apache.org/dubbo-go/v3/common/constant" -"dubbo.apache.org/dubbo-go/v3/common/extension" -"dubbo.apache.org/dubbo-go/v3/protocol" -) - -func init() { -extension.SetLoadbalance(constant.LoadBalanceKeyRandom, NewRandomLoadBalance) -} -``` - -So far, when all init methods are executed, the instantiated object can be obtained through the extension module Get method. - -### 1.4 imports module - -dubbogo puts all built-in modules in imports/imports.go. When users use the framework, they need to import this module to use the basic capabilities provided by the framework. - -```go -import ( -_ "dubbo.apache.org/dubbo-go/v3/imports" -) -``` - -## 2. Component loading process - -1. The user introduces _ "dubbo.apache.org/dubbo-go/v3/imports" into the code - -2. The program starts, the init function is executed in sequence, and the factory function/instantiated object is registered to the extension module. - -3. The framework starts, loads the configuration, obtains the key of the module to be loaded in the configuration, and obtains the instantiated object according to the key. - -4. Users can also manually call the Get method of the extension to obtain the instantiated object and use it directly. - -## 3. Custom components - -On the basis of the above introduction, developers can follow the example of built-in modules and write custom extension components. - - -## 4. Aspect-Oriented Programming Design (AOP) - -In the Dubbo-go service framework, many interfaces are designed based on the idea of AOP. For example Invoker, Filter, LoadBalance, Router. - -Multiple implementations of these interfaces often form a set of call chains, and a single implementation class only handles the logic it cares about. - -Related reading: [[AOP wikipedia]](https://en.wikipedia.org/wiki/Aspect-oriented_programming) \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/preface/design/app_and_interface.md b/content/en/docs3-v2/golang-sdk/preface/design/app_and_interface.md deleted file mode 100644 index 1454d2d76155..000000000000 --- a/content/en/docs3-v2/golang-sdk/preface/design/app_and_interface.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -type: docs -title: Dubbo's application and interface -keywords: basic concepts -description: Dubbo's application and interface ---- - -## Dubbogo service level - -Dubbogo has two service levels: App Level and Interface Level, which are closely related to the **framework configuration** structure. - -As shown in the figure below, you can see that the components at the application level are marked in light red, and the components at the interface level are marked in light blue: - -![img](/imgs/docs3-v2/golang-sdk/concept/more/app_and_interface/dubbogo-concept.png) - -## 1. Application level components - -Features of application-level components: shared by all interface-level components of the current application. - -The main components at the application level are as follows: - -- Application information module - - Contains information related to application dimensions, including application name, version number, data reporting method, etc. - -- Consumer module - - The Consumer module is responsible for client-related information, including one or more Reference structures, as well as timeouts, consumer filters, and other related information. - --Provider module - -The Provider module is responsible for server-related information, including one or more service (Service) structures, server-side filters (provider filters) and other related information. - -- Registry module - - The registration center module is responsible for defining a series of registration centers to be used, such as middleware such as ZK, Nacos, etcd supported by the framework. The registration module at the application level is only responsible for the declaration, which is referenced by the components at the interface level, and the user-defined registry ID (registryID) is used as an index when citing. - -- Protocol module - - Protocol modules only exist on the server side. - - The protocol module cares about the exposed information of the service, such as protocol name, service listening IP, port number and other information. The protocol module belongs to the application level and is only responsible for declaration, and is referenced by the interface-level components with the user-defined protocol ID (protocolID) as the index. - -- Metadata Center Module - - The metadata center is similar to the registration center module, which is responsible for declaring the metadata center that the framework needs to use, so that the metadata can be successfully reported. - -- Configuration center module -- Routing module -- log module -- Monitoring module - -## 2. Interface level components - -- Service module - - The service module is used for any exposed service, declares the information required for interface exposure, including interface name, protocol, serialization method, etc., and is responsible for the exposure of a single service interface. - -- Reference module - - The drinking module is used by the client of the remote service that needs to be called. It declares the information required to request the interface, including interface name, protocol, serialization method, etc., is responsible for the abstraction of specific protocols, and participates in the generation of the client. - -## 3. Description - -The exposed services are at the interface level. A user-defined Provider Struct/a user-defined Consumer Struct corresponds to a Service/Reference module. An application can have both a Consumer module and a Provider module at the same time, so multiple Service/Reference modules can exist at the same time. . diff --git a/content/en/docs3-v2/golang-sdk/preface/design/architecture.md b/content/en/docs3-v2/golang-sdk/preface/design/architecture.md deleted file mode 100644 index 23e0f0209d14..000000000000 --- a/content/en/docs3-v2/golang-sdk/preface/design/architecture.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: Architecture -keywords: architecture ---- - -![architecture](/imgs/docs3-v2/golang-sdk/concept/more/architecture/architecture.png) - -#### Node description - -* `Registry` : The registry responsible for service registration and discovery in dubbo-go -* `Consumer` : The service consumer who invokes the remote service -* `Provider` : The service provider of the exposed service - -#### Process description -* `0.register` : When the service provider starts, it will automatically register its own service to the registration center -* `1. subscribe` : The service consumer will subscribe to the registration center for the services it needs when it starts -* `2. notify`: The registration center returns the service registration information to the service consumer. When the subscribed service changes, it will push the changed data to the consumer -* `3. invoke`: The service consumer selects a suitable service address to initiate a request through the load balancing algorithm according to the service address obtained from the registration center \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/preface/samples.md b/content/en/docs3-v2/golang-sdk/preface/samples.md deleted file mode 100644 index 44addf0b8343..000000000000 --- a/content/en/docs3-v2/golang-sdk/preface/samples.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -type: docs -title: "Dubbo-go Samples" -linkTitle: "Dubbo-go Samples" -description: This article introduces how to use Dubbo-go Samples -weight: 5 ---- - - -In order to facilitate the use of Dubbogo framework users, we provide the Samples repository for user reference: - -[[Dubbo-go-samples warehouse address]](https://github.com/apache/dubbo-go-samples) - -## 1. Examples contained in the Samples repository - -* config-api: use API for configuration initialization -* configcenter: Use different configuration centers, currently supports three types: zookeeper, apollo, and nacos -* context: how to use context to pass attachment -* direct: direct connection mode -* game: game service example -* generic: generalized call -* rpc: RPC call example, including Triple, Dubbo and other protocols and cross-language/gRPC interoperability examples -* helloworld: RPC call entry example -* logger: log example -* registry: Show the docking with different registry centers, including zk, nacos, etcd -* metrics: data reporting -* filter: Examples of using provided filters and custom filters -* registry/servicediscovery: application-level service discovery example -* router: routing example -* tracing: link tracing example - -## 2. How to run - -There are currently three ways to run dubbo-go examples: - -1. Quick start through bash command: start the sample and unit test through a simple command line -2. Start quickly in the IDE, which is also the **recommended** way: In the project ".run" subdirectory, all example GoLand run configuration files are provided, so users can simply click to run all in the IDE example. -3. Manually configure and run in the IDE: For the purpose of completeness, and in case you do not use GoLand and use other IDEs, here is also a step-by-step configuration guide to help users understand how to configure in the IDE , to run or debug dubbo-go examples. - -### 2.1 Quick start via command line - -*Preconditions: docker environment is required to be ready* - -Below we will use "helloworld" as an example: - -1. **Start the registration center (such as zookeeper)** - - ```bash - make -f build/Makefile docker-up - ``` - - When you see output similar to the following, it means that the zookeeper server is ready to start. - - ```bash - > Starting dependency services with ./integrate_test/dockercompose/docker-compose.yml - Docker Compose is now in the Docker CLI, try `docker compose up` - - Creating network "dockercompose_default" with the default driver - Creating dockercompose_zookeeper_1... done - Creating etcd... done - Creating nacos-standalone... done - ``` - - If you want to stop the registry, you can do it by running the following command: - - ```bash - make -f build/Makefile docker-down - ``` - -2. **Start Service Provider** - - ```bash - cd helloworld/go-server/cmd - export DUBBO_GO_CONFIG_PATH="../conf/dubbogo.yml" - go run . - ``` - - When you see output similar to the following, the service provider is ready to start. - - ```bash - 2021/10/27 00:33:10 Connected to 127.0.0.1:2181 - 2021/10/27 00:33:10 Authenticated: id=72057926938066944, timeout=10000 - 2021/10/27 00:33:10 Re-submitting `0` credentials after reconnect - ``` - -3. **Run service caller** - - ```bash - cd helloworld/go-client/cmd - export DUBBO_GO_CONFIG_PATH="../conf/dubbogo.yml" - go run . - ``` - - When the following information is output, it means that `go-client` calls `go-server` successfully. - - ```bash - 2021-10-27T00:40:44.879+0800 DEBUG triple/dubbo3_client.go:106 TripleClient.Invoke: get reply = name:"Hello laurence" id:"12345" age:21 - 2021-10-27T00:40:44.879+0800 DEBUG proxy/proxy.go:218 [makeDubboCallProxy] result: name:"Hello laurence" id:"12345" age:21 , err: - 2021-10-27T00:40:44.879+0800 INFO cmd/client.go:51 client response result: name:"Hello laurence" id:"12345" age:21 - ``` - -4. **Integration tests** - In addition to showing how to use the functions and features in dubbo-go, this project dubbo-go-samples is also used for integration testing of apache/dubbo-go. Integration tests designed for `go-server` can be run as follows: - - Start the server first - ```bash - cd helloworld/go-server/cmd - export DUBBO_GO_CONFIG_PATH="../conf/dubbogo.yml" - go run . - ``` - - Then switch to the single test directory, set the environment variables, and then execute the single test - ```bash - cd integrate_test/helloworld/tests/integration - export DUBBO_GO_CONFIG_PATH="../../../../helloworld/go-client/conf/dubbogo.yml" - go test -v - ``` - - When the following information is output, the integration test has passed. - - ```bash - > Running integration test for application go-server - ... - --- PASS: TestSayHello (0.01s) - PASS - ok github.com/apache/dubbo-go-samples/integrate_test/helloworld/tests/integration0.119s - ``` - -7. **Close and Cleanup** - ```bash - make -f build/Makefile clean docker-down - ``` - -*The following two modes of operation are related to the IDE. Here we take Intellij GoLand as an example to discuss. * - -### 2.2 Quick start in IDE - -Once you open this project in GoLand, you can find that in the "Run Configuration" pop-up menu, there are already a series of pre-configured options for running related service providers and callers, for example: "helloworld-go-server " and "helloworld-go-client". - -You can select any of these quick start related examples. Of course, before running, it is assumed that the required registry has been started in advance, otherwise the use case will fail. You can choose to start it manually, or use the "docker-compose.yml" provided in the project to start the docker instance in the registration center. - -### 2.3. Manually run in the IDE - -Take *Intellij GoLand* as an example here. After opening the dubbo-go-samples project in GoLand, follow the steps below to run/debug this sample: - -1. **Start the zookeeper server** - - Open the "integrate_test/dockercompose/docker-compose.yml" file, and click the ▶︎▶︎ icon in the left gutter column of the editor to run, the "Service" Tab should pop up and output a text message similar to the following: - ``` - Deploying 'Compose: docker'... - /usr/local/bin/docker-compose -f ...integrate_test/dockercompose/docker-compose.yml up -d - Creating network "docker_default" with the default driver - Creating docker_zookeeper_1... - 'Compose: docker' has been deployed successfully. - ``` - -2. **Start Service Provider** - - Open the "helloworld/go-server/cmd/server.go" file, then click the ▶︎ icon next to the "main" function in the left gutter column, and select "Modify Run Configuration..." from the pop-up menu, And make sure the following configuration is accurate: - * Working Directory: Absolute path of "helloworld/go-server" directory, for example: */home/dubbo-go-samples/helloworld/go-server* - * Environment: DUBBO_GO_CONFIG_PATH="../conf/dubbogo.yml" - - In this way, the server in the example is ready and ready to run. - -3. **Run Service Consumer** - - Open the "helloworld/go-client/cmd/client.go" file, then click the ▶︎ icon next to the "main" function from the left gutter column, and then select "Modify Run Configuration... ", and make sure the following configuration is accurate: - * Working Directory: Absolute path of "helloworld/go-client" directory, for example: */home/dubbo-go-samples/helloworld/go-client* - * Environment: DUBBO_GO_CONFIG_PATH="../conf/dubbogo.yml" - - Then you can run and call the remote service. If the call is successful, there will be the following output: - ``` - [2021-02-03/16:19:30 main.main: client.go: 66] response result: &{A001 Alex Stocks 18 2020-02-04 16:19:30.422 +0800 CST} - ``` - -If you need to debug this example or the dubbo-go framework, you can switch from "Run" to "Debug" in the IDE. If you want to end, just click ◼︎ directly. \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/preface/what.md b/content/en/docs3-v2/golang-sdk/preface/what.md deleted file mode 100644 index 8ac32eff4166..000000000000 --- a/content/en/docs3-v2/golang-sdk/preface/what.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "What is Dubbo-go" -linkTitle: "What is Dubbo-go" -description: An article introducing what Dubbo-go is and what it can do -weight: 1 ---- - -![img](/imgs/docs3-v2/golang-sdk/concept/dubbogo.png) - -Apache/Dubbo-go ([github.com/apache/dubbo-go](https://github.com/apache/dubbo-go)) - -It is a distributed RPC framework; it is the Go language implementation of Apache/Dubbo. It aims to provide developers with a convenient microservice application development experience. - -Dubbo-go builds a bridge between Java and Go languages, interconnects with the gRPC/Dubbo/SpringCloud ecology, and relies on the Go language ecology to explore the technical dividends of the cloud-native era. \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/quickstart/_index.md b/content/en/docs3-v2/golang-sdk/quickstart/_index.md deleted file mode 100644 index 0c4c2dbcb1fd..000000000000 --- a/content/en/docs3-v2/golang-sdk/quickstart/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "Quick Start" -linkTitle: "Quick Start" -weight: 2 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/quickstart/install.md b/content/en/docs3-v2/golang-sdk/quickstart/install.md deleted file mode 100644 index 4af4ef0bf388..000000000000 --- a/content/en/docs3-v2/golang-sdk/quickstart/install.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -type: docs -title: Install Dubbo-go development environment -weight: 1 ---- -### 1. Install the Go language environment - -It is recommended to use the latest version of go 1.17 - -go version >= go 1.15 - -[[Go language official website download address]](https://golang.google.cn/) - -Add $GOPATH/bin to environment variable - -### 2. Install the serialization tool protoc - -[[protoc download address]](https://github.com/protocolbuffers/protobuf/releases) - -### 3. Install dubbogo-cli and related plugins - -Execute the following command to install dubbogo-cli to $GOPATH/bin - -```bash -$ export GOPROXY="https://goproxy.cn" -$ go install github.com/dubbogo/dubbogo-cli@latest -$ dubbogo-cli -hello -``` - -Install dependent tool plugins - -```bash -$ dubbogo-cli install all -``` - -Make sure the tools installed above are located in the system environment variables - -```bash -$ protoc --version -libprotoc 3.14.0 -$ protoc-gen-go --version -protoc-gen-go v1.26.0 -$ protoc-gen-go-triple --version -protoc-gen-go-triple 1.0.8 -``` \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/quickstart/quickstart_triple.md b/content/en/docs3-v2/golang-sdk/quickstart/quickstart_triple.md deleted file mode 100644 index 0f5cc6ca8d3c..000000000000 --- a/content/en/docs3-v2/golang-sdk/quickstart/quickstart_triple.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -type: docs -title: Complete an RPC call -weight: 2 ---- - - -## 1. Generate Demo project - -Use the installed dubbogo-cli tool to create a demo project. - -```bash -$ mkdir quickstart -$ cd quickstart -$ dubbogo-cli newDemo. -$ tree . -. -├── api -│ ├── samples_api.pb.go -│ ├── samples_api.proto -│ └── samples_api_triple.pb.go -├── go-client -│ ├── cmd -│ │ └── client.go -│ └── conf -│ └── dubbogo.yaml -├── go-server -│ ├── cmd -│ │ └── server.go -│ └── conf -│ └── dubbogo.yaml -└── go.mod -``` - -You can see that the generated project contains a client project and a server project, as well as related configuration files. - -### 1.1 View the interface description file helloworld.proto - -```protobuf -syntax = "proto3"; -package api; - -option go_package = "./;api"; - -// The greeting service definition. -service Greeter { - // Sends a greeting - rpc SayHello (HelloRequest) returns (User) {} - // Sends a greeting via stream - rpc SayHelloStream (stream HelloRequest) returns (stream User) {} -} - -// The request message containing the user's name. -message HelloRequest { - string name = 1; -} - -// The response message containing the greetings -message User { - string name = 1; - string id = 2; - int32 age = 3; -} -``` - -In the demo project, an interface description file is generated by default. The interface service name is api.Greeter, which contains two RPC methods, the input parameter is HelloRequest, and the return value is User. The two methods are ordinary RPC methods and Streaming type RPC methods. - -### 1.2 (*Optional) Compile the pb interface with the installed compilation tool - -```bash -$ cd api -$ protoc --go_out=. --go-triple_out=. ./samples_api.proto -``` - -Parameter meaning: `--go_out=.` Use the `protoc-gen-go` plugin installed above to generate files to the current directory, `--go-triple_out=.` Use the `protoc-gen-go-triple installed above ` Plugins, generate files to the current directory. - -After executing this command, two files will be generated, namely helloworld.pb (contains proto structure) and helloworld_triple.pb.go (contains triple protocol interface). - -In the demo project, these two files are pre-generated. After modifying the .proto file, execute the command generation again to overwrite it. - -## 2. Open an RPC call - -Execution in the project root directory - -``` -$ go mod tidy -``` - -Pull to the latest framework dependencies: - -```go -module helloworld - -go 1.17 - -require ( -dubbo.apache.org/dubbo-go/v3 v3.0.1 -github.com/dubbogo/grpc-go v1.42.9 -github.com/dubbogo/triple v1.1.8 -google.golang.org/protobuf v1.27.1 -) - -require ( -... -) - -``` - -Start the server and the client successively: Open two terminals, execute `go run .` in the go-server/cmd and go-client/cmd folders respectively, and you can see the output on the client: - -```shell -client response result: name: "Hello laurence" id: "12345" age:21 -``` - -Get the result of the call successfully - -## 3. more - -Careful readers can find that the server written in the above example can accept ordinary RPC and streaming RPC call requests from the client. At present, only the Client for common calls has been written. Readers can try to write streaming clients and servers based on the examples in the samples library. diff --git a/content/en/docs3-v2/golang-sdk/quickstart/quickstart_triple_with_customize.md b/content/en/docs3-v2/golang-sdk/quickstart/quickstart_triple_with_customize.md deleted file mode 100644 index e345777ed134..000000000000 --- a/content/en/docs3-v2/golang-sdk/quickstart/quickstart_triple_with_customize.md +++ /dev/null @@ -1,207 +0,0 @@ ---- -type: docs -title: Complete an RPC call (the version that defines the interface yourself) -weight: 3 ---- - -## 1 Overview -In this chapter, we will implement a simple small requirement and implement a distributed ID generation service through which distributed IDs can be obtained -(Assuming a distributed ID, we will not discuss the ID generation scheme and algorithm, here we directly use uuid instead, just to demonstrate the creation of custom services) - -## 2. Server implementation -First use dubbogo-cli to create IDC service -```bash -dubbogo-cli newApp IDC -cd IDC -tree. - -. -├── Makefile -├── api -│ ├── api.pb.go -│ ├── api.proto -│ └── api_triple.pb.go -├──build -│ └── Dockerfile -├── chart -│ ├── app -│ │ ├── Chart.yaml -│ │ ├── templates -│ │ │ ├── _helpers.tpl -│ │ │ ├── deployment.yaml -│ │ │ ├── service.yaml -│ │ │ └── serviceaccount.yaml -│ │ └── values.yaml -│ └── nacos_env -│ ├── Chart.yaml -│ ├── templates -│ │ ├── _helpers.tpl -│ │ ├── deployment.yaml -│ │ └── service.yaml -│ └── values.yaml -├── cmd -│ └── app.go -├── conf -│ └── dubbogo.yaml -├── go.mod -├── go.sum -└── pkg - └── service - └── service.go - -``` - -We edit proto to define our interface - -```protobuf -syntax = "proto3"; -package api; - -option go_package = "./;api"; - -service Generator { - rpc GetID (GenReq) returns (GenResp) {} -} - -message GenReq { - string appId = 1; -} - -message GenResp { - string id = 1; -} -``` - -generate code - -```bash -$ cd api -$ protoc --go_out=. --go-triple_out=. ./api.proto -``` - -Let's tune the service -Directory: pkg/service/service.go -The modified code is as follows - -```go -type GeneratorServerImpl struct { -api. UnimplementedGeneratorServer -} - -func (s *GeneratorServerImpl) GetID(ctx context.Context, in *api.GenReq) (*api.GenResp, error) { -logger.Infof("Dubbo-go GeneratorProvider AppId = %s\n", in.AppId) -uuid, err := uuid. NewV4() -if err != nil { -logger.Infof("Dubbo-go GeneratorProvider get id err = %v\n", err) -return nil, err -} -return &api.GenResp{Id: uuid.String()}, nil -} - -func init() { -config. SetProviderService(&GeneratorServerImpl{}) -} -``` -At the same time, we adjust the provider part in conf/dubbogo.yaml, -```yaml -dubbo: - registries: - nacos: - protocol: nacos - address: 127.0.0.1:8848 - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GeneratorServerImpl: - interface: "" # read from stub -``` -We need to pull up a dependent registry, nacos, if you have a ready-made one, this step can be ignored, we use docker to quickly start a nacos, - -```bash -git clone https://github.com/nacos-group/nacos-docker.git -cd nacos-docker -docker-compose -f example/standalone-derby.yaml up -``` - -Finally, we start the server. -```go -export DUBBO_GO_CONFIG_PATH=conf/dubbogo.yaml -go run cmd/app.go -``` -Open the nacos console, you can see that the service has been registered -![img](/imgs/docs3-v2/golang-sdk/quickstart/nacos.jpg) - - -## 2. Client use -First, we can share the API of our server to the client and generate related codes (here we can share proto according to actual project needs, each consumer generates code by itself, or introduce it to dependent services after unified generation of sdk) -The client directory is as follows: -```bash -. -├── api -│ ├── api.pb.go -│ ├── api.proto -│ └── api_triple.pb.go -├── cmd -│ └── client.go -├── conf -│ └── dubbogo.yml -├── go.mod -├── go.sum - -``` -The api directory is the same as the server's api directory -The client.go code is as follows -```go - -var grpcGeneratorImpl = new(api. GeneratorClientImpl) - -func main() { -config. SetConsumerService(grpcGeneratorImpl) -if err := config.Load(); err != nil { -panic(err) -} - -logger.Info("start to test dubbo") -req := &api. GenReq{ -AppId: "laurence", -} -reply, err := grpcGeneratorImpl. GetID(context. Background(), req) -if err != nil { -logger. Error(err) -} -logger.Infof("get id result: %v\n", reply.Id) -} - -``` - -dubbogo.yml is as follows -```yaml -dubbo: - registries: - nacos: - protocol: nacos - address: 127.0.0.1:8848 - consumer: - references: - GeneratorClientImpl: - protocol: tri - interface: "" -``` - -Run the client to get the id, as follows: - -```bash -export DUBBO_GO_CONFIG_PATH=conf/dubbogo.yml -go run cmd/client.go -... -... -2022-12-30T20:59:19.971+0800 INFO cmd/client.go:44 start to test dubbo -2022-12-30T20:59:19.982+0800 INFO cmd/client.go:52 get id result: aafd9c73-4014-4d67-a67f-5d107105647b - -``` -## 3. more - -It can be found that we use nacos for the registration center. Of course, we can also use other registration centers. For more usage methods, you can refer to [Registry](/en/docs3-v2/golang-sdk/tutorial/develop/registry/) \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/refer/_index.md b/content/en/docs3-v2/golang-sdk/refer/_index.md deleted file mode 100644 index c9dc67b4ad4d..000000000000 --- a/content/en/docs3-v2/golang-sdk/refer/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Reference" -weight: 5 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/refer/basic_concept.md b/content/en/docs3-v2/golang-sdk/refer/basic_concept.md deleted file mode 100644 index d5c931ae43d8..000000000000 --- a/content/en/docs3-v2/golang-sdk/refer/basic_concept.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -type: docs -title: Basic concepts of configuration -keywords: configure basic concepts ---- - -## 1. Framework configuration - -The Dubbo-go framework needs to rely on configuration to start. Configuration contains the various capabilities that a developer wishes to use with the framework. - -### Configuration format - -yaml - -### Configuration path - -Load framework configuration from `../conf/dubbogo.yaml` by default - -You can modify the configuration file path by specifying the environment variable: DUBBO_GO_CONFIG_PATH=$(your_config_path)/dubbogo.yaml. - -### Configure the root structure - -Located at [dubbo.apache.org/dubbo-go/v3/config/root_config.go: RootConfig](https://github.com/apache/dubbo-go/blob/e00cf8d6fb2be3cd9c6e42cc3d6efa54e10229d3/config/root_config.go#L50) - -When the framework is loaded, any form of configuration will be parsed into RootConfig and loaded in the RootConfig.Init method. - -## 2. Configuration API - -Developers can start the framework by building configurations in the form of an API. This method is more suitable for the situation where dubbo-go is introduced as a third-party component. - - -## 3. Configuration Center - -Developers can place configurations in the configuration center to facilitate configuration management and modification. diff --git a/content/en/docs3-v2/golang-sdk/refer/compatible_version.md b/content/en/docs3-v2/golang-sdk/refer/compatible_version.md deleted file mode 100644 index 39e1e10ca488..000000000000 --- a/content/en/docs3-v2/golang-sdk/refer/compatible_version.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: Depends on the adaptation version number -type: docs -weight: 4 ---- - -When Dubbo-go releases a new version, update the version it currently depends on. - -| Dependency | Dubbo-go | Triple | protoc-gen-go-triple | -| :--: | ------------ | ------ | -------------------- | -| | v3.0.1 | v1.1.8 | v1.0.8 | -| | v3.0.0 | v1.1.6 | v1.0.5 | -| | v3.0.0-rc4-1 | v1.1.3 | v1.0.2 | -| | v3.0.0-rc3 | v1.0.9 | v1.0.0 | \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/refer/config.md b/content/en/docs3-v2/golang-sdk/refer/config.md deleted file mode 100644 index 10d160482ff6..000000000000 --- a/content/en/docs3-v2/golang-sdk/refer/config.md +++ /dev/null @@ -1,121 +0,0 @@ ---- -title: configuration item reference -type: docs -weight: 1 ---- - -## root configuration - -## Client configuration - -## Server configuration - -## Registry configuration - -### Using the Configuration API - -- The client sets up the registry using the configuration API - -You can quickly set the registry for debugging by calling the config.NewRegistryConfigWithProtocolDefaultPort method, and support zookeeper(127.0.0.1:2181) and nacos(127.0.0.1:8848) - -```go -rc := config. NewRootConfigBuilder(). - SetConsumer(config. NewConsumerConfigBuilder(). - SetRegistryIDs("zookeeperID"). // use defined registryID - Build()). - AddRegistry("zookeeperID", config. NewRegistryConfigWithProtocolDefaultPort("zookeeper")). - build() -``` - -All interfaces: can be configured by calling the rich interfaces provided by RegistryConfigBuilder. - -```go -rc := config. NewRootConfigBuilder(). - SetConsumer(config. NewConsumerConfigBuilder(). - SetRegistryIDs("nacosRegistryID"). // use defined registryID - AddReference("GreeterClientImpl", /*...*/). - build() - AddRegistry("nacosRegistryID", config. NewRegistryConfigBuilder(). - SetProtocol("nacos"). - SetAddress("127.0.0.1:8848"). - SetGroup("dubbo-go"). - SetNamespace("dubbo"). - SetUsername("admin"). - SetPassword("admin"). - SetTimeout("3s"). - Build()). - build() -``` - -- The server uses the configuration API to set the configuration center - -Simple interface config.NewRegistryConfigWithProtocolDefaultPort - -```go -rc := config. NewRootConfigBuilder(). - SetProvider(config. NewProviderConfigBuilder(). - AddService("GreeterProvider", /*...*/). - SetRegistryIDs("registryKey"). // use defined registryIDs - Build()). - AddRegistry("registryKey", config. NewRegistryConfigWithProtocolDefaultPort("zookeeper")). - build() -``` - -All interfaces: can be configured by calling the rich interfaces provided by RegistryConfigBuilder. - -```go -rc := config. NewRootConfigBuilder(). - SetProvider(config. NewProviderConfigBuilder(). - AddService("GreeterProvider", /*...*/) - SetRegistryIDs("registryKey"). // use defined registryIDs - Build()). - AddRegistry("registryKey", config. NewRegistryConfigBuilder(). - SetProtocol("nacos"). - SetAddress("127.0.0.1:8848"). - SetGroup("dubbo-go"). - SetNamespace("dubbo"). - SetUsername("admin"). - SetPassword("admin"). - SetTimeout("3s"). - Build()). - build() -``` - -### - -## Network protocol - -### configuration file - -### Using the Configuration API - -- The client sets the network protocol using the configuration API - -```go -rc := config. NewRootConfigBuilder(). - SetConsumer(config. NewConsumerConfigBuilder(). - AddReference("GreeterClientImpl", config. NewReferenceConfigBuilder(). - SetInterface("org. apache. dubbo. UserProvider"). - SetProtocol("tri"). // set reference protocol to triple - Build()). - Build()). - build() -``` - -- The server uses the configuration API to set the network protocol - -```go -rc := config. NewRootConfigBuilder(). - SetProvider(config. NewProviderConfigBuilder(). - AddService("GreeterProvider", config. NewServiceConfigBuilder(). - SetInterface("org. apache. dubbo. UserProvider"). - SetProtocolIDs("tripleProtocolKey"). // use protocolID 'tripleProtocolKey' - Build()). - Build()). - AddProtocol("tripleProtocolKey", config. NewProtocolConfigBuilder(). // define protocol config with protocolID 'tripleProtocolKey' - SetName("tri"). // set service protocol to triple - Build()). - build() -``` - -### \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/refer/ecology.md b/content/en/docs3-v2/golang-sdk/refer/ecology.md deleted file mode 100644 index cc51ae73dc9f..000000000000 --- a/content/en/docs3-v2/golang-sdk/refer/ecology.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Dubbogo Ecological Components -type: docs -weight: 3 ---- - -### Dubbo-go / Dubbo-go 3.0 - -[github.com/apache/dubbo-go](https://github.com/apache/dubbo-go) - -Apache Dubbo is implemented in Go language, which bridges between Java and Golang. - -### Dubbo-go-pixiu - -[github.com/apache/dubbo-go-pixiu](https://github.com/apache/dubbo-go-pixiu) - -dubbo-go-pixiu gateway supports calling dubbo/dubbo-go clusters with dubbo protocol and http protocol - -### Dubbo-getty - -[github.com/apache/dubbo-getty](https://github.com/apache/dubbo-getty) - -dubbo-getty is an asynchronous network io library in Go language that supports tcp/udp/websocket protocols. - -### Dubbo-go-hessian2 - -[github.com/apache/dubbo-go-hessian2](https://github.com/apache/dubbo-go-hessian2) - -Dubbo-go-hessian2 is a Go language hessian2 serialization protocol library - -### Dubbogo-tools - -[github.com/dubbogo/tools](https://github.com/dubbogo/tools) - -Dubbogo-tools includes - -- dubbo-cli tool -- imports-formatter Go language imports block formatter -- protoc-gen-triple PB compilation plugin -- protoc-gen-dubbo3grpc PB compilation plugin - -### Triple-go - -[github.com/dubbogo/triple](https://github.com/dubbogo/triple) - -Triple-go is a Triple (Dubbo3) network protocol library implemented in Go language, based on HTTP2 protocol. \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/refer/use_dubbogo_cli.md b/content/en/docs3-v2/golang-sdk/refer/use_dubbogo_cli.md deleted file mode 100644 index 49956c76b7c8..000000000000 --- a/content/en/docs3-v2/golang-sdk/refer/use_dubbogo_cli.md +++ /dev/null @@ -1,429 +0,0 @@ ---- -title: Use dubbogo-cli tool -type: docs -weight: 2 ---- - -## 1. Installation - -dubbogo-cli is a sub-project of the Apache/dubbo-go ecosystem, which provides developers with convenient functions such as application template creation, tool installation, and interface debugging to improve user R&D efficiency. - -Execute the following command to install dubbogo-cli to $GOPATH/bin - -``` -go install github.com/dubbogo/dubbogo-cli@latest -``` - -## 2. Function overview - -dubbogo-cli supports the following capabilities - -- Application template creation - - ``` - dubbogo-cli newApp. - ``` - - Create an application template in the current directory - -- Demo creation - - ``` - dubbogo-cli newDemo. - ``` - - Create an RPC example in the current directory, including a client and a server - -- Compile and debug tool installation - - ``` - dubbogo-cli install all - ``` - - One-click installation of the following tools to $GOPATH/bin - - -protoc-gen-go-triple - - Compilation for triple protocol interface - - - imports-formatter - - Used to tidy up code import blocks. - - [import-formatte README](https://github.com/dubbogo/tools#imports-formatter) - - - -- View dubbo-go application registration information - - - View the registration information on Zookeeper to get a list of interfaces and methods - - ```bash - $ dubbogo-cli show --r zookeeper --h 127.0.0.1:2181 - interface: com.dubbogo.pixiu.UserService - methods: [CreateUser, GetUserByCode, GetUserByName, GetUserByNameAndAge, GetUserTimeout, UpdateUser, UpdateUserByName] - ``` - - - View the registration information on Nacos [function under development] - - - View the registration information of Istio [function under development] - -- Debug Dubbo protocol interface - -- Debug Triple protocol interface - -## 3. Function details - -### 3.1 Demo application introduction - -#### 3.1.1 Demo Creation - -``` -dubbogo-cli newDemo. -``` - -Create a demo in the current directory, including the client and server. The demo shows the completion of an RPC call based on a set of interfaces. - -The Demo uses the direct connection mode without relying on the registration center. The server side exposes the service to the local port 20000, and the client initiates the call. - -```shell -. -├── api -│ ├── samples_api.pb.go -│ ├── samples_api.proto -│ └── samples_api_triple.pb.go -├── go-client -│ ├── cmd -│ │ └── client.go -│ └── conf -│ └── dubbogo.yaml -├── go-server -│ ├── cmd -│ │ └── server.go -│ └── conf -│ └── dubbogo.yaml -└── go.mod -``` - -#### 3.1.2 Running Demo - -Start the server - -``` -$ cd go-server/cmd -$ go run . -``` - -Another terminal opens the client - -``` -$ go mod tidy -$ cd go-client/cmd -$ go run . - -``` - -You can see the print log - -``` -INFO cmd/client.go:49 client response result: name:"Hello laurence" id:"12345" age:21 -``` - -### 3.2 Application template introduction - -#### 3.2.1 Application template creation - -``` -dubbogo-cli newApp. -``` - -Create an application template in the current directory: - -``` -. -├── Makefile -├── api -│ ├── api.pb.go -│ ├── api.proto -│ └── api_triple.pb.go -├──build -│ └── Dockerfile -├── chart -│ ├── app -│ │ ├── Chart.yaml -│ │ ├── templates -│ │ │ ├── _helpers.tpl -│ │ │ ├── deployment.yaml -│ │ │ ├── service.yaml -│ │ │ └── serviceaccount.yaml -│ │ └── values.yaml -│ └── nacos_env -│ ├── Chart.yaml -│ ├── templates -│ │ ├── _helpers.tpl -│ │ ├── deployment.yaml -│ │ └── service.yaml -│ └── values.yaml -├── cmd -│ └── app.go -├── conf -│ └── dubbogo.yaml -├── go.mod -├── go.sum -└── pkg - └── service - └── service.go - -``` - -#### 3.2.2 Application template introduction - -The generated project includes several directories: - -- api: place interface files: proto file and generated .pb.go file -- build: place mirror build related files -- Chart: place the chart warehouse for publishing, the basic environment chart warehouse: nacos, mesh (under development) -- cmd: program entry -- conf: framework configuration -- pkg/service: RPC service implementation -- Makefile: - -- - Image, helm deployment name: - -- - - IMAGE = $(your_repo)/$(namespace)/$(image_name) - TAG = 1.0.0 -- HELM_INSTALL_NAME = dubbo-go-app, helm installation name, used for helm install/uninstall command. - -- - Provide scripts such as: - -- - - make build # Package the image and push it -- make buildx-publish # The arm architecture locally packs the amd64 image and pushes it, relying on docker buildx -- make deploy # Publish the application through helm -- make remove # Delete the published helm application -- make proto-gen # generate pb.go file under api - -- - -Development process using application templates - -> Dependent environment: make, go, helm, kubectl, docker - -1. Generate a template through dubbogo-cli -2. Modify api/api.proto -3. make proto-gen -4. Development interface -5. Modify the image name of IMAGE and release name of HELM_INSTALL_NAME in the makefile -6. Make a mirror image and push -7. Modify the value configuration related to deployment in chart/app/values, focusing on the image part. - -``` -image: - repository: $(your_repo)/$(namespace)/$(image_name) - pullPolicy: Always - tag: "1.0.0" -``` - -8. make deploy, use helm to publish the application. - -### 3.3 Debug dubbo-go application with gRPC protocol - -#### 3.3.1 Introduction - -The grpc_cli tool is a tool used by the gRPC ecosystem to debug services. It can be obtained under the premise that [reflection service] (https://github.com/grpc/grpc/blob/master/doc/server-reflection.md) is enabled on the server Go to the service's proto file, service name, method name, parameter list, and initiate a gRPC call. - -The Triple protocol is compatible with the gRPC ecosystem, and the gRPC reflection service is enabled by default, so you can directly use grpc_cli to debug the triple service. - -#### 3.3.2 Install grpc_cli - -> Subsequent installation will be done by dubbogo-cli, currently users need to install manually - -Refer to [grpc_cli documentation](https://github.com/grpc/grpc/blob/master/doc/command_line_tool.md) - -#### 3.3.3 Use grpc_cli to debug Triple service - -1. View the interface definition of the triple service - -```shell -$ grpc_cli ls localhost:20001 -l -filename: helloworld.proto -package: org.apache.dubbo.quickstart.samples; -service UserProvider { - rpc SayHello(org.apache.dubbo.quickstart.samples.HelloRequest) returns (org.apache.dubbo.quickstart.samples.User) {} - rpc SayHelloStream(stream org.apache.dubbo.quickstart.samples.HelloRequest) returns (stream org.apache.dubbo.quickstart.samples.User) {} -} -``` - -2. Check the request parameter type - -For example, if a developer wants to test the SayHello method of the above port, and tries to obtain the specific definition of HelloRequest, he needs to execute the following command to view the definition of the corresponding parameters. - -```shell -$ grpc_cli type localhost:20001 org.apache.dubbo.quickstart.samples.HelloRequest -message HelloRequest { - string name = 1 [json_name = "name"]; -} -``` - -3. Request interface - -Knowing the specific type of the request parameter, you can initiate a call to test the corresponding service. Check to see if the return value is as expected. - -```shell -$ grpc_cli call localhost:20001 SayHello "name: 'laurence'" -connecting to localhost:20001 -name: "Hello Laurence" -id: "12345" -age: 21 -Received trailing metadata from server: -accept-encoding: identity, gzip -adaptive-service.inflight : 0 -adaptive-service. remaining : 50 -grpc-accept-encoding : identity,deflate,gzip -Rpc succeeded with OK status -``` - -### 3.4 Debug dubbo-go application with Dubbo protocol - -#### 3.4.1 Open Dubbo server - -Example: user.go: - -``` -func (u *UserProvider) GetUser(ctx context.Context, userStruct *CallUserStruct) (*User, error) { -fmt.Printf("=========================\nreq:%#v\n", userStruct) -rsp := User{"A002", "Alex Stocks", 18, userStruct.SubInfo} -fmt.Printf("========================\nrsp:%#v\n", rsp) -return &rsp, nil -} -``` - -The server opens a service named GetUser, passes in a CallUserStruct parameter, and returns a User parameter -CallUserStruct parameter definition: - -``` -type CallUserStruct struct { -ID string -Male bool -SubInfo SubInfo // nested substructure -} -func (cs CallUserStruct) JavaClassName() string { -return "com.ikurento.user.CallUserStruct" -} - -type SubInfo struct { -SubID string -SubMale bool -SubAge int -} - -func (s SubInfo) JavaClassName() string { -return "com.ikurento.user.SubInfo" -} -``` - -User structure definition: - -``` -type User struct { -Id string -name string -Age int32 -SubInfo SubInfo // Nest the above substructure SubInfo -} - -func (u *User) JavaClassName() string { -return "com.ikurento.user.User" -} -``` - -Start the service: - -``` -cd server` -`source builddev.sh` -`go run. -``` - -#### 3.4.2 Define request body (adapted to serialization protocol) - -The request body is defined as a json file, and the agreed key value is string -The key corresponds to the field name of the Go language struct, such as "ID" and "Name", and the value corresponds to "type@val" -Among them, type supports string int bool time, and val is initialized with string. If only type is filled in, it will be initialized to a zero value. It is agreed that each struct must have a JavaClassName field, which must strictly correspond to the server side - -See userCall.json: - -``` -{ - "ID": "string@A000", - "Male": "bool@true", - "SubInfo": { - "SubID": "string@A001", - "SubMale": "bool@false", - "SubAge": "int@18", - "JavaClassName": "string@com.ikurento.user.SubInfo" - }, - "JavaClassName": "string@com.ikurento.user.CallUserStruct" -} -``` - -userCall.json defines the structure of the parameter CallUserStruct and the substructure SubInfo, and assigns values to the request parameters. - -Similarly, user.json does not need to assign an initial value as the return value, but the JavaClassName field must strictly correspond to the server side - -``` -{ - "ID": "string", - "Name": "string", - "Age": "int", - "JavaClassName": "string@com.ikurento.user.User", - "SubInfo": { - "SubID": "string", - "SubMale": "bool", - "SubAge": "int", - "JavaClassName": "string@com.ikurento.user.SubInfo" - } -} -``` - -#### 3.4.3 Debug port - -``` -./dubbo-go-cli -h=localhost -p=20001 -proto=dubbo -i=com.ikurento.user.UserProvider -method=GetUser -sendObj="./userCall.json" -recvObj="./user .json" -``` - -Print result: - -``` -2020/10/26 20:47:45 Created pkg: -2020/10/26 20:47:45 &{ID:A000 Male:true SubInfo:0xc00006ea20 JavaClassName:com.ikurento.user.CallUserStruct} -2020/10/26 20:47:45 SubInfo: -2020/10/26 20:47:45 &{SubID:A001 SubMale:false SubAge:18 JavaClassName:com.ikurento.user.SubInfo} - - -2020/10/26 20:47:45 Created pkg: -2020/10/26 20:47:45 &{ID: Name: Age:0 JavaClassName:com.ikurento.user.User SubInfo:0xc00006ec90} -2020/10/26 20:47:45 SubInfo: -2020/10/26 20:47:45 &{SubID: SubMale:false SubAge:0 JavaClassName:com.ikurento.user.SubInfo} - - -2020/10/26 20:47:45 connected to localhost:20001! -2020/10/26 20:47:45 try calling interface: com.ikurento.user.UserProvider.GetUser -2020/10/26 20:47:45 with protocol: dubbo - -2020/10/26 20:47:45 After 3ms , Got Rsp: -2020/10/26 20:47:45 &{ID:A002 Name:Alex Stocks Age:18 JavaClassName: SubInfo:0xc0001241b0} -2020/10/26 20:47:45 SubInfo: -2020/10/26 20:47:45 &{SubID:A001 SubMale:false SubAge:18 JavaClassName:}``` -``` - -You can see the detailed request body assignment, as well as the returned result and time-consuming. Supports nested structures - -Print the result on the server side - -``` -========================= -req:&main.CallUserStruct{ID:"A000", Male:true, SubInfo:main.SubInfo{SubID:"A001", SubMale:false, SubAge:18}} -========================= -``` - -It can be seen that the data from the cli has been received \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/sourcecode/_index.md b/content/en/docs3-v2/golang-sdk/sourcecode/_index.md deleted file mode 100644 index 10a3e0b11862..000000000000 --- a/content/en/docs3-v2/golang-sdk/sourcecode/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Source Code Interpretation" -type: docs -weight: 4 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/sourcecode/protocol.md b/content/en/docs3-v2/golang-sdk/sourcecode/protocol.md deleted file mode 100644 index cea5079ae7d5..000000000000 --- a/content/en/docs3-v2/golang-sdk/sourcecode/protocol.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: Network Protocol -type: docs -weight: 1 ---- - -For the Dubbogo microservice framework, the network protocol is the module responsible for network communication in the remote procedure call, responsible for data serialization, packaging, request initiation, network port monitoring and other functions from the application layer to the network layer. Dubbogo abstracts a set of interfaces for the protocol as follows: - -```go -type Protocol interface { -// Export service for remote invocation -Export (invoker Invoker) Exporter -// Refer a remote service -Refer(url *common.URL) Invoker -// Destroy will destroy all invoker and exporter, so it only is called once. -Destroy() -} -``` - -This interface contains three methods. Among them, the Export method is responsible for the exposure process of the service. The input parameter invoker is the concept of dubbo, which encapsulates an instance that can be invoked. In the Export method implemented by a specific network protocol (such as Triple), for a specific protocol, the callable instance Invoker encapsulated with certain logic will be exposed to external services in the form of network port monitoring, and external requests for this network port will be It will be obtained by the monitoring coroutine opened by the Export method, and then the package will be disassembled and deserialized according to the network protocol to obtain the parsed request data. - -The Refer method is responsible for the referral process of the service. The input parameter url is a common structure of the dubbo framework, which can describe a service that you want to refer to. The url parameter contains multiple parameters that you want to refer to the service, such as the interface name of the corresponding service. Version number (version), usage agreement (protocol) and so on. In the Refer method implemented by a specific network protocol (such as Triple), the specific network protocol will be encapsulated into the method of the Invoker callable instance, and the RPC call initiated by the user layer can directly initiate the network of the specific protocol through the returned Invoker object. ask. - -The Destroy method is used to destroy the currently exposed service and is used in service offline scenarios. The Dubbogo framework has an elegant offline mechanism, which can log off all started services in the form of listening signals before the service process terminates. \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/sourcecode/registry.md b/content/en/docs3-v2/golang-sdk/sourcecode/registry.md deleted file mode 100644 index bcfe9578908f..000000000000 --- a/content/en/docs3-v2/golang-sdk/sourcecode/registry.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: 注册中心 -type: docs -weight: 1 ---- - -Dubbogo 为注册中心抽象了一套接口如下: - -```go -// Registry Extension - Registry -type Registry interface { - common.Node - - // Register is used for service provider calling, register services - // to registry. And it is also used for service consumer calling, register - // services cared about, for dubbo's admin monitoring. - Register(url *common.URL) error - - // UnRegister is required to support the contract: - // 1. If it is the persistent stored data of dynamic=false, the - // registration data can not be found, then the IllegalStateException - // is thrown, otherwise it is ignored. - // 2. Unregister according to the full url match. - // url Registration information, is not allowed to be empty, e.g: - // dubbo://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin - UnRegister(url *common.URL) error - - // Subscribe is required to support the contract: - // When creating new registry extension, pls select one of the - // following modes. - // Will remove in dubbogo version v1.1.0 - // mode1: return Listener with Next function which can return - // subscribe service event from registry - // Deprecated! - // subscribe(event.URL) (Listener, error) - // Will replace mode1 in dubbogo version v1.1.0 - // mode2: callback mode, subscribe with notify(notify listener). - Subscribe(*common.URL, NotifyListener) error - - // UnSubscribe is required to support the contract: - // 1. If don't subscribe, ignore it directly. - // 2. Unsubscribe by full URL match. - // url Subscription condition, not allowed to be empty, e.g. - // consumer://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin - // listener A listener of the change event, not allowed to be empty - UnSubscribe(*common.URL, NotifyListener) error -} -``` - -该接口主要包含四个方法,分别是注册、反注册、订阅、取消订阅。顾名思义,概括了客户端和服务端与注册中心交互的动作。针对普通接口级服务注册发现场景,在Provider 服务启动时,会将自身服务接口信息抽象为一个 url,该 url 包含了客户端发起调用所需的所有信息(ip、端口、协议等),服务端的注册中心组件会将该 url 写入注册中心(例如zk)。客户端启动后,在服务引用 Refer 步骤会通过注册中心组件订阅(Subscribe)需要的服务信息,获取到的服务信息以异步事件更新的形式写入客户端缓存,从而在服务发现成功后,可以根据拿到的服务 url 参数,向对应服务提供者发起调用。 - -## \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/_index.md deleted file mode 100755 index f9aec9187c5e..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Task" -weight: 3 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/debugging/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/debugging/_index.md deleted file mode 100755 index 0dcaa02da252..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/debugging/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Service Debugging" -weight: 2 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/debugging/grpc_cli.md b/content/en/docs3-v2/golang-sdk/tutorial/debugging/grpc_cli.md deleted file mode 100644 index 26e472af711c..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/debugging/grpc_cli.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -title: Use grpc_cli to debug Dubbo-go service -type: docs -weight: 1 ---- - -The grpc_cli tool is a tool used by the gRPC ecosystem to debug services. It can be obtained under the premise that [reflection service] (https://github.com/grpc/grpc/blob/master/doc/server-reflection.md) is enabled on the server Go to the service's proto file, service name, method name, parameter list, and initiate a gRPC call. - -The Triple protocol is compatible with the gRPC ecosystem, and the gRPC reflection service is enabled by default, so you can directly use grpc_cli to debug the triple service. - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Create a new demo application -- Install grpc_cli, refer to [grpc_cli documentation](https://github.com/grpc/grpc/blob/master/doc/command_line_tool.md) - -## 2. Use grpc_cli tool to debug Triple service - -### 2.1 Start demo application server - -```bash -$ mkdir grpc_cli_test -$ cd grpc_cli_test -$ dubbogo-cli newDemo. -$ go mod tidy -$ cd go-server/cmd -$ go run . -``` - -### 2.2 Use grpc_cli for service debugging - -1. View the interface definition of the triple service - -```shell -$ grpc_cli ls localhost:20000 -l -filename: samples_api.proto -package: api; -service Greeter { - rpc SayHello(api.HelloRequest) returns (api.User) {} - rpc SayHelloStream(stream api.HelloRequest) returns (stream api.User) {} -} -``` - -2. Check the request parameter type - - For example, if a developer wants to test the SayHello method of the above port and try to obtain the specific definition of HelloRequest, he needs to execute the following command to view the definition of the corresponding parameters. - -```shell -$ grpc_cli type localhost:20000 api.HelloRequest -message HelloRequest { - string name = 1 [json_name = "name"]; -} -``` - -3. Request interface - - Knowing the specific type of the request parameter, you can initiate a call to test the corresponding service. Check to see if the return value is as expected. - -```shell -$ grpc_cli call localhost:20000 SayHello "name: 'laurence'" -connecting to localhost:20000 -name: "Hello Laurence" -id: "12345" -age: 21 -Received trailing metadata from server: -accept-encoding: identity, gzip -grpc-accept-encoding : identity,deflate,gzip -Rpc succeeded with OK status -``` - -It can be seen that the correct return value has been obtained. On the server side, you can observe the logs that are correctly requested: - -```shell -Dubbo3 GreeterProvider get user name = laurence -``` \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/deployment/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/deployment/_index.md deleted file mode 100755 index 49650a037a31..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/deployment/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Deployment Service" -weight: 3 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/deployment/docker/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/deployment/docker/_index.md deleted file mode 100644 index 474d6810a3b2..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/deployment/docker/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Docker image packaging tutorial" -weight: 2 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/deployment/kubernetes/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/deployment/kubernetes/_index.md deleted file mode 100644 index 016fb7f4beac..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/deployment/kubernetes/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Kubernetes Deployment Tutorial" -weight: 3 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/deployment/practice/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/deployment/practice/_index.md deleted file mode 100644 index af605e2e9cde..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/deployment/practice/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Introduction to Best Practices for Production Deployment" -weight: 1 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/_index.md deleted file mode 100755 index bb8e8dfe3740..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Develop Services" -weight: 1 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/_index.md deleted file mode 100644 index b5a1814c2672..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Configuration Center" -weight: 5 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/config-center-dynamic.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/config-center-dynamic.md deleted file mode 100644 index de32911dc533..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/config-center-dynamic.md +++ /dev/null @@ -1,148 +0,0 @@ ---- -title: Dubbogo 3.0 configuration center and configuration monitoring -weight: 2 -type: docs ---- - -## 1. Configuration center concept - -The configuration center means that in a distributed scenario, the latest framework configuration files and applications cannot be bound together. You can specify the information of the configuration center, such as the type and address of the configuration center, and pull it from the configuration center when the framework starts Start the corresponding configuration. - -## 2. Configuration of the configuration center - -Reference repository: [dubbo-go-samples/configcenter](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/configcenter) - -dubbogo.yml - -```yaml -dubbo: - config-center: - protocol: nacos - address: 127.0.0.1:8848 - data-id: dubbo-go-samples-configcenter-nacos-server - namespace: myNamespaceID # optional configuration nacos namespace ID, the default is public - group: mygroup # Optional configuration nacos group, default is DEFAULT_GROUP -``` - -In the configuration center nacos - -group defaults to `dubbo` - -dataID is the specified id: `dubbo-go-samples-configcenter-nacos-server` - -Write the framework configuration such as the following to start normally. - -```yaml -dubbo: - registries: - demoZK: - protocol: zookeeper - timeout: 3s - address: 127.0.0.1:2181 - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GreeterProvider: - interface: com.apache.dubbo.sample.basic.IGreeter -``` - - - -## 3. Dubbogo dynamic configuration API - -Config API is the API used by dubbogo 3.0 to manipulate the configuration structure. You can use the Config API provided by the framework to initialize the configuration structure, obtain component instances and use them. An example is as follows, including initialization of dynamic configuration instance, publish configuration, read configuration, and subscribe configuration operations. - -```go -const configCenterNacosServerConfig = `# set in config center, group is 'dubbo', dataid is 'dubbo-go-samples-configcenter-nacos-server', namespace is default 'public' -dubbo: - registries: - demoZK: - protocol: zookeeper - address: 127.0.0.1:2181 - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GreeterProvider: - interface: com.apache.dubbo.sample.basic.IGreeter # must be compatible with grpc or dubbo-java` - -type GreeterProvider struct { - api. GreeterProviderBase -} - -func (s *GreeterProvider) SayHello(ctx context.Context, in *api.HelloRequest) (*api.User, error) { - logger.Infof("Dubbo3 GreeterProvider get user name = %s\n", in.Name) - return &api.User{Name: "Hello " + in.Name, Id: "12345", Age: 21}, nil -} - -// There is no need to export DUBBO_GO_CONFIG_PATH, as you are using config api to set config -func main() { -// Get dynamic configuration instance dynamicConfig - dynamicConfig, err := config.NewConfigCenterConfigBuilder(). - SetProtocol("nacos"). - SetAddress("127.0.0.1:8848"). - SetGroup("dubbo"). - Build(). GetDynamicConfiguration() - if err != nil { - panic(err) - } - - // Use the dynamicConfig structure to publish the configuration - if err := dynamicConfig.PublishConfig("dubbo-go-samples-configcenter-nacos-server", "dubbo", configCenterNacosServerConfig); err != nil { - panic(err) - } - - // use dynamicConfig structure to read configuration - data, err := dynamicConfig.GetRule("dubbo-go-samples-configcenter-nacos-server", config_center.WithGroup("dubbo")) - if err != nil{ - panic(err) - } - logger.Infof("get config = %s", data) - - - // Use the dynamicConfig structure to subscribe to configuration update events through a custom listener - l := &listener{} - dynamicConfig.AddListener("dubbo-go-samples-configcenter-nacos-server", l) - - time. Sleep(time. Second * 10) - - config. SetProviderService(&GreeterProvider{}) - - // Start the framework in the form of API - rootConfig := config. NewRootConfigBuilder(). - SetConfigCenter(config. NewConfigCenterConfigBuilder(). - SetProtocol("nacos").SetAddress("127.0.0.1:8848"). // Set the configuration center according to the configuration structure - SetDataID("dubbo-go-samples-configcenter-nacos-server"). // Set configuration ID - SetGroup("dubbo"). - Build()). - build() - - if err := rootConfig.Init(); err != nil { // framework starts - panic(err) - } - select {} -} - -type listener struct { - -} - -func (l listener) Process(event *config_center. ConfigChangeEvent) { - logger.Infof("listener get config = %s", event.Value) -} - -``` - -Of course, when starting the framework in the form of API, you can start the framework directly in the form of API. - -## 4. Dubbogo configuration hot update - -//todo - -under development - diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/desc.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/desc.md deleted file mode 100644 index 3e915d660e89..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/desc.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Introduction to Configuration Center -weight: 1 -type: docs ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/remote_config.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/remote_config.md deleted file mode 100644 index fcc21b50c93b..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/config-center/remote_config.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -type: docs -title: Remote loading configuration start -weight: 3 ---- - -# Remote loading configuration start - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Create a new demo application -- Start a Nacos instance locally/remotely, and log in to the console - -## 2. Create a configuration in the configuration center - -The Dubbogo service framework supports pre-putting the content of the configuration file 'dubbogo.yaml' into the configuration center, and then configuring the address of the registration center. In the local dubbogo.yaml configuration file, you only need to write the information of the configuration center. The middleware currently supported as the configuration center are: apollo, nacos, zookeeper - -You can refer to [Configuration Center samples](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/configcenter), any service that is correctly configured with config-center configuration will first load the entire configuration from the configuration center document. - -```yaml -dubbo: - config-center: - protocol: nacos - address: 127.0.0.1:8848 - data-id: dubbo-go-samples-configcenter-nacos-server - group: myGroup # nacos group, default is DEFAULT_GROUP -# namespace: 9fb00abb-278d-42fc-96bf-e0151601e4a1 # nacos namespaceID, default is public namespace - -## set in config center, group is 'dubbo', dataid is 'dubbo-go-samples-configcenter-nacos-server', namespace is default -#dubbo: -# registries: -# demoZK: -# protocol: nacos -# timeout: 3s -# address: 127.0.0.1:8848 -# protocols: -# triple: -# name: tri -# port: 20000 -# provider: -# services: -# GreeterProvider: -# interface: com.apache.dubbo.sample.basic.IGreeter # must be compatible with grpc or dubbo-java -``` diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/features/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/features/_index.md deleted file mode 100644 index a9fdfd51498a..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/features/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Advanced Features" -weight: 6 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/features/config_api.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/features/config_api.md deleted file mode 100644 index 1f0efb2400f5..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/features/config_api.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -type: docs -title: Launching the Application Using the Configuration API -weight: 2 ---- - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Create a new demo application - -## 2. Start the application using the configuration API - -Users do not need to use configuration files, and can directly write configurations in the code in the form of API calls - -### 2.1 Modify the server code: - -```go -func main() { -config. SetProviderService(&GreeterProvider{}) - -protocolConfig := config. NewProtocolConfigBuilder(). -SetPort("20000"). -SetName("tri"). -build() - -serviceConfig := config. NewServiceConfigBuilder(). -SetInterface(""). // read interface from pb -build() - -providerConfig := config. NewProviderConfigBuilder(). -AddService("GreeterProvider", serviceConfig). -build() - -rootConfig := config. NewRootConfigBuilder(). -AddProtocol("triple-protocol-id", protocolConfig). // add protocol, key is custom -SetProvider(providerConfig).Build() - -if err := config.Load(config.WithRootConfig(rootConfig)); err != nil { -panic(err) -} -select {} -} - -``` - -The configuration API looks complicated, but the construction process of a single configuration structure is consistent. Referring to the design of Java Builder, we use `New().SetA().SetB().Build()` in the configuration API module way to construct a single configuration structure layer by layer. - -Once done, the go-server/conf folder can be deleted. - - - -### 2.2 Modify the client code: - -go-client/cmd/client.go - -```go -func main() { -config. SetConsumerService(grpcGreeterImpl) - -referenceConfig := config. NewReferenceConfigBuilder(). -SetProtocol("tri"). -SetURL("tri://localhost:20000"). -SetInterface(""). // read interface name from pb -build() - -consumerConfig := config.NewConsumerConfigBuilder(). -AddReference("GreeterClientImpl", referenceConfig). -build() - -rootConfig := config. NewRootConfigBuilder(). -SetConsumer(consumerConfig).Build() -if err := config.Load(config.WithRootConfig(rootConfig)); err != nil { -panic(err) -} - -logger.Info("start to test dubbo") -req := &api.HelloRequest{ -Name: "Laurence", -} -reply, err := grpcGreeterImpl.SayHello(context.Background(), req) -if err != nil { -logger. Error(err) -} -logger.Infof("client response result: %v\n", reply) -} - -``` - -Once done, the go-client/conf folder can be deleted. - -### 2.3 Verify Config API - -Start the server and client respectively to view the call information. - -``` -INFO cmd/client.go:62 client response result: name:"Hello laurence" id:"12345" age:21 -``` \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/features/context.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/features/context.md deleted file mode 100644 index 5a64eee28562..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/features/context.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: Use ctx to pass context information -type: docs -weight: 6 ---- - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Create a new demo application - -## 2. Use context to pass additional information - -Reference [dubbo-go-samples/context](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/context) diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/features/custom-logger.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/features/custom-logger.md deleted file mode 100644 index f2ee7f371d77..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/features/custom-logger.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -title: log -weight: 6 -type: docs ---- - -Refer to samples [dubbo-go-samples/logger](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/logger) - -## 1. Log configuration - -dubbogo 3.0 uses the zap log library by default. If you do not add logger configuration in the configuration file, the log will be printed to the control. The default level is debug. You can also configure the log level in the configuration file. You can configure zap-config and lumberjack-config as follows to customize the log output. - -```yaml -dubbo: - logger: - zap-config: - level: debug # log level - development: false - disableCaller: false - disableStacktrace: false - encoding: "console" - # zap encoder configuration - encoderConfig: - messageKey: "message" - levelKey: "level" - timeKey: "time" - nameKey: "logger" - callerKey: "caller" - stacktraceKey: "stacktrace" - lineEnding: "" - levelEncoder: "capitalColor" - timeEncoder: "iso8601" - durationEncoder: "seconds" - callerEncoder: "short" - nameEncoder: "" - outputPaths: - - "stderr" - errorOutputPaths: - - "stderr" - lumberjack-config: - # Write the log file name - filename: "logs.log" - # The maximum size of each log file length, in MiB. Default 100MiB - maxSize: 1 - # The maximum number of days to keep the log (only keep the log of the last few days) - maxAge: 3 - # Only how many recent log files are kept to control the size of the total log of the program - maxBackups: 5 - # Whether to use local time or not, UTC time is used by default - localTime: true - # Whether to compress the log file, compression method gzip - compress: false -``` - -## 2. Logging API and custom logging - -log interface - -```go -type Logger interface { -Info(args...interface{}) -Warn(args ... interface{}) -Error(args...interface{}) -Debug(args...interface{}) -Fatal(args...interface{}) - -Infof(fmt string, args...interface{}) -Warnf(fmt string, args...interface{}) -Errorf(fmt string, args...interface{}) -Debugf(fmt string, args...interface{}) -Fatalf(fmt string, args ... interface{}) -} -``` - -log API - -```go -import "dubbo.apache.org/dubbo-go/v3/common/logger" - - -logger.SetLoggerLevel(warn) // Set the log level in the main function -logger.SetLogger(myLogger) // Set a custom logger in the main function -``` - -- The log API cannot be used in the Init phase, otherwise unexpected problems may occur. diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/features/generic-2.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/features/generic-2.md deleted file mode 100644 index 43ac00e21678..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/features/generic-2.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -title: generalization call -weight: 8 -type: docs ---- - -## 1. Dubbogo generalization calls Java Server - -Use Triple protocol + hessian2 serialization scheme - -Please refer to Dubbogo 3.0 [Generalization Call Documentation](https://www.yuque.com/docs/share/f4e72670-74ab-45b9-bc0c-4b42249ed953?#) - -### 1.1 Java-Server startup - -1. Transmission structure definition - -```java -package org.apache.dubbo; - -import java.io.Serializable; -import java.util.Date; - -public class User implements Serializable { -private String id; - - private String name; - - private int age; - - private Date time = new Date(); -} -``` - -2. Interface definition - -```java -package org.apache.dubbo; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -//import org.apache.dubbo.rpc.filter.GenericFilter; - -public interface UserProvider { -User GetUser1(String userId); -} -``` - -### 1.2 Go-Client generalization call - -Constructing a generalized interface reference in the form of an API is shown here - -```go -// Initialize the Reference configuration -refConf := config. NewReferenceConfigBuilder(). - SetInterface("org. apache. dubbo. UserProvider"). - SetRegistryIDs("zk"). - SetProtocol(tripleConst.TRIPLE). - SetGeneric(true). - SetSerialization("hessian2"). - build() - -// Construct the Root configuration and import the registry module -rootConfig := config. NewRootConfigBuilder(). - AddRegistry("zk", config. NewRegistryConfigWithProtocolDefaultPort("zookeeper")). - build() - -// Reference configuration initialization, because you need to use the registry for service discovery, you need to pass in the configured rootConfig -if err := refConf.Init(rootConfig); err != nil{ - panic(err) -} - -// Generalized call loading, service discovery -refConf. GenericLoad(appName) - -time. Sleep(time. Second) - -// Initiate generalization call -resp, err := refConf.GetRPCService().(*generic.GenericService).Invoke( - context. TODO(), - "getUser1", - []string{"java. lang. String"}, - []hessian. Object{"A003"}, -) - -if err != nil { - panic(err) -} -logger.Infof("GetUser1(userId string) res: %+v", resp) -``` - -The Invoke method of GenericService includes three parameters: context.Context, []string, []hessian.Object, - -The second parameter is the Java class name of the corresponding parameter, such as java.lang.String, org.apache.dubbo.User, the third parameter is the parameter list, and hessian.Object is the interface. The second and third parameters should be consistent with the method signature and correspond in order. - -Get the return result of the map structure - -``` -INFO cmd/client.go:89 GetUser1(userId string) res: map[age:48 class:org.apache.dubbo.User id:A003 name:Joe sex:MAN time:2021-10-04 14:03:03.37 +0800 CST] -``` \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/features/generic.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/features/generic.md deleted file mode 100644 index aeefc49519be..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/features/generic.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: generalization call -type: docs -weight: 7 ---- - -## 1. Dubbo-go generalization calls Java Server - -Use Triple protocol + hessian2 serialization scheme - -### 1.1 Java-Server startup - -1. Transmission structure definition - -```java -package org.apache.dubbo; - -import java.io.Serializable; -import java.util.Date; - -public class User implements Serializable { -private String id; - - private String name; - - private int age; - - private Date time = new Date(); -} -``` - -2. Interface definition - -```java -package org.apache.dubbo; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -//import org.apache.dubbo.rpc.filter.GenericFilter; - -public interface UserProvider { -User GetUser1(String userId); -} -``` - -### 1.2 Go-Client generalization call - -Constructing a generalized interface reference in the form of an API is shown here - -```go -// Initialize the Reference configuration -refConf := config. NewReferenceConfigBuilder(). - SetInterface("org. apache. dubbo. UserProvider"). - SetRegistryIDs("zk"). - SetProtocol(tripleConst.TRIPLE). - SetGeneric(true). - SetSerialization("hessian2"). - build() - -// Construct the Root configuration and import the registry module -rootConfig := config. NewRootConfigBuilder(). - AddRegistry("zk", config. NewRegistryConfigWithProtocolDefaultPort("zookeeper")). - build() - -// Reference configuration initialization, because you need to use the registry for service discovery, you need to pass in the configured rootConfig -if err := refConf.Init(rootConfig); err != nil{ - panic(err) -} - -// Generalized call loading, service discovery -refConf. GenericLoad(appName) - -time. Sleep(time. Second) - -// Initiate generalization call -resp, err := refConf.GetRPCService().(*generic.GenericService).Invoke( - context. TODO(), - "getUser1", - []string{"java. lang. String"}, - []hessian. Object{"A003"}, -) - -if err != nil { - panic(err) -} -logger.Infof("GetUser1(userId string) res: %+v", resp) -``` - -The Invoke method of GenericService includes three parameters: context.Context, []string, []hessian.Object, - -The second parameter is the Java class name of the corresponding parameter, such as java.lang.String, org.apache.dubbo.User, the third parameter is the parameter list, and hessian.Object is the interface. The second and third parameters should be consistent with the method signature and correspond in order. - -Get the return result of the map structure - -``` -INFO cmd/client.go:89 GetUser1(userId string) res: map[age:48 class:org.apache.dubbo.User id:A003 name:Joe sex:MAN time:2021-10-04 14:03:03.37 +0800 CST] -``` \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/interflow/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/interflow/_index.md deleted file mode 100644 index a23c604ac2b4..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/interflow/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Heterogeneous System Interoperability" -weight: 4 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_grpc.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_grpc.md deleted file mode 100644 index 74f7c167ea59..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_grpc.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: Interoperate with gRPC applications -type: docs -weight: 5 ---- - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Create a new demo application - -## 2. Interoperability between Dubbo-go application and gRPC application - -Reference [dubbo-go-samples/rpc/triple/pb/dubbogo-grpc](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/rpc/triple/pb/dubbogo-grpc) diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java.md deleted file mode 100644 index d86f4e381ae8..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/interflow/call_java.md +++ /dev/null @@ -1,842 +0,0 @@ ---- -title: Cross-language interoperability with Java applications -type: docs -weight: 4 ---- - -## Preparation - -### environment - -JDK 8, Golang >= 1.15, Dubbo 3.0.2, zookeeper enabled, - -### Go-Java Interoperability Prerequisites - -- The transfer structure defined by Go/Java is consistent - - - PB serialization - - proto for Go - - ```protobuf - // The response message containing the greetings - message User { - string name = 1; - string id = 2; - int32 age = 3; - } - ``` - - proto for Java - - ```protobuf - // The response message containing the greetings - message User { - string name = 1; - string id = 2; - int32 age = 3; - } - ``` - - - Hessian serialization - - POJO for Go, please refer to [Dubbogo Hessian serialization support document](https://www.yuque.com/docs/share/c698bd6e-e4d6-47db-bc1c-c757cc9b4f3e?) - - ```go - type User struct { - ID string - name string - Age int32 - } - - func (u *User) JavaClassName() string { - return "org.apache.dubbo.User" - } - - func init(){ - hessian.RegisterPOJO(&User{}) - } - ``` - - POJOs for Java - - ```java - package org.apache.dubbo - - public class User { - private String id; - private String name; - private int age; - } - ``` - -- Java requires the same method signature as Go - - E.g: - - Java Interface - - ```java - public interface IGreeter { - /** - *
-     * Sends a greeting
-     * 
- */ - User sayHello(HelloRequest request); - } - ``` - - Go client (automatically generated by protoc-gen-go-triple based on proto files) - - ```go - type GreeterClientImpl struct { - // Sends a greeting - SayHello func(ctx context.Context, in *HelloRequest) (*User, error) - } - ``` - - Go server (defined by the developer) - - ```go - type GreeterProvider struct { - api. GreeterProviderBase - } - - func (s *GreeterProvider) SayHello(ctx context.Context, in *api.HelloRequest) (*api.User, error) { - logger.Infof("Dubbo3 GreeterProvider get user name = %s\n", in.Name) - return &api.User{Name: "Hello " + in.Name, Id: "12345", Age: 21}, nil - } - ``` - - Go methods need to comply with [Dubbogo 3.0 User Service Interface Definition Specification](https://www.yuque.com/docs/share/eff9c51f-a7f4-47d6-87ff-11a2152bdffe?) - - - -- Java's triplet is consistent with the interface configured by Go service/reference - - The triplet is configured at the interface level: interface, group, version. **It should be noted that the concept of group and version is the group and vesion of the dubbo interface, which are configured in the properties file of spring cloud when starting the dubbo-java service, not the version that mvn depends on in pom.xml. ** group and version are empty by default, in the dubbo-go framework, you can specify group and version in the corresponding position of service/reference. - - E.g: - - Java interface full name: com.apache.dubbo.sample.basic.IGreeter, interface version is v1.0.1, group is - - Go-client: - - ```yaml - references: - GreeterClientImpl: - protocol: tri - interface: com.apache.dubbo.sample.basic.IGreeter # must be compatible with grpc or dubbo-java - group: dubbogo # need to correspond to the server, the default is empty - version: v1.0.1 # needs to correspond to the server, the default is empty - ``` - - Go-server: - - ```yaml - services: - GreeterProvider: - protocol-ids: tripleProtocol - interface: com.apache.dubbo.sample.basic.IGreeter # must be compatible with grpc or dubbo-java - group: dubbogo # need to correspond to the server, the default is empty - version: v1.0.1 # needs to correspond to the server, the default is empty - ``` - - - -## 1. Intercommunication based on Triple protocol (PB serialization) - -Reference [dubbo-go-samples/helloworld](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/helloworld) - -### 1.1 Go-Client -> Java-Server - -#### Java-Server start - -1. Define Java PB file, please refer to [Dubbo Quick Start](/zh-cn/docs/quick-start/) - -```protobuf -syntax = "proto3"; - -option java_package = "org.apache.dubbo.sample.hello"; - -package helloworld; - -// The request message containing the user's name. -message HelloRequest { - string name = 1; -} - -// The response message containing the greetings -message User { - string name = 1; - string id = 2; - int32 age = 3; -} -``` - -The interface description file defines the generated Java class org.apache.dubbo.sample.hello.Helloworld, and the transmission structure HelloRequest and User class included in the class. - -2. Define the service interface: - - com.apache.dubbo.sample.basic.IGreeter - -```java -package com.apache.dubbo.sample.basic; - -// Import the class generated according to PB -import org.apache.dubbo.sample.hello.Helloworld.User; -import org.apache.dubbo.sample.hello.Helloworld.HelloRequest; - -public interface IGreeter { - /** - *
-     * Sends a greeting
-     * 
- */ - // define the interface -User sayHello(HelloRequest request); -} -``` - -3. Implement the service interface: - - IGreeter1Impl.java - -```java -package com.apache.dubbo.sample.basic; - -import org.apache.dubbo.sample.hello.Helloworld.User; -import org.apache.dubbo.sample.hello.Helloworld.HelloRequest; - -public class IGreeter1Impl implements IGreeter { - @Override - public User sayHello(HelloRequest request) { - System.out.println("receiv: " + request); - User usr = User. newBuilder() - .setName("hello " + request.getName()) - .setAge(18) - .setId("12345").build(); - return usr; - } -} -``` - -4. Use the Dubbo3 framework to start the service - - ApiProvider.java - -```java -package com.apache.dubbo.sample.basic; - -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -import java.util.concurrent.CountDownLatch; - -public class ApiProvider { - public static void main(String[] args) throws InterruptedException { - ServiceConfig service = new ServiceConfig<>(); - service.setInterface(IGreeter.class); - service.setRef(new IGreeter1Impl()); - // Use the Triple protocol - service.setProtocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051)); - service.setApplication(new ApplicationConfig("demo-provider")); - // Use ZK as the registration center - service.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181")); - service. export(); - System.out.println("dubbo service started"); - new CountDownLatch(1). await(); - } -} -``` - -Start the service, you can see the following log output, which means that the Java Triple Server started successfully - -``` -main INFO bootstrap.DubboBootstrap: [DUBBO] DubboBootstrap has started., dubbo version: 3.0.2, current host: 192.168.0.108 -dubbo service started -``` - -#### Go-Client start - -For the Dubbo service that has been started, if you need to develop its corresponding Go-client, you need to perform the following steps: - -1. Write a proto file adapted to Java - - samples_api.proto - -```protobuf -syntax = "proto3"; -package api; // pacakge name is optional - -//necessary -option go_package = "./;api"; - -// The greeting service definition. -service Greeter { - // Sends a greeting - rpc SayHello (HelloRequest) returns (User) {} -} - -// The request message containing the user's name. -message HelloRequest { - string name = 1; -} - -// The response message containing the greetings -message User { - string name = 1; - string id = 2; - int32 age = 3; -} -``` - -2. Use protoc-gen-triple to generate interface files - -```bash -protoc -I .samples_api.proto --triple_out=plugins=triple:. -``` - -3. Write configuration file: dubbogo.yml - -```yaml -dubbo: - registries: - demoZK: - protocol: zookeeper - address: 127.0.0.1:2181 - consumer: - references: - GreeterClientImpl: - protocol: tri - interface: com.apache.dubbo.sample.basic.IGreeter # must be compatible with grpc or dubbo-java -``` - -4. Write the main.go file and initiate the call - -```go -// Import the generated interface structure -var grpcGreeterImpl = new(api. GreeterClientImpl) - -// export DUBBO_GO_CONFIG_PATH=dubbogo.yml -func main() { -config. SetConsumerService(grpcGreeterImpl) -if err := config.Load(); err != nil { -panic(err) -} -time. Sleep(3 * time. Second) - -logger.Info("start to test dubbo") -req := &api.HelloRequest{ -Name: "Laurence", -} -reply, err := grpcGreeterImpl.SayHello(context.Background(), req) -if err != nil { -logger. Error(err) -} -logger.Infof("client response result: %v\n", reply) -} -``` - -5. You can view the log of the successful call - -- go-client - -``` -cmd/client.go:53 client response result: name:"hello laurence" id:"12345" age:18 -``` - --java-server - -``` -receiver: name: "laurence" -``` - -### 1.2 Java-Client -> Go-Server - -#### Go-Server start - -1. Define the configuration file - -```yaml -dubbo: - registries: - demoZK: - protocol: zookeeper - address: 127.0.0.1:2181 - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GreeterProvider: - interface: com.apache.dubbo.sample.basic.IGreeter # must be compatible with grpc or dubbo-java -``` - -2. Introduce the transport structure and define the service - -```go -type GreeterProvider struct { -api. GreeterProviderBase -} - -func (s *GreeterProvider) SayHello(ctx context.Context, in *api.HelloRequest) (*api.User, error) { -logger.Infof("Dubbo3 GreeterProvider get user name = %s\n", in.Name) -return &api.User{Name: "Hello " + in.Name, Id: "12345", Age: 21}, nil -} -``` - -3. Start the service - -```go -// export DUBBO_GO_CONFIG_PATH=dubbogo.yml -func main() { -config. SetProviderService(&GreeterProvider{}) -if err := config.Load(); err != nil { -panic(err) -} -select {} -} -``` - - - -#### Java-Client start - -1. Proto file writing and interface generation refer to the introduction of the above java-server - -2. Start Consumer - - ApiCnosumer.java - -```java -public class ApiConsumer { - public static void main(String[] args) throws InterruptedException, IOException { - ReferenceConfig ref = new ReferenceConfig<>(); - ref. setInterface(IGreeter. class); - ref. setCheck(false); - ref.setProtocol(CommonConstants.TRIPLE); - ref. setLazy(true); - ref. setTimeout(100000); - ref. setApplication(new ApplicationConfig("demo-consumer")); - ref.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181")); - final IGreeter iGreeter = ref. get(); - - System.out.println("dubbo ref started"); - Helloworld.HelloRequest req = Helloworld.HelloRequest.newBuilder().setName("laurence").build(); - try { - final Helloworld. User reply = iGreeter. sayHello(req); - TimeUnit. SECONDS. sleep(1); - System.out.println("Reply:" + reply); - } catch (Throwable t) { - t. printStackTrace(); - } - System.in.read(); - } -} -``` - -## 2. Intercommunication based on Dubbo protocol (Hessian2 serialization) - -Reference [dubbo-go-samples/rpc/dubbo](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/rpc/dubbo) - -### 2.1 Go-Client -> Java-Server - -#### Java-Server start - -1. Define the Java interface, parameters and return values, please refer to [Dubbo Quick Start](/zh-cn/docs/quick-start/) - -```java -package org.apache.dubbo; - -// The service interface that needs to be exposed -public interface UserProvider { - User getUser(int usercode); -} - -``` - -```java -package org.apache.dubbo; - -public class User implements Serializable { - - private String id; - - private String name; - - private int age; - - private Date time = new Date(); -/* ... */ -} -``` - -2. Implement the service interface: - -UserProviderImpl.java - -```java -package org.apache.dubbo; -public class UserProviderImpl implements UserProvider { - public User getUser(int userCode) { - return new User(String. valueOf(userCode), "userCode get", 48); - } -} - -``` - -3. Start with SpringBoot - -Provider.java - -```java -package org.apache.dubbo; - -// use when config by API -/* -import java.util.concurrent.CountDownLatch; - -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -*/ -import org.springframework.context.support.ClassPathXmlApplicationContext; - -public class Provider { - // main function, config from spring boot - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo.provider.xml"}); - context. start(); - System.in.read(); // press any key to exit - } - - -// config by API -// public static void startComplexService() throws InterruptedException { -// ServiceConfig service = new ServiceConfig<>(); -// service.setInterface(ComplexProvider.class); -// service. setRef(new ComplexProviderImpl()); -// service.setProtocol(new ProtocolConfig(CommonConstants.DUBBO_PROTOCOL, 20001)); -// service.setApplication(new ApplicationConfig("demo-provider")); -// service.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181")); -// service. export(); -// System.out.println("dubbo service started"); -// new CountDownLatch(1). await(); -// } -} - -``` - -4. Configure Dubbo parameters through Spring - - Resources/META-INF.spring/dubbo.provider.xml - -```xml - - - - - - - - - - - - - - - - - - - - -``` - - - -Start the Provider class, and you can see the following log output, which means that the Dubbo Server has started successfully - -``` -[DUBBO] Dubbo Bootstrap is ready., dubbo version: 2.7.7, current host: 127.0.0.1 -[DUBBO] Dubbo Bootstrap has started., dubbo version: 2.7.7, current host: 127.0.0.1 -``` - -#### Go-Client start - -For the Dubbo service that has been started, if you need to develop its corresponding Go-client, you need to perform the following steps: - -1. Write the POJO class User adapted to Java - - -```go -import( - hessian "github.com/apache/dubbo-go-hessian2" -) - -// The field needs to correspond to the Java side, with the first letter capitalized -type User struct { -ID string -name string -Age int32 -Time time. Time -} - - -func (u *User) JavaClassName() string { -return "org.apache.dubbo.User" // needs to correspond to the User class name on the Java side -} - -func init(){ -hessian.RegisterPOJO(&pkg.User{}) // register POJO -} -``` - -2. Write a client stub class that is consistent with the Java side, and its interface method needs to correspond to the Java side - - It is stipulated that the first parameter must be context.Context, and the last return value must be error - -```go -import( -"dubbo.apache.org/dubbo-go/v3/config" -) - -var ( -userProvider = &pkg. UserProvider{} -) - -// UserProvider client stub class -type UserProvider struct { - // The dubbo label is used to adapt the uppercase method name of the go side client -> the lowercase method name of the java side, only the dubbo protocol client needs to use it -GetUser func(ctx context.Context, req int32) (*User, error) `dubbo:"getUser"` -} - -func init(){ - // Register the client stub class to the framework, and instantiate the client interface pointer userProvider -config. SetConsumerService(userProvider) -} - -``` - -3. Write configuration file: dubbogo.yml - -```yaml -dubbo: - registries: - demoZK: # Define the registration center ID - protocol: zookeeper - timeout: 3s - address: 127.0.0.1:2181 - consumer: - references: - UserProvider: # stub class name - protocol: dubbo # dubbo protocol, default hessian2 serialization method - interface: org.apache.dubbo.UserProvider # The interface needs to correspond to the Java side - logger: - zap-config: - level: info # log level -``` - -Or use Triple + Hessian2 to serialize the request Server. If this example communicates with Java Server, Triple cannot be used. - -```yaml -dubbo: - registries: - demoZK: - protocol: zookeeper - timeout: 3s - address: 127.0.0.1:2181 - consumer: - references: - UserProvider: - protocol: tri # triple protocol - serialization: hessian2 # serialization method hessian2, triple protocol defaults to pb serialization, if not configured, an error will be reported - interface: org.apache.dubbo.UserProvider - logger: - zap-config: - level: info -``` - -4. Write the main.go file and initiate the call - -```go -func main(){ - config. Load() -var i int32 = 1 -user, err := userProvider. GetUser2(context. TODO(), i) -if err != nil { -panic(err) -} -logger.Infof("response result: %v", user) -} -``` - -5. You can view the log of the successful call, which meets expectations - -- go-client - -```bash -response result: User{ID:1, Name:userCode get, Age:48, Time:2021-10-21 20:25:26.009 +0800 CST} -``` - -### 2.2 Java-Client -> Go-Server - -#### Go-Server start - -1. Define the configuration file - -```yaml -dubbo: - registries: - demoZK: - protocol: zookeeper - address: 127.0.0.1:2181 - protocols: - dubbo: - name: dubbo - port: 20000 - provider: - services: - UserProvider: - interface: org.apache.dubbo.UserProvider - logger: - zap-config: - level: info -``` - -2. Introduce transport structure, define service and method name mapping - -```go -type UserProvider struct { -} - -func (u *UserProvider) GetUser(ctx context.Context, req int32) (*User, error) { -var err error -logger.Infof("req:%#v", req) -user := &User{} -user.ID = strconv.Itoa(int(req)) -return user, err -} - -// MethodMapper defines method name mapping, from Go method name to Java lowercase method name, only dubbo protocol service interface needs to use -func (s *UserProvider) MethodMapper() map[string]string { -return map[string]string{ -"GetUser": "getUser", -} -} - -func init(){ - config.SetProviderService(&pkg.UserProvider{}) -} - -``` - -3. Start the service - -```go -// export DUBBO_GO_CONFIG_PATH=dubbogo.yml -func main() { -if err := config.Load(); err != nil { -panic(err) -} -select {} -} -``` - - - -#### Java-Client start - -1. Java client Spring configuration - - resources/META-INF.spring/dubbo.consumer.xml - - ```xml - - - - - - - - - - - - - - - - - - - - - - - - - - - ``` - -2. Initiate the call - -```java -public class Consumer { - // Define a private variable (Required in Spring) - private static UserProvider userProvider; - - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo.consumer.xml"}); - userProvider = (UserProvider)context. getBean("userProvider"); - testGetUser(); - } - - - private static void testGetUser() throws Exception { - User user = userProvider. getUser(1); - System.out.println(user.getId()); - } -} -``` diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/_index.md deleted file mode 100644 index f333fcadf056..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Protocol Configuration" -weight: 3 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/choose_protocol.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/choose_protocol.md deleted file mode 100644 index 149df9b1b48f..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/choose_protocol.md +++ /dev/null @@ -1,231 +0,0 @@ ---- -title: Select the network protocol to use -keywords: select the network protocol to use -description: Select the network protocol to use - ---- - -# Modify the protocol used - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Create a new demo application - -## 2. How to configure the network protocol - -As you can see in the Quick Start section, the generated Demo sets the Protocol to tri, indicating that the Triple protocol is used for service exposure and service invocation. The configuration API used in the quick start chapter writes the configuration, which has the advantage of not needing to use configuration files. We extract and explain the content related to the network protocol. - -### Using configuration files - -See samples/helloworld - -- The client uses a configuration file to set the network protocol - -```yaml -dubbo: - consumer: - references: - GreeterClientImpl: - protocol: tri # set protocol to tri - interface: com.apache.dubbo.sample.basic.IGreeter -``` - -- The server uses the configuration file to set the network protocol - -```yaml -dubbo: - protocols: - triple: # define protocol-id 'triple' - name: tri # set protocol to tri - port: 20000 # set port to be listened - provider: - services: - GreeterProvider: - protocol-ids: triple # use protocol-ids named 'triple' - interface: com.apache.dubbo.sample.basic.IGreeter -``` - - - -## 3. Write the interface and implementation of Dubbo protocol - -### 3.1 Define the interface and transmission structure, located in api/api.go - -```go -package api - -import ( -"context" -"dubbo.apache.org/dubbo-go/v3/config" -hessian "github.com/apache/dubbo-go-hessian2" -"time" -) - -//1. Define the transmission structure. If Java intercommunication is required, the field needs to correspond to the Java side, and the first letter is capitalized -type User struct { -ID string -name string -Age int32 -Time time. Time -} - -func (u *User) JavaClassName() string { -return "org.apache.dubbo.User" // If it communicates with Java, it needs to correspond to the full name of the User class on the Java side, -} - - -var ( -UserProviderClient = &UserProvider{} // client pointer -) - -// 2. Define the client stub class: UserProvider -type UserProvider struct { -// The dubbo label is used to adapt the uppercase method name of the go side client -> the lowercase method name of the java side, only the dubbo protocol client needs to use it -GetUser func(ctx context.Context, req int32) (*User, error) //`dubbo:"getUser"` -} - -func init(){ -hessian.RegisterPOJO(&User{}) // register transfer structure to hessian library -// Register the client stub class to the framework, and instantiate the client interface pointer userProvider -config. SetConsumerService(UserProviderClient) -} -``` - -### 2.2 Write Go-Server configuration and code - -server/dubbogo.yaml - -```yaml -dubbo: - registries: - demoZK: # Define the service registration discovery center - protocol: zookeeper - address: 127.0.0.1:2181 - protocols: - dubbo: - name: dubbo # protocol name dubbo - port: 20000 # Listening port - provider: - services: - UserProvider: # service provider structure class name - interface: org.apache.dubbo.UserProvider # The interface needs to correspond to the go/java client -``` - -server/server.go - -```go -package main - -import ( -"context" -"dubbo.apache.org/dubbo-go/v3/common/logger" // dubbogo framework log -"dubbo.apache.org/dubbo-go/v3/config" -_ "dubbo.apache.org/dubbo-go/v3/imports" // dubbogo framework dependency, all dubbogo processes need to import once implicitly -"dubbo3-demo/api" -"strconv" -"time" -) - -type UserProvider struct { -} - -// implement the interface method -func (u *UserProvider) GetUser(ctx context.Context, req int32) (*api.User, error) { -var err error -logger.Infof("req:%#v", req) -user := &api. User{} -user.ID = strconv.Itoa(int(req)) -user.Name = "Laurence" -user.Age = 22 -user.Time = time.Now() -return user, err -} - -//// MethodMapper defines method name mapping, from Go method name to Java lowercase method name, only dubbo protocol service interface needs to use -//// go -> go interoperability does not need to be used -//func (s *UserProvider) MethodMapper() map[string]string { -// return map[string]string{ -// "GetUser": "getUser", -// } -//} - -func init(){ -config.SetProviderService(&UserProvider{}) // Register the service provider class, the class name corresponds to the service in the configuration file -} - -// export DUBBO_GO_CONFIG_PATH=dubbogo.yml needs to set environment variables before running, and specify the location of the configuration file -func main() { -if err := config.Load(); err != nil { -panic(err) -} -select {} -} - -``` - - - -### 2.3 Write Go-Client configuration and code - -client/dubbogo.yaml - -```yaml -dubbo: - registries: - demoZK: # Define the service registration discovery center - protocol: zookeeper - address: 127.0.0.1:2181 - consumer: - references: - UserProvider: # stub class name - protocol: dubbo # dubbo protocol, default hessian2 serialization method - interface: org.apache.dubbo.UserProvider # The interface needs to correspond to the go/java client -``` - -client/client.go - -```go -package main - -import ( -"context" -"dubbo.apache.org/dubbo-go/v3/common/logger" -"dubbo.apache.org/dubbo-go/v3/config" -_ "dubbo.apache.org/dubbo-go/v3/imports" -"dubbo3-demo/api" -) - -func main(){ - // start frame -if err := config.Load(); err != nil{ -panic(err) -} -var i int32 = 1 - // initiate the call -user, err := api.UserProviderClient.GetUser(context.TODO(), i) -if err != nil { -panic(err) -} -logger.Infof("response result: %+v", user) -} -``` - -## 4. Start the service - -Open two terminals and enter the server client directory respectively - -execute separately; - -```shell -export DUBBO_GO_CONFIG_PATH=dubbogo.yml -go run . -``` - -Start the server and the client successively, and you can see the output on the client: - -```shell -response result: &{ID:1 Name:laurence Age:22 Time:2021-11-12 17:59:39.185 +0800 CST} -``` - -successful call diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/error.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/error.md deleted file mode 100644 index 2576938f3b37..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/error.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: exception information return -type: docs -weight: 8 ---- - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Create a new demo application - -## 2. Pass exception information - -Refer to samples [dubbo-go-samples/error](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/error) - -### User exception return introduction - -The user can generate user-defined exception information on the provider side, and can record the exception generation stack. The triple protocol can ensure that the user can get the exception message on the client side, and can view the error stack, which is convenient for locating the problem. - -Note that when returning an error other than nil, the framework is not responsible for the delivery of other return values. - -- An exception is returned on the Triple provider side, taking pb serialization as an example: - -```go -package main - -import ( -"context" -) - -import ( -"dubbo.apache.org/dubbo-go/v3/common/logger" - - // Use an exception library that can record the stack, take "github.com/pkg/errors" as an example here -"github.com/pkg/errors" -) - -import ( -triplepb "github.com/apache/dubbo-go-samples/api" -) - - -// A service provider structure that implements the pb interface -type ErrorResponseProvider struct { -triplepb. UnimplementedGreeterServer -} - -// return error interface -func (s *ErrorResponseProvider) SayHello(ctx context.Context, in *triplepb.HelloRequest) (*triplepb.User, error) { -logger.Infof("Dubbo3 GreeterProvider get user name = %s\n" + in.Name) - // return user-defined exception -return &triplepb.User{Name: "Hello " + in.Name, Id: "12345", Age: 21}, errors.New("user defined error") -} - -``` - - - -- Client print exception and stack - -```go -package main - -import ( -"context" -) - -import ( -"dubbo.apache.org/dubbo-go/v3/common/logger" -"dubbo.apache.org/dubbo-go/v3/config" -_ "dubbo.apache.org/dubbo-go/v3/imports" - -tripleCommon "github.com/dubbogo/triple/pkg/common" -) - -import ( -triplepb "github.com/apache/dubbo-go-samples/api" -) - -var greeterProvider = new(triplepb. GreeterClientImpl) - -func init() { -config. SetConsumerService(greeterProvider) -} - -func main() { -if err := config.Load(); err != nil { -panic(err) -} - -req := triplepb.HelloRequest{ -Name: "Laurence", -} - - // initiate the call -if user, err := greeterProvider. SayHello(context. TODO(), &req); err != nil { - // Print the exception information, err.Error() will return a user-defined message, namely user defined error -logger.Infof("response result: %v, error = %s", user, err) - - // Print the exception stack, it needs to be asserted as tripleCommon.TripleError -logger.Infof("error details = %+v", err.(tripleCommon.TripleError).Stacks()) -} -} - -``` - -```text -2021-11-12T18:36:33.730+0800 INFO cmd/client.go:53 response result: , error = user defined error -2021-11-12T18:36:33.730+0800 INFO cmd/client.go:54 error details = [type.googleapis.com/google.rpc.DebugInfo]:{stack_entries:"user defined error -main.(*ErrorResponseProvider).SayHello - /dubbo-go-samples/error/triple/pb/go-server/cmd/error_reponse.go:40 -reflect.Value.call - /usr/local/go/src/reflect/value.go:543 -reflect.Value.Call - /usr/local/go/src/reflect/value.go:339 -dubbo.apache.org/dubbo-go/v3/common/proxy/proxy_factory.(*ProxyInvoker).Invoke - /Users/laurence/go/pkg/mod/dubbo.apache.org/dubbo-go/v3@v3.0.0-rc4-1/common/proxy/proxy_factory/default.go:145 - ... - -``` - -You can see the error message and stack diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/exception_response.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/exception_response.md deleted file mode 100644 index f5f22ba9cb5c..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/protocol/exception_response.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -title: Triple exception return -weight: 5 -type: docs ---- - -Refer to samples [dubbo-go-samples/error](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/error) - -## User exception return introduction - -The user can generate user-defined exception information on the provider side, and can record the exception generation stack. The triple protocol can ensure that the user can get the exception message on the client side, and can view the error stack, which is convenient for locating the problem. - -Note that when returning an error other than nil, the framework is not responsible for the delivery of other return values. - -- An exception is returned on the Triple provider side, taking pb serialization as an example: - -```go -package main - -import ( -"context" -) - -import ( -"dubbo.apache.org/dubbo-go/v3/common/logger" - - // Use an exception library that can record battle information, here we take "github.com/pkg/errors" as an example -"github.com/pkg/errors" -) - -import ( -triplepb "github.com/apache/dubbo-go-samples/api" -) - - -// A service provider structure that implements the pb interface -type ErrorResponseProvider struct { -triplepb. UnimplementedGreeterServer -} - -// return error interface -func (s *ErrorResponseProvider) SayHello(ctx context.Context, in *triplepb.HelloRequest) (*triplepb.User, error) { -logger.Infof("Dubbo3 GreeterProvider get user name = %s\n" + in.Name) - // return user-defined exception -return &triplepb.User{Name: "Hello " + in.Name, Id: "12345", Age: 21}, errors.New("user defined error") -} - -``` - - - -- Client print exception and stack - -```go -package main - -import ( -"context" -) - -import ( -"dubbo.apache.org/dubbo-go/v3/common/logger" -"dubbo.apache.org/dubbo-go/v3/config" -_ "dubbo.apache.org/dubbo-go/v3/imports" - -tripleCommon "github.com/dubbogo/triple/pkg/common" -) - -import ( -triplepb "github.com/apache/dubbo-go-samples/api" -) - -var greeterProvider = new(triplepb. GreeterClientImpl) - -func init() { -config. SetConsumerService(greeterProvider) -} - -func main() { -if err := config.Load(); err != nil { -panic(err) -} - -req := triplepb.HelloRequest{ -Name: "Laurence", -} - - // initiate the call -if user, err := greeterProvider. SayHello(context. TODO(), &req); err != nil { - // Print the exception information, err.Error() will return a user-defined message, namely user defined error -logger.Infof("response result: %v, error = %s", user, err) - - // Print the exception stack, it needs to be asserted as tripleCommon.TripleError -logger.Infof("error details = %+v", err.(tripleCommon.TripleError).Stacks()) -} -} - -``` - -```text -2021-11-12T18:36:33.730+0800 INFO cmd/client.go:53 response result: , error = user defined error -2021-11-12T18:36:33.730+0800 INFO cmd/client.go:54 error details = [type.googleapis.com/google.rpc.DebugInfo]:{stack_entries:"user defined error -main.(*ErrorResponseProvider).SayHello - /dubbo-go-samples/error/triple/pb/go-server/cmd/error_reponse.go:40 -reflect.Value.call - /usr/local/go/src/reflect/value.go:543 -reflect.Value.Call - /usr/local/go/src/reflect/value.go:339 -dubbo.apache.org/dubbo-go/v3/common/proxy/proxy_factory.(*ProxyInvoker).Invoke - /Users/laurence/go/pkg/mod/dubbo.apache.org/dubbo-go/v3@v3.0.0-rc4-1/common/proxy/proxy_factory/default.go:145 - ... - -``` - -You can see the error message and stack diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/_index.md deleted file mode 100644 index 0013cb3e0673..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Registry" -weight: 2 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/desc.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/desc.md deleted file mode 100644 index 5e2fee7efa5a..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/desc.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Understanding the Registry" -weight: 1 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/multi_registry.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/multi_registry.md deleted file mode 100644 index 16b83f677225..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/multi_registry.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: Multiple Registries -type: docs -weight: 100 ---- - -A registration center for multiple interface dimensions that can be configured by a Dubbo-go application. - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Create a new demo application -- Start Nacos and Zookeeper locally - -## 2. Using multiple registries - -Modify the server configuration go-server/conf/dubbogo.yaml, and register the service on two registration centers at the same time. - -```yaml -dubbo: - registries: - zookeeper: # Specify the zookeeper registration center - protocol: zookeeper - address: 127.0.0.1:2181 - nacos: # Specify the nacos registration center - protocol: nacos - address: 127.0.0.1:8848 - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GreeterProvider: - registry-ids: # Simultaneous registration - - zookeeper - - nacos - interface: "" -``` - -Modify client configuration go-client/conf/dubbogo.yaml - -```yaml -dubbo: - registries: - nacos: # Specify the nacos registration center - protocol: nacos - address: 127.0.0.1:8848 - zookeeper: # Specify the zookeeper registration center - protocol: zookeeper - address: 127.0.0.1:2181 - consumer: - references: - GreeterClientImpl: - registry-ids: # Discovered from the nacos registry service - - nacos - protocol: tri - interface: "" - GreeterClientImpl2: - registry-ids: # service discovery from zookeeper registry - - zookeeper - protocol: tri - interface: "" -``` - -Modify the client code and define a client stub class named GreeterClientImpl2: - -```go -var grpcGreeterImpl2 = new(GreeterClientImpl2) - -type GreeterClientImpl2 struct{ -api. GreeterClientImpl -} -``` - -The client writes the calling code: - -```go -func main() { -config. SetConsumerService(grpcGreeterImpl) -config.SetConsumerService(grpcGreeterImpl2) -if err := config.Load(); err != nil { -panic(err) -} - -logger.Info("start to test dubbo") -req := &api.HelloRequest{ -Name: "Laurence", -} -reply, err := grpcGreeterImpl.SayHello(context.Background(), req) -if err != nil { -logger. Error(err) -} -logger.Infof("nacos server response result: %v\n", reply) - -reply, err = grpcGreeterImpl2. SayHello(context. Background(), req) -if err != nil { -logger. Error(err) -} -logger.Infof("zk server response result: %v\n", reply) -} - -``` - - - -## 3. Multi-registry service discovery verification - -Start go-server/cmd and go-client/cmd respectively to view two logs of successful calls: - -``` -INFO cmd/client.go:55 nacos server response result: name:"Hello laurence" id:"12345" age:21 - -INFO cmd/client.go:61 zk server response result: name:"Hello laurence" id:"12345" age:21 - -``` \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/nacos-2.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/nacos-2.md deleted file mode 100644 index b6e9238164cd..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/nacos-2.md +++ /dev/null @@ -1,157 +0,0 @@ ---- -title: 使用 Nacos 作为注册中心 -type: docs -weight: 10 ---- - -## 1. 准备工作 - -- dubbo-go cli 工具和依赖工具已安装 -- 创建一个新的 demo 应用 -- 启动一个 Nacos 实例,暴露 8848 端口 - -## 2. 配置注册中心 ---- -title: Use Nacos as a registry -type: docs -weight: 10 ---- - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Create a new demo application -- Start a Nacos instance and expose port 8848 - -## 2. Configure the registration center - -Modify the server configuration go-server/conf/dubbogo.yaml - -```yaml -dubbo: - registries: - nacos: # configure Nacos registration center - protocol: nacos - address: 127.0.0.1:8848 # Specify Nacos address - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GreeterProvider: - interface: "" # read from pb -``` - -Modify client configuration go-client/conf/dubbogo.yaml - -```yaml -dubbo: - registries: - nacos: - protocol: nacos - address: 127.0.0.1:8848 - consumer: - references: - GreeterClientImpl: - protocol: tri - interface: "" # read from pb -``` - - - -## 3. Use Nacos for service discovery - -- Start go-server/cmd and check the log - - ```bash - [Nacos Registry] Registry instance with param ... - ``` - - The log contains Nacos registration information, and the current service interface is registered in Nacos. - - You can log in to the console http://localhost:8848/nacos to view the registered services - -- Start go-client/cmd to view logs - - ``` - [Nacos Registry] Update begin, service event: ServiceEvent{Action{add}, Path{tri://xxx.xxx.xxx.xxx:20000/api.Greeter ... - ``` - - The log contains the subscription event information of the Nacos registration component, and the server IP and port number are obtained, indicating that the call is successful. - - ``` - client response result: name: "Hello laurence" id: "12345" age:21 - ``` - - - -## 4. More supported registries - -Reference [dubbo-go-samples/registry](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/registry) -修改服务端配置 go-server/conf/dubbogo.yaml - -```yaml -dubbo: - registries: - nacos: # 配置 Nacos 注册中心 - protocol: nacos - address: 127.0.0.1:8848 # 指定 Nacos 地址 - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GreeterProvider: - interface: "" # read from pb -``` - -修改客户端配置 go-client/conf/dubbogo.yaml - -```yaml -dubbo: - registries: - nacos: - protocol: nacos - address: 127.0.0.1:8848 - consumer: - references: - GreeterClientImpl: - protocol: tri - interface: "" # read from pb -``` - - - -## 3. 使用 Nacos 进行服务发现 - -- 启动go-server/cmd,查看日志 - - ```bash - [Nacos Registry] Registry instance with param ... - ``` - - 日志中包含 Nacos 注册信息,将当前服务接口注册在 Nacos。 - - 可登陆控制台 http://localhost:8848/nacos 查看注册的服务 - -- 启动 go-client/cmd 查看日志 - - ``` - [Nacos Registry] Update begin, service event: ServiceEvent{Action{add}, Path{tri://xxx.xxx.xxx.xxx:20000/api.Greeter ... - ``` - - 日志中包含 Nacos 注册组件的订阅事件信息,获取到服务端 IP 和端口号,显示调用成功。 - - ``` - client response result: name:"Hello laurence" id:"12345" age:21 - ``` - - - -## 4. 更多支持的注册中心 - -参考 [dubbo-go-samples/registry](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/registry) - - diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/nacos.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/nacos.md deleted file mode 100644 index af4cffe62270..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/nacos.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -title: Use Nacos as a registry -type: docs -weight: 10 ---- - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Create a new demo application - -## 2. Use grpc_cli tool to debug Dubbo service - -### 2.1 Start the server -Example: user.go: -```go -func (u *UserProvider) GetUser(ctx context.Context, userStruct *CallUserStruct) (*User, error) { -fmt.Printf("=========================\nreq:%#v\n", userStruct) -rsp := User{"A002", "Alex Stocks", 18, userStruct.SubInfo} -fmt.Printf("========================\nrsp:%#v\n", rsp) -return &rsp, nil -} - -``` -The server opens a service named GetUser, passes in a CallUserStruct parameter, and returns a User parameter\ -CallUserStruct parameter definition: -```go -type CallUserStruct struct { -ID string -Male bool -SubInfo SubInfo // nested substructure -} -func (cs CallUserStruct) JavaClassName() string { -return "com.ikurento.user.CallUserStruct" -} - -type SubInfo struct { -SubID string -SubMale bool -SubAge int -} - -func (s SubInfo) JavaClassName() string { -return "com.ikurento.user.SubInfo" -} - -``` -User structure definition: -```go -type User struct { -Id string -name string -Age int32 -SubInfo SubInfo // Nest the above substructure SubInfo -} - -func (u *User) JavaClassName() string { -return "com.ikurento.user.User" -} -``` - -Start the service: - -`cd server`\ -`source builddev.sh`\ -`go run.` - -### 2.2 Define the request body (unpacking protocol) - -The request body is defined as a json file, and the agreed key value is string\ -The key corresponds to the field name of the go language struct, such as "ID" and "Name", and the value corresponds to "type@val"\ -Among them, type supports string int bool time, and val is initialized with string. If only type is filled in, it will be initialized to a zero value. -It is agreed that each struct must have a JavaClassName field, which must strictly correspond to the server side - -See userCall.json: -```json -{ - "ID": "string@A000", - "Male": "bool@true", - "SubInfo": { - "SubID": "string@A001", - "SubMale": "bool@false", - "SubAge": "int@18", - "JavaClassName": "string@com.ikurento.user.SubInfo" - }, - "JavaClassName": "string@com.ikurento.user.CallUserStruct" -} -``` -userCall.json defines the structure of the parameter CallUserStruct and the substructure SubInfo, and assigns values to the request parameters. - -Similarly, user.json does not need to assign an initial value as the return value, but the JavaClassName field must strictly correspond to the server side -```go -{ - "ID": "string", - "Name": "string", - "Age": "int", - "JavaClassName": "string@com.ikurento.user.User", - "SubInfo": { - "SubID": "string", - "SubMale": "bool", - "SubAge": "int", - "JavaClassName": "string@com.ikurento.user.SubInfo" - } -} -``` - -### 2.3 Executing the request -`dubbogo-cli call --h=localhost --p 20001 --proto=dubbo --i=com.ikurento.user.UserProvider --method=GetUser --sendObj="./userCall.json" --recvObj= "./user.json"` - -The client prints the result: -``` log -2020/10/26 20:47:45 Created pkg: -2020/10/26 20:47:45 &{ID:A000 Male:true SubInfo:0xc00006ea20 JavaClassName:com.ikurento.user.CallUserStruct} -2020/10/26 20:47:45 SubInfo: -2020/10/26 20:47:45 &{SubID:A001 SubMale:false SubAge:18 JavaClassName:com.ikurento.user.SubInfo} - - -2020/10/26 20:47:45 Created pkg: -2020/10/26 20:47:45 &{ID: Name: Age:0 JavaClassName:com.ikurento.user.User SubInfo:0xc00006ec90} -2020/10/26 20:47:45 SubInfo: -2020/10/26 20:47:45 &{SubID: SubMale:false SubAge:0 JavaClassName:com.ikurento.user.SubInfo} - - -2020/10/26 20:47:45 connected to localhost:20001! -2020/10/26 20:47:45 try calling interface: com.ikurento.user.UserProvider.GetUser -2020/10/26 20:47:45 with protocol: dubbo - -2020/10/26 20:47:45 After 3ms , Got Rsp: -2020/10/26 20:47:45 &{ID:A002 Name:Alex Stocks Age:18 JavaClassName: SubInfo:0xc0001241b0} -2020/10/26 20:47:45 SubInfo: -2020/10/26 20:47:45 &{SubID:A001 SubMale:false SubAge:18 JavaClassName:}``` -``` -You can see the detailed request body assignment, as well as the returned result and time-consuming. Supports nested structures - -Print the result on the server side -``` -========================= -req:&main.CallUserStruct{ID:"A000", Male:true, SubInfo:main.SubInfo{SubID:"A001", SubMale:false, SubAge:18}} -========================= -``` -It can be seen that the data from the cli has been received \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/polaris.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/polaris.md deleted file mode 100644 index 0f18dc4a07e6..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/polaris.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Using Polaris as a Registry -type: docs -weight: 12 ---- - -TBD \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/registry.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/registry.md deleted file mode 100644 index 39790b36383d..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/registry.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: Registry Configuration -weight: 4 -type: docs ---- - -Refer to samples [dubbo-go-samples/registry](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/registry) - -## Registry registration center configuration - -- **Nacos Registration Center** - -```yaml -dubbo: - application: # Application information, after the service is started, the relevant information will be registered in the registration center, which can be identified by the client from the url - name: myApp # application=myApp; name=myApp - module: opensource # module=opensource - organization: dubbo # organization=dubbo - owner: laurence # owner=laurence - version: myversion # app.version=myversion - environment: pro # environment=pro - registries: - nacosWithCustomGroup: - protocol: nacos # The registration center chooses nacos - address: 127.0.0.1:8848 # nacos ip - group: myGroup # nacos group, default DEFAULT_GROUP - namespace: 9fb00abb-278d-42fc-96bf-e0151601e4a1 # nacos namespaceID, should be created before. Default public - username: abc - password: abc - protocols: - dubbo: - name: dubbo - port: 20000 - provider: - services: - UserProviderWithCustomGroupAndVersion: # Interface triplet: interface name, version number, group. client and server need to be consistent. - interface: org.apache.dubbo.UserProvider.Test # interface name is required - version: myInterfaceVersion # Default is empty - group: myInterfaceGroup # Default is empty -``` - -The group, namespace, username, and password configured in the registration center of dubbogo correspond to nacos-related concepts. - -- **Zookeeper Registry** - -```yaml -dubbo: - # application: Consistent with nacos, no more details - registries: - demoZK: - protocol: zookeeper # The registration center chooses nacos - address: 127.0.0.1:2181 # zookeeper ip - group: myGroup # nacos group, default dubbo - protocols: - triple: - name: tri - port: 20000 - provider: - services: - UserProviderWithCustomGroupAndVersion: # Interface triplet: interface name, version number, group. client and server need to be consistent. - interface: com.apache.dubbo.sample.basic.IGreeter # interface name is required - version: myInterfaceVersion # Default is empty - group: myInterfaceGroup # Default is empty -``` - -When zookeeper is registered, the provider side registers the interface information in `/$(group)/$(interface)/providers` node, taking the above configuration as an example, the registered zk path is `/myGroup/com.apache.dubbo.sample. basic.IGreeter/providers/` - -The consumer side is registered in /$(group)/$(interface)/consumers for statistics. - -- **ETCD Registration Center** - -```yaml -dubbo: - registries: - etcd: - protocol: etcdv3 - timeout: 3s - address: 127.0.0.1:2379 - protocols: - dubbo: - name: dubbo - port: 20000 - provider: - services: - UserProvider: - interface: org.apache.dubbo.UserProvider -``` - -- **Application-level service registration discovery** - -```yaml -dubbo: - registries: - demoZK: - protocol: zookeeper # nacos/zookeeper - address: 127.0.0.1:2181 - registry-type: service # Use application-level service discovery - metadata-report: # configure metadata center - protocol: zookeeper - address: 127.0.0.1:2181 - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GreeterProvider: - interface: com.apache.dubbo.sample.basic.IGreeter -``` diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/service-discovery.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/service-discovery.md deleted file mode 100644 index 5843c3f852a4..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/service-discovery.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Application-Level Service Discovery -weight: 2 -type: docs ---- - -Reference article [**"Dubbo takes an important step towards cloud native application-level service discovery analysis"**](https://baijiahao.baidu.com/s?id=1669266413887039723&wfr=spider&for=pc) - -Reference repository: [dubbo-go-samples/registry/serivcediscovery](https://github.com/apache/dubbo-go-samples/tree/45a0d843b54e4922c240900e63516176cc7da4f6/registry/servicediscovery) - -## Configuration - -- Consumer side - -```yaml -dubbo: - registries: - demoZK: - protocol: nacos - address: 127.0.0.1:8848 - registry-type: service # Specify the registry as application-level service discovery, if not filled, it defaults to interface level - metadata-report: # Define metadata center - protocol: nacos # The metadata center can choose nacos/zk - address: 127.0.0.1:8848 - consumer: - references: - GreeterClientImpl: - protocol: tri - interface: com.apache.dubbo.sample.basic.IGreeter -``` - - - -- Provider side - -```yaml -dubbo: - registries: - demoZK: - protocol: nacos - address: 127.0.0.1:8848 - registry-type: service # Specify the registry as application-level service discovery, if not filled, it defaults to interface level - metadata-report: # Define metadata center - protocol: nacos # The metadata center can choose nacos/zk - address: 127.0.0.1:8848 - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GreeterProvider: - interface: com.apache.dubbo.sample.basic.IGreeter -``` - -Compared with the conventional configuration, after defining registry-type: service and defining the metadata center, application-level service registration/service discovery will be used. diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/zookeeper.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/zookeeper.md deleted file mode 100644 index 5c00d750c3a4..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/registry/zookeeper.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Using Zookeeper as a Registry -type: docs -weight: 11 ---- - -TBD \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/develop/template.md b/content/en/docs3-v2/golang-sdk/tutorial/develop/template.md deleted file mode 100644 index 55fbcd8cf583..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/develop/template.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -type: docs -title: "Apply Template" -weight: 1 ---- - - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed - -## 2. Use dubbogo-cli to create a project template - -Run `dubbogo-cli newApp .` - -```plain -$ mkdir cli-create-server -$ cd cli-create-server -$ dubbogo-cli newApp . -$ tree . -. -├── Makefile -├── api -│ └── api.proto -├──build -│ └── Dockerfile -├── chart -│ ├── app -│ │ ├── Chart.yaml -│ │ ├── templates -│ │ │ ├── _helpers.tpl -│ │ │ ├── deployment.yaml -│ │ │ ├── service.yaml -│ │ │ └── serviceaccount.yaml -│ │ └── values.yaml -│ └── nacos_env -│ ├── Chart.yaml -│ ├── templates -│ │ ├── _helpers.tpl -│ │ ├── deployment.yaml -│ │ └── service.yaml -│ └── values.yaml -├── cmd -│ └── app.go -├── conf -│ └── dubbogo.yaml -├── go.mod -├── go.sum -└── pkg - └── service - └── service.go -``` - -The generated project includes several directories: - -- api: place interface files: proto file and generated pb.go file - -- build: place build related files - -- chart: place the chart package for publishing, the chart package of the basic environment: nacos, mesh (under development) - -- cmd: program entry - -- conf: framework configuration - -- pkg/service: RPC service implementation - -- Makefile: - - - Image, application name: - - - IMAGE = $(your_repo)/$(namespace)/$(image_name) - TAG = 1.0.0 - - - APPNAME = dubbo-go-app # For helm publishing, corresponding to chart name, application name and service name (service name) - - - Provide scripts such as: - - - make build # Package the image and push it - - - make buildx-publish # The arm architecture locally packs the amd64 image and pushes it, relying on docker buildx - - - make deploy # Publish the application through helm - - - make remove # Delete the published helm application - - - make proto-gen # generate pb.go file under api/ \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/_index.md deleted file mode 100755 index a29ae6acab92..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Service Governance" -weight: 4 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/features/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/features/_index.md deleted file mode 100644 index a9fdfd51498a..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/features/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Advanced Features" -weight: 6 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/features/aop.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/features/aop.md deleted file mode 100644 index 6b13d073cae2..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/features/aop.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: Custom service call middleware -type: docs -weight: 1 ---- - -Refer to samples [dubbo-go-samples/filter](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/filter) - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Read [[Component Loading and Extensibility]](/en/docs3-v2/golang-sdk/preface/design/aop_and_extension/) -- Create a new demo application - -## 2. Configure the specified Filter - -When specifying a filter, it can be separated by ',' - -- Consumer side - - ```yaml - dubbo: - consumer: - filter: echo,token,tps,myCustomFilter # Custom filter can be specified - ``` - - - -- Provider side - - ```yaml - dubbo: - provider: - services: - GreeterProvider: - filter: myCustomFilter, echo, tps - ``` - -## 3. Custom Filter - -Users can customize Filter in the code, register it on the framework, and choose to use it in the configuration. - -```go -func init() { -extension. SetFilter("myCustomFilter", NewMyClientFilter) -} - -func NewMyClientFilter() filter. Filter { -return &MyClientFilter{} -} - -type MyClientFilter struct { -} - -func (f *MyClientFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { -fmt.Println("MyClientFilter Invoke is called, method Name = ", invocation.MethodName()) -return invoker. Invoke(ctx, invocation) -} -func (f *MyClientFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, protocol protocol.Invocation) protocol.Result { -fmt.Println("MyClientFilter OnResponse is called") -return result -} - -``` diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/features/custom-filter.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/features/custom-filter.md deleted file mode 100644 index 0c06980dca8d..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/features/custom-filter.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: Custom Filter component -weight: 3 -type: docs ---- - -Refer to samples [dubbo-go-samples/filter](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/filter) - -## 1. Filter concept - -```go -// Filter interface defines the functions of a filter -// Extension - Filter -type Filter interface { -// Invoke is the core function of a filter, it determines the process of the filter -Invoke(context.Context, protocol.Invoker, protocol.Invocation) protocol.Result -// OnResponse updates the results from Invoke and then returns the modified results. -OnResponse(context.Context, protocol.Result, protocol.Invoker, protocol.Invocation) protocol.Result -} -``` - -Filter can be loaded on the Consumer side or the Provider side. When loaded on the Consumer side, the downstream of its Invoke function call is the network layer, and OnResponse is called after the request is completed and the return result is obtained from the network layer. When loaded on the Provider side, the downstream of its Invoke function call is user code, and OnResponse is called after the user code is executed and passed down to the network layer. - -Filter adopts the idea of aspect-oriented design. Through reasonable expansion of Filter, it can record logs, set data management, record the performance of the server corresponding to the invoker, limit traffic, and so on. - -## 2. Framework predefined Filter - -The framework predefines a series of filters, which can be used directly in the configuration, and its code implementation is located at [filter](https://github.com/apache/dubbo-go/tree/release-3.0/filter) - -- accesslog -- active -- sign: AuthConsumerFilter -- auth: AuthProviderFilter - -echo -- execute: ExecuteLimitFilter -- generic: GenericFilter -- generic_service: GenericServiceFilter -- pshutdown: GracefulShutdownProviderFilter - -cshutdown: GracefulShutdownConsumerFilter -- hystrix_consumer: HystrixConsumerFilter -- hystrix_provider: HystrixProviderFilter -- metrics -- seata -- sentinel-provider -- sentinel-consumer - -token - -tps -- tracing - -## 3. Load Filter by default - -When the user configures the filter to be used in the configuration file, the framework uses the filter configured by the user, otherwise the default filter is loaded: - --Consumer: - -cshutdown - -- Provider: - - echo, metrics, token, accesslog, tps, generic_service, executivete, pshutdown - -## 4. User specified Filter - -When specifying a filter, it can be separated by ',' - -- Consumer side - - ```yaml - dubbo: - consumer: - filter: echo,token,tps,myCustomFilter # Custom filter can be specified - ``` - - - -- Provider side - - ```yaml - dubbo: - provider: - services: - GreeterProvider: - filter: myCustomFilter, echo, tps - ``` - -## 5. Custom Filter - -Users can customize Filter in the code, register it on the framework, and choose to use it in the configuration. - -```go -func init() { -extension. SetFilter("myCustomFilter", NewMyClientFilter) -} - -func NewMyClientFilter() filter. Filter { -return &MyClientFilter{} -} - -type MyClientFilter struct { -} - -func (f *MyClientFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { -fmt.Println("MyClientFilter Invoke is called, method Name = ", invocation.MethodName()) -return invoker. Invoke(ctx, invocation) -} -func (f *MyClientFilter) OnResponse(ctx context.Context, result protocol.Result, invoker protocol.Invoker, protocol protocol.Invocation) protocol.Result { -fmt.Println("MyClientFilter OnResponse is called") -return result -} - -``` - - diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/features/timeout.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/features/timeout.md deleted file mode 100644 index 6489fab55fe8..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/features/timeout.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: timeout for configuration calls -type: docs -weight: 1 ---- - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Create a new demo application - -## 2. Modify RPC call-related parameters through configuration items - -### 2.1 Modify the timeout of the call and verify - -```yaml -dubbo: - consumer: - request-timeout: 15s # Configure client timeout -``` - -The default RPC timeout of the Dubbo-go application is 3s. After the request times out, the client will return an error with the error context deadline exceeded. In this task, you need to first modify the server function of the demo application to take a long time, and then check the client's timeout error; and then configure the client timeout so that the time-consuming function can be called normally. - -1. go-server/cmd/server.go: Modify the function of the demo application server to a function that takes 10s - - ```go - func (s *GreeterProvider) SayHello(ctx context.Context, in *api.HelloRequest) (*api.User, error) { - logger.Infof("Dubbo3 GreeterProvider get user name = %s\n", in.Name) - time.Sleep(time.Second*10) // sleep 10s - return &api.User{Name: "Hello " + in.Name, Id: "12345", Age: 21}, nil - } - ``` - -2. The client initiates a call and observes the error log - - ``` - ERROR cmd/client.go:47 context deadline exceeded - ``` - -3. go-client/conf/dubbogo.yaml: client modification timeout - - ```yaml - dubbo: - consumer: - request-timeout: 15s # Configure client timeout - references: - GreeterClientImpl: - protocol: tri - url: "tri://localhost:20000" - interface: "" # read from pb - ``` - -4. Initiate the call through the client again, observe the log, and return normally: - - ```bash - client response result: name: "Hello laurence" id: "12345" age:21 - ``` \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/health/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/health/_index.md deleted file mode 100644 index 75eabe727971..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/health/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Health Check" -weight: 3 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/health/kubernetes.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/health/kubernetes.md deleted file mode 100644 index b825255a80e6..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/health/kubernetes.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Kubernetes Probe -weight: 4 -type: docs ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/health/start-check.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/health/start-check.md deleted file mode 100644 index 88bf85f935eb..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/health/start-check.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: dubbogo 3.0 check at startup -keywords: check when dubbogo 3.0 starts -description: Check when dubbogo 3.0 starts -weight: 4 -type: docs ---- - -# check at startup - -Check if dependent services are available at startup - -By default, Dubbo-go will check whether the dependent services are available at startup. When they are not available, an exception will be thrown to prevent the application from completing initialization, so that problems can be detected early when going online. The default check="true" and wait for 3s. - -You can turn off the check with check="false". For example, when testing, some services don't care, or there is a circular dependency, and one of them must be started first. - -After closing check, please note that when the number of providers is large, there may be a certain delay when the consumer subscribes to the provider to generate the service dictionary. If the consumer provides services to the outside world as soon as it starts, -May cause "cold start". So at this time, please warm up the service. - -Example: - -```yaml -dubbo: - consumer: - check: false - reference: - myserivce: - check: true -``` \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/health/triple-health-check.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/health/triple-health-check.md deleted file mode 100644 index c87faee2cb7d..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/health/triple-health-check.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: Grpc-based health check -type: docs -weight: 2 ---- - -## 1. Grpc health check - -The Grpc health check is implemented through an ordinary user rpc call. The Grpc health check defines the following protobuf, so that the intercommunication of all Grpc protocol health checks can be realized. - -> Firstly, since it is a GRPC service itself, doing a health check is in the same format as a normal rpc. Secondly, it has rich semantics such as per-service health status. Thirdly, as a GRPC service, it is able to reuse All the existing billing, quota infrastructure, etc, and thus the server has full control over the access of the health checking service. - -``` protobuf -syntax = "proto3"; - -package grpc.health.v1; - -message HealthCheckRequest { - string service = 1; -} - -message HealthCheckResponse { - enum ServingStatus { - UNKNOWN = 0; - SERVING = 1; - NOT_SERVING = 2; - SERVICE_UNKNOWN = 3; // Used only by the Watch method. - } - ServingStatus status = 1; -} - -service Health { - rpc Check(HealthCheckRequest) returns (HealthCheckResponse); - - rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse); -} -``` - -## 2 triple health check service - -+ The Dubbo-go framework will automatically register the health check service with the framework after startup, and provide health check services based on grpc health proto, without additional configuration in the configuration file. -+ The triple health check service can check the status of the service in the framework through grpc-health-probe, and can also call the health check service through grpc, but it cannot call the health check service through the triple client (the health check service based on grpc does not pass the registration Center registration), the called service name is "grpc.health.v1.Health", and the interface is check. - -### 2.1 Call the health check service through the gprc client: - -+ Start [triple service](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/rpc/triple/pb/dubbogo-grpc/go-server) in dubbo-go-samples, through The following grpc client can view the status of "org.apache.dubbogo.samples.api.Greeter". The triple health check service communicates with grpc, so the health status of services based on the triple protocol can be checked through the grpc client. - -``` go -package main - -import ( -"context" -"fmt" -"log" -) - -import ( -"google.golang.org/grpc" -"google.golang.org/grpc/credentials/insecure" -healthpb "google.golang.org/grpc/health/grpc_health_v1" -) - -const ( -address = "localhost:20000" -) - -func main() { -// Set up a connection to the server -conn, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials())) -if err != nil { -log.Fatalf("did not connect: %v", err) -} - -defer func() { -_ = conn.Close() -}() - -checkHealth("org.apache.dubbogo.samples.api.Greeter", conn) -} - -func checkHealth(service string, conn *grpc.ClientConn) { -fmt.Printf(">>>>> gRPC-go check %s status", service) - -req := &healthpb.HealthCheckRequest{ -Service: service, -} -ctx := context. Background() -rsp, err := healthpb. NewHealthClient(conn). Check(ctx, req) -if err != nil { -panic(err) -} -fmt.Printf("get service status = %+v\n", rsp) -} -``` - -### 2.2 grpc-health-probe debugging health check service: - -+ Start [triple service](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/rpc/triple/pb/dubbogo-grpc/go-server) in dubbo-go-samples, provide `org.apache.dubbogo.samples.api.Greeter` service. Use grpc-health-probe to check the health status of the service, `grpc-health-probe -addr=localhost:20000 -service "org.apache.dubbogo.samples.api.Greeter"` - -![image-health-check](/imgs/docs3-v2/golang-sdk/tasks/service_management/triple-health-check/health-check.png) - -#### refer to: - -+ https://github.com/grpc/grpc/blob/master/doc/health-checking.md -+ https://github.com/grpc/grpc-go/tree/master/health diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/_index.md deleted file mode 100644 index 1a9655938b2e..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Rate Limit" -weight: 4 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/adaptive-service.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/adaptive-service.md deleted file mode 100644 index 66118c6208fe..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/adaptive-service.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: dubbogo 3.0 flexible service -keywords: dubbogo 3.0 flexible service -description: dubbogo 3.0 flexible service ---- - -# Flexible load balancing (flexible service) - -Flexible service is a decentralized intelligent load balancing component, and it is also one of the major new features in Dubbo-go version 3.0. Flexible services are still in the early experimental stage, and this feature will continue to be optimized in subsequent versions, and we will work with the Dubbo community to explore a set of best practices suitable for microservice scenarios. - -The traditional load balancing algorithm is implemented by algorithms such as random nodes and RoundRobin. Their limitation is that they do not know the load situation of the current service provider, and the algorithm always calls different service providers with as fair a probability as possible. In practice, fairness does not mean high performance, and cluster service performance is also related to multiple factors such as service load and task complexity. In order to solve the shortcomings of traditional load balancing algorithms, Dubbo-go introduced flexible services in version 3.0, realizing dynamic capacity evaluation and distribution functions. - -Capacity assessment is the core of flexible services, which can dynamically assess the capacity level of the server. In the process of capacity evaluation, the two core indicators are TPS and response time. It is necessary to balance the relationship between system utilization and system performance, so that the whole is in the best state. - -- TPS reflects system utilization from the perspective of service providers. Before the system pressure is saturated, the greater the number of requests, the higher the system utilization rate. However, if the request volume is further increased until the system is oversaturated, the problem of overload occurs, resulting in a downward trend in overall efficiency. -- Response time reflects system performance from the perspective of service callers. Before the system pressure is not saturated, the response time increases linearly with the number of requests, but when the amount of requests is further increased until the system is oversaturated, the response time and the number of requests increase exponentially. - -![img](/imgs/docs3-v2/golang-sdk/samples/adaptive-service/adaptive.png) - - -Flexible services are collected during the call - -In Dubbo-go version 3.0, service flexible load balancing is supported. In the microservice scenario, the client will collect the hardware resource consumption of the downstream server instance of the service during the invocation process, and select the most suitable downstream instance for invocation through capacity evaluation and screening strategies, thereby improving the overall system performance. - -Service flexibility will continue to be optimized in subsequent iterations, seeking to explore best practices with the Dubbo community. - diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/internally/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/internally/_index.md deleted file mode 100644 index 0ad6bd0008af..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/internally/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Dubbo Go's built-in current limit usage tutorial" -weight: 1 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/polaris/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/polaris/_index.md deleted file mode 100644 index 7f8c126952bc..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/polaris/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Polaris-Based Current Limiting Tutorial" -weight: 3 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/sentinel/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/sentinel/_index.md deleted file mode 100644 index 5b7dbfd79f98..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/sentinel/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Current Limiting Tutorial Based on Sentinel" -weight: 2 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/tps_limiter.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/tps_limiter.md deleted file mode 100644 index c07fddff4ba5..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/limit/tps_limiter.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: Set current limit for the server -type: docs -weight: 3 ---- - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Create a new demo application - -## 2. Modify the current limiting logic and verify - -Dubbo-go provides users with built-in flow-limiting rejection logic, and supports users to define the required flow-limiting mechanism and rejection logic according to their own business scenarios. - -Under normal circumstances, no flow limit is set. When the user configures the flow limit logic and parameters on the server side, it will - -### 2.1 Configure current limiting parameters - -go-server/conf/dubbogo.yaml: Configure current limiting parameters - -```yaml -dubbo: - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GreeterProvider: - interface: "" # read from pb - tps.limiter: "method-service" - tps.limit.strategy: "slidingWindow" - tps.limit.rejected.handler: "default" - tps.limit.interval: 1000 - tps.limit.rate: 3 - -``` - -Parameter Description: - -- tps.limiter: current limiter selection. method-service is a current limiter built into the framework, which can configure service and method-level current limit logic, which can be customized. -- tps.limit.strategy: selection of current limiting strategy, slidingWindow is a built-in current limiting strategy of the framework, which can reject requests exceeding the traffic limit in the window in the form of a sliding window. -- tps.limit.rejected.handler: rejection strategy, default is the default rejection method, returns an empty object, can be customized -- tps.limit.interval: current limit window interval, the unit is ms. -- tps.limit.rate: The traffic limit in the window, the unit is the number of requests. - -According to the above configuration, the server only allows the current interface to be called three times within one second. - -### 2.2 Initiate a super-flow request to verify the current-limiting capability - -Set the client's request logic to request five times per second, and calculate the success rate. - -go-client/cmd/client.go - -```go - -func main() { -config. SetConsumerService(grpcGreeterImpl) -if err := config.Load(); err != nil { -panic(err) -} - -logger.Info("start to test dubbo") -req := &api.HelloRequest{ -Name: "Laurence", -} - -for { -goodCount := 0 -badCount := 0 -for { -time.Sleep(time.Millisecond*200) -reply, _ := grpcGreeterImpl.SayHello(context.Background(), req) -if reply.Name == "" { -badCount++ -} else { -goodCount++ -} -if badCount + goodCount == 5{ -break -} -} -logger.Infof("Success rate = %v\n", float64(goodCount)/float64(goodCount + badCount)) -} -} -``` - -It can be seen in the log that the request success rate is 0.6, and only three requests are allowed to be executed per second. - -```bash -INFO cmd/client.go:62 Success rate = 0.6 - -INFO cmd/client.go:62 Success rate = 0.6 - -INFO cmd/client.go:62 Success rate = 0.6 -``` - -You can see the rejection information in the server log: - -```bash -ERROR tps/filter.go:84 The invocation was rejected due to over the limiter limitation... -``` \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/_index.md deleted file mode 100644 index da190bfd12f6..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Service Status Monitoring" -weight: 1 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/grafana/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/grafana/_index.md deleted file mode 100644 index 2650c4e548ed..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/grafana/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Grafana-based Visual Monitoring Tutorial" -weight: 3 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/http/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/http/_index.md deleted file mode 100644 index 97a786e5726b..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/http/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Indicator observation based on http metrics" -weight: 1 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/logger/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/logger/_index.md deleted file mode 100644 index 68bef58cd554..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/logger/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Dubbo Go Log Management" -weight: 4 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/metrics.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/metrics.md deleted file mode 100644 index ddfdb5be0bee..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/metrics.md +++ /dev/null @@ -1,205 +0,0 @@ ---- -title: Metrics data reporting -weight: 7 -type: docs ---- - -Reference Samples: [dubbo-go-samples/metrics](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/metrics) - -## 1. Data reporting configuration - -When the metrics: field is not specified, the pull mode prometheus data reporting is enabled by default, the default port is 9090, and the monitoring path defaults to /metrics. You can customize it by referring to the server configuration example below. - -```yaml -dubbo: - application: - version: 3.0.0-rc3 # version number - metrics: - enable: true # default is true - path: /custom-metrics-path # default is /metrics - port: 9091 # default is 9090 - namespace: dubbo # default is dubbo as the prefix for data reporting metrics - registries: - myzk: - protocol: zookeeper - address: localhost:2181 - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GreeterProvider: - group: dubbo-go # belongs to the group, need to be consistent with the client - interface: com.apache.dubbo.HelloService # interface name -``` - -## 2. Default data reporting indicators - -After starting the above server locally, you can collect default data metrics at localhost:9091/custom-metrics-path, including gc, goroutine number, memory usage, etc. - -```yaml -# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles. -# TYPE go_gc_duration_seconds summary -go_gc_duration_seconds{quantile="0"} 3.0916e-05 -go_gc_duration_seconds{quantile="0.25"} 3.0916e-05 -go_gc_duration_seconds{quantile="0.5"} 3.1167e-05 -go_gc_duration_seconds{quantile="0.75"} 0.000164084 -go_gc_duration_seconds{quantile="1"} 0.000164084 -go_gc_duration_seconds_sum 0.000226167 -go_gc_duration_seconds_count 3 -# HELP go_goroutines Number of goroutines that currently exist. -# TYPE go_goroutines gauge -go_goroutines 25 -# HELP go_info Information about the Go environment. -# TYPE go_info gauge -go_info{version="go1.17.2"} 1 -# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use. -# TYPE go_memstats_alloc_bytes gauge -go_memstats_alloc_bytes 6.195808e+06 -# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed. -# TYPE go_memstats_alloc_bytes_total counter -go_memstats_alloc_bytes_total 9.482768e+06 -# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table. -# TYPE go_memstats_buck_hash_sys_bytes gauge -go_memstats_buck_hash_sys_bytes 1.449179e+06 -# HELP go_memstats_frees_total Total number of frees. -# TYPE go_memstats_frees_total counter -go_memstats_frees_total 29419 -# HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started. -# TYPE go_memstats_gc_cpu_fraction gauge -go_memstats_gc_cpu_fraction 0.022937924367975027 -# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata. -# TYPE go_memstats_gc_sys_bytes gauge -go_memstats_gc_sys_bytes 5.235864e+06 -# HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and still in use. -# TYPE go_memstats_heap_alloc_bytes gauge -go_memstats_heap_alloc_bytes 6.195808e+06 -# HELP go_memstats_heap_idle_bytes Number of heap bytes waiting to be used. -# TYPE go_memstats_heap_idle_bytes gauge -go_memstats_heap_idle_bytes 3.792896e+06 -# HELP go_memstats_heap_inuse_bytes Number of heap bytes that are in use. -# TYPE go_memstats_heap_inuse_bytes gauge -go_memstats_heap_inuse_bytes 8.036352e+06 -# HELP go_memstats_heap_objects Number of allocated objects. -# TYPE go_memstats_heap_objects gauge -go_memstats_heap_objects 16489 -# HELP go_memstats_heap_released_bytes Number of heap bytes released to OS. -# TYPE go_memstats_heap_released_bytes gauge -go_memstats_heap_released_bytes 3.416064e+06 -# HELP go_memstats_heap_sys_bytes Number of heap bytes obtained from system. -# TYPE go_memstats_heap_sys_bytes gauge -go_memstats_heap_sys_bytes 1.1829248e+07 -# HELP go_memstats_last_gc_time_seconds Number of seconds since 1970 of last garbage collection. -# TYPE go_memstats_last_gc_time_seconds gauge -go_memstats_last_gc_time_seconds 1.635778234064745e+09 -# HELP go_memstats_lookups_total Total number of pointer lookups. -# TYPE go_memstats_lookups_total counter -go_memstats_lookups_total 0 -# HELP go_memstats_mallocs_total Total number of mallocs. -# TYPE go_memstats_mallocs_total counter -go_memstats_mallocs_total 45908 -# HELP go_memstats_mcache_inuse_bytes Number of bytes in use by mcache structures. -# TYPE go_memstats_mcache_inuse_bytes gauge -go_memstats_mcache_inuse_bytes 9600 -# HELP go_memstats_mcache_sys_bytes Number of bytes used for mcache structures obtained from system. -# TYPE go_memstats_mcache_sys_bytes gauge -go_memstats_mcache_sys_bytes 16384 -# HELP go_memstats_mspan_inuse_bytes Number of bytes in use by mspan structures. -# TYPE go_memstats_mspan_inuse_bytes gauge -go_memstats_mspan_inuse_bytes 116144 -# HELP go_memstats_mspan_sys_bytes Number of bytes used for mspan structures obtained from system. -# TYPE go_memstats_mspan_sys_bytes gauge -go_memstats_mspan_sys_bytes 131072 -# HELP go_memstats_next_gc_bytes Number of heap bytes when next garbage collection will take place. -# TYPE go_memstats_next_gc_bytes gauge -go_memstats_next_gc_bytes 7.935184e+06 -# HELP go_memstats_other_sys_bytes Number of bytes used for other system allocations. -# TYPE go_memstats_other_sys_bytes gauge -go_memstats_other_sys_bytes 1.426069e+06 -# HELP go_memstats_stack_inuse_bytes Number of bytes in use by the stack allocator. -# TYPE go_memstats_stack_inuse_bytes gauge -go_memstats_stack_inuse_bytes 753664 -# HELP go_memstats_stack_sys_bytes Number of bytes obtained from system for stack allocator. -# TYPE go_memstats_stack_sys_bytes gauge -go_memstats_stack_sys_bytes 753664 -# HELP go_memstats_sys_bytes Number of bytes obtained from system. -# TYPE go_memstats_sys_bytes gauge -go_memstats_sys_bytes 2.084148e+07 -# HELP go_threads Number of OS threads created. -# TYPE go_threads gauge -go_threads 12 -``` - -## 3. Call indicator RT - -Start the client in the example. After several calls, you will find that the corresponding data indicators have been added, prefixed with the default namespace dubbo. - -```yaml -# HELP dubbo_provider_service_rt -# TYPE dubbo_provider_service_rt gauge -dubbo_provider_service_rt{group="dubbo-go", method="SayHello", service="com.apache.dubbo.HelloService", timeout="", version="3.0.0-rc3"} 127542 -``` - -You can see the request rt time corresponding to the interface name and method name. This part of the calling indicators is to be improved later. - -## 4. Manual data reporting - -The API can be called in the business code for manual data reporting. Supports Counter, Summary, Gauge types, and supports multiple labels. It can be collected after reporting. - -```go -import "dubbo.apache.org/dubbo-go/v3/metrics/prometheus" - -for { -// metrics refresh per second -time. Sleep(time. Second) -prometheus.IncSummary("test_summary", rand.Float64()) -prometheus.IncSummaryWithLabel("test_summary_with_label", rand.Float64(), map[string]string{ -"summarylabel1": "value1", // label and value for this summary -"summarylabel2": "value2", -}) - -prometheus. IncCounter("test_counter") -prometheus.IncCounterWithLabel("test_counter_with_label", map[string]string{ -"counterlabel1": "value1", // label and value for this counter -"counterlabel2": "value2", -}) - -prometheus. SetGauge("test_gauge", rand. Float64()) -prometheus.SetGaugeWithLabel("test_gauge_with_label", rand.Float64(), map[string]string{ -"gaugelabel1": "value1", -"gaugelabel2": "value2", -}) -} -``` - -After running for a period of time, the following user-defined indicators can be collected - -```yaml -# HELP dubbo_test_counter -# TYPE dubbo_test_counter counter -dubbo_test_counter 463 -# HELP dubbo_test_counter_with_label -# TYPE dubbo_test_counter_with_label counter -dubbo_test_counter_with_label{counterlabel1="value1", counterlabel2="value2"} 463 -# HELP dubbo_test_gauge -# TYPE dubbo_test_gauge gauge -dubbo_test_gauge 0.7402836247772934 -# HELP dubbo_test_gauge_with_label -# TYPE dubbo_test_gauge_with_label gauge -dubbo_test_gauge_with_label{gaugelabel1="value1", gaugelabel2="value2"} 0.8360973807546456 -# HELP dubbo_test_summary -# TYPE dubbo_test_summary summary -dubbo_test_summary_sum 228.1800106582441 -dubbo_test_summary_count 463 -# HELP dubbo_test_summary_with_label -# TYPE dubbo_test_summary_with_label summary -dubbo_test_summary_with_label{summarylabel1="value1",summarylabel2="value2",quantile="0.5"} 0.5174757569778469 -dubbo_test_summary_with_label{summarylabel1="value1",summarylabel2="value2",quantile="0.75"} 0.734268575017709 -dubbo_test_summary_with_label{summarylabel1="value1",summarylabel2="value2",quantile="0.9"} 0.9059918694279894 -dubbo_test_summary_with_label{summarylabel1="value1",summarylabel2="value2",quantile="0.98"} 0.9761803018478838 -dubbo_test_summary_with_label{summarylabel1="value1",summarylabel2="value2",quantile="0.99"} 0.9820270046489341 -dubbo_test_summary_with_label{summarylabel1="value1",summarylabel2="value2",quantile="0.999"} 0.9986025122460248 -dubbo_test_summary_with_label_sum{summarylabel1="value1",summarylabel2="value2"} 233.609026131067 -dubbo_test_summary_with_label_count{summarylabel1="value1",summarylabel2="value2"} 463 -``` diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/promethus/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/promethus/_index.md deleted file mode 100644 index dfd6e615851c..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/promethus/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Data Reporting Promethus Tutorial" -weight: 2 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/rpc_metrics.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/rpc_metrics.md deleted file mode 100644 index 2cca56431f69..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/monitor/rpc_metrics.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: View monitoring information of RPC calls -type: docs -weight: 1 ---- - -## 1. Preparations - -- dubbo-go cli tools and dependent tools have been installed -- Create a new demo application - -## 2. Modify the client logic and initiate calls repeatedly - -go-client/cmd/client.go - -```go -func main() { -config. SetConsumerService(grpcGreeterImpl) -if err := config.Load(); err != nil { -panic(err) -} - -logger.Info("start to test dubbo") -req := &api.HelloRequest{ -Name: "Laurence", -} -for{ // repeat the call -reply, err := grpcGreeterImpl.SayHello(context.Background(), req) -if err != nil { -logger. Error(err) -} -logger.Infof("client response result: %v\n", reply) -} -} -``` - -## 3. View request RT information - -Start the server and client service applications successively. View localhost:9090/metrics in the browser, search for "dubbo", and you can view the request delay of the exposed interface on the server, in ns. - -``` -$ curl localhost:9090/metrics | grep dubbo - -# HELP dubbo_provider_service_rt -# TYPE dubbo_provider_service_rt gauge -dubbo_provider_service_rt{group="",method="SayHello",service="api.Greeter",timeout="",version="3.0.0"} 41084 -``` - -It can be seen that the latest request rt is 41084 ns. \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/_index.md deleted file mode 100644 index 1a9ce98e193b..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Service Mesh" -weight: 5 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/deploy.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/deploy.md deleted file mode 100644 index 15297a23d899..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/deploy.md +++ /dev/null @@ -1,426 +0,0 @@ ---- -title: Deploy Dubbo-go application in Istio environment -type: docs -weight: 2 ---- - -In this chapter, we will use the application template to quickly create a set of Dubbo-go Server and Client applications and deploy them in the Istio cluster; observe, debug and verify that service discovery and invocation are successful. - -## 1. Preparations - -- The dubbo-go cli tool and dependent tools have been installed, grpc_cli (for local debugging). -- The docker, helm, and kubectl environments have been installed. (arm machines need to support docker buildx) -- [Task [istio environment deployment]](../istio/) completed - -## 2. Develop server-side Dubbo-go application - -### 2.1 Use dubbogo-cli to create a project template - -```plain -$ mkdir mesh-app-server -$ cd mesh-app-server -$ dubbogo-cli newApp . -$ tree . -. -├── Makefile -├── api -│ └── api.proto -├──build -│ └── Dockerfile -├── chart -│ ├── app -│ │ ├── Chart.yaml -│ │ ├── templates -│ │ │ ├── _helpers.tpl -│ │ │ ├── deployment.yaml -│ │ │ ├── service.yaml -│ │ │ └── serviceaccount.yaml -│ │ └── values.yaml -│ └── nacos_env -│ ├── Chart.yaml -│ ├── templates -│ │ ├── _helpers.tpl -│ │ ├── deployment.yaml -│ │ └── service.yaml -│ └── values.yaml -├── cmd -│ └── app.go -├── conf -│ └── dubbogo.yaml -├── go.mod -├── go.sum -└── pkg - └── service - └── service.go -``` - -The generated project includes several directories: - -- api: place interface files: proto file and generated pb.go file -- build: place build related files -- Chart: place the chart warehouse for publishing, the basic environment chart warehouse: nacos, mesh (under development) -- cmd: program entry -- conf: framework configuration -- pkg/service: RPC service implementation -- Makefile: - -- - Mirror, Helm installation name: - -- - ``` - IMAGE = $(your_repo)/$(namespace)/$(image_name) - TAG = 1.0.0 - HELM_INSTALL_NAME = dubbo-go-app - ``` - -- - Provide scripts such as: - -- - - make build # Package the image and push it -- make buildx-publish # The arm architecture locally packs the amd64 image and pushes it, relying on buildx -- make deploy # Publish the application through helm -- make remove # Delete the published helm application -- make proto-gen # generate pb.go file under api - -... - -### 2.2 Develop and deploy Dubbo-go applications: - -#### Developing Applications - -- compile interface - - Developers need to modify the proto file, and the default interface can be used directly in this task. - - ```bash - $ make proto-gen - protoc --go_out=./api --go-triple_out=./api ./api/api.proto - ``` - -- pull dependencies - - ```bash - $ go get dubbo.apache.org/dubbo-go/v3@3.0 - $ make tidy - go mod tidy - ``` - -- Write business logic - - Modify pkg/service/service.go to implement the function, and the version displayed in the returned string is v1.0.0 - - ```go - func (s *GreeterServerImpl) SayHello(ctx context.Context, in *api.HelloRequest) (*api.User, error) { - return &api.User{Name: "Hello " + in.Name, Id: "v1.0.0"}, nil - } - ``` - -- Modify the following configuration fields to use the xds protocol as the registration center - - conf/dubbogo.yaml - - ```yaml - dubbo: - registries: - xds: - protocol: xds - address: istiod.istio-system.svc.cluster.local:15010 - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GreeterServerImpl: - interface: "" # read from stub - - ``` - - At this point, the application development is complete. - -#### Configure build and deployment parameters - -- Specify the image to be built: - - Modify the following fields in the Makefile to specify the address and version of the image to be built. - - Specify the name that needs to be installed through helm. - - ``` - IMAGE = xxx/dubbo-go-server - TAG = 1.0.0 - HELM_INSTALL_NAME = dubbo-go-server-v1 - ``` - -- Specify the application and image to be deployed: - - Modify the following fields in chart/app/Chart.yaml, and specify the current application name as `dubbo-go-server`. When deploying, a service named dubbo-go-server will be created and associated with all versions of the current application. - - ```yaml - apiVersion: v1 - name: dubbo-go-server - description: dubbo-go-server - ``` - - Modify the following fields in chart/app/values.yaml, and specify the image to be deployed and the currently developed application version dubbogoAppVersion as v1. - - The deployed image needs to be consistent with the image built above. The current application version is used for mesh traffic rule control. - - ```yaml - image: - repository: xxx/dubbo-go-server - pullPolicy: Always - tag: "1.0.0" - - # Dubbo-go-mesh version control labels - version: - labels: - dubbogoAppVersion: v1 - ``` - - At this point, the build parameters and release parameters have been specified, ready to build and deploy. - -#### Use templates to build and deploy Dubbo-go applications - -- Build and push images - - `$ make build` (locally for amd64 machines) - - or - - `$ make buildx-publish` (Local is arm64 machine, depends on docker buildx command) - -- Publish the Dubbo-go application to the cluster - - ```bash - $ make deploy - helm install dubbo-go-server-v1 ./chart/app - NAME: dubbo-go-server-v1 - LAST DEPLOYED: Thu Apr 7 11:19:42 2022 - NAMESPACE: default - STATUS: deployed - REVISION: 1 - TEST SUITE: None - $ helm list - NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION - dubbo-go-server-v1 default 1 2022-04-07 11:19:42.350553 +0800 CST deployed dubbo-go-server-0.0.1 1.16.0 - ``` - - It can be seen that the deployment through helm is successful - - - -### 2.3 Verify application - -#### View resource deployment - -View the deployed deployment, the version is v1. - -```bash -$ kubectl get deployment -NAME READY UP-TO-DATE AVAILABLE AGE -dubbo-go-server-v1 1/1 1 1 26s -``` - -View the deployed service. - -```bash -$ kubectl get svc -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -dubbo-go-server ClusterIP 192.168.216.253 20000/TCP 70s -``` - -#### (*Optional) Debug the deployed Dubbo-go application locally - -Use kubectl port-forward Dubbo-go to apply locally - -```bash -$ kubectl port-forward svc/dubbo-go-server 20000 -Forwarding from 127.0.0.1:20000 -> 20000 -Forwarding from [::1]:20000 -> 20000 -``` - -Use grpc_cli to debug applications in the cluster, refer to the task [[Use grpc_cli to debug Dubbo-go applications]](/en/docs3-v2/golang-sdk/tutorial/debugging/grpc_cli/) - -```bash -$ grpc_cli ls localhost:20000 -l -filename: api/api.proto -package: api; -service Greeter { - rpc SayHello(api.HelloRequest) returns (api.User) {} - rpc SayHelloStream(stream api.HelloRequest) returns (stream api.User) {} -} -``` - -Use grpc_cli to initiate a call to test the interface - -```bash -$ grpc_cli call localhost:20000 SayHello "name: 'laurence'" -connecting to localhost:20000 -name: "Hello Laurence" -id: "v1.0.0" -Received trailing metadata from server: -accept-encoding: identity, gzip -grpc-accept-encoding : identity,deflate,gzip -Rpc succeeded with OK status -``` - -So far, we have successfully developed an application and deployed it in the istio cluster. - -## 3. Develop client-side Dubbo-go application - -### 3.1 Use dubbogo-cli to create another project template - -```bash -$ dubbogo-cli newApp . -``` - -### 3.2 Develop and deploy client Dubbo-go applications: - -#### Write business logic - -- Modify the main method of cmd/app.go to initiate a call to the downstream interface every second - -```go -func main() { -client := &api. GreeterClientImpl{} -config. SetConsumerService(client) -if err := config.Load(); err != nil { -panic(err) -} -request := &api.HelloRequest{ -Name: "Laurence", -} - -for { -if rsp, err := client.SayHello(context.Background(), request); err != nil{ -logger.Errorf("call server error = %s", err) -}else{ -logger.Infof("call server response = %+v", rsp) -} -time. Sleep(time. Second) -} -} -``` - -- Modify the following configuration file, use the xds protocol as the registration center, and load the client service named GreeterClientImpl. - - conf/dubbogo.yaml - - ```yaml - dubbo: - registries: - xds: - protocol: xds - address: istiod.istio-system.svc.cluster.local:15010 - consumer: - references: - GreeterClientImpl: - protocol: tri - interface: "" # read from stub - ``` - - At this point, the application development is complete. - -#### Configure build and deployment parameters - -- Specify the image to be built: - - Modify the following fields in the Makefile to specify the address and version of the image to be built. - - Specify the name that needs to be installed through helm. - - ``` - IMAGE=xxx/dubbo-go-client - TAG = 1.0.0 - HELM_INSTALL_NAME = dubbo-go-client - ``` - -- Specify the application and image to be deployed: - - Modify the following fields in chart/app/Chart.yaml, and specify the current application name as `dubbo-go-client`. When deploying, a service named dubbo-go-client will be created and associated with all versions of the current application. For a client-only application, you don’t need to create a sevice, and it can be modified by the developer in the template. In this tutorial, we create it by default. - - ```yaml - apiVersion: v1 - name: dubbo-go-client - description: dubbo-go-client - ``` - - Modify the following fields in chart/app/values.yaml, and specify the image to be deployed and the currently developed application version dubbogoAppVersion as v1. - - The deployed image needs to be consistent with the image built above. The current application version is used for mesh traffic rule control. - - ```yaml - image: - repository: xxx/dubbo-go-client - pullPolicy: Always - tag: "1.0.0" - - # Dubbo-go-mesh version control labels - version: - labels: - dubbogoAppVersion: v1 - ``` - - At this point, the build parameters and release parameters have been specified, ready to build and deploy. - -#### Use templates to build and deploy Dubbo-go applications - -- Build and push images - - `$ make build` (locally for amd64 machines) - - or - - `$ make buildx-publish` (Local is arm64 machine, depends on docker buildx command) - -- Publish the Dubbo-go Client application to the cluster - - ```bash - $ make deploy - helm install dubbo-go-client ./chart/app - NAME: dubbo-go-client - LAST DEPLOYED: Thu Apr 7 11:49:55 2022 - NAMESPACE: default - STATUS: deployed - REVISION: 1 - TEST SUITE: None - $ helm list - NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION - dubbo-go-client default 1 2022-04-07 11:49:55.517898 +0800 CST deployed dubbo-go-client-0.0.1 1.16.0 - dubbo-go-server-v1 default 1 2022-04-07 11:23:18.397658 +0800 CST deployed dubbo-go-server-0.0.1 1.16.0 - ``` - - It can be seen that the deployment through helm is successful, and there are two applications, Client and Server, in the cluster. - -### 3.3 Verify application - -#### View resource deployment - -View the deployed client and server two deployments. - -```bash -$ kubectl get deployment -NAME READY UP-TO-DATE AVAILABLE AGE -dubbo-go-client-v1 1/1 1 1 22m -dubbo-go-server-v1 1/1 1 1 49m -``` - -Check the client call log - -```bash -$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs -... -2022-04-07T04:13:55.777Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T04:13:56.778Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T04:13:57.779Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T04:13:58.781Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T04:13:59.782Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T04:14:00.784Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T04:14:01.785Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -``` - -The verification call was successful - -## 4. Summary - -The application template provided by dubbogo-cli can conveniently support developers to build, push, and deploy images. - -In the Istio environment, the server application registers its own service information on Isito, and the client monitors the xds resource and queries the istio debug port for interface-level service discovery. Developers don't need to care about concepts such as service name, host name, and cluster name. They only need to introduce interfaces and initiate calls. \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/istio.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/istio.md deleted file mode 100644 index c83a3e2c9d73..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/istio.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: Deploy the Istio environment -type: docs -weight: 1 ---- - -## 1. Preparations - -- The docker, helm, and kubectl environments have been installed. -- dubbo-go cli tools and dependent tools have been installed - -## 2. Deploy the Istio environment - -1. Use helm to install istio base CRD and istiod components. You can also refer to [Istio Documentation](https://istio.io/) to install using istioctl. - -```bash -$ helm repo add istio https://istio-release.storage.googleapis.com/charts -$ kubectl create namespace istio-system -$ helm install istio-base istio/base -n istio-system -$ helm install istiod istio/istiod --namespace istio-system -``` - -2. Delete istio horizontal expansion resource - - *Currently dubbo-go relies on a single istiod instance for service discovery. - -```bash -$ kubectl delete hpa istiod -n istio-system -``` - -After the installation is complete, you can see an istiod pod running normally under the istio-system namespace. \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/_index.md deleted file mode 100644 index d5d74b34eecf..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Use Pixiu gateway to access Ingress traffic" -weight: 4 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/http_triple.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/http_triple.md deleted file mode 100644 index 90f92598019a..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/http_triple.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: Access Ingress Traffic -type: docs -weight: 1 ---- - -## 1. Preparations - --kubectl -- A k8s cluster with kubeconfig configured - -## 2. Use the HTTP protocol to call the Triple application through the gateway - -The Dubbo-go-pixiu gateway supports calling GO/Java Dubbo clusters. In the Dubbo-go 3.0 scenario, we can use the Pixiu gateway to request the Pixiu gateway with the HTTP protocol outside the cluster, perform protocol conversion at the gateway layer, and further call the Dubbo-go service in the cluster. - -![image.png](/imgs/docs3-v2/golang-sdk/tasks/pixiu/http_triple/triple-pixiu.png) - -The path for users to call Dubbo-go service is http://$(app_name)/$(service_name)/$(method). - -For example, a proto file has the following definition: - -```protobuf -package org.apache.dubbo.quickstart.samples; - -service UserProvider { - rpc SayHello (HelloRequest) returns (User) {} -} - -message HelloRequest { - string name = 1; -} -``` - -And configure the application name in dubbogo.yml when the dubbo-go service is started: my-dubbogo-app: - -```yaml -dubbo: - application: - name: my-dubbogo-app -``` - -The pixiu gateway can resolve the route whose path is my-dubbogo-app/org.apache.dubbo.quickstart.samples.UserProvider/SayHello and forward it to the corresponding service. The body from the external HTTP request is a json serialized request parameter, such as {"name":"test"}. - -We currently recommend using Nacos as the registry. - -Users can deploy our demo in their own clusters. It is better for the cluster to have the ability to expose lb type services, so that the services in the cluster can be accessed from the public network, and you can also make requests directly in the cluster. - -For your cluster, execute: - -```bash -$ kubectl apply -f https://raw.githubusercontent.com/dubbogo/triple-pixiu-demo/master/deploy/pixiu-triple-demo.yml -``` - -The following resources will be created under the dubbogo-triple-nacos namespace, including three triple-servers, one pixiu gateway, and one nacos server. And expose the service to the public network through Servcie. - -```bash -namespace/dubbogo-triple-nacos created -service/dubbo-go-nacos created -deployment.apps/dubbogo-nacos-deployment created -deployment.apps/pixiu created -deployment.apps/server created -service/pixiu created -``` - -Obtain pixiu public network ip and call it - -```pgsql -$ kubectl get svc -n dubbogo-triple-nacos -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -dubbo-go-nacos ClusterIP 192.168.123.204 8848/TCP 32s -pixiu LoadBalancer 192.168.156.175 30.XXX.XXX.XX 8881:30173/TCP 32s -``` - -Call the demo service through curl and get the response result. - -```bash -$ curl -X POST -d '{"name":"laurence"}' http://30.XXX.XXX.XX:8881/dubbogoDemoServer/org.apache.dubbo.laurence.samples.UserProvider/SayHello -{"name":"Hello Laurence","id":"12345","age":21} -``` \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/pixiu-nacos-triple.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/pixiu-nacos-triple.md deleted file mode 100644 index aa7ce2ca70b9..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/pixiu/pixiu-nacos-triple.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: Use Pixiu to expose Dubbo-go service -weight: 9 -type: docs ---- - -The Dubbo-go-pixiu gateway supports calling GO/Java Dubbo clusters. In the Dubbo-go 3.0 scenario, we can use the Pixiu gateway to request the Pixiu gateway with the HTTP protocol outside the cluster, perform protocol conversion at the gateway layer, and further call the Dubbo-go service in the cluster. - -![img](/imgs/docs3-v2/golang-sdk/samples/pixiu-nacos-triple/triple-pixiu.png) - -The path for the user to call the Dubbo-go service is http://$(app_name)/$(service_name)/$(method) - -For example, a proto file has the following definition: - -```protobuf -package org.apache.dubbo.quickstart.samples; - -service UserProvider { - rpc SayHello (HelloRequest) returns (User) {} -} - -message HelloRequest { - string name = 1; -} -``` - -And configure the application name in dubbogo.yml when the dubbo-go service is started: my-dubbogo-app: - -```yaml -dubbo: -application: - name: my-dubbogo-app -``` - -The pixiu gateway can resolve the route whose path is http://my-dubbogo-app/org.apache.dubbo.quickstart.samples.UserProvider/SayHello and forward it to the corresponding service. The body from the external HTTP request is a json serialized request parameter, such as {"name":"test"}. - -We currently recommend using Nacos as the registry. - -Users can deploy our demo in their own clusters. It is better for the cluster to have the ability to expose lb type services, so that the services in the cluster can be accessed from the public network, and you can also make requests directly in the cluster. For your cluster, execute: - -```bash -$ kubectl apply -f https://raw.githubusercontent.com/dubbogo/triple-pixiu-demo/master/deploy/pixiu-triple-demo.yml -``` - -The following resources will be created under the dubbogo-triple-nacos namespace, including three triple-servers, one pixiu gateway, and one nacos server. And expose the service to the public network through Servcie. - -```plain -namespace/dubbogo-triple-nacos created -service/dubbo-go-nacos created -deployment.apps/dubbogo-nacos-deployment created -deployment.apps/pixiu created -deployment.apps/server created -service/pixiu created -``` - -Obtain pixiu public network ip and call it - -```plain -$ kubectl get svc -n dubbogo-triple-nacos -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -dubbo-go-nacos ClusterIP 192.168.123.204 8848/TCP 32s -pixiu LoadBalancer 192.168.156.175 30.XXX.XXX.XX 8881:30173/TCP 32s -``` - -Call the demo service through curl and get the response result. - -```bash -$ curl -X POST -d '{"name":"laurence"}' http://30.XXX.XXX.XX:8881/dubbogoDemoServer/org.apache.dubbo.laurence.samples.UserProvider/SayHello -{"name":"Hello Laurence","id":"12345","age":21} -``` \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/proxyless_service_mesh.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/proxyless_service_mesh.md deleted file mode 100644 index 2a742508b189..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/proxyless_service_mesh.md +++ /dev/null @@ -1,107 +0,0 @@ ---- -type: docs -title: Proxyless Service Mesh -keywords: proxyless service mesh ---- - -## 1. What is Proxyless Service-Mesh (No Proxy Service Mesh) ? - -### 1.1 Brief Analysis of Service Mesh - -Istio is the most popular open source service mesh today. It consists of a control plane and a data plane. Its architecture is as follows. The picture is taken from [istio official website](https://istio.io/) - -![After using Istio](/imgs/docs3-v2/golang-sdk/concept/mesh/proxyless_service_mesh/service-mesh.svg) - -The control plane located in the lower half of the figure is responsible for the delivery of resources such as configuration, service information, and certificates. The data plane located in the upper part pays attention to the communication traffic between services; the traditional service grid intercepts all business network traffic through proxy, and the proxy needs to perceive the configuration resources issued by the control plane, so as to control the direction of network traffic as required . - -In the Istiod environment, its control plane is a process called istiod and the network proxy is envoy. istiod obtains service information by monitoring K8S resources such as Service and Endpoint, and sends these resources to the network agent on the data plane through the XDS protocol. Envoy is an independent process that runs with the business application Pod in the form of a sidecar (sidecar). It shares the same host network with the application process and hijacks the network traffic of the business application by modifying the routing table. - -Service Mesh can solve many problems in microservice scenarios. With the expansion of cluster size and the growth of business complexity, container orchestration solutions based on native k8s will be difficult to cope with, and developers have to face huge service governance challenges. Service Mesh solves this problem very well. It encapsulates service governance requirements in the control plane and proxy, and business developers only need to focus on business logic. After the application is deployed, the operation and maintenance personnel only need to modify the configuration to implement functions such as fault recovery, load balancing, and gray release, which greatly improves the efficiency of R&D and iteration. - -Istio's sidecar accompanies the entire life cycle of the business application process through container injection, and is non-invasive to the business application, which solves the problems of business application migration, multi-language, and infrastructure coupling. But this also brings problems of high resource consumption and increased request delay. - -Service provides a good idea for service governance, decoupling infrastructure from business logic, so that application developers only need to focus on business. On the other hand, due to the disadvantages of sidecar, we can consider using sdk instead of sidecar to support the data plane. - -### 1.2 Proxyless Service-Mesh - -Agentless service grid is a new concept proposed in recent years. Open source communities such as isito, gRPC, and brpc have all explored and practiced in this direction. The agentless service grid framework is introduced by business applications in the form of SDK, and is responsible for communication and governance between services. The configuration from the control plane is directly sent to the service framework, and the service framework replaces the functions of the above sidecar. - -![img](/imgs/docs3-v2/golang-sdk/concept/mesh/proxyless_service_mesh/894c0e52-9d34-4490-b49b-24973ef4aabc.png) - -The main capabilities of the service framework (SDK) can be summarized as the following three points: - -1. Connect to the control plane and monitor configuration resources. -2. Docking applications, providing developers with a convenient interface. -3. Connect to the network and respond to traffic rules according to resource changes. - -### 1.3 Advantages and disadvantages of Proxyless - -advantage: - -- Performance: The network call in the agentless mode is a point-to-point direct communication, and the network delay will be much smaller than that in the agent mode. -- Stability: The proxyless mode is a single process, with a simple topology, easy debugging, and high stability. -- Framework integration: There are already many sdk-mode service frameworks on the market, and after switching to mesh, they have the ability to reuse frameworks -- Resource consumption: no sidecar, low resource consumption - -shortcoming: - -- Language binding: need to develop sdk in multiple languages -- Low portability: It is impossible to upgrade the infrastructure non-intrusively by switching the form of sidecar. - -Generally speaking, the Proxyless architecture is more suitable for use in production environments due to its high performance and high stability. - -## 2. Dubbo-go and Proxyless Service-Mesh - -### 2.1 Design of Dubbo-go in Proxyless Service-Mesh scene - -#### Service Registration Discovery - -Dubbo-go itself has scalable service registration and discovery capabilities, and we have adapted the implementation of the registration center for the service mesh scenario. Developers can register dubbo-go application information on the istiod control plane. The client application can query the registered interface data to complete the service discovery process. - -![img](/imgs/docs3-v2/golang-sdk/concept/mesh/proxyless_service_mesh/454d1e31-0be3-41fe-97ec-f52673ebf74f.png) - -1. Developers use the dubbogo-cli tool to create application templates and publish Deployment / Service to the cluster. -2. The server pulls the full amount of CDS and EDS, compares the local IP, and gets the host name of the current application. And register all the mappings from interface names to host names of this application on Istiod. -3. The client pulls the mapping from the full interface name to the host name from istiod and caches it locally. When a call needs to be made, the local cache is queried, the interface name is converted to a host name, and then pulled to the full endpoint corresponding to the current cluster through CDS and EDS. -4. All endpoints pass through Dubbo-go's built-in Mesh Router to filter out the final subset of endpoints and make requests according to the configured load balancing strategy. - -Developers only need to pay attention to the interface throughout the process, and do not need to care about the host name and port information at all. That is, the server developer only needs to implement the pb interface and expose it using the framework; the client developer only needs to introduce the pb interface and initiate a call directly. - -#### Traffic management - -Dubbo-go has routing capabilities, subscribes to routing configuration from istiod through the xds protocol client, and updates to local routing rules in real time, so as to realize service management. Dubbo-go is compatible with the traffic governance rules of the istio ecology. By configuring Virtual Service and Destination Rule, the marked traffic can be routed to a specified subset, and it can also be used more deeply in scenarios such as grayscale release and flow switching. - -#### Cloud Native Scaffolding - -dubbogo-cli is a sub-project of the Apache/dubbo-go ecosystem, which provides developers with convenient functions such as application template creation, tool installation, and interface debugging to improve user R&D efficiency. - -For details, please refer to [[dubbogo-cli tool]](/en/docs3-v2/golang-sdk/refer/use_dubbogo_cli/) - -## 3. Advantages of Dubbo-go-Mesh - -### 3.1 Interface-level service discovery - -The previous article introduced the advantages of discovery through interface-level service registration, that is, developers do not need to care about downstream host names and port numbers, but only need to introduce interface stubs, or implement interfaces, and start them through the framework. - -### 3.2 High Performance - -We deployed the istio environment in the k8s cluster, and tested the gRPC service call in sidecar mode and the dubbo-go application service call in Proxyless mode. It is found that proxyless is an order of magnitude less than sidecar mode in terms of request time consumption, that is, the performance is improved by about ten times. - -### 3.3 Cross-ecology - -Dubbo-go is a service framework that spans multiple ecosystems. - -- mesh ecology - - Developers can use Dubbo-go for application development while using the powerful capabilities provided by the istio ecosystem. - -- gRPC ecology - - - Dubbo-go supports interoperability with gRPC services, HTTP2 protocol stack. - - Dubbo-go uses pb serialization by default, high performance. - -- Dubbo Ecology - - - Multilingual advantage, can realize go-java application intercommunication. - - Compatible with pixiu gateway, convenient for service exposure and protocol conversion. - - Use Dubbo-go ecological components. diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/traffic_management.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/traffic_management.md deleted file mode 100644 index b98bf3a4b0b4..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/service-mesh/traffic_management.md +++ /dev/null @@ -1,416 +0,0 @@ ---- -title: traffic management -type: docs -weight: 3 ---- - -In this section, we will continue the previous task [[Deploy Dubbo-go application in Istio environment]](../deploy/). - -In the previous task, we deployed a set of Dubbo-go Server and Client applications in the cluster, and verified the success of service discovery and invocation. In this section, we will create a new version of the server-side application. By configuring VirtualService and DestinationRule, routing management and traffic transfer capabilities are realized - -## 1. Preparations - -- The dubbo-go cli tool and dependent tools have been installed, grpc_cli (for local debugging). -- The docker, helm, and kubectl environments have been installed. (arm machines need to support docker buildx) -- Task [[Deploy Dubbo-go application in Istio environment]](../deploy/) completed - -## 2. Develop multi-version Dubbo-go applications. - -### 2.1 Use dubbogo-cli to create another project template - -```bash -$ dubbogo-cli newApp . -``` - -### 2.2 Develop and deploy client Dubbo-go application v2: - -#### Write business logic - -- Modify the implementation method of package/service/service.go, and return the version number as v2.0.0 - -```go -func (s *GreeterServerImpl) SayHello(ctx context.Context, in *api.HelloRequest) (*api.User, error) { -return &api.User{Name: "Hello " + in.Name, Id: "v2.0.0"}, nil -} -``` - -- Modify the following configuration file, use the xds protocol as the registration center, and load the service structure named GreeterServerImpl. - - conf/dubbogo.yaml - - ```yaml - dubbo: - registries: - xds: - protocol: xds - address: istiod.istio-system.svc.cluster.local:15010 - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GreeterServerImpl: - interface: "" # read from stub - - ``` - - At this point, the application development is complete. - -#### Configure build and deployment parameters - -- Specify the image to be built: - - Modify the following fields in the Makefile, specify the address and version of the image to be built, and change the image tag to 2.0.0. - - Specify the name that needs to be installed through helm. - - ``` - IMAGE = xxx/dubbo-go-server - TAG = 2.0.0 - HELM_INSTALL_NAME = dubbo-go-server - ``` - -- Specify the application and image to be deployed: - - Modify the following fields in chart/app/Chart.yaml, and specify the current application name as `dubbo-go-server`. When we created the v1 version of the service, we already had the service of the application. The template will not be created during this deployment service. - - ```yaml - apiVersion: v1 - name: dubbo-go-server - description: dubbo-go-server - ``` - - Modify the following fields in chart/app/values.yaml, specify the image to be deployed as 2.0.0, and the currently developed application version dubbogoAppVersion as v2. - - The deployed image needs to be consistent with the image built above. The current application version is used for mesh traffic rule control. - - ```yaml - image: - repository: xxx/dubbo-go-server - pullPolicy: Always - tag: "2.0.0" - - # Dubbo-go-mesh version control labels - version: - labels: - dubbogoAppVersion: v2 - ``` - - At this point, the build parameters and release parameters have been specified, ready to build and deploy. - -#### Use templates to build and deploy Dubbo-go applications - -- Build and push images - - `$ make build` (locally for amd64 machines) - - or - - `$ make buildx-publish` (Local is arm64 machine, depends on docker buildx command) - -- Publish Dubbo-go Server v2 to the cluster - - ```bash - $ make deploy - NAME: dubbo-go-server-v2 - LAST DEPLOYED: Thu Apr 7 12:29:28 2022 - NAMESPACE: default - STATUS: deployed - REVISION: 1 - TEST SUITE: None - $ helm list - NAME NAMESPACE REVISION UPDATED STATUS CHART dubbo-go-client default 1 2022-04-07 11:49:55.517898 +0800 CST deployed dubbo-go-client-0.0.1 1.16.0 - dubbo-go-server-v1 default 1 2022-04-07 11:23:18.397658 +0800 CST deployed dubbo-go-server-0.0.1 1.16.0 - dubbo-go-server-v2 default 1 2022-04-07 12:29:28.497476 +0800 CST deployed dubbo-go-client-0.0.1 1.16.0 - ``` - - It can be seen that the deployment through helm is successful, and there is already a Client application and two versions of Server in the cluster. - -### 2.3 Verify application - -#### View resource deployment - -Looking at the deployed deployment, the server contains two versions. - -```bash -$ kubectl get deployment -NAME READY UP-TO-DATE AVAILABLE AGE -dubbo-go-client-v1 1/1 1 1 40m -dubbo-go-server-v2 1/1 1 1 77s -dubbo-go-server-v1 1/1 1 1 67m -``` - -View the deployed service. Two versions of the deployment share the same service. - -```bash -$ kubectl get svc -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -dubbo-go-client ClusterIP 192.168.8.176 20000/TCP 41m -dubbo-go-server ClusterIP 192.168.216.253 20000/TCP 67m -``` - -Check the Client application log to verify that the request is called to two versions of the application. - -```bash -$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs -... -2022-04-07T05:06:40.384Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0" -2022-04-07T05:06:41.386Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0" -2022-04-07T05:06:42.388Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:06:43.389Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0" -2022-04-07T05:06:44.390Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0" -2022-04-07T05:06:45.392Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:06:46.393Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:06:47.394Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:06:48.396Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0" -2022-04-07T05:06:49.397Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -``` - -So far, we have successfully developed and deployed multi-version applications. - -## 3. Configure request routing - -### 3.1 Configure target rules - -Execute the following command to create a target rule that subdivides dubbo-go-server into two subsets. v1 and v2 - -```bash -$ kubectl apply -f destinationrule.yaml -``` - -destinationrule.yaml content: - -```yaml -apiVersion: networking.istio.io/v1alpha3 -kind: DestinationRule -metadata: - name: dubbo-go-server -spec: - host: dubbo-go-server - subsets: - - name: v1 - labels: - dubbogoAppVersion: v1 # corresponds to the version label specified in chart/app/values.yaml in the application template - - name: v2 - labels: - dubbogoAppVersion: v2 -``` - -### 3.2 Apply Virtual Service - -Execute the following command to create a route that routes all traffic to the v1 application. - -```bash -$ kubectl apply -f virtualservice.yaml -``` - -virtualservice.yaml content - -```yaml -apiVersion: networking.istio.io/v1alpha3 -kind: VirtualService -metadata: - name: dubbo-go-server -spec: - hosts: - - dubbo-go-server - http: - - route: - -destination: - host: dubbo-go-server - subset: v1 -``` - - - -### 3.3 Verify that the routing takes effect - -All traffic will go to the v1 app. - -```bash -$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs -... -2022-04-07T05:40:44.353Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:40:45.354Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:40:46.356Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:40:47.357Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:40:48.359Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:40:49.361Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" -``` - - - -## 4. Routing based on user identity - -With the above foundation of multi-version application routing, we can implement flexible traffic management through some strategies. - -### 4.1 Add user identity for client application - -We hope that traffic with the user: admin identifier can experience the new v2 version of the application. - -Go back to the previously created dubbo-go-client project, modify the main function of cmd/app.go, and add the calling identifier: `user: admin`. - -```go -func main() { -client := &api. GreeterClientImpl{} -config. SetConsumerService(client) -if err := config.Load(); err != nil { -panic(err) -} -request := &api.HelloRequest{ -Name: "Laurence", -} - -for { -ctx := context. Background() -ctx = context.WithValue(ctx, constant.AttachmentKey, map[string]string{ -"user":"admin", // Use the context context to add identity to the call -}) - -if rsp, err := client.SayHello(ctx, request); err != nil{ -logger.Errorf("call server error = %s", err) -}else{ -logger.Infof("call server response = %+v", rsp) -} -time. Sleep(time. Second) -} -} -``` - -- Build and push mirrors, overwriting previous commits. You can also upgrade the released image version. - - `$ make build` (locally for amd64 machines) - - or - - `$ make buildx-publish` (Local is arm64 machine, depends on docker buildx command) - -- Remove dubbo-go-client application - - ``` - $ make remove - helm uninstall dubbo-go-client - release "dubbo-go-client" uninstalled - ``` - -- Republish the app. - - `$ make deploy` - - After publishing, the verification call is successful because of the previous routing configuration. All traffic goes to the v1 version. - - ```bash - $ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs - ... - 2022-04-07T05:40:44.353Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" - 2022-04-07T05:40:45.354Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" - 2022-04-07T05:40:46.356Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" - 2022-04-07T05:40:47.357Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" - 2022-04-07T05:40:48.359Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" - 2022-04-07T05:40:49.361Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0" - ``` - -### 4.2 Create a route based on user identity - -Execute the following command to modify/create a route that routes all traffic with the user: admin identifier in the request header to the v2 version. - -```bash -$ kubectl apply -f virtualservice.yaml -``` - -virtualservice.yaml content - -```yaml -apiVersion: networking.istio.io/v1alpha3 -kind: VirtualService -metadata: - name: dubbo-go-server -spec: - hosts: - - dubbo-go-server - http: - - match: - - headers: - user: - exact: admin - route: - -destination: - host: dubbo-go-server - subset: v2 - - route: - -destination: - host: dubbo-go-server - subset: v1 -``` - -### 4.3 Verify that the routing takes effect - -All traffic will go to the v2 app. - -```bash -$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs -... -2022-04-07T05:52:18.714Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" -2022-04-07T05:52:19.716Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" -2022-04-07T05:52:20.717Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" -2022-04-07T05:52:21.718Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" -2022-04-07T05:52:22.720Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" -2022-04-07T05:52:23.722Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" -2022-04-07T05:52:24.723Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" -``` - - - -## 5. Weight-based routing - -### 5.1 Create weight-based routing - -Continuing the above tasks, we execute the following commands to modify/create a route that imports 10% of the traffic into the new version of the application for grayscale testing. - -```bash -$ kubectl apply -f virtualservice.yaml -``` - -virtualservice.yaml content - -```yaml -apiVersion: networking.istio.io/v1alpha3 -kind: VirtualService -metadata: - name: dubbo-go-server -spec: - hosts: - - dubbo-go-server - http: - - route: - -destination: - host: dubbo-go-server - subset: v1 - weight: 90 - -destination: - host: dubbo-go-server - subset: v2 - weight: 10 -``` - -### 5.2 Verify that the routing takes effect - -A small amount of traffic will go to the v2 release. - -```bash -$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs -... -2022-04-07T05:55:52.035Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:55:53.036Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:55:54.037Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:55:55.039Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:55:56.041Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:55:57.043Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:55:58.045Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:55:59.047Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:56:00.049Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:56:01.050Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0" -2022-04-07T05:56:02.053Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" -2022-04-07T05:56:03.055Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0" -``` \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/_index.md deleted file mode 100644 index 7f1b2ca35326..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Full Link Tracking" -weight: 2 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/jaeger/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/jaeger/_index.md deleted file mode 100644 index 8b1ffc4045e0..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/jaeger/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Link Tracking Based on Jaeger" -weight: 1 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/opentelmentry/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/opentelmentry/_index.md deleted file mode 100644 index 920e135bfdde..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/opentelmentry/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Using the OpenTelmentry Protocol" -weight: 2 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/skywalking/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/skywalking/_index.md deleted file mode 100644 index 306c22b6a6cb..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/tracing/skywalking/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Skywalking-based Tracking" -weight: 3 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/traffic/_index.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/traffic/_index.md deleted file mode 100644 index 1ee42b0a75d4..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/traffic/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: docs -title: "Traffic Management" -weight: 3 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/traffic/graceful_shutdown.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/traffic/graceful_shutdown.md deleted file mode 100644 index 10f49d73a47b..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/traffic/graceful_shutdown.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -type: docs -title: Elegant online and offline -keywords: elegant online and offline -description: Elegant online and offline ---- - -# Gracefully log in and out - -## Introduction - -In the process of stable production, container scheduling is completely controlled by k8s, and microservice governance is completely maintained and managed by service framework or operation and maintenance personnel. In the case of releasing a new version or expanding or shrinking the capacity, the old container instance will be terminated and replaced with a new container instance. For an online production environment carrying high traffic, if the connection of this replacement process is unreasonable, the A large number of wrong requests are caused in a short period of time, triggering alarms and even affecting normal business. For larger manufacturers, the loss caused by problems in the release process will be huge. - -Therefore, the appeal of graceful online and offline is put forward. This requires that the service framework, on the basis of having stable service invocation capabilities and traditional service governance capabilities, should provide stable guarantees during the process of going online and offline, thereby reducing operation and maintenance costs and improving application stability. - -## Expected effect - -Ideally, the effect of graceful offline and offline is that in a distributed system carrying a large amount of traffic, all component instances can be expanded, reduced, and rolled over at will. In this case, it is necessary to ensure stable tps and rt, to ensure that no request errors are caused by the application going offline. - -## How to use - -The Dubbo-go app enables graceful log-off and offline by default. - -Related reading: [[Design and Practice of Dubbo-go Elegant Online and Offline]](https://developer.aliyun.com/article/860775) \ No newline at end of file diff --git a/content/en/docs3-v2/golang-sdk/tutorial/governance/traffic/mesh_router.md b/content/en/docs3-v2/golang-sdk/tutorial/governance/traffic/mesh_router.md deleted file mode 100644 index 86d06be18e55..000000000000 --- a/content/en/docs3-v2/golang-sdk/tutorial/governance/traffic/mesh_router.md +++ /dev/null @@ -1,144 +0,0 @@ ---- -title: routing rules -weight: 12 -type: docs ---- - -## Introduction to routing rules -["Microservice Mesh Routing Scheme Draft V2"](https://www.yuque.com/docs/share/c132d5db-0dcb-487f-8833-7c7732964bd4?# ) - -## Introduction - -Routing rules, in simple terms, are to send **specific request** traffic to **specific service provider** according to **specific conditions**. Thereby realizing the distribution of flow. - -In the definition of Dubbo3 unified routing rules, two resources in yaml format need to be provided: virtual service and destination rule. Its format is very similar to the routing rules defined by service mesh. -- virtual service - -Define the host, which is used to establish a relationship with the destination rule. \ -Define service matching rules\ -Define match matching rules\ -After matching a specific request, search and verify the target cluster, and use the fallback mechanism for empty cases. - --destination rule - -Define a specific cluster subset and the tags that the subset is adapted to. The tags are obtained from the url exposed on the provider side and try to match. - -## Provide capabilities -### Routing configuration based on configuration center - -For the sample example, see [Mesh Router](https://github.com/apache/dubbo-go-samples/tree/f7febed9d686cb940ea55d34b5baa567d7574a44/route/meshroute) - -#### 1. Routing rule file annotation - -The routing rules are only for the client. For the server, you only need to label specific parameters when the service is provided. - -##### 1.1 virtual-service - -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: {name: demo-route} -spec: - dubbo: - # Use a regular expression to match the service name, only a request that satisfies the service name can be routed. - # For this example, if the request does not satisfy the service name, the provider will not be found directly - # - services: - # - { regex: org.apache.dubbo.UserProvider* } - - route detail: - - match: - # Matching rules, if (sourceLabel) client url satisfies the parameter `trafficLabel: xxx`, the match can be successful - - sourceLabels: {trafficLabel: xxx} - name: xxx-project - route: # Once the above match rule is matched, the subset named isolation defined in dest_rule will be selected - - destination: {host: demo, subset: isolation} - - match: - - sourceLabels: {trafficLabel: testing-trunk} - name: testing-trunk - route: # Once the above match rule is matched, the subset named testing-trunk defined in dest_rule will be selected - - destination: {host: demo, subset: testing-trunk} - - name: testing # There is no match, the bottom-up logic, if the above-mentioned dissatisfaction is met, it will be matched. - route: - - destination: {host: demo, subset: testing} - services: - - {exact: com.apache.dubbo.sample.basic.IGreeter} - hosts: [demo] # Match the host in dest_rule.yml as demo -``` - -##### 1.2 destination-rule - -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: DestinationRule -metadata: { name: demo-route } -spec: - host: demo - subsets: - - labels: { env-sign: xxx, tag1: hello } - name: isolation - - labels: { env-sign: yyy } - name: testing-trunk - - labels: { env-sign: zzz } - name: testing - trafficPolicy: - loadBalancer: { simple: ROUND_ROBIN } -``` - -#### 2. Client and server routing parameter settings - -- client side - - dubbogo.yml - - Define configuration center - -```yaml - config-center: - protocol: zookeeper - address: 127.0.0.1:2181 - data-id: "dubbo-go-samples-configcenter-zookeeper-client" -``` - -Publish the configuration to the configuration center through the API in the code, or manually configure it in advance. - -```go -dynamicConfiguration, err := config.GetRootConfig().ConfigCenter.GetDynamicConfiguration() -if err != nil { - panic(err) -} - -// publish mesh route config -err = dynamicConfiguration. PublishConfig("dubbo.io. MESHAPPRULE", "dubbo", MeshRouteConf) -if err != nil { - return -} -``` - - - -server side - -```yaml -dubbo: - registries: - demoZK: - protocol: zookeeper - timeout: 3s - address: 127.0.0.1:2181 - protocols: - triple: - name: tri - port: 20000 - provider: - services: - GreeterProvider: - interface: com.apache.dubbo.sample.basic.IGreeter # must be compatible with grpc or dubbo-java - params: - env-sign: zzz # server label, corresponding to the testing in the destination Rule, that is, the bottom-up logic -``` - -#### 3. Run method - -Run this example directly using goland - - -After running, it can be observed that all client traffic is routed to the server. According to the source label, there is no virtualService hit, so it is routed to the bottom-up test. diff --git a/content/en/docs3-v2/java-sdk/_index.md b/content/en/docs3-v2/java-sdk/_index.md deleted file mode 100755 index 341bf2830b76..000000000000 --- a/content/en/docs3-v2/java-sdk/_index.md +++ /dev/null @@ -1,19 +0,0 @@ - ---- -type: docs -title: "Java" -weight: 10 -no_list: true -hide_summary: true -description: "Java SDK Manual" ---- - -- Quick start: - - [Spring Boot Quick Development Dubbo Service](quick-start/spring-boot/) - - [Configuration Reference Manual](reference-manual/config/) -- Advanced features: - - [Extended Filter, Router to intercept traffic](concepts-and-architecture/service-invocation/) -- Reference book: - - [Registry Configuration Guide](reference-manual/registry/) -- Upgrades and Compatibility: - - [3.0 Migration Guide](upgrades-and-compatibility/) diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/_index.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/_index.md deleted file mode 100755 index 75167223dfd7..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/_index.md +++ /dev/null @@ -1,11 +0,0 @@ - ---- -type: docs -title: "Advanced Features" -linkTitle: "Advanced Features" -weight: 4 -no_list: true -hide_summary: true -description: "The following is a list of all functions supported by Dubbo, browse directly on this page or view them by category on the left menu." ---- - diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/_index.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/_index.md deleted file mode 100755 index 0e1583a8a9b9..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/_index.md +++ /dev/null @@ -1,26 +0,0 @@ - ---- -type: docs -title: "Observability of Dubbo" -linkTitle: "Observability" -weight: 2 -no_list: true -hide_summary: true ---- - - - -# Observability of Dubbo -Observability is the ability to observe the internal state of a running system from the outside. It consists of three pillars of logging, metrics and tracing. -To gain insight into what's going on inside Dubbo, Dubbo Observability includes many additional features to help you monitor and manage your application as you push it to production. You can choose to use HTTP endpoints or JMX to manage and monitor the application. Auditing, health and metrics collection can also be automatically applied to applications. - - -Dubbo observability mainly manages the following latitudes: -- [meter](./meter/) -- [tracing](./tracing/) -- [logging](./logging/) -- [health information](./health-information/) -- [kubernetes probes](./kubernetes-probes/) -- [Document case](./doc/) - - diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/doc.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/doc.md deleted file mode 100644 index e38a22dc04e9..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/doc.md +++ /dev/null @@ -1,9 +0,0 @@ - ---- -type: docs -title: "Document case" -linkTitle: "Document case" -weight: 6 -no_list: true -hide_summary: true ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/health-information.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/health-information.md deleted file mode 100644 index 65fef7f4ae7b..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/health-information.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "Health Information" -linkTitle: "Health Information" -weight: 4 -no_list: true -hide_summary: true ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/kubernetes-probes.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/kubernetes-probes.md deleted file mode 100644 index 9a677e95711c..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/kubernetes-probes.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "Kubernetes Probes" -linkTitle: "Kubernetes Probes" -weight: 5 -no_list: true -hide_summary: true ---- diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/logging.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/logging.md deleted file mode 100644 index 6a9f0de8539f..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/logging.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "Logging" -linkTitle: "Logging" -weight: 3 -no_list: true -hide_summary: true ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/meter.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/meter.md deleted file mode 100644 index 44cd1ffb9f69..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/meter.md +++ /dev/null @@ -1,505 +0,0 @@ ---- -type: docs -title: "Meter" -linkTitle: "Meter" -weight: 1 -no_list: true -hide_summary: true ---- - -# overview - -## 1. Indicator access instructions - -## 2. Indicator system design -Dubbo's indicator system involves three parts in total, indicator collection, local aggregation, and indicator push -Indicator collection: Push the indicators that need to be monitored inside Dubbo to a unified Collector for storage -Local Aggregation: All indicators collected are basic indicators, and some quantile indicators need to be calculated through local aggregation -Indicator push: The collected and aggregated indicators are pushed to third-party servers in a certain way, currently only involving Prometheus -## 3. Structural Design -- Remove the original classes related to Metrics -- Create new modules dubbo-metrics/dubbo-metrics-api, dubbo-metrics/dubbo-metrics-prometheus, MetricsConfig as the configuration class of the module -- Use micrometer, use basic types in Collector to represent indicators, such as Long, Double, etc., and introduce micrometer in dubbo-metrics-api, and use micrometer to convert internal indicators - -## 4. data flow -![img.png](/imgs/docs3-v2/java-sdk/observability/dataflow.png) - - -## 5. Goals -The indicator interface will provide a MetricsService, which not only provides interface-level data of the flexible service, but also provides query methods for all indicators. The interface for querying method-level indicators can be declared as follows -```java -public interface MetricsService { - - /** - * Default {@link MetricsService} extension name. - */ - String DEFAULT_EXTENSION_NAME = "default"; - - /** - * The contract version of {@link MetricsService}, the future update must make sure compatible. - */ - String VERSION = "1.0.0"; - - /** - * Get metrics by prefixes - * - * @param categories categories - * @return metrics - key=MetricCategory value=MetricsEntityList - */ - Map> getMetricsByCategories(List categories); - - /** - * Get metrics by interface and prefixes - * - * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) - * @param categories categories - * @return metrics - key=MetricCategory value=MetricsEntityList - */ - Map> getMetricsByCategories(String serviceUniqueName, List categories); - - /** - * Get metrics by interface、method and prefixes - * - * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) - * @param methodName methodName - * @param parameterTypes method parameter types - * @param categories categories - * @return metrics - key=MetricCategory value=MetricsEntityList - */ - Map> getMetricsByCategories(String serviceUniqueName, String methodName, Class[] parameterTypes, List categories); -} -``` - -Among them, MetricsCategory is designed as follows: -```java -public enum MetricsCategory { - RT, - QPS, - REQUESTS, -} -``` -MetricsEntity is designed as follows -```java -public class MetricsEntity { - private String name; - private Map tags; - private MetricsCategory category; - private Object value; -} -``` - -# metrics collection -## 1. Embedding position -The Dubbo architecture diagram is as follows -![img.png](/imgs/docs3-v2/java-sdk/observability/dubbo.png) - -Add a layer of MetricsFilter to the provider, rewrite the invoke method, embed the call link to collect metrics, and use try-catch-finally for processing. The core code is as follows -```java -@Activate(group = PROVIDER, order = -1) -public class MetricsFilter implements Filter, ScopeModelAware { - @Override - public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - collector.increaseTotalRequests(interfaceName, methodName, group, version); - collector.increaseProcessingRequests(interfaceName, methodName, group, version); - Long startTime = System.currentTimeMillis(); - try { - Result invoke = invoker.invoke(invocation); - collector.increaseSucceedRequests(interfaceName, methodName, group, version); - return invoke; - } catch (RpcException e) { - collector.increaseFailedRequests(interfaceName, methodName, group, version); - throw e; - } finally { - Long endTime = System.currentTimeMillis(); - Long rt = endTime - startTime; - collector.addRT(interfaceName, methodName, group, version, rt); - collector.decreaseProcessingRequests(interfaceName, methodName, group, version); - } - } -} - -``` - -## 2. Indicator identification -Use the following five attributes as the isolation level to distinguish and identify different methods, which are also the keys of each ConcurrentHashMap -```java -public class MethodMetric { - private String applicationName; - private String interfaceName; - private String methodName; - private String group; - private String version; -} -``` - -## 3. Basic indicators -Metrics store all metrics data through MetricsCollector under the common module -```java -public class DefaultMetricsCollector implements MetricsCollector { - private Boolean collectEnabled = false; - private final List listeners = new ArrayList<>(); - private final ApplicationModel applicationModel; - private final String applicationName; - - private final Map totalRequests = new ConcurrentHashMap<>(); - private final Map succeedRequests = new ConcurrentHashMap<>(); - private final Map failedRequests = new ConcurrentHashMap<>(); - private final Map processingRequests = new ConcurrentHashMap<>(); - - private final Map lastRT = new ConcurrentHashMap<>(); - private final Map minRT = new ConcurrentHashMap<>(); - private final Map maxRT = new ConcurrentHashMap<>(); - private final Map avgRT = new ConcurrentHashMap<>(); - private final Map totalRT = new ConcurrentHashMap<>(); - private final Map rtCount = new ConcurrentHashMap<>(); - } -``` - -# local aggregation -Local aggregation refers to the process of obtaining quantile indicators by calculating some simple indicators -## 1. Parameter Design -When collecting indicators, only the basic indicators are collected by default, and some stand-alone aggregation indicators need to enable service flexibility or start a new thread calculation after local aggregation. If service flexibility is enabled here, local aggregation is enabled by default - -### 1.1 How to enable local aggregation -```xml - - - -``` -### 1.2 Index Aggregation Parameters -```xml - - - -``` - -## 2. Specific indicators - -Four key metrics to monitor. They call it the "four golden signals": Latency, Traffic, Errors, and Saturation. -Dubbo mainly includes the following monitoring indicators: - -| | infrastructure | business monitoring | -| :------- |:------------------------------------------|:---------------------------------------------------------| -| Latency | IO wait; RPC Latency; | Interface, average service time, TP90, TP99, TP999, etc. | -| Traffic | network and disk IO; | QPS at the service level | -| Errors | Downtime; disk (bad disk or file system error); process or port hang; network packet loss; | Error log; business status code, error code trend; | -| Saturation | System resource utilization: CPU, memory, disk, network, etc.; Saturation: number of waiting threads, queue backlog length; | This mainly includes JVM, thread pool, etc. | - - -- qps: Get dynamic qps based on sliding window -- rt: Get dynamic rt based on sliding window -- Number of failed requests: Get the number of failed requests in the latest time based on the sliding window -- Number of successful requests: Get the number of successful requests in the latest time based on the sliding window -- The number of processing requests: Add Filter simple statistics before and after -- Specific indicators rely on sliding windows, and additionally use AggregateMetricsCollector to collect - -The relevant indicators output to Prometheus can be referred to as follows: -``` -# HELP jvm_gc_live_data_size_bytes Size of long-lived heap memory pool after reclamation -# TYPE jvm_gc_live_data_size_bytes gauge -jvm_gc_live_data_size_bytes 1.6086528E7 -# HELP requests_succeed_aggregate Aggregated Succeed Requests -# TYPE requests_succeed_aggregate gauge -requests_succeed_aggregate{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 39.0 -# HELP jvm_buffer_memory_used_bytes An estimate of the memory that the Java virtual machine is using for this buffer pool -# TYPE jvm_buffer_memory_used_bytes gauge -jvm_buffer_memory_used_bytes{id="direct",} 1.679975E7 -jvm_buffer_memory_used_bytes{id="mapped",} 0.0 -# HELP jvm_gc_memory_allocated_bytes_total Incremented for an increase in the size of the (young) heap memory pool after one GC to before the next -# TYPE jvm_gc_memory_allocated_bytes_total counter -jvm_gc_memory_allocated_bytes_total 2.9884416E9 -# HELP requests_total_aggregate Aggregated Total Requests -# TYPE requests_total_aggregate gauge -requests_total_aggregate{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 39.0 -# HELP system_load_average_1m The sum of the number of runnable entities queued to available processors and the number of runnable entities running on the available processors averaged over a period of time -# TYPE system_load_average_1m gauge -system_load_average_1m 0.0 -# HELP system_cpu_usage The "recent cpu usage" for the whole system -# TYPE system_cpu_usage gauge -system_cpu_usage 0.015802269043760128 -# HELP jvm_threads_peak_threads The peak live thread count since the Java virtual machine started or peak was reset -# TYPE jvm_threads_peak_threads gauge -jvm_threads_peak_threads 40.0 -# HELP requests_processing Processing Requests -# TYPE requests_processing gauge -requests_processing{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 -# HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management -# TYPE jvm_memory_max_bytes gauge -jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'profiled nmethods'",} 1.22912768E8 -jvm_memory_max_bytes{area="heap",id="G1 Survivor Space",} -1.0 -jvm_memory_max_bytes{area="heap",id="G1 Old Gen",} 9.52107008E8 -jvm_memory_max_bytes{area="nonheap",id="Metaspace",} -1.0 -jvm_memory_max_bytes{area="heap",id="G1 Eden Space",} -1.0 -jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 5828608.0 -jvm_memory_max_bytes{area="nonheap",id="Compressed Class Space",} 1.073741824E9 -jvm_memory_max_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 1.22916864E8 -# HELP jvm_threads_states_threads The current number of threads having BLOCKED state -# TYPE jvm_threads_states_threads gauge -jvm_threads_states_threads{state="blocked",} 0.0 -jvm_threads_states_threads{state="runnable",} 10.0 -jvm_threads_states_threads{state="waiting",} 16.0 -jvm_threads_states_threads{state="timed-waiting",} 13.0 -jvm_threads_states_threads{state="new",} 0.0 -jvm_threads_states_threads{state="terminated",} 0.0 -# HELP jvm_buffer_total_capacity_bytes An estimate of the total capacity of the buffers in this pool -# TYPE jvm_buffer_total_capacity_bytes gauge -jvm_buffer_total_capacity_bytes{id="direct",} 1.6799749E7 -jvm_buffer_total_capacity_bytes{id="mapped",} 0.0 -# HELP rt_p99 Response Time P99 -# TYPE rt_p99 gauge -rt_p99{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 1.0 -# HELP jvm_memory_used_bytes The amount of used memory -# TYPE jvm_memory_used_bytes gauge -jvm_memory_used_bytes{area="heap",id="G1 Survivor Space",} 1048576.0 -jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'profiled nmethods'",} 1.462464E7 -jvm_memory_used_bytes{area="heap",id="G1 Old Gen",} 1.6098728E7 -jvm_memory_used_bytes{area="nonheap",id="Metaspace",} 4.0126952E7 -jvm_memory_used_bytes{area="heap",id="G1 Eden Space",} 8.2837504E7 -jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 1372032.0 -jvm_memory_used_bytes{area="nonheap",id="Compressed Class Space",} 4519248.0 -jvm_memory_used_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 5697408.0 -# HELP qps Query Per Seconds -# TYPE qps gauge -qps{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.3333333333333333 -# HELP rt_min Min Response Time -# TYPE rt_min gauge -rt_min{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 -# HELP jvm_buffer_count_buffers An estimate of the number of buffers in the pool -# TYPE jvm_buffer_count_buffers gauge -jvm_buffer_count_buffers{id="mapped",} 0.0 -jvm_buffer_count_buffers{id="direct",} 10.0 -# HELP system_cpu_count The number of processors available to the Java virtual machine -# TYPE system_cpu_count gauge -system_cpu_count 2.0 -# HELP jvm_classes_loaded_classes The number of classes that are currently loaded in the Java virtual machine -# TYPE jvm_classes_loaded_classes gauge -jvm_classes_loaded_classes 7325.0 -# HELP rt_total Total Response Time -# TYPE rt_total gauge -rt_total{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 2783.0 -# HELP rt_last Last Response Time -# TYPE rt_last gauge -rt_last{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 -# HELP jvm_gc_memory_promoted_bytes_total Count of positive increases in the size of the old generation memory pool before GC to after GC -# TYPE jvm_gc_memory_promoted_bytes_total counter -jvm_gc_memory_promoted_bytes_total 1.4450952E7 -# HELP jvm_gc_pause_seconds Time spent in GC pause -# TYPE jvm_gc_pause_seconds summary -jvm_gc_pause_seconds_count{action="end of minor GC",cause="Metadata GC Threshold",} 2.0 -jvm_gc_pause_seconds_sum{action="end of minor GC",cause="Metadata GC Threshold",} 0.026 -jvm_gc_pause_seconds_count{action="end of minor GC",cause="G1 Evacuation Pause",} 37.0 -jvm_gc_pause_seconds_sum{action="end of minor GC",cause="G1 Evacuation Pause",} 0.156 -# HELP jvm_gc_pause_seconds_max Time spent in GC pause -# TYPE jvm_gc_pause_seconds_max gauge -jvm_gc_pause_seconds_max{action="end of minor GC",cause="Metadata GC Threshold",} 0.0 -jvm_gc_pause_seconds_max{action="end of minor GC",cause="G1 Evacuation Pause",} 0.0 -# HELP rt_p95 Response Time P95 -# TYPE rt_p95 gauge -rt_p95{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 -# HELP requests_total Total Requests -# TYPE requests_total gauge -requests_total{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 27738.0 -# HELP process_cpu_usage The "recent cpu usage" for the Java Virtual Machine process -# TYPE process_cpu_usage gauge -process_cpu_usage 8.103727714748784E-4 -# HELP rt_max Max Response Time -# TYPE rt_max gauge -rt_max{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 4.0 -# HELP jvm_gc_max_data_size_bytes Max size of long-lived heap memory pool -# TYPE jvm_gc_max_data_size_bytes gauge -jvm_gc_max_data_size_bytes 9.52107008E8 -# HELP jvm_threads_live_threads The current number of live threads including both daemon and non-daemon threads -# TYPE jvm_threads_live_threads gauge -jvm_threads_live_threads 39.0 -# HELP jvm_threads_daemon_threads The current number of live daemon threads -# TYPE jvm_threads_daemon_threads gauge -jvm_threads_daemon_threads 36.0 -# HELP jvm_classes_unloaded_classes_total The total number of classes unloaded since the Java virtual machine has started execution -# TYPE jvm_classes_unloaded_classes_total counter -jvm_classes_unloaded_classes_total 0.0 -# HELP jvm_memory_committed_bytes The amount of memory in bytes that is committed for the Java virtual machine to use -# TYPE jvm_memory_committed_bytes gauge -jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'profiled nmethods'",} 1.4680064E7 -jvm_memory_committed_bytes{area="heap",id="G1 Survivor Space",} 1048576.0 -jvm_memory_committed_bytes{area="heap",id="G1 Old Gen",} 5.24288E7 -jvm_memory_committed_bytes{area="nonheap",id="Metaspace",} 4.1623552E7 -jvm_memory_committed_bytes{area="heap",id="G1 Eden Space",} 9.0177536E7 -jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'non-nmethods'",} 2555904.0 -jvm_memory_committed_bytes{area="nonheap",id="Compressed Class Space",} 5111808.0 -jvm_memory_committed_bytes{area="nonheap",id="CodeHeap 'non-profiled nmethods'",} 5701632.0 -# HELP requests_succeed Succeed Requests -# TYPE requests_succeed gauge -requests_succeed{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 27738.0 -# HELP rt_avg Average Response Time -# TYPE rt_avg gauge -rt_avg{application_name="metrics-provider",group="",hostname="iZ8lgm9icspkthZ",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="172.28.236.104",method="sayHello",version="",} 0.0 -``` - -## aggregate collector -```java -public class AggregateMetricsCollector implements MetricsCollector, MetricsListener { - private int bucketNum; - private int timeWindowSeconds; - - private final Map totalRequests = new ConcurrentHashMap<>(); - private final Map succeedRequests = new ConcurrentHashMap<>(); - private final Map failedRequests = new ConcurrentHashMap<>(); - private final Map qps = new ConcurrentHashMap<>(); - private final Map rt = new ConcurrentHashMap<>(); - - private final ApplicationModel applicationModel; - - private static final Integer DEFAULT_COMPRESSION = 100; - private static final Integer DEFAULT_BUCKET_NUM = 10; - private static final Integer DEFAULT_TIME_WINDOW_SECONDS = 120; - -//在构造函数中解析配置信息 - - public AggregateMetricsCollector(ApplicationModel applicationModel) { - this.applicationModel = applicationModel; - ConfigManager configManager = applicationModel.getApplicationConfigManager(); - MetricsConfig config = configManager.getMetrics().orElse(null); - if (config != null && config.getAggregation() != null && Boolean.TRUE.equals(config.getAggregation().getEnabled())) { - // only registered when aggregation is enabled. - registerListener(); - - AggregationConfig aggregation = config.getAggregation(); - this.bucketNum = aggregation.getBucketNum() == null ? DEFAULT_BUCKET_NUM : aggregation.getBucketNum(); - this.timeWindowSeconds = aggregation.getTimeWindowSeconds() == null ? DEFAULT_TIME_WINDOW_SECONDS : aggregation.getTimeWindowSeconds(); - } - } -} -``` - -If local aggregation is enabled, listeners are added through spring’s BeanFactory, and AggregateMetricsCollector is bound to DefaultMetricsCollector to implement a survivor-consumer model. DefaultMetricsCollector uses a list of listeners for easy expansion -```java -private void registerListener() { - applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).addListener(this); -} -``` - -## 3. Index Aggregation -sliding window -Suppose we initially have 6 buckets, and each window time is set to 2 minutes -Every time the index data is written, the data will be written into 6 buckets respectively, and a bucket will be moved every two minutes and the data in the original bucket will be cleared -When reading the indicator, read the bucket pointed to by the current current to achieve the effect of sliding window -Specifically, as shown in the figure below, the current bucket stores the data within the bucket life cycle set in the configuration, that is, the recent data -![img_1.png](/imgs/docs3-v2/java-sdk/observability/aggre.png) - -In each bucket, use the **TDigest algorithm** to calculate the quantile index -> **TDigest algorithm** (extreme quantile accuracy is high, such as p1 p99, middle quantile accuracy is low, such as p50), the relevant information is as follows> -> - https://op8867555.github.io/posts/2018-04-09-tdigest.html -> - https://blog.csdn.net/csdnnews/article/details/116246540 -> - Open Impl:https://github.com/tdunning/t-digest - -The code is implemented as follows, in addition to TimeWindowQuantile is used to calculate quantile indicators, and TimeWindowCounter is provided to collect the number of indicators in the time interval -```java -public class TimeWindowQuantile { - private final double compression; - private final TDigest[] ringBuffer; - private int currentBucket; - private long lastRotateTimestampMillis; - private final long durationBetweenRotatesMillis; - - public TimeWindowQuantile(double compression, int bucketNum, int timeWindowSeconds) { - this.compression = compression; - this.ringBuffer = new TDigest[bucketNum]; - for (int i = 0; i < bucketNum; i++) { - this.ringBuffer[i] = TDigest.createDigest(compression); - } - - this.currentBucket = 0; - this.lastRotateTimestampMillis = System.currentTimeMillis(); - this.durationBetweenRotatesMillis = TimeUnit.SECONDS.toMillis(timeWindowSeconds) / bucketNum; - } - - public synchronized double quantile(double q) { - TDigest currentBucket = rotate(); - return currentBucket.quantile(q); - } - - public synchronized void add(double value) { - rotate(); - for (TDigest bucket : ringBuffer) { - bucket.add(value); - } - } - - private TDigest rotate() { - long timeSinceLastRotateMillis = System.currentTimeMillis() - lastRotateTimestampMillis; - while (timeSinceLastRotateMillis > durationBetweenRotatesMillis) { - ringBuffer[currentBucket] = TDigest.createDigest(compression); - if (++currentBucket >= ringBuffer.length) { - currentBucket = 0; - } - timeSinceLastRotateMillis -= durationBetweenRotatesMillis; - lastRotateTimestampMillis += durationBetweenRotatesMillis; - } - return ringBuffer[currentBucket]; - } -} -``` -# Indicator push -Metrics push can only be enabled after the user has set configuration and configured protocol parameters. If only metrics aggregation is enabled, metrics will not be pushed by default. -## 1. Promehteus Pull Service Discovery -Use dubbo-admin and other similar middle layers, and push the local IP, Port, and MetricsURL address information to dubbo-admin (or any middle layer) according to the configuration at startup, and expose HTTP ServiceDiscovery for prometheus to read. The configuration method is as follows: dubbo:metrics protocol="prometheus" mode="pull" address="${dubbo-admin.address}" port="20888" url="/metrics"/>, where address is an optional parameter in pull mode, If not filled, the user needs to manually configure the address in the Prometheus configuration file -```java -private void exportHttpServer() { - boolean exporterEnabled = url.getParameter(PROMETHEUS_EXPORTER_ENABLED_KEY, false); - if (exporterEnabled) { - int port = url.getParameter(PROMETHEUS_EXPORTER_METRICS_PORT_KEY, PROMETHEUS_DEFAULT_METRICS_PORT); - String path = url.getParameter(PROMETHEUS_EXPORTER_METRICS_PATH_KEY, PROMETHEUS_DEFAULT_METRICS_PATH); - if (!path.startsWith("/")) { - path = "/" + path; - } - - try { - prometheusExporterHttpServer = HttpServer.create(new InetSocketAddress(port), 0); - prometheusExporterHttpServer.createContext(path, httpExchange -> { - String response = prometheusRegistry.scrape(); - httpExchange.sendResponseHeaders(200, response.getBytes().length); - try (OutputStream os = httpExchange.getResponseBody()) { - os.write(response.getBytes()); - } - }); - - httpServerThread = new Thread(prometheusExporterHttpServer::start); - httpServerThread.start(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } -} -``` -## 2. Prometheus Push Pushgateway -Users can directly configure the address of Prometheus Pushgateway in the Dubbo configuration file, such as , Where interval represents the push interval -```java - -private void schedulePushJob() { - boolean pushEnabled = url.getParameter(PROMETHEUS_PUSHGATEWAY_ENABLED_KEY, false); - if (pushEnabled) { - String baseUrl = url.getParameter(PROMETHEUS_PUSHGATEWAY_BASE_URL_KEY); - String job = url.getParameter(PROMETHEUS_PUSHGATEWAY_JOB_KEY, PROMETHEUS_DEFAULT_JOB_NAME); - int pushInterval = url.getParameter(PROMETHEUS_PUSHGATEWAY_PUSH_INTERVAL_KEY, PROMETHEUS_DEFAULT_PUSH_INTERVAL); - String username = url.getParameter(PROMETHEUS_PUSHGATEWAY_USERNAME_KEY); - String password = url.getParameter(PROMETHEUS_PUSHGATEWAY_PASSWORD_KEY); - - NamedThreadFactory threadFactory = new NamedThreadFactory("prometheus-push-job", true); - pushJobExecutor = Executors.newScheduledThreadPool(1, threadFactory); - PushGateway pushGateway = new PushGateway(baseUrl); - if (!StringUtils.isBlank(username)) { - pushGateway.setConnectionFactory(new BasicAuthHttpConnectionFactory(username, password)); - } - - pushJobExecutor.scheduleWithFixedDelay(() -> push(pushGateway, job), pushInterval, pushInterval, TimeUnit.SECONDS); - } -} - -protected void push(PushGateway pushGateway, String job) { - try { - pushGateway.pushAdd(prometheusRegistry.getPrometheusRegistry(), job); - } catch (IOException e) { - logger.error("Error occurred when pushing metrics to prometheus: ", e); - } -} -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/tracing.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/tracing.md deleted file mode 100644 index c80e305aadd9..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/observability/tracing.md +++ /dev/null @@ -1,181 +0,0 @@ ---- -type: docs -title: "Tracing" -linkTitle: "Tracing" -weight: 2 -no_list: true -hide_summary: true ---- - -# Overview - -Apache Dubbo has inbuilt tracing through [Micrometer Observations](https://micrometer.io/) and [Micrometer Tracing](https://github.com/micrometer-metrics/tracing). - -## 1. Adding Micrometer Observation To Your Project - -In order to add Micrometer to the classpath and add metrics for Dubbo you need to add the `dubbo-metrics-api` dependency as shown below: - -```xml - - org.apache.dubbo - dubbo-metrics-api - -``` - -Thanks to the usage of [Micrometer Observations](https://micrometer.io/) Dubbo got instrumented once, but depending on the setup will allow emission of metrics, tracer or other signals via custom `ObservationHandlers`. Please read the [documentation under docs/observation](https://micrometer.io) for more information. - -## 2. Adding Micrometer Tracing Bridge To Your Project - -In order to start creating spans for Dubbo based projects a `bridge` between Micrometer Tracing and an actual Tracer is required. - -> NOTE: Tracer is a library that handles lifecycle of spans (e.g. it can create, start, stop, sample, report spans). - -Micrometer Tracing supports [Brave](https://github.com/openzipkin/brave) and [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-java) as Tracers as shown below: - -```xml - - - - io.micrometer - micrometer-tracing-bridge-brave - - - - - io.micrometer - micrometer-tracing-bridge-otel - -``` - -## 3. Adding Micrometer Tracing Exporter To Your Project - -After having added the Tracer, an exporter (also known as a reporter) is required. It's a component that will export the finished span and send it to a reporting system. Micrometer Tracer natively supports Tanzu Observability by Wavefront and Zipkin as shown below: - -Tanzu Observability by Wavefront - -```xml - - io.micrometer - micrometer-tracing-reporter-wavefront - -``` - -OpenZipkin Zipkin with Brave - -```xml - - io.zipkin.reporter2 - zipkin-reporter-brave - -``` - -OpenZipkin Zipkin with OpenTelemetry - -```xml - - io.opentelemetry - opentelemetry-exporter-zipkin - -``` - -An OpenZipkin URL sender dependency to send out spans to Zipkin via a URLConnectionSender - -```xml - - io.zipkin.reporter2 - zipkin-sender-urlconnection - -``` - -You can read more about tracing setup [this documentation, under docs/tracing](https://micrometer.io/). - -## 4. Setting Up The Observation Registry - -To use Micrometer Observation an `ObservationRegistry` needs setting up. In essence `ObservationRegistry` requires passing of `ObservationHandler`s that will react to lifecycle events of observations such as start, stop etc. There are 3 main types of handlers - -* `MeterObservationHandler` - metrics related handlers (coming from `micrometer-core`) -* `TracingObservationHandler` - tracing related handlers (coming from `micrometer-tracing`) -* `ObservationHandler` - any other handler - -`ObservationRegistry` will iterate over all handlers and will pick all of the matching ones. It's good practice to put all `MeterObservationHandler`s into one `FirstMatchingCompositeObservationHandler` and all `TracingObservationHandler`s into another composite so that only one gets executed respectively. Example of such setup can be found below (an up to date copy is maintained [here under docs/tracing](https://micrometer.io)). - - -```java - -// ----- MICROMETER TRACING + BRAVE ----- - -// [Brave component] Example of using a SpanHandler. SpanHandler is a component -// that gets called when a span is finished. Here we have an example of setting it -// up with sending spans -// in a Zipkin format to the provided location via the UrlConnectionSender -// (through the dependency) -// Another option could be to use a TestSpanHandler for testing purposes. -SpanHandler spanHandler = ZipkinSpanHandler - .create(AsyncReporter.create(URLConnectionSender.create("http://localhost:9411/api/v2/spans"))); - -// [Brave component] CurrentTraceContext is a Brave component that allows you to -// retrieve the current TraceContext. -StrictCurrentTraceContext braveCurrentTraceContext = StrictCurrentTraceContext.create(); - -// [Micrometer Tracing component] A Micrometer Tracing wrapper for Brave's -// CurrentTraceContext -CurrentTraceContext bridgeContext = new BraveCurrentTraceContext(this.braveCurrentTraceContext); - -// [Brave component] Tracing is the root component that allows to configure the -// tracer, handlers, context propagation etc. -Tracing tracing = Tracing.newBuilder().currentTraceContext(this.braveCurrentTraceContext).supportsJoin(false) - .traceId128Bit(true) - // For Baggage to work you need to provide a list of fields to propagate - .propagationFactory(BaggagePropagation.newFactoryBuilder(B3Propagation.FACTORY) - .add(BaggagePropagationConfig.SingleBaggageField - .remote(BaggageField.create("from_span_in_scope 1"))) - .add(BaggagePropagationConfig.SingleBaggageField - .remote(BaggageField.create("from_span_in_scope 2"))) - .add(BaggagePropagationConfig.SingleBaggageField.remote(BaggageField.create("from_span"))) - .build()) - .sampler(Sampler.ALWAYS_SAMPLE).addSpanHandler(this.spanHandler).build(); - - -// [Brave component] Tracer is a component that handles the life-cycle of a span -brave.Tracer braveTracer = tracing.tracer(); - -// [Micrometer Tracing component] A wrapper for Brave's Propagator -Propagator propagator = new BravePropagator(tracing); - -// [Micrometer Tracing component] A Micrometer Tracing wrapper for Brave's Tracer -Tracer tracer = new BraveTracer(braveTracer, bridgeContext, new BraveBaggageManager()); - -// ----- MICROMETER CORE ----- - -MeterRegistry meterRegistry = new SimpleMeterRegistry(); - -// ----- MICROMETER OBSERVATION ----- - -ObservationRegistry observationRegistry = ObservationRegistry.create(); - -// Adding metrics handler -observationRegistry.observationConfig().observationHandler(new TracingAwareMeterObservationHandler<>(new DefaultMeterObservationHandler(meterRegistry), tracer)); - -// Adding tracing handlers -observationRegistry.observationConfig() - .observationHandler(new ObservationHandler.FirstMatchingCompositeObservationHandler(new PropagatingReceiverTracingObservationHandler<>(tracer, propagator), new PropagatingSenderTracingObservationHandler<>(tracer, propagator), new DefaultTracingObservationHandler(tracer))); - - -// ----- DUBBO ----- - -ApplicationModel applicationModel = ApplicationModel.defaultModel(); -applicationModel.getBeanFactory().registerBean(observationRegistry); -// reuse the applicationModel in your system -``` - -By using the new consumer and provider Dubbo filters that use Micrometer Observation, after setting up the registry, metrics and traces would be created and spans would be sent to Zipkin upon their closing. - -> IMPORTANT! Staring from Spring Boot 3 the whole Micrometer Tracer, Micrometer Core and Micrometer Observation setup happens out of the box. You don't need to manually set it up. - -## 5. Customizing Observation Filters - -To customize the tags present in metrics (low cardinality tags) and in spans (low and high cardinality tags) you should create your own versions of `DubboServerObservationConvention` (server side) and `DubboClientObservationConvention` (client side) and register them in the `ApplicationModel`'s `BeanFactory`. To reuse the existing ones check `DefaultDubboServerObservationConvention` (server side) and `DefaultDubboClientObservationConvention` (client side). - -## 6. Sample Setup - -Since Micrometer Observation is a new feature in Micrometer 1.10, Spring Boot 2 doesn't have it configured out of the box (SB2 uses Micrometer 1.9). In this [this demo sample](https://github.com/apache/dubbo/tree/3.2/dubbo-demo/dubbo-demo-spring-boot) you can see how Micrometer Observation is manually set up together with OpenTelemetry Bridge. diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/Docker.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/Docker.md deleted file mode 100644 index 0bd90624aa9b..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/Docker.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -type: docs -title: "Dubbo deploy to Docker environment" -linkTitle: "Docker Deploy" -weight: 6 -description: "take Dubbo deploy to Docker environment" ---- - -Some deployment scenarios need to dynamically specify the address of service registration. For example, docker bridge network mode need to specify a registered host IP for external network communication. Dubbo provides two pairs of system attributes in the startup phase, which are used to set the IP and port addresses of external communication. -* DUBBO_IP_TO_REGISTRY --- Registering to the IP address of the registration center -* DUBBO_PORT_TO_REGISTRY --- Registering to the port of the registration center -* DUBBO_IP_TO_BIND --- Listening IP addresses   -* DUBBO_PORT_TO_BIND --- Listening ports - -> 1. The above four configurations are optional. Dubbo will automatically get IP and port if there is no configuration. Please choose them flexibly according to deployment scenarios. -> 2. Dubbo supports multi-protocol. **If an application exposes multiple different protocol services simultaneously and need to specify IP or port separately for each service. Please add the protocol prefix before the above attributes separately.** For example: -> * HESSIAN_DUBBO_PORT_TO_BIND hessian protocol bound port -> * DUBBO_DUBBO_PORT_TO_BIND   dubbo protocol bound port -> * HESSIAN_DUBBO_IP_TO_REGISTRY hessian protocol registered IP -> * DUBBO_DUBBO_IP_TO_REGISTRY     dubbo protocol registered IP -> 3. `PORT_TO_REGISTRY` or `IP_TO_REGISTRY`won’t be used as default `PORT_TO_BIND` or `IP_TO_BIND`,But the reverse is true. -> * If set`PORT_TO_REGISTRY=20881` `IP_TO_REGISTRY=30.5.97.6`,then `PORT_TO_BIND` `IP_TO_BIND`won’t be affected. -> * If set`PORT_TO_BIND=20881` `IP_TO_BIND=30.5.97.6`,then `PORT_TO_REGISTRY=20881` `IP_TO_REGISTRY=30.5.97.6` by default. -> - -[dubbo-docker-sample](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-docker) local operation process: - -1. clone project to local -```sh -git clone git@github.com:dubbo/dubbo-docker-sample.git -cd dubbo-docker-sample -``` -2. package local maven -```sh -mvn clean install -``` -3. build a mirror by docker build -```sh -docker build --no-cache -t dubbo-docker-sample . -``` -Dockerfile -```sh -FROM openjdk:8-jdk-alpine -ADD target/dubbo-docker-sample-0.0.1-SNAPSHOT.jar app.jar -ENV JAVA_OPTS="" -ENTRYPOINT exec java $JAVA_OPTS -jar /app.jar -``` -4. Create and run containers from mirroring -```sh -# Since we use the zk registration center, we start zk container first -docker run --name zkserver --restart always -d zookeeper:3.4.9 -``` -```sh -docker run -e DUBBO_IP_TO_REGISTRY=30.5.97.6 -e DUBBO_PORT_TO_REGISTRY=20881 -p 30.5.97.6:20881:20880 --link zkserver:zkserver -it --rm dubbo-docker-sample -``` - -> Suppose the host IP is 30.5.97.6. -> set the provider to register the IP address and port of the registration center by environment variables `DUBBO_IP_TO_REGISTRY=30.5.97.6` `DUBBO_PORT_TO_REGISTRY=20881`   -> Implement the port mapping by`-p 30.5.97.6:20881:20880`, where 20880 is the listening port automatically selected by dubbo. There is no monitoring IP configuration, so it will listen 0.0.0.0 (all IP). -> After startup, the registered address of provider is 30.5.97.6:20881, and the listening address of the container is: 0.0.0.0:20880  - -5. Test -Execute from another host or container -```sh -telnet 30.5.97.6 20881 -ls -invoke org.apache.dubbo.test.docker.DemoService.hello("world") -``` diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/_index.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/_index.md deleted file mode 100755 index b469c5d75294..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/_index.md +++ /dev/null @@ -1,8 +0,0 @@ - ---- -type: docs -title: "Others" -linkTitle: "Others" -weight: 5 ---- - diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/dubbo-kubernetes-probe.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/dubbo-kubernetes-probe.md deleted file mode 100644 index 838ec3ec36c7..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/dubbo-kubernetes-probe.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -type: docs -title: "Kubernetes Probe" -linkTitle: "Kubernetes Probe" -weight: 5 -description: "Understand the extension and application scenarios of Dubbo3 and Kubernetes life cycle alignment probe" ---- - -## Feature description -[Pod lifecycle](https://kubernetes.io/zh/docs/concepts/workloads/pods/pod-lifecycle/) is closely related to service scheduling. Through the implementation of official Kubernetes probes, Dubbo3 and even the entire application can The life cycle of the Pod and the life cycle of the Pod. In the entire life cycle of the Pod, only the health check part of the Pod is affected. We can configure the liveness probe (survival probe) and readiness probe (readability probe) to Affects the life cycle of the container. - -Through the SPI mechanism of Dubbo3, various "probes" are implemented internally, based on the HTTP service of the Dubbo3 QOS operation and maintenance module, so that the container probe can obtain the status of the corresponding probe in the application. In addition, the implementation mechanism of SPI is also conducive to users' self-expanding of internal "probes", so that the entire application life cycle can be more effectively controlled. - -**SPI interfaces corresponding to the three probes** - -- livenessProbe: `org.apache.dubbo.qos.probe.LivenessProbe` -- readinessProbe: `org.apache.dubbo.qos.probe.ReadinessProbe` -- startupProbe: `org.apache.dubbo.qos.probe.StartupProbe` - -The interface will automatically obtain the implementation of all SPIs of the current application, and the interface will return success if the SPI implementations of the corresponding interface are successfully ready. - -For an introduction to more extensions of Dubbo3 SPI, see [Dubbo SPI Extensions](/en/docs3-v2/java-sdk/reference-manual/spi/description/) - -## scenes to be used -- kubelet uses `liveness probe` to determine if your application is running, to see if it is alive. Generally speaking, if your program crashes, Kubernetes will immediately know that the program has terminated, and then restart the program. The purpose of our liveness probe is to capture that the current application has not terminated or crashed. If these situations occur, restart the container in this state so that the application can still continue in the presence of bugs run down. -- The kubelet uses `readiness probe` to determine if the container is ready to receive traffic. Is it ready and ready to work now. Only when the containers in the Pod are all in the ready state, the kubelet will consider the Pod to be in the ready state, because there may be multiple containers under a Pod. If the Pod is not ready, we will remove it from the Service's Endpoints list, so that our traffic will not be routed to the Pod. - -## How to use - -### Survival detection - -For the livenessProbe liveness detection, since the Dubbo3 framework itself cannot obtain the liveness status of the application, this interface has no default implementation and returns success by default. Developers can expand this SPI interface according to the SPI definition, and judge whether it is alive or not from the application level. - -About [liveness liveness probe](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/liveness/) extension example -### Readiness check - -For the readinessProbe readiness detection, Dubbo3 currently provides two detection dimensions by default. One is to judge whether the Dubbo3 service itself is started or stopped, and the other is to check whether all services have registered interfaces. If all services have been offline from the registration center (you can Operate via QOS Operations) will return Not Ready. - -About the [readiness readiness probe](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/readiness/) extended example - -### Start detection - -For startupProbe startup detection, Dubbo3 currently provides a detection dimension by default, which is to return to the ready state after all startup processes (interface exposure, registration center writing, etc.) are completed. - -About the [startup startup probe](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/startup/) extended example - -### Reference example -```yaml -livenessProbe: - httpGet: - path: /live - port: 22222 - initialDelaySeconds: 5 - periodSeconds: 5 -readinessProbe: - httpGet: - path: /ready - port: 22222 - initialDelaySeconds: 5 - periodSeconds: 5 -startupProbe: - httpGet: - path: /startup - port: 22222 - failureThreshold: 30 - periodSeconds: 10 -``` -> QOS When the computing node detects memory pressure, kuberentes will BestEffort -> Burstable -> Guaranteed to evict Pods in sequence. - -At present, all three probes have corresponding interfaces, and the path is the command in QOS. Please modify the port information according to the QOS configuration (the default port is 22222). For other parameters, please refer to [Kubernetes official documentation](https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/). diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/graceful-shutdown.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/graceful-shutdown.md deleted file mode 100644 index c7e7ec012c99..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/graceful-shutdown.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -type: docs -title: "Graceful shutdown" -linkTitle: "Graceful shutdown" -weight: 2 -description: "Let the Dubbo service complete graceful shutdown" ---- - -## Feature description - -Graceful shutdown means that the service instance can be stopped safely and smoothly without affecting the ongoing business. -A Dubbo service may be both a service provider and a service consumer. When the service is stopped: -1. Consumers will no longer request stopped service instances -2. The request being processed by the service instance can be processed normally - -## scenes to be used - -1. Stop the service with `kill PID` -2. Stop the service through `/shutdown` of SpringBoot Actuator - -Dubbo 3.0 and above supports different types of Java applications, including SpringBoot applications, Spring applications, and non-Spring applications. - -## How to use - -Set the graceful shutdown timeout, the default timeout is 10 seconds, if it times out, it will be forced to shut down. -This parameter can be configured in the dubbo.properties file, for example: 30 seconds. -```properties -# Stop service waiting time, unit: milliseconds -dubbo.service.shutdown.wait=30000 -``` - -## Precautions - -1. Dubbo uses JDK's ShutdownHook to complete graceful shutdown, so if the user uses `kill -9 PID` and other forced shutdown commands, it will not execute graceful shutdown, and will only execute when `kill PID` is passed. - -2. Verify that Dubbo's ShutdownHook is executed. You can find the keyword in the log file: `Run shutdown hook now.` - -3. If Spring is used, please upgrade to version 4.2 and above, it is recommended to use version 5 or above - -4. If SpringBoot is used, Dubbo's ShutdownHook will be executed before SpringBoot's ShutdownHook, - If you use SpringBoot 2.3 and above, it is recommended to use it with SpringBoot's graceful shutdown, and configure it in the configuration file application.yml: -```yml -server: - shutdown: graceful -``` - -5. If the ShutdownHook does not take effect, you can call it yourself according to the specific scenario: -```java -ApplicationModel.defaultModel().destroy(); -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/logger-howto.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/logger-howto.md deleted file mode 100644 index ffb035af7b75..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/logger-howto.md +++ /dev/null @@ -1,177 +0,0 @@ ---- -aliases: - - /en/docs3-v2/java-sdk/advanced-features-and-usage/others/logger-howto/ -description: How to configure and use the logging framework in dubbo and dubbo-samples -linkTitle: Logging Framework Configuration and Usage -title: Logging Framework Configuration and Usage -type: docs -weight: 7 ---- - -## Feature Description - -Prior to dubbo 3.3.0, dubbo and dubbo-samples were using a mix of log4j and logback, leading to frequent conflicts and errors due to some modules lacking log configuration. Therefore, after 3.3.0-beta.3, the logging components have been upgraded to log4j2 for simplicity and reduced maintenance costs. This document explains how to configure and use the logging framework to avoid conflicts caused by indirectly introducing multiple logging frameworks. - -## How To Use - -### Usage Conventions - -* Please use log4j2 as the logging framework, and avoid using log4j and logback. Except for some legacy scenarios, using a single logging framework can reduce usage cost and prevent conflicts. -* Avoid passing logging framework dependencies upstream, which can be resolved by setting scope to `test` or `provider` in maven, or by setting `true`. As a service framework, dubbo should ideally avoid passing non-essential dependencies and leave the choice of logging framework to the user. - -### Usage Scenarios - -#### 1. General dubbo Module - -Most modules are of this type, generally requiring logging frameworks for unit testing. - - -1. Include Maven dependency, note if parent has already included it, then there's no need to add it again: - - ```xml - - org.apache.logging.log4j - log4j-slf4j-impl - test - - ``` - -2. Add log4j2 logging configuration `src/test/resources/log4j2-test.xml`, the reason for using this name is to ensure the highest priority. - - ```xml - - - - - - - - - - - - - - ``` - - -#### 2. Non spring-boot Demo Module -1. Include Maven dependency, note if parent has already included it, then there's no need to add it again - - ```xml - - org.apache.logging.log4j - log4j-slf4j-impl - - ``` - -2. Add log4j2 logging configuration `src/test/resources/log4j2-test.xml` - - ```xml - - - - - - - - - - - - - - ``` - -#### 3. Spring-boot Demo Module - -Spring-boot supports introducing log4j2 dependencies via a starter, but note that spring-boot defaults to using logback, so it needs to be excluded in `` - -1. Exclude spring-boot-starter-logging - - ```xml - - - - org.springframework.boot - spring-boot-dependencies - ${spring-boot.version} - pom - import - - - org.springframework.boot - spring-boot-starter - ${spring-boot.version} - - - org.springframework.boot - spring-boot-starter-logging - - - - - - ``` - -2. Include Maven dependency: - - ```xml - - org.springframework.boot - spring-boot-starter-log4j2 - - ``` - -3. Add log4j2 logging configuration `src/main/resources/log4j2.xml` - - Optional, as spring-boot comes with a default logging configuration. - -#### 4. Spring-boot native Demo Module - -Since log4j2 does not yet support native, use logback as the logging framework. No changes are necessary, retain the existing approach and ensure not to indirectly introduce log4j or slf4j-log4j12. - -## Common Logging Framework Issues - -#### 1. Missing Logging Framework - -Console output: - -``` -SLF4J: No SLF4J providers were found. -SLF4J: Defaulting to no-operation (NOP) logger implementation -SLF4J: See SLF4J Error Codes for further details. -``` - -Solution: Add log4j2 dependency - -```xml - - org.apache.logging.log4j - log4j-slf4j-impl - -``` - -#### 2. Logging Framework Conflict - -Console output: - -``` -SLF4J: Class path contains multiple SLF4J bindings. -SLF4J: Found binding in [jar:file:.../slf4j-log4j12-1.x.x.jar!/org/slf4j/impl/StaticLoggerBinder.class] -SLF4J: Found binding in [jar:file:.../logback-classic-1.x.x.jar!/org/slf4j/impl/StaticLoggerBinder.class] -SLF4J: Found binding in [jar:file:.../log4j-slf4j-impl-2.x.x.jar!/org/slf4j/impl/StaticLoggerBinder.class] -SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. -SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory] -``` - -Or - -``` -Exception in thread "main" java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath -``` -Solution: Exclude all dependencies except for log4j-slf4j-impl. It's highly recommended to use [Maven Helper - IntelliJ IDEs Plugin](https://plugins.jetbrains.com/plugin/7179-maven-helper) for dependency analysis and exclusion. - -#### 3. Other Issues - -Refer to: [SLF4J Error Codes](https://www.slf4j.org/codes.html) diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/logger-management.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/logger-management.md deleted file mode 100644 index cbceac3e78d5..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/logger-management.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -type: docs -title: "Log Framework Adaptation and Runtime Management" -linkTitle: "Log framework adaptation and runtime management" -weight: 4 -description: "Adapt to the log framework in Dubbo and support dynamic switching of the log framework used at runtime" ---- -## Feature description -Adaptation of log frameworks. Since `2.2.1`, dubbo has built-in adaptation of log4j, slf4j, jcl, and jdk log frameworks. - -Log framework runtime management, starting from `3.0.10`, dubbo-qos runtime management supports query log configuration and dynamically modify the used log framework and log level. - -> The log configuration modified by dubbo-qos is not stored persistently, and will become invalid after the application is restarted. -## scenes to be used - -## How to use -## Log framework adaptation -The logging output policy can be explicitly configured in the following ways - -### 1. Command line - -```sh -java -Ddubbo.application.logger=log4j -``` - -### 2. Specify in `dubbo.properties` - -``` -dubbo.application.logger=log4j -``` - -### 3. Configuration in `dubbo.xml` - -```xml - -``` - -For custom extensions, please refer to [Log Adapter Extension](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/logger-adapter) - -## Logging framework runtime management -### 1. Query log configuration - -Command: `loggerInfo` - -**example** -```bash -> telnet 127.0.0.1 22222 -> loggerInfo -``` - -**output** -``` -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. - ___ __ __ ___ ___ ____ - / _ \ / / / // _ ) / _ ) / __ \ - / // // /_/ // _ |/ _ |/ /_/ / -/____/ \____//____//____/ \____/ -dubbo>loggerInfo -Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: INFO -``` - -### 2. Modify log level - -Command: `switchLogLevel {level}` - -level: `ALL`, `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `OFF` - -**example** -```bash -> telnet 127.0.0.1 22222 -> switchLogLevel WARN -``` - -**output** -``` -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. - ___ __ __ ___ ___ ____ - / _ \ / / / // _ ) / _ ) / __ \ - / // // /_/ // _ |/ _ |/ /_/ / -/____/ \____//____//____/ \____/ -dubbo>loggerInfo -Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: INFO -dubbo>switchLogLevel WARN -OK -dubbo>loggerInfo -Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: WARN``` -``` - -### 3. Modify the log output framework - -Command: `switchLogger {loggerAdapterName}` - -loggerAdapterName: `slf4j`, `jcl`, `log4j`, `jdk`, `log4j2` - -**example** -```bash -> telnet 127.0.0.1 22222 -> switchLogger slf4j -``` - -**output** -``` -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. - ___ __ __ ___ ___ ____ - / _ \ / / / // _ ) / _ ) / __ \ - / // // /_/ // _ |/ _ |/ /_/ / -/____/ \____//____//____/ \____/ -dubbo>loggerInfo -Available logger adapters: [jcl, slf4j, log4j, jdk]. Current Adapter: [log4j]. Log level: INFO -dubbo>switchLogger slf4j -OK -dubbo>loggerInfo -Available logger adapters: [jcl, slf4j, log4j, jdk]. Current Adapter: [slf4j]. Log level: INFO -``` diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/service-container.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/service-container.md deleted file mode 100644 index a2df989b7bab..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/service-container.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -type: docs -title: "Custom Service Container" -linkTitle: "Custom service container" -weight: 1 -description: "Understand the service custom container type and usage in Dubbo 3" ---- - -## Feature description -The service container of Dubbo 3 is a standalone startup program, because the background service does not need the functions of web containers such as Tomcat or JBoss. If you insist on using the web container to load the service provider, it will increase complexity and waste resources. Therefore, services usually do not require the features of web containers such as Tomcat/JBoss, and there is no need to use web containers to load services. - -The Dubbo3 service container is just a simple Main method and loads a simple Spring container for exposing services. - -The loading content of the service container can be extended, and spring, jetty, log4j, etc. are built-in, and can be extended through [container extension point](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/container). The configuration is configured in the -D parameter of the java command or `dubbo.properties`. - -## scenes to be used -The web container is mainly used to respond to http requests and static pages. The Dubbo service provider only provides dubbo services externally. It is not suitable to use the web container. As a dubbo service provider alone, it only needs to load a simple spring container through a main method Expose the service. - -## How to use -### Spring Container -- Autoload all Spring configurations under the `META-INF/spring` directory. - -- Configure the spring configuration loading location: - - ```fallback - dubbo.spring.config=classpath*:META-INF/spring/*.xml -### Jetty Container -- Starts an embedded Jetty for reporting status. -- configuration: - - `dubbo.jetty.port=8080`: configure jetty startup port - - `dubbo.jetty.directory=/foo/bar`: Configure a directory that can be directly accessed through jetty to store static files - - `dubbo.jetty.page=log,status,system`: configure the displayed pages, all pages are loaded by default - -### Log4j Container - -- Automatically configure the configuration of log4j. When multiple processes are started, the log files are automatically divided into directories by process. -- configuration: - - `dubbo.log4j.file=/foo/bar.log`: configure log file path - - `dubbo.log4j.level=WARN`: configure log level - - `dubbo.log4j.subdirectory=20880`: Configure the log subdirectory for multi-process startup to avoid conflicts - - -### Container loading instructions -Only spring is loaded by default -```sh -java org.apache.dubbo.container.Main -``` -Pass in the container to be loaded through the main function parameter -```sh -java org.apache.dubbo.container.Main spring jetty log4j -``` -Pass in the container to be loaded through the JVM startup parameters - -```sh -java org.apache.dubbo.container.Main -Ddubbo.container=spring,jetty,log4j -``` -Pass in the container to be loaded through `dubbo.properties` configuration under the classpath -```fallback -dubbo.container=spring,jetty,log4j -``` diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/set-host.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/set-host.md deleted file mode 100644 index 7dba5c2b4e52..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/others/set-host.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -type: docs -title: "Host Address Custom Exposure" -linkTitle: "Host address custom exposure" -weight: 3 -description: "Custom Dubbo service exposed host address" ---- - -## Feature description - -In Dubbo, Provider mainly does two things when it starts -- One is to start the server -- The second is to register the service with the registration center. When starting the server, the socket needs to be bound, and when the service is registered with the registration center, the unique service address of the socket needs to be sent. - -1. What is the default `host` when `host` is not set in `dubbo`? -2. How to specify the `host` of the service in `dubbo`, can we use hostname or domain instead of IP address as `host`? -3. When using docker, sometimes it is necessary to set port mapping. At this time, the socket bound when starting the server and the socket registered with the registration center use different port numbers. How to set it at this time? - -## scenes to be used -## How to use -### Default host when no host is set - -The general dubbo protocol configuration is as follows: -```xml - ... - - ... -``` - -It can be seen that only the port number is configured, and the host is not configured. What is the host set at this time? - -Looking at the code, it is found that in `org.apache.dubbo.config.ServiceConfig#findConfigedHosts()`, the default host is obtained through `InetAddress.getLocalHost().getHostAddress()`. Its return value is as follows: - -1. When not connected to the Internet, return 127.0.0.1 -2. In the Alibaba Cloud server, return the private address, such as: 172.18.46.234 -3. When testing locally, return the public address, such as: 30.5.10.11 - -### Specify the socket of the service - -Besides, you can configure `host` through `dubbo.protocol` or `dubbo.provider`’s `host` property, which supports IP address and domain name, as follows: - -```xml - ... - - ... -``` - -### socket uses a different port number - -See [dubbo set host by environment variable](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-docker) - -Some deployment scenarios need to dynamically specify the address of the service registration, such as the docker bridge network mode to specify the registration host ip to achieve external network communication. dubbo provides two pairs of system properties in the startup phase, which are used to set the ip and port addresses for external communication. - -* **DUBBO_IP_TO_REGISTRY**: Register to the ip address of the registration center -* **DUBBO_PORT_TO_REGISTRY**: Register to the port of the registry center -* **DUBBO_IP_TO_BIND**: Listening ip address -* **DUBBO_PORT_TO_BIND**: Listening port - -The above four configuration items are optional. If you do not configure dubbo, it will automatically obtain the ip and port. Please choose the configuration flexibly according to the specific deployment scenario. -dubbo supports multiple protocols. If an application exposes multiple different protocol services at the same time, and you need to specify an ip or port for each service separately, please add a protocol prefix before the above attributes. Such as: - -* **HESSIAN_DUBBO_PORT_TO_BIND**: port bound by hessian protocol -* **DUBBO_DUBBO_PORT_TO_BIND**: port bound by dubbo protocol -* **HESSIAN_DUBBO_IP_TO_REGISTRY**: ip registered by hessian protocol -* **DUBBO_DUBBO_IP_TO_REGISTRY**: ip registered by dubbo protocol - -PORT_TO_REGISTRY or IP_TO_REGISTRY will not be used as default PORT_TO_BIND or IP_TO_BIND, but the reverse is true. Such as: - -* Set `PORT_TO_REGISTRY=20881` and `IP_TO_REGISTRY=30.5.97.6`, then `PORT_TO_BIND` and `IP_TO_BIND` will not be affected -* Set `PORT_TO_BIND=20881` and `IP_TO_BIND=30.5.97.6`, then default `PORT_TO_REGISTRY=20881` and `IP_TO_REGISTRY=30.5.97.6` - -### Summarize - -1. You can configure `host` through the `host` attribute of `dubbo.protocol` or `dubbo.provider`, and support IP addresses and domain names. But at this time, the IP address registered to the registration center and the listening IP address are the same value -2. In order to solve the problem that the consumer cannot communicate with the provider in the virtual environment or LAN, you can set the IP address registered to the registration center and the listening IP address respectively through environment variables, and its priority is higher than `dubbo.protocol` or `dubbo. provider`s `host` configuration - -### refer to - -1. [Proposal: support hostname or domain in service discovery.](https://github.com/apache/dubbo/issues/2043) -2. [dubbo sets host through environment variables](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-docker) \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/_index.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/_index.md deleted file mode 100755 index d7c861b65991..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "Diagnostics and Tuning" -linkTitle: "Diagnostics" -weight: 3 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control.md deleted file mode 100644 index 295dd160f046..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/concurrency-control.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -type: docs -title: "Concurrency Control" -linkTitle: "Concurrency Control" -weight: 28 -description: "Concurrency Control in Dubbo" ---- - -## Configuration example - -### Example 1 - -To limit each method of `com.foo.BarService`, the concurrent execution on the server side (or the number of threads in the thread pool) cannot exceed 10: - -```xml - -``` - -### Example 2 - -To limit the `sayHello` method of `com.foo.BarService`, the concurrent execution on the server side (or the number of threads in the thread pool) cannot exceed 10: - -```xml - - - -``` -### Example 3 - -Limit each method of `com.foo.BarService` to no more than 10 concurrent executions per client (or the number of requests occupying a connection): - -```xml - -``` - -or - -```xml - -``` - -### Example 4 - -Limit the `sayHello` method of `com.foo.BarService` to no more than 10 concurrent executions (or the number of requests that occupy a connection) per client: - -```xml - - - -``` - -or - -```xml - - - -``` - -If both `` and `` are configured with actives, `` takes precedence, see: [Configuration override strategy](../../../reference- manual/config/principle/). - -## Load Balance - -The `loadbalance` attribute of the client side of the configuration service is `leastactive`, and this Loadbalance will call the Provider with the smallest number of concurrency (Consumer-side concurrency). - -```xml - -``` - -or - -```xml - -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/config-connections.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/config-connections.md deleted file mode 100644 index 2013a87eb567..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/config-connections.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -type: docs -title: "Connection Control" -linkTitle: "Connection Control" -weight: 29 -description: "Connection control between server and client in Dubbo" ---- -## Feature description - -## scenes to be used - -## How to use -### Server connection control - -Limit the number of connections accepted by the server to no more than 10 [^1]: - -```xml - -``` - -or - -```xml - -``` - -### Client connection control - -Limit the client service to use no more than 10 connections [^2]: - -```xml - -``` - -or - -```xml - -``` - -If both `` and `` are configured with connections, `` takes precedence, see: [Configuration override strategy](../../../reference- manual/config/principle/) - -[^1]: Because it is connected to the Server, it is configured on the Provider -[^2]: If it is a long connection, such as the Dubbo protocol, connections indicates the number of long connections established by the service for each provider \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/dump.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/dump.md deleted file mode 100644 index a0dcb3360f0b..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/dump.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -type: docs -title: "Export thread stack" -linkTitle: "Export thread stack" -weight: 43 -description: "Automatically export thread stack in Dubbo to preserve the field" ---- -## Feature description -Dubbo automatically exports the thread stack through Jstack to keep the scene, which is convenient for troubleshooting. - -default policy - -* Export path: the user's home directory identified by user.home -* Export Interval: The shortest interval allows an export every 10 minutes -* Export switch: open by default - -## scenes to be used -When the business thread pool is full, we need to know which resources and conditions the threads are waiting for in order to find the bottleneck or abnormal point of the system. - -## How to use -### Export switch control -```properties -# dubbo.properties -dubbo.application.dump.enable=true -``` -```xml - -``` - -```yaml -dubbo: - application: - name: dubbo-springboot-demo-provider - dump-enable: false -``` - - - -### Specify the export path - -```properties -# dubbo.properties -dubbo.application.dump.directory=/tmp -``` - -```xml - -``` - -```yaml -dubbo: - application: - name: dubbo-springboot-demo-provider - dump-directory: /tmp -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/lazy-connect.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/lazy-connect.md deleted file mode 100644 index b9d6269cb491..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/lazy-connect.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "Delayed Connection" -linkTitle: "Delayed connection" -weight: 30 -description: "Configure delayed connection in Dubbo" ---- -## Feature description - -## scenes to be used -Delayed connections are used to reduce the number of long connections. When a call is initiated, create a persistent connection. - -## How to use -```xml - -``` - -> This configuration is only valid for the dubbo protocol that uses long connections. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance.md deleted file mode 100644 index 349b3828b05a..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/loadbalance.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -type: docs -title: "Load Balancing" -linkTitle: "Load Balancing" -weight: 3 -description: "Cluster load balancing strategy provided by Dubbo" ---- - -When cluster load balancing, Dubbo provides a variety of balancing strategies, the default is `random` random calls. - -In terms of specific implementation, Dubbo provides client load balancing, that is, the Consumer uses the load balancing algorithm to determine which Provider instance to submit the request to. - -You can expand the load balancing strategy by yourself, see: [Load Balance Extension](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/load-balance) - -## load balancing strategy -Currently Dubbo has the following built-in load balancing algorithms, which users can directly configure and use: - -| Algorithms | Features | Remarks | -| :-------------------------- | :-------------------- -- | :---------------------------------------------- | -| RandomLoadBalance | Weighted random | Default algorithm, same weight by default | -| RoundRobinLoadBalance | Weighted round-robin | Based on Nginx's smooth weighted round-robin algorithm, the default weight is the same, | -| LeastActiveLoadBalance | Least Active Priority + Weighted Random | Behind it is the idea that those who can do more work | -| ShortestResponseLoadBalance | Shortest Response First + Weighted Random | More focus on response speed | -| ConsistentHashLoadBalance | Consistent Hash | Definite input parameters, definite provider, suitable for stateful requests | - - - -### Random - -* **Weighted random**, set random probability by weight. -* The probability of collision on a section is high, but the greater the call volume, the more uniform the distribution, and the weight is also more uniform after using the probability, which is conducive to dynamically adjusting the provider weight. -* Disadvantages: There is a problem of accumulating requests from slow providers. For example: the second machine is very slow, but it is not hung up. When the request is transferred to the second machine, it is stuck there. Over time, all requests are stuck in the second machine. on stage. - -### RoundRobin -* **Weighted polling**, set the polling ratio according to the weight after the convention, and call the node cyclically -* Disadvantage: There is also the problem of accumulating requests for slow providers. - -During the weighted round-robin process, if the weight of a node is too large, there will be a problem of too concentrated calls within a certain period of time. -For example, ABC three nodes have the following weights: `{A: 3, B: 2, C: 1}` -Then according to the most primitive polling algorithm, the calling process will become: `A A A B B C` - -In this regard, Dubbo has optimized it by referring to Nginx's smooth weighted round-robin algorithm. The calling process can be abstracted into the following table: - -| Pre-round sum weight | Current round winner | Total weight | Post-round weight (winner minus total weight) | -| :------------------ | :------- | :------- | :---------- ----------------- | -| Starting round | \ | \ | `A(0), B(0), C(0)` | -| `A(3), B(2), C(1)` | A | 6 | `A(-3), B(2), C(1)` | -| `A(0), B(4), C(2)` | B | 6 | `A(0), B(-2), C(2)` | -| `A(3), B(0), C(3)` | A | 6 | `A(-3), B(0), C(3)` | -| `A(0), B(2), C(4)` | C | 6 | `A(0), B(2), C(-2)` | -| `A(3), B(4), C(-1)` | B | 6 | `A(3), B(-2), C(-1)` | -| `A(6), B(0), C(0)` | A | 6 | `A(0), B(0), C(0)` | - -We found that after the total weight (3+2+1) rounds, the cycle returns to the starting point, the node traffic is smooth throughout the process, and even in a short period of time, the probability is distributed according to expectations. - -If users have the requirement of weighted polling, they can use this algorithm with confidence. - -### LeastActive -* **Weighted least active call priority**, the lower the active number, the higher the priority call, the same active number will be weighted randomly. The active number refers to the count difference before and after the call (for a specific provider: the number of requests sent - the number of responses returned), which indicates the amount of tasks accumulated by a specific provider. The lower the active number, the stronger the processing capability of the provider. -* Make the slow provider receive fewer requests, because the slower the provider, the greater the count difference before and after the call; relatively, the node with the stronger processing capacity can handle more requests. - -###ShortestResponse -* **Weighted Shortest Response Priority**, in the latest sliding window, the shorter the response time, the higher the priority to call. The same response time is weighted randomly. -* Make providers with faster response times handle more requests. -* Disadvantage: It may cause traffic to be too concentrated on high-performance nodes. - -Response time here = the average response time of a provider within the window time, and the default window time is 30s. - - -###ConsistentHash -* **Consistent Hash**, requests with the same parameters are always sent to the same provider. -* When a certain provider is down, the request originally sent to the provider will be spread to other providers based on the virtual node, and will not cause drastic changes. -* Algorithm see: [Consistent Hashing | WIKIPEDIA](http://en.wikipedia.org/wiki/Consistent_hashing) -* By default only the first parameter Hash, if you want to modify, please configure `` -* 160 virtual nodes are used by default, if you want to modify, please configure `` - -## configuration - -### Server service level - -```xml - -``` - -### Client service level - -```xml - -``` - -### Server method level - -```xml - - - -``` - -### Client method level - -```xml - - - -``` diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/profiler.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/profiler.md deleted file mode 100644 index 1f39dfb489b3..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/profiler.md +++ /dev/null @@ -1,189 +0,0 @@ ---- -type: docs -title: "Request time-consuming sampling" -linkTitle: "Request time-consuming sampling" -weight: 1 -description: "Dubbo 3 request time-consuming sampling" ---- - -## Function Description - -The performance sampling function can detect the time consumption of various parts of the Dubbo processing link. When a timeout occurs, `( usageTime / timeout > profilerWarnPercent * 100 )` records the time consumption of calls through logs. - -This function is divided into `simple profiler` and `detail profiler` two modes, where `simple profiler` mode is enabled by default, and `detail profiler` mode is disabled by default. -Compared with the `simple profiler` mode, the `detail profiler` collects more time-consuming processing of each filter, specific time-consuming protocols, etc. -In the `simple profiler` mode, if you find that there is a long time-consuming situation inside the Dubbo framework, you can enable the `detail profiler` mode to better troubleshoot the problem. - -## scenes to be used - -Scenarios that need to collect and analyze the precise time consumption of Dubbo requests, such as service timeouts for unknown reasons, etc. - -## How to use - -`simple profiler` is automatically enabled by default, and for requests whose processing time exceeds 3/4 of the timeout time, the slow call information will be printed out through the log. If you need to enable the `detail profiler` mode or modify the timeout alarm ratio, you can refer to the [performance sampling command](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/profiler/) document. - -### output example - -#### Log description - -The meaning of each field in the log is as follows: - -``` -[Dubbo-Consumer] execute service interface#method cost actual time-consuming, this invocation almost (maybe already) timeout. Timeout: timeout -invocation context: -request context -thread info: -Start time: start request time (nano time) -+-[ Offset: the start time of the current node; Usage: the total time spent on the current node, the time-consuming ratio of the current node ] Description of the current node - +-[ Offset: the start time of the current node; Usage: the total time spent on the current node, the time-consuming ratio of the current node ] Description of the current node -``` - -For the request time-consuming, here are two examples: - -``` -methodA() { - do something (1) - methodB (2) - do something (3) -} - -methodB() { - do something (4) - methodC (5) - do something (6) -} - -methodC() { - do something (7) -} - -+-[ Offset: 0 ms; Usage: (1) + (2) + (3) ms] execute methodA - +-[ Offset: (1) ms; Usage: (4) + (5) + (6) = (2) ms ] execute methodB - +-[ Offset: (1) + (4) ms; Usage: (7) = (5) ms ] execute methodC - -(1) (2) (3) ... are all time placeholders -``` - -``` -methodA() { - do something (1) - methodB (2) - methodE (3) - do something (4) -} - -methodB() { - do something (5) - methodC (6) - method D (7) - do something (8) -} - -methodC() { - do something (9) -} - -methodD() { - do something (10) -} - -methodE() { - do something (11) -} - -+-[ Offset: 0 ms; Usage: (1) + (2) + (3) + (4) ms] execute methodA - +-[ Offset: (1) ms; Usage: (5) + (6) + (7) + (8) = (2) ms ] execute methodB - +-[ Offset: (1) + (5) ms; Usage: (9) = (6) ms ] execute methodC - +-[ Offset: (1) + (5) + (6) ms; Usage: (10) = (7) ms ] execute methodD - +-[ Offset: (1) + (2) ms; Usage: (11) = (3) ms ] execute methodE - -(1) (2) (3) ... are all time placeholders -``` - -#### simple profiler - -Consumer side: -``` -[19/07/22 07:08:35:035 CST] main WARN proxy.InvokerInvocationHandler: [DUBBO] [Dubbo-Consumer] execute service org.apache.dubbo.samples.api.GreetingsService#sayHi cost 1003.015746 ms, this invocation almost (maybe already) timeout. Timeout: 1000ms -invocation context: -path=org.apache.dubbo.samples.api.GreetingsService; -remote.application=first-dubbo-consumer; -interface=org.apache.dubbo.samples.api.GreetingsService; -version=0.0.0; -timeout=1000; -thread info: -Start time: 285821581299853 -+-[ Offset: 0.000000ms; Usage: 1003.015746ms, 100% ] Receive request. Client invoke begin. ServiceKey: org.apache.dubbo.samples.api.GreetingsService MethodName:sayHi - +-[ Offset: 7.987015ms; Usage: 994.207928ms, 99% ] Invoker invoke. Target Address: xx.xx.xx.xx:20880, dubbo version: 3.0.10-SNAPSHOT, current host: xx.xx.xx. xx -``` - -Provider side: -``` -[19/07/22 07:08:35:035 CST] DubboServerHandler-30.227.64.173:20880-thread-2 WARN filter.ProfilerServerFilter: [DUBBO] [Dubbo-Provider] execute service org.apache.dubbo.samples.api .GreetingsService:0.0.0#sayHi cost 808.494672 ms, this invocation almost (maybe already) timeout. Timeout: 1000ms -client: xx.xx.xx.xx:51604 -invocation context: -input=281; -path=org.apache.dubbo.samples.api.GreetingsService; -remote.application=first-dubbo-consumer; -dubbo=2.0.2; -interface=org.apache.dubbo.samples.api.GreetingsService; -version=0.0.0; -timeout=1000; -thread info: -Start time: 285821754461125 -+-[ Offset: 0.000000ms; Usage: 808.494672ms, 100% ] Receive request. Server invoke begin. - +-[ Offset: 1.030912ms; Usage: 804.236342ms, 99% ] Receive request. Server biz impl invoke begin., dubbo version: 3.0.10-SNAPSHOT, current host: xx.xx.xx.xx -``` - -#### detail profiler - -Consumer side: -``` -[19/07/22 07:10:59:059 CST] main WARN proxy.InvokerInvocationHandler: [DUBBO] [Dubbo-Consumer] execute service org.apache.dubbo.samples.api.GreetingsService#sayHi cost 990.828336 ms, this invocation almost (maybe already) timeout. Timeout: 1000ms -invocation context: -path=org.apache.dubbo.samples.api.GreetingsService; -remote.application=first-dubbo-consumer; -interface=org.apache.dubbo.samples.api.GreetingsService; -version=0.0.0; -timeout=1000; -thread info: -Start time: 285965458479241 -+-[ Offset: 0.000000ms; Usage: 990.828336ms, 100% ] Receive request. Client invoke begin. ServiceKey: org.apache.dubbo.samples.api.GreetingsService MethodName:sayHi - +-[ Offset: 0.852044ms; Usage: 989.899439ms, 99% ] Filter org.apache.dubbo.rpc.cluster.filter.support.ConsumerContextFilter invoke. - +-[ Offset: 1.814858ms; Usage: 988.924876ms, 99% ] Filter org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter invoke. - +-[ Offset: 1.853211ms; Usage: 988.877928ms, 99% ] Filter org.apache.dubbo.monitor.support.MonitorClusterFilter invoke. - +-[ Offset: 1.873243ms; Usage: 988.661708ms, 99% ] Filter org.apache.dubbo.rpc.cluster.router.RouterSnapshotFilter invoke. - +-[ Offset: 2.159140ms; Usage: 0.504939ms, 0% ] Router route. - +-[ Offset: 8.125823ms; Usage: 981.748366ms, 99% ] Cluster org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker invoke. - +-[ Offset: 8.258359ms; Usage: 981.612033ms, 99% ] Invoker invoke. Target Address: xx.xx.xx.xx:20880, dubbo version: 3.0.10-SNAPSHOT, current host: xx.xx.xx. xx -``` - -Provider side: -``` -[19/07/22 07:10:59:059 CST] DubboServerHandler-30.227.64.173:20880-thread-2 WARN filter.ProfilerServerFilter: [DUBBO] [Dubbo-Provider] execute service org.apache.dubbo.samples.api .GreetingsService:0.0.0#sayHi cost 811.017347 ms, this invocation almost (maybe already) timeout. Timeout: 1000ms -client: xx.xx.xx.xx:52019 -invocation context: -input=281; -path=org.apache.dubbo.samples.api.GreetingsService; -remote.application=first-dubbo-consumer; -dubbo=2.0.2; -interface=org.apache.dubbo.samples.api.GreetingsService; -version=0.0.0; -timeout=1000; -thread info: -Start time: 285965612316294 -+-[ Offset: 0.000000ms; Usage: 811.017347ms, 100% ] Receive request. Server invoke begin. - +-[ Offset: 1.096880ms; Usage: 809.916668ms, 99% ] Filter org.apache.dubbo.rpc.filter.EchoFilter invoke. - +-[ Offset: 1.133478ms; Usage: 809.866204ms, 99% ] Filter org.apache.dubbo.rpc.filter.ClassLoaderFilter invoke. - +-[ Offset: 1.157563ms; Usage: 809.838572ms, 99% ] Filter org.apache.dubbo.rpc.filter.GenericFilter invoke. - +-[ Offset: 1.202075ms; Usage: 809.736843ms, 99% ] Filter org.apache.dubbo.rpc.filter.ContextFilter invoke. - +-[ Offset: 1.433193ms; Usage: 809.504401ms, 99% ] Filter org.apache.dubbo.auth.filter.ProviderAuthFilter invoke. - +-[ Offset: 1.470760ms; Usage: 809.464291ms, 99% ] Filter org.apache.dubbo.rpc.filter.ExceptionFilter invoke. - +-[ Offset: 1.489103ms; Usage: 809.440183ms, 99% ] Filter org.apache.dubbo.monitor.support.MonitorFilter invoke. - +-[ Offset: 1.515757ms; Usage: 809.381893ms, 99% ] Filter org.apache.dubbo.rpc.filter.TimeoutFilter invoke. - +-[ Offset: 1.526632ms; Usage: 809.366553ms, 99% ] Filter org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter invoke. - +-[ Offset: 1.536964ms; Usage: 809.335907ms, 99% ] Filter org.apache.dubbo.rpc.filter.ClassLoaderCallbackFilter invoke. - +-[ Offset: 1.558545ms; Usage: 804.276436ms, 99% ] Receive request. Server biz impl invoke begin., dubbo version: 3.0.10-SNAPSHOT, current host: xx.xx.xx.xx -``` - -Note: If the log is empty due to the mismatch of the log framework, you can refer to [Log Framework Adaptation and Runtime Management](../../others/logger-management/) to dynamically modify the log output framework. diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/reference-config-cache.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/reference-config-cache.md deleted file mode 100644 index 0228901c1db9..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/reference-config-cache.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -type: docs -title: "Service Reference Configuration Object Cache" -linkTitle: "Service Reference Configuration Object Cache" -weight: 2 -description: "Cache ReferenceConfig in Dubbo3" ---- -## Feature description - -The `ReferenceConfig` instance is heavy, encapsulates the connection to the registry and the connection to the provider, and needs to be cached. Otherwise repeatedly generating `ReferenceConfig` may cause performance problems and have memory and connection leaks. It's easy to overlook this problem when programming in the API way. - -Therefore, since `2.4.0` version, dubbo provides a simple tool class `ReferenceConfigCache` for caching `ReferenceConfig` instances. -## scenes to be used - -There are scenarios such as gateways that dynamically create subscriptions. Because ReferenceConfig itself is very heavy, it will create a lot of intermediate objects, and proxy itself can be reused, so the properties of this part can be cached through ReferenceConfigCache. - -## How to use -### Eliminate and destroy -Eliminating the `ReferenceConfig` in the Cache will destroy the `ReferenceConfig` and release the corresponding resources. -```java -ReferenceConfig reference = new ReferenceConfig(); -reference.setInterface(XxxService.class); -reference.setVersion("1.0.0"); - … -ReferenceConfigCache cache = ReferenceConfigCache. getCache(); -// The reference object will be cached in the cache.get method, and the ReferenceConfig.get method will be called to start the ReferenceConfig -XxxService xxxService = cache. get(reference); -// Notice! The Cache will hold the ReferenceConfig, do not call the destroy method of the ReferenceConfig outside, causing the ReferenceConfig in the Cache to become invalid! -// Use the xxxService object -xxxService. sayHello(); -``` -```java -ReferenceConfigCache cache = ReferenceConfigCache. getCache(); -cache.destroy(reference); -``` -The default `ReferenceConfigCache` considers `ReferenceConfig` of the same service group, interface, and version to be the same, and caches a copy. That is, the service group, interface, and version are cached keys. - -### Modify strategy -You can modify this strategy to pass a `KeyGenerator` when `ReferenceConfigCache.getCache`. See methods of the `ReferenceConfigCache` class for details. -```java -KeyGenerator keyGenerator = new... -ReferenceConfigCache cache = ReferenceConfigCache. getCache(keyGenerator); -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/result-cache.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/result-cache.md deleted file mode 100644 index 068bcbc34bfa..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/result-cache.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -type: docs -title: "Call Result Cache" -linkTitle: "Call result cache" -weight: 7 -description: "Speed up access by caching results" ---- -## Feature description - -#### cache type - -* `lru` deletes redundant caches based on the least recently used principle, keeping the hottest data cached. -* `threadlocal` The current thread cache, such as a page rendering, uses many portals, and each portal needs to check user information. Through thread caching, this redundant access can be reduced. -* `jcache` integrates with [JSR107](http://jcp.org/en/jsr/detail?id=107%27) to bridge various cache implementations. - -Cache Type Extensible [Cache Extensions](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/cache) - -About [sample code](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-cache) - -## scenes to be used - -The result cache is used to speed up access to popular data. Dubbo provides a declarative cache to reduce the workload of users adding cache. - -## How to use - -```xml - -``` - -or: - -```xml - - - -``` diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/router-snapshot.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/router-snapshot.md deleted file mode 100644 index 9d294101c72b..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/router-snapshot.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -type: docs -title: "Routing Status Collection" -linkTitle: "Routing Status Collection" -weight: 2 -description: "routing status collection" ---- -## Function Description -## scenes to be used - -Many of Dubbo's traffic management capabilities are implemented based on Router. In a production environment, if traffic results do not meet expectations, you can use the routing status command to check the routing status to locate possible problems. - -## How to use - -### View route cache status - -When Dubbo receives the address change, it will push the address information to all `Routers`, and these `Routers` can calculate the routing packets in advance at this stage and cache them to avoid the need to traverse all provider calculations when calling grouping parameters. -The `StateRouter` introduced in Dubbo 3 provides the ability to obtain the status of each route in real time through the qos command tool. - -The operation and maintenance personnel can obtain the status of the route through the `getRouterSnapshot` command. For specific commands, please refer to the [getRouterSnapshot command](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/router-snapshot/#getroutersnapshot-command) document. - -**Note: This feature only supports `StateRoute`, and `StateRouter` needs to implement the `doBuildSnapshot` interface based on `AbstractStateRouter`. ** - -### View the route calculation result of the actual request - -By default in Dubbo 3, the node status of route calculation is printed when the route filter is empty. Operation and maintenance personnel can judge whether the calculation result of each route meets expectations through logs. - -#### Log format - -``` -No provider available after route for the service service from registry registration center address on the consumer consumer IP using the dubbo version 3.0.7. Router snapshot is below: -[ Parent (Input: Number of input addresses of the current node) (Current Node Output: Number of calculation results of the current node) (Chain Node Output: Number of intersection results of the current node and subsequent nodes) ] Input: Examples of input addresses (up to 5 are displayed) -> Chain Node Output: Example of addresses output by the current node (up to 5 are displayed) - [Route name (Input: number of input addresses of the current node) (Current Node Output: number of calculation results of the current node) (Chain Node Output: number of intersection results of the current node and subsequent nodes) Router message: routing log] Current Node Output: current node Example of addresses output (up to 5 displayed) - [routing name (Input: current node input address number) (Current Node Output: current node calculation result number) (Chain Node Output: current node and subsequent node intersection result number) Router message: routing log] Current Node Output: current input Examples of addresses for (show up to 5) -``` - -#### Notice: -- The routing log needs to rely on the routing implementation to judge the `needToPrintMessage` parameter, and write the `messageHolder` routing log when needed -- Since the result of multi-level routing is the intersection of the results, the calculation result of the current node may be empty after the intersection with the subsequent level - -#### Log example - -``` -[19/07/22 07:42:46:046 CST] main WARN cluster.RouterChain: [DUBBO] No provider available after route for the service org.apache.dubbo.samples.governance.api.DemoService from registry 30.227.64.173 on the consumer 30.227.64.173 using the dubbo version 3.0.7. Router snapshot is below: -[ Parent (Input: 2) (Current Node Output: 2) (Chain Node Output: 0) ] Input: 30.227.64.173:20881,30.227.64.173:20880 -> Chain Node Output: Empty - [ MockInvokersSelector (Input: 2) (Current Node Output: 2) (Chain Node Output: 0) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 30.227.64.173:20881,30.223.64.17 :20880 - [ StandardMeshRuleRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 0) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 30.227.64.173:20881,30.227.624.1803: - [ TagStateRouter (Input: 2) (Current Node Output: 0) (Chain Node Output: 0) Router message: FAILOVER: return all Providers without any tags ] Current Node Output: Empty, dubbo version: 3.0.7, current host: 30.227 .64.173 -``` - -#### Open route full sampling - -In some special cases, the request may be called to the wrong server, but because the address selection is not empty, the process information of the route cannot be seen. At this time, you can [Enable full route sampling through qos](../../. ./reference-manual/qos/router-snapshot/). The latest routing snapshot can be obtained remotely through the `getRecentRouterSnapshot` command of qos. - -``` -dubbo>getRecentRouterSnapshot -1658224330156 - Router snapshot service com.dubbo.dubbointegration.BackendService from registry 172.18.111.184 on the consumer 172.18.111.184 using the dubbo version 3.0.9 is below: -[ Parent (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) ] Input: 172.18.111.187:20880,172.18.111.183:20880 -> Chain Node Output: 172.18.111.187:20880.3172.18 :20880 - [ MockInvokersSelector (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 172.18.111.187:20880,172.183.111. :20880 - [ StandardMeshRuleRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 172.18.111.187:20880,172.1803:1121.88 - [ TagStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: 172.18.111.187:20880,172.183.111. 20880 - [ ServiceStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880 ,172.18.111.183:20880 - [ AppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880 ,172.18.111.183:20880 - -1658224330156 - Router snapshot service com.dubbo.dubbointegration.BackendService from registry 172.18.111.184 on the consumer 172.18.111.184 using the dubbo version 3.0.9 is below: -[ Parent (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) ] Input: 172.18.111.187:20880,172.18.111.183:20880 -> Chain Node Output: 172.18.111.187:20880.3172.18 :20880 - [ MockInvokersSelector (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 172.18.111.187:20880,172.183.111. :20880 - [ StandardMeshRuleRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 172.18.111.187:20880,172.1803:1121.88 - [ TagStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: 172.18.111.187:20880,172.183.111. 20880 - [ ServiceStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880 ,172.18.111.183:20880 - [ AppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880 ,172.18.111.183:20880 - -··· - -dubbo> -``` - -#### Notice: -If the log is empty due to the mismatch of the log framework, you can refer to [Log Framework Adaptation and Runtime Management](../../others/logger-management/) to dynamically modify the log output framework. diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/serialization.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/serialization.md deleted file mode 100644 index 865ece825f66..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/serialization.md +++ /dev/null @@ -1,241 +0,0 @@ ---- -type: docs -title: "Kryo and FST Serialization" -linkTitle: "Kryo and FST serialization" -weight: 46 -description: "Using efficient Java serialization (Kryo and FST) in Dubbo" ---- - -## Table of contents - -* Serialization talk -* Enable Kryo and FST -* Register the class to be serialized -* No parameter constructor and Serializable interface -* Serialization performance analysis and testing - * test environment - * Test script - * Comparison of byte sizes generated by different serializations in Dubbo RPC - * Comparison of response time and throughput of different serializations in Dubbo RPC -* future - - -## Serialization talk - -dubbo RPC is the core high-performance, high-throughput remote call method in the dubbo system. I like to call it a multiplexed TCP long connection call. Simply put: - -* Long connection: avoiding the need to create a new TCP connection each time, improving the response speed of the call -* Multiplexing: A single TCP connection can alternately transmit multiple request and response messages, reducing the waiting idle time of the connection, thereby reducing the number of network connections under the same concurrent number and improving system throughput. - -dubbo RPC is mainly used for remote calls between two dubbo systems, especially suitable for Internet scenarios with high concurrency and small data. - -Serialization also plays a vital role in the response speed, throughput, and network bandwidth consumption of remote calls, and is one of the most critical factors for us to improve the performance of distributed systems. - -In dubbo RPC, multiple serialization methods are supported at the same time, for example: - -1. Dubbo serialization: Ali has not yet developed a mature and efficient java serialization implementation, and Ali does not recommend using it in a production environment -1. Hessian2 serialization: Hessian is a cross-language efficient binary serialization method. But here is actually not the original hessian2 serialization, but the hessian lite modified by Ali, which is the default serialization method enabled by dubbo RPC -1. JSON serialization: There are currently two implementations, one is to use Ali's fastjson library, and the other is to use the simple json library implemented by dubbo, but the implementation is not particularly mature, and the text sequence of json The serialization performance is generally not as good as the above two binary serializations. -1. Java serialization: It is mainly implemented by using the Java serialization that comes with the JDK, and the performance is not ideal. - -In general, the performance of the four main serialization methods decreases from top to bottom. For dubbo RPC, which pursues high-performance remote calls, there are actually only two high-efficiency serialization methods, 1 and 2, that are more suitable, and the first dubbo serialization is still immature, so only 2 is actually available. So dubbo RPC uses hessian2 serialization by default. - -But hessian is an older serialization implementation, and it is cross-language, so it is not optimized for java alone. In fact, dubbo RPC is a remote call from Java to Java. In fact, there is no need to adopt cross-language serialization (of course, cross-language serialization is certainly not excluded). - -In recent years, various new efficient serialization methods have emerged one after another, constantly refreshing the upper limit of serialization performance, the most typical ones include: - -* Specifically for the Java language: Kryo, FST, etc. -* Cross-language: Protostuff, ProtoBuf, Thrift, Avro, MsgPack, etc. - -The performance of most of these serialization methods is significantly better than hessian2 (even including the immature dubbo serialization). - -In view of this, we introduce two efficient Java serialization implementations, Kryo and FST, for dubbo to gradually replace hessian2. - -Among them, Kryo is a very mature serialization implementation, which has been widely used in Twitter, Groupon, Yahoo and many famous open source projects (such as Hive and Storm). While FST is a newer serialization implementation, it still lacks enough mature use cases, but I think it is still very promising. - -In production-oriented applications, I recommend Kryo as the preferred choice for now. - -## Enable Kryo and FST - -Using Kryo and FST is very simple, just add the corresponding dependencies first: -More plugins: [Dubbo SPI Extensions](/zh-cn/download/spi-extensions) - -```xml - - org.apache.dubbo.extensions - dubbo-serialization-kryo - 1.0.0 - -``` - -```xml - - org.apache.dubbo.extensions - dubbo-serialization-fst - 1.0.0 - -``` - -Then add an attribute in the XML configuration of dubbo RPC: - -```xml - -``` - -```xml - -``` - -## Register the class to be serialized - -To make Kryo and FST fully perform with high performance, it is best to register those classes that need to be serialized in the dubbo system. For example, we can implement the following callback interface: - -```java -public class SerializationOptimizerImpl implements SerializationOptimizer { - - public Collection getSerializableClasses() { - List classes = new LinkedList(); - classes.add(BidRequest.class); - classes. add(BidResponse. class); - classes. add(Device. class); - classes. add(Geo. class); - classes. add(Impression. class); - classes.add(SeatBid.class); - return classes; - } -} -``` - -Then add in XML configuration: - -```xml - -``` - -After registering these classes, serialization performance may be greatly improved, especially for small numbers of nested objects. - -Of course, when serializing a class, many classes may be cascaded, such as Java collection classes. In response to this situation, we have automatically registered common classes in the JDK, so you don't need to register them repeatedly (of course, there is no effect if you register repeatedly), including: - -``` -Gregorian Calendar -InvocationHandler -BigDecimal -BigInteger -pattern -BitSet -URIs -UUID -HashMap -ArrayList -LinkedList -HashSet -TreeSet -Hashtable -date -Calendar -ConcurrentHashMap -SimpleDateFormat -vector -BitSet -StringBuffer -String Builder -object -Object[] -String[] -byte[] -char[] -int[] -float[] -double[] -``` - -Since registering classes to be serialized is only for performance optimization purposes, it doesn't matter if you forget to register some classes. In fact, even without registering any classes, the performance of Kryo and FST is generally better than that of hessian and dubbo serialization. - -> Of course, someone may ask why not use configuration files to register these classes? This is because there are often a large number of classes to be registered, resulting in lengthy configuration files; and without good IDE support, writing and refactoring configuration files are much more troublesome than java classes; finally, these registered classes are generally It is not necessary to make dynamic modifications after the project is compiled and packaged. - -> In addition, some people will also think that manually registering the serialized class is a relatively cumbersome work, can it be marked with annotation, and then the system will automatically discover and register. But the limitation of annotation here is that it can only be used to mark classes that you can modify, and many classes referenced in serialization are likely to be things that you cannot modify (such as third-party libraries or JDK system classes or classes of other projects ). In addition, adding annotation after all slightly "polluted" the code, making the application code a little bit more dependent on the framework. - -> In addition to annotation, we can also consider other ways to automatically register serialized classes, such as scanning the class path, automatically discovering classes that implement the Serializable interface (even including Externalizable) and registering them. Of course, we know that there may be a lot of Serializable classes on the classpath, so we can also consider using package prefixes to limit the scanning range to a certain extent. - -> Of course, in the automatic registration mechanism, it is especially necessary to consider how to ensure that both the service provider and the consumer register classes in the same order (or ID) to avoid misalignment. After all, the number of classes that can be discovered and registered at both ends may be the same. are different. - -## No parameter constructor and Serializable interface - -If the class to be serialized does not contain a parameterless constructor, the performance of Kryo's serialization will be greatly reduced, because at this time we will use Java's serialization to transparently replace Kryo's serialization at the bottom layer. Therefore, it is a best practice to add a no-argument constructor for each serialized class as much as possible (of course, if a java class does not customize a constructor, it will have a no-argument constructor by default). - -In addition, Kryo and FST do not require the serialized class to implement the Serializable interface, but we still recommend that every serialized class implement it, because this can maintain compatibility with Java serialization and dubbo serialization. In addition It also makes it possible for us to adopt some of the above automatic registration mechanisms in the future. - -## Serialization performance analysis and testing - -In this article, we mainly discuss serialization, but when doing performance analysis and testing, we do not deal with each serialization method separately, but put them in dubbo RPC for comparison, because this is more realistic. - -### test environment - -Roughly as follows: - -* Two independent servers -* Quad-core Intel(R) Xeon(R) CPU E5-2603 0 @ 1.80GHz -* 8G memory -* The network between virtual machines passes through a 100M switch -* CentOS 5 -* JDK 7 -* Tomcat 7 -* JVM parameters -server -Xms1g -Xmx1g -XX:PermSize=64M -XX:+UseConcMarkSweepGC - -Of course, the test environment is limited, so the current test results may not be very authoritative and representative. - -### Test script - -Keeping close to dubbo's own benchmarks: - -10 concurrent clients continuously making requests: - -* Pass in a nested complex object (but the amount of individual data is small), do not do any processing, and return as it is -* Pass in 50K strings, do not do any processing, and return as they are (TODO: the result has not been listed yet) - -Run a 5-minute performance test. (Quoting dubbo's own test considerations: "It mainly examines the performance of serialization and network IO, so the server does not have any business logic. The reason for taking 10 concurrency is to consider that the rpc protocol may have a high CPU usage rate under high concurrency. to the bottleneck.") - -### Comparison of byte sizes generated by different serializations in Dubbo RPC - -The size of the number of bytes generated by serialization is a relatively deterministic indicator, which determines the network transmission time and bandwidth occupation of the remote call. - -The results for complex objects are as follows (lower numbers are better): - -| Serialization Implementation | Request Bytes | Response Bytes | -| ----------- | ------------- | ------------- | -| Kryo | 272 | 90 | -| FST | 288 | 96 | -| Dubbo Serialization | 430 | 186 | -| Hessian | 546 | 329 | -| FastJson | 461 | 218 | -| Json | 657 | 409 | -| Java Serialization | 963 | 630 | - - -### Comparison of different serialization response time and throughput in Dubbo RPC - -| Remote call method | Average response time | Average TPS (transactions per second) | -| ----------- | ------------- | ------------- | -| REST: Jetty + JSON | 7.806 | 1280 | -| REST: Jetty + JSON + GZIP | TODO | TODO | -| REST: Jetty + XML | TODO | TODO | -| REST: Jetty + XML + GZIP | TODO | TODO | -| REST: Tomcat + JSON | 2.082 | 4796 | -| REST: Netty + JSON | 2.182 | 4576 | -| Dubbo: FST | 1.211 | 8244 | -| Dubbo: kyro | 1.182 | 8444 | -| Dubbo: dubbo serialization | 1.43 | 6982 | -| Dubbo: hessian2 | 1.49 | 6701 | -| Dubbo: fastjson | 1.572 | 6352 | - -![rt](/imgs/user/rt.png) - -![tps](/imgs/user/tps.png) - -### Test Summary - -As far as the current results are concerned, we can see that Kryo and FST have significantly improved compared to the original serialization method in Dubbo RPC, regardless of the size of generated bytes, average response time and average TPS. - -## future - -In the future, when Kryo or FST is mature enough in dubbo, we will probably change the default serialization of dubbo RPC from hessian2 to one of them. diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/simplify-registry-data.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/simplify-registry-data.md deleted file mode 100644 index 60db7c0b6c14..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/simplify-registry-data.md +++ /dev/null @@ -1,255 +0,0 @@ ---- -type: docs -title: "Registration Information Simplified" -linkTitle: "Registration Information Simplified" -weight: 3 -description: "Learn about dubbo3 to reduce the registration data of services on the registry" ---- - -## Feature description - -There are nearly [30 configuration items](/zh-cn/docs/references/xml/dubbo-parameter) in the service configuration items in Dubbo provider. Excluding the need for registry service governance, a large part of configuration items are used by the provider itself and do not need to be transparently passed to consumers. This part of data does not need to enter the registry, but only needs to be stored persistently in the form of key-value. - -The configuration items in Dubbo consumer also have [20+ configuration items](/zh-cn/docs/references/xml/dubbo-consumer). In the registration center, only a small amount of configuration such as application, version, group, ip, and dubbo version need to be concerned in the service consumer list, and other configurations can also be stored persistently in the form of key-value. -These data are registered into the registration center in the dimension of service, which leads to the expansion of the data volume, which in turn leads to an increase in the network overhead of the registration center (such as zookeeper) and a decrease in performance. - -#### Design goals and objectives -It is desirable to simplify the number of provider and consumer configurations that go into the registry. -It is expected that some configuration items will be stored in other forms. These configuration items need to be satisfied: not on the service call link, and these configuration items are not on the core link of the registration center (service query, service list). - -#### Configuration - -Simplify the configuration of the registry, only supported in versions after 2.7. -After enabling provider or consumer to simplify the configuration, the default reserved configuration items are as follows: - -provider: - -| Constant Key | Key | remark | -| ------ |---------------| ------ | -| APPLICATION_KEY | application | | -| CODEC_KEY | codec | | -| EXCHANGER_KEY | exchanger | | -| SERIALIZATION_KEY | serialization | | -| CLUSTER_KEY | cluster | | -| CONNECTIONS_KEY | connections | | -| DEPRECATED_KEY | deprecated | | -| GROUP_KEY | group | | -| LOADBALANCE_KEY | loadbalance | | -| MOCK_KEY | mock | | -| PATH_KEY | path | | -| TIMEOUT_KEY | timeout | | -| TOKEN_KEY | token | | -| VERSION_KEY | version | | -| WARMUP_KEY | warmup | | -| WEIGHT_KEY | weight | | -| DUBBO_VERSION_KEY | dubbo | | -| RELEASE_KEY | release | | -| SIDE_KEY | side | | - - -consumer: - -| Constant Key | Key | remark | -| ------ | ------ | ------ | -| APPLICATION_KEY | application | | -| VERSION_KEY | version | | -| GROUP_KEY | group | | -| DUBBO_VERSION_KEY | dubbo | | - -Constant Key represents a field from the class org.apache.dubbo.common.Constants. - -The following introduces several commonly used methods. All samples, you can view [sample-2.7](https://github.com/dubbo/dubbo-samples/tree/master) - -## scenes to be used - -A large amount of data leads to an increase in the network overhead of the registration center and a decrease in performance. - -## How to use - -**EXISTING FUNCTIONALITY sample** A simple demonstration of the current state of affairs. Through this demonstration, analyze why simplified configuration is needed. - -Refer to the sample subproject: dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-nosimple (before running the sample, first run ZKClean to clean up the configuration items) - -##### dubbo-provider.xml configuration: - -``` - - - - -``` - -After starting the provider's main method, view the content of the zookeeper leaf node (path: /dubbo/org.apache.dubbo.samples.simplified.registry.nosimple.api.DemoService/providers directory) as follows: - -``` -dubbo%3A%2F%2F30.5.124.158%3A20880%2Forg.apache.dubbo.samples.simplified.registry.nosimple.api.DemoService -%3Fanyhost%3Dtrue%26application%3Dsimplified-registry-xml-provider%26async%3Dtrue%26dubbo%3D -2.0.2%26executes%3D4500%26generic%3Dfalse%26group%3Ddubbo-simple%26interface%3D -org.apache.dubbo.samples.simplified.registry.nosimple.api.DemoService%26methods%3D -sayHello%26owner%3Dvict%26pid%3D2767%26retries%3D7%26revision%3D1.2.3%26side%3D -provider%26timeout%3D5300%26timestamp%3D1542361152795%26valid%3Dtrue%26version%3D1.2.3 -``` - -You can see that there are: `executes`, `retries`, `owner`, `timeout`. But not all these fields need to be passed to dubbo ops or dubbo consumer. Similarly, the consumer also has this problem, which can be viewed by starting the main method of the consumer in the example. - - - -### Method 1. Configure dubbo.properties - -The sample is under the dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-xml project (before running the sample, first run ZKClean to clean up the configuration items) - -##### dubbo.properties - -```properties -dubbo.registry.simplified=true -dubbo.registry.extra-keys=retries,owner -``` -Compared with the **existing function sample** above, in the above sample, the four configuration items of executes, retries, owner, and timeout have all entered the registration center. But this example is not, the configuration is divided into: - -* Configuration: dubbo.registry.simplified=true, by default, timeout is in the default configuration item list, so it will still enter the registry; -* Configuration: dubbo.registry.extra-keys=retries,owner, so retries, owner will also enter the registry. - -configuration type: -- provider side configuration -- consumer side configuration - -#### Provider side configuration: - -```xml - - - - - - - - -``` -Get the value of the leaf node of zookeeper: -``` -dubbo%3A%2F%2F30.5.124.149%3A20880%2Forg.apache.dubbo.samples.simplified.registry.nosimple.api.DemoService%3F -application%3Dsimplified-registry-xml-provider%26dubbo%3D2.0.2%26group%3Ddubbo-simple%26owner%3D -vict%26retries%3D7%26timeout%3D5300%26timestamp%3D1542594503305%26version%3D1.2.3 -``` - -#### consumer side configuration -* Configuration: dubbo.registry.simplified=true -* Default: application, version, group, and dubbo are in the default configuration item list, so they will still enter the registration center. -```xml - - - - - - - - - - -``` -Get the value of the leaf node of zookeeper: -``` -consumer%3A%2F%2F30.5.124.149%2Forg.apache.dubbo.samples.simplified.registry.nosimple.api.DemoService%3F -actives%3D6%26application%3Dsimplified-registry-xml-consumer%26category%3D -consumers%26check%3Dfalse%26dubbo%3D2.0.2%26group%3Ddubbo-simple%26owner%3Dvvv%26version%3D1.2.3 -``` - -### Method 2. Configuration declaration spring bean - -The sample is under the dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-annotation project (before running the sample, first run ZKClean to clean up the configuration items) - -The effect of dubbo.properties in the above sample is the same. - -* Default: timeout is in the default configuration item list, so it will still enter the registration center; -* Configuration: retries, owner enter the registry as an additional key, so retries, owner will also enter the registry. - -configuration type: - --Provider configuration --Consumer configuration - -#### Provider configuration - -##### private side bean configuration: -```java -// Equivalent to dubbo.properties configuration, configured in the form of @Bean -@Bean -public RegistryConfig registryConfig() { - RegistryConfig registryConfig = new RegistryConfig(); - registryConfig.setAddress("zookeeper://127.0.0.1:2181"); - registryConfig.setSimplified(true); - registryConfig.setExtraKeys("retries,owner"); - return registryConfig; -} -``` - -```java -// expose the service -@Service(version = "1.1.8", group = "d-test", executes = 4500, retries = 7, owner = "victanno", timeout = 5300) -public class AnnotationServiceImpl implements AnnotationService { - @Override - public String sayHello(String name) { - System.out.println("async provider received: " + name); - return "annotation: hello, " + name; - } -} -``` -#### Consumer configuration - -It is the same as **consumer side configuration** in the sample above. - -Default: application, version, group, and dubbo are in the default configuration item list, so they will still enter the registration center. - -##### consumer side bean configuration: -```java -@Bean -public RegistryConfig registryConfig() { - RegistryConfig registryConfig = new RegistryConfig(); - registryConfig.setAddress("zookeeper://127.0.0.1:2181"); - registryConfig.setSimplified(true); - return registryConfig; - } -``` - -Consumer Services: - -```java -@Component("annotationAction") -public class AnnotationAction { - - @Reference(version = "1.1.8", group = "d-test", owner = "vvvanno", retries = 4, actives = 6, timeout = 4500) - private AnnotationService annotationService; - public String doSayHello(String name) { - return annotationService.sayHello(name); - } -} -``` -#### Notice: -If there are both provider and consumer in an application, the configuration needs to be merged into: -```java -@Bean -public RegistryConfig registryConfig() { - RegistryConfig registryConfig = new RegistryConfig(); - registryConfig.setAddress("zookeeper://127.0.0.1:2181"); - registryConfig.setSimplified(true); - //Only valid for provider - registryConfig.setExtraKeys("retries,owner"); - return registryConfig; -} -``` - -#### hint: - -This version also retains a large number of configuration items, and in the next version, all configuration items will be gradually deleted. diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/stickiness.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/stickiness.md deleted file mode 100644 index 9b35f4b2cbf3..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/stickiness.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -type: docs -title: "Stick Connection" -linkTitle: "Stick connection" -weight: 31 -description: "Configure sticky connections for stateful services" ---- -## Feature description - -## scenes to be used -Sticky connections are used for stateful services, so that the client always initiates calls to the same provider as much as possible, unless the provider hangs up and connects to another one. - -Sticky connection will automatically enable [Delayed Connection](../lazy-connect) to reduce the number of long connections. - -## How to use -```xml - -``` - -Dubbo supports method-level sticky connections, if you want more fine-grained control, you can also configure it like this. - -```xml - - - -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/support-graalvm.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/support-graalvm.md deleted file mode 100644 index 273d30c3641b..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/support-graalvm.md +++ /dev/null @@ -1,213 +0,0 @@ ---- -type: docs -title: "Support Graal VM" -linkTitle: "Support Graal VM" -weight: 40 -description: "" ---- - -dubbo3.0 supports native-image document - -## Feature description -This document will introduce the process of connecting dubbo3.0 project to GraalVM and compiling native-image into binary. - -More information about GraalVm can be read https://www.graalvm.org/docs/getting-started/container-images/ this document. - -## scenes to be used - -## How to use -Before compiling our dubbo project, we need to make sure that we are based on the graalVm environment. - -### Install GraalVM -Go to https://www.graalvm.org/ official website and select the latest version to install according to your own system: - -![img](/imgs/blog/dubbo3.0-graalvm-support/graalvmgw.jpg) - -After the installation is complete, modify the path to configure JAVA_HOME, and check the local jdk after it takes effect, you can see the following: - -![img](/imgs/blog/dubbo3.0-graalvm-support/graalvm_env.jpg) -Here we use GraalVM based on jdk1.8 version. - -- To install native-image, just execute gu install native-image. - -1. Pull the dubbo code and switch to the [apache:3.0](https://github.com/apache/dubbo) branch. -2. Manually execute the generated SPI code. - -Since the current compilation of native-image does not support code dynamic generation and compilation, the part related to code dynamic generation needs to be generated manually. Here is a tool function: - -![img](/imgs/blog/dubbo3.0-graalvm-support/code_generator.jpg) -Execute CodeGenerator to generate SPI code under the dubbo-native module. - -### Execute install in the root directory - -``` -MacdeMacBook-pro-3:incubator-dubbo mac$ pwd - -/Users/mac/Documents/Mi/project/incubator-dubbo - -MacdeMacBook-pro-3:incubator-dubbo mac$ mvn clean package install -Dmaven.test.skip=true -``` - -### Compile the demo project - -Here we provide a sample project that can be directly compiled, dubbo-demo/dubbo-demo-native. After the above steps are installed, first go to the provider of dubbo-demo-native and execute native-image compilation: - -``` - mvn clean package -P native -Dmaven.test.skip=true -``` - -Here, since we have introduced the native-image plug-in in maven, the plug-in can be executed directly -P native. - -![img](/imgs/blog/dubbo3.0-graalvm-support/native_image_build.jpg) -After the compilation is successful, you can see the generated binary file under the target, start a zookeeper locally, and execute the binary directly. It can be seen that the startup is successful as follows: - -![img](/imgs/blog/dubbo3.0-graalvm-support/run_provider.jpg) -The consumer side also executes compilation, and a binary file is also generated under the consumer target: demo-native-consumer. Execute this binary and you can see the result of the call as follows: - -![img](/imgs/blog/dubbo3.0-graalvm-support/run_consumer.jpg) -### Specific steps - -In fact, we have done some work under this demo to ensure that the project can be compiled and executed. There are mainly the following steps - -- Introduce dubbo-native dependency - -``` - - - org.apache.dubbo - - dubbo-native - - ${project.version} - - -``` - -Under this module is the SPI code we generated. - -- Introduce native-image plugin - -``` - - - org.graalvm.nativeimage - - native-image-maven-plugin - - 21.0.0.2 - - - - - - - - native-image - - - - package - - - - - - - - false - - demo-native-provider - - org.apache.dubbo.demo.graalvm.provider.Application - - - - --no-fallback - - --initialize-at-build-time=org.slf4j.MDC - - --initialize-at-build-time=org.slf4j.LoggerFactory - - --initialize-at-build-time=org.slf4j.impl.StaticLoggerBinder - - --initialize-at-build-time=org.apache.log4j.helpers.Loader - - --initialize-at-build-time=org.apache.log4j.Logger - - --initialize-at-build-time=org.apache.log4j.helpers.LogLog - - --initialize-at-build-time=org.apache.log4j.LogManager - - --initialize-at-build-time=org.apache.log4j.spi.LoggingEvent - - --initialize-at-build-time=org.slf4j.impl.Log4jLoggerFactory - - --initialize-at-build-time=org.slf4j.impl.Log4jLoggerAdapter - - --initialize-at-build-time=org.eclipse.collections.api.factory.Sets - - --initialize-at-run-time=io.netty.channel.epoll.Epoll - - --initialize-at-run-time=io.netty.channel.epoll.Native - - --initialize-at-run-time=io.netty.channel.epoll.EpollEventLoop - - --initialize-at-run-time=io.netty.channel.epoll.EpollEventArray - - --initialize-at-run-time=io.netty.channel.DefaultFileRegion - - --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventArray - - --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventLoop - - --initialize-at-run-time=io.netty.channel.kqueue.Native - - --initialize-at-run-time=io.netty.channel.unix.Errors - - --initialize-at-run-time=io.netty.channel.unix.IovArray - - --initialize-at-run-time=io.netty.channel.unix.Limits - - --initialize-at-run-time=io.netty.util.internal.logging.Log4JLogger - - --initialize-at-run-time=io.netty.channel.unix.Socket - - --initialize-at-run-time=io.netty.channel.ChannelHandlerMask - - - - --report-unsupported-elements-at-runtime - - --allow-incomplete-classpath - - --enable-url-protocols=http - - -H:+ReportExceptionStackTraces - - - - - - -``` - -It defines the name of the generated image and some parameters for building the image. - -- mount native-image-agent - -Since we need to specify some reflection, JNI and other classes first, we need to use the agent to run it in a normal way to generate information in the form of json for these classes. - -In the startup parameters add: - -``` --agentlib:native-image-agent=config-output-dir=/tmp/config/,config-write-period-secs=300,config-write-initial-delay-secs=5 -``` - -Start in the normal way, create a folder META-INF.native-image under the resources of the project, and paste the files generated in the local directory: - -![img](/imgs/blog/dubbo3.0-graalvm-support/resources.jpg) -(There may be missing class information that is not generated, which needs to be added manually according to the error message when compiling or running.) - - - -** After completing the above steps, the project can be compiled. ** diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/_index.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/_index.md deleted file mode 100755 index 63b5690e4d23..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "Threading Model" -linkTitle: "Threading Model" -weight: 1 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/consumer.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/consumer.md deleted file mode 100644 index 6a9d13466199..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/consumer.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -type: docs -title: "Consumer Thread Model" -linkTitle: "Consumer thread model" -weight: 2 -description: "Dubbo Consumer Thread Pool Model Usage" ---- - -The 2.7.5 version has fully optimized the entire call link. According to the pressure test results, the overall QPS performance has been improved by nearly 30%, and the memory allocation overhead during the call process has also been reduced. One of the design points worth mentioning is that 2.7.5 introduces the concept of Servicerepository, which generates ServiceDescriptor and MethodDescriptor in advance in the service registration phase to reduce resource consumption caused by calculating the original information of the Service in the RPC call phase. - -## Consumer thread pool model optimization - -For Dubbo applications before version 2.7.5, especially some consumer-side applications, when faced with high-traffic scenarios that need to consume a large number of services and have a relatively large number of concurrency (typically such as gateway scenarios), the number of threads on the consumer side is often over-allocated. There are a lot of problems, for specific discussion, please refer to [Need a limited Threadpool in consumer side #2013](https://github.com/apache/dubbo/issues/2013) - -The improved consumer-side thread pool model solves this problem well by reusing the blocked threads on the business side. - -## The old thread pool model - -![Consumer thread pool.png](/imgs/user/consumer-threadpool0.png) - -Let's focus on the Consumer part: - -1. The business thread sends a request and gets a Future instance. -2. The business thread then calls future.get to block and wait for the business result to return. -3. When the business data is returned, it will be deserialized by the independent consumer-side thread pool, and future.set will be called to return the deserialized business results. -4. The business thread returns directly after getting the result - - - -## The thread pool model introduced in version 2.7.5 - -![Consumer thread pool new.png](/imgs/user/consumer-threadpool1.png) - -1. The business thread sends a request and gets a Future instance. -2. Before calling future.get(), call ThreadlessExecutor.wait() first, wait will make the business thread wait on a blocking queue until elements are added to the queue. -3. When the business data is returned, generate a Runnable Task and put it into the ThreadlessExecutor queue -4. The business thread takes out the Task and executes it in this thread: deserialize the business data and set it to Future. -5. The business thread returns directly after getting the result - -In this way, compared with the old thread pool model, the business thread itself is responsible for monitoring and parsing the returned results, eliminating the need for additional consumption-side thread pool overhead. - -Regarding performance optimization, it will continue to advance in the next version, mainly starting from the following two aspects: - -1. RPC call link. The points that can be seen so far include: further reducing the memory allocation of the execution link, improving the efficiency of protocol transmission under the premise of ensuring protocol compatibility, and improving the computing efficiency of Filter and Router. -2. Service governance link. Further reduce memory and cpu resource consumption caused by address push and service governance rule push. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/provider.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/provider.md deleted file mode 100644 index 52ebe33be068..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/provider.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -type: docs -title: "Server Thread Model" -linkTitle: "Server-side threading model" -weight: 1 -description: "Dubbo service provides end-to-end thread pool model and usage" ---- - - - -The current threading models of the Dubbo protocol and the Triple protocol are not yet aligned. The threading models of the Triple protocol and the Dubbo protocol are introduced separately below. - -# Dubbo protocol - Provider-side threading model - -Before introducing the Provider-side threading model of the Dubbo protocol, it is introduced that Dubbo abstracts the operations on the channel into five behaviors: - -- Establish a connection: connected, the main responsibility is to record the time of read and write in the channel, and handle the callback logic after the connection is established. For example, dubbo supports a custom callback hook (onconnect) after disconnection, that is, in this operation implement. -- Disconnected: disconnected, the main responsibility is to remove the read and write time of the channel, and handle the callback logic after the connection is opened. For example, dubbo supports a custom callback hook (ondisconnect) after disconnection, that is, in in this operation. -- Send message: sent, including sending request and sending response. Record the write time. -- Received message: received, including receiving request and receiving response. Record the read time. -- Exception capture: caught, used to handle various exceptions that occur on the channel. - -The thread model of the Dubbo framework is closely related to the above five behaviors. The thread model of the Dubbo protocol Provider can be divided into five categories, namely AllDispatcher, DirectDispatcher, MessageOnlyDispatcher, ExecutionDispatcher, and ConnectionOrderedDispatcher. - -### All Dispatcher - -The following figure is an illustration of the threading model of All Dispatcher: - -![dubbo-provider-alldispatcher](/imgs/v3/feature/performance/threading-model/dubbo-provider-alldispatcher.png) - -- The operations performed in the IO thread are: - 1. The sent operation is executed on the IO thread. - 2. The serialized response is executed on the IO thread. -- The operations performed in the Dubbo thread are: - 1. Received, connected, disconnected, and caught are all executed on the Dubbo thread. - 2. The behavior of deserializing the request is done in Dubbo. - -### Direct Dispatcher - -The following figure is an illustration of the threading model of Direct Dispatcher: - -![dubbo-provider-directDispatcher](/imgs/v3/feature/performance/threading-model/dubbo-provider-directDispatcher.png) - -- The operations performed in the IO thread are: - 1. The received, connected, disconnected, caught, and sent operations are executed on the IO thread. - 2. The deserialization request and serialization response are executed on the IO thread. -- 1. It does not operate on Dubbo threads. - -### Execution Dispatcher - -The following figure is an illustration of the thread model of Execution Dispatcher: - -![dubbo-provider-ExecutionDispatcher](/imgs/v3/feature/performance/threading-model/dubbo-provider-executionDispatcher.png) - -- The operations performed in the IO thread are: - 1. The sent, connected, disconnected, and caught operations are executed on the IO thread. - 2. The serialized response is executed on the IO thread. -- The operations performed in the Dubbo thread are: - 1. Received is executed on the Dubbo thread. - 2. The behavior of deserializing the request is done in Dubbo. - -### Message Only Dispatcher - -On the Provider side, the threading models of Message Only Dispatcher and Execution Dispatcher are consistent, so the following figure is consistent with that of Execution Dispatcher, and the difference is on the Consumer side. See the threading model on the Consumer side below. - -The following figure is an illustration of the threading model of Message Only Dispatcher: - -![dubbo-provider-ExecutionDispatcher](/imgs/v3/feature/performance/threading-model/dubbo-provider-executionDispatcher.png) - -- The operations performed in the IO thread are: - 1. The sent, connected, disconnected, and caught operations are executed on the IO thread. - 2. The serialized response is executed on the IO thread. -- The operations performed in the Dubbo thread are: - 1. Received is executed on the Dubbo thread. - 2. The behavior of deserializing the request is done in Dubbo. - -### Connection Ordered Dispatcher - -The following figure is an illustration of the threading model of the Connection Ordered Dispatcher: - -![dubbbo-provider-connectionOrderedDispatcher](/imgs/v3/feature/performance/threading-model/dubbbo-provider-connectionOrderedDispatcher.png) - -- The operations performed in the IO thread are: - 1. The sent operation is executed on the IO thread. - 2. The serialized response is executed on the IO thread. -- The operations performed in the Dubbo thread are: - 1. Received, connected, disconnected, and caught are all executed on the Dubbo thread. But the two behaviors of connected and disconnected are isolated from the other two behaviors through the thread pool. And in Dubbo connected thread pool, link limit and warning light capabilities are provided. - 2. The behavior of deserializing the request is done in Dubbo. - -# Triple protocol——Provider-side threading model - -The following figure shows the threading model of the Provider side of the Triple protocol - -![triple-provider](/imgs/v3/feature/performance/threading-model/triple-provider.png) - -The provider thread model of the Triple protocol is relatively simple at present. Currently, the serialization and deserialization operations work on the Dubbo thread, while the IO thread does not carry these tasks. - - - -# How to adjust the threading model - -Take the yaml configuration method as an example: configure dispatcher: all under protocol to adjust the thread model of the dubbo protocol to All Dispatcher - -```yaml -dubbo: - application: - name: dubbo-springboot-demo-provider - protocol: - name: dubbo - port: -1 - dispatcher: all - registry: - id: zk-registry - address: zookeeper://127.0.0.1:2181 - config-center: - address: zookeeper://127.0.0.1:2181 - metadata-report: - address: zookeeper://127.0.0.1:2181 -``` - -Configuration values for each threading model: - -- All Dispatcher all - -Direct Dispatcher direct -- Execution Dispatcher execution -- Message Only Dispatcher: message -- Connection Ordered Dispatcher: connection \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/_index.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/_index.md deleted file mode 100755 index 8532cb9ba4f2..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "Improve service security" -linkTitle: "Improve Security" -weight: 4 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/auth.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/auth.md deleted file mode 100644 index 2bb754816aa5..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/auth.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -type: docs -title: "Service Authentication" -linkTitle: "Service Authentication" -weight: 23 -description: "Understand dubbo3 service authentication" ---- - -## Feature description - -Security-sensitive businesses like payments may have a need to limit anonymous calls. In terms of security enhancement, 2.7.5 introduces the authentication and authentication mechanism based on the AK/SK mechanism, and introduces the authentication service center. The main principle is that when the consumer requests a service that requires authentication, it will pass SK, request Data, timestamps, parameters and other information to generate the corresponding request signature, which is carried to the peer end through Dubbo's Attahcment mechanism for signature verification, and business logic processing is performed only after the signature verification is passed. As shown below: - -![img](/imgs/docsv2.7/user/examples/auth/auth.png) - - -## scenes to be used - -## How to use -### access method - -1. Users need to fill in their application information on the microservice site and generate a unique certificate for the application. - -2. Submit a work order on the management site to apply for the permission to use a certain sensitive business service, which will be approved by the corresponding business manager. After the approval is passed, the corresponding AK/SK will be generated and sent to the authentication service center. - -3. Import the certificate to the corresponding application and configure it. The configuration method is also very simple. Take the annotation method as an example: - - ### Service Provider - You only need to set `service.auth` to true, which means that the call of the service needs to pass the authentication. `param.sign` is `true`, which means that the parameter needs to be verified. - - ```java - @Service(parameters = {"service.auth","true","param.sign","true"}) - public class AuthDemoServiceImpl implements AuthService { - } - - ``` - - ### Service consumer - You only need to configure the corresponding certificate and other information, and then the signature operation will be automatically performed before invoking these interfaces that require authentication. Through the interaction with the authentication service, the user does not need to configure sensitive information such as AK/SK in the code , and refresh the AK/SK without restarting the application to achieve the purpose of dynamically issuing permissions. - -The solution has been submitted to the Dubbo open source community, and the basic framework has been merged. In addition to the AK/SK authentication method, the SPI mechanism supports user-customizable authentication and encryption that adapts to the company's internal infrastructure. key storage. diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/class-check.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/class-check.md deleted file mode 100644 index 6eff959e8cd8..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/class-check.md +++ /dev/null @@ -1,215 +0,0 @@ ---- -type: docs -title: "Dubbo Class Inspection Mechanism" -linkTitle: "Dubbo Class Inspection Mechanism" -weight: 1 -description: "Understand the Dubbo class inspection mechanism" ---- - -## Supported versions - -Dubbo >= 3.1.6 - -## Scope of application -Currently, the serialization check supports Hessian2, Fastjson2 serialization and generalized calls. Other serialization methods are not currently supported. - -## configuration method - -### 1. Check mode -The inspection mode is divided into three levels: `STRICT` strict inspection, `WARN` warning, `DISABLED` disabled. -`STRICT` Strict checks: disallow deserialization of all classes that are not in the allowed serialization list (whitelist). -`WARN` warning: only prohibits serialization of all classes in the disallowed serialization list (blacklist), and alerts through logs when deserializing classes that are not in the allowed serialization list (whitelist). -`DISABLED` Disabled: Do not do any checks. - -Version 3.1 defaults to `WARN` warning level, and version 3.2 defaults to `STRICT` strict checking level. - -Configuration via ApplicationConfig: -```java -ApplicationConfig applicationConfig = new ApplicationConfig(); -applicationConfig.setSerializeCheckStatus("STRICT"); -``` - -Configuration via Spring XML: -```xml - -``` - -Configure via Spring Properties / dubbo.properties: -```properties -dubbo.application.serialize-check-status=STRICT -``` - -Configure via System Property: -```properties --Ddubbo.application.serialize-check-status=STRICT -``` - -After the configuration is successful, you can see the following prompts in the log: -``` -INFO utils.SerializeSecurityManager: [DUBBO] Serialize check level: STRICT -``` - -Note: If multiple applications under the same process (Dubbo Framework Model) are configured with different inspection modes at the same time, the "loosenest" level will eventually take effect. If two Spring Contexts are started at the same time, one is configured as `STRICT` and the other is configured as `WARN`, the `WARN` level configuration will finally take effect. - -### 2. Serializable interface check - -The Serializable interface check mode is divided into two levels: `true` is enabled, and `false` is disabled. When the check is turned on, it will refuse to deserialize all classes that do not implement `Serializable`. - -The default configuration in Dubbo is `true` to enable the check. - -Configuration via ApplicationConfig: -```java -ApplicationConfig applicationConfig = new ApplicationConfig(); -applicationConfig.setCheckSerializable(true); -``` - -Configuration via Spring XML: -```xml - -``` - -Configure via Spring Properties / dubbo.properties: -```properties -dubbo.application.check-serializable=true -``` - -Configure via System Property: -```properties --Ddubbo.application.check-serializable=true -``` - -After the configuration is successful, you can see the following prompts in the log: -``` -INFO utils.SerializeSecurityManager: [DUBBO] Serialize check serializable: true -``` - -Note 1: If multiple applications under the same process (Dubbo Framework Model) are configured with different Serializable interface inspection modes at the same time, the "loosenest" level will eventually take effect. If two Spring Contexts are started at the same time, one configured as `true` and the other configured as `false`, the `false` level configuration will finally take effect. -Note 2: At present, the built-in `Serializable` check configuration of Hessian2 and Fastjson2 has not been opened. For generalized calls, you only need to configure `dubbo.application.check-serializable` to modify the check configuration; for Hessian2 serialization, you need to modify `dubbo.application.check-serializable` and `dubbo.hessian.allowNonSerializable` at the same time - -### 3. Automatically scan related configurations - -There are two configuration items in the Dubbo class automatic scanning mechanism: `AutoTrustSerializeClass - -To put it simply, after automatic class scanning is enabled, Dubbo will automatically scan all related classes that may be used by the interface through `ReferenceConfig` and `ServiceConfig`, and recursively trust its package. `TrustSerializeClassLevel - -The default configuration in Dubbo is `AutoTrustSerializeClass - -Configuration via ApplicationConfig: -```java -ApplicationConfig applicationConfig = new ApplicationConfig(); -applicationConfig.setAutoTrustSerializeClass(true); -applicationConfig.setTrustSerializeClassLevel(3); -``` - -Configuration via Spring XML: -```xml - -``` - -Configure via Spring Properties / dubbo.properties: -```properties -dubbo.application.auto-trust-serialize-class=true -dubbo.application.trust-serialize-class-level=3 -``` - -Configure via System Property: -```properties --Ddubbo.application.auto-trust-serialize-class=true --Ddubbo.application.trust-serialize-class-level=3 -``` - -After the configuration is successful, you can use the QoS command to check whether the results of the currently loaded trusted classes meet expectations. - -Note: After the check is enabled, there will be a certain performance loss during the startup process. - -### 4. Custom configuration of trusted/untrusted classes - -In addition to Dubbo's automatic scanning classes, it also supports configuration of trusted/untrusted class lists through resource files. - -Configuration method: define the following files under the resource directory (resource). - -```properties -# security/serialize.allowlist -io.dubbo.test -``` - -```properties -# security/serialize.blockedlist -io.dubbo.block -``` - -After the configuration is successful, you can see the following prompts in the log: -```properties -INFO utils.SerializeSecurityConfigurator: [DUBBO] Read serialize allow list from file:/Users/albumen/code/dubbo-integration-cases/99-integration/dubbo-samples-serialize-check/target/classes/security/serialize.allowlist -INFO utils.SerializeSecurityConfigurator: [DUBBO] Read serialize blocked list from file:/Users/albumen/code/dubbo-integration-cases/99-integration/dubbo-samples-serialize-check/target/classes/security/serialize.blockedlist -``` - -The configuration priority is: user-defined trusted class = built-in trusted class of the framework > user-defined untrusted class = built-in untrusted class of the framework > automatic class scanning trusted class. - -## Audit method - -Dubbo supports real-time viewing of current configuration information and trusted/untrusted class lists through QoS commands. Currently supports two commands: `serializeCheckStatus` to view the current configuration information, `serializeWarnedClasses` to view the real-time alarm list. - -1. `serializeCheckStatus` View the current configuration information - -Access directly through the console: -```bash -> telnet 127.0.0.1 22222 -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. - ___ __ __ ___ ___ ____ - / _ \ / / / // _ ) / _ ) / __ \ - / // // /_/ // _ |/ _ |/ /_/ / -/____/ \____//____//____/ \____/ -dubbo>serializeCheckStatus -CheckStatus: WARN - -CheckSerializable: true - -AllowedPrefix: -... - -DisAllowedPrefix: -... - - -dubbo> -``` - -Request the result in json format via http: -```bash -> curl http://127.0.0.1:22222/serializeCheckStatus -{"checkStatus": "WARN","allowedPrefix":[...],"checkSerializable":true,"disAllowedPrefix":[...]} -``` - -2. `serializeWarnedClasses` view real-time warning list - -Access directly through the console: -```bash -> telnet 127.0.0.1 22222 -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. - ___ __ __ ___ ___ ____ - / _ \ / / / // _ ) / _ ) / __ \ - / // // /_/ // _ |/ _ |/ /_/ / -/____/ \____//____//____/ \____/ -dubbo>serializeWarnedClasses -Warned Classes: -io.dubbo.test.NotSerializable -io.dubbo.test2.NotSerializable -io.dubbo.test2.OthersSerializable -org.apache.dubbo.samples.NotSerializable - - -dubbo> -``` - -Request the result in json format via http: -```bash -> curl http://127.0.0.1:22222/serializeWarnedClasses -{"warnedClasses":["io.dubbo.test2.NotSerializable","org.apache.dubbo.samples.NotSerializable","io.dubbo.test.NotSerializable","io.dubbo.test2.OthersSerializable"]} -``` - -Note: It is recommended to pay attention to the result of `serializeWarnedClasses` in time, and judge whether it is attacked by whether the returned result is not empty. diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/tls.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/tls.md deleted file mode 100644 index 31802fb6a815..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/tls.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -type: docs -title: "TLS Support" -linkTitle: "TLS support" -weight: 1 -description: "Learn about TLS in dubbo3 for secure transport" ---- -## Feature description - -Both the built-in Dubbo Netty Server and the newly introduced gRPC protocol provide a TLS-based secure link transmission mechanism. - -There is a unified entry for TLS configuration. - -## scenes to be used - -Users who require encryption for the entire link can use TLS. - -## Reference use case - -[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-ssl](https://github.com/apache/dubbo-samples/tree/master/4-governance/dubbo-samples-ssl) - -## How to use - -### Provider side -```java -SslConfig sslConfig = new SslConfig(); -sslConfig.setServerKeyCertChainPath("path to cert"); -sslConfig.setServerPrivateKeyPath(args[1]); -// If two-way cert authentication is enabled -if (mutualTls) { - sslConfig.setServerTrustCertCollectionPath(args[2]); -} - -ProtocolConfig protocolConfig = new ProtocolConfig("dubbo/grpc"); -protocolConfig.setSslEnabled(true); -``` -If you want to use the gRPC protocol, the protocol negotiation mechanism will be used when TLS is turned on, so you must use a Provider that supports the ALPN mechanism. The recommended one is netty-tcnative. For details, please refer to [Summary](https:/ /github.com/grpc/grpc-java/blob/master/SECURITY.md) - - -### Consumer side - -```java -if (!mutualTls) {} - sslConfig.setClientTrustCertCollectionPath(args[0]); -} else { - sslConfig.setClientTrustCertCollectionPath(args[0]); - sslConfig.setClientKeyCertChainPath(args[1]); - sslConfig.setClientPrivateKeyPath(args[2]); -} -``` - -In order to ensure the flexibility of application startup as much as possible, the specification of TLS Cert can also be dynamically specified during the startup phase according to the deployment environment through -D parameters or environment variables. Refer to Dubbo [Configuration Read Rules](/zh-cn/docs/advanced /config-rule) - - -> On the security of service calls, Dubbo will continue to invest in subsequent versions, and the authentication mechanism for service discovery/calling is expected to meet you in the next version. diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/token-authorization.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/token-authorization.md deleted file mode 100644 index 8d7f6ad43d75..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/security/token-authorization.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -type: docs -title: "Access Control" -linkTitle: "Access Control" -weight: 2 -description: "Understand the configuration and use of dubbo3 permission control" ---- - -## Feature description -Control authority in the registration center through token verification to decide whether to issue tokens to consumers, -can prevent consumers from bypassing the registry to access the provider, -In addition, the authorization method can be flexibly changed through the registration center without modifying or upgrading the provider. - -![/user-guide/images/dubbo-token.jpg](/imgs/user/dubbo-token.jpg) - -## scenes to be used - -To a certain extent, the trusted authentication of the client and the server is realized, preventing any client from being able to access, and reducing the risk of security problems. - -## How to use -### Global Settings - -Enable token verification - -```xml - - -``` - -or - -```xml - - -``` -### Service Level Settings - -```xml - - -``` - -or - -```xml - - -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/_index.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/_index.md deleted file mode 100755 index 4d9752c9a4ce..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "Configuration Framework and Service Behavior" -linkTitle: "Framework and Services" -weight: 1 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/accesslog.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/accesslog.md deleted file mode 100644 index cf4187ca1ab0..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/accesslog.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -type: docs -title: "Call Information Record" -linkTitle: "Call Information Record" -weight: 13 -description: "Understand dubbo3 call information records to configure and use through access logs" ---- -## Feature description - -The log in dubbo3 is divided into log adaptation and access log. If you want to record each request information, you can enable the access log, which is similar to the apache access log. - -## scenes to be used - -Based on audit needs, etc. similar to nginx accesslog output, etc. - -## How to use -### log4j log -Output access logs to the current application's log4j log -```xml - -``` -### specify the file -Output the access log to the specified file -```xml - -``` -> The log volume is relatively large, please pay attention to the disk capacity. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/async-call.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/async-call.md deleted file mode 100644 index 6ac0a377276d..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/async-call.md +++ /dev/null @@ -1,177 +0,0 @@ ---- -type: docs -title: "Asynchronous call" -linkTitle: "Asynchronous call" -weight: 3 -description: "Initiate an asynchronous call in Dubbo" ---- - -## Feature description -#### background - -Starting from 2.7.0, all asynchronous programming interfaces of Dubbo are based on [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) - -Based on NIO's non-blocking implementation of parallel calls, the client does not need to start multi-threads to complete parallel calls to multiple remote services, and the overhead of multi-threading is relatively small. - -![/user-guide/images/future.jpg](/imgs/user/future.jpg) - -## Reference use case - -[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-async](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-async) -## scenes to be used - -Send the user request content to the target request. When the target request encounters high traffic or needs to be processed for a long time, the asynchronous call function will allow the response to be returned to the user immediately, while the target request continues to process the request in the background. When the target request returns the result, the content will be sent displayed to the user. - -## How to use -### Interface signed with CompletableFuture - -For services that require service providers to define CompletableFuture signatures in advance, the interface definition guidelines are as follows: - -The asynchronous execution of the provider side switches the blocked business from Dubbo's internal thread pool to the business-defined thread, avoiding excessive occupation of the Dubbo thread pool, and helping to avoid the mutual influence between different services. Asynchronous execution is tantamount to saving resources or improving RPC response performance, because if business execution needs to be blocked, there is always a thread to be responsible for execution. - -> **Provider-side asynchronous execution and Consumer-side asynchronous call are independent of each other, any orthogonal combination of two configurations** -> - Consumer Synchronization - Provider Synchronization -> - Consumer asynchronous - Provider synchronous -> - Consumer synchronous - Provider asynchronous -> - Consumer asynchronous - Provider asynchronous - -### Define the interface of CompletableFuture signature - -service interface definition -```java -public interface AsyncService { - CompletableFuture sayHello(String name); -} -``` - -service realization -```java -public class AsyncServiceImpl implements AsyncService { - @Override - public CompletableFuture sayHello(String name) { - return CompletableFuture. supplyAsync(() -> { - System.out.println(name); - try { - Thread. sleep(5000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "async response from provider."; - }); - } -} -``` - -Through `return CompletableFuture.supplyAsync()`, the business execution has been switched from the Dubbo thread to the business thread, avoiding the blocking of the Dubbo thread pool. - - - -### Using AsyncContext - -Dubbo provides an asynchronous interface `AsyncContext` similar to Servlet 3.0, which can also implement asynchronous execution on the Provider side without the CompletableFuture signature interface. - -service interface definition -```java -public interface AsyncService { - String sayHello(String name); -} -``` - -Service exposure, exactly the same as ordinary services -```xml - - -``` - -service realization -```java -public class AsyncServiceImpl implements AsyncService { - public String sayHello(String name) { - final AsyncContext asyncContext = RpcContext. startAsync(); - new Thread(() -> { - // If you want to use the context, it must be executed in the first sentence - asyncContext.signalContextSwitch(); - try { - Thread. sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - // write back the response - asyncContext.write("Hello " + name + ", response from provider."); - }).start(); - return null; - } -} -``` - -Note that the return type of the interface is `CompletableFuture`. - -XML Reference Service -```xml - -``` - -call remote service -```java -// The call directly returns CompletableFuture -CompletableFuture future = asyncService.sayHello("async call request"); -// add callback -future. whenComplete((v, t) -> { - if (t != null) { - t. printStackTrace(); - } else { - System.out.println("Response: " + v); - } -}); -// earlier than the result output -System.out.println("Executed before response return."); -``` - -### Using RpcContext -Configure in consumer.xml -```xml - - - -``` - -calling code -```java -// this call returns null immediately -asyncService.sayHello("world"); -// Get the Future reference of the call, when the result is returned, it will be notified and set to this Future -CompletableFuture helloFuture = RpcContext.getServiceContext().getCompletableFuture(); -// add callback for Future -helloFuture. whenComplete((retValue, exception) -> { - if (exception == null) { - System.out.println(retValue); - } else { - exception. printStackTrace(); - } -}); -``` - -Alternatively, it is also possible to do this asynchronously by calling -```java -CompletableFuture future = RpcContext.getServiceContext().asyncCall( - () -> { - asyncService.sayHello("oneway call request1"); - } -); - -future. get(); -``` - - -**Asynchronous always does not wait for return**, you can also set whether to wait for the message to be sent -- `sent="true"` waits for the message to be sent, and an exception will be thrown if the message fails to be sent. -- `sent="false"` does not wait for the message to be sent, puts the message in the IO queue, and returns immediately. - -```xml - -``` - -If you just want to be asynchronous and completely ignore the return value, you can configure `return="false"` to reduce the cost of creating and managing Future objects -```xml - -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/async-execute-on-provider.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/async-execute-on-provider.md deleted file mode 100644 index 18eb74ab01f5..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/async-execute-on-provider.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -type: docs -title: "Asynchronous execution" -linkTitle: "Asynchronous execution" -weight: 21 -description: "Asynchronous execution of Dubbo service provider" ---- - -{{% pageinfo %}} This document is no longer maintained. You are currently viewing a snapshot version. If you want to see the latest version of the documentation, see [Latest Version](/en/docs3-v2/java-sdk/advanced-features-and-usage/service/attachment/). -{{% /pageinfo %}} - - -The asynchronous execution of the provider side switches the blocked business from Dubbo's internal thread pool to the business-defined thread, avoiding excessive occupation of the Dubbo thread pool, and helping to avoid the mutual influence between different services. Asynchronous execution is tantamount to saving resources or improving RPC response performance, because if business execution needs to be blocked, there is always a thread to be responsible for execution. - -{{% alert title="Attention" color="warning" %}} -The asynchronous execution on the Provider side and the asynchronous call on the Consumer side are independent of each other, and you can configure both ends in any orthogonal combination -- Consumer Synchronization - Provider Synchronization -- Consumer asynchronous - Provider synchronous -- Consumer synchronous - Provider asynchronous -- Consumer asynchronous - Provider asynchronous - {{% /alert %}} - - -## Define the interface of CompletableFuture signature - -Service interface definition: - -```java -public interface AsyncService { - CompletableFuture sayHello(String name); -} -``` - -Service implementation: - -```java -public class AsyncServiceImpl implements AsyncService { - @Override - public CompletableFuture sayHello(String name) { - RpcContext savedContext = RpcContext. getContext(); - // It is recommended to provide a custom thread pool for supplyAsync and avoid using the JDK public thread pool - return CompletableFuture. supplyAsync(() -> { - System.out.println(savedContext.getAttachment("consumer-key1")); - try { - Thread. sleep(5000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "async response from provider."; - }); - } -} -``` - -Through `return CompletableFuture.supplyAsync()`, the business execution has been switched from the Dubbo thread to the business thread, avoiding the blocking of the Dubbo thread pool. - - - -## Using AsyncContext - -Dubbo provides an asynchronous interface `AsyncContext` similar to Servlet 3.0, which can also implement asynchronous execution on the Provider side without the CompletableFuture signature interface. - -Service interface definition: - -```java -public interface AsyncService { - String sayHello(String name); -} -``` - -Service exposure is exactly the same as ordinary services: - -```xml - - -``` - -Service implementation: - -```java -public class AsyncServiceImpl implements AsyncService { - public String sayHello(String name) { - final AsyncContext asyncContext = RpcContext. startAsync(); - new Thread(() -> { - // If you want to use the context, it must be executed in the first sentence - asyncContext.signalContextSwitch(); - try { - Thread. sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - // write back the response - asyncContext.write("Hello " + name + ", response from provider."); - }).start(); - return null; - } -} -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/attachment.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/attachment.md deleted file mode 100644 index cbc173f7e2a4..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/attachment.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -type: docs -title: "Call link to pass implicit parameters" -linkTitle: "Call link to pass implicit parameters" -weight: 5 -description: "Implicitly pass parameters between service consumers and providers through Attachment in Dubbo" ---- - -## Feature description - -Parameters can be implicitly passed between the service consumer and the provider through `setAttachment` and `getAttachment` on `RpcContext`. - -#### background - -Context information is a very important function of the RPC framework. Using RpcContext can specify different configurations for a single call. For example, in the distributed link tracking scenario, the implementation principle is to maintain a traceId in the context of the entire link. The Consumer and Provider connect an RPC call by passing the traceId. After reporting the logs respectively, they can be connected in series in the tracking system and display the complete call. process. In this way, it is easier to find abnormalities and locate problems. -RpcContext in Dubbo is a ThreadLocal temporary state recorder. When RPC requests are received or RPC requests are initiated, the state of RpcContext will change. For example: **A tunes B, B tunes C, then on machine B, before B tunes C, RpcContext records the information of A and B, after B tunes C, RpcContext records the information of B and C. ** - -In Dubbo 3, RpcContext is split into four major modules (ServerContext, ClientAttachment, ServerAttachment and ServiceContext). - -They bear different accusations respectively: -- ServiceContext: Used internally by Dubbo to pass parameter information on the call link, such as invoker objects, etc. -- ClientAttachment: Used on the client side, the parameters written in ClientAttachment will be passed to the server side -- ServerAttachment: Used on the Server side, the parameters read from ServerAttachment are passed from the Client -- ServerContext: It is used on both the client side and the server side, and is used to pass back from the server side to the client side. The parameters written by the server side to the ServerContext can be obtained from the ServerContext on the client side after the call ends - -![/imgs/v3/concepts/rpccontext.png](/imgs/v3/concepts/rpccontext.png) - -As shown in the figure above, when the consumer initiates an invocation, it can directly initiate a call to the remote service through Method Invoke, and at the same time, the data written by the consumer to RpcClientAttachment will be written into Invocation together with the parameter information of Invoke. -The Invocation on the consumer side is serialized and sent to the server through network transmission. The server parses the Invocation to generate the parameters of Method Invoke and RpcServerAttachment, and then initiates the real call. -After the processing on the server end, the Method Response result together with the RpcServiceContext will generate a Result object. -The Result object on the server is serialized and sent back to the consumer through network transmission. The consumer parses the Result to generate a Method Response result and RpcServiceContext, and returns the actual call result and context to the consumer. - -> path, group, version, dubbo, token, timeout several keys are reserved fields, please use other values. - -## scenes to be used - -How to transparently transmit traceId to the service provider when the internal system calls through Dubbo. - -## How to use - -> The KV pair set by `setAttachment` will be cleared after the following remote call is completed, that is, multiple remote calls need to be set multiple times. - -### Set implicit parameters on the service consumer side - -```java -RpcContext.getClientAttachment().setAttachment("index", "1"); // Implicit parameter passing, subsequent remote calls will implicitly send these parameters to the server, similar to cookies, used for framework integration, not recommended business use -xxxService.xxx(); // remote call -//... -``` - -### Obtain implicit parameters on the service provider side - -```java -public class XxxServiceImpl implements XxxService { - - public void xxx() { - // Obtain the parameters implicitly passed in by the client for framework integration, not recommended for general business use - String index = RpcContext.getServerAttachment().getAttachment("index"); - } -} -``` - -### Write return parameters in the service provider - -```java -public class XxxServiceImpl implements XxxService { - - public void xxx() { - String index = xxx; - RpcContext.getServerContext().setAttachment("result", index); - } -} -``` - -### Obtain the return parameters on the consumer side - -```java -xxxService.xxx(); // remote call -String result = RpcContext.getServerContext().getAttachment("result"); -//... -``` - -## Parameter transparent transmission problem - -In Dubbo 2.7, after the parameters set on the A side are called, if B continues to call C, the parameters originally set in A will also be brought to the C side, causing the problem of parameter pollution. -Dubbo 3 has refactored RpcContext to support optional parameter transparent transmission, and parameter transparent transmission is enabled by default. - -The following SPI is provided in Dubbo 3. There is no implementation by default. Users can define their own implementation. The result of `select` (you can get all the current parameters from RpcClientAttachment) will be passed to the next hop as a key-value pair that needs to be transparently transmitted. If Returning null means that parameters are not transparently passed. - -```java -@SPI -public interface PenetrateAttachmentSelector { - - /** - * Select some attachments to pass to next hop. - * These attachments can fetch from {@link RpcContext#getServerAttachment()} or user defined. - * - * @return attachment pass to next hop - */ - Map select(); - -} -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/callback-parameter.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/callback-parameter.md deleted file mode 100644 index 6e01d24ef5f6..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/callback-parameter.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -type: docs -title: "The server makes a callback to the client" -linkTitle: "The server makes a callback to the client" -weight: 9 -description: "Call client-side logic from server-side via parameter callback" ---- -## Feature description -The parameter callback method is the same as calling a local callback or listener, you only need to declare which parameter is the callback type in the Spring configuration file. Dubbo will generate a reverse proxy based on the persistent connection, so that the client logic can be invoked from the server. You can refer to [sample code in the dubbo project](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-callback). - -## scenes to be used -The callback function notifies the client of the execution result, or sends a notification. When the method execution time is relatively long, it is similar to an asynchronous call, and the client approval result is called back in the approval workflow. - -## How to use -### Service interface example - -CallbackService.java -```java -package com. callback; - -public interface CallbackService { - void addListener(String key, CallbackListener listener); -} -``` - -CallbackListener.java -```java -package com. callback; - -public interface CallbackListener { - void changed(String msg); -} -``` - -### Service provider interface implementation example - -```java -package com.callback.impl; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import com.callback.CallbackListener; -import com.callback.CallbackService; - -public class CallbackServiceImpl implements CallbackService { - - private final Map listeners = new ConcurrentHashMap(); - - public CallbackServiceImpl() { - Thread t = new Thread(new Runnable() { - public void run() { - while(true) { - try { - for(Map.Entry entry : listeners.entrySet()){ - try { - entry.getValue().changed(getChanged(entry.getKey())); - } catch (Throwable t) { - listeners. remove(entry. getKey()); - } - } - Thread.sleep(5000); // Timely trigger change notification - } catch (Throwable t) { // defensive fault tolerance - t. printStackTrace(); - } - } - } - }); - t. setDaemon(true); - t. start(); - } - - public void addListener(String key, CallbackListener listener) { - listeners. put(key, listener); - listener.changed(getChanged(key)); // send change notification - } - - private String getChanged(String key) { - return "Changed: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); - } -} -``` - -### Service provider configuration example - -```xml - - - - - - - - -``` - -### Service consumer configuration example - -```xml - -``` - -### Service consumer call example - -```java -ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:consumer.xml"); -context. start(); - -CallbackService callbackService = (CallbackService) context. getBean("callbackService"); - -callbackService.addListener("foo.bar", new CallbackListener(){ - public void changed(String msg) { - System.out.println("callback1:" + msg); - } -}); -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/consistent-hash.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/consistent-hash.md deleted file mode 100644 index 6ab48e08fe5e..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/consistent-hash.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -type: docs -title: "Consistent Hash Site Selection" -linkTitle: "Consistent Hash Site Selection" -weight: 6 -description: "Address selection based on consistent hash in the load balancing phase" ---- -## Feature description - -[Analysis of Dubbo Consistent Hash Load Balancing Implementation](/zh-cn/blog/2019/05/01/dubbo-%E4%B8%80%E8%87%B4%E6%80%A7hash%E8%B4%9F%E8 %BD%BD%E5%9D%87%E8%A1%A1%E5%AE%9E%E7%8E%B0%E5%89%96%E6%9E%90/) - -## scenes to be used - -When there are multiple servers, the server is selected according to the consistent hashing of the request parameters. - -## How to use - -There are many ways to configure consistent hashing, the most common are: - -### Annotation configuration - -> @DubboReference(loadbalance = "consistenthash") - -### API configuration - -> referenceConfig.setLoadBalance("consistenthash"); - -### Properties configuration - -> dubbo.reference.loadbalance=consistenthash - -### XML configuration - -> - -By default, the first parameter is used as the hash key. If you need to switch parameters, you can specify the `hash.arguments` property - -```java -ReferenceConfig referenceConfig = new ReferenceConfig(); -// ...init -Map parameters = new HashMap(); -parameters. put("hash. arguments", "1"); -parameters. put("sayHello. hash. arguments", "0,1"); -referenceConfig.setParameters(parameters); -referenceConfig.setLoadBalance("consistenthash"); -referenceConfig. get(); -``` diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/context.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/context.md deleted file mode 100644 index b84121f0ace9..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/context.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -type: docs -title: "RPC call context" -linkTitle: "RPC call context" -weight: 6 -description: "Store the environment information required in the current calling process through the context" ---- -## Feature description -The context stores the environment information needed in the current calling process. All configuration information will be converted to URL parameters, see the **corresponding URL parameters** column in [schema configuration reference manual](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties//). - -RpcContext is a temporary state recorder for ThreadLocal. When RPC requests are received or RPC requests are initiated, the state of RpcContext will change. For example: A tunes B, B then tunes C, then on machine B, before B tunes C, RpcContext records the information of A's tune to B, after B tunes C, RpcContext records the information of B's tune to C. - -## scenes to be used -Global link tracking and hiding parameters. - -## How to use - -### Service consumer -```java -// remote call -xxxService. xxx(); -// Whether this end is a consumer end, here will return true -boolean isConsumerSide = RpcContext.getServiceContext().isConsumerSide(); -// Get the provider IP address of the last call -String serverIP = RpcContext.getServiceContext().getRemoteHost(); -// Get the current service configuration information, all configuration information will be converted into URL parameters -String application = RpcContext.getServiceContext().getUrl().getParameter("application"); -// Note: Every time an RPC call is initiated, the context state will change -yyyService.yyy(); -``` - -### Service Provider -```java -public class XxxServiceImpl implements XxxService { - - public void xxx() { - // Whether this end is the provider end, here will return true - boolean isProviderSide = RpcContext.getServiceContext().isProviderSide(); - // Get the IP address of the caller - String clientIP = RpcContext.getServiceContext().getRemoteHost(); - // Get the current service configuration information, all configuration information will be converted into URL parameters - String application = RpcContext.getServiceContext().getUrl().getParameter("application"); - // Note: Every time an RPC call is initiated, the context state will change - yyyService.yyy(); - // At this point, the local end becomes the consumer end, and false will be returned here - boolean isProviderSide = RpcContext.getServiceContext().isProviderSide(); - } -} -``` diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/delay-publish.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/delay-publish.md deleted file mode 100644 index 49dd4fe16d75..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/delay-publish.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -type: docs -title: "Delayed Exposure" -linkTitle: "Delayed Exposure" -weight: 27 -description: "Delayed exposure of Dubbo services" ---- - -If your service needs warm-up time, such as initializing the cache, waiting for related resources to be in place, etc., you can use delay for delayed exposure. In Dubbo version 2.6.5, we made minor adjustments to the service delay exposure logic, and postponed the countdown action for services that require delay exposure (delay > 0) until Spring initialization is complete. You will not feel this change while using Dubbo, so please feel free to use it. - -## Versions before Dubbo 2.6.5 - -Delay until Spring initialization completes before exposing services[^1] - -```xml - -``` - -Expose service with 5 second delay - -```xml - -``` - -## Dubbo 2.6.5 and later versions - -All services will be exposed after Spring initialization is complete. If you do not need to delay exposing services, you do not need to configure delay. - -Expose service with 5 second delay - -```xml - -``` - -## Spring 2.x initialization deadlock problem - -### Triggering conditions - -When Spring resolves to ``, the service has been exposed, and Spring is still initializing other beans. If a request comes in at this time, and there is a usage of calling `applicationContext.getBean()` in the implementation class of the service. - -1. The applicationContext.getBean() call of the requesting thread first synchronizes the singletonObjects to determine whether the Bean exists, and initializes the synchronization beanDefinitionMap if it does not exist, and then synchronizes the singletonObjects again to write the Bean instance cache. - - ![deadlock](/imgs/user/lock-get-bean.jpg) - -2. The Spring initialization thread, because it does not need to judge the existence of the bean, directly synchronizes the beanDefinitionMap to initialize, and synchronizes singletonObjects to write the bean instance cache. - - ![/user-guide/images/lock-init-context.jpg](/imgs/user/lock-init-context.jpg) - - This causes the getBean thread to lock singletonObjects first, then beanDefinitionMap, and singletonObjects again. - The Spring initialization thread first locks beanDefinitionMap and then singletonObjects. The reverse lock leads to thread deadlock, unable to provide services, and unable to start. - -### Workaround - -1. It is strongly recommended not to call applicationContext.getBean() in the service implementation class, and all use Spring beans by IoC injection. -2. If you really want to call getBean(), you can load the Dubbo configuration at the end of Spring. -3. If you don’t want to depend on the configuration order, you can use `` to make Dubbo expose the service after the Spring container is initialized. -4. If you use getBean() extensively, it is equivalent to degenerating Spring into a factory mode, and you can isolate Dubbo's services into a separate Spring container. - -[^1]: Trigger exposure based on Spring's ContextRefreshedEvent event \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction.md deleted file mode 100644 index efd9919644ff..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/distributed-transaction.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "Distributed transaction support" -linkTitle: "Distributed transaction support" -weight: 42 -description: "Support for distributed transactions in Dubbo" ---- - -Distributed transactions are implemented based on the JTA/XA specification. - -**two-phase commit** - -![/user-guide/images/jta-xa.jpg](/imgs/user/jta-xa.jpg) - -In Dubbo, you can use [seata](/zh-cn/blog/2019/01/17/How to use seata to ensure the consistency between dubbo microservices/) to complete the support for distributed transactions. diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/echo-service.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/echo-service.md deleted file mode 100644 index ba34d266f644..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/echo-service.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -type: docs -title: "Echo Test" -linkTitle: "Echo Test" -weight: 12 -description: "Check whether Dubbo service is available by echo test" ---- - -## Feature description -The echo test is used to detect whether the service is available. The echo test is performed according to the normal request process. It can test whether the entire call is smooth and can be used for monitoring. - -## Reference use case -[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-echo](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-echo) - -## scenes to be used - -## How to use -All services automatically implement the `EchoService` interface, just cast any service reference to `EchoService` to use it. - -### Spring configuration -```xml - -``` - -### code -```java -// remote service reference -MemberService memberService = ctx. getBean("memberService"); - -EchoService echoService = (EchoService) memberService; // Mandatory transformation to EchoService - -// echo test availability -String status = echoService. $echo("OK"); - -assert(status. equals("OK")); -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/events-notify.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/events-notify.md deleted file mode 100644 index c83e68522677..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/events-notify.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -type: docs -title: "Call trigger event notification" -linkTitle: "Call trigger event notification" -weight: 8 -description: "Event notification when an exception occurs before and after the call" ---- -## Feature description -Before calling, after calling, and when an exception occurs, three events `oninvoke`, `onreturn`, and `onthrow` will be triggered. You can configure which method of which class to notify when an event occurs. - -## Reference use case - -[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-notify](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-notify) - -## scenes to be used - -Before calling the service method, we can record the start time, and after the call ends, we can count the entire call cost. When an exception occurs, we can warn or print error logs, or record request logs and response logs before and after calling the service. - -## How to use - -### Service provider and consumer share service interface - -```java -interface IDemoService { - public Person get(int id); -} -``` -### Service provider implementation - -```java -class NormalDemoService implements IDemoService { - public Person get(int id) { - return new Person(id, "charles`son", 4); - } -} -``` - -### Service provider configuration - -```xml - - - - -``` -### Service consumer Callback interface - -```java -interface Notify { - public void onreturn(Person msg, Integer id); - public void onthrow(Throwable ex, Integer id); -} -``` - -### Service consumer Callback implementation - -```java -class NotifyImpl implements Notify { - public Map ret = new HashMap(); - public Map errors = new HashMap(); - - public void onreturn(Person msg, Integer id) { - System.out.println("onreturn:" + msg); - ret. put(id, msg); - } - - public void onthrow(Throwable ex, Integer id) { - errors. put(id, ex); - } -} -``` - -### Service consumer Callback configuration - -There are the following combinations of the two: - -* Asynchronous callback mode: `async=true onreturn="xxx"` -* Synchronous callback mode: `async=false onreturn="xxx"` -* Asynchronous without callback: `async=true` -* Synchronous without callback: `async=false` - -`callback` and `async` function are decomposed orthogonally, `async=true` indicates whether the result is returned immediately, `async=false` is the default, `onreturn` indicates whether a callback is required. -```xml - - - - -``` - - -### Test code - -```java -IDemoService demoService = (IDemoService) context. getBean("demoService"); -NotifyImpl notify = (NotifyImpl) context. getBean("demoCallback"); -int requestId = 2; -Person ret = demoService. get(requestId); -Assert.assertEquals(null, ret); -//for Test: It is only used to illustrate that the callback is called normally, and the specific implementation of the business is determined by itself. -for (int i = 0; i < 10; i++) { - if (!notify.ret.containsKey(requestId)) { - Thread. sleep(200); - } else { - break; - } -} -Assert.assertEquals(requestId, notify.ret.get(requestId).getId()); -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/explicit-target.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/explicit-target.md deleted file mode 100644 index 7b12bb16d755..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/explicit-target.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -type: docs -title: "Direct Connection Provider" -linkTitle: "Direct Link Provider" -weight: 5 -description: "Direct point-to-point connection in Dubbo" ---- - -{{% pageinfo %}} This document is no longer maintained. You are currently viewing a snapshot version. If you want to view the latest version of the documentation, see [Latest Version](/en/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip/). -{{% /pageinfo %}} - -In the development and testing environment, it is often necessary to bypass the registration center and only test the specified service provider. At this time, point-to-point direct connection may be required. The point-to-point direct connection method will use the service interface as the unit and ignore the provider list of the registration center. A The point-to-point interface configuration does not affect the B interface to obtain the list from the registration center. - -![/user-guide/images/dubbo-directly.jpg](/imgs/user/dubbo-directly.jpg) - -## Configuration via XML - -If the online demand needs point-to-point, you can configure the url to point to the provider in ``, which will bypass the registration center. Multiple addresses are separated by semicolons, and the configuration is as follows: - -```xml - -``` - -{{% alert title="Prompt" color="primary" %}} -`1.0.6` and above version support -{{% /alert %}} - -## Specified by -D parameter - -Add the -D parameter mapping service address to the JVM startup parameters, such as: - -```sh -java -Dcom.alibaba.xxx.XxxService=dubbo://localhost:20890 -``` - -{{% alert title="Prompt" color="primary" %}} -The key is the service name, and the value is the service provider url. This configuration has the highest priority and is supported by `1.0.15` and above versions -{{% /alert %}} - -## By file mapping - -If there are many services, you can also use file mapping, use `-Ddubbo.resolve.file` to specify the mapping file path, this configuration has a higher priority than the configuration [^3] in ``, such as: - -```sh -java -Ddubbo.resolve.file=xxx.properties -``` - -Then add the configuration to the mapping file `xxx.properties`, where the key is the service name and the value is the service provider URL: - -```properties -com.alibaba.xxx.XxxService=dubbo://localhost:20890 -``` - -{{% alert title="Prompt" color="primary" %}} -`1.0.15` and above versions support, `2.0` and above versions automatically load the ${user.home}/dubbo-resolve.properties file, no configuration required -{{% /alert %}} - -{{% alert title="Attention" color="warning" %}} -In order to avoid complicating the online environment, do not use this feature online, it should only be used during the testing phase. -{{% /alert %}} \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/fault-tolerent-strategy.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/fault-tolerent-strategy.md deleted file mode 100644 index e8169c44d409..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/fault-tolerent-strategy.md +++ /dev/null @@ -1,137 +0,0 @@ ---- -type: docs -title: "Cluster Fault Tolerance" -linkTitle: "Cluster Fault Tolerance" -weight: 2 -description: "When the cluster call fails, the fault tolerance solution provided by Dubbo" ---- - -When the cluster call fails, Dubbo provides a variety of fault tolerance schemes, and the default is failover retry. - -![cluster](/imgs/user/cluster.jpg) - -Each node relationship: - -* Here `Invoker` is an abstraction of `Provider` that can call `Service`, `Invoker` encapsulates `Provider` address and `Service` interface information -* `Directory` represents multiple `Invoker`, which can be regarded as `List`, but different from `List`, its value may change dynamically, such as the registration center pushing changes -* `Cluster` disguises multiple `Invoker` in `Directory` as an `Invoker`, which is transparent to the upper layer. The masquerading process includes fault-tolerant logic. After the call fails, try another one -* `Router` is responsible for selecting subsets from multiple `Invoker` according to routing rules, such as read-write separation, application isolation, etc. -* `LoadBalance` is responsible for selecting a specific one from multiple `Invoker`s for this call. The selection process includes a load balancing algorithm. After the call fails, it needs to be re-selected - -## Cluster fault tolerance mode - -You can expand the cluster fault-tolerant strategy by yourself, see: [Cluster Expansion](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/cluster/) - -### Failover Cluster - -Automatic switching on failure, when a failure occurs, retry other servers. Usually used for read operations, but retries can introduce longer delays. The number of retries can be set by `retries="2"` (excluding the first time). - -The number of retries is configured as follows: - -```xml - -``` - -or - -```xml - -``` - -or - -```xml - - - -``` - -{{% alert title="Prompt" color="primary" %}} -This configuration is the default configuration -{{% /alert %}} - -### Failfast Cluster - -Fail fast, only one call is made, and an error will be reported immediately if it fails. Usually used for non-idempotent write operations, such as adding new records. - -### Failsafe Cluster - -Fail safe, when an exception occurs, just ignore it. Typically used for operations such as writing to audit logs. - -### Failback Cluster - -The failure is automatically recovered, and the failed request is recorded in the background and resent at regular intervals. Typically used for message notification operations. - -### Forking Cluster - -Call multiple servers in parallel, and return as long as one succeeds. It is usually used for read operations with high real-time requirements, but more service resources need to be wasted. The maximum parallelism can be set by `forks="2"`. - -### Broadcast Cluster - -Broadcast calls all providers one by one, and if any one reports an error, it will report an error. Usually used to notify all providers to update local resource information such as cache or logs. - -Now in the broadcast call, you can configure the failure ratio of the node call through broadcast.fail.percent. When this ratio is reached, the BroadcastClusterInvoker -No other nodes will be called, and an exception will be thrown directly. broadcast.fail.percent ranges from 0 to 100. By default, an exception is thrown when all calls fail. -broadcast.fail.percent only controls whether to continue to call other nodes after failure, and does not change the result (if any node reports an error, it will report an error). broadcast.fail.percent parameter -Effective in dubbo2.7.10 and above. - -Broadcast Cluster configuration broadcast.fail.percent. - -broadcast.fail.percent=20 means that when 20% of the nodes fail to call, an exception will be thrown, and no other nodes will be called. - -```text -@reference(cluster = "broadcast", parameters = {"broadcast. fail. percent", "20"}) -``` - - -{{% alert title="Prompt" color="primary" %}} -`2.1.0` started to support -{{% /alert %}} - -### Available Cluster - -Calls the currently available instance (only one is called), or throws an exception if no instance is currently available. Usually used in scenarios that do not require load balancing. - -### Mergeable Cluster - -Aggregate the call results in the cluster and return the result, usually used together with group. Aggregate the results by grouping and return the aggregated results, such as menu services, use group to distinguish multiple implementations of the same interface, now the consumer needs to call once from each group and return the results, and return the results after merging, so that You can implement aggregated menu items. - -### ZoneAware Cluster - -In the scenario of multi-registry subscription, load balancing between registry clusters. There are four strategies for address selection between multiple registries: - -1. Specify the priority: `preferred="true"`The address of the registration center will be selected first - -```xml - -``` - -2. Same center priority: check the area to which the current request belongs, and give priority to registration centers with the same area - -```xml - -``` - -3. Weight polling: distribute traffic according to the weight of each registry - -```xml - - - -``` - -4. Default: Select an available registry - -## Cluster mode configuration - -Follow the example below to configure cluster mode on the service provider and consumer - -```xml - -``` - -or - -```xml - -``` diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-reference.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-reference.md deleted file mode 100644 index cae9beb30d03..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-reference.md +++ /dev/null @@ -1,376 +0,0 @@ ---- -type: docs -linkTitle: "Generalized call" -title: "Generalization call (client generalization)" -weight: 4 -description: "RPC calls that do not require a server-side API" ---- - -## Feature description - -Generalized call refers to calling the server without the API (SDK) provided by the server, and the call result can be obtained normally. - -## scenes to be used - -The generalization call is mainly used to implement a general remote service mock framework, which can handle all service requests by implementing the GenericService interface. For example, the following scenario: - -1. Gateway service: If you want to build a gateway service, then the service gateway should be the calling end of all RPC services. However, the gateway itself should not depend on the interface API of the service provider (this will cause the code of the gateway to be modified and redeployed every time a new service is released), so support for generalization calls is required. - -2. Test platform: If you want to build a platform that can test RPC calls, the user can test the corresponding RPC service by inputting information such as group name, interface, method name, etc. Then, for the same reason (that is, every time a new service is released, the code of the gateway needs to be modified and redeployed), the platform itself should not depend on the interface API of the service provider. So support for generalized calls is needed. - -## How to use - -The demo can be seen [sample code in the dubbo project](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-generic) - -The API part uses this demo as an example to explain how to use it. - -### Service definition - -#### Service interface - -```java -public interface HelloService { - - String sayHello(String name); - - CompletableFuture sayHelloAsync(String name); - - CompletableFuture sayHelloAsyncComplex(String name); - - CompletableFuture> sayHelloAsyncGenericComplex(String name); -} - -``` - -#### Service implementation class - -```java -public class HelloServiceImpl implements HelloService { - - @Override - public String sayHello(String name) { - return "sayHello: " + name; - } - - @Override - public CompletableFuture sayHelloAsync(String name) { - CompletableFuture future = new CompletableFuture<>(); - new Thread(() -> { - try { - Thread. sleep(5000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - future.complete("sayHelloAsync: " + name); - }).start(); - - return future; - } - - @Override - public CompletableFuture sayHelloAsyncComplex(String name) { - Person person = new Person(1, "sayHelloAsyncComplex: " + name); - CompletableFuture future = new CompletableFuture<>(); - new Thread(() -> { - try { - Thread. sleep(5000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - future. complete(person); - }).start(); - - return future; - } - - @Override - public CompletableFuture> sayHelloAsyncGenericComplex(String name) { - Person person = new Person(1, "sayHelloAsyncGenericComplex: " + name); - GenericType genericType = new GenericType<>(person); - CompletableFuture> future = new CompletableFuture<>(); - new Thread(() -> { - try { - Thread. sleep(5000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - future. complete(genericType); - }).start(); - - return future; - } -} - -``` - -### Using generic calls through the API - -#### Service initiator - -1. When setting `ServiceConfig`, use `setGeneric("true")` to enable generic calls - -2. When setting `ServiceConfig`, when using setRef to specify the implementation class, you must set a `GenericService` object. instead of the real service implementation class object - -3. Other settings are consistent with normal Api service startup - -```java -private static String zookeeperAddress = "zookeeper://" + System.getProperty("zookeeper.address", "127.0.0.1") + ":2181"; - - public static void main(String[] args) throws Exception { - new Embedded ZooKeeper(2181, false).start(); - - //Create ApplicationConfig - ApplicationConfig applicationConfig = new ApplicationConfig(); - applicationConfig.setName("generic-impl-provider"); - //Create registry configuration - RegistryConfig registryConfig = new RegistryConfig(); - registryConfig.setAddress(zookeeperAddress); - - //Create a new service implementation class, pay attention to use GenericService to receive - GenericService helloService = new GenericImplOfHelloService(); - - //Create service related configuration - ServiceConfig service = new ServiceConfig<>(); - service.setApplication(applicationConfig); - service.setRegistry(registryConfig); - service.setInterface("org.apache.dubbo.samples.generic.call.api.HelloService"); - service.setRef(helloService); - // Key point: set to generalization call - // Note: it is no longer recommended to use the setGeneric function whose parameter is a Boolean value - //should use referenceConfig.setGeneric("true") instead - service.setGeneric("true"); - service. export(); - - System.out.println("dubbo service started"); - - new CountDownLatch(1). await(); - } -} -``` - -#### Generalizing the caller -step: - -1. When setting `ReferenceConfig`, use `setGeneric("true")` to enable generic calls - -2. After configuring `ReferenceConfig`, use `referenceConfig.get()` to get the instance of the `GenericService` class - -3. Use its `$invoke` method to get the result - -4. Other settings are consistent with normal Api service startup - -```java - //Define generalized call service class - private static GenericService genericService; - public static void main(String[] args) throws Exception { - //Create ApplicationConfig - ApplicationConfig applicationConfig = new ApplicationConfig(); - applicationConfig.setName("generic-call-consumer"); - //Create registry configuration - RegistryConfig registryConfig = new RegistryConfig(); - registryConfig.setAddress("zookeeper://127.0.0.1:2181"); - //Create service reference configuration - ReferenceConfig referenceConfig = new ReferenceConfig<>(); - //Set the interface - referenceConfig.setInterface("org.apache.dubbo.samples.generic.call.api.HelloService"); - applicationConfig.setRegistry(registryConfig); - referenceConfig.setApplication(applicationConfig); - // Key point: set to generalization call - // Note: it is no longer recommended to use the setGeneric function whose parameter is a Boolean value - //should use referenceConfig.setGeneric("true") instead - referenceConfig.setGeneric(true); - //Set asynchronous, not necessary, it depends on the business. - referenceConfig.setAsync(true); - //Set the timeout - referenceConfig.setTimeout(7000); - - //Get the service, because it is a generalized call, so it must be of the GenericService type - genericService = referenceConfig. get(); - - //Using the $invoke method of the GenericService class object can be used instead of the original method - //The first parameter is the name of the method to call - //The second parameter is the parameter type array of the method to be called, which is a String array, and the full class name of the parameter is stored in it. - //The third parameter is the parameter array of the method to be called, which is an Object array, and the required parameters are stored in it. - Object result = genericService. $invoke("sayHello", new String[]{"java. lang. String"}, new Object[]{"world"}); - //Use CountDownLatch, if you use synchronous calls, you don't need to do this. - CountDownLatch latch = new CountDownLatch(1); - //Get the result - CompletableFuture future = RpcContext.getContext().getCompletableFuture(); - future. whenComplete((value, t) -> { - System.err.println("invokeSayHello(whenComplete): " + value); - latch. countDown(); - }); - // print the result - System.err.println("invokeSayHello(return): " + result); - latch. await(); - } -``` - -### Using generic calls with Spring -There are many ways to use service exposure and service discovery in Spring, such as xml and annotations. Take xml as an example here. -step: - -1. There is no need to change the producer side - -2. Add the attribute of `generic=true` to the original `dubbo:reference` tag on the consumer side. - -```xml - -``` - -3. Get the Bean container, and get the `GenericService` instance through the Bean container. - -4. Call the `$invoke` method to get the result - -```java - - private static GenericService genericService; - - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/generic-impl-consumer.xml"); - context. start(); - //The name of the bean corresponding to the service is determined by the id of the xml tag - genericService = context. getBean("helloService"); - //Get the result - Object result = genericService. $invoke("sayHello", new String[]{"java. lang. String"}, new Object[]{"world"}); - } -``` - - -### Protobuf object generalization call - -General generalization calls can only be used when the generated service parameters are POJOs, while GoogleProtobuf objects are abnormal POJOs generated based on Builder, which can be generalized and called through protobuf-json. - -GoogleProtobuf serialization-related Demo can refer to [protobuf-demo](https://github.com/apache/dubbo-samples/tree/master/3-extensions/serialization/dubbo-samples-protobuf) - -#### Generic calls to Google Protobuf objects through Spring - -Configure the declaration generic = "protobuf-json" in Spring - -```xml - -``` - -Get barService in Java code and start generalizing calls: - -```java -GenericService barService = (GenericService) applicationContext. getBean("barService"); -Object result = barService.$invoke("sayHello",new String[]{"org.apache.dubbo.protobuf.GooglePbBasic$CDubboGooglePBRequestType"}, new Object[]{"{\"double\":0.0,\"float \":0.0,\"bytesType\":\"Base64String\",\"int32\":0}"}); -``` - -#### Generalized calls to Google Protobuf objects through API - -```java -ReferenceConfig reference = new ReferenceConfig(); -// Weakly typed interface name -reference.setInterface(GenericService.class.getName()); -reference.setInterface("com.xxx.XxxService"); -// Declare as Protobuf-json -reference.setGeneric(Constants.GENERIC_SERIALIZATION_PROTOBUF); - -GenericService genericService = reference. get(); -Map person = new HashMap(); -person. put("fixed64", "0"); -person. put("int64", "0"); -// Referring to Google's official protobuf 3 syntax, only one POJO object is transmitted in each method of the service -// The generalized call of protobuf only allows passing a json object of type String to represent the request parameter -String requestString = new Gson().toJson(person); -// The return object is the json string of the GoolgeProtobuf response object. -Object result = genericService. $invoke("sayHello", new String[] { - "com.xxx.XxxService.GooglePbBasic$CDubboGooglePBRequestType"}, - new Object[] {requestString}); -``` - -#### Processing of GoogleProtobuf objects - -The GoogleProtobuf object is generated by the Protocol contract. For related knowledge, please refer to [ProtocolBuffers Documentation](https://developers.google.com/protocol-buffers/?hl=zh-CN). If there is the following Protobuf contract - -```proto -syntax = "proto3"; -package com.xxx.XxxService.GooglePbBasic.basic; -message CDubboGooglePBRequestType { - double double = 1; - float float = 2; - int32 int32 = 3; - bool bool = 13; - string string = 14; - bytes bytesType = 15; -} - -message CDubboGooglePBResponseType { - string msg = 1; -} - -service CDubboGooglePBService { - rpc sayHello (CDubboGooglePBRequestType) returns (CDubboGooglePBResponseType); -} -``` - -Then the corresponding request is constructed according to the following method - -```java -Map person = new HashMap<>(); -person. put("double", "1.000"); -person. put("float", "1.00"); -person. put("int32","1"); -person. put("bool","false"); -//String objects need to be base64 encoded -person. put("string","someBaseString"); -person. put("bytesType","150"); -``` - -#### GoogleProtobuf service metadata analysis - -Google Protobuf objects lack standard JSON formatting and the resulting service metadata information is incorrect. Please add the following dependencies that depend on metadata parsing. - -```xml - - org.apache.dubbo - dubbo-metadata-definition-protobuf - ${dubbo.version} - -``` - -It is also relatively easy to construct generalized call objects from service metadata. - - -## Precautions - -1. If the parameter is a basic type or Date, List, Map, etc., there is no need to convert it, just call it directly. - -2. If the parameter is another POJO, use Map instead. - -Such as: -```java -public class Student { - String name; - int age; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this. age = age; - } -} - -``` - -Should be converted to: - -```java -Map student = new HashMap(); -student. put("name", "xxx"); -student. put("age", "xxx"); -``` - -3. For other serialization formats, special configuration is required \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-service.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-service.md deleted file mode 100644 index e9154e2b64d0..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/generic-service.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -type: docs -linkTitle: "Generalized call" -title: "Achieving generalization (server-side generalization)" -weight: 17 -description: "Implement a generic remote service Mock framework, which can handle all service requests by implementing the GenericService interface" ---- -## Feature description -The universal interface implementation method is mainly used when there is no API interface and model classifier on the server side. All POJOs in the parameters and return values are represented by Map, which is usually used for framework integration. For example, to implement a general remote service Mock framework, you can All service requests are handled by implementing the GenericService interface. - -## scenes to be used - -## How to use -Implement the `GenericService` interface in Java code - -```java -package com.foo; -public class MyGenericService implements GenericService { - - public Object $invoke(String methodName, String[] parameterTypes, Object[] args) throws GenericException { - if ("sayHello".equals(methodName)) { - return "Welcome " + args[0]; - } - } -} -``` - -### Exposing generic implementations via Spring - -Declare the implementation of the service in the Spring configuration - -```xml - - -``` - -### Expose the generalization implementation through the API - -```java -... -// Use org.apache.dubbo.rpc.service.GenericService to replace all interface implementations -GenericService xxxService = new XxxGenericService(); - -// This instance is very heavy, and it encapsulates all connections with the registry and service providers, please cache -ServiceConfig service = new ServiceConfig(); -// Weakly typed interface name -service.setInterface("com.xxx.XxxService"); -service.setVersion("1.0.0"); -// point to a generic service implementation -service.setRef(xxxService); - -// expose and register services -service. export(); -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/group-merger.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/group-merger.md deleted file mode 100644 index 968b01a6c3ce..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/group-merger.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -type: docs -title: "Group Aggregation" -linkTitle: "Group Aggregation" -weight: 1 -description: "Aggregate the results by grouping and return the aggregated results" ---- - -## Feature description -Aggregate the results by grouping and return the aggregated results, such as menu service, use group to distinguish multiple implementations of the same interface, now the consumer needs to call once from each group and return the result, and return the result after merging, so You can implement aggregated menu items. - -For relevant codes, please refer to [Samples in the dubbo project](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-merge) - -## scenes to be used - -Service Grouping and Multiple Versions - -## How to use - -### Search all groups - -```xml - -``` - -### Merge specified groups - -```xml - -``` -### Specify method merge - -Combine the results of the specified method, and other unspecified methods will only call one Group - -```xml - - - -``` -### A method is not merged - -One method does not combine results, others combine results - -```xml - - - -``` -### Specify merge strategy - -Specify the merge strategy, the default is to automatically match according to the return value type, if there are two combiners of the same type, you need to specify the name of the combiner [Merge result extension](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/ description/merger) - -```xml - - - -``` -### Specify merge method - -Specify the merge method to merge the specified method that returns the result of the call. The parameter type of the merge method must be the return result type itself - -```xml - - - -``` - -#### hint: -Supported since `2.1.0` version diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/isolation-executor.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/isolation-executor.md deleted file mode 100644 index bd6ef217b48d..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/isolation-executor.md +++ /dev/null @@ -1,230 +0,0 @@ ---- -type: docs -linkTitle: "Thread Pool Isolation" -title: "Thread Pool Isolation" -weight: 4 -description: "Provide a new thread pool management method for isolating thread pools between services" ---- - -## Feature description -A new thread pool management method enables the thread pools of each service in the provider application to be isolated and independent from each other. The exhaustion of the thread pool resources of a certain service will not affect other normal services. Support thread pool configurable, manually specified by the user. - -## scenes to be used - -## How to use - -Currently, it can be configured in the form of API, XML, and Annotation - -**Configuration parameters** -- `ApplicationConfig` adds `String executor-management-mode` parameter, the configuration values are `default` and `isolation`, and the default is `default`. - - `executor-management-mode = default` use the original **thread pool management mode with the protocol port as the granularity and sharing between services** - - `executor-management-mode = isolation` uses the newly added thread pool management method with **service triplet as granularity and isolation between services** -- `ServiceConfig` adds `Executor executor` parameter, **thread pool for isolation between services**, can be configured by the user to provide the thread pool you want, if not specified, it will be configured according to the protocol (` ProtocolConfig`) information to build a default thread pool for service isolation. - -> `ServiceConfig` adds the `Executor executor` configuration parameter to take effect only if `executor-management-mode = isolation` is specified. -### APIs -```java - public void test() { - // provider app - DubboBootstrap providerBootstrap = DubboBootstrap. newInstance(); - - ServiceConfig serviceConfig1 = new ServiceConfig(); - serviceConfig1.setInterface(DemoService.class); - serviceConfig1.setRef(new DemoServiceImpl()); - serviceConfig1.setVersion(version1); - // set executor1 for serviceConfig1, max threads is 10 - NamedThreadFactory threadFactory1 = new NamedThreadFactory("DemoService-executor"); - ExecutorService executor1 = Executors. newFixedThreadPool(10, threadFactory1); - serviceConfig1.setExecutor(executor1); - - ServiceConfig serviceConfig2 = new ServiceConfig(); - serviceConfig2.setInterface(HelloService.class); - serviceConfig2.setRef(new HelloServiceImpl()); - serviceConfig2.setVersion(version2); - // set executor2 for serviceConfig2, max threads is 100 - NamedThreadFactory threadFactory2 = new NamedThreadFactory("HelloService-executor"); - ExecutorService executor2 = Executors. newFixedThreadPool(100, threadFactory2); - serviceConfig2.setExecutor(executor2); - - ServiceConfig serviceConfig3 = new ServiceConfig(); - serviceConfig3.setInterface(HelloService.class); - serviceConfig3.setRef(new HelloServiceImpl()); - serviceConfig3.setVersion(version3); - // Because executor is not set for serviceConfig3, the default executor of serviceConfig3 is built using - // the threadpool parameter of the protocolConfig ( FixedThreadpool , max threads is 200) - serviceConfig3.setExecutor(null); - - // It takes effect only if [executor-management-mode=isolation] is configured - ApplicationConfig applicationConfig = new ApplicationConfig("provider-app"); - applicationConfig.setExecutorManagementMode("isolation"); - - providerBootstrap - .application(applicationConfig) - .registry(registryConfig) - // export with tri and dubbo protocol - .protocol(new ProtocolConfig("tri", 20001)) - .protocol(new ProtocolConfig("dubbo", 20002)) - .service(serviceConfig1) - .service(serviceConfig2) - .service(serviceConfig3); - - providerBootstrap.start(); - } -``` - -### XML -```xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` -### Annotation -```java -@Configuration -@EnableDubbo(scanBasePackages = "org.apache.dubbo.config.spring.isolation.spring.annotation.provider") -public class ProviderConfiguration { - @Bean - public RegistryConfig registryConfig() { - RegistryConfig registryConfig = new RegistryConfig(); - registryConfig.setAddress("zookeeper://127.0.0.1:2181"); - return registryConfig; - } - - // NOTE: we need config executor-management-mode="isolation" - @Bean - public ApplicationConfig applicationConfig() { - ApplicationConfig applicationConfig = new ApplicationConfig("provider-app"); - - applicationConfig.setExecutorManagementMode("isolation"); - return applicationConfig; - } - - // expose services with dubbo protocol - @Bean - public ProtocolConfig dubbo() { - ProtocolConfig protocolConfig = new ProtocolConfig("dubbo"); - return protocolConfig; - } - - // expose services with tri protocol - @Bean - public ProtocolConfig tri() { - ProtocolConfig protocolConfig = new ProtocolConfig("tri"); - return protocolConfig; - } - - // customized thread pool - @Bean("executor-demo-service") - public Executor demoServiceExecutor() { - return new DemoServiceExecutor(); - } - - // customized thread pool - @Bean("executor-hello-service") - public Executor helloServiceExecutor() { - return new HelloServiceExecutor(); - } -} -``` -```java -// customized thread pool -public class DemoServiceExecutor extends ThreadPoolExecutor { - public DemoServiceExecutor() { - super(10, 10, 60, TimeUnit. SECONDS, new LinkedBlockingDeque<>(), - new NamedThreadFactory("DemoServiceExecutor")); - } -} -``` - -```java -// customized thread pool -public class HelloServiceExecutor extends ThreadPoolExecutor { - public HelloServiceExecutor() { - super(100, 100, 60, TimeUnit. SECONDS, new LinkedBlockingDeque<>(), - new NamedThreadFactory("HelloServiceExecutor")); - } -} -``` -```java -// "executor-hello-service" is beanName -@DubboService(executor = "executor-demo-service", version = "1.0.0", group = "Group1") -public class DemoServiceImplV1 implements DemoService { - - @Override - public String sayName(String name) { - return "server name"; - } - - @Override - public Box getBox() { - return null; - } -} - -``` - -```java -// not set executor for this service, the default executor built using threadpool parameter of the protocolConfig -@DubboService(version = "3.0.0", group = "Group3") -public class HelloServiceImplV2 implements HelloService { - private static final Logger logger = LoggerFactory.getLogger(HelloServiceImplV2.class); - - @Override - public String sayHello(String name) { - return "server hello"; - } -} - -``` - -```java -@DubboService(executor = "executor-hello-service", version = "2.0.0", group = "Group2") -public class HelloServiceImplV3 implements HelloService { - private static final Logger logger = LoggerFactory.getLogger(HelloServiceImplV3.class); - - @Override - public String sayHello(String name) { - return "server hello"; - } -} -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-call.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-call.md deleted file mode 100644 index 4271b2e8cf04..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-call.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -type: docs -title: "Local call" -linkTitle: "Local call" -weight: 22 -description: "Local call in Dubbo" ---- - -## Feature description -The local call uses the injvm protocol, which is a pseudo-protocol. It does not open ports, does not initiate remote calls, and is only directly associated in the JVM, but executes Dubbo's Filter chain. - -## scenes to be used - -When we need to call a remote service, the remote service has not been developed yet, and similar services are implemented locally using the injvm protocol. When calling this service, we can call our local implementation service. - -## How to use - -### Define the injvm protocol -```xml - -``` - -### Set the default protocol - -```xml - -``` - -### Set service protocol - -```xml - -``` - -### Prioritize the use of injvm - -```xml - - -``` - -**or** - -```xml - - -``` - -#### Notice: -Dubbo from `2.2.0`, each service will be exposed locally by default, and can be referenced locally without any configuration. If you do not want the service to be exposed remotely, you only need to set the protocol to injvm in the provider. ** - - -### Automatic exposure - -Starting with `2.2.0`, every service is exposed locally by default. When referencing services, local services are preferred by default. If you want to reference remote services, you can use the following configuration to force references to remote services. - -```xml - -``` - -### Dynamic configuration call behavior - -Starting with' 3.2', the api provided by Dubbo allows users to dynamically configure whether a single call is a local call or a remote call, and when it is not configured, the local service will be referenced first by default. - -**Configure a single call as a remote call.** - -```java -RpcContext.getServiceContext().setLocalInvoke(false); -``` - -**Configure a single call as a local call.** - -```java -RpcContext.getServiceContext().setLocalInvoker(true); -``` - diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-mock.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-mock.md deleted file mode 100644 index fe40ed3bcdf1..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-mock.md +++ /dev/null @@ -1,157 +0,0 @@ ---- -type: docs -title: "Local Masquerade" -linkTitle: "Local camouflage" -weight: 10 -description: "Learn how to use local masquerade to achieve service degradation in Dubbo3" ---- - -## Feature description - -There is a mechanism in Dubbo3 to achieve lightweight service degradation, which is local masquerade[^1]. - -## scenes to be used - -Local masquerading is often used for service degradation. For example, for a verification service, when all the service providers hang up, if the service consumer initiates a remote call at this time, the call will fail and an `RpcException` will be thrown. - -In order to avoid such a situation where an exception is thrown directly, the client can use local masquerade to provide Mock data and return authorization failure. - -## How to use - -### Enable mock configuration - -Configured in the following way in the Spring XML configuration file: - -```xml - -``` - -or - -```xml - -``` - -Provide Mock implementation in the project [^2]: - -```java -package com.foo; -public class BarServiceMock implements BarService { - public String sayHello(String name) { - // You can fake fault-tolerant data, this method is only executed when RpcException occurs - return "fault tolerance data"; - } -} -``` - -### Use the return keyword to mock the return value - -Use `return` to return an object represented by a string as the return value of the Mock. Legal strings can be: -- *empty*: stands for empty, returns the default value of the basic type, the empty value of the collection class, and the empty object of the custom entity class [^3] -- *null*: return `null` -- *true*: returns `true` -- *false*: return `false` -- *JSON string*: returns the object obtained after deserializing the JSON string - -For example, if the consumer of the service often needs try-catch to catch exceptions, such as: - -```java -public class DemoService { - - public Offer findOffer(String offerId) { - Offer offer = null; - try { - offer = offerService. findOffer(offerId); - } catch (RpcException e) { - logger. error(e); - } - - return offer; - } -} -``` - -Then consider changing to a Mock implementation, and `return null` in the Mock implementation. If you just want to simply ignore exceptions, it is available in `2.0.11` and above: - -```xml - -``` - -### Use the throw keyword Mock to throw an exception - -Use `throw` to return an Exception object as the return value of the Mock. - -A default RPCException is thrown when the call fails: - -```xml - - -``` - -When an error occurs in the call, throw the specified Exception [^4]: - -```xml - - -``` - -### Use the force and fail keywords to configure the behavior of the Mock - -`force:` means to force the use of Mock behavior, in which case no remote calls will be made. - -`fail:` Consistent with the default behavior, the mock behavior is only used when an error occurs in the remote call. That is to say, it is actually possible not to use the `fail` keyword when configuring, but to use `throw` or `return` directly. - -Both `force:` and `fail:` are supported in combination with `throw` or `return`. - -Force a specified value to be returned: - -```xml - - -``` - -Force the specified exception to be thrown: - -```xml - - -``` - -The specified value is returned when the call fails: -```xml - - - - - -``` - -An exception is thrown when the call fails - -```xml - - - - - -``` - -### Configure Mock at method level - -Mock can be specified at the method level, assuming there are several methods on `com.foo.BarService`, we can specify Mock behavior for the `sayHello()` method separately. - -The specific configuration is as follows. In this example, whenever `sayHello()` is called, it is forced to return "fake": - -```xml - - - - -``` - -## Precautions - -[^1]: Mock is a subset of Stub, which is convenient for service providers to implement fault-tolerant logic on the client side. Because it is often necessary to perform fault-tolerant when RpcException (such as network failure, timeout, etc.) occurs, and when business exceptions (such as login Wrong username and password) does not require fault tolerance. If you use Stub, you may need to catch and rely on the RpcException class, but you can use Mock without relying on RpcException, because its agreement is to execute only when RpcException occurs. -[^2]: Next to the interface, put a Mock implementation that implements the BarService interface and has a no-argument constructor. At the same time, if the Mock class is not explicitly specified in the configuration file, then it is necessary to ensure that the fully qualified class name of the Mock class is in the form of `original fully qualified class name+Mock`, such as `com.foo.BarServiceMock`, otherwise it will be Mock will fail. -[^3]: If the return value is an entity class, then it will return an empty object with default values instead of `null`. -[^4]: Custom exceptions must have a constructor with `String` as the input parameter, which will be used to receive exception information. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-stub.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-stub.md deleted file mode 100644 index 9139d0faef52..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/local-stub.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -type: docs -title: "Local Stub" -linkTitle: "Local Stub" -weight: 11 -description: "Understand the use of local stubs in Dubbo3 to execute part of the logic on the client" ---- -## Feature description: - -After the remote service, the client usually only has the interface, and the implementation is all on the server side, but the provider sometimes wants to execute some logic on the client side. - -![/user-guide/images/stub.jpg](/imgs/user/stub.jpg) - -## scenes to be used -Do ThreadLocal cache, verify parameters in advance, forge fault-tolerant data after call failure, etc. At this time, you need to bring a Stub in the API, and the client generates a Proxy instance, which will pass the Proxy to the Stub through the constructor [^1], and then pass the The Stub is exposed to the user, and the Stub can decide whether to call the Proxy. - -## How to use -### spring configuration file configuration - -```xml - -``` - -or - -```xml - -``` - -### Provide Stub implementation [^2] - -```java -package com.foo; -public class BarServiceStub implements BarService { - private final BarService barService; - - // The constructor passes in the real remote proxy object - public BarServiceStub(BarService barService){ - this. barService = barService; - } - - public String sayHello(String name) { - // This code is executed on the client side, you can do ThreadLocal local cache on the client side, or pre-verify whether the parameters are legal, etc. - try { - return barService.sayHello(name); - } catch (Exception e) { - // You are fault tolerant and can do any AOP interception - return "fault tolerance data"; - } - } -} -``` - -[^1]: Stub must have a constructor that can be passed to Proxy. -[^2]: Next to the interface put a Stub implementation that implements the BarService interface and has a constructor that passes in the remote BarService instance. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-protocols.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-protocols.md deleted file mode 100644 index 7fe2ca5a0ba5..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-protocols.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -type: docs -title: "Multi-protocol" -linkTitle: "Multi-protocol" -weight: 9 -description: "Configure multi-protocol in Dubbo" ---- -## Feature description -Dubbo allows multi-protocol configuration, supports different protocols on different services or supports multiple protocols on the same service at the same time. - -## scenes to be used - -## How to use - -### Different protocols for different services -Different services apply different protocols for transmission in terms of performance. For example, short connection protocols are used for large data, and long connection protocols are used for small data and large concurrency. - -```xml - - - - - - - - - - - - -``` - -### Multi-protocol exposed services -Needed to interoperate with http clients - -```xml - - - - - - - - - - -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-registry.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-registry.md deleted file mode 100644 index 7f3d0ec1583a..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-registry.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -type: docs -title: "Multiple Registries" -linkTitle: "Multiple Registration Centers" -weight: 10 -description: "Register the same service to multiple registries in Dubbo" ---- -## Feature description -Dubbo supports the simultaneous registration of the same service to multiple registries, or the registration of different services to different registries, or even references to services with the same name registered on different registries at the same time. In addition, the registry is [^1] that supports custom extensions. -## scenes to be used - -## How to use -### Multi-registry registration - -For example: Some services of the Chinese website are too late to be deployed in Qingdao, and are only deployed in Hangzhou, while other applications in Qingdao need to reference this service, so the service can be registered to two registration centers at the same time. -```xml - - - - - - - - - -``` - -### Different services use different registries - -For example: some CRM services are specially designed for international websites, and some services are specially designed for Chinese websites. -```xml - - - - - - - - - - - -``` - -### Multiple Registry References - -For example: CRM needs to call the PC2 service of the Chinese station and the international station at the same time. PC2 is deployed in both the Chinese station and the international station. The interface and version number are the same, but the connected databases are different. -```xml - - - - - - - - - - - -``` - -If only the test environment temporarily needs to connect to two different registration centers, use vertical symbols to separate multiple different registration center addresses: - -```xml - - - - - - - - -``` - -[^1]: You can extend the registry by yourself, see: [Registry Extension](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/registry) diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-versions.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-versions.md deleted file mode 100644 index 2554479c4896..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/multi-versions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -type: docs -title: "Service Version" -linkTitle: "Service version" -weight: 1 -description: "Configure multiple versions for the same service in Dubbo" ---- - -## Feature description -**Follow the steps below for version migration** - -1. During low-stress periods, first upgrade half of the providers to the new version -2. Upgrade all consumers to the new version -3. Then upgrade the remaining half of the providers to the new version - -#### Configuration -- Old and new versions of service providers -- New and old version service consumers - -## scenes to be used -When an interface is implemented and an incompatible upgrade occurs, the version number can be used for transition, and services with different version numbers do not refer to each other. - -## Reference use case - -[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-version](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-version) - -## How to use -### service provider -Old version service provider configuration -```xml - -``` -New Version Service Provider Configuration -```xml - -``` -### Service Consumer -Old version service consumer configuration -```xml - -``` -New Version Service Consumer Configuration -```xml - -``` -### Does not distinguish between versions -If you don't need to distinguish between versions, you can configure it in the following way -```xml - -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/parameter-validation.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/parameter-validation.md deleted file mode 100644 index b32956df1aa7..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/parameter-validation.md +++ /dev/null @@ -1,196 +0,0 @@ ---- -type: docs -title: "Parameter Validation" -linkTitle: "Parameter verification" -weight: 2 -description: "Parameter verification in dubbo3" ---- -## Feature description -The parameter verification function is implemented based on [JSR303](https://jcp.org/en/jsr/detail?id=303), users only need to identify the verification annotation of the JSR303 standard, and realize the verification by declaring the filter. - -#### Maven dependencies - -```xml - - javax.validation - validation-api - 1.0.0.GA - - - org.hibernate - hibernate-validator - 4.2.0.Final - -``` - -## scenes to be used - -When the server provides interface services to the outside, it solves various interface parameter verification problems. - -## Reference use case - -[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-validation](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-validation) - -## How to use - -### Parameter annotation example - -```java -import java.io.Serializable; -import java.util.Date; - -import javax.validation.constraints.Future; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Past; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; - -public class ValidationParameter implements Serializable { - private static final long serialVersionUID = 7158911668568000392L; - - @NotNull // not allowed to be null - @Size(min = 1, max = 20) // length or size range - private String name; - - @NotNull(groups = ValidationService.Save.class) // It is not allowed to be empty when saving, and it is allowed to be empty when updating, indicating that the field will not be updated - @Pattern(regexp = "^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[- .][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$") - private String email; - - @Min(18) // minimum value - @Max(100) // maximum value - private int age; - - @Past // must be a past time - private Date loginDate; - - @Future // must be a future time - private Date expiryDate; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this. age = age; - } - - public Date getLoginDate() { - return loginDate; - } - - public void setLoginDate(Date loginDate) { - this. loginDate = loginDate; - } - - public Date getExpiryDate() { - return expiryDate; - } - - public void setExpiryDate(Date expiryDate) { - this.expiryDate = expiryDate; - } -} -``` - -### Group verification example - -```java -public interface ValidationService { // By default, validation scenarios can be distinguished by service interface, such as: @NotNull(groups = ValidationService.class) - @interface Save{} // The interface with the same name as the method, the first letter is capitalized, used to distinguish validation scenarios, such as: @NotNull(groups = ValidationService.Save.class), optional - void save(ValidationParameter parameter); - void update(ValidationParameter parameter); -} -``` - -### Association Validation Example - -```java -import javax.validation.GroupSequence; - -public interface ValidationService { - @GroupSequence(Update.class) // Verify Update group rules at the same time - @interface Save{} - void save(ValidationParameter parameter); - - @interface Update{} - void update(ValidationParameter parameter); -} -``` - -### Parameter validation example - -```java -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; - -public interface ValidationService { - void save(@NotNull ValidationParameter parameter); // validation parameter is not empty - void delete(@Min(1) int id); // directly verify the basic type parameters -} -``` - -### Validate parameters on the client side - -```xml - -``` - -### Validate parameters on the server side - -```xml - -``` - -> **Dubbo supports hibernate-validator version <=6.x by default, if you use hibernate-validator 7.x version, please declare the validation parameter as jvalidatorNew** - -### Verify exception information - -```java -import javax.validation.ConstraintViolationException; -import javax.validation.ConstraintViolationException; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import org.apache.dubbo.examples.validation.api.ValidationParameter; -import org.apache.dubbo.examples.validation.api.ValidationService; -import org.apache.dubbo.rpc.RpcException; - -public class ValidationConsumer { - public static void main(String[] args) throws Exception { - String config = ValidationConsumer.class.getPackage().getName().replace('.', '/') + "/validation-consumer.xml"; - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(config); - context. start(); - ValidationService validationService = (ValidationService)context.getBean("validationService"); - // Error - try { - parameter = new ValidationParameter(); - validationService. save(parameter); - System.out.println("Validation ERROR"); - } catch (RpcException e) { // What is thrown is RpcException - ConstraintViolationException ve = (ConstraintViolationException) e.getCause(); // A ConstraintViolationException is embedded in it - Set> violations = ve.getConstraintViolations(); // You can get a collection of verification error details - System.out.println(violations); - } - } -} -``` - -> **The validation method can be extended, see [Validation Extension](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/validation) in the developer manual for the extension method** diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/port-unification.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/port-unification.md deleted file mode 100644 index 355203f54230..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/port-unification.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -type: docs -title: "Port Protocol Multiplexing" -linkTitle: "Port protocol multiplexing" -weight: 1 -description: "dubbo3 port protocol multiplexing, single port multi-protocol support" ---- -## Feature description -By configuring the protocol, dubbo3 can support port protocol multiplexing. -For example, after using the Triple protocol to enable port multiplexing, you can add -Dubbo protocol support, and Qos protocol support. These protocols are identified by a unified port multiplexing -It can be used for service protocol migration, which is processed by the server, and can save ports and related resources and reduce the complexity of operation and maintenance. - -![pu-server-image1](/imgs/blog/pu-server/pu-server-flow.png) - -- In the service creation phase, different Protocol objects are created for export by obtaining the protocol configuration exported by the service from the Config layer. in the process of exporting - In , if it is not the first time to create a server with port multiplexing, the Exchanger will save the data passed by the protocol layer to the server for subsequent processing of messages of this protocol type. - -- When the client's message is delivered, it will first be passed to the ProtocolDetector through the server. If the identification is completed, the client will be marked as the corresponding protocol. And configure the corresponding processing logic through WireProtocol, and finally hand it over to ChannelOperator to complete the binding of the underlying IO framework and the processing logic of the corresponding Dubbo framework. - -- After the above protocol identification is completed, the Channel has determined how to process the remote client message, and it can be processed through the corresponding ServerPipeline (the processing thread of the message will also be determined according to the configuration information during the processing). - - -## Reference use case -[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-port-unification](https://github.com/apache/dubbo-samples/tree/master/3-extensions/ protocol/dubbo-samples-port-unification) - - -## configuration method - -For the configuration method supported by Dubbo, please refer to [Configuration Instructions](/zh-cn/overview/mannual/java-sdk/reference-manual/config/) - -### Service multi-protocol export - -The ext-protocol parameter supports configuring multiple different protocols, and the protocols are separated by ",". - -#### xml configuration - -```xml - - - - - - -``` - -#### API configuration - -```java -ProtocolConfig config = new ProtocolConfig(CommonConstants.TRIPLE, -1); - -config.setExtProtocol(CommonConstants.DUBBO+","); -``` - -#### yaml configuration - -```yaml -dubbo: - application: - name: dubbo-springboot-demo-provider - protocol: - name: tri - port: -1 - ext-protocol: dubbo, -``` - -#### properties configuration -```properties -dubbo.protocol.name=tri -dubbo.protocol.ext-protocol=dubbo, -dubbo.protocol.port=20880 -``` - -### Qos access - -#### Qos module import - -```xml - - org.apache.dubbo - dubbo-qos - -``` - -After importing the Qos module, related configuration items can be configured by referring to [Qos Operation Manual](/zh-cn/overview/mannual/java-sdk/reference-manual/qos/overview/) . - -By default, the Qos service based on port multiplexing is started after the module is imported. - -## How to use - -### Qos used - -When the Qos protocol is connected to the port multiplexing scenario, after the connection is established, the client needs to send a message to the server first. Compared with the Qos protocol that provides services through a single port, the port multiplexing version of the Qos protocol handles the telnet connection. In some cases, the user needs to perform some operations to complete the protocol identification (choose one of the two). - -1. Call the command directly - - The recognition can also be completed by directly calling the commands supported by telnet. If the user is not familiar with it, the help command can be called to complete the recognition. - - ![pu-server-image2](/imgs/blog/pu-server/qos-telnet-directcall.png) - -2. Send telnet command to identify - - After establishing a connection through the telnet command, perform the following steps: - - 1. Use crtl + "]" to enter the telnet interactive interface (telnet default escape character) - 2. Call "send ayt" to send a special identification field to the server (a special field of the telnet protocol) - 3. Press Enter to complete the message sending and enter the interactive interface of dubbo - - ![pu-server-imgs3](/imgs/blog/pu-server/qos-telnet-sendayt.png) - - -### Service reference - -Based on the example in [dubbo-samples-port-unification](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-port-unification), quote The configuration of services of different protocols and non-port multiplexing is consistent. Next, the URL information in the calling process is output through the InvokerListener on the Consumer side. - -```java -ReferenceConfig reference = new ReferenceConfig<>(); -reference.setInterface(GreetingService.class); -reference.setListener("consumer"); -reference.setProtocol(this.protocol); -// reference.setProtocol(CommonConstants.DUBBO); -// reference.setProtocol(CommonConstants.TRIPLE); -``` - -![pu-server-imgs4](/imgs/blog/pu-server/reference-service.png) diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/preflight-check.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/preflight-check.md deleted file mode 100644 index ae51b3bb4b06..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/preflight-check.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -type: docs -title: "Check at startup" -linkTitle: "Check at startup" -weight: 1 -description: "Check that dependent services are available at startup" ---- -## Feature description -By default, Dubbo will check whether the dependent service is available at startup, and will throw an exception when it is unavailable, preventing Spring initialization from completing, so that problems can be detected early when going online. The default `check="true"`. - -Checking can be turned off by `check="false"`. For example, when testing, some services do not care, or there is a circular dependency, and one of them must be started first. - -In addition, if your Spring container is lazy-loaded, or if you delay the reference service through API programming, please turn off check, otherwise when the service is temporarily unavailable, an exception will be thrown and a null reference will be obtained. If `check="false"`, always Yes, it will return the reference, and when the service is restored, it can be connected automatically. - -## scenes to be used - -- One-way dependency: with dependency (recommended default setting) and without dependency (check=false can be set) -- Interdependence: that is, circular dependency, (it is not recommended to set check=false) -- Lazy loading handling - -> check is only used to check at startup, if there is no corresponding dependency at runtime, an error will still be reported. - -## How to use - -### via spring configuration file - -Turn off startup checks for a service - -```xml - -``` - -Turn off startup checks for all services - -```xml - -``` - -Turn off registry checks at startup - -```xml - -``` - -### via dubbo.properties - -```properties -dubbo.reference.com.foo.BarService.check=false -dubbo.consumer.check=false -dubbo.registry.check=false -``` - -### via the -D parameter - -```sh -java -Ddubbo.reference.com.foo.BarService.check=false -java -Ddubbo.consumer.check=false -java -Ddubbo.registry.check=false -``` - -## Meaning of configuration - -`dubbo.reference.com.foo.BarService.check`, overrides the check value of the reference of `com.foo.BarService`, even if there is a statement in the configuration, it will be overwritten. - -`dubbo.consumer.check=false` is the default value of `check` for setting reference. If there is an explicit statement in the configuration, such as: ``, it will not be affected influences. - -`dubbo.registry.check=false`, the first two means that the subscription is successful, but whether the provider list is empty or whether an error is reported, if the registration subscription fails, it is also allowed to start, you need to use this option, and will retry periodically in the background . \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/reactive.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/reactive.md deleted file mode 100644 index 8d558dd189c4..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/reactive.md +++ /dev/null @@ -1,235 +0,0 @@ ---- -type: docs -title: "Reactive Programming" -linkTitle: "Reactive Programming" -weight: 1 -description: "Using the Reactive API to operate Triple streaming calls" ---- - -## Feature description - -This feature is implemented based on the Triple protocol and Project Reactor, and is supported in versions above `3.1.0`. Users only need to write the IDL file and specify the corresponding Generator of the protobuf plug-in to generate and use the Stub code that supports the responsive API. - -There are four call modes, namely OneToOne, OneToMany, ManyToOne, and ManyToMany, corresponding to Unary calls, server streams, client streams, and bidirectional streams. In the implementation of Reactor, One corresponds to Mono, and Many corresponds to Flux. - -#### background - -Reactive Stream provides a set of standard asynchronous stream processing APIs. While allowing applications to write event-driven programs, it also ensures node stability through BackPressure. The Triple protocol adds support for streaming scenarios to the Dubbo framework at the communication protocol level. On this basis, it can realize the business requirements of the upper layer including large file transmission and push mechanisms. - -The combined mode of Dubbo + Reactive Stream Stub can bring users the most convenient way of streaming and improve the asynchronous performance of the whole link. - -## Reference use case - -[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-triple-reactor](https://github.com/apache/dubbo-samples/tree/master/3-extensions/ protocol/dubbo-samples-triple-reactor) - -## scenes to be used - -The system needs to handle a large number of concurrent requests without overloading any servers. Systems with large numbers of users providing real-time data and want to ensure that the system can handle the load without crashing or slowing down. - -## How to use - -For Triple usage and configuration, please refer to [Using Triple in IDL](/zh-cn/overview/mannual/java-sdk/reference-manual/protocol/triple/idl/), and ensure that the Dubbo version> = 3.1.0. - -### Add the necessary dependencies - -To use Reactor Triple, you need to add the following additional dependencies. - -```xml - - org.reactivestreams - reactive-streams - - - io.projectreactor - reactor-core - -``` - -### Setup protobuf Maven plugin - -Just change mainClass to `org.apache.dubbo.gen.tri.reactive.ReactorDubbo3TripleGenerator` and make sure `${compiler.version}` >= 3.1.0 - -```xml - - - - org.xolstice.maven.plugins - protobuf-maven-plugin - 0.6.1 - - com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} - - grpc-java - io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} - - - - dubbo - org.apache.dubbo - dubbo-compiler - ${compiler.version} - org.apache.dubbo.gen.tri.reactive.ReactorDubbo3TripleGenerator - - - - - - - compile - - - - - - -``` - -### Write and compile the IDL file - -The writing of the IDL file is completely consistent with the native Triple protocol, and the corresponding code will be seen in the `target/generated-sources/protobuf/java` directory by default after compilation. - -```protobuf -syntax = "proto3"; - -option java_multiple_files = true; - -package org.apache.dubbo.samples.triple.reactor; - -// The request message containing the user's name. -message GreeterRequest { - string name = 1; -} - -// The response message containing the greetings -message GreeterReply { - string message = 1; -} - -service GreeterService { - - rpc greetOneToOne(GreeterRequest) returns (GreeterReply); - - rpc greetOneToMany(GreeterRequest) returns (stream GreeterReply); - - rpc greetManyToOne(stream GreeterRequest) returns (GreeterReply); - - rpc greetManyToMany(stream GreeterRequest) returns (stream GreeterReply); -} -``` - -### use - -1. Add server interface implementation - -```java -package org.apache.dubbo.samples.triple.reactor.impl; - -import org.apache.dubbo.samples.triple.reactor.DubboGreeterServiceTriple; -import org.apache.dubbo.samples.triple.reactor.GreeterReply; -import org.apache.dubbo.samples.triple.reactor.GreeterRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Flux; - -public class GreeterServiceImpl extends DubboGreeterServiceTriple.GreeterServiceImplBase { - - private static final Logger LOGGER = LoggerFactory. getLogger(GreeterServiceImpl. class); - - @Override - public Flux greetManyToMany(Flux request) { - return request.doOnNext(req -> LOGGER.info("greetManyToMany get data: {}", req)) - .map(req -> GreeterReply. newBuilder(). setMessage(req. getName() + " -> server get"). build()) - .doOnNext(res -> LOGGER.info("greetManyToMany response data: {}", res)); - } -} -``` - -2. Add the server interface startup class - -```java -package org.apache.dubbo.samples.triple.reactor; - -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.samples.triple.reactor.impl.GreeterServiceImpl; - -public class ReactorServer { - - private static final int PORT = 50052; - - public static void main(String[] args) { - ServiceConfig reactorService = new ServiceConfig<>(); - reactorService.setInterface(GreeterService.class); - reactorService.setRef(new GreeterServiceImpl()); - - DubboBootstrap bootstrap = DubboBootstrap. getInstance(); - bootstrap. application(new ApplicationConfig("tri-reactor-stub-server")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .protocol(new ProtocolConfig(CommonConstants.TRIPLE, PORT)) - .service(reactorService) - .start(); - } -} -``` - -3. Add client startup class and consumer program - -```java -package org.apache.dubbo.samples.triple.reactor; - -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ReferenceConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.io.IOException; - -public class ReactorConsumer { - - private static final Logger LOGGER = LoggerFactory. getLogger(ReactorConsumer. class); - - private final GreeterService greeterService; - - public ReactorConsumer() { - ReferenceConfig referenceConfig = new ReferenceConfig<>(); - referenceConfig.setInterface(GreeterService.class); - referenceConfig.setProtocol(CommonConstants.TRIPLE); - referenceConfig.setProxy(CommonConstants.NATIVE_STUB); - referenceConfig.setTimeout(10000); - - DubboBootstrap bootstrap = DubboBootstrap. getInstance(); - bootstrap. application(new ApplicationConfig("tri-reactor-stub-server")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .reference(referenceConfig) - .start(); - GreeterService greeterService = referenceConfig. get(); - } - - public static void main(String[] args) throws IOException { - ReactorConsumer reactorConsumer = new ReactorConsumer(); - reactorConsumer.consumeManyToMany(); - System.in.read(); - } - - private void consumeManyToMany() { - greeterService. greetManyToMany(Flux. range(1, 10) - .map(num-> - GreeterRequest.newBuilder().setName(String.valueOf(num)).build()) - .doOnNext(req -> LOGGER.info("consumeManyToMany request data: {}", req))) - .subscribe(res -> LOGGER.info("consumeManyToMany get response: {}", res)); - } -} -``` - -4. Start the server - -5. Start the consumer diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/registry-only.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/registry-only.md deleted file mode 100644 index 1f4b818c96fc..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/registry-only.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -type: docs -title: "Sign Up Only" -linkTitle: "Sign up only" -weight: 41 -description: "Only register but not subscribe" ---- -## Feature description -If there are two mirroring environments and two registries, one service is only deployed in one of the registries, and the other registry has not yet been deployed, and other applications in the two registries need to rely on this service. At this time, the service provider can only register the service to another registration center, but not subscribe to the service from another registration center. - - -## scenes to be used - -## How to use -### Disable subscription configuration - -```xml - - -``` - -**or** - -```xml - - -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade.md deleted file mode 100644 index 0cdfe52442ef..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-downgrade.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -type: docs -title: "Service Downgrade" -linkTitle: "Service Downgrade" -weight: 3 -description: "Downgrade Dubbo service" ---- - -## Feature description -It is recommended to use relevant current limiting and downgrading components (such as [Sentinel](https://sentinelguard.io/zh-cn/docs/open-source-framework-integrations.html)) to achieve the best experience. Reference example practice: [Microservice Governance/Limit and Downgrade](/zh-cn/overview/tasks/ecosystem/rate-limit/) - -Service degradation refers to the emergency treatment of service degradation under abnormal circumstances. - -## scenes to be used - -- When the load of a certain service or interface exceeds the maximum carrying capacity range, downgrade emergency treatment is required to avoid system crash -- When a non-critical service or interface called is temporarily unavailable, simulated data or null is returned, and the business can continue to be available -- Downgrade non-core business services or interfaces, free up system resources, and try to ensure the normal operation of core business -- When an upstream basic service times out or is unavailable, execute a downgrade plan that can respond quickly to avoid the overall avalanche of services - -## How to use - -Take xml configuration as an example: (configuration through annotations is similar) - -### 1. Configure `mock="true"` -example: -```xml - -``` -This method requires an implementation class with the class name + `Mock` suffix under the same package, that is, there is a `DemoServiceMock` class under the `com.xxx.service` package. - -### 2. Configure `mock="com.xxx.service.DemoServiceMock"` -example: -```xml - -``` -This method specifies the full path of the Mock class. - -### 3. Configure `mock="[fail|force]return|throw xxx"` - -* The fail or force keyword is optional, indicating that the call fails or does not call to enforce the mock method, if no keyword is specified, the default is fail -* return indicates the specified return result, and throw indicates that the specified exception is thrown -* xxx is parsed according to the return type of the interface, you can specify the return value or throw a custom exception - -example: -```xml - -``` - -```xml - -``` - -```xml - -``` - -```xml - -``` - -```xml - -``` - -```xml - -``` - -### 4. Use with dubbo-admin - -* Introduce `dubbo-mock-admin`< /a>dependency - -* Set the JVM parameters when the application consumer starts, `-Denable.dubbo.admin.mock=true` - -* Start dubbo-admin, set the Mock rule under the service Mock->rule configuration menu - -Set rules in the dimension of service methods, set return mock data, and dynamically enable/disable rules - -## Precautions - -When Dubbo starts, it will check the configuration. When the configuration of the mock attribute value is wrong, it will fail to start. You can troubleshoot according to the error message - -- The configuration format is wrong, such as `return+null` will report an error, and it will be treated as a mock type. `return` can be omitted or followed by a space followed by the return value - -- Type not found error, such as custom mock class, throw custom exception, please check if the type exists or if there is a typo diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-group.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-group.md deleted file mode 100644 index 3ae84bc76534..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/service-group.md +++ /dev/null @@ -1,184 +0,0 @@ ---- -type: docs -title: "Service Group" -linkTitle: "Service Group" -weight: 2 -description: "Use service groups to differentiate between different implementations of a service interface" ---- - -## Feature description -The same interface can use service grouping to distinguish different implementation methods for different business scenarios, different usage requirements, or different functional modules. At the same time, the services provided by these different implementations can coexist and support mutual calls. - -## scenes to be used -When an interface has multiple implementations, it can be distinguished by group. - -## Reference use case - -[https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-group](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-group) - -## How to use - -### Annotation configuration - -#### Service provider (annotation configuration) - -Use @DubboService annotation, add group parameter - -```java -@DubboService(group = "demo") -public class DemoServiceImpl implements DemoService { - ... -} - -@DubboService(group = "demo2") -public class Demo2ServiceImpl implements DemoService { - ... -} -``` - -Start the Dubbo service, and you can see services with the same service name and different groups in the registry. Taking Nacos as the registry as an example, the following content is displayed: - -![image-service-group-1.png](/imgs/blog/service-group-1.png) - -#### Service consumer (annotation configuration) - -Use @DubboReference annotation to add group parameter - -```java -@DubboReference(group = "demo") -private DemoService demoService; - -@DubboReference(group = "demo2") -private DemoService demoService2; - -//group value is *, the identifier matches any service group -@DubboReference(group = "*") -private DemoService demoService2; -``` - -### Group Aggregation - -> Reference Example -[https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-merge](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-merge) - -```java -// Group aggregation, merging all groups and returning the result -@DubboReference(group = "*", merger = "true") -private DemoService demoService2; - -// Group aggregation, merging specified groups and returning the result -@DubboReference(group = "merge,merge2", merger = "true") -private DemoService demoService2; -``` - -After starting the Dubbo service, you can see the references of the same service name in different groups in the registration center. Taking Nacos as the registration center as an example, the following content is displayed: -![image-service-group-2.png](/imgs/blog/service-group-2.png) - -### xml configuration - -#### Service provider (xml configuration) - -Use tag, add group parameter - -```xml - - -... - - - -... - -``` - -Start the Dubbo service, and you can see services with the same service name and different groups in the registry. Taking Nacos as the registry as an example, the following content is displayed: - -![image-service-group-1.png](/imgs/blog/service-group-1.png) - -#### Service consumer (xml configuration) - -Use annotation to add group parameter - -```xml - - - ... - - - - - - - - ... - -``` - -After starting the Dubbo service, you can see the references of the same service name in different groups in the registration center. Taking Nacos as the registration center as an example, the following content is displayed: - -![image-service-group-2.png](/imgs/blog/service-group-2.png) - -### API configuration - -#### Service provider (API configuration) - -Use org.apache.dubbo.config.ServiceConfig class, add group parameter - -```java -// ServiceConfig is a heavy object, which internally encapsulates the connection with the registration center and opens the service port -// Please cache by yourself, otherwise it may cause memory and connection leaks -ServiceConfig service = new ServiceConfig<>(); -service.setInterface(DemoService.class); -service.setGroup("demo"); -... - -ServiceConfig service2 = new ServiceConfig<>(); -service.setInterface(DemoService.class); -service.setGroup("demo2"); -... -``` - -Start the Dubbo service, and you can see services with the same service name and different groups in the registry. Taking Nacos as the registry as an example, the following content is displayed: - -![image-service-group-1.png](/imgs/blog/service-group-1.png) - -#### Service consumer (API configuration) - -Use org.apache.dubbo.config.ReferenceConfig, add group parameter - -```java -// ReferenceConfig is a heavy object, which internally encapsulates the connection with the registration center and opens the service port -// Please cache by yourself, otherwise it may cause memory and connection leaks -ReferenceConfig reference = new ReferenceConfig<>(); -reference.setInterface(DemoService.class); -reference.setGroup("demo"); -... - -ReferenceConfig reference2 = new ReferenceConfig<>(); -reference2.setInterface(DemoService.class); -reference2.setGroup("demo2"); -... - -ReferenceConfig reference3 = new ReferenceConfig<>(); -reference3.setInterface(DemoService.class); -reference3.setGroup("*"); -... - -``` -After starting the Dubbo service, you can see the references of the same service name in different groups in the registration center. Taking Nacos as the registration center as an example, the following content is displayed: -![image-service-group-2.png](/imgs/blog/service-group-2.png) - - -> Always *call** only one available group implementation \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip.md deleted file mode 100644 index 93c7ac87f4fc..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/specify-ip.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -type: docs -title: "Dynamic IP call" -linkTitle: "Dynamic IP call at runtime" -weight: 5 -description: "Specify the target IP of this call before initiating a Dubbo call" ---- -## Feature description -Use the extension of Dubbo to realize the specified IP call. - -## scenes to be used - -When initiating a request, you need to specify the server for this call, such as message callback, traffic isolation, etc. - -## How to use - -### Plugin dependencies - -Adapt to Dubbo 3 version - -```xml - - org.apache.dubbo.extensions - dubbo-cluster-specify-address-dubbo3 - 1.0.0 - -``` - -Adapt to Dubbo 2 version - -```xml - - org.apache.dubbo.extensions - dubbo-cluster-specify-address-dubbo2 - 1.0.0 - -``` - -### call example - -```java -ReferenceConfig referenceConfig = new ReferenceConfig<>(); -// ...init -DemoService demoService = referenceConfig. get(); - -// for invoke -// 1. find 10.10.10.10:20880 exist -// 2. if not exist, create a invoker to 10.10.10.10:20880 if `needToCreate` is true (only support in Dubbo 3.x's implementation) -UserSpecifiedAddressUtil.setAddress(new Address("10.10.10.10", 20880, true)); -demoService.sayHello("world"); - - -// for invoke -// 1. find 10.10.10.10:any exist -// 2. if not exist, create a invoker to 10.10.10.10:20880 if `needToCreate` is true (only support in Dubbo 3.x's implementation) -UserSpecifiedAddressUtil.setAddress(new Address("10.10.10.10", 0, true)); -demoService.sayHello("world"); -``` - -### Parameter Description - -Parameters specifying an IP call wrap around an `Address` object. The parameter type reference is as follows: - -```java -package org.apache.dubbo.rpc.cluster.specifyaddress; - -public class Address implements Serializable { - // ip - priority: 3 - private String ip; - - // ip+port - priority: 2 - private int port; - - // address - priority: 1 - private URL urlAddress; - - private boolean needToCreate = false; - - // ignore setter and getter -} -``` - -1. `urlAddress` is the highest priority, if the URL address of the target is specified, it will be used first. (no longer matches follow-up) -2. ip + port (non-0 port) is the second priority, and will be matched from the addresses that have been pushed by the registration center. (no longer matches follow-up) -3. IP is the third priority, and it will be matched from the addresses that have been pushed by the registration center. - -In particular, if `needToCreate` is specified as `true`, an invoker will be automatically built according to the parameters passed in. For addresses specified by specifying ip ( + port ), -It will automatically use the parameter of the first address in the registry to create the template; if there is no address, it will be automatically created based on the Dubbo protocol. -To customize the logic of creating invoker, please implement `org.apache.dubbo.rpc.cluster.specifyaddress.UserSpecifiedServiceAddressBuilder` SPI interface. (This function is only supported by **Dubbo 3 implementation**) - -Pass the `UserSpecifiedAddressUtil` tool class to the Dubbo framework before constructing the `Address` parameter for each request. - -```java -package org.apache.dubbo.rpc.cluster.specifyaddress; - -public class UserSpecifiedAddressUtil { - - public static void setAddress(Address address) { ... } - -} -``` - -> **Must be set every time, and the call must be initiated immediately after setting**, if there is an interceptor error (remove this value in the Dubbo framework is performed during the address selection process), it is recommended to set null to avoid ThreadLocal memory leaks that will affect the follow-up transfer. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/streaming.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/streaming.md deleted file mode 100644 index 3e0f865302ca..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/streaming.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -type: docs -title: "Stream Communication" -linkTitle: "Stream Communication" -weight: 4 -description: "Stream communication based on Triple protocol" ---- - -TBD \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/subscribe-only.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/subscribe-only.md deleted file mode 100644 index 3113ec6848ca..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/subscribe-only.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -type: docs -title: "Subscription Only" -linkTitle: "Subscription Only" -weight: 6 -description: "Only subscribe without registration" ---- -## Feature description - -In order to facilitate development and testing, a registration center that is available for all services is often shared offline. At this time, if a service provider under development registers, it may affect the normal operation of consumers. - -The service provider developer can only subscribe to the service (the developed service may depend on other services), without registering the service under development, and test the service under development through direct connection. - -![/user-guide/images/subscribe-only.jpg](/imgs/user/subscribe-only.jpg) -## scenes to be used -## How to use - -### Disable registration configuration - -```xml - -``` -**or** - -```xml - -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/transaction.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/transaction.md deleted file mode 100644 index a34b86e0b817..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/service/transaction.md +++ /dev/null @@ -1,397 +0,0 @@ ---- -type: docs -title: "Distributed Transactions" -linkTitle: "Distributed Transaction" -weight: 1 -description: "Use distributed transactions in Dubbo" ---- - -## How to use - -### **First step** - -First visit: [https://seata.apache.org/unversioned/download/seata-server](https://seata.apache.org/unversioned/download/seata-server) - -Download the seata1.5.2 service we need to use - -### **Second step** - -1. Add the undo_log table to your database participating in global transactions (TCC, SAGA, XA can skip this step) - -```sql --- for AT mode you must to init this sql for you business database. the seata server not need it. -CREATE TABLE IF NOT EXISTS `undo_log` -( - `branch_id` BIGINT(20) NOT NULL COMMENT 'branch transaction id', - `xid` VARCHAR(100) NOT NULL COMMENT 'global transaction id', - `context` VARCHAR(128) NOT NULL COMMENT 'undo_log context, such as serialization', - `rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info', - `log_status` INT(11) NOT NULL COMMENT '0: normal status,1: defense status', - `log_created` DATETIME(6) NOT NULL COMMENT 'create datetime', - `log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime', - UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`) -) ENGINE = InnoDB - AUTO_INCREMENT = 1 - DEFAULT CHARSET = utf8 COMMENT = 'AT transaction mode undo table'; -``` - -2. Create a library named seata in your mysql database, and use the following sql - -```sql --- -------------------------------- The script used when storeMode is 'db' ------- ------------------------- --- the table to store GlobalSession data -CREATE TABLE IF NOT EXISTS `global_table` -( - `xid` VARCHAR(128) NOT NULL, - `transaction_id` BIGINT, - `status` TINYINT NOT NULL, - `application_id` VARCHAR(32), - `transaction_service_group` VARCHAR(32), - `transaction_name` VARCHAR(128), - `timeout` INT, - `begin_time` BIGINT, - `application_data` VARCHAR(2000), - `gmt_create` DATETIME, - `gmt_modified` DATETIME, - PRIMARY KEY (`xid`), - KEY `idx_gmt_modified_status` (`gmt_modified`, `status`), - KEY `idx_transaction_id` (`transaction_id`) -) ENGINE = InnoDB - DEFAULT CHARSET = utf8; - --- the table to store BranchSession data -CREATE TABLE IF NOT EXISTS `branch_table` -( - `branch_id` BIGINT NOT NULL, - `xid` VARCHAR(128) NOT NULL, - `transaction_id` BIGINT, - `resource_group_id` VARCHAR(32), - `resource_id` VARCHAR(256), - `branch_type` VARCHAR(8), - `status` TINYINT, - `client_id` VARCHAR(64), - `application_data` VARCHAR(2000), - `gmt_create` DATETIME(6), - `gmt_modified` DATETIME(6), - PRIMARY KEY (`branch_id`), - KEY `idx_xid` (`xid`) -) ENGINE = InnoDB - DEFAULT CHARSET = utf8; - --- the table to store lock data -CREATE TABLE IF NOT EXISTS `lock_table` -( - `row_key` VARCHAR(128) NOT NULL, - `xid` VARCHAR(96), - `transaction_id` BIGINT, - `branch_id` BIGINT NOT NULL, - `resource_id` VARCHAR(256), - `table_name` VARCHAR(32), - `pk` VARCHAR(36), - `gmt_create` DATETIME, - `gmt_modified` DATETIME, - PRIMARY KEY (`row_key`), - KEY `idx_branch_id` (`branch_id`) -) ENGINE = InnoDB - DEFAULT CHARSET = utf8; -``` - -### **third step** - -Introduce seata dependency into your project - -spring-boot application: - -``` - - io.seata - seata-spring-boot-starter - 1.5.2 - -``` - -spring application: - -``` - - io.seata - seata-all - 1.5.2 - -``` - -### **the fourth step** - -spring-boot application: - -Reference [seata/script/client/spring at develop seata/seata (github.com)](https://github.com/seata/seata/tree/develop/script/client/spring) - -Add it to your project's application.yml. - -```yaml -seata: - enabled: true - application-id: applicationName - tx-service-group: my_test_tx_group - enable-auto-data-source-proxy: true #Only AT and XA modes need to be true, and the data source will be automatically proxied after opening - data-source-proxy-mode: AT #Optional AT&XA - config: - type: nacos - nacos: - #namespace: If the configuration is created in a non-default namespace, please fill in the id of the namespace here - serverAddr: 127.0.0.1:8848 - group: SEATA_GROUP - username: "nacos" - password: "nacos" - data-id: seata.properties - registry: - type: nacos - nacos: - application: seata-server - server-addr: 127.0.0.1:8848 - group: SEATA_GROUP - #namespace: If the configuration is created in a non-default namespace, please fill in the id of the namespace here - username: "nacos" - password: "nacos" -``` - -spring application: - -Add [seata/script/client/conf at develop · seata/seata (github.com)](https://github.com/seata/seata/tree/develop/script/client/conf) under registry.conf, because High-availability deployment uses a third-party configuration center, so file.conf is not required - -``` -registry { - # file, nacos, eureka, redis, zk, consul, etcd3, sofa, custom - type = "nacos" - nacos { - application = "seata-server" - serverAddr = "127.0.0.1:8848" - group = "SEATA_GROUP" - namespace = "" - username = "" - password = "" - ##if use MSE Nacos with auth, mutex with username/password attribute - #accessKey = "" - #secretKey = "" - ##if use Nacos naming meta-data for SLB service registry, specify nacos address pattern rules here - #slbPattern = "" - } -} - -config { - # file, nacos, apollo, zk, consul, etcd3, springCloudConfig, custom - type = "nacos" - nacos { - serverAddr = "127.0.0.1:8848" - namespace = "" - group = "SEATA_GROUP" - username = "" - password = "" - ##if use MSE Nacos with auth, mutex with username/password attribute - #accessKey = "" - #secretKey = "" - dataId = "seata.properties" - } -} -``` - -### **the fifth step** - -Run the nacos you downloaded, and refer to [https://github.com/seata/seata/tree/develop/script/config-center](https://github.com/seata/seata/tree/develop/script/config-center) and modify the config.txt - -```properties -#Only used by client -#The transaction group is called my_test_tx_group and the corresponding seata-server cluster is default -service.vgroupMapping.my_test_tx_group=default -#The following are only used by server -store.mode=db -store.db.datasource=druid -store.db.dbType=mysql -store.db.driverClassName=com.mysql.jdbc.Driver -store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true -store.db.user=username -store.db.password=password -store.db.minConn=5 -store.db.maxConn=30 -store.db.globalTable=global_table -store.db.branchTable=branch_table -store.db.queryLimit=100 -store.db.lockTable=lock_table -store.db.maxWait=5000 -``` - -Open the nacos console, create a configuration whose dataId is seata.properties under the corresponding namespace, fill in the group as SEATA_GROUP, and fill in the above content and select the type as properties to save -Dingtalk_20220724021635.jpg.png - -### **Step 6** - -Change application.yml in server - -```yaml -server: - port: 7091 - -spring: - application: - name: seata-server - -record: - config: classpath:logback-spring.xml - file: - path: ${user.home}/logs/seata - -console: - user: - username: seata - password: seata - -seata: - config: - # support: nacos, consul, apollo, zk, etcd3 - type: nacos - nacos: - server-addr: 127.0.0.1:8848 - #namespace: If the configuration is created in a non-default namespace, please fill in the id of the namespace here - group: SEATA_GROUP - username: - password: - ##if use MSE Nacos with auth, mutex with username/password attribute - #access-key: "" - #secret-key: "" - data-id: seata.properties - registry: - # support: nacos, eureka, redis, zk, consul, etcd3, sofa - type: nacos - nacos: - application: seata-server - server-addr: 127.0.0.1:8848 - group: SEATA_GROUP - namespace: - cluster: default - #namespace: If the configuration is created in a non-default namespace, please fill in the id of the namespace here - password: - ##if use MSE Nacos with auth, mutex with username/password attribute - #access-key: "" - #secret-key: "" -# server: -# service-port: 8091 #If not configured, the default is '${server.port} + 1000' - security: - secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017 - tokenValidityInMilliseconds: 1800000 - ignore: - urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*. png, /**/*.ico, /console-fe/public/**, /api/v1/auth/login -``` - -### **Step Seven** - -An example of adding @GlobalTransactional to the interface of the global transaction caller (the service that initiates the global transaction) is as follows: - -```java -@GetMapping(value = "testCommit") -@GlobalTransactional -public Object testCommit(@RequestParam(name = "id",defaultValue = "1") Integer id, - @RequestParam(name = "sum", defaultValue = "1") Integer sum) { - Boolean ok = productService. reduceStock(id, sum); - if (ok) { - LocalDateTime now = LocalDateTime.now(); - Orders orders = new Orders(); - orders.setCreateTime(now); - orders.setProductId(id); - orders. setReplaceTime(now); - orders. setSum(sum); - orderService. save(orders); - return "ok"; - } else { - return "fail"; - } -} -``` - -Spring applications need to manually proxy the data source to select the transaction mode and initialize the transaction scanner when using AT or XA mode - -```java -@Primary -@Bean("dataSource") -public DataSource dataSource(DataSource druidDataSource) { - //AT agent choose one of the two - return new DataSourceProxy(druidDataSource); - //XA Proxy - return new DataSourceProxyXA(druidDataSource) -} -``` - -```java - @Bean - public GlobalTransactionScanner globalTransactionScanner() { - return new GlobalTransactionScanner("application name", "my_test_tx_group"); - } -``` - -If you use tcc mode, you need to additionally define two-stage try and confirm(commit) cancel(rollback) in the serviceimpl of the corresponding provider - -The spring-boot application needs to close the data source proxy - -```yaml -seata: - enable-auto-data-source-proxy: false -``` - -```java -/** - * Define two-phase commit name = the bean name of the tcc, globally unique commitMethod = commit is the two-phase confirmation method rollbackMethod = rollback is the two-phase cancellation method - * useTCCFence=true is to enable anti-hanging - * BusinessActionContextParameter annotation to pass parameters to the second stage - * - * @param params - input parameters - * @return String - */ -@TwoPhaseBusinessAction(name = "beanName", commitMethod = "commit", rollbackMethod = "rollback", useTCCFence = true) -public void insert(@BusinessActionContextParameter(paramName = "params") Map params) { - logger.info("You can reserve resources here, or use the characteristics of tcc to mix with AT. In the second stage, use the messages stored here in the first stage and send them out through the second stage, such as redis, mq and other operations"); -} - -/** - * The confirmation method can be named otherwise, but it must be consistent with the commitMethod. The context can pass the parameters of the try method - * - * @param context context - * @return boolean - */ -public void commit(BusinessActionContext context) { - logger.info("Reserved resources are actually processed, or send mq messages and redis storage"); -} - -/** - * Two-stage cancellation method - * - * @param context context - * @return boolean - */ -public void rollback(BusinessActionContext context) { - logger.info("Release reserved resources, or clear the message cache sent when the first phase is ready to be submitted by the second phase"); -} -``` - -linux/macos - -```shell -cd bin - -sh seata-server.sh -``` - -windows - -```shell -cd bin -./seata-server.bat -``` - -Run seata-server, after success, run your own service dubbo provider&consumer - - - -### **The eighth step is to build a highly available Seata-server** - -Since seata-server supports the separation mode of computing and storage, and supports exposing service addresses to multiple registration centers, it only needs to be configured according to the sixth step and then expanded horizontally - -For details, please visit: https://seata.io/ diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/_index.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/_index.md deleted file mode 100755 index 35b08d27a470..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/_index.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -type: docs -title: "Traffic Governance Rules" -linkTitle: "Traffic Governance" -weight: 2 -no_list: true -hide_summary: true ---- - - - -### Traffic Management - -The essence of traffic management is to distribute requests to application services according to established routing rules, as shown in the following figure: - -![What is traffic control](/imgs/v3/concepts/what-is-traffic-control.png) - -in: -+ There can be multiple routing rules, and different routing rules have priorities. Such as: Router(1) -> Router(2) -> ... -> Router(n) -+ A routing rule can route to multiple different application services. For example: Router(2) can route to Service(1) or Service(2) -+ Multiple different routing rules can route to the same application service. For example: both Router(1) and Router(2) can route to Service(2) -+ Routing rules can also not route to any application service. For example: Router(m) is not routed to any Service, all requests hitting Router(m) will cause errors because there is no corresponding application service processing -+ Application service can be a single instance or an application cluster. - -### Dubbo Mesh format traffic management introduction - -Dubbo provides a traffic management strategy that supports the mesh method, which can easily implement [A/B testing](./mesh-style/ab-testing-deployment/), [canary release](./mesh-style/canary -deployment/), [blue-green deployment](./mesh-style/blue-green-deployment/) and other capabilities. - -Dubbo divides the entire traffic management into two parts: [VirtualService](./mesh-style/virtualservice/) and [DestinationRule](./mesh-style/destination-rule/). When Consumer receives a request, it will follow [DubboRoute](./mesh-style/virtualservice/#dubboroute) and [DubboRouteDetail](./mesh- style/virtualservice/#dubboroutedetail) is matched to the corresponding subnet in [DubboDestination](./mesh-style/virtualservice/#dubbodestination), and finally according to the configuration in [DestinationRule](./mesh-style/destination-rule/) The labels in [subnet](./mesh-style/destination-rule/#subset) information find the corresponding Provider cluster that needs specific routing. in: - -+ [VirtualService](./mesh-style/virtualservice/) mainly deals with rules for inbound traffic diversion, and supports service-level and method-level diversion. -+ [DubboRoute](./mesh-style/virtualservice/#dubboroute) mainly solves the problem of service level shunting. At the same time, it also provides retry mechanism, timeout, fault injection, mirroring traffic and other capabilities. -+ [DubboRouteDetail](./mesh-style/virtualservice/#dubboroutedetail) mainly solves the method-level shunt problem in a service. Supports shunting capabilities in various dimensions such as method name, method parameters, number of parameters, parameter types, headers, etc. At the same time, it also supports method-level retry mechanism, timeout, fault injection, mirroring traffic and other capabilities. -+ [DubboDestination](./mesh-style/virtualservice/#dubbodestination) is used to describe the destination address of routing traffic, and supports host, port, subnet and other methods. -+ [DestinationRule](./mesh-style/destination-rule/) mainly deals with destination address rules, which can be associated with Provider clusters through hosts, subnet, etc. At the same time, load balancing can be achieved through [trafficPolicy](./mesh-style/destination-rule/#trafficpolicy). - -This design concept solves the coupling problem between traffic diversion and destination address very well. Not only simplifies the configuration rules to effectively avoid the problem of configuration redundancy, but also supports any combination of [VirtualService](./mesh-style/virtualservice/) and [DestinationRule](./mesh-style/destination-rule/), It can flexibly support various business usage scenarios. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/config-rule.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/config-rule.md deleted file mode 100644 index 3078b58750aa..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/config-rule.md +++ /dev/null @@ -1,172 +0,0 @@ ---- -type: docs -title: "Configuration Rules" -linkTitle: "Configuration Rules" -weight: 34 -description: "Configure application-level governance rules and service-level governance rules in Dubbo" ---- -## override rules -Overriding rules is a capability designed by Dubbo to dynamically adjust the behavior of RPC calls without restarting the application. Starting from version 2.7.0, dynamic configuration adjustments are supported at two granularities of **service** and **application**. - -### Overview - -Please view or modify override rules in the service governance console. - -**Application Granularity** - -```yaml -# Change the weight of all services (scope:application) provided by the application demo (key:demo) on port 20880 (side:provider) to 1000 (weight:1000). ---- -configVersion: v2.7 -scope: application -key: demo -enabled: true -configs: -- addresses: ["0.0.0.0:20880"] - side: provider - parameters: - weight: 1000 - ... -``` - -**Service Granularity** - -```yaml -# All consumer (side:consumer) DemoService service (key:org.apache.dubbo.samples.governance.api.DemoService) application instance (addresses:[0.0.0.0]), the timeout is changed to 6000ms ---- -configVersion: v2.7 -scope: service -key: org.apache.dubbo.samples.governance.api.DemoService -enabled: true -configs: -- addresses: [0.0.0.0] - side: consumer - parameters: - timeout: 6000 - ... -``` - -## Detailed Rules - -### Configuration template - -```yaml ---- -configVersion: v2.7 -scope: application/service -key: app-name/group+service+version -enabled: true -configs: -- addresses: ["0.0.0.0"] - providerAddresses: ["1.1.1.1:20880", "2.2.2.2:20881"] - side: consumer - applications/services: [] - parameters: - timeout: 1000 - cluster: failfase - loadbalance: random -- addresses: ["0.0.0.0:20880"] - side: provider - applications/services: [] - parameters: - threadpool: fixed - threads: 200 - iothreads: 4 - dispatcher: all - weight: 200 -... -``` - -in: -- `configVersion` means dubbo version -- `scope` indicates the scope of configuration, which is the granularity of application or service. **Required**. -- `key` specifies which service or application the rule body acts on. **Required**. - - When scope=service, the key value is a combination of [{group}:]{service}[:{version}] -- When scope=application, the key value is the application name -- `enabled=true` Whether the overriding rule is valid, it can be left blank, and it is valid by default. -- `configs` defines specific coverage rule content, and n (n>=1) rule bodies can be specified. **Required**. - - side, - - applications - - services - -parameters - - addresses - - providerAddresses - -**For most configuration scenarios, you only need to clarify the following questions to know how to write the configuration:** -1. Whether you want to modify the configuration of the entire application or a service. - - Application: `scope: application, key: app-name` (you can also use `services` to specify certain services). - - Service: `scope: service, key:group+service+version`. - -2. Whether the modification is applied to the consumer or the provider. - - Consumer: `side: consumer`, when acting on the consumer side (you can further use `providerAddress`, `applications` to select specific provider examples or applications). - - Provider: `side: provider`. - -3. Whether the configuration takes effect only for certain specific instances. - - All instances: `addresses: ["0.0.0.0"]` or `addresses: ["0.0.0.0:*"]` depends on the side value. - - Specified instances: `addersses[list of instance addresses]`. - -4. Which property is to be modified. - -### Example - -**1. Disable provider: (Usually used to temporarily kick off a provider machine, similarly, please use routing rules to prohibit consumer access)** - - ```yaml - --- - configVersion: v2.7 - scope: application - key: demo-provider - enabled: true - configs: - - addresses: ["10.20.153.10:20880"] - side: provider - parameters: - disabled: true - ... - ``` - -**2. Adjust the weight: (usually used for capacity evaluation, the default weight is 200)** - - ```yaml - --- - configVersion: v2.7 - scope: application - key: demo-provider - enabled: true - configs: - - addresses: ["10.20.153.10:20880"] - side: provider - parameters: - weight: 200 - ... - ``` - -**3. Adjust the load balancing strategy: (the default load balancing strategy is random)** - - ```yaml - --- - configVersion: v2.7 - scope: application - key: demo-consumer - enabled: true - configs: - - side: consumer - parameters: - loadbalance: random - ... - ``` - -**4. Service downgrade: (Usually used to temporarily shield a non-critical service that has an error)** - - ```yaml - --- -configVersion: v2.7 -scope: service -key: org.apache.dubbo.samples.governance.api.DemoService -enabled: true -configs: -- side: consumer - parameters: - force: return null - ... - ``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/_index.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/_index.md deleted file mode 100644 index 7d82636e40c1..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/_index.md +++ /dev/null @@ -1,268 +0,0 @@ ---- -type: docs -title: "Mesh Routing Rules" -linkTitle: "Mesh Routing Rules" -weight: 40 -description: "Dubbo supports Mesh routing types and cooperation methods" ---- - -### Basic idea -Based on the routing chain, the Pipeline processing method is adopted, as shown in the following figure: - -![route-rule1.png](/imgs/user/route-rule1.png) - - -The logic of the routing chain can be simply understood as target = rn(...r3(r2(r1(src)))). For the internal logic of each router, it can be abstracted as n disjoint address pools addrs-pool-1 ... addrs-pool- n According to the implementation-defined rules, the intersection is taken as the output addrs-out. By analogy, the calculation of the entire routing chain is completed. - -![route-rule2.png](/imgs/user/route-rule2.png) - -On the other hand, if router(n) needs to execute fallback logic, then the fallback logic should be determined after router(n) - - -### fallback processing principle - -After multiple conditional components between multiple routers, it is easy for the address to be filtered to be empty, so we need to perform fallback processing for this situation to ensure that the business can successfully find a valid address under the premise of correctness. - -First we look at the following rules - -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo-route -spec: - hosts: - - demo // Uniformly defined as the application name - dubbo: - - service: - - exact: com.taobao.hsf.demoService:1.0.0 - - exact: com.taobao.hsf.demoService:2.0.0 - route details: - - name: sayHello-String-method-route - match: - -method: - name_match: - exact: "sayHello" - ..... - argp: - - string - route: - -destination: - host: demo - subset: v1 - fallback: - destination: - host: demo - subset: v2 - fallback: - destination: - host: demo - subset: v3 - - - name: sayHello-method-route - match: - -method: - name_match: - exact: "s-method" - route: - -destination: - host: demo - subset: v2 - fallback: - destination: - host: demo - subset: v3 - - - name: interface-route - route: - -destination: - host: demo - subset: v3 - - - service: - - .... ---- -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: DestinationRule -metadata: - name: demo-route -spec: - host: demo - subsets: - - name: v1 - labels: - sigma.ali/mg: v1-host - - - name: v2 - labels: - sigma.ali/mg: v2-host - - - name: v3 - labels: - sigma.ali/mg:v3-host - -``` - -Let's take script routing as an example. The matching conditions of this script routing follow a principle, that is, the matching range is a process from precise to broad. In this example, it is sayHello(string) parameter -> sayHello method -> A matching lookup process for interface-level routing. - -So if we have met a certain condition, but the selected subset address is empty, how will we perform fallback processing? - -Take the condition of matching sayHello(string) parameters as an example. We selected the v1 subset. If it is empty, we can go up to the next level to find the address, that is, to find the address at the method level. The specific configuration is as follows - -```yaml - - name: sayHello-String-method-route - match: - -method: - name_match: - exact: "sayHello" - ..... - argp: - - string - route: - -destination: - host: demo - subset: v1 - fallback: - destination: - host: demo - subset: v2 - fallback: - destination: - host: demo - subset: v3 -``` - -At this time, the address we selected is the v2 method-level address. If v2 still has no address, according to the definition of the rules, we can fallback to the v3 interface level. - -Suppose we have a method matching, if there is no address, we need to report an error directly without fallback, we can configure it like this - - -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo-route -spec: - hosts: - - demo // Uniformly defined as the application name - dubbo: - - service: - - exact: com.taobao.hsf.demoService:1.0.0 - - exact: com.taobao.hsf.demoService:2.0.0 - route details: - - name: sayHello-String-method-route - match: - -method: - name_match: - exact: "sayHello" - ..... - argp: - - string - route: - -destination: - host: demo - subset: v1 - fallback: - destination: - host: demo - subset: v2 - fallback: - destination: - host: demo - subset: v3 - - - name: sayHello-method-route - match: - -method: - name_match: - exact: "s-method" - route: - -destination: - host: demo - subset: v2 - fallback: - destination: - host: demo - subset: v3 - - name: some-method-route - match: - -method: - name_match: - exact: "some-method" - route: - -destination: - host: demo - subset: v4 - - - name: interface-route - route: - -destination: - host: demo - subset: v3 - - - service: - - .... ---- -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: DestinationRule -metadata: - name: demo-route -spec: - host: demo - subsets: - - name: v1 - labels: - sigma.ali/mg: v1-host - - - name: v2 - labels: - sigma.ali/mg: v2-host - - - name: v3 - labels: - sigma.ali/mg:v3-host -``` - -From this rule, we can see that when the some-method condition is matched, it corresponds to the v4 subset, then when v4 is empty, because no fallback is configured, an error will be reported directly at this time - -#### Summary of fallback processing principles - -- We should configure the fallback processing logic of Destination in the VirtualService route -- In fallback subset, if the corresponding subset is also configured with fallback subset, it should also be processed recursively; the relationship between fallback subsets should also be from specific to broad -- When we write matching conditions, we should follow the principle of moving from specific conditions to broad conditions - -### Assembly mode of RouteChain (currently not implemented) - -![route-rule3.png](/imgs/user/route-rule3.png) - - -We see the above figure, in the routing process, we are the processing method of Pipeline, the Router nodes of Pipeline exist in order, and each Router has a unique corresponding VirtualService and **multiple** corresponding DestinationRules for description . - -Take the routing rule configuration stored on Nacos as an example, the format of the configuration is as follows: - -```yaml -DataId: Demo.rule.yaml -GROUP: HSF - -content: - -Virtual Service A ---- -DestinationRule A1 ---- -DestinationRule A2 ---- -Virtual Service B ---- -DestinationRule B ---- -VirtualServiceC ---- -DestinationRule C ---- -... -``` - -`VirtualService A` and `DestinationRule A1`, `DestinationRule A2` form a Router A, `VirtualService B` and `DestinationRule B` form a Router B, and so on to complete the assembly of the entire router chain. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/ab-testing-deployment.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/ab-testing-deployment.md deleted file mode 100644 index e551cf4251ca..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/ab-testing-deployment.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "Ab Test" -linkTitle: "Ab Test" -weight: 30 -description: "On the premise that the old version on the line continues to run, deploy the new version directly and then test it. When the new version passes the test, switch the traffic to the new version, and finally upgrade the old version to the new version." ---- - -### Scene Description -Describe the current IDC, service deployment, service information, desired effects, etc. -### Operation process - -+ step 1 - + routing configuration - + authentication scheme - -+ step 2 - + routing configuration - + authentication scheme \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/blue-green-deployment.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/blue-green-deployment.md deleted file mode 100644 index 9ee61cd78774..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/blue-green-deployment.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "Blue-Green Deployment" -linkTitle: "Blue-green deployment" -weight: 20 -description: "On the premise that the old version on the line continues to run, deploy the new version directly and then test it. When the new version passes the test, switch the traffic to the new version, and finally upgrade the old version to the new version." ---- - -### Scene Description -Describe the current IDC, service deployment, service information, desired effects, etc. -### Operation process - -+ step 1 - + routing configuration - + authentication scheme - -+ step 2 - + routing configuration - + authentication scheme \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/canary-deployment.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/canary-deployment.md deleted file mode 100644 index cf47bd273b3c..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/canary-deployment.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "Canary" -linkTitle: "Canary" -weight: 40 ---- - -### Scene Description - -Describe the current IDC, service deployment, service information, desired effects, etc. - -### Operation process - -+ step 1 - + routing configuration - + authentication scheme - -+ step 2 - + routing configuration - + authentication scheme \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/demo-rule-deployment.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/demo-rule-deployment.md deleted file mode 100644 index f3ef2d6ad312..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/demo-rule-deployment.md +++ /dev/null @@ -1,349 +0,0 @@ ---- -type: docs -title: "Use Case" -linkTitle: "Use Case" -weight: 18 -description: "Make routing rules based on the actual situation." ---- - -### Application Services - -```yaml -com.taobao.hsf.DemoService:1.0.0 -``` - -### service address - -```yaml -10.0.0.1:12200?_p=hessian2&APP=demo&st=na61&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.2:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.3:12200?_p=hessian2&APP=demo&st=na610&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.4:12200?_p=hessian2&APP=demo&st=na620&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER - - -10.0.0.4:12200?_p=hessian2&APP=demo&st=et12&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNSH -10.0.0.5:12200?_p=hessian2&APP=demo&st=et12&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNSH - -10.0.0.6:12200?_p=hessian2&APP=demo&st=SA128&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNSZ -10.0.0.7:12200?_p=hessian2&APP=demo&st=SA128&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNSZ - -10.0.0.8:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX -10.0.0.9:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX -10.0.0.10:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX - -``` -### Routing rules - -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/UnitRouter -spec: - hosts: - - demo - dubbo: - - name: UnitServiceRoute - services: - - exact: com.taobao.hsf.DemoService:1.0.0 - route details: - - name: center-env - match: - - context: - hsfcontext: - user_unit: - exact: CENTER - route: - -destination: - host: demo - subset: CENTER - fallback: // There is no fallback in unitization, and an error is reported directly - - name: unsh-env - match: - - context: - hsfcontext: - user_unit: - exact: UNSH - route: - -destination: - host: demo - subset: UNSH - - name: unsz-env - match: - - context: - hsfcontext: - user_unit: - exact: UNSZ - route: - -destination: - host: demo - subset: UNSZ - - name: zbmix-env - match: - - context: - hsfcontext: - user_unit: - exact: ZBMIX - route: - -destination: - host: demo - subset: ZBMIX - ----- - - -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: DestinationRule -metadata: - name: demo/UnitRouter -spec: - host: demo // This is consistent with the above - subsets: - - name: CENTER - labels: - sigma.ali/unit: CENTER - - name: UNSH - labels: - sigma.ali/unit: UNSH - - name: UNSZ - labels: - sigma.ali/unit: UNSZ - - name: ZBMIX - labels: - sigma.ali/unit: ZBMIX - - ----- - -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/MachineRouter -spec: - hosts: - - demo - dubbo: - - name: MachineRoomRouteDefault // same machine room - services: - - regex: * - route details: - - name: na61-samesite-route // Send traffic from na61 computer room to na61, na610 computer room - match: - - sourceables: - sigma.ali/site:na61 - route: - -destination: - host: demo - subset: na61 - -destination: - host: demo - subset: na610 - weight: 40 - - name: na62-samesite-route // Send traffic from na62 computer room to na62 computer room - match: - - sourceables: - sigma.ali/site: na62 - route: - -destination: - host: demo - subset: na62 - - name: default // Bottom line routing, traffic from other computer rooms can be sent at will - route: - -destination: - host: demo - ..... - ----- - ----- - -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: DestinationRule -metadata: - name: demo/MachineRouter -spec: - host: demo// This is consistent with the above - subsets: - - name: na61 - labels: - sigma.ali/site:na61 - - name: na610 - labels: - sigma.ali/site:na610 - - name: na62 - labels: - sigma.ali/site:na62 - - name: na620 - labels: - sigma.ali/site: na620 - ..... - -``` - -### Case Description - -Taking the above configuration as an example, assuming that the consumer is in the na62 computer room marked by CENTER, the user_unit in the request context belongs to CENTER - -Then we have the following routing flow: - -As we pass through the UnitRouter, the address is divided into four parts - -+CENTER: - -```yaml -10.0.0.1:12200?_p=hessian2&APP=demo&st=na61&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.2:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.3:12200?_p=hessian2&APP=demo&st=na610&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.4:12200?_p=hessian2&APP=demo&st=na620&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER - -``` - - -+ UNSH - -```yaml -10.0.0.4:12200?_p=hessian2&APP=demo&st=et12&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNSH -10.0.0.5:12200?_p=hessian2&APP=demo&st=et12&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNSH - -``` - -+ UNSZ - -```yaml -10.0.0.6:12200?_p=hessian2&APP=demo&st=SA128&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNSZ -10.0.0.7:12200?_p=hessian2&APP=demo&st=SA128&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNSZ - -``` - -+ UNZBMIX - -```yaml -10.0.0.8:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX -10.0.0.9:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX -10.0.0.10:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX - -``` - -Because user_unit belongs to CENTER, we choose the part of CENTER as the address input of MachineRoomRouter, which is - -CENTER - -```yaml -10.0.0.1:12200?_p=hessian2&APP=demo&st=na61&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.2:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.3:12200?_p=hessian2&APP=demo&st=na610&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.4:12200?_p=hessian2&APP=demo&st=na620&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER - -``` - -In the second step, MachineRoomRoute can be divided into five parts - - -na61 - -```yaml -10.0.0.1:12200?_p=hessian2&APP=demo&st=na61&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER - -``` - - -na610 - -```yaml -10.0.0.3:12200?_p=hessian2&APP=demo&st=na610&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER - -``` - -na62 - -```yaml -10.0.0.2:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.8:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX -10.0.0.9:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX -10.0.0.10:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX - -``` - -na620 - -```yaml -10.0.0.4:12200?_p=hessian2&APP=demo&st=na620&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER - -``` - -##### fallback - -```yaml -10.0.0.1:12200?_p=hessian2&APP=demo&st=na61&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.2:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.3:12200?_p=hessian2&APP=demo&st=na610&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.4:12200?_p=hessian2&APP=demo&st=na620&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER - - -10.0.0.4:12200?_p=hessian2&APP=demo&st=et12&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNSH -10.0.0.5:12200?_p=hessian2&APP=demo&st=et12&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNSH - -10.0.0.6:12200?_p=hessian2&APP=demo&st=SA128&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNSZ -10.0.0.7:12200?_p=hessian2&APP=demo&st=SA128&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNSZ - -10.0.0.8:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX -10.0.0.9:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX -10.0.0.10:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX - -``` - -Since the consumer initiates the call in the na62 computer room, it matches - -```yaml - - name: na62-samesite-route // Send traffic from na62 computer room to na62 computer room - match: - - sourceables: - sigma.ali/site: na62 - route: - -destination: - host: demo - subset: na62 - -``` - - -This rule, then, is to choose - -na62 - -```yaml -10.0.0.2:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.8:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX -10.0.0.9:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX -10.0.0.10:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=UNZBMIX - -``` - -The input of UnitRouter to MachineRoomRouter is - -CENTER - -```yaml -10.0.0.1:12200?_p=hessian2&APP=demo&st=na61&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.2:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.3:12200?_p=hessian2&APP=demo&st=na610&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER -10.0.0.4:12200?_p=hessian2&APP=demo&st=na620&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER - -``` - - -The result of the intersection of the two is - -```yaml - 10.0.0.2:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER - -``` - -This result will be used as the output of the next route, repeating the previous actions; - -If this routing rule has ended, the address of the call will be - -```yaml -10.0.0.2:12200?_p=hessian2&APP=demo&st=na62&v=2.0&_TIMEOUT=3000&_ih2=y&mg=demohost&_CONNECTTIMEOUT=1000&_SERIALIZETYPE=hessian&ut=CENTER - -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/destination-rule.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/destination-rule.md deleted file mode 100644 index 3ea88d7151aa..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/destination-rule.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -type: docs -title: "DestinationRule" -linkTitle: "DestinationRule" -weight: 40 -description: "Destination address rule" ---- - - -### DestinationRule -`DestinationRule` is used to process the rules of the target address, and `ServiceEntry`, `WorkloadEntry` and other definitions related to `DestinationRule` are consistent with open source -+ Example of use - -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: DestinationRule -metadata: - name: demo-route -spec: - host: demo - subsets: - trafficPolicy: -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| name | string | The name of the rule, easy to identify the purpose of the rule | YES | -| host | string | The corresponding key value in the registry, now it is the interface name | YES | -| trafficPolicy | TrafficPolicy | traffic policy | NO | -| subsets | Subset[] | naming of single or multiple versions of the service | YES | - -### Subset -The name of the `Subset` application service, which can be single or multiple versions -+ Example of use - -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: DestinationRule -metadata: - name: demo-route -spec: - subsets: #Subnet[] - - name: - labels: -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| name | string | service version name | YES | -| labels | map | labels on the service | YES | - -### TrafficPolicy -`TrafficPolicy` represents the load balancing policy -+ Example of use - -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: DestinationRule -metadata: - name: demo-route -spec: - trafficPolicy: #TrafficPolicy - loadBalancer: -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| loadBalancer | LoadBalancerSettings | Load Balancer Settings | YES | - -### LoadBalancerSettings -`LoadBalancerSettings` is used to represent the configuration related to load balancing -+ Example of use - -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: DestinationRule -metadata: - name: demo-route -spec: - trafficPolicy: - loadBalancer: #LoadBalancerSettings - simple: - consistentHash: -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| simple | string | load balancing strategy, including: `ROUND_ROBIN`, `LEAST_CONN`, `RANDOM`, `PASSTHROUGH` | YES | -| consistentHash | ConsistentHashLB | Consistent Hash strategy (not implemented) NO -| NO | \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/dynamic-rule-deployment.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/dynamic-rule-deployment.md deleted file mode 100644 index 2f066328e967..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/dynamic-rule-deployment.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -type: docs -title: "Dynamic Routing" -linkTitle: "Dynamic Routing" -weight: 15 -description: "Dynamic routing for groovy scripts." ---- - -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - - demo - dubbo: - - services: - - exact: com.taobao.hsf.demoservice:1.0.0 - route details: - - name: sayHello-route - match: - -method: - name_match: - exact: "s-method" - argc: 5 - args: - - index: 2 - type: double - num_value: - oneof: - - range: - start: 100.1 - - index: 1 - type: string - str_value: - oneof: - - regex: "*abc*" - - exact: parameter-1 - - index: 3 - type: bool - - index: 4 - type: int - num_value: - oneof: - - range: - start: 1 - end: 100 - - sourceables: - sigma.ali/appName: "ump2" - route: - -destination: - host: demo - subset: v1 - fallback: - host: demo - subset: v2 - - - name: default-route - route: - -destination: - host: demo - subset: v2 ---- -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: DestinationRule -metadata: - name: reviews-route -spec: - host: demo - subsets: - - name: v1 - labels: - sigma.ali/mg: v1-host - - name: v2 - labels: - sigma.ali/mg: v2-host -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/virtualservice.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/virtualservice.md deleted file mode 100644 index 74048444c4b5..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/virtualservice.md +++ /dev/null @@ -1,481 +0,0 @@ ---- -type: docs -title: "VirtualService" -linkTitle: "VirtualService" -weight: 30 -description: "Rules for inbound traffic" ---- - -### VirtualService -`VirtualService` is a rule used to process inbound traffic, that is to say, it is used to describe which inbound traffic applies to this routing rule. -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| name | string | should be named in the form of `application name/router type`. The `name` attribute is determined once the Router type is defined | YES | -| hosts | string[] | generally refers to the application name | NO | -| dubbo | DubboRoute[] | dubbo routing rules, executed sequentially, return immediately when conditions are met | NO | - -+ Router types are as follows: - -| name | Description | -| --- | --- | -| StandardRouter | A Router that fully uses the standard VirtualService description | -| to be added | to be added | - - -### DubboRoute -`DubboRoute` is an attribute in `VirtualService`, which is used to describe the boundary of the routing strategy. -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: #DubboRoute - - name: - service: - fault: - mirror: - retries: - timeout: - route details: -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| name | string | The name of the rule, easy to identify the purpose of the rule | NO | -| services | StringMatch[] | A list of service names for which the rule takes effect. You can use a specific service name or a regular * to match; if it is not configured by default, it means that all services are valid | | -| fault | dubboFaultInject[] | fault injection (not implemented) | NO | -| mirror | Destination | mirror traffic (not implemented) | NO | -| retries | DubboRetry[] | Retry related (unimplemented) | NO | -| timeout | DubboTimeout[] | timeout related (unimplemented) | NO | -| routedetail | DubboRouteDetail[] | Specific traffic rules, executed sequentially, return immediately when conditions are met | YES | - -### DubboRouteDetail -`DubboRouteDetail` is used to describe detailed routing rules -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - routedetail: #DubboRouteDetail - - name: - match: - route: - mirror: - retries: - timeout: -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| name | string | The name of the rule details, easy to identify the purpose of the rule | NO | -| match | DubboMatchRequest[] | matching condition | YES | -| route | DubboRouteDestination[] | the actual destination address of the qualified traffic | YES | -| mirror | Destination | mirror traffic (not implemented) | NO | -| retries | DubboRetry[] | Retry related (unimplemented) | NO | -| timeout | DubboTimeout[] | timeout related (unimplemented) | NO | - - -### DubboMatchRequest -`DubboMatchRequest` is used to describe the matching rules of the request -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - route detail: - - match: #DubboMatchRequest - - name: - method: - sourceLabels: - attachments: - headers: - threshold: -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| name | string | matching rule name | YES | -| method | DubboMethodMatch | method related matching | YES | -| sourceLabels | map\ | Related labels typed by the caller, including application name, machine group, machine environment variable information, etc.; for HSF-JAVA, you can get the corresponding key from the reported URL/ value | YES | -| attachments | DubboAttachmentMatch | Other information attached to the request, such as HSF request context, Eagleeye context, etc. | NO | -| headers | map\ | Common request protocol fields, etc., such as interface name, method name, timeout, etc. | NO | -| threshold | DoubleMatch | The machines in the called subset list account for the threshold of the entire host | NO | - -Since there may be duplication of fields among headers, attachmes, and methods, TODO further refines - -### DubboMethodMatch -`DubboMethodMatch` is used to achieve method matching -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - route detail: - - match: - - method: #DubboMethodRequest - - name_match: - argc: - args: - argp: - headers: -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| name_match | StringMatch | match the calling method name in the request | YES | -| argc | int | The number of parameters matching the request | NO | -| args | DubboMethodArg[]| is an array of DubboMethodArg type, indicating the condition that each parameter value needs to meet | NO | -| argp | StringMatch[] | match request parameter type | NO | -| headers | map\ | reserved | NO | - -### DubboMethodArg -`DubboMethodArg` is used to match method parameters -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - route detail: - - match: - -method: - - args: #DubboMethodArg - - index: - str_value: - type: - num_value: - bool_value: - reserve: -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| index | uint32 | The position of the matching parameter, the index field starts from 1 (that is, the $index parameter) | YES | -| type | string | The type of the matching parameter, taking the string type of java as an example, the value of this field is java.lang.String, and the default value of this field is java.lang.String | YES | -| str_value | ListStringMatch | The value of the matching parameter, parsed according to $type ListStringMatcher: match java.lang.String) | NO | -| num_value | ListDoubleMatch | Numeric type match | NO | -| bool_value | BoolMatch | bool value type match | NO | -| reserve | reserve | Complex type matching, not defined for now | NO | - - -### DubboAttachmentMatch -`DubboAttachmentMatch` is used to fully match any object -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - route detail: - - match: - - attachments: #DubboAttachmentMatch - eagleeyecontext: - dubbo context: -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| eagleeyecontext| map\ | eagleeye context | NO | -| dubbocontext| map\ | Dubbo request context | NO | - -### ListStringMatch -`ListStringMatch` is a set of `StringMatch` collections, any `StringMatch` matches -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - route detail: - - match: - -method: - - args: - - index: 1 - str_value: #ListStringMatch - oneof: - - regex: "*abc*" - - exact: parameter-1 -``` - -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| oneof | StringMatch[] | matches if any `StringMatch` matches | NO | - -### StringMatch -`StringMatch` is used to describe string matching rules -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - service: #StringMatch - - exact: org.apache.dubbo.demoService:1.0.0 - - prefix: org.apache.dubbo.hello - - regex: org.apache.dubbo.*Service:2.0.0 -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| exact | string (oneof) | exact match | NO | -| prefix | string (oneof) | prefix match | NO | -| regex | string (oneof) | [regular match](https://github.com/google/re2/wiki/Syntax) | NO | -| noempty | string (oneof) | non-empty character match | NO | -| empty | string (oneof) | empty character match | NO | - - -### ListDoubleMatch -`ListDoubleMatch` is a set of `DoubleMatch` collections, any `DoubleMatch` match matches the parameters -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - route detail: - - match: - -method: - - args: - - index: 1 - type: java.lang.Double - num_value: #ListDoubleMatch - oneof: - - range: - start: 1 - end: 100 - -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| oneof | DoubleMatch[] | matches if any `DoubleMatch` matches | NO | - -### DoubleMatch -`DoubleMatch` is used to match values of type `int`, `long`, `double` - -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - route detail: - - match: - -method: - - args: - - index: 1 - type: java.lang.Double - num_value: - oneof: #DoubleMatch[] - - range: - start: 1 - end: 100 - #Assume that the parameter value of the currently input Double type is x, - #The meaning of the following expression is: x%mode=exact, - #That is, it matches only when x%10=6 - - exact: 6 - mode: 10 - -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| exact | double(oneof) | exact value match | NO | -| range | DoubleRangeMatch(oneof) | value range matching | NO | -| mode | double | Modulo operation, it needs to be configured together with the above two semantics | NO | - -### DoubleRangeMatch -`DoubleRangeMatch` is to match the range of `double` values -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - route detail: - - match: - -method: - - args: - - index: 1 - type: java.lang.Double - num_value: - oneof: - - range: #DoubleRangeMatch - start: 1.2 - end: 1000.5 - -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| start | double | value greater than or equal to | YES | -| end | double | value less than | YES | - - -### BoolMatch -`BoolMatch` is used to match `true`, `false` exactly -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - route detail: - - match: - -method: - - args: - - index: 1 - type: java.lang.Boolean - bool_value: #BoolMatch - - exact: true -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| exact | bool(oneof) | `true`, `false`, exact match | | - -### ObjectMatch (not implemented) -`ObjectMatch` for an exact match on any object -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - route detail: - - match: - -method: - - args: - - index: 1 - type: java.lang.String - str_value: - oneof: - - regex: "*abc*" - - exact: parameter-1 -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| type | string | The type of the matching parameter, taking the string type of java as an example, the value of this field is java.lang.String, and the default value of this field is java.lang.String | YES | -| str_value | ListStringMatch | The value of the matching parameter, parsed according to $type ListStringMatcher: match java.lang.String) | NO | -| num_value | ListDoubleMatch | | NO | -| bool_value | BoolMatch | | NO | - -### DubboRouteDestination -`DubboRouteDestination` is used to describe the strategy of traffic to the destination address -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - route detail: - - route: #DubboRouteDestination - destination: - weight: 50 -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| destination | DubboDestination | routing destination Destination | YES | -| weight | int | routing weight | NO | - -### DubboDestination -`DubboDestination` is used to describe the destination address of routing traffic -+ Example of use -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: demo/StandardRouter -spec: - hosts: - dubbo: - - route detail: - - route: #DubboRouteDestination - destination: - host: - subnet: - port: - fallback: -``` -+ property description - -| Field | Type | Description | Required | -| --- | --- | --- | --- | -| host | string | The corresponding `key` value in the registry, now it is the interface name |YES| -| subset | string | address list | YES | -| port | int| port number | YES | -| fallback | DubboDestination | another address list for fallback | NO | \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/weight-rule-deployment.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/weight-rule-deployment.md deleted file mode 100644 index 11865d6ef6a2..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/weight-rule-deployment.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -type: docs -title: "Weight Routing" -linkTitle: "Weight Routing" -weight: 16 -description: "Realize routing function based on user-defined weight." ---- - -```yaml -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: VirtualService -metadata: - name: reviews-route -spec: - hosts: - - reviews.prod.svc.cluster.local - dubbo: - - name: weightRoute - route details: - - name: weight - route: - -destination: - host: reviews.prod.svc.cluster.local - subset: v1 - weight: 60 - - -destination: - host: reviews.prod.svc.cluster.local - subset: v2 - weight: 40 - - ---- -apiVersion: service.dubbo.apache.org/v1alpha1 -kind: DestinationRule -metadata: - name: reviews-route -spec: - host: reviews.prod.svc.cluster.local - subsets: - - name: v1 - labels: - version: v1 - - name: v2 - labels: - version: v2 -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/routing-rule.md b/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/routing-rule.md deleted file mode 100644 index 66aea5700729..000000000000 --- a/content/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/routing-rule.md +++ /dev/null @@ -1,254 +0,0 @@ ---- -type: docs -title: "Routing Rules" -linkTitle: "Routing Rules" -weight: 33 -description: "Service governance through routing rules in Dubbo" ---- - -Routing rules play a role in filtering the address of the target server before initiating an RPC call, and the filtered address list will be used as an alternative address for the consumer to finally initiate an RPC call. - -- Conditional routing. Supports configuring routing rules at the granularity of services or consumer applications. -- Label routing. Configure routing rules at the granularity of Provider applications. - -In the future, we plan to continue to enhance the script routing function based on the 2.6.x version. - -## Conditional Routing - -You can write routing rules in the service management console [Dubbo-Admin](https://github.com/apache/dubbo-admin) at any time - -### Introduction - -- Application granularity - - ```yaml - # The consumer of app1 can only consume all service instances with port 20880 - # The consumers of app2 can only consume all service instances with port 20881 - --- - scope: application - force: true - runtime: true - enabled: true - key: governance-conditionrouter-consumer - conditions: - - application=app1 => address=*:20880 - - application=app2 => address=*:20881 - ... - ``` - -- Service Granularity - - ```yaml - # The sayHello method of DemoService can only consume all service instances with port 20880 - # The sayHi method of DemoService can only consume all service instances with port 20881 - --- - scope: service - force: true - runtime: true - enabled: true - key: org.apache.dubbo.samples.governance.api.DemoService - conditions: - - method=sayHello => address=*:20880 - - method=sayHi => address=*:20881 - ... - ``` - - - -### Detailed rules - -#### The meaning of each field - -- `scope` indicates the granularity of routing rules, and the value of scope will determine the value of key. **Required**. - - service service granularity - - application application granularity -- `Key` specifies which service or application the rule body acts on. **Required**. - - When scope=service, the key value is a combination of [{group}:]{service}[:{version}] - - When scope=application, the key value is the application name -- `enabled=true` Whether the current routing rule is valid, it can be left blank, and it is valid by default. -- `force=false` When the routing result is empty, whether to enforce it, if not enforced, the routing rule with an empty routing result will automatically fail, you can leave it blank, the default is `false`. -- Whether `runtime=false` executes the routing rules every time it is called, otherwise it only pre-executes and caches the results when the provider address list changes, and directly obtains the routing results from the cache when calling. If parameter routing is used, it must be set to `true`. It should be noted that the setting will affect the performance of the call. It can be left blank. The default is `false`. -- `priority=1` is the priority of routing rules, used for sorting, the higher the priority, the higher the execution, it can be left blank, the default is `0`. -- `conditions` defines specific routing rule content. **Required**. - -#### Conditions rule body - - The `conditions` part is the main body of the rule, which consists of 1 to any number of rules. Below we describe the configuration syntax of each rule in detail: - -1. **Format** - -- Before `=>` is the consumer matching condition, all parameters are compared with the consumer’s URL, and when the consumer meets the matching condition, the following filtering rules will be executed for the consumer. -- After `=>`, it is the filter condition of the provider's address list. All parameters are compared with the provider's URL, and consumers only get the filtered address list in the end. -- If the matching condition is empty, it means to apply to all consumers, such as: `=> host != 10.20.153.11` -- If the filter condition is empty, access is prohibited, such as: `host = 10.20.153.10 =>` - -2. **Expression** - -Parameter support: - -- Service call information, such as: method, argument, etc., currently does not support parameter routing -- Fields of the URL itself, such as: protocol, host, port, etc. -- and all parameters on the URL, such as: application, organization, etc. - -Conditional support: - -- The equal sign `=` means "match", such as: `host = 10.20.153.10` -- The inequality sign `!=` means "no match", such as: `host != 10.20.153.10` - -Value support: - -- Separate multiple values with comma `,`, such as: `host != 10.20.153.10,10.20.153.11` -- End with an asterisk `*`, which means wildcard, such as: `host != 10.20.*` -- Start with a dollar sign `$`, which means to quote consumer parameters, such as: `host = $host` - -3. **Condition Example** - -- Exclude pre-release machines: - -``` -=> host != 172.22.3.91 -``` - -- whitelist: - -``` -register.ip != 10.20.153.10,10.20.153.11 => -``` - -{{% alert title="Attention" color="warning" %}} -A service can only have one whitelist rule, otherwise the two rules will be filtered out -{{% /alert %}} - -- Blacklist: - -``` -register.ip = 10.20.153.10,10.20.153.11 => -``` - -- The service is hosted on the application, and only a part of the machine is exposed to prevent the entire cluster from hanging: - -``` -=> host = 172.22.3.1*,172.22.3.2* -``` - -- Additional machines for important applications: - -``` -application != kylin => host != 172.22.3.95,172.22.3.96 -``` - -- Read and write separation: - -``` -method = find*,list*,get*,is* => host = 172.22.3.94,172.22.3.95,172.22.3.96 -method != find*,list*,get*,is* => host = 172.22.3.97,172.22.3.98 -``` - -- Separation of front and back: - -``` -application = bops => host = 172.22.3.91,172.22.3.92,172.22.3.93 -application != bops => host = 172.22.3.94,172.22.3.95,172.22.3.96 -``` - -- Isolate network segments in different computer rooms: - -``` -host != 172.22.3.* => host != 172.22.3.* -``` - -- The provider and consumer are deployed in the same cluster, and the local machine only accesses the local service: - -``` -=> host = $host -``` - - - -## Label Routing Rules - -### Introduction - -Label routing divides one or more service providers into the same group and constrains traffic to flow only in the specified group, so as to achieve the purpose of traffic isolation, which can be used as the capability basis for scenarios such as blue-green release and grayscale release. - -#### Provider - -Tags mainly refer to the grouping of provider-side application instances. Currently, there are two ways to complete instance grouping, namely `dynamic rule marking` and `static rule marking`, where dynamic rules have a higher priority than static rules , and when two rules exist at the same time and conflict occurs, the dynamic rule will prevail. - --Dynamic rule marking, you can issue label grouping rules in the **Service Governance Console** at any time - - ```yaml - # The governance-tagrouter-provider application adds two tag groups tag1 and tag2 - # tag1 contains an instance 127.0.0.1:20880 - # tag2 contains an instance 127.0.0.1:20881 - --- - force: false - runtime: true - enabled: true - key: governance-tagrouter-provider - tags: - - name: tag1 - addresses: ["127.0.0.1:20880"] - - name: tag2 - addresses: ["127.0.0.1:20881"] - ... - ``` - - - -- static marking - - ```xml - - ``` - - or - - ```xml - - ``` - - or - - ```properties - java -jar xxx-provider.jar -Ddubbo.provider.tag={the tag you want, may come from OS ENV} - ``` - - - -#### Consumer - -```java -RpcContext.getContext().setAttachment(Constants.TAG_KEY,"tag1"); -``` - -The scope of the request tag is each invocation. Use attachment to pass the request tag. Note that the value stored in the attachment will continue to be passed in a complete remote call. Thanks to this feature, we only need to call , through the setting of one line of code, the continuous transmission of tags is achieved. - -> Currently only supports hardcoding to set dubboTag. Note that RpcContext is thread-bound and use the TagRouter feature elegantly. It is recommended to set dubboTag through servlet filter (in web environment) or custom SPI filter. - - - -### Detailed rules - -#### Format - -- `Key` specifies which application the rule body applies to. **Required**. -- `enabled=true` Whether the current routing rule is valid, it can be left blank, and it is valid by default. -- `force=false` When the routing result is empty, whether to enforce it, if not enforced, the routing rule with an empty routing result will automatically fail, you can leave it blank, the default is `false`. -- Whether `runtime=false` executes the routing rules every time it is called, otherwise it only pre-executes and caches the results when the provider address list changes, and directly obtains the routing results from the cache when calling. If parameter routing is used, it must be set to `true`. It should be noted that the setting will affect the performance of the call. It can be left blank. The default is `false`. -- `priority=1` is the priority of routing rules, used for sorting, the higher the priority, the higher the execution, it can be left blank, the default is `0`. -- `tags` defines specific tag grouping content, can define any n (n>=1) tags and specify an instance list for each tag. **Required**. - - name, label name -- addresses, the list of instances contained in the current label - - - -#### Downgrading Conventions - -1. When `dubbo.tag=tag1`, the provider marked with `tag=tag1` is preferred. If there is no service corresponding to the request tag in the cluster, the provider with an empty request tag will be downgraded by default; if you want to change this default behavior, that is, no provider matching tag1 will return an exception, you need to set `dubbo.force.tag= true`. - -2. When `dubbo.tag` is not set, only the provider whose tag is empty will be matched. Even if there is an available service in the cluster, if the tag does not match, it cannot be called. This is different from Convention 1. Requests with tags can be downgraded to untagged services, but requests without tags/with other types of tags can never be accessed to other tabbed services. - -{{% alert title="Prompt" color="primary" %}} -Custom routing reference [routing extension](/en/docs3-v2/java-sdk/reference-manual/spi/description/router/) -{{% /alert %}} \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/concepts-and-architecture/_index.md b/content/en/docs3-v2/java-sdk/concepts-and-architecture/_index.md deleted file mode 100755 index 3abffcbaa4a2..000000000000 --- a/content/en/docs3-v2/java-sdk/concepts-and-architecture/_index.md +++ /dev/null @@ -1,8 +0,0 @@ - ---- -type: docs -title: "Concepts and Architecture" -linkTitle: "Concepts and Architecture" -weight: 3 ---- - diff --git a/content/en/docs3-v2/java-sdk/concepts-and-architecture/code-architecture.md b/content/en/docs3-v2/java-sdk/concepts-and-architecture/code-architecture.md deleted file mode 100644 index 27822c0a2bb0..000000000000 --- a/content/en/docs3-v2/java-sdk/concepts-and-architecture/code-architecture.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -type: docs -title: "Code Architecture" -linkTitle: "Code Architecture" -weight: 2 ---- - - -## overall design - -![/dev-guide/images/dubbo-framework.jpg](/imgs/dev/dubbo-framework.jpg) - -illustration: - -* The light blue background on the left in the figure is the interface used by the service consumer, the light green background on the right is the interface used by the service provider, and the interface on the central axis is the interface used by both parties. -* The figure is divided into ten layers from bottom to top. Each layer is one-way dependent. The black arrow on the right represents the dependency relationship between layers. Each layer can be reused by stripping the upper layer. Among them, the Service and Config layers are API , the other layers are SPI. -* The small green block in the figure is the extension interface, and the small blue block is the implementation class. Only the implementation class used to associate each layer is shown in the figure. -* The blue dotted line in the figure is the initialization process, that is, the assembly chain at startup, the red solid line is the method call process, that is, the runtime call chain, and the purple triangle arrow is inheritance. You can regard the subclass as the same node of the parent class, and the line The text above is the method to call. - -## Description of each layer - -* **Config configuration layer**: external configuration interface, centered on `ServiceConfig`, `ReferenceConfig`, can directly initialize configuration classes, or generate configuration classes through spring parsing configuration -* **Proxy service proxy layer**: service interface transparent proxy, generating service client Stub and server Skeleton, with `ServiceProxy` as the center, the extended interface is `ProxyFactory` -* **Registry registration center layer**: Encapsulates the registration and discovery of service addresses, centered on service URLs, and the extended interfaces are `RegistryFactory`, `Registry`, `RegistryService` -* **Cluster routing layer**: Encapsulate the routing and load balancing of multiple providers, and bridge the registration center, with `Invoker` as the center, and the extended interfaces are `Cluster`, `Directory`, `Router`, `LoadBalance` -* **Monitor monitoring layer**: RPC call times and call time monitoring, centered on `Statistics`, extended interfaces are `MonitorFactory`, `Monitor`, `MonitorService` -* **Protocol remote call layer**: Encapsulates RPC calls, centered on `Invocation`, `Result`, extended interfaces are `Protocol`, `Invoker`, `Exporter` -* **Exchange information exchange layer**: encapsulation request response mode, synchronous to asynchronous, centered on `Request`, `Response`, extended interfaces are `Exchanger`, `ExchangeChannel`, `ExchangeClient`, `ExchangeServer` -* **Transport network transport layer**: Abstract mina and netty as a unified interface, with `Message` as the center, and extended interfaces as `Channel`, `Transporter`, `Client`, `Server`, `Codec` -* **Serialize data serialization layer**: some reusable tools, the extended interfaces are `Serialization`, `ObjectInput`, `ObjectOutput`, `ThreadPool` - -## Relationship description - -* In RPC, Protocol is the core layer, that is, as long as there is Protocol + Invoker + Exporter, non-transparent RPC calls can be completed, and then Filter interception points on the main process of Invoker. -* The Consumer and Provider in the picture are abstract concepts, just to let the viewer understand more intuitively which classes belong to the client and server. The reason for not using Client and Server is that Dubbo uses Provider, Consumer, Registry in many scenarios , Monitor divides logical topology nodes and maintains a unified concept. -* Cluster is a peripheral concept, so the purpose of Cluster is to disguise multiple Invokers as one Invoker, so that other people only need to pay attention to the Protocol layer Invoker. Adding Cluster or removing Cluster will not affect other layers, because there is only one Provider, Cluster is not required. -* The Proxy layer encapsulates the transparent proxy of all interfaces, and the Invoker is the center in other layers. Only when it is exposed to the user, the Proxy is used to convert the Invoker into an interface, or convert the interface implementation into an Invoker, that is, remove Proxy layer RPC can be run, but it is not so transparent, and it does not look like calling remote services like calling local services. -* The Remoting implementation is the implementation of the Dubbo protocol. If you choose the RMI protocol, the entire Remoting will not be used. The Remoting is divided into the Transport transport layer and the Exchange information exchange layer. The Transport layer is only responsible for one-way message transmission. , Netty, Grizzly's abstraction, it can also extend UDP transmission, and the Exchange layer encapsulates the Request-Response semantics above the transport layer. -* Registry and Monitor are actually not considered a layer, but an independent node, just for a global overview, drawn together in layers. - -## Module Subpackage - -![/dev-guide/images/dubbo-modules.jpg](/imgs/dev/dubbo-modules.jpg) - -Module description: - -* **dubbo-common public logic module**: including Util class and common model. -* **dubbo-remoting remote communication module**: equivalent to the implementation of the Dubbo protocol, if the RPC uses the RMI protocol, this package does not need to be used. -* **dubbo-rpc remote call module**: abstracts various protocols and dynamic proxy, only includes one-to-one calls, and does not care about cluster management. -* **dubbo-cluster cluster module**: Disguise multiple service providers as one provider, including: load balancing, fault tolerance, routing, etc. The address list of the cluster can be statically configured, or it can be configured by the registration center send. -* **dubbo-registry registration center module**: based on the clustering method issued by the registration center, and the abstraction of various registration centers. -* **dubbo-monitor monitoring module**: Statistics of service call times, call time, and call chain tracking services. -* **dubbo-config configuration module**: Dubbo’s external API, users use Dubbo through Config, hiding all details of Dubbo. -* **dubbo-container container module**: It is a Standlone container, loaded with a simple Main to start Spring, because services usually do not require the features of web containers such as Tomcat/JBoss, there is no need to use web containers to load services. - -On the whole, subcontracting is carried out according to the hierarchical structure. The difference from the layering is: - -* Container is a service container, which is used to deploy and run services, and is not drawn in the layer. -* Both the Protocol layer and the Proxy layer are placed in the rpc module. These two layers are the core of rpc. When there is no need for a cluster, that is, there is only one provider, you can use only these two layers to complete the rpc call. -* Both the Transport layer and the Exchange layer are placed in the remoting module, which is the communication basis for rpc calls. -* The Serialize layer is placed in the common module for greater reuse. - -## Dependencies - -![/dev-guide/images/dubbo-relation.jpg](/imgs/dev/dubbo-relation.jpg) - -illustration: - -* The small squares in the figure Protocol, Cluster, Proxy, Service, Container, Registry, Monitor represent layers or modules, the blue ones indicate that they interact with the business, and the green ones only interact with Dubbo internally. -* The background squares Consumer, Provider, Registry, Monitor in the figure represent the deployment logic topology nodes. -* The blue dotted line in the figure is the call at initialization, the red dotted line is the asynchronous call at runtime, and the red solid line is the synchronous call at runtime. -* Only the RPC layer is included in the figure, and the Remoting layer is not included. Remoting is implicitly included in the Protocol as a whole. - -## call chain - -Expand the red call chain of the general design diagram, as follows: - -![/dev-guide/images/dubbo-extension.jpg](/imgs/dev/dubbo-extension.jpg) - -## Expose service timing - -Expand the blue initialization chain of the exposed service of the service provider on the right side of the general design diagram, and the sequence diagram is as follows: - -![/dev-guide/images/dubbo-export.jpg](/imgs/dev/dubbo-export.jpg) - -## Reference service timing - -Expand the green initialization chain of the service consumer reference service on the left side of the general design diagram, and the sequence diagram is as follows: - -![/dev-guide/images/dubbo-refer.jpg](/imgs/dev/dubbo-refer.jpg) - -## Domain Model - -In Dubbo's core domain model: - -* Protocol is the service domain, which is the main function entry exposed and referenced by Invoker, and it is responsible for the life cycle management of Invoker. -* Invoker is an entity domain, it is the core model of Dubbo, other models are close to it, or converted to it, it represents an executable body, can initiate an invoke call to it, it may be a local implementation, or it may be Is a remote implementation, and possibly a cluster implementation. -* Invocation is a session domain, which holds variables in the calling process, such as method names, parameters, etc. - -## Basic Design Principles - -* Adopt Microkernel + Plugin mode, Microkernel is only responsible for assembling Plugin, and Dubbo's own functions are also realized through extension points, that is, all function points of Dubbo can be replaced by user-defined extensions. -* URL is used as the unified format of configuration information, and all extension points carry configuration information by passing URL. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/concepts-and-architecture/mesh.md b/content/en/docs3-v2/java-sdk/concepts-and-architecture/mesh.md deleted file mode 100644 index fde73380c52f..000000000000 --- a/content/en/docs3-v2/java-sdk/concepts-and-architecture/mesh.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -type: docs -title: "Dubbo Mesh" -linkTitle: "Dubbo Mesh" -weight: 5 ---- - -From the design concept, Dubbo Mesh emphasizes the unified control, standardization and governance capabilities of the control plane, while giving more choices on the data plane, including deployment modes such as Sidecar Mesh and Proxyless Mesh. Multiple deployment models provide enterprises with more choices. Through the hybrid deployment model, while realizing the sharing of the service governance control plane, it can better respond to the deployment requirements of different scenarios (performance, deployment complexity, etc.), and adapt to complex infrastructure environment and improve the availability of the architecture as a whole. - -## background -In the context of cloud native, if we understand Service Mesh as the underlying infrastructure, in the Mesh architecture, some of the capabilities of microservice governance that were previously coupled in the business process are being taken over by Mesh. The traditional microservice framework pays more attention to RPC protocols and programming. Model. The following is an architecture diagram of the popular Mesh product Istio: - -![istio](/imgs/v3/mesh/istio.jpg) - -Under the Mesh architecture -* The unified control plane provides certificate management, observability, traffic governance and other capabilities -* Sidecar makes the SDK lighter and less intrusive, better implementing transparent upgrades, traffic interception, etc. - -## Dubbo Mesh Overall Architecture - -![istio](/imgs/v3/mesh/dubbo-mesh-arc.png) - -* The data plane performs RPC communication based on the Triple protocol; -* The address discovery model adopts application-level service discovery to support ultra-large-scale instance clusters while providing richer service governance capabilities; -* The Dubbo Mesh control plane is based on the industry's mainstream Istio extension, supports Dubbo service discovery customization solutions, and provides richer traffic control capabilities; -* The data plane supports two modes: ThinSDK + Sidecar (such as Envoy) and Proxyless; - - -> For old Dubbo2 users or users who have upgraded Dubbo3 but have not yet migrated new features, you can consider referring to Dubbo solutions provided by other Mesh open source communities (such as Aeraki). -> However, some functions may be limited, and there will be certain performance and capacity bottlenecks. - -### Dubbo Sidecar Mesh -Dubbo provides a ThinSDK deployment mode. In this mode, Dubbo ThinSDK will only provide business application-oriented programming APIs and RPC transmission and communication capabilities, and the rest of the service management -Including address discovery, load balancing, routing addressing, etc., all sink to Sidecar, and Sidecar is responsible for direct communication with the control plane and receiving various traffic control rules. The following is a basic deployment architecture diagram. Dubbo ThinSDK and Sidecar are deployed in the same pod or container. By deploying an independent control plane on the periphery, unified control of traffic and governance is achieved. The control plane and Sicecar are configured and distributed through the xDS protocol shown in the dotted line in the figure, and the communication between Dubbo processes is no longer a direct connection mode, but instead passes through the Sidecar proxy, which intercepts all incoming and outgoing traffic and completes routing and addressing, etc. Service governance tasks. - -![dubbo-sidecar](/imgs/v3/mesh/dubbo-sidecar.png) - -The community recommends Envoy as a sidecar, and the communication protocol uses Triple for better gateway penetration and performance experience. For users who are still using the Dubbo2 protocol who cannot upgrade Triple temporarily, they can refer to the Dubbo2 protocol support solutions provided by Envoy and Aeraki Mesh. - -The Mesh architecture of the ThinSDK + Sidecar mode has many advantages, such as smooth upgrade, multi-language, and small business intrusion, but it also brings some additional problems, such as: -* Sidecar communication brings additional performance loss, which will become especially obvious in network calls with complex topologies. -* The existence of Sidecar makes the life cycle management of the application more complicated. -* The deployment environment is limited, not all environments can meet the requirements of Sidecar deployment and request interception. - -For detailed scheme design and examples, please refer to -* [Dubbo ThinSDK Proposal](/zh-cn/overview/tasks/mesh) -* [Example of use](/zh-cn/overview/tasks/mesh) - -### Dubbo Proxyless Mesh -As a supplement to the ThinSDK + Sidecar model, the Dubbo community has conceived and thought about the direct connection of Dubbo to the control plane since a long time ago, which is currently called the Proxyless Mesh model. The Proxyless mode brings microservices back to the deployment architecture of the 2.x era. As shown in the figure below, it is very similar to the Dubbo classic service governance model we saw above, so this model is not new. Dubbo has been such a design model from the very beginning. However, compared with the Mesh architecture, Dubbo2 does not emphasize the unified management and control of the control plane, which is exactly what Service Mesh emphasizes. It emphasizes the standardized management, control and governance of traffic, observability, certificates, etc., which is also an advanced part of the Mesh concept. . - -![dubbo-proxyless](/imgs/v3/mesh/dubbo-proxyless.png) - -Through the Dubbo3 SDK of different language versions, the xDS protocol analysis can be directly realized, and the Dubbo process can directly communicate with the control plane (Control Plane), so as to realize the unified control of traffic control, service governance, observability, security, etc. of the control plane, avoiding the Sidecar mode The resulting performance loss and complexity of the deployment architecture. - -> Proxyless mode supports both Dubbo2 and Triple protocols, but only supports the address model of application-level service discovery. - -In the Dubbo3 Proxyless architecture mode, the Dubbo process will directly communicate with the control plane, and the Dubbo process will continue to maintain a direct communication mode. We can see the advantages of the Proxyless architecture: -* There is no additional proxy loss, so it is more suitable for performance-sensitive applications -* More conducive to smooth migration of legacy systems -* Simple architecture, easy operation and maintenance deployment -* Suitable for almost all deployment environments - -For detailed scheme design and examples, please refer to -* [Dubbo Proxyless Mesh](/zh-cn/overview/tasks/mesh) -* [Example of use](/zh-cn/overview/tasks/mesh) - -### Dubbo Control Plane Governance Rules -TBD - -Dubbo SDK provides very flexible configurations to control service governance behaviors, such as interface granular service address discovery capabilities, interface granular configuration synchronization, etc. These capabilities make application development and deployment more flexible. However, some advanced functions may be limited under the general Mesh deployment scheme or product, which generally affects the ease of use and flexibility. To this end, Dubbo plans to provide self-developed control surface products to maximize the capabilities of Dubbo3 in the Mesh system. diff --git a/content/en/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture.md b/content/en/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture.md deleted file mode 100644 index f1aadd0eb72a..000000000000 --- a/content/en/docs3-v2/java-sdk/concepts-and-architecture/overall-architecture.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -type: docs -title: "Overall Architecture" -linkTitle: "Overall Architecture" -weight: 1 ---- - - -![dubbo-architecture](/imgs/user/dubbo-architecture.jpg) - -##### Node role description - -| Node | Role Description | -| ------------- | ------------- | -| `Provider` | The service provider of the exposed service | -| `Consumer` | The service consumer who invokes the remote service | -| `Registry` | Registry for service registration and discovery | -| `Monitor` | A monitoring center that counts service calls and call times | -| `Container` | service running container | - -##### Description of calling relationship - -0. The service container is responsible for starting, loading, and running the service provider. -1. When the service provider starts, it registers the services it provides with the registration center. -2. When a service consumer starts, it subscribes to the registration center for the services it needs. -3. The registration center returns the service provider address list to the consumer. If there is a change, the registration center will push the change data to the consumer based on the long connection. -4. The service consumer, from the provider address list, selects a provider to call based on the soft load balancing algorithm, and if the call fails, select another provider to call. -5. Service consumers and providers accumulate the number of invocations and invocation time in memory, and regularly send statistical data to the monitoring center every minute. - -The Dubbo architecture has the following characteristics, namely connectivity, robustness, scalability, and upgradeability to future architectures. - -## Connectivity - -* The registration center is responsible for the registration and search of service addresses, which is equivalent to directory services. Service providers and consumers only interact with the registration center at startup. The registration center does not forward requests, and the pressure is less -* The monitoring center is responsible for counting the number of service calls, call time, etc., and the statistics are first summarized in the memory and sent to the monitoring center server every minute, and displayed in reports -* The service provider registers the services it provides with the registration center, and reports the call time to the monitoring center, which does not include network overhead -* The service consumer obtains the address list of the service provider from the registration center, and directly calls the provider according to the load algorithm, and reports the calling time to the monitoring center, which includes network overhead -* The registration center, service provider, and service consumer are all long connections, except for the monitoring center -* The registration center perceives the existence of the service provider through a long connection, and if the service provider goes down, the registration center will immediately push the event to notify the consumer -* The registration center and monitoring center are all down, and the running providers and consumers are not affected. Consumers cache the list of providers locally -* Both registration center and monitoring center are optional, and service consumers can directly connect to service providers - -## Robustness - -* The downtime of the monitoring center does not affect the use, but part of the sampling data is lost -* After the database is down, the registration center can still provide service list query through the cache, but cannot register new services -* Registration center peer-to-peer cluster, when any one goes down, it will automatically switch to another -* After the registration center is completely down, the service provider and the service consumer can still communicate through the local cache -* The service provider is stateless, and if any one goes down, it will not affect the use -* After the service provider is all down, the service consumer application will be unavailable and will reconnect infinitely waiting for the service provider to recover - -## Scalability - -* The registration center is a peer-to-peer cluster, which can dynamically increase machine deployment instances, and all clients will automatically discover the new registration center -* The service provider is stateless and can dynamically increase machine deployment instances, and the registration center will push new service provider information to consumers - -## Upgradability - -When the scale of service clusters is further expanded and the IT governance structure is further upgraded, it is necessary to realize dynamic deployment and perform flow computing, and the existing distributed service architecture will not bring resistance. The following figure is a possible architecture in the future: - -![dubbo-architecture-futures](/imgs/user/dubbo-architecture-future.jpg) - -##### Node role description - -| Node | Role Description | -| ------------- | ------------- | -| `Deployer` | A local proxy for auto-deployment services | -| `Repository` | The warehouse is used to store the service application release package | -| `Scheduler` | The scheduling center automatically increases or decreases service providers based on access pressure | -| `Admin` | Unified Admin Console | -| `Registry` | Registry for service registration and discovery | -| `Monitor` | A monitoring center that counts service calls and call times | \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/concepts-and-architecture/service-discovery.md b/content/en/docs3-v2/java-sdk/concepts-and-architecture/service-discovery.md deleted file mode 100644 index 21017e978d07..000000000000 --- a/content/en/docs3-v2/java-sdk/concepts-and-architecture/service-discovery.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -type: docs -title: "Service Discovery" -linkTitle: "Service Discovery" -weight: 3 ---- -Service discovery, that is, the ability of the consumer to automatically discover the list of service addresses, is a key capability that the microservice framework needs to have. With the help of automated service discovery, microservices can be implemented without knowing the deployment location and IP address of the peer. communication. - -### Method to realize -There are many ways to realize service discovery. Dubbo provides a Client-Based service discovery mechanism. Usually, additional third-party registry components need to be deployed to coordinate the service discovery process, such as commonly used Nacos, Consul, Zookeeper, etc. Dubbo itself also provides the connection to various registry components, and users can choose flexibly. - -### working principle -Dubbo is based on the automatic service discovery capability of the consumer, and its basic working principle is as follows: - -![//imgs/architecture.png](/imgs/architecture.png) - -A core component of service discovery is the registry, Provider registers addresses to the registry, and Consumer reads and subscribes to the Provider address list from the registry. -Therefore, to enable service discovery, you need to add registry configuration to Dubbo: - -Take dubbo-spring-boot-starter as an example, add registry configuration - -```properties -# application.properties -dubbo - registry - address: zookeeper://127.0.0.1:2181 -``` - -### Introduction to application-level service discovery -In summary, the application-level service discovery introduced by Dubbo3 mainly has the following advantages -* Adapt to cloud-native microservice changes. The infrastructure capabilities in the cloud-native era are continuously released upwards. Platforms such as Kubernetes integrate the conceptual abstraction of microservices. Dubbo3's application-level service discovery is a general model for adapting various microservice systems. -* Improved performance and scalability. The service governance that supports ultra-large-scale clusters has always been Dubbo's advantage. By introducing an application-level service discovery model, it essentially solves the storage and push pressure of the registry address data, and the corresponding address calculation pressure on the consumer side also drops by an order of magnitude. ; The cluster size has also become predictable and assessable (it has nothing to do with the number of RPC interfaces, but only with the instance deployment scale). - -The following figure shows the service discovery model of Dubbo2: Provider registers the service address, Consumer coordinates with the registration center and discovers the service address, and then initiates communication with the address. This is the classic service discovery process used by most microservice frameworks. The special feature of Dubbo2 is that it also integrates the information of "RPC interface" into the address discovery process, and this part of information is often closely related to specific business definitions. - -![//imgs/v3/concepts/servicediscovery_old.png](/imgs/v3/concepts/servicediscovery_old.png) - -After accessing the cloud-native infrastructure, the infrastructure incorporates the abstraction of the concept of microservices, and the process of orchestrating and scheduling containerized microservices completes the registration at the infrastructure level. As shown in the figure below, the infrastructure not only assumes the responsibility of the registration center, but also completes the service registration action, and the information of the "RPC interface", because it is related to specific businesses, is impossible and unsuitable to be hosted by the infrastructure. - -![//imgs/v3/concepts/servicediscovery_k8s.png](/imgs/v3/concepts/servicediscovery_k8s.png) - -In such a scenario, there are two requirements for Dubbo3's service registration discovery mechanism: -Dubbo3 needs to abstract a common address mapping model that has nothing to do with business logic in the original service discovery process, and ensure that this part of the model is reasonable enough to support entrusting the registration behavior and storage of addresses to the underlying infrastructure -Dubbo3's unique business interface synchronization mechanism is an advantage that Dubbo3 needs to retain. It needs to be resolved through its own mechanism within the framework on top of the new address model defined in Dubbo3. - -The new service discovery model designed in this way brings greater advantages to Dubbo3 in terms of architecture compatibility and scalability. - -![//imgs/v3/concepts/servicediscovery_mem.png](/imgs/v3/concepts/servicediscovery_mem.png) - -In terms of architectural compatibility, as mentioned above, it is possible for Dubbo3 to reuse the service abstraction capabilities of the underlying infrastructure; on the other hand, other microservice solutions in the industry such as Spring Cloud also follow this model. -After opening the address discovery, it becomes possible for users to explore using Dubbo to connect heterogeneous microservice systems. - -The Dubbo3 service discovery model is more suitable for building a scalable service system. How to understand this? -Here is a simple example to intuitively compare the data flow changes in the address discovery process between Dubbo2 and Dubbo3: Suppose a microservice application defines 100 interfaces (services in Dubbo), -You need to register 100 services in the registry. If this application is deployed on 100 machines, then these 100 services will generate a total of 100 * 100 = 10000 virtual nodes; and the same application, -For Dubbo3, the new registration discovery model only needs 1 service (only related to the application and has nothing to do with the interface), and only registers 1 * 100 = 100 virtual nodes equal to the number of machine instances to the registration center. -In this simple example, the number of addresses registered by Dubbo has dropped to 1/100 of the original, which greatly relieves the storage pressure on the registration center and subscribers. more importantly, -The address discovery capacity is completely decoupled from the business RPC definition, and the capacity evaluation of the entire cluster will become more transparent for operation and maintenance: as many machines are deployed as there are loads, it will not be like Dubbo2. -Because business RPC reconstruction will affect the stability of the entire cluster service discovery. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/concepts-and-architecture/service-invocation.md b/content/en/docs3-v2/java-sdk/concepts-and-architecture/service-invocation.md deleted file mode 100644 index c5b731acb549..000000000000 --- a/content/en/docs3-v2/java-sdk/concepts-and-architecture/service-invocation.md +++ /dev/null @@ -1,155 +0,0 @@ ---- -type: docs -title: "Service Call Extension Point" -linkTitle: "Service Call" -weight: 4 -description: "This article will introduce how to customize the core extension points on the call link in Dubbo 3 to meet your needs." ---- - -![dubbo-architecture](/imgs/v3/concepts/invoke-arch.jpg) - -As shown in the figure above, from the perspective of service invocation, Dubbo provides a wealth of extension points in the link, covering load balancing methods, interceptors before and after site selection, and server-side processing interceptors. -To put it simply, when Dubbo initiates a remote call, the main workflow can be divided into two parts: the consumer side and the server side. - -The workflow on the consumer side is as follows: -- Receive requests from users through Stub and encapsulate them in `Invocation` object -- Pass the `Invocation` object to `ClusterFilter` (**extension point**) for request preprocessing before site selection, such as conversion of request parameters, request logging, current limiting and other operations are carried out at this stage -- Pass the `Invocation` object to `Cluster` (**extension point**) for decision-making of cluster invocation logic, such as fast failure mode, safe failure mode and other decisions are made at this stage - - `Cluster` calls `Directory` to get all available server address information - - `Directory` calls `StateRouter` (**extension point**, recommended) and `Router` (**extension point**) to filter the address information of the server. This stage is mainly from the full amount of address information Filter out the targets that are allowed to be called in this call, such as marking-based traffic routing is carried out at this stage - - After `Cluster` obtains the available server information provided by `Directory`, it will call `LoadBalance` (**extension point**) to select a target for this call from multiple addresses, such as random call, polling Strategies such as calling and consistent hashing are carried out at this stage - - `Cluster` obtains the `Invoker` of the target, and then passes `Invocation` to the corresponding `Invoker`, and waits for the result to be returned, and executes the corresponding decision if an error occurs (such as fast failure, safety failure, etc.) -- After the above processing, the `Invoker` with the target address information is obtained, and `Filter` (**extension point**) will be called to process the request after the address selection (due to the `Filter` created on the consumer side The magnitude is the same as that of the server address. If there is no special need, it is recommended to use `ClusterFilter` for extended interception to improve performance) -- Finally `Invocation` will be sent to the server over the network - -The workflow of the server is as follows: -- After the server communication layer receives the request, it will pass the request to the protocol layer to construct `Invocation` -- Pass the `Invocation` object to `Filter` (**extension point**) to pre-process the server request, such as server authentication, logging, current limiting and other operations are performed at this stage -- Pass the `Invocation` object to the dynamic proxy to make the real server call - -## Filter (interceptor) - -The interceptor can implement the interception of the call process of the service provider and the service consumer. Most of Dubbo's own functions are implemented based on this extension point. Every time the remote method is executed, the interception will be executed. Please pay attention to the impact on performance. -Among them, on the consumer side, `ClusterFilter` is used for interception before location selection and `Filter` is used for interception after location selection. If there is no special need, use `ClusterFilter` for extended interception to improve performance. - -![filter-architecture](/imgs/v3/concepts/filter-arch.jpg) - -In Dubbo 3, the interface signatures of `Filter` and `ClusterFilter` are unified and abstracted into `BaseFilter`, and developers can implement the interfaces of `Filter` or `ClusterFilter` respectively to implement their own interceptors. -If you need to intercept the return status, you can directly implement the `BaseFilter.Listener` interface, and Dubbo will automatically recognize and call it. - -```java -package org.apache.dubbo.rpc; - -public interface BaseFilter { - - Result invoke(Invoker invoker, Invocation invocation) throws RpcException; - - interface Listener { - - void onResponse(Result appResponse, Invoker invoker, Invocation invocation); - - void onError(Throwable t, Invoker invoker, Invocation invocation); - } -} -``` - -```java -package org.apache.dubbo.rpc; - -@SPI(scope = ExtensionScope. MODULE) -public interface Filter extends BaseFilter { -} -``` - -```java -package org.apache.dubbo.rpc.cluster.filter; - -@SPI(scope = ExtensionScope. MODULE) -public interface ClusterFilter extends BaseFilter { -} -``` - -In particular, if `Filter` or `ClusterFilter` needs to be effective on the Consumer side, the `@Activate` annotation needs to be added, and the value of `group` needs to be `consumer`. - -```java -@Activate(group = CommonConstants. CONSUMER) -``` - -If `Filter` or `ClusterFilter` needs to be effective on the Provider side, the `@Activate` annotation needs to be added, and the value of `group` needs to be `provider`. - -```java -@Activate(group = CommonConstants. PROVIDER) -``` - -Please refer to [Reference](../../reference-manual/spi/description/filter/) for specific call interception extension methods - -## Router (routing address selection) - -Routing address selection provides the ability to select a batch of target providers that meet the conditions from multiple service providers to call. -Dubbo's routing mainly needs to implement 3 interfaces, which are the `route` method responsible for each call screening, the `notify` method responsible for caching after the address is pushed, and the `stop` method for destroying the route. -It is recommended to implement the `StateRouter` interface in Dubbo 3, which can provide high-performance routing address selection. - -```java -package org.apache.dubbo.rpc.cluster.router.state; - -public interface StateRouter { - - BitList> route(BitList> invokers, URL url, Invocation invocation, - boolean needToPrintMessage, Holder> nodeHolder) throws RpcException; - - void notify(BitList> invokers); - - void stop(); -} -``` - -```java -package org.apache.dubbo.rpc.cluster; - -public interface Router extends Comparable { - - @Deprecated - List> route(List> invokers, URL url, Invocation invocation) throws RpcException; - - RouterResult> route(List> invokers, URL url, Invocation invocation, - boolean needToPrintMessage) throws RpcException; - - void notify(List> invokers); - - void stop(); -} -``` - -Please refer to [Reference](../../reference-manual/spi/description/router/) for specific routing address selection expansion methods - -## Cluster (cluster rules) - -Cluster rules provide capabilities such as result aggregation and fault tolerance when there are multiple service providers. - -```java -package org.apache.dubbo.rpc.cluster.support; - -public abstract class AbstractClusterInvoker implements ClusterInvoker { - - protected abstract Result doInvoke(Invocation invocation, List> invokers, - LoadBalance loadbalance) throws RpcException; -} -``` - - -Please refer to [Reference](../../reference-manual/spi/description/cluster/) for specific cluster rule extension methods - -## LoadBalance - -Load balancing provides the ability to select **one** target provider to call from multiple service providers. - -```java -package org.apache.dubbo.rpc.cluster; - -public interface LoadBalance { - - Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException; -} -``` - -Please refer to [Reference](../../reference-manual/spi/description/load-balance/) for specific call interception extension methods \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/concepts-and-architecture/triple.md b/content/en/docs3-v2/java-sdk/concepts-and-architecture/triple.md deleted file mode 100644 index 76630a550226..000000000000 --- a/content/en/docs3-v2/java-sdk/concepts-and-architecture/triple.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -type: docs -title: "Triple Protocol" -linkTitle: "Triple Protocol" -weight: 6 ---- -### Protocol Description -Triple is an HTTP2-based open protocol proposed by Dubbo3, which aims to solve the interoperability problems brought about by Dubbo2's private protocol. Compared with the original Dubbo2 protocol, Triple has the following advantages: - -1. Interoperability between native and gRPC protocols. Open up the gRPC ecology and reduce the migration cost from gRPC to Dubbo. -2. Enhance multilingual ecology. Avoid the problem of difficulty in business selection and adaptation due to insufficient capabilities of Dubbo SDK in CPP/C#/RUST and other languages. -3. Gateway friendly. The gateway does not need to participate in serialization, which is convenient for users to upgrade from the traditional HTTP to generalized Dubbo call gateway to the open source or cloud vendor's Ingress solution. -4. Perfect asynchronous and streaming support. It brings performance improvement from the underlying protocol to the upper-layer business, and it is easy to build a full-link asynchronous streaming service that strictly guarantees the order of messages. - -**Currently, the Dubbo SDK for Java and Go fully supports the Triple protocol. ** In Alibaba, the Triple protocol is widely used for cross-environment, cross-language, and cross-ecology interoperability, and hundreds of thousands of containers have been used in production. - -### Support methods -Java SDK supports [IDL Generate Stub](/en/docs3-v2/java-sdk/quick-start/idl) -and [Java Interface](/en/docs3-v2/java-sdk/quick-start/idl), the IDL method is recommended for multi-language, ecological interoperability, and streaming requirements, and the smooth upgrade of existing services is recommended -Interface method. - -- How old Dubbo2 users can upgrade from existing protocol to Triple(TBD) -- New user or business reference [Dubbo3 Triple Quick Start](/en/docs3-v2/java-sdk/quick-start/idl/) -- In-depth understanding of the Triple protocol: [Dubbo3 Triple Protocol Design and Principles](https://github.com/apache/dubbo-awesome/blob/master/proposals/D0-triple.md) \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/1.md b/content/en/docs3-v2/java-sdk/faq/0/1.md deleted file mode 100644 index c6726dcefb9a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/1.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -type: docs -title: "0-1 - thread pool resource exhausted" -linkTitle: "0-1 - thread pool resources exhausted" -weight: 1 ---- -The server's thread resources are exhausted. -By default, the number of business threads on the Dubbo server is 200. If the number of concurrent requests exceeds 200, new requests will be rejected and this error will be thrown. - -### Possible Reason -1. The amount of concurrent requests from the Consumer is too large, causing the number of threads created on the Provider to exceed the limit. -2. It is possible that when the Provider side executes the business, the thread is blocked because the business calls the external application interface, which makes the thread pool unable to recycle the thread. - -### Troubleshooting and resolution steps -* Enable Dubbo's access log function to check whether there are a large number of calls to RPC services in a short period of time. -* Check the status of each thread in the thread pool through the `jps` and `jstack` instructions to see if there is any business calling the external application interface to cause blocking. -* If the amount of concurrent requests from the Consumer is too large, then adjust the `dubbo.provider.threads` parameter on the Provider side to increase the number of Dubbo thread pools. -* If the QPS of the Provider business is too large to be handled by the current number of servers, then increase the number of Provider-side servers so that more servers can share the pressure. - - -> The FAQ page of this error code refers to ["Dubbo Common Errors and Solutions"](https://github.com/StabilityMan/StabilityGuide/blob/master/docs/diagnosis/plugin/rpc/%E7%B3%BB%E7%BB%9F%E7%A8%B3%E5%AE%9A%E6%80%A7%E2%80%94%E2%80%94Dubbo%E5%B8%B8%E8%A7%81%E9%94%99%E8%AF%AF%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95.md). -Articles cited are compiled under license [CC-BY-4.0](http://creativecommons.org/licenses/by/4.0/). Thanks to the original author here. diff --git a/content/en/docs3-v2/java-sdk/faq/0/10.md b/content/en/docs3-v2/java-sdk/faq/0/10.md deleted file mode 100644 index 1528e2d0e197..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/10.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "0-10 - The current call is no longer supported" -linkTitle: "0-10 - The current call is no longer supported" -weight: 10 ---- - - -### Possible Reason - -The currently called method may have been deprecated or declared `@Deprecated`, which does not affect the execution result. - -### Troubleshooting and resolution steps - -Please use other alternative API methods. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/11.md b/content/en/docs3-v2/java-sdk/faq/0/11.md deleted file mode 100644 index 9a86aa156b93..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/11.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "0-11 - Service stop failed" -linkTitle: "0-11 - Service stop failure" -weight: 11 ---- - - -### Possible Reason - -The connection is not closed in time or the memory is insufficient, causing some exceptions when the service stops. - -### Troubleshooting and resolution steps - -Close the connection after the response content is completed. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/12.md b/content/en/docs3-v2/java-sdk/faq/0/12.md deleted file mode 100644 index ad09730a7d13..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/12.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "0-12 - Unknown exception" -linkTitle: "0-12 - Unknown exception" -weight: 12 ---- -Unknown exception, usually API usage or configuration exception - -### Possible Reason - -Such as: transcoding exception, unsupported encryption and decryption methods, etc. - -### Troubleshooting and resolution steps - -The business code line can be located according to the stack information. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/13.md b/content/en/docs3-v2/java-sdk/faq/0/13.md deleted file mode 100644 index 80f394792cd4..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/13.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "0-13 - An exception occurred in the metrics collector" -linkTitle: "0-13 - An exception occurred in the metrics collector" -weight: 13 ---- - - -### Possible Reason - -An error occurred during the push process of the indicator data, the pushed server could not be connected or some configuration errors were made. Prometheus is currently supported. - -### Troubleshooting and resolution steps - -Please refer to the configuration item reference manual[configuration item reference manual](/en/docs3-v2/java-sdk/reference-manual/config/properties/). - -

diff --git a/content/en/docs3-v2/java-sdk/faq/0/14.md b/content/en/docs3-v2/java-sdk/faq/0/14.md deleted file mode 100644 index b063b8080293..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/14.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "0-14 - Monitoring exception" -linkTitle: "0-14 - Monitoring exception" -weight: 14 ---- -It is used to count the number of RPC calls and the call time. The extension interface is MonitorFactory, and the corresponding implementation class is DubboMonitorFactroy. - - -### Possible Reason - -Users can implement the MonitorFactory extension interface of this layer to implement custom monitoring statistics strategies. -In the implementation class of the custom monitoring statistics strategy, an exception occurred during business runtime. - -### Troubleshooting and resolution steps - -Check the business class of `org.apache.dubbo.monitor.MonitorFactory` interface, there may be code logic errors in the implementation method. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/15.md b/content/en/docs3-v2/java-sdk/faq/0/15.md deleted file mode 100644 index bc8f568e7bf2..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/15.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "0-15 - An exception occurred while loading the extension class" -linkTitle: "0-15 - An exception occurred while loading the extension class" -weight: 15 ---- - - -### Possible Reason - -1. The `clazz` class does not implement the interface class of the current extension point. -2. The extension may be an interface or not exist. - -### Troubleshooting and resolution steps - -1. Check the extension class declaration, and there is no matching extension implementation class. -2. The extension implementation class needs to implement the extension point interface class and method. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/16.md b/content/en/docs3-v2/java-sdk/faq/0/16.md deleted file mode 100644 index 0e3bd1852ca9..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/16.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "0-16 - No actuators available" -linkTitle: "0-16 - No actuators available" -weight: 16 ---- - - -### Possible Reason - -The internal executor is not available and null is returned at this time. - -### Troubleshooting and resolution steps - -No need to intervene, dubbo will execute the `createExecutorIfAbsent` method internally to construct a new executor. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/17.md b/content/en/docs3-v2/java-sdk/faq/0/17.md deleted file mode 100644 index 6b27163b11ba..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/17.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "0-17 - Actuator encountered an unknown exception while shutting down" -linkTitle: "0-17 - An unknown exception occurred while the actuator was shutting down" -weight: 17 ---- - - -### Possible Reason - -A custom executor may be used, and an exception was generated when writing the destruction method. - -### Troubleshooting and resolution steps - -Check whether `org.apache.dubbo.common.threadpool.manager.ExecutorRepository` is custom implemented, and check the custom `shutdown` method. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/18.md b/content/en/docs3-v2/java-sdk/faq/0/18.md deleted file mode 100644 index 17cf79e130a0..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/18.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "0-18 - thread pool executor is misused" -linkTitle: "0-18 - thread pool executor is misused" -weight: 18 ---- - - -### Possible Reason - -The number of threads is customized, and an unknown exception occurs inside the system. - -### Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/19.md b/content/en/docs3-v2/java-sdk/faq/0/19.md deleted file mode 100644 index d73839ac951c..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/19.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "0-19 - An exception occurred while processing the task" -linkTitle: "0-19 - An exception occurred while processing the task" -weight: 19 ---- - - -### Possible Reason - -The custom business class processing logic is improper. - -### Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/2.md b/content/en/docs3-v2/java-sdk/faq/0/2.md deleted file mode 100644 index 90b7d0fc07df..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/2.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -type: docs -title: "0-2 - Illegal property value" -linkTitle: "0-2 - Illegal attribute value" -weight: 2 ---- - -### Possible Reason -This hint means that the value configured by the user does not match the data type required by the attribute itself. For example, the `dubbo.comsumer.threads` attribute can only accept numeric attributes, but the value entered by the user is mixed with letters. - -### Troubleshooting and resolution steps -According to the [Configuration Item Reference Manual](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/), find the wrong configuration item, check the type specified by the item, and check whether there is a type inconsistency. - -

diff --git a/content/en/docs3-v2/java-sdk/faq/0/20.md b/content/en/docs3-v2/java-sdk/faq/0/20.md deleted file mode 100644 index 78763d845f6b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/20.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "0-20 - An exception occurred while storing stack information" -linkTitle: "0-20 - An exception occurred while storing stack information" -weight: 20 ---- - - -### Possible Reason - -1. The JVM has set the parameter `-XX:+DisableAttachMechanism` -2. Set a stack dump path that does not exist in the system. If it does not exist, the system will try to create it. A `SecurityException` occurs during creation. - May not have permission. - -### Troubleshooting and resolution steps - -1. Check whether the JVM has set the above parameters. -2. Check whether the account currently starting the service has permission to create folders. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/21.md b/content/en/docs3-v2/java-sdk/faq/0/21.md deleted file mode 100644 index 993c8828b0ad..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/21.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "0-21 - Too many instances built" -linkTitle: "0-21 - Too many instances built" -weight: 21 ---- - -### Possible Reason - -Generally, it means that `org.apache.dubbo.common.timer.HashedWheelTimer` creates too many instances. - -### Troubleshooting and resolution steps - -It does not affect the construction of the instance, and there may be a risk of memory leaks. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/22.md b/content/en/docs3-v2/java-sdk/faq/0/22.md deleted file mode 100644 index f81c3a9b4f14..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/22.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -type: docs -title: "0-22 - I/O stream exception" -linkTitle: "0-22 - I/O stream exception" -weight: 22 ---- - - -### Possible Reason - -1. Read a local file that is no longer available. -2. Attempt to read/write the file but do not have permission. -3. An attempt was made to write a file but disk space is no longer available. - -### Troubleshooting and resolution steps - -1. Check if the local file exists. -2. Check the file permissions. -3. Check the disk space. - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/23.md b/content/en/docs3-v2/java-sdk/faq/0/23.md deleted file mode 100644 index 00a062d3a276..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/23.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -type: docs -title: "0-23 - Serialized data conversion exception" -linkTitle: "0-23 - Serialized data conversion exception" -weight: 23 ---- - - -### Possible Reason - -1. There is a circular reference in the data to be serialized, resulting in a stack overflow. -2. The version of the referenced jar package is low or there is a compatibility problem. - -### Troubleshooting and resolution steps - -1. If using FastJson, remove `SerializerFeature.DisableCircularReferenceDetect` -2. Check or upgrade the version to try. - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/24.md b/content/en/docs3-v2/java-sdk/faq/0/24.md deleted file mode 100644 index b8d2cd083dcb..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/24.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "0-24 - Override field value exception" -linkTitle: "0-24 - Override field value exception" -weight: 24 ---- - - -### Possible Reason - -1. The entity class does not have a setter/getter method. -2. There may be nested attributes. - -### Troubleshooting and resolution steps - -1. Check the entity class and set the setter/getter method. -2. According to the stack information, check whether nested annotations are used. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/25.md b/content/en/docs3-v2/java-sdk/faq/0/25.md deleted file mode 100644 index 41076cb7ffa4..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/25.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "0-25 - Error loading map" -linkTitle: "0-25 - Error loading map" -weight: 25 ---- - - -### Possible Reason - -Insufficient file access rights - -### Troubleshooting and resolution steps - -Check file permissions. -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/26.md b/content/en/docs3-v2/java-sdk/faq/0/26.md deleted file mode 100644 index c063fd1b4328..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/26.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "0-26 - Warning message when metadata is published to the service" -linkTitle: "0-26 - Warning message when metadata publishing service" -weight: 26 ---- - -### Possible Reason - -When the metadata stores the mapping relationship between the interface and the application, the reminder message displayed. - -### Troubleshooting and resolution steps - -Generally, it can be analyzed according to the stack information, or it can not be processed. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/27.md b/content/en/docs3-v2/java-sdk/faq/0/27.md deleted file mode 100644 index 35be3b1de477..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/27.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "0-27 - Thread pool isolation configuration exception" -linkTitle: "0-27 - Thread pool isolation configuration exception" -weight: 27 ---- - -### Possible Reason - -The thread pool isolation capability of the application is not enabled, but the isolated thread pool information is configured in `ServiceConfig`. - -### Troubleshooting and resolution steps - -Configure and enable the thread pool isolation capability of the application: `dubbo.application.executor-management-mode=isolation` - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/3.md b/content/en/docs3-v2/java-sdk/faq/0/3.md deleted file mode 100644 index d05d5244c0dc..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/3.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -type: docs -title: "0-3 - Unable to access cache path" -linkTitle: "0-3 - Unable to access cache path" -weight: 3 ---- - -Other modules reuse the file-based caching mechanism of the Common layer (currently the metadata module), and the file caching mechanism of the Common layer cannot access the directory it specifies. - -``` -2022-08-29 00:35:00,189 ERROR [org.apache.dubbo.common.cache.FileCacheStoreFactory:?] - [DUBBO] Cache store path can't be created: , dubbo version: , current host: 10.0.1.1 , error code: 0-3. This may be caused by inaccessible of cache path, go to https://dubbo.apache.org/faq/0/3 to find instructions. -java.nio.file.FileAlreadyExistsException: [Path] -at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:87) -at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103) -at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108) -at java.base/sun.nio.fs.WindowsFileSystemProvider.createDirectory(WindowsFileSystemProvider.java:521) -at java.base/java.nio.file.Files.createDirectory(Files.java:700) -at java.base/java.nio.file.Files.createAndCheckIsDirectory(Files.java:807) -at java.base/java.nio.file.Files.createDirectories(Files.java:753) -at org.apache.dubbo.common.cache.FileCacheStoreFactory.getInstance(FileCacheStoreFactory.java:90) -... -``` - -### Possible Reason -1. Multiple Dubbo processes (or other Java processes) use the same cache file. -2. Due to the file system permission problem of the directory where the cache file is located, reading and writing fails. - -### Troubleshooting and resolution steps -1. According to the actual exception shown below, find the directory that cannot be accessed, and determine its file access permission. -2. Determine whether other Dubbo instances are accessing this path. -3. Try to configure **Java System Property (Java system properties configured with -D)** `dubbo.meta.cache.filePath` and `dubbo.mapping.cache.filePath`, specify it as a current user can completely under the control directory. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/4.md b/content/en/docs3-v2/java-sdk/faq/0/4.md deleted file mode 100644 index 4fe68029dafd..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/4.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -type: docs -title: "0-4 - cache entry exceeded" -linkTitle: "0-4 - Cache entry limit exceeded" -weight: 4 ---- -Other modules reuse the common layer's file-based caching mechanism (currently the metadata module), and the common layer's file caching mechanism "sees" that the entry limit is exceeded. - - -### Possible Reason -User improperly configured **Java System Property** (Java system property configured with -D) `dubbo.mapping.cache.entrySize` or `dubbo.meta.cache.entrySize` - -**Defaults** - - - - - - - - - - - - -
dubbo.mapping.cache.entrySizedubbo.meta.cache.entrySize
10000100
- -### Troubleshooting and resolution steps -1. Try reconfiguring the above **Java System Property (Java System Property configured with -D)**. -2. If these **System Property** are not configured, please go to [GitHub Issue Tracker](https://github.com/apache/dubbo/issues) to issue an Issue. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/5.md b/content/en/docs3-v2/java-sdk/faq/0/5.md deleted file mode 100644 index a8e8688362b7..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/5.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -type: docs -title: "0-5 - Cache file size exceeded" -linkTitle: "0-5 - Cache file size exceeded" -weight: 5 ---- -Other modules reuse the file-based caching mechanism of the Common layer (currently the metadata module), and the file caching mechanism of the Common layer "discovers" that the file size exceeds the limit. - - -### Possible Reason -1. The user has unreasonably configured the Java System Property (the Java system property configured with -D) `dubbo.mapping.cache.maxFileSize` or `dubbo.meta.cache.maxFileSize` -2. The cache file is corrupted due to file system or disk errors. - - -> `dubbo.mapping.cache.maxFileSize` and `dubbo.meta.cache.maxFileSize` do not show default values, -The default value of the maximum file size found according to the logic of `org.apache.dubbo.common.cache.FileCacheStore.LimitedLengthBufferedWriter` is: `Long.MAX_VALUE` ( 263-1 ). - - - -### Troubleshooting and resolution steps -1. Try reconfiguring the above **Java System Property (Java System Property configured with -D)**. -2. Delete the cache folder and restart **Provider** and **Consumer** (the location of the cache folder is usually `~/.dubbo`. If `dubbo.meta.cache.filePath` and `dubbo.mapping` are configured .cache.filePath` is that path). -3. If these **System Property** are not configured, please go to [GitHub Issue Tracker](https://github.com/apache/dubbo/issues) to issue an Issue. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/6.md b/content/en/docs3-v2/java-sdk/faq/0/6.md deleted file mode 100644 index 2337e8abac85..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/6.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "0-6 - Thread interruption exception" -linkTitle: "0-6 - Thread interruption exception" -weight: 6 ---- - - -### Possible Reason - -When a running thread is in `wait, sleep, join`, it is explicitly called `interrupt()` - -### Troubleshooting and resolution steps - -After a normal running thread calls the `interrupt()` method, the interrupt status of the current thread will be set to true, but the execution of the thread will not be affected. -You can operate according to the actual situation or check whether the business code is used incorrectly. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/7.md b/content/en/docs3-v2/java-sdk/faq/0/7.md deleted file mode 100644 index f50eb0aaa64e..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/7.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "0-7 - Reflection class not found" -linkTitle: "0-7 - Reflection class not found" -weight: 7 ---- - - -### Possible Reason - -1. Generally, when `Class.forName(className)` executes this method, the current class of `className` cannot be found. -2. The business code shows that the current `className` class is excluded, so it is not found when loading. - -### Troubleshooting and resolution steps - -1. Check whether `className` exists in `Class.forName(className)`. -2. Check the business code to see whether some classes or packages have been excluded by using the configuration or scanning annotation `exclude`. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/8.md b/content/en/docs3-v2/java-sdk/faq/0/8.md deleted file mode 100644 index c7fb47dec03b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/8.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "0-8 - reflection failed" -linkTitle: "0-8 - reflection failed" -weight: 8 ---- - - -### Possible Reason - -When a method is called by reflection, the correct parameter type value is not set for the current method, that is, the parameter type does not match. - -### Troubleshooting and resolution steps - -Check for matching type values that are not set correctly. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/9.md b/content/en/docs3-v2/java-sdk/faq/0/9.md deleted file mode 100644 index 63719f25845e..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/9.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "0-9 - Failed to notify event" -linkTitle: "0-9 - Failed to notify event" -weight: 9 ---- - - -### Possible Reason - -A custom listener that generated a runtime exception during processing. - -### Troubleshooting and resolution steps - -Check the business class that implements the `org.apache.dubbo.rpc.ExporterListener` interface. There may be code logic errors in the implementation method. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/0/_index.md b/content/en/docs3-v2/java-sdk/faq/0/_index.md deleted file mode 100644 index 11534c905ef9..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/0/_index.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "0 - Common" -linkTitle: "0 - Common" -weight: 1 ---- - -This is mainly used to indicate errors that occur on components that are common to each layer. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/1.md b/content/en/docs3-v2/java-sdk/faq/1/1.md deleted file mode 100644 index f3451b2f5b8a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/1.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "1-1 - Address Illegal" -linkTitle: "1-1 - Illegal address" -weight: 1 ---- - -This log can be ignored, service version or grouping mismatch. Appears only in the zookeeper registry, this check has been removed in version 3.1.7. - -### possible reason -1. The `service.group` configured on the Provider side does not match the `reference.group` configured on the Consumer side (that is, the configuration of the service group). -2. The `service.version` configured on the Provider side does not match the `reference.version` configured on the Consumer side (that is, the configuration of the service version). - -### Troubleshooting and resolution steps -Can be ignored, this check has been removed in version 3.1.7. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/10.md b/content/en/docs3-v2/java-sdk/faq/1/10.md deleted file mode 100644 index bc9847016c44..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/10.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "1-10 - Failed to read and write registry service cache" -linkTitle: "1-10 - Failed to read and write registry service cache" -weight: 10 ---- - -### Possible Reason -1. Multiple Dubbo processes use the same cache file. -2. In the case of multiple registries, multiple registries are specified to use the same file storage. - -### Troubleshooting and resolution steps -This error often occurs with errors 1-9. Check whether multiple Dubbo processes use the same cache file or specify multiple registries to use the same cache file. - -> see also -[Reference Manual for Registry Configuration Items](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#registry) diff --git a/content/en/docs3-v2/java-sdk/faq/1/11.md b/content/en/docs3-v2/java-sdk/faq/1/11.md deleted file mode 100644 index fe474723ee64..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/11.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -type: docs -title: "1-11 - Registration service instance creation failed" -linkTitle: "1-11 - Registration service instance creation failed" -weight: 11 ---- - -### Possible Reason -It may be caused by Registry's SPI/IOC configuration error. -### Troubleshooting and resolution steps -This error is an internal error of Dubbo. If you encounter it, you can create an Issue on github and provide the error information and steps to reproduce it. We will help you solve the problem. - -> see also -[Dubbo Community](https://github.com/apache/dubbo) \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/12.md b/content/en/docs3-v2/java-sdk/faq/1/12.md deleted file mode 100644 index 793be1778810..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/12.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "1-12 - Instances of \"Registry Service\" have been destroyed" -linkTitle: "1-12 - Instances of \"Registration Service\" have been destroyed" -weight: 12 ---- - -### Possible Reason -During the graceful shutdown of Dubbo, unregister by calling `destroyAll` of `AbstractRegistryFactory`. - -During the process of destroying the `unexport` of `Registryprotocol`, the `getRegistry` of `AbstractRegistryFactory` will be used to try to obtain the registry that has been destroyed, which leads to the destruction of all instances of the "registry service". - -### Troubleshooting and resolution steps -> see also -[Configuration item reference manual](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/docs3-v2/java-sdk/faq/1/13.md b/content/en/docs3-v2/java-sdk/faq/1/13.md deleted file mode 100644 index c02038d1194b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/13.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -type: docs -title: "1-13 - Failed to execute task retry" -linkTitle: "1-13 - Failed to execute retry task" -weight: 13 ---- - -### Possible Reason -1. The registry is offline. - -### Troubleshooting and resolution steps - -1. Check if the registry is working properly. -2. Check whether the server where the registration center is located and its network are working normally. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/14.md b/content/en/docs3-v2/java-sdk/faq/1/14.md deleted file mode 100644 index 7bbb3b7af609..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/14.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "1-14 - Dynamic configuration recognition failed" -linkTitle: "1-14 - Dynamic configuration recognition failed" -weight: 14 ---- - -### Possible Reason -When using the service management function of dubbo admin for dynamic configuration, if the content or format of the configuration file is incorrect, the content of the dynamic configuration cannot be parsed, resulting in 1-14 errors. -### Troubleshooting and resolution steps -Please check whether the content or format of the dynamic configuration file is correct. - - -### See also -> [Configuration Reference Manual](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/docs3-v2/java-sdk/faq/1/15.md b/content/en/docs3-v2/java-sdk/faq/1/15.md deleted file mode 100644 index 80383433f527..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/15.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "1-15 - Failed to destroy service" -linkTitle: "1-15 - Failed to destroy service" -weight: 15 ---- - -### Possible Reason -Throwing an exception while destroying all invokers in the RegistryDirectory may trigger errors 1-15. - -### Troubleshooting and resolution steps -This error is an internal error of Dubbo. If you encounter it, you can create an Issue on github and provide the error information and steps to reproduce it. We will help you solve the problem. - - -> See also [Dubbo Community](https://github.com/apache/dubbo) \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/16.md b/content/en/docs3-v2/java-sdk/faq/1/16.md deleted file mode 100644 index 5d13cf289a20..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/16.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "1-16 - There are unsupported categories" -linkTitle: "1-16 - There are unsupported categories" -weight: 16 ---- - -## Possible Reason -When the registration center changes, the corresponding listener will be notified. If the category is illegal during notify, 1-16 errors will be generated. - - -## Troubleshooting and resolution steps -This error is an internal error of Dubbo. If you encounter it, you can create an Issue on github and provide the error information and steps to reproduce it. We will help you solve the problem. - - -## Dubbo Community -[github](https://github.com/apache/dubbo) - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/17.md b/content/en/docs3-v2/java-sdk/faq/1/17.md deleted file mode 100644 index e625f0cfc874..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/17.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "1-17 - Metadata Server Failure" -linkTitle: "1-17 - Metadata Server failure" -weight: 17 ---- - -## Possible Reason -It may be that there is a problem with the parameter configuration of metadata, especially `metadataServiceProtocol` and `metadataServicePort`. - -## Troubleshooting and resolution steps -1. Check whether it occurs at the same time as 1-18 error, if it occurs at the same time, first try to solve 1-18 -2. Check whether the `metadataServicePort` port number conflicts. If the ports configured by Provider and Consumer are in conflict at the same time, a 1-17 error will be generated. - -## see also -[Configuration item reference manual](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) - -

diff --git a/content/en/docs3-v2/java-sdk/faq/1/18.md b/content/en/docs3-v2/java-sdk/faq/1/18.md deleted file mode 100644 index b81501e92489..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/18.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "1-18 - metadata service port not provided" -linkTitle: "1-18 - metadata service port not provided" -weight: 18 ---- - -## Possible Reason -It may be that `metadataType` is in local mode, and `metadataServicePort` is configured incorrectly. - -## Troubleshooting and resolution steps -1. Check the `metadataType` attribute value on the Provider side. -2. Check whether the configuration of `metadataServicePort` on the Provider side is correct, and pay special attention to whether there is any conflict with other application ports. - -## see also -[Configuration item reference manual](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) - -

diff --git a/content/en/docs3-v2/java-sdk/faq/1/19.md b/content/en/docs3-v2/java-sdk/faq/1/19.md deleted file mode 100644 index bda050144f7a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/19.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "1-19 - K8S monitoring exception" -linkTitle: "1-19 - K8S monitoring exception" -weight: 19 ---- - -## Possible Reason - -1. K8S custom resource type, the configuration has been modified or removed by the container. -2. The K8S container is disconnected from the service. - -## Troubleshooting and resolution steps - -1. Check whether the custom resource type is correctly configured. For syntax, please refer to the official documentation of K8S. -2. Check whether the network is normal or the port mapping is correct. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/20.md b/content/en/docs3-v2/java-sdk/faq/1/20.md deleted file mode 100644 index 905bc383a821..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/20.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "1-20 - K8S Pod does not exist" -linkTitle: "1-20 - K8S Pod does not exist" -weight: 20 ---- - -## Possible Reason - -Pods may not exist or have been removed by containers. - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/21.md b/content/en/docs3-v2/java-sdk/faq/1/21.md deleted file mode 100644 index e3b142338001..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/21.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "1-21 - K8S No Service Available" -linkTitle: "1-21 - No service available for K8S" -weight: 21 ---- - -## Possible Reason - -1. The current service is not loaded correctly. -2. The configured Pod does not exist in the current instance service. - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/22.md b/content/en/docs3-v2/java-sdk/faq/1/22.md deleted file mode 100644 index 2ecc8e05d797..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/22.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "1-22 - K8S configuration address error" -linkTitle: "1-22 - K8S configuration address error" -weight: 22 ---- - -## Possible Reason - -The K8S url is configured incorrectly and cannot be accessed normally. - -## Troubleshooting and resolution steps - -Check the K8S url configuration information to ensure that the port mapping can also be accessed normally. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/23.md b/content/en/docs3-v2/java-sdk/faq/1/23.md deleted file mode 100644 index 45761e06e22b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/23.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "1-23 - Unable to download files via url" -linkTitle: "1-23 - Unable to download files via url" -weight: 23 ---- - -## Possible Reason - -1. The url mapping file does not exist. -2. The URL cannot be connected. - -## Troubleshooting and resolution steps - -1. Check whether the url mapping file exists. -2. Whether it can be accessed normally through a browser or other tools. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/24.md b/content/en/docs3-v2/java-sdk/faq/1/24.md deleted file mode 100644 index 419dd83aab34..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/24.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "1-24 - ZK startup exception" -linkTitle: "1-24 - ZK startup exception" -weight: 24 ---- - -## Possible Reason - -1. There is an incompatibility between the zk server version and the client version, and the connection cannot be made. -2. The zk service is not started normally or the firewall cannot provide external services. - -## Troubleshooting and resolution steps - -1. Confirm that the client version is consistent with the server version. -2. zk can start normally or provide normal external services. - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/25.md b/content/en/docs3-v2/java-sdk/faq/1/25.md deleted file mode 100644 index 7b6d10a22b96..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/25.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "1-25 - ZK destruction exception" -linkTitle: "1-25 - ZK destruction exception" -weight: 25 ---- - -## Possible Reason - -The current instance has been destroyed. -The network may be disconnected. - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/26.md b/content/en/docs3-v2/java-sdk/faq/1/26.md deleted file mode 100644 index 1e6a5c3255c2..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/26.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "1-26 - xDS certificate generation failed" -linkTitle: "1-26 - xDS certificate generation failed" -weight: 26 ---- - -## Possible Reason - -The system may not support algorithms `secp256r1` and `RSA` to generate certificates. - -## Troubleshooting and resolution steps - -Check if the operating system supports `secp256r1` and `RSA` algorithms. Need to download the dll file or lib for - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/27.md b/content/en/docs3-v2/java-sdk/faq/1/27.md deleted file mode 100644 index 6d5f3043126c..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/27.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "1-27 - K8S monitoring exception" -linkTitle: "1-27 - K8S monitoring exception" -weight: 27 ---- - -## Possible Reason - -The system may not support algorithms `secp256r1` and `RSA` to generate certificates. - -## Troubleshooting and resolution steps - -Check if the operating system supports `secp256r1` and `RSA` algorithms. Need to download the dll file or lib for - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/28.md b/content/en/docs3-v2/java-sdk/faq/1/28.md deleted file mode 100644 index 13886a47a7fd..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/28.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "1-28 - xDS Stub Error" -linkTitle: "1-28 - xDS stub error" -weight: 28 ---- - -## Possible Reason - -The current pod may be down. - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/29.md b/content/en/docs3-v2/java-sdk/faq/1/29.md deleted file mode 100644 index 6767105f41ed..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/29.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "1-29 - xDS failed to read file" -linkTitle: "1-29 - xDS failed to read file" -weight: 29 ---- - -## Possible Reason - -The network is disconnected or the target file is corrupted at this time. - -## Troubleshooting and resolution steps - -1. Whether the network is normal. -2. You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/3.md b/content/en/docs3-v2/java-sdk/faq/1/3.md deleted file mode 100644 index bd71505ee1ff..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/3.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -type: docs -title: "1-3 - URL destruction failed" -linkTitle: "1-3 - URL destruction failed" -weight: 3 ---- - -### Possible Reason -When `FrameworkExecutorRepository` is destroyed, calling `CacheableFailbackRegistry.evictURLCache` will cause the destruction to fail and generate an error code. - -### Troubleshooting and resolution steps - -> See also the [Configuration Items Reference Manual](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/docs3-v2/java-sdk/faq/1/30.md b/content/en/docs3-v2/java-sdk/faq/1/30.md deleted file mode 100644 index 3415e338856a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/30.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "1-30 - xDS request failed" -linkTitle: "1-30 - xDS request failed" -weight: 30 ---- - -## Possible Reason - -1. Versions may be inconsistent or incompatible. -2. Timeout while reading data. -3. There is a problem with parameter configuration. - -## Troubleshooting and resolution steps - -1. It can be adapted according to the introduction of the third-party official website. -2. Check whether the timeout setting is too short or there is a problem on the server. -3. Check whether the port mapping relationship is correct. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/31.md b/content/en/docs3-v2/java-sdk/faq/1/31.md deleted file mode 100644 index 6ad2b44b6cbd..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/31.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "1-31 - xDS Response Failed" -linkTitle: "1-31 - xDS Response Failed" -weight: 31 ---- - -## Possible Reason - -1. The client service has disconnected from the server. -2. The server is unavailable or offline. - -## Troubleshooting and resolution steps - -1. Check whether the server is offline or the network of the client is disconnected. -2. Check whether the service on the server side is normal, and the interface request can be made through the network. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/32.md b/content/en/docs3-v2/java-sdk/faq/1/32.md deleted file mode 100644 index 36b05c3d28fa..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/32.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "1-32 - xDS Channel initialization failed" -linkTitle: "1-32 - xDS Channel initialization failed" -weight: 32 ---- - -## Possible Reason - -1. Versions may be inconsistent or incompatible. -2. Timeout while reading data. -3. There is a problem with parameter configuration. - -## Troubleshooting and resolution steps - -1. It can be adapted according to the introduction of the third-party official website. -2. Check whether the timeout setting is too short or there is a problem on the server. -3. Check whether the port mapping relationship is correct. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/33.md b/content/en/docs3-v2/java-sdk/faq/1/33.md deleted file mode 100644 index b1a85d83a414..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/33.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "1-33 - xDS service discovery initialization failed" -linkTitle: "1-33 - xDS service discovery initialization failed" -weight: 33 ---- - -## Possible Reason - -1. The address configuration of the registration center in xDS mode is wrong. -2. The firewall and third-party protection software make it impossible to provide external connections. - -## Troubleshooting and resolution steps - -1. Check whether the xDS configuration is correct and whether the Istio status is normal. -2. Check the firewall configuration or use the `ping` command of cmd for basic detection. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/34.md b/content/en/docs3-v2/java-sdk/faq/1/34.md deleted file mode 100644 index 12ec5faa6346..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/34.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "1-34 - Error parsing xDS" -linkTitle: "1-34 - Error parsing xDS" -weight: 34 ---- - -## Possible Reason - -There is an error in the xDS protocol content. - -## Troubleshooting and resolution steps - -The cause can be located according to the Endpoints List printed by the stack. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/35.md b/content/en/docs3-v2/java-sdk/faq/1/35.md deleted file mode 100644 index dcedb44b922b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/35.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "1-35 - ZK Anomaly" -linkTitle: "1-35 - ZK Anomaly" -weight: 35 ---- - -## Possible Reason - -1. ZK cannot connect or the connection times out. -2. The ZNode already exists at the time of creation. - -## Troubleshooting and resolution steps - -1. Check whether ZK configuration IP and port number are correct. Connection testing can be done using the third-party tool ZooInspector -2. According to the stack reminder ZNode information, judge whether the current node can be cleaned up. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/36.md b/content/en/docs3-v2/java-sdk/faq/1/36.md deleted file mode 100644 index 02caecc0973f..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/36.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "1-36 - Unknown exception" -linkTitle: "1-36 - Unknown exception" -weight: 36 ---- - -## Possible Reason - - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/37.md b/content/en/docs3-v2/java-sdk/faq/1/37.md deleted file mode 100644 index 5dc49cec8ae2..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/37.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "1-37 - Nacos Anomaly" -linkTitle: "1-37 - Nacos Anomaly" -weight: 37 ---- - -## Possible Reason - -Nacos configuration information is not configured correctly. - -## Troubleshooting and resolution steps - -Check whether the ip and port number configured for Nacos are correct. If the security authentication of Nacos is enabled, check whether the user name and password are configured correctly. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/38.md b/content/en/docs3-v2/java-sdk/faq/1/38.md deleted file mode 100644 index 1ba637742cd8..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/38.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "1-38 - Socket connection exception" -linkTitle: "1-38 - Socket connection exception" -weight: 38 ---- - -## Possible Reason - -1. Connection refused. -2. The connection has been closed. - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/39.md b/content/en/docs3-v2/java-sdk/faq/1/39.md deleted file mode 100644 index 21e82d4e1bff..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/39.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "1-39 - Failed to fetch metadata" -linkTitle: "1-39 - Failed to get metadata" -weight: 39 ---- - -## Possible Reason - -1. Metadata Center has been disconnected from App Service. -2. The data in the metadata center may have been modified. - -## Troubleshooting and resolution steps - -1. Check whether the network communication is normal, you can use some simple cmd commands to detect, such as `ping` and so on. -2. Connect and view content through third-party tools. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/4.md b/content/en/docs3-v2/java-sdk/faq/1/4.md deleted file mode 100644 index 2288b3210e38..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/4.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "1-4 - Empty address" -linkTitle: "1-4 - Empty address" -weight: 4 ---- - -### Possible Reason -1. Errors 1-4 in registry.integration.RegistryDirectory are caused by the null invokerUrls in the refreshInvoker process, which can be ignored. -2. The 1-4 errors in registry.support.CacheableFailbackRegistry may be caused by the mismatch between consumer and provider, and the "null protection" is turned off. - -### Troubleshooting and resolution steps -1. Make sure that the service group configurations on the Provider and Consumer side correspond. -2. Make sure that the service version configurations on the Provider and Consumer side correspond. -3. Check whether `enable-empty-protection` of the registration center is true (the default is true). - -> see also -[Configuration item reference manual](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/docs3-v2/java-sdk/faq/1/40.md b/content/en/docs3-v2/java-sdk/faq/1/40.md deleted file mode 100644 index b431813f5c41..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/40.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "1-40 - Route waiting too long" -linkTitle: "1-40 - Route waiting too long" -weight: 40 ---- - -## Possible Reason - -The route calculation time is too long, so the address notification cannot wait for an appropriate time to update the address. - -## Troubleshooting and resolution steps - -1. Check the application QPS, if the QPS is very high, this is the expected log -2. Check the implementation of custom routes, and check whether there are abnormal implementations, such as deadlocks, infinite loops, etc. -3. You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/41.md b/content/en/docs3-v2/java-sdk/faq/1/41.md deleted file mode 100644 index 135a4bc974df..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/41.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "1-41 - Istio exceptions" -linkTitle: "1-41 - Istio exception" -weight: 41 ---- - -## Possible Reason - -Failed to fetch configuration file for istio - -## Troubleshooting and resolution steps - -1. Check whether the application is deployed in the Kubernetes Pod environment, currently does not support VM deployment - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/42.md b/content/en/docs3-v2/java-sdk/faq/1/42.md deleted file mode 100644 index b9fe434372e5..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/42.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -description: 1-42 - Nacos has a low version service -linkTitle: 1-42 - Nacos has a low version service -title: 1-42 - Nacos has a low version service -type: docs -weight: 42 ---- - -### possible reason - -The Nacos registry has subscribed to an old version of the service, usually because the Dubbo version on the server side is lower than 2.7.3. - -### Troubleshooting and resolution steps - -Upgrade the server to the latest stable version. diff --git a/content/en/docs3-v2/java-sdk/faq/1/5.md b/content/en/docs3-v2/java-sdk/faq/1/5.md deleted file mode 100644 index b66b0fbaf830..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/5.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -type: docs -title: "1-5 - URL received without any parameters" -linkTitle: "1-5 - URL received without any parameters" -weight: 5 ---- - -### Possible Reason -When calling `CacheableFailbackRegistry.toUrlsWithoutEmpty`, if there is a provider in `Collectionproviders` that does not have any parameters, the URL without any parameters will be received. -### Troubleshooting and resolution steps -This error is an internal error of Dubbo. If you encounter it, you can create an Issue on github and provide the error information and steps to reproduce it. We will help you solve the problem. - -> see also -[Dubbo Community](https://github.com/apache/dubbo) \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/6.md b/content/en/docs3-v2/java-sdk/faq/1/6.md deleted file mode 100644 index 7502ac08062b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/6.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "1-6 - Error clearing URL cache" -linkTitle: "1-6 - Error clearing URL cache" -weight: 6 ---- - -### Possible Reason -An error while clearing the url cache in `CacheableFailbackRegistry.RemovalTask` will trigger an error in clearing the URL cache. - -### Troubleshooting and resolution steps -This error is an internal error of Dubbo, if you encounter it, you can create **issues** on github and provide the error information and steps to reproduce, we will help you solve the problem. - -> see also -[Dubbo Community](https://github.com/apache/dubbo) \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/1/7.md b/content/en/docs3-v2/java-sdk/faq/1/7.md deleted file mode 100644 index 90a235be2f1b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/7.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "1-7 - Notification registration event failed" -linkTitle: "1-7 - Failed to read and write registry service cache" -weight: 7 ---- - -### Possible Reason - -1. When applied to related platforms based on the xDS protocol, when metadata is updated, consumers need to be notified. If a consumer is offline, the notification will fail and the listener of the corresponding consumer will be removed. - -### Troubleshooting and resolution steps - -> see also -[Registration Center - Configuration Item Reference Manual](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#registry) diff --git a/content/en/docs3-v2/java-sdk/faq/1/8.md b/content/en/docs3-v2/java-sdk/faq/1/8.md deleted file mode 100644 index 98b866944ff3..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/8.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "1-8 - Unregister (unsubscribe) address failed on destroy" -linkTitle: "1-8 - Unregister (unsubscribe) address failed on destroy" -weight: 8 ---- - -### Possible Reason -1. An error may occur when the consumer logs out or unsubscribes due to the downtime of the registration center. -2. It may be that the corresponding provider has not been released successfully. - -### Troubleshooting and resolution steps -1. Check whether the registration center is running normally. -2. Check whether the provider is released successfully. -3. Check whether the provider’s registry-related parameters such as `registry` `config-center` `metadata-report` are configured correctly. - -> see also -[Configuration item reference manual](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/) diff --git a/content/en/docs3-v2/java-sdk/faq/1/9.md b/content/en/docs3-v2/java-sdk/faq/1/9.md deleted file mode 100644 index 71abaff2e66a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/9.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -type: docs -title: "1-9 - Failed to read and write registry service cache" -linkTitle: "1-9 - Failed to read and write registry service cache" -weight: 9 ---- - -### Possible Reason -1. Multiple Dubbo processes (or other Java processes) use the same cache file. -2. Due to the file system permission problem of the directory where the cache file is located, reading and writing fails. -3. The value of `dubbo.registry.file` is entered incorrectly. -4. Accidentally specify two registries to use the same file store. - -> **Hint:** -If `dubbo.registry.file` is not specified, the registry service cache path defaults to the `~/.dubbo` directory -(where `~` is the user's HOME directory) - -### Troubleshooting and resolution steps -1. Check the value of `dubbo.registry.file` for typos. -2. Check whether other processes use the same cache file. -3. If `dubbo.registry.file` is specified, check its permissions in the file system. -4. Check whether the situation of "two registration centers use the same file storage" occurs, and adjust if it occurs. - -> see also -[Reference Manual for Registry Configuration Items](/zh-cn/overview/mannual/java-sdk/reference-manual/config/properties/#registry) diff --git a/content/en/docs3-v2/java-sdk/faq/1/_index.md b/content/en/docs3-v2/java-sdk/faq/1/_index.md deleted file mode 100755 index 20479b62549a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/1/_index.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "1 - Registry" -linkTitle: "1 - Registry" -weight: 1 ---- - -This is mainly used to indicate errors that occurred on the registry layer. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/1.md b/content/en/docs3-v2/java-sdk/faq/2/1.md deleted file mode 100644 index c85708371220..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/1.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "2-1 - Routing execution failed" -linkTitle: "2-1 - Execution of routing address selection failed" -weight: 1 ---- - -## Routing address execution failed \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/10.md b/content/en/docs3-v2/java-sdk/faq/2/10.md deleted file mode 100644 index 98f0a4687d86..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/10.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -type: docs -title: "2-10 - Failed to call service provider" -linkTitle: "2-10 - Failed to call service provider" -weight: 10 ---- - -## Possible Reason - -* Dubbo failed to call the service provider and started retrying. -* Dubbo retries to call the service provider and continues to fail. -* Dubbo retries calling the service provider reaches the upper limit. - -## Troubleshooting and resolution steps -1. Check network resources such as time-consuming network connections between consumers and providers. -2. Check whether the corresponding port of the provider can respond normally through telnet or other means. -3. Check that the provider program is functioning properly. - - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/11.md b/content/en/docs3-v2/java-sdk/faq/2/11.md deleted file mode 100644 index 6e07657aff9a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/11.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "2-11 - Label Routing Rules Illegal" -linkTitle: "2-11 - Label routing rules are invalid" -weight: 2 ---- - -## Possible Reason - -* The label routing rule configured by the user is invalid. -* The label routing address configured by the user is invalid. - -## Troubleshooting and resolution steps -1. Refer to the community label routing configuration specification, and check the label routing configuration. - - - -

diff --git a/content/en/docs3-v2/java-sdk/faq/2/12.md b/content/en/docs3-v2/java-sdk/faq/2/12.md deleted file mode 100644 index 231c25179c41..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/12.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "2-12 - Label route acquisition provider application name is empty" -linkTitle: "2-12 - Label route acquisition provider application name is empty" -weight: 2 ---- - -## Possible Reason - -* The label route obtains the provider application name from the push provider address list and is empty. - -## Troubleshooting and resolution steps -1. This exception is an exception of the Dubbo framework itself. Please file an issue in the community and provide the environment site information and reproduction steps. - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/13.md b/content/en/docs3-v2/java-sdk/faq/2/13.md deleted file mode 100644 index fe5b0f9e7e78..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/13.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "2-13 - Failed to receive and load mesh routing rules" -linkTitle: "2-13 - Failed to receive and load mesh routing rules" -weight: 2 ---- - -## Possible Reason - -* The rules of the mesh routing configuration are illegal, and the loading is abnormal. - -## Troubleshooting and resolution steps -1. Check the mesh routing rule configuration. ["Mesh Example"](/zh-cn/overview/tasks/mesh/). - - - -

diff --git a/content/en/docs3-v2/java-sdk/faq/2/14.md b/content/en/docs3-v2/java-sdk/faq/2/14.md deleted file mode 100644 index e6a9e1e20c90..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/14.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "2-15 - Script route execution failed" -linkTitle: "2-15 - Script route execution failed" -weight: 2 ---- - -## Possible Reason - -* Script routing rules are illegal, resulting in rule parsing failure. -* Dubbo framework failed to execute the script. - -## Troubleshooting and resolution steps -1. Check that the script is written according to the specification. - - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/15.md b/content/en/docs3-v2/java-sdk/faq/2/15.md deleted file mode 100644 index 81bcba0058ff..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/15.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "2-15 - Routing rule parsing failed" -linkTitle: "2-15 - Routing rule parsing failed" -weight: 2 ---- - -## Possible Reason - -* The routing rule configured by the user is invalid. - -## Troubleshooting and resolution steps -1. Check the configured routing rules. - - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/16.md b/content/en/docs3-v2/java-sdk/faq/2/16.md deleted file mode 100644 index c0913a39fb52..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/16.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "2-16 - Request retries failed multiple times" -linkTitle: "2-16 - Request retries failed multiple times" -weight: 2 ---- - -## Possible Reason - -* The provider is abnormal, causing the consumer to retry and fail many times. - -## Troubleshooting and resolution steps -1. Check the health status of the provider. - - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/17.md b/content/en/docs3-v2/java-sdk/faq/2/17.md deleted file mode 100644 index f5ac29a61998..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/17.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "2-17 - mock request failed" -linkTitle: "2-17 - Mock request failed" -weight: 2 ---- - -## Possible Reason - -* Configured mandatory mock, suggestive log. -* Executing the mock request is abnormal. - -## Troubleshooting and resolution steps -1. Check whether mandatory mock is configured. -2. Check whether the mock response is normal. - - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/18.md b/content/en/docs3-v2/java-sdk/faq/2/18.md deleted file mode 100644 index 32cec0d8cb9a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/18.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "2-18 - Mesh routing rules are not monitored" -linkTitle: "2-18 - Mesh routing rules are not monitored" -weight: 2 ---- - -## Possible Reason - -* Mesh delivered routing rules, but the rules were not monitored. - -## Troubleshooting and resolution steps -1. Check whether the mesh routing rule configuration complies with the specification. - - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/19.md b/content/en/docs3-v2/java-sdk/faq/2/19.md deleted file mode 100644 index 8d44cc4f5ff2..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/19.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "2-19 - Asynchronous request failed" -linkTitle: "2-19 - Asynchronous request failed" -weight: 2 ---- - -## Possible Reason - -* The provider is abnormal, causing the asynchronous request of the consumer to fail. -* The network is abnormal, causing the asynchronous request of the consumer to fail. - -## Troubleshooting and resolution steps -1. Check the health status of the provider. -1. Check the network status. - - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/2.md b/content/en/docs3-v2/java-sdk/faq/2/2.md deleted file mode 100644 index b07703688ae6..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/2.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -type: docs -title: "2-2 - No Provider available (address not found)" -linkTitle: "2-2 - No Provider available (address not found)" -weight: 2 ---- - -## Possible Reason -There may be several situations at this time: - -* The Provider service is not started, or the registration center (such as ZooKeeper, Nacos, Consul) is down. -* There is an error in the service configuration of Dubbo, you must ensure that the service name, group (default is Dubbo), and version are all correct. -* The accessed environment is wrong: Usually we have multiple environments such as development environment, test environment, and online production environment. Sometimes the published service goes to the test environment, but the development environment goes away when the access call is made. - -## Troubleshooting and resolution steps -1. Visit the Ops system of the registration center to check whether there is a provider list for the corresponding service; at the same time, check the log of the server where the caller application is located (generally, the client of each registered service will have corresponding log records) to check whether there is address information push/pull records. -2. If not, it means that the publisher failed to publish the service. Check whether the publisher's application starts successfully. -3. If there is a service, check the registration center that the caller application is connected to, and confirm that it matches the expected environment. -4. If there is no problem with the above, check whether the routing filtering rules are configured. - -## Acknowledgments -The FAQ page of this error code refers to ["Dubbo Common Errors and Solutions"](https://github.com/StabilityMan/StabilityGuide/blob/master/docs/diagnosis/plugin/rpc/%E7%B3%BB%E7%BB%9F%E7%A8%B3%E5%AE%9A%E6%80%A7%E2%80%94%E2%80%94Dubbo%E5%B8%B8%E8%A7%81%E9%94%99%E8%AF%AF%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95.md). - -Articles cited are compiled under license [CC-BY-4.0](http://creativecommons.org/licenses/by/4.0/). Thanks to the original author here. - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/20.md b/content/en/docs3-v2/java-sdk/faq/2/20.md deleted file mode 100644 index 4d14bcf14cc7..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/20.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "2-20 - Failed to get grouped results merged" -linkTitle: "2-20 - Failed to get grouped results combined" -weight: 20 ---- - -## Possible Reason - -1. Failed to get grouped results merged. - -## Troubleshooting and resolution steps - -1. When the result is returned, there may be runtime exceptions in business logic, which can be traced according to the number of lines of code specified in the console. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/3.md b/content/en/docs3-v2/java-sdk/faq/2/3.md deleted file mode 100644 index f7c35f4c6702..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/3.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "2-3 - Routing shutdown failed" -linkTitle: "2-3 - Routing shutdown failed" -weight: 3 ---- - -## Possible Reason - -* User-defined routes are not written according to the specification. - -## Troubleshooting and resolution steps -1. Refer to the community SPI extension manual to check user-defined routes, ["SPI Extension User Manual"](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/ ). - - - -

diff --git a/content/en/docs3-v2/java-sdk/faq/2/4.md b/content/en/docs3-v2/java-sdk/faq/2/4.md deleted file mode 100644 index dc71a96e6bbd..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/4.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "2-4 - Merger interface failed to load" -linkTitle: "2-4 - Merger interface failed to load" -weight: 4 ---- - -## Possible Reason - -* Dubbo provides an SPI extension Merger interface that aggregates the responses of all downstream providers. When Dubbo loads the user-defined extension Merger interface, the loading configuration fails. - -## Troubleshooting and resolution steps -1. Refer to the community SPI extension manual to check the implementation of the user-defined extension Merger interface, ["SPI Extension User Manual"](/zh-cn/overview/mannual/java-sdk/reference-manual /spi/). - - - -

diff --git a/content/en/docs3-v2/java-sdk/faq/2/5.md b/content/en/docs3-v2/java-sdk/faq/2/5.md deleted file mode 100644 index aafe6aae64f0..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/5.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "2-5 - Filter Provider Failed" -linkTitle: "2-5 - Screening providers failed" -weight: 5 ---- - -## Possible Reason - -* Dubbo will finally select a provider from the provider list to initiate a call during load balancing. During the selection process, the provider list changes, and read-write conflicts occur, resulting in screening exceptions. -* When the Dubbo retry mechanism fails to call the provider, it will re-screen another provider to initiate the call, and an exception occurs during the re-screening process. - -## Troubleshooting and resolution steps -1. Check the registry provider list and the availability of the corresponding provider. -2. Raise an issue in the community, provide environmental site information and reproduction steps. - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/6.md b/content/en/docs3-v2/java-sdk/faq/2/6.md deleted file mode 100644 index 05abdab49bf1..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/6.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "2-6 - Conditional routing filter provider list is empty" -linkTitle: "2-6 - Conditional routing filter provider list is empty" -weight: 6 ---- - -## Possible Reason - -* Conditional routing provider filter condition is empty. -* Conditional routing filter provider list remains empty under forced downgrade. - -## Troubleshooting and resolution steps -1. Refer to the community request routing example to adjust the conditional routing configuration. - - - -

diff --git a/content/en/docs3-v2/java-sdk/faq/2/7.md b/content/en/docs3-v2/java-sdk/faq/2/7.md deleted file mode 100644 index 2e14d4615df4..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/7.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "2-7 - Conditional routing execution exception" -linkTitle: "2-7 - Conditional routing execution exception" -weight: 7 ---- - -## Possible Reason - -* Conditional routing rules are not configured according to the specification, resulting in exceptions when executing conditional routing filtering. - -## Troubleshooting and resolution steps -1. Refer to the community request routing example to adjust the conditional routing configuration. - - - -

diff --git a/content/en/docs3-v2/java-sdk/faq/2/8.md b/content/en/docs3-v2/java-sdk/faq/2/8.md deleted file mode 100644 index 3073d1bd698f..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/8.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "2-8 - The provider returned an abnormal response" -linkTitle: "2-8 - The provider returned an abnormal response" -weight: 8 ---- - -## Possible Reason - -* The provider's own processing result throws an exception. - -## Troubleshooting and resolution steps -1. Check whether the provider program is normal. - - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/9.md b/content/en/docs3-v2/java-sdk/faq/2/9.md deleted file mode 100644 index 386263f8ac39..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/9.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "2-9 - Increase timeout check task failed" -linkTitle: "2-9 - Increase timeout check task failed" -weight: 9 ---- - -## Possible Reason - -* The Dubbo framework will add a timeout check task to the request call, and the added timeout check task fails. - -## Troubleshooting and resolution steps -1. This exception is an exception of the Dubbo framework itself. Please file an issue in the community and provide the environment site information and reproduction steps. - - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/2/_index.md b/content/en/docs3-v2/java-sdk/faq/2/_index.md deleted file mode 100644 index bcb55b62f53e..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/2/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "2 - Routing" -linkTitle: "2 - Routing" -weight: 2 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/3/1.md b/content/en/docs3-v2/java-sdk/faq/3/1.md deleted file mode 100644 index 33dc70d9d8a9..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/3/1.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -type: docs -title: "3-1 - Failed to convert address to Invoker" -linkTitle: "3-1 - Failed to convert address to Invoker" -weight: 1 ---- - -## Possible Reason - -1. The protocol configured on the client side does not match the protocol configured on the server side. (For example, the protocol configured by the client is the Dubbo protocol, but the server can only provide services of the Rest protocol.) - - -2. The registration center (or configuration center) is unreliable and pushes illegal data. - - - -## Troubleshooting and resolution steps - -1. Check the protocol configuration of both the provider and the consumer. -2. Update the version of the registry. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/3/2.md b/content/en/docs3-v2/java-sdk/faq/3/2.md deleted file mode 100644 index 10616aef864c..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/3/2.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "3-2 - Publish or push service failed" -linkTitle: "3-2 - Publish or push service failed" -weight: 2 ---- - -## Possible Reason - -1. The registration center cannot be connected. -2. The registration center cannot provide external services. - -## Troubleshooting and resolution steps - -1. Whether the service and registration center network is normal. -2. Whether the registration center starts normally and can be connected through third-party tools. -3. Whether there is a version compatibility problem between the version referenced by the service and the version of the registration center. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/3/3.md b/content/en/docs3-v2/java-sdk/faq/3/3.md deleted file mode 100644 index f93b365081bd..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/3/3.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -type: docs -title: "3-3 - Failed to generate bytecode via Javassist" -linkTitle: "3-3 - Failed to generate bytecode through Javassist" -weight: 3 ---- - -## Reminder -The meaning of this error code has been adjusted. If you are looking for information of this error code in Dubbo versions prior than (or equal) 3.1.4 or 3.2.0-beta.3, head to [3-8](/zh-cn/overview/mannual/java-sdk/faq/3/8/). - -(This error code is currently absent.) - -

diff --git a/content/en/docs3-v2/java-sdk/faq/3/4.md b/content/en/docs3-v2/java-sdk/faq/3/4.md deleted file mode 100644 index 3dd10b301989..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/3/4.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "3-4 - Client sending request timed out" -linkTitle: "3-4 - Client sending request timed out" -weight: 4 ---- - -## Possible Reason - -1. The number of client connections is too high, the response is slow, and the request cannot be sent to the server in time. -2. Some reasons for the network. - -## Troubleshooting and resolution steps - -1. Whether the network is normal. -2. You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/3/5.md b/content/en/docs3-v2/java-sdk/faq/3/5.md deleted file mode 100644 index b45a7b877e79..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/3/5.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "3-5 - An exception occurred in the asynchronous response" -linkTitle: "3-5 - An exception occurred in the asynchronous response" -weight: 5 ---- - -## Possible Reason - -1. The business logic does have a runtime exception. -2. The connection is refused due to network reasons. - -## Troubleshooting and resolution steps - -1. For the business code, please trace back and check according to the prompt line of the stack. -2. Check whether the network of the service provider is normal. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/3/6.md b/content/en/docs3-v2/java-sdk/faq/3/6.md deleted file mode 100644 index a0d3fa72db41..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/3/6.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "3-6 - An exception occurred in the proxy execution service" -linkTitle: "3-6 - An exception occurred in the proxy execution service" -weight: 6 ---- - -## Possible Reason - -1. The current service parameters have been displayed as `deprecated`. -2. This reminder may appear for generic declaration classes. - -## Troubleshooting and resolution steps - -1. Confirm whether there is a display parameter `deprecated=true` in the URL -2. If this error occurs in the generic declaration class, it will try to create a proxy without the actual interface class. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/3/7.md b/content/en/docs3-v2/java-sdk/faq/3/7.md deleted file mode 100644 index 259fc5a5be8d..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/3/7.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -type: docs -title: "3-7 - Server response timed out" -linkTitle: "3-7 - Server response timed out" -weight: 7 ---- -The server did not get a response within the time set by the client. - -## Possible Reason - -1. The business processing logic of the server is complex and cannot respond within the effective time. -2. The connection between the server and the client is disconnected, and the network packet is lost. -3. The server load is too high. - -## Troubleshooting and resolution steps - -1. Check whether there is indeed a performance bottleneck in the business processing capability of the server. -2. Whether the network is normal. -3. You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/3/8.md b/content/en/docs3-v2/java-sdk/faq/3/8.md deleted file mode 100644 index 48db2c4d75df..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/3/8.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -type: docs -title: "3-8 - Proxy Failure" -linkTitle: "3-8 - Agent failed" -weight: 8 ---- - -Failed to generate dynamic proxy. - -## Possible Reason - -1. There is dynamic class loading -2. Class format exception - -## Troubleshooting and resolution steps - -1. If `Fallback to use JDK proxy success` is displayed in the log, - It means that Dubbo has successfully created a dynamic proxy after automatically falling back to the JDK proxy. If the program is running normally, you can ignore it -2. If the log shows `Fallback to use JDK proxy is also failed`, - Please check whether the corresponding class loading is normal according to the exception stack information, you can use tools such as arthas to assist in troubleshooting - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/3/_index.md b/content/en/docs3-v2/java-sdk/faq/3/_index.md deleted file mode 100644 index 6f7d0bd424de..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/3/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "3 - Proxy" -linkTitle: "3 - Proxy" -weight: 3 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/1.md b/content/en/docs3-v2/java-sdk/faq/4/1.md deleted file mode 100644 index b154bc16c3f6..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/1.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -type: docs -title: "4-1 - Unsupported protocol" -linkTitle: "4-1 - Unsupported protocol" -weight: 1 ---- - -## Possible Reason -This situation may occur in the scenario of custom Protocol. Dubbo's SPI mechanism cannot find the Protocol specified in the URL. - - -## Troubleshooting and resolution steps -1. Make sure that the Consumer has dependencies on the Protocol used by the server. -2. Make sure that the name of the SPI configuration file of the Protocol's dependent package is correct. - -## see also -[Dubbo SPI Overview](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/overview/) - -[Protocol Extension Description](/zh-cn/overview/mannual/java-sdk/reference-manual/spi/description/protocol/) - -

diff --git a/content/en/docs3-v2/java-sdk/faq/4/10.md b/content/en/docs3-v2/java-sdk/faq/4/10.md deleted file mode 100644 index fe939e4523f6..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/10.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "4-10 - Triple serialization result failed" -linkTitle: "4-10 - Triple serialization result failed" -weight: 10 ---- - -## Possible Reason - -Usually an internal error. - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. -At the same time, please submit an issue in the community. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/11.md b/content/en/docs3-v2/java-sdk/faq/4/11.md deleted file mode 100644 index 697ccffcec72..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/11.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "4-11 - Failed to initiate request" -linkTitle: "4-11 - Failed to initiate the request" -weight: 11 ---- - -## Possible Reason - -1. The server is closed. -2. The IP of the caller is not in the whitelist of the server. -3. The requested specific address service does not exist. - -## Troubleshooting and resolution steps - -1. Check the startup and operation of the server. -2. Check or use a third-party tool to test whether the network environment can be connected normally. -3. According to the serviceName of the stack, check or simulate the call in the management platform to see if it is normal. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/12.md b/content/en/docs3-v2/java-sdk/faq/4/12.md deleted file mode 100644 index 27c3e0accfcc..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/12.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "4-12 - Failed to create Triple stream" -linkTitle: "4-12 - Failed to create Triple stream" -weight: 12 ---- - -## Possible Reason - -Usually an internal error. - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. -At the same time, please submit an issue in the community. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/13.md b/content/en/docs3-v2/java-sdk/faq/4/13.md deleted file mode 100644 index 5045691728e8..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/13.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "4-13 - Server Timeout" -linkTitle: "4-13 - Server Timeout" -weight: 13 ---- - -## Possible Reason - -1. Server-side logic processing is relatively time-consuming. -2. The server load request is too high to respond. -3. The current timeout parameter setting threshold is quite different from the actual situation. - -## Troubleshooting and resolution steps - -1. Check whether there is time-consuming processing based on the interface name. -2. It can monitor the status of the server and the service calls invoked by the server. -3. Try increasing the timeout parameter. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/14.md b/content/en/docs3-v2/java-sdk/faq/4/14.md deleted file mode 100644 index 90872e2aad3e..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/14.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "4-14 - Response Result Failed" -linkTitle: "4-14 - Response result failed" -weight: 14 ---- - -## Possible Reason - -1. The server pipeline may be temporarily disconnected due to network reasons. -2. The currently used version is lower or you can check the current parameter configuration to see if `send.reconnect=true` is enabled, and the higher version defaults to true. - -## Troubleshooting and resolution steps - -1. Check whether the directly connected network is smooth and whether there is any packet loss. -2. Check the above parameter values, or try to use a higher version. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/15.md b/content/en/docs3-v2/java-sdk/faq/4/15.md deleted file mode 100644 index a4e5ac400298..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/15.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "4-15 - Client Stream Listener" -linkTitle: "4-15 - Client Stream Listener" -weight: 15 ---- - -## Possible Reason - -After receiving the response from the server, the client stream listener will output this information for reminder. - -## Troubleshooting and resolution steps - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/16.md b/content/en/docs3-v2/java-sdk/faq/4/16.md deleted file mode 100644 index b8ba647f8301..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/16.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "4-16 - Service Closed" -linkTitle: "4-16 - Service is closed" -weight: 16 ---- - -## Possible Reason - -Incorrect use of internal `org.apache.dubbo.rpc.protocol.tri.service.TriHealthImpl#enterTerminalState` - -## Troubleshooting and resolution steps - -Calling the above method multiple times will remind you. Generally only used for unit testing. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/17.md b/content/en/docs3-v2/java-sdk/faq/4/17.md deleted file mode 100644 index 8d1f4fc4c32e..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/17.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "4-17 - Error closing all callers" -linkTitle: "4-17 - Error closing all callers" -weight: 17 ---- - -## Possible Reason - -Usually an internal error. - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. -At the same time, please submit an issue in the community. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/18.md b/content/en/docs3-v2/java-sdk/faq/4/18.md deleted file mode 100644 index 36a3c4e763be..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/18.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "4-18 - Unable to get service model from call" -linkTitle: "4-18 - Unable to get service model from call" -weight: 18 ---- - -## Possible Reason - -Currently only used in unit test scenarios, the service model will be initialized by default. - -## Troubleshooting and resolution steps - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/19.md b/content/en/docs3-v2/java-sdk/faq/4/19.md deleted file mode 100644 index 0986308a5f2a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/19.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "4-19 - Parameter values may be wrong" -linkTitle: "4-19 - Parameter values may be wrong" -weight: 19 ---- - -## Important Reminder -The meaning of this error code has been adjusted. For Dubbo 3.1.4, 3.2.0-beta.3 and previous versions of this error code, please refer to Error Code [0-2](/zh-cn/overview/mannual/java-sdk/faq/0/2/). - -## Possible Reason -This error code indicates that the parameter value may no longer be correct. - -At present, it appears that the same protocol is listening to multiple ports at the same time. Due to design limitations, a single protocol can only listen on one port, otherwise the port configuration will be overwritten. - -## Troubleshooting and resolution steps -Adjust the monitoring relationship between protocols and ports. - -

diff --git a/content/en/docs3-v2/java-sdk/faq/4/2.md b/content/en/docs3-v2/java-sdk/faq/4/2.md deleted file mode 100644 index 0c61a3545bc8..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/2.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "4-2 - Serialization optimizer initial error" -linkTitle: "4-2 - Serialization optimizer initial error" -weight: 2 ---- - -## Possible Reason - -The serialization configuration of Kryo and FST is currently used. - -## Troubleshooting and resolution steps - -Please refer to [Kryo and FST serialization](/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/serialization/) - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/20.md b/content/en/docs3-v2/java-sdk/faq/4/20.md deleted file mode 100644 index afec7e5ce2f8..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/20.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "4-20 - Data decoding failed" -linkTitle: "4-20 - Data decoding failed" -weight: 20 ---- - -## Possible Reason - -Version mismatch between server and caller. - -## Troubleshooting and resolution steps - -Check the currently used dubbo version, and try to keep a consistent or backward compatible high version. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/21.md b/content/en/docs3-v2/java-sdk/faq/4/21.md deleted file mode 100644 index af354fba417b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/21.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -type: docs -title: "4-21 - Insecure serialized data detected" -linkTitle: "4-21 - Insecure serialized data detected" -weight: 21 ---- - -## possible reason - -The current server may be under attack or Dubbo's built-in class checking logic has not scanned the class you defined. - -## Troubleshooting and resolution steps - -1. If the source of the request is an attack source, please perform security hardening in time. -2. If the request source is expected, please declare the class name you are using in the `security/serialize.allowlist` resource file, and Dubbo will automatically load it into the security list. - -## hint - -Currently Dubbo can work in monitoring mode and restricted mode. The monitoring mode only prints logs and does not intercept; the restricted model will intercept. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/3.md b/content/en/docs3-v2/java-sdk/faq/4/3.md deleted file mode 100644 index 1c946ca3636c..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/3.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "4-3 - Interface reference call failed" -linkTitle: "4-3 - Interface reference call failed" -weight: 3 ---- - -## Possible Reason - -No exposed service interface or method was found based on the specified protocol parameter. - -## Troubleshooting and resolution steps - -You can confirm whether the server exists according to the interface URL and method name. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/4.md b/content/en/docs3-v2/java-sdk/faq/4/4.md deleted file mode 100644 index 36dc579dced9..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/4.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "4-4 - Non-safe serialization method" -linkTitle: "4-4 - Non-safe serialization method" -weight: 4 ---- - -## Possible Reason - -Currently using an unsafe serializer, which is not recommended. The specific configuration is: `serialization="java"` - -## Troubleshooting and resolution steps - -Modify the parameter value of the setting. Change the serialization parameter value in the protocol to other. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/5.md b/content/en/docs3-v2/java-sdk/faq/4/5.md deleted file mode 100644 index 24e9106971b7..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/5.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "4-5 - Stream closed exception" -linkTitle: "4-5 - Stream closed exception" -weight: 5 ---- - -## Possible Reason - -The prompt information does not affect the execution result of the program. - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/6.md b/content/en/docs3-v2/java-sdk/faq/4/6.md deleted file mode 100644 index f0272f8fd16a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/6.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "4-6 - Deserialization failed" -linkTitle: "4-6 - Deserialization failed" -weight: 6 ---- - -## Possible Reason - -There is a logic error in the custom SPI `org.apache.dubbo.common.serialize.Serialization` serialization method. - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/7.md b/content/en/docs3-v2/java-sdk/faq/4/7.md deleted file mode 100644 index 78843e21d1e0..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/7.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "4-7 - An error occurred while closing the client" -linkTitle: "4-7 - An error occurred while closing the client" -weight: 7 ---- - -## Possible Reason - - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/8.md b/content/en/docs3-v2/java-sdk/faq/4/8.md deleted file mode 100644 index bf47ebde247e..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/8.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "4-8 - An error occurred while closing the server" -linkTitle: "4-8 - An error occurred while closing the server" -weight: 8 ---- - -## Possible Reason - - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/9.md b/content/en/docs3-v2/java-sdk/faq/4/9.md deleted file mode 100644 index 171504f276f0..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/9.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "4-9 - Parse failed" -linkTitle: "4-9 - Parse failed" -weight: 9 ---- - -## Possible Reason - -Generally, the parameter value does not conform to the rules, and an error occurs during forced conversion. - -## Troubleshooting and resolution steps - -Modify the configuration according to the key name prompted by the stack information. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/4/_index.md b/content/en/docs3-v2/java-sdk/faq/4/_index.md deleted file mode 100644 index df259aff6502..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/4/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "4 - Protocol" -linkTitle: "4 - Protocol" -weight: 4 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/1.md b/content/en/docs3-v2/java-sdk/faq/5/1.md deleted file mode 100644 index 0c701258bad5..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/1.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -type: docs -title: "5-1 - Failed to connect to configuration center" -linkTitle: "5-1 - Failed to connect to the configuration center" -weight: 1 ---- - -## Possible Reason - -1. The server where the configuration center is located is shut down or down. -2. Wrong IP or port number. -3. The firewall blocked the port of the configuration center by mistake. - - -## Troubleshooting and resolution steps - -1. Check configuration center IP and port configuration. -2. Check whether the server is turned on and works normally. -3. Check whether the port used by the configuration center is allowed by the firewall or not. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/10.md b/content/en/docs3-v2/java-sdk/faq/5/10.md deleted file mode 100644 index b026290e6210..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/10.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-10 - Registration interface application mapping failed for service" -linkTitle: "5-10 - Service's registration interface application mapping failed" -weight: 10 ---- - -## Possible Reason - -The service metadata exposed by the service does not match the application, or has been tampered with. - -## Troubleshooting and resolution steps - -Check that the metadata content in the configuration center matches that in the application. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/11.md b/content/en/docs3-v2/java-sdk/faq/5/11.md deleted file mode 100644 index 0b9bbdc064bd..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/11.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "5-11 - Registration Instance Error" -linkTitle: "5-11 - Registration instance error" -weight: 11 ---- - -## Possible Reason - -1. The service of the configuration center cannot be connected. -2. The configured protocol, IP, and port are incorrect. -3. The client version of the configuration center conflicts with the server version, and a valid connection cannot be established. - -## Troubleshooting and resolution steps - -1. Check whether the service status of the configuration center is normal. -2. Check that the configured protocol, IP, and port are incorrect. -3. Check whether the version of the configuration center client used is compatible with the version of the server. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/12.md b/content/en/docs3-v2/java-sdk/faq/5/12.md deleted file mode 100644 index a4a8e0f8579b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/12.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "5-12 - Refresh instance and metadata errors" -linkTitle: "5-12 - Refresh instance and metadata errors" -weight: 12 ---- - -## Possible Reason - -1. The service of the configuration center cannot be connected. -2. The configured protocol, IP, and port are incorrect. -3. The client version of the configuration center conflicts with the server version, and a valid connection cannot be established. - -## Troubleshooting and resolution steps - -1. Check whether the service status of the configuration center is normal. -2. Check that the configured protocol, IP, and port are incorrect. -3. Check whether the version of the configuration center client used is compatible with the version of the server. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/13.md b/content/en/docs3-v2/java-sdk/faq/5/13.md deleted file mode 100644 index 4dfba048a75e..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/13.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-13 - Model cannot be destroyed" -linkTitle: "5-13 - Model cannot be destroyed" -weight: 13 ---- - -## Possible Reason - -There is an exception in the business processing of the custom destruction method. - -## Troubleshooting and resolution steps - -Check the custom destruction method and business processing logic for runtime exceptions. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/14.md b/content/en/docs3-v2/java-sdk/faq/5/14.md deleted file mode 100644 index 68a23e05965d..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/14.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "5-14 - Model startup error" -linkTitle: "5-14 - Model startup error" -weight: 14 ---- - -## Possible Reason - -1. The connection is disconnected while the service is waiting to publish or subscribe. -2. The network connection timed out. - -## Troubleshooting and resolution steps - -1. Check whether the connection between the application server and the configuration center is normal. -2. Check whether there is a timeout in the network connection, etc. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/15.md b/content/en/docs3-v2/java-sdk/faq/5/15.md deleted file mode 100644 index daec4e4723d6..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/15.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-15 - Model Reference Error" -linkTitle: "5-15 - Model Reference Error" -weight: 15 ---- - -## Possible Reason - -The method of Dubbo core processing class is misused or tampered with. - -## Troubleshooting and resolution steps - -Check for misuse or decompiled modifications on the application. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/16.md b/content/en/docs3-v2/java-sdk/faq/5/16.md deleted file mode 100644 index 43876eca3719..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/16.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "5-16 - Unable to find any valid agreements" -linkTitle: "5-16 - Unable to find any valid agreements" -weight: 16 ---- - -## Possible Reason - -The configured protocol is not supported. - -## Troubleshooting and resolution steps - -Currently supported protocols are dubbo, rmi, hessian, http, webservice, thrift, redis, etc. - -## see also -[Configuration item reference manual](/zh-cn/overview/mannual/java-sdk/reference-manual/config/) - -

diff --git a/content/en/docs3-v2/java-sdk/faq/5/17.md b/content/en/docs3-v2/java-sdk/faq/5/17.md deleted file mode 100644 index 090e10417896..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/17.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "5-17 - Parameter value format error" -linkTitle: "5-17 - Parameter value format error" -weight: 17 ---- - -## Possible Reason - -1. The attribute configuration value is too long, generally set within 200 characters. -2. The format of the attribute configuration value is wrong, currently supports numbers, -, _, etc. - -## Troubleshooting and resolution steps - -1. Check whether the content of the attribute configuration value is too long, and modify it according to the prompt information. -2. Check whether the attribute configuration value contains special characters, such as @#$%^&, etc. For details, please refer to the prompt information to modify. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/18.md b/content/en/docs3-v2/java-sdk/faq/5/18.md deleted file mode 100644 index 9ddafbededdf..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/18.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "5-18 - Notification registration event failed" -linkTitle: "5-18 - Notification registration event failed" -weight: 18 ---- - -## Possible Reason - -1. The notification has been sent, and an unexpected error occurred in the business processing logic. -2. The configuration center cannot be connected, timeout error. - -## Troubleshooting and resolution steps - -1. Check the custom business logic implementation, whether there is a runtime exception. -2. Check whether the configuration center can be connected normally. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/19.md b/content/en/docs3-v2/java-sdk/faq/5/19.md deleted file mode 100644 index 60c93649603c..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/19.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -type: docs -title: "5-19 - Embedded ZooKeeper running abnormally" -linkTitle: "5-19 - The embedded ZooKeeper runs abnormally" -weight: 19 ---- - -## Possible Reason - -1. The ZooKeeper service is running abnormally or down. -2. The Zookeeper client version is incompatible with the server startup version and cannot be connected. -3. The connection between the application server and the ZooKeeper service is interrupted. -4. Restricted firewall or third-party protection tools. - -## Troubleshooting and resolution steps - -1. Check the ZooKeeper service and the health status of the server where it resides. -2. Check whether there is a compatibility problem between the Zookeeper client version and the server startup version, and keep the versions consistent. -3. Check whether the ports of the application server and the ZooKeeper service are unblocked. -4. Check the firewall or third-party protection tool settings to see if it is disabled. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/2.md b/content/en/docs3-v2/java-sdk/faq/5/2.md deleted file mode 100644 index 00203be34986..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/2.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-2 - Failed to register/unregister shutdown hook method" -linkTitle: "5-2 - Failed to register/unregister shutdown hook method" -weight: 2 ---- - -## Possible Reason - -There are exceptions in the custom hook method and business processing logic. - -## Troubleshooting and resolution steps - -Check the custom hook method and business processing logic for runtime exceptions. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/20.md b/content/en/docs3-v2/java-sdk/faq/5/20.md deleted file mode 100644 index f7ff1a88a21f..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/20.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "5-20 - Error occurred while stopping dubbo module" -linkTitle: "5-20 - An error occurred while stopping the dubbo module" -weight: 20 ---- - -## Possible Reason - -1. Customize the implementation of the destruction method, and there may be exceptions when the business logic is running. -2. The service has not been gracefully stopped, and there may be cases where the business logic has not been processed. - -## Troubleshooting and resolution steps - -1. Check the custom implementation of the destruction method and business logic. -2. Check whether there is time-consuming business processing logic when the service is stopped. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/21.md b/content/en/docs3-v2/java-sdk/faq/5/21.md deleted file mode 100644 index 2ee84ec8974c..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/21.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "5-21 - An exception occurred when the service was destroyed" -linkTitle: "5-21 - An exception occurred when the service was destroyed" -weight: 21 ---- - - -## Possible Reason - -The service discovery instance has been destroyed - -Attachment: The current method has been discontinued in version 3.1 - -## Troubleshooting and resolution steps - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/22.md b/content/en/docs3-v2/java-sdk/faq/5/22.md deleted file mode 100644 index 73c4d6b7ab2a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/22.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -type: docs -title: "5-22 - An error occurred while initializing the registry" -linkTitle: "5-22 - An error occurred while initializing the registry" -weight: 22 ---- - - -## Possible Reason - -1. The address configuration of the registration center is wrong. -2. The configured address information cannot be connected through the network normally. -3. The version of the configuration center client does not match the version of the actual server, and there is a compatibility exception. - -## Troubleshooting and resolution steps - -1. Check whether the configured address is correct. -2. Check whether the network is smooth and can be connected through a third-party client. -3. Check whether there is a compatibility matching problem, you can refer to the third-party website for version adaptation. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/23.md b/content/en/docs3-v2/java-sdk/faq/5/23.md deleted file mode 100644 index 760b52898333..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/23.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "5-23 - Waiting for export/reference service exception" -linkTitle: "5-23 - Waiting for export/reference service exception" -weight: 23 ---- - - -## Possible Reason - -When exporting/referencing services, the registration center stops abnormally or fails to provide normal services externally. - -## Troubleshooting and resolution steps - -Check whether the registration center can be connected normally, and check whether the current client version is compatible with the server. - -Attachment: The exception is handled in the export/quote method, and theoretically this exception will not be thrown. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/24.md b/content/en/docs3-v2/java-sdk/faq/5/24.md deleted file mode 100644 index a4e58f9ca781..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/24.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "5-24 - An exception occurred while asynchronously waiting for the reference service" -linkTitle: "5-24 - An exception occurred while asynchronously waiting for the reference service" -weight: 24 ---- - - -## Possible Reason - -The registration center stops abnormally or cannot provide normal services to the outside world. - -## Troubleshooting and resolution steps - -Check whether the registration center can be connected normally, and check whether the current client version is compatible with the server. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/25.md b/content/en/docs3-v2/java-sdk/faq/5/25.md deleted file mode 100644 index 48343bdd91d3..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/25.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-25 - Undefined exception from custom implementation" -linkTitle: "5-25 - Undefined exception from custom implementation" -weight: 25 ---- - -## Possible Reason - -The custom implemented `org.apache.dubbo.rpc.Protocol` protocol has a business logic exception when the method calls destroy. - -## Troubleshooting and resolution steps - -Check the `destory` method of the custom implementation class code. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/26.md b/content/en/docs3-v2/java-sdk/faq/5/26.md deleted file mode 100644 index 386f07b8fb37..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/26.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "5-26 - Metadata Exported" -linkTitle: "5-26 - Metadata exported" -weight: 26 ---- - -## Possible Reason - -Metadata has been exported in the current JVM. - -## Troubleshooting and resolution steps - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/27.md b/content/en/docs3-v2/java-sdk/faq/5/27.md deleted file mode 100644 index ac6b38ccdf28..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/27.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-27 - Inner class API is misused" -linkTitle: "5-27 - Inner class API is misused" -weight: 27 ---- - -## Possible Reason - -`org.apache.dubbo.config.ReferenceConfig` and `org.apache.dubbo.common.config.ReferenceCache` may be defined as non-singleton mode. - -## Troubleshooting and resolution steps - -Check custom annotations or configurations, define the core application class as a non-singleton mode, check `scope` configuration. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/28.md b/content/en/docs3-v2/java-sdk/faq/5/28.md deleted file mode 100644 index c638c6e2a210..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/28.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-28 - No available annotation found" -linkTitle: "5-28 - No available annotation found" -weight: 28 ---- - -## Possible Reason - -No reliable annotations were found under the scan package configuration. Mainly `@DubboService` or `@Service` - -## Troubleshooting and resolution steps - -Check the current version, `@Service` annotation will be scanned before 2.7.7, and `@DubboService` after that - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/29.md b/content/en/docs3-v2/java-sdk/faq/5/29.md deleted file mode 100644 index bfa2f7b1dbc2..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/29.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-29 - Scan package not configured" -linkTitle: "5-29 - Scan package not configured" -weight: 29 ---- - -## Possible Reason - -`@EnableDubbo.scanBasePackages` annotation parameter value is not configured - -## Troubleshooting and resolution steps - -`@EnableDubbo.scanBasePackages` can be configured. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/3.md b/content/en/docs3-v2/java-sdk/faq/5/3.md deleted file mode 100644 index 991e4d18e836..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/3.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-3 - An unexpected error occurred while destroying a method call" -linkTitle: "5-3 - An unexpected error occurred while destroying a method call" -weight: 3 ---- - -## Possible Reason - -There is an exception in the business processing of the custom destruction method. - -## Troubleshooting and resolution steps - -Check the custom destruction method and business processing logic for runtime exceptions. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/30.md b/content/en/docs3-v2/java-sdk/faq/5/30.md deleted file mode 100644 index 67ce4ed8747a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/30.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-30 - Duplicate bean definition" -linkTitle: "5-30 - Duplicate bean definition" -weight: 30 ---- - -## Possible Reason - -Duplicate object id or name declared. - -## Troubleshooting and resolution steps - -According to the fully qualified class name output by the console, the name can only be modified to be unique. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/31.md b/content/en/docs3-v2/java-sdk/faq/5/31.md deleted file mode 100644 index 97ef2299077a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/31.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-31 - Status Check Error" -linkTitle: "5-31 - Status check error" -weight: 31 ---- - -## Possible Reason - -Currently running server status, system CPU usage is too high or memory and other indicators are too low - -## Troubleshooting and resolution steps - -Check the memory usage status of the current server, and other indicators such as CPU usage, there may be a danger of downtime. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/32.md b/content/en/docs3-v2/java-sdk/faq/5/32.md deleted file mode 100644 index 4ab1a602c0f1..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/32.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-32 - Apollo disconnected with an error" -linkTitle: "5-32 - Apollo disconnected with an error" -weight: 32 ---- - -## Possible Reason - -The Apollo Config Center may be down or disconnected from the network. - -## Troubleshooting and resolution steps - -Check the service status of the Apollo server and whether the network can communicate normally. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/33.md b/content/en/docs3-v2/java-sdk/faq/5/33.md deleted file mode 100644 index 8e8356cbe4da..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/33.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-33 - An exception occurred in the Apollo configuration update event" -linkTitle: "5-33 - An exception occurred in the Apollo configuration update event" -weight: 33 ---- - -## Possible Reason - -The Apollo configuration API is used incorrectly. - -## Troubleshooting and resolution steps - -Please refer to the description about Apollo in the Dynamic Configuration Center Documentation. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/34.md b/content/en/docs3-v2/java-sdk/faq/5/34.md deleted file mode 100644 index efc2ce609e36..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/34.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-34 - NACOS Error" -linkTitle: "5-34 - NACOS went wrong" -weight: 34 ---- - -## Possible Reason - -NACOS configuration API usage error. - -## Troubleshooting and resolution steps - -Please refer to the description about NACOS in the Dynamic Configuration Center Documentation. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/35.md b/content/en/docs3-v2/java-sdk/faq/5/35.md deleted file mode 100644 index a73608cd30e8..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/35.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "5-35 - Container initialization failed" -linkTitle: "5-35 - Container initialization failed" -weight: 35 ---- - -## Possible Reason - -The `org.apache.dubbo.container.Container` SPI implementation of the undefined interface. - -P.S. It is currently tested and used in `org.apache.dubbo.container.Main` class. - -## Troubleshooting and resolution steps - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/36.md b/content/en/docs3-v2/java-sdk/faq/5/36.md deleted file mode 100644 index 708cce39c1e0..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/36.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-36 - An error occurred during filter validation" -linkTitle: "5-36 - An error occurred during filter validation" -weight: 36 ---- - -## Possible Reason - -The `invoke` method rewritten in the custom filter extension class has a business code exception. - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/37.md b/content/en/docs3-v2/java-sdk/faq/5/37.md deleted file mode 100644 index fa8f9cdb1a1c..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/37.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "5-37 - An error occurred in the processing of dynamic configuration monitoring" -linkTitle: "5-37 - An error occurred in the processing of dynamic configuration monitoring" -weight: 37 ---- -When the file changes, the listening event processing fails - -## Possible Reason - -File permissions changed or directory permissions changed. - -## Troubleshooting and resolution steps - -The code can be located according to the stack information of the console. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/38.md b/content/en/docs3-v2/java-sdk/faq/5/38.md deleted file mode 100644 index cc2ea9e5554b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/38.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-38 - Configuration parameter undefined" -linkTitle: "5-38 - Configuration parameter undefined" -weight: 38 ---- - -## Possible Reason - -configuration parameter is undefined - -## Troubleshooting and resolution steps - -It is mostly used in test cases, and parameters can be set according to the prompt details. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/39.md b/content/en/docs3-v2/java-sdk/faq/5/39.md deleted file mode 100644 index 1645e65eea53..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/39.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "5-39 - An error occurred in the Dubbo configuration bean initializer" -linkTitle: "5-39 - An error occurred in the Dubbo configuration bean initializer" -weight: 39 ---- - -## Possible Reason - -source code or modified - -## Troubleshooting and resolution steps - -Check that the business code does not modify the source code or load sequence of the core class. -Such as: org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/4.md b/content/en/docs3-v2/java-sdk/faq/5/4.md deleted file mode 100644 index ddae7d6068d1..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/4.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "5-4 - Method not found in service interface" -linkTitle: "5-4 - Method not found in service interface" -weight: 4 ---- - -## Possible Reason - -1. The interface name#method called by the consumer does not exist. -2. The server does not expose the current interface correctly. - -## Troubleshooting and resolution steps - -1. Check whether the interface name# method called by the consumer exists. -2. Check whether it exists in the service list exposed by the server. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/40.md b/content/en/docs3-v2/java-sdk/faq/5/40.md deleted file mode 100644 index 5ee6e85d6dd4..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/40.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "5-40 - Dubbo configuration bean not found" -linkTitle: "5-40 - Dubbo configuration bean not found" -weight: 40 ---- - -## Possible Reason - -source code or modified - -## Troubleshooting and resolution steps - -Check that the business code does not modify the source code or load sequence of the core class. -Such as: org.apache.dubbo.config.spring.context.DubboConfigBeanInitializer - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/41.md b/content/en/docs3-v2/java-sdk/faq/5/41.md deleted file mode 100644 index 6c47ed1f5288..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/41.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -type: docs -title: "5-41 - Failed to read SSL certificate" -linkTitle: "5-41 - Failed to read SSL certificate" -weight: 41 ---- - -### possible reason - -SSL certificate configuration exception - -### Troubleshooting and resolution steps - -Check the configuration of the SSL certificate to see if the corresponding file exists diff --git a/content/en/docs3-v2/java-sdk/faq/5/42.md b/content/en/docs3-v2/java-sdk/faq/5/42.md deleted file mode 100644 index b14f48741f5a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/42.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-42 - Dubbo certificate issuance failed" -linkTitle: "5-42 - Dubbo certificate issuance failed" -weight: 42 ---- - -### possible reason - -Dubbo failed to request the remote CA to issue a certificate - -### Troubleshooting and resolution steps - -- Check CA connection configuration -- Check CA health status -- Check CA logs diff --git a/content/en/docs3-v2/java-sdk/faq/5/43.md b/content/en/docs3-v2/java-sdk/faq/5/43.md deleted file mode 100644 index 5091e82fc07c..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/43.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -type: docs -title: "5-43 - Dubbo certificate signing connection is not secure" -linkTitle: "5-43 - Dubbo certificate signing connection is insecure" -weight: 43 ---- - -### possible reason - -Dubbo's connection to remote CA is not secure - -### Troubleshooting and resolution steps - -- Check whether the Dubbo process has correctly configured the CA certificate information and the Token acquisition method of OIDC (OpenID Connect) diff --git a/content/en/docs3-v2/java-sdk/faq/5/5.md b/content/en/docs3-v2/java-sdk/faq/5/5.md deleted file mode 100644 index 40e16d7b24ad..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/5.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-5 - Unable to get env variables" -linkTitle: "5-5 - Unable to get env variables" -weight: 5 ---- - -## Possible Reason - -Environment variable could not be obtained. - -## Troubleshooting and resolution steps - -Check the prompted variable name, whether it is configured and can be read and loaded normally. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/6.md b/content/en/docs3-v2/java-sdk/faq/5/6.md deleted file mode 100644 index 7ad47240a2f9..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/6.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-6 - Attribute Conflict of Interface Type" -linkTitle: "5-6 - Attribute Conflict of Interface Type" -weight: 6 ---- - -## Possible Reason - -The generalization definition is not configured correctly. - -## Troubleshooting and resolution steps - -Check that the generalization definition is correct. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/7.md b/content/en/docs3-v2/java-sdk/faq/5/7.md deleted file mode 100644 index 29cfdf43a2a2..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/7.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "5-7 - An unexpected error occurred while canceling the export" -linkTitle: "5-7 - An unexpected error occurred while canceling the export" -weight: 7 ---- - -## Possible Reason - -1. The service of the configuration center cannot be connected. -2. The configured protocol, IP, and port are incorrect. -3. The client version of the configuration center conflicts with the server version, and a valid connection cannot be established. - -## Troubleshooting and resolution steps - -1. Check whether the service status of the configuration center is normal. -2. Check that the configured protocol, IP, and port are incorrect. -3. Check whether the version of the configuration center client used is compatible with the version of the server. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/8.md b/content/en/docs3-v2/java-sdk/faq/5/8.md deleted file mode 100644 index b904ccadffc9..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/8.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "5-8 - The protocol will use a random available port" -linkTitle: "5-8 - The protocol will use a random available port" -weight: 8 ---- - -## Possible Reason - -The port specified by the protocol is occupied, and the port is randomly selected for startup. - -## Troubleshooting and resolution steps - -Check whether the currently configured port is occupied by other applications. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/9.md b/content/en/docs3-v2/java-sdk/faq/5/9.md deleted file mode 100644 index ce673f106196..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/9.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "5-9 - Service Configuration Export Failed" -linkTitle: "5-9 - Service configuration export failed" -weight: 9 ---- - -## Possible Reason - -1. The service of the configuration center cannot be connected. -2. The configured protocol, IP, and port are incorrect. -3. The client version of the configuration center conflicts with the server version, and a valid connection cannot be established. - -## Troubleshooting and resolution steps - -1. Check whether the service status of the configuration center is normal. -2. Check that the configured protocol, IP, and port are incorrect. -3. Check whether the version of the configuration center client used is compatible with the version of the server. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/5/_index.md b/content/en/docs3-v2/java-sdk/faq/5/_index.md deleted file mode 100644 index 7350301f1891..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/5/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "5 - Config Center" -linkTitle: "5 - Config Center" -weight: 5 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/1.md b/content/en/docs3-v2/java-sdk/faq/6/1.md deleted file mode 100644 index 5f7282a66e75..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/1.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "6-1 - Server Connection Failed" -linkTitle: "6-1 - Server connection failed" -weight: 1 ---- -Network communication layer, failed to connect to the service provider service - -## Possible Reason - -The service provider's network is abnormally disconnected or blocked by firewalls and third-party tools, and cannot provide external services. - -## Troubleshooting and resolution steps - -1. If it is a rest connection, check whether the requested server configuration is correct. -2. Check whether the network communication is normal, you can use some simple cmd commands to detect, such as `ping` and so on. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/10.md b/content/en/docs3-v2/java-sdk/faq/6/10.md deleted file mode 100644 index d8affa936bde..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/10.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "6-10 - Payload Limit Exceeded Exception" -linkTitle: "6-10 - Payload Limit Exceeded Exception" -weight: 10 ---- -The default `payload=8M`, please check the configuration - -## Possible Reason - - -## Troubleshooting and resolution steps - -For the specific configuration items and meanings supported by each component, please refer to [Configuration Item Manual](/en/docs3-v2/java-sdk/reference-manual/config/properties/) - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/11.md b/content/en/docs3-v2/java-sdk/faq/6/11.md deleted file mode 100644 index 9063ed1a8c01..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/11.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "6-11 - Character set not supported" -linkTitle: "6-11 - Character set not supported" -weight: 11 ---- -Default `UTF-8` charset - -## Possible Reason - - -## Troubleshooting and resolution steps - -The result will end up being processed in the `UTF-8` character set. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/12.md b/content/en/docs3-v2/java-sdk/faq/6/12.md deleted file mode 100644 index 1563384f2b4a..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/12.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "6-12 - An error occurred when the ZK client was destroyed" -linkTitle: "6-12 - An error occurred when the ZK client was destroyed" -weight: 12 ---- - - -## Possible Reason - -The connection between the client and the server has been refused -When the client is being destroyed, the server may be performing elections or other operations, resulting in an exception. - -## Troubleshooting and resolution steps - -The shutdown method can be used to query stack information. Generally do not deal with. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/13.md b/content/en/docs3-v2/java-sdk/faq/6/13.md deleted file mode 100644 index 061561b12915..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/13.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "6-13 - Stream closed exception" -linkTitle: "6-13 - Stream closed exception" -weight: 13 ---- - - -## Possible Reason - -`Stream is closed` or the stream is closed while other threads are reading - -## Troubleshooting and resolution steps - -Generally, the order in which the code closes the streams is reversed. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/14.md b/content/en/docs3-v2/java-sdk/faq/6/14.md deleted file mode 100644 index d36e5131519b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/14.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "6-14 - Server response failed" -linkTitle: "6-14 - Server response failed" -weight: 14 ---- - -## Possible Reason - -When the server interacts with the client to generate data, the client closes abnormally. - -## Troubleshooting and resolution steps - -The client terminated abnormally or the server crashed. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/15.md b/content/en/docs3-v2/java-sdk/faq/6/15.md deleted file mode 100644 index ca443e5641b2..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/15.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -type: docs -title: "6-15 - Skip unread stream data" -linkTitle: "6-15 - Skip unread stream data" -weight: 15 ---- -When decoding, if there is unread data in the stream, the unread stream will be skipped - -## Possible Reason - -## Troubleshooting and resolution steps - -When decoding, all the data will be read at one time - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/16.md b/content/en/docs3-v2/java-sdk/faq/6/16.md deleted file mode 100644 index 5a490b147fd0..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/16.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "6-16 - An exception occurred during reconnection" -linkTitle: "6-16 - An exception occurred during reconnection" -weight: 16 ---- -Prompt every time a reconnection occurs - -## Possible Reason - -Delayed reconnection caused by network instability. - -## Troubleshooting and resolution steps - -Check for network packet loss. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/2.md b/content/en/docs3-v2/java-sdk/faq/6/2.md deleted file mode 100644 index ba465cc9f3d5..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/2.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -type: docs -title: "6-2 - Client Timeout" -linkTitle: "6-2 - Client Timeout" -weight: 2 ---- -Timeout occurs when the caller fails to obtain the corresponding response within the specified time after the request is sent. - -## Possible Reason -1. The server is really slow in processing and cannot return the result within the specified time. The caller will automatically return a timeout exception response to end the call. -2. If the server responds quickly, but when the client load is high and the load pressure is high, it will time out due to problems such as the client request not being sent out or the response stuck in the TCP Buffer. Because the client receives the data sent by the server or requests the data from the server, it will be queued at the system level. If the system load is relatively high, the time spent in the kernel state will increase, causing the client to time out when it gets the value. . -3. Usually the business processing is too slow, and it can be executed on the service provider machine: `jstack [PID] > jstack.log` to analyze which method calls the threads are stuck on, which is the reason for the slowness. If performance tuning is not an option, increase the timeout threshold. - - -## Troubleshooting and resolution steps - -1. There may be GC on both sides. Check the GC logs of the server and client. A GC that takes a long time will cause a timeout. The occurrence of a timeout probably means that the resource (CPU, memory, or network) of the caller or server has a bottleneck. It is necessary to check whether the problem is on the server or the caller to rule out suspicions such as GC jitter. -2. Check the network quality of the server, such as the retransmission rate to rule out network suspicions. -3. With the help of link tracking analysis services (such as Ali's [ARMS](https://help.aliyun.com/document_detail/63796.html), the open source [OpenTracing](https://github.com/opentracing/ opentracing-java) - System implementation [Zipkin](https://github.com/openzipkin/zipkin), [SkyWalking](https://github.com/apache/skywalking) etc.) to analyze the time-consuming situation of each point. - -## Acknowledgments -The FAQ page of this error code refers to ["Dubbo Common Errors and Solutions"](https://github.com/StabilityMan/StabilityGuide/blob/master/docs/diagnosis/plugin/rpc/%E7%B3%BB%E7%BB%9F%E7%A8%B3%E5%AE%9A%E6%80%A7%E2%80%94%E2%80%94Dubbo%E5%B8%B8%E8%A7%81%E9%94%99%E8%AF%AF%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95.md). - -Articles cited are compiled under license [CC-BY-4.0](http://creativecommons.org/licenses/by/4.0/). Thanks to the original author here. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/3.md b/content/en/docs3-v2/java-sdk/faq/6/3.md deleted file mode 100644 index 30e09bc2913b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/3.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "6-3 - Failed to close network connection" -linkTitle: "6-3 - Failed to close the network connection" -weight: 3 ---- -Network connection close failed - -## Possible Reason - -Non-graceful shutdown of the service. At this time, the server may not complete the external output stream. - -## Troubleshooting and resolution steps - -Generally, it is a prompt warning message, which does not affect subsequent program execution. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/4.md b/content/en/docs3-v2/java-sdk/faq/6/4.md deleted file mode 100644 index 15cce7c49465..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/4.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -type: docs -title: "6-4 - Network communication layer unknown exception" -linkTitle: "6-4 - Unknown exception in the network communication layer" -weight: 4 ---- -## Reminder -The meaning of this error code has been adjusted. If you are looking for information of this error code in Dubbo versions prior than (or equal) 3.1.4 or 3.2.0-beta.3, head to [99-0](/en/docs3-v2/java-sdk/faq/99/0/). - -(This error code is currently absent.) - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/5.md b/content/en/docs3-v2/java-sdk/faq/6/5.md deleted file mode 100644 index 050ab02a2059..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/5.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "6-5 - Network disconnection failed" -linkTitle: "6-5 - Network disconnection failed" -weight: 5 ---- -Timeout occurs when the caller fails to obtain the corresponding response within the specified time after the request is sent. - -## Possible Reason - -Client actively disconnects - -## Troubleshooting and resolution steps - -Generally, it is a prompt warning message, which does not affect subsequent program execution. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/6.md b/content/en/docs3-v2/java-sdk/faq/6/6.md deleted file mode 100644 index b82f23c4e586..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/6.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -type: docs -title: "6-6 - Unsupported message" -linkTitle: "6-6 - Unsupported message" -weight: 6 ---- - - -## Possible Reason - -The returned data is serialized incorrectly, or exceeds the serialization maximum - -## Troubleshooting and resolution steps - -You can use some third-party tools or `jstack [PID] > jstack.log` to analyze the stack information and locate it. - -For the specific configuration items and meanings supported by each component, please refer to [Configuration Item Manual](/en/docs3-v2/java-sdk/reference-manual/config/properties/) - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/7.md b/content/en/docs3-v2/java-sdk/faq/6/7.md deleted file mode 100644 index 01a3bd7dbeb5..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/7.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "6-7 - Thread Connection Exceeded Warning" -linkTitle: "6-7 - Server connection failed" -weight: 7 ---- -Reminder message when the number of connections exceeds the limit - -## Possible Reason - -A warning reminder that the configuration or the number of connections exceeds the configured number. - -## Troubleshooting and resolution steps - -The default configuration item `connect.queue.warning.size=1000` can be adjusted through configuration. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/8.md b/content/en/docs3-v2/java-sdk/faq/6/8.md deleted file mode 100644 index 81c85b6efd9b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/8.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "6-8 - Return data decoding failed" -linkTitle: "6-8 - Return data decoding failed" -weight: 8 ---- - - -## Possible Reason - -Return data format error or decoding failed - -## Troubleshooting and resolution steps - -Through the debug/warn log mode, the specific service class name and the returned message and stack information can be output. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/9.md b/content/en/docs3-v2/java-sdk/faq/6/9.md deleted file mode 100644 index 36a2a723ecd8..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/9.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "6-9 - There are duplicate serial number IDs" -linkTitle: "6-9 - Server connection failed" -weight: 9 ---- - - -## Possible Reason - -1. An empty object is returned. -2. The custom serial number class, `org.apache.dubbo.common.serialize.Serialization#getContentTypeId` is duplicated with the built-in system, - At this time, when loading, the first loaded SPI instance shall prevail. Other items will be skipped. - -## Troubleshooting and resolution steps - -1. Check the return result. -2. The built-in value can refer to the class `org.apache.dubbo.common.serialize.Constants` - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/6/_index.md b/content/en/docs3-v2/java-sdk/faq/6/_index.md deleted file mode 100644 index 9757a07c6690..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/6/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "6 - Transport" -linkTitle: "6 - Transport" -weight: 6 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/7/1.md b/content/en/docs3-v2/java-sdk/faq/7/1.md deleted file mode 100644 index e179ae5b4d89..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/7/1.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "7-1 - QOS OFF" -linkTitle: "7-1 - QOS is off" -weight: 1 ---- - -## Possible Reason - -QOS is off - -## Troubleshooting and resolution steps - - -Please refer to [QOS Operation Manual](/en/docs3-v2/java-sdk/reference-manual/qos/). -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/7/2.md b/content/en/docs3-v2/java-sdk/faq/7/2.md deleted file mode 100644 index aa780e03ccc2..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/7/2.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "7-2 - QOS is on" -linkTitle: "7-2 - QOS is on" -weight: 2 ---- - -## Possible Reason - -QOS is enabled, and it is enabled by default. - -## Troubleshooting and resolution steps - - -Please refer to [QOS Operation Manual](/en/docs3-v2/java-sdk/reference-manual/qos/). -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/7/3.md b/content/en/docs3-v2/java-sdk/faq/7/3.md deleted file mode 100644 index c821a4017105..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/7/3.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "7-3 - Set warning percentage value for timeout" -linkTitle: "7-3 - Set warning percentage value for timeout" -weight: 3 ---- - -## Possible Reason - -The warning percentage value of QOS setting timeout time, the default is 0.75. After modification, the console prints this message. - -## Troubleshooting and resolution steps - - -Please refer to QOS Operation Manual [Performance Sampling Command](/en/docs3-v2/java-sdk/reference-manual/qos/profiler/). -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/7/4.md b/content/en/docs3-v2/java-sdk/faq/7/4.md deleted file mode 100644 index beabf791d7e4..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/7/4.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -type: docs -title: "7-4 - QOS service failed to start" -linkTitle: "7-4 - QOS service failed to start" -weight: 4 ---- - -## Possible Reason - -The QOS parameter value is not set correctly. The main parameters are `qos.host` and `qos.port` - -## Troubleshooting and resolution steps - - -Please refer to the QOS Operation Manual [QOS Overview](/en/docs3-v2/java-sdk/reference-manual/qos/overview/). -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/7/5.md b/content/en/docs3-v2/java-sdk/faq/7/5.md deleted file mode 100644 index d07a173bbc19..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/7/5.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "7-5 - QOS command not found" -linkTitle: "7-5 - QOS command not found" -weight: 5 ---- - -## Possible Reason - -1. The QOS command is misspelled. - -## Troubleshooting and resolution steps - -1. QOS command does not exist. - -Please refer to QOS Operation Manual [Basic Command Manual](/en/docs3-v2/java-sdk/reference-manual/qos/command/). -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/7/6.md b/content/en/docs3-v2/java-sdk/faq/7/6.md deleted file mode 100644 index 69a64bb98ee1..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/7/6.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -type: docs -title: "7-6 - Unknown exception occurred in QOS" -linkTitle: "7-6 - Unknown exception occurred in QOS" -weight: 6 ---- - -## Possible Reason - -1. An unknown exception occurred in QOS - -## Troubleshooting and resolution steps - -1. Check whether the currently requested service can be accessed normally. -2. Perhaps for some reason, the `CommandContext` instance was not properly loaded or returned. You can troubleshoot and locate according to the error reminder information on the console. - - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/7/7.md b/content/en/docs3-v2/java-sdk/faq/7/7.md deleted file mode 100644 index e351d373e5c3..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/7/7.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "7-7 - QOS Unprivileged Access" -linkTitle: "7-7 - QOS Unprivileged Access" -weight: 7 ---- - -## Possible Reason - -This QoS request does not have permission to access the corresponding resources, which usually occurs in a malicious attack scenario - -## Troubleshooting and resolution steps - -Check whether the request is expected, if not, please check whether there is a malicious attack source, -If it is expected, please refer to [QoS Security](/en/docs3-v2/java-sdk/reference-manual/qos/overview/#safety) to configure the corresponding permission information . - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/7/_index.md b/content/en/docs3-v2/java-sdk/faq/7/_index.md deleted file mode 100644 index 6f1fd4fd0450..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/7/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "7 - QoS" -linkTitle: "7 - QoS" -weight: 7 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/99/0.md b/content/en/docs3-v2/java-sdk/faq/99/0.md deleted file mode 100644 index 7529e5735908..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/99/0.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -type: docs -title: "99-0 - Internal Unknown Error" -linkTitle: "99-0 - Internal unknown error" -weight: 0 ---- -A unknown error happened inside Dubbo. - -### Possible Reason -Unknown error. - -### Troubleshooting and resolution steps -1. Protect the site. Save the log file, and record as much as possible the situation at the time of the failure. -2. If there are other error code log records before this error code, please check the record of that error code first. -3. Check whether the configuration file is correct. -4. If the error was introduced by modifying the code, try to roll back to the previous version. -5. If nothing is resolved, please make a minimal demo that reproduces the problem as much as possible, and then file an issue to [GitHub Issue Tracker](https://github.com/apache/dubbo/issues). - -### References -[Configuration Manual](/en/docs3-v2/java-sdk/reference-manual/config/properties/) diff --git a/content/en/docs3-v2/java-sdk/faq/99/1.md b/content/en/docs3-v2/java-sdk/faq/99/1.md deleted file mode 100644 index 6073a4af5c8b..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/99/1.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -type: docs -title: "99-1 - Program Interrupted" -linkTitle: "99-1 - Program interrupted" -weight: 1 ---- -Unknown error inside Dubbo. - -### Possible Reason - -The program receives an interrupt notification from the JVM level and is forced to stop blocking and waiting - -### Troubleshooting and resolution steps - -This exception usually occurs when the thread pool is closed or the application is closed. -Please check whether the normal use of the business is affected. If there is no impact, it can be ignored. If there is an impact, please refer to the corresponding troubleshooting manual. -For more troubleshooting ideas, please refer to [99-0](../0/). \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/99/_index.md b/content/en/docs3-v2/java-sdk/faq/99/_index.md deleted file mode 100644 index 06eb93998d84..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/99/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "99 - Unknown" -linkTitle: "99 - Unknown" -weight: 99 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/_index.md b/content/en/docs3-v2/java-sdk/faq/_index.md deleted file mode 100755 index 238089b95528..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/_index.md +++ /dev/null @@ -1,9 +0,0 @@ - ---- -type: docs -title: "FAQ" -linkTitle: "FAQ" -weight: 7 ---- - -The main purpose here is to provide the possible causes and solutions of various error codes in the Java SDK. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/faq/intro.md b/content/en/docs3-v2/java-sdk/faq/intro.md deleted file mode 100644 index 5539e2c6637f..000000000000 --- a/content/en/docs3-v2/java-sdk/faq/intro.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -type: docs -title: "Introduction to Error Code Mechanism" -linkTitle: "Introduction to Error Code Mechanism" -weight: 0 ---- - -## background -The Logger abstraction layer that Dubbo relies on internally provides log output capabilities, but most of the exception logs do not come with troubleshooting instructions, resulting in users being unable to handle the exception after seeing it. - -In order to solve this problem, since Dubbo version 3.1, an error code mechanism has been introduced. It connects the error code FAQ in the official documentation with the logging framework. When the abstract output of the log is abnormal, a link to the official website document corresponding to the output is attached to guide the user to conduct independent investigation. - -## Error code format -`[Cat]-[X]` - -Both spaces are numbers. The first number is the category, and the second number is the specific error code. - -## The format of the prompt display -``` -This may be caused by ..., go to https://dubbo.apache.org/faq/[Cat]/[X] to find instructions. -``` -In addition, supplementary information (ie extendedInformation) can be specified after this sentence. - -## Displayed examples -`[31/07/22 02:43:07:796 CST] main WARN support.AbortPolicyWithReport: [DUBBO] Thread pool is EXHAUSTED! Thread Name: Test, Pool Size: 0 (active: 0, core: 1, max: 1, largest: 0), Task: 0 (completed: 0), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://10.20.130.230:20880!, dubbo version: , current host: 10.20.130.230, error code: 0-1. This may be caused by too much client requesting provider, go to https://dubbo.apache.org/faq/0/1 to find instructions.` - -Users only need to click on the link to find the reason according to the error code. - -## Logger interface support -To ensure compatibility, Dubbo 3.1 builds a new interface `ErrorTypeAwareLogger` based on the original Logger abstraction. It extends the method of warn level as follows: -``` -void warn(String code, String cause, String extendedInformation, String msg); -void warn(String code, String cause, String extendedInformation, String msg, Throwable e); -``` - -Among them, code refers to the error code, cause refers to the Possible Reason (that is, the text followed by caused by...), extendedInformation is used as supplementary information, and is directly attached to the sentence caused by. - -The same extension is done for the error level. - -

\ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/quick-start/_index.md b/content/en/docs3-v2/java-sdk/quick-start/_index.md deleted file mode 100755 index 070e342d1592..000000000000 --- a/content/en/docs3-v2/java-sdk/quick-start/_index.md +++ /dev/null @@ -1,8 +0,0 @@ - ---- -type: docs -title: "Quick Start" -linkTitle: "Quick Start" -weight: 2 -description: "" ---- diff --git a/content/en/docs3-v2/java-sdk/quick-start/api.md b/content/en/docs3-v2/java-sdk/quick-start/api.md deleted file mode 100644 index 43b8cb4c6ee8..000000000000 --- a/content/en/docs3-v2/java-sdk/quick-start/api.md +++ /dev/null @@ -1,343 +0,0 @@ ---- -type: docs -title: "2 - Develop microservice applications based on Dubbo API" -linkTitle: "Develop microservice applications based on Dubbo API" -weight: 2 -description: "This article will demonstrate how to quickly develop microservice applications through Dubbo API based on Dubbo Samples." ---- - -## Target - -Develop Dubbo-based microservices from scratch - -## Difficulty - -Low - -## Environmental requirements - -- System: Windows, Linux, MacOS - -- JDK 8 and above (JDK17 is recommended) - -- Git - -- IntelliJ IDEA (optional) - -- Docker (optional) - -## Hands - -This chapter will teach you how to develop a microservice application from scratch through step-by-step tutorials. - -### 1. Start the registration center - -For a microservice application, the registry is an indispensable component. Only through the registration center, the consumer can successfully discover the address information of the server, and then make a call. - -To make this tutorial easier to use, we provide a simple starter based on the Apache Zookeeper registry. If you need to deploy the registry in a production environment, please refer to [Production Environment Initialization](/) to deploy a highly available registry. - -```bash -Windows: -git clone --depth=1 --branch master git@github.com:apache/dubbo-samples.git -cd dubbo-samples -./mvnw.cmd clean compile exec:java -pl tools/embedded-zookeeper - -Linux / MacOS: -git clone --depth=1 --branch master git@github.com:apache/dubbo-samples.git -cd dubbo-samples -./mvnw clean compile exec:java -pl tools/embedded-zookeeper - -Docker: -docker run --name some-zookeeper --restart always -d zookeeper -``` - -### 2. Initialize the project - -Starting from this section, the project will be built and tested based on IntelliJ IDEA. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-01-31-10-50-33-image.png) - -As shown above, a basic project can be built. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-01-31-15-42-11-image.png) - -After initializing the project, you need to create `org.apache.dubbo.samples.api`, `org.apache.dubbo.samples.client` and `org.apache.dubbo.samples` in the `src/main/java` directory .provider` three packages. - - - -In the future, we will create the corresponding interface under `api`, create the corresponding client subscription service function under `client`, and create the corresponding server implementation and publish service function under `provider`. - - - -The above three packages respectively correspond to the APIs that the application depends on, the modules of the consumer-side application, and the modules of the server-side application. In actual deployment, it needs to be split into three projects, and the common dependency of the consumer and the service is the api module. Starting from simplicity, this tutorial will be developed in the same project to distinguish between multiple startup classes. - - - -### 3. Add Maven dependencies - -After initializing the project, we need to add Dubbo-related maven dependencies first. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-01-31-10-51-06-image.png) - -Edit the `pom.xml` file and add the following configuration. - -```xml - - - org.apache.dubbo - dubbo - 3.2.0-beta.4 - - - - org.apache.curator - curator-x-discovery - 4.3.0 - - - org.apache.zookeeper - zookeeper - 3.8.0 - - - io.netty - netty-handler - - - io.netty - netty-transport-native-epoll - - - - -``` - -In this configuration, the dependencies of dubbo and zookeeper (and the corresponding connector curator) are defined. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-01-31-16-06-15-image.png) - -After adding the above configuration, you can refresh dependencies through IDEA's `Maven - Reload All Maven Projects`. - -### 4. Define service interface - -The service interface is a bridge between the consumer and the server in Dubbo. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-01-31-15-42-43-image.png) - -Create `GreetingsService` interface under `org.apache.dubbo.samples.api`, defined as follows: - -```java -package org.apache.dubbo.samples.api; - -public interface GreetingsService { - - String sayHi(String name); -} -``` - -In `GreetingsService`, the `sayHi` method is defined. Subsequent services published by the server and services subscribed by the consumer are all developed around the `GreetingsService` interface. - -### 5. Define the implementation of the server - -After defining the service interface, you can define the corresponding implementation on the server side. Compared with the consumer side, this part of the implementation is a remote implementation, and there is no relevant information locally. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-01-31-15-43-34-image.png) - -Create `GreetingsServiceImpl` class under `org.apache.dubbo.samples.provider`, defined as follows: - -```java -package org.apache.dubbo.samples.provider; - -import org.apache.dubbo.samples.api.GreetingsService; - -public class GreetingsServiceImpl implements GreetingsService { - @Override - public String sayHi(String name) { - return "hi," + name; - } -} -``` - -In `GreetingsServiceImpl`, implement `GreetingsService` interface, return `hi, name` for `sayHi` method. - - - -### 6. The server publishes the service - - - -After implementing the service, this section will publish the service on the network through Dubbo's API. - - - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-01-31-15-44-22-image.png) - - - -Create `Application` class under `org.apache.dubbo.samples.provider`, defined as follows: - - - -```java -package org.apache.dubbo.samples.provider; - -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.samples.api.GreetingsService; - -public class Application { - public static void main(String[] args) { - // define a specific service - ServiceConfig service = new ServiceConfig<>(); - service.setInterface(GreetingsService.class); - service.setRef(new GreetingsServiceImpl()); - - // start Dubbo - DubboBootstrap. getInstance() - .application("first-dubbo-provider") - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .protocol(new ProtocolConfig("dubbo", -1)) - .service(service) - .start() - .await(); - } -} -``` - - - -In `org.apache.dubbo.samples.provider.Application`, there are two parts of functions: firstly, based on `ServiceConfig`, the published service information is defined, including interface information and corresponding implementation class objects; secondly, Dubbo is configured In the launcher, the application name, registration center address, protocol information, and service information are passed in. - - - -Note: `registry`, `protocol` and `service` in DubboBootstrap can be passed in multiple times. - - - -### 7. The consumer subscribes and calls - - - -For the consumer side, you can subscribe to the consumer side through Dubbo's API. - - - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-01-31-15-55-09-image.png) - - - -Create `Application` class under `org.apache.dubbo.samples.client`, defined as follows: - - - -```java -package org.apache.dubbo.samples.client; - -import java.io.IOException; - -import org.apache.dubbo.config.ReferenceConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.samples.api.GreetingsService; - -public class Application { - public static void main(String[] args) throws IOException { - ReferenceConfig reference = new ReferenceConfig<>(); - reference.setInterface(GreetingsService.class); - - DubboBootstrap. getInstance() - .application("first-dubbo-consumer") - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .reference(reference); - - GreetingsService service = reference. get(); - String message = service.sayHi("dubbo"); - System.out.println("Receive result ======> " + message); - System.in.read(); - } -} -``` - - - -There are three functions in `org.apache.dubbo.samples.client.Application`: - -The first is to define the subscribed service information based on `ReferenceConfig`, including interface information. - -The second is to configure the Dubbo launcher, passing in the application name, registration center address, protocol information, and service information. - -Finally, get the object of the dynamic proxy and call it. - - - -Note: DubboBootstrap supports `service` and `reference` to be passed in at the same time, which means that an application can be both a consumer and a server at the same time. - - - -### 8. Start the application - - - -As of step 7, the code has been developed, and this section will start the entire project and verify it. - - - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-01-31-15-52-26-image.png) - - - -The first thing is to start `org.apache.dubbo.samples.provider.Application`, and wait for a while to see the log (`DubboBootstrap awaiting`) as shown in the figure below, which means that the service provider has started, indicating that the service provider can provide served. - - - -``` log -[DUBBO] DubboBootstrap awaiting ..., dubbo version: 3.2.0-beta.4, current host: 169.254.44.42 -``` - - - -Then start `org.apache.dubbo.samples.client.Application`, and wait for a while to see the log (`hi, dubbo`) as shown in the figure below, which means that the service consumer is started and the call to the server is successfully obtained. - - - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-01-31-15-54-42-image.png) - - - -``` log -Receive result ======> hi, dubbo -``` - - - -## Further reading - - - -### 1. Dubbo configuration introduction - - - -The main configuration entries of Dubbo are `ReferenceConfig`, `ServiceConfig` and `DubboBootstrap`. For more details, please refer to [API Configuration | Apache Dubbo](/en/docs3-v2/java-sdk/reference-manual/config/api /) article. - - - -### 2. In addition to the API method, other usage methods - - - -In addition to the API method, Dubbo also supports configuration methods such as Spring XML, Annotation, and Spring Boot. In the next tutorial, we will explain how to quickly develop with the Spring Boot configuration method. - - - -For details about XML and Annotation, please refer to [XML configuration | Apache Dubbo](/en/docs3-v2/java-sdk/reference-manual/config/xml/), [Annotation configuration | Apache Dubbo](/en/docs3- v2/java-sdk/reference-manual/config/annotation/) doubt. - - - - - -## More - -This tutorial introduces how to develop a microservice application based on Dubbo's pure API. In the next tutorial, we will introduce how to develop microservice projects based on Spring Boot. diff --git a/content/en/docs3-v2/java-sdk/quick-start/brief.md b/content/en/docs3-v2/java-sdk/quick-start/brief.md deleted file mode 100644 index 41d9dedc5d76..000000000000 --- a/content/en/docs3-v2/java-sdk/quick-start/brief.md +++ /dev/null @@ -1,311 +0,0 @@ ---- -type: docs -title: "1 - Rapidly deploy a microservice application" -linkTitle: "Quickly deploy a microservice application" -weight: 1 -description: "This article will demonstrate how to quickly build and deploy a microservice application based on Dubbo Samples." ---- - -## Background - -![arch-service-discovery](/imgs/architecture.png) - -As a microservice framework, Dubbo is most important to provide users with cross-process RPC remote call capabilities. As shown in the figure above, Dubbo's service consumer (Consumer) sends requests to the service provider (Provider) through a series of tasks. - -In order to achieve such a goal, Dubbo introduces the Registry component. Through the Registry, service consumers can perceive the connection method of the service provider, so as to send the request to the correct service provider. - -## Target - -Understand the way of calling microservices and the capabilities of Dubbo - -## Difficulty - -Low - -## Environmental requirements - -- System: Windows, Linux, MacOS - -- JDK 8 and above (JDK17 is recommended) - -- Git - -- Docker (optional) - -## Hands - -This chapter will teach you step by step how to deploy and run the simplest Dubbo use case through a few simple commands. - -### 1. Get the test project - -Before starting the whole tutorial, we need to get the code of the test project. All test case codes of Dubbo are stored in the repository [apache/dubbo-samples](https://github.com/apache/dubbo-samples), the following command can help you get all the codes in the Samples repository. - -```bash -git clone --depth=1 --branch master git@github.com:apache/dubbo-samples.git -``` - -### 2. Understand the project structure of Dubbo Samples - -After the [apache/dubbo-samples](https://github.com/apache/dubbo-samples) warehouse is cloned locally, this section will explain the specific organization of the warehouse. - -``` -. -├── codestyle // style configuration file for development - -├── 1-basic // basic introductory use cases -├── 2-advanced // advanced usage -├── 3-extensions // Example of extension usage -├── 4-governance // service governance use cases -├── 10-task // Example of Dubbo learning series - -├── 99-integration // integration test use -├── test // integration test use -└── tools // three-party component quick start tool -``` - -As shown in the above table, [apache/dubbo-samples](https://github.com/apache/dubbo-samples) mainly consists of three parts: code style file, test code, and integration test. - -1. The code style file can be used when developing Dubbo code, including the configuration file of IntelliJ IDEA. - -2. The test code is the core content required by this textbook. It currently includes 5 parts: basic entry use cases for beginners, advanced advanced usage for developers, extensions Dubbo peripheral extension usage examples for middleware maintainers, governance service governance use cases for production, and Dubbo learning series. This article will explain the simplest way to use Dubbo API based on the basic introductory use case. - -3. Integration testing is an important part of Dubbo's quality assurance system. Each version of Dubbo will perform regression verification on all samples to ensure that all changes in Dubbo will not affect the use of samples. - -### 3. Start a simple registration center - -Starting from this section, a microservice application will be formally deployed through three commands. - -From the [Background](#background) section, we can see that a major prerequisite for running Dubbo applications is to deploy a registry. In order to make this tutorial easier to use, we provide a simple starter based on the Apache Zookeeper registry. If You need to deploy the registration center in the production environment. Please refer to [Production Environment Initialization](/) to deploy a highly available registration center. - -```bash -Windows: -./mvnw.cmd clean compile exec:java -pl tools/embedded-zookeeper - -Linux / MacOS: -./mvnw clean compile exec:java -pl tools/embedded-zookeeper - -Note: You need to open an independent terminal to run, and the command will keep executing. - -Docker: -docker run --name some-zookeeper --restart always -d zookeeper -``` - -After executing the above command, wait for a while for the log as shown in the figure below to appear, which means that the registration center is started, and you can continue to perform subsequent tasks. - -![registry](/imgs/docs3-v2/java-sdk/quickstart/2023-01-19-15-55-23-image.png) - -### 4. Start the service provider - -After starting the registry, the next step is to start a service provider that provides services externally. Corresponding samples are also provided in dubbo-samples, which can be quickly pulled up by the following command. - -```bash -Windows: -./mvnw.cmd clean compile exec:java -pl 1-basic/dubbo-samples-api "-Dexec.mainClass=org.apache.dubbo.samples.provider.Application" - -Linux / MacOS: -./mvnw clean compile exec:java -pl 1-basic/dubbo-samples-api -Dexec.mainClass="org.apache.dubbo.samples.provider.Application" - -Note: You need to open an independent terminal to run, and the command will keep executing. -``` - -After executing the above command, wait for a while for the log (`DubboBootstrap awaiting`) as shown in the figure below to appear, which means that the service provider has started, indicating that the service provider can provide services externally. - -![provider](/imgs/docs3-v2/java-sdk/quickstart/2023-01-19-15-56-09-image.png) - -``` log -[19/01/23 03:55:49:049 CST] org.apache.dubbo.samples.provider.Application.main() INFO bootstrap.DubboBootstrap: [DUBBO] DubboBootstrap awaiting ..., dubbo version: 3.2.0 -beta.3, current host: 169.254.44.42 -``` - -### 5. Start service consumer - -The last step is to start a service consumer to call the service provider, which is the core of the RPC call, providing a bridge for the service consumer to call the service provider. - -```bash -Windows: -./mvnw.cmd clean compile exec:java -pl 1-basic/dubbo-samples-api "-Dexec.mainClass=org.apache.dubbo.samples.client.Application" - -Linux / MacOS: -./mvnw clean compile exec:java -pl 1-basic/dubbo-samples-api -Dexec.mainClass="org.apache.dubbo.samples.client.Application" -``` - -After executing the above command, wait for a while for the log (`hi, dubbo`) to appear as shown in the figure below. The printed data is returned after the service provider processes it, marking the success of a service call. - -![consumer](/imgs/docs3-v2/java-sdk/quickstart/2023-01-19-16-30-14-image.png) - -``` log -Receive result ======> hi, dubbo -``` - -## Further reading - -### 1. How does the consumer find the server? - -In step 3 of this use case, a Zookeeper registration center is started, and the service provider will write its own address into the registration center for service consumers to obtain. - -Dubbo will write the connection information of the service provider under `/dubbo/interfaceName` and `/services/appName` of Zookeeper. - -The following is an example of data on Zookeeper: - -``` -[zk: localhost:2181(CONNECTED) 5] ls /dubbo/org.apache.dubbo.samples.api.GreetingsService/providers -[dubbo%3A%2F%2F30.221.146.35%3A20880%2Forg.apache.dubbo.samples.api.GreetingsService%3Fanyhost%3Dtrue%26application%3Dfirst-dubbo-provider%26background%3Dfalse%26deprecated%3Dfalse%26dubbo%3D2 .0.2%26dynamic%3Dtrue%26environment%3Dproduct%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.samples.api.GreetingsService%26ipv6%3Dfd00%3A1%3A5%3A5200%3A3218%3A774a%3A4f67%3A23ho1% %26pid%3D85639%26release%3D3.1.4%26service-name-mapping%3Dtrue%26side%3Dprovider%26timestamp%3D1674960780647] - -[zk: localhost:2181(CONNECTED) 2] ls /services/first-dubbo-provider -[30.221.146.35:20880] -[zk: localhost:2181(CONNECTED) 3] get /services/first-dubbo-provider/30.221.146.35:20880 -{"name":"first-dubbo-provider","id":"30.221.146.35:20880","address":"30.221.146.35","port":20880,"sslPort":null,"payload" :{"@class":"org.apache.dubbo.registry.zookeeper.ZookeeperInstance","id":"30.221.146.35:20880","name":"first-dubbo-provider","metadata":{ "dubbo.endpoints":"[{\"port\":20880,\"protocol\":\"dubbo\"}]", "dubbo.metadata-service.url-params": "{\"connections\ ":\"1\",\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"3.1.4\", \"side\":\"provider\",\"ipv6\":\"fd00:1:5:5200:3218:774a:4f67:2341\",\"port\":\"20880\", \"protocol\":\"dubbo\"}","dubbo.metadata.revision":"871fbc9cb2730caea9b0d858852d5ede","dubbo.metadata.storage-type":"local","ipv6":"fd00:1:5 :5200:3218:774a:4f67:2341","timestamp":"1674960780647"}},"registrationTimeUTC":1674960781893,"serviceType":"DYNAMIC","uriSpec":null} -``` - -For more details about Dubbo's service discovery model, please refer to [Service Discovery](/zh-cn/overview/mannual/java-sdk/concepts-and-architecture/service-discovery/). - -### 2. How does the consumer initiate the request? - -In Dubbo's invocation model, the bridge that connects service consumers and service providers is the interface. - -The service provider implements the specified interface, and the service consumer subscribes to this interface through Dubbo. When the service consumer calls the interface, Dubbo will encapsulate the request into a network request, and then send it to the service provider for the actual call. - -In this use case, an interface `GreetingsService` is defined, which has a method called `sayHi`. - -```java -// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/api/GreetingsService.java - -package org.apache.dubbo.samples.api; - -public interface GreetingsService { - - String sayHi(String name); - -} -``` - -Service consumers can obtain the proxy of the `GreetingsService` interface through Dubbo's API, and then call it in the normal way of calling the interface. **Thanks to Dubbo's dynamic proxy mechanism, all this is like a local call. ** - -```java -// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/client/Application.java - -// Get the subscribed Stub -GreetingsService service = reference. get(); -// call like a normal java interface -String message = service.sayHi("dubbo"); -``` - -### 3. Can multiple servers be deployed? - -Yes, this section will demonstrate how to start a server-side **cluster**. - -1) To start a registration center, you can refer to the [Tutorial] in Section 3 of the hands-on practice (#3-start a simple registration center) - -2) Modify the data returned by the service provider so that the first started service provider returns `hi, dubbo. I am provider 1.` - -Modify line 25 of `1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java` file as follows. - -```java -// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java - -package org.apache.dubbo.samples.provider; - -import org.apache.dubbo.samples.api.GreetingsService; - -public class GreetingsServiceImpl implements GreetingsService { - @Override - public String sayHi(String name) { - return "hi, " + name + ". I am provider 1."; - } -} -``` - -3) To start the first service provider, you can refer to the [Tutorial] in Section 4 of the hands-on practice (#4-Start the service provider) - -4) Modify the data returned by the service provider so that the second started service provider returns `hi, dubbo. I am provider 2.` - -Modify line 25 of `1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java` file as follows. - -```java -// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java - -package org.apache.dubbo.samples.provider; - -import org.apache.dubbo.samples.api.GreetingsService; - -public class GreetingsServiceImpl implements GreetingsService { - @Override - public String sayHi(String name) { - return "hi, " + name + ". I am provider 2."; - } -} -``` - -4) Start the second service provider, you can refer to the [Tutorial] in Section 4 of the hands-on practice (#4-Start the service provider) - -5) To start the service consumer, you can refer to the [Tutorial] in Section 5 of the hands-on practice (#5-Start the service consumer). If you start the consumer multiple times, you can see that the returned results are different. - -In dubbo-samples, there is also a consumer application `org.apache.dubbo.samples.client.AlwaysApplication` that will initiate calls periodically, which can be started by the following command. - -```bash -Windows: -./mvnw.cmd clean compile exec:java -pl 1-basic/dubbo-samples-api -Dexec.mainClass="org.apache.dubbo.samples.client.AlwaysApplication" - -Linux / MacOS: -./mvnw clean compile exec:java -pl 1-basic/dubbo-samples-api -Dexec.mainClass="org.apache.dubbo.samples.client.AlwaysApplication" -``` - -After startup, you can see a log similar to the following. The consumer will randomly call different service providers, and the returned result is also the result that the remote service provider thinks. - -``` -Sun Jan 29 11:23:37 CST 2023 Receive result ======> hi, dubbo. I am provider 1. -Sun Jan 29 11:23:38 CST 2023 Receive result ======> hi, dubbo. I am provider 2. -Sun Jan 29 11:23:39 CST 2023 Receive result ======> hi, dubbo. I am provider 2. -Sun Jan 29 11:23:40 CST 2023 Receive result ======> hi, dubbo. I am provider 1. -Sun Jan 29 11:23:41 CST 2023 Receive result ======> hi, dubbo. I am provider 1. -``` - -### 4. Is this use case complex? - -No, Dubbo only needs a simple configuration to achieve stable and efficient remote calls. - -The following is a simple example of a service provider that can be started by defining a few configurations. - -```java -// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/Application.java - -// define all services -ServiceConfig service = new ServiceConfig<>(); -service.setInterface(GreetingsService.class); -service.setRef(new GreetingsServiceImpl()); - -// start Dubbo -DubboBootstrap. getInstance() - .application("first-dubbo-provider") - .registry(new RegistryConfig(ZOOKEEPER_ADDRESS)) - .protocol(new ProtocolConfig("dubbo", -1)) - .service(service) - .start(); -``` - -The following is a simple example of a service consumer. After defining several configurations, the corresponding proxy object can be obtained after startup. After that, the user does not need to perceive the complex implementation behind this object at all. **Everything only needs to be the same as the local call. **. - -```java -// 1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/client/Application.java - -// define all subscriptions -ReferenceConfig reference = new ReferenceConfig<>(); -reference.setInterface(GreetingsService.class); - -// start Dubbo -DubboBootstrap. getInstance() - .application("first-dubbo-consumer") - .registry(new RegistryConfig(ZOOKEEPER_ADDRESS)) - .reference(reference) - .start(); - -// Get the subscribed Stub -GreetingsService service = reference. get(); -// call like a normal java interface -String message = service.sayHi("dubbo"); -``` - -## More - -This use case introduces the basic process of an RPC remote call, and simulates a microservice deployment architecture by starting three nodes: the registration center, the service provider, and the service consumer. - -In the next tutorial, we will explain the configurations of service providers and service consumers, and tell you how to build a microservice application from scratch. diff --git a/content/en/docs3-v2/java-sdk/quick-start/idl.md b/content/en/docs3-v2/java-sdk/quick-start/idl.md deleted file mode 100755 index dea1ef72d23c..000000000000 --- a/content/en/docs3-v2/java-sdk/quick-start/idl.md +++ /dev/null @@ -1,233 +0,0 @@ ---- -type: docs -title: "IDL defines cross-language services" -linkTitle: "IDL Defines" -weight: 11 -description: "Demo from zero how to define Dubbo service based on IDL and use Triple protocol" ---- - -Using IDL to define services has better cross-language friendliness. For new users of Dubbo3, we recommend this method. -However, the Triple protocol is not strongly bound to IDL. You can also use Java Interface + Pojo to define services and enable the Triple protocol. For details, see [Example](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/pojo). - -For more usage of Triple and IDL, please refer to [official samples](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple) - -### precondition -- [JDK](https://jdk.java.net/) version >= 8 -- Installed [Maven](https://maven.apache.org/) - -### Create project -1. First create an empty maven project - ``` - $ mvn archetype:generate \ - -DgroupId=org.apache.dubbo \ - -DartifactId=tri-stub-demo \ - -DarchetypeArtifactId=maven-archetype-quickstart \ - -DarchetypeVersion=1.4 \ - -DarchetypeGroupId=org.apache.maven.archetypes \ - -Dversion=1.0-SNAPSHOT - ``` -2. Switch to the project directory - ``` - $ cd tri-stub-demo - ``` -3. Set JDK version in `pom.xml`, add Dubbo dependencies and plugins - ```xml - - UTF-8 - 1.8 - 1.8 - 3.1.7 - - - - - junit - junit - 4.13 - test - - - org.apache.dubbo - dubbo - ${dubbo.version} - - - org.apache.dubbo - dubbo-dependencies-zookeeper-curator5 - pom - ${dubbo.version} - - - com.google.protobuf - protobuf-java - 3.19.4 - - - - - - - kr.motd.maven - os-maven-plugin - 1.6.1 - - - - - org.xolstice.maven.plugins - protobuf-maven-plugin - 0.6.1 - - com.google.protobuf:protoc:3.19.4:exe:${os.detected.classifier} - - - dubbo - org.apache.dubbo - dubbo-compiler - ${dubbo.version} - org.apache.dubbo.gen.tri.Dubbo3TripleGenerator - - - - - - - compile - - - - - - - ``` -4. Add the interface definition file `src/main/proto/hello.proto`, Dubbo uses [Protobuf](https://developers.google.com/protocol-buffers) as IDL - ```protobuf - syntax = "proto3"; - - option java_multiple_files = true; - option java_package = "org.apache.dubbo.hello"; - option java_outer_classname = "HelloWorldProto"; - option objc_class_prefix = "HLW"; - - package helloworld; - - message HelloRequest { - string name = 1; - } - - message HelloReply { - string message = 1; - } - service Greeter{ - rpc greet(HelloRequest) returns (HelloReply); - } - - ``` -5. Compile the IDL - ``` - $ mvn clean install - ``` - After the compilation is successful, you can see that the code file is generated in the `target/generated-sources/protobuf/java` directory - ``` - $ ls org/apache/dubbo/hello/ - DubboGreeterTriple.java HelloReply.java HelloRequest.java HelloWorldProto.java - Greeter.java HelloReplyOrBuilder.java HelloRequestOrBuilder.java - ``` - -6. Add server interface implementation `src/main/java/org/apache/dubbo/GreeterImpl.java` - ```java - package org.apache.dubbo; - - import org.apache.dubbo.hello.DubboGreeterTriple; - import org.apache.dubbo.hello.HelloReply; - import org.apache.dubbo.hello.HelloRequest; - - public class GreeterImpl extends DubboGreeterTriple. GreeterImplBase { - @Override - public HelloReply greet(HelloRequest request) { - return HelloReply.newBuilder() - .setMessage("Hello," + request.getName() + "!") - .build(); - } - } - ``` -7. Add server startup class `src/main/java/org/apache/dubbo/MyDubboServer.java` - ```java - package org.apache.dubbo; - - import org.apache.dubbo.common.constants.CommonConstants; - import org.apache.dubbo.config.ApplicationConfig; - import org.apache.dubbo.config.ProtocolConfig; - import org.apache.dubbo.config.RegistryConfig; - import org.apache.dubbo.config.ServiceConfig; - import org.apache.dubbo.config.bootstrap.DubboBootstrap; - import org.apache.dubbo.hello.Greeter; - - import java.io.IOException; - - public class MyDubboServer { - - public static void main(String[] args) throws IOException { - ServiceConfig service = new ServiceConfig<>(); - service.setInterface(Greeter.class); - service.setRef(new GreeterImpl()); - - DubboBootstrap bootstrap = DubboBootstrap.getInstance(); - bootstrap.application(new ApplicationConfig("tri-stub-server")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051)) - .service(service) - .start(); - System.out.println("Dubbo triple stub server started"); - System.in.read(); - } - } - ``` - -8. Add the client startup class `src/main/java/org/apache/dubbo/MyDubboClient.java` - ```java - package org.apache.dubbo; - - import org.apache.dubbo.common.constants.CommonConstants; - import org.apache.dubbo.config.ApplicationConfig; - import org.apache.dubbo.config.ReferenceConfig; - import org.apache.dubbo.config.RegistryConfig; - import org.apache.dubbo.config.bootstrap.DubboBootstrap; - import org.apache.dubbo.hello.Greeter; - import org.apache.dubbo.hello.HelloReply; - import org.apache.dubbo.hello.HelloRequest; - - public class MyDubboClient { - public static void main(String[] args) { - DubboBootstrap bootstrap = DubboBootstrap.getInstance(); - ReferenceConfig ref = new ReferenceConfig<>(); - ref.setInterface(Greeter.class); - ref.setProtocol(CommonConstants.TRIPLE); - ref.setProxy(CommonConstants.NATIVE_STUB); - ref.setTimeout(3000); - bootstrap.application(new ApplicationConfig("tri-stub-client")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .reference(ref) - .start(); - - Greeter greeter = ref.get(); - HelloRequest request = HelloRequest.newBuilder().setName("Demo").build(); - HelloReply reply = greeter.greet(request); - System.out.println("Received reply:" + reply); - } - } - ``` -9. Compile the code - ``` - $ mvn clean install - ``` -10. Start the server - ``` - $ mvn org.codehaus.mojo:exec-maven-plugin:3.0.0:java -Dexec.mainClass="org.apache.dubbo.MyDubboServer" - Dubbo triple stub server started - ``` -11. Open a new terminal and start the client - ``` - $ mvn org.codehaus.mojo:exec-maven-plugin:3.0.0:java -Dexec.mainClass="org.apache.dubbo.MyDubboClient" - Received reply: message: "Hello, Demo!" - ``` diff --git a/content/en/docs3-v2/java-sdk/quick-start/spring-boot.md b/content/en/docs3-v2/java-sdk/quick-start/spring-boot.md deleted file mode 100644 index c7c2c9cbc06b..000000000000 --- a/content/en/docs3-v2/java-sdk/quick-start/spring-boot.md +++ /dev/null @@ -1,643 +0,0 @@ ---- -type: docs -title: "3 - Dubbo x Spring Boot to develop microservice applications" -linkTitle: "Dubbo x Spring Boot to develop microservice applications" -weight: 3 -description: "This article will demonstrate how to quickly develop microservice applications through Dubbo x Spring Boot based on Dubbo Samples." ---- - -## Target - -Start from scratch to develop microservices based on Dubbo x Spring Boot, and understand the configuration method of Dubbo x Spring Boot. - -## Difficulty - -Low - -## Environmental requirements - -- System: Windows, Linux, MacOS - -- JDK 8 and above (JDK17 is recommended) - -- Git - -- IntelliJ IDEA (optional) - -- Docker (optional) - -## Project Introduction - -In this task, it will be divided into three sub-modules for independent development, simulating the deployment architecture in the production environment. - - - -``` -.//apache/dubbo-samples/1-basic/dubbo-samples-spring-boot -├── dubbo-samples-spring-boot-interface // shared API module -├── dubbo-samples-spring-boot-consumer // consumer module -└── dubbo-samples-spring-boot-provider // server module -``` - - - -As shown above, there are 3 modules in total, among which the `interface` module is jointly dependent by the `consumer` and `provider` modules, and stores the API interface used by RPC communication. - - - -``` -.//apache/dubbo-samples/1-basic/dubbo-samples-spring-boot -├── dubbo-samples-spring-boot-interface // shared API module -│ ├── pom.xml -│ └── src -│ └── main -│ └── java -│ └── org -│ └── apache -│ └── dubbo -│ └── springboot -│ └── demo -│ └── DemoService.java // API interface -├── dubbo-samples-spring-boot-consumer // consumer module -│ ├── pom.xml -│ └── src -│ ├── main -│ │ ├── java -│ │ │ └── org -│ │ │ └── apache -│ │ │ └── dubbo -│ │ │ └── springboot -│ │ │ └── demo -│ │ │ └── consumer -│ │ │ ├── ConsumerApplication.java // consumer startup class -│ │ │ └── Task.java // The consumer simulates calling tasks -│ │ └── resources -│ │ └── application.yml // Spring Boot configuration file -├── dubbo-samples-spring-boot-provider // server module -│ ├── pom.xml -│ └── src -│ └── main -│ ├── java -│ │ └── org -│ │ └── apache -│ │ └── dubbo -│ │ └── springboot -│ │ └── demo -│ │ └── provider -│ │ ├── DemoServiceImpl.java // server implementation class -│ │ └── ProviderApplication.java // server startup class -│ └── resources -│ └── application.yml // Spring Boot configuration file -└── pom.xml -``` - - - -The above is the file structure of the project that will be used in this tutorial. - - - -## Rapid deployment (directly started based on Samples) - -This chapter will teach you step by step how to deploy and run a Dubbo x Spring Boot-based use case through a few simple commands. - -Note: The details of the code deployed in this chapter can be found in `1-basic/dubbo-samples-spring-boot` in the repository of [apache/dubbo-samples](https://github.com/apache/dubbo-samples), It will also be explained in the next chapter. - -### 1. Get the test project - -Before starting the whole tutorial, we need to get the code of the test project. All test case codes of Dubbo are stored in the repository [apache/dubbo-samples](https://github.com/apache/dubbo-samples), the following command can help you get all the codes in the Samples repository. - -```bash -git clone --depth=1 --branch master git@github.com:apache/dubbo-samples.git -``` - -### 2. Start a simple registration center - -For a microservice application, the registry is an indispensable component. Only through the registration center, the consumer can successfully discover the address information of the server, and then make a call. - -To make this tutorial easier to use, we provide a simple starter based on the Apache Zookeeper registry. If you need to deploy the registry in a production environment, please refer to [Production Environment Initialization](/) to deploy a highly available registry. - -```bash -Windows: -./mvnw.cmd clean compile exec:java -pl tools/embedded-zookeeper - -Linux / MacOS: -./mvnw clean compile exec:java -pl tools/embedded-zookeeper - -Docker: -docker run --name some-zookeeper -p 2181:2181 --restart always -d zookeeper -``` - - - -### 3. Local packaging API module - -In order to successfully compile the server and consumer modules, you need to package and install the `dubbo-samples-spring-boot-interface` module locally first. - -```bash -./mvnw clean install -pl 1-basic/dubbo-samples-spring-boot -./mvnw clean install -pl 1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-interface -``` - - - -### 4. Start the service provider - -After starting the registry, the next step is to start a service provider that provides services externally. Corresponding samples are also provided in dubbo-samples, which can be quickly pulled up by the following command. - -```bash -Windows: -./mvnw.cmd clean compile exec:java -pl 1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-provider "-Dexec.mainClass=org.apache.dubbo.springboot.demo.provider.ProviderApplication" - -Linux / MacOS: -./mvnw clean compile exec:java -pl 1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-provider -Dexec.mainClass="org.apache.dubbo.springboot.demo.provider.ProviderApplication" - -Note: You need to open an independent terminal to run, and the command will keep executing. -``` - -After executing the above command, wait for a while for the following log to appear (`Current Spring Boot Application is await`), which means that the service provider has started, indicating that the service provider can provide services externally. - -``` log -2023-02-08 17:13:00.357 INFO 80600 --- [lication.main()] o.a.d.c.d.DefaultApplicationDeployer : [DUBBO] Dubbo Application[1.1](dubbo-springboot-demo-provider) is ready., dubbo version: 3.2 .0-beta.4, current host: 30.221.128.96 -2023-02-08 17:13:00.369 INFO 80600 --- [lication.main()] o.a.d.s.d.provider.ProviderApplication : Started ProviderApplication in 9.114 seconds (JVM running for 26.522) -2023-02-08 17:13:00.387 INFO 80600 --- [pool-1-thread-1].b.c.e.AwaitingNonWebApplicationListener : [Dubbo] Current Spring Boot Application is await... -``` - -### 5. Start service consumer - -The last step is to start a service consumer to call the service provider, which is the core of the RPC call, providing a bridge for the service consumer to call the service provider. - -```bash -Windows: -./mvnw.cmd clean compile exec:java -pl 1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-consumer "-Dexec.mainClass=org.apache.dubbo.springboot.demo.consumer.ConsumerApplication" - -Linux / MacOS: -./mvnw clean compile exec:java -pl 1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-consumer -Dexec.mainClass="org.apache.dubbo.springboot.demo.consumer.ConsumerApplication" - - -``` - - - -After executing the above command, wait for a while for the following log (`Hello world`) to appear. The printed data is returned after the service provider processes it, marking the success of a service call. - - - -``` log -2023-02-08 17:14:33.045 INFO 80740 --- [lication.main()] o.a.d.s.d.consumer.ConsumerApplication : Started ConsumerApplication in 11.052 seconds (JVM running for 31.62) -Receive result ======> Hello world -2023-02-08 17:14:33.146 INFO 80740 --- [pool-1-thread-1].b.c.e.AwaitingNonWebApplicationListener : [Dubbo] Current Spring Boot Application is await... -Wed Feb 08 17:14:34 CST 2023 Receive result ======> Hello world -Wed Feb 08 17:14:35 CST 2023 Receive result ======> Hello world -Wed Feb 08 17:14:36 CST 2023 Receive result ======> Hello world -Wed Feb 08 17:14:37 CST 2023 Receive result ======> Hello world -``` - - - -## Hands-on practice (from zero code development version) - -This chapter will teach you how to develop a microservice application from scratch through step-by-step tutorials. - - - -### 1. Start the registration center - -For a microservice application, the registry is an indispensable component. Only through the registration center, the consumer can successfully discover the address information of the server, and then make a call. - -To make this tutorial easier to use, we provide a simple starter based on the Apache Zookeeper registry. If you need to deploy the registry in a production environment, please refer to [Production Environment Initialization](/) to deploy a highly available registry. - -```bash -Windows: -git clone --depth=1 --branch master git@github.com:apache/dubbo-samples.git -cd dubbo-samples -./mvnw.cmd clean compile exec:java -pl tools/embedded-zookeeper - -Linux / MacOS: -git clone --depth=1 --branch master git@github.com:apache/dubbo-samples.git -cd dubbo-samples -./mvnw clean compile exec:java -pl tools/embedded-zookeeper - -Docker: -docker run --name some-zookeeper -p 2181:2181 --restart always -d zookeeper -``` - -### 2. Initialize the project - -Starting from this section, the project will be built and tested based on IntelliJ IDEA. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-17-25-27-image.png) - -As shown above, a basic project can be built. - - - -After building the basic project, we need to create three submodules `dubbo-spring-boot-demo-interface`, `dubbo-spring-boot-demo-provider` and `dubbo-spring-boot-demo-consumer`. - - - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-17-27-17-image.png) - - - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-17-26-57-image.png) - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-17-27-45-image.png) - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-17-28-26-image.png) - - - -After creating the three submodules, you need to create the following folders: - -1. Create `org.apache.dubbo.springboot.demo.consumer` package under `dubbo-spring-boot-demo-consumer/src/main/java` - -2. Create `org.apache.dubbo.springboot.demo` package under `dubbo-spring-boot-demo-interface/src/main/java` - -3. Create `org.apache.dubbo.springboot.demo.provider` package under `dubbo-spring-boot-demo-provider/src/main/java` - - - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-17-32-50-image.png) - - - -The final folder reference is shown in the image above. - - - -### 3. Add Maven dependencies - - - -After initializing the project, we need to add Dubbo-related maven dependencies first. - - - -For multi-module projects, you first need to configure dependency information in `pom.xml` of the parent project. - - - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-17-53-18-image.png) - - - -Edit the `./pom.xml` file and add the following configuration. - - - -```xml - - 3.2.0-beta.4 - 2.7.8 - 17 - 17 - UTF-8 - - - - - - - org.springframework.boot - spring-boot-dependencies - ${spring-boot.version} - pom - import - - - - - org.apache.dubbo - dubbo-bom - ${dubbo.version} - pom - import - - - - org.apache.dubbo - dubbo-dependencies-zookeeper-curator5 - ${dubbo.version} - pom - - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot.version} - - - - -``` - - - -Then configure specific dependencies in the two modules `pom.xml` of `dubbo-spring-boot-consumer` and `dubbo-spring-boot-provider`. - - - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-17-52-53-image.png) - - - -Edit `./dubbo-spring-boot-consumer/pom.xml` and `./dubbo-spring-boot-provider/pom.xml` and add the following configurations. - - - -```xml - - - org.apache.dubbo - dubbo-samples-spring-boot-interface - ${project.parent.version} - - - - - org.apache.dubbo - dubbo-spring-boot-starter - - - org.apache.dubbo - dubbo-dependencies-zookeeper-curator5 - pom - - - slf4j-reload4j - org.slf4j - - - - - - - org.springframework.boot - spring-boot-starter - - - -``` - - - -In this configuration, the dependencies of dubbo and zookeeper (and the corresponding connector curator) are defined. - -After adding the above configuration, you can refresh dependencies through IDEA's `Maven - Reload All Maven Projects`. - - - -### 4. Define service interface - -The service interface is a bridge between the consumer and the server in Dubbo. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-17-57-29-image.png) - -Create `DemoService` interface under `org.apache.dubbo.samples.api` of `dubbo-spring-boot-demo-interface` module, defined as follows: - -```java -package org.apache.dubbo.springboot.demo; - -public interface DemoService { - - String sayHello(String name); -} -``` - -In `DemoService`, the `sayHello` method is defined. Subsequent services published by the server and services subscribed by the consumer are all developed around the `DemoService` interface. - - - -### 5. Define the implementation of the server - -After defining the service interface, you can define the corresponding implementation on the server side. Compared with the consumer side, this part of the implementation is a remote implementation, and there is no relevant information locally. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-17-59-46-image.png) - -Create `DemoServiceImpl` class under `org.apache.dubbo.samples.provider` of `dubbo-spring-boot-demo-provider` module, defined as follows: - - - -```java -package org.apache.dubbo.springboot.demo.provider; - -import org.apache.dubbo.config.annotation.DubboService; -import org.apache.dubbo.springboot.demo.DemoService; - -@DubboService -public class DemoServiceImpl implements DemoService { - - @Override - public String sayHello(String name) { - return "Hello " + name; - } -} -``` - -In `DemoServiceImpl`, implement `DemoService` interface, return `Hello name` for `sayHello` method. - - - -Note: The `@DubboService` annotation is added to the `DemoServiceImpl` class. Through this configuration, the Dubbo service can be published based on Spring Boot. - - - -### 6. Configure the server-side Yaml configuration file - -From this step to step 7, some basic information of Dubbo will be configured through Spring Boot. - - - -First, let's create a configuration file for the server. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-18-00-24-image.png) - -Create `application.yml` file under `resources` resource folder of `dubbo-spring-boot-demo-provider` module, defined as follows: - -```yaml -dubbo: - application: - name: dubbo-springboot-demo-provider - protocol: - name: dubbo - port: -1 - registry: - address: zookeeper://${zookeeper.address:127.0.0.1}:2181 -``` - -In this configuration file, the Dubbo application name, Dubbo protocol information, and the registration center address used by Dubbo are defined. - - - -### 7. Configure the consumer Yaml configuration file - -Similarly, we need to create a configuration file for the consumer. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-18-01-03-image.png) - -Create `application.yml` file under `resources` resource folder of `dubbo-spring-boot-demo-consumer` module, defined as follows: - -```yaml -dubbo: - application: - name: dubbo-springboot-demo-consumer - protocol: - name: dubbo - port: -1 - registry: - address: zookeeper://${zookeeper.address:127.0.0.1}:2181 -``` - -In this configuration file, the Dubbo application name, Dubbo protocol information, and the registration center address used by Dubbo are defined. - - - -### 8. Configure the server startup class based on Spring - -In addition to configuring the Yaml configuration file, we also need to create a Spring Boot-based startup class. - -First of all, we first create the startup class of the server. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-18-01-38-image.png) - -Create `Application` class under `org.apache.dubbo.springboot.demo.provider` of `dubbo-spring-boot-demo-provider` module, defined as follows: - -```java -package org.apache.dubbo.springboot.demo.provider; - -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableDubbo -public class ProviderApplication { - public static void main(String[] args) { - SpringApplication.run(ProviderApplication.class, args); - } -} - -``` - -In this startup class, a `ProviderApplication` is configured to read the `application.yml` configuration file defined in step 6 above and start the application. - - - -### 9. Configure consumer startup classes based on Spring - -Similarly, we need to create a startup class for the consumer. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-18-02-11-image.png) - -Create `Application` class under `org.apache.dubbo.springboot.demo.consumer` of `dubbo-spring-boot-demo-consumer` module, defined as follows: - -```java -package org.apache.dubbo.springboot.demo.consumer; - -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableDubbo -public class ConsumerApplication { - - public static void main(String[] args) { - SpringApplication.run(ConsumerApplication.class, args); - } -} - -``` - -In this startup class, a `ConsumerApplication` is configured to read the `application.yml` configuration file defined in step 7 above and start the application. - - - -### 10. Configure consumer request tasks - -In addition to configuring the startup class of the consumer side, we can also create it based on `CommandLineRunner` in Spring Boot mode - - - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-18-02-33-image.png) - -Create a `Task` class under `org.apache.dubbo.springboot.demo.consumer` of `dubbo-spring-boot-demo-consumer` module, defined as follows: - -```java -package org.apache.dubbo.springboot.demo.consumer; - -import java.util.Date; - -import org.apache.dubbo.config.annotation.DubboReference; -import org.apache.dubbo.springboot.demo.DemoService; -import org.springframework.boot.CommandLineRunner; -import org.springframework.stereotype.Component; - -@Component -public class Task implements CommandLineRunner { - @DubboReference - private DemoService demoService; - - @Override - public void run(String... args) throws Exception { - String result = demoService. sayHello("world"); - System.out.println("Receive result ======> " + result); - - new Thread(()-> { - while (true) { - try { - Thread. sleep(1000); - System.out.println(new Date() + " Receive result ======> " + demoService.sayHello("world")); - } catch (InterruptedException e) { - e.printStackTrace(); - Thread. currentThread(). interrupt(); - } - } - }).start(); - } -} - -``` - - - -In the `Task` class, an RPC subscription is obtained from Dubbo through `@DubboReference`, and this `demoService` can be called directly like a local call. A thread is created for the call in the `run` method. - - - -### 11. Start the application - -As of step 10, the code has been developed, and this section will start the entire project and verify it. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-18-03-59-image.png) - -The first is to start `org.apache.dubbo.samples.provider.Application`, wait for a while to appear the log as shown in the figure below (`Current Spring Boot Application is await`), which means that the service provider has started, marking that the service provides can provide services externally. - -``` log -[Dubbo] Current Spring Boot Application is await... -``` - -Then start `org.apache.dubbo.samples.client.Application`, and wait for a while to see the log (`Hello world`) as shown in the figure below, which means that the service consumer is started and the call to the server is successfully obtained. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-18-05-02-image.png) - -``` log -Receive result ======> Hello world -``` - -## Further reading - -### 1. Dubbo's Spring configuration introduction - -The main configuration entries of Dubbo include yaml configuration content, `@DubboReference` and `@DubboService`, etc. For more details, please refer to [Annotation Configuration | Apache Dubbo](/zh-cn/overview/mannual/java-sdk/reference-manual /config/annotation/) article. - -## More - -This tutorial introduces how to develop a microservice application based on Dubbo x Spring Boot. In the next section, another Dubbo configuration method - Dubbo x Spring XML will be introduced. diff --git a/content/en/docs3-v2/java-sdk/quick-start/spring-xml.md b/content/en/docs3-v2/java-sdk/quick-start/spring-xml.md deleted file mode 100644 index 1228a421bdb0..000000000000 --- a/content/en/docs3-v2/java-sdk/quick-start/spring-xml.md +++ /dev/null @@ -1,393 +0,0 @@ ---- -type: docs -title: "4 - Dubbo x Spring XML to develop microservice applications" -linkTitle: "Dubbo x Spring XML to develop microservice applications" -weight: 4 -description: "This article will demonstrate how to quickly develop microservice applications through Dubbo x Spring XML based on Dubbo Samples." ---- - -## Target - -Develop Dubbo x Spring XML-based microservice development from scratch, and understand the Dubbo x Spring XML configuration method. - -## Difficulty - -Low - -## Environmental requirements - -- System: Windows, Linux, MacOS - -- JDK 8 and above (JDK17 is recommended) - -- Git - -- IntelliJ IDEA (optional) - -- Docker (optional) - -## Rapid deployment (directly started based on Samples) - -This chapter will teach you step by step how to deploy and run a Dubbo x Spring XML-based use case through a few simple commands. - -Note: The details of the code deployed in this chapter can be found in `1-basic/dubbo-samples-spring-xml` in the repository of [apache/dubbo-samples](https://github.com/apache/dubbo-samples), It will also be explained in the next chapter. - -### 1. Get the test project - -Before starting the whole tutorial, we need to get the code of the test project. All test case codes of Dubbo are stored in the repository [apache/dubbo-samples](https://github.com/apache/dubbo-samples), the following command can help you get all the codes in the Samples repository. - -```bash -git clone --depth=1 --branch master git@github.com:apache/dubbo-samples.git -``` - -### 2. Start a simple registration center - -For a microservice application, the registry is an indispensable component. Only through the registration center, the consumer can successfully discover the address information of the server, and then make a call. - -To make this tutorial easier to use, we provide a simple starter based on the Apache Zookeeper registry. If you need to deploy the registry in a production environment, please refer to [Production Environment Initialization](/) to deploy a highly available registry. - -```bash -Windows: -./mvnw.cmd clean compile exec:java -pl tools/embedded-zookeeper - -Linux / MacOS: -./mvnw clean compile exec:java -pl tools/embedded-zookeeper - -Docker: -docker run --name some-zookeeper -p 2181:2181 --restart always -d zookeeper -``` - -### 3. Start the service provider - -After starting the registry, the next step is to start a service provider that provides services externally. Corresponding samples are also provided in dubbo-samples, which can be quickly pulled up by the following command. - -```bash -Windows: -./mvnw.cmd clean compile exec:java -pl 1-basic/dubbo-samples-spring-xml "-Dexec.mainClass=org.apache.dubbo.samples.provider.Application" - -Linux / MacOS: -./mvnw clean compile exec:java -pl 1-basic/dubbo-samples-spring-xml -Dexec.mainClass="org.apache.dubbo.samples.provider.Application" - -Note: You need to open an independent terminal to run, and the command will keep executing. -``` - -After executing the above command, wait for a while for the following log to appear (`Dubbo Application[1.1](demo-provider) is ready.`), which means that the service provider has started, indicating that the service provider can provide served. - -``` log -[08/02/23 03:26:52:052 CST] org.apache.dubbo.samples.provider.Application.main() INFO metadata.ConfigurableMetadataServiceExporter: [DUBBO] The MetadataService exports urls : [dubbo://30.221. 128.96:20880/org.apache.dubbo.metadata.MetadataService?anyhost=true&application=demo-provider&background=false&bind.ip=30.221.128.96&bind.port=20880&connections=1&corethreads=2&delay=true0&deprecated=false&dubbo=10ync=0genic=0genic=0&exeted =false&getAndListenInstanceMetadata.1.callback=true&getAndListenInstanceMetadata.return=true&getAndListenInstanceMetadata.sent=true&group=demo-provider&interface=org.apache.dubbo.metadata.MetadataService&ipv6=fd00:1:5:5200:4d53:9f5:a545:804d&methods=exportInstanceMetadata,getAndListenInstanceMetadata , getExportedServiceURLs, getExportedURLs, getExportedURLs, getExportedURLs, getExportedURLs, getExportedURLs, getInstanceMetadataChangedListenerMap, getMetadataInfo, getMetadataInfos, getMetadataURL, getServiceDefinition, getServiceDefinition, getSubscribedURLs, isMetadata aService,serviceName,toSortedStrings,toSortedStrings,version&pid=70803®ister=false&release=3.1.6&revision=3.1.6&side=provider&threadpool=cached&threads=100×tamp=1675841212727&version=1.0.0], dubbo version: 3.1.23host: 6 -[08/02/23 03:26:52:052 CST] org.apache.dubbo.samples.provider.Application.main() INFO metadata.ServiceInstanceMetadataUtils: [DUBBO] Start registering instance address to registry., dubbo version: 3.1 .6, current host: 30.221.128.96 -[08/02/23 03:26:52:052 CST] org.apache.dubbo.samples.provider.Application.main() INFO metadata.MetadataInfo: [DUBBO] metadata revision changed: null -> 602d44cc6d653b9cd42ab23c3948b5ab, app: demo -provider, services: 1, dubbo version: 3.1.6, current host: 30.221.128.96 -[08/02/23 03:26:52:052 CST] org.apache.dubbo.samples.provider.Application.main() INFO deploy.DefaultApplicationDeployer: [DUBBO] Dubbo Application[1.1](demo-provider) is ready ., dubbo version: 3.1.6, current host: 30.221.128.96 -``` - -### 4. Start service consumer - -The last step is to start a service consumer to call the service provider, which is the core of the RPC call, providing a bridge for the service consumer to call the service provider. - -```bash -Windows: -./mvnw.cmd clean compile exec:java -pl 1-basic/dubbo-samples-spring-xml "-Dexec.mainClass=org.apache.dubbo.samples.client.Application" - -Linux / MacOS: -./mvnw clean compile exec:java -pl 1-basic/dubbo-samples-spring-xml -Dexec.mainClass="org.apache.dubbo.samples.client.Application" -``` - -After executing the above command, wait for a while for the following log (`hi, dubbo`) to appear. The printed data is returned by the service provider after processing, marking the success of a service call. - -``` log -[08/02/23 03:28:23:023 CST] org.apache.dubbo.samples.client.Application.main() INFO deploy.DefaultApplicationDeployer: [DUBBO] Dubbo Application[1.1](demo-consumer) is ready ., dubbo version: 3.1.6, current host: 30.221.128.96 -Receive result ======> hi, dubbo -``` - -## Hands-on practice (from zero code development version) - -This chapter will teach you how to develop a microservice application from scratch through step-by-step tutorials. - -### 1. Start the registration center - -For a microservice application, the registry is an indispensable component. Only through the registration center, the consumer can successfully discover the address information of the server, and then make a call. - -To make this tutorial easier to use, we provide a simple starter based on the Apache Zookeeper registry. If you need to deploy the registry in a production environment, please refer to [Production Environment Initialization](/) to deploy a highly available registry. - -```bash -Windows: -git clone --depth=1 --branch master git@github.com:apache/dubbo-samples.git -cd dubbo-samples -./mvnw.cmd clean compile exec:java -pl tools/embedded-zookeeper - -Linux / MacOS: -git clone --depth=1 --branch master git@github.com:apache/dubbo-samples.git -cd dubbo-samples -./mvnw clean compile exec:java -pl tools/embedded-zookeeper - -Docker: -docker run --name some-zookeeper -p 2181:2181 --restart always -d zookeeper -``` - -### 2. Initialize the project - -Starting from this section, the project will be built and tested based on IntelliJ IDEA. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-15-32-16-image.png) - -As shown above, a basic project can be built. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-15-33-20-image.png) - -After initializing the project, you need to create `org.apache.dubbo.samples.api`, `org.apache.dubbo.samples.client` and `org.apache.dubbo.samples` in the `src/main/java` directory .provider` three packages. - -In the future, we will create the corresponding interface under `api`, create the corresponding client subscription service function under `client`, and create the corresponding server implementation and publish service function under `provider`. - -The above three packages respectively correspond to the APIs that the application depends on, the modules of the consumer-side application, and the modules of the server-side application. In actual deployment, it needs to be split into three projects, and the common dependency of the consumer and the service is the api module. Starting from simplicity, this tutorial will be developed in the same project to distinguish between multiple startup classes. - -### 3. Add Maven dependencies - -After initializing the project, we need to add Dubbo-related maven dependencies first. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-15-36-57-image.png) - -Edit the `pom.xml` file and add the following configuration. - -```xml - - - org.apache.dubbo - dubbo - 3.1.6 - - - - org.springframework - spring-context - 5.3.25 - - - - org.apache.curator - curator-x-discovery - 5.2.0 - - - org.apache.zookeeper - zookeeper - 3.8.0 - - -``` - -In this configuration, the dependencies of dubbo and zookeeper (and the corresponding connector curator) are defined. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-15-36-31-image.png) - -After adding the above configuration, you can refresh dependencies through IDEA's `Maven - Reload All Maven Projects`. - -### 4. Define service interface - -The service interface is a bridge between the consumer and the server in Dubbo. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-15-37-31-image.png) - -Create `GreetingsService` interface under `org.apache.dubbo.samples.api`, defined as follows: - -```java -package org.apache.dubbo.samples.api; - -public interface GreetingsService { - - String sayHi(String name); -} -``` - -In `GreetingsService`, the `sayHi` method is defined. Subsequent services published by the server and services subscribed by the consumer are all developed around the `GreetingsService` interface. - -### 5. Define the implementation of the server - -After defining the service interface, you can define the corresponding implementation on the server side. Compared with the consumer side, this part of the implementation is a remote implementation, and there is no relevant information locally. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-15-38-04-image.png) - -Create `GreetingsServiceImpl` class under `org.apache.dubbo.samples.provider`, defined as follows: - -```java -package org.apache.dubbo.samples.provider; - -import org.apache.dubbo.samples.api.GreetingsService; - -public class GreetingsServiceImpl implements GreetingsService { - @Override - public String sayHi(String name) { - return "hi," + name; - } -} -``` - -In `GreetingsServiceImpl`, implement `GreetingsService` interface, return `hi, name` for `sayHi` method. - -### 6. Configure server-side XML configuration file - -From this step to step 7, the information of Dubbo service will be configured through Spring XML. - -First, let's create a configuration file for the server. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-15-40-07-image.png) - -Create a `dubbo-demo-provider.xml` file under the `resources` resource folder, defined as follows: - -```xml - - - - - - - - - - - - - - - - -``` - -In this configuration file, the application name of Dubbo, the address of the registration center used by Dubbo, the spring bean for publishing the service, and the bean to be published through Dubbo are defined. - -### 7. Configure the consumer XML configuration file - -Similarly, we need to create a configuration file for the consumer. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-15-40-59-image.png) - -Create a `dubbo-demo-consumer.xml` file under the `resources` resource folder, defined as follows: - -```xml - - - - - - - - - - - - - - - -``` - -In this configuration file, the Dubbo application name, the registry address used by Dubbo, and the subscribed service information are defined. - -### 8. Configure the server startup class based on Spring - -In addition to configuring the XML configuration file, we also need to create a Spring Context-based startup class. - -First of all, we first create the startup class of the server. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-15-46-49-image.png) - -Create `Application` class under `org.apache.dubbo.samples.provider`, defined as follows: - -```java -package org.apache.dubbo.samples.provider; - -import java.util.concurrent.CountDownLatch; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -public class Application { - - public static void main(String[] args) throws InterruptedException { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("dubbo-demo-provider.xml"); - context. start(); - - // Suspend the main thread to prevent exit - new CountDownLatch(1). await(); - } -} -``` - -In this startup class, a `ClassPathXmlApplicationContext` is configured to read the `dubbo-demo-provider.xml` configuration file defined in the previous step 6. - -### 9. Configure consumer startup classes based on Spring - -Similarly, we need to create a startup class for the consumer. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-15-48-26-image.png) - -Create `Application` class under `org.apache.dubbo.samples.client`, defined as follows: - -```java -package org.apache.dubbo.samples.client; - -import java.io.IOException; - -import org.apache.dubbo.samples.api.GreetingsService; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -public class Application { - public static void main(String[] args) throws IOException { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("dubbo-demo-consumer.xml"); - context. start(); - GreetingsService greetingsService = (GreetingsService) context. getBean("greetingsService"); - - String message = greetingsService.sayHi("dubbo"); - System.out.println("Receive result ======> " + message); - System.in.read(); - System. exit(0); - } - -} -``` - -In this startup class, three functions are mainly performed: - -1. Configure a `ClassPathXmlApplicationContext` to read the `dubbo-demo-consumer.xml` configuration file defined in the previous step 7 - -2. Obtain the bean created by Dubbo named `greetingsService` from the Spring Context - -3. Initiate a call to the remote end through this bean - -### 10. Start the application - -As of step 9, the code has been developed, and this section will start the entire project and verify it. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-16-01-29-image.png) - -The first is to start `org.apache.dubbo.samples.provider.Application`, wait for a while to appear the log as shown in the figure below (`Dubbo Application[1.1](demo-provider) is ready`), which means that the service provider is started , which indicates that the service provider can provide services externally. - -``` log -[DUBBO] Dubbo Application[1.1](demo-provider) is ready., dubbo version: 3.1.6, current host: 30.221.128.96 -``` - -Then start `org.apache.dubbo.samples.client.Application`, and wait for a while to see the log (`hi, dubbo`) as shown in the figure below, which means that the service consumer is started and the call to the server is successfully obtained. - -![img](/imgs/docs3-v2/java-sdk/quickstart/2023-02-08-16-02-50-image.png) - -``` log -Receive result ======> hi, dubbo -``` - -## Further reading - -### 1. Dubbo XML configuration introduction - -The main configuration entries of Dubbo include `dubbo:application`, `dubbo:registry`, `dubbo:reference` and `dubbo:service`, etc. For more details, please refer to [XML configuration | Apache Dubbo](/zh-cn/docs3- v2/java-sdk/reference-manual/config/xml/) article. - -## More - -This tutorial introduces how to develop a microservice application based on Dubbo x Spring XML. So far, the three main startup methods of Dubbo based on API, Spring Boot and Spring XML have been introduced. - -In the next section, the microservice development method based on Protobuf IDL configuration will be introduced. diff --git a/content/en/docs3-v2/java-sdk/reference-manual/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/_index.md deleted file mode 100755 index 056f3032b615..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/_index.md +++ /dev/null @@ -1,8 +0,0 @@ - ---- -type: docs -title: "Reference Manual" -linkTitle: "Reference Manual" -weight: 5 ---- - diff --git a/content/en/docs3-v2/java-sdk/reference-manual/config-center/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/config-center/_index.md deleted file mode 100644 index c4b367820feb..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/config-center/_index.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -type: docs -title: "Configuration Center" -linkTitle: "Configuration Center" -weight: 7 -description: "" ---- - -The configuration center (config-center) can undertake two types of responsibilities in Dubbo: - -1. [Externalized configuration](../config/principle/#33-externalized configuration): Centralized storage of startup configuration (simply understood as externalized storage of dubbo.properties). -2. Storage of traffic governance rules - -Please refer to the specific extension implementation to learn how to enable the configuration center. - -It is worth noting that the Dubbo dynamic configuration center defines two different levels of isolation options, namely namespce and group. -* namespace - configuration namespace, the default value is `dubbo`. Namespaces are usually used for multi-tenant isolation, that is, to logically isolate different users, different environments, or a series of configurations that are completely unrelated. The point of difference from physical isolation is whether different namespaces are used or the same physical cluster. -* group - configuration grouping, default value `dubbo`. `group` is usually used to classify a group of configuration items of the same type/purpose, which is a further isolation of configuration items under `namespace`. - -Refer to [Configuration Instructions - Configuration Item Manual](../config/properties/#config-center) for more configuration items opened by config-center other than namespce and group. - -> In order to be compatible with the 2.6.x version configuration, when Zookeeper is used as the registration center and the configuration center is not displayed, the Dubbo framework will use this Zookeeper as the configuration center by default, but it will only be used for service governance. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/config-center/apollo.md b/content/en/docs3-v2/java-sdk/reference-manual/config-center/apollo.md deleted file mode 100644 index 407a6e834ae9..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/config-center/apollo.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -type: docs -title: "Apollo" -linkTitle: "Apollo" -weight: 4 -description: "The basic usage and working principle of Apollo Configuration Center." ---- - -## 1 precondition -* Understand [Dubbo basic development steps](../../../quick-start/spring-boot/) -* Install and start [Apollo](https://www.apolloconfig.com/#/zh/README) - -## 2 Instructions for use -Check here [full sample code](https://github.com/apache/dubbo-samples/tree/master/3-extensions/configcenter/dubbo-samples-configcenter-apollo) - -### 2.1 Add Maven dependency - -```xml - - org.apache.dubbo - dubbo - 3.0.9 - - - com.ctrip.framework.apollo - apollo-openapi - 2.0.0 - - - com.ctrip.framework.apollo - apollo-client - 2.0.0 - -``` - -### 2.2 Enable Apollo Configuration Center -```xml - -``` - -or - -```yaml -dubbo - config-center - address: apollo://localhost:8080 -``` - -or - -```properties -dubbo.config-center.address=apollo://localhost:8080 -``` - -or - -```java -ConfigCenterConfig configCenter = new ConfigCenterConfig(); -configCenter.setAddress("apollo://localhost:8080"); -``` - -## 3 Advanced configuration -A core concept in Apollo is the namespace - namespace, which is different from the namespace concepts of Zookeeper and Nacos above, so the usage method is also special. It is recommended to read the following documents after fully understanding the usage of Apollo itself. - -But in general, for the adaptation of Apollo: -* namespace is specially used for isolation of traffic governance rules, see 3.1 -* group is specially used for isolation of externalized configuration, see 3.2 - -### 3.1 External configuration - -```xml - -``` - -The `group` of config-center determines where Apollo reads the externalized configuration `dubbo.properties` file: -1. If the group is empty, the configuration will be read from the `dubbo` namespace by default, and the user must write the externalized configuration under the `dubbo` namespace. -2. If group is not empty - 2.1 If the group value is the application name, the configuration is read from the current namespace of the application, and the user must write the externalized configuration under the default namespace of the application automatically designated by Apollo. - 2.2 If the group value is any value, the configuration is read from the corresponding namespace, and the user must write the externalized configuration under the namespace. - -For example, the following example uses the default global externalization configuration of group='dubbo', that is, the configuration can be read by all applications. -![apollo-configcenter-dubbo.png](/imgs/user/apollo-configcenter-dubbo.png) - -If the configuration group='application name' is an application-specific configuration, only this application can read it. - -> Regarding externalized file configuration hosting, it is equivalent to storing the contents of the `dubbo.properties` configuration file in Apollo. Each application can inherit the public configuration by associating with the shared `dubbo` namespace, and then can override individual configuration items individually. - -### 3.2 Traffic Governance Rules -**Traffic governance rules must be shared globally, so the namespace configuration in each application should be consistent. ** - -```xml - -``` - -The `namespace` of config-center determines where Apollo accesses `traffic governance rules`: -1. If the namespace is empty, the configuration will be accessed from the `dubbo` namespace by default, and the governance rules must be written under the `dubbo` namespace. -2. If the namespace is not empty, read the rules from the corresponding namespace value, and the governance rules must be written under this namespace. - -For example, the following example puts the traffic governance rules under the `governance` namespace through `namespace='governance'`. -![apollo-configcenter-governance-dubbo.png](/imgs/user/apollo-configcenter-governance-dubbo.png) - -### 3.3 More Apollo-specific configurations -Currently Dubbo is adapted to env, apollo.meta, apollo.cluster, apollo.id and other unique configuration items, which can be configured through the extended parameters of config-center. - -Such as -```properties -dubbo.config-center.address=apollo://localhost:8080 -``` - -or - -```properties -dubbo.config-center.prameters.apollo.meta=xxx -dubbo.config-center.prameters.env=xxx -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/config-center/nacos.md b/content/en/docs3-v2/java-sdk/reference-manual/config-center/nacos.md deleted file mode 100644 index 2dc71866133a..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/config-center/nacos.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -type: docs -title: "Nacos" -linkTitle: "Nacos" -weight: 3 -description: "The basic usage and working principle of Nacos Configuration Center." ---- - -## 1 precondition -* Understand [Dubbo basic development steps](../../../quick-start/spring-boot/) -* Install and start [Nacos](https://nacos.io/zh-cn/docs/quick-start.html) -> When Dubbo uses `3.0.0` and above, it needs to use Nacos `2.0.0` and above. - -## 2 Instructions for use - -### 2.1 Add Maven dependency -If the project has enabled Nacos as the registration center, no additional configuration is required. - -If the Nacos registry is not enabled, please refer to [Adding Nacos dependencies to the registry](../../registry/nacos/#21-Add dependencies). - -### 2.2 Enable Nacos Configuration Center -```xml - -``` - -or - -```yaml -dubbo - config-center - address: nacos://127.0.0.1:8848 -``` - -or - -```properties -dubbo.config-center.address=nacos://127.0.0.1:8848 -``` - -or - -```java -ConfigCenterConfig configCenter = new ConfigCenterConfig(); -configCenter.setAddress("nacos://127.0.0.1:8848"); -``` - -For `address` format, please refer to [Nacos Registry - Enable Configuration](../../registry/nacos/#22-configure and enable-nacos) - -## 3 Advanced configuration -To enable authentication authentication, please refer to [Nacos Registry - Enable Authentication Authentication](../../registry/nacos/#31-authentication) - -### 3.1 External configuration -#### 3.1.1 Global externalization configuration -**1. The application opens config-center configuration** -```yaml -dubbo - config-center - address: nacos://127.0.0.1:2181 - config-file: dubbo.properties # optional -``` -`config-file` - global externalized configuration file key value, default `dubbo.properties`. `config-file` represents the key value corresponding to the file in the configuration center when the Dubbo configuration file is stored in the remote registration center, and it is generally not recommended to modify this configuration item. - -**2. Add configuration to Nacos Server** - -![nacos-configcenter-global-properties.png](/imgs/user/nacos-configcenter-global-properties.png) - -dataId is `dubbo.properties`, group grouping is consistent with config-center, if not set, `dubbo` will be filled by default. - -#### 3.1.2 Application-specific externalization configuration - -**1. The application opens config-center configuration** -```yaml -dubbo - config-center - address: nacos://127.0.0.1:2181 - app-config-file: dubbo.properties # optional -``` - -`app-config-file` - The current application-specific externalization configuration file key value, such as `app-name-dubbo.properties`, only configured when it needs to override the global externalization configuration file `config-file`. - -**2. Add configuration to Nacos Server** - -![nacos-configcenter-application-properties.png](/imgs/user/nacos-configcenter-application-properties.png) - -The dataId is `dubbo.properties`, and the group is set to the application name, namely `demo-provider`. - -### 3.2 Set group and namespace -```yaml -dubbo - config-center - address: zookeeper://127.0.0.1:2181 - group: dubbo-cluster1 - namespace: dev1 -``` - -For the configuration center, `group` and `namespace` should be unified across the company (cluster), and different applications should be prevented from using different values. - -### 3.3 Nacos extended configuration -For more parameter configurations supported by Nacos sdk/server, please refer to [Nacos Registry - More Configurations](../../registry/nacos/#35-More Configurations) - -## 4 Traffic Governance Rules -For Nacos, all traffic governance rules and external configurations should be globally visible, so applications in the same logical cluster must use the same namespace and group. Among them, the default value of namespace is `public`, and the default value of group is `dubbo`. The application should not modify the namespace and group without authorization, unless it can maintain global consistency. - -It is recommended to add, delete, and modify traffic governance rules through dubbo-admin. For more information, please refer to the traffic governance capabilities supported by Dubbo. - -![nacos-configcenter-governance.jpg](/imgs/user/nacos-configcenter-governance.png) - -There are many types of traffic governance rules, and the suffixes of dataId for different types of rules are different: - -- configurators, [override rules](/zh-cn/overview/core-features/traffic/configuration-rule/) -- tag-router, [tag routing](/zh-cn/overview/core-features/traffic/tag-rule/) -- condition-router, [conditional routing](/zh-cn/overview/core-features/traffic/condition-rule/) diff --git a/content/en/docs3-v2/java-sdk/reference-manual/config-center/zookeeper.md b/content/en/docs3-v2/java-sdk/reference-manual/config-center/zookeeper.md deleted file mode 100644 index 9249cd6aeca8..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/config-center/zookeeper.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -type: docs -title: "Zookeeper" -linkTitle: "Zookeeper" -weight: 2 -description: "The basic usage and working principle of the Zookeeper configuration center." ---- - -## 1 precondition -* Understand [Dubbo basic development steps](../../../quick-start/spring-boot/) -* Install and start [Zookeeper](https://zookeeper.apache.org/) - -## 2 Instructions for use -View [full sample code](https://github.com/apache/dubbo-samples/tree/master/3-extensions/configcenter/dubbo-samples-configcenter-annotation) here - -### 2.1 Add Maven dependency -If the project has enabled Zookeeper as the registry, no additional configuration is required. - -If the Zookeeper registry is not used, please refer to [Add Zookeeper-related dependencies for the registry](../../registry/zookeeper/#21-add-maven-dependency). - -### 2.2 Enable Zookeeper Configuration Center -```xml - -``` - -or - -```yaml -dubbo - config-center - address: zookeeper://127.0.0.1:2181 -``` - -or - -```properties -dubbo.config-center.address=zookeeper://127.0.0.1:2181 -``` - -or - -```java -ConfigCenterConfig configCenter = new ConfigCenterConfig(); -configCenter.setAddress("zookeeper://127.0.0.1:2181"); -``` - -For `address` format, please refer to [zookeeper registry - enable configuration](../../registry/zookeeper/#22-configure and enable-zookeeper) - -## 3 Advanced configuration -To enable authentication, please refer to [zookeeper registry - enable authentication](../../registry/zookeeper/#31-authentication and authentication) - -### 3.1 Customize external configuration key -**1. Enable external configuration and specify key** -```yaml -dubbo - config-center - address: zookeeper://127.0.0.1:2181 - config-file: dubbo.properties -``` - -`config-file` - externalized configuration file key value, default `dubbo.properties`. `config-file` represents the key value corresponding to the file in the configuration center when the Dubbo configuration file is stored in the remote registration center, and it is generally not recommended to modify this configuration item. - -**2. Add configuration to Zookeeper configuration center** -The storage structure of the externalized configuration is shown in the figure below - -![zk-configcenter.jpg](/imgs/user/zk-configcenter.jpg) - -- namespace, used for environment isolation of different configurations. -- config, a fixed node agreed by Dubbo, cannot be changed, and all configuration and traffic governance rules are stored under this node. -- dubbo and application are used to isolate global configuration and application-level configuration respectively: dubbo is the default group value, and application corresponds to the application name -- dubbo.properties, the node value of this node stores the specific configuration content - -> Here is to explain the working principle, it is recommended to use dubbo-admin for configuration management. - -### 3.2 Set group and namespace -```yaml -dubbo - config-center - address: zookeeper://127.0.0.1:2181 - group: dubbo-cluster1 - namespace: dev1 -``` - -For the configuration center, `group` and `namespace` should be unified across the company (cluster), avoid using different values for different applications, and external configuration and governance rules should also be stored in the corresponding group and namespace. - -## 4 Traffic Governance Rules -All traffic governance rules are stored under the `/dubbo/config` node by default. The specific node structure diagram is as follows. It is recommended to add, delete, and modify traffic governance rules through dubbo-admin. For more information, please refer to the specific traffic governance capabilities supported by Dubbo - -![zk-configcenter-governance](/imgs/user/zk-configcenter-governance.jpg) - -- namespace, used for environment isolation of different configurations. -- config, a fixed node agreed by Dubbo, cannot be changed, and all configuration and traffic governance rules are stored under this node. -- dubbo, all service governance rules are global, dubbo is the default node -- configurators/tag-router/condition-router/migration, different service governance rule types, node value stores specific rule content \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/config/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/config/_index.md deleted file mode 100644 index b18a80924bad..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/config/_index.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "Configuration Manual" -linkTitle: "Configuration instructions" -weight: 1 -description: "Dubbo abstracts a series of structured configurations. For different users, it can not only quickly start services with minimal configuration, but also precisely control service behavior through complex configurations when needed; - In addition to the basic usage of API + Properties, Dubbo also supports SpringBoot, Annotation, XML, YAML, etc. in the form of configuration through the integration with Spring. " ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/config/annotation.md b/content/en/docs3-v2/java-sdk/reference-manual/config/annotation.md deleted file mode 100644 index 3863690c889d..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/config/annotation.md +++ /dev/null @@ -1,209 +0,0 @@ ---- -type: docs -title: "Annotation configuration" -linkTitle: "Annotation Configuration" -weight: 3 -description: "Develop Dubbo application with Annotation and Spring Boot" ---- - -This article uses the Spring Boot + Annotation mode to describe Dubbo application development. Check out the Spring Annotation development mode without Spring Boot here [complete example](https://github.com/apache/dubbo-samples/tree/master/1-basic/ dubbo-samples-annotation) - -In Dubbo Spring Boot development, you only need to add a few annotations and configure the `application.properties` or `application.yml` file to complete the Dubbo service definition: -* Annotations include `@DubboService`, `@DubboReference` and `EnableDubbo`. Among them, `@DubboService` and `@DubboReference` are used to mark Dubbo services, and `EnableDubbo` starts Dubbo-related configuration and specifies the Spring Boot scanning package path. -* Configuration file `application.properties` or `application.yml` - -For complete examples of the following content, please refer to [dubbo-samples](https://github.com/apache/dubbo-samples/tree/master/1-basic/dubbo-samples-spring-boot) - -## Add Maven dependency - -Use Dubbo Spring Boot Starter to first introduce the following Maven dependencies -```xml - - - - - org.springframework.boot - spring-boot-dependencies - ${spring-boot.version} - pom - import - - - - org.apache.dubbo - dubbo-bom - ${dubbo.version} - pom - import - - - - - org.apache.dubbo - dubbo-dependencies-zookeeper - ${dubbo.version} - pom - - - -``` - -Then add it to the pom of the corresponding module -```xml - - - - org.apache.dubbo - dubbo - - - org.apache.dubbo - dubbo-dependencies-zookeeper - pom - - - - - org.apache.dubbo - dubbo-spring-boot-starter - - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-autoconfigure - - -``` -> Distinguish between ** and ** above - -## application.yml or application.properties - -Components other than service and reference can be set in the application.yml file. If you want to extend the annotation configuration of service or reference, you need to add `dubbo.properties` configuration file or use other non-annotation methods such as Java Config. For details, please See [Extended Annotation Configuration](#Extended Annotation Configuration) below. - -Service and reference components can also be associated with global components in the application through `id`, take the following configuration as an example: - -```yaml -dubbo: - application: - name: dubbo-springboot-demo-provider - protocol: - name: dubbo - port: -1 - registry: - id: zk-registry - address: zookeeper://127.0.0.1:2181 - config-center: - address: zookeeper://127.0.0.1:2181 - metadata-report: - address: zookeeper://127.0.0.1:2181 -``` - -Associate the service with the specific registry defined above via annotations -```java -@DubboService(registry="zk-registry") -public class DemoServiceImpl implements DemoService {} -``` - -The same is true for association through Java Config configuration -```java -@Configuration -public class ProviderConfiguration { - @Bean - public ServiceConfig demoService() { - ServiceConfig service = new ServiceConfig(); - service.setRegistry("zk-registry"); - return service; - } -} -``` -## Annotation -### @DubboService annotation - -> The `@Service` annotation has been deprecated since version 3.0, use `@DubboService` to distinguish it from Spring's `@Service` annotation - -After defining the Dubbo service interface, provide the implementation logic of the service interface and mark it with `@DubboService` annotation to realize the service exposure of Dubbo - -```java -@DubboService -public class DemoServiceImpl implements DemoService {} -``` - -If you want to set service parameters, `@DubboService` also provides a way to set common parameters. If you have more complex parameter setting requirements, you can consider using other setting methods -```java -@DubboService(version = "1.0.0", group = "dev", timeout = 5000) -public class DemoServiceImpl implements DemoService {} -``` - -### @DubboReference annotation - -> The `@Reference` annotation has been deprecated since version 3.0, use `@DubboReference` to distinguish it from Spring's `@Reference` annotation - -```java -@Component -public class DemoClient { - @DubboReference - private DemoService demoService; -} -``` - -The `@DubboReference` annotation will be automatically injected as a Dubbo service proxy instance, and remote service calls can be initiated using demoService - -### @EnableDubbo annotation -The `@EnableDubbo` annotation must be configured, otherwise the service defined by the Dubbo annotation will not be loaded, `@EnableDubbo` can be defined on the main class - -```java -@SpringBootApplication -@EnableDubbo -public class ProviderApplication { - public static void main(String[] args) throws Exception { - SpringApplication.run(ProviderApplication.class, args); - } -} -``` - -Spring Boot annotations will only scan the package where the main class is located by default. If the service is defined in other packages, you need to add the configuration `EnableDubbo(scanBasePackages = {"org.apache.dubbo.springboot.demo.provider"})` - -### Extended annotation configuration -Although the configuration parameters can be adjusted through `@DubboService` and `DubboReference` (as shown in the code snippet below), overall the configuration items provided by annotations are still very limited. In this case, if there are more complex parameter setting requirements, you can use `Java Config` or `dubbo.properties` two ways. - -```java -@DubboService(version = "1.0.0", group = "dev", timeout = 5000) -@DubboReference(version = "1.0.0", group = "dev", timeout = 5000) -``` - -### Use Java Config instead of annotations - -Note that Java Config is an alternative to `DubboService` or `DubboReference`, which is recommended for services with complex configuration requirements. - -```java -@Configuration -public class ProviderConfiguration { - @Bean - public ServiceConfig demoService() { - ServiceConfig service = new ServiceConfig(); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - service.setGroup("dev"); - service.setVersion("1.0.0"); - Map parameters = new HashMap<>(); - service. setParameters(parameters); - return service; - } -} -``` - -### Supplementary configuration through dubbo.properties -For scenarios using `DubboService` or `DubboReference`, you can use dubbo.properties as a configuration supplement, [specific format](../principle/#1-configuration format) is explained in more detail here. - -```properties -dubbo.service.org.apache.dubbo.springboot.demo.DemoService.timeout=5000 -dubbo.service.org.apache.dubbo.springboot.demo.DemoService.parameters=[{myKey:myValue},{anotherKey:anotherValue}] -dubbo.reference.org.apache.dubbo.springboot.demo.DemoService.timeout=6000 -``` - -> Properties format configuration is currently not very structural, for example, the key field is more redundant, and support for yaml format will be considered in the future. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/config/api.md b/content/en/docs3-v2/java-sdk/reference-manual/config/api.md deleted file mode 100644 index e62df7d8a017..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/config/api.md +++ /dev/null @@ -1,311 +0,0 @@ ---- -type: docs -title: "API Configuration" -linkTitle: "API Configuration" -weight: 2 -description: "Use API to configure your Dubbo application" ---- - -Assemble configuration, start Dubbo, publish and subscribe services through API coding. This method can support dynamic creation of ReferenceConfig/ServiceConfig, combined with generalized calls to meet the needs of API Gateway or test platform. - -> Reference [API Samples](https://github.com/apache/dubbo-samples/tree/master/1-basic/dubbo-samples-api) - -## service provider - -Expose the service interface through ServiceConfig, and publish the service interface to the registration center. - -> Note: In order to better support Dubbo3 application-level service discovery, it is recommended to use the new [DubboBootstrap API](#bootstrap-api). - -```java -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ProviderConfig; -import org.apache.dubbo.config.ServiceConfig; -import com.xxx.DemoService; -import com.xxx.DemoServiceImpl; - -public class DemoProvider { - public static void main(String[] args) { - // service implementation - DemoService demoService = new DemoServiceImpl(); - - // current application configuration - ApplicationConfig application = new ApplicationConfig(); - application.setName("demo-provider"); - - // connect registry configuration - RegistryConfig registry = new RegistryConfig(); - registry.setAddress("zookeeper://10.20.130.230:2181"); - - // service provider protocol configuration - ProtocolConfig protocol = new ProtocolConfig(); - protocol.setName("dubbo"); - protocol.setPort(12345); - protocol.setThreads(200); - - // Note: ServiceConfig is a heavy object, which internally encapsulates the connection with the registration center and opens the service port - // The service provider exposes the service configuration - ServiceConfig service = new ServiceConfig(); // This instance is very heavy and encapsulates the connection with the registration center, please cache it yourself, otherwise it may cause memory and connection leaks - service. setApplication(application); - service.setRegistry(registry); // Multiple registries can use setRegistries() - service.setProtocol(protocol); // multiple protocols can use setProtocols() - service.setInterface(DemoService.class); - service.setRef(demoService); - service.setVersion("1.0.0"); - - // expose and register services - service. export(); - - // Suspend waiting (to prevent the process from exiting) - System.in.read(); - } -} -``` - -## Service Consumer - -Reference the remote service through ReferenceConfig, and subscribe to the service interface from the registry. - -> Note: In order to better support Dubbo3 application-level service discovery, it is recommended to use the new [DubboBootstrap API](#bootstrap-api). - -```java -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ConsumerConfig; -import org.apache.dubbo.config.ReferenceConfig; -import com.xxx.DemoService; - -public class DemoConsumer { - public static void main(String[] args) { - // current application configuration - ApplicationConfig application = new ApplicationConfig(); - application.setName("demo-consumer"); - - // connect registry configuration - RegistryConfig registry = new RegistryConfig(); - registry.setAddress("zookeeper://10.20.130.230:2181"); - - // Note: ReferenceConfig is a heavy object, which internally encapsulates the connection with the registry and the connection with the service provider - // reference the remote service - ReferenceConfig reference = new ReferenceConfig(); // This instance is very heavy and encapsulates the connection with the registry and the provider, please cache it yourself, otherwise it may cause memory and connection leaks - reference.setApplication(application); - reference.setRegistry(registry); // Multiple registries can use setRegistries() - reference.setInterface(DemoService.class); - reference.setVersion("1.0.0"); - - // use demoService like local bean - // Note: This proxy object internally encapsulates all communication details, the object is heavy, please cache and reuse - DemoService demoService = reference. get(); - demoService.sayHello("Dubbo"); - } -} -``` - -## Bootstrap API - -DubboBootstrap API can reduce repeated configuration, better control the startup process, support batch publishing/subscribing service interfaces, and better support Dubbo3's application-level service discovery. - -```java -import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ProviderConfig; -import org.apache.dubbo.config.ServiceConfig; -import com.xxx.DemoService; -import com.xxx.DemoServiceImpl; - -public class DemoProvider { - public static void main(String[] args) { - - ConfigCenterConfig configCenter = new ConfigCenterConfig(); - configCenter.setAddress("zookeeper://127.0.0.1:2181"); - - // service provider protocol configuration - ProtocolConfig protocol = new ProtocolConfig(); - protocol.setName("dubbo"); - protocol.setPort(12345); - protocol.setThreads(200); - - // Note: ServiceConfig is a heavy object, which internally encapsulates the connection with the registration center and opens the service port - // The service provider exposes the service configuration - ServiceConfig demoServiceConfig = new ServiceConfig<>(); - demoServiceConfig.setInterface(DemoService.class); - demoServiceConfig.setRef(new DemoServiceImpl()); - demoServiceConfig.setVersion("1.0.0"); - - // Second service configuration - ServiceConfig fooServiceConfig = new ServiceConfig<>(); - fooServiceConfig.setInterface(FooService.class); - fooServiceConfig.setRef(new FooServiceImpl()); - fooServiceConfig.setVersion("1.0.0"); - - ... - - // Use DubboBootstrap to simplify configuration assembly and control the startup process - DubboBootstrap. getInstance() - .application("demo-provider") // application configuration - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) // registry configuration - .protocol(protocol) // global default protocol configuration - .service(demoServiceConfig) // add ServiceConfig - .service(fooServiceConfig) - .start() // start Dubbo - .await(); // suspend waiting (to prevent the process from exiting) - } -} -``` - -```java -import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ProviderConfig; -import org.apache.dubbo.config.ServiceConfig; -import com.xxx.DemoService; -import com.xxx.DemoServiceImpl; - -public class DemoConsumer { - public static void main(String[] args) { - - // reference the remote service - ReferenceConfig demoServiceReference = new ReferenceConfig(); - demoServiceReference.setInterface(DemoService.class); - demoServiceReference.setVersion("1.0.0"); - - ReferenceConfig fooServiceReference = new ReferenceConfig(); - fooServiceReference.setInterface(FooService.class); - fooServiceReference.setVersion("1.0.0"); - - // Use DubboBootstrap to simplify configuration assembly and control the startup process - DubboBootstrap bootstrap = DubboBootstrap. getInstance(); - bootstrap.application("demo-consumer") // application configuration - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) // registry configuration - .reference(demoServiceReference) // add ReferenceConfig - .service(fooServiceReference) - .start(); // Start Dubbo - - ... - - // use demoService like local bean - // Obtain the remote service interface proxy through Interface, without relying on the ReferenceConfig object - DemoService demoService = DubboBootstrap.getInstance().getCache().get(DemoService.class); - demoService.sayHello("Dubbo"); - - FooService fooService = DubboBootstrap.getInstance().getCache().get(FooService.class); - fooService. greeting("Dubbo"); - } - -} - -``` - -## Other configuration - -- basic configuration -- Method level configuration -- Point-to-point direct connection - -The API provides the most flexible and rich configuration capabilities, the following are some examples of configurable components. - -#### basic configuration - -Global basic configuration can be set in DubboBootstrap, including application configuration, protocol configuration, registration center, configuration center, metadata center, module, monitoring, SSL, provider configuration, consumer configuration, etc. - -```java -// registry -RegistryConfig registry = new RegistryConfig(); -registry.setAddress("zookeeper://192.168.10.1:2181"); -... - -// service provider protocol configuration -ProtocolConfig protocol = new ProtocolConfig(); -protocol.setName("dubbo"); -protocol.setPort(12345); -protocol.setThreads(200); -... - -// configuration center -ConfigCenterConfig configCenter = new ConfigCenterConfig(); -configCenter.setAddress("zookeeper://192.168.10.2:2181"); -... - -// metadata center -MetadataReportConfig metadataReport = new MetadataReportConfig(); -metadataReport.setAddress("zookeeper://192.168.10.3:2181"); -... - -// Metrics -MetricsConfig metrics = new MetricsConfig(); -metrics.setProtocol("dubbo"); -... - -// SSL -SslConfig ssl = new SslConfig(); -ssl.setServerKeyCertChainPath("/path/ssl/server-key-cert-chain"); -ssl.setServerPrivateKeyPath("/path/ssl/server-private-key"); -... - -// Provider configuration (ServiceConfig default configuration) -ProviderConfig provider = new ProviderConfig(); -provider.setGroup("demo"); -provider.setVersion("1.0.0"); -... - -// Consumer configuration (ReferenceConfig default configuration) -ConsumerConfig consumer = new ConsumerConfig(); -consumer.setGroup("demo"); -consumer.setVersion("1.0.0"); -consumer.setTimeout(2000); -... - -DubboBootstrap. getInstance() - .application("demo-app") - .registry(registry) - .protocol(protocol) - .configCenter(configCenter) - .metadataReport(metadataReport) - .module(new ModuleConfig("module")) - .metrics(metrics) - .ssl (ssl) - .provider(provider) - .consumer(consumer) - ... - .start(); - -``` - -#### Method level settings - -```java -... - -// method-level configuration -List methods = new ArrayList(); -MethodConfig method = new MethodConfig(); -method. setName("sayHello"); -method.setTimeout(10000); -method. setRetries(0); -methods. add(method); - -// reference the remote service -ReferenceConfig reference = new ReferenceConfig(); // This instance is very heavy and encapsulates the connection with the registry and the provider, please cache it yourself, otherwise it may cause memory and connection leaks -... -reference.setMethods(methods); // Set method-level configuration - -... -``` - -#### Point-to-point direct connection - -```java - -... - -// This instance is very heavy, it encapsulates the connection with the registry and the provider, please cache it yourself, otherwise it may cause memory and connection leaks -ReferenceConfig reference = new ReferenceConfig(); -// If point-to-point direct connection, you can use reference.setUrl() to specify the target address. After setting the url, the registration center will be bypassed. -// Among them, the protocol corresponds to the value of provider.setProtocol(), and the port corresponds to the value of provider.setPort(). -// The path corresponds to the value of service.setPath(). If no path is set, the default path is the interface name -reference.setUrl("dubbo://10.20.130.230:20880/com.xxx.DemoService"); - -... -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/config/overview.md b/content/en/docs3-v2/java-sdk/reference-manual/config/overview.md deleted file mode 100644 index 0246e4bdc243..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/config/overview.md +++ /dev/null @@ -1,166 +0,0 @@ ---- -type: docs -title: "Configuration Overview" -linkTitle: "Configuration Overview" -weight: 1 -description: "A general overview of the overall design and working principle of Dubbo configuration, including configuration components, configuration sources, configuration methods, and configuration loading processes." ---- -Quickly jump to the content you care about through the following links: -* [Use Spring Boot to quickly develop Dubbo applications](../../../quick-start/spring-boot/) -* [Configuration item reference manual to know what configuration items are available](../properties) -* [How configuration loading and overriding works](../principle) - -## Configuration components - -In order to better manage various configurations, Dubbo abstracts a set of structured configuration components. Each component is generally divided by purpose and controls the behavior of different scopes. - -![dubbo-config](/imgs/user/dubbo-config.jpg) - -Component Name | Description | Scope | Required ------- | ------ | ------ | ------ -application | Specify the application-level information such as the application name | Only one application is allowed in an application | Required -service | Declare a common interface or implementation class as a Dubbo service | There can be 0 or more services in an application | At least one service/reference -reference | Declare a common interface as a Dubbo service | There can be 0 or more references in an application | At least one service/reference -protocol | The RPC protocol to be exposed and related configurations such as port numbers, etc. | One application can be configured with multiple, one protocol can be used for a set of service&reference | optional, default dubbo -registry | Registry type, address and related configuration | Multiple configurations can be made in one application, and one registry can be applied to a group of service&references | Mandatory -config-center | configuration center type, address and related configurations | multiple configurations in one application, shared by all services | optional -metadata-report | metadata center type, address and related configuration | multiple configurations in one application, shared by all services | optional -Consumer | The default configuration shared between references | Multiple configurations can be configured in one application, and one consumer can act on a group of references | Optional -Provider | The default configuration shared between services | Multiple configurations can be configured in one application, and one provider can be used for a group of services | Optional -monitor | monitoring system type and address | only one can be configured in an application | optional -metrics | related configuration of the data acquisition module | only one configuration is allowed in an application | optional -ssl | ssl/tls security link-related certificate configuration | Only one configuration is allowed in an application | optional -method | specifies method-level configuration | subconfigurations for service and reference | optional -argument | parameter configuration of a method | subconfiguration of method | optional - - -> 1. From the perspective of implementation principle, all configuration items of Dubbo will be assembled into the URL in the end, and the URL will be used as the carrier to pass during subsequent startup and RPC calls, thereby controlling the behavior of the framework. For more information, please refer to the Dubbo source code analysis series of documents or [Blog](/zh-cn/blog/2019/10/17/dubbo-in-url-unified model/#rpc call). -> 2. For the specific configuration items supported by each component and their meanings, please refer to [Configuration Item Manual](../properties) - -### service and reference -`service` and `reference` are the two most basic configuration items of Dubbo, they are used to register a specified interface or implementation class as a Dubbo service, and control the behavior of the service through configuration items. -* `service` is used on the service provider side, the interface and implementation class configured by `service` will be defined as a standard Dubbo service, so as to provide external RPC request services. -* `reference` is used for service consumers, the interface configured by `reference` will be defined as a standard Dubbo service, and the generated proxy can initiate an RPC request to the remote end. - -Any number of `service` and `reference` can be configured in an application. - -### consumer and provider -* When there are multiple `reference` configurations in the application, `consumer` specifies the default values shared by these `reference`s, such as shared timeouts, etc. to simplify cumbersome configurations, such as setting configurations separately in a `reference` Item value, the configuration in this `reference` takes precedence. -* When there are multiple `service` configurations in the application, `provider` specifies the default value shared by these `service`, if a configuration item value is set separately in a `service`, the configuration priority in the `service` higher. - -> The consumer component can also carry out virtual grouping of references, and references under different groups can have different consumer default value settings; for example, in XML format configuration, the tag can be nested in Implement grouping within tags. The same effect can also be achieved between provider and service. - -## configuration method - -According to the driving mode, it can be divided into the following five modes: - -### API configuration -The configuration is organized in the form of Java coding, including Raw API and Bootstrap API. For details, please refer to [API configuration](../api). - -```java -public static void main(String[] args) throws IOException { - ServiceConfig service = new ServiceConfig<>(); - service.setApplication(new ApplicationConfig("first-dubbo-provider")); - service.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234")); - service.setInterface(GreetingsService.class); - service.setRef(new GreetingsServiceImpl()); - service. export(); - System.out.println("first-dubbo-provider is running."); - System.in.read(); -} -``` - -### XML configuration -Configure various components in XML and support seamless integration with Spring. For details, please refer to [XML Configuration](../xml). - -```xml - - - - - - - - - - - -``` - -### Annotation configuration -Expose services and reference service interfaces in the form of annotations, and support seamless integration with Spring. For details, please refer to [Annotation Configuration](../annotation). - -```java - // AnnotationService service implementation - - @DubboService - public class AnnotationServiceImpl implements AnnotationService { - @Override - public String sayHello(String name) { - System.out.println("async provider received: " + name); - return "annotation: hello, " + name; - } - } -``` - -```properties -## dubbo.properties - -dubbo.application.name=annotation-provider -dubbo.registry.address=zookeeper://127.0.0.1:2181 -dubbo.protocol.name=dubbo -dubbo.protocol.port=20880 -``` - -### Spring Boot -Use Spring Boot to reduce unnecessary configuration, and combine Annotation and application.properties/application.yml to develop Dubbo applications. For details, please refer to [Annotation Configuration](../annotation). - -```properties -## application.properties - -# Spring boot application -spring.application.name=dubbo-externalized-configuration-provider-sample - -# Base packages to scan Dubbo Component: @com.alibaba.dubbo.config.annotation.Service -dubbo.scan.base-packages=com.alibaba.boot.dubbo.demo.provider.service - -# Dubbo Application -## The default value of dubbo.application.name is ${spring.application.name} -## dubbo.application.name=${spring.application.name} - -#Dubbo Protocol -dubbo.protocol.name=dubbo -dubbo.protocol.port=12345 - -## Dubbo Registry -dubbo.registry.address=N/A - -## DemoService version -demo.service.version=1.0.0 -``` - -### Property configuration -Generate configuration components according to the attribute Key-value, similar to SpringBoot's ConfigurationProperties, please refer to [property configuration](../properties) for details. - -Another important feature of property configuration is [property override](../principle/#32-property override), which overrides the created configuration component property with the value of an external property. - -If you want to put the attribute configuration in an external configuration center, please refer to [Externalized Configuration](../principle/#33-Externalized Configuration). - -In addition to the differences in peripheral drive methods, Dubbo's configuration reading generally follows the following principles: - -1. Dubbo supports multi-level configuration, and automatically realizes the coverage between configurations according to the predetermined priority. Finally, all configurations are summarized into the data bus URL to drive subsequent service exposure, reference and other processes. -2. The configuration format is mainly Properties, and the configuration content follows the agreed `path-based`[naming convention](../principle/#1-configuration format) - - -## Configure the loading process - -### Configuration specifications and sources - -Dubbo follows a [path-based configuration specification](../principle/), and each configuration component can be expressed in this way. In terms of configuration sources, a total of 6 configuration sources are supported, that is, Dubbo will try to load configuration data from the following locations: - -- JVM System Properties, JVM -D parameter -- System environment, the environment variable of the JVM process -- Externalized Configuration, [externalized configuration] (../principle/#33-externalized configuration), read from the configuration center -- Application Configuration, application attribute configuration, extract the attribute set starting with "dubbo" from the Spring application Environment -- The configuration collected by programming interfaces such as API/XML/annotation can be understood as a kind of configuration source, which is a configuration collection method directly oriented to user programming -- Read configuration file dubbo.properties from classpath diff --git a/content/en/docs3-v2/java-sdk/reference-manual/config/principle.md b/content/en/docs3-v2/java-sdk/reference-manual/config/principle.md deleted file mode 100644 index c914fa64b2eb..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/config/principle.md +++ /dev/null @@ -1,374 +0,0 @@ ---- -type: docs -title: "How Configuration Works" -linkTitle: "How configuration works" -weight: 5 -description: "An in-depth interpretation of Dubbo configuration methods and working principles, including configuration formats, design ideas, sources, loading processes, etc." ---- - -The following is an example of Dubbo property configuration [dubbo-spring-boot-samples](https://github.com/apache/dubbo-spring-boot-project/tree/master/dubbo-spring-boot-samples) - -```properties - ## application.properties - - # Spring boot application - spring.application.name=dubbo-externalized-configuration-provider-sample - - # Base packages to scan Dubbo Component: @com.alibaba.dubbo.config.annotation.Service - dubbo.scan.base-packages=com.alibaba.boot.dubbo.demo.provider.service - - # Dubbo Application - ## The default value of dubbo.application.name is ${spring.application.name} - ## dubbo.application.name=${spring.application.name} - - #Dubbo Protocol - dubbo.protocol.name=dubbo - dubbo.protocol.port=12345 - - ## Dubbo Registry - dubbo.registry.address=N/A - - ## service default version - dubbo.provider.version=1.0.0 -``` -Next, around this example, we analyze the working principle of Dubbo configuration from three aspects: configuration format, configuration source, and loading process. - -## 1 configuration format - -All configurations currently supported by Dubbo are in `.properties` format, including `-D`, `Externalized Configuration`, etc. All configuration items in `.properties` follow a `path-based` configuration format. - -In the Spring application, you can also put the attribute configuration in `application.yml`, and the tree hierarchy is more readable. - -```properties -# Application-level configuration (no id) -dubbo.{config-type}.{config-item}={config-item-value} - -# Instance-level configuration (specify id or name) -dubbo.{config-type}s.{config-id}.{config-item}={config-item-value} -dubbo.{config-type}s.{config-name}.{config-item}={config-item-value} - -# Service interface configuration -dubbo.service.{interface-name}.{config-item}={config-item-value} -dubbo.reference.{interface-name}.{config-item}={config-item-value} - -# method configuration -dubbo.service.{interface-name}.{method-name}.{config-item}={config-item-value} -dubbo.reference.{interface-name}.{method-name}.{config-item}={config-item-value} - -# Method argument configuration -dubbo.reference.{interface-name}.{method-name}.{argument-index}.{config-item}={config-item-value} - -``` - -### 1.1 Application-level configuration (no id) - -The format of application-level configuration is: configuration type singular prefix, no id/name. -```properties -# Application-level configuration (no id) -dubbo.{config-type}.{config-item}={config-item-value} -``` - -Similar to `application`, `monitor`, `metrics`, etc. are all application-level components, so only a single instance is allowed to be configured; while `protocol`, `registry`, etc. allow to configure multiple components, when only singleton configuration is required , in the format described in this section. Common examples are as follows: - -```properties -dubbo.application.name=demo-provider -dubbo.application.qos-enable=false - -dubbo.registry.address=zookeeper://127.0.0.1:2181 - -dubbo.protocol.name=dubbo -dubbo.protocol.port=-1 -``` - -### 1.2 Instance-level configuration (specify id or name) - -The attribute configuration for an instance needs to specify an id or name, and its prefix format is: configuration type plural prefix + id/name. Applicable to `protocol`, `registry` and other components that support multiple configurations. - -```properties -# Instance-level configuration (specify id or name) -dubbo.{config-type}s.{config-id}.{config-item}={config-item-value} -dubbo.{config-type}s.{config-name}.{config-item}={config-item-value} -``` - -* If there is no instance of the id or name, the framework will create a configuration component instance based on the properties listed here. -* If an instance with the same id or name already exists, the framework will use the attributes listed here as a supplement to the existing instance configuration. For details, please refer to [Attribute Override](../principle#32-Attribute Override). -* Please refer to the [single and plural configuration comparison table] (../principle#17-single and plural configuration item comparison table) - -Configuration example: - -```properties -dubbo.registries.unit1.address=zookeeper://127.0.0.1:2181 -dubbo.registries.unit2.address=zookeeper://127.0.0.1:2182 - -dubbo.protocols.dubbo.name=dubbo -dubbo.protocols.dubbo.port=20880 - -dubbo.protocols.hessian.name=hessian -dubbo.protocols.hessian.port=8089 -``` - -### 1.3 Service interface configuration - -```properties -dubbo.service.org.apache.dubbo.samples.api.DemoService.timeout=5000 -dubbo.reference.org.apache.dubbo.samples.api.DemoService.timeout=6000 -``` - -### Method configuration - -Method configuration format: - -```properties -# method configuration -dubbo.service.{interface-name}.{method-name}.{config-item}={config-item-value} -dubbo.reference.{interface-name}.{method-name}.{config-item}={config-item-value} - -# Method argument configuration -dubbo.reference.{interface-name}.{method-name}.{argument-index}.{config-item}={config-item-value} -``` - -Example method configuration: -```properties -dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.timeout=7000 -dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.oninvoke=notifyService.onInvoke -dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.onreturn=notifyService.onReturn -dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.onthrow=notifyService.onThrow -dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.0.callback=true -``` - -Equivalent to XML configuration: - -```xml - - - - - -``` - -### 1.4 Parameter configuration - -The parameters parameter is a map object, which supports configuration in the form of xxx.parameters=[{key:value},{key:value}]. -```properties -dubbo.application.parameters=[{item1:value1},{item2:value2}] -dubbo.reference.org.apache.dubbo.samples.api.DemoService.parameters=[{item3:value3}] -``` - -### 1.5 Transport layer configuration - -The triple protocol uses Http2 as the underlying communication protocol, allowing users to customize [6 settings parameters] of Http2 (https://datatracker.ietf.org/doc/html/rfc7540#section-6.5.2) - -The configuration format is as follows: - -```properties -# Notify the peer header of the upper limit of compressed index tables -dubbo.rpc.tri.header-table-size=4096 - -# Enable server-side push function -dubbo.rpc.tri.enable-push=false - -# Notify the peer of the maximum number of concurrent streams allowed -dubbo.rpc.tri.max-concurrent-streams=2147483647 - -# Declare the window size of the sender -dubbo.rpc.tri.initial-window-size=1048576 - -# Set the maximum number of bytes for the frame -dubbo.rpc.tri.max-frame-size=32768 - -# Notify the peer of the maximum number of uncompressed bytes in the header -dubbo.rpc.tri.max-header-list-size=8192 -``` - -Equivalent to yml configuration: - -```yaml -dubbo: - rpc: - tri: - header-table-size: 4096 - enable-push: false - max-concurrent-streams: 2147483647 - initial-window-size: 1048576 - max-frame-size: 32768 - max-header-list-size: 8192 -``` - - - -### 1.6 Attribute and XML configuration mapping rules - -The xml tag name and attribute name can be combined, separated by '.'. One attribute per line. - -* `dubbo.application.name=foo` is equivalent to `` -* `dubbo.registry.address=10.20.153.10:9090` is equivalent to ` ` - -If there is more than one tag in xml configuration, then you can use 'id' to differentiate. If you don't specify an id, it will apply to all tags. - -* `dubbo.protocols.rmi.port=1099` is equivalent to ` ` -* `dubbo.registries.china.address=10.20.153.10:9090` is equivalent to `` - -### 1.7 Single and plural comparison table for configuration items -Plural configurations are named in the same way as regular words are pluralized: - -1. When the letter y ends, remove y and change to ies -2. At the end of the letter s, add es -3. Others add s - -| Config Type | Singular Configuration | Plural Configuration | -| ------------------------------------ | --------------- ------------------------------------------------ | ---- ---------------------------------- | -| application | dubbo.application.xxx=xxx | dubbo.applications.{id}.xxx=xxx
dubbo.applications.{name}.xxx=xxx | -| protocol | dubbo.protocol.xxx=xxx | dubbo.protocols.{id}.xxx=xxx
dubbo.protocols.{name}.xxx=xxx | -| module | dubbo.module.xxx=xxx | dubbo.modules.{id}.xxx=xxx
dubbo.modules.{name}.xxx=xxx | -| registry | dubbo.registry.xxx=xxx | dubbo.registries.{id}.xxx=xxx | -| monitor | dubbo.monitor.xxx=xxx | dubbo.monitors.{id}.xxx=xxx | -| config-center | dubbo.config-center.xxx=xxx | dubbo.config-centers.{id}.xxx=xxx | -| metadata-report | dubbo.metadata-report.xxx=xxx | dubbo.metadata-reports.{id}.xxx=xxx | -| ssl | dubbo.ssl.xxx=xxx | dubbo.ssls.{id}.xxx=xxx | -| metrics | dubbo.metrics.xxx=xxx | dubbo.metricses.{id}.xxx=xxx | -| provider | dubbo.provider.xxx=xxx | dubbo.providers.{id}.xxx=xxx | -| consumer | dubbo.consumer.xxx=xxx | dubbo.consumers.{id}.xxx=xxx | -| service | dubbo.service.{interfaceName}.xxx=xxx | None | -| reference | dubbo.reference.{interfaceName}.xxx=xxx | None | -| method | dubbo.service.{interfaceName}.{methodName}.xxx=xxx
dubbo.reference.{interfaceName}.{methodName}.xxx=xxx | None | -| argument | dubbo.service.{interfaceName}.{methodName}.{arg-index}.xxx=xxx | None | - - -## 2 Configure sources - -Dubbo supports 6 configuration sources by default: - -- JVM System Properties, JVM -D parameter -- System environment, the environment variable of the JVM process -- Externalized Configuration, [externalized configuration] (#33-externalized configuration), read from the configuration center -- Application Configuration, application attribute configuration, extract the attribute set starting with "dubbo" from the Spring application Environment -- The configuration collected by programming interfaces such as API/XML/annotation can be understood as a kind of configuration source, which is a configuration collection method directly oriented to user programming -- Read configuration file dubbo.properties from classpath - -About the dubbo.properties attribute: - -1. If there is more than one dubbo.properties file under the classpath, for example, two jar packages each contain dubbo.properties, dubbo will randomly select one to load and print an error log. -2. Dubbo can automatically load dubbo.properties in the root directory of the classpath, but you can also use JVM parameters to specify the path: `-Ddubbo.properties.file=xxx.properties`. - -### 2.1 Coverage relationship - -If the same configuration item is specified through multiple configuration sources, configuration items will overlap each other. Please refer to the next section for specific coverage relationship and priority. - -## 3 Configuration loading process - -### 3.1 Processing flow - -Dubbo configuration loading is roughly divided into two stages: - -![Configuration loading process](/imgs/v3/config/config-load.svg) - -* The first stage is before the initialization of DubboBootstrap, parse and process the XML configuration/annotation configuration/Java-config or execute the API configuration code when the Spring context starts, create a config bean and add it to the ConfigManager. -* The second stage is the DubboBootstrap initialization process, which reads the external configuration from the configuration center, processes instance-level attribute configuration and application-level attribute configuration in turn, and finally refreshes the attributes of all configuration instances, that is, [property override](../principle#32 -property override). - -### 3.2 Property Override - -There may be two situations where property overriding occurs, and the two may occur at the same time: -1. The same configuration item is configured in different configuration sources -2. The same configuration source, but the same configuration item is specified at different levels - -#### 3.2.1 Different configuration sources - -![Override relationship](/imgs/blog/configuration.jpg) - -#### 3.2.1 Same configuration source - -Property override refers to overriding the properties of the config bean instance with the configured property values, similar to Spring [PropertyOverrideConfigurer](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/ factory/config/PropertyOverrideConfigurer.html) . - -> Property resource configurer that overrides bean property values in an application context definition. It pushes values from a properties file into bean definitions. -Configuration lines are expected to be of the following form: -> -> beanName.property=value - -But the difference from `PropertyOverrideConfigurer` is that Dubbo's property override has multiple matching formats, and the priority from high to low is: - -```properties -#1. Instance-level configuration of the specified id -dubbo.{config-type}s.{config-id}.{config-item}={config-item-value} - -#2. Specify the instance-level configuration of the name -dubbo.{config-type}s.{config-name}.{config-item}={config-item-value} - -#3. Application-level configuration (singular configuration) -dubbo.{config-type}.{config-item}={config-item-value} -``` - -Attribute override processing flow: - -Search in order of priority from high to low. If an attribute starting with this prefix is found, use this prefix to extract the attribute and ignore the subsequent configuration. - -![Properties Override Process](/imgs/v3/config/properties-override.svg) - -### 3.3 Externalization configuration - -One of the purposes of external configuration is to achieve centralized management of configuration. There are already many mature professional configuration systems in this part of the industry, such as Apollo, Nacos, etc. What Dubbo does is mainly to ensure that it can work with these systems. - -There is no difference in content and format between externalized configuration and other local configurations. It can be simply understood as the externalized storage of `dubbo.properties`. The configuration center is more suitable for extracting some public configurations such as registration centers and metadata center configurations for future use. centralized management. - -```properties -# Centralized management of registration center address, metadata center address and other configurations can achieve a unified environment and reduce development-side perception. -dubbo.registry.address=zookeeper://127.0.0.1:2181 -dubbo.registry.simplified=true - -dubbo.metadata-report.address=zookeeper://127.0.0.1:2181 - -dubbo.protocol.name=dubbo -dubbo.protocol.port=20880 - -dubbo.application.qos.port=33333 -``` - -- priority - By default, the externalized configuration has a higher priority than the local configuration, so the content configured here will override the local configuration value. There is a separate chapter explaining the [Override Relationship] (#21-Override Relationship) between various configuration forms. - -- scope - There are two levels of external configuration: global and application. The global configuration is shared by all applications. The application-level configuration is maintained by each application and is only visible to itself. Currently supported extensions include Zookeeper, Apollo, and Nacos. - -#### 3.3.1 How to use external configuration - -1. Add config-center configuration - -```xml - -``` - -2. Add global configuration items in the corresponding configuration center (zookeeper, Nacos, etc.), take Nacos as an example as follows: - -![nacos-extenal-properties](/imgs/v3/config-center/nacos-extenal-properties.png) - -After the external configuration is enabled, global configurations such as registry, metadata-report, protocol, and qos theoretically no longer need to be configured in the application. The application development side focuses on business service configuration, and some globally shared global configurations are transferred to O&M. The personnel are uniformly configured in the remote configuration center. - -The effect of this is that the application only needs to care about: -* Service exposure, subscription configuration -* Configuration center address - When deployed to different environments, other configurations can be automatically read from the corresponding configuration center. - -For example, only the following Dubbo-related configurations in each application may be sufficient, and the rest are hosted in the configuration center in the corresponding environment: - -```yaml -dubbo - application - name: demo - config-center - address: nacos://127.0.0.1:8848 -``` - -#### 3.3.2 Load external configuration by itself - -The so-called Dubbo's support for the configuration center is essentially to pull `.properties` from the remote to the local, and then integrate it with the local configuration. In theory, as long as the Dubbo framework can get the required configuration, it can start normally. It doesn't care whether these configurations are loaded by itself or directly inserted by the application, so Dubbo also provides the following APIs to allow users to organize themselves. The configuration is stuffed into the Dubbo framework (the configuration loading process is to be completed by the user), so that the Dubbo framework no longer directly interacts with Apollo or Zookeeper to read the configuration. - -```java -// The application loads its own configuration -Map dubboConfigurations = new HashMap<>(); - dubboConfigurations.put("dubbo.registry.address", "zookeeper://127.0.0.1:2181"); - dubboConfigurations.put("dubbo.registry.simplified", "true"); - -//Throw the organized configuration into the Dubbo framework - ConfigCenterConfig configCenter = new ConfigCenterConfig(); - configCenter.setExternalConfig(dubboConfigurations); -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/config/properties.md b/content/en/docs3-v2/java-sdk/reference-manual/config/properties.md deleted file mode 100644 index 38570073b1a4..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/config/properties.md +++ /dev/null @@ -1,558 +0,0 @@ ---- -type: docs -title: "Configuration Item Reference Manual" -linkTitle: "Configuration Item Manual" -weight: 6 -description: "Contains all configuration components supported by Dubbo and all configuration items supported by each configuration component" ---- - -## Configuration Details - -### application - -Each application must have one and only one application configuration, corresponding configuration class: `org.apache.dubbo.config.ApplicationConfig` - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| name | application | string | Required | | Service Governance| The name of the current application, which is used by the registry to calculate dependencies between applications. Note: the consumer and provider application names should not be the same, this parameter is not Matching conditions, you can fill in the name of your current project, which has nothing to do with the role of the provider and consumer. For example, if the kylin application calls the service of the morgan application, the kylin project will be kylin, and the morgan project will be morgan. Maybe kylin also provides other The service is used by others, but the kylin project will always be dubbed kylin, so the registry will show that kylin depends on morgan | version 2.7 .0 or later | -compiler | compiler | string | optional | javassist | performance optimization | Java bytecode compiler, used to generate dynamic classes, optional: jdk or javassist | version 2.7.0 or later | -| logger | logger | string | optional | slf4j | performance optimization | log output method, optional: slf4j, jcl, log4j, log4j2, jdk | version 2.7.0 or later | -| owner | owner | string | Optional | | Service Governance | The person in charge of the application, used for service governance, please fill in the email prefix of the person in charge | Version above 2.0.5 | -| organization | organization | string | Optional | | Service Governance | Organization name (BU or department), which is used by the registration center to distinguish service sources. It is recommended not to use autoconfig for this configuration item, and write it directly in the configuration, such as china, intl, itu, crm, asc, dw, aliexpress, etc. | Version 2.0.0 and above | -| architecture
| architecture
| string | optional | | Service Governance | . Different architectures use different layers. | Version 2.0. 7 and above | -| environment | environment | string | Optional | | Service Governance | Application environment, such as: develop/test/product, different environments use different default values, and it is only used as a restriction for developing and testing functions | 2.0.0 and above version | -| version | application.version | string | optional | | service governance | current application version | version 2.7.0 or later | -| dumpDirectory | dump.directory | string | Optional | | Service Governance | When the process has a problem such as the thread pool is full, the storage path of the framework's automatic dump file | Version 2.7.0 or later | -| qosEnable | qos.enable | boolean | Optional | | Service governance | Whether to enable the qos operation and maintenance port | Version 2.7.0 or later | -| qosHost | qos.host | string | Optional | | Service Governance | Network interface address to monitor, default 0.0.0.0 | Version 2.7.3 or later | -| qosPort | qos.port | int | optional | | service governance | network port to monitor | version 2.7.0 or later | -| qosAcceptForeignIp | qos.accept.foreign.ip | boolean | Optional | | Service Governance | Security configuration, whether to accept external requests except localhost local access | Version 2.7.0 or later | -| shutwait | dubbo.service.shutdown.wait | string | optional | | service governance | shutdown waiting time (ms) during graceful shutdown | version 2.7.0 or later | -| hostname | | string | optional | local hostname | service governance | hostname | version 2.7.5 or later | -| registerConsumer | registerConsumer | boolean | optional | true | service governance | whether to register the instance to the registry. Only set to `false` when the instance is a pure consumer | Version 2.7.5 and above | -| repository | application.version | string | optional | | service governance | current application version | version 2.7.6 or later | -| enableFileCache | file.cache | boolean | optional | true | service governance | whether to enable local cache | version 3.0.0 or later | -| protocol | | string | optional | dubbo | service governance | preferred protocol, applicable when the preferred protocol cannot be determined | version 3.0.0 or later | -| metadataType | metadata-type |String| Optional | local | Service Governance | Application-level service discovery The metadata delivery method is from the perspective of Provider, and the configuration on the Consumer side is invalid. The optional values are:
* remote - Provider Put the metadata in the remote registry, and the Consumer gets it from the registry;
* local - Provider puts the metadata locally, and the Consumer gets it directly from the Provider; | Version 2.7.5 and above | -| -| metadataServicePort | metadata-service-port | int | Optional | | Service Governance | If metadataType is configured as local, this property sets the port number used by the MetadataService service | Version 2.7.9 or later | -| livenessProbe | liveness-probe | string | optional | | service governance | concept and format corresponding to k8s system liveness probe | version 3.0.0 or later | -| readinessProbe | readiness-probe | string | optional | | service governance | concept and format corresponding to k8s system readiness probe | version 3.0.0 or later | -| startupProbe | startup-probe | string | Optional | | Service Governance | The concept and format correspond to the k8s system startup probe | Version 3.0.0 or later | -| registerMode | register-mode | string | Optional | all | Service Governance | Control address registration behavior, used for application-level service discovery and migration.
* instance only registers application-level addresses;
* interface only registers interface-level addresses;
* all (default) registers both application-level and interface-level addresses; | Version 3.0.0 and above | -| enableEmptyProtection | enable-empty-protection | boolean | Optional | true | Service Governance | Whether to enable the protection of the empty address list on the consumer side globally. After enabling it, the empty address push from the registration center will be ignored. The default is true | Version 3.0.0 or later | -| parameters | None | Map | Optional | | Service Governance | Reserved for extensions, any parameters can be extended and defined, and all extended parameters will be reflected in the URL configuration as they are | Version 2.7.0 and above | - - -### service - -A service provider exposes service configuration. Corresponding configuration class: `org.apache.dubbo.config.ServiceConfig` - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| interface | | class | required | | service discovery | service interface name | version 1.0.0 or later | -| ref | | object | required | | service discovery | service object implementation reference | version 1.0.0 or later | -| version | version | string | optional | 0.0.0 | service discovery | service version, it is recommended to use a two-digit version, such as: 1.0, usually the version number needs to be upgraded when the interface is not compatible | version 1.0.0 or later | -| group | group | string | optional | | service discovery | service grouping, when an interface has multiple implementations, they can be distinguished by grouping | version 1.0.7 or later | -| path | | string | optional | default interface name | service discovery | service path (note: 1.0 does not support custom path, always use the interface name, if there is 1.0 to 2.0, the configuration service path may not be Compatible) | Version 1.0.12+ | -| delay | delay | int | Optional | 0 | Performance tuning | Delayed registration service time (milliseconds), when set to -1, it means that the service is delayed until the initialization of the Spring container is completed | Version 1.0.14 and above | -timeout | timeout | int | optional | 1000 | performance tuning | remote service call timeout (milliseconds) | version 2.0.0 or later | -| retries | retries | int | Optional | 2 | Performance tuning | The number of remote service call retries, excluding the first call, please set it to 0 if you don't need to retry | Version 2.0.0 or later | -connections | connections | int | optional | 100 | performance tuning | the maximum number of connections for each provider, short connection protocols such as rmi, http, and hessian indicate the limit on the number of connections, and long connection agreements such as dubbo indicate the established long connections Number | Version 2.0.0 or above | -loadbalance | loadbalance | string | optional | random | performance tuning | load balancing strategy, optional values:
* random - random;
* roundrobin - polling;
* leastactive - Least active calls; br/>* consistenthash - consistent hash (2.1.0+);
* shortestresponse - shortest response (2.7.7+);| 2.0.0+| -| async | async | boolean | Optional | false | Performance tuning | Whether to execute asynchronously by default, unreliable asynchronous, just ignore the return value, do not block the execution thread | Version above 2.0.0 | -| local | local | class/boolean | optional | false | service governance | set to true, means to use the default proxy class name, that is: interface name + Local suffix, obsolete, please use stub| 2.0.0 or above | -| stub | stub | class/boolean | Optional | false | Service Governance | Set to true, which means to use the default proxy class name, that is: interface name + Stub suffix, the local proxy class name of the service interface client, used in the client The client executes local logic, such as local cache, etc. The constructor of the local proxy class must allow remote proxy objects to be passed in, such as: public XxxServiceStub(XxxService xxxService) | Version 2.0.0 or later | -| mock | mock | class/boolean | Optional | false | Service Governance | Set to true, which means to use the default Mock class name, that is: interface name + Mock suffix, if the service interface fails to call the Mock implementation class , the Mock class must have A no-argument constructor, the difference from Local is that Local is always executed, while Mock is only executed when non-business exceptions (such as timeouts, network exceptions, etc.) occur, Local is executed before remote calls, and Mock is executed after remote calls . | Version 2.0.0 and above | -| token | token | string/boolean | Optional | | service governance | Consumers bypass the registration center for direct access to ensure that the authorization function of the registration center is valid. If point-to-point calls are used, the token function must be turned off | version 2.0.0 or later | -| registry | | string | optional | default registration to all registries | configuration association | registration to the specified registry, used in multiple registries, the value is the id attribute of , used for multiple registries IDs Separated by commas, If you don't want to register the service to any registry, you can set the value to N/A | Version 2.0.0 or later | -| provider | | string | optional | the first provider configuration is used by default | configuration association | specify the provider, the value is the id attribute of | version above 2.0.0 | -| deprecated | deprecated | boolean | Optional | false | Service Governance | Whether the service is deprecated, if set to true, the consumer will print the service deprecated warning error log | 2.0.5 or later | -| dynamic | dynamic | boolean | Optional | true | Service Governance | Whether the service is dynamically registered, if it is set to false, the disabled status will be displayed after registration, and it needs to be manually enabled, and the registration will not be canceled automatically when the service provider stops , need to be disabled manually. | Version 2.0.5 and above | -| accesslog | accesslog | string/boolean | optional | false | service management | set to true, the access log will be output to the logger, and the access log file path can also be filled in to output the access log directly to the specified file | 2.0.5 and above version | -| owner | owner | string | optional | | service governance | -| document | document | string | optional | | service governance | service document URL | version 2.0.5 or later | -| weight | weight | int | optional | | performance tuning | service weight | version 2.0.5 or later | -| executes | executes | int | optional | 0 | performance tuning | the maximum number of parallel execution requests per service and method of a service provider | version 2.0.5 or later | -actives | actives | int | optional | 0 | performance tuning | maximum number of concurrent calls per service consumer per service per method | version 2.0.5 or later | -proxy | proxy | string | optional | javassist | performance tuning | generate dynamic proxy, optional: jdk/javassist | version 2.0.5 or later | -cluster | cluster | string | optional | failover | performance tuning | cluster mode, optional: failover/failfast/failsafe/failback/forking/available/mergeable (2.1. )/zone-aware (version 2.7.5 or later) | version 2.0 .5 or later | -filter | service.filter | string | optional | default | performance tuning | service provider remote call process interceptor name, multiple names separated by commas | version 2.0.5 or later | -| listener | exporter.listener | string | optional | default | performance tuning | service provider export service listener name, multiple names separated by commas | | -| protocol | | string | optional | | configuration association | use the specified protocol to expose the service, used in multi-protocol, the value is the id attribute of , multiple protocol IDs are separated by commas | version 2.0 .5 or later | -| layer | layer | string | optional | | service governance | the layer where the service provider resides. Such as: biz, dao, intl:web, china:acton. | Version 2.0.7 and above | -| register | register | boolean | optional | true | service governance | whether the service of this protocol is registered to the registry | version 2.0.8 or later | -| validation | validation | string | optional | | service governance | whether to enable JSR303 standard annotation validation, if enabled, the annotations on the method parameters will be validated | version 2.7.0 or later | -| parameters | None | Map | Optional | | Service Governance | Reserved for extensions, any parameters can be extended and defined, and all extended parameters will be reflected in the URL configuration as they are | Version 2.0.0 and above | - -### reference - - -A service consumer references a service configuration. Corresponding configuration class: `org.apache.dubbo.config.ReferenceConfig` - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| id | | string | required | | configuration association | service reference BeanId | version 1.0.0 or later | -| interface | | class | required | | service discovery | service interface name | version 1.0.0 or later | -| version | version | string | optional | | service discovery | service version, consistent with the version of the service provider | version above 1.0.0 | -| group | group | string | optional | | service discovery | service grouping, when an interface has multiple implementations, they can be distinguished by grouping, must be consistent with the service provider | version 1.0.7 or later | -| timeout | timeout | long | optional | timeout of is used by default | performance tuning | service method call timeout (milliseconds) | version 1.0.5 or later | -retries | retries | int | optional | retries of are used by default | performance tuning | retries of remote service calls, excluding the first call, please set to 0 | 2.0. Version 0 and above | -connections | connections | int | optional | default connections of | performance tuning | the maximum number of connections for each provider, rmi, http, hessian and other short connection protocols indicate the limit of the number of connections, dubbo The equal-length connection association indicates the number of established long connections | Version 2.0.0 or later | -| loadbalance | loadbalance | string | optional | default loadbalance of | performance tuning | load balancing strategy, optional values:
* random - random;
* roundrobin - round
* leastactive - least active call;
* consistenthash - consistent hash (version 2.1.0 and above);
* shortestresponse - shortest response (version 2.7.7 and above); | 2.0 .0+ version | -| async | async | boolean | optional | async of is used by default | performance tuning | whether to execute asynchronously, unreliable and asynchronous, just ignore the return value and not block the execution thread | version 2.0.0 or later | -| generic | generic | boolean | optional | default generic | service governance | whether to default the generic interface, if it is a generic interface, it will return GenericService | version 2.0.0 or later | -| check | check | boolean | optional | default check of | service governance | check whether the provider exists at startup, true will report an error, false will ignore | version 2.0.0 or later | -| url | url | string | optional | | service governance | point-to-point direct connection service provider address, will bypass the registration center | version 1.0.6 or later | -| stub | stub | class/boolean | Optional | | Service Governance | The name of the service interface client's local proxy class, which is used to execute local logic on the client, such as local cache, etc. The constructor of the local proxy class must allow input Remote proxy object, constructor such as: public XxxServiceLocal(XxxService xxxService) | version 2.0.0 or later | -| mock | mock | class/boolean | Optional | | Service Governance | Service interface call failure Mock implementation class name, the Mock class must have a no-argument constructor, the difference from Local is that Local is always executed, while Mock Execute only When a non-business exception occurs (such as timeout, network exception, etc.), Local is executed before the remote call, and Mock is executed after the remote call. | Supported by Dubbo1.0.13 and above | -| cache | cache | string/boolean | Optional | | Service Governance | The call parameter is used as the key to cache the returned result, optional: lru, threadlocal, jcache, etc. | Supported by Dubbo2.1.0 and above | -| validation | validation | boolean | optional | | service governance | whether to enable JSR303 standard annotation validation, if enabled, the annotations on the method parameters will be validated | Dubbo2.1.0 and above versions support | -proxy | proxy | boolean | optional | javassist | performance tuning | choose dynamic proxy implementation strategy, optional: javassist, jdk | version above 2.0.2 | -| client | client | string | optional | | performance tuning | client transport type setting, such as netty or mina of Dubbo protocol. | Supported by Dubbo2.0.0 and above | -| registry | | string | optional | By default, the service list will be obtained from all registries and the results will be merged | Configuration Association | Register to obtain the service list from the specified registry, used when there are multiple registries, the value is The id attribute, multiple registration center IDs are separated by commas | Version 2.0.0 or later | -| owner | owner | string | Optional | | Service Governance | To call the person in charge of the service for service governance, please fill in the email prefix of the person in charge | Version above 2.0.5 | -actives | actives | int | optional | 0 | performance tuning | maximum number of concurrent calls per service consumer per service per method | version 2.0.5 or later | -cluster | cluster | string | optional | failover | performance tuning | cluster mode, optional: failover/failfast/failsafe/failback/forking/available/mergeable (2.1. )/zone-aware (version 2.7.5 or later) | version 2.0 .5 or later | -connections | connections | int | optional | 100 | performance tuning | the maximum number of connections for each provider, short connection protocols such as rmi, http, and hessian indicate the limit on the number of connections, and long connection agreements such as dubbo indicate the established long connections Number | Version 2.0.0 or above | -filter | reference.filter | string | optional | default | performance tuning | service consumer remote call process interceptor name, multiple names separated by commas | version 2.0.5 or later | -listener | invoker.listener | string | optional | default | performance tuning | The service consumer quotes the name of the service listener, and multiple names are separated by commas | Version 2.0.5 or later | -| layer | layer | string | optional | | service governance | the layer where the service caller resides. Such as: biz, dao, intl:web, china:acton. | Version 2.0.7 and above | -| init | init | boolean | optional | false | Performance tuning | Whether to starvely initialize the reference when afterPropertiesSet(), otherwise wait until someone injects or references the instance before initializing. | Version 2.0.10 and above | -| protocol | protocol | string | optional | | service governance | only call the service provider of the specified protocol, and ignore other protocols. | Version 2.7.0 and above | -client | client | string | optional | dubbo protocol defaults to netty | service discovery | protocol client implementation type, such as: dubbo protocol mina, netty, etc. | version 2.7.0 or later | -| providerPort | provider-port | int | Optional | | Service Mesh | When dubbo.consumer.meshEnable=true, Dubbo will convert the request to K8S standard format by default, and combine VirtualService and DestinationRule for traffic management. At this time, the consumer can perceive to provider. If you don't want to use VirtualService and DestinationRule, please set providerPort to make the consumer aware of the service port exposed by the provider | Version 3.1.0 and above | -| unloadClusterRelated | unloadClusterRelated | boolean | Optional | false | Service Mesh | When dubbo.consumer.meshEnable=true, in Service Mesh mode, set it to true to unload the Directory, Router and Load Balance related to the Cluster in the current call , Delegate retry, load balancing, timeout and other traffic management functions to Sidecar, use VirtualService and DestinationRule for traffic management | Version 3.1.0 and above | -| parameters | None | Map | Optional | | Service Governance | Reserved for extensions, any parameters can be extended and defined, and all extended parameters will be reflected in the URL configuration as they are | Version 2.0.0 and above | -| providedBy | provided-by | string | Optional | | Service Mesh | When dubbo.consumer.meshEnable=true, Dubbo will convert the request to K8S standard format by default, and combine VirtualService and DestinationRule for traffic management. At this time, the consumer can perceive to provider. The value should be consistent with the declared `k8s service` | Version 3.1.0 or later | -| providerNamespace | provider-namespace | string | Optional | | Service Mesh | When dubbo.consumer.meshEnable=true, Dubbo will convert the request into K8S standard format by default, and combine VirtualService and DestinationRule for traffic management. At this time, the Consumer can perceive to provider. Please set the providerNamespace so that the consumer can address the provider dns according to this configuration, the default `default` | version 3.1.2 or later | - - -### registry - -Registry configuration. Corresponding configuration class: `org.apache.dubbo.config.RegistryConfig`. At the same time, if there are multiple different registries, you can declare multiple `` tags, and specify the registry to use in the `registry` attribute of `` or `` . - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| id | | string | optional | | configuration association | the registration center references the BeanId, which can be referenced in or | version 1.0.16 or later | -| address | | string | Required | | Service discovery| The address of the registration center server. If the address has no port, the default is 9090. Multiple addresses in the same cluster are separated by commas. Such as: ip:port, ip:port, registry centers of different clusters, please configure multiple tags | Version 1.0.16 or later | -| protocol | | string | optional | dubbo | service discovery | registry address protocol, support `dubbo`, `multicast`, `zookeeper`, `redis`, `consul(2.7. .2)`, `etcd( 2.7.2)`, `nacos(2.7.2)` and other protocols | Version 2.0.0 and above | -| port | | int | optional | 9090 | service discovery | the default port of the registry, when the address does not have a port, use this port as the default value | version 2.0.0 or later | -| username | | string | Optional | | Service Governance | Username for logging in to the registration center, if the registration center does not require verification, it can be left blank | Version 2.0.0 or later | -| password | | string | Optional | | Service Governance | Password for logging in to the registration center, if the registration center does not require verification, you can leave it blank | Version 2.0.0 or later | -transport | registry.transporter | string | optional | netty | performance tuning | network transport mode, optional mina, netty | version 2.0.0 or later | -| timeout | registry.timeout | int | optional | 5000 | performance tuning | registry center request timeout (milliseconds) | version 2.0.0 or later | -| session | registry.session | int | optional | 60000 | Performance tuning | Registry session timeout (milliseconds), used to detect dirty data after abnormal disconnection of the provider, such as the implementation of heartbeat detection, this time It is the heartbeat interval , which is different for different registration centers. | Version 2.1.0 and above | -| zone | zone | string | optional | | service governance | the region to which the registry belongs, usually used for traffic isolation | version 2.7.5 or later -| file | registry.file | string | Optional | | Service Governance | Use a file to cache the registry address list and service provider list. When the application is restarted, it will be restored based on this file. Note: two registries cannot use the same file storage | Version 2.0.0 or later | -| wait | registry.wait | int | optional | 0 | performance tuning | wait notification completion time (milliseconds) when stopping | version 2.0.0 or later | -| check | check | boolean | optional | true | service governance | whether to report an error when the registration center does not exist | version 2.0.0 or later | -| register | register | boolean | Optional | true | Service Governance | Whether to register the service with this registry, if set to false, it will only subscribe and not register | Version 2.0.5 and above | -| subscribe | subscribe | boolean | optional | true | service governance | whether to subscribe to this registry service, if set to false, it will only register, not subscribe | version 2.0.5 or later | -| dynamic | dynamic | boolean | Optional | true | Service Governance | Whether the service is dynamically registered, if it is set to false, it will be displayed as disabled after registration, it needs to be manually enabled, and when the service provider stops , it will not be automatically unregistered , need to be disabled manually. | Version 2.0.5 and above | -| group | group | string | Optional | dubbo | Service Governance | Service registration grouping, cross-group services will not affect each other, and cannot call each other, suitable for environment isolation. | Version 2.0.5 and above | -| version | version | string | optional | | service discovery | service version | version above 1.0.0 | -| simplified | simplified | boolean | optional | false | service governance | whether the URL registered to the registration center is in simplified mode (compatible with lower versions) | version 2.7.0 or later | -| extra-keys | extraKeys | string | Optional | | Service Governance | When simplified=true, extraKeys allows you to put extra keys in the URL besides the default parameters, in the format: "interface,key1,key2". | Version 2.7 .0 and above | -| useAsConfigCenter | | boolean | optional | | service governance | whether the registry is used as a configuration center | version 2.7.5 or later | -| useAsMetadataCenter | | boolean | optional | | service governance | whether the registry is used as a metadata center | version 2.7.5 or later | -| accepts | accepts | string | Optional | | Service Governance | The registry receives a list of rpc protocols, multiple protocols are separated by commas, such as dubbo, rest | version 2.7.5 or later | -| preferred | preferred | boolean | optional | | service governance | whether to be the preferred registry. When subscribing to multiple registries, if set to true, the registries will be preferred | Version 2.7.5 and above | -| weight | weight | int | optional | | performance tuning | registration traffic weight. When using multiple registries, you can use this value to adjust the distribution of registration traffic. This value does not take effect when setting the preferred registry | Version 2.7. 5 or later | -| registerMode | register-mode | string | Optional | all | Service Governance | Control address registration behavior, used for application-level service discovery and migration.
* instance only registers application-level addresses;
* interface only registers interface-level addresses;
* all (default) registers both application-level and interface-level addresses; | Version 3.0.0 and above | -| enableEmptyProtection | enable-empty-protection | boolean | Optional | true | Service Governance | Whether to enable the protection of the empty address list on the consumer side globally. After enabling it, the empty address push from the registration center will be ignored. The default is true | Version 3.0.0 or later | -| parameters | None | Map | Optional | | Service Governance | Reserved for extensions, any parameters can be extended and defined, and all extended parameters will be reflected in the URL configuration as they are | Version 2.0.0 and above | - -### config-center - -configuration center. Corresponding configuration class: `org.apache.dubbo.config.ConfigCenterConfig` - -| Attribute | Corresponding URL parameter | Type | Required | Default | Description | Compatibility | -| ---------------- | ---------------------- | --------- ---------- | -------- | ---------------- | ------------- -------------------------------------------------- | -- ---- | -| protocol | protocol | string | optional | zookeeper | Which configuration center to use: apollo, zookeeper, nacos, etc.
Take zookeeper as an example
1. If the protocol is specified, the address can be simplified to `127.0.0.1:2181`;
2. If the protocol is not specified, the address value will be `zookeeper:// 127.0.0.1:2181` | Version 2.7.0 or higher | -| address | address | string | Mandatory | | Configuration center address.
See the protocol description for the value | Version 2.7.0 and above | -| highestPriority | highest-priority| boolean | optional | true | The configuration item from the configuration center has the highest priority, that is, the local configuration item will be overwritten. | Version 2.7.0 and above | -| namespace | namespace | string | optional | dubbo | Usually used for multi-tenant isolation, the actual meaning depends on the specific configuration center.
Such as:
zookeeper - environment isolation, the default value is ` dubbo`;
apollo - distinguishes configuration sets in different domains, using `dubbo` and `application` by default | Version 2.7.0 and above | -| cluster | cluster | string | optional | | The meaning depends on the selected configuration center.
It is used to distinguish different configuration clusters in Apollo | Version 2.7.0 and above | -group | group | string | optional | dubbo | The meaning depends on the selected configuration center.
nacos - isolate different configuration sets
zookeeper - isolate different configuration sets | Version 2.7.0 and above | -| check | check | boolean | optional | true | Whether to terminate the application startup when the connection to the configuration center fails. | Version 2.7.0 and above | -| configFile | config-file | string | optional | dubbo.properties | the key to which the global configuration file is mapped
zookeeper - default path /dubbo/config/dubbo/dubbo.properties
apollo - dubbo dubbo.properties key in namespace | Version 2.7.0 or later | -| appConfigFile | app-config-file | string | optional | | "configFile" is shared globally. This item is restricted to properties configured by this application | 2.7.0+ | -| timeout | timeout | int | optional | 3000ms | get the configured timeout | version 2.7.0 or later | -| username | username | string | optional | | If the configuration center needs to be verified, the username
Apollo is not enabled yet | Version 2.7.0 or later | -| password | password | string | Optional | | If the configuration center needs to be verified, the password
Apollo is not enabled yet | Version 2.7.0 or later | -| parameters | parameters | Map | Optional | | Extended parameters, used to support customized configuration parameters of different configuration centers | Version 2.7.0 or later | -| includeSpringEnv |include-spring-env| boolean | Optional | false | Supported when using the Spring framework. When true, the configuration will be automatically read from the Spring Environment.
By default,
key is dubbo .properties configuration
key is Dubbo.properties PropertySource | Version 2.7.0 or above | - -### metadata-report-config - -metadata center. Corresponding configuration class: `org.apache.dubbo.config.MetadataReportConfig` - -| Attribute | Corresponding URL parameter | Type | Required | Default | Description | Compatibility | -| --------------- | --------- | ------ | -------- | ------- -- | ----------------------------------------------- ------------- | ------ | -| address | address | string | required | | metadata center address. | Version 2.7.0 and above | -protocol | protocol | string | optional | zookeeper | metadata center protocol: zookeeper, nacos, redis, etc.
Take zookeeper as an example
1. If the protocol is specified, the address can be simplified to `127.0.0.1:2181`;
2. If the protocol is not specified, the address value will be `zookeeper:// 127.0.0.1:2181` | Version 2.7.13 and above | -| port | port | int | optional | | metadata center port number. Specify the port, then the address can be simplified, no need to configure the port number | Version 2.7.13 or later | -| username | username | string | optional | | metadata center needs to be verified, username
Apollo is not enabled yet | version 2.7.0 or later | -| password | password | string | Optional | | The metadata center needs to be verified, and the password
Apollo is not enabled yet | Version 2.7.0 or later | -| timeout | timeout | int | optional | | get metadata timeout (ms) | version 2.7.0 or later | -| group | group | string | optional | dubbo | Metadata grouping, suitable for environment isolation. It has the same meaning as the registration center group | Version 2.7.0 and above | -| retryTimes | retry-times | int | optional | 100 | number of retries | version 2.7.0 or later | -| retryPeriod | retry-period | int | optional | 3000ms | retry interval (ms) | version 2.7.0 or later | -| cycleReport | cycle-report | boolean| optional | true | Whether to update full metadata every day | Version 2.7.0 and above | -| syncReport | sync-report | boolean| optional | false | whether to update metadata synchronously, the default is asynchronous | version 2.7.0 or later | -| cluster | cluster | string | optional | | The meaning depends on the selected metadata center.
It is used to distinguish different configuration clusters in Apollo | Version 2.7.0 and above | -| file | file | string | optional | | use the file cache metadata center list, when the application is restarted, it will be restored based on this file, note: two metadata centers cannot use the same file storage | version 2.7.0 or later | -| check | check | boolean | optional | true | Whether to terminate the application startup when the metadata center connection fails. | Version 3.0.0 and above | -| reportMetadata | report-metadata | boolean | Optional | false | Whether to upload the interface configuration report metadata in the address discovery, `dubbo.application.metadata-type=remote` If the configuration does not work, it will be reported, `dubbo. Whether to report when application.metadata-type=local` is determined by the configuration value | Version 3.0.0 or later | -| reportDefinition | report-definition | boolean | Optional | true | Whether to report metadata for service operation and maintenance | Version 3.0.0 or later | -| reportConsumerDefinition | report-consumer-definition | boolean | Optional | true | Whether to report metadata for service operation and maintenance on the consumer side | Version 3.0.0 or later | -| parameters | parameters | Map | Optional | | Extended parameters, used to support customized configuration parameters of different metadata centers | Version 2.7.0 or later | - -### protocol - -Service provider protocol configuration. Corresponding configuration class: `org.apache.dubbo.config.ProtocolConfig`. At the same time, if you need to support multiple protocols, you can declare multiple `` tags, and specify the used protocol through the `protocol` attribute in ``. - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| id | | string | optional | dubbo | configuration association | protocol BeanId, you can refer to this ID in , if the ID is not filled, the default is the same as the value of the name attribute, and if it is repeated, it will be in the name followed by the serial number. | Version 2.0.5 and above | -| name | | string | Required | dubbo | Performance tuning | Protocol name | Version above 2.0.5 | -| port | | int | optional | The default port of dubbo protocol is 20880, the default port of rmi protocol is 1099, the default port of http and hessian protocol is 80; if no port is configured, The default port will be used automatically, if configured as -1, an unoccupied port will be allocated. For Dubbo 2.4.0+, the allocated port is increased on the basis of the default port of the protocol to ensure that the port segment is controllable. | Service Discovery | Service Port | Version 2.0.5 and above | -| host | | string | Optional | Automatically find local IP | Service discovery | - Service host name, used when selecting multiple network cards or specifying VIP and domain name, if it is empty, it will automatically find local IP, - it is recommended not to configure , let Dubbo automatically obtain the local IP | version 2.0.5 or later | -| threadpool | threadpool | string | optional | fixed | performance tuning | thread pool type, optional: fixed/cached/limit (above 2.5.3)/eager (above 2.6.x) | version 2.0.5 or above | -| threadname | threadname | string | optional | | performance tuning | thread pool name | version 2.7.6 or later | -| threads | threads | int | optional | 200 | performance tuning | service thread pool size (fixed size) | version 2.0.5 or later | -| corethreads | corethreads | int | optional | 200 | performance tuning | thread pool core thread size | version 2.0.5 or later | -| iothreads | threads | int | optional | number of cpus + 1 | performance tuning | io thread pool size (fixed size) | version 2.0.5 or later | -| accepts | accepts | int | optional | 0 | -| payload | payload | int | optional | 8388608(=8M) | performance tuning | request and response packet size limit, unit: byte | version 2.0.5 or later | -| codec | codec | string | optional | dubbo | performance tuning | protocol encoding | version 2.0.5 or later | -| serialization | serialization | string | optional | dubbo protocol defaults to hessian2, rmi protocol defaults to java, http protocol defaults to json | performance tuning | protocol serialization method, used when the protocol supports multiple serialization methods , such as: dubbo, hessian2, java, compactedjava of dubbo protocol, and json of http protocol, etc. | Version 2.0.5 and above | -| accesslog | accesslog | string/boolean | Optional | | Service Governance| Set to true, the access log will be output to the logger, you can also fill in the access log file path, directly output the access log to the specified file | Version 2.0.5 or later | -| path | | string | optional | | service discovery | provider context path, prefix of service path | version 2.0.5 or later | -| transporter | transporter | string | optional | dubbo protocol defaults to netty | performance tuning | protocol server and client implementation types, such as: dubbo protocol mina, netty, etc., can be split into server and client configuration | Version 2.0.5 and above | -| server | server | string | Optional | Dubbo protocol defaults to netty, http protocol defaults to servlet | Performance tuning | The server-side implementation type of the protocol, such as: mina, netty of dubbo protocol, etc., jetty of http protocol, servlet, etc. | Version 2.0.5 and above | -| client | client | string | Optional | Dubbo protocol defaults to netty | Performance tuning | Protocol client implementation type, such as: dubbo protocol mina, netty, etc. | Version 2.0.5 or later | -| dispatcher | dispatcher | string | optional | dubbo protocol defaults to all | performance tuning | protocol message distribution method, used to specify the thread model, such as: all, direct, message, execution, connection, etc. of dubbo protocol | 2.1 .0+ version | -| queues | queues | int | optional | 0 | performance tuning | thread pool queue size, when the thread pool is full, the size of the queue waiting to be executed, it is recommended not to set, when the thread pool is full, it should fail immediately, and retry other Serving provisioning machines, rather than queuing, unless there is a special need. | Version 2.0.5 and above | -| charset | charset | string | optional | UTF-8 | performance tuning | serialization encoding | version 2.0.5 or later | -| buffer | buffer | int | optional | 8192 | performance tuning | network read and write buffer size | version 2.0.5 or later | -| heartbeat | heartbeat | int | Optional | 0 | Performance Tuning| A heartbeat is required to help check if a connection is broken | 2.0.10+ | -| telnet | telnet | string | Optional | | Service Governance | Supported telnet commands, separated by commas | Version 2.0.5 and above | -| register | register | boolean | optional | true | service governance | whether the service of this protocol is registered to the registry | version 2.0.8 or later | -| contextpath | contextpath | String | optional | default is empty string | service governance | context path | version 2.0.6 or later | -| sslEnabled | ssl-enabled | boolean | optional | false | service governance | whether to enable ssl | version 2.7.5 or later | -| parameters | parameters | Map | optional | | extended parameters | version 2.0.0 or later | - -### provider - -Service provider default configuration. Corresponding configuration class: `org.apache.dubbo.config.ProviderConfig`. At the same time, this tag is the default value setting of `` and `` tags. - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| id | | string | optional | dubbo | configuration association | protocol BeanId, you can refer to this ID in | version above 1.0.16 | -| protocol | | string | optional | dubbo | performance tuning | protocol name | version 1.0.16 or later | -| host | | string | Optional | Automatically search for local IP | Service discovery | Service host name, used when selecting multiple network cards or specifying VIP and domain name, if it is empty, it will automatically search for local IP. Dubbo automatically obtains the local IP | version 1.0.16 or later | -| threads | threads | int | optional | 200 | performance tuning | service thread pool size (fixed size) | version 1.0.16 or later | -| payload | payload | int | optional | 8388608(=8M) | performance tuning | request and response packet size limit, unit: byte | version above 2.0.0 | -| path | | string | optional | | service discovery | provider context path, prefix of service path | version 2.0.0 or later | -| transporter | transporter | string | optional | dubbo protocol defaults to netty | performance tuning | protocol server and client implementation types, such as: dubbo protocol mina, netty, etc., can be split into server and client configuration | Version 2.0.5 and above | -| server | server | string | Optional | Dubbo protocol defaults to netty, http protocol defaults to servlet | Performance tuning | The server-side implementation type of the protocol, such as: mina, netty of dubbo protocol, etc., jetty of http protocol, servlet, etc. | Version 2.0.0 and above | -| client | client | string | Optional | Dubbo protocol defaults to netty | Performance tuning | Protocol client implementation type, such as: dubbo protocol mina, netty, etc. | Version 2.0.0 or later | -| dispatcher | dispatcher | string | optional | dubbo protocol defaults to all | performance tuning | protocol message distribution method, used to specify the thread model, such as: all, direct, message, execution, connection, etc. of dubbo protocol | 2.1 .0+ version | -| codec | codec | string | optional | dubbo | performance tuning | protocol encoding | version 2.0.0 or later | -| serialization | serialization | string | optional | dubbo protocol defaults to hessian2, rmi protocol defaults to java, http protocol defaults to json | performance tuning | protocol serialization method, used when the protocol supports multiple serialization methods , such as: dubbo, hessian2, java, compactedjava of the dubbo protocol, and json, xml of the http protocol | Version 2.0.5 and above | -| default | | boolean | optional | false | configuration association | whether it is the default protocol, used for multi-protocol | version 1.0.16 or later | -| filter | service.filter | string | optional | | performance tuning | service provider remote call process interceptor name, multiple names separated by commas | version 2.0.5 or later | -| listener | exporter.listener | string | optional | | performance tuning | service provider export service listener name, multiple names separated by commas | version 2.0.5 or later | -| threadpool | threadpool | string | optional | fixed | performance tuning | thread pool type, optional: fixed/cached/limit (above 2.5.3)/eager (above 2.6.x) | version 2.0.5 or above | -| threadname | threadname | string | optional | | performance tuning | thread pool name | version 2.7.6 or later | -| accepts | accepts | int | optional | 0 | -| version | version | string | optional | 0.0.0 | service discovery | service version, it is recommended to use a two-digit version, such as: 1.0, usually the version number needs to be upgraded when the interface is incompatible | version 2.0.5 or later | -| group | group | string | optional | | service discovery | service grouping, when an interface has multiple implementations, they can be distinguished by grouping | version 2.0.5 or later | -| delay | delay | int | Optional | 0 | Performance tuning | Delayed registration service time (milliseconds) - When set to -1, it means that the service is delayed until the initialization of the Spring container is completed | Version 2.0.5 and above | -| timeout | default.timeout | int | optional | 1000 | performance tuning | remote service call timeout (milliseconds) | version 2.0.5 or later | -| retries | default.retries | int | optional | 2 | Performance tuning | The number of remote service call retries, excluding the first call, please set it to 0 if you don't need to retry | Version 2.0.5 or later | -| connections | default.connections | int | optional | 0 | performance tuning | the maximum number of connections for each provider, short connection protocols such as rmi, http, and hessian indicate the limit on the number of connections, long connection agreements such as dubbo indicate the established The number of long connections | Version 2.0.5 and above | -| loadbalance | default.loadbalance | string | optional | random | performance tuning | load balancing strategy, optional values:
* random - random;
* roundrobin - round robin; leastactive - least active call;
* consistenthash - consistent hash (2.1.0+);
* shortestresponse - shortest response (2.7.7+); | 2.0.5+ | -| async | default.async | boolean | optional | false | performance tuning | whether to execute asynchronously by default, unreliable and asynchronous, just ignore the return value and not block the execution thread | Version 2.0.5 and above | -| stub | stub | boolean | Optional | false | Service Governance | If set to true, it means to use the default proxy class name, namely: interface name + Local suffix. | Version 2.0.5 and above | -| mock | mock | boolean | Optional | false | Service Governance | Set to true to use the default Mock class name, namely: interface name + Mock suffix. | Version 2.0.5 and above | -| token | token | boolean | Optional | | Service Governance | Token verification, empty means not enabled, if true, means randomly generated dynamic tokens | Version 2.0.5 and above | -| registry | registry | string | optional | register with all registries by default | configuration association | register with the specified registry, used when there are multiple registries, the value is the id attribute of , multiple registry IDs Separated by commas, if you do not want to register the service to any registry, you can set the value to N/A | Version 2.0.5 or later | -| dynamic | dynamic | boolean | Optional | true | Service Governance | Whether the service is dynamically registered, if it is set to false, the disabled status will be displayed after registration, and it needs to be manually enabled, and the registration will not be canceled automatically when the service provider stops , need to be disabled manually. | Version 2.0.5 and above | -| accesslog | accesslog | string/boolean | optional | false | service management | set to true, the access log will be output to the logger, and the access log file path can also be filled in to output the access log directly to the specified file | 2.0.5 and above version | -| owner | owner | string | optional | | service governance | -| document | document | string | optional | | service governance | service document URL | version 2.0.5 or later | -| weight | weight | int | optional | | performance tuning | service weight | version 2.0.5 or later | -| executes | executes | int | optional | 0 | performance tuning | the maximum number of parallel execution requests per service and method of a service provider | version 2.0.5 or later | -| actives | default.actives | int | optional | 0 | performance tuning | maximum number of concurrent calls per service consumer per service per method | version 2.0.5 or later | -proxy | proxy | string | optional | javassist | performance tuning | generate dynamic proxy, optional: jdk/javassist | version 2.0.5 or later | -| cluster | default.cluster | string | optional | failover | performance tuning | cluster mode, optional: failover/failfast/failsafe/failback/forking | version above 2.0.5 | -| deprecated | deprecated | boolean | Optional | false | Service Governance | Whether the service is deprecated, if set to true, the consumer will print the service deprecated warning error log | 2.0.5 or later | -| queues | queues | int | optional | 0 | performance tuning | thread pool queue size, when the thread pool is full, the size of the queue waiting to be executed, it is recommended not to set, when the thread pool is full, it should fail immediately, and retry other Serving provisioning machines, rather than queuing, unless there is a special need. | Version 2.0.5 and above | -| charset | charset | string | optional | UTF-8 | performance tuning | serialization encoding | version 2.0.5 or later | -| buffer | buffer | int | optional | 8192 | performance tuning | network read and write buffer size | version 2.0.5 or later | -| iothreads | iothreads | int | Optional | CPU + 1 | Performance tuning | IO thread pool, receive network read and write interrupts, serialize and deserialize, do not process business, business thread pool see threads configuration, this thread pool It is related to the CPU and is not recommended to be configured. | Version 2.0.5 and above | -| alive | alive | int | optional | | service management | thread pool keepAliveTime, the default unit is ms | version 2.0.5 or later | -| telnet | telnet | string | Optional | | Service Governance | Supported telnet commands, separated by commas | Version 2.0.5 and above | -| wait | wait | int | Optional | | Service Governance | Waiting time when stopping the service | -| contextpath | contextpath | String | optional | default is empty string | service governance | context path | version 2.0.6 or later | -| layer | layer | string | optional | | service governance | the layer where the service provider resides. Such as: biz, dao, intl:web, china:acton. | Version 2.0.7 and above | -| parameters | parameters | Map | optional | | service governance | extended parameters | version 2.0.0 or later | - -### consumer - -Service consumer default configuration. Configuration class: `org.apache.dubbo.config.ConsumerConfig`. At the same time, this tag is the default value setting of the `` tag. - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| timeout | default.timeout | int | optional | 1000 | performance tuning | remote service call timeout (milliseconds) | version 1.0.16 or later | -| retries | default.retries | int | optional | 2 | Performance tuning | The number of remote service call retries, excluding the first call, please set it to 0 if you do not need to retry, it is only valid when the cluster is failback/failover | Version 1.0.16 and above | -| loadbalance | default.loadbalance | string | optional | random | performance tuning | load balancing strategy, optional values:
* random - random;
* roundrobin - round robin; leastactive - least active call;
* consistenthash - consistent hash (2.1.0+);
* shortestresponse - shortest response (2.7.7+); | 1.0.16+ | -| async | default.async | boolean | optional | false | performance tuning | whether to execute asynchronously by default, unreliable and asynchronous, just ignore the return value and not block the execution thread | Version 2.0.0 or later | -| sent | default.sent | boolean | optional | true | service governance | when calling asynchronously, when the flag sent=true, it means that the network has sent data | version 2.0.6 or later | -| connections | default.connections | int | optional | 100 | performance tuning | the maximum number of connections for each service to each provider, rmi, http, hessian and other short connection protocols support this configuration, dubbo protocol long connection does not support This configuration | 1.0.16+ version | -| generic | generic | boolean | optional | false | service governance | whether to default the generic interface, if it is a generic interface, it will return GenericService | version above 2.0.0 | -| check | check | boolean | Optional | true | Service Governance | Check whether the provider exists at startup, true reports an error, false ignores | version 1.0.16 and above | -proxy | proxy | string | optional | javassist | performance tuning | generate dynamic proxy, optional: jdk/javassist | version 2.0.5 or later | -| owner | owner | string | Optional | | Service Governance | To call the person in charge of the service for service governance, please fill in the email prefix of the person in charge | Version above 2.0.5 | -| actives | default.actives | int | optional | 0 | performance tuning | maximum number of concurrent calls per service consumer per service per method | version 2.0.5 or later | -| cluster | default.cluster | string | optional | failover | performance tuning | cluster mode, optional: failover/failfast/failsafe/failback/forking/available/mergeable (2.1. above)/zone-aware(2.7.5 above) | 2.0.5 above | -| filter | reference.filter | string | optional | | performance tuning | service consumer remote call process interceptor name, multiple names separated by commas | version 2.0.5 or later | -| listener | invoker.listener | string | optional | | performance tuning | the service consumer quotes the name of the service listener, multiple names are separated by commas | version 2.0.5 or later | -| registry | | string | optional | default registration to all registries | configuration association | registration to the specified registry, used in multiple registries, the value is the id attribute of , used for multiple registries IDs Separated by commas, if you do not want to register the service to any registry, you can set the value to N/A | Version 2.0.5 or later | -| layer | layer | string | optional | | service governance | the layer where the service caller resides. Such as: biz, dao, intl:web, china:acton. | Version 2.0.7 and above | -| init | init | boolean | optional | false | Performance tuning | Whether to starvely initialize the reference when afterPropertiesSet(), otherwise wait until someone injects or references the instance before initializing. | Version 2.0.10 and above | -| cache | cache | string/boolean | Optional | | Service Governance | The call parameter is used as the key to cache the returned result, optional: lru, threadlocal, jcache, etc. | Supported by version 2.1.0 and above | -| validation | validation | boolean | optional | | service governance | whether to enable JSR303 standard annotation validation, if enabled, the annotations on the method parameters will be validated | 2.1.0 and above version support | -| version | version | string | optional | | service governance | configure multiple versions for the same service in Dubbo | 2.2.0 and above versions support | -| client | client | string | Optional | Dubbo protocol defaults to netty | Performance tuning | Protocol client implementation type, such as: dubbo protocol mina, netty, etc. | Version 2.0.0 or later | -| threadpool | threadpool | string | optional | fixed | performance tuning | thread pool type, optional: fixed/cached/limit (above 2.5.3)/eager (above 2.6.x) | version 2.0.5 or above | -| corethreads | corethreads | int | optional | 200 | performance tuning | thread pool core thread size | version 2.0.5 or later | -| threads | threads | int | optional | 200 | performance tuning | service thread pool size (fixed size) | version 2.0.5 or later | -| queues | queues | int | optional | 0 | performance tuning | thread pool queue size, when the thread pool is full, the size of the queue waiting to be executed, it is recommended not to set, when the thread pool is full, it should fail immediately, and retry other Serving provisioning machines, rather than queuing, unless there is a special need. | Version 2.0.5 and above | -| shareconnections | shareconnections | int | optional | 1 | performance tuning | number of shared connections. When the connection parameter is set to 0, the shared mode connection will be enabled, and there is only one connection by default. Only supports dubbo protocol | version 2.7.0 and above | -| referThreadNum | | int | optional | | performance optimization | thread pool size for asynchronous calls | version 3.0.0 or later | -| meshEnable | mesh-enable| boolean | optional | false | Service Mesh | Dubbo Mesh mode switch. After it is turned on, it can adapt to the SideCar mode and convert Dubbo service calls to K8S standard calls. Only supports the Triple protocol and is compatible with GRPC. After setting to true, the native docking K8S, no third-party registration center is required, just set dubbo.registry.address=N/A | Version 3.1.0 or later | -| parameters | parameters | Map | optional | | service governance | extended parameters | version 2.0.0 or later | - -### metrics - -Indicator configuration. Configuration class: `org.apache.dubbo.config.MetricsConfig` - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| protocol | protocol | string | optional | prometheus | performance tuning | protocol name, prometheus is used by default | version 3.0.0 or later | -| prometheus | | PrometheusConfig | optional | | configuration association | prometheus related configuration | version 3.0.0 or later | -| aggregation | | AggregationConfig | Optional | | Configuration association | Indicator aggregation related configuration | Version 3.0.0 or later | - -- PrometheusConfig corresponding class: `org.apache.dubbo.config.nested.PrometheusConfig` - -| Attribute | Type | Required | Default | Description | -| --- | --- | ---- | --- | --- | -| exporter.enabled | boolean | optional | | whether to enable prometheus exporter | -| exporter.enableHttpServiceDiscovery | boolean | optional | | whether to enable http service discovery | -| exporter.httpServiceDiscoveryUrl | string | optional | | http service discovery URL | -| exporter.metricsPort | int | optional | | port number to expose when using the pull method | -| exporter.metricsPath | string | optional | | path to expose metrics when using pull method | -| pushgateway.enabled | boolean | optional | | whether to publish metrics through the Pushgateway of prometheus | -| pushgateway.baseUrl | string | optional | | Pushgateway address | -| pushgateway.username | string | optional | | Pushgateway username | -| pushgateway.password | string | optional | | Pushgateway password | -| pushgateway.pushInterval | int | optional | | push indicator interval time | - -- AggregationConfig corresponding class: `org.apache.dubbo.config.nested.AggregationConfig` - -| Attribute | Type | Required | Default | Description | -| --- | --- | ---- | --- | --- | -| enabled | boolean | optional | | Whether to enable the local indicator aggregation function | -| bucketNum | int | optional | | the number of time window buckets | -| timeWindowSeconds | int | optional | | time window duration (s) | - - -### ssl - -TLS authentication configuration. Configuration class: `org.apache.dubbo.config.SslConfig` - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| serverKeyCertChainPath | server-key-cert-chain-path | string | optional | | security configuration | -| serverPrivateKeyPath | server-private-key-path | string | optional | | security configuration | server private key path | version 2.7.5 or later | -| serverKeyPassword | server-key-password | string | optional | | security configuration | server key password | version 2.7.5 or later | -| serverTrustCertCollectionPath | server-trust-cert-collection-path | string | optional | | security configuration | server trust certificate path | version 2.7.5 or later | -| clientKeyCertChainPath | client-key-cert-chain-path | string | optional | | security configuration | client signature certificate path | version 2.7.5 or later | -| clientPrivateKeyPath | client-private-key-path | string | optional | | security configuration | client private key path | version 2.7.5 or later | -| clientKeyPassword | client-key-password | string | optional | | security configuration | client key password | version 2.7.5 or later | -| clientTrustCertCollectionPath | client-trust-cert-collection-path | string | optional | | security configuration | client trust certificate path | version 2.7.5 or later | - -### module - -Module information configuration. The corresponding configuration class `org.apache.dubbo.config.ModuleConfig` - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| name | module | string | Required | | Service Governance | Current module name, used by the registry to calculate dependencies between modules | Version 2.2.0 or later | -| version | module.version | string | optional | | service governance | current module version | version 2.2.0 or later | -| owner | module.owner | string | Optional | | Service Governance | The person in charge of the module, used for service governance, please fill in the email prefix of the person in charge | Version above 2.2.0 | -| organization | module.organization | string | Optional | | Service Governance | Organization name (BU or department), which is used by the registration center to distinguish service sources. It is recommended not to use autoconfig for this configuration item, and write it directly in the configuration, such as China, intl, itu, crm, asc, dw, aliexpress, etc. | Version 2.2.0 and above | -| background | background | boolean | optional | | performance tuning | whether to enable the background startup mode. If enabled, there is no need to wait for the spring ContextRefreshedEvent event to complete | Version 3.0.0 and above | -| referAsync | referAsync | boolean | Optional | | Performance tuning | Whether to enable asynchronous calls on the consumer side | Version 3.0.0 or later | -| referThreadNum | referThreadNum | int | optional | | performance tuning | thread pool size for asynchronous calls | version 3.0.0 or later | -| exportAsync | exportAsync | boolean | Optional | | Performance tuning | Whether export is enabled on the server | Version 3.0.0 or later | -| exportThreadNum | exportThreadNum | int | optional | | asynchronous export thread pool size | | version 3.0.0 or later | - -### monitor - -Monitoring center configuration. Corresponding configuration class: `org.apache.dubbo.config.MonitorConfig` - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| protocol | protocol | string | optional | dubbo | service governance | monitoring center protocol, if it is protocol="registry", it means that the address of the monitoring center is found from the registry, otherwise it is directly connected to the monitoring center. | Version 2.0.9 and above | -| address | | string | Optional | | Service Governance | Directly connected to the monitoring center server address, address="10.20.130.230:12080" | Version 1.0.16 or later | -| username | username | string | optional | | service governance | monitoring center username | version 2.0.9 or later | -| password | password | string | optional | | service governance | monitoring center password | version 2.0.9 or later | -| group | group | string | optional | | service governance | grouping | version 2.0.9 or later | -| version | version | string | optional | | service governance | version number | version 2.0.9 or later | -| interval | interval | string | optional | | service governance | interval time | version 2.0.9 or later | -| parameters | parameters | Map | optional | | custom parameters | version 2.0.0 or later | - -### method - -Method-level configuration. Corresponding configuration class: `org.apache.dubbo.config.MethodConfig`. At the same time, this tag is a sub-tag of `service` or `reference`, which is used to control to the method level. - -for example: - -```xml - - - -``` - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| name | | string | required | | logo | method name | version 1.0.8 or later | -| timeout | .timeout | int | optional | default is timeout | performance tuning | method call timeout (milliseconds) | version 1.0.8 or later | -| retries | .retries | int | optional | The default is retries of | Performance tuning | The number of retries for remote service calls, excluding the first call, please set it to 0 | Version 2.0.0 or higher | -| loadbalance | .loadbalance | string | optional | default is loadbalance | performance tuning | load balancing strategy, optional values:
* random - random;
* roundrobin - polling ;
* leastactive - least active call;
* consistenthash - consistent hash (version 2.1.0+);
* shortestresponse - shortest response (version 2.7.7+); | 2.0. Version 0 and above | -| async | .async | boolean | Optional | The default is async of | Performance tuning | Whether to execute asynchronously, unreliable and asynchronous, just ignore the return value and not block the execution thread | 1.0.9 above version | -| sent | .sent | boolean | Optional | true | Performance tuning | When calling asynchronously, when the mark sent=true, it means that the network has sent data | Version 2.0.6 or later | -| actives | .actives | int | optional | 0 | performance tuning | maximum concurrent call limit for each service consumer | version 2.0.5 or later | -| executes | .executes | int | optional | 0 | performance tuning | the maximum number of threads used per service and method - -, this attribute is only used when is used as a subtag of Valid | Version 2.0.5 and above | -| deprecated | .deprecated | boolean | Optional | false | Service Governance | Whether the service method is deprecated, this attribute is only valid when is used as a subtag of | Version above 2.0.5 | -| sticky | .sticky | boolean | optional | false | service governance | set true All methods on this interface use the same provider. If you need more complex rules, please use routing | 2.0.6 or later | -| return | .return | boolean | Optional | true | Performance tuning | Whether the method call needs to return a value. It will take effect only when async is set to true. If it is set to true, it will return future, or call back methods such as onreturn. If set to false, Null will be returned directly after the request is sent successfully | Versions above 2.0.6 | -| oninvoke | attribute attribute, not reflected in the URL | String | Optional | | Performance tuning | Intercept before instance execution | Version 2.0.6 or later | -| onreturn | attribute attribute, not reflected in the URL | String | Optional | | Performance tuning | Intercept after instance execution returns | -| onthrow | attribute attribute, not reflected in the URL | String | optional | | performance tuning | exception interception in instance execution | -| oninvokeMethod | attribute attribute, not reflected in the URL | String | Optional | | Performance tuning | Intercept before method execution | Version 2.0.6 or later | -| onreturnMethod | attribute attribute, not reflected in the URL | String | Optional | | Performance tuning | Intercept after method execution returns | Version above 2.0.6 | -| onthrowMethod | attribute attribute, not reflected in the URL | String | Optional | | Performance tuning | Method execution has exception interception | Version 2.0.6 or later | -| cache | .cache | string/boolean | Optional | | Service Governance | Use the call parameter as the key to cache the returned result, optional: lru, threadlocal, jcache, etc. | Version above 2.1.0 | -| validation | .validation | boolean | Optional | | Service Governance | Whether to enable JSR303 standard annotation validation, if enabled, the annotations on method parameters will be validated | Version 2.1.0 or later | - -### argument - -Method parameter configuration. Corresponding configuration class: `org.apache.dubbo.config.ArgumentConfig`. This tag is a sub-tag of `method`, which is used to describe the characteristics of method parameters, such as XML format: - -```xml - - - -``` - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| index | | int | required | | identifier | parameter index | version 2.0.6 or later | -| type | | String | choose one of index and index | | identification | find parameter index by parameter type | version 2.0.6 or later | -| callback | .callback | boolean | optional | | service governance | whether the parameter is a callback interface, if it is callback, the service provider will generate a reverse proxy, and the consumer can be reversely called from the service provider , usually used for event push. | Versions above 2.0.6 | - -### parameter - -Option parameter configuration. Corresponding configuration class: `java.util.Map`. At the same time, the label is a sub-label of `protocol` or `service` or `provider` or `reference` or `consumer` or `monitor` or `registry` or `metadata-config` or `config-center`, used for configuration Custom parameters, this configuration item will be used as an extension point to set custom parameters. - -for example: - -```xml - - - -``` - -You can also: - -```xml - -``` - -| Attribute | Corresponding URL parameter | Type | Required | Default | -| --- | --- | ---- | --- | --- | --- | --- | --- | -| key | key | string | Required | | Service governance | Routing parameter key | Version 2.0.0 or later | -| value | value | string | Required | | Service governance | Routing parameter value | Version 2.0.0 or later | - -### Environment variables -The supported keys are the following two: - -1. `dubbo.labels`, specify a list of key-value pairs configured in the URL, usually through JVM -D or system environment variables. - - Add the following configuration: - - ```properties - # JVM - -Ddubbo.labels = "tag1=value1; tag2=value2" - # environment variables - DUBBO_LABELS = "tag1=value1; tag2=value2" - ``` - - The final generated URL will contain two keys tag1 and tag2: `dubbo://xxx?tag1=value1&tag2=value2` - -2. `dubbo.env.keys`, specify the environment variable key value, Dubbo will try to load each key from the environment variable - - ```properties - # JVM - -Ddubbo.env.keys="DUBBO_TAG1, DUBBO_TAG2" - # environment variables - DUBBO_ENV_KEYS = "DUBBO_TAG1, DUBBO_TAG2" - ``` - - The final generated URL will contain two keys DUBBO_TAG1 and DUBBO_TAG2: `dubbo://xxx?DUBBO_TAG1=value1&DUBBO_TAG2=value2` -### Other configuration -#### config-mode -**background** - -Some types of configuration class instances can only appear once in each dubbo application (such as `ApplicationConfig`, `MonitorConfig`, `MetricsConfig`, `SslConfig`, `ModuleConfig`), and some can appear multiple times (such as `RegistryConfig` , `ProtocolConfig`, etc.). - -If the application accidentally scans multiple unique configuration class instances (for example, the user misconfigures two `ApplicationConfig` in a dubbo application), which strategy should be used to deal with this situation? Is it throwing an exception directly? Is it to keep the former and ignore the latter? Is it to ignore the former and keep the latter? Or does it allow a certain form of coexistence (such as the attributes of the latter overriding the former)? - -Currently, the only configuration class type in dubbo and the configuration modes/strategies allowed by finding multiple instances of a unique configuration type are as follows. - -**Unique configuration class type** - -`ApplicationConfig`, `MonitorConfig`, `MetricsConfig`, `SslConfig`, `ModuleConfig`. - -The first four belong to the application level, and the last one belongs to the module level. - -**configuration mode** - -- `strict`: Strict mode. Throw an exception directly. -- `override`: override mode. Ignore the former and keep the latter. -- `ignore`: ignore pattern. Ignore the latter and keep the former. -- `override_all`: attribute override mode. No matter whether the attribute value of the former is empty or not, the attribute of the latter is overwritten/set on the former. -- `override_if_absent`: attribute override mode if absent. Only when the corresponding attribute value of the former is empty, can the attribute of the latter be overwritten/set on the former. - -Note: The latter two also affect property overrides for configuration instances. Because dubbo has multiple configuration methods, that is, there are multiple configuration sources, and the configuration sources also have priorities. For example, a `ServiceConfig` is configured through xml and the attribute `version=1.0.0` is specified. At the same time, we configure `dubbo.service.{interface}.version=2.0.0` in the external configuration (configuration center), Before the `config-mode` configuration item is introduced, according to the original configuration source priority, `version=2.0.0` of the final instance. However, after the `config-mode` configuration item is introduced, the configuration priority rules are no longer so strict, that is, if `config-mode is override_all` is specified, it is `version=2.0.0`, if `config-mode is override_if_absent` If it is `version=1.0.0`, if `config-mode` is other values, the property setting/overwriting will follow the original configuration priority. - -**Configuration method** - -The configured key is `dubbo.config.mode`, the configured values are as described above, and the default policy value is `strict`. A sample configuration is shown below - -```properties -# JVM -D --Ddubbo.config.mode=strict - -# environment variables -DUBBO_CONFIG_MODE=strict - -# External configuration (configuration center), Environment of Spring application, dubbo.properties -dubbo.config.mode=strict -``` diff --git a/content/en/docs3-v2/java-sdk/reference-manual/config/xml.md b/content/en/docs3-v2/java-sdk/reference-manual/config/xml.md deleted file mode 100644 index 21eb7d9f39f9..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/config/xml.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -type: docs -title: "XML Configuration" -linkTitle: "XML Configuration" -weight: 4 -description: "Develop Dubbo application with Spring XML" ---- - -Dubbo has custom configuration components based on Spring Schema extensions, and the configuration capabilities that can be achieved using XML are generally equivalent to [Configuration Reference Manual](../properties). - - -For complete examples of the following content, please refer to [dubbo-samples](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-spring-xml) - -## service provider - - -### Define service interface - -DemoService.java: - -```java -package org.apache.dubbo.demo; - -public interface DemoService { - String sayHello(String name); -} -``` - -### Implement the interface on the service provider side - -DemoServiceImpl.java: - -```java -package org.apache.dubbo.demo.provider; -import org.apache.dubbo.demo.DemoService; - -public class DemoServiceImpl implements DemoService { - public String sayHello(String name) { - return "Hello " + name; - } -} -``` - -### Expose services with Spring configuration declarations - -```xml - - - - - - - - - - - - - - - -``` - -### Load Spring configuration - -```java -public class DemoServiceImpl implements DemoService { - @Override - public String sayHello(String name) { - System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + - ", request from consumer: " + RpcContext. getContext(). getRemoteAddress()); - return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); - } -} -``` - -## Service Consumer - -### Reference remote services through Spring configuration - -```xml - - - - - - - - - - - -``` - -### Load Spring configuration and call remote service - -```java -public class BasicConsumer { - public static void main(String[] args) { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-demo-consumer.xml"); - context. start(); - DemoService demoService = (DemoService) context. getBean("demoService"); - String hello = demoService.sayHello("world"); - System.out.println(hello); - } -} -``` diff --git a/content/en/docs3-v2/java-sdk/reference-manual/graalvm/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/graalvm/_index.md deleted file mode 100644 index b8f80a5aa45b..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/graalvm/_index.md +++ /dev/null @@ -1,216 +0,0 @@ ---- -type: docs -title: "Dubbo Integration Graalvm Reference Manual" -linkTitle: "Dubbo Integration Graalvm Reference Manual" -toc_hide: true -hide_summary: true -weight: 9 -description: "" ---- - -dubbo3.0 supports native-image document - -## Overview - -This document will introduce the process of connecting dubbo3.0 project to GraalVM and compiling native-image into binary. - -More information about GraalVm can be read https://www.graalvm.org/docs/getting-started/container-images/ this document. - -## Use the example - -Before compiling our dubbo project, we need to make sure that we are based on the graalVm environment. - -1. Install GraalVM - -Go to https://www.graalvm.org/ official website and select the latest version to install according to your own system: - -![img](/imgs/blog/dubbo3.0-graalvm-support/graalvmgw.jpg) - -After the installation is complete, modify the path to configure JAVA_HOME, and check the local jdk after it takes effect, you can see the following: - -![img](/imgs/blog/dubbo3.0-graalvm-support/graalvm_env.jpg) -Here we use GraalVM based on jdk1.8 version. - -- To install native-image, just execute gu install native-image. - -1. Pull the dubbo code and switch to the [apache:3.0](https://github.com/apache/dubbo) branch. -2. Manually execute the generated SPI code. - -Since the current compilation of native-image does not support code dynamic generation and compilation, the part related to code dynamic generation needs to be generated manually. Here is a tool function: - -![img](/imgs/blog/dubbo3.0-graalvm-support/code_generator.jpg) -Execute CodeGenerator to generate SPI code under the dubbo-native module. - -1. Execute install in the root directory - -``` -MacdeMacBook-pro-3:incubator-dubbo mac$ pwd - -/Users/mac/Documents/Mi/project/incubator-dubbo - -MacdeMacBook-pro-3:incubator-dubbo mac$ mvn clean package install -Dmaven.test.skip=true -``` - -1. Compile the demo project - -Here we provide a sample project that can be directly compiled, dubbo-demo/dubbo-demo-native. After the above steps are installed, first go to the provider of dubbo-demo-native and execute native-image compilation: - -``` - mvn clean package -P native -Dmaven.test.skip=true -``` - -Here, since we have introduced the native-image plug-in in maven, the plug-in can be executed directly -P native. - -![img](/imgs/blog/dubbo3.0-graalvm-support/native_image_build.jpg) -After the compilation is successful, you can see the generated binary file under the target, start a zookeeper locally, and execute the binary directly. It can be seen that the startup is successful as follows: - -![img](/imgs/blog/dubbo3.0-graalvm-support/run_provider.jpg) -The consumer side also executes compilation, and a binary file is also generated under the consumer target: demo-native-consumer. Execute this binary and you can see the result of the call as follows: - -![img](/imgs/blog/dubbo3.0-graalvm-support/run_consumer.jpg) -### Specific steps - -In fact, we have done some work under this demo to ensure that the project can be compiled and executed. There are mainly the following steps - -- Introduce dubbo-native dependency - -``` - - - org.apache.dubbo - - dubbo-native - - ${project.version} - - -``` - -Under this module is the SPI code we generated. - -- Introduce native-image plugin - -``` - - - org.graalvm.nativeimage - - native-image-maven-plugin - - 21.0.0.2 - - - - - - - - native-image - - - - package - - - - - - - - false - - demo-native-provider - - org.apache.dubbo.demo.graalvm.provider.Application - - - - --no-fallback - - --initialize-at-build-time=org.slf4j.MDC - - --initialize-at-build-time=org.slf4j.LoggerFactory - - --initialize-at-build-time=org.slf4j.impl.StaticLoggerBinder - - --initialize-at-build-time=org.apache.log4j.helpers.Loader - - --initialize-at-build-time=org.apache.log4j.Logger - - --initialize-at-build-time=org.apache.log4j.helpers.LogLog - - --initialize-at-build-time=org.apache.log4j.LogManager - - --initialize-at-build-time=org.apache.log4j.spi.LoggingEvent - - --initialize-at-build-time=org.slf4j.impl.Log4jLoggerFactory - - --initialize-at-build-time=org.slf4j.impl.Log4jLoggerAdapter - - --initialize-at-build-time=org.eclipse.collections.api.factory.Sets - - --initialize-at-run-time=io.netty.channel.epoll.Epoll - - --initialize-at-run-time=io.netty.channel.epoll.Native - - --initialize-at-run-time=io.netty.channel.epoll.EpollEventLoop - - --initialize-at-run-time=io.netty.channel.epoll.EpollEventArray - - --initialize-at-run-time=io.netty.channel.DefaultFileRegion - - --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventArray - - --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventLoop - - --initialize-at-run-time=io.netty.channel.kqueue.Native - - --initialize-at-run-time=io.netty.channel.unix.Errors - - --initialize-at-run-time=io.netty.channel.unix.IovArray - - --initialize-at-run-time=io.netty.channel.unix.Limits - - --initialize-at-run-time=io.netty.util.internal.logging.Log4JLogger - - --initialize-at-run-time=io.netty.channel.unix.Socket - - --initialize-at-run-time=io.netty.channel.ChannelHandlerMask - - - - --report-unsupported-elements-at-runtime - - --allow-incomplete-classpath - - --enable-url-protocols=http - - -H:+ReportExceptionStackTraces - - - - - - -``` - -It defines the name of the generated image and some parameters for building the image. - -- mount native-image-agent - -Since we need to specify some reflection, JNI and other classes first, we need to use the agent to run it in a normal way to generate information in the form of json for these classes. - -In the startup parameters add: - -``` --agentlib:native-image-agent=config-output-dir=/tmp/config/,config-write-period-secs=300,config-write-initial-delay-secs=5 -``` - -Start in the normal way, create a folder META-INF.native-image under the resources of the project, and paste the files generated in the local directory: - -![img](/imgs/blog/dubbo3.0-graalvm-support/resources.jpg) -(There may be missing class information that is not generated, which needs to be added manually according to the error message when compiling or running.) - - - -** After completing the above steps, the project can be compiled. ** diff --git a/content/en/docs3-v2/java-sdk/reference-manual/mesh/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/mesh/_index.md deleted file mode 100644 index d94bdddaad35..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/mesh/_index.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -type: docs -title: "Mesh Manual" -linkTitle: "Mesh Manual" -weight: 7 -description: "" ---- - -An overview of Dubbo mesh usage and debugging methods. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/mesh/mesh.md b/content/en/docs3-v2/java-sdk/reference-manual/mesh/mesh.md deleted file mode 100644 index dd0676ca9f7b..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/mesh/mesh.md +++ /dev/null @@ -1,157 +0,0 @@ ---- -type: docs -title: "Debug Reference Documentation" -linkTitle: "Debug Reference Documentation" -weight: 2 -description: "Describe how to debug Dubbo mesh proxyless mode." ---- - -## Pre-environment preparation - -* docker environment -* kubernetes environment (docker desktop is recommended, with a graphical interface, and a small Kubernetes environment is embedded, and the following demonstration is also based on docker desktop) -* istio environment -* dubbo-samples code, the master branch is fine -* dubbo version >= 3.1.0 - Build a Kubernetes environment - Currently Dubbo only supports Mesh deployment in the Kubernetes environment, so you need to set up the Kubernetes environment before running and starting this example. (It is recommended to use docker desktop to build, and you can run a kubernetes environment directly) - https://docs.docker.com/desktop/install/mac-install/ - -## Build Kubernetes environment - -Currently Dubbo only supports Mesh deployment in the Kubernetes environment, so you need to set up the Kubernetes environment before running and starting this example. (It is recommended to use docker desktop to build, and you can run a kubernetes environment directly) -https://docs.docker.com/desktop/install/mac-install/ - -## Build Kubernetes environment - -Build the Istio environment reference document: -Istio installation documentation (https://istio.io/latest/docs/setup/getting-started/) -Note: When installing Istio, you need to enable first-party-jwt support (add the --set values.global.jwtPolicy=first-party-jwt parameter when using the istioctl tool to install), otherwise it will cause client authentication to fail. -Attached installation command reference: - -```java -curl -L https://istio.io/downloadIstio | sh - -cd istio-1.xx.x -export PATH=$PWD/bin:$PATH -istioctl install --set profile=demo --set values.global.jwtPolicy=first-party-jwt -y -``` - -## Start to build dubbo and dubbo-samples environment - -Enter dubbo-dependencies-bom, change grpc version to 1.41.0 - -```java -1.41.0 -``` - -Enter the dubbo-samples-xds directory and add configuration: - -```java -dubbo.application.metadataServiceProtocol=dubbo -``` - -Package the dubbo code, switch to the dubbo root directory, and execute the following command to package: - -```java -mvn clean package -DskipTests -``` - -Switch to the dubbo-samples code, and introduce the newly packaged dubbo code into the pom file of dubbo-samples-xds. -Next, modify the debug mode, taking dubbo-xds-consumer as an example: -Change the docker file of dubbo-samples-consumer and change the debug mode to suspend=y, the changed docker file is as follows: - -```java -FROM openjdk:8-jdk -ADD ./target/dubbo-samples-xds-consumer-1.0-SNAPSHOT.jar dubbo-samples-xds-consumer-1.0-SNAPSHOT.jar -EXPOSE 31000 -CMD java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=31000 /dubbo-samples-xds-consumer-1.0-SNAPSHOT.jar -``` - -Then execute the following command to package: - -```java -cd dubbo-samples/dubbo-samples-xds -mvn clean package -DskipTests -``` - -## Build docker image - -```java -cd ./dubbo-samples-xds-provider/ -# dubbo-samples-xds/dubbo-samples-xds-provider/Dockerfile -docker build -t apache/dubbo-demo:dubbo-samples-xds-provider_0.0.1 . -cd ../dubbo-samples-xds-consumer/ -# dubbo-samples-xds/dubbo-samples-xds-consumer/Dockerfile -docker build -t apache/dubbo-demo:dubbo-samples-xds-consumer_0.0.1 . -cd ../ -``` - -## Create K8s namespace - -```java -# Initialize the namespace -kubectl apply -f https://raw.githubusercontent.com/apache/dubbo-samples/master/dubbo-samples-xds/deploy/Namespace.yml - -# switch namespace -kubens dubbo-demo -``` - -If the kubens switch is unsuccessful, just install kubectl -## deploy container - -```java -cd ./dubbo-samples-xds-provider/src/main/resources/k8s -# dubbo-samples-xds/dubbo-samples-xds-provider/src/main/resources/k8s/Deployment.yml -# dubbo-samples-xds/dubbo-samples-xds-provider/src/main/resources/k8s/Service.yml -kubectl apply -f Deployment.yml -kubectl apply -f Service.yml -cd ../../../../../dubbo-samples-xds-consumer/src/main/resources/k8s -# dubbo-samples-xds/dubbo-samples-xds-consumer/src/main/resources/k8s/Deployment.yml -kubectl apply -f Deployment.yml -cd ../../../../../ -``` - -After successfully executing the above command, the docker desktop containers page looks like this, in which there are several containers in dubbo-samples, including consumer and provider: - -![docker-desktop.png](/imgs/user/docker-desktop.png) - - - -View the k8s_server_dubbo-samples-xds-provider-XXX log, the following log appears: - -```java -Dec 28, 2022 8:42:48 AM org.apache.dubbo.config.deploy.DefaultApplicationDeployer info -INFO: [DUBBO] Dubbo Application[1.1](dubbo-samples-xds-provider) is ready., dubbo version: 1.0-SNAPSHOT, current host: 10.1.5.64 -Dec 28, 2022 8:42:49 AM org.apache.dubbo.registry.xds.util.protocol.AbstractProtocol info -INFO: [DUBBO] receive notification from xds server, type: type.googleapis.com/envoy.config.listener.v3.Listener, dubbo version: 1.0-SNAPSHOT, current host: 10.1.5.64 -Dec 28, 2022 8:42:53 AM org.apache.dubbo.registry.xds.util.protocol.AbstractProtocol info -INFO: [DUBBO] receive notification from xds server, type: type.googleapis.com/envoy.config.listener.v3.Listener, dubbo version: 1.0-SNAPSHOT, current host: 10.1.5.64 -dubbo service started -``` - -![xds-provider-log.png](/imgs/user/xds-provider-log.png) - -Check the k8s_server_dubbo-samples-xds-consumer-XXX log and find that it is waiting for a debug connection: -![xds-consumer-listener.png](/imgs/user/xds-consumer-listener.png) -Open the command terminal and enter the command to view the pods that are available and in the Running state: - -```java -kubectl get pods -``` -![k8s-pods.png](/imgs/user/k8s-pods.png) - -Enter the following command to map the port of the pods to the local: - -```java -kubectl port-forward dubbo-samples-xds-consumer-64c6c6f444-kk2vr 31000:31000 -``` - -![port-forward.png](/imgs/user/port-forward.png) - -Switch to idea, edit configuration, select attach to remote JVM for debugger mode, select the port of the above docker file expose for port, select dubbo-samples-xds-consumer for module classpath, and click debug to connect successfully -![remote-debug.png](/imgs/user/remote-debug.png) - -You can see that the breakpoint has successfully entered: -![xds-debug-success.png](/imgs/user/xds-debug-success.png) -At this point, check the log of k8s_server_dubbo-samples-xds-consumer-XXX to see that it has been successfully running: -![xds-consumer-debug-success-log.png](/imgs/user/xds-consumer-debug-success-log.png) \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/_index.md deleted file mode 100644 index a2a1166e8a92..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/_index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: docs -title: "Metadata Center" -linkTitle: "Metadata Center" -weight: 6 -description: "" ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/nacos.md b/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/nacos.md deleted file mode 100644 index e9a6ab83edc8..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/nacos.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -type: docs -title: "Nacos" -linkTitle: "Nacos" -weight: 2 -description: "Basic use and working principle of Nacos metadata center" ---- - -## 1 Preparations -- Understand [Dubbo basic development steps](/en/docs3-v2/java-sdk/quick-start/spring-boot/) -- Refer to [Nacos Quick Start](https://nacos.io/zh-cn/docs/quick-start.html) to start the Nacos server - -> When Dubbo uses `3.0.0` and above, it needs to use Nacos `2.0.0` and above - -## 2 Instructions for use -The operation steps for Dubbo to integrate Nacos into a metadata center are very simple, roughly divided into two steps: `adding Maven dependencies` and `configuring the metadata center`. -> If the metadata address (dubbo.metadata-report.address) is not configured, the address of the registration center will be used as the metadata center. - -### 2.1 Add Maven dependency -If the project has enabled Nacos as the registration center, no additional configuration is required. - -If the Nacos registry is not enabled, please refer to [Adding Nacos dependencies to the registry](../../registry/nacos/#21-Add dependencies). - -### 2.2 Enable Nacos Configuration Center -```xml - -``` - -or - -```yaml -dubbo - metadata-report - address: nacos://127.0.0.1:8848 -``` - -or - -```properties -dubbo.metadata-report.address=nacos://127.0.0.1:8848 -``` - -or - -```java -MetadataReportConfig metadataConfig = new MetadataReportConfig(); -metadataConfig.setAddress("nacos://127.0.0.1:8848"); -``` - -For `address` format, please refer to [Nacos Registry - Enable Configuration](../../registry/nacos/#22-configure and enable-nacos) - -## 3 Advanced configuration - -For complete configuration parameters, please refer to [metadata-report-config](../../config/properties/#metadata-report-config). - -## 4 How it works - -### 4.1 [Service Operation and Maintenance Metadata](../overview/#2-Service Operation and Maintenance Metadata) - -On the Nacos console, you can see the metadata information related to the service operation and maintenance registered by the service provider and consumer: - -![image-dubbo-metadata-nacos-1.png](/imgs/blog/dubbo-metadata-nacos-1.png) - -In Nacos, the concept of configuration center itself exists, which happens to be used for metadata storage. In the scenario of the configuration center, there is a concept of namespace - namespace, and under the namespace, there is also the concept of group. That is, locate a configuration item through namespace, group, and dataId. If no namespace is specified, ```public``` is used as the default namespace by default. - -```properties -Provider: namespace: 'public', dataId: '{service name}:{version}:{group}:provider:{application name}', group: 'dubbo' -Consumer: namespace: 'public', dataId: '{service name}:{version}:{group}:consumer:{application name}', group: 'dubbo' -``` -`:` remains when version or group does not exist: -```properties -Provider: namespace: 'public', dataId: '{service name}:::provider:{application name}', group: 'dubbo' -Consumer: namespace: 'public', dataId: '{service name}:::consumer:{application name}', group: 'dubbo' -``` - -Providers interface metadata details (use `report-definition=true` to control whether this part of data needs to be reported): - -![image-dubbo-metadata-nacos-3.png](/imgs/blog/dubbo-metadata-nacos-3.png) - -Consumers interface meta information details (whether reporting is controlled by `report-consumer-definition=true`, the default is false): - -![image-dubbo-metadata-nacos-4.png](/imgs/blog/dubbo-metadata-nacos-4.png) - -### 4.2 [Address Discovery - Interface-Application Mapping](../overview//#11-Interface---Application Mapping Relationship) -As mentioned above, service name and application name may be one-to-many. In nacos, a single key-value is used for storage, and multiple application names are separated by English commas `,`. Since a single key-value is used to save data, there may be a problem of concurrent coverage in the case of multiple clients. Therefore, we use the ability of publishConfigCas in nacos to solve this problem. In nacos, using publishConfigCas will allow the user to pass a parameter casMd5, which means the md5 value of the previous configuration content. Before updating, different clients first check the content value of nacos, calculate the md5 value, and use it as a local certificate. When updating, pass the md5 of the credential to the server to compare the md5 value. If it is inconsistent, it means that it has been modified by other clients during this period. Re-obtain the credential and try again (CAS). At present, if the 6 retries fail, the update mapping behavior is abandoned. - -Nacos api: -```java -ConfigService configService = ... -configService.publishConfigCas(key, group, content, ticket); -``` - -The mapping information is located in namespace: 'public', dataId: '{service name}', group: 'mapping'. - -![nacos-metadata-report-service-name-mapping.png](/imgs/user/nacos-metadata-report-service-name-mapping.png) - -### 4.3 [Address Discovery - Interface Configuration Metadata](../overview/#12-Interface Configuration Metadata) - -To enable remote interface configuration metadata registration, the following configuration needs to be added to the application, because by default Dubbo3 application-level service discovery will enable service introspection mode and will not register data to the metadata center. - -```properties - dubbo.application.metadata-type=remote - ``` - -Alternatively, still enable centralized metadata registration in introspection mode - -```properties -dubbo.application.metadata-type=local -dubbo.metadata-report.report-metadata=true -``` - -The details of metadata information in Nacos server are as follows: - -![image-dubbo-metadata-nacos-2.png](/imgs/blog/dubbo-metadata-nacos-2.png) \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/overview.md b/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/overview.md deleted file mode 100644 index 846359851992..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/overview.md +++ /dev/null @@ -1,212 +0,0 @@ ---- -type: docs -title: "Overview of Metadata Center" -linkTitle: "Overview of Metadata Center" -weight: 1 ---- - -The metadata center provides access to two types of metadata in Dubbo: -- 1 address discovery metadata - - 1.1 'Interface-Application' mapping relationship - - 1.2 Interface configuration data -- 2 Service operation and maintenance metadata - - 2.1 Interface definition description data - - 2.2 Consumers subscribe to relational data - -For how to configure and open the metadata center, please refer to the specific implementation document. - -## 1 Address Discovery Metadata -[Application-level service discovery mechanism](/en/docs3-v2/java-sdk/concepts-and-architecture/service-discovery/#Application-level service discovery introduction) is introduced in Dubbo3 to solve the problem of heterogeneous microservice system interoperability and For performance issues in large-scale cluster practice, application-level service discovery will fully replace interface-level service discovery in the 2.x era. -At the same time, in order to maintain Dubbo's service/interface-oriented ease of use and flexibility of service governance, Dubbo has built a set of metadata mechanisms around application-level service discovery, namely `interface-application mapping relationship` and `interface configuration metadata`. - -### 1.1 Interface - application mapping relationship -Dubbo has always been able to achieve precise address discovery, that is, only subscribe to the services and related address lists that the Consumer declares to care about. Compared with pulling/subscribing to the full address list, this has a good performance advantage. -In the application-level service discovery model, it is not easy to subscribe to precise addresses, because Dubbo Consumer only declares the list of interfaces to be consumed, and Consumers need to be able to convert interfaces into Provider application names to subscribe to precise services. - -For this reason, Dubbo needs to maintain the corresponding relationship of `interface name->application name` in the metadata center, and Dubbo3 actively reports to the metadata center when it is started through the provider. -The mapping relationship between interface (service name) and application (Provider application name) can be one-to-many, that is, one service name may correspond to multiple different application names. - -Taking zookeeper as an example, the mapping relationship is stored in the following locations: - -```shell -$ ./zkCli.sh -$ get /dubbo/mapping/org.apache.dubbo.demo.DemoService -$ demo-provider, two-demo-provider, dubbo-demo-annotation-provider -``` - -1. The node path is `/dubbo/mapping/{interface name}` -2. Multiple application names are separated by English commas `,` - -### 1.2 Interface Configuration Metadata - -`Interface-level configuration metadata` is a supplement to address discovery. Compared with address discovery models such as Spring Cloud, which can only synchronize ip and port information, Dubbo's service discovery mechanism can synchronize information such as interface list, interface definition, and interface-level parameter configuration. . -This part of the content is calculated based on the current application's own information and interface information, and from a performance perspective, a revision is also generated based on metadata to achieve metadata aggregation between different machine instances. - -Taking Zookeeper as an example, the interface configuration metadata is stored in the following locations. If multiple instances generate the same revision, they will eventually share the same metadata configuration: - -/dubbo/metadata/{application name}/{revision} - -```shell script -[zk: localhost:2181(CONNECTED) 33] get /dubbo/metadata/demo-provider/da3be833baa2088c5f6776fb7ab1a436 -``` - -```json -{ - "app": "demo-provider", - "revision": "da3be833baa2088c5f6776fb7ab1a436", - "services": { - "org.apache.dubbo.demo.DemoService:dubbo":{ - "name": "org.apache.dubbo.demo.DemoService", - "protocol": "dubbo", - "path": "org.apache.dubbo.demo.DemoService", - "params": { - "side": "provider", - "release": "", - "methods": "sayHello, sayHelloAsync", - "deprecated": "false", - "dubbo": "2.0.2", - "pid": "38298", - "interface": "org.apache.dubbo.demo.DemoService", - "service-name-mapping": "true", - "timeout": "3000", - "generic": "false", - "metadata-type": "remote", - "delay": "5000", - "application": "demo-provider", - "dynamic": "true", - "REGISTRY_CLUSTER": "registry1", - "anyhost": "true", - "timestamp":"1626887121829" - } - }, - "org.apache.dubbo.demo.RestDemoService:1.0.0:rest":{ - "name": "org.apache.dubbo.demo.RestDemoService", - "version": "1.0.0", - "protocol": "rest", - "path": "org.apache.dubbo.demo.RestDemoService", - "params": { - "side": "provider", - "release": "", - "methods": "getRemoteApplicationName, sayHello, hello, error", - "deprecated": "false", - "dubbo": "2.0.2", - "pid": "38298", - "interface": "org.apache.dubbo.demo.RestDemoService", - "service-name-mapping": "true", - "version": "1.0.0", - "timeout": "5000", - "generic": "false", - "revision": "1.0.0", - "metadata-type": "remote", - "delay": "5000", - "application": "demo-provider", - "dynamic": "true", - "REGISTRY_CLUSTER": "registry1", - "anyhost": "true", - "timestamp": "1626887120943" - } - } - } -} -``` - -## 2 Service operation and maintenance metadata - -The service operation and maintenance metadata reported by Dubbo is usually used by various operation and maintenance systems, such as service testing, gateway data mapping, service static dependency analysis, etc. Various third-party systems can directly read and use this part of the data. For specific connection methods, please refer to the third-party systems mentioned in this chapter. - -### 2.1 Metadata reported by Provider -The metadata content stored on the provider side is as follows: - -```json -{ - "parameters": { - "side": "provider", - "methods": "sayHello", - "dubbo": "2.0.2", - "threads": "100", - "interface": "org.apache.dubbo.samples.metadatareport.configcenter.api.AnnotationService", - "threadpool": "fixed", - "version": "1.1.1", - "generic": "false", - "revision": "1.1.1", - "valid": "true", - "application": "metadatareport-configcenter-provider", - "default.timeout": "5000", - "group": "d-test", - "anyhost": "true" - }, - "canonicalName": "org.apache.dubbo.samples.metadatareport.configcenter.api.AnnotationService", - "codeSource": "file:/Users/cvictory/workspace/work-mw/dubbo-samples/dubbo-samples-metadata-report/dubbo-samples-metadata-report-configcenter/target/classes/", - "methods": [{ - "name": "sayHello", - "parameterTypes": ["java. lang. String"], - "returnType": "java.lang.String" - }], - "types": [{ - "type": "java. lang. String", - "properties": { - "value": { - "type": "char[]" - }, - "hash": { - "type": "int" - } - } - }, { - "type": "int" - }, { - "type": "char" - }] -} -``` - -There are two main parts: -* `parameters` is the service configuration and parameter details. -* `types` defines information for the service. - -##### Metadata reported by Consumer: - -```json -{ - "valid": "true", - "side": "consumer", - "application": "metadatareport-configcenter-consumer", - "methods": "sayHello", - "default.timeout": "6666", - "dubbo": "2.0.2", - "interface": "org.apache.dubbo.samples.metadatareport.configcenter.api.AnnotationService", - "version": "1.1.1", - "revision": "1.1.1", - "group": "d-test" -} -``` - -Configuration metadata used by the Consumer process when subscribing. - -## 3 Metadata reporting mechanism - -Metadata reporting is an asynchronous process by default. In order to better control the asynchronous behavior, the metadata configuration component (metadata-report) opens up two configuration items: -* Retry on failure -* Refresh regularly every day - -### 3.1 retrytimes failed retry -Failure retries can be set through retrytimes (retry times, default 100), retryperiod (retry period, default 3000ms). - -### 3.2 Timing Refresh -It is enabled by default and can be disabled by setting cycleReport=false. - -### 3.3 Complete configuration items - -```properties -dubbo.metadata-report.address=zookeeper://127.0.0.1:2181 -dubbo.metadata-report.username=xxx ##Not required -dubbo.metadata-report.password=xxx ##Not required -dubbo.metadata-report.retry-times=30 ##Non-required, default value 100 -dubbo.metadata-report.retry-period=5000 ##Not required, default value is 3000 -dubbo.metadata-report.cycle-report=false ##Not required, default value is true -dubbo.metadata-report.sync.report=false ##Not required, the default value is false -``` -> If the metadata address (dubbo.metadata-report.address) is not configured, it will judge whether the protocol of the registration center supports the metadata center. If yes, the address of the registration center will be used as the metadata center. - -## 4 Learn how to extend -See [Extending metadata-report](../../spi/description/metadata-report/) for how to extend custom third-party implementations. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/redis.md b/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/redis.md deleted file mode 100644 index a351e5f274ec..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/redis.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -type: docs -title: "Redis" -linkTitle: "Redis" -weight: 4 -description: "Basic use and working principle of Redis metadata center" ---- -Not yet supported \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/zookeeper.md b/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/zookeeper.md deleted file mode 100644 index 72683ec9ff67..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/metadata-center/zookeeper.md +++ /dev/null @@ -1,173 +0,0 @@ ---- -type: docs -title: "Zookeeper" -linkTitle: "Zookeeper" -weight: 3 -description: "Basic use and working principle of Zookeeper metadata center" ---- - -## 1 Preparations -- Understand [Dubbo basic development steps](/en/docs3-v2/java-sdk/quick-start/spring-boot/) -- Install and start [Zookeeper](https://zookeeper.apache.org/) - -## 2 Instructions for use - -### 2.1 Add Maven dependency -If the project has enabled Zookeeper as the registry, no additional configuration is required. - -If the Zookeeper registry is not used, please refer to [Add Zookeeper-related dependencies for the registry](../../registry/zookeeper/#21-add-maven-dependency). - -### 2.2 Enable Zookeeper Configuration Center -```xml - -``` - -or - -```yaml -dubbo - metadata-report - address: zookeeper://127.0.0.1:2181 -``` - -or - -```properties -dubbo.metadata-report.address=zookeeper://127.0.0.1:2181 -``` - -or - -```java -MetadataReportConfig metadataConfig = new MetadataReportConfig(); -metadataConfig.setAddress("zookeeper://127.0.0.1:2181"); -``` - -For `address` format, please refer to [zookeeper registry - enable configuration](../../registry/zookeeper/#22-configure and enable-zookeeper) - -## 3 Advanced configuration - -For complete configuration parameters, please refer to [metadata-report-config](../../config/properties/#metadata-report-config). - -## 4 How it works - -### 4.1 [Service Operation and Maintenance Metadata](../overview/#2-Service Operation and Maintenance Metadata) - -Zookeeper stores data based on a tree structure, and its metadata information is located in the following nodes: -```text -Provider: /dubbo/metadata/{interface name}/{version}/{group}/provider/{application name} -Consumer: /dubbo/metadata/{interface name}/{version}/{group}/consumer/{application name} -``` - -When the version or group does not exist, the version path and group path will be canceled, the paths are as follows: -```text -Provider: /dubbo/metadata/{interface name}/provider/{application name} -Consumer: /dubbo/metadata/{interface name}/consumer/{application name} -``` - -View data via the zkCli get operation. - -Provider node: -```shell script -[zk: localhost:2181(CONNECTED) 8] get /dubbo/metadata/org.apache.dubbo.demo.DemoService/provider/demo-provider -{"parameters":{"side":"provider","interface":"org.apache.dubbo.demo.DemoService","metadata-type":"remote","application":"demo-provider", "dubbo":"2.0.2","release":"","anyhost":"true","delay":"5000","methods":"sayHello,sayHelloAsync","deprecated":"false" ,"dynamic":"true","timeout":"3000","generic":"false"},"canonicalName":"org.apache.dubbo.demo.DemoService","codeSource":"file:/ Users/apple/IdeaProjects/dubbo/dubbo-demo/dubbo-demo-interface/target/classes/","methods":[{"name":"sayHelloAsync","parameterTypes":["java.lang.String" ],"returnType":"java.util.concurrent.CompletableFuture"},{"name":"sayHello","parameterTypes":["java.lang.String"],"returnType":"java.lang.String "}],"types":[{"type":"java.util.concurrent.CompletableFuture","properties":{"result":"java.lang.Object","stack":"java.util. concurrent.CompletableFuture.Completion"}},{"type":"java.lang.Object"},{"type":"java.lang.String"},{"type":"java.util.concurrent.CompletableFuture .Completion","properties":{"next":"java.util.concurrent.Co mpletableFuture. Completion", "status": "int"}}, {"type": "int"}]} -cZxid = 0x25a9b1 -ctime = Mon Jun 28 21:35:17 CST 2021 -mZxid = 0x25a9b1 -mtime = Mon Jun 28 21:35:17 CST 2021 -pZxid = 0x25a9b1 -cversion = 0 -dataVersion = 0 -aclVersion = 0 -ephemeralOwner = 0x0 -dataLength = 1061 -numChildren = 0 -``` - -Consumer node: -```shell script -[zk: localhost:2181(CONNECTED) 10] get /dubbo/metadata/org.apache.dubbo.demo.DemoService/consumer/demo-consumer -{"side":"consumer","interface":"org.apache.dubbo.demo.DemoService","metadata-type":"remote","application":"demo-consumer","dubbo":" 2.0.2","release":"","sticky":"false","check":"false","methods":"sayHello,sayHelloAsync"} -cZxid = 0x25aa24 -ctime = Mon Jun 28 21:57:43 CST 2021 -mZxid = 0x25aa24 -mtime = Mon Jun 28 21:57:43 CST 2021 -pZxid = 0x25aa24 -cversion = 0 -dataVersion = 0 -aclVersion = 0 -ephemeralOwner = 0x0 -dataLength = 219 -numChildren = 0 -``` - -### 4.2 [Address Discovery - Interface-Application Name Mapping](../overview/#11-Interface---Application Mapping Relationship) -In Dubbo 3.0, the service introspection mechanism is used by default to realize service discovery. For service introspection, please refer to [Service Introspection](https://mercyblitz.github.io/2020/05/11/Apache-Dubbo-%E6%9C%8D%E5%8A%A1%E8%87%AA%E7%9C%81%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/) - -In short, the service introspection mechanism needs to be able to find the corresponding application name through the interface name. This relationship can be one-to-many, that is, one service name may correspond to multiple different application names. In 3.0, the metadata center provides this mapping capability. - - -##### Zookeeper -As mentioned above, service name and application name may be one-to-many. In zookeeper, a single key-value is used for storage, and multiple application names are separated by English commas`,`. Since a single key-value is used to save data, there may be a problem of concurrent coverage in the case of multiple clients. Therefore, we use the version mechanism version in zookeeper to solve this problem. In zookeeper, every time the data is modified, the dataVersion will increase. We can use the version mechanism to solve the concurrent problem of multiple clients updating the mapping at the same time. Before updating, different clients check the version once and use it as a local certificate. When updating, pass the credential version to the server to compare the version. If it is inconsistent, it means that it has been modified by other clients during this period. Re-obtain the credential and try again (CAS). At present, if the 6 retries fail, the update mapping behavior is abandoned. - -Curator api. -```java -CuratorFramework client = ... -client.setData().withVersion(ticket).forPath(path, dataBytes); -``` - -Mapping information is located at: -```text -/dubbo/mapping/{service name} -``` - -View data via the zkCli get operation. - -```shell script -[zk: localhost:2181(CONNECTED) 26] get /dubbo/mapping/org.apache.dubbo.demo.DemoService -demo-provider, two-demo-provider, dubbo-demo-annotation-provider -cZxid = 0x25a80f -ctime = Thu Jun 10 01:36:40 CST 2021 -mZxid = 0x25a918 -mtime = Fri Jun 11 18:46:40 CST 2021 -pZxid = 0x25a80f -cversion = 0 -dataVersion = 2 -aclVersion = 0 -ephemeralOwner = 0x0 -dataLength = 62 -numChildren = 0 -``` - -### 4.3 [Address Discovery - Interface Configuration Metadata](../overview/#12-Interface Configuration Metadata) - -To enable remote interface configuration metadata registration, the following configuration needs to be added to the application, because by default Dubbo3 application-level service discovery will enable service introspection mode and will not register data to the metadata center. - -```properties - dubbo.application.metadata-type=remote - ``` - -Alternatively, still enable centralized metadata registration in introspection mode - -```properties -dubbo.application.metadata-type=local -dubbo.metadata-report.report-metadata=true -``` - -Zookeeper's application level metadata is located at /dubbo/metadata/{application name}/{revision} - -```shell script -[zk: localhost:2181(CONNECTED) 33] get /dubbo/metadata/demo-provider/da3be833baa2088c5f6776fb7ab1a436 -{"app":"demo-provider","revision":"da3be833baa2088c5f6776fb7ab1a436","services":{"org.apache.dubbo.demo.DemoService:dubbo":{"name":"org.apache.dubbo. demo.DemoService","protocol":"dubbo","path":"org.apache.dubbo.demo.DemoService","params":{"side":"provider","release":""," methods":"sayHello,sayHelloAsync","deprecated":"false","dubbo":"2.0.2","pid":"38298","interface":"org.apache.dubbo.demo.DemoService" ,"service-name-mapping":"true","timeout":"3000","generic":"false","metadata-type":"remote","delay":"5000","application" :"demo-provider","dynamic":"true","REGISTRY_CLUSTER":"registry1","anyhost":"true","timestamp":"1626887121829"}},"org.apache.dubbo.demo. RestDemoService:1.0.0:rest":{"name":"org.apache.dubbo.demo.RestDemoService","version":"1.0.0","protocol":"rest","path":"org .apache.dubbo.demo.RestDemoService","params":{"side":"provider","release":"","methods":"getRemoteApplicationName,sayHello,hello,error","deprecated":"false ","dubbo":"2.0.2","pid":"38298","interface":"org.apache.dubbo.demo .RestDemoService","service-name-mapping":"true","version":"1.0.0","timeout":"5000","generic":"false","revision":"1.0.0 ","metadata-type":"remote","delay":"5000","application":"demo-provider","dynamic":"true","REGISTRY_CLUSTER":"registry1","anyhost": "true","timestamp":"1626887120943"}}}} -cZxid = 0x25b336 -ctime = Thu Jul 22 01:05:55 CST 2021 -mZxid = 0x25b336 -mtime = Thu Jul 22 01:05:55 CST 2021 -pZxid = 0x25b336 -cversion = 0 -dataVersion = 0 -aclVersion = 0 -ephemeralOwner = 0x0 -dataLength = 1286 -numChildren = 0 -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/performance/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/performance/_index.md deleted file mode 100755 index 551396298188..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/performance/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "Performance Reference Manual" -linkTitle: "Performance Reference Manual" -weight: 8 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/performance/benchmarking.md b/content/en/docs3-v2/java-sdk/reference-manual/performance/benchmarking.md deleted file mode 100644 index 97ae6f8302ee..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/performance/benchmarking.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -type: docs -title: "Application-Level Service Discovery Benchmark" -linkTitle: "Application-Level Service Discovery Benchmark" -weight: 1 -description: "" ---- - - -## 1 Benchmark Conclusion - -Compared with 2.x version, Dubbo3 version - -- Significantly improved service discovery resource utilization. - - Compared with interface-level services, it is found that the resident memory of a single machine is reduced by 50%, and the GC consumption during the address change period is reduced by an order of magnitude (hundred times -> ten times) - - Comparing application-level services, it is found that the resident memory of a single machine is reduced by 75%, and the number of GCs tends to zero - - -The following is the detailed pressure measurement process and data - -## 2 Application-level service discovery (address push link) - -This part of the stress test data is given by the ICBC Dubbo team based on internal production data. The stress test process simulates the service discovery architecture of "production environment address + zookeeper". - -### 2.1 Environment - -| | Description | -| ------------ | ------------------------------------ ------------------------ | -| **Pressure test data** | Provider
500 running instances✖️8interface✖️5protocol, that is, each provider registers 40 URLs with the registration center, a total of 20,000 URLs, and the length of each URL is about 1k characters.

Registration center
2 independent zookeeper registration centers, service providers and consumers adopt parallel configuration.

Consumer
Configure 1c2g, xmx=768, enable GC, subscribe from 2 registries, and call the service every 5 seconds. Run for 20 hours. | -| **Pressure test environment** | Java version "1.8.0"
Java(TM) SE Runtime Environment (build pxa6480sr3fp12-20160919_01(SR3 FP12))
IBM J9 VM (Build 2.8, JRE 1.8 .0 Linux amd64-64 Compressed References 20160915_318796, JIT enabled, AOT enabled) | - - -### 2.2 Data Analysis - -![//imgs/v3/performance/registry-mem.svg](/imgs/v3/performance/registry-mem.svg) - -
Figure 1 Changes in memory usage of the service discovery model

- -- Dubbo3 interface-level service discovery model, the resident memory is reduced by about 50% compared with version 2.x -- Dubbo3 application-level service discovery model, the resident memory is reduced by about 75% compared with version 2.x - - -![//imgs/v3/performance/registry-gc.svg](/imgs/v3/performance/registry-gc.svg) - -
Figure 2 Service Discovery Model GC Changes

- -- Dubbo3 interface-level service discovery model, the number of YGC times in version 2.x has dropped significantly, from hundreds of times to more than a dozen times -- Dubbo3 application-level service discovery model, the number of FGC times in version 2.x has dropped significantly, from hundreds of times to zero \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/performance/rpc-benchmarking.md b/content/en/docs3-v2/java-sdk/reference-manual/performance/rpc-benchmarking.md deleted file mode 100644 index 0519f2e279af..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/performance/rpc-benchmarking.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -type: docs -title: "RPC Protocol Triple&Dubbo Benchmark" -linkTitle: "RPC Benchmark" -weight: 1 -description: "" ---- - -- The _Dubbo protocol_ implementation of Dubbo3 is basically the same as the Dubbo2 version in terms of performance. -- Since the Triple protocol itself is built based on HTTP/2, the RPC call on a single link is not improved compared with TCP-based Dubbo2, but has a certain decline in some call scenarios. But the greater advantage of the _Triple protocol _ lies in the gateway penetration, versatility, and overall throughput improvement brought about by the Stream communication model. -- Triple is expected to have better performance in the gateway proxy scenario. In view of the current stress testing environment, this round of benchmarks has not yet been provided. - -## 1.1 Environment - - -| | Description | -| ------------ | ------------------------------------ ------------------------ | -| **Machine** | 4C8G Linux JDK 1.8 (Provider) 4C8G Linux JDK 1.8 (Consumer) | -| **Pressure test case** | RPC method types include: no parameters and no return value, normal pojo return value, pojo list return value

2.7 version Dubbo protocol (Hessian2 serialization)
Version 3.0 Dubbo protocol (Hessian2 serialization)
3.0 version Dubbo protocol (Protobuf serialization)
3.0 version Triple protocol (Protobuf serialization)
3.0 version Triple protocol (Protobuf sets Hessian2 serialization) | -| **Pressure test method** | In a single-link scenario, the consumer starts 32 concurrent threads (the current machine configuration qps rt has a more balanced number of concurrency), and collects the pressure test data after continuous pressure
The pressure test data passes https: //github.com/apache/dubbo-benchmark Get | - -
- -## 1.2 Data Analysis - -| | **Dubbo + Hessian2
2.7** | **Dubbo + Hessian2
3.0** | **Dubbo + Protobuf
3.0** | **Triple + Protobuf
3.0** | **Triple + Protobuf(Hessian)
3.0** | -| ------------------ | ----------------------------- | ----------------------------- | -------------------- --------- | ------------------------------ | --------- --------------------------------- | -| **No parameter method** | 30333 ops/s
2.5ms P99 | 30414 ops/s
2.4ms P99 | 24123 ops/s
3.2ms P99 | 7016 ops/s< br />8.7ms P99 | 6635 ops/s
9.1ms P99 | -| **pojo return value** | 8984 ops/s
6.1 ms P99 | 12279 ops/s
5.7 ms P99 | 21479 ops/s
3.0 ms P99 | 6255 ops/s< br />8.9 ms P99 | 6491 ops/s
10 ms P99 | -| **pojo list return value** | 1916 ops/s
34 ms P99 | 2037 ops/s
34 ms P99 | 12722 ops/s
7.7 ms P99 | 6920 ops/s
9.6 ms P99 | 2833 ops/s
27 ms P99 | - -### 1.2.1 Comparison of different versions of Dubbo protocol - -![//imgs/v3/performance/rpc-dubbo.svg](/imgs/v3/performance/rpc-dubbo.svg) - -
Figure 3 Comparison of implementations of the Dubbo protocol in different versions
- -- As far as the default combination of Dubbo RPC + Hessian is concerned, the performance of Dubbo3 and Dubbo2 is basically the same in different calling scenarios - -### 1.2.2 Dubbo protocol vs Triple protocol - -![//imgs/v3/performance/rpc-triple.svg](/imgs/v3/performance/rpc-triple.svg) - -
Figure 4 Triple vs Dubbo
- -- Simply looking at the point-to-point calls of Consumer <-> Provider, it can be seen that the Triple protocol itself is not dominant. Also using the Protobuf serialization method, the overall performance of the Dubbo RPC protocol is still better than Triple.

-- Triple implementation will continue to be optimized in version 3.0, but it cannot completely change the situation where "RPC protocol based on HTTP/2" is at a disadvantage compared to "RPC protocol based on TCP" in some scenarios - -### 1.2.3 Supplementary gateway scenarios - -TBD

- -### 1.2.4 Simulate the throughput improvement of the Stream communication scenario - -TBD \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/_index.md deleted file mode 100755 index 8f99ba5944f8..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "RPC protocol" -linkTitle: "RPC Protocol" -weight: 4 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/dubbo.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/dubbo.md deleted file mode 100644 index 994c2bab578a..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/dubbo.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -type: docs -title: "Dubbo protocol" -linkTitle: "Dubbo protocol" -weight: 2 ---- - -## Feature description -Dubbo's default protocol uses a single long connection and NIO asynchronous communication, which is suitable for small data volume and large concurrent service calls, and the situation where the number of service consumer machines is much larger than the number of service provider machines. - -Conversely, Dubbo's default protocol is not suitable for services that transmit large amounts of data, such as file transfers, video transfers, etc., unless the request volume is very low. - -![dubbo-protocol.jpg](/imgs/user/dubbo-protocol.jpg) - -* Transporter: mina, netty, grizzy -* Serialization: dubbo, hessian2, java, json -* Dispatcher: all, direct, message, execution, connection -* ThreadPool: fixed, cached - - -Default protocol, using tbremoting interaction based on netty `3.2.5.Final` and hessian2 `3.2.1-fixed-2(Alibaba embed version)`. - -* Number of connections: single connection -* Connection method: long connection -* Transport protocol: TCP -* Transmission method: NIO asynchronous transmission -* Serialization: Hessian binary serialization -* Scope of application: The incoming and outgoing parameter data packets are small (recommended to be less than 100K), the number of consumers is more than that of the provider, and a single consumer cannot fill the provider. Try not to use the dubbo protocol to transfer large files or very large strings. -* Applicable scenario: regular remote service method call - -**constraint** - -* Parameters and return values need to implement `Serializable` interface -* Parameters and return values cannot be customized to implement `List`, `Map`, `Number`, `Date`, `Calendar` and other interfaces, only the implementations that come with JDK can be used, because hessian will do special processing and customize the implementation All attribute values in the class are lost. -* Hessian serialization, only pass member attribute values and value types, do not pass methods or static variables, compatibility **provided by Wu Yajun** - -| Data communication | Situation | Results | -| ------------- | ------------- | ------------- | -| A->B | Class A has one more attribute (or class B has one less attribute) | No exception is thrown, the value of the attribute with more A, B does not, and the others are normal | -| A->B | enumeration A has one more enumeration (or B has one less enumeration) | A uses the extra enumeration for transmission | throws exception | -| A->B | Enumeration A has one more enumeration (or B has one less enumeration) | A does not use the extra enumeration for transmission | No exception is thrown, B receives data normally | -| A->B | The attributes of A and B have the same name but different types | Throw an exception | -| A->B | The serialId is different | Normal transmission | - -The method added to the interface has no impact on the client. If the method is not required by the client, the client does not need to redeploy. The addition of attributes in input parameters and result sets has no effect on the client. If the client does not need new attributes, there is no need to redeploy. - -Changes in input parameters and result set attribute names have no impact on client serialization, but if the client is not redeployed, regardless of input or output, the attribute values with changed attribute names cannot be obtained. - -**Summarize** -- The server and the client do not need to be completely consistent with the domain objects, but follow the principle of maximum matching. -- An exception will be thrown: one more type of enumeration value and one less type, just use a different one, or the attribute name is the same, but the type is different. - - -## scenes to be used - -It is suitable for service calls with large concurrent and small data volumes, and the service consumer is much larger than the service provider. - -## How to use - -### Configuration protocol - -```xml - -``` - -### Set the default protocol - -```xml - -``` - -### Set the protocol of a service - -```xml - -``` - -### Multiport - -```xml - - -``` - -### Configure protocol options - -```xml - -``` - -### Multi-connection configuration - -By default, the Dubbo protocol uses a single long connection per service, per provider and per consumer. If the amount of data is large, multiple connections can be used. - -```xml - - -``` - -* `` or `` means that the service uses JVM shared persistent connection. **default** -* `` or `` means that the service uses independent persistent connections. -* `` or `` means that the service uses two independent persistent connections. - -In order to prevent being hung up by a large number of connections, the maximum number of receiving connections can be limited on the service provider to achieve self-protection of the service provider. - -```xml - -``` - -## common problem - -### Q1 -Why should there be more consumers than providers? - -Because the dubbo protocol uses a single long connection, assuming that the network is a gigabit network card **1024Mbit=128MByte**, according to the test experience data, each connection can only be filled up to 7MByte (different environments may be different, for reference), theoretically 1 A service provider needs 20 service consumers to fill up the network card. - -### Q2 -Why can't I send large packets? - -Because the dubbo protocol uses a single long connection, if the data packet size of each request is 500KByte, assuming that the network is a Gigabit network card**1024Mbit=128MByte**, each connection can be up to 7MByte (different environments may be different), a single service provides The maximum TPS (transactions per second) of the latter is: 128MByte / 500KByte = 262. The maximum TPS (transactions per second) for a single consumer to call a single service provider is: 7MByte / 500KByte = 14. If acceptable, you can consider using it, otherwise the network will become a bottleneck. - -### Q3 -Why use asynchronous single long connection? - -Because the current situation of the service is that there are few service providers, usually only a few machines, but many service consumers, the entire website may be accessing the service. For example, Morgan’s provider has only 6 providers, but there are hundreds of consumers. Or, there are 150 million calls per day. If the conventional Hessian service is used, the service provider is easily overwhelmed. Through a single connection, it is guaranteed that a single consumer will not overwhelm the provider, long-term connection, reducing connection handshake verification, etc. And use asynchronous IO, reuse thread pool, prevent C10K problem. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/grpc.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/grpc.md deleted file mode 100644 index 0f2cc472b98e..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/grpc.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -type: docs -title: "gRPC Protocol" -linkTitle: "gRPC Protocol" -weight: 5 ---- - - -## Feature description -Dubbo has supported the gRPC protocol since version 2.7.5. For developers who plan to use HTTP/2 communication, or want to take advantage of the capabilities of Stream, backpressure, and Reactive programming brought by gRPC, -You can consider enabling the gRPC protocol. - -#### Benefits of supporting gRPC -* Bring service governance capabilities to users who expect to use the gRPC protocol, and facilitate access to the Dubbo system -* Users can use Dubbo-style, interface-based programming style to define and use remote services - -## scenes to be used - -- Synchronous backend microservice-to-microservice communication that requires an immediate response to continue processing. -- Requires a Polyglot environment that supports mixed programming platforms. -- Low latency and high throughput communications where performance is critical. -- Peer-to-peer real-time communication - gRPC pushes messages in real time without polling and has excellent support for bidirectional streaming. -- Network Constrained Environments - Binary gRPC messages are always smaller than equivalent text-based JSON messages. - -## How to use -### Using gRPC in Dubbo -[Example](https://github.com/apache/dubbo-samples/tree/925c3d150d9030bc72988564e4f97eca1f6fcb89/3-extensions/protocol/dubbo-samples-grpc) - -### steps -1. Define a service using IDL -2. Configure the compiler plug-in, precompile locally -3. Configure to expose/reference Dubbo service - -> In addition to the native StreamObserver interface type, Dubbo also supports [RxJava](https://github.com/apache/dubbo-samples/tree/925c3d150d9030bc72988564e4f97eca1f6fcb89/3-extensions/protocol/dubbo-samples-grpc/dubbo-samples-rxjava), [Reactor](https://github.com/apache/dubbo-samples/tree/925c3d150d9030bc72988564e4f97eca1f6fcb89/3-extensions/protocol/dubbo-samples-grpc/dubbo-samples-reactor) programming style API. diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/hessian.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/hessian.md deleted file mode 100644 index 16a75866f35d..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/hessian.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -type: docs -title: "Hessian Agreement" -linkTitle: "Hessian Protocol" -weight: 10 ---- - - -## Feature description -The Hessian protocol is used to integrate Hessian's services. The bottom layer of Hessian uses Http communication and Servlet to expose services. Dubbo's default embedded Jetty is implemented as a server. - -[Hessian](http://hessian.caucho.com) is an open source RPC framework of Caucho, whose communication efficiency is higher than the serialization that comes with WebService and Java. - -* Number of connections: multiple connections -* Connection method: short connection -* Transmission protocol: HTTP -* Transmission method: synchronous transmission -* Serialization: Hessian binary serialization -* Scope of application: The incoming and outgoing parameter data packets are large, the number of providers is larger than that of consumers, the pressure on providers is high, and files can be transferred. -* Applicable scenarios: page transfer, file transfer, or interoperability with native Hessian services. - -Dubbo's Hessian protocol can interoperate with native Hessian services, namely: - -* The provider uses Dubbo's Hessian protocol to expose the service, and the consumer directly uses the standard Hessian interface to call, -* Or the provider uses the standard Hessian to expose the service, and the consumer uses Dubbo's Hessian protocol to call. - -#### Constraints -* Parameters and return values need to implement `Serializable` interface. -* Parameters and return values cannot be customized to implement `List`, `Map`, `Number`, `Date`, `Calendar` and other interfaces, only the implementations that come with JDK can be used, because hessian will do special processing and customize the implementation All attribute values in the class are lost. - -## scenes to be used -Hessian is a lightweight RPC service implemented based on the Binary-RPC protocol, serializing and deserializing instances. - - -## How to use - -### Dependencies - -Starting from Dubbo 3, the Hessian protocol is no longer embedded in Dubbo, and an independent [module](/zh-cn/download/spi-extensions/#dubbo-rpc) needs to be introduced separately. -```xml - - org.apache.dubbo.extensions - dubbo-rpc-hessian - 1.0.0 - -``` - -```xml - - com.caucho - hessian - 4.0.7 - -``` - -### Define the hessian protocol -```xml - -``` - -### Set the default protocol -```xml - -``` - -### Set service protocol -```xml - -``` - -### Multiport -```xml - - -``` - -### direct connection -```xml - -``` diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/http.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/http.md deleted file mode 100644 index bb943f4e0e39..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/http.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -type: docs -title: "HTTP protocol" -linkTitle: "HTTP protocol" -weight: 6 ---- - - -{{% alert title="Note" color="warning" %}} -Since Dubbo 3.3, the rest protocol has been moved to the extensions library, with the triple protocol now providing more comprehensive support for Rest. For details refer to [Triple Rest User Manual](../../tripe-rest-manual/). -If you wish to continue using the original rest protocol, please include the corresponding [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) dependency. -{{% /alert %}} - -## Feature description -HTTP form-based remote invocation protocol, implemented by Spring's HttpInvoker, supported by versions above `2.3.0`. - -* Number of connections: multiple connections -* Connection method: short connection -* Transmission protocol: HTTP -* Transmission method: synchronous transmission -* Serialization: form serialization -* Scope of application: The size of incoming and outgoing parameter data packets is mixed, the number of providers is more than that of consumers, it can be viewed with a browser, and parameters can be passed in by form or URL, and file transfer is not supported for now. -* Applicable scenarios: services that need to be used by both application and browser JS. - -#### Constraints -* Parameters and return values must conform to the Bean specification - -## scenes to be used - -HTTP short connection, standardized and easy-to-read protocol, easy to connect to external systems, suitable for upper-level business modules. - -## How to use - -Starting from Dubbo 3, the Http protocol is no longer embedded in Dubbo, and an independent [module](/zh-cn/download/spi-extensions/#dubbo-rpc) needs to be introduced separately. -```xml - - org.apache.dubbo.extensions - dubbo-rpc-http - 1.0.0 - -``` - -### Configuration protocol -```xml - -``` - -### Configure Jetty Server (default) -```xml - -``` - -### Configure Servlet Bridge Server (recommended) -```xml - -``` - -### Configure DispatcherServlet - -```xml - - dubbo - org.apache.dubbo.remoting.http.servlet.DispatcherServlet - 1 - - - dubbo - /* - -``` - -> If a servlet is used to dispatch the request -> * The protocol port `` must be the same as the port of the servlet container, -> * The context path of the protocol `` must be the same as the context path of the servlet application. diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/memcached.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/memcached.md deleted file mode 100644 index 989b5c5d81ce..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/memcached.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -type: docs -title: "Memcached protocol" -linkTitle: "Memcached protocol" -weight: 12 ---- -## Feature description -RPC protocol implemented based on memcached. `2.3.0` and above are supported. - -[Memcached](http://memcached.org/) is an efficient KV cache server. - -## scenes to be used -Relieve database pressure, improve interaction speed, etc. - -## How to use -### Import dependencies - -Starting from Dubbo 3, the Memcached protocol is no longer embedded in Dubbo, and an independent [module](/zh-cn/download/spi-extensions/#dubbo-rpc) needs to be introduced separately. -```xml - - org.apache.dubbo.extensions - dubbo-rpc-memcached - 1.0.0 - -``` - -### Register the address of memcached service -```java -RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); -Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); -registry.register(URL.valueOf("memcached://10.20.153.11/com.foo.BarService?category=providers&dynamic=false&application=foo&group=member&loadbalance=consistenthash")); -``` - -### Referenced on the client side -**Do not need to be aware of the address of Memcached** - -use on client side - -```xml - -``` - -Or point-to-point direct connection - -```xml - -``` - -You can also use a custom interface -```xml - -``` - -Where "p:xxx" is the standard p tag of spring -```xml - -``` -If the method name is different from the standard method name of memcached, you need to configure the mapping relationship; - -The method name is recommended to be the same as the standard method name of memcached, namely: get(key), set(key, value), delete(key). diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/overview.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/overview.md deleted file mode 100644 index 6ce31a3a1f08..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/overview.md +++ /dev/null @@ -1,200 +0,0 @@ ---- -type: docs -title: "Protocol Overview" -linkTitle: "Protocol Overview" -weight: 1 ---- - -Dubbo3 provides Triple (Dubbo3) and Dubbo2 protocols, which are native protocols of the Dubbo framework. In addition, Dubbo3 also integrates many third-party protocols and incorporates them into Dubbo's programming and service governance system. -Including gRPC, Thrift, JsonRPC, Hessian2, REST, etc. The following focuses on the Triple and Dubbo2 protocols. - -## protocol description - -The Triple protocol is the main protocol launched by Dubbo3. Triple means the third generation. Through the evolution of the Dubbo1.0/Dubbo2.0 two-generation protocol and the wave of technology standardization brought by cloud native, the new Dubbo3 protocol Triple came into being. - -### Select the RPC protocol - -The protocol is the core of RPC, which regulates the content and format of data transmission in the network. In addition to the necessary request and response data, it usually contains additional control data, such as the serialization method of a single request, timeout period, compression method, and authentication information. - -The content of the agreement consists of three parts -- Data exchange format: Define the byte stream content of RPC request and response objects in network transmission, also known as serialization mode -- Protocol structure: defines the list of fields, the semantics of each field, and the arrangement of different fields -- Protocols define how data is transmitted across networks by defining rules, formats, and semantics. A successful RPC requires both ends of the communication to be able to read and write network byte streams and convert objects according to the protocol. If the two ends cannot reach an agreement on the protocol used, there will be chickens talking with ducks, which cannot meet the needs of long-distance communication. - -![Protocol Selection](/imgs/v3/concepts/triple-protocol.png) - -The design of the RPC protocol needs to consider the following: -- Versatility: Unified binary format, cross-language, cross-platform, multi-transport layer protocol support -- Extensibility: protocol adds fields, upgrades, supports user extensions and additional business metadata -- Performance: As fast as it can be -- Penetration: can be identified and forwarded by various terminal devices: gateways, proxy servers, etc. - Generally, versatility and high performance cannot be achieved at the same time, and protocol designers need to make certain trade-offs. - -### HTTP/1.1 protocol - -Compared with the private RPC protocol directly built on the TCP transport layer, the remote call solution built on HTTP will have better versatility, such as WebServices or REST architecture, using HTTP + JSON can be said to be a de facto standard solution . - -Choosing to build on top of HTTP has two biggest advantages: - -- The semantics and scalability of HTTP well meet the requirements of RPC calls. -- Versatility, the HTTP protocol is supported by almost all devices on the network, and has good protocol penetration. - -But there are also obvious problems: - -- In a typical Request-Response model, there can only be one waiting Request request on a link at a time. HOL will be generated. -- Human Readable Headers, using a more general, human-readable header transfer format, but with considerably poorer performance -- No direct Server Push support, need to use workarounds such as Polling Long-Polling - -### gRPC protocol -The above mentioned the advantages and disadvantages of building the RPC protocol on top of the HTTP and TCP protocols. Compared with Dubbo built on the TCP transport layer, Google chose to define gRPC directly on top of the HTTP/2 protocol. -The advantages of gRPC are inherited from HTTP2 and Protobuf. - -- The HTTP2-based protocol is simple enough, with low learning costs for users, and naturally has server push/multiplexing/flow control capabilities -- Protobuf-based multi-language cross-platform binary compatibility, providing powerful unified cross-language capabilities -- The ecology based on the protocol itself is relatively rich, the natural support protocol of components such as k8s/etcd, and the de facto protocol standard of cloud native - -But there are also some problems - -- The support for service governance is relatively basic, and it is more inclined to the basic RPC function. The protocol layer lacks the necessary unified definition, and it is not easy for users to use it directly. -- The serialization method of strong binding protobuf requires high learning cost and transformation cost. For the existing monolingual users, the migration cost cannot be ignored - -### Finally choose the Triple protocol -In the end, we chose to be compatible with gRPC and use HTTP2 as the transport layer to build a new protocol, which is Triple. - -The rise of containerized applications and microservices has led to the development of techniques optimized for workload content. The traditional communication protocols (RESTFUL or other HTTP-based custom protocols) used in the client are difficult to meet the convenience requirements of the application in terms of performance, maintainability, scalability, and security. A cross-language, modular protocol will gradually become a new application development protocol standard. Since the gRPC protocol became a CNCF project in 2017, more and more infrastructure and businesses including k8s and etcd have begun to use the gRPC ecosystem. As a cloud-native microservice framework, Dubbo's new protocol is also perfectly compatible with gRPC . Moreover, Triple will also enhance and supplement some imperfect parts of the gRPC protocol. - -So, does the Triple protocol solve the series of problems we mentioned above? - -- In terms of performance: The Triple protocol adopts the strategy of separating metadata and payload, so that intermediate devices, such as gateways, can be avoided to parse and deserialize payload, thereby reducing response time. -- In terms of routing support, since metadata supports users to add custom headers, users can more conveniently divide clusters or perform routing according to headers, so that when publishing, there is more flexibility in switching grayscale or disaster recovery. -- In terms of security, it supports encrypted transmission capabilities such as two-way TLS authentication (mTLS). -- In terms of ease of use, in addition to supporting Protobuf serialization recommended by native gRPC, Triple supports other serializations such as Hessian/JSON in a general way, allowing users to upgrade to the Triple protocol more conveniently. For the original Dubbo service, modifying or adding the Triple protocol only needs to add a line of protocol configuration in the code block declaring the service, and the transformation cost is almost zero. - -## Triple protocol - -![Triple protocol communication method](/imgs/v3/concepts/triple.png) - -status quo - -- 1. Fully compatible with grpc, client/server can connect with native grpc client - -- 2. At present, it has been verified by large-scale production practice and has reached the production level - -Features and advantages - -- 1. Capable of cross-language intercommunication. Both the traditional multi-language multi-SDK mode and the Mesh cross-language mode require a more general and scalable data transmission format. - -- 2. Provide a more complete request model. In addition to the Request/Response model, it should also support Streaming and Bidirectional. - -- 3. Easy to expand, high penetration, including but not limited to Tracing / Monitoring and other support, should also be recognized by devices at all levels, gateway facilities, etc. can identify data packets, friendly to Service Mesh deployment, and reduce the difficulty of understanding for users. - -- 4. Multiple serialization methods support and smooth upgrade - -- 5. Support Java users to upgrade without awareness, no need to define cumbersome IDL files, and only need to simply modify the protocol name to easily upgrade to the Triple protocol - -### Triple protocol content introduction - -Further extension based on the grpc protocol - -- Service-Version → "tri-service-version" {Dubbo service version} -- Service-Group → "tri-service-group" {Dubbo service group} -- Tracing-ID → "tri-trace-traceid" {tracing id} -- Tracing-RPC-ID → "tri-trace-rpcid" {_span id _} -- Cluster-Info → "tri-unit-info" {cluster infomation} - -Among them, Service-Version and Service-Group respectively identify the version and group information of the Dubbo service, because the path of grpc declares the service name and method name, compared with the Dubbo protocol, it lacks version and group information; Tracing-ID, Tracing- RPC-ID is used for full-link tracking capabilities, which respectively represent tracing id and span id information; Cluster-Info represents cluster information, which can be used to build some flexible service management capabilities related to routing such as cluster division. - -### Triple Streaming - -Compared with the traditional unary method, the Triple protocol has more streaming RPC capabilities currently provided - -- What scenario is Streaming used for? - -In some application scenarios such as large file transmission and live broadcast, the consumer or provider needs to transmit a large amount of data with the peer. Since the amount of data in these cases is very large, there is no way to transmit it in one RPC packet. Transmission, so for these data packets, we need to fragment the data packets and transmit them through multiple RPC calls. If we transmit these split RPC data packets in parallel, then the relevant data packets after reaching the peer end It is unordered, and the received data needs to be sorted and spliced, and the related logic will be very complicated. But if we serially transmit the split RPC packets, the corresponding network transmission RTT and data processing delay will be very large. - -In order to solve the above problems, and to transmit a large amount of data between the consumer and the provider in a pipelined manner, the Streaming RPC model came into being. - -Through the Streaming RPC method of the Triple protocol, multiple user-mode long connections, Stream, will be established between the consumer and the provider. Multiple Streams can exist on the same TCP connection at the same time, and each Stream is identified by a StreamId, and the data packets on a Stream will be read and written sequentially. - -### Summarize - -In the world of APIs, the most important trend is the rise of standardized technologies. The Triple protocol is the main protocol launched by Dubbo3. It adopts a layered design, and its data exchange format is developed based on the Protobuf (Protocol Buffers) protocol, which has excellent serialization/deserialization efficiency. Of course, it also supports multiple serialization methods and many development languages. In the transport layer protocol, Triple chose HTTP/2, which has greatly improved its transmission efficiency compared with HTTP/1.1. In addition, as a mature open standard, HTTP/2 has rich security and flow control capabilities, and has good interoperability. Triple can not only be used for server-side service calls, but also support the interaction between browsers, mobile apps, and IoT devices and back-end services. At the same time, the Triple protocol seamlessly supports all service management capabilities of Dubbo3. - -Under the trend of Cloud Native, the interoperability requirements between cross-platform, cross-vendor, and cross-environment systems will inevitably give rise to RPC technology based on open standards, and gRPC conforms to the historical trend and has been more and more widely used. In the field of microservices, the proposal and implementation of the Triple protocol is a big step for Dubbo3 to move towards cloud-native microservices. - -##Dubbo2 - -### Protocol SPEC - -![/dev-guide/images/dubbo_protocol_header.jpg](/imgs/dev/dubbo_protocol_header.png) - - -- Magic - Magic High & Magic Low (16 bits) - - Identifies dubbo protocol with value: 0xdabb - -- Req/Res (1 bit) - - Identifies this is a request or response. Request - 1; Response - 0. - -- 2 Way (1 bit) - - Only useful when Req/Res is 1 (Request), expect for a return value from server or not. Set to 1 if need a return value from server. - --Event (1 bit) - -Identifies an event message or not, for example, heartbeat event. Set to 1 if this is an event. - --Serialization ID (5 bits) - -Identifies serialization type: the value for fastjson is 6. - -- Status (8 bits) - - Only useful when Req/Res is 0 (Response), identifies the status of response - - - 20 - OK - - 30 - CLIENT_TIMEOUT - - 31 - SERVER_TIMEOUT - - 40 - BAD_REQUEST - - 50 - BAD_RESPONSE - - 60 - SERVICE_NOT_FOUND - - 70 - SERVICE_ERROR - - 80 - SERVER_ERROR - - 90 - CLIENT_ERROR - - 100 - SERVER_THREADPOOL_EXHAUSTED_ERROR - -- Request ID (64 bits) - - Identifies an unique request. Numeric (long). - -- Data Length (32) - - Length of the content (the variable part) after serialization, counted by bytes. Numeric (integer). - --Variable Part - -Each part is a byte[] after serialization with specific serialization type, identifies by Serialization ID. - -Every part is a byte[] after serialization with specific serialization type, identifies by Serialization ID - -1. If the content is a Request (Req/Res = 1), each part consists of the content, in turn is: - - Dubbo version - - Service name - - Service version - -Method name - -Method parameter types - -Method arguments - -Attachments - -1. If the content is a Response (Req/Res = 0), each part consists of the content, in turn is: - - Return value type, identifies what kind of value returns from server side: RESPONSE_NULL_VALUE - 2, RESPONSE_VALUE - 1, RESPONSE_WITH_EXCEPTION - 0. - - Return value, the real value returns from server. - - -> For the (Variable Part) variable length part, when the current version of the dubbo framework uses json serialization, an extra line break is added between each part of the content as a separator. Please add an extra line break after each part of the Variable Part, such as : - -``` -Dubbo version bytes (line break) -Service name bytes (newline) -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/redis.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/redis.md deleted file mode 100644 index 20bb755cf81c..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/redis.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -type: docs -title: "Redis protocol" -linkTitle: "Redis Protocol" -weight: 9 ---- - - -## Feature description -RPC protocol implemented based on Redis. `2.3.0` and above are supported. - -[Redis](http://redis.io) is an efficient KV storage server. - -## scenes to be used - -Caching, current limiting, distributed locks, etc. - -## How to use - -### Import dependencies - -Starting from Dubbo 3, the Redis protocol is no longer embedded in Dubbo, and an independent [module](/zh-cn/download/spi-extensions/#dubbo-rpc) needs to be introduced separately. -```xml - - org.apache.dubbo.extensions - dubbo-rpc-redis - 1.0.0 - -``` - - -### Register the address of the redis service -```java -RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); -Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); -registry.register(URL.valueOf("redis://10.20.153.11/com.foo.BarService?category=providers&dynamic=false&application=foo&group=member&loadbalance=consistenthash")); -``` - -### Referenced on the client side -Does not need to be aware of Redis addresses - -On the client side use: -```xml - -``` -Or point-to-point direct connection: -```xml - -``` -It is also possible to use a custom interface: -```xml - -``` - -Where "p:xxx" is the standard p tag of spring -```xml - -``` -The method name is suggested to be the same as the standard method name of redis, namely: get(key), set(key, value), delete(key). - -If the method name is different from the standard method name of redis, you need to configure the mapping relationship: diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/rest.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/rest.md deleted file mode 100644 index d9acddd826a2..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/rest.md +++ /dev/null @@ -1,747 +0,0 @@ ---- -type: docs -title: "Rest protocol" -linkTitle: "Rest protocol" -weight: 4 ---- - -{{% alert title="Note" color="warning" %}} -Since Dubbo 3.3, the rest protocol has been moved to the extensions library, with the triple protocol now providing more comprehensive support for Rest. For details refer to [Triple Rest User Manual](../../tripe-rest-manual/). -If you wish to continue using the original rest protocol, please include the corresponding [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) dependency. -{{% /alert %}} - -Support for REST calls based on the standard Java REST API - JAX-RS 2.0 (short for Java API for RESTful Web Services) - -### Quick Start - -It is relatively simple to develop a REST-style service in dubbo. Let's take a simple service for registered users as an example. - -The function of this service is to provide the following URL (note: this URL is not fully in line with REST style, but it is simpler and more practical) -``` -http://localhost:8080/users/register -``` -And any client can POST a JSON string containing user information to the above URL to complete user registration. - -First, develop the interface of the service - -```java -public class UserService { - void registerUser(User user); -} -``` - -Then, develop the implementation of the service - -```java -@Path("users") -public class UserServiceImpl implements UserService { - - @POST - @Path("register") - @Consumes({MediaType. APPLICATION_JSON}) - public void registerUser(User user) { - // save the user... - } -} -``` -The above implementation is very simple, but since the REST service is to be published to a specified URL for access by clients of any language or even browsers, several standard annotations of JAX-RS are added here for related configuration. - -@Path("users"): Specifies that the relative path of the URL to access UserService is /users, ie http://localhost:8080/users - -@Path("register"): Specifies that the relative path of the URL to access the registerUser() method is /register, combined with the path specified by the previous @Path for UserService, the full path to call UserService.register() is http://localhost :8080/users/register - -@POST: Specifies to access registerUser() with the HTTP POST method - -@Consumes({MediaType.APPLICATION_JSON}): Specifies that registerUser() receives data in JSON format. The REST framework will automatically deserialize the JSON data into a User object - -Finally, add this service in the spring configuration file to complete all service development work - - ```xml - - - - - - - - -``` - -### Detailed explanation of REST service provider - -Next, we expand the UserService in the "Quick Start" to further demonstrate the development points of the REST service provider in dubbo. - -### Implementation of HTTP POST/GET - -In the REST service, although it is recommended to use the four standard methods POST, DELETE, PUT, and GET in the HTTP protocol to implement common "addition, deletion, modification and query" respectively, in practice, we generally use POST directly to implement "addition and modification", and GET to implement Just implement "delete check" (DELETE and PUT will even be blocked by some firewalls). - -The implementation of POST has been briefly demonstrated before. Here, we add a function of obtaining registered user information to UserService to demonstrate the implementation of GET. - -This function is to enable the client to obtain user profiles with different IDs by accessing the following URLs - -``` -http://localhost:8080/users/1001 -http://localhost:8080/users/1002 -http://localhost:8080/users/1003 -``` - -Of course, user profiles with different IDs can also be accessed through other forms of URLs, for example - -``` -http://localhost:8080/users/load?id=1001 -``` - -JAX-RS natively supports all of these forms. But the above form of including query parameters in the URL path (http://localhost:8080/users/1001) is more in line with the general habits of REST, so it is recommended for everyone to use. Next, we will add a getUser() method to UserService to achieve this form of URL access - -```java -@GET -@Path("{id : \\d+}") -@Produces({MediaType. APPLICATION_JSON}) -public User getUser(@PathParam("id") Long id) { - //... -} -``` - -@GET: Specifies to use the HTTP GET method to access - -@Path("{id : \\d+}"): According to the functional requirements above, the URL to access getUser() should be "http://localhost:8080/users/ + any number", and this number should be made Pass the getUser() method as a parameter. In the annotation configuration here, {id: xxx} in the middle of @Path specifies that the URL relative path contains a parameter named id, and its value will be automatically passed to the method parameter modified with @PathParam("id") below id. {id: followed by \\d+ is a regular expression, specifying that the id parameter must be a number. - -@Produces({MediaType.APPLICATION_JSON}): Specify getUser() to output data in JSON format. The framework will automatically serialize the User object into JSON data. - -### Annotation is placed in the interface class or the implementation class - -The development of REST services in Dubbo is mainly configured through JAX-RS annotations. In the above examples, we put the annotations in the service implementation class. But in fact, we can also put the annotation on the interface of the service. The two methods are completely equivalent, for example: - -```java -@Path("users") -public interface UserService { - - @GET - @Path("{id : \\d+}") - @Produces({MediaType. APPLICATION_JSON}) - User getUser(@PathParam("id") Long id); -} -``` - -In general applications, we recommend placing the annotation in the service implementation class, so that the location of the annotation and the java implementation code are closer, making it easier to develop and maintain. In addition, more importantly, we generally tend to avoid pollution of the interface, and maintain the purity and wide applicability of the interface. - -However, as mentioned later, if we want to use the consumer directly developed by dubbo to access this service, the annotation must be placed on the interface. - -If annotations are added to both the interface and the implementation class, the annotation configuration of the implementation class will take effect, and the annotation on the interface will be ignored directly. - -### Support for multiple data formats such as JSON and XML - -The REST service developed in dubbo can support the transmission of data in multiple formats at the same time to provide clients with maximum flexibility. Among them we currently have added extra functionality especially for the most commonly used formats JSON and XML. - -For example, if we want the getUser() method in the above example to support returning data in JSON and XML formats, we only need to include both formats in the annotation - -```java -@Produces({MediaType. APPLICATION_JSON, MediaType. TEXT_XML}) -User getUser(@PathParam("id") Long id); -``` - -Or you can directly use strings (wildcards are also supported) to represent MediaType - -```java -@Produces({"application/json", "text/xml"}) -User getUser(@PathParam("id") Long id); -``` - -If all methods support the same type of input and output data format, we don't need to configure each method, just add annotation to the service class - -```java -@Path("users") -@Consumes({MediaType. APPLICATION_JSON, MediaType. TEXT_XML}) -@Produces({MediaType. APPLICATION_JSON, MediaType. TEXT_XML}) -public class UserServiceImpl implements UserService { - //... -} - -``` - -In the case that a REST service supports multiple data formats at the same time, according to the JAX-RS standard, the MIME header (content-type and accept) in HTTP is generally used to specify which format data is currently wanted. - -But in dubbo, we also automatically support the method commonly used in the industry at present, that is, use a URL suffix (.json and .xml) to specify the desired data format. For example, after adding the above annotation, direct access to http://localhost:8888/users/1001.json means to use json format, and direct access to http://localhost:8888/users/1002.xml means to use xml format, Simpler and more intuitive than using HTTP Header. The REST APIs of Twitter, Weibo, etc. all use this method. -If you add neither HTTP header nor suffix, dubbo's REST will give priority to the data format that ranks first in the above annotation definition. - -> Note: To support XML format data here, you can use MediaType.TEXT_XML or MediaType.APPLICATION_XML in annotation, but TEXT_XML is more commonly used, and if you want to use the above URL suffix method to specify the data format, you can only use Only when it is configured as TEXT_XML can it take effect. - -### Chinese character support - -In order to output Chinese characters normally in dubbo REST, like usual Java web applications, we need to set the contentType of the HTTP response to UTF-8 encoding. - -Based on the standard usage of JAX-RS, we only need to do the following annotation configuration: - -```java -@Produces({"application/json; charset=UTF-8", "text/xml; charset=UTF-8"}) -User getUser(@PathParam("id") Long id); -``` - -For the convenience of users, we directly added a support class in dubbo REST to define the above constants, which can be used directly to reduce the possibility of errors. - -```java -@Produces({ContentType. APPLICATION_JSON_UTF_8, ContentType. TEXT_XML_UTF_8}) -User getUser(@PathParam("id") Long id); -``` - -### Additional requirements for XML data format - -Since the implementation of JAX-RS generally uses the standard JAXB (Java API for XML Binding) to serialize and deserialize XML format data, we need to add a class-level JAXB annotation for each object to be transmitted in XML, Otherwise serialization will report an error. For example, add the following to the User returned in getUser() - -```java -@XmlRootElement -public class User implements Serializable { - //... -} -``` - -In addition, if the return values in the service method are Java primitive types (such as int, long, float, double, etc.), it is best to add a layer of wrapper objects for them, because JAXB cannot directly serialize primitive types. - -For example, we want the aforementioned registerUser() method to return the ID number generated by the server for the user: - -```java -long registerUser(User user); -``` - -Since primitive types are not supported by JAXB serialization, add a wrapper object: - -```java -@XmlRootElement -public class RegistrationResult implements Serializable { - - private Long id; - - public RegistrationResult() { - } - - public RegistrationResult(Long id) { - this.id = id; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } -} -``` - -And modify the service method: - -```java -RegistrationResult registerUser(User user); -``` - -This not only solves the problem of XML serialization, but also makes the returned data conform to the specifications of XML and JSON. For example, in JSON, the return would be of the form - -```javascript -{"id": 1001} -``` - -If no wrapper is added, the JSON return value will be directly - -``` -1001 -``` - -In XML, the return value after adding wrapper will be: - -```xml - - 1002 - -``` - -This kind of wrapper object actually uses the so-called Data Transfer Object (DTO) pattern, and using DTO can also do more useful customizations for the transferred data. - -### Custom serialization - -As mentioned above, the underlying implementation of REST will automatically serialize/deserialize between service objects and JSON/XML data formats. However, in some scenarios, if you feel that this automatic conversion does not meet the requirements, you can customize it. - -The REST implementation in Dubbo uses JAXB for XML serialization and Jackson for JSON serialization, so you can customize the mapping by adding JAXB or Jackson annotations to objects. - -For example, custom object properties map to XML element names: - -```java -@XmlRootElement -@XmlAccessorType(XmlAccessType.FIELD) -public class User implements Serializable { - - @XmlElement(name="username") - private String name; -} -``` - -Map custom object properties to JSON field names: - -```java -public class User implements Serializable { - - @JsonProperty("username") - private String name; -} -``` - -For more information, please refer to the official documentation of JAXB and Jackson, or google yourself. - -### Configure the implementation of REST Server - -Currently in dubbo, we support the implementation of 5 embedded rest servers, and at the same time support the implementation of the rest server using an external application server. The rest server can be implemented through the following configuration: - -```xml - -``` - -The above configuration uses the embedded jetty as the rest server. At the same time, if the server attribute is not configured, the rest protocol also uses jetty by default. jetty is a very mature java servlet container, and has been well integrated with dubbo (currently, among the five embedded servers, only jetty and tomcat and tjws described later have seamlessly integrated with dubbo monitoring system), Therefore, if your dubbo system is a separate startup process, you can directly use jetty by default. - - -```xml - -``` - -The above configuration uses the embedded tomcat as the rest server. On the embedded tomcat, the performance of REST is much better than that on jetty (see the benchmark test later), it is recommended to use tomcat in the scenario that requires high performance. - -```xml - -``` - -The above configuration uses embedded netty as the rest server. (TODO more contents to add) - -```xml - (tjws is now deprecated) - -``` - -The above configuration uses the embedded tjws or Sun HTTP server as the rest server. These two server implementations are very lightweight, very convenient for quick start-up in integration tests, and of course they can also be used in production environments with low load. Note: tjws is currently deprecated because it doesn't work well with the servlet 3.1 API. - -If your dubbo system is not a separate startup process, but is deployed in a Java application server, it is recommended that you use the following configuration - -```xml - -``` - -By setting the server as a servlet, dubbo will use the servlet container of the external application server as the rest server. At the same time, add the following configuration to the web.xml of the dubbo system - -```xml - - - contextConfigLocation - /WEB-INF/classes/META-INF/spring/dubbo-demo-provider.xml - - - - org.apache.dubbo.remoting.http.servlet.BootstrapListener - - - - org.springframework.web.context.ContextLoaderListener - - - - dispatcher - org.apache.dubbo.remoting.http.servlet.DispatcherServlet - 1 - - - - dispatcher - /* - - -``` - -That is, dubbo's BootstrapListener and DispatherServlet must be added to web.xml to complete the integration of dubbo's REST function with the external servlet container. - -> Note: If you use spring's ContextLoaderListener to load spring, you must ensure that BootstrapListener is configured before ContextLoaderListener, otherwise dubbo initialization will fail. - -In fact, you can still use the embedded server in this scenario, but the servlet container of the external application server is often more powerful than the embedded server (especially if you are deploying to a more robust and scalable WebLogic, WebSphere, etc.), and Sometimes it is also convenient for unified management, monitoring, etc. on the application server. - -### Get context information - -In the remote call, there may be many kinds of context information worth obtaining. Here, the client IP is taken as an example. - -In dubbo's REST, we have two ways to get client IP. - -The first way, using JAX-RS standard @Context annotation - -```java -public User getUser(@PathParam("id") Long id, @Context HttpServletRequest request) { - System.out.println("Client address is " + request.getRemoteAddr()); -} -``` - -After modifying a method parameter of getUser() with Context, you can inject the current HttpServletRequest into it, and then directly call the servlet api to obtain the IP. - -> Note: This method can only work when the server is set to tjws, tomcat, jetty or servlet, because only these server implementations provide a servlet container. In addition, the standard JAX-RS also supports using @Context to modify an instance field of the service class to obtain HttpServletRequest, but we do not support this in dubbo. - -The second way, use RpcContext commonly used in dubbo - -```java -public User getUser(@PathParam("id") Long id) { - System.out.println("Client address is " + RpcContext.getContext().getRemoteAddressString()); -} -``` - -> Note: This method can only work when setting server="jetty" or server="tomcat" or server="servlet" or server="tjws". In addition, currently dubbo's RpcContext is a relatively intrusive usage, and we are likely to refactor it in the future. - -If you want to keep your project compatible with JAX-RS and run without dubbo in the future, please choose the first method. If you want a more elegant service interface definition, please choose the second way. - -In addition, in the latest dubbo rest, it is also supported to obtain HttpServletRequest and HttpServletResponse through RpcContext to provide greater flexibility for users to implement some complex functions, such as accessing HTTP Header in dubbo standard filter. An example of usage is as follows - -```java -if (RpcContext.getContext().getRequest() != null && RpcContext.getContext().getRequest() instanceof HttpServletRequest) { - System.out.println("Client address is " + ((HttpServletRequest) RpcContext.getContext().getRequest()).getRemoteAddr()); -} - -if (RpcContext.getContext().getResponse() != null && RpcContext.getContext().getResponse() instanceof HttpServletResponse) { - System.out.println("Response object from RpcContext: " + RpcContext.getContext().getResponse()); -} -``` - -> Note: In order to maintain the neutrality of the protocol, RpcContext.getRequest() and RpcContext.getResponse() return only an Object class, and may be null. So, you have to do null and type checking yourself. - -> Note: Only when server="jetty" or server="tomcat" or server="servlet" is set, can you get HttpServletRequest and HttpServletResponse correctly through the above method, because only these servers implement the servlet container. - -In order to simplify programming, you can also use generics to directly obtain specific types of request/response: - -```java -if (RpcContext. getContext(). getRequest(HttpServletRequest. class) != null) { - System.out.println("Client address is " + RpcContext.getContext().getRequest(HttpServletRequest.class).getRemoteAddr()); -} - -if (RpcContext. getContext(). getResponse(HttpServletResponse. class) != null) { - System.out.println("Response object from RpcContext: " + RpcContext.getContext().getResponse(HttpServletResponse.class)); -} -``` - -If the request/response does not conform to the specified type, null will also be returned here. - -### Configure port number and Context Path - -The rest protocol in dubbo will use port 80 by default. If you want to modify the port, configure it directly: - -```xml - -``` - -In addition, as mentioned earlier, we can use @Path to configure the URL relative path of a single rest service. But in fact, we can also set a basic relative path that is applicable to all rest services, that is, the context path that is often said in java web applications. - -Just add the following contextpath attribute: - -```xml - -``` - -Take the previous code as an example: - -```java -@Path("users") -public class UserServiceImpl implements UserService { - - @POST - @Path("register") - @Consumes({MediaType. APPLICATION_JSON}) - public void registerUser(User user) { - // save the user... - } -} -``` - -Now the full access path of registerUser() - -``` -http://localhost:8888/services/users/register -``` - -Note: If you choose an external application server as the rest server, that is, configure - -```xml - -``` - -You must ensure that the port and contextpath set here are consistent with the port of the external application server and the context path of DispatcherServlet (that is, webapp path plus servlet url pattern). For example, for an application deployed as the tomcat ROOT path, the contextpath here must be exactly the same as `` of DispacherServlet in web.xml: - -```xml - - dispatcher - /services/* - -``` - -### Configure the number of threads and IO threads - -Thread pool size can be configured for rest services - -```xml - -``` - -> Note: The current thread pool settings only take effect when server="netty" or server="jetty" or server="tomcat". In addition, if server="servlet", since the external application server is enabled as the rest server at this time, it is not controlled by dubbo, so the thread pool setting here is also invalid. - -If you choose netty server, you can also configure the number of IO worker threads of Netty - -```xml - -``` - -### Configure long connection - -The rest service in Dubbo is accessed by http long connection by default, if you want to switch to short connection, configure it directly - -```xml - -``` - -> Note: This configuration is currently only valid for server="netty" and server="tomcat". - -### Configure the maximum number of HTTP connections - -The maximum number of HTTP connections that the server provider can receive at the same time can be configured to prevent the REST server from being overwhelmed by too many connections, as a basic self-protection mechanism - -```xml - -``` - -Of course, since this configuration is effective for the consumer side, it can also be configured on the consumer side - -```xml - -``` - -However, in general we recommend configuration to provide such configuration on the service provider side. According to dubbo's official documentation: "Providers should be configured with as many properties as possible on the Consumer side, so that Provider implementers can think about Provider service characteristics and service quality issues from the very beginning." - -> Note: If dubbo's REST service is published to non-dubbo clients, the configuration on `` here is completely invalid, because such clients are not controlled by dubbo. - - -### Replace part of Spring XML configuration with Annotation - -All the above discussions are based on the xml configuration of dubbo in spring. However, dubbo/spring itself also supports the use of annotations for configuration, so we can also follow the steps in dubbo's official documentation to add related annotations to the implementation of REST services to replace some xml configurations, for example - -```java -@Service(protocol = "rest") -@Path("users") -public class UserServiceImpl implements UserService { - - @Autowired - private UserRepository userRepository; - - @POST - @Path("register") - @Consumes({MediaType. APPLICATION_JSON}) - public void registerUser(User user) { - // save the user - userRepository. save(user); - } -} -``` - -The configuration of annotation is simpler and more precise, and it is usually easier to maintain (of course, modern IDEs can support such as class name refactoring in xml, so in terms of specific use cases here, xml is also very maintainable). And xml is less intrusive to the code, especially conducive to dynamic modification of configuration, especially if you want to configure connection timeout, maximum number of connections per client, cluster strategy, weight, etc. for a single service. In addition, especially for complex applications or modules, xml provides a central point to cover all components and configurations, which is more clear at a glance and generally more convenient for long-term project maintenance. - -Of course, there is no absolute advantage or disadvantage in choosing which configuration method to choose, and it has nothing to do with personal preference. - -### Add custom Filter, Interceptor, etc. - -Dubbo's REST also supports JAX-RS standard Filter and Interceptor to facilitate customized interception of REST request and response processes. - -Among them, Filter is mainly used to access and set HTTP request and response parameters, URI, etc. For example, to set the cache header of an HTTP response: - -```java -public class CacheControlFilter implements ContainerResponseFilter { - - public void filter(ContainerRequestContext req, ContainerResponseContext res) { - if (req. getMethod(). equals("GET")) { - res.getHeaders().add("Cache-Control", "someValue"); - } - } -} -``` - -Interceptor is mainly used to access and modify input and output byte streams, for example, manually add GZIP compression - -```java -public class GZIPWriterInterceptor implements WriterInterceptor { - - @Override - public void aroundWriteTo(WriterInterceptorContext context) - throws IOException, WebApplicationException { - OutputStream outputStream = context. getOutputStream(); - context.setOutputStream(new GZIPOutputStream(outputStream)); - context. proceed(); - } -} -``` - -In standard JAX-RS applications, we generally add @Provider annotations for Filter and Interceptor, and then JAX-RS runtime will automatically discover and enable them. In dubbo, we register Filter and Interceptor by adding XML configuration: - -```xml - -``` - -Here, we can add all three types of objects, Filter, Interceptor and DynamicFeature, to the `extension` attribute, and separate them with commas. (DynamicFeature is another interface, which can facilitate us to enable Filter and Interceptor more dynamically. If you are interested, please google yourself.) - -Of course, dubbo itself also supports the concept of Filter, but the Filter and Interceptor we discuss here are closer to the bottom layer of the protocol implementation. Compared with Dubbo's filter, it can be customized at a lower level. - -> Note: The XML attribute here is called extension, not interceptor or filter, because in addition to Interceptor and Filter, we will add more extension types in the future. - -If the consumer side of REST is also a dubbo system (see the discussion below), you can also configure Interceptor and Filter for the consumer side in a similar way. But note that the consumer-side Filter and the provider-side Filter in JAX-RS are two different interfaces. For example, in the previous example, the server is the ContainerResponseFilter interface, while the consumer corresponds to the ClientResponseFilter: - -```java -public class LoggingFilter implements ClientResponseFilter { - - public void filter(ClientRequestContext reqCtx, ClientResponseContext resCtx) throws IOException { - System.out.println("status: " + resCtx.getStatus()); -System.out.println("date: " + resCtx.getDate()); -System.out.println("last-modified: " + resCtx.getLastModified()); -System.out.println("location: " + resCtx.getLocation()); -System.out.println("headers:"); -for (Entry> header : resCtx. getHeaders(). entrySet()) { - System.out.print("\t" + header.getKey() + " :"); -for (String value : header. getValue()) { -System.out.print(value + ", "); -} -System.out.print("\n"); -} -System.out.println("media-type: " + resCtx.getMediaType().getType()); - } -} -``` - -### Add custom Exception handling - -Dubbo's REST also supports JAX-RS standard ExceptionMapper, which can be used to customize the HTTP response that should be returned after a specific exception occurs. - -```java -public class CustomExceptionMapper implements ExceptionMapper { - - public Response toResponse(NotFoundException e) { - return Response.status(Response.Status.NOT_FOUND).entity("Oops! the requested resource is not found!").type("text/plain").build(); - } -} -``` - -Similar to Interceptor and Filter, it can be enabled by adding it to the XML configuration file - -```xml - -``` - -### Configure HTTP log output - -Dubbo rest supports outputting header fields and body message bodies in all HTTP requests/responses. - -Add the following built-in REST filter in the XML configuration: - -```xml - -``` - -Then configure to turn on INFO level log output for at least org.apache.dubbo.rpc.protocol.rest.support in the logging configuration, for example, configure in log4j.xml - -```xml - - - - -``` - -Of course, you can also directly open INFO level log output in ROOT logger - -```xml - - - - -``` - -Then something similar to the following will be output in the log - -``` -The HTTP headers are: -accept: application/json;charset=UTF-8 -accept-encoding: gzip, deflate -connection: Keep-Alive -content-length: 22 -content-type: application/json -host: 192.168.1.100:8888 -user-agent: Apache-HttpClient/4.2.1 (java 1.5) -``` - -``` -The contents of request body are: -{"id":1,"name":"dang"} -``` - -After HTTP log output is enabled, in addition to the performance overhead of normal log output, additional overhead will be generated when parsing HTTP requests, for example, because additional memory buffers need to be established to prepare data for log output. - -### Validation of input parameters - -Dubbo's rest supports Java standard bean validation annotation (JSR 303) for input validation http://beanvalidation.org/ - -In order to be consistent with other dubbo remote call protocols, the annotation for verification in rest must be placed on the service interface, for example - -```java -public interface UserService { - - User getUser(@Min(value=1L, message="User ID must be greater than 1") Long id); -} - -``` - -Of course, in many other bean validation application scenarios, the annotation is placed on the implementation class instead of the interface. At least one advantage of putting the annotation on the interface is that dubbo clients can share the information of this interface, and dubbo can complete the input verification locally without even making remote calls. - -Then open the validation in the XML configuration according to dubbo's standard way: - -```xml - -``` - -In many other remote call protocols of dubbo, if the input verification fails, `RpcException` is directly thrown to the client, but in rest, since the client is often a non-dubbo or even non-java system, it is inconvenient to directly throw a Java exception . Therefore, currently we return validation errors as XML - -```xml - - - getUserArgument0 - User ID must be greater than 1 - 0 - - -``` - -Return values in other data formats will be supported later. As for how to internationalize the validation error message, just refer to the relevant documents of bean validation. - -If you think that the default validation error return format does not meet your requirements, you can add a custom ExceptionMapper to freely customize the error return format as described in the above section. It should be noted that this ExceptionMapper must use a generic declaration to catch dubbo's RpcException, in order to successfully override the default exception handling strategy of dubbo rest. In order to simplify the operation, in fact, the easiest way here is to directly inherit the RpcExceptionMapper of dubbo rest, and override the method of handling verification exceptions - -```java -public class MyValidationExceptionMapper extends RpcExceptionMapper { - - protected Response handleConstraintViolationException(ConstraintViolationException cve) { - ViolationReport report = new ViolationReport(); - for (ConstraintViolation cv : cve. getConstraintViolations()) { - report.addConstraintViolation(new RestConstraintViolation( - cv.getPropertyPath().toString(), - cv. getMessage(), - cv.getInvalidValue() == null ? "null" : cv.getInvalidValue().toString())); - } - // Use json output instead of xml output - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(report).type(ContentType.APPLICATION_JSON_UTF_8).build(); - } -} -``` - -Then add this ExceptionMapper to the XML configuration: - -```xml - -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/rmi.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/rmi.md deleted file mode 100644 index d334e2de126b..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/rmi.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -type: docs -title: "Rmi agreement" -linkTitle: "Rmi Agreement" -weight: 8 ---- - -## Feature description -The RMI protocol is implemented using the JDK standard `java.rmi.*`, using blocking short connections and JDK standard serialization. - -* Number of connections: multiple connections -* Connection method: short connection -* Transport protocol: TCP -* Transmission method: synchronous transmission -* Serialization: Java standard binary serialization -* Scope of application: Incoming and outgoing parameter packets are mixed in size, the number of consumers and providers is similar, and files can be transferred. -* Applicable scenarios: regular remote service method calls, interoperability with native RMI services - -#### Constraints - -* Parameters and return values need to implement `Serializable` interface -* The timeout in dubbo configuration is invalid for RMI, you need to use the java startup parameter setting: `-Dsun.rmi.transport.tcp.responseTimeout=3000`, see the following RMI configuration - - -## scenes to be used - -It is a set of Java APIs that supports the development of distributed applications, and realizes the method calling of programs between different operating systems. - -## How to use - -### Import dependencies - -Starting from Dubbo 3, the RMI protocol is no longer embedded in Dubbo, and an independent [module](/zh-cn/download/spi-extensions/#dubbo-rpc) needs to be introduced separately. -```xml - - org.apache.dubbo.extensions - dubbo-rpc-rmi - 1.0.0 - -``` - -```sh -java -Dsun.rmi.transport.tcp.responseTimeout=3000 -``` -For more RMI optimization parameters, please see [JDK Documentation](https://docs.oracle.com/javase/6/docs/technotes/guides/rmi/sunrmiproperties.html) - -### Interface Description -If the service interface inherits the `java.rmi.Remote` interface, it can interoperate with native RMI, namely: - -* The provider uses Dubbo's RMI protocol to expose the service, and the consumer directly uses the standard RMI interface to call, -* Or the provider uses standard RMI to expose the service, and the consumer uses Dubbo's RMI protocol to call. - -If the service interface does not extend the `java.rmi.Remote` interface: - -* By default, Dubbo will automatically generate a `com.xxx.XxxService$Remote` interface, inherit the `java.rmi.Remote` interface, and expose the service through this interface, -* But if `` is set, the `$Remote` interface will not be generated, and the service will be exposed using Spring’s `RmiInvocationHandler` interface, which is compatible with Spring. - -**Define the RMI protocol** - -```xml - -``` - -**SET DEFAULT PROTOCOL** - -```xml - -``` - -**Set the protocol of a service** - -```xml - -``` - -**Multiple ports** - -```xml - - - - -``` - -**Spring Compatibility** - -```xml - -``` - - -> - **If you are using RMI to provide services for external access,** there should be no risk of attack in the company's intranet environment. - -> - **At the same time, if the application relies on the old common-collections package,** dubbo will not depend on this package. Please check whether your application has used it. - -> - ** There is a deserialization security risk. ** Please check the application: Please upgrade commons-collections3 to [3.2.2](https://commons.apache.org/proper/commons-collections/release_3_2_2.html); Please upgrade commons-collections4 to [4.1](https://commons.apache.org/proper/commons-collections/release_4_1.html). The new version of commons-collections solves this problem. diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/thrift.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/thrift.md deleted file mode 100644 index af3b6c31a50a..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/thrift.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -type: docs -title: "Thrift protocol" -linkTitle: "Thrift protocol" -weight: 7 ---- - - -## Feature description -The thrift protocol currently supported by dubbo is an extension of the thrift native protocol, adding some additional header information on the basis of the native protocol, such as service name, magic number, etc. `2.3.0` and above are supported. - -[Thrift](http://thrift.apache.org) is an RPC framework donated by Facebook to Apache. - -Using the dubbo thrift protocol also needs to use thrift's idl compiler to compile and generate the corresponding java code, and some enhancements will be made in this regard in subsequent versions. - -## scenes to be used - -For SOA standard RPC framework. - -## How to use -### Dependencies - -Starting from Dubbo 3, the Thrift protocol is no longer embedded in Dubbo, and an independent [module](/zh-cn/download/spi-extensions/#dubbo-rpc) needs to be introduced separately. -```xml - - org.apache.dubbo.extensions - dubbo-rpc-native-thrift - 1.0.0 - -``` - - -```xml - - org.apache.thrift - libthrift - 0.8.0 - -``` - -### All services share one port - -Incompatible with native Thrift -```xml - -``` - -[Example code in dubbo project](https://github.com/apache/dubbo/tree/master/dubbo-rpc/dubbo-rpc-thrift/src/test/java/org/apache/dubbo/rpc/protocol /thrift) - - -> Thrift does not support null values, ie: you cannot pass null values in the protocol diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-3.3.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-3.3.md deleted file mode 100644 index d87aa6e3de69..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-3.3.md +++ /dev/null @@ -1,282 +0,0 @@ ---- -type: docs -title: "Tripe 3.3 New Features" -linkTitle: "Tripe 3.3 New Features" -weight: 13 ---- - -
- -## New Rest Support - -### Rest Features - -Since Dubbo 3.3, the Triple protocol reuses the existing HTTP stack to fully support RESTful service exports. Without the need for generic or gateway protocol conversion, users can -directly access backend Triple protocol services via HTTP in a decentralized manner. Additionally, it offers extensive annotation and SPI extension support for advanced REST usage, -such as path customization, output format customization, and exception handling. Key features include: - -- **Triple Protocol Integration** - Reuses the existing Triple HTTP stack, allowing support for HTTP/1, HTTP/2, and HTTP/3 without additional configuration or new ports. -- **Decentralization** - Exposes Rest APIs directly, eliminating dependency on gateway applications for traffic forwarding, thus improving performance and reducing stability risks caused by gateways. - Security concerns can be addressed through internal application extensions, a practice verified in Taobao’s MTOP. -- **Support for Existing Servlet Infrastructure** - Supports Servlet API and Filter, allowing users to reuse existing security components based on the Servlet API. Integrating OAuth and Spring Security is as simple as implementing - a Servlet Filter. -- **Multiple Dialects** - Considering that most users are accustomed to using SpringMVC or JAX-RS for REST API development, Triple Rest allows continued use of these methods for service definitions and - supports most extensions and exception handling mechanisms (with over 80% of the original framework’s functionality). For lightweight users, the Basic dialect is available, and - Triple’s out-of-the-box REST capabilities are based on this dialect. -- **High Extensibility** - Offers more than 20 extension points, enabling users to easily create custom dialects and flexibly customize parameter retrieval, type conversion, error handling, and other - logic. -- **Out-of-the-Box** - REST capabilities are available out of the box; simply enable the Triple protocol to have direct REST access to services. -- **High-Performance Routing** - The routing component uses an - optimized [Radix Tree](https://github.com/apache/dubbo/blob/3.3/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java) and Zero - Copy technology to improve routing performance. -- **Seamless OpenAPI Integration (TBD)** - Upcoming OpenAPI integration will allow for out-of-the-box OpenAPI Schema export. With the Swagger dependency, a Web UI can be used for service testing. Using the OpenAPI Schema, - API tools like [Postman](https://www.postman.com/) and [Apifox](https://apifox.com/) can manage and test APIs, and the OpenAPI ecosystem can facilitate cross-language calls. - Future enhancements will support a Schema First approach, allowing frontend teams to define OpenAPI collaboratively, generate call code and mocks based on OpenAPI, and enable - backend development using stubs generated from OpenAPI, greatly improving collaboration efficiency. - - - -### Example - - - -###### Sample Code - -```java -package org.apache.dubbo.rest.demo; - -import org.apache.dubbo.remoting.http12.rest.Mapping; -import org.apache.dubbo.remoting.http12.rest.Param; - -// Service Interface -public interface DemoService { - String hello(String name); - - @Mapping(path = "/hi", method = HttpMethods.POST) - String hello(User user, @Param(value = "c", type = ParamType.Header) int count); -} - -// Service Implementation -@DubboService -public class DemoServiceImpl implements DemoService { - @Override - public String hello(String name) { - return "Hello " + name; - } - - @Override - public String hello(User user, int count) { - return "Hello " + user.getTitle() + ". " + user.getName() + ", " + count; - } -} - -// Model -@Data -public class User { - private String title; - private String name; -} -``` - - - -###### Download and Run Example - -```bash -# Get the example code -git clone --depth=1 https://github.com/apache/dubbo-samples.git -cd dubbo-samples/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-basic -# Run -mvn spring-boot:run -``` - - - -###### Curl Test - -```bash -curl -v "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hello?name=world" -# Output -#> GET /org.apache.dubbo.rest.demo.DemoService/hello?name=world HTTP/1.1 -#> -#< HTTP/1.1 200 OK -#< content-type: application/json -#< content-length: 13 -#< -#"Hello world" -# -# Explanation -# The output shows "Hello world", with quotes because the default content-type is application/json. -# This example shows that Triple exports services to the /{serviceInterface}/{methodName} path by default, supporting parameter passing via URL. - -curl -v -H "c: 3" -d 'name=Yang' "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr" -# Output -#> POST /org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr HTTP/1.1 -#> c: 3 -#> Content-Length: 9 -#> Content-Type: application/x-www-form-urlencoded -#> -#< HTTP/1.1 200 OK -#< content-type: text/plain -#< content-length: 17 -#< -#Hello Mr. Yang, 3 -# -# Explanation -# The output shows "Hello Mr. Yang, 3", without quotes because the output was specified as text/plain by using the txt suffix. -# This example shows how to customize paths using the Mapping annotation and customize parameter sources using the Param annotation, supporting parameter passing via post body or URL. -``` - - - -### Documentation - -Please visit the user manual: [Triple Rest Manual](../triple-rest-manual/) - - -## Support for Servlet Integration - -In version 3.3, you can reuse existing Spring Boot servlet listening ports to handle HTTP traffic, eliminating the need for Netty to listen on new ports. This simplifies deployment -and reduces maintenance costs. By reducing reliance on external ports, it helps to easily pass through enterprise firewalls and gateways, simplifying network deployment and -enhancing the maintainability and security of enterprise applications. - - -### Example - - - -###### Download and Run Example - -```bash -# Get the sample code -git clone --depth=1 https://github.com/apache/dubbo-samples.git -cd dubbo-samples/2-advanced/dubbo-samples-triple-servlet -# Run directly -mvn spring-boot:run -``` - - - -###### Curl Test - -```shell -curl --http2-prior-knowledge -v 'http://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world' -# Output -#* [HTTP/2] [1] OPENED stream for http://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world -#* [HTTP/2] [1] [:method: GET] -#* [HTTP/2] [1] [:scheme: http] -#* [HTTP/2] [1] [:authority: localhost:50052] -#* [HTTP/2] [1] [:path: /org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world] -#> -#* Request completely sent off -#< HTTP/2 200 -#< content-type: application/json -#< date: Sun, 25 Aug 2024 03:38:12 GMT -#< -#"Hello world" -``` - - - -### Documentation - -Please -visit: [how-to-enable-servlet-support-for-triple](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-servlet#how-to-enable-servlet-support-for-triple) -to learn how to configure and enable servlet support. - - -## Support for HTTP/3 Protocol - - - -### HTTP/3 Features - -In version 3.3, Triple implements support for the HTTP/3 protocol, allowing RPC and REST requests to be transmitted via HTTP/3. Using HTTP/3 offers the following benefits: - -- **Enhanced Performance** - With HTTP/3 support, the use of the QUIC protocol reduces latency and accelerates request-response times. This significantly boosts overall service - performance, especially in high-latency or complex network environments. -- **Improved Reliability** - HTTP/3 leverages multiplexing and connection migration to avoid head-of-line blocking, maintaining stable connections even under poor network conditions - and ensuring reliable service delivery. -- **Increased Security** - HTTP/3 enforces TLS 1.3 encryption, providing a more secure communication channel compared to the optional encryption in traditional HTTP/2. -- **Better Adaptation to Weak Networks** - In scenarios with high packet loss or unstable bandwidth, HTTP/3 maintains high connection quality and service performance, improving - outcomes in weak network environments. - -Since HTTP/3 is based on the QUIC protocol (UDP), it might be blocked by firewalls or gateways. To mitigate this, Triple has implemented HTTP/3 negotiation capabilities and enabled -it by default. Connections are initially established via HTTP/2, and if the server responds with an [Alt-Svc](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Alt-Svc) -header indicating HTTP/3 support, the client will automatically switch to HTTP/3. - - -### Example - - - -###### Download and Run Example - -```bash -# Get the sample code -git clone --depth=1 https://github.com/apache/dubbo-samples.git -cd dubbo-samples/2-advanced/dubbo-samples-triple-http3 -# Run directly -mvn spring-boot:run -``` - - - -###### Testing with Curl - -Note that Curl must be upgraded to a version that supports HTTP/3. Refer to: [https://curl.se/docs/http3.html](https://curl.se/docs/http3.html). - -```shell - -curl --http3 -vk 'https://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world' -# Output -#* QUIC cipher selection: TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256 -#* Skipped certificate verification -#* using HTTP/3 -#* [HTTP/3] [0] OPENED stream for https://localhost:50052/org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world -#* [HTTP/3] [0] [:method: GET] -#* [HTTP/3] [0] [:scheme: https] -#* [HTTP/3] [0] [:authority: localhost:50052] -#* [HTTP/3] [0] [:path: /org.apache.dubbo.demo.GreeterService/sayHelloAsync?request=world] -#> -#* Request completely sent off -#< HTTP/3 200 -#< content-type: application/json -#< -#"Hello world" -``` - - - -### Performance Comparison - -#### Impact of Packet Loss on QPS - -![http3-qps.jpg](/imgs/v3/manual/java/protocol/http3-qps.jpg) - -#### Impact of Packet Loss on RT - -![http3-rt.jpg](/imgs/v3/manual/java/protocol/http3-rt.jpg) - - - -### Architecture Diagram - -![http3-arch.jpg](/imgs/v3/manual/java/protocol/http3-arch.jpg) - -### Documentation - -For information on how to configure and enable HTTP/3 support, please -visit: [how-to-enable-http3-support-for-triple](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-http3#how-to-enable-http3-support-for-triple). diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-rest-manual.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-rest-manual.md deleted file mode 100644 index d7fd5125944b..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/tripe-rest-manual.md +++ /dev/null @@ -1,984 +0,0 @@ ---- -linkTitle: Triple Rest User Manual -title: Triple Rest User Manual -type: docs -weight: 14 ---- - -{{% alert title="Note" color="warning" %}} -Since Dubbo 3.3, the original Rest protocol has been moved to the Extensions library, and the Triple protocol now provides more comprehensive support for Rest. To continue using -the original Rest protocol, you can add the corresponding [dubbo-spi-extensions](https://github.com/apache/dubbo-spi-extensions/tree/master/dubbo-rpc-extensions/dubbo-rpc-rest) -library dependency. -{{% /alert %}} - -## Introduction - -Since Dubbo 3.3, the Triple protocol reuses the existing HTTP stack to fully support RESTful service exports. Without the need for generic or gateway protocol conversion, users can -directly access backend Triple protocol services via HTTP in a decentralized manner. Additionally, it offers extensive annotation and SPI extension support for advanced REST usage, -such as path customization, output format customization, and exception handling. Key features include: - -- **Triple Protocol Integration** - Reuses the existing Triple HTTP stack, allowing support for HTTP/1, HTTP/2, and HTTP/3 without additional configuration or new ports. -- **Decentralization** - Exposes Rest APIs directly, eliminating dependency on gateway applications for traffic forwarding, thus improving performance and reducing stability risks caused by gateways. - Security concerns can be addressed through internal application extensions, a practice verified in Taobao’s MTOP. -- **Support for Existing Servlet Infrastructure** - Supports Servlet API and Filter, allowing users to reuse existing security components based on the Servlet API. Integrating OAuth and Spring Security is as simple as implementing - a Servlet Filter. -- **Multiple Dialects** - Considering that most users are accustomed to using SpringMVC or JAX-RS for REST API development, Triple Rest allows continued use of these methods for service definitions and - supports most extensions and exception handling mechanisms (with over 80% of the original framework’s functionality). For lightweight users, the Basic dialect is available, and - Triple’s out-of-the-box REST capabilities are based on this dialect. -- **High Extensibility** - Offers more than 20 extension points, enabling users to easily create custom dialects and flexibly customize parameter retrieval, type conversion, error handling, and other - logic. -- **Out-of-the-Box** - REST capabilities are available out of the box; simply enable the Triple protocol to have direct REST access to services. -- **High-Performance Routing** - The routing component uses an - optimized [Radix Tree](https://github.com/apache/dubbo/blob/3.3/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java) and Zero - Copy technology to improve routing performance. -- **Seamless OpenAPI Integration (TBD)** - Upcoming OpenAPI integration will allow for out-of-the-box OpenAPI Schema export. With the Swagger dependency, a Web UI can be used for service testing. Using the OpenAPI Schema, - API tools like [Postman](https://www.postman.com/) and [Apifox](https://apifox.com/) can manage and test APIs, and the OpenAPI ecosystem can facilitate cross-language calls. - Future enhancements will support a Schema First approach, allowing frontend teams to define OpenAPI collaboratively, generate call code and mocks based on OpenAPI, and enable - backend development using stubs generated from OpenAPI, greatly improving collaboration efficiency. - - -## Quick Start - -Let's explore Triple Rest with a simple example. You can directly download the existing sample project to get started quickly. Assume you have Java, Maven, and Git installed. - -### Download and Run the Example - -```bash -# Get the sample code -git clone --depth=1 https://github.com/apache/dubbo-samples.git -cd dubbo-samples/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-basic -# Run directly -mvn spring-boot:run -# Or package and run -mvn clean package -DskipTests -java -jar target/dubbo-samples-triple-rest-basic-1.0.0-SNAPSHOT.jar -``` - -Alternatively, you can import the project into your IDE and directly execute `org.apache.dubbo.rest.demo.BasicRestApplication#main` to run it. You can also debug by setting -breakpoints to deeply understand the principles. - -### Example Code - -```java -// Service Interface -package org.apache.dubbo.rest.demo; - -import org.apache.dubbo.remoting.http12.rest.Mapping; -import org.apache.dubbo.remoting.http12.rest.Param; - -public interface DemoService { - String hello(String name); - - @Mapping(path = "/hi", method = HttpMethods.POST) - String hello(User user, @Param(value = "c", type = ParamType.Header) int count); -} - -// Service Implementation -@DubboService -public class DemoServiceImpl implements DemoService { - @Override - public String hello(String name) { - return "Hello " + name; - } - - @Override - public String hello(User user, int count) { - return "Hello " + user.getTitle() + ". " + user.getName() + ", " + count; - } -} - -// Model -@Data -public class User { - private String title; - private String name; -} -``` - - - -### Test the Basic Service - -```bash -curl -v "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hello?name=world" -# Output: -#> GET /org.apache.dubbo.rest.demo.DemoService/hello?name=world HTTP/1.1 -#> Host: 127.0.0.1:8081 -#> User-Agent: curl/8.7.1 -#> Accept: */* -#> -#* Request completely sent off -#< HTTP/1.1 200 OK -#< content-type: application/json -#< alt-svc: h2=":8081" -#< content-length: 13 -#< -#"Hello world" -``` - -Explanation:
You see the output `"Hello world"`. The quotes are because the default content-type is `application/json`. This example demonstrates how Triple exports services -to the `/{serviceInterface}/{methodName}` path by default and supports passing parameters via URL. - - -### Test the Advanced Service - -```bash -curl -v -H "c: 3" -d 'name=Yang' "http://127.0.0.1:8081/org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr" -# Output: -#> POST /org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr HTTP/1.1 -#> Host: 127.0.0.1:8081 -#> User-Agent: curl/8.7.1 -#> Accept: */* -#> c: 3 -#> Content-Length: 9 -#> Content-Type: application/x-www-form-urlencoded -#> -#* upload completely sent off: 9 bytes -#< HTTP/1.1 200 OK -#< content-type: text/plain -#< alt-svc: h2=":8081" -#< content-length: 17 -#< -#Hello Mr. Yang, 3 -``` - -Explanation:
The output `"Hello Mr. Yang, 3"` has no quotes because the `.txt` suffix was specified to request `text/plain` output. This example shows how to customize paths -using the `Mapping` annotation, customize parameter sources with the `Param` annotation, and pass parameters via post body or URL. For more details, see -the [Basic Usage Guide](#GdlnC) - - -### Observe Logs - -Enable debug logging to understand the rest startup and request response process: - -```yaml -logging: - level: - "org.apache.dubbo.rpc.protocol.tri": debug - "org.apache.dubbo.remoting": debug -``` - -Once enabled, you can observe the Rest mapping registration and request process: - -``` -# Register mapping -DEBUG o.a.d.r.p.t.TripleProtocol : [DUBBO] Register triple grpc mapping: 'org.apache.dubbo.rest.demo.DemoService' -> invoker[tri://192.168.2.216:8081/org.apache.dubbo.rest.demo.DemoService] - INFO .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] BasicRequestMappingResolver resolving rest mappings for ServiceMeta{interface=org.apache.dubbo.rest.demo.DemoService, service=DemoServiceImpl@2a8f6e6} at url [tri://192.168.2.216:8081/org.apache.dubbo.rest.demo.DemoService] -DEBUG .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Register rest mapping: '/org.apache.dubbo.rest.demo.DemoService/hi' -> mapping=RequestMapping{name='DemoServiceImpl#hello', path=PathCondition{paths=[org.apache.dubbo.rest.demo.DemoService/hi]}, methods=MethodsCondition{methods=[POST]}}, method=MethodMeta{method=org.apache.dubbo.rest.demo.DemoService.hello(User, int), service=DemoServiceImpl@2a8f6e6} -DEBUG .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Register rest mapping: '/org.apache.dubbo.rest.demo.DemoService/hello' -> mapping=RequestMapping{name='DemoServiceImpl#hello~S', path=PathCondition{paths=[org.apache.dubbo.rest.demo.DemoService/hello]}}, method=MethodMeta{method=org.apache.dubbo.rest.demo.DemoService.hello(String), service=DemoServiceImpl@2a8f6e6} - INFO .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Registered 2 REST mappings for service [DemoServiceImpl@44627686] at url [tri://192.168.2.216:8081/org.apache.dubbo.rest.demo.DemoService] in 11ms - -# 请求响应 -DEBUG .a.d.r.p.t.r.m.RestRequestHandlerMapping : [DUBBO] Received http request: DefaultHttpRequest{method='POST', uri='/org.apache.dubbo.rest.demo.DemoService/hi.txt?title=Mr', contentType='application/x-www-form-urlencoded'} -DEBUG .r.p.t.r.m.DefaultRequestMappingRegistry : [DUBBO] Matched rest mapping=RequestMapping{name='DemoServiceImpl#hello', path=PathCondition{paths=[/org.apache.dubbo.rest.demo.DemoService/hi]}, methods=MethodsCondition{methods=[POST]}}, method=MethodMeta{method=org.apache.dubbo.rest.demo.DemoService.hello(User, int), service=DemoServiceImpl@2a8f6e6} -DEBUG .a.d.r.p.t.r.m.RestRequestHandlerMapping : [DUBBO] Content-type negotiate result: request='application/x-www-form-urlencoded', response='text/plain' -DEBUG .d.r.h.AbstractServerHttpChannelObserver : [DUBBO] Http response body is: '"Hello Mr. Yang, 3"' -DEBUG .d.r.h.AbstractServerHttpChannelObserver : [DUBBO] Http response headers sent: {:status=[200], content-type=[text/plain], alt-svc=[h2=":8081"], content-length=[17]} -``` - - - -## General Features - - - -### Path Mapping - -The Triple protocol is compatible with both SpringMVC and JAX-RS mapping methods. For more information, refer to: - -- [Spring Mapping Requests](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-uri-templates) -- [Spring PathPattern](https://docs.spring.io/spring-framework/docs/6.1.12/javadoc-api/org/springframework/web/util/pattern/PathPattern.html) -- [Spring AntPathMatcher](https://docs.spring.io/spring-framework/docs/6.1.12/javadoc-api/org/springframework/util/AntPathMatcher.html) -- [JAX-RS Path and regular expression mappings](https://docs.jboss.org/resteasy/docs/6.2.7.Final/userguide/html/ch04.html) - -You can also customize path mapping by implementing the SPI `org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver`. - - -#### Supported Patterns - -1. `books`: A string constant matching a fixed segment. -2. `?`: Matches a single character. -3. `*`: Matches zero or more characters within a path segment. -4. `**`: Matches zero or more path segments until the end of the path. -5. `{spring}`: Matches a path segment and captures it as a variable named "spring." -6. `{spring:[a-z]+}`: Uses a regular expression `[a-z]+` to match a path segment and captures it as a variable named "spring." -7. `{*spring}`: Matches zero or more path segments until the end of the path and captures them as a variable named "spring." `{*}` without a variable name indicates that no - capturing is done. - - -#### Examples (from Spring Documentation) - -- `/pages/t?st.html`: Matches `/pages/test.html` and `/pages/tXst.html`, but not `/pages/toast.html`. -- `/resources/*.png`: Matches all `.png` files in the `resources` directory. -- `com/**/test.jsp`: Matches all `test.jsp` files under the `com` path. -- `org/springframework/**/*.jsp`: Matches all `.jsp` files under the `org/springframework` path. -- `/resources/**`: Matches all files under the `/resources/` path, including `/resources/image.png` and `/resources/css/spring.css`. -- `/resources/{*path}`: Matches all files under `/resources/` as well as `/resources` itself, capturing the relative path as the variable "path." For example, - `/resources/image.png` would map to "path" → "/image.png", and `/resources/css/spring.css` would map to "path" → "/css/spring.css". -- `/resources/{filename:\\w+}.dat`: Matches `/resources/spring.dat` and assigns the value "spring" to the `filename` variable. -- `/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}`: Matches `/example-2.1.5.html`, with `name` as `example`, `version` as `2.1.5`, and `ext` as `.html`. - -Tip: If you do not want the regular expression to span multiple segments, use `{name:[^/]+}`. - - -#### Full Mapping Process - -The detailed matching logic is implemented in the following -code: [DefaultRequestMappingRegistry.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java#L196), [RequestMapping.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java#L127). - -1. Normalize the path using `PathUtils.normalize` to remove indirect paths such as `/one/../` or `/one/./`, ensuring the path starts with `/`. -2. Check if the HTTP method matches. -3. Check if the path matches. -4. Check if the parameter matches (not supported by JAX-RS). -5. Check if the header matches. -6. Check if the content type matches (Consumes). -7. Check if the accept header matches (Produces). -8. Check if `serviceGroup` and `serviceVersion` match. -9. Check if the method signature matches. -10. If no match is found, retry after removing the trailing `/` if trailing slash matching is enabled. -11. If no match is found, retry after removing the extension if extension matching is enabled. -12. If the last path segment contains `~`, retry with method signature matching enabled. -13. If no candidates remain, return `null`. -14. If one candidate remains, return it. -15. If multiple candidates remain, sort them. -16. Compare the first and second candidates. -17. If the result is inconclusive, throw an exception. -18. If the first candidate wins, return it. - - -#### Handling Path Conflicts - -Unlike Spring, which raises an error and prevents startup when paths are identical, Triple Rest focuses on out-of-the-box usage. To avoid disrupting existing services, it logs a -warning by default. At runtime, if it cannot determine the highest priority mapping, an error will be thrown. - - - -### Parameter Types - -Supported parameter types vary by dialect. Please refer to the specific dialect's guide for more details. You can also customize parameter resolution by implementing the SPI -`org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver`. - -#### Common Parameter Types - -| Name | Description | Basic Annotation | SpringMVC Annotation | JAX-RS Annotation | Array or Collection Handling | Map Handling | -|----------------|-------------------------|-----------------------------|----------------------|-------------------|-----------------------------------------------|----------------------------------| -| Param | Query or Form parameter | @Param | @RequestParam | - | Multi-value | Map of all parameters | -| Query | URL parameter | - | - | @QueryParam | Multi-value | Map of all Query parameters | -| Form | Form parameter | - | - | @FormParam | Multi-value | Map of all Form parameters | -| Header | HTTP header | @Param(type=Header) | @RequestHeader | @HeaderParam | Multi-value | Map of all Headers | -| Cookie | Cookie value | @Param(type=Cookie) | @CookieValue | @CookieParam | Multi-value | Map of all Cookies | -| Attribute | Request attribute | @Param(type=Attribute) | @RequestAttribute | - | Multi-value | Map of all Attributes | -| Part | Multipart file | @Param(type=Part) | @RequestHeader | @HeaderParam | Multi-value | Map of all Parts | -| Body | Request body | @Param(type=Body) | @RequestBody | @Body | Attempts to parse as array or collection | Attempts to parse as target type | -| PathVariable | Path variable | @Param(type=PathVariable) | @PathVariable | @PathParam | Single-value array or collection | Single-value Map | -| MatrixVariable | Matrix variable | @Param(type=MatrixVariable) | @MatrixVariable | @MatrixParam | Multi-value | Single-value Map | -| Bean | Java Bean | No annotation needed | @ModelAttribute | @BeanParam | Attempts to parse as Bean array or collection | - | - - - -#### Special Parameter Types - -| Type | Description | Activation Condition | -|-------------------------------------------------|--------------------------------|--------------------------| -| `org.apache.dubbo.remoting.http12.HttpRequest` | HttpRequest object | Activated by default | -| `org.apache.dubbo.remoting.http12.HttpResponse` | HttpResponse object | Activated by default | -| `org.apache.dubbo.remoting.http12.HttpMethods` | HTTP request method | Activated by default | -| `java.util.Locale` | Request Locale | Activated by default | -| `java.io.InputStream` | Request InputStream | Activated by default | -| `java.io.OutputStream` | Response OutputStream | Activated by default | -| `javax.servlet.http.HttpServletRequest` | Servlet HttpRequest object | Requires Servlet API jar | -| `javax.servlet.http.HttpServletResponse` | Servlet HttpResponse object | Same as above | -| `javax.servlet.http.HttpSession` | Servlet HttpSession object | Same as above | -| `javax.servlet.http.Cookie` | Servlet Cookie object | Same as above | -| `java.io.Reader` | Servlet Request Reader object | Same as above | -| `java.io.Writer` | Servlet Response Writer object | Same as above | - - - -#### Parameters without Annotations - -The handling varies by dialect; refer to the specific dialect's guide. - - -#### Accessing HTTP Input and Output Parameters without Annotations - -You can use `RpcContext` to retrieve them: - -```java -// Dubbo http req/resp -HttpRequest request = RpcContext.getServiceContext().getRequest(HttpRequest.class); -HttpResponse response = RpcContext.getServiceContext().getRequest(HttpResponse.class); -// Servlet http req/resp -HttpServletRequest request = RpcContext.getServiceContext().getRequest(HttpServletRequest.class); -HttpServletResponse response = RpcContext.getServiceContext().getRequest(HttpServletResponse.class); -``` - -After obtaining the request, you can access some built-in attributes through `attribute`. -See: [RestConstants.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestConstants.java#L40) - - -### Parameter Type Conversion - -By default, most parameter type conversions from `String` to target types are supported, including: - -- JDK built-in types (e.g., basic types, date, `Optional`, etc.) -- Array types -- Collection types -- Map types - -Generic types, including complex nesting, are fully supported. For implementation details, refer -to: [GeneralTypeConverter.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/GeneralTypeConverter.java). -Custom parameter type conversion can also be achieved by implementing SPI `org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter`. - -| Source Type | Target Type | Description | Default Value | -|-------------|-------------------------|----------------------------------|---------------| -| `String` | `double` | Converts to a double | 0.0d | -| `String` | `float` | Converts to a float | 0.0f | -| `String` | `long` | Converts to a long | 0L | -| `String` | `int` | Converts to an integer | 0 | -| `String` | `short` | Converts to a short | 0 | -| `String` | `char` | Converts to a character | 0 | -| `String` | `byte` | Converts to a byte | 0 | -| `String` | `boolean` | Converts to a boolean | false | -| `String` | `BigInteger` | Converts to a BigInteger | null | -| `String` | `BigDecimal` | Converts to a BigDecimal | null | -| `String` | `Date` | Converts to a Date | null | -| `String` | `Calendar` | Converts to a Calendar | null | -| `String` | `Timestamp` | Converts to a Timestamp | null | -| `String` | `Instant` | Converts to an Instant | null | -| `String` | `ZonedDateTime` | Converts to a ZonedDateTime | null | -| `String` | `LocalDate` | Converts to a LocalDate | null | -| `String` | `LocalTime` | Converts to a LocalTime | null | -| `String` | `LocalDateTime` | Converts to a LocalDateTime | null | -| `String` | `ZoneId` | Converts to a ZoneId | null | -| `String` | `TimeZone` | Converts to a TimeZone | null | -| `String` | `File` | Converts to a File | null | -| `String` | `Path` | Converts to a Path | null | -| `String` | `Charset` | Converts to a Charset | null | -| `String` | `InetAddress` | Converts to an InetAddress | null | -| `String` | `URI` | Converts to a URI | null | -| `String` | `URL` | Converts to a URL | null | -| `String` | `UUID` | Converts to a UUID | null | -| `String` | `Locale` | Converts to a Locale | null | -| `String` | `Currency` | Converts to a Currency | null | -| `String` | `Pattern` | Converts to a Pattern | null | -| `String` | `Class` | Converts to a Class | null | -| `String` | `byte[]` | Converts to a byte array | null | -| `String` | `char[]` | Converts to a char array | null | -| `String` | `OptionalInt` | Converts to an OptionalInt | null | -| `String` | `OptionalLong` | Converts to an OptionalLong | null | -| `String` | `OptionalDouble` | Converts to an OptionalDouble | null | -| `String` | `Enum class` | Enum.valueOf | null | -| `String` | `Array` or `Collection` | Split by comma | null | -| `String` | `Specified class` | Try JSON String to Object | null | -| `String` | `Specified class` | Try construct with single String | null | -| `String` | `Specified class` | Try call static method `valueOf` | null | - - - -### Supported Content-Types - -By default, the following Content-Types are supported with corresponding encoding and decoding capabilities. Extension is available by implementing SPI -`org.apache.dubbo.remoting.http12.message.(HttpMessageDecoderFactory|HttpMessageEncoderFactory)`. - -| Media Type | Description | -|-------------------------------------|----------------------------| -| `application/json` | JSON format | -| `application/xml` | XML format | -| `application/yaml` | YAML format | -| `application/octet-stream` | Binary data | -| `application/grpc` | gRPC format | -| `application/grpc+proto` | gRPC with Protocol Buffers | -| `application/x-www-form-urlencoded` | URL-encoded form data | -| `multipart/form-data` | Form data with file upload | -| `text/json` | JSON format as text | -| `text/xml` | XML format as text | -| `text/yaml` | YAML format as text | -| `text/css` | CSS format | -| `text/javascript` | JavaScript format as text | -| `text/html` | HTML format | -| `text/plain` | Plain text | - - - -### Content Negotiation - -Supports comprehensive content negotiation to determine the output Content-Type based on mapping or input. The process is as follows: - -1. Try to read the mediaType specified by Mapping, retrieve the list of mediaTypes specified by Produces, and match wildcard to appropriate Media Type. For example, Spring's: - `@RequestMapping(produces = "application/json")` -2. Try to find mediaType using the Accept header, parse the request's `Accept` header, and match wildcard to appropriate Media Type. For example: `Accept: application/json` -3. Try to find mediaType using the format parameter, read the format parameter value, and match it to an appropriate Media Type. For example `/hello?format=yml` -4. Try to find mediaType using the request path extension, match the extension to an appropriate Media Type. For example `/hello.txt` -5. Try to use the request's Content-Type header as Media Type (excluding two form types). For example `Content-Type: application/json` -6. Default to `application/json` - - - -### CORS Support - -Provides full CORS support, enabled by configuring global parameters. Default behavior is consistent with SpringMVC. Fine-grained configuration is also supported through -`@CrossOrigin` in SpringMVC. For supported CORS configuration items, refer to: [8.4 CORS Configuration](#NLQqj) - - -### Custom HTTP Output - -Custom HTTP output is required in many scenarios, such as 302 redirects or setting HTTP headers. Triple Rest offers the following generic solutions, with dialect-specific -approaches available in each dialect's user guide: - -- Set the return value to: `org.apache.dubbo.remoting.http12.HttpResult` and build using `HttpResult#builder`. -- Throw a Payload exception: `throws new org.apache.dubbo.remoting.http12.exception.HttpResultPayloadException(HttpResult)`. Example code: - -```java -throw new HttpResult.found("https://a.com"). - -toPayload(); -``` - -This exception avoids filling error stacks, has minimal performance impact, and does not require return value logic, making it recommended for customizing output. - -- Customize after obtaining HttpResponse. Example code: - -```java -HttpResponse response = RpcContext.getServiceContext().getRequest(HttpResponse.class); - -response. - -sendRedirect("https://a.com"); -response. - -setStatus(404); -response. - -outputStream(). - -write(data); -// It is recommended to commit after writing to avoid being modified by other extensions -response. - -commit(); -``` - -If only adding `http headers`, use this method. - - -### Custom JSON Serialization - -Multiple JSON frameworks are supported, including Jackson, fastjson2, fastjson, and gson. Please ensure that the corresponding jar dependencies have been imported before use. - -#### Specifying the JSON Framework to Use - -```properties -dubbo.protocol.triple.rest.json-framework=jackson -``` - -#### Customization through JsonUtil SPI - -You can customize JSON processing by implementing the SPI `org.apache.dubbo.common.json.JsonUtil`. For specific examples, you can refer to the existing implementations -in [org/apache/dubbo/common/json/impl](https://github.com/apache/dubbo/tree/3.3/dubbo-common/src/main/java/org/apache/dubbo/common/json/impl). It is recommended to extend an -existing implementation and override as needed. - - - -### Exception Handling - -Unhandled exceptions are ultimately converted to the `ErrorResponse` class and encoded for output: - -```java - -@Data -public class ErrorResponse { - /** - * HTTP status code - */ - private String status; - - /** - * Exception message - */ - private String message; -} -``` - -Note that for errors with status 500 and above, to avoid disclosing internal server information, the default message output is "Internal Server Error". To customize the message, -create an exception that extends `org.apache.dubbo.remoting.http12.exception.HttpStatusException` and override the `getDisplayMessage` method.
The following general methods -are available for customizing exception handling: - -- Refer to [9.2 Custom Exception Return Results](#zFD9A) for using SPI to customize global exception handling. -- Use Dubbo's Filter SPI to process and transform exceptions. To access the HTTP context, extend `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilterAdapter`. -- Use SPI `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter` to transform exceptions, which is more lightweight and provides path matching configuration capabilities. - -Note that the latter two methods only intercept exceptions occurring in the invoke chain. If exceptions occur during path matching, only method 1 can handle them. - - -## Basic Usage Guide - -See -example: [dubbo-samples-triple-rest/dubbo-samples-triple-rest-basic](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-basic) - - -### Path Mapping - -Basic, as an out-of-the-box REST mapping, will by default map methods to: `/{contextPath}/{serviceInterface}/{methodName}`, where `/{contextPath}` will be ignored if not -configured, resulting in: `/{serviceInterface}/{methodName}`.
Custom mappings are supported through the `org.apache.dubbo.remoting.http12.rest.Mapping` annotation. The -attribute descriptions are as follows: - -| Config Name | Description | Default Behavior | -|-------------|----------------------------------------------------------------------------------------|------------------------------------| -| `value` | Mapped URL paths, which can be one or more paths. | Empty array | -| `path` | Mapped URL paths, same as `value`, can be one or more paths. | Empty array | -| `method` | Supported HTTP methods list, such as `GET`, `POST`, etc. | Empty array (supports all methods) | -| `params` | List of parameters that must be included in the request. | Empty array | -| `headers` | List of headers that must be included in the request. | Empty array | -| `consumes` | Content types (Content-Type) for processing requests, which can be one or more types. | Empty array | -| `produces` | Content types (Content-Type) for generating responses, which can be one or more types. | Empty array | -| `enabled` | Whether to enable this mapping. | `true` (enabled) | - -- Attributes can be configured using placeholders: `@Mapping("${prefix}/hi")` -- To prevent a specific service or method from being exported as REST, set `@Mapping(enabled = false)` - - -### Parameter Types - -General parameters are discussed in: [3.2 Parameter Types](#kmCzf) - - - -#### Parameters Without Annotations - -Basic supports parameters without annotations through the -class: [FallbackArgumentResolver.java](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java#L41). -The detailed processing flow is as follows:
![rest-arg.jpg](/imgs/v3/manual/java/protocol/rest-arg.jpg) - - -## SpringMVC Usage Guide - -See -example: [dubbo-samples-triple-rest/dubbo-samples-triple-rest-springmvc](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-springmvc) - - -### Path Mapping - -Refer directly to the SpringMVC documentation, which supports most -features, [Mapping Requests :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-uri-templates)
-Note that `@Controller` or `@RestController` annotations are not required; in addition to `@RequestMapping`, the new `@HttpExchange` is also supported. - - -### Parameter Types - - - -#### General Parameters - -See: [3.2 Parameter Types](#kmCzf) - - -#### Annotated Parameter Types - -See [3.2.1 Annotated Parameter Types](#dCgzz) - - -#### Special Parameter Types - -| Type | Description | Activation Condition | -|----------------------------------------------------------|-------------------------|-------------------------------| -| org.springframework.web.context.request.WebRequest | WebRequest object | SpringWeb dependency required | -| org.springframework.web.context.request.NativeWebRequest | NativeWebRequest object | Same as above | -| org.springframework.http.HttpEntity | Http entity | Same as above | -| org.springframework.http.HttpHeaders | Http headers | Same as above | -| org.springframework.util.MultiValueMap | Multi-value map | Same as above | - - - -#### Parameters Without Annotations - -- For basic types (as determined - by [TypeUtils#isSimpleProperty](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java#L105)), - directly obtained from Parameter -- For non-basic types, - use [@ModelAttribute :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/modelattrib-method-args.html) to bind complex - bean type parameters - - -### Parameter Type Conversion - -Prefer using Spring's `org.springframework.core.convert.ConversionService` to convert parameters. For Spring Boot applications, the default is `mvcConversionService`; otherwise, -use `org.springframework.core.convert.support.DefaultConversionService#getSharedInstance` to obtain the shared `ConversionService`.
If `ConversionService` does not support it, -it will fall back to general type conversion: [3.3 Parameter Type Conversion](#I56vX) - - -### Exception Handling - -In addition to supporting the methods mentioned in [3.8 Exception Handling](#XeDPr), Spring's `@ExceptionHandler` annotation method is also -supported, [Exceptions :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-exceptionhandler.html). Note that this method only -handles exceptions thrown during method calls; other exceptions cannot be captured. - - -### CORS Configuration - -In addition to supporting global CORS configuration as described in [8.4 CORS Configuration](#NLQqj), Spring's `@CrossOrigin` allows for fine-grained -configuration, [CORS :: Spring Framework](https://docs.spring.io/spring-framework/reference/web/webmvc-cors.html#mvc-cors-controller). - - -### Custom HTTP Output - -Supports the following Spring customization methods: - -1. Use `@ResponseStatus` annotation -2. Return `org.springframework.http.ResponseEntity` object - - -### Supported Extensions - -- org.springframework.web.servlet.HandlerInterceptor
Usage is similar to [7.1 Using Filter Extensions](#xCEi3) - - -## JAX-RS Usage Guide - -See -example: [dubbo-samples-triple-rest/dubbo-samples-triple-rest-jaxrs](https://github.com/apache/dubbo-samples/tree/master/2-advanced/dubbo-samples-triple-rest/dubbo-samples-triple-rest-jaxrs) - - -### Path Mapping - -Services need to explicitly add the @Path annotation, and methods need to add request method annotations like @GET, @POST, @HEAD.
Refer directly to the Resteasy documentation, -which supports most features, [Chapter 4. Using @Path and @GET, @POST, etc.](https://docs.jboss.org/resteasy/docs/6.2.7.Final/userguide/html/ch04.html) - - -### Parameter Types - - - -#### General Parameters - -See: [3.2 Parameter Types](#kmCzf) - - -#### Annotation Type Parameters - -| Annotation | Parameter Location | Description | -|---------------|--------------------|----------------------------------------| -| @QueryParam | querystring | Parameters corresponding to ?a=a&b=b | -| @HeaderParam | header | | -| @PathParam | path | | -| @FormParam | form | body in key1=value2&key2=value2 format | -| No annotation | body | Not explicitly annotated | - - - -#### Special Type Parameters - -| Type | Description | Activation Condition | -|---------------------------------|-----------------|----------------------------| -| javax.ws.rs.core.Cookie | Cookie object | Requires Jax-rs dependency | -| javax.ws.rs.core.Form | Form object | Same as above | -| javax.ws.rs.core.HttpHeaders | Http headers | Same as above | -| javax.ws.rs.core.MediaType | Media type | Same as above | -| javax.ws.rs.core.MultivaluedMap | Multivalued Map | Same as above | -| javax.ws.rs.core.UriInfo | Uri information | Same as above | - - - -#### Non-Annotated Parameters - -- For basic types (as determined - by [TypeUtils#isSimpleProperty](https://github.com/apache/dubbo/blob/dubbo-3.3.0-beta.5/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java#L105)), - directly retrieved from Parameter -- For non-basic types, treated as request body to decode the object - - -### Parameter Type Conversion - -Custom parameter conversion can be extended via the following interfaces: - -``` -org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver -javax.ws.rs.ext.ParamConverterProvider -``` - - - -### Exception Handling - -Custom exception handling can be extended via the following interfaces: - -``` -javax.ws.rs.ext.ExceptionMapper -org.apache.dubbo.remoting.http12.ExceptionHandler -``` - - - -### CORS Configuration - -Supports [8.4 CORS Configuration](#NLQqj) global configuration - - -### Custom HTTP Output - -Supports the following JAX-RS customizations: - -- Returning `javax.ws.rs.core.Response` object - - -### Supported Extensions - -1. javax.ws.rs.container.ContainerRequestFilter
Request filter, allows pre-processing of requests before they reach the resource method. -2. javax.ws.rs.container.ContainerResponseFilter
Response filter, allows post-processing of responses after they leave the resource method. -3. javax.ws.rs.ext.ExceptionMapper
Exception mapper, maps thrown exceptions to HTTP responses. -4. javax.ws.rs.ext.ParamConverterProvider
Parameter converter, allows conversion of request parameters to resource method parameter types. -5. javax.ws.rs.ext.ReaderInterceptor
Reader interceptor, allows interception and handling when reading request entities. -6. javax.ws.rs.ext.WriterInterceptor
Writer interceptor, allows interception and handling when writing response entities. - - -## Servlet Usage Guide - -For both lower version javax and higher version jakarta servlet APIs, jakarta API has higher priority. Simply include the jar to use HttpServletRequest and HttpServletResponse as -parameters. - - -### Using Filter Extension - -Method 1: Implement `Filter` interface and `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension` interface, then register SPI - -```java -import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension; - -import javax.servlet.Filter; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -public class DemoFilter implements Filter, RestExtension { - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { - chain.doFilter(request, response); - } - - @Override - public String[] getPatterns() { - return new String[]{"/demo/**", "!/demo/one"}; - } - - @Override - public int getPriority() { - return -200; - } -} -``` - -Method 2: Implement `Supplier` interface and `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension` interface, then register SPI - -```java -public class DemoFilter implements Supplier, RestExtension { - - private final Filter filter = new SsoFilter(); - - @Override - public Filter get() { - return filter; - } -} -``` - -This method is convenient for reusing existing Filters, and can even obtain Filter instances from Spring Context and register them - -```java -public class DemoFilter implements Supplier, RestExtension { - - private final Filter filter = new SsoFilter(); - - public DemoFilter(FrameworkModel frameworkModel) { - SpringExtensionInjector injector = SpringExtensionInjector.get(frameworkModel.defaultApplication()); - filter = injector.getInstance(SsoFilter.class, null); - } - - @Override - public Filter get() { - return filter; - } -} -``` - - - -### HttpSession Support - -Implement SPI `org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.HttpSessionFactory` - - -### Unsupported Features - -- Wrapping request and response objects in Filter will not work due to the large number of filter types supported by Rest, leading to complex nesting and handling. -- `request.getRequestDispatcher` is not supported - - -### Security Configuration - -When Rest services open direct access to the public network, there are security risks of potential attacks. Therefore, before exposing services, it's necessary to thoroughly assess -the risks and choose appropriate authentication methods to ensure security. Triple provides various security authentication mechanisms, and users can also implement their own -extensions to perform security checks on access. - -#### Basic Authentication - -To enable Basic Authentication, modify the following configuration: - -```yaml -dubbo: - provider: - auth: true - authenticator: basic - username: admin - password: admin -``` - -Once enabled, all HTTP requests will require Basic Authentication to access. - -For RPC calls, you also need to configure the corresponding username and password on the consumer side: - -```yaml -dubbo: - consumer: - auth: true - authenticator: basic - username: admin - password: admin -``` - -With this configuration, communication between provider and consumer will use Basic Authentication to ensure security. Make sure to use strong passwords in production environments -and consider using HTTPS for encrypted transmission. - -### Authentication Extensions - -#### Implementing Custom Authenticator - -You can customize authentication by implementing the SPI `org.apache.dubbo.auth.spi.Authenticator`, and select the Authenticator to enable through the configuration -`dubbo.provider.authenticator`. - -#### Implementing HTTP Request Filtering - -You can customize HTTP filtering logic by implementing the SPI `org.apache.dubbo.rpc.HeaderFilter` or `org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter`. - -## Global Parameter Configuration - - - -### Case Sensitivity - -Configuration Name: `dubbo.protocol.triple.rest.case-sensitive-match`
Whether path matching should be case-sensitive. If enabled, methods mapped to `/users` will not match -`/Users`
Default is `true` - - -### Trailing Slash Matching - -Configuration Name: `dubbo.protocol.triple.rest.trailing-slash-match`
Whether path matching should match paths with trailing slashes. If enabled, methods mapped to `/users` -will also match `/users/`
Default is `true` - - -### Suffix Matching - -Configuration Name: `dubbo.protocol.triple.rest.suffix-pattern-match`
Whether path matching uses suffix pattern matching (.*). If enabled, methods mapped to `/users` will also -match `/users.*`, with suffix content negotiation enabled, media types inferred from URL suffix, e.g., `.json` corresponds to `application/json`
Default is `true` - - -### CORS Configuration - -| Configuration Name | Description | Default Value | -|-----------------------------------------------------|----------------------------------------------------------------------------------------------------|------------------------------------------| -| `dubbo.protocol.triple.rest.cors.allowed-origins` | List of allowed origins for cross-origin requests, can be specific domains or `*` for all origins. | Not set (no origins allowed) | -| `dubbo.protocol.triple.rest.cors.allowed-methods` | List of allowed HTTP methods, e.g., `GET`, `POST`, `PUT`, `*` for all methods. | Not set (only `GET` and `HEAD`) | -| `dubbo.protocol.triple.rest.cors.allowed-headers` | List of allowed request headers in preflight requests, `*` for all headers. | Not set | -| `dubbo.protocol.triple.rest.cors.exposed-headers` | List of response headers exposed to clients, `*` for all headers. | Not set | -| `dubbo.protocol.triple.rest.cors.allow-credentials` | Whether user credentials are supported. | Not set (user credentials not supported) | -| `dubbo.protocol.triple.rest.cors.max-age` | Time (in seconds) that the client can cache the preflight request response. | Not set | - - - -## Advanced Usage Guide - - - -### Summary of Supported Extensions - -1. javax.servlet.Filter
Servlet API filter. -2. org.apache.dubbo.rpc.protocol.tri.rest.support.servlet.HttpSessionFactory
Supports HttpSession in Servlet API. -3. javax.ws.rs.container.ContainerRequestFilter
JAX-RS request filter, allows pre-processing of requests before they reach the resource method. -4. javax.ws.rs.container.ContainerResponseFilter
JAX-RS response filter, allows post-processing of responses after they leave the resource method. -5. javax.ws.rs.ext.ExceptionMapper
JAX-RS exception mapper, maps thrown exceptions to HTTP responses. -6. javax.ws.rs.ext.ParamConverterProvider
JAX-RS parameter converter, allows conversion of request parameters to resource method parameter types. -7. javax.ws.rs.ext.ReaderInterceptor
JAX-RS reader interceptor, allows interception and handling when reading request entities. -8. javax.ws.rs.ext.WriterInterceptor
JAX-RS writer interceptor, allows interception and handling when writing response entities. -9. org.springframework.web.servlet.HandlerInterceptor
Spring MVC handler interceptor. -10. org.apache.dubbo.remoting.http12.ExceptionHandler
Provides custom exception handling mechanism. -11. org.apache.dubbo.remoting.http12.message.HttpMessageAdapterFactory
Provides adaptation and conversion functions for HTTP messages. -12. org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory
Provides HTTP message decoding functions. -13. org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory
Provides HTTP message encoding functions. -14. org.apache.dubbo.rpc.HeaderFilter
Dubbo RPC header filter, allows filtering and handling of request and response headers. -15. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestHeaderFilterAdapter
Header filter adapter providing access to HTTP input and output capabilities. -16. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilterAdapter
Dubbo Filter REST adapter, providing access to HTTP input and output capabilities. -17. org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping
Provides request mapping capability in Dubbo Triple. -18. org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver
Resolves REST request mappings. -19. org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit
Provides REST-related tools and utilities. -20. org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentConverter
Provides argument type conversion functionality. -21. org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver
Provides argument resolution functionality. -22. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter
Provides filtering functionality for REST requests and responses. -23. org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtensionAdapter
RestExtension adapter providing mapping of existing filter interfaces to RestFilter interfaces. - - -### Custom Exception Handling - -Custom exception handling logic can be implemented via the SPI `org.apache.dubbo.remoting.http12.ExceptionHandler` - -```java -public interface ExceptionHandler { - /** - * Resolves the log level for a given throwable. - */ - default Level resolveLogLevel(E throwable) { - return null; - } - - /** - * Handle the exception and return a result. - */ - default T handle(E throwable, RequestMetadata metadata, MethodDescriptor descriptor) { - return null; - } -} -``` - -Implement SPI and specify the exception type E to handle - -- resolveLogLevel
Dubbo framework will log Rest handling exceptions, customize log level or ignore logs by implementing this method. -- handle
If the result is not null, it will be directly returned; customize output headers and status code by returning `org.apache.dubbo.remoting.http12.HttpResult`. - - -### Enable Debug Logging - -```yaml -logging: - level: - "org.apache.dubbo.rpc.protocol.tri": debug - "org.apache.dubbo.remoting": debug -``` - -Enable debug logging will output detailed startup logs and request/response logs for troubleshooting. - - -### Enable Verbose Output - -```yaml -dubbo: - protocol: - triple: - verbose: true -``` - -Enable verbose output will return internal error stack traces to the caller and output more error logs for troubleshooting. diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/_index.md deleted file mode 100755 index e46f7bd5288f..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "Triple Protocol" -linkTitle: "Triple Protocol" -weight: 3 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/guide.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/guide.md deleted file mode 100644 index b90e4d63c842..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/guide.md +++ /dev/null @@ -1,278 +0,0 @@ ---- -type: docs -title: "Instructions for Use" -linkTitle: "Instructions for use" -weight: 2 ---- - -The Triple protocol is the main protocol of Dubbo3, fully compatible with gRPC over HTTP/2, and has expanded load balancing and flow control related mechanisms at the protocol level. This document is intended to guide users to use the Triple protocol correctly. - -Before starting, you need to decide the serialization method used by the service. If it is a new service, it is recommended to use protobuf as the default serialization, which will have better performance and cross-language effects. If the original service wants to upgrade the protocol, the Triple protocol already supports other serialization methods, such as Hessian / JSON, etc. - - - -### Protobuf - -1. Write the IDL file - ```protobuf - syntax = "proto3"; - - option java_multiple_files = true; - option java_package = "org.apache.dubbo.hello"; - option java_outer_classname = "HelloWorldProto"; - option objc_class_prefix = "HLW"; - - package helloworld; - - // The request message containing the user's name. - message HelloRequest { - string name = 1; - } - - // The response message containing the greetings - message HelloReply { - string message = 1; - } - ``` - -2. Add the extension and plugin for compiling protobuf (take maven as an example) - ```xml - - - kr.motd.maven - os-maven-plugin - 1.6.1 - - - - - org.xolstice.maven.plugins - protobuf-maven-plugin - 0.6.1 - - com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier} - triple-java - build/generated/source/proto/main/java - - - - - compile - test-compile - - - - - - ``` - -3. Build/compile to generate protobuf Message class - ```shell - $ mvn clean install - ``` - -### Unary way - -4. Writing the Java interface - ```java - import org.apache.dubbo.hello.HelloReply; - import org.apache.dubbo.hello.HelloRequest; - - public interface IGreeter { - /** - *
-         * Sends a greeting
-         * 
- */ - HelloReply sayHello(HelloRequest request); - - } - ``` - -5. Create a Provider - ```java - public static void main(String[] args) throws InterruptedException { - ServiceConfig service = new ServiceConfig<>(); - service.setInterface(IGreeter.class); - service.setRef(new IGreeter1Impl()); - // Here you need to show that the protocol used by the declaration is triple - service.setProtocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051)); - service.setApplication(new ApplicationConfig("demo-provider")); - service.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181")); - service. export(); - System.out.println("dubbo service started"); - new CountDownLatch(1). await(); - } - - ``` - - -6. Create Consumer - - ```java - public static void main(String[] args) throws IOException { - ReferenceConfig ref = new ReferenceConfig<>(); - ref. setInterface(IGreeter. class); - ref. setCheck(false); - ref.setProtocol(CommonConstants.TRIPLE); - ref. setLazy(true); - ref. setTimeout(100000); - ref. setApplication(new ApplicationConfig("demo-consumer")); - ref.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181")); - final IGreeter iGreeter = ref. get(); - - System.out.println("dubbo ref started"); - try { - final HelloReply reply = iGreeter.sayHello(HelloRequest.newBuilder() - .setName("name") - .build()); - TimeUnit. SECONDS. sleep(1); - System.out.println("Reply:" + reply); - } catch (Throwable t) { - t. printStackTrace(); - } - System.in.read(); - } - ``` - -7. Run Provider and Consumer, you can see that the request returns normally - > Reply: message: "name" - -### stream mode - -8. Writing Java Interfaces - ```java - import org.apache.dubbo.hello.HelloReply; - import org.apache.dubbo.hello.HelloRequest; - - public interface IGreeter { - /** - *
-     * Sends greeting by stream
-     * 
- */ -StreamObserver sayHello(StreamObserver replyObserver); - - } - ``` - -9. Write the implementation class - ```java -public class IStreamGreeterImpl implements IStreamGreeter { - -@Override -public StreamObserver sayHello(StreamObserver replyObserver) { - -return new StreamObserver() { -private List replyList = new ArrayList<>(); - -@Override -public void onNext(HelloRequest helloRequest) { -System.out.println("onNext receive request name:" + helloRequest.getName()); -replyList.add(HelloReply.newBuilder() -.setMessage("receive name:" + helloRequest.getName()) -.build()); -} - -@Override -public void onError(Throwable cause) { -System.out.println("onError"); -replyObserver.onError(cause); -} - -@Override -public void onCompleted() { -System.out.println("onComplete receive request size:" + replyList.size()); -for (HelloReply reply : replyList) { -replyObserver.onNext(reply); -} -replyObserver.onCompleted(); -} -}; -} -} -``` - -10. Create a Provider - - ```java -public class StreamProvider { -public static void main(String[] args) throws InterruptedException { -ServiceConfig service = new ServiceConfig<>(); -service.setInterface(IStreamGreeter.class); -service.setRef(new IStreamGreeterImpl()); -service.setProtocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051)); -service.setApplication(new ApplicationConfig("stream-provider")); -service.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181")); -service. export(); -System.out.println("dubbo service started"); -new CountDownLatch(1). await(); -} -} -``` - -11. Create Consumer - - ```java -public class StreamConsumer { -public static void main(String[] args) throws InterruptedException, IOException { -ReferenceConfig ref = new ReferenceConfig<>(); -ref. setInterface(IStreamGreeter. class); -ref. setCheck(false); -ref.setProtocol(CommonConstants.TRIPLE); -ref. setLazy(true); -ref. setTimeout(100000); -ref. setApplication(new ApplicationConfig("stream-consumer")); -ref.setRegistry(new RegistryConfig("zookeeper://mse-6e9fda00-p.zk.mse.aliyuncs.com:2181")); -final IStreamGreeter iStreamGreeter = ref. get(); - -System.out.println("dubbo ref started"); -try { - -StreamObserver streamObserver = iStreamGreeter.sayHello(new StreamObserver() { -@Override -public void onNext(HelloReply reply) { -System.out.println("onNext"); -System.out.println(reply.getMessage()); -} - -@Override -public void onError(Throwable throwable) { -System.out.println("onError:" + throwable.getMessage()); -} - -@Override -public void onCompleted() { -System.out.println("onCompleted"); -} -}); - -streamObserver.onNext(HelloRequest.newBuilder() -.setName("tony") -.build()); - -streamObserver.onNext(HelloRequest.newBuilder() -.setName("nick") -.build()); - -streamObserver.onCompleted(); -} catch (Throwable t) { -t. printStackTrace(); -} -System.in.read(); -} -} -``` - -12. Run Provider and Consumer, you can see that the request returns normally - > onNext\ - > receive name:tony\ - > onNext\ - > receive name:nick\ - > onCompleted - -### Other serialization methods -Omit steps 1-3 above, and specify the protocol used by Provider and Consumer to complete the protocol upgrade. - -### Example program -The sample program of this article can be found in [triple-samples](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple) \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/idl.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/idl.md deleted file mode 100644 index 172c1e4ecba4..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/idl.md +++ /dev/null @@ -1,238 +0,0 @@ ---- -type: docs -title: "Using Triple in IDL" -linkTitle: "Using Triple in IDL" -weight: 2 ---- - -This tutorial will demonstrate how to use Dubbo Triple based on IDL by building a simple project from scratch - -## precondition -- [JDK](https://jdk.java.net/) version >= 8 -- Installed [Maven](https://maven.apache.org/) -- Installed and started [Zookeeper](https://zookeeper.apache.org/) - -## Create project -### 1. Create an empty maven project - ``` -$ mvn archetype:generate \ - -DgroupId=org.apache.dubbo\ - -DartifactId=tri-stub-demo \ - -DarchetypeArtifactId=maven-archetype-quickstart \ - -DarchetypeVersion=1.4 \ - -DarchetypeGroupId=org.apache.maven.archetypes \ - -Dversion=1.0-SNAPSHOT -``` -### 2. Switch to the project directory -``` - $ cd tri-stub-demo -``` -### 3. Add Dubbo dependencies and plugins - -Set JDK version in `pom.xml` -```xml - - UTF-8 - 1.8 - 1.8 - 3.1.7 - - - - - junit - junit - 4.13 - test - - - org.apache.dubbo - dubbo - ${dubbo.version} - - - org.apache.dubbo - dubbo-dependencies-zookeeper-curator5 - pom - ${dubbo.version} - - - com.google.protobuf - protobuf-java - 3.19.4 - - - - - - - kr.motd.maven - os-maven-plugin - 1.6.1 - - - - - org.xolstice.maven.plugins - protobuf-maven-plugin - 0.6.1 - - com.google.protobuf:protoc:3.19.4:exe:${os.detected.classifier} - - - dubbo - org.apache.dubbo - dubbo-compiler - ${dubbo.version} - org.apache.dubbo.gen.tri.Dubbo3TripleGenerator - - - - - - - compile - - - - - - -``` -### 4. Add interface definition file - -`src/main/proto/hello.proto`, Dubbo uses [Protobuf](https://developers.google.com/protocol-buffers) as IDL -```protobuf - syntax = "proto3"; - - option java_multiple_files = true; - option java_package = "org.apache.dubbo.hello"; - option java_outer_classname = "HelloWorldProto"; - option objc_class_prefix = "HLW"; - - package helloworld; - - message HelloRequest { - string name = 1; - } - - message HelloReply { - string message = 1; - } - service Greeter{ - rpc greet(HelloRequest) returns (HelloReply); - } - -``` -### 5. Compile IDL -``` - $ mvn clean install -``` -After the compilation is successful, you can see that the code file is generated in the `target/generated-sources/protobuf/java` directory -``` - $ ls org/apache/dubbo/hello/ - DubboGreeterTriple.java HelloReply.java HelloRequest.java HelloWorldProto.java - Greeter.java HelloReplyOrBuilder.java HelloRequestOrBuilder.java -``` - -### 6. Add server interface implementation - -`src/main/java/org/apache/dubbo/GreeterImpl.java` -```java - package org.apache.dubbo; - - import org.apache.dubbo.hello.DubboGreeterTriple; - import org.apache.dubbo.hello.HelloReply; - import org.apache.dubbo.hello.HelloRequest; - - public class GreeterImpl extends DubboGreeterTriple. GreeterImplBase { - @Override - public HelloReply greet(HelloRequest request) { - return HelloReply. newBuilder() - .setMessage("Hello," + request.getName() + "!") - .build(); - } - } -``` -### 7. Add server startup class -`src/main/java/org/apache/dubbo/MyDubboServer.java` -```java - package org.apache.dubbo; - - import org.apache.dubbo.common.constants.CommonConstants; - import org.apache.dubbo.config.ApplicationConfig; - import org.apache.dubbo.config.ProtocolConfig; - import org.apache.dubbo.config.RegistryConfig; - import org.apache.dubbo.config.ServiceConfig; - import org.apache.dubbo.config.bootstrap.DubboBootstrap; - import org.apache.dubbo.hello.Greeter; - - import java.io.IOException; - - public class MyDubboServer { - - public static void main(String[] args) throws IOException { - ServiceConfig service = new ServiceConfig<>(); - service.setInterface(Greeter.class); - service.setRef(new GreeterImpl()); - - DubboBootstrap bootstrap = DubboBootstrap. getInstance(); - bootstrap. application(new ApplicationConfig("tri-stub-server")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051)) - .service(service) - .start(); - System.out.println("Dubbo triple stub server started"); - System.in.read(); - } - } -``` - -### 8. Add client startup class -`src/main/java/org/apache/dubbo/MyDubboClient.java` -```java - package org.apache.dubbo; - - import org.apache.dubbo.common.constants.CommonConstants; - import org.apache.dubbo.config.ApplicationConfig; - import org.apache.dubbo.config.ReferenceConfig; - import org.apache.dubbo.config.RegistryConfig; - import org.apache.dubbo.config.bootstrap.DubboBootstrap; - import org.apache.dubbo.hello.Greeter; - import org.apache.dubbo.hello.HelloReply; - import org.apache.dubbo.hello.HelloRequest; - - public class MyDubboClient { - public static void main(String[] args) { - DubboBootstrap bootstrap = DubboBootstrap. getInstance(); - ReferenceConfig ref = new ReferenceConfig<>(); - ref. setInterface(Greeter. class); - ref.setProtocol(CommonConstants.TRIPLE); - ref.setProxy(CommonConstants.NATIVE_STUB); - ref. setTimeout(3000); - bootstrap. application(new ApplicationConfig("tri-stub-client")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .reference(ref) - .start(); - - Greeter greeter = ref. get(); - HelloRequest request = HelloRequest.newBuilder().setName("Demo").build(); - HelloReply reply = greeter. greet(request); - System.out.println("Received reply:" + reply); - } - } -``` -### 9. Compile the code -``` -$ mvn clean install -``` -### 10. Start the server -``` -$ mvn org.codehaus.mojo:exec-maven-plugin:3.0.0:java -Dexec.mainClass="org.apache.dubbo.MyDubboServer" -Dubbo triple stub server started -``` -### 11. Open a new terminal and start the client -``` -$ mvn org.codehaus.mojo:exec-maven-plugin:3.0.0:java -Dexec.mainClass="org.apache.dubbo.MyDubboClient" -Received reply: message: "Hello, Demo!" -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/migration.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/migration.md deleted file mode 100644 index b6d2cf77321e..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/migration.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -type: docs -title: "Dubbo2 Protocol Migration" -linkTitle: "Dubbo2 Protocol Migration" -weight: 10 ---- - -## Dubbo2 protocol migration process - -Dubbo2 users use dubbo protocol + custom serialization, such as hessian2 to complete remote calls. - -By default, Grpc only supports Protobuf serialization, and it cannot support multi-parameter and method overloading in the Java language. - -At the beginning of Dubbo3, one goal was to be perfectly compatible with Dubbo2. Therefore, in order to ensure the smooth upgrade of Dubbo2, the Dubbo framework has done a lot of work to ensure that the upgrade is seamless. Currently, the default serialization is consistent with Dubbo2 as `hessian2`. - -Therefore, if you decide to upgrade to the `Triple` protocol of Dubbo3, you only need to modify the protocol name in the configuration to `tri` (note: not triple). - -Next we use a [project] (https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/ org/apache/dubbo/sample/tri/migration) as an example, how to upgrade safely step by step. - -1. Only use the `dubbo` protocol to start `provider` and `consumer`, and complete the call. -2. Use `dubbo` and `tri` protocols to start `provider`, use `dubbo` protocol to start `consumer`, and complete the call. -3. Start `provider` and `consumer` using only `tri` protocol, and complete the call. - -### Define the service - -1. Define the interface -```java -public interface IWrapperGreeter { - - //... - - /** - * This is a normal interface, not serialized using pb - */ - String sayHello(String request); - -} -``` - -2. The implementation class is as follows -```java -public class IGreeter2Impl implements IWrapperGreeter { - - @Override - public String sayHello(String request) { - return "hello," + request; - } -} -``` - -### Only use dubbo protocol - -To ensure compatibility, we first upgrade some providers to the `dubbo3` version and use the `dubbo` protocol. - -Start a [`Provider`] using the `dubbo` protocol (https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org /apache/dubbo/sample/tri/migration/ApiMigrationDubboProvider.java) and [`Consumer`](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboConsumer.java), complete the call, the output is as follows: -![result](/imgs/v3/migration/tri/dubbo3-tri-migration-dubbo-dubbo-result.png) - -### Use dubbo and triple protocol at the same time - -For the upgrade of online services, it is impossible to complete the provider and consumer upgrades at the same time. It needs to be operated step by step to ensure business stability. -In the second step, the provider provides a dual-protocol way to support dubbo + tri clients at the same time. - -The structure is shown in the figure: -![trust](/imgs/v3/migration/tri/migrate-dubbo-tri-strust.png) - -> According to the recommended upgrade steps, the provider already supports the tri protocol, so the consumer of dubbo3 can directly use the tri protocol - -Start [`Provider`] using `dubbo` protocol and `triple` protocol (https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main /java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothProvider.java) and [`Consumer`](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/ dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothConsumer.java), complete the call, the output is as follows: - -![result](/imgs/v3/migration/tri/dubbo3-tri-migration-both-dubbo-tri-result.png) - - -### Only use triple protocol - -When all consuemr are upgraded to a version that supports the `Triple` protocol, the provider can be switched to only use the `Triple` protocol to start - -The structure is shown in the figure: -![trust](/imgs/v3/migration/tri/migrate-only-tri-strust.png) - -[Provider](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ migration/ApiMigrationTriProvider.java) -and [Consumer](https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri /migration/ApiMigrationTriConsumer.java) to complete the call, the output is as follows: - -![result](/imgs/v3/migration/tri/dubbo3-tri-migration-tri-tri-result.png) \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview.md deleted file mode 100644 index 5b5bdb6e3df5..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -type: docs -title: "Protocol Overview" -linkTitle: "Protocol Overview" -weight: 1 ---- - -## Triple overview - -For the format and principle of the `Triple` protocol, please refer to [RPC Communication Protocol](/zh-cn/docs/concepts/rpc-protocol/) - -According to the goal of Triple design, the `Triple` protocol has the following advantages - -- Capable of cross-language interaction. Both the traditional multi-language and multi-SDK mode and the Mesh cross-language mode require a more general and scalable data transmission protocol. -- Provide a more complete request model. In addition to supporting the traditional Request/Response model (Unary one-way communication), it also supports Stream (streaming communication) and Bidirectional (two-way communication). -- Easy to expand, high penetration, including but not limited to Tracing / Monitoring and other support, should also be recognized by devices at all levels, gateway facilities, etc. can identify data packets, friendly to Service Mesh deployment, and reduce the difficulty of understanding for users. -- Fully compatible with grpc, the client/server can communicate with the native grpc client. -- Components in the existing grpc ecosystem can be reused to meet cross-language, cross-environment, and cross-platform intercommunication requirements in cloud-native scenarios. - -For Dubbo users currently using other protocols, the framework provides migration capabilities compatible with existing serialization methods. Without affecting existing online businesses, the cost of migrating protocols is almost zero. -### grpc docking -Dubbo users who need to add grpc services can directly use the Triple protocol to get through, without the need to introduce grpc client separately to complete, not only can retain the existing ease of use of Dubbo, but also reduce the complexity of the program and development and maintenance Cost, it can be connected to the existing ecology without additional adaptation and development. -### Gateway Access -For Dubbo users who need gateway access, the Triple protocol provides a more native way to make gateway development or use open source grpc gateway components easier. The gateway can choose not to parse the payload, which greatly improves the performance. When using the Dubbo protocol, the language-related serialization method is a big pain point for the gateway, and the traditional HTTP-to-Dubbo method is almost powerless for cross-language serialization. At the same time, since Triple's protocol metadata is stored in the request header, the gateway can easily implement customized requirements, such as routing and current limiting. - - -## common problem - -### protobuf class not found - -Since the bottom layer of the Triple protocol needs to rely on the protobuf protocol for transmission, even if the defined service interface does not use protobuf, it is necessary to introduce protobuf dependencies into the environment. - -```xml - - com.google.protobuf - protobuf-java - 3.19.4 - -``` diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/pojo.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/pojo.md deleted file mode 100644 index b18d34fbfb72..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/pojo.md +++ /dev/null @@ -1,189 +0,0 @@ ---- -type: docs -title: "POJO way to use Triple" -linkTitle: "POJO way to use Triple" -weight: 2 ---- - -This tutorial will demonstrate how to use Dubbo Triple based on POJO by building a simple project from scratch, and upgrade to the Triple protocol while the application does not change the existing interface definition. - - -### Implementation principle - -Through the upgrade process described above, we can easily complete the upgrade by modifying the protocol type. How does the framework help us do this? - -Through the introduction of the `Triple` protocol, we know that the data type of `Triple` in Dubbo3 is a `protobuf` object, so why non-`protobuf` java objects can also be transmitted normally. - -Here Dubbo3 uses an ingenious design, first judge whether the parameter type is a `protobuf` object, if not. Use a `protobuf` object to wrap `request` and `response`, which shields the complexity brought by other serialization. Declare the serialization type inside the `wrapper` object to support serialization extensions. - -The IDL of `protobuf` of wrapper is as follows: -```proto -syntax = "proto3"; - -package org.apache.dubbo.triple; - -message TripleRequestWrapper { - //hessian4 - // json - string serializeType = 1; - repeated bytes args = 2; - repeated string argTypes = 3; -} - -message TripleResponseWrapper { - string serializeType = 1; - bytes data = 2; - string type = 3; -} -``` - -For requests, use `TripleRequestWrapper` for wrapping, and for responses, use `TripleResponseWrapper` for wrapping. - -> For request parameters, you can see that args is modified by `repeated`, this is because multiple parameters of the java method need to be supported. Of course, serialization can only be one. The implementation of serialization follows the spi implemented by Dubbo2 - -### precondition -- [JDK](https://jdk.java.net/) version >= 8 -- Installed [Maven](https://maven.apache.org/) -- Installed and started [Zookeeper](https://zookeeper.apache.org/) - -### Create project -1. First create an empty maven project - ``` - $ mvn archetype:generate \ - -DgroupId=org.apache.dubbo\ - -DartifactId=tri-pojo-demo\ - -DarchetypeArtifactId=maven-archetype-quickstart \ - -DarchetypeVersion=1.4 \ - -DarchetypeGroupId=org.apache.maven.archetypes \ - -Dversion=1.0-SNAPSHOT - ``` -2. Switch to the project directory - ``` - $ cd tri-pojo-demo - ``` -3. Set JDK version in `pom.xml`, add Dubbo dependencies and plugins - ```xml - - UTF-8 - 1.8 - 1.8 - - - - - junit - junit - 4.13 - test - - - org.apache.dubbo - dubbo - 3.0.8 - - - org.apache.dubbo - dubbo-dependencies-zookeeper-curator5 - pom - 3.0.8 - - - com.google.protobuf - protobuf-java - 3.19.4 - - - ``` -4. Add interface definition `src/main/java/org/apache/dubbo/Greeter.java` - ```java - package org.apache.dubbo; - - public interface Greeter { - String sayHello(String name); - } - ``` -5. Add server-side interface implementation `src/main/java/org/apache/dubbo/GreeterImpl.java` - ```java - package org.apache.dubbo; - - public class GreeterImpl implements Greeter { - @Override - public String sayHello(String name) { - return "Hello," + name + "!"; - } - } - ``` -6. Add server startup class `src/main/java/org/apache/dubbo/MyDubboServer.java` - ```java - package org.apache.dubbo; - - import org.apache.dubbo.common.constants.CommonConstants; - import org.apache.dubbo.config.ApplicationConfig; - import org.apache.dubbo.config.ProtocolConfig; - import org.apache.dubbo.config.RegistryConfig; - import org.apache.dubbo.config.ServiceConfig; - import org.apache.dubbo.config.bootstrap.DubboBootstrap; - - import java.io.IOException; - - public class MyDubboServer { - - public static void main(String[] args) throws IOException { - ServiceConfig service = new ServiceConfig<>(); - service.setInterface(Greeter.class); - service.setRef(new GreeterImpl()); - - DubboBootstrap bootstrap = DubboBootstrap. getInstance(); - bootstrap. application(new ApplicationConfig("tri-pojo-server")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051)) - .service(service) - .start(); - System.out.println("Dubbo triple pojo server started"); - System.in.read(); - } - } - ``` - -7. Add the client startup class `src/main/java/org/apache/dubbo/MyDubboClient.java` - ```java - package org.apache.dubbo; - - import org.apache.dubbo.common.constants.CommonConstants; - import org.apache.dubbo.config.ApplicationConfig; - import org.apache.dubbo.config.ReferenceConfig; - import org.apache.dubbo.config.RegistryConfig; - import org.apache.dubbo.config.bootstrap.DubboBootstrap; - - public class MyDubboClient { - public static void main(String[] args) { - DubboBootstrap bootstrap = DubboBootstrap. getInstance(); - ReferenceConfig ref = new ReferenceConfig<>(); - ref. setInterface(Greeter. class); - ref.setProtocol(CommonConstants.TRIPLE); - ref. setTimeout(3000); - bootstrap. application(new ApplicationConfig("tri-pojo-client")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .reference(ref) - .start(); - - Greeter greeter = ref. get(); - String reply = greeter. sayHello("pojo"); - System.out.println("Received reply:" + reply); - } - } - ``` -8. Compile the code - ``` - $ mvn clean install - ``` -9. Start the server - ``` - $ mvn org.codehaus.mojo:exec-maven-plugin:3.0.0:java -Dexec.mainClass="org.apache.dubbo.MyDubboServer" - Dubbo triple pojo server started - ``` -10. Open a new terminal and start the client - ``` - $ mvn org.codehaus.mojo:exec-maven-plugin:3.0.0:java -Dexec.mainClass="org.apache.dubbo.MyDubboClient" - Received reply: message: "Hello, Demo!" - ``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/streaming.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/streaming.md deleted file mode 100644 index fc48e3288a55..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/triple/streaming.md +++ /dev/null @@ -1,153 +0,0 @@ ---- -type: docs -title: "Streaming Communication" -linkTitle: "Streaming communication" -weight: 10 ---- -## Implementation principle of stream - -Stream mode for the `Triple` protocol - -- From the perspective of the protocol layer, `Triple` is built on the basis of `HTTP2`, so it directly has all the capabilities of `HTTP2`, so it has the ability to split `stream` and full-duplex. - -- In terms of the framework layer, `StreamObserver` is provided to users as a stream interface to provide stream processing for input and output parameters. The framework makes corresponding interface calls when sending and receiving stream data, so as to ensure the integrity of the life cycle of the stream. - -## Enable new features of Triple -### Stream stream -Stream is a new call type provided by Dubbo3. It is recommended to use stream in the following scenarios: - -- The interface needs to send a large amount of data. These data cannot be placed in an RPC request or response, and need to be sent in batches. However, if the application layer cannot solve the order and performance problems in the traditional multiple RPC method, if the order needs to be guaranteed , it can only be sent serially -- In streaming scenarios, data needs to be processed in the order they are sent, and the data itself has no definite boundary -- In push scenarios, multiple messages are sent and processed in the context of the same call - -Stream is divided into the following three types: -- SERVER_STREAM (server stream) - ![SERVER_STREAM](/imgs/v3/migration/tri/migrate-server-stream.png) -- CLIENT_STREAM (client stream) - ![CLIENT_STREAM](/imgs/v3/migration/tri/migrate-client-stream.png) -- BIDIRECTIONAL_STREAM (bidirectional stream) - ![BIDIRECTIONAL_STREAM](/imgs/v3/migration/tri/migrate-bi-stream.png) - -> Due to the limitations of the `java` language, the implementation of BIDIRECTIONAL_STREAM and CLIENT_STREAM is the same. - -In Dubbo3, the stream interface is declared and used as `SteamObserver`, and users can use and implement this interface to send and handle stream data, exceptions, and end. - -> For Dubbo2 users, they may be unfamiliar with StreamObserver, which is a stream type defined by Dubbo3. There is no Stream type in Dubbo2, so it has no impact on migration scenarios. - -Stream Semantic Guarantees -- Provide message boundaries, which can easily process messages separately -- Strictly ordered, the order of the sender is consistent with the order of the receiver -- Full duplex, no need to wait for sending -- Support cancellation and timeout - -## Non-PB serialized stream -### APIs -```java -public interface IWrapperGreeter { - - StreamObserver sayHelloStream(StreamObserver response); - - void sayHelloServerStream(String request, StreamObserver response); -} -``` - -> The method input parameters and return values of the Stream method are strictly agreed. In order to prevent problems caused by writing errors, the Dubbo3 framework side checks the parameters, and throws an exception if there is an error. -> For `BIDIRECTIONAL_STREAM`, it should be noted that `StreamObserver` in the parameter is the response stream, and `StreamObserver` in the return parameter is the request stream. -### Implementation class -```java -public class WrapGreeterImpl implements WrapGreeter { - - //... - - @Override - public StreamObserver sayHelloStream(StreamObserver response) { - return new StreamObserver() { - @Override - public void onNext(String data) { - System.out.println(data); - response.onNext("hello,"+data); - } - - @Override - public void onError(Throwable throwable) { - throwable. printStackTrace(); - } - - @Override - public void onCompleted() { - System.out.println("onCompleted"); - response.onCompleted(); - } - }; - } - - @Override - public void sayHelloServerStream(String request, StreamObserver response) { - for (int i = 0; i < 10; i++) { - response.onNext("hello," + request); - } - response.onCompleted(); - } -} -``` - -### Call method -```java -delegate.sayHelloServerStream("server stream", new StreamObserver() { - @Override - public void onNext(String data) { - System.out.println(data); - } - - @Override - public void onError(Throwable throwable) { - throwable. printStackTrace(); - } - - @Override - public void onCompleted() { - System.out.println("onCompleted"); - } -}); - - -StreamObserver request = delegate.sayHelloStream(new StreamObserver() { - @Override - public void onNext(String data) { - System.out.println(data); - } - - @Override - public void onError(Throwable throwable) { - throwable. printStackTrace(); - } - - @Override - public void onCompleted() { - System.out.println("onCompleted"); - } -}); -for (int i = 0; i < n; i++) { - request.onNext("stream request" + i); -} -request.onCompleted(); -``` - -## Serialized stream using Protobuf - -For the `Protobuf` serialization method, it is recommended to write `IDL` and use the `compiler` plugin to compile and generate. The generated code is roughly as follows: -```java -public interface PbGreeter { - - static final String JAVA_SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; - static final String SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; - - static final boolean inited = PbGreeterDubbo.init(); - - //... - - void greetServerStream(org.apache.dubbo.sample.tri.GreeterRequest request, org.apache.dubbo.common.stream.StreamObserver responseObserver); - - org.apache.dubbo.common.stream.StreamObserver greetStream(org.apache.dubbo.common.stream.StreamObserver responseObserver); -} -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/protocol/webservice.md b/content/en/docs3-v2/java-sdk/reference-manual/protocol/webservice.md deleted file mode 100644 index b0e69b6cdfee..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/protocol/webservice.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -type: docs -title: "Webservice protocol" -linkTitle: "Webservice protocol" -weight: 11 ---- - - -## Feature description -WebService-based remote invocation protocol, implemented based on `frontend-simple` and `transports-http` of [Apache CXF](http://cxf.apache.org). `2.3.0` and above are supported. - -CXF is an open source RPC framework of Apache, which is merged from Xfire and Celtix. -* Number of connections: multiple connections -* Connection method: short connection -* Transmission protocol: HTTP -* Transmission method: synchronous transmission -* Serialization: SOAP text serialization -* Applicable scenarios: system integration, cross-language call - -It can interoperate with native WebService services, namely: - -* The provider uses Dubbo's WebService protocol to expose the service, and the consumer directly uses the standard WebService interface to call, -* Or the provider uses the standard WebService to expose the service, and the consumer uses Dubbo's WebService protocol to call. -#### Constraints -* Parameters and return values need to implement `Serializable` interface -* Parameters try to use basic types and POJO - -## scenes to be used -To publish a service (internal/external), regardless of client type or performance, it is recommended to use webservice. The server has determined to use webservice, the client cannot choose, and must use webservice. -## How to use -### Dependencies - -Starting from Dubbo 3, the Webservice protocol is no longer embedded in Dubbo, and an independent [module](/zh-cn/download/spi-extensions/#dubbo-rpc) needs to be introduced separately. -```xml - - org.apache.dubbo.extensions - dubbo-rpc-webservice - 1.0.0 - -``` - -```xml - - org.apache.cxf - cxf-rt-frontend-simple - 2.6.1 - - - org.apache.cxf - cxf-rt-transports-http - 2.6.1 - -``` - -### Configuration protocol -```xml - -``` - -### Configure the default protocol -```xml - -``` - -### Configure service protocol -```xml - -``` - -### Multiport -```xml - - -``` - -### direct connection -```xml - -``` - -###WSDL -``` -http://10.20.153.10:8080/com.foo.HelloWorld?wsdl -``` - -### Jetty Server (default) - -```xml - -``` - -### Servlet Bridge Server (recommended) -```xml - -``` - -### Configure DispatcherServlet -```xml - - dubbo - org.apache.dubbo.remoting.http.servlet.DispatcherServlet - 1 - - - dubbo - /* - -``` - -> If a servlet is used to dispatch the request -> * The protocol port `` must be the same as the port of the servlet container. -> * The context path of the protocol `` must be the same as the context path of the servlet application. diff --git a/content/en/docs3-v2/java-sdk/reference-manual/qos/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/qos/_index.md deleted file mode 100755 index bacf7fa4a229..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/qos/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "QOS Operation Manual" -linkTitle: "QOS Operation Manual" -weight: 3 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/qos/command.md b/content/en/docs3-v2/java-sdk/reference-manual/qos/command.md deleted file mode 100644 index 8f711acd03e6..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/qos/command.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -type: docs -title: "Basic Command Manual" -linkTitle: "Basic command manual" -weight: 2 -description: "Basic command manual" ---- - - -## help command - -``` -// list all commands -dubbo>help - -//List the specific usage of a single command -dubbo>help online -+--------------+---------------------------------- ------------------------------------------------+ -| COMMAND NAME | online | -+--------------+---------------------------------- ------------------------------------------------+ -| EXAMPLE | online dubbo | -| | online xx.xx.xxx.service | -+--------------+---------------------------------- ------------------------------------------------+ - -dubbo> -``` - -## version command - -Display the version number of the currently running Dubbo - -``` -dubbo>version -dubbo version "3.0.10-SNAPSHOT" - -dubbo> -``` - -## quit command - -exit command state - -``` -dubbo>quit -BYE! -Connection closed by foreign host. - -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/qos/logger-management.md b/content/en/docs3-v2/java-sdk/reference-manual/qos/logger-management.md deleted file mode 100644 index d73600c44b08..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/qos/logger-management.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -type: docs -title: "Logging framework runtime management" -linkTitle: "Logging framework runtime management" -weight: 5 -description: "Dynamically switch the log framework used when running in Dubbo" ---- - -## Logging framework runtime management - -Starting from `3.0.10`, dubbo-qos runtime control supports querying log configuration and dynamically modifying the used log framework and log level. - -Note: The log configuration modified by dubbo-qos is not stored persistently and will become invalid after the application is restarted. - -### 1. Query log configuration - -Command: `loggerInfo` - -Example: -```bash -> telnet 127.0.0.1 22222 -> loggerInfo -``` - -output: -``` -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. - ___ __ __ ___ ___ ____ - / _ \ / / / // _ ) / _ ) / __ \ - / // // /_/ // _ |/ _ |/ /_/ / -/____/ \____//____//____/ \____/ -dubbo>loggerInfo -Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: INFO -``` - -### 2. Modify log level - -Command: `switchLogLevel {level}` - -level: `ALL`, `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `OFF` - -Example: -```bash -> telnet 127.0.0.1 22222 -> switchLogLevel WARN -``` - -output: -``` -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. - ___ __ __ ___ ___ ____ - / _ \ / / / // _ ) / _ ) / __ \ - / // // /_/ // _ |/ _ |/ /_/ / -/____/ \____//____//____/ \____/ -dubbo>loggerInfo -Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: INFO -dubbo>switchLogLevel WARN -OK -dubbo>loggerInfo -Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: WARN``` -``` - -### 3. Modify the log output framework - -Command: `switchLogger {loggerAdapterName}` - -loggerAdapterName: `slf4j`, `jcl`, `log4j`, `jdk`, `log4j2` - -Example: -```bash -> telnet 127.0.0.1 22222 -> switchLogger slf4j -``` - -output: -``` -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. - ___ __ __ ___ ___ ____ - / _ \ / / / // _ ) / _ ) / __ \ - / // // /_/ // _ |/ _ |/ /_/ / -/____/ \____//____//____/ \____/ -dubbo>loggerInfo -Available logger adapters: [jcl, slf4j, log4j, jdk]. Current Adapter: [log4j]. Log level: INFO -dubbo>switchLogger slf4j -OK -dubbo>loggerInfo -Available logger adapters: [jcl, slf4j, log4j, jdk]. Current Adapter: [slf4j]. Log level: INFO -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/qos/overview.md b/content/en/docs3-v2/java-sdk/reference-manual/qos/overview.md deleted file mode 100644 index 35dbdd2a127c..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/qos/overview.md +++ /dev/null @@ -1,212 +0,0 @@ ---- -type: docs -title: "QOS Overview" -linkTitle: "QOS Overview" -weight: 1 -description: The new version of dubbo 2.5.8 adds QOS module and provides new telnet command support. ---- - -## Description of related parameters -QoS provides some startup parameters to configure startup, they mainly include: - -| Parameters | Description | Default | -|---------------------------------|----------------|-----------| -| qos-enable | Whether to enable QoS | true | -| qos-port | Enable QoS binding port | 22222 | -| qos-accept-foreign-ip | Whether to allow remote access | false | -| qos-accept-foreign-ip-whitelist | Supported remote host ip address (segment) | (none) | -| qos-anonymous-access-permission-level | Permission level for anonymous access supported | PUBLIC(1) | - -> Note, starting from 2.6.4/2.7.0, the default configuration of qos-accept-foreign-ip is changed to false. If qos-accept-foreign-ip is set to true, it may bring security risks, please evaluate carefully Open. - -## QoS parameter configuration - -* system properties -* dubbo.properties -* XML method -* Spring-boot automatic assembly method - -Among them, the priority order of the above methods is system properties > dubbo.properties > XML/Spring-boot automatic assembly method. - - -## port -The port of the new version of telnet is different from the port of the dubbo protocol, the default is `22222` - -It can be modified through the configuration file `dubbo.properties`: -``` -dubbo.application.qos-port=33333 -``` -or -You can set the JVM parameter: -``` --Ddubbo.application.qos-port=33333 -``` - -## Safety -By default, dubbo accepts commands initiated by any host - -It can be modified through the configuration file `dubbo.properties`: -``` -dubbo.application.qos-accept-foreign-ip=false -``` -or - -You can set the JVM parameter: -``` --Ddubbo.application.qos-accept-foreign-ip=false -``` -Reject commands issued by the remote host, and only allow the service to execute locally. - -At the same time, you can specify the supported remote host ip addresses (segments) by setting `qos-accept-foreign-ip-whitelist`, and separate multiple ip addresses (segments) with **comma**, such as: -> Configuration file `dubbo.properties` -``` -dubbo.application.qos-accept-foreign-ip-whitelist=123.12.10.13, 132.12.10.13/24 -``` -> Set JVM parameters: -``` --Ddubbo.application.qos-accept-foreign-ip-whitelist=123.12.10.13,132.12.10.13/24 -``` - -## Permissions -In order to support the life cycle probe by default, QoS provides the ability to access anonymously and set the permission level. The currently supported permission levels are: -- PUBLIC(1) - By default, the command permission level of anonymous access is supported. Currently, only commands related to lifecycle probes are supported. -- PROTECTED(2) - command default privilege level -- PRIVATE(3) - The highest privilege level reserved, currently unsupported -- NONE - The lowest privilege level, i.e. anonymous access is not supported - -> Privilege level `PRIVATE`> `PROTECTED`> `PUBLIC`> `NONE`, high-level permissions can access commands of the same level and low-level permissions. -Currently the permissions of the following commands are `PUBLIC`, and the default permissions of other commands are `PROTECTED`. - -| command | privilege level | -|------------------------------------------|-------------------| -| Live | PUBLIC (1) | -| Startup | PUBLIC (1) | -| Ready | PUBLIC (1) | -| Quit | PUBLIC (1)| - -By default, dubbo allows anonymous hosts to initiate anonymous access, only commands with `PUBLIC` permission level can be executed, and other commands with higher permissions will be rejected. - -**Turn off anonymous access** -Anonymous access can be turned off by setting `qos-anonymous-access-permission-level=NONE`. - -**SET PERMISSION LEVEL** -It can be modified through the configuration file `dubbo.properties`: -``` -dubbo.application.qos-anonymous-access-permission-level=PROTECTED -``` -or -You can set the JVM parameter: -``` --Ddubbo.application.qos-anonymous-access-permission-level=PROTECTED -``` -to allow anonymous access to higher-level privileged commands. - -## agreement -### telnet and http protocols - -The telnet module now supports both the http protocol and the telnet protocol, which is convenient for use in various situations -Example: -``` -➜ ~ telnet localhost 22222 -Trying ::1... -telnet: connect to address ::1: Connection refused -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. - ████████▄ ███ █▄ ▀█████████▄ ▀█████████▄ ▄██████▄ - ███ ▀███ ███ ███ ███ ███ ███ ███ ███ ███ - ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ - ███ ███ ███ ███ ▄███▄▄▄██▀ ▄███▄▄▄██▀ ███ ███ - ███ ███ ███ ███ ▀▀███▀▀▀██▄ ▀▀███▀▀▀██▄ ███ ███ - ███ ███ ███ ███ ███ ██▄ ███ ██▄ ███ ███ - ███ ▄███ ███ ███ ███ ███ ███ ███ ███ ███ - ████████▀ ████████▀ ▄█████████▀ ▄█████████▀ ▀██████▀ - - -dubbo>ls -As Provider side: -+----------------------------------+---+ -| Provider Service Name |PUB| -+----------------------------------+---+ -|org.apache.dubbo.demo.DemoService|N| -+----------------------------------+---+ -As Consumer side: -+---------------------+---+ -|Consumer Service Name|NUM| -+---------------------+---+ - -dubbo> -``` - - -``` -➜ ~ curl "localhost:22222/ls?arg1=xxx&arg2=xxxx" -As Provider side: -+----------------------------------+---+ -| Provider Service Name |PUB| -+----------------------------------+---+ -|org.apache.dubbo.demo.DemoService|N| -+----------------------------------+---+ -As Consumer side: -+---------------------+---+ -|Consumer Service Name|NUM| -+---------------------+---+ -``` -## Use configuration -### Use system properties to configure -``` --Ddubbo.application.qos-enable=true --Ddubbo.application.qos-port=33333 --Ddubbo.application.qos-accept-foreign-ip=false --Ddubbo.application.qos-accept-foreign-ip-whitelist=123.12.10.13,132.12.10.13/24 --Ddubbo.application.qos-anonymous-access-permission-level=PUBLIC -``` - -### Use dubbo.properties file configuration -Add the dubbo.properties file in the `src/main/resources` directory of the project, the content is as follows: -``` -dubbo.application.qos-enable=true -dubbo.application.qos-port=33333 -dubbo.application.qos-accept-foreign-ip=false -dubbo.application.qos-accept-foreign-ip-whitelist=123.12.10.13, 132.12.10.13/24 -dubbo.application.qos-anonymous-access-permission-level=PUBLIC -``` - -### Use the XML method to configure -If you want to configure the QoS-related parameters of the response through XML, you can configure them as follows: -```xml - - - - - - - - - - - - - - -``` - -### Use spring-boot automatic assembly configuration -If it is a spring-boot application, it can be configured on `application.properties` or `application.yml`: - -``` -dubbo.application.qos-enable=true -dubbo.application.qos-port=33333 -dubbo.application.qos-accept-foreign-ip=false -dubbo.application.qos-accept-foreign-ip-whitelist=123.12.10.13, 132.12.10.13/24 -dubbo.application.qos-anonymous-access-permission-level=NONE -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/qos/probe.md b/content/en/docs3-v2/java-sdk/reference-manual/qos/probe.md deleted file mode 100644 index 086a30da4fa4..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/qos/probe.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -type: docs -title: "Frame State Command" -linkTitle: "Frame State Command" -weight: 4 -description: "Frame State Command" ---- - -Reference document: [Kubernetes Lifecycle Probe](../../../advanced-features-and-usage/others/dubbo-kubernetes-probe/) - -## startup command - -Check if the current framework has been started - -``` -dubbo>startup -true - -dubbo> -``` - -## ready command - -Detect whether the current framework can provide services normally (may be temporarily offline) - -``` -dubbo>ready -true - -dubbo> -``` - -## live command - -Check if the current framework is running normally (possibly a permanent exception) - -``` -dubbo>live -true - -dubbo> -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/qos/profiler.md b/content/en/docs3-v2/java-sdk/reference-manual/qos/profiler.md deleted file mode 100644 index a05d627ca100..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/qos/profiler.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -type: docs -title: "Performance Sampling Command" -linkTitle: "Performance Sampling Command" -weight: 7 -description: "Performance Sampling Command" ---- - -The performance sampling function can detect the time consumption of various parts of the Dubbo processing link. When a timeout occurs, `( usageTime / timeout > profilerWarnPercent * 100 )` records the time consumption of calls through logs. - -This function is divided into `simple profiler` and `detail profiler` two modes, where `simple profiler` mode is enabled by default, and `detail profiler` mode is disabled by default. -Compared with the `simple profiler` mode, the `detail profiler` collects more time-consuming processing of each filter, specific time-consuming protocols, etc. -In the `simple profiler` mode, if you find that there is a long time-consuming situation inside the Dubbo framework, you can enable the `detail profiler` mode to better troubleshoot the problem. - -Reference link: [Request time-consuming sampling](../../../advanced-features-and-usage/performance/profiler/) - -## enableSimpleProfiler command - -Enable `simple profiler` mode, enabled by default - -``` -dubbo>enableSimpleProfiler -OK - -dubbo> -``` - -## disableSimpleProfiler command - -Turn off the `simple profiler` mode, and the `detail profiler` will not be enabled after it is turned off - -``` -dubbo>disableSimpleProfiler -OK - -dubbo> -``` - -## enableDetailProfiler command - -Enable the `detail profiler` mode, which is disabled by default, you need to enable the `simple profiler` mode to actually enable it - -``` -dubbo>enableDetailProfiler -OK. This will cause performance degradation, please be careful! - -dubbo> -``` - -## disableDetailProfiler command - -Turn off `detail profiler` mode, it will not affect `simple profiler` - -``` -dubbo>disableDetailProfiler -OK - -dubbo> -``` - -## setProfilerWarnPercent command - -Set the warning percentage for the timeout - -Command: `setProfilerWarnPercent {profilerWarnPercent}` - -profilerWarnPercent: The warning percentage of the timeout period, the value range is 0.0 ~ 1.0, and the default value is 0.75 - -``` -dubbo>setProfilerWarnPercent 0.75 -OK - -dubbo> -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/qos/router-snapshot.md b/content/en/docs3-v2/java-sdk/reference-manual/qos/router-snapshot.md deleted file mode 100644 index 2295e27a89e4..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/qos/router-snapshot.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -type: docs -title: "Routing Status Command" -linkTitle: "Routing Status Command" -weight: 8 -description: "Route Status Command" ---- - -Many of Dubbo's traffic management capabilities are implemented based on Router. In a production environment, if traffic results do not meet expectations, you can use the routing status command to check the routing status to locate possible problems. - -Reference link: [routing status collection](../../../advanced-features-and-usage/performance/router-snapshot/) - -## getRouterSnapshot command - -Get the current grouping status of each layer of routing. (Only supports StateRouter) - -Command: `getRouterSnapshot {serviceName}` - -`serviceName` is the name of the service to be collected, which supports matching - -``` -dubbo>getRouterSnapshot com.dubbo.dubbointegration.BackendService -com.dubbo.dubbointegration.BackendService@2c2e824a -[ All Invokers: 2 ] [ Valid Invokers: 2 ] - -MockInvokersSelector Total: 2 -[ Mocked -> Empty (Total: 0) ] -[ Normal -> 172.18.111.187:20880,172.18.111.183:20880 (Total: 2) ] - ↓ -StandardMeshRuleRouter not support - ↓ -TagStateRouter not support - ↓ -ServiceStateRouter not support - ↓ -AppStateRouter not support - ↓ -TailStateRouterEnd - - -dubbo> -``` - -## enableRouterSnapshot command - -Enable routing result collection mode - -Command: `enableRouterSnapshot {serviceName}` - -`serviceName` is the name of the service to be collected, which supports matching - -``` -dubbo>enableRouterSnapshot com.dubbo.* -OK. Found service count: 1. This will cause performance degradation, please be careful! - -dubbo> -``` - -## disableRouterSnapshot command - -Disable routing result collection mode - -Command: `disableRouterSnapshot {serviceName}` - -`serviceName` is the name of the service to be collected, which supports matching - -``` -dubbo>disableRouterSnapshot com.dubbo.* -OK. Found service count: 1 - -dubbo> -``` - -## getEnabledRouterSnapshot command - -Get the services that are currently collecting - -``` -dubbo>getEnabledRouterSnapshot -com.dubbo.dubbointegration.BackendService - -dubbo> -``` - -## getRecentRouterSnapshot command - -Obtain the historical routing status through the qos command. (up to 32 results stored) - -``` -dubbo>getRecentRouterSnapshot -1658224330156 - Router snapshot service com.dubbo.dubbointegration.BackendService from registry 172.18.111.184 on the consumer 172.18.111.184 using the dubbo version 3.0.9 is below: -[ Parent (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) ] Input: 172.18.111.187:20880,172.18.111.183:20880 -> Chain Node Output: 172.18.111.187:20880.3172.18 :20880 - [ MockInvokersSelector (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 172.18.111.187:20880,172.183.111. :20880 - [ StandardMeshRuleRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 172.18.111.187:20880,172.1803:1121.88 - [ TagStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: 172.18.111.187:20880,172.183.111. 20880 - [ ServiceStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880 ,172.18.111.183:20880 - [ AppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880 ,172.18.111.183:20880 - -1658224330156 - Router snapshot service com.dubbo.dubbointegration.BackendService from registry 172.18.111.184 on the consumer 172.18.111.184 using the dubbo version 3.0.9 is below: -[ Parent (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) ] Input: 172.18.111.187:20880,172.18.111.183:20880 -> Chain Node Output: 172.18.111.187:20880.3172.18 :20880 - [ MockInvokersSelector (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: 172.18.111.187:20880,172.183.111. :20880 - [ StandardMeshRuleRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: MeshRuleCache has not been built. Skip route. ] Current Node Output: 172.18.111.187:20880,172.1803:1121.88 - [ TagStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: 172.18.111.187:20880,172.183.111. 20880 - [ ServiceStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880 ,172.18.111.183:20880 - [ AppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 2) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: 172.18.111.187:20880 ,172.18.111.183:20880 - -··· - -dubbo> -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/qos/security.md b/content/en/docs3-v2/java-sdk/reference-manual/qos/security.md deleted file mode 100644 index adc3906c8c96..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/qos/security.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -type: docs -title: "Serialization Security Audit" -linkTitle: "Serialization Security Audit" -weight: 9 -description: "Serialization Security Audit" ---- - -Dubbo supports real-time viewing of current configuration information and trusted/untrusted class lists through QoS commands. Currently supports two commands: `serializeCheckStatus` to view the current configuration information, `serializeWarnedClasses` to view the real-time alarm list. - -### `serializeCheckStatus` command - -Access directly through the console: -```bash -> telnet 127.0.0.1 22222 -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. - ___ __ __ ___ ___ ____ - / _ \ / / / // _ ) / _ ) / __ \ - / // // /_/ // _ |/ _ |/ /_/ / -/____/ \____//____//____/ \____/ -dubbo>serializeCheckStatus -CheckStatus: WARN - -CheckSerializable: true - -AllowedPrefix: -... - -DisAllowedPrefix: -... - - -dubbo> -``` - -Request the result in json format via http: -```bash -> curl http://127.0.0.1:22222/serializeCheckStatus -{"checkStatus": "WARN","allowedPrefix":[...],"checkSerializable":true,"disAllowedPrefix":[...]} -``` - -### `serializeWarnedClasses` command - -Access directly through the console: -```bash -> telnet 127.0.0.1 22222 -Trying 127.0.0.1... -Connected to localhost. -Escape character is '^]'. - ___ __ __ ___ ___ ____ - / _ \ / / / // _ ) / _ ) / __ \ - / // // /_/ // _ |/ _ |/ /_/ / -/____/ \____//____//____/ \____/ -dubbo>serializeWarnedClasses -Warned Classes: -io.dubbo.test.NotSerializable -io.dubbo.test2.NotSerializable -io.dubbo.test2.OthersSerializable -org.apache.dubbo.samples.NotSerializable - - -dubbo> -``` - -Request the result in json format via http: -```bash -> curl http://127.0.0.1:22222/serializeWarnedClasses -{"warnedClasses":["io.dubbo.test2.NotSerializable","org.apache.dubbo.samples.NotSerializable","io.dubbo.test.NotSerializable","io.dubbo.test2.OthersSerializable"]} -``` - -Note: It is recommended to pay attention to the result of `serializeWarnedClasses` in time, and judge whether it is attacked by whether the returned result is not empty. - -> For more configuration details, please refer to [Dubbo Class Check Mechanism](/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/security/class-check/). diff --git a/content/en/docs3-v2/java-sdk/reference-manual/qos/service-management.md b/content/en/docs3-v2/java-sdk/reference-manual/qos/service-management.md deleted file mode 100644 index dff83efdf452..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/qos/service-management.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -type: docs -title: "Service Management Commands" -linkTitle: "Service Management Command" -weight: 3 -description: "Service Management Command" ---- - - -## ls command - -List consumers and providers - -``` -dubbo>ls -As Provider side: -+------------------------------------------------- -----------------------+---------------------+ -| Provider Service Name | PUB | -+------------------------------------------------- -----------------------+---------------------+ -|DubboInternal - UserRead/org.apache.dubbo.metadata.MetadataService:1.0.0| | -+------------------------------------------------- -----------------------+---------------------+ -| com.dubbo.dubbointegration.UserReadService |nacos-A(Y)/nacos-I(Y)| -+------------------------------------------------- -----------------------+---------------------+ -As Consumer side: -+-----------------------------------------+------- ----------+ -| Consumer Service Name | NUM | -+-----------------------------------------+------- ----------+ -|com.dubbo.dubbointegration.BackendService|nacos-AF(I-2,A-2)| -+-----------------------------------------+------- ----------+ - -``` - -List the services provided and consumed by dubbo, as well as the number of service addresses consumed. - -Note: -- Services prefixed with `DubboInternal` are built-in services of Dubbo, and are not registered with the registry by default. -- The first part of `nacos-A(Y)` in the service publishing status is the corresponding registry name, and the second part is the registration mode (`A` stands for application-level address registration, `I` stands for interface-level address registration), The third part represents whether the corresponding mode has been registered -- The first part of `nacos-AF(I-2,A-2)` in the service subscription status is the corresponding registration center name, and the second part is the subscription mode (`AF` stands for dual subscription mode, `FA` stands for only Application-level subscription, `FI` stands for interface-level subscription only), the first half of the third part represents the source of the address mode (`A` stands for application-level address, `I` stands for interface-level address), and the second half represents the corresponding number of addresses - -## online - -### online commands - -Online online service command - -When using the delayed release function (by setting org.apache.dubbo.config.AbstractServiceConfig#register to false), when you need to go online later, you can use the Online command -``` -//Online all services -dubbo>online -OK - -//According to the rules, launch some services -dubbo>online com.* -OK -``` - -## log off - - -### offline command - -Offline service command - -Due to failure and other reasons, it is necessary to temporarily go offline to maintain the site, and you can use the Offline offline command. - -``` -//Offline all services -dubbo>offline -OK - -//According to the rules, some services are offline -dubbo>offline com.* -OK -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/registry/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/registry/_index.md deleted file mode 100644 index e01cd5ce8995..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/registry/_index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: docs -title: "Registration Center Description" -linkTitle: "Description of Registration Center" -weight: 5 -description: "The design and working method of the Dubbo registration center covers the mainstream registration centers adapted by Dubbo such as Zookeeper and Nacos" ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/registry/multicast/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/registry/multicast/_index.md deleted file mode 100644 index 8b161351fc63..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/registry/multicast/_index.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -type: docs -title: "Multicast" -linkTitle: "Multicast" -weight: 4 -description: "Multicast broadcast registration center (use only in development stage)." ---- - -The Multicast registration center does not need to start any central nodes, as long as the broadcast address is the same, they can discover each other. - -![/user-guide/images/multicast.jpg](/imgs/user/multicast.jpg) - -## 1 Instructions for use - -```xml - -``` - -or - -```xml - -``` -#### Notice: -In order to reduce the amount of broadcasting, Dubbo uses unicast to send provider address information to consumers by default. -If multiple consumer processes are started on a machine at the same time, the consumer must declare `unicast=false`, otherwise only one consumer can receive the message; when the server and the consumer run on the same machine, the consumer It is also necessary to declare `unicast=false`, otherwise the consumer cannot receive the message, resulting in No provider available for the service exception: - -```xml - - - -``` - -or - -```xml - - - -``` - - -## 2 How it works - -### 2.1 Basic process -0. The provider broadcasts its own address when it starts -1. Broadcast subscription request when consumer starts -2. When the provider receives the subscription request, it will unicast its own address to the subscribers. If `unicast=false` is set, it will broadcast to the subscribers -3. When the consumer receives the provider's address, it connects to the address to make an RPC call. - -### 2.2 Restrictions on Use -Multicast is limited by the network structure and is only suitable for small-scale applications or development stages. Multicast address segment: 224.0.0.0 - 239.255.255.255 \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/registry/multiple-registry/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/registry/multiple-registry/_index.md deleted file mode 100644 index 0c7a737fddea..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/registry/multiple-registry/_index.md +++ /dev/null @@ -1,187 +0,0 @@ ---- -type: docs -title: "Multiple Registries" -linkTitle: "Multiple Registration Centers" -weight: 6 -description: "This article introduces Dubbo's multi-registry support and usage scenarios, how to implement cross-regional service deployment and service migration through multi-registration/multi-subscription, and also describes the implementation of traffic scheduling across computer rooms with limited access to the same computer room." ---- - -## 1 Associated service and multiple registration centers - -### 1.1 Global Default Registration Center - -The Dubbo registry and services are configured independently. Usually, developers do not need to set the relationship between services and registry components. The Dubbo framework will automatically perform the following actions: -* For all Service services, register the service address with all global default registries. -* For all Reference services, subscribe service addresses from all global default registries. - -```yml -# application.yml (Spring Boot) -dubbo - registries - beijing Registry - address: zookeeper://localhost:2181 - shanghai Registry - address: zookeeper://localhost:2182 -``` - -```java -@DubboService -public class DemoServiceImpl implements DemoService {} - -@DubboService -public class HelloServiceImpl implements HelloService {} -``` - -The above takes Spring Boot development as an example (XML and API methods are similar) to configure two global default registries, beijingRegistry and shanghaiRegistry, and the services DemoService and HelloService will be registered to the two default registries respectively. - -In addition to the framework mentioned above to automatically set the global registry for the service, there are two ways to flexibly adjust the association between the service and multiple registry. - -### 1.2 Set the global default registration center -```yml -# application.yml (Spring Boot) -dubbo - registries - beijing Registry - address: zookeeper://localhost:2181 - default: true - shanghai Registry - address: zookeeper://localhost:2182 - default: false -``` - -`default` is used to set the global default registry, the default value is `true` which is regarded as the global registry. Services that do not specify a registry id will automatically register or subscribe to the global default registry. - -### 1.3 Display associated services and registry - -By adding the registry configuration to the Dubbo service definition component, the service is associated with the registry. - -```java -@DubboServiceregistry = {"beijingRegistry"} -public class DemoServiceImpl implements DemoService {} - -@DubboServiceregistry = {"shanghaiRegistry"} -public class HelloServiceImpl implements HelloService {} -``` - -After adding the above configuration, DemoService will only be registered to beijingRegistry, and HelloService will be registered to shanghaiRegistry. - -## 2 Multi-registry subscription - -Since service subscription involves address aggregation and routing address selection, the logic will be more complicated. From the perspective of a single service subscription, if there is a multi-registry subscription, it can be divided into two scenarios according to whether the addresses between the registries are aggregated. - -### 2.1 Multi-registry addresses are not aggregated - -```xml - - -``` - -For the independently configured registry component shown above, the address list is completely isolated on the consumer side by default, and the load balancing address selection needs to go through two steps: -1. Site selection among the registration center clusters, select a cluster -2. Select the address in the registration center cluster, and perform address screening in the cluster - -![multi-registris-no-aggregation](/imgs/v3/registry/no-aggregation.png) - -Below we will focus on how to control **Registration center inter-cluster site selection**, the optional strategies are as follows -**random** -Each request is randomly assigned to a registry cluster - -> There will be an availability check in the random process, that is, each cluster must ensure that at least one address is available before it can be selected. - -**preferred priority** -```xml - - -``` -If there is a registry cluster configured with `preferred="true"`, all traffic will be routed to this cluster. - -**weighted** -```xml - - -``` - -Based on weighted random load balancing, there will be about 10:1 traffic distribution among the above clusters. - -**same zone priority** -```xml - - -``` - -```java -RpcContext.getContext().setAttachment("registry_zone", "qingdao"); -``` - -According to the traffic parameters carried in the Invocation or the parameters set through the context context on the current node, the traffic will be accurately guided to the corresponding cluster. - -### 2.2 Multi-registry address aggregation -```xml - -``` - -Here, a registration center starting with a special multiple protocol is added, where: -* `multiple://127.0.0.1:2181` has no specific meaning, it is just a placeholder in a specific format, and the address can be specified at will -* `reference-registry` specifies the list of registry clusters to be aggregated. In the example, there are two clusters, `zookeeper://address11?backup=address12,address13` and `zookeeper://address21?backup=address22` ,address23`, which also specifies the cluster separator `separator=";"` - -As shown in the figure below, the addresses of different registration center clusters will be aggregated into one address pool for load balancing or routing address selection on the consumer side. - -![multi-registris-aggregation](/imgs/v3/registry/aggregation.png) - -In version 3.1.0 and later, it is also supported to set specific attachments attributes on each registry cluster to achieve specific marking of addresses under the registry cluster, and then cooperate with Router component extensions such as TagRouter to realize cross-machine rooms traffic management capabilities. - -```xml - -``` - -After adding `attachments=zone=hangzhou,tag=middleware`, all URL addresses from the registration center will automatically carry the two identifiers of `zone` and `tag`, which facilitates more flexible traffic management on the consumer side. - -## 3 Scenario example - -### 3.1 Scenario 1: Cross-region registration service - -For example: Some services of the Chinese website are too late to be deployed in Qingdao, and are only deployed in Hangzhou, while other applications in Qingdao need to reference this service, so the service can be registered to two registration centers at the same time. - -```xml - - - - -``` - -### 3.2 Scenario 2: Isolation based on business - -Some CRM services are specially designed for international websites, and some services are specially designed for Chinese websites. - -```xml - - - - - - - -``` - -### 3.3 Scenario 3: Invoking services based on business - -CRM needs to call the PC2 service of the Chinese station and the international station at the same time. PC2 is deployed in both the Chinese station and the international station. The interface and version number are the same, but the connected database is different. - -```xml - - - - - - - -``` - -If only the test environment temporarily needs to connect to two different registration centers, use vertical symbols to separate multiple different registration center addresses: - -```xml - - - - -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/registry/nacos/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/registry/nacos/_index.md deleted file mode 100644 index 4d131bbaadd4..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/registry/nacos/_index.md +++ /dev/null @@ -1,190 +0,0 @@ ---- -type: docs -title: "Nacos" -linkTitle: "Nacos" -weight: 3 -description: "The basic usage and working principle of the Nacos registry." ---- - -## 1 precondition -* Understand [Dubbo basic development steps](../../../quick-start/spring-boot/) -* Install and start [Nacos service](https://nacos.io/zh-cn/docs/quick-start.html) ->When Dubbo uses `3.0.0` and above, it needs to use Nacos `2.0.0` and above. - -## 2 Instructions for use -Check here [full sample code](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-nacos/dubbo-samples-nacos-registry) - -### 2.1 Add dependencies -```xml - - - org.apache.dubbo - dubbo - 3.0.9 - - - com.alibaba.nacos - nacos-client - 2.1.0 - - - - -``` -Add Dubbo and Nacos dependencies - -> Dubbo `3.0.0` and above require nacos-client `2.0.0` and above - -### 2.2 Configure and enable Nacos - -```yaml -# application.yml (Spring Boot) -dubbo - registry - address: nacos://localhost:8848 -``` -or -```properties -# dubbo.properties -dubbo.registry.address=nacos://localhost:8848 -``` -or -```xml - -``` - -To enable the app, see what it looks like after registration or how it works, see [How it works](#4-How it works). - -## 3 Advanced configuration - -### 3.1 Authentication - -```yaml -# application.yml (Spring Boot) -dubbo - registry - address: nacos://localhost:8848?username=nacos&password=nacos -``` - -or - -```properties -# dubbo.properties -dubbo.registry.address: nacos://nacos:nacos@localhost:8848 -``` - -### 3.2 Custom namespace - -```yaml -# application.yml (Spring Boot) -dubbo: - registry: - address: nacos://localhost:8848?namespace=5cbb70a5-xxx-xxx-xxx-d43479ae0932 -``` - -or - -```yaml -# application.yml (Spring Boot) -dubbo: - registry: - address: nacos://localhost:8848 - parameters.namespace: 5cbb70a5-xxx-xxx-xxx-d43479ae0932 -``` - -### 3.3 Custom grouping - -```yaml -# application.yml -dubbo: - registry: - address: nacos://localhost:8848 - group: dubbo -``` - -> If not configured, the group is specified by Nacos by default. Group and namespace represent different isolation levels in Nacos. Generally speaking, namespace is used to isolate different users or environments, and group is used to further group data in the same environment. - -### 3.4 Register interface-level consumers -After Dubbo3.0.0, the parameter of whether to register consumers is added. If you need to register consumers to the nacos registration center, you need to set the parameter (register-consumer-url) to true, and the default is false. -```yaml -# application.yml -dubbo: - registry: - address: nacos://localhost:8848?register-consumer-url=true -``` -or -```yaml -# application.yml -dubbo: - registry: - address: nacos://localhost:8848 - parameters.register-consumer-url: true - -``` - -### 3.5 More configurations - -Parameter name | Chinese description | Default value ----|---|--- -username|username to connect to Nacos Server|nacos -paasword|password to connect to Nacos Server|nacos -backup|backup address|null -namespace|Namespace ID|public -group|group name|DEFAULT_GROUP -register-consumer-url|Whether to register the consumer side|false -com.alibaba.nacos.naming.log.filename|initialization log file name|naming.log -endpoint|Connect to the connection point specified by Nacos Server, please refer to [documentation](https://nacos.io/zh-cn/blog/address-server.html)|empty -endpointPort|Connect to the connection point port specified by Nacos Server, you can refer to [documentation](https://nacos.io/zh-cn/blog/address-server.html)|empty -endpointQueryParams|endpoint query parameter query|null -isUseCloudNamespaceParsing|whether to parse namespace parameters in the cloud environment|true -isUseEndpointParsingRule|whether to enable endpoint parameter rule parsing|true -namingLoadCacheAtStart|whether to read the local cache first at startup|true -namingCacheRegistryDir|Specify the cache subdirectory, the location is .../nacos/{SUB_DIR}/naming|empty -namingClientBeatThreadCount | client heartbeat thread pool size | half of the number of CPUs of the machine -namingPollingThreadCount|Client timing polling thread pool size for data update|half of the CPU number of the machine -namingRequestDomainMaxRetryCount|Number of retries requested by client to Nacos Server via HTTP|3 -namingPushEmptyProtection|When the service does not have a valid (healthy) instance, whether to enable the protection, after enabling it, the old service instance will be used|false -push.receiver.udp.port|port of client UDP|null - -After the nacos-server@`1.0.0` version, the client is supported to control some behaviors of the instance by reporting some instances containing specific metadata to the server. - -Parameter name | Chinese description | Default value ----|---|--- -preserved.heart.beat.timeout|The time (in milliseconds) from healthy to unhealthy after the instance does not send a heartbeat|15000 -preserved.ip.delete.timeout|The instance is deleted by the server after the instance does not send a heartbeat (milliseconds)|30000 -preserved.heart.beat.interval|Interval time for the instance to report the heartbeat on the client (milliseconds)|5000 -preserved.instance.id.generator|The id generation strategy of this instance, when the value is `snowflake`, it will increase from 0|simple -preserved.register.source|Registration instance registration service framework type (such as Dubbo, Spring Cloud, etc.)|empty - -These parameters can be configured to Nacos through parameter expansion in a manner similar to `namespace`, such as - - ```properties - dubbo.registry.parameters.preserved.heart.beat.timeout=5000 - ``` - -## 4 How it works - -The following is just to show the working principle of Nacos as the Dubbo registration center. It is recommended to use [Dubbo Admin](https://github.com/apache/dubbo-admin) for Dubbo service operation and maintenance - -### 4.1 Dubbo2 registration data - -Then, restart your Dubbo application, and Dubbo's service provision and consumption information can be displayed in the Nacos console: - -![dubbo-registry-nacos-1.png](/imgs/blog/dubbo-registry-nacos-1.png) - -As shown in the figure, the service name prefixed with `providers:` is the meta information of the service provider, and `consumers:` represents the meta information of the service consumer. Click "**Details**" to view the service status details: - -![image-dubbo-registry-nacos-2.png](/imgs/blog/dubbo-registry-nacos-2.png) - -### 4.2 Dubbo3 registration data -The "service name" for application-level service discovery is the application name - - - -> Dubbo3 adopts the dual registration mode of "application-level service discovery + interface-level service discovery" by default, so you will find that application-level services (application names) and interface-level services (interface names) appear in the Nacos console at the same time, you can configure `dubbo .registry.register-mode=instance/interface/all` to change the registration behavior. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/registry/overview/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/registry/overview/_index.md deleted file mode 100644 index c485a10a1d0a..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/registry/overview/_index.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -type: docs -title: "Overview" -linkTitle: "Overview" -weight: 1 -description: "" ---- - -The registration center is the core component of Dubbo service governance. Dubbo relies on the coordination of the registration center to realize service (address) discovery. Automatic service discovery is the basis for microservices to achieve dynamic scaling, load balancing, and traffic management. Dubbo's service discovery mechanism has experienced interface-level service discovery in the Dubbo2 era and application-level service discovery in the Dubbo3 era. For details, see [Service Discovery Mechanism](/en/docs3-v2/java-sdk/concepts-and-architecture/service -discovery/) analysis to understand the specific evolution process. - -## Basic usage -The Dubbo registry component must be specified when developing an application. The configuration is very simple, just specify the cluster address of the registry: - -Taking Spring Boot development as an example, add a registry configuration item in application.yml - -```yaml -dubbo - registry - address: {protocol}://{cluster-address} -``` -Among them, protocol is the selected configuration center type, and cluster-address is the cluster address for accessing the registration center, such as - -`address: nacos://localshot:8848` - -If you need a cluster format address, you can use the backup parameter - -`address: nacos://localshot:8848?backup=localshot:8846,localshot:8847` - -> The application must specify the Dubbo registration center, even if the registration center is not enabled (you can set the address to be empty address='N/A' ). - -In addition to the rest, depending on each configuration center, you can refer to the [registry configuration reference manual](/en/docs3-v2/java-sdk/reference-manual/config/properties/#registry) or expand through the parameters parameter. - -## Configuration Center and Metadata Center -The configuration center and metadata center are the basic components to realize Dubbo's high-level service governance capabilities. Compared with the registration center, the configuration of these two components is usually optional. - -In order to be compatible with configurations of 2.6 and older versions, Dubbo will use it as both a metadata center and a configuration center for some registry types (such as Zookeeper, Nacos, etc.). - -```yaml -dubbo - registry - address: nacos://localhost:8848 -``` - -Default behavior after frame resolution - -```yaml -dubbo - registry - address: nacos://localhost:8848 - config-center - address: nacos://localhost:8848 - metadata-report - address: nacos://localhost:8848 -``` - -The default behavior can be adjusted or controlled by the following two parameters - -```yaml -dubbo - registry - address: nacos://localhost:8848 - use-as-config-center: false - use-as-metadata-report: false -``` - -## Registration Center Ecology -The mainstream registry implementations currently supported by the Dubbo backbone include -* Zookeeper -* Nacos -* Redis - -It also supports service discovery of Kubernetes and Mesh systems. - -In addition, [Dubbo extension ecology](https://github.com/apache/dubbo-spi-extensions) also provides registry extension implementations such as Consul, Eureka, and Etcd. Also welcome to contribute more registry implementations to the Dubbo ecosystem through [registry spi extension](../../spi/). - -Dubbo also supports [specifying multiple registries] (../multiple-registry/) in an application, and grouping services according to registries, which makes service group management or service migration easier. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/registry/redis/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/registry/redis/_index.md deleted file mode 100644 index 054965a6b5f2..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/registry/redis/_index.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -type: docs -title: "Redis" -linkTitle: "Redis" -weight: 5 -description: "The basic usage and working principle of the Redis registry." ---- - -## precondition -* Understand [Dubbo basic development steps](../../../quick-start/spring-boot/) -* Install and start the [Redis](http://redis.io) service - -## Instructions for use - -```xml - -``` - -or - -```xml - -``` - -or - -```xml - -``` - -or - -```xml - -``` - -## options - -* You can set the prefix of the key in redis through ``, the default is `dubbo`. -* The redis cluster strategy can be set via ``, the default is `failover`: - * `failover`: Only write and read any one, and retry another one when it fails, the server needs to configure data synchronization by itself - * `replicate`: Write to all servers at the same time on the client side, only read a single server, the server side does not need to be synchronized, the registration center cluster increases, and the performance pressure will also be greater - - -## working principle - -A registry implemented based on Redis [^1]. - -Redis expired data detects dirty data through heartbeat, the server time must be synchronized, and there is a certain pressure on the server, otherwise the expiration detection will be inaccurate - -![/user-guide/images/dubbo-redis-registry.jpg](/imgs/user/dubbo-redis-registry.jpg) - -Use Redis's Key/Map structure to store data structures: - -* The main key is the service name and type -* The Key in the Map is the URL address -* The Value in the Map is the expiration time, which is used to judge dirty data, and the dirty data will be deleted by the monitoring center [^3] - -Use Redis's Publish/Subscribe events to notify data changes: - -* Differentiate the event type by the value of the event: `register`, `unregister`, `subscribe`, `unsubscribe` -* Ordinary consumers directly subscribe to the Key of the specified service provider, and will only receive `register`, `unregister` events of the specified service -* The monitoring center subscribes to `/dubbo/*` through the `psubscribe` function, and will receive all change events of all services - -Call process: - -0. When the service provider starts, add the address of the current provider to `Key:/dubbo/com.foo.BarService/providers` -1. And send `register` event to `Channel:/dubbo/com.foo.BarService/providers` -2. When the service consumer starts, subscribe to `register` and `unregister` events from `Channel:/dubbo/com.foo.BarService/providers` -3. Add the address of the current consumer to `Key:/dubbo/com.foo.BarService/consumers` -4. After receiving the `register` and `unregister` events, the service consumer obtains the provider address list from `Key:/dubbo/com.foo.BarService/providers` -5. When the service monitoring center starts, subscribe to `register` and `unregister`, and `subscribe` and `unsubscribe` events from `Channel:/dubbo/*` -6. After receiving the `register` and `unregister` events, the service monitoring center obtains the provider address list from `Key:/dubbo/com.foo.BarService/providers` -7. After receiving the `subscribe` and `unsubscribe` events, the service monitoring center obtains the consumer address list from `Key:/dubbo/com.foo.BarService/consumers` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/registry/simple.md b/content/en/docs3-v2/java-sdk/reference-manual/registry/simple.md deleted file mode 100644 index 568b6d5b3b2a..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/registry/simple.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -type: docs -title: "Simple Registry" -linkTitle: "Simple" -weight: 7 -description: "Simple Registry Reference Manual" ---- - -{{% pageinfo %}} This function has been removed in Dubbo 2.7, please select [other registry](../) for migration. -{{% /pageinfo %}} - -The Simple registry itself is an ordinary Dubbo service, which can reduce third-party dependencies and make the overall communication method consistent. - -## configuration - -Expose the Simple registry as a Dubbo service: - -```xml - - - - - - - - - - - - - - -``` - -Quoting the Simple Registry service: - -```xml - -``` - -or: - -```xml - -``` - -or: - -```xml - -``` - -## Applicability Notes - -This `SimpleRegistryService` is just a simple implementation and does not support clustering. It can be used as a reference for a custom registry, but it is not suitable for direct use in a production environment. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/registry/zookeeper/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/registry/zookeeper/_index.md deleted file mode 100644 index 2ccc1a8716d1..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/registry/zookeeper/_index.md +++ /dev/null @@ -1,133 +0,0 @@ ---- -type: docs -title: "Zookeeper" -linkTitle: "Zookeeper" -weight: 2 -description: "The basic usage and working principle of the Zookeeper registry." ---- - -## 1 precondition -* Understand [Dubbo basic development steps](../../../quick-start/spring-boot/) -* Install and start [Zookeeper](https://zookeeper.apache.org/) - -## 2 Instructions for use -Check out [full sample code](https://github.com/apache/dubbo-samples/tree/master/3-extensions/registry/dubbo-samples-zookeeper) here - -### 2.1 Add Maven dependency -```xml - - 3.0.8 - - - - - org.apache.dubbo - dubbo - ${dubbo.version} - - - - org.apache.dubbo - dubbo-dependencies-zookeeper - ${dubbo.version} - pom - - -``` - -`dubbo-dependencies-zookeeper` will automatically add Zookeeper-related client dependencies to the application, reducing the cost of using Zookeeper for users. If there is a version compatibility problem during use, users can also add it by themselves instead of using `dubbo-dependencies-zookeeper` Curator, Zookeeper Client and other dependencies. - -Since Dubbo uses Curator as a programming client interacting with Zookeeper Server, special attention should be paid to the compatibility between Zookeeper Server and Dubbo version dependencies - -|Zookeeper Server Version|Dubbo Version|Dubbo Zookeeper Dependency Package|Description| -|-----|-----|-----|-----| -|3.4.x and below|3.0.x and above|dubbo-dependencies-zookeeper|transitive dependencies Curator 4.x, Zookeeper 3.4.x| -|3.5.x and above|3.0.x and above|dubbo-dependencies-zookeeper-curator5|transitive dependencies Curator 5.x, Zookeeper 3.7.x| -|3.4.x and above|2.7.x and below|dubbo-dependencies-zookeeper|transitive dependencies Curator 4.x, Zookeeper 3.4.x| -|3.5.x and above|2.7.x and below|None|Need to add Curator, Zookeeper and other related client dependencies| - -### 2.2 Configure and enable Zookeeper -```yaml -# application.yml -dubbo - registry - address: zookeeper://localhost:2181 -``` -or -```properties -# dubbo.properties -dubbo.registry.address=zookeeper://localhost:2181 -``` -or -```xml - -``` - -`address` is the only attribute that must be specified to enable the zookeeper registration center, and in a production environment, `address` is usually specified as the cluster address, such as - -`address=zookeeper://10.20.153.10:2181?backup=10.20.153.11:2181,10.20.153.12:2181` - -It is also possible to configure protocol and address separately, such as - -`` - -## 3 Advanced configuration -### 3.1 Authentication and Authorization - -If Zookeeper enables authentication, Dubbo supports passing in the identity by specifying username and password. - -```yaml -# application.yml -dubbo - registry - address: zookeeper://localhost:2181 - username: hello - password: 1234 -``` - -You can also directly expand the parameters on the address `address=zookeeper://hello:1234@localhost:2181` - -### 3.2 Group isolation -By specifying the `group` attribute, the logical isolation of microservice addresses can be achieved within the same Zookeeper cluster. For example, multiple sets of development environments can be isolated in one cluster, and isolation can be achieved at the address discovery level. - -```yaml -# application.yml -dubbo - registry - address: zookeeper://localhost:2181 - group: daily1 -``` -### 3.3 Other extended configurations -Configure connection and session expiration time -```yaml -# application.yml -dubbo - registry - address: zookeeper://localhost:2181 - timeout: 30 * 1000* # Connection timeout, default 30s - session: 60 * 1000* # Session timeout, default 60s -``` - -The Zookeeper registry also supports some other control parameters, for details, see [Registry configuration item manual](../../config/properties#registry) - -## 4 How it works -### 4.1 Dubbo2 node structure - -![/user-guide/images/zookeeper.jpg](/imgs/user/zookeeper.jpg) - -process: -* When the service provider starts: write its own URL address to the `/dubbo/com.foo.BarService/providers` directory. -* When the service consumer starts: subscribe to the provider URL address under the `/dubbo/com.foo.BarService/providers` directory. And write your own URL address to `/dubbo/com.foo.BarService/consumers` directory -* When monitoring center starts: subscribe to all provider and consumer URL addresses under `/dubbo/com.foo.BarService` directory. - -The following functions are supported: - -* When the provider has abnormal downtime such as power failure, the registration center can automatically delete the provider information -* When the registration center restarts, the registration data and subscription requests can be automatically restored -* When the session expires, the registration data and subscription request can be automatically restored -* When `` is set, the failed registration and subscription requests will be recorded, and the background will retry periodically -* You can set zookeeper login information through `` -* The root node of zookeeper can be set through ``, if not configured, the default root node will be used. -* Support `*` wildcard ``, you can subscribe to all groups of services and providers of all versions - -### 4.2 Dubbo3 node structure \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/_index.md deleted file mode 100755 index 4dd88f9f8c06..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "SPI Extension Manual" -linkTitle: "SPI Extension Manual" -weight: 9 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/_index.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/_index.md deleted file mode 100644 index 7504e5b12640..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "Dubbo SPI extension implementation description" -linkTitle: "Dubbo SPI extension implementation description" -weight: 2 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/cache.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/cache.md deleted file mode 100644 index 9f9997eb6144..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/cache.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -type: docs -title: "Cache Extension" -linkTitle: "Cache Extension" -weight: 24 ---- - -## Expansion Description - -Use the request parameter as the key to cache the returned result. - -## Extension ports - -`org.apache.dubbo.cache.CacheFactory` - -## Extended configuration - -```xml - - - - - -``` - -## Known extensions - -* `org.apache.dubbo.cache.support.lru.LruCacheFactory` -* `org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory` -* `org.apache.dubbo.cache.support.jcache.JCacheFactory` - - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxCacheFactory.java (implements the CacheFactory interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.cache.CacheFactory (plain text file, content: xxx=com.xxx.XxxCacheFactory) -``` - -XxxCacheFactory.java: - -```java -package com.xxx; - -import org.apache.dubbo.cache.CacheFactory; - -public class XxxCacheFactory implements CacheFactory { - public Cache getCache(URL url, String name) { - return new XxxCache(url, name); - } -} -``` - -XxxCache.java: - -```java -package com.xxx; - -import org.apache.dubbo.cache.Cache; - -public class XxxCache implements Cache { - public Cache(URL url, String name) { - //... - } - public void put(Object key, Object value) { - //... - } - public Object get(Object key) { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.cache.CacheFactory: - -```properties -xxx=com.xxx.XxxCacheFactory -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/cluster.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/cluster.md deleted file mode 100644 index a55d31e0b36d..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/cluster.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -type: docs -title: "Cluster Expansion" -linkTitle: "Cluster Expansion" -weight: 5 ---- - -## Expansion Description - -When there are multiple service providers, organize multiple service providers into a cluster and pretend to be one provider. - -## Extension ports - -`org.apache.dubbo.rpc.cluster.Cluster` - -## Extended configuration - -```xml - - - -``` - -## Known extensions - -* `org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper` -* `org.apache.dubbo.rpc.cluster.support.FailoverCluster` -* `org.apache.dubbo.rpc.cluster.support.FailfastCluster` -* `org.apache.dubbo.rpc.cluster.support.FailsafeCluster` -* `org.apache.dubbo.rpc.cluster.support.FailbackCluster` -* `org.apache.dubbo.rpc.cluster.support.ForkingCluster` -* `org.apache.dubbo.rpc.cluster.support.AvailableCluster` -* `org.apache.dubbo.rpc.cluster.support.MergeableCluster` -* `org.apache.dubbo.rpc.cluster.support.BroadcastCluster` -* `org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxCluster.java (implements the Cluster interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.cluster.Cluster (plain text file, content: xxx=com.xxx.XxxCluster) -``` - -XxxCluster.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.cluster.Cluster; -import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker; -import org.apache.dubbo.rpc.cluster.Directory; -import org.apache.dubbo.rpc.cluster.LoadBalance; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.Invocation; -import org.apache.dubbo.rpc.Result; -import org.apache.dubbo.rpc.RpcException; - -public class XxxCluster implements Cluster { - public Invoker merge(Directory directory) throws RpcException { - return new AbstractClusterInvoker(directory) { - public Result doInvoke(Invocation invocation, List> invokers, LoadBalance loadbalance) throws RpcException { - //... - } - }; - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.cluster.Cluster: - -```properties -xxx=com.xxx.XxxCluster -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/compiler.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/compiler.md deleted file mode 100644 index 193d8feaa54c..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/compiler.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -type: docs -title: "Compiler Extensions" -linkTitle: "Compiler Extensions" -weight: 13 ---- - -## Expansion Description - -Java code compiler, used to dynamically generate bytecode to speed up calls. - -## Extension ports - -`org.apache.dubbo.common.compiler.Compiler` - -## Extended configuration - -autoload - -## Known extensions - -* `org.apache.dubbo.common.compiler.support.JdkCompiler` -* `org.apache.dubbo.common.compiler.support.JavassistCompiler` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxCompiler.java (implement Compiler interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.common.compiler.Compiler (plain text file, content: xxx=com.xxx.XxxCompiler) -``` - -XxxCompiler.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.compiler.Compiler; - -public class XxxCompiler implements Compiler { - public Object getExtension(Class type, String name) { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.common.compiler.Compiler: - -```properties -xxx=com.xxx.XxxCompiler -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/config-center.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/config-center.md deleted file mode 100644 index 57e7de7599c5..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/config-center.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -type: docs -title: "Configuration Center Extension" -linkTitle: "Configuration Center Extension" -weight: 13 ---- - -## aim of design - -The core function of the configuration center is as Key-Value storage. The Dubbo framework informs the configuration center of the key it cares about, and the configuration center returns the value corresponding to the key. - -According to the application scenarios, the configuration center mainly undertakes the following responsibilities in the Dubbo framework: - -- As an external configuration center, it stores the dubbo.properties configuration file. At this time, the key value is usually the file name such as dubbo.properties, and the value is the content of the configuration file. -- Store individual configuration items, such as various switch items, constant values, etc. -- Store service governance rules. At this time, the key is usually organized in the format of "service name + rule type", and the value is the specific governance rule. - -In order to further realize the group management of key-value, Dubbo's configuration center also added the concepts of namespace and group. These concepts are reflected in many professional third-party configuration centers. Usually, namespace is used to isolate different tenants , group is used to group the key collection of the same tenant. - -Currently, the Dubbo configuration center has realized the docking of Zookeeper, Nacos, Etcd, Consul, and Apollo. Next, let’s take a look at how Dubbo’s abstract configuration center is mapped to a specific third-party implementation. - -## Extension ports - -* `org.apache.dubbo.configcenter.DynamicConfigurationFactory` -* `org.apache.dubbo.configcenter.DynamicConfiguration` - -## Known extensions - -* `org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfigurationFactory` -* `org.apache.dubbo.configcenter.support.nacos.NacosDynamicConfigurationFactory` -* `org.apache.dubbo.configcenter.support.etcd.EtcdDynamicConfigurationFactory` -* `org.apache.dubbo.configcenter.consul.ConsulDynamicConfigurationFactory` -* `org.apache.dubbo.configcenter.support.apollo.ApolloDynamicConfigurationFactory` -* `org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfigurationFactory` - -## Implementation principle - -### Zookeeper - -zookeeper provides a tree-like storage model, the implementation principle is as follows: - -![image-20190127225608553](/imgs/dev/configcenter_zk_model.jpg) - -namespace, group, key, etc. correspond to different levels of ZNode nodes, and value is stored as the value of the root ZNode node. - -1. External configuration center dubbo.properties - - ![image-20190127225608553](/imgs/dev/configcenter_zk_properties.jpg) - - The figure above shows the storage structure of dubbo.properties files in two different scopes in zookeeper: - - Namespace namespace is: dubbo - - Grouping group: the global level is dubbo, shared by all applications; the application level is the application name demo-provider, which only takes effect for this application - - key: dubbo.properties - -2. Single configuration item - - ![image-20190127225608553](/imgs/dev/configcenter_zk_singleitem.jpg) - - Set the graceful shutdown event to 15000: - - Namespace namespace: dubbo - - Grouping group: dubbo - - key: dubbo.service.shutdown.wait - - value: 15000 - -3. Service Governance Rules - - ![image-20190127225608553](/imgs/dev/configcenter_zk_rule.jpg) - - The figure above shows an application-level conditional routing rule: - - - Namespace namespace: dubbo - - Grouping group: dubbo - - key: governance-conditionrouter-consumer.condition-router, where governance-conditionrouter-consumer is the application name, and condition-router represents conditional routing - - - > Note: - > - > Dubbo supports service governance rules at two granularities of application and service at the same time. For these two granularities, the key value rules are as follows: - > * Application granularity {application name + rule suffix}. Such as: `demo-application.configurators`, `demo-application.tag-router`, etc. - > * Service granularity {service interface name:[service version]:[service group] + rule suffix}, where service version and service group are optional, if they are configured, they will be reflected in the key, if they are not configured, use " :"Occupy place. Such as - > `org.apache.dubbo.demo.DemoService::.configurators`, `org.apache.dubbo.demo.DemoService:1.0.0:group1.configurators` - -### Etcd & Consul - -Etcd and Consul are essentially a tree-like storage structure similar to zookeeper. For implementation, please refer to zookeeper. - -### Nacos - -As a professional third-party configuration center, Nacos has a storage structure specially designed for configuration centers, including built-in concepts such as namespace, group, and dataid. And these concepts are basically in one-to-one correspondence with the abstract configuration center of the Dubbo framework. - -The corresponding relationship with Zookeeper implementation is as follows: - -![image-20190127225608553](/imgs/dev/configcenter_nacos_model.jpg) - -Referring to the example described above about the zookeeper implementation, the dataid here may be: -* External configuration center: dubbo.properties -* Single configuration item: dubbo.service.shutdown.wait -* Service governance rules: org.apache.dubbo.demo.DemoService:1.0.0:group1.configurators - -### Apollo - -Apollo is similar to Nacos, please refer to the description about Apollo in the Dynamic Configuration Center Documentation. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/container.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/container.md deleted file mode 100644 index 6e287baf6fbd..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/container.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -type: docs -title: "Container Extension" -linkTitle: "Container Extension" -weight: 22 ---- - -## Expansion Description - -Service container extension for custom loading content. - -## Extension ports - -`org.apache.dubbo.container.Container` - -## Extended configuration - -```sh -java org.apache.dubbo.container.Main spring jetty log4j -``` - -## Known extensions - -* `org.apache.dubbo.container.spring.SpringContainer` -* `org.apache.dubbo.container.spring.JettyContainer` -* `org.apache.dubbo.container.spring.Log4jContainer` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxContainer.java (implements the Container interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.container.Container (plain text file, content: xxx=com.xxx.XxxContainer) -``` - -XxxContainer.java: - -```java -package com.xxx; - -org.apache.dubbo.container.Container; - - -public class XxxContainer implements Container { - public Status start() { - //... - } - public Status stop() { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.container.Container: - -```properties -xxx=com.xxx.XxxContainer -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/dispatcher.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/dispatcher.md deleted file mode 100644 index 5b99c65a893b..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/dispatcher.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -type: docs -title: "Message Dispatch Extension" -linkTitle: "Message dispatch extension" -weight: 14 ---- - -## Expansion Description - -Channel information dispatcher, used to specify the thread pool model. - -## Extension ports - -`org.apache.dubbo.remoting.Dispatcher` - -## Extended configuration - -```xml - - - -``` - -## Known extensions - -* `org.apache.dubbo.remoting.transport.dispatcher.all.AllDispatcher` -* `org.apache.dubbo.remoting.transport.dispatcher.direct.DirectDispatcher` -* `org.apache.dubbo.remoting.transport.dispatcher.message.MessageOnlyDispatcher` -* `org.apache.dubbo.remoting.transport.dispatcher.execution.ExecutionDispatcher` -* `org.apache.dubbo.remoting.transport.dispatcher.connection.ConnectionOrderedDispatcher` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxDispatcher.java (implements the Dispatcher interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.remoting.Dispatcher (plain text file, content: xxx=com.xxx.XxxDispatcher) -``` - -XxxDispatcher.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.Dispatcher; - -public class XxxDispatcher implements Dispatcher { - public Group lookup(URL url) { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.remoting.Dispatcher: - -```properties -xxx=com.xxx.XxxDispatcher -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/dubbo-spi.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/dubbo-spi.md deleted file mode 100644 index 1f46d386c1f4..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/dubbo-spi.md +++ /dev/null @@ -1,705 +0,0 @@ ---- -type: docs -title: "Extension Point Development Guide" -linkTitle: "Extension Point Development Guide" -weight: 0 -description: "This article introduces the principle and implementation details of Dubbo SPI" ---- - -## 1 Introduction - -The full name of SPI is Service Provider Interface, which is a service discovery mechanism. The essence of SPI is to configure the fully qualified name of the interface implementation class in the file, and the service loader reads the configuration file and loads the implementation class. In this way, the implementation class can be dynamically replaced for the interface at runtime. Because of this feature, we can easily provide extended functions for our programs through the SPI mechanism. The SPI mechanism is also used in third-party frameworks. For example, Dubbo loads all components through the SPI mechanism. However, Dubbo does not use Java's native SPI mechanism, but enhances it to better meet the needs. In Dubbo, SPI is a very important module. Based on SPI, we can easily expand Dubbo. -In Dubbo, SPI has two main usages, one is to load fixed extension classes, and the other is to load adaptive extension classes. These two methods will be described in detail below. -Special attention should be paid to: In Dubbo, classes loaded based on SPI extensions are singletons. - -### 1.1 Load fixed extension classes - -If you were asked to design and load fixed extension classes, what would you do? -A common idea is to read the configuration file in a specific directory, then parse out the full class name, instantiate the class through the reflection mechanism, and then store the class in the collection. If necessary, directly from the collection Take. The implementation in Dubbo is also such an idea. -However, in Dubbo, the implementation is more complete, and it implements the functions of IOC and AOP. IOC means that if this extended class depends on other properties, Dubbo will automatically inject this property. How is this function implemented? A common idea is to get the setter of this extended class -method, call the setter method for property injection. What does AOP refer to? This means that Dubbo can inject its wrapper class into the extension class. For example, DubboProtocol is an extension class of Protocol, and ProtocolListenerWrapper is a wrapper class of DubboProtocol. - -### 1.2 Load adaptive extension class - -First explain the usage scenarios of adaptive extension classes. For example, we have a requirement that when calling a certain method, we can call different implementation classes based on parameter selection. Somewhat similar to the factory method, different instance objects are constructed based on different parameters. -The idea of implementation in Dubbo is similar to this, but the implementation of Dubbo is more flexible, and its implementation is somewhat similar to the strategy mode. Each extension class is equivalent to a strategy. Based on the URL message bus, the parameters are passed to the ExtensionLoader, and the corresponding extension class is loaded based on the parameters through the ExtensionLoader to realize the dynamic call to the target instance at runtime. - -## 2. Dubbo SPI source code analysis - -### 2.1 Load fixed extension class - -In Dubbo, the entry point for SPI to load fixed extension classes is the getExtension method of ExtensionLoader. Next, we will analyze the process of obtaining extension class objects in detail. - -```java -public T getExtension(String name) { - if (name == null || name. length() == 0) - throw new IllegalArgumentException("Extension name == null"); - if ("true".equals(name)) { - // Get the default extension implementation class - return getDefaultExtension(); - } - // Holder, as the name suggests, is used to hold the target object - Holder holder = cachedInstances. get(name); - // This logic ensures that only one thread can create a Holder object - if (holder == null) { - cachedInstances. putIfAbsent(name, new Holder()); - holder = cachedInstances. get(name); - } - Object instance = holder. get(); - // double check - if (instance == null) { - synchronized (holder) { - instance = holder. get(); - if (instance == null) { - // create extension instance - instance = createExtension(name); - // set the instance to the holder - holder.set(instance); - } - } - } - return (T) instance; -} -``` - -The logic of the above code is relatively simple. First, the cache is checked, and if the cache misses, an extended object is created. Let's take a look at the process of creating an extended object. - -```java -private T createExtension(String name, boolean wrap) { - // Load all extension classes from the configuration file to get the mapping relationship table from "configuration item name" to "configuration class" - Class clazz = getExtensionClasses().get(name); - // If there is no extension of the interface, or the implementation class of the interface does not allow repetition but actually repeats, an exception is thrown directly - if (clazz == null || unacceptableExceptions. contains(name)) { - throw findException(name); - } - try { - T instance = (T) EXTENSION_INSTANCES. get(clazz); - // This code ensures that the extended class will only be constructed once, which is a singleton. - if (instance == null) { - EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance()); - instance = (T) EXTENSION_INSTANCES. get(clazz); - } - // Inject dependencies into the instance - injectExtension(instance); - - // Automatically wrap if wrapping is enabled. - // For example, I defined the extension of DubboProtocol based on Protocol, but in fact, DubboProtocol is not directly used in Dubbo, but its wrapper class - // ProtocolListenerWrapper - if (wrap) { - - List> wrapperClassesList = new ArrayList<>(); - if (cachedWrapperClasses != null) { - wrapperClassesList.addAll(cachedWrapperClasses); - wrapperClassesList.sort(WrapperComparator. COMPARATOR); - Collections. reverse(wrapperClassesList); - } - - // Loop to create Wrapper instances - if (CollectionUtils. isNotEmpty(wrapperClassesList)) { - for (Class wrapperClass : wrapperClassesList) { - Wrapper wrapper = wrapperClass. getAnnotation(Wrapper. class); - if (wrapper == null - || (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) { - // Pass the current instance as a parameter to the constructor of Wrapper, and create a Wrapper instance through reflection. - // Then inject dependencies into the Wrapper instance, and finally assign the Wrapper instance to the instance variable again - instance = injectExtension((T) wrapperClass. getConstructor(type). newInstance(instance)); - } - } - } - } - // initialization - initExtension(instance); - return instance; - } catch (Throwable t) { - throw new IllegalStateException("Extension instance (name: " + name + ", class: " + - type + ") couldn't be instantiated: " + t. getMessage(), t); - } -} -``` - -The logic of the createExtension method is a little more complicated, including the following steps: - -1. Get all extension classes through getExtensionClasses -2. Create an extended object through reflection -3. Inject dependencies into extended objects -4. Wrap the extension object in the corresponding Wrapper object -5. Initialize the extension object - -Among the above steps, the first step is the key to loading the extension class, and the third and fourth steps are the specific implementation of Dubbo IOC and AOP. In the following chapters, we will focus on analyzing the logic of the getExtensionClasses method and briefly introduce the specific implementation of Dubbo IOC. - -### 2.1.1 Get all extension classes - -Before we obtain the extension class by name, we first need to parse out the mapping relationship table from the extension item name to the extension class (Map\) according to the configuration file, and then extract it from the mapping relationship table according to the extension item name The corresponding extension class can be. The code analysis of the relevant process is as follows: - -```java -private Map> getExtensionClasses() { - // Get the loaded extension class from the cache - Map> classes = cachedClasses. get(); - // double check - if (classes == null) { - synchronized (cachedClasses) { - classes = cachedClasses. get(); - if (classes == null) { - // load extension class - classes = loadExtensionClasses(); - cachedClasses.set(classes); - } - } - } - return classes; -} -``` - -Here is also to check the cache first, and if the cache misses, lock it through synchronized. After locking, check the cache again and find it empty. At this time, if classes is still null, the extension class is loaded through loadExtensionClasses. Let's analyze the logic of the loadExtensionClasses method. - -```java -private Map> loadExtensionClasses() { - // Cache the default SPI extension - cacheDefaultExtensionName(); - - Map> extensionClasses = new HashMap<>(); - - // Load the files in the specified folder based on the policy - // Currently there are four strategies to read the configuration files in META-INF/services/ META-INF/dubbo/ META-INF/dubbo/internal/ META-INF/dubbo/external/ respectively - for (LoadingStrategy strategy : strategies) { - loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages()); - loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages()); - } - - return extensionClasses; -} -``` - -The loadExtensionClasses method does two things in total, one is to parse the SPI annotations, and the other is to call the loadDirectory method to load the specified folder configuration file. The process of parsing SPI annotations is relatively simple, so there is no need to say more. Let's take a look at what loadDirectory does. - -```java -private void loadDirectory(Map> extensionClasses, String dir, String type, - boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) { - // fileName = folder path + type fully qualified name - String fileName = dir + type; - try { - Enumeration urls = null; - ClassLoader classLoader = findClassLoader(); - - // try to load from ExtensionLoader's ClassLoader first - if (extensionLoaderClassLoaderFirst) { - ClassLoader extensionLoaderClassLoader = ExtensionLoader. class. getClassLoader(); - if (ClassLoader. getSystemClassLoader() != extensionLoaderClassLoader) { - urls = extensionLoaderClassLoader. getResources(fileName); - } - } - // Load all files with the same name according to the file name - if (urls == null || !urls.hasMoreElements()) { - if (classLoader != null) { - urls = classLoader. getResources(fileName); - } else { - urls = ClassLoader. getSystemResources(fileName); - } - } - - if (urls != null) { - while (urls. hasMoreElements()) { - java.net.URL resourceURL = urls.nextElement(); - // load resources - loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages); - } - } - } catch (Throwable t) { - logger.error("Exception occurred when loading extension class (interface: " + - type + ", description file: " + fileName + ").", t); - } -} -``` - -The loadDirectory method first obtains all resource links through classLoader, and then loads resources through the loadResource method. Let's go ahead and take a look at the implementation of the loadResource method. - -```java -private void loadResource(Map> extensionClasses, ClassLoader classLoader, - java.net.URL resourceURL, boolean overridden, String... excludedPackages) { - try { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL. openStream(), StandardCharsets. UTF_8))) { - String line; - String clazz = null; - // Read configuration content line by line - while ((line = reader. readLine()) != null) { - // locate # characters - final int ci = line. indexOf('#'); - if (ci >= 0) { - // Intercept the string before #, the content after # is a comment, which needs to be ignored - line = line. substring(0, ci); - } - line = line. trim(); - if (line. length() > 0) { - try { - String name = null; - // Use the equal sign = as the boundary to intercept the key and value - int i = line. indexOf('='); - if (i > 0) { - name = line.substring(0, i).trim(); - clazz = line.substring(i + 1).trim(); - } else { - clazz = line; - } - // Load the class and cache the class through the loadClass method - if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages)) { - loadClass(extensionClasses, resourceURL, Class. forName(clazz, true, classLoader), name, overridden); - } - } catch (Throwable t) { - IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t); - exceptions. put(line, e); - } - } - } - } - } catch (Throwable t) { - logger.error("Exception occurred when loading extension class (interface: " + - type + ", class file: " + resourceURL + ") in " + resourceURL, t); - } -} -``` - -The loadResource method is used to read and parse configuration files, load classes through reflection, and finally call the loadClass method for other operations. The loadClass method is mainly used to operate the cache. The logic of this method is as follows: - -```java -private void loadClass(Map> extensionClasses, java.net.URL resourceURL, Class clazz, String name, - boolean overridden) throws NoSuchMethodException { - if (!type.isAssignableFrom(clazz)) { - throw new IllegalStateException("Error occurred when loading extension class (interface: " + - type + ", class line: " + clazz. getName() + "), class " - + clazz.getName() + " is not subtype of interface."); - } - // Check if there are Adaptive annotations on the target class - if (clazz. isAnnotationPresent(Adaptive. class)) { - cacheAdaptiveClass(clazz, overridden); - } else if (isWrapperClass(clazz)) { - // cache wrapper class - cacheWrapperClass(clazz); - } else { - // Enter here, indicating that this class is just an ordinary extension class - // Check if clazz has a default constructor, if not, throw an exception - clazz. getConstructor(); - if (StringUtils. isEmpty(name)) { - // If name is empty, try to get name from Extension annotation, or use lowercase class name as name - name = findAnnotationName(clazz); - if (name. length() == 0) { - throw new IllegalStateException("No such extension name for the class " + clazz. getName() + " in the config " + resourceURL); - } - } - - String[] names = NAME_SEPARATOR. split(name); - if (ArrayUtils. isNotEmpty(names)) { - // If the class has the Activate annotation, use the first element of the names array as the key, - // Store the mapping relationship between name and Activate annotation object - cacheActivateClass(clazz, names[0]); - for (String n : names) { - // Store the mapping relationship from Class to name - cacheName(clazz, n); - // Store the mapping relationship from name to Class. - // If there are multiple implementation classes corresponding to the same extension, whether overriding is allowed based on the override parameter, if not, an exception is thrown. - saveInExtensionClass(extensionClasses, clazz, n, overridden); - } - } - } -} -``` - -As above, the loadClass method operates different caches, such as cachedAdaptiveClass, cachedWrapperClasses and cachedNames, etc. Apart from that, there is no other logic in this method. - -At this point, the analysis of the process of caching class loading is over. There is nothing particularly complicated in the whole process. You can analyze it step by step, and you can debug it if you don’t understand it. Next, let's talk about Dubbo IOC. - -### 2.1.2 Dubbo IOC - -Dubbo IOC injects dependencies through the setter method. Dubbo first obtains all methods of the instance through reflection, and then traverses the method list to detect whether the method name has the characteristics of a setter method. If so, obtain the dependent object through ObjectFactory, and finally call the setter method through reflection to set the dependency to the target object. The code corresponding to the whole process is as follows: - -```java -private T injectExtension(T instance) { - - if (objectFactory == null) { - return instance; - } - - try { - // traverse all methods of the target class - for (Method method : instance. getClass(). getMethods()) { - // Check whether the method starts with set, and the method has only one parameter, and the method access level is public - if (!isSetter(method)) { - continue; - } - /** - * Detect whether there is DisableInject annotation modification. - */ - if (method. getAnnotation(DisableInject. class) != null) { - continue; - } - - /** - * Detect whether the ScopeModelAware and ExtensionAccessorAware classes are implemented, and if implemented, do not inject - */ - if (method. getDeclaringClass() == ScopeModelAware. class) { - continue; - } - if (instance instanceof ScopeModelAware || instance instanceof ExtensionAccessorAware) { - if (ignoredInjectMethodsDesc. contains(ReflectUtils. getDesc(method))) { - continue; - } - } - - // Primitive types are not injected - Class pt = method. getParameterTypes()[0]; - if (ReflectUtils. isPrimitives(pt)) { - continue; - } - - try { - // Get the attribute name, for example, the setName method corresponds to the attribute name name - String property = getSetterProperty(method); - // Get dependent objects from ObjectFactory - Object object = objectFactory. getExtension(pt, property); - if (object != null) { - // inject - method.invoke(instance, object); - } - } catch (Exception e) { - logger.error("Failed to inject via method " + method.getName() - + " of interface " + type. getName() + ": " + e. getMessage(), e); - } - - } - } catch (Exception e) { - logger. error(e. getMessage(), e); - } - return instance; -} -``` - -In the above code, the type of the objectFactory variable is AdaptiveExtensionFactory, and AdaptiveExtensionFactory internally maintains an ExtensionFactory list for storing other types of ExtensionFactory. Dubbo currently provides two types of ExtensionFactory, namely SpiExtensionFactory and SpringExtensionFactory. The former is used to create adaptive extensions, and the latter is used to obtain the required extensions from Spring's IOC container. The codes of these two classes are not very complicated, so I won't analyze them one by one here. - -Dubbo IOC currently only supports setter injection. Generally speaking, the logic is relatively simple and easy to understand. - -### 2.2 Load adaptive extension class - -The meaning of adaptive extension class is that, based on parameters, a specific target class is dynamically selected at runtime and then executed. -In Dubbo, many extensions are loaded through the SPI mechanism, such as Protocol, Cluster, LoadBalance, etc. Sometimes, some extensions do not want to be loaded during the framework startup phase, but want to be loaded according to runtime parameters when the extension method is called. This sounds contradictory. If the extension is not loaded, the extension methods cannot be called (except static methods). If the extension method is not called, the extension cannot be loaded. For this contradictory problem, Dubbo has solved it well through the adaptive expansion mechanism. The implementation logic of the self-adaptive expansion mechanism is relatively complicated. First, Dubbo will generate code with proxy functions for the expansion interface. Then compile this code through javassist or jdk to get the Class class. Finally, the proxy class is created through reflection, and the whole process is more complicated. - -The entry point for loading adaptive extension classes is the getAdaptiveExtension method of ExtensionLoader. - -```java -public T getAdaptiveExtension() { - // Get the adaptive extension from the cache - Object instance = cachedAdaptiveInstance. get(); - if (instance == null) { - // If there is an exception, throw it directly - if (createAdaptiveInstanceError != null) { - throw new IllegalStateException("Failed to create adaptive instance: " + - createAdaptiveInstanceError.toString(), - createAdaptiveInstanceError); - } - - synchronized (cachedAdaptiveInstance) { - instance = cachedAdaptiveInstance. get(); - // double check - if (instance == null) { - try { - // create adaptive extension - // There are two cases here: one is that there is an Adaptive class, and the other is that an Adaptive class needs to be generated - instance = createAdaptiveExtension(); - cachedAdaptiveInstance.set(instance); - } catch (Throwable t) { - createAdaptiveInstanceError = t; - throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t); - } - } - } - } - - return (T) instance; -} -``` - -The getAdaptiveExtension method will first check the cache, and if the cache misses, call the createAdaptiveExtension method to create an adaptive extension. Next, let's look at the code of the createAdaptiveExtension method. - -```java -private T createAdaptiveExtension() { - try { - // Get the adaptive extension class and instantiate it through reflection - return injectExtension((T) getAdaptiveExtensionClass(). newInstance()); - } catch (Exception e) { - throw new IllegalStateException("Can not create adaptive extension ..."); - } -} -``` -The code of the createAdaptiveExtension method is relatively small, but it contains three logics, which are as follows: - -1. Call the getAdaptiveExtensionClass method to obtain the adaptive extension Class object -2. Instantiation via reflection -3. Call the injectExtension method to inject dependencies into the extension instance - -The first two logics are easy to understand, and the third logic is used to inject dependencies into adaptive extension objects. This logic may seem redundant, but it is necessary to exist. Here is a brief explanation. As mentioned earlier, there are two types of adaptive extensions in Dubbo, one is manually coded and the other is automatically generated. There may be some dependencies in the hand-coded Adaptive extension, while the automatically generated Adaptive extension will not depend on other classes. The purpose of calling the injectExtension method here is to inject dependencies for the hand-coded adaptive extension, which requires everyone to pay attention. Regarding the injectExtension method, it has been analyzed in the previous article, so I won’t go into details here. Next, analyze the logic of the getAdaptiveExtensionClass method. - -```java -private Class getAdaptiveExtensionClass() { - // Get all extension classes through SPI - getExtensionClasses(); - // Check the cache, if the cache is not empty, return the cache directly - if (cachedAdaptiveClass != null) { - return cachedAdaptiveClass; - } - // Create an adaptive extension class - return cachedAdaptiveClass = createAdaptiveExtensionClass(); -} -``` - -The getAdaptiveExtensionClass method also contains three logics, as follows: - -1. Call getExtensionClasses to get all extension classes -2. Check the cache, if the cache is not empty, return the cache -3. If the cache is empty, call createAdaptiveExtensionClass to create an adaptive extension class - -These three logics seem unremarkable, and there seems to be no need to talk about them. But there are some details hidden in this bland code that need to be explained. First, let’s start with the first logic. The getExtensionClasses method is used to get all the implementation classes of an interface. For example, this method can obtain DubboProtocol, HttpProtocol, InjvmProtocol and other implementation classes of the Protocol interface. In the process of obtaining the implementation class, if an implementation class is modified by the Adaptive annotation, then the class will be assigned to the cachedAdaptiveClass variable. At this point, the condition of the second step in the above steps is satisfied (the cache is not empty), just return the cachedAdaptiveClass directly. If all implementation classes are not modified by Adaptive annotations, then execute the logic of the third step to create adaptive extension classes. The relevant code is as follows: - -```java -private Class createAdaptiveExtensionClass() { - // Build adaptive extension code - String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate(); - ClassLoader classLoader = findClassLoader(); - // Get the compiler implementation class - org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); - // Compile the code and generate Class - return compiler.compile(code, classLoader); -} -``` - -The createAdaptiveExtensionClass method is used to generate an adaptive extension class. This method first generates the source code of the adaptive extension class, and then compiles the source code through a Compiler instance (Dubbo uses javassist as the compiler by default) to obtain a proxy class Class instance. Next, we will focus on the logic of proxy class code generation, and analyze other logic by yourself. - -### 2.2.1 Adaptive extension class code generation - -AdaptiveClassCodeGenerator#generate method generates extension class code -```java -public String generate() { - // If there is no method in the interface modified by the @Adaptive annotation, an exception is thrown directly - if (!hasAdaptiveMethod()) { - throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!"); - } - - StringBuilder code = new StringBuilder(); - // Generate package name, import, method, etc. - code.append(generatePackageInfo()); - code.append(generateImports()); - code.append(generateClassDeclaration()); - - Method[] methods = type. getMethods(); - for (Method method : methods) { - code.append(generateMethod(method)); - } - code.append("}"); - - if (logger. isDebugEnabled()) { - logger. debug(code. toString()); - } - return code. toString(); -} - -``` - -#### 2.2.2 Generation method - -In the above code, the logic of the generation method is the most critical, let's analyze it in detail. -```java -private String generateMethod(Method method) { - String methodReturnType = method. getReturnType(). getCanonicalName(); - String methodName = method. getName(); - // generate method content - String methodContent = generateMethodContent(method); - String methodArgs = generateMethodArguments(method); - String methodThrows = generateMethodThrows(method); - return String. format(CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent); -} -``` - -generateMethodContent Analysis - -```java -private String generateMethodContent(Method method) { - // This method must be decorated with @Adaptive annotation - Adaptive adaptiveAnnotation = method. getAnnotation(Adaptive. class); - StringBuilder code = new StringBuilder(512); - if (adaptiveAnnotation == null) { - // Without @Adaptive annotation modification, exception information is generated - return generateUnsupported(method); - } else { - // Get the index of the URL on the parameter list - int urlTypeIndex = getUrlTypeIndex(method); - - if (urlTypeIndex != -1) { - // Generate a null check for the URL if it exists on the parameter list - code.append(generateUrlNullCheck(urlTypeIndex)); - } else { - // If there is no parameter of URL type in the parameter list, then it depends on whether the parameter object on the parameter list contains the getUrl method - // If there is, generate a URL null check - code.append(generateUrlAssignmentIndirectly(method)); - } - // parse the value attribute on the Adaptive annotation - String[] value = getMethodAdaptiveValue(adaptiveAnnotation); - // If there is a parameter of type Invocation on the parameter list, generate a null check and get the methodName. - boolean hasInvocation = hasInvocationArgument(method); - - code.append(generateInvocationArgumentNullCheck(method)); - // This logic is mainly to generate extName (that is, the extension) - // Divided into multiple situations: - // 1. Does defaultExtName exist? - // 2. Whether there is an invocation type parameter in the parameter - // 3. Whether to generate a proxy for the protocol - // Why should the protocol be considered separately? Because there is a method to get the protocol value in the URL - code.append(generateExtNameAssignment(value, hasInvocation)); - // check extName == null? - code.append(generateExtNameNullCheck(value)); - - // generate get extension (using ExtensionLoader.getExtension method) - code.append(generateExtensionAssignment()); - - // generate return statement - code.append(generateReturnAndInvocation(method)); - } - - return code. toString(); -} -``` - -The above logic mainly does the following things: -1. Check whether the Adaptive annotation is modified on the method -2. When generating code for a method, there must be a URL on the parameter list (or a URL in the parameter object) -3. Use ExtensionLoader.getExtension to get the extension -4. Execute the corresponding method - -### 2.2.3 Attach an example of dynamically generated code - -```java -package org.apache.dubbo.common.extension.adaptive; - -import org.apache.dubbo.common.extension.ExtensionLoader; - - -public class HasAdaptiveExt$Adaptive implements org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt { - public java.lang.String echo(org.apache.dubbo.common.URL arg0, - java. lang. String arg1) { - // URL null check - if (arg0 == null) { - throw new IllegalArgumentException("url == null"); - } - - org.apache.dubbo.common.URL url = arg0; - // get the extension - String extName = url. getParameter("has. adaptive. ext", "adaptive"); - // extension null check - if (extName == null) { - throw new IllegalStateException( - "Failed to get extension (org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt) name from url (" + - url.toString() + ") use keys([has.adaptive.ext])"); - } - // get extension - org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt extension = (org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt) ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.extension.adaptive.HasAdaptiveExt.class) - .getExtension(extName); - // Execute the corresponding method - return extension.echo(arg0, arg1); - } -} - -``` - - -## 3. SPI extension example - -### 3.1 Load fixed extension class - -### 3.1.1 Write SPI interface and implementation class - -Whether it is Java SPI or SPI implemented in Dubbo, you need to write an interface. However, the interface in Dubbo needs to be decorated with @SPI annotation. - -```java -@SPI -public interface DemoSpi { - void say(); -} - -public class DemoSpiImpl implements DemoSpi { - public void say() { - } -} -``` - -#### 3.1.2 Put the implementation class in a specific directory - -From the above code, we can see that when dubbo loads the extension class, it will read from four directories. We create a new file named after the DemoSpi interface in the META-INF/dubbo directory, the content is as follows: - - -```text -demoSpiImpl = com.xxx.xxx.DemoSpiImpl (full class name for the implementation class of the DemoSpi interface) -``` - -#### 3.1.3 Use - -```java -public class DubboSPITest { - - @Test - public void sayHello() throws Exception { - ExtensionLoader extensionLoader = - ExtensionLoader. getExtensionLoader(DemoSpi. class); - DemoSpi dmeoSpi = extensionLoader. getExtension("demoSpiImpl"); - optimusPrime. sayHello(); - } -} -``` - -### 3.2 Load adaptive extension class - -This takes Protocol as an example to illustrate - -### 3.2.1 Protocol interface (extract some core methods) - -```java -@SPI("dubbo") -public interface Protocol { - @Adaptive - Exporter export(Invoker invoker) throws RpcException; - - @Adaptive - Invoker refer(Class type, URL url) throws RpcException; -} - -public class DubboProtocol extends AbstractProtocol { -  … - @Override - public Invoker refer(Class type, URL url) throws RpcException { - return protocolBindingRefer(type, url); - } - - @Override - public Exporter export(Invoker invoker) throws RpcException { -  … - return exporter; - } -} -``` - -### 3.2.2 Put the implementation class in a specific directory -In dubbo, the configuration path is META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol -```text -dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol -``` - -It should be noted that in dubbo, DubboProtocol is not used directly, but its wrapper class is used. - -### 3.2.3 Use - -```java -public class DubboAdaptiveTest { - - @Test - public void sayHello() throws Exception { - URL url = URL.valueOf("dubbo://localhost/test"); - Protocol adaptiveProtocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); - adaptiveProtocol. refer(type, url); - } -} -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/exchanger.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/exchanger.md deleted file mode 100644 index ab59dc011d58..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/exchanger.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -type: docs -title: "Information Exchange Extension" -linkTitle: "Information exchange extension" -weight: 18 ---- - -## Expansion Description - -Based on the transport layer, implement the Request-Response information exchange semantics. - -## Extension ports - -* `org.apache.dubbo.remoting.exchange.Exchanger` -* `org.apache.dubbo.remoting.exchange.ExchangeServer` -* `org.apache.dubbo.remoting.exchange.ExchangeClient` - -## Extended configuration - -```xml - - - -``` - -## Known extensions - -`org.apache.dubbo.remoting.exchange.exchanger.HeaderExchanger` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxExchanger.java (implements the Exchanger interface) - |-XxxExchangeServer.java (implements ExchangeServer interface) - |-XxxExchangeClient.java (implements ExchangeClient interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.remoting.exchange.Exchanger (plain text file, content: xxx=com.xxx.XxxExchanger) -``` - -XxxExchanger.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.exchange.Exchanger; - - -public class XxxExchanger implements Exchanger { - public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException { - return new XxxExchangeServer(url, handler); - } - public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException { - return new XxxExchangeClient(url, handler); - } -} -``` - -XxxExchangeServer.java: - -```java - -package com.xxx; - -import org.apache.dubbo.remoting.exchange.ExchangeServer; - -public class XxxExchangeServer impelements ExchangeServer { - //... -} -``` - -XxxExchangeClient.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.exchange.ExchangeClient; - -public class XxxExchangeClient impelments ExchangeClient { - //... -} -``` - -META-INF/dubbo/org.apache.dubbo.remoting.exchange.Exchanger: - -```properties -xxx=com.xxx.XxxExchanger -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/exporter-listener.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/exporter-listener.md deleted file mode 100644 index 80a0f2bb85c8..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/exporter-listener.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -type: docs -title: "Expose Listener Extension" -linkTitle: "Expose listener extension" -weight: 4 ---- - -## Expansion Description - -This event is triggered when a service is exposed. - -## Extension ports - -`org.apache.dubbo.rpc.ExporterListener` - -## Extended configuration - -```xml - - - - -``` - -## Known extensions - -`org.apache.dubbo.registry.directory.RegistryExporterListener` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxExporterListener.java (implements ExporterListener interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.ExporterListener (plain text file, content: xxx=com.xxx.XxxExporterListener) -``` - -XxxExporterListener.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.ExporterListener; -import org.apache.dubbo.rpc.Exporter; -import org.apache.dubbo.rpc.RpcException; - - -public class XxxExporterListener implements ExporterListener { - public void exported(Exporter exporter) throws RpcException { - //... - } - public void unexported(Exporter exporter) throws RpcException { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.ExporterListener: - -```properties -xxx=com.xxx.XxxExporterListener -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/extension-factory.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/extension-factory.md deleted file mode 100644 index fa38be8d45ff..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/extension-factory.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -type: docs -title: "Extension Point Load Extension" -linkTitle: "Extension point load extension" -weight: 11 ---- - -## Expansion Description - -The loading container of the extension point itself, which can load the extension point from different containers. - -## Extension ports - -`org.apache.dubbo.common.extension.ExtensionFactory` - -## Extended configuration - -```xml - -``` - -## Known extensions - -* `org.apache.dubbo.common.extension.factory.SpiExtensionFactory` -* `org.apache.dubbo.config.spring.extension.SpringExtensionFactory` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxExtensionFactory.java (implements ExtensionFactory interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.common.extension.ExtensionFactory (plain text file, content: xxx=com.xxx.XxxExtensionFactory) -``` - -XxxExtensionFactory.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.extension.ExtensionFactory; - -public class XxxExtensionFactory implements ExtensionFactory { - public Object getExtension(Class type, String name) { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.common.extension.ExtensionFactory: - -```properties -xxx=com.xxx.XxxExtensionFactory -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/filter.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/filter.md deleted file mode 100644 index a6481670a72a..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/filter.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -type: docs -title: "Call Intercept Extension" -linkTitle: "Call Intercept Extension" -weight: 2 ---- - -## Expansion Description - -Service provider and service consumer call process interception. Most functions of Dubbo itself are implemented based on this extension point. Every time a remote method is executed, this interception will be executed. Please pay attention to the impact on performance. - -agreement: - -* User-defined filters are by default after built-in filters. -* The special value `default`, indicating where the default extension point is inserted. For example: `filter="xxx,default,yyy"`, means `xxx` is before the default filter, and `yyy` is after the default filter. -* The special symbol `-` means culling. For example: `filter="-foo1"`, exclude adding the default extension point `foo1`. For example: `filter="-default"`, remove all default extension points. -* When the provider and service configure filters at the same time, all filters are accumulated instead of overwritten. For example: `` and ``, then `xxx`,`yyy`,`aaa`,`bbb` will take effect. If you want to overwrite, you need to configure: `` - -## Extension ports - -`org.apache.dubbo.rpc.Filter` - -## Extended configuration - -```xml - - - - - - - - -``` - -## Known extensions - -* `org.apache.dubbo.rpc.filter.EchoFilter` -* `org.apache.dubbo.rpc.filter.GenericFilter` -* `org.apache.dubbo.rpc.filter.GenericImplFilter` -* `org.apache.dubbo.rpc.filter.TokenFilter` -* `org.apache.dubbo.rpc.filter.AccessLogFilter` -* `org.apache.dubbo.rpc.filter.CountFilter` -* `org.apache.dubbo.rpc.filter.ActiveLimitFilter` -* `org.apache.dubbo.rpc.filter.ClassLoaderFilter` -* `org.apache.dubbo.rpc.filter.ContextFilter` -* `org.apache.dubbo.rpc.filter.ConsumerContextFilter` -* `org.apache.dubbo.rpc.filter.ExceptionFilter` -* `org.apache.dubbo.rpc.filter.ExecuteLimitFilter` -* `org.apache.dubbo.rpc.filter.DeprecatedFilter` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxFilter.java (implement the Filter interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.Filter (plain text file, content: xxx=com.xxx.XxxFilter) -``` - -XxxFilter.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.Filter; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.Invocation; -import org.apache.dubbo.rpc.Result; -import org.apache.dubbo.rpc.RpcException; - -public class XxxFilter implements Filter { - public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - // before filter... - Result result = invoker.invoke(invocation); - // after filter... - return result; - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.Filter: - -```properties -xxx=com.xxx.XxxFilter -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/invoker-listener.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/invoker-listener.md deleted file mode 100644 index d1f600ec93b0..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/invoker-listener.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -type: docs -title: "Reference Listener Extension" -linkTitle: "Reference listener extension" -weight: 3 ---- - -## Expansion Description - -This event is triggered when there is a service reference. - -## Extension ports - -`org.apache.dubbo.rpc.InvokerListener` - -## Extended configuration - -```xml - - - - -``` - -## Known extensions - -`org.apache.dubbo.rpc.listener.DeprecatedInvokerListener` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxInvokerListener.java (implements the InvokerListener interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.InvokerListener (plain text file, content: xxx=com.xxx.XxxInvokerListener) -``` - -XxxInvokerListener.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.InvokerListener; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.RpcException; - -public class XxxInvokerListener implements InvokerListener { - public void referred(Invoker invoker) throws RpcException { - //... - } - public void destroyed(Invoker invoker) throws RpcException { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.InvokerListener: - -```properties -xxx=com.xxx.XxxInvokerListener -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/liveness.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/liveness.md deleted file mode 100644 index b4ba1f71b600..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/liveness.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -type: docs -title: "Liveness Survival Probe" -linkTitle: "Survival Probe" -weight: 12 ---- - -## Expansion Description - - -Expand the detection point of application survival. - - -## Extension ports - - -`org.apache.dubbo.qos.probe.LivenessProbe` - - -## Extended configuration - - -Dubbo QOS `live` command automatic discovery - - -## Known extensions - - -No default implementation yet - - -## Extended example - - -Maven project structure: - - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxLivenessProbe.java (implement LivenessProbe interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.qos.probe.LivenessProbe (plain text file, content: xxx=com.xxx.XxxLivenessProbe) -``` - - -XxxLivenessProbe.java: - - -```java -package com.xxx; - -public class XxxLivenessProbe implements LivenessProbe { - - public boolean check() { - //... - } -} -``` - - -META-INF/dubbo/org.apache.dubbo.qos.probe.LivenessProbe: - - -``` -xxx=com.xxx.XxxLivenessProbe -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/load-balance.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/load-balance.md deleted file mode 100644 index c4c880b83bf9..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/load-balance.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -type: docs -title: "Load Balancing Extension" -linkTitle: "Load Balancing Extension" -weight: 7 ---- - -## Expansion Description - -Select one of multiple service providers to call - -## Extension ports - -`org.apache.dubbo.rpc.cluster.LoadBalance` - -## Extended configuration - -```xml - - - -``` - -## Known extensions - -* `org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance` -* `org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance` -* `org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance` -* `org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance` -* `org.apache.dubbo.rpc.cluster.loadbalance.ShortestResponseLoadBalance` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxLoadBalance.java (implements the LoadBalance interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.cluster.LoadBalance (plain text file, content: xxx=com.xxx.XxxLoadBalance) -``` - -XxxLoadBalance.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.cluster.LoadBalance; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.Invocation; -import org.apache.dubbo.rpc.RpcException; - -public class XxxLoadBalance implements LoadBalance { - public Invoker select(List> invokers, Invocation invocation) throws RpcException { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.cluster.LoadBalance: - -```properties -xxx=com.xxx.XxxLoadBalance -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/logger-adapter.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/logger-adapter.md deleted file mode 100644 index 34346c83149a..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/logger-adapter.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -type: docs -title: "Log Adaptation Extension" -linkTitle: "Log adaptation extension" -weight: 26 ---- - -## Expansion Description - -Log output adaptation extension point. - -## Extension ports - -`org.apache.dubbo.common.logger.LoggerAdapter` - -## Extended configuration - -```xml - -``` - -or: - -```sh --Ddubbo:application.logger=xxx -``` - -## Known extensions - -* `org.apache.dubbo.common.logger.slf4j.Slf4jLoggerAdapter` -* `org.apache.dubbo.common.logger.jcl.JclLoggerAdapter` -* `org.apache.dubbo.common.logger.log4j.Log4jLoggerAdapter` -* `org.apache.dubbo.common.logger.log4j2.Log4j2LoggerAdapter` -* `org.apache.dubbo.common.logger.jdk.JdkLoggerAdapter` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxLoggerAdapter.java (implement LoggerAdapter interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.common.logger.LoggerAdapter (plain text file, content: xxx=com.xxx.XxxLoggerAdapter) -``` - -XxxLoggerAdapter.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.logger.LoggerAdapter; - -public class XxxLoggerAdapter implements LoggerAdapter { - public Logger getLogger(URL url) { - //... - } -} -``` - -XxxLogger.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.logger.Logger; - -public class XxxLogger implements Logger { - public XxxLogger(URL url) { - //... - } - public void info(String msg) { - //... - } - //... -} -``` - -META-INF/dubbo/org.apache.dubbo.common.logger.LoggerAdapter: - -```properties -xxx=com.xxx.XxxLoggerAdapter -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/merger.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/merger.md deleted file mode 100644 index e6f489cac6e9..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/merger.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -type: docs -title: "Merge result extension" -linkTitle: "Merge result extension" -weight: 8 ---- - -## Expansion Description - -Merge returns results for grouping and aggregation. - -## Extension ports - -`org.apache.dubbo.rpc.cluster.Merger` - -## Extended configuration - -```xml - -``` - -## Known extensions - -* `org.apache.dubbo.rpc.cluster.merger.ArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.ListMerger` -* `org.apache.dubbo.rpc.cluster.merger.SetMerger` -* `org.apache.dubbo.rpc.cluster.merger.MapMerger` -* `org.apache.dubbo.rpc.cluster.merger.ByteArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.CharArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.ShortArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.IntArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.LongArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.FloatArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.DoubleArrayMerger` -* `org.apache.dubbo.rpc.cluster.merger.BooleanArrayMerger` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxMerger.java (implement Merger interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.cluster.Merger (plain text file, content: xxx=com.xxx.XxxMerger) -``` - -XxxMerger.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.cluster.Merger; - -public class XxxMerger implements Merger { - public T merge(T... results) { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.cluster.Merger: - -```properties -xxx=com.xxx.XxxMerger -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/metadata-report.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/metadata-report.md deleted file mode 100644 index a8ad57bc61b5..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/metadata-report.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -type: docs -title: "Metadata Center Extension" -linkTitle: "Metadata Center Extension" -weight: 13 ---- - -## aim of design -See the [Metadata Center Manual](../../../metadata-center/overview/) - -## Extension ports - -* `org.apache.dubbo.metadata.store.MetadataReportFactory` -* `org.apache.dubbo.metadata.store.MetadataReport` - -## Known extensions - -## Implementation principle - -### SPI definition - -Reference: org.apache.dubbo.metadata.store.MetadataReportFactory, org.apache.dubbo.metadata.store.MetadataReport - -```java -@SPI("redis") -public interface MetadataReportFactory { - @Adaptive({"protocol"}) - MetadataReport getMetadataReport(URL url); -} -``` - - - -### Custom metadata storage - -The following uses Redis storage as an example for illustration. - -To create a new project, you need to support the following modifications: - -#### Extend AbstractMetadataReport - -```java -public class RedisMetadataReport extends AbstractMetadataReport { - private final static Logger logger = LoggerFactory. getLogger(RedisMetadataReport. class); - final JedisPool pool; - - public RedisMetadataReport(URL url) { - super(url); - pool = new JedisPool(new JedisPoolConfig(), url. getHost(), url. getPort()); - } - @Override - protected void doStoreProviderMetadata(ProviderMetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) { - this.storeMetadata(providerMetadataIdentifier, serviceDefinitions); - } - @Override - protected void doStoreConsumerMetadata(ConsumerMetadataIdentifier consumerMetadataIdentifier, String value) { - this.storeMetadata(consumerMetadataIdentifier, value); - } - private void storeMetadata(MetadataIdentifier metadataIdentifier, String v) { - try (Jedis jedis = pool. getResource()) { - jedis.set(metadataIdentifier.getIdentifierKey() + META_DATA_SOTRE_TAG, v); - } catch (Throwable e) { - logger.error("Failed to put " + metadataIdentifier + " to redis " + v + ", cause: " + e.getMessage(), e); - throw new RpcException("Failed to put " + metadataIdentifier + " to redis " + v + ", cause: " + e.getMessage(), e); - } - } -} -``` - -#### Extends AbstractMetadataReportFactory - -```java -public class RedisMetadataReportFactory extends AbstractMetadataReportFactory { - @Override - public MetadataReport createMetadataReport(URL url) { - return new RedisMetadataReport(url); - } -} -``` - -#### Add MetadataReportFactory - -> META-INF/dubbo/internal/org.apache.dubbo.metadata.store.MetadataReportFactory - -```properties -redis=org.apache.dubbo.metadata.store.redis.RedisMetadataReportFactory -``` - -Just pack the above modification and project into a jar package, and then configure the url of the metadata center: redis://10.20.153.10:6379. - -At this point, a custom metadata store is ready to run. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/monitor.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/monitor.md deleted file mode 100644 index 3aab26c04561..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/monitor.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -type: docs -title: "Monitoring Center Extension" -linkTitle: "Monitoring Center Extension" -weight: 10 ---- - -## Expansion Description - -Responsible for the monitoring of service call times and call time. - -## Extension ports - -* `org.apache.dubbo.monitor.MonitorFactory` -* `org.apache.dubbo.monitor.Monitor` - -## Extended configuration - -```xml - - -``` - -## Known extensions - -org.apache.dubbo.monitor.support.dubbo.DubboMonitorFactory - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxMonitorFactoryjava (implement the MonitorFactory interface) - |-XxxMonitor.java (implement Monitor interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.monitor.MonitorFactory (plain text file, content: xxx=com.xxx.XxxMonitorFactory) -``` - -XxxMonitorFactory.java: - -```java -package com.xxx; - -import org.apache.dubbo.monitor.MonitorFactory; -import org.apache.dubbo.monitor.Monitor; -import org.apache.dubbo.common.URL; - -public class XxxMonitorFactory implements MonitorFactory { - public Monitor getMonitor(URL url) { - return new XxxMonitor(url); - } -} -``` - -XxxMonitor.java: - -```java -package com.xxx; - -import org.apache.dubbo.monitor.Monitor; - -public class XxxMonitor implements Monitor { - public void count(URL statistics) { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.monitor.MonitorFactory: - -```properties -xxx=com.xxx.XxxMonitorFactory -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/networker.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/networker.md deleted file mode 100644 index 24f4163f80df..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/networker.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -type: docs -title: "Network Expansion" -linkTitle: "Network Expansion" -weight: 19 ---- - -## Expansion Description - -Peer-to-peer network node builder. - -## Extension ports - -`org.apache.dubbo.remoting.p2p.Networker` - -## Extended configuration - -```xml - - - -``` - -## Known extensions - -* `org.apache.dubbo.remoting.p2p.support.MulticastNetworker` -* `org.apache.dubbo.remoting.p2p.support.FileNetworker` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxNetworker.java (implement Networker interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.remoting.p2p.Networker (plain text file, content: xxx=com.xxx.XxxNetworker) -``` - -XxxNetworker.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.p2p.Networker; - -public class XxxNetworker implements Networker { - public Group lookup(URL url) { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.remoting.p2p.Networker: - -```properties -xxx=com.xxx.XxxNetworker -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/page.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/page.md deleted file mode 100644 index c6db0234244a..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/page.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -type: docs -title: "Peer-to-peer network node builder extension" -linkTitle: "Peer-to-peer network node builder extension" -weight: 19 ---- - -# page extension - -## Expansion Description - -Peer-to-peer network node builder. - -## Extension ports - -`org.apache.dubbo.container.page.PageHandler` - -## Extended configuration - -```xml - - - -``` - -## Known extensions - -* `org.apache.dubbo.container.page.pages.HomePageHandler` -* `org.apache.dubbo.container.page.pages.StatusPageHandler` -* `org.apache.dubbo.container.page.pages.LogPageHandler` -* `org.apache.dubbo.container.page.pages.SystemPageHandler` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxPageHandler.java (implement PageHandler interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.container.page.PageHandler (plain text file, content: xxx=com.xxx.XxxPageHandler) -``` - -XxxPageHandler.java: - -```java -package com.xxx; - -import org.apache.dubbo.container.page.PageHandler; - -public class XxxPageHandler implements PageHandler { - public Group lookup(URL url) { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.container.page.PageHandler: - -```properties -xxx=com.xxx.XxxPageHandler -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/protocol.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/protocol.md deleted file mode 100644 index e37114fe9d87..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/protocol.md +++ /dev/null @@ -1,158 +0,0 @@ ---- -type: docs -title: "Protocol Extension" -linkTitle: "Protocol Extension" -weight: 1 ---- - -## Expansion Description - -RPC protocol extension, encapsulates remote call details. - -contract: - -* When the user calls the `invoke()` method of the `Invoker` object returned by `refer()`, the protocol needs to execute the `invoke()` of the `Invoker` object passed in from the remote `export()` of the URL accordingly ` method. -* Among them, the `Invoker` returned by `refer()` is implemented by the protocol, and the protocol usually needs to send a remote request in this `Invoker`, and the `Invoker` passed in by `export()` is implemented and passed in by the framework, and the protocol does not need to care. - -Notice: - -* The protocol does not care about the transparent proxy of the business interface, with `Invoker` as the center, and the outer layer converts `Invoker` into a business interface. -* The protocol does not have to be TCP network communication, such as through shared files, IPC inter-process communication, etc. - -## Extension ports - -* `org.apache.dubbo.rpc.Protocol` -* `org.apache.dubbo.rpc.Exporter` -* `org.apache.dubbo.rpc.Invoker` - -```java -public interface Protocol { - /** - * Expose remote services:
- * 1. When receiving a request, the protocol should record the request source address information: RpcContext.getContext().setRemoteAddress();
- * 2. export() must be idempotent, that is, exposing the Invoker of the same URL twice is no different from exposing it once.
- * 3. The Invoker passed in by export() is implemented and passed in by the framework, and the protocol does not need to care.
- * - * @param type of service - * @param invoker service execution body - * @return exporter The reference of the exposed service, used to cancel the exposure - * @throws RpcException Throws when there is an error in the exposed service, such as the port is already occupied - */ - Exporter export(Invoker invoker) throws RpcException; - - /** - * Quoting remote services:
- * 1. When the user calls the invoke() method of the Invoker object returned by refer(), the protocol needs to correspondingly execute the invoke() method of the Invoker object passed in from the URL remote export().
- * 2. The Invoker returned by refer() is implemented by the protocol, and the protocol usually needs to send a remote request in this Invoker.
- * 3. When check=false is set in the url, an exception cannot be thrown if the connection fails, and internal automatic recovery is required.
- * - * @param type of service - * @param type service type - * @param url URL address of the remote service - * @return The local proxy for the invoker service - * @throws RpcException thrown when the connection to the service provider fails - */ - Invoker refer(Class type, URL url) throws RpcException; - -} -``` - -## Extended configuration - -```xml - - - - - - -``` - -## Known extensions - -* `org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol` -* `org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol` -* `org.apache.dubbo.rpc.protocol.rmi.RmiProtocol` -* `org.apache.dubbo.rpc.protocol.http.HttpProtocol` -* `org.apache.dubbo.rpc.protocol.http.hessian.HessianProtocol` -* `org.apache.dubbo.rpc.support.MockProtocol` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxProtocol.java (implement the Protocol interface) - |-XxxExporter.java (implements the Exporter interface) - |-XxxInvoker.java (implements the Invoker interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.Protocol (plain text file, content: xxx=com.xxx.XxxProtocol) -``` - -XxxProtocol.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.Protocol; - -public class XxxProtocol implements Protocol { - public Exporter export(Invoker invoker) throws RpcException { - return new XxxExporter(invoker); - } - public Invoker refer(Class type, URL url) throws RpcException { - return new XxxInvoker(type, url); - } -} -``` - -XxxExporter.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.support.AbstractExporter; - -public class XxxExporter extends AbstractExporter { - public XxxExporter(Invoker invoker) throws RemotingException{ - super(invoker); - //... - } - public void unexport() { - super. unexport(); - //... - } -} -``` - -XxxInvoker.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.support.AbstractInvoker; - -public class XxxInvoker extends AbstractInvoker { - public XxxInvoker(Class type, URL url) throws RemotingException{ - super(type, url); - } - - @Override - protected Result doInvoke(Invocation invocation) throws Throwable { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.Protocol: - -```properties -xxx=com.xxx.XxxProtocol -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/proxy-factory.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/proxy-factory.md deleted file mode 100644 index 7e9bd5d11af5..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/proxy-factory.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -type: docs -title: "Dynamic Proxy Extension" -linkTitle: "Dynamic proxy extension" -weight: 12 ---- - -## Expansion Description - -Convert the `Invoker` interface into a business interface. - -## Extension ports - -`org.apache.dubbo.rpc.ProxyFactory` - -## Extended configuration - -```xml - - - -``` - -## Known extensions - -* `org.apache.dubbo.rpc.proxy.JdkProxyFactory` -* `org.apache.dubbo.rpc.proxy.JavassistProxyFactory` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxProxyFactory.java (implement ProxyFactory interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.ProxyFactory (plain text file, content: xxx=com.xxx.XxxProxyFactory) -``` - -XxxProxyFactory.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.ProxyFactory; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.RpcException; - - -public class XxxProxyFactory implements ProxyFactory { - public T getProxy(Invoker invoker) throws RpcException { - //... - } - public Invoker getInvoker(T proxy, Class type, URL url) throws RpcException { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.ProxyFactory: - -```properties -xxx=com.xxx.XxxProxyFactory -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/qos-permission.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/qos-permission.md deleted file mode 100644 index 90e840c21cd8..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/qos-permission.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -type: docs -title: "QoS Anonymous Access Verification Extension" -linkTitle: "QoS Anonymous Access Verification Extension" -weight: 27 ---- - -## Expansion Description - -QoS anonymous access authentication extension point. - -## Extension ports - -`org.apache.dubbo.qos.permission.PermissionChecker` - -## Extended configuration - - -Dubbo QoS `dubbo.application.qos-anonymous-access-permission-level` Anonymous access permission verification. - -## Default implementation - -`org.apache.dubbo.qos.permission.DefaultAnonymousAccessPermissionChecker` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxPermissionChecker.java (implements PermissionChecker interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.qos.permission.PermissionChecker` (plain text file, content: qosPermissionChecker=com.xxx.XxxPermissionChecker) -``` - -XxxPermissionChecker.java: - -```java -package com.xxx.qos.permission; - -import org.apache.dubbo.qos.permission.PermissionChecker; - -public class XxxAnonymousAccessPermissionChecker implements PermissionChecker { - - @Override - public boolean access(CommandContext commandContext, PermissionLevel defaultCmdRequiredPermissionLevel) { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.qos.permission.PermissionChecker: - -```properties -qosPermissionChecker=com.xxx.XxxPermissionChecker -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/readiness.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/readiness.md deleted file mode 100644 index f26c42fdf40a..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/readiness.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -type: docs -title: "Readiness Probe" -linkTitle: "Readiness Probe" -weight: 12 ---- - -## Expansion Description - - -Extend the detection points of application readiness. - - -## Extension ports - - -`org.apache.dubbo.qos.probe.ReadinessProbe` - - -## Extended configuration - - -Dubbo QOS `ready` command auto-discovery - - -## Known extensions - - -- `org.apache.dubbo.qos.probe.impl.BootstrapReadinessProbe` -- `org.apache.dubbo.qos.probe.impl.ProviderReadinessProbe` - - - -## Extended example - - -Maven project structure: - - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxReadinessProbe.java (implements ReadinessProbe interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.qos.probe.ReadinessProbe (plain text file, content: xxx=com.xxx.XxxReadinessProbe) -``` - - -XxxReadinessProbe.java: - - -```java -package com.xxx; - -public class XxxReadinessProbe implements ReadinessProbe { - - public boolean check() { - //... - } -} -``` - - -META-INF/dubbo/org.apache.dubbo.qos.probe.ReadinessProbe: - - -``` -xxx=com.xxx.XxxReadinessProbe -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/registry.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/registry.md deleted file mode 100644 index d4b26daac4c5..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/registry.md +++ /dev/null @@ -1,210 +0,0 @@ ---- -type: docs -title: "Registry Extension" -linkTitle: "Registry Extension" -weight: 9 ---- - -## Expansion Description - -Responsible for service registration and discovery. - -## Extension ports - -* `org.apache.dubbo.registry.RegistryFactory` -* `org.apache.dubbo.registry.Registry` - -## Extended configuration - -```xml - - - - - - -``` - -## Extension contract - -RegistryFactory.java: - -```java -public interface RegistryFactory { - /** - * Connect to the registration center. - * - * The connection to the registration center needs to deal with the contract:
- * 1. When check=false is set, it means that the connection will not be checked, otherwise an exception will be thrown when the connection fails.
- * 2. Support username:password authority authentication on the URL.
- * 3. Support backup=10.20.153.10 alternative registration center cluster address.
- * 4. Support file=registry.cache local disk file cache.
- * 5. Support timeout=1000 request timeout setting.
- * 6. Support session=60000 session timeout or expiration setting.
- * - * @param url Registry address, not allowed to be empty - * @return Registry reference, never return empty - */ - Registry getRegistry(URL url); -} -``` - -RegistryService.java: - -```java -public interface RegistryService { // Registry extends RegistryService - /** - * Registration service. - * - * Registration requires processing contract:
- * 1. When the URL is set to check=false, no error will be reported after the registration fails, and it will be retried regularly in the background, otherwise an exception will be thrown.
- * 2. When the dynamic=false parameter is set in the URL, it needs to be stored persistently. Otherwise, when the registrant exits abnormally due to power failure, etc., it needs to be automatically deleted.
- * 3. When category=overrides is set in the URL, it means classified storage, the default category is providers, and the data can be notified by category.
- * 4. When the registration center restarts and the network fluctuates, data cannot be lost, including automatic deletion of data when disconnected.
- * 5. URLs with the same URI but different parameters are allowed to coexist, and cannot be overwritten.
- * - * @param url Registration information, not allowed to be empty, such as: dubbo://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin - */ - void register(URL url); - - /** - * Unregister service. - * - * Cancellation of registration needs to deal with the contract:
- * 1. If it is persistent storage data with dynamic=false and registration data cannot be found, throw IllegalStateException, otherwise ignore it.
- * 2. Cancel registration by full URL matching.
- * - * @param url Registration information, not allowed to be empty, such as: dubbo://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin - */ - void unregister(URL url); - - /** - * Subscription service. - * - * Subscription requires processing contract:
- * 1. When the URL is set to check=false, no error will be reported after the subscription fails, and it will be retried periodically in the background.
- * 2. When category=overrides is set in the URL, only the data of the specified category will be notified. Multiple categories are separated by commas, and wildcards of asterisks are allowed, which means to subscribe to all category data.
- * 3. It is allowed to use interface, group, version, classifier as conditional query, such as: interface=com.alibaba.foo.BarService&version=1.0.0
- * 4. And the query condition allows asterisk wildcards, subscribe to all versions of all groups of all interfaces, or: interface=*&group=*&version=*&classifier=*
- * 5. When the registration center restarts and the network fluctuates, the subscription request needs to be automatically resumed.
- * 6. URLs with the same URI but different parameters are allowed to coexist, and cannot be overwritten.
- * 7. The subscription process must be blocked, and return after the first notification.
- * - * @param url subscription condition, not allowed to be empty, such as: consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin - * @param listener Change event listener, not allowed to be empty - */ - void subscribe(URL url, NotifyListener listener); - - /** - * Unsubscribe service. - * - * Unsubscribing requires processing contract:
- * 1. If there is no subscription, just ignore it.
- * 2. Unsubscribe by full URL match.
- * - * @param url subscription condition, not allowed to be empty, such as: consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin - * @param listener Change event listener, not allowed to be empty - */ - void unsubscribe(URL url, NotifyListener listener); - - /** - * Query the registration list, corresponding to the push mode of subscription, here is the pull mode, and the result is returned only once. - * - * @see org.apache.dubbo.registry.NotifyListener#notify(List) - * @param url query condition, not allowed to be empty, such as: consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin - * @return The registered information list, which may be empty, has the same meaning as the parameter of {@link org.apache.dubbo.registry.NotifyListener#notify(List)}. - */ - List lookup(URL url); - -} -``` - -NotifyListener.java: - -```java -public interface NotifyListener { - /** - * Triggered when a service change notification is received. - * - * Notice to process contract:
- * 1. The full notification is always based on the service interface and data type, that is, the partial data of the same type of a service will not be notified, and the user does not need to compare the results of the previous notification.
- * 2. The first notification when subscribing must be a full notification of all types of data for a service.
- * 3. When changing midway, different types of data are allowed to be notified separately, such as: providers, consumers, routes, overrides, and only one type is allowed to be notified, but the data of this type must be full, not incremental.
- * 4. If one type of data is empty, it is necessary to notify an empty protocol and identification URL data with category parameter.
- * 5. The notifier (that is, the registration center implementation) needs to ensure the order of notifications, such as: single-threaded push, queue serialization, and version comparison.
- * - * @param urls Registered information list, always not empty, the meaning is the same as the return value of {@link org.apache.dubbo.registry.RegistryService#lookup(URL)}. - */ - void notify(List urls); - -} -``` - -## Known extensions - -`org.apache.dubbo.registry.support.dubbo.DubboRegistryFactory` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxRegistryFactoryjava (implements RegistryFactory interface) - |-XxxRegistry.java (implement Registry interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.registry.RegistryFactory (plain text file, content: xxx=com.xxx.XxxRegistryFactory) -``` - -XxxRegistryFactory.java: - -```java -package com.xxx; - -import org.apache.dubbo.registry.RegistryFactory; -import org.apache.dubbo.registry.Registry; -import org.apache.dubbo.common.URL; - -public class XxxRegistryFactory implements RegistryFactory { - public Registry getRegistry(URL url) { - return new XxxRegistry(url); - } -} -``` - -XxxRegistry.java: - -```java -package com.xxx; - -import org.apache.dubbo.registry.Registry; -import org.apache.dubbo.registry.NotifyListener; -import org.apache.dubbo.common.URL; - -public class XxxRegistry implements Registry { - public void register(URL url) { - //... - } - public void unregister(URL url) { - //... - } - public void subscribe(URL url, NotifyListener listener) { - //... - } - public void unsubscribe(URL url, NotifyListener listener) { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.registry.RegistryFactory: - -```properties -xxx=com.xxx.XxxRegistryFactory -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/remoting.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/remoting.md deleted file mode 100644 index 1beb8b4a2092..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/remoting.md +++ /dev/null @@ -1,127 +0,0 @@ ---- -type: docs -title: "Network Transport Extension" -linkTitle: "Network Transport Extension" -weight: 17 ---- - -## Expansion Description - -Realization of remote communication server and client transmission. - -## Extension ports - -* `org.apache.dubbo.remoting.Transporter` -* `org.apache.dubbo.remoting.Server` -* `org.apache.dubbo.remoting.Client` - -## Extended configuration - -```xml - - - - - - -``` - -## Known extensions - -* `org.apache.dubbo.remoting.transport.transporter.netty.NettyTransporter` -* `org.apache.dubbo.remoting.transport.transporter.mina.MinaTransporter` -* `org.apache.dubbo.remoting.transport.transporter.grizzly.GrizzlyTransporter` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxTransporter.java (implements the Transporter interface) - |-XxxServer.java (implement Server interface) - |-XxxClient.java (implement Client interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.remoting.Transporter (plain text file, content: xxx=com.xxx.XxxTransporter) -``` - -XxxTransporter.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.Transporter; - -public class XxxTransporter implements Transporter { - public Server bind(URL url, ChannelHandler handler) throws RemotingException { - return new XxxServer(url, handler); - } - public Client connect(URL url, ChannelHandler handler) throws RemotingException { - return new XxxClient(url, handler); - } -} -``` - -XxxServer.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.transport.transporter.AbstractServer; - -public class XxxServer extends AbstractServer { - public XxxServer(URL url, ChannelHandler handler) throws RemotingException{ - super(url, handler); - } - protected void doOpen() throws Throwable { - //... - } - protected void doClose() throws Throwable { - //... - } - public Collection getChannels() { - //... - } - public Channel getChannel(InetSocketAddress remoteAddress) { - //... - } -} -``` - -XxxClient.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.transport.transporter.AbstractClient; - -public class XxxClient extends AbstractClient { - public XxxServer(URL url, ChannelHandler handler) throws RemotingException{ - super(url, handler); - } - protected void doOpen() throws Throwable { - //... - } - protected void doClose() throws Throwable { - //... - } - protected void doConnect() throws Throwable { - //... - } - public Channel getChannel() { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.remoting.Transporter: - -```properties -xxx=com.xxx.XxxTransporter -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/router.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/router.md deleted file mode 100644 index 73a71eb3b1a5..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/router.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -type: docs -title: "Route Extension" -linkTitle: "Routing Extension" -weight: 6 ---- - -## Expansion Description - -Select one of multiple service providers to call. - -## Extension ports - -* `org.apache.dubbo.rpc.cluster.RouterFactory` -* `org.apache.dubbo.rpc.cluster.Router` - -## Known extensions - -* `org.apache.dubbo.rpc.cluster.router.ScriptRouterFactory` -* `org.apache.dubbo.rpc.cluster.router.FileRouterFactory` -* `org.apache.dubbo.rpc.cluster.router.condition.config.AppRouterFactory` -* `org.apache.dubbo.rpc.cluster.CacheableRouterFactory` -* `org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory` -* `org.apache.dubbo.rpc.cluster.router.mock.MockRouterFactory` -* `org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouterFactory` -* `org.apache.dubbo.rpc.cluster.router.tag.TagRouterFactory` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxRouterFactory.java (implements RouterFactory interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.rpc.cluster.RouterFactory (plain text file, content: xxx=com.xxx.XxxRouterFactory) - -``` - -XxxRouterFactory.java: - -```java -package com.xxx; - -import org.apache.dubbo.rpc.cluster.RouterFactory; -import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.Invocation; -import org.apache.dubbo.rpc.RpcException; - -public class XxxRouterFactory implements RouterFactory { - public Router getRouter(URL url) { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.rpc.cluster.RouterFactory: - -```properties -xxx=com.xxx.XxxRouterFactory -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/serialize.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/serialize.md deleted file mode 100644 index 1b2e955bf04e..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/serialize.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -type: docs -title: "Serialization Extension" -linkTitle: "Serialization Extension" -weight: 16 ---- - -## Expansion Description - -Convert the object into a byte stream for network transmission, and convert the byte stream into an object for restoring the byte stream data into an object. - -## Extension ports - -* `org.apache.dubbo.common.serialize.Serialization` -* `org.apache.dubbo.common.serialize.ObjectInput` -* `org.apache.dubbo.common.serialize.ObjectOutput` - -## Extended configuration - -```xml - - - - -``` - -## Known extensions - -* `org.apache.dubbo.common.serialize.dubbo.DubboSerialization` -* `org.apache.dubbo.common.serialize.hessian.Hessian2Serialization` -* `org.apache.dubbo.common.serialize.java.JavaSerialization` -* `org.apache.dubbo.common.serialize.java.CompactedJavaSerialization` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxSerialization.java (implements the Serialization interface) - |-XxxObjectInput.java (implement ObjectInput interface) - |-XxxObjectOutput.java (implement ObjectOutput interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.common.serialize.Serialization (plain text file, content: xxx=com.xxx.XxxSerialization) -``` - -XxxSerialization.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.serialize.Serialization; -import org.apache.dubbo.common.serialize.ObjectInput; -import org.apache.dubbo.common.serialize.ObjectOutput; - - -public class XxxSerialization implements Serialization { - public ObjectOutput serialize(Parameters parameters, OutputStream output) throws IOException { - return new XxxObjectOutput(output); - } - public ObjectInput deserialize(Parameters parameters, InputStream input) throws IOException { - return new XxxObjectInput(input); - } -} -``` - -META-INF/dubbo/org.apache.dubbo.common.serialize.Serialization: - -```properties -xxx=com.xxx.XxxSerialization -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/startup.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/startup.md deleted file mode 100644 index 8a2dc0b61e33..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/startup.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -type: docs -title: "Startup Startup Probe" -linkTitle: "Start Probe" -weight: 12 ---- - -## Expansion Description - - -Extend the detection point of application startup. - - -## Extension ports - - -`org.apache.dubbo.qos.probe.StartupProbe` - - -## Extended configuration - - -Dubbo QOS `startup` command auto-discovery - - -## Known extensions - - -- `org.apache.dubbo.qos.probe.impl.BootstrapLivenessProbe` - - - -## Extended example - - -Maven project structure: - - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxStartupProbe.java (implement the StartupProbe interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.qos.probe.StartupProbe (plain text file, content: xxx=com.xxx.XxxStartupProbe) -``` - - -XxxStartupProbee.java: - - -```java -package com.xxx; - -public class XxxStartupProbe implements StartupProbe { - - public boolean check() { - //... - } -} -``` - - -META-INF/dubbo/org.apache.dubbo.qos.probe.StartupProbe: - - -``` -xxx=com.xxx.XxxStartupProbe -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/status-checker.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/status-checker.md deleted file mode 100644 index 7d8c1ab63275..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/status-checker.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -type: docs -title: "Status Check Extension" -linkTitle: "Status Check Extension" -weight: 21 ---- - -## Expansion Description - -Check the status of various resources that the service relies on. This status check can be used for both telnet's status command and hosting's status page. - -## Extension ports - -`org.apache.dubbo.common.status.StatusChecker` - -## Extended configuration - -```xml - - - -``` - -## Known extensions - -* `org.apache.dubbo.common.status.support.MemoryStatusChecker` -* `org.apache.dubbo.common.status.support.LoadStatusChecker` -* `org.apache.dubbo.rpc.dubbo.status.ServerStatusChecker` -* `org.apache.dubbo.rpc.dubbo.status.ThreadPoolStatusChecker` -* `org.apache.dubbo.registry.directory.RegistryStatusChecker` -* `org.apache.dubbo.rpc.config.spring.status.SpringStatusChecker` -* `org.apache.dubbo.rpc.config.spring.status.DataSourceStatusChecker` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxStatusChecker.java (implement StatusChecker interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.common.status.StatusChecker (plain text file, content: xxx=com.xxx.XxxStatusChecker) -``` - -XxxStatusChecker.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.status.StatusChecker; - -public class XxxStatusChecker implements StatusChecker { - public Status check() { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.common.status.StatusChecker: - -```properties -xxx=com.xxx.XxxStatusChecker -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/telnet-handler.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/telnet-handler.md deleted file mode 100644 index d5750ac2411d..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/telnet-handler.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -type: docs -title: "Telnet Command Extensions" -linkTitle: "Telnet command extension" -weight: 20 ---- - -## Expansion Description - -All servers support telnet access for manual intervention. - -## Extension ports - -`org.apache.dubbo.remoting.telnet.TelnetHandler` - -## Extended configuration - -```xml - - - -``` - -## Known extensions - -* `org.apache.dubbo.remoting.telnet.support.ClearTelnetHandler` -* `org.apache.dubbo.remoting.telnet.support.ExitTelnetHandler` -* `org.apache.dubbo.remoting.telnet.support.HelpTelnetHandler` -* `org.apache.dubbo.remoting.telnet.support.StatusTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.ListTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.ChangeTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.CurrentTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.InvokeTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.TraceTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.CountTelnetHandler` -* `org.apache.dubbo.rpc.dubbo.telnet.PortTelnetHandler` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxTelnetHandler.java (implement TelnetHandler interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.remoting.telnet.TelnetHandler (plain text file, content: xxx=com.xxx.XxxTelnetHandler) -``` - -XxxTelnetHandler.java: - -```java -package com.xxx; - -import org.apache.dubbo.remoting.telnet.TelnetHandler; - -@Help(parameter="...", summary="...", detail="...") - -public class XxxTelnetHandler implements TelnetHandler { - public String telnet(Channel channel, String message) throws RemotingException { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.remoting.telnet.TelnetHandler: - -```properties -xxx=com.xxx.XxxTelnetHandler -``` - -## Usage - -```sh -telnet 127.0.0.1 20880 -dubbo> xxx args -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/threadpool.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/threadpool.md deleted file mode 100644 index 861e0a59414a..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/threadpool.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -type: docs -title: "Thread Pool Extension" -linkTitle: "Thread pool extension" -weight: 15 ---- - -## Expansion Description - -The service provider's thread pool implements the strategy. When the server receives a request, it needs to create a thread in the thread pool to execute the service provider's business logic. - -## Extension ports - -`org.apache.dubbo.common.threadpool.ThreadPool` - -## Extended configuration - -```xml - - - -``` - -## Known extensions - -* `org.apache.dubbo.common.threadpool.FixedThreadPool` -* `org.apache.dubbo.common.threadpool.CachedThreadPool` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxThreadPool.java (implement ThreadPool interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.common.threadpool.ThreadPool (plain text file, content: xxx=com.xxx.XxxThreadPool) -``` - -XxxThreadPool.java: - -```java -package com.xxx; - -import org.apache.dubbo.common.threadpool.ThreadPool; -import java.util.concurrent.Executor; - -public class XxxThreadPool implements ThreadPool { - public Executor getExecutor() { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.common.threadpool.ThreadPool: - -```properties -xxx=com.xxx.XxxThreadPool -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/validation.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/description/validation.md deleted file mode 100644 index b3b43f061e87..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/description/validation.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -type: docs -title: "Authentication Extension" -linkTitle: "Authentication Extension" -weight: 25 ---- - -## Expansion Description - -Parameter validation extension point. - -## Extension ports - -`org.apache.dubbo.validation.Validation` - -## Extended configuration - -```xml - - - -``` - -## Known extensions - -`org.apache.dubbo.validation.support.jvalidation.JValidation` - -## Extended example - -Maven project structure: - -``` -src - |-main - |-java - |-com - |-xxx - |-XxxValidation.java (implement Validation interface) - |-resources - |-META-INF - |-dubbo - |-org.apache.dubbo.validation.Validation (plain text file, content: xxx=com.xxx.XxxValidation) -``` - -XxxValidation.java: - -```java -package com.xxx; - -import org.apache.dubbo.validation.Validation; - -public class XxxValidation implements Validation { - public Object getValidator(URL url) { - //... - } -} -``` - -XxxValidator.java: - -```java -package com.xxx; - -import org.apache.dubbo.validation.Validator; - -public class XxxValidator implements Validator { - public XxxValidator(URL url) { - //... - } - public void validate(Invocation invocation) throws Exception { - //... - } -} -``` - -META-INF/dubbo/org.apache.dubbo.validation.Validation: - -```properties -xxx=com.xxx.XxxValidation -``` \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/reference-manual/spi/overview.md b/content/en/docs3-v2/java-sdk/reference-manual/spi/overview.md deleted file mode 100644 index cd063b93ab9f..000000000000 --- a/content/en/docs3-v2/java-sdk/reference-manual/spi/overview.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -type: docs -title: "Dubbo SPI Overview" -linkTitle: "Dubbo SPI overview" -weight: 1 -description: "Dubbo provides very flexible scalability through the SPI mechanism" ---- - -## Extended Design Ideas - -Scalability is what any system pursues, and it is equally applicable to Dubbo. - -### What is scalability - -Scalability is a design concept that represents our vision for the future. We hope that based on the existing architecture or design, when some aspects change in the future, we can adapt to this with minimal changes. kind of change. - -### Advantages of Scalability - -The advantage of scalability is mainly manifested in the decoupling between modules, which conforms to the principle of opening and closing, which is open to expansion and closed to modification. When a new function is added to the system, there is no need to modify the structure and code of the existing system, just add an extension. - -### Extended implementation - -Generally speaking, the system will use Factory, IoC, OSGI, etc. to manage the extension (plug-in) life cycle. Considering the applicability of Dubbo, I don't want to strongly rely on IoC containers such as Spring. -And building a small IoC container by myself feels a bit over-designed, so choose the simplest Factory way to manage extensions (plug-ins). In Dubbo, all internal and third-party implementations are equal. - -### Scalability in Dubbo - -* Treat third-party implementations equally. In Dubbo, all internal implementations and third-party implementations are equal, and users can replace the native implementations provided by Dubbo based on their own business needs. -* Each extension point only encapsulates one change factor to maximize reuse. The implementers of each extension point often only care about one thing. If users need to expand, they only need to expand the extension points they care about, which greatly reduces the workload of users. - -## Features of Dubbo extension - -The extension capability in Dubbo is enhanced from the JDK standard SPI extension point discovery mechanism, which improves the following problems of the JDK standard SPI: - -* The JDK standard SPI will instantiate all the implementations of the extension point at one time. If there is an extension implementation, it will be time-consuming to initialize, but if it is not used, it will be loaded, which will be a waste of resources. -* If the extension point fails to load, even the name of the extension point cannot be obtained. For example: JDK standard ScriptEngine, get the name of the script type through getName(), but if RubyScriptEngine fails to load the RubyScriptEngine class because the jruby. When the user executes the ruby script, it will report that ruby is not supported, not the real reason for the failure. - -Based on the expansion capabilities provided by Dubbo, users can easily expand other protocols, filters, routes, etc. based on their own needs. The following introduces the characteristics of Dubbo's extension capabilities. - -* Load on demand. Dubbo's extension capability does not instantiate all implementations at once, but instantiates with extended classes to reduce resource waste. -* Increase the IOC capability of the extended class. Dubbo's extension ability is not just to discover the extension service implementation class, but to go further on this basis. If the attributes of the extension class depend on other objects, Dubbo will automatically complete the injection function of the dependent object. -* Increase the AOP capability of extended classes. Dubbo's extension capability will automatically discover the wrapper class of the extension class, complete the construction of the wrapper class, and enhance the function of the extension class. -* Possess the ability to dynamically select the extension implementation. The Dubbo extension will dynamically select the corresponding extension class at runtime based on parameters, which improves Dubbo's scalability. -* The extension implementation can be sorted. The execution order of the extension implementation can be specified based on user requirements. -* Provides the Adaptive capability of the extension point. This capability enables some extension classes to take effect on the consumer side, and some extension classes to take effect on the provider side. - -From the design goal of Dubbo extension, it can be seen that some features implemented by Dubbo, such as dynamic selection of extension implementation, IOC, AOP, etc., can provide users with very flexible expansion capabilities. - -## Dubbo extension loading process - -The whole process of Dubbo loading extension is as follows: - -![//imgs/v3/concepts/extension-load.png](/imgs/v3/concepts/extension-load.png) - -There are 4 main steps: -* Read and parse configuration files -* Cache all extension implementations -* Based on the extension name executed by the user, instantiate the corresponding extension implementation -* Perform IOC injection of extended instance attributes and instantiate extended wrapper classes to realize AOP features - -## How to use Dubbo's extension capability to expand - -The following takes the extension protocol as an example to illustrate how to use the extension capabilities provided by Dubbo to extend the Triple protocol. - -(1) Place a text file in the protocol implementation jar package: META-INF/dubbo/org.apache.dubbo.remoting.api.WireProtocol -```text -tri=org.apache.dubbo.rpc.protocol.tri.TripleHttp2Protocol -``` - -(2) Implementation class content -```java -@Activate -public class TripleHttp2Protocol extends Http2WireProtocol { - //... -} -``` - -Instructions: Http2WireProtocol implements the WireProtocol interface - -(3) In the Dubbo configuration module, each extension point has a corresponding configuration attribute or label, and the configuration specifies which extension to use. for example: -```text - -``` - -As can be seen from the above expansion steps, the user basically completes the expansion under the black box. - -## Dubbo extended application - -Dubbo's expansion capability is very flexible, and it is ubiquitous in the realization of its own functions. - -![//imgs/v3/concepts/extension-use.png](/imgs/v3/concepts/extension-use.png) - -Dubbo's extensibility makes it easy to divide the Dubbo project into sub-modules one by one to realize the hot-swappable feature. Users can completely replace Dubbo's native implementation based on their own needs to meet their own business needs. - -## scenes to be used - -* If you need to customize the load balancing strategy, you can use Dubbo's scalability. -* If you need to implement a custom registry, you can use Dubbo's extension capabilities. -* If you need to implement custom filters, you can use Dubbo's extension capabilities. - -Dubbo extensions treat internal implementations and third-party implementations equally. For more usage scenarios, see [SPI extension implementation](../description/) \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide.md b/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide.md deleted file mode 100644 index 866fba7f5270..000000000000 --- a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/2.x-to-3.x-compatibility-guide.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -type: docs -title: "2.x to 3.x Operation Guide" -linkTitle: "2.x to 3.x Operation Guide" -weight: 1 -description: "Quickly understand the upgrade steps and compatibility of Dubbo 3" ---- -## Benefits of upgrading to Dubbo 3.X -Dubbo3 still maintains the classic architecture of 2.x. Its main responsibility is to solve the communication between microservice processes, and to better manage and control microservice clusters through rich service governance (such as address discovery, traffic management, etc.); The upgrade of the framework is comprehensive, reflected in almost every aspect of the core Dubbo features, through the upgrade to achieve a comprehensive improvement in stability, performance, scalability, and ease of use. - -![architecture-1](/imgs/v3/concepts/architecture-1.png) - -- **Universal communication protocol. ** The new RPC protocol should abandon the private protocol stack, use the more general HTTP/2 protocol as the transport layer carrier, and use the standardized features of the HTTP protocol to solve the problems of traffic versatility and penetration, so that the protocol can better respond Scenarios such as front-end and back-end docking, gateway proxy, etc.; supports the Stream communication mode, which meets the demands of different business communication models and brings greater throughput to the cluster. -- **For millions of cluster instances, the cluster is highly scalable. ** With the promotion of micro-service practices, the scale of micro-service cluster instances is also constantly expanding, which benefits from the characteristics of light-weight micro-services and easy horizontal expansion, but also brings a burden to the entire cluster capacity, especially It is some centralized service governance components; Dubbo3 needs to solve various resource bottlenecks caused by the expansion of instance scale, and realize truly unlimited horizontal expansion. -- **Comprehensively embrace cloud native. ** - - -## Dubbo 3.0 new features -The new features provided by Dubbo 3.0 include: - -* ** New address discovery model (application-level service discovery). ** - * See [Application-Level Service Discovery Migration Samples](/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples/). - * See [Migration steps for application-level service discovery](/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery/) - * See [Description of application-level service discovery address migration rules](/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule/) -* **The next generation of the HTTP/2-based Triple protocol. ** - * See [Triple Protocol Migration Steps](/en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple/) - * See [Triple protocol usage](/en/docs3-v2/java-sdk/reference-manual/protocol/triple/guide/) - * See [Triple Protocol Design and Implementation](/en/docs3-v2/java-sdk/reference-manual/protocol/triple/overview/). -* **Unified routing rules. ** - * See [Design and Implementation of Unified Routing Rules](/en/docs3-v2/java-sdk/advanced-features-and-usage/traffic/mesh-style/) - - -## Compatibility check before upgrade -In the process of cross-version upgrade, the existing risks are from big to small: directly modify Dubbo source code -> expand based on Dubbo SPI extension points -> use methods based on API or Spring. - -### 1. Directly modify Dubbo source code -For those who need to directly modify this part of Dubbo source code, the modifying party must judge whether it works normally in the higher version. For this non-standard behavior, Dubbo cannot guarantee its previous compatibility. In addition, the modification of Dubbo at runtime through javagent or asm is also within this scope. Most of these modifications can be detected by the scanning tools provided below. - -### 2. SPI extension -#### Incompatibilities -For SPI extensions, except that the two mechanisms of application-level service direction and EventDispatcher have been destructively modified in 3.x, most of the extensions provided in 2.7.x are also provided in 3.x. There are two areas to focus on in this section: - -- Event bus: Due to the complexity of event management, the support of EventDispatcher and EventListener in Dubbo 3.x has been removed. If there is a use of the corresponding extension mechanism, please consider refactoring to an extension corresponding to the Dubbo function. -- Application-level service discovery: The overall mechanism of application-level service discovery in Dubbo 2.7 has been completely refactored in Dubbo 3.x, and the performance and stability of functions have been greatly improved. Therefore, we recommend that you do not use the application-level service discovery mechanism in Dubbo 2.7. If there is a corresponding extension, you can re-verify the implementation based on the new code after upgrading to Dubbo 3.x (most APIs for application-level service discovery are forward Compatible). - -#### Optimization items (optional) -In addition, Dubbo 3.x has optimized the working mechanism of some extension points, which can greatly improve the performance of the application. - -- 1) Interceptor mechanism - -Dubbo can intercept requests based on Filter interceptors. In Dubbo 2.7, it is supported to intercept the request after the routing address is selected. In Dubbo 3.x, a new ClusterFilter mechanism is abstracted, which can greatly reduce the memory usage, and has great benefits for ultra-large-scale clusters. -If you have some interceptors on the consumer side that are implemented based on the Filter mechanism, and if there is no logic that is strongly bound to the remote IP address, we recommend that you add the corresponding `org.apache.dubbo.rpc.Filter` SPI extension point Migrated to the new SPI extension point `org.apache.dubbo.rpc.cluster.filter.ClusterFilter`. The method definitions of the two interfaces are exactly the same. - -- 2) Router -> StateRouter - -Dubbo provides Router, the ability to dynamically select and route, and most of the service governance capabilities are also implemented based on this Router extension point. In Dubbo 3.x, Dubbo abstracts a new StateRouter mechanism based on Router, which can greatly optimize address selection performance and memory usage. We will publish more about StateRouter in subsequent documents. - -### 3. API / Spring usage -For the use based on API or Spring, Dubbo 3.x and 2.7.x are used in the same way. In Dubbo 3.x, some invalid configurations are strongly checked, and this part of the exception will directly report an error during the startup process. , please follow the prompts to modify. - -## Upgrade process -### 1. Dependency upgrade -If you use Nacos as the registration center, due to the support of Nacos features, you need to upgrade Nacos Server to 2.x before upgrading to Dubbo 3.x (refer to the document [https://nacos.io/zh-cn/docs/v2 /upgrading/2.0.0-upgrading.html](https://nacos.io/zh-cn/docs/v2/upgrading/2.0.0-upgrading.html)), and then upgrade the Nacos Client of the application . No processing is required if using a Zookeeper registry. -If you are using Spring Cloud Alibaba Dubbo for access, please upgrade to xxx due to changes in some internal APIs of Dubbo. - -Please upgrade to the latest version 3.1.3 for Dubbo dependencies. Dubbo and the corresponding springboot starter GAV are as follows. -```xml - - org.apache.dubbo - dubbo - 3.1.3 - - - - org.apache.dubbo - dubbo-spring-boot-starter - 3.1.3 - -``` -### 2. Gray scale upgrade -The Dubbo 3 upgrade has no special restrictions on the release process, and it can be released according to normal business. -Since Dubbo is undergoing changes and upgrades across major versions, please release as many batches as possible during the release, and at the same time increase the time interval between the first batch and the second batch of releases, and make sufficient observations. -During the publishing process, we recommend that you first upgrade the downstream of the application (that is, the service provider), and then proceed with subsequent publishing after verifying that the service is processed normally. - -### 3. Upgrade observation indicators -During the release process, there are the following latitude indicators to judge whether there is a problem with the upgrade. - -- CPU, memory usage of the machine -- Interface request success rate -- Interface Request RT -- Log error message -- Does the custom extension behave as expected - -## Precautions -### 1. Application-level service discovery -Due to design problems in the application-level service discovery model of Dubbo 2.7, a large number of format changes have been made in Dubbo 3.x, so the application-level service discovery of 2.7.x and 3.x may not be able to subscribe to each other. sex. Although Dubbo will eliminate unrecognized instances, from the perspective of stability, if you enable the application-level service discovery feature in 2.7.x (not registered by default in 2.7.x), we recommend first Turn it off, and turn it on again after upgrading to 3.x. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/3.0-to-3.1-compatibility-guide.md b/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/3.0-to-3.1-compatibility-guide.md deleted file mode 100644 index 2a19692de11c..000000000000 --- a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/3.0-to-3.1-compatibility-guide.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -type: docs -title: "3.0 to 3.1 Operation Guide" -linkTitle: "3.0 to 3.1 Operation Guide" -weight: 1000 -description: "Quickly understand the upgrade steps and compatibility of Dubbo 3.1" ---- - -## Function modification points - -### 1. Nacos Group alignment (application-level service discovery) - -In Dubbo 2.7.x, the group value configured on the Nacos Registry URL is aligned with the group group in the Nacos Registry. (group can be regarded as a soft isolation similar to namespace) - -In Dubbo 3.0.x, the group configured on the Nacos Registry URL is not used by default, and all use DEFAULT_GROUP. (group no longer provides isolation) - -In Dubbo 3.1.x, the group value configured on the Nacos Registry URL will realign the group grouping in the Nacos Registry. - -Precautions: - -1. Please check whether the group attribute has been configured on the URL of the registration center. If so, check whether the group of the server and the consumer are consistent. If not, please modify it to be consistent. -2. If you do not want the group to be realigned to the group grouping in the Nacos registry, you can configure the `dubbo.nacos-service-discovery.use-default-group=false` global property value to ignore this function \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/3.1-to-3.2-compatibility-guide.md b/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/3.1-to-3.2-compatibility-guide.md deleted file mode 100644 index e617edf2bd6a..000000000000 --- a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/3.1-to-3.2-compatibility-guide.md +++ /dev/null @@ -1,140 +0,0 @@ ---- -description: Dubbo 3.2 Upgrade and Compatibility Guide -linkTitle: 3.1 upgrade to 3.2 -title: 3.1 upgrade to 3.2 -type: docs -weight: 3 ---- - -For the vast majority of users, upgrading to Dubbo 3.2.0 is completely smooth, and only needs to modify the version of the dependent package. - -```xml - - org.apache.dubbo - dubbo - 3.2.0 - -``` - -or - -```xml - - org.apache.dubbo - dubbo-spring-boot-starter - 3.2.0 - -``` - -# Compatibility CheckList - -## 1. Serialization check mode (important!!!) - -In Dubbo 3.2.0 version, Dubbo will enable the strong verification of the serialized whitelist by default to improve the security of Dubbo and avoid the problem of remote command execution. -For some users who use generics and may have incomplete scanning or **large service scale**, we recommend that you add `-Ddubbo.application.serialize-check-status=WARN` configuration. -After observing for a period of time (via logs and QoS commands), if no security alarm is triggered, you can configure the strong check mode. - -For the configuration of the custom whitelist, please refer to [Documentation/SDK Manual/Java SDK/Advanced Features and Usage/Improve Security/Class Inspection Mechanism](/en/docs3-v2/java-sdk/advanced-features-and-usage/security/class-check/) article to configure. - -#### Q1: Why do you need to enable strong verification of the serialization whitelist? - -Due to the problem of Java's own mechanism, the non-IDL serialization supported by Dubbo naturally allows access to arbitrary classes, which may lead to remote command execution (RCE) risks. - -#### Q2: What are the best practices for upgrading to 3.2? - -We recommend **all users** to add `-Ddubbo.application.serialize-check-status=WARN` configuration before upgrading Dubbo 3.2.0 to ensure the best compatibility. Otherwise, it may lead to abnormal online data! - ---- - -## 2. Default serialization switch - -Starting from Dubbo version 3.2.0, the default serialization method is switched from `hessian2` to `fastjson2`. For applications upgraded to 3.2.0, Dubbo will automatically try to use `fastjson2` for serialization. - -#### Q1: Will it affect the intercommunication with lower versions of Dubbo? - -Won't. Interoperability with lower versions still uses `hessian-lite`. For the principle, please refer to [Serialization Protocol Upgrade Guide](/zh-cn/overview/mannual/java-sdk/upgrades-and-compatibility/serialization-upgrade/). - -#### Q2: Why switch the default serialization method? - -`fastjson2` is a high-performance serialization framework with better performance than `hessian2`, natively supports JDK17, Native, etc., and is fully forward compatible with all functions of `hessian2`. -Since `hessian-lite` will become more and more difficult to maintain in the future, we decided to switch the default serialization method from `hessian2` to `fastjson2`. - -#### Q3: What is the relationship with native JSON? - -Dubbo uses the JSONB format of `fastjson2` instead of the native JSON format. The JSONB format corresponds to the JSON format, can fully represent JSON, and is a binary format. -For the specific protocol format, please refer to: [JSONB format](https://github.com/alibaba/fastjson2/wiki/jsonb_format_cn) - -#### Q4: What if I don't want to use `fastjson2`? - -If you don't want to use `fastjson2`, you can configure `prefer-serialization` to override the default configuration for `hessian2`. (such as `dubbo.provider.prefer-serialization=fastjson2,hessian2`) If there is no special requirement, we do not recommend continuing to use `hessian2`. - ---- - -## 3. Push short protection is disabled by default - -Since version 3.2.0 of Dubbo, the push protection is turned off by default. Even if the registration center pushes an empty address, Dubbo will not keep the last batch of provider information. -If you need to enable empty protection, you can configure `dubbo.application.enable-empty-protection` to `true`. - -#### Q1: How does disabling push short protection affect me? - -In most scenarios it has no effect. -The purpose of push empty protection is that when the registration center fails and actively pushes empty addresses, Dubbo keeps the last batch of provider information to ensure service availability. -However, when most registration centers fail, the registration center will not push empty addresses, only in some special cases. -However, if the push short protection is turned on, it will have a greater impact on Dubbo's Fallback logic, heartbeat logic, etc., and bring troubles to the development and use of Dubbo. - -#### Q2: I want to enable short push protection, what should I do? - -If you need to enable push empty protection for high availability in production, you can configure `dubbo.application.enable-empty-protection` to `true`. -At present, it is known that turning on the push-out protection will cause the server-side application to upgrade from `2.6. In this scenario, the service call will fail. -In addition, after the push-to-empty protection is turned on, when the server address is really empty, there will be more heartbeat exceptions and log exceptions. - ---- - -## 4. Transitive dependency changes - -* Dubbo version 3.2.0 no longer shade `hessian-lite` code in `dubbo-all` by default, but use transitive dependency transfer instead. If you don't need to use `hessian-lite` in your application, you can remove `hessian-lite` from dependencies. -* From version 3.2.0 of Dubbo, `gson`, `fastjson` dependencies are no longer passed in `dubbo-all`, if you need to use `gson`, `fastjson` in your application, please manually install `gson`, `fastjson` ` Dependencies are added to the application. -* Dubbo 3.2.0 version passes `fastjson2` dependency in `dubbo-all`. - ---- - -## 5. Default internal serialization tool switch - -Since version 3.2.0 of Dubbo, the default **internal** serialization tool is switched from `fastjson` to `fastjson2`. - -#### Q1: Will it affect the RPC request traffic? - -Won't. The internal serialization tool is used when Dubbo internally parses parameters, not the RPC transmission serialization protocol. - -#### Q2: Why switch the default internal serialization tool? - -From version 3.2.0 of Dubbo, the default transitive dependencies no longer pass `fastjson` and `gson`. For compatibility reasons, the default internal serialization tool is switched to `fastjson2`. - -#### Q3: What if there is no `fastjson2` in my environment? - -Dubbo supports automatic switching of various serialization frameworks. If there is no `fastjson2` in your environment, Dubbo will automatically try to switch to `fastsjon` or `gson`. - -#### Q4: I want to specify the internal serialization tool of Dubbo, what should I do? - -You can configure `dubbo.json-framework.prefer` parameters, such as `-Ddubbo.json-framework.prefer=gson`. - ---- - -## 6. Triple protocol supports passing custom exceptions - -Starting from Dubbo version 3.2.0, the Triple protocol supports returning custom exceptions instead of only returning `RpcException`. If the service interface throws an exception, after Dubbo 3.2.0, the custom exception object will be returned by default according to the Dubbo protocol. - ---- - -## 7. Triple protocol version number alignment - -Starting from Dubbo version 3.2.0, the communication of the Triple protocol requires the version number and grouping of the client and server to be consistent, otherwise the service will not be found. When interoperating with the native gRPC SDK, the Dubbo side cannot configure groups and version numbers. - -#### Q1: How was Dubbo before 3.2.0? - -1) Triple will think that the empty version number is consistent with the 1.0.0 version number. If your server and client version numbers are inconsistent, but they are both empty version numbers or 1.0.0 version numbers, they can communicate normally. -2) For a service that does not match a version number, Triple will try to match a service with any version number. If it matches a service with any version number, it can also communicate normally. - -#### Q2: How to ensure that it is aligned with the original behavior? - -By configuring `-Ddubbo.rpc.tri.ignore-1.0.0-version=true -Ddubbo.rpc.tri.resolve-fallback-to-default=true`, the previous behavior of Dubbo 3.2.0 can be achieved. diff --git a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/_index.md b/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/_index.md deleted file mode 100755 index 97dd65a7ac0b..000000000000 --- a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/_index.md +++ /dev/null @@ -1,8 +0,0 @@ - ---- -type: docs -title: "Upgrade Compatibility" -linkTitle: "Upgrade Compatibility" -weight: 6 ---- - diff --git a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple.md b/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple.md deleted file mode 100644 index 0c1f60b9669d..000000000000 --- a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/migration-triple.md +++ /dev/null @@ -1,344 +0,0 @@ ---- -type: docs -title: "Guide to Migrating Dubbo Protocol to Triple Protocol" -linkTitle: "Guide to migrating Dubbo protocol to Triple protocol" -weight: 2 -description: "Triple Protocol Migration Guide" ---- - -## Triple Introduction - -For the format and principle of the `Triple` protocol, please refer to [RPC Communication Protocol](/zh-cn/docs/concepts/rpc-protocol/) - -According to the goals of Triple design, the `Triple` protocol has the following advantages: - -- Capable of cross-language interaction. Both the traditional multi-language and multi-SDK mode and the Mesh cross-language mode require a more general and scalable data transmission protocol. -- Provide a more complete request model. In addition to supporting the traditional Request/Response model (Unary one-way communication), it also supports Stream (streaming communication) and Bidirectional (two-way communication). -- Easy to expand, high penetration, including but not limited to Tracing / Monitoring and other support, should also be recognized by devices at all levels, gateway facilities, etc. can identify data packets, friendly to Service Mesh deployment, and reduce the difficulty of understanding for users. -- Fully compatible with grpc, the client/server can communicate with the native grpc client. -- Components in the existing grpc ecosystem can be reused to meet cross-language, cross-environment, and cross-platform intercommunication requirements in cloud-native scenarios. - -For Dubbo users currently using other protocols, the framework provides migration capabilities compatible with existing serialization methods. Without affecting existing online businesses, the cost of migrating protocols is almost zero. - -Dubbo users who need to add new connection to Grpc service can directly use the Triple protocol to achieve the connection, and do not need to introduce the grpc client separately to complete it. Not only can the existing Dubbo ease of use be retained, but also the complexity of the program and the development and maintenance can be reduced. Cost, it can be connected to the existing ecology without additional adaptation and development. - -For Dubbo users who need gateway access, the Triple protocol provides a more native way to make gateway development or use open source grpc gateway components easier. The gateway can choose not to parse the payload, which greatly improves the performance. When using the Dubbo protocol, the language-related serialization method is a big pain point for the gateway, and the traditional HTTP-to-Dubbo method is almost powerless for cross-language serialization. At the same time, since Triple's protocol metadata is stored in the request header, the gateway can easily implement customized requirements, such as routing and current limiting. - - -## Dubbo2 protocol migration process - -Dubbo2 users use dubbo protocol + custom serialization, such as hessian2 to complete remote calls. - -By default, Grpc only supports Protobuf serialization, and it cannot support multi-parameter and method overloading in the Java language. - -At the beginning of Dubbo3, one goal was to be perfectly compatible with Dubbo2. Therefore, in order to ensure the smooth upgrade of Dubbo2, the Dubbo framework has done a lot of work to ensure that the upgrade is seamless. Currently, the default serialization is consistent with Dubbo2 as `hessian2`. - -Therefore, if you decide to upgrade to the `Triple` protocol of Dubbo3, you only need to modify the protocol name in the configuration to `tri` (note: not triple). - -Next we use a [project] (https://github.com/apache/dubbo-samples/tree/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/ org/apache/dubbo/sample/tri/migration) as an example, how to upgrade safely step by step. - -1. Only use the `dubbo` protocol to start `provider` and `consumer`, and complete the call. -2. Use `dubbo` and `tri` protocols to start `provider`, use `dubbo` protocol to start `consumer`, and complete the call. -3. Start `provider` and `consumer` using only `tri` protocol, and complete the call. - -### Define the service - -1. Define the interface -```java -public interface IWrapperGreeter { - - //... - - /** - * This is a normal interface, not serialized using pb - */ - String sayHello(String request); - -} -``` - -2. The implementation class is as follows -```java -public class IGreeter2Impl implements IWrapperGreeter { - - @Override - public String sayHello(String request) { - return "hello," + request; - } -} -``` - -### Only use dubbo protocol - -To ensure compatibility, we first upgrade some providers to the `dubbo3` version and use the `dubbo` protocol. - -Start a [`Provider`] using the `dubbo` protocol (https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org /apache/dubbo/sample/tri/migration/ApiMigrationDubboProvider.java) and [`Consumer`](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationDubboConsumer.java), complete the call, the output is as follows: -![result](/imgs/v3/migration/tri/dubbo3-tri-migration-dubbo-dubbo-result.png) - -### Use dubbo and triple protocol at the same time - -For the upgrade of online services, it is impossible to complete the provider and consumer upgrades at the same time. It needs to be operated step by step to ensure business stability. -In the second step, the provider provides a dual-protocol way to support dubbo + tri clients at the same time. - -The structure is shown in the figure: -![trust](/imgs/v3/migration/tri/migrate-dubbo-tri-strust.png) - -> According to the recommended upgrade steps, the provider already supports the tri protocol, so the consumer of dubbo3 can directly use the tri protocol - -Start [`Provider`] using `dubbo` protocol and `triple` protocol (https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main /java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothProvider.java) and [`Consumer`](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/ dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/migration/ApiMigrationBothConsumer.java), complete the call, the output is as follows: - -![result](/imgs/v3/migration/tri/dubbo3-tri-migration-both-dubbo-tri-result.png) - - -### Only use triple protocol - -When all consuemr are upgraded to a version that supports the `Triple` protocol, the provider can be switched to only use the `Triple` protocol to start - -The structure is shown in the figure: -![trust](/imgs/v3/migration/tri/migrate-only-tri-strust.png) - -[Provider](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri/ migration/ApiMigrationTriProvider.java) -and [Consumer](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/java/org/apache/dubbo/sample/tri /migration/ApiMigrationTriConsumer.java) to complete the call, the output is as follows: - -![result](/imgs/v3/migration/tri/dubbo3-tri-migration-tri-tri-result.png) - - -### Implementation principle - -Through the upgrade process described above, we can easily complete the upgrade by modifying the protocol type. How does the framework help us do this? - -Through the introduction of the `Triple` protocol, we know that the data type of `Triple` in Dubbo3 is a `protobuf` object, so why non-`protobuf` java objects can also be transmitted normally. - -Here Dubbo3 uses an ingenious design, first judge whether the parameter type is a `protobuf` object, if not. Use a `protobuf` object to wrap `request` and `response`, which shields the complexity brought by other serialization. Declare the serialization type inside the `wrapper` object to support serialization extensions. - -The IDL of `protobuf` of wrapper is as follows: -```proto -syntax = "proto3"; - -package org.apache.dubbo.triple; - -message TripleRequestWrapper { - //hessian4 - // json - string serializeType = 1; - repeated bytes args = 2; - repeated string argTypes = 3; -} - -message TripleResponseWrapper { - string serializeType = 1; - bytes data = 2; - string type = 3; -} -``` - -For requests, use `TripleRequestWrapper` for wrapping, and for responses, use `TripleResponseWrapper` for wrapping. - -> For request parameters, you can see that args is modified by `repeated`, this is because multiple parameters of the java method need to be supported. Of course, serialization can only be one. The implementation of serialization follows the spi implemented by Dubbo2 - - -## Multilingual users (using Protobuf) -> It is recommended that all new services use this method - -For Dubbo3 and Triple, the main recommendation is to use `protobuf` serialization, and use `IDL` defined by `proto` to generate related interface definitions. Using `IDL` as a common interface convention in multiple languages, coupled with the natural interoperability of `Triple` and `Grpc`, can easily achieve cross-language interaction, such as Go language. - - -Use the `dubbo-compiler` plug-in to compile the prepared `.proto` file and write the implementation class to complete the method call: - -![result](/imgs/v3/migration/tri/dubbo3-tri-migration-tri-tri-result.png) - -From the upgrade example above, we can know that the `Triple` protocol uses `protbuf` objects to be serialized for transmission, so there is no other logic for methods that are themselves `protobuf` objects. - -The interface after compiling with the `protobuf` plugin is as follows: -```java -public interface PbGreeter { - - static final String JAVA_SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; - static final String SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; - - static final boolean inited = PbGreeterDubbo.init(); - - org.apache.dubbo.sample.tri.GreeterReply greet(org.apache.dubbo.sample.tri.GreeterRequest request); - - default CompletableFuture greetAsync(org.apache.dubbo.sample.tri.GreeterRequest request){ - return CompletableFuture. supplyAsync(() -> greet(request)); - } - - void greetServerStream(org.apache.dubbo.sample.tri.GreeterRequest request, org.apache.dubbo.common.stream.StreamObserver responseObserver); - - org.apache.dubbo.common.stream.StreamObserver greetStream(org.apache.dubbo.common.stream.StreamObserver responseObserver); -} -``` - -## Open the new feature of Triple - Stream (stream) -Stream is a new call type provided by Dubbo3. It is recommended to use stream in the following scenarios: - -- The interface needs to send a large amount of data. These data cannot be placed in an RPC request or response, and need to be sent in batches. However, if the application layer cannot solve the order and performance problems in the traditional multiple RPC method, if the order needs to be guaranteed , it can only be sent serially -- In streaming scenarios, data needs to be processed in the order they are sent, and the data itself has no definite boundary -- In push scenarios, multiple messages are sent and processed in the context of the same call - -Stream is divided into the following three types: -- SERVER_STREAM (server stream) - ![SERVER_STREAM](/imgs/v3/migration/tri/migrate-server-stream.png) -- CLIENT_STREAM (client stream) - ![CLIENT_STREAM](/imgs/v3/migration/tri/migrate-client-stream.png) -- BIDIRECTIONAL_STREAM (bidirectional stream) - ![BIDIRECTIONAL_STREAM](/imgs/v3/migration/tri/migrate-bi-stream.png) - -> Due to the limitations of the `java` language, the implementation of BIDIRECTIONAL_STREAM and CLIENT_STREAM is the same. - -In Dubbo3, the stream interface is declared and used as `SteamObserver`, and users can use and implement this interface to send and handle stream data, exceptions, and end. - -> For Dubbo2 users, they may be unfamiliar with StreamObserver, which is a stream type defined by Dubbo3. There is no Stream type in Dubbo2, so it has no impact on migration scenarios. - -Stream Semantic Guarantees -- Provide message boundaries, which can easily process messages separately -- Strictly ordered, the order of the sender is consistent with the order of the receiver -- Full duplex, no need to wait for sending -- Support cancellation and timeout - -### Non-PB serialized stream -1. api -```java -public interface IWrapperGreeter { - - StreamObserver sayHelloStream(StreamObserver response); - - void sayHelloServerStream(String request, StreamObserver response); -} -``` - -> The method input parameters and return values of the Stream method are strictly agreed. In order to prevent problems caused by writing errors, the Dubbo3 framework side checks the parameters, and throws an exception if there is an error. -> For `BIDIRECTIONAL_STREAM`, it should be noted that `StreamObserver` in the parameter is the response stream, and `StreamObserver` in the return parameter is the request stream. - -2. Implementation class -```java -public class WrapGreeterImpl implements WrapGreeter { - - //... - - @Override - public StreamObserver sayHelloStream(StreamObserver response) { - return new StreamObserver() { - @Override - public void onNext(String data) { - System.out.println(data); - response.onNext("hello,"+data); - } - - @Override - public void onError(Throwable throwable) { - throwable. printStackTrace(); - } - - @Override - public void onCompleted() { - System.out.println("onCompleted"); - response.onCompleted(); - } - }; - } - - @Override - public void sayHelloServerStream(String request, StreamObserver response) { - for (int i = 0; i < 10; i++) { - response.onNext("hello," + request); - } - response.onCompleted(); - } -} -``` - -3. Call method -```java -delegate.sayHelloServerStream("server stream", new StreamObserver() { - @Override - public void onNext(String data) { - System.out.println(data); - } - - @Override - public void onError(Throwable throwable) { - throwable. printStackTrace(); - } - - @Override - public void onCompleted() { - System.out.println("onCompleted"); - } -}); - - -StreamObserver request = delegate.sayHelloStream(new StreamObserver() { - @Override - public void onNext(String data) { - System.out.println(data); - } - - @Override - public void onError(Throwable throwable) { - throwable. printStackTrace(); - } - - @Override - public void onCompleted() { - System.out.println("onCompleted"); - } -}); -for (int i = 0; i < n; i++) { - request.onNext("stream request" + i); -} -request.onCompleted(); -``` - -## Serialized stream using Protobuf - -For the `Protobuf` serialization method, it is recommended to write `IDL` and use the `compiler` plugin to compile and generate. The generated code is roughly as follows: -```java -public interface PbGreeter { - - static final String JAVA_SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; - static final String SERVICE_NAME = "org.apache.dubbo.sample.tri.PbGreeter"; - - static final boolean inited = PbGreeterDubbo.init(); - - //... - - void greetServerStream(org.apache.dubbo.sample.tri.GreeterRequest request, org.apache.dubbo.common.stream.StreamObserver responseObserver); - - org.apache.dubbo.common.stream.StreamObserver greetStream(org.apache.dubbo.common.stream.StreamObserver responseObserver); -} -``` - -### Implementation principle of stream - -How does the streaming mode of the `Triple` protocol support it? - -- From the perspective of the protocol layer, `Triple` is built on the basis of `HTTP2`, so it directly has all the capabilities of `HTTP2`, so it has the ability to split `stream` and full-duplex. - -- In terms of the framework layer, `StreamObserver` is provided to users as a stream interface to provide stream processing for input and output parameters. The framework makes corresponding interface calls when sending and receiving stream data, so as to ensure the integrity of the life cycle of the stream. - -## Triple and application-level registration discovery - -The application-level service registration and discovery of the Triple protocol is consistent with other languages, and you can learn more about it through the following content. - -- [Service Discovery](/zh-cn/docs/concepts/service-discovery/) -- [Application-level address discovery migration guide](/zh-cn/docs/migration/migration-service-discovery/) - -## Intercommunicate with GRPC - -Through the introduction of the protocol, we know that the `Triple` protocol is based on `HTTP2` and compatible with `GRPC`. In order to ensure and verify the interoperability with `GRPC`, Dubbo3 has also written various tests in slave scenarios. For details, you can learn more through [here](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/README.MD). - -## Future: Everything on Stub - -Students who have used `Grpc` should be familiar with `Stub`. -Grpc uses `compiler` to compile the written `proto` file into related protobuf objects and related rpc interfaces. By default several different `stubs` will be generated at the same time - --blockingStub -- futureStub - -reactorStub - -... - -`stub` helps us shield the details of different calling methods in a unified way. However, currently `Dubbo3` only supports the traditional way of defining and calling interfaces. - -In the near future, `Triple` will also implement various commonly used `Stub`, allowing users to write a `proto` file, which can be conveniently used in any scene through `comipler`, please wait and see. diff --git a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/protobuf&interface.md b/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/protobuf&interface.md deleted file mode 100644 index fe49cfc5182d..000000000000 --- a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/protobuf&interface.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -type: docs -title: "Comparison of Protobuf and Interface" -linkTitle: "Protobuf vs Interface" -weight: 100 -description: >- - This article compares the differences between the two IDLs, Protobuf and Interface, to help Dubbo protocol developers understand Protobuf, and pave the way for the subsequent transfer to Triple protocol and Grpc protocol. ---- - -## 1. Data type - -### 1.1. Basic types - -| ptoto type | java type | -| ---- | ---- | -double | double -float | float -int32 | int -int64 | long -uint32 | int[Note] -uint64 | long[Note] -sint32 | int -sint64 | long -fixed32 | int[Note] -fixed64 | long[Note] -sfixed32 | int -sfixed64 | long -bool | boolean -string | String -bytes | ByteString - -> [Note] In Java, unsigned 32-bit and 64-bit integers are represented using their signed logarithms, with the top bit only stored in the sign bit. -## 2. Composite types - -### 2.1. Enumeration - -* Original pb code - -```java. -enum TrafficLightColor { - TRAFFIC_LIGHT_COLOR_INVALID = 0; - TRAFFIC_LIGHT_COLOR_UNSET = 1; - TRAFFIC_LIGHT_COLOR_GREEN = 2; - TRAFFIC_LIGHT_COLOR_YELLOW = 3; - TRAFFIC_LIGHT_COLOR_RED = 4; -} -``` - -* Generated java code - -![image](/imgs/docs/advanced/protobufinterface/124234531-b96c2c80-db46-11eb-8155-a77dbe059f07.png) - -> Enumerations are constants, so use uppercase -### 2.2. Arrays - -* Original pb code - -```java -message VipIDToRidReq { - repeated uint32 vipID = 1; -} -``` - -* Generated java code - -![image](/imgs/docs/advanced/protobufinterface/124234564-c4bf5800-db46-11eb-94fc-a056af6089cb.png) - -> The bottom layer is actually an ArrayList -### 2.3. Collections - -PB does not support unordered and non-repeating collections, and can only ``borrow arrays to implement``, and needs to ``remove duplicates by itself``. - -### 2.4. Dictionaries - -* Original pb code - -```java -message BatchOnlineRes { - map onlineMap = 1;//online status -} -``` - -* Generated java code - -![image](/imgs/docs/advanced/protobufinterface/124234654-e4568080-db46-11eb-9700-b30022ebee21.png) - -### 2.5. Nesting - -* Original pb code - -```java -message BatchAnchorInfoRes { - map list = 1; //user information map list -} -/* -* The function of the corresponding interface: get user information in batches or individually -*/ -message AnchorInfo { - uint32 ownerUid = 1 [json_name="uid"]; //user id - string nickName = 2 [json_name="nn"]; //User nickname - string smallAvatar = 3 [json_name="savt"]; //full path of user avatar - small - string middleAvatar = 4 [json_name="mavt"]; //Full path of user avatar - middle - string bigAvatar = 5 [json_name="bavt"]; //Full path of user avatar - big - string avatar = 6 [json_name="avt"]; //User avatar -} -``` - -* Generated java code - -![image](/imgs/docs/advanced/protobufinterface/124234723-f89a7d80-db46-11eb-82d0-a8aee5322098.png) - -## 3. Field default value - -* For strings, the default is the empty string. -* For bytes, the default is the null byte. -* For bools, the default is false. -* For numeric types, the default value is zero. -* For enums, the default is the first defined enum value, which must be 0. -* For the message field, the field is not set. Its exact value is language dependent. See the generated code guide for details. - -## 4. Overall structure - -| Feature | Java Interface | Protobuf | Remarks | -| ---- | ---- | ---- | ---- | -| Method Overloading | √ | × | | -| Generic/templated | √ | × | | -| method inheritance | √ | × | | -| Nested definition | √ | Partial support | PB only supports message and enum nesting | -| import file | √ | √ | | -| field is null | √ | × | | -| Multiple input parameters | √ | × | PB only supports single input parameters | -| 0 input parameters | √ | × | PB must have input parameters | -| 0 output parameters | √ | × | PB must have output parameters | -| The input/output parameters are abstract classes | √ | × | The input/output parameters of PB must be concrete classes | -| The input/output parameters are interfaces | √ | × | The input/output parameters of PB must be concrete | -| The input parameter/output parameter is the basic type | √ | × | The input parameter/output parameter of PB must be a structure | - -## 5. Community profile -* Community homepage address: https://developers.google.cn/protocol-buffers/ -* Community open source address: https://github.com/google/protobuf -* Maven of related jars: https://search.maven.org/search?q=com.google.protobuf \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/serialization-upgrade.md b/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/serialization-upgrade.md deleted file mode 100644 index 2c5572300940..000000000000 --- a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/serialization-upgrade.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -type: docs -title: "Serialization Protocol Upgrade Guide" -linkTitle: "Serialization Protocol Upgrade Guide" -weight: 6 -description: "Best practice for lossless upgrade serialization protocols" ---- -In version 3.1.0, the serialization protocol supported by Dubbo by default adds support for Fastjson2. Some users may consider upgrading the serialization protocol in the existing system, but the difference between the server and client versions may cause the client to not support the serialization protocol of the server. In version 3.2.0, Dubbo's server introduces a new configuration `prefer-serialization`, which can perfectly solve the possible risks in the server-side serialization upgrade process. - - -### Best Practices - -Serialization protocol upgrade needs to be done in two steps: - -* **First, it is necessary to promote the serialization protocol upgrade of the server, and at the same time, the `prefer-serialization` configuration needs to be added to the exposed configuration of the server. For example: the serialization protocol before the upgrade is hessian2, and the serialization protocol after the upgrade is Fastjson2, then the configuration shown below should be added to the exposed configuration of the server ** - -```yaml -dubbo.provider.prefer-serialization=fastjson2,hessian2 -dubbo.provider.serialization=hessian2 -``` -* **Secondly, the client needs to be upgraded to the same version as the server** - -### Implementation principle - -The dubbo client serialization protocol is selected according to the registration configuration of the server (that is, the `serialization` configuration of the server). In the request phase, dubbo will assemble the serialization protocol of the client into the request header, and the server will determine the deserialization protocol according to the request header when performing deserialization. -- **So, if the versions of the server and the client are inconsistent, the client may not be able to serialize. ** In order to solve this situation, 3.2.0 will use the protocol configured by `prefer-serialization` first when serializing the client. If the protocol related to `prefer-serialization` is not supported, the protocol configured by `serialization` will be used . (You can think of `serialization` as a bottom-up configuration) \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/_index.md b/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/_index.md deleted file mode 100755 index 1bcd924a8fa5..000000000000 --- a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/_index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: docs -title: "Application Level Service Discovery" -linkTitle: "Application-Level Service Discovery" -weight: 6 ---- \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery.md b/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery.md deleted file mode 100644 index ebc675d317c8..000000000000 --- a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/migration-service-discovery.md +++ /dev/null @@ -1,159 +0,0 @@ ---- -type: docs -title: "Guidelines for migrating interface-level service discovery to application-level service discovery" -linkTitle: "Guidelines for migrating interface-level service discovery to application-level service discovery" -weight: 10 -description: "This document is specifically aimed at old users of version 2.x. It explains in detail the default address registration and discovery behavior after upgrading to 3.x, and how to smoothly migrate to the address model of the new version." ---- - -**In general, 3.x is fully compatible with 2.x in address registration and discovery, which means that users can choose to upgrade any number of applications or machines in the cluster to 3.x, and at the same time Interoperability with 2.x versions is maintained in the process. ** -If you are concerned about the working principle behind migration, please refer to [Migration Rule Details and Working Principle](../service-discovery-rule) - -## 1 Quick upgrade steps - -Simply modify the pom.xml to the latest version to complete the upgrade. If you want to migrate to the application-level address, you only need to adjust the switch to control the default behavior of the 3.x version. - -1. Upgrade the Provider application to the latest 3.x version dependency, configure the dual registration switch `dubbo.application.register-mode=all` (it is recommended to set it through the global configuration center, it is automatically enabled by default), and complete the application release. -2. Upgrade the Consumer application to the latest 3.x version dependency, configure the dual subscription switch `dubbo.application.service-discovery.migration=APPLICATION_FIRST` (it is recommended to set it through the global configuration center, it is automatically enabled by default), and complete the application release. -3. After confirming that all consumers on the Provider have completed the application-level address migration, the Provider switches to the application-level address list registration. complete upgrade - - - -The following is a detailed description of the migration process. - -## 2 Provider-side upgrade process details - -Without changing any Dubbo configuration, an application or instance can be upgraded to version 3.x, and the upgraded Dubbo instance will tacitly guarantee compatibility with version 2.x, that is, the 2.x format will be registered normally address to the registry, so upgraded instances will still remain visible to the entire cluster. - - - -At the same time, the new address discovery model (registering application-level addresses) will also be automatically registered. - -![//imgs/v3/migration/provider-registration.png](/imgs/v3/migration/provider-registration.png) - -Through the -D parameter, you can specify the registration behavior when the provider starts - -```text --Ddubbo.application.register-mode=all -# Optional values interface, instance, all, the default is all, that is, both interface-level addresses and application-level addresses are registered -``` - - - -In addition, the global default behavior can be modified in the configuration center to control the registration behavior of all 3.x instances. Among them, the priority of the global switch is lower than that of the -D parameter. - - - -In order to ensure smooth migration, that is, instances upgraded to 3.x can be discovered by 2.x and 3.x consumer instances at the same time, 3.x instances need to enable dual registration; when all upstream consumers are migrated to 3.x After the address model is specified, the provider can switch to the instance mode (only register application-level addresses). See the next section for how to upgrade the consumer to 3.x. - -### 2.1 Resource consumption caused by double registration - -Double registration will inevitably bring additional storage pressure on the registration center, but considering the great advantages of the data volume of the application-level address discovery model in terms of storage, even for some ultra-large-scale cluster users, the new data volume It doesn't cause storage problems either. Generally speaking, for an ordinary cluster, data growth can be controlled at 1/100 ~ 1/1000 of the previous total data - -Take a medium-sized cluster instance: 2000 instances, 50 applications (500 Dubbo interfaces, 10 interfaces per application on average). - -Assume that the average size of each interface-level URL address is 5kb, and the average size of each application-level URL is 0.5kb - -Old interface-level address volume: 2000 * 500 * 5kb ≈ 4.8G - -New application-level addresses: 2000 * 50 * 0.5kb ≈ 48M - -After double registration, only 48M data volume has been increased. - - - -## 3 Consumer side upgrade process - -For 2.x consumer instances, they will naturally see the 2.x version of the provider address list; - -For 3.x consumers, it has the ability to discover both 2.x and 3.x provider address lists. By default, if there is a 3.x address that can be consumed in the cluster, the 3.x address will be automatically consumed, and if there is no new address, the 2.x address will be automatically consumed. Dubbo3 provides a switch to control this behavior: - -```text -dubbo.application.service-discovery.migration=APPLICATION_FIRST -# optional value -# FORCE_INTERFACE, only consume interface-level addresses, if there is no address, an error will be reported, and only subscribe to 2.x addresses -# APPLICATION_FIRST, intelligent decision interface level/application level address, double subscription -# FORCE_APPLICATION, only consume application-level addresses, if there is no address, an error will be reported, and only subscribe to 3.x addresses -``` - -`dubbo.application.service-discovery.migration` supports configuration via `-D` and `Global Configuration Center`. - - - -![//imgs/v3/migration/consumer-subscription.png](/imgs/v3/migration/consumer-subscription.png) - - -Next, let's take a closer look at how to migrate consumers upgraded to 3.x to application-level addresses through the dual subscription mode (APPLICATION_FIRST). Before the specific development, first clarify the location selection behavior of the consumer: **For the dual subscription scenario, although the consumer can hold the 2.x address and the 3.x address at the same time, the two addresses are completely isolated during the location selection process Definitely: Either use 2.x address or 3.x address, there is no mixed calling of two addresses, this decision-making process is completed after receiving the first address notification. ** - - - -Next, let's look at the specific operation process of an `APPLICATION_FIRST` strategy. - -First, configure a configuration item in the global configuration center Nacos in advance (all consumers will implement this address selection strategy by default): - -![//imgs/v3/migration/nacos-migration-item.png](/imgs/v3/migration/nacos-migration-item.png) - - - -Next, upgrade the consumer to version 3.x and start it. At this time, the consumer reads the `APPLICATION_FIRST` configuration and executes the double subscription logic (subscribing to 2.x interface-level addresses and 3.x application-level addresses) - - - -At this point, the upgrade operation is completed, and the rest is the execution within the framework. Before the call occurs, the framework will have a "site selection process" on the consumer side. Note that the site selection here is different from the previous 2.x version. The site selection process includes two layers of screening: - -* Filter the address list (ClusterInvoker) first (interface-level address or application-level address) -* Then perform the actual provider address (Invoker) screening. - -![//imgs/v3/migration/migration-cluster-item.png](/imgs/v3/migration/migration-cluster-invoker.png) - -The basis for ClusterInvoker screening can be defined by the MigrationAddressComparator SPI. Currently, the official provides a simple address quantity comparison strategy, that is, migration will be performed when `application-level address quantity == interface-level address quantity` is satisfied. - -> In fact, FORCE_INTERFACE, APPLICATION_FIRST, and FORCE_APPLICATION control the filtering strategy of the ClusterInvoker type here - - - -### 3.1 Resource consumption caused by double subscription - -Double subscription will inevitably increase the memory consumption of the consumer, but due to the advantages of application-level address discovery in terms of the total number of addresses, this process is usually acceptable. We analyze it from two aspects: - -1. The amount of address push data increased due to double subscription. We introduced this point in the "Double Registration Resource Consumption" section, and the data volume growth of the registration center brought about by application-level service discovery is very limited. -2. The increase in memory on the consumer side brought about by double subscriptions. It should be noted that double subscription only exists in the startup transient state, and one of the addresses will be completely destroyed after the ClusterInvoker site selection decision; for a single service, the memory growth caused by the double subscription during the startup phase can be controlled at about 30% of the original memory % ~ 40%, and then it will drop to the single subscription level. If you switch to the application-level address, you can achieve a 50% drop in memory. - - - -### 3.2 Finer-grained control on the consumer side - -In addition to the global migration strategy, Dubbo provides more fine-grained migration strategy support on the consumer side. The control unit can be a certain consumer application, and the service A and service B it consumes can have their own independent migration strategies. The specific method is to configure the migration rules on the consumer side: - - -```yaml -key: demo-consumer -step: APPLICATION_FIRST -applications: - - name: demo-provider - step: FORCE_APPLICATION -services: - - serviceKey: org.apache.dubbo.config.api.DemoService:1.0.0 - step: FORCE_INTERFACE -``` - -Using this method can achieve more fine-grained migration control, but the current and subsequent transformation costs will be relatively high. Except for some special scenarios, we do not recommend enabling this configuration method. -([Migration Guide](../service-discovery-rule/)) **Officially recommended global switch-type migration strategy, allowing consumer instances to decide which available address list to use during the startup phase. ** - - - -## 4 Convergence of transition state - -In order to be compatible with the 2.x version at the same time, the application upgraded to the 3.x version is either in the double registration state or in the double subscription state for a period of time. - -To solve this problem, we still look at it from the Provider perspective. When all Providers are switched to application-level address registration, there will be no double subscription problem. - -### 4.1 Different upgrade strategies have a great impact - -There is no doubt that the sooner and more thoroughly the upgrade will be able to get rid of this situation as soon as possible. Imagine that if all applications in the organization can be upgraded to version 3.x, version convergence becomes very simple: Provider always maintains dual registration during the upgrade process. After all applications are upgraded to 3.x, you can Adjust the global default behavior to make Providers become application-level address list registrations. This process will not cause trouble for Consumer applications, because they are already version 3.x that can recognize application-level addresses. - -If there is no way to upgrade the entire application, or even only a part of the application can be upgraded within a long period of time, the inevitable migration state will last for a relatively long time. -In this case, what we can only pursue is to keep the upstream and downstream implementation versions and functions of the upgraded application converged as much as possible. The upstream consumers of certain Providers are promoted to upgrade to Dubbo3, so that the dual registration of these Providers can be lifted. To do this, the support of some auxiliary statistical tools may be required. - -1. To be able to analyze the dependencies between applications, such as which consumer applications a Provdier application is consumed by, this can be achieved through the service metadata reporting capability provided by Dubbo. -2. To know the dubbo version currently used by each application, you can scan or actively report. \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule.md b/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule.md deleted file mode 100644 index 7159df792d72..000000000000 --- a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-rule.md +++ /dev/null @@ -1,203 +0,0 @@ ---- -type: docs -title: "Application-level Service Discovery Address Migration Rules Description" -linkTitle: "Application-level service discovery address migration rules" -weight: 42 -description: "This article specifies the rule body information used in the address migration process. Users can customize their own migration rules according to their needs." ---- - -## State Model - - -Before Dubbo 3, the address registration model was registered to the registry at the interface-level granularity, while the new application-level registration model of Dubbo 3 is registered to the registry at the application-level granularity. The implementation of the registry is almost different, which leads to the inability to merge the invokers obtained from the interface-level registration model with the invokers obtained from the application-level registration model. In order to help users migrate from the interface level to the application level, Dubbo 3 has designed the Migration mechanism, which realizes the switching of the address model in the actual call based on the switching of the three states. - - -![//imgs/v3/migration/migration-1.png](/imgs/v3/migration/migration-1.png) - -Currently there are three states, FORCE_INTERFACE (mandatory interface level), APPLICATION_FIRST (application level priority), FORCE_APPLICATION (mandatory application level). - - -FORCE_INTERFACE: Only enable the registry logic for interface-level service discovery in compatibility mode, and 100% of the call traffic follows the original process -APPLICATION_FIRST: Enable interface-level and application-level dual subscriptions, and dynamically determine the calling traffic direction according to the threshold and grayscale traffic ratio at runtime -FORCE_APPLICATION: Only enable the registration center logic of application-level service discovery in the new mode, and 100% of the call traffic goes to the address of the application-level subscription - - -## Description of rule body - - -The rules are configured in yaml format, and the specific configuration is as follows: -```yaml -key: consumer application name (required) -step: state name (required) -threshold: decision threshold (default 1.0) -proportion: grayscale ratio (default 100) -delay: delay decision time (default 0) -force: force switching (default false) -interfaces: interface granularity configuration (optional) - - serviceKey: interface name (interface + : + version number) (required) - threshold: decision threshold - proportion: grayscale ratio - delay: delay decision time - force: force switch - step: state name (required) - - serviceKey: interface name (interface + : + version number) - step: state name -applications: application granular configuration (optional) - - serviceKey: application name (consumed upstream application name) (required) - threshold: decision threshold - proportion: grayscale ratio - delay: delay decision time - force: force switch - step: state name (required) -``` - - -- key: consumer application name -- step: state name (FORCE_INTERFACE, APPLICATION_FIRST, FORCE_APPLICATION) -- threshold: decision threshold (floating point number, refer to the following for specific meaning) -- proportion: grayscale ratio (0 to 100, determines the proportion of calling times) -- delay: Delay decision time (delay decision time, the actual waiting time is 1~2 times the delay time, depending on the time of the first notification from the registration center, for the current Dubbo registration center to achieve secondary configuration items keep 0) -- force: Forced switching (for FORCE_INTERFACE, FORCE_APPLICATION whether to switch directly without considering the decision, which may cause no address call failure) -- interfaces: interface granularity configuration - - - -The reference configuration example is as follows: -```yaml -key: demo-consumer -step: APPLICATION_FIRST -threshold: 1.0 -proportion: 60 -delay: 0 -force: false -interfaces: - - serviceKey: DemoService: 1.0.0 - threshold: 0.5 - proportion: 30 - delay: 0 - force: true - step: APPLICATION_FIRST - - serviceKey: GreetingService: 1.0.0 - step: FORCE_APPLICATION -``` - - -## Description of configuration method -### 1. Configuration center configuration file delivery (recommended) - - -- Key: consumer application name + ".migration" -- Group: DUBBO_SERVICEDISCOVERY_MIGRATION - - -Refer to the previous section for the content of configuration items - - -When the program starts, it will pull this configuration as the highest priority startup item. When the configuration item is a startup item, no checking operation will be performed, and the final state will be reached directly according to the status information. -When a new configuration item is received during the running of the program, the migration operation will be performed, and the configuration information will be checked during the process. If the check fails, it will be rolled back to the pre-migration state. Migration is performed at the interface granularity, that is, if an application has 10 interfaces, 8 of which migrate successfully and 2 fail, then in the final state, the 8 successfully migrated interfaces will execute the new behavior, and the 2 failed interfaces will still be old state. If it is necessary to re-trigger the migration, it can be achieved by re-delivering the rules. - - -Note: If the program is rolled back due to check failure during migration, since the program does not have the behavior of writing back configuration items, if the program is restarted at this time, the program will directly initialize according to the new behavior without checking. - - -### 2. Start parameter configuration - - -- Configuration item name: dubbo.application.service-discovery.migration -- Range of allowed values: FORCE_INTERFACE, APPLICATION_FIRST, FORCE_APPLICATION - - - -This configuration item can be passed in through environment variables or the configuration center, and has a lower priority than the configuration file at startup, that is, when the configuration file in the configuration center does not exist, this configuration item is read as the startup status. - - -### 3. Local file configuration - - - -| Configuration item name | Default value | Description | -| --- | --- | --- | -| dubbo.migration.file | dubbo-migration.yaml | Local configuration file path | -| dubbo.application.migration.delay | 60000 | Configuration file delay effective time (milliseconds) | - -The format in the configuration file is consistent with the rules mentioned above - - -The local file configuration method is essentially a delayed configuration notification method. The local file will not affect the default startup method. When the delay time is reached, a notification with the same content as the local file will be triggered. The delay time here is not related to the delay field in the rule body. -The local file configuration method can ensure that the startup is initialized with the default behavior. When the delay is reached, the migration operation is triggered and the corresponding check is performed to avoid starting in the final state at startup. - - -## Decision statement -### 1. Threshold detection - - -The threshold mechanism is designed to check the number of addresses before traffic switching. If the number of available addresses at the application level is compared with the number of available addresses at the interface level, the check fails if the threshold is not reached. - - -The core code is as follows: -```java -if (((float) newAddressSize / (float) oldAddressSize) >= threshold) { - return true; -} -return false; -``` - - -At the same time, MigrationAddressComparator is also an SPI extension point, users can expand it by themselves, and the results of all checks are intersected. - - -### 2. Gray scale - - -The gray scale function only takes effect in the application-level priority state. This feature allows users to determine the proportion of calls to the address of the new mode application-level registry. The prerequisite for the gray scale to take effect is to meet the threshold detection. In the application-level priority state, if the threshold detection passes, `currentAvailableInvoker` will be switched to the invoker corresponding to the application-level address; if the detection fails, `currentAvailableInvoker` will still be the original interface-level address The invoker. - - -The flow chart is as follows: -detection stage -![//imgs/v3/migration/migration-2.png](/imgs/v3/migration/migration-2.png) -call phase -![//imgs/v3/migration/migration-3.png](/imgs/v3/migration/migration-3.png) - - -The core code is as follows: -```java -// currentAvailableInvoker is based on MigrationAddressComparator's result -if (currentAvailableInvoker != null) { - if (step == APPLICATION_FIRST) { - // call ratio calculation based on random value - if (ThreadLocalRandom. current(). nextDouble(100) > promotion) { - return invoker.invoke(invocation); - } - } - return currentAvailableInvoker.invoke(invocation); -} - -``` - - -## Description of switching process - - -The process of address migration involves the switching of three states. In order to ensure smooth migration, there are 6 switching paths that need to be supported, which can be summarized as switching from mandatory interface level, mandatory application level to application level priority; application level priority to mandatory interface level, Mandatory application-level switching; there are also mandatory interface-level and mandatory application-level switching. -The switching process for the same interface is always synchronous. If a new rule is received before the previous rule has been processed, it will wait. - - -### 1. Switch to application-level priority - - -Switching from mandatory interface level, mandatory application level to application level priority is essentially a process of switching from a single subscription to a dual subscription, retaining the original subscription and creating another subscription. In this switching mode, the delay configuration configured in the rule body will not take effect, that is, the threshold detection will be performed immediately after the subscription is created, and a decision will be made to select a certain group of subscriptions for the actual priority call. Since the application-level priority mode supports dynamic threshold detection at runtime, the threshold will be recalculated and switched after all addresses are notified for the scenario where some registry centers fail to start and obtain all addresses. -Dynamic switching in the application-level priority mode is implemented based on the address listener of the service directory (Directory). -![//imgs/v3/migration/migration-4.png](/imgs/v3/migration/migration-4.png) - - -### 2. Application-level priority switch to mandatory - - -The process of switching from application-level priority to mandatory interface level and mandatory application level is to check the address of the double subscription. If it is satisfied, the other subscription will be destroyed. If it is not satisfied, the original application-level priority status will be rolled back. -If the user wants the switching process to switch directly without checking, it can be realized by configuring the force parameter. -![//imgs/v3/migration/migration-5.png](/imgs/v3/migration/migration-5.png) -### 3. Mandatory interface level and mandatory application level switch between each other - - -To switch between the mandatory interface level and the mandatory application level, a new subscription needs to be temporarily created to determine whether the new subscription (that is, the number of addresses of the new subscription is used to subtract the number of addresses of the old subscription when calculating the threshold) is up to the standard. Failure to meet the standard will destroy the new subscription and roll back to the previous state. -![//imgs/v3/migration/migration-6.png](/imgs/v3/migration/migration-6.png) \ No newline at end of file diff --git a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples.md b/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples.md deleted file mode 100644 index d6c4234aa12a..000000000000 --- a/content/en/docs3-v2/java-sdk/upgrades-and-compatibility/service-discovery/service-discovery-samples.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -type: docs -title: "Application-Level Service Discovery Migration Example" -linkTitle: "Application-level service discovery migration example" -weight: 5 -description: "This article specifically explains how users can quickly enable new features of application-level service discovery after upgrading to Dubbo 3.0." ---- - -Application-level service discovery is a protocol for service discovery between applications. Therefore, to use application-level service discovery, both the consumer and the server must be upgraded to Dubbo 3.0 and new features enabled (enabled by default) to use application-level service discovery in the link. Take advantage of application-level service discovery. -## Open method -### Server -After the application is upgraded to Dubbo 3.0, the server will automatically enable the interface-level + application-level dual registration function, and the developer does not need to modify any configuration by default - -### Consumer side -After the application is upgraded to Dubbo 3.0, the consumer side automatically starts the interface-level + application-level dual subscription function, and the developer does not need to modify any configuration by default. It is recommended that after the server is upgraded to Dubbo 3.0 and the application-level registration is enabled, configure the consumer end to close the interface-level subscription through rules to release the corresponding memory space. - -## Detailed description -### Server configuration - -1. Global switch - -Application configuration (can be specified by configuration file or -D) `dubbo.application.register-mode` enables the global registration switch for instance (only register application level) and all (both interface level and application level registration). After configuring this switch , by default, application-level addresses will be registered with all registries for service discovery on the consumer side. -> Example: [https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-cloud-native/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-provider2/src/main/resources/ dubbo.properties](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-provider2/src /main/resources/dubbo.properties) - -``` -# double registration -dubbo.application.register-mode=all -``` -``` -# Application-level registration only -dubbo.application.register-mode=instance -``` - -2. Registration center address parameter configuration - -Registry-type=service can be configured on the address of the registry to display the registry that specifies the registry as application-level service discovery, and the registry with this configuration will only perform application-level service discovery. -> Example: [https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-cloud-native/dubbo-demo-servicediscovery-xml/servicediscovery-provider/src/main/resources/spring/ dubbo-provider.xml](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-demo-servicediscovery-xml/servicediscovery-provider/src /main/resources/spring/dubbo-provider.xml) - -```xml - -``` -### Consumer Subscription Mode -FORCE_INTERFACE: only interface-level subscription, the behavior is consistent with Dubbo 2.7 and previous versions. -APPLICATION_FIRST: interface level + application level multi-subscription, if the application level can subscribe to the address, use the application level subscription, if the address cannot be subscribed, use the interface level subscription, so as to ensure the greatest compatibility during the migration process. (Note: Due to the simultaneous subscription behavior, the memory usage in this mode will increase to a certain extent, so after all servers are upgraded to Dubbo 3.0, it is recommended to migrate to FORCE_APPLICATION mode to reduce memory usage) -FORCE_APPLICATION: Only application-level subscriptions will only use the new service discovery model. -### Consumer configuration - -1. Default configuration (no configuration required) - -After upgrading to Dubbo 3.0, the default behavior is interface-level + application-level multi-subscription. If the address can be subscribed at the application level, the application-level subscription will be used. If the address cannot be subscribed, the interface-level subscription will be used to ensure maximum compatibility. - -2. Subscription parameter configuration - -Application configuration (can be specified by configuration file or -D) `dubbo.application.service-discovery.migration` is `APPLICATION_FIRST` to enable multi-subscription mode, and configuration to `FORCE_APPLICATION` can force application-level subscription mode only. -The specific interface subscription can be configured in `parameters` in `ReferenceConfig`, and the Key is `migration.step`, and the Value is `APPLICATION_FIRST` or `FORCE_APPLICATION` key-value pair to configure a single subscription. -> Example: [https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-cloud-native/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-consumer/src/test/java/ org/apache/dubbo/demo/consumer/DemoServiceConfigIT.java](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration /dubbo-servicediscovery-migration-consumer/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConfigIT.java) - -```java -System.setProperty("dubbo.application.service-discovery.migration", "APPLICATION_FIRST"); -``` -```java -ReferenceConfig referenceConfig = new ReferenceConfig<>(applicationModel. newModule()); -referenceConfig.setInterface(DemoService.class); -referenceConfig.setParameters(new HashMap<>()); -referenceConfig.getParameters().put("migration.step", mode); -return referenceConfig.get(); -``` - -3. Dynamic configuration (highest priority, configuration can be modified at runtime) - -This configuration needs to be pushed based on the configuration center, the Key is the application name + `.migration` (such as `demo-application.migraion`), and the Group is `DUBBO_SERVICEDISCOVERY_MIGRATION`. For details on rule body configuration, see [Guidelines for migrating from interface-level service discovery to application-level service discovery](../migration-service-discovery/). -> Example: [https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-cloud-native/dubbo-servicediscovery-migration/dubbo-servicediscovery-migration-consumer/src/main/java/ org/apache/dubbo/demo/consumer/UpgradeUtil.java](https://github.com/apache/dubbo-samples/blob/master/2-advanced/dubbo-samples-service-discovery/dubbo-servicediscovery-migration /dubbo-servicediscovery-migration-consumer/src/main/java/org/apache/dubbo/demo/consumer/UpgradeUtil.java) - -```java -step: FORCE_INTERFACE -``` diff --git a/content/en/docs3-v2/rust-sdk/_index.md b/content/en/docs3-v2/rust-sdk/_index.md deleted file mode 100755 index 018a89bfb4cb..000000000000 --- a/content/en/docs3-v2/rust-sdk/_index.md +++ /dev/null @@ -1,9 +0,0 @@ - ---- -type: docs -title: "Rust" -linkTitle: "Rust" -weight: 100 -description: "Rust SDK Manual" ---- - diff --git a/content/en/docs3-v2/rust-sdk/java-interoperability.md b/content/en/docs3-v2/rust-sdk/java-interoperability.md deleted file mode 100644 index b19cd9d35de9..000000000000 --- a/content/en/docs3-v2/rust-sdk/java-interoperability.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -type: docs -title: "Rust and Java interoperability" -linkTitle: "Rust and Java interoperability" -weight: 2 -description: "Use Dubbo-rust call Duboo Java service" ---- - -## 1 Prerequisite -- Install [Rust development environment](https://rustup.rs/). -- Install [protoc](https://grpc.io/docs/protoc-installation/). -- Install Java development environment. - -## 2 Run example of Java Dubbo provider - -Java version of Dubbo provider example . - -Clone the source code, compile, and run provider: - -```sh -$ # clone the source code -$ git clone https://github.com/apache/dubbo-samples.git -$ cd dubbo-samples/dubbo-samples-triple/ - -$ # compile and build -$ mvn clean compile package -DskipTests - -$ # run provider -$ java -Dprovider.port=8888 -jar ./target/dubbo-samples-triple-1.0-SNAPSHOT.jar -# … some logs -Dubbo triple stub server started, port=8888 -``` - -[The interface defination on Java side](https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/main/proto/greeter.proto) - -## 3 Run Rust version of Dubbo consumer - -Rust version of Dubbo consumer . - -Clone the source code, compile and run consumer: - -```sh -$ # clone the source code -$ git clone https://github.com/apache/dubbo-rust.git -$ cd dubbo-rust/examples/greeter/ - -$ # build -$ cargo build - -$ # run consumer, call provider -$ ../../target/debug/greeter-client -# unary call -Response: GreeterReply { message: "hello, dubbo-rust" } -# client stream -client streaming, Response: GreeterReply { message: "hello client streaming" } -# bi stream -parts: Metadata { inner: {"content-type": "application/grpc", "date": "Wed, 28 Sep 2022 23:54:56 GMT"} } -reply: GreeterReply { message: "server reply: \"msg1 from client\"" } -reply: GreeterReply { message: "server reply: \"msg2 from client\"" } -reply: GreeterReply { message: "server reply: \"msg3 from client\"" } -trailer: Some(Metadata { inner: {"grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity", "content-type": "application/grpc", "grpc-status": "0"} }) -# server stream -parts: Metadata { inner: {"content-type": "application/grpc", "date": "Wed, 28 Sep 2022 23:54:56 GMT"} } -reply: GreeterReply { message: "msg1 from server" } -reply: GreeterReply { message: "msg2 from server" } -reply: GreeterReply { message: "msg3 from server" } -trailer: Some(Metadata { inner: {"content-type": "application/grpc", "grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity", "grpc-status": "0"} }) -``` - -[The interface defination on Rust side](https://github.com/apache/dubbo-rust/blob/main/examples/greeter/proto/greeter.proto) diff --git a/content/en/docs3-v2/rust-sdk/protocol.md b/content/en/docs3-v2/rust-sdk/protocol.md deleted file mode 100644 index bda0867b09f7..000000000000 --- a/content/en/docs3-v2/rust-sdk/protocol.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: docs -title: "Network Protocol" -linkTitle: "Network Protocol" -weight: 3 -description: "Network Protocol" ---- \ No newline at end of file diff --git a/content/en/docs3-v2/rust-sdk/quick-start.md b/content/en/docs3-v2/rust-sdk/quick-start.md deleted file mode 100644 index a70d529a65a2..000000000000 --- a/content/en/docs3-v2/rust-sdk/quick-start.md +++ /dev/null @@ -1,458 +0,0 @@ ---- -type: docs -title: "Quick start" -linkTitle: "Quick start" -weight: 1 -description: "Quick start to use Dubbo-rust" ---- - -See the full example [here](https://github.com/apache/dubbo-rust/tree/main/examples/greeter). - -## 1 Prerequisite -- Install [Rust development environment](https://rustup.rs/). -- Install [protoc](https://grpc.io/docs/protoc-installation/). - -## 2 Use IDL to define Dubbo service - -The Greeter service is defined as follows, contains a Unary, Client stream, Server stream, Bidirectional stream model Dubbo service: - -```protobuf -// ./proto/greeter.proto -syntax = "proto3"; - -option java_multiple_files = true; - -package org.apache.dubbo.sample.tri; - - -// The request message containing the user's name. -message GreeterRequest { - string name = 1; -} - -// The response message containing the greetings -message GreeterReply { - string message = 1; -} - -service Greeter{ - - // unary - rpc greet(GreeterRequest) returns (GreeterReply); - - // clientStream - rpc greetClientStream(stream GreeterRequest) returns (GreeterReply); - - // serverStream - rpc greetServerStream(GreeterRequest) returns (stream GreeterReply); - - // bi streaming - rpc greetStream(stream GreeterRequest) returns (stream GreeterReply); - -} -``` - -## 3 Add Dubbo-rust and other dependencies -```toml -# ./Cargo.toml -[package] -name = "example-greeter" -version = "0.1.0" -edition = "2021" - -[[bin]] -name = "greeter-server" -path = "src/greeter/server.rs" - -[[bin]] -name = "greeter-client" -path = "src/greeter/client.rs" - -[dependencies] -http = "0.2" -http-body = "0.4.4" -futures-util = {version = "0.3", default-features = false} -tokio = { version = "1.0", features = [ "rt-multi-thread", "time", "fs", "macros", "net", "signal"] } -prost-derive = {version = "0.10", optional = true} -prost = "0.10.4" -async-trait = "0.1.56" -tokio-stream = "0.1" - -dubbo = "0.1.0" -dubbo-config = "0.1.0" - -[build-dependencies] -dubbo-build = "0.1.0" -``` - -## 4 Configure dubbo-build to compile IDL - -Create `build.rs` at project root directory: - -```rust -// ./build.rs -fn main() -> Result<(), Box> { - tonic_build::compile_protos("proto/helloworld.proto")?; - Ok(()) -} -``` - -After this configuration, the project compiling will generate Dubbo stub code, where the path is usually located `./target/debug/build/example-greeter-/out/org.apache.dubbo.sample.tri.rs`. - -## 5 Implement server and client - -### 5.1 Write Dubbo-rust Server - -```rust -// ./src/greeter/server.rs -pub mod protos { - include!(concat!(env!("OUT_DIR"), "/org.apache.dubbo.sample.tri.rs")); -} - -use futures_util::StreamExt; -use protos::{ - greeter_server::{register_server, Greeter}, - GreeterReply, GreeterRequest, -}; - -use std::{io::ErrorKind, pin::Pin}; - -use async_trait::async_trait; -use futures_util::Stream; -use tokio::sync::mpsc; -use tokio_stream::wrappers::ReceiverStream; - -use dubbo_config::RootConfig; -use dubbo::{codegen::*, Dubbo}; - -type ResponseStream = - Pin> + Send>>; - -#[tokio::main] -async fn main() { - register_server(GreeterServerImpl { - name: "greeter".to_string(), - }); - - // Dubbo::new().start().await; - Dubbo::new() - .with_config({ - let r = RootConfig::new(); - match r.load() { - Ok(config) => config, - Err(_err) => panic!("err: {:?}", _err), // response was droped - } - }) - .start() - .await; -} - -#[allow(dead_code)] -#[derive(Default, Clone)] -struct GreeterServerImpl { - name: String, -} - -// #[async_trait] -#[async_trait] -impl Greeter for GreeterServerImpl { - async fn greet( - &self, - request: Request, - ) -> Result, dubbo::status::Status> { - println!("GreeterServer::greet {:?}", request.metadata); - - Ok(Response::new(GreeterReply { - message: "hello, dubbo-rust".to_string(), - })) - } - - async fn greet_client_stream( - &self, - request: Request>, - ) -> Result, dubbo::status::Status> { - let mut s = request.into_inner(); - loop { - let result = s.next().await; - match result { - Some(Ok(val)) => println!("result: {:?}", val), - Some(Err(val)) => println!("err: {:?}", val), - None => break, - } - } - Ok(Response::new(GreeterReply { - message: "hello client streaming".to_string(), - })) - } - - type greetServerStreamStream = ResponseStream; - async fn greet_server_stream( - &self, - request: Request, - ) -> Result, dubbo::status::Status> { - println!("greet_server_stream: {:?}", request.into_inner()); - - let data = vec![ - Result::<_, dubbo::status::Status>::Ok(GreeterReply { - message: "msg1 from server".to_string(), - }), - Result::<_, dubbo::status::Status>::Ok(GreeterReply { - message: "msg2 from server".to_string(), - }), - Result::<_, dubbo::status::Status>::Ok(GreeterReply { - message: "msg3 from server".to_string(), - }), - ]; - let resp = futures_util::stream::iter(data); - - Ok(Response::new(Box::pin(resp))) - } - - type greetStreamStream = ResponseStream; - async fn greet_stream( - &self, - request: Request>, - ) -> Result, dubbo::status::Status> { - println!( - "GreeterServer::greet_stream, grpc header: {:?}", - request.metadata - ); - - let mut in_stream = request.into_inner(); - let (tx, rx) = mpsc::channel(128); - - // this spawn here is required if you want to handle connection error. - // If we just map `in_stream` and write it back as `out_stream` the `out_stream` - // will be drooped when connection error occurs and error will never be propagated - // to mapped version of `in_stream`. - tokio::spawn(async move { - while let Some(result) = in_stream.next().await { - match result { - Ok(v) => { - // if v.name.starts_with("msg2") { - // tx.send(Err(dubbo::status::Status::internal(format!("err: args is invalid, {:?}", v.name)) - // )).await.expect("working rx"); - // continue; - // } - tx.send(Ok(GreeterReply { - message: format!("server reply: {:?}", v.name), - })) - .await - .expect("working rx") - } - Err(err) => { - if let Some(io_err) = match_for_io_error(&err) { - if io_err.kind() == ErrorKind::BrokenPipe { - // here you can handle special case when client - // disconnected in unexpected way - eprintln!("\tclient disconnected: broken pipe"); - break; - } - } - - match tx.send(Err(err)).await { - Ok(_) => (), - Err(_err) => break, // response was droped - } - } - } - } - println!("\tstream ended"); - }); - - // echo just write the same data that was received - let out_stream = ReceiverStream::new(rx); - - Ok(Response::new( - Box::pin(out_stream) as Self::greetStreamStream - )) - } -} - -fn match_for_io_error(err_status: &dubbo::status::Status) -> Option<&std::io::Error> { - let mut err: &(dyn std::error::Error + 'static) = err_status; - - loop { - if let Some(io_err) = err.downcast_ref::() { - return Some(io_err); - } - - err = match err.source() { - Some(err) => err, - None => return None, - }; - } -} -``` - -### 5.2 Configure dubbo.yaml - -`dubbo.yaml` indicates the configuration of the server, including the exposed service list, protocol configuration, listening configuration, and so on. - -```yaml -# ./dubbo.yaml -name: dubbo -service: - org.apache.dubbo.sample.tri.Greeter: - version: 1.0.0 - group: test - protocol: triple - registry: '' - serializer: json - protocol_configs: - triple: - ip: 0.0.0.0 - port: '8888' - name: triple -protocols: - triple: - ip: 0.0.0.0 - port: '8888' - name: triple -``` - -### 5.3 Write Dubbo-rust Client - -```rust -// ./src/greeter/client.rs -pub mod protos { - include!(concat!(env!("OUT_DIR"), "/org.apache.dubbo.sample.tri.rs")); -} - -use dubbo::codegen::*; -use futures_util::StreamExt; -use protos::{greeter_client::GreeterClient, GreeterRequest}; - -#[tokio::main] -async fn main() { - let mut cli = GreeterClient::new().with_uri("http://127.0.0.1:8888".to_string()); - - println!("# unary call"); - let resp = cli - .greet(Request::new(GreeterRequest { - name: "message from client".to_string(), - })) - .await; - let resp = match resp { - Ok(resp) => resp, - Err(err) => return println!("{:?}", err), - }; - let (_parts, body) = resp.into_parts(); - println!("Response: {:?}", body); - - println!("# client stream"); - let data = vec![ - GreeterRequest { - name: "msg1 from client streaming".to_string(), - }, - GreeterRequest { - name: "msg2 from client streaming".to_string(), - }, - GreeterRequest { - name: "msg3 from client streaming".to_string(), - }, - ]; - let req = futures_util::stream::iter(data); - let resp = cli.greet_client_stream(req).await; - let client_streaming_resp = match resp { - Ok(resp) => resp, - Err(err) => return println!("{:?}", err), - }; - let (_parts, resp_body) = client_streaming_resp.into_parts(); - println!("client streaming, Response: {:?}", resp_body); - - println!("# bi stream"); - let data = vec![ - GreeterRequest { - name: "msg1 from client".to_string(), - }, - GreeterRequest { - name: "msg2 from client".to_string(), - }, - GreeterRequest { - name: "msg3 from client".to_string(), - }, - ]; - let req = futures_util::stream::iter(data); - - let bidi_resp = cli.greet_stream(req).await.unwrap(); - - let (parts, mut body) = bidi_resp.into_parts(); - println!("parts: {:?}", parts); - while let Some(item) = body.next().await { - match item { - Ok(v) => { - println!("reply: {:?}", v); - } - Err(err) => { - println!("err: {:?}", err); - } - } - } - let trailer = body.trailer().await.unwrap(); - println!("trailer: {:?}", trailer); - - println!("# server stream"); - let resp = cli - .greet_server_stream(Request::new(GreeterRequest { - name: "server streaming req".to_string(), - })) - .await - .unwrap(); - - let (parts, mut body) = resp.into_parts(); - println!("parts: {:?}", parts); - while let Some(item) = body.next().await { - match item { - Ok(v) => { - println!("reply: {:?}", v); - } - Err(err) => { - println!("err: {:?}", err); - } - } - } - let trailer = body.trailer().await.unwrap(); - println!("trailer: {:?}", trailer); -} -``` - -## 6 Run - -1. Compile - -Run `cargo build` to compile server and client. - -2. Run server - -Run `./target/debug/greeter-server` to start server. as configured above by dubbo.yaml, the server listens on port 8888 and provides RPC services over triple protocol: - -```sh -$ ./target/debug/greeter-server -2022-09-28T23:33:28.104577Z INFO dubbo::framework: url: Some(Url { uri: "triple://0.0.0.0:8888/org.apache.dubbo.sample.tri.Greeter", protocol: "triple", location: "0.0.0.0:8888", ip: "0.0.0.0", port: "8888", service_key: ["org.apache.dubbo.sample.tri.Greeter"], params: {} }) -``` - -3. Run client, verify that the call was successful - -Run `./target/debug/greeter-client` to start client, which will call methods under `triple://127.0.0.1:8888/org.apache.dubbo.sample.tri.Greeter`: - - -```sh -$ ./target/debug/greeter-client -# unary call -Response: GreeterReply { message: "hello, dubbo-rust" } -# client stream -client streaming, Response: GreeterReply { message: "hello client streaming" } -# bi stream -parts: Metadata { inner: {"content-type": "application/grpc", "date": "Wed, 28 Sep 2022 23:34:20 GMT"} } -reply: GreeterReply { message: "server reply: \"msg1 from client\"" } -reply: GreeterReply { message: "server reply: \"msg2 from client\"" } -reply: GreeterReply { message: "server reply: \"msg3 from client\"" } -trailer: Some(Metadata { inner: {"content-type": "application/grpc", "grpc-status": "0", "grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity"} }) -# server stream -parts: Metadata { inner: {"content-type": "application/grpc", "date": "Wed, 28 Sep 2022 23:34:20 GMT"} } -reply: GreeterReply { message: "msg1 from server" } -reply: GreeterReply { message: "msg2 from server" } -reply: GreeterReply { message: "msg3 from server" } -trailer: Some(Metadata { inner: {"content-type": "application/grpc", "grpc-status": "0", "grpc-message": "poll trailer successfully.", "grpc-accept-encoding": "gzip,identity"} }) -``` diff --git a/content/en/overview/mannual/java-sdk/tasks/extensibility/filter.md b/content/en/overview/mannual/java-sdk/tasks/extensibility/filter.md index 8994ecb594f2..bc0196772876 100644 --- a/content/en/overview/mannual/java-sdk/tasks/extensibility/filter.md +++ b/content/en/overview/mannual/java-sdk/tasks/extensibility/filter.md @@ -2,7 +2,7 @@ aliases: - /en/overview/tasks/extensibility/filter/ - /en/overview/tasks/extensibility/filter/ -description: In this article, we will learn how to extend custom filter implementations: a unified Filter processor that can handle and validate returned results, reducing disruptions to developers. +description: "In this article, we will learn how to extend custom filter implementations: a unified Filter processor that can handle and validate returned results, reducing disruptions to developers." linkTitle: Filter no_list: true title: Filter